コア コンセプト

出典:Calcite Design System - core concepts

Calcite Components は、Stencil.js を使用して構築された、再利用可能な Web コンポーネントのライブラリです。Calcite Components を使用すると、ブランド力のある、軽量でアクセスしやすい Web アプリケーションをすばやく構築できます。

Web コンポーネントはブラウザのネイティブ規格であり、Calcite Components で開発するために必要な技術的概念の多くは、このライブラリに固有のものではありません。このページでは、効果的な開発を行うために必要な、Web の主要コンセプトを紹介しています。さらに詳しい情報について、このページにあるすべての概念は、MDN Web Docs やその他の Web 標準ドキュメントのソースで見つけることができます。

カスタム要素

カスタム要素は、Web コンポーネント標準の一部であり、HTML と任意の JavaScript ライブラリまたは Web フレームワークを使用して、モダン ブラウザ全体で動作します。カスタム要素は機能をカプセル化するため、他のコードとのコンフリクトを防ぐことができます。

Calcite Components はカスタム要素であり、ネイティブの HTML 要素と同様に使用することができます。

<calcite-tip heading="Platypus"></calcite-tip>

スロット

スロットはプレースホルダー要素であり、スロットの名前を参照することで独自のコンテンツを追加することができます。スロットは一般的な Web コンポーネントの概念であり、あなたもすでに使用している可能性があります。例えば、次のような HTML を考えてみましょう。

<select>
  <option value="platypus">Platypus</option>
  <option value="sloth">Sloth</option>
  <option value="armadillo">Nine-banded armadillo</option>
</select>

Web コンポーネントの用語で、option 要素は select のデフォルト スロットに配置されます。また、「Platypus」、「Sloth」、「Nine-banded」のテキストは、それぞれの option のデフォルト スロットに配置されます。

また、多くの Calcite Components は、デフォルトのスロットを利用しています。例えば、下の calcite-tip では、デフォルトのスロットに p コンテンツが追加されています。

<calcite-tip heading="Platypus">
  <img slot="thumbnail" src="platypus.jpg" alt="A platypus sensing its prey using electrical fields." />
  <p>A platypus is a mammal with a bill, similar to a duck. They use their bill to sense prey via electrolocation.</p>
</calcite-tip>

多くの場合、デフォルトのスロットがあれば十分です。しかし、コンポーネントが複雑になればなるほど、子要素の位置やスタイルを変える必要が出てきます。そこで活躍するのがネームドスロットです。上の例では、チップの thumbnail スロットに画像が配置されています。これは、画像がデフォルトスロットの要素とは異なる方法で処理されるべきであることをコンポーネントに通知するものです。

もしコンポーネントにスロットがあれば、slots for calcite-card のように、ドキュメントに記載されます。また詳細については、slots on MDN で学ぶこともできます。


Shadow DOM

カスタム要素はカプセル化され、そのマークアップ構造、スタイル、動作はページ上の他のコードから隠され、分離された状態に保たれます。Shadow DOM は、カスタム要素をカプセル化する仕組みです。その結果、Shadow DOM は Web コンポーネントの DOM 要素を隠して分離するため、ブラウザでレンダリングされますが、他のコードとぶつかることはありません。

Shadow DOM のカプセル化により、アプリケーション間で永続的なスタイルと機能を実現し、ユーザーに一貫したユーザー エクスペリエンスを提供することができます。


CSS 変数

Calcite Components は、スタイルを上書きするための CSS 変数を提供しています。Web コンポーネントの Shadow DOM のため、CSS 変数がないと簡単にスタイルを変更することができません。トークンには CSS 変数があり、colortypography など、デザインシステム全体で使用されます。

さらに、一部の Calcite Components には、コンポーネント固有のスタイルを変更するための独自の CSS 変数があります。これらの CSS 変数は、CSS variables for cacite-loader のように、コンポーネントのドキュメントで見つけることができます。

使用例としては、CSS 変数を使用して、calcite-notice の前景色と文字色を入れ替えることができます。

calcite-notice {
  --calcite-ui-foreground-1: #151515;
  --calcite-ui-text-1: #ffffff;
}

CSS variable MDN documentation に、機能の詳細が説明されています。


コンポーネント ロード

Web コンポーネントはプレーンな HTML 要素として始まり、その実装がブラウザで定義されると同時にアップグレードされます。Calcite Components は、インポートされ、アプリケーションで使用されると、自動的に定義されます。しかし、特定のコードを実行する前に、コンポーネントが定義されるまで待つ必要がある場合があります。

ハイドレーション

Stencil.js では、コンポーネントとそのすべての子コンポーネントのハイドレーションが終了したときに、フラグを追加するオプションが用意されています。これにより、様々なコンポーネントのダウンロードとレンダリングが非同期に行われるため、FOUC(Flash of Unstyled Content)を防止することができます。Calcite Components では、一度ハイドレーションされたコンポーネントに calcite-hydrated というCSSクラスが追加され、アプリケーションをデバッグする際に便利です。

定義されたとき

customElementRegistry インターフェースの whenDefined() メソッドは、指定された要素が定義されたときに満たされる Promise を返します。

Promise が満たされると、次のようにコンポーネントの定義を必要とするコードを実行できるようになります。

customElements.whenDefined("calcite-button").then(() => document.querySelector("calcite-button").setFocus());

コンポーネントの準備

コンポーネントがいつレンダリングされるかを決定するには、Stencilの componentOnReady() メソッドを使用します。このメソッドは、componentDidLoad() ライフサイクルメソッドが起動した後に解決される Promise を返します。これは、コンポーネントのメソッドを使用する前にコンポーネントがロードされていることを確認する場合や、あるコンポーネントが他のコンポーネントに依存している場合に便利です。

例えば、他のコンポーネントのレンダリングが終了するまで、calcite-loader を表示させたい場合があります。

(async () => {
  await customElements.whenDefined("calcite-alert");
  await document.querySelector("calcite-alert").componentOnReady();
  document.querySelector("calcite-loader").hidden = true;
})();

requestAnimationFrame のコールバックとしてコンポーネントのメソッドを呼び出すことで、コンポーネントの状態でユーザー インターフェースが更新されます。例えば、ユーザーの閲覧履歴に基づいて、calcite-stepper の現在のステップを設定したい場合、goToStep()メソッドを使うことができます。

(async () => {
  await customElements.whenDefined("calcite-stepper");
  const el = await document.querySelector("calcite-stepper").componentOnReady();
  requestAnimationFrame(() => el.goToStep(3));
})();

イベント

Calcite Components は、CustomEvent() コンストラクターを使用してイベントの作成とトリガーを行います。

CustomEventEvent と似たような振る舞いをします。これは button をクリックしたときなどの HTML 要素から放出されます。例えば、イベント ペイロードの target プロパティで要素にアクセスすることは可能です。また、一部の CustomEvent のペイロードは、detail プロパティにイベント固有の情報を含みます。

コンポーネントのドキュメント ページを表示すると、calcite-pagination event のようなイベントを持つかどうかを確認することができます。

document.addEventListener("calcitePaginationChange", event => {
  console.log(`Starting item number on the page: ${event.target.startItem}`);
});

フォーム

フォーム送信時に適切に値を渡すためには、フォーム内の各コンポーネントに name 属性を設定する必要があります。例えば、Input Date PickerText Areaname 属性を追加します。

<form>
  <calcite-label>
    Observation date:
    <calcite-input-date-picker name="observation-date"></calcite-input-date-picker>
  </calcite-label>
  <calcite-label>
    Observation notes:
    <calcite-text-area name="observation-notes" placeholder="Observation notes" max-length="250"></calcite-text-area>
  </calcite-label>
  <calcite-button type="submit">Submit</calcite-button>
</form>

フォームに関するその他の考慮事項については、フォームのアクセシビリティを参照してください。


モード

Calcite Components には明暗モードがあり、対応する CSS クラス calcite-mode-lightcalcite-mode-dark を使って変更できる。calcite-mode-auto クラスもあり、ブラウザの prefers-color-scheme CSS メディアクエリに従うことで、明るいモードと暗いモードのどちらを使用するかを決定します。

要素に モード クラスを設定すると、その子ノードもすべて変更されます。したがって、アプリケーション全体を明るい状態から暗い状態に切り替えるには、次のようにします。

<body class="calcite-mode-dark">
  <!-- Your application content -->
</body>