# Esri Calcite デザインシステム

## Esri Calcite デザインシステムのインターフェースプレビュー

リストまたは模式図からサイトを選択し、レビュー状態を絞り込み、再読み込みまでサイトごとに保持されるメモを検証できます。

## Esri Calcite デザインシステムのデザインリファレンス

Calcite のデザイントークン 4.1.0 と現行コンポーネントAPIを、Components 5.1.2 とあわせて確認しています。トークンパッケージとコンポーネントパッケージのバージョン番号は別々です。埋め込みのサンプルは独自のHTML/CSSの解釈であり、Calcite のランタイムを再配布するものでも、ネイティブの動作を保証するものでもありません。

### ライトテーマのサーフェス、テキスト、インタラクション

| 名前 / ルール | 値 / 設定 | 用途 |
| --- | --- | --- |
| --calcite-color-surface-1 | #f7f7f7 | トークンが示す役割に関するセマンティックリファレンスです。選択状態とフィールドの境界には、それぞれ異なるコントラストが必要です。 |
| --calcite-color-surface-2 | #ffffff | トークンが示す役割に関するセマンティックリファレンスです。選択状態とフィールドの境界には、それぞれ異なるコントラストが必要です。 |
| --calcite-color-surface-3 | #f2f2f2 | トークンが示す役割に関するセマンティックリファレンスです。選択状態とフィールドの境界には、それぞれ異なるコントラストが必要です。 |
| --calcite-color-surface-4 | #ebebeb | トークンが示す役割に関するセマンティックリファレンスです。選択状態とフィールドの境界には、それぞれ異なるコントラストが必要です。 |
| --calcite-color-surface-highlight | #d6efff | トークンが示す役割に関するセマンティックリファレンスです。選択状態とフィールドの境界には、それぞれ異なるコントラストが必要です。 |
| --calcite-color-text-1 | #141414 | トークンが示す役割に関するセマンティックリファレンスです。選択状態とフィールドの境界には、それぞれ異なるコントラストが必要です。 |
| --calcite-color-text-2 | #4a4a4a | トークンが示す役割に関するセマンティックリファレンスです。選択状態とフィールドの境界には、それぞれ異なるコントラストが必要です。 |
| --calcite-color-text-3 | #6b6b6b | トークンが示す役割に関するセマンティックリファレンスです。選択状態とフィールドの境界には、それぞれ異なるコントラストが必要です。 |
| --calcite-color-text-inverse | #ffffff | トークンが示す役割に関するセマンティックリファレンスです。選択状態とフィールドの境界には、それぞれ異なるコントラストが必要です。 |
| --calcite-color-text-link | #00619b | トークンが示す役割に関するセマンティックリファレンスです。選択状態とフィールドの境界には、それぞれ異なるコントラストが必要です。 |
| --calcite-color-border-1 | #d4d4d4 | トークンが示す役割に関するセマンティックリファレンスです。選択状態とフィールドの境界には、それぞれ異なるコントラストが必要です。 |
| --calcite-color-border-2 | #dedede | トークンが示す役割に関するセマンティックリファレンスです。選択状態とフィールドの境界には、それぞれ異なるコントラストが必要です。 |
| --calcite-color-border-3 | #ebebeb | トークンが示す役割に関するセマンティックリファレンスです。選択状態とフィールドの境界には、それぞれ異なるコントラストが必要です。 |
| --calcite-color-border-input | #949494 | トークンが示す役割に関するセマンティックリファレンスです。選択状態とフィールドの境界には、それぞれ異なるコントラストが必要です。 |
| --calcite-color-brand | #007ac2 | トークンが示す役割に関するセマンティックリファレンスです。選択状態とフィールドの境界には、それぞれ異なるコントラストが必要です。 |
| --calcite-color-brand-hover | #00619b | トークンが示す役割に関するセマンティックリファレンスです。選択状態とフィールドの境界には、それぞれ異なるコントラストが必要です。 |
| --calcite-color-brand-press | #004874 | トークンが示す役割に関するセマンティックリファレンスです。選択状態とフィールドの境界には、それぞれ異なるコントラストが必要です。 |
### 現行のスペーシングスケール

| 名前 / ルール | 値 / 設定 | 用途 |
| --- | --- | --- |
| --calcite-space-none | 0 | 現行のスペーストークンファミリーです。rem単位のステップはルートサイズに基づきます。非推奨のスペーシングエイリアスと混在させないでください。 |
| --calcite-space-px | 1px | 現行のスペーストークンファミリーです。rem単位のステップはルートサイズに基づきます。非推奨のスペーシングエイリアスと混在させないでください。 |
| --calcite-space-base | 2px | 現行のスペーストークンファミリーです。rem単位のステップはルートサイズに基づきます。非推奨のスペーシングエイリアスと混在させないでください。 |
| --calcite-space-2xs | 0.25rem | 現行のスペーストークンファミリーです。rem単位のステップはルートサイズに基づきます。非推奨のスペーシングエイリアスと混在させないでください。 |
| --calcite-space-xs | 0.375rem | 現行のスペーストークンファミリーです。rem単位のステップはルートサイズに基づきます。非推奨のスペーシングエイリアスと混在させないでください。 |
| --calcite-space-sm | 0.5rem | 現行のスペーストークンファミリーです。rem単位のステップはルートサイズに基づきます。非推奨のスペーシングエイリアスと混在させないでください。 |
| --calcite-space-sm-plus | 0.625rem | 現行のスペーストークンファミリーです。rem単位のステップはルートサイズに基づきます。非推奨のスペーシングエイリアスと混在させないでください。 |
| --calcite-space-md | 0.75rem | 現行のスペーストークンファミリーです。rem単位のステップはルートサイズに基づきます。非推奨のスペーシングエイリアスと混在させないでください。 |
| --calcite-space-md-plus | 0.875rem | 現行のスペーストークンファミリーです。rem単位のステップはルートサイズに基づきます。非推奨のスペーシングエイリアスと混在させないでください。 |
| --calcite-space-lg | 1rem | 現行のスペーストークンファミリーです。rem単位のステップはルートサイズに基づきます。非推奨のスペーシングエイリアスと混在させないでください。 |
| --calcite-space-xl | 1.25rem | 現行のスペーストークンファミリーです。rem単位のステップはルートサイズに基づきます。非推奨のスペーシングエイリアスと混在させないでください。 |
| --calcite-space-2xl | 1.5rem | 現行のスペーストークンファミリーです。rem単位のステップはルートサイズに基づきます。非推奨のスペーシングエイリアスと混在させないでください。 |
| --calcite-space-3xl | 2rem | 現行のスペーストークンファミリーです。rem単位のステップはルートサイズに基づきます。非推奨のスペーシングエイリアスと混在させないでください。 |
| --calcite-space-4xl | 2.75rem | 現行のスペーストークンファミリーです。rem単位のステップはルートサイズに基づきます。非推奨のスペーシングエイリアスと混在させないでください。 |
### 文字と角丸のスケール

| 名前 / ルール | 値 / 設定 | 用途 |
| --- | --- | --- |
| --calcite-corner-radius-none | 0 | 公開されている値です。スクリーンショットから推定した測定値ではありません。 |
| --calcite-corner-radius-xs | 2px | 公開されている値です。スクリーンショットから推定した測定値ではありません。 |
| --calcite-corner-radius-sm | 4px | 公開されている値です。スクリーンショットから推定した測定値ではありません。 |
| --calcite-corner-radius-pill | 9999px | 公開されている値です。スクリーンショットから推定した測定値ではありません。 |
| --calcite-font-size-xs | 10px | 公開されている値です。スクリーンショットから推定した測定値ではありません。 |
| --calcite-font-size-sm | 12px | 公開されている値です。スクリーンショットから推定した測定値ではありません。 |
| --calcite-font-size | 14px | 公開されている値です。スクリーンショットから推定した測定値ではありません。 |
| --calcite-font-size-md | 16px | 公開されている値です。スクリーンショットから推定した測定値ではありません。 |
| --calcite-font-size-lg | 18px | 公開されている値です。スクリーンショットから推定した測定値ではありません。 |
| --calcite-font-size-xl | 20px | 公開されている値です。スクリーンショットから推定した測定値ではありません。 |
| --calcite-font-size-2xl | 24px | 公開されている値です。スクリーンショットから推定した測定値ではありません。 |
### 入力コンポーネントAPI

| 名前 / ルール | 値 / 設定 | 用途 |
| --- | --- | --- |
| scale | s / m / l; default m | コンポーネントのスケールは意図的に変更してください。ページのズーム変更とは異なります。 |
| status | idle / valid / invalid | フィールドの有効性は、色だけでなくメッセージでも伝えてください。 |
| labelText | string | 現在の入力APIに表示されるラベルテキストです。 |
| validationMessage | string | 無効な入力の説明を、コントロールの横に表示します。 |
| calciteInputInput | event | 入力のたびに event.target.value を読み取ります。 |
| setFocus() | Promise<void> | アプリケーションの検証エラー後に、ネイティブコンポーネントへフォーカスを移します。 |
## Esri Calcite デザインシステム完全ガイド

実際のインターフェースで、このデザインシステムを選び、適用し、レビューするための実践ガイドです。

詳しいガイダンス、実装の出発点、ソースへのリンクをまとめています。

## Esri Calcite デザインシステムのワークスペースとパネルの構成

### オブジェクトの情報を常に表示する

> 空間を扱うタスクには通常、確認対象の領域と選択中のオブジェクトという、少なくとも2つのコンテキストがあります。この例では、小さなサイト一覧を独自の模式図とインスペクターの横に配置しています。一覧の行またはピンを選択すると、同じ固定IDのサイトが設定されるため、名前、ステータス、メモが別々のオブジェクトを指してしまうことはありません。

### イラストと実際のマップを明確に分ける

SVGは、一覧と空間サーフェスの関係を示します。投影法、座標、レイヤー、ズーム、ジオコーディング、ルート検索の機能はありません。キャプションには「模式図・縮尺不同」と明記しています。本番環境でArcGISビューを使用するには、個別のSDK統合、データ、アクセシビリティ対応が必要です。Calciteのシェルだけでは、これらの機能は提供されません。

## Esri Calcite デザインシステムのセマンティックカラーの役割

### カードを多用せず、サーフェスでツールを区切る

このリファレンスではsurface-1からsurface-4までを使い分け、surface-highlightは強調表示用にしています。サンプルでは、克制されたオフホワイトのキャンバスに白いインスペクターを配置し、選択中の行を淡い青で示しています。細いニュートラルカラーの境界線でパネルを区切り、フィールドごとに浮き上がったカードを追加することは避けています。

### 青に一貫したインタラクションの意味を持たせる

ブランド、ホバー、押下の色は、#007ac2、#00619b、#004874の順に暗くなります。選択中のピンと主要な保存アクションには、異なるインタラクション上の役割で同じ色の系統を使用しています。レビュー状態とメモの検証メッセージは、色だけに頼らず読み取れるようにしています。

## Esri Calcite デザインシステムの文字と情報密度

### 細かな情報階層を保つ

公開されている絶対値の文字サイズには、12pxの小さいテキスト、14pxの基本テキスト、16pxの中サイズ、20pxの特大サイズがあります。このサンプルでは、20pxのワークスペースタイトルに、16pxのパネル見出しと14pxのコントロールを組み合わせています。メタデータは小さめですが、選択中のオブジェクトを識別する唯一の情報源にはしていません。

### フォールバックフォントとブランドフォントを区別する

この独立したサンプルでは、Arialとシステムフォントをフォールバックとして使用しています。Esriのブランドフォントは同梱しておらず、フォールバックをAvenirと表示することもありません。ネイティブの統合を行う場合は、固定したCalciteリリースに付属するアセットとテーマ設定に従ってください。フォントを変更すると改行位置やコントロール幅に影響することがあるため、実際にデプロイするアセット一式でテストしてください。

## Esri Calcite デザインシステムのスペーストークンとレスポンシブパネル

### 現行のトークン名を選ぶ

このリファレンスでは、最小のステップにピクセル値、大きい間隔にrem値を使う現行の--calcite-space-*スケールを使用しています。ネイティブテーマを実装する際は、これらの役割名を一貫して使用してください。このサンプルのアプリケーションレイアウトでは、制限のあるパッケージをインポートせずに解釈を実行できるよう、明示的なCSSの値を使用しています。

### フィールドを詰め込む前にインスペクターを折り返す

アプリケーションの元のブレークポイントでは、インスペクターが一覧とイラストの下に移動します。幅の狭いスマートフォンでは、3つの領域が縦に並びます。テキストエリアは、ラベル、補助テキスト、保存アクションとともに全幅を保ちます。これらのブレークポイントは独自に設定したレイアウト上の選択であり、Calciteのトークン値を示すものではありません。

## Esri Calcite デザインシステムの選択とフィルタリングの動作

### 選択IDを1つに統一する

一覧と模式図では、現在の配列位置ではなくA-01、B-02、C-03を使って選択状態を共有しています。「確認済み」に絞り込むと、一致するサイトのうち選択可能なものが選択され、インスペクターにも反映されます。一覧のボタンと対応するピンの両方で、押下状態を示します。

### 保存済みのメモと未保存の下書きを分ける

保存済みのメモは、サイトIDをキーとするMapに保存されます。そのサイトに戻るとメモが復元され、保存せずに別のサイトへ移動すると未保存のテキストは置き換わります。補助テキストでは、ローカルでの保存期間を明示しています。下書きの消失に大きな影響がある本番向けエディターでは、未保存の変更を保護する機能を追加してください。

## Esri Calcite デザインシステムの入力検証と復旧

### Calciteを採用する場合は、実際のネイティブ入力APIを使用する

ネイティブの例では、labelText、value、status、validationMessageを使用しています。calciteInputInputイベントで古いエラーを消去でき、setFocus()を使うとアプリケーション側の検証に失敗した後にコンポーネントへ注意を戻せます。これらは公開されているAPIの名前であり、内部の入力要素を探すためにシャドウルートへアクセスする方法とは異なります。

### ローカルでの保存確認とサービスへの永続化を混同しない

単体のプレビューでは、前後の空白を除いて10文字以上が必要で、入力欄の上限は240文字です。確認メッセージにはサイト名が表示され、保存先がローカルであることが明記されます。再読み込みするとメモは消去されます。ネットワークを介して保存する場合は、処理中、失敗、再試行、競合への対応が必要です。ローカル保存のメッセージは、こうした機能を備えていることを意味しません。

1. 空欄または短いメモを保存して、エラーを確認してください。

2. 長めのメモを入力して保存し、別のサイトを選択してから戻ってください。

3. 再読み込みして、このサンプルが永続化を約束していないことを確認してください。

## Esri Calcite デザインシステム：空間情報のアクセシブルな代替手段

### 各ピンに対応するリストを用意する

操作可能なピンはすべて、サイト一覧にもテキストボタンとして表示されます。そのため、図示された地図だけがオブジェクトを選ぶ唯一の方法にはなりません。SVGには簡潔な説明を設定し、各コントロールには個別の名前と、視認できるフォーカス枠を設けています。実際の地図で必要なのは、模式図の代替テキストをコピーすることだけではありません。

### 入力欄の近くにエラーを表示する

テキストエリアでは aria-describedby を使い、補足説明とエラーの両方を関連付けています。保存に失敗すると aria-invalid を設定してフォーカスを移動し、編集を始めると古い無効状態を解除します。確認メッセージにはステータス領域を使用します。キーボードユーザーは、描画された地理図形を操作せずに、サイトの選択、メモの入力、保存を行えます。

## Esri Calcite デザインシステム：バージョンと統合の境界

### パッケージのバージョンを固定し、ライセンス要件を確認する

Components 5.1.2 と design tokens 4.1.0 は別々のパッケージです。現在のライセンスページでは、ArcGIS Online、Enterprise、または Location Platform のアカウントがあれば利用できると説明されています。以前のオープンソース版についての前提を、現在のパッケージに当てはめないでください。以下のネイティブソースは、これらの要件を満たしたプロジェクト向けです。

- Components：5.1.2。

- デザイントークンのリファレンス：4.1.0。

- プレビュー：HTML、CSS、JavaScriptを独立して使用。Esriランタイムは含みません。

### 使用するコンポーネントだけを登録する

最小限のモジュール例では、入力コンポーネントとボタンコンポーネントのエントリーポイントをインポートし、公開されているプロパティとイベントを使用します。独立した完全版のHTMLの例は単体で動作します。ネイティブのコード断片は、バージョンを固定したパッケージをインストール済みのViteプロジェクトで使うための別のエントリーポイントです。この例は公開されているAPIに照らして確認済みですが、模式図の背後で動くコンパイル済みランタイムを表すものではありません。

## Esri Calcite デザインシステム：コンポーネントの例

### 独立して動作するサイト調査サンプル

このプレビューで使用している、単体で動作するHTML、CSS、JavaScriptの完全版です。index.html として保存し、ブラウザーで開いてください。

```
<!doctype html>
<html lang="en">
  <meta charset="utf-8" /><meta
    name="viewport"
    content="width=device-width,initial-scale=1"
  /><title>Site inspection panel</title
  ><style>
    * {
      box-sizing: border-box;
    }
    body {
      margin: 0;
      font:
        14px/1.5 Arial,
        sans-serif;
      color: #141414;
      background: #f7f7f7;
    }
    button,
    input,
    select,
    textarea {
      font: inherit;
    }
    button {
      cursor: pointer;
    }
    button:focus-visible,
    input:focus-visible,
    select:focus-visible,
    textarea:focus-visible {
      outline: 2px solid #007ac2;
      outline-offset: 3px;
    }
    header {
      padding: 20px 24px;
      background: #fff;
      border-bottom: 1px solid #d4d4d4;
      display: flex;
      justify-content: space-between;
      gap: 16px;
      align-items: center;
    }
    h1 {
      font-size: 20px;
      margin: 0;
    }
    header p {
      margin: 2px 0 0;
      color: #6b6b6b;
      font-size: 12px;
    }
    .badge {
      background: #d6efff;
      color: #004874;
      padding: 4px 8px;
      font-size: 12px;
    }
    .layout {
      display: grid;
      grid-template-columns: 240px minmax(0, 1fr) 280px;
      min-height: 510px;
    }
    .sites,
    .inspector {
      background: #fff;
      padding: 20px;
      border-right: 1px solid #d4d4d4;
    }
    .inspector {
      border-right: 0;
      border-left: 1px solid #d4d4d4;
    }
    h2 {
      font-size: 16px;
      margin: 0 0 16px;
    }
    label {
      display: block;
      font-weight: 600;
      margin: 12px 0 6px;
    }
    select,
    textarea {
      width: 100%;
      border: 1px solid #949494;
      background: #fff;
      padding: 8px;
      color: inherit;
    }
    textarea {
      resize: vertical;
      min-height: 96px;
    }
    .site {
      display: block;
      width: 100%;
      text-align: left;
      background: #fff;
      border: 1px solid #dedede;
      padding: 12px;
      margin-top: 8px;
    }
    .site[aria-pressed="true"] {
      border-left: 4px solid #007ac2;
      background: #d6efff;
    }
    .site small {
      display: block;
      color: #4a4a4a;
      margin-top: 3px;
    }
    .map {
      position: relative;
      overflow: hidden;
      min-height: 360px;
      background: #ebebe5;
    }
    .map svg {
      width: 100%;
      height: 100%;
      position: absolute;
      inset: 0;
    }
    .map-caption {
      position: absolute;
      bottom: 12px;
      left: 12px;
      padding: 4px 8px;
      background: #fff;
      font-size: 12px;
    }
    .pin {
      position: absolute;
      width: 36px;
      height: 36px;
      border-radius: 50%;
      border: 3px solid #fff;
      background: #007ac2;
      color: #fff;
      font-weight: bold;
      box-shadow: 0 2px 8px #0004;
    }
    .pin[aria-pressed="true"] {
      background: #004874;
      outline: 3px solid #007ac2;
      outline-offset: 3px;
    }
    .pin[hidden] {
      display: none;
    }
    dl {
      display: grid;
      grid-template-columns: 1fr 1fr;
      gap: 8px;
      font-size: 12px;
    }
    dt {
      color: #6b6b6b;
    }
    dd {
      margin: 0;
      text-align: right;
    }
    .primary {
      background: #007ac2;
      color: white;
      border: 0;
      width: 100%;
      padding: 10px;
      margin-top: 12px;
    }
    .primary:hover {
      background: #00619b;
    }
    .error {
      color: #a11b1b;
      font-size: 12px;
    }
    .saved {
      color: #237000;
      font-size: 12px;
    }
    footer {
      padding: 16px 24px;
      border-top: 1px solid #d4d4d4;
      color: #6b6b6b;
      font-size: 12px;
      background: #fff;
    }
    @media (max-width: 1000px) {
      .layout {
        grid-template-columns: 210px minmax(0, 1fr);
      }
      .inspector {
        grid-column: 1/-1;
        border-left: 0;
        border-top: 1px solid #d4d4d4;
      }
      .inspector form {
        max-width: 640px;
      }
    }
    @media (max-width: 550px) {
      header {
        align-items: flex-start;
        flex-direction: column;
      }
      .layout {
        display: flex;
        flex-direction: column;
      }
      .sites {
        border-right: 0;
      }
      .map {
        height: 300px;
        min-height: 300px;
      }
      .inspector {
        padding: 20px;
      }
      .site {
        display: inline-block;
        width: 100%;
      }
    }
  </style>
  <body>
    <header>
      <div>
        <h1>Field inspection workspace</h1>
        <p>Original Calcite-inspired layout study · fictional site data</p>
      </div>
      <span class="badge">Local notes only</span>
    </header>
    <main class="layout">
      <aside class="sites">
        <h2>Inspection sites</h2>
        <label for="filter">Show sites</label
        ><select id="filter">
          <option value="all">All sites</option>
          <option value="review">Needs review</option>
          <option value="checked">Checked</option>
        </select>
        <div id="site-list"></div>
        <p id="count" aria-live="polite"></p>
      </aside>
      <section class="map" aria-label="Illustrated site plan">
        <svg
          viewBox="0 0 700 510"
          preserveAspectRatio="xMidYMid slice"
          role="img"
          aria-label="Original schematic with a river, roads and three inspection sites; not a geographic map"
        >
          <rect width="700" height="510" fill="#e4e8db" />
          <path
            d="M480 -50Q230 110 440 260T360 570"
            fill="none"
            stroke="#b6dbe9"
            stroke-width="100"
          />
          <path
            d="M-20 150L720 280M160 -20L290 530M-20 400L720 80"
            stroke="#fff"
            stroke-width="22"
          />
          <path
            d="M-20 150L720 280M160 -20L290 530M-20 400L720 80"
            stroke="#c8c8bf"
            stroke-width="2"
          />
          <g fill="#c4cfb5">
            <rect x="50" y="50" width="100" height="70" />
            <rect x="510" y="340" width="130" height="80" />
            <rect x="80" y="260" width="70" height="60" />
          </g>
        </svg>
        <div id="pins"></div>
        <span class="map-caption">Schematic illustration · not to scale</span>
      </section>
      <aside class="inspector">
        <h2 id="site-title">North access</h2>
        <dl>
          <dt>Site ID</dt>
          <dd id="site-id"></dd>
          <dt>Review state</dt>
          <dd id="site-state"></dd>
        </dl>
        <form id="note-form" novalidate>
          <label for="note">Inspection note</label
          ><textarea
            id="note"
            aria-describedby="note-help error"
            maxlength="240"
          ></textarea>
          <p id="note-help">
            Add 10–240 characters. Notes stay in this page until reload.
          </p>
          <p id="error" class="error" hidden>
            Write at least 10 characters before saving.
          </p>
          <button class="primary" type="submit">Save local note</button>
          <p id="saved" class="saved" role="status"></p>
        </form>
      </aside>
    </main>
    <footer>
      Independent HTML/CSS interpretation by OpenDesign. No Calcite runtime,
      Esri fonts, ArcGIS map or service is loaded.
    </footer>
    <script>
      const sites = [
        { id: "A-01", name: "North access", state: "review", x: 29, y: 24 },
        { id: "B-02", name: "River crossing", state: "review", x: 62, y: 48 },
        { id: "C-03", name: "South garden", state: "checked", x: 34, y: 76 },
      ];
      let selected = "A-01";
      const notes = new Map(),
        list = document.querySelector("#site-list"),
        pins = document.querySelector("#pins"),
        filter = document.querySelector("#filter"),
        note = document.querySelector("#note"),
        error = document.querySelector("#error"),
        saved = document.querySelector("#saved");
      function render() {
        const visible = sites.filter(
          (s) => filter.value === "all" || s.state === filter.value,
        );
        if (!visible.some((s) => s.id === selected)) selected = visible[0]?.id;
        list.replaceChildren();
        pins.replaceChildren();
        for (const s of visible) {
          const b = document.createElement("button");
          b.type = "button";
          b.className = "site";
          b.setAttribute("aria-pressed", String(s.id === selected));
          b.textContent = s.name;
          const small = document.createElement("small");
          small.textContent =
            s.id + " · " + (s.state === "review" ? "Needs review" : "Checked");
          b.append(small);
          b.onclick = () => {
            selected = s.id;
            render();
          };
          list.append(b);
          const pin = document.createElement("button");
          pin.type = "button";
          pin.className = "pin";
          pin.style.left = s.x + "%";
          pin.style.top = s.y + "%";
          pin.textContent = s.id[0];
          pin.setAttribute("aria-label", "Select " + s.name);
          pin.setAttribute("aria-pressed", String(s.id === selected));
          pin.onclick = b.onclick;
          pins.append(pin);
        }
        const s = sites.find((s) => s.id === selected);
        document.querySelector("#count").textContent =
          visible.length + " sites shown";
        document.querySelector("#site-title").textContent = s.name;
        document.querySelector("#site-id").textContent = s.id;
        document.querySelector("#site-state").textContent =
          s.state === "review" ? "Needs review" : "Checked";
        note.value = notes.get(s.id) || "";
        error.hidden = true;
        note.removeAttribute("aria-invalid");
        saved.textContent = "";
      }
      filter.onchange = render;
      note.oninput = () => {
        error.hidden = true;
        note.removeAttribute("aria-invalid");
        saved.textContent = "";
      };
      document.querySelector("#note-form").onsubmit = (e) => {
        e.preventDefault();
        const value = note.value.trim();
        if (value.length < 10) {
          error.hidden = false;
          note.setAttribute("aria-invalid", "true");
          note.focus();
          return;
        }
        notes.set(selected, value);
        saved.textContent = "Note saved locally for " + selected + ".";
      };
      render();
    </script>
  </body>
</html>
```

コードリファレンス

- 元の模式図とアプリケーションの動作です。地図SDK、外部データ、Esriランタイムは含まれていません。

### Calcite Inputのネイティブ版

index.html に <div id="app"></div> を含む、Viteのバニラプロジェクトで src/main.js を置き換えてください。

```
import "@esri/calcite-components/components/calcite-input";
import "@esri/calcite-components/components/calcite-button";

document.querySelector("#app").innerHTML = `
  <calcite-input id="inspection-note" label-text="Inspection note"
    validation-message="Enter at least ten characters"></calcite-input>
  <calcite-button id="save-note">Validate note</calcite-button>
  <p id="result" role="status"></p>`;
const field = document.querySelector("#inspection-note");
const result = document.querySelector("#result");
field.addEventListener("calciteInputInput", () => {
  field.status = "idle";
  result.textContent = "";
});
document.querySelector("#save-note").addEventListener("click", async () => {
  if (field.value.trim().length < 10) {
    field.status = "invalid";
    await field.setFocus();
    return;
  }
  field.status = "valid";
  result.textContent = "The note passes the local rule. Nothing was sent.";
});
```

コードリファレンス

- 現在のライセンス要件を確認したうえで、@esri/calcite-components@5.1.2 をインストールしてください。この代替例はAPIを使って確認済みです。上記の独立したプレビューは、ブラウザーでテストしたサンプルです。

## Esri Calcite デザインシステム：エージェントのセットアップ

### 実装の出発点

現在のライセンス条件では、ネイティブコンポーネントパッケージの利用に、対象となるArcGISアカウントが必要です。コンポーネントのアセットをセルフホストする場合は、アセットパスの要件を確認してください。

```
# Independent specimen: save the complete HTML example as index.html.
# Native alternative for an appropriately licensed project:
npm create vite@latest calcite-note -- --template vanilla
cd calcite-note
npm install
npm install @esri/calcite-components@5.1.2
# Replace src/main.js with the native input example.
npm run dev
```

### あなたのプロジェクト向けプロンプト

```
Calciteのリファレンスを活用し、空間情報の調査に特化したワークスペースを構築します。リストとインスペクターで選択中のオブジェクトIDを一致させ、保存状態を明確に示し、ローカルメモとサービスへの永続化を区別してください。出発点としてスタンドアロン版を使うか、ライセンスが必要なネイティブコンポーネントの利用を選択してください。元の模式図をArcGISの地図と説明しないでください。
```

## Esri Calcite デザインシステム：ソースと適用範囲

OpenDesignのアプリケーションガイドです。図示された例は独立して実装され、架空のデータを使用しています。現在のCalciteの利用にはEsriのライセンスが適用され、対象となるArcGISアカウントが必要です。ネイティブ統合の例は、適切なライセンスを取得したプロジェクト向けの代替手段であり、このプレビューのランタイムではありません。

- Calcite Input API フィールドのプロパティ、イベント、フォーカスメソッド。

- Calciteの導入 コンポーネントの登録とアセットの設定。

- 現在のライセンス ArcGISアカウントと利用要件。

- 公開されているデザイントークン バージョンを固定した書体、スペース、角丸のリファレンス。

## Esri Calcite デザインシステム：関連リソース

### GitLab Pajamas

技術ワークフロー向けの Pajamas ガイド。実際のセマンティックトークン、可変のタイポグラフィと間隔、段階的なパイプラインインスペクター、読みやすいエラー出力、そしてローカル限定のリトライシミュレーションを紹介します。

### HPE Grommet

Grommet のレイアウトプリミティブ、制御可能なフォームフィールド、数値メーターを使って、容量予約の画面を作成します。テーマのスケールを意図的に使い、基本の Grommet テーマと別途インストールする HPE テーマを区別してください。

### Infor デザインシステム

実際のIDS入力状態、テーマのエイリアス、正確なアセット識別子を使って、企業向け保守フォームを構成します。公開中のテーマトークン、バージョンを固定したWeb Componentsパッケージ、入力検証とリセットに対応したローカル下書きのワークフローを確認できます。


- [実装リファレンス](https://developers.arcgis.com/calcite-design-system/)
- [ソース](https://cdn.jsdelivr.net/npm/@esri/calcite-design-tokens@4.1.0/dist/css/light.css)
- [ソース](https://cdn.jsdelivr.net/npm/@esri/calcite-design-tokens@4.1.0/dist/css/global.css)
- [ソース](https://developers.arcgis.com/calcite-design-system/components/input/)
- [コードリファレンス](https://cdn.jsdelivr.net/npm/@esri/calcite-design-tokens@4.1.0/dist/css/light.css)
- [コードリファレンス](https://developers.arcgis.com/calcite-design-system/components/input/)
- [Calcite Input API フィールドのプロパティ、イベント、フォーカスメソッド。](https://developers.arcgis.com/calcite-design-system/components/input/)
- [Calciteの導入 コンポーネントの登録とアセットの設定。](https://developers.arcgis.com/calcite-design-system/get-started/)
- [現在のライセンス ArcGISアカウントと利用要件。](https://developers.arcgis.com/calcite-design-system/resources/licensing/)
- [公開されているデザイントークン バージョンを固定した書体、スペース、角丸のリファレンス。](https://cdn.jsdelivr.net/npm/@esri/calcite-design-tokens@4.1.0/dist/css/global.css)
