# Дизайн-система Kiwi Orbit

## Предварительный просмотр интерфейса дизайн-системы Kiwi Orbit

Измените число путешественников и выберите дополнительные опции. Просмотрите разбивку стоимости и измените выбор, чтобы сбросить устаревшее подтверждение.

## Справочник по дизайн-системе Kiwi Orbit

Нативные компоненты Orbit React версии 27.7.0 с defaultTheme и скомпилированным Tailwind CSS; справочник токенов версии 11.0.0.

### Цвета действий продукта

| Название / правило | Значение / конфигурация | Применение |
| --- | --- | --- |
| buttonPrimaryBackground | #008F7B | Справочник состояний основного действия. Различайте роли состояний при наведении, нажатии и фокусе. |
| buttonPrimaryBackgroundHover | #007565 | Справочник состояний основного действия. Различайте роли состояний при наведении, нажатии и фокусе. |
| buttonPrimaryBackgroundActive | #006153 | Справочник состояний основного действия. Различайте роли состояний при наведении, нажатии и фокусе. |
| buttonPrimaryForeground | #FFFFFF | Справочник состояний основного действия. Различайте роли состояний при наведении, нажатии и фокусе. |
| buttonPrimaryForegroundHover | #FFFFFF | Справочник состояний основного действия. Различайте роли состояний при наведении, нажатии и фокусе. |
| buttonPrimaryForegroundActive | #FFFFFF | Справочник состояний основного действия. Различайте роли состояний при наведении, нажатии и фокусе. |
| buttonPrimaryBorderColorFocus | rgba(0, 143, 123, 0.5) | Справочник состояний основного действия. Различайте роли состояний при наведении, нажатии и фокусе. |
### Интервалы компонентов

| Название / правило | Значение / конфигурация | Применение |
| --- | --- | --- |
| space50 | 2px | Фактические значения шагов в пикселях из опубликованного пакета токенов. |
| space100 | 4px | Фактические значения шагов в пикселях из опубликованного пакета токенов. |
| space150 | 6px | Фактические значения шагов в пикселях из опубликованного пакета токенов. |
| space200 | 8px | Фактические значения шагов в пикселях из опубликованного пакета токенов. |
| space300 | 12px | Фактические значения шагов в пикселях из опубликованного пакета токенов. |
| space400 | 16px | Фактические значения шагов в пикселях из опубликованного пакета токенов. |
| space500 | 20px | Фактические значения шагов в пикселях из опубликованного пакета токенов. |
| space600 | 24px | Фактические значения шагов в пикселях из опубликованного пакета токенов. |
| space800 | 32px | Фактические значения шагов в пикселях из опубликованного пакета токенов. |
| space1000 | 40px | Фактические значения шагов в пикселях из опубликованного пакета токенов. |
| space1200 | 48px | Фактические значения шагов в пикселях из опубликованного пакета токенов. |
### Радиусы скругления

| Название / правило | Значение / конфигурация | Применение |
| --- | --- | --- |
| borderRadius50 | 2px | Разные радиусы подходят для элементов управления и более крупных поверхностей интерфейса путешествия. |
| borderRadius100 | 4px | Разные радиусы подходят для элементов управления и более крупных поверхностей интерфейса путешествия. |
| borderRadius150 | 6px | Разные радиусы подходят для элементов управления и более крупных поверхностей интерфейса путешествия. |
| borderRadius200 | 8px | Разные радиусы подходят для элементов управления и более крупных поверхностей интерфейса путешествия. |
| borderRadius300 | 12px | Разные радиусы подходят для элементов управления и более крупных поверхностей интерфейса путешествия. |
| borderRadius400 | 16px | Разные радиусы подходят для элементов управления и более крупных поверхностей интерфейса путешествия. |
| borderRadiusNone | 0 | Разные радиусы подходят для элементов управления и более крупных поверхностей интерфейса путешествия. |
| borderRadiusFull | 9999px | Разные радиусы подходят для элементов управления и более крупных поверхностей интерфейса путешествия. |
### Основной текст

| Название / правило | Значение / конфигурация | Применение |
| --- | --- | --- |
| fontSizeTextSmall | 13px | Опубликованные роли основного текста; заголовки страниц задаются отдельно в приложении. |
| fontSizeTextNormal | 15px | Опубликованные роли основного текста; заголовки страниц задаются отдельно в приложении. |
| fontSizeTextLarge | 16px | Опубликованные роли основного текста; заголовки страниц задаются отдельно в приложении. |
| fontSizeTextExtraLarge | 18px | Опубликованные роли основного текста; заголовки страниц задаются отдельно в приложении. |
### Поверхности продукта и нейтральные поверхности

| Название / правило | Значение / конфигурация | Применение |
| --- | --- | --- |
| paletteCloudLight | #F5F7F9 | Используйте спокойные поверхности и хорошо читаемый текст в сочетании с цветом действий продукта. |
| paletteCloudNormal | #E8EDF1 | Используйте спокойные поверхности и хорошо читаемый текст в сочетании с цветом действий продукта. |
| paletteInkDark | #252A31 | Используйте спокойные поверхности и хорошо читаемый текст в сочетании с цветом действий продукта. |
| paletteInkLight | #657890 | Используйте спокойные поверхности и хорошо читаемый текст в сочетании с цветом действий продукта. |
| paletteInkNormal | #4F5E71 | Используйте спокойные поверхности и хорошо читаемый текст в сочетании с цветом действий продукта. |
| paletteProductLight | #E1F4F3 | Используйте спокойные поверхности и хорошо читаемый текст в сочетании с цветом действий продукта. |
| paletteProductNormal | #008F7B | Используйте спокойные поверхности и хорошо читаемый текст в сочетании с цветом действий продукта. |
| paletteProductDark | #007061 | Используйте спокойные поверхности и хорошо читаемый текст в сочетании с цветом действий продукта. |
## Полное руководство по дизайн-системе Kiwi Orbit

Практическое руководство по выбору, применению и оценке этой системы для реального интерфейса.

Подробные рекомендации, отправная точка для реализации и ссылки на источники.

## Макет выбора путешествия в дизайн-системе Kiwi Orbit

### Сначала покажите маршрут, затем дополнительные опции

> В сводке маршрута указаны коды двух аэропортов, названия городов и вымышленная продолжительность поездки. Она показывается до выбора багажа, чтобы контекст покупки оставался виден при сравнении дополнительных опций. Пунктирная линия — оригинальная иллюстрация CSS, а не схема маршрута перевозчика и не обещание реальной услуги.

### Отделите выбор от итоговой стоимости

С одной стороны расположены параметры путешественников и багажа, с другой — разбивка стоимости. Одно и то же состояние определяет и выбранные элементы управления, и суммы. На телефоне сводка следует за вариантами выбора в порядке документа, поэтому понятно, какие параметры влияют на итоговую стоимость.

## Цвета продукта и обратная связь в дизайн-системе Kiwi Orbit

### Используйте цветовую палитру продукта для основного действия

В пакете токенов для действий продукта предусмотрен зелёный цвет с отдельными оттенками для состояний при наведении и нажатии. В справочнике приведены точные значения для роли кнопки — вместо предположительного фирменного зелёного. Нейтральные облачные поверхности обрамляют дополнительные варианты выбора и не отвлекают внимание от действия проверки.

### Связывайте обратную связь с результатом

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

## Типографика и иерархия цен в дизайн-системе Kiwi Orbit

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

В Orbit есть стандартные стили основного текста размером 13px и 15px, а также более крупные варианты. В примере используются нативные компоненты Text и Heading, а коды маршрута и итоговая стоимость выделены отдельно. Здесь браузер использует документированный запасной набор шрифтов; фирменный шрифт Kiwi.com не загружается незаметно для пользователя.

### Указывайте единицы измерения рядом с ценами

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

## Шкалы радиусов и интервалов дизайн-системы Kiwi Orbit

### Разграничивайте элементы управления и крупные поверхности

В текущую шкалу радиусов входят значения 2, 4, 6, 8, 12 и 16px, а также варианты без скругления и с полным скруглением. В созданных для примера панелях маршрута и сводки используются углы радиусом 12px, а для нативных элементов управления действуют собственные правила темы. Если применить наибольший радиус ко всем вложенным элементам, иерархия формы станет менее выраженной.

### Сохраняйте целостность строки варианта при переносе

В строке багажа сгруппированы нативный флажок, пояснение о норме багажа и цена. Описанию отводится гибкая ширина, а цена остаётся хорошо читаемой. Страница переключается на одну колонку до того, как любая из двух основных областей станет слишком узкой для сравнения вариантов.

## Флажок и список выбора в дизайн-системе Kiwi Orbit

### Используйте подписи компонентов и информационные поля

Флажок получает видимую подпись и поясняющую информацию через публичные свойства. Для компонента Select задаются подпись и явные варианты числа путешественников — от одного до четырёх. Эти нативные компоненты сохраняют предусмотренное поведение взаимодействия и подписей, не подменяя элемент управления багажом кликабельным div.

### Моделируйте каждую дополнительную опцию независимо

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

## Расчёт и проверка выбора в дизайн-системе Kiwi Orbit

### Рассчитывайте итог по единой формуле

В примере число путешественников умножается на базовую стоимость и выбранные дополнительные услуги на человека. Итоговая сумма не хранится отдельно и не может разойтись с отображаемыми вариантами. Все цены и нормы багажа вымышлены и не являются актуальными предложениями Kiwi.com.

### Сохраняйте снимок проверенного выбора

При проверке вместе сохраняются число путешественников, параметры багажа и итоговая стоимость. При изменении любого элемента управления этот снимок сбрасывается. Так пример показывает согласованность состояния, не выдавая локальное нажатие за бронирование, оплату, проверку доступности в реальном времени или окончательное ценовое предложение.

## Доступная обратная связь при выборе в дизайн-системе Kiwi Orbit

### Проверяйте работу подписей и пересчёта одновременно

С помощью нативных элементов управления пользователь может выбрать число путешественников и отметить любой из вариантов багажа с клавиатуры или указателем. Результат проверки отображается в области статуса. Проверка необязательного багажа не выдумывается: в рамках этого вымышленного тарифа допустимо не выбирать ни одну дополнительную опцию.

1. Выберите двух путешественников и добавьте ручную кладь.

2. Добавьте зарегистрированный багаж и проверьте все три суммы в разбивке.

3. Локально проверьте выбор, измените один из параметров и убедитесь, что прежнее подтверждение исчезло.

### Не допускайте скрытых последствий

Вымышленный характер примера поясняется над формой и рядом с итоговой стоимостью. Действие называется «Проверить выбор локально», а не «Купить» или «Забронировать». Все изменения остаются на странице; личные данные пассажиров, не нужные для демонстрации, не запрашиваются.

## Провайдер и скомпилированные стили в дизайн-системе Kiwi Orbit

### Используйте соответствующую стабильную версию

В этом примере зафиксированы версии компонентов React 27.7.0 и ссылок на токены 11.0.0. Подключаются OrbitProvider, defaultTheme пакета и скомпилированный файл lib/tailwind.css. Без этой таблицы стилей оформление компонентов, использующих утилитарные классы, будет неполным, даже если дерево React отобразится.

- OrbitProvider и defaultTheme пакета.

- Скомпилированный файл lib/tailwind.css из components 27.7.0.

- Для среды сборки пакета требуется Node.js версии 22 или новее.

### Явно указывайте требования к развёртыванию

В пакете указано требование Node.js версии 22 или новее. Приведённую точку входа Vite можно воспроизвести в этой среде с зафиксированной версией пакета компонентов. Исходный код CSS отвечает только за композицию маршрута; для нативных элементов управления сохраняются опубликованные стили компонентов и поведение провайдера.

## Примеры компонентов дизайн-системы Kiwi Orbit

### main.jsx — полный рабочий образец

Выберите багаж и посмотрите пример итоговой стоимости. Ниже приведён полный код точки входа React, включая всё состояние и проверки.

```
import React, { useState } from "react";
import { createRoot } from "react-dom/client";
import {
  OrbitProvider,
  Button,
  Checkbox,
  Select,
  Alert,
  Heading,
  Text,
} from "@kiwicom/orbit-components";
import defaultTheme from "@kiwicom/orbit-components/lib/defaultTheme";
import "@kiwicom/orbit-components/lib/tailwind.css";
import "./orbit.css";
function App() {
  const [travellers, setTravellers] = useState("1"),
    [cabin, setCabin] = useState(false),
    [checked, setChecked] = useState(false),
    [saved, setSaved] = useState(null);
  const count = Number(travellers),
    extras = (cabin ? 18 : 0) + (checked ? 32 : 0),
    total = count * (96 + extras);
  function update(fn) {
    fn();
    setSaved(null);
  }
  return (
    <OrbitProvider theme={defaultTheme}>
      <main className="trip">
        <header>
          <Text size="small">ORIGINAL TRAVEL SPECIMEN</Text>
          <Heading as="h1" type="title1">Choose what travels with you</Heading>
          <Text>
            Fictional one-way fare. Prices illustrate the interface, not a
            bookable flight.
          </Text>
        </header>
        <div className="trip-grid">
          <section>
            <div className="route">
              <div>
                <strong>PRG</strong>
                <span>Prague</span>
              </div>
              <div className="route-line">
                <span>1h 45m · direct</span>
                <i></i>
              </div>
              <div>
                <strong>AMS</strong>
                <span>Amsterdam</span>
              </div>
            </div>
            <div className="options">
              <Heading as="h2" type="title3">Travellers and baggage</Heading>
              <Select
                label="Travellers"
                ariaLabel="Travellers"
                value={travellers}
                options={[1, 2, 3, 4].map((n) => ({
                  value: String(n),
                  label: n + " adult" + (n === 1 ? "" : "s"),
                }))}
                onChange={(e) => update(() => setTravellers(e.target.value))}
              />
              <div className="bag-option">
                <div>
                  <Heading as="h3" type="title4">Personal item</Heading>
                  <Text size="small">
                    Fits under the seat · included in this example fare
                  </Text>
                </div>
                <strong>Included</strong>
              </div>
              <div className="bag-option">
                <Checkbox
                  label="Add cabin baggage"
                  info="One 10 kg bag per traveller · fictional allowance"
                  checked={cabin}
                  onChange={(e) => update(() => setCabin(e.target.checked))}
                />
                <strong>
                  €18<span>/ traveller</span>
                </strong>
              </div>
              <div className="bag-option">
                <Checkbox
                  label="Add checked baggage"
                  info="One 20 kg bag per traveller · fictional allowance"
                  checked={checked}
                  onChange={(e) => update(() => setChecked(e.target.checked))}
                />
                <strong>
                  €32<span>/ traveller</span>
                </strong>
              </div>
            </div>
          </section>
          <aside>
            <Heading as="h2" type="title3">Your example selection</Heading>
            <dl>
              <dt>Base fare × {count}</dt>
              <dd>€{96 * count}</dd>
              {cabin && (
                <>
                  <dt>Cabin baggage × {count}</dt>
                  <dd>€{18 * count}</dd>
                </>
              )}
              {checked && (
                <>
                  <dt>Checked baggage × {count}</dt>
                  <dd>€{32 * count}</dd>
                </>
              )}
            </dl>
            <div className="trip-total">
              <span>Total</span>
              <strong>€{total}</strong>
            </div>
            <Text size="small">
              All amounts are illustrative. No payment or reservation will be
              created.
            </Text>
            <Button
              fullWidth
              onClick={() => setSaved({ count, cabin, checked, total })}
            >
              Review local selection
            </Button>
            {saved && (
              <div role="status" className="trip-confirm">
                <Alert type="success" title="Selection reviewed locally">
                  {saved.count} traveller{saved.count === 1 ? "" : "s"} · €
                  {saved.total}. No booking created.
                </Alert>
              </div>
            )}
          </aside>
        </div>
        <footer>
          Native Orbit 27.7.0 components and compiled package styles. Original
          layout and fictional pricing logic by OpenDesign.
        </footer>
      </main>
    </OrbitProvider>
  );
}
createRoot(document.getElementById("root")).render(<App />);
```

Справочник по коду

- Создайте проект React на Vite, сохраните <div id="root"></div> и загрузите этот код как src/main.jsx.

### orbit.css — оригинальная адаптивная композиция

Слой компоновки приложения поверх нативных компонентов.

```
* {
  box-sizing: border-box;
}
body {
  margin: 0;
  background: #f5f7f9;
  color: #252a31;
  font:
    16px/1.5 Arial,
    sans-serif;
}
.trip {
  padding: 32px;
}
.trip header {
  max-width: 760px;
  margin-bottom: 28px;
}
.trip header h1 {
  margin: 8px 0 12px;
}
.trip-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.5fr) minmax(280px, 1fr);
  gap: 24px;
}
.route,
.options,
.trip aside {
  background: #fff;
  border-radius: 12px;
  border: 1px solid #e8edf1;
  padding: 24px;
}
.route {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  margin-bottom: 20px;
}
.route strong {
  font-size: 32px;
  display: block;
}
.route span {
  font-size: 14px;
  display: block;
  color: #4f5e71;
}
.route-line {
  flex: 1;
  text-align: center;
}
.route-line i {
  display: block;
  border-top: 2px dashed #bac7d5;
  margin-top: 12px;
}
.options > h3 {
  margin-bottom: 20px;
}
.options > div:first-of-type {
  margin-bottom: 12px;
}
.bag-option {
  display: flex;
  gap: 20px;
  align-items: center;
  justify-content: space-between;
  padding: 24px 0;
  border-top: 1px solid #e8edf1;
}
.bag-option:last-child {
  padding-bottom: 0;
}
.bag-option > strong {
  white-space: nowrap;
  font-size: 18px;
}
.bag-option > strong span {
  display: block;
  font-size: 12px;
  font-weight: 400;
  color: #657890;
}
.trip aside {
  align-self: start;
}
.trip dl {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 16px;
  margin: 24px 0;
}
.trip dd {
  margin: 0;
  text-align: right;
  font-weight: 600;
}
.trip-total {
  display: flex;
  justify-content: space-between;
  align-items: center;
  border-top: 1px solid #bac7d5;
  padding: 20px 0;
}
.trip-total strong {
  font-size: 32px;
}
.trip aside > button {
  margin-top: 24px;
}
.trip-confirm {
  margin-top: 20px;
}
.trip footer {
  font-size: 12px;
  color: #657890;
  margin-top: 24px;
}
@media (max-width: 900px) {
  .trip-grid {
    grid-template-columns: 1fr;
  }
}
@media (max-width: 550px) {
  .trip {
    padding: 16px;
  }
  .route,
  .options,
  .trip aside {
    padding: 20px;
  }
  .route {
    gap: 12px;
  }
  .route strong {
    font-size: 28px;
  }
  .route-line span {
    font-size: 12px;
  }
  .bag-option {
    align-items: flex-start;
    gap: 12px;
  }
}
```

Справочник по коду

- Сохраните рядом с main.jsx. Эти собственные правила композиции отделены от справочника токенов библиотеки.

## Настройка агента дизайн-системы Kiwi Orbit

### Отправная точка для реализации

Пример с закреплёнными версиями нативных компонентов собран и проверен в браузере локально. В образце используется только локальное состояние приложения.

```
npm create vite@latest orbit-trip -- --template react
cd orbit-trip
npm install
npm install react@18.3.1 react-dom@18.3.1 @kiwicom/orbit-components@27.7.0
# Use Node.js >=22. Replace src/main.jsx and add src/orbit.css.
npm run dev
```

### Запрос для вашего проекта

```
Создайте форму выбора дополнительных услуг для путешествия с помощью нативных компонентов Orbit и скомпилированных стилей. Поддерживайте согласованность сведений о маршруте, цен на человека, выбранных опций и итоговой стоимости. Ясно укажите, что цены вымышлены, а проверка выполняется локально; сбрасывайте устаревшее подтверждение при редактировании и не создавайте впечатление, что доступны бронирование или оплата.
```

## Источники и область применения дизайн-системы Kiwi Orbit

Руководство по приложению OpenDesign. Маршрут, продолжительность поездки, цены и нормы багажа вымышлены. Нативные элементы управления Orbit работают локально; поиск рейсов, бронирование и оплата не выполняются.

- Начало работы с Orbit Текущие версии компонентов и токенов, а также материалы по реализации.

- Исходный код компонентов Orbit Нативные свойства, стили и требования к пакету.

- Экспорт токенов закреплённой версии Точные значения цветов продукта, типографики, интервалов и радиусов.

## Связанные материалы по дизайн-системе Kiwi Orbit

### Maersk дизайн-система

Изучите язык операционного интерфейса Maersk на примере настоящих ролей светлой темы, шкал заголовков и основного текста, вложенных скруглений и обработки идентификаторов. Пример поиска отправления показывает точное совпадение по номеру и доступную историю событий, не создавая впечатления доступа к данным текущей логистики.

### Microsoft Fluent 2

Создайте рабочую область Fluent UI React v9 с настоящими семантическими токенами, веб-шкалами типографики и отступов, управляемыми вкладками и диалогом доступа с валидацией. Сравните значения тем, изучите анатомию компонентов и проверьте локальное взаимодействие перед использованием полного примера React.

### Monday Vibe

Создайте рабочую доску доставки с токенами Vibe 4 и элементами управления React. Разберитесь, чем семантические цвета действий отличаются от меток на доске, изучите именованные шаги отступов и сокращённые записи шрифтов, а также настройте CSS, необходимую новому приложению.


- [Справочник по реализации](https://orbit.kiwi/getting-started/)
- [Источник](https://cdn.jsdelivr.net/npm/@kiwicom/orbit-design-tokens@11.0.0/dist/index.js)
- [Справочник по коду](https://orbit.kiwi/getting-started/)
- [Начало работы с Orbit Текущие версии компонентов и токенов, а также материалы по реализации.](https://orbit.kiwi/getting-started/)
- [Исходный код компонентов Orbit Нативные свойства, стили и требования к пакету.](https://github.com/kiwicom/orbit)
- [Экспорт токенов закреплённой версии Точные значения цветов продукта, типографики, интервалов и радиусов.](https://cdn.jsdelivr.net/npm/@kiwicom/orbit-design-tokens@11.0.0/dist/index.js)
