# Дизайн-система 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

### Не скрывайте контекст объекта

> В пространственной задаче обычно есть как минимум два контекста: исследуемая область и выбранный объект. В примере рядом с оригинальной схемой и панелью сведений размещён небольшой список объектов. Выбор строки списка или метки устанавливает один и тот же стабильный идентификатор объекта, поэтому имя, статус и заметка не могут случайно относиться к разным объектам.

### Отделяйте иллюстрацию от настоящей карты

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

### Используйте актуальные имена токенов

В справочнике используется актуальная шкала --calcite-space-*, где для самых маленьких шагов заданы значения в пикселях, а для более крупных — в rem. При создании нативной темы последовательно используйте эти именованные роли. В этом примере для компоновки приложения заданы явные значения CSS, поэтому интерпретация работает без импорта закрытых пакетов.

### Перестройте панель сведений, прежде чем сжимать поле

При исходной контрольной точке приложения панель сведений перемещается под список и иллюстрацию. На узком экране телефона все три области выстраиваются вертикально. Текстовое поле остаётся во всю ширину, вместе с подписью, подсказкой и кнопкой сохранения. Эти контрольные точки заданы для компоновки приложения и не являются заявленными значениями токенов Calcite.

## Поведение выбора и фильтрации в дизайн-системе Esri Calcite

### Используйте один идентификатор выбранного объекта

Выбор в списке и на схеме связан через A-01, B-02 и C-03, а не через текущую позицию в массиве. Фильтр «Проверено» выбирает подходящий объект из результатов, и панель сведений отображает его. Состояние нажатия показано как на кнопке строки списка, так и на соответствующей метке.

### Храните сохранённые заметки отдельно от черновиков

Сохранённые заметки хранятся в Map с ключом в виде идентификатора объекта. При повторном выборе объекта заметка восстанавливается; если перейти к другому объекту, не сохранив текст, несохранённый текст заменяется. В подсказке явно указано, что данные хранятся только локально. В рабочем редакторе следует предупреждать о несохранённых изменениях, если потеря черновика может иметь серьёзные последствия.

## Проверка ввода и восстановление в дизайн-системе Esri Calcite

### При использовании Calcite выбирайте настоящий нативный компонент ввода API

В нативном примере используются labelText, value, status и validationMessage. Событие calciteInputInput позволяет убрать устаревшую ошибку при вводе, а setFocus() возвращает фокус на компонент после неудачной проверки по правилу приложения. Это общедоступные имена API, в отличие от обращения к внутреннему полю ввода через shadow root.

### Не путайте локальное подтверждение с сохранением на сервере

В независимом предпросмотре требуется не менее десяти символов после удаления пробелов по краям; максимальная длина поля — 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.

- Справочник design tokens: 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

Замените src/main.js в обычном проекте Vite, где в index.html содержится <div id="app"></div>.

```
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 и использованию.

- Опубликованные design tokens Зафиксированные значения типографики, отступов и скругления.

## Связанные материалы по дизайн-системе 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/)
- [Опубликованные design tokens Зафиксированные значения типографики, отступов и скругления.](https://cdn.jsdelivr.net/npm/@esri/calcite-design-tokens@4.1.0/dist/css/global.css)
