codex/design-system-foundation #33
79
apps/docs/docs/adr/ADR-016-design-system.md
Normal file
79
apps/docs/docs/adr/ADR-016-design-system.md
Normal file
@ -0,0 +1,79 @@
|
||||
# ADR-016: Дизайн-система — гибридный подход (theme + wrapper-компоненты)
|
||||
|
||||
**Статус:** Accepted
|
||||
|
||||
**Дата:** 2026-06-21
|
||||
|
||||
## Контекст
|
||||
|
||||
Фронтенд MoexVibe нуждался в единообразном UI. Ранее каждая страница использовала MUI напрямую, что приводило к:
|
||||
|
||||
- неконсистентным вариантам компонентов (разные цвета, размеры, отступы);
|
||||
- отсутствию единой системы токенов;
|
||||
- размножению стилей в CSS custom properties.
|
||||
|
||||
Рост количества страниц и компонентов потребовал системного подхода.
|
||||
|
||||
## Рассмотренные варианты
|
||||
|
||||
### 1. Theme-only
|
||||
|
||||
Оставить прямое использование MUI, но настроить единую тему (palette, typography, shape).
|
||||
|
||||
**Плюсы:** минимальные изменения, полная гибкость MUI.
|
||||
**Минусы:** нет гарантии консистентности — разработчики могут использовать любые варианты MUI-компонентов.
|
||||
|
||||
### 2. Hybrid (выбран)
|
||||
|
||||
MUI theme обеспечивает фундамент (палитра, типографика, скругления); wrapper-компоненты поверх MUI гарантируют консистентность и ограничивают варианты.
|
||||
|
||||
**Плюсы:**
|
||||
|
||||
- единый source of truth в теме MUI;
|
||||
- компоненты с ограниченным API (только нужные варианты);
|
||||
- возможность миграции (можно заменить реализацию под капотом);
|
||||
- Box/Stack/Grid остаются как allowlist для лэйаута.
|
||||
|
||||
**Минусы:**
|
||||
|
||||
- необходимо написать 20+ wrapper-компонентов;
|
||||
- двойная прослойка для некоторых сценариев.
|
||||
|
||||
### 3. Full wrapper
|
||||
|
||||
Все UI через собственные компоненты, без прямого использования MUI.
|
||||
|
||||
**Плюсы:** полный контроль, независимость от MUI.
|
||||
**Минусы:** огромный объём работы, дублирование функциональности MUI.
|
||||
|
||||
## Решение
|
||||
|
||||
Выбран гибридный подход (option 2):
|
||||
|
||||
- **Токены:** трёхуровневая система (primitives → semantic → component) с DTCG-резолвером.
|
||||
- **Тема:** MUI 6.5 theme, построенная на семантических токенах. CSS-переменные `--mv-*` для доступа из CSS.
|
||||
- **Компоненты:** 20+ wrapper-компонентов, каждый с ограниченным пропс-интерфейсом.
|
||||
- **ESLint:** `no-restricted-imports` запрещает прямой импорт MUI-компонентов (кроме Box, Stack, Grid).
|
||||
- **Storybook:** инженерный стенд с a11y-проверками.
|
||||
- **Документация:** Docusaurus для опубликованных гайдлайнов (этот сайт).
|
||||
|
||||
## Последствия
|
||||
|
||||
### Положительные
|
||||
|
||||
- Консистентный UI во всех страницах.
|
||||
- Единая система токенов, доступная из CSS (через `--mv-*`).
|
||||
- Изолированная библиотека компонентов, которую можно тестировать и развивать независимо.
|
||||
- Возможность замены реализации под капотом без изменения потребителей.
|
||||
|
||||
### Отрицательные
|
||||
|
||||
- 20+ компонентов нужно поддерживать.
|
||||
- Оверхед на поддержку пропс-интерфейсов (каждый компонент ограничивает MUI API).
|
||||
- Новые разработчики должны знать два слоя (MUI theme + wrapper-компоненты).
|
||||
|
||||
### Future
|
||||
|
||||
- DTCG-экспорт токенов для дизайн-инструментов.
|
||||
- Android-адаптеры для нативных приложений.
|
||||
- Расширение компонентной базы.
|
||||
@ -16,5 +16,7 @@
|
||||
| [ADR-012](ADR-012-frontend-broker-account-aggregation) | Accepted | Агрегация сводки брокерских счетов на frontend |
|
||||
| [ADR-013](ADR-013-frontend-fsd-broker-pilot) | Accepted | Пилотная FSD-миграция broker-домена |
|
||||
| [ADR-014](ADR-014-frontend-fsd-market-pages) | Accepted | FSD-миграция market pages и market widgets |
|
||||
| [ADR-015](ADR-015-frontend-libraries-modernization) | — | Модернизация инфраструктуры фронтенда |
|
||||
| [ADR-016](ADR-016-design-system) | Accepted | Дизайн-система — гибридный подход |
|
||||
|
||||
Все опубликованные ADR находятся в `apps/docs/docs/adr/` и отображаются в этом Docusaurus-разделе.
|
||||
|
||||
49
apps/docs/docs/design-system/accessibility.md
Normal file
49
apps/docs/docs/design-system/accessibility.md
Normal file
@ -0,0 +1,49 @@
|
||||
# Доступность (Accessibility)
|
||||
|
||||
## Целевой уровень
|
||||
|
||||
WCAG 2.2 AA.
|
||||
|
||||
## Требования к компонентам
|
||||
|
||||
### IconButton
|
||||
|
||||
**Требует `label`** — свойство `aria-label` обязательно для всех иконок без текста.
|
||||
|
||||
```tsx
|
||||
<IconButton label="Настройки">
|
||||
<SettingsIcon />
|
||||
</IconButton>
|
||||
```
|
||||
|
||||
### Dialog
|
||||
|
||||
- **Требует `title`** — заголовок, используемый как `aria-labelledby`
|
||||
- Содержит focus trap (фокус не покидает диалог)
|
||||
- Закрывается по Escape
|
||||
|
||||
### Progress
|
||||
|
||||
- `indeterminate`-режим выставляет `aria-busy` на контейнере
|
||||
|
||||
### PriceChange
|
||||
|
||||
- Использует **текстовый индикатор направления** (`+`, `−`, `—`), а не только цвет
|
||||
- Скринридеры получают знак перед числом
|
||||
|
||||
### DataTable
|
||||
|
||||
- **Требует `caption`** — описание таблицы для скринридеров
|
||||
- Семантические заголовки через `<th scope="col">`
|
||||
|
||||
### Skeleton
|
||||
|
||||
- `aria-hidden` по умолчанию — скелетоны не должны озвучиваться
|
||||
|
||||
### Alert
|
||||
|
||||
- Использует `role="alert"` для немедленного объявления скринридером
|
||||
|
||||
### LoadingState
|
||||
|
||||
- `aria-live="polite"` — скринридер объявит об изменении после завершения текущей речи
|
||||
259
apps/docs/docs/design-system/components.md
Normal file
259
apps/docs/docs/design-system/components.md
Normal file
@ -0,0 +1,259 @@
|
||||
# Компоненты
|
||||
|
||||
## Матрица «задача → компонент»
|
||||
|
||||
| Задача | Рекомендуемый компонент | Не использовать |
|
||||
|--------|------------------------|-----------------|
|
||||
| Отображение текста | Text, Heading | MUI Typography напрямую |
|
||||
| Ссылка | Link | MUI Link напрямую |
|
||||
| Действие | Button, IconButton | MUI Button напрямую |
|
||||
| Ввод текста | TextField | MUI TextField напрямую |
|
||||
| Выбор из списка | Select | MUI Select напрямую |
|
||||
| Выбор опции | Checkbox | MUI Checkbox напрямую |
|
||||
| Контейнер/фон | Surface | MUI Paper напрямую |
|
||||
| Карточка | Card | MUI Card напрямую |
|
||||
| Ярлык/тег | Chip | MUI Chip напрямую |
|
||||
| Бейдж | Badge | MUI Badge напрямую |
|
||||
| Уведомление | Alert | MUI Alert напрямую |
|
||||
| Модальное окно | Dialog | MUI Dialog напрямую |
|
||||
| Загрузка скелета | Skeleton | MUI Skeleton напрямую |
|
||||
| Индикатор прогресса | Progress | MUI CircularProgress / LinearProgress напрямую |
|
||||
| Финансовое значение | Money, Metric, PriceChange | сырое число |
|
||||
| Таблица | DataTable | MUI Table напрямую |
|
||||
| Поле формы | FormField | ручная связка label + helperText |
|
||||
| Панель фильтров | FilterBar | ручная вёрстка фильтров |
|
||||
| Пустое состояние | EmptyState | ручная вёрстка |
|
||||
| Ошибка | ErrorState | ручная вёрстка |
|
||||
| Загрузка | LoadingState | ручная вёрстка |
|
||||
|
||||
## Каталог компонентов
|
||||
|
||||
### Text
|
||||
|
||||
Отображение текста с заданным семантическим размером.
|
||||
|
||||
| Свойство | Тип | По умолчанию |
|
||||
|----------|-----|--------------|
|
||||
| `variant` | `'body1' \| 'body2' \| 'caption' \| 'overline'` | `'body1'` |
|
||||
| `color` | `'primary' \| 'secondary' \| 'disabled' \| 'inverse'` | `'primary'` |
|
||||
|
||||
### Heading
|
||||
|
||||
Заголовок.
|
||||
|
||||
| Свойство | Тип | По умолчанию |
|
||||
|----------|-----|--------------|
|
||||
| `variant` | `'h1' \| 'h2' \| 'h3' \| 'h4' \| 'h5' \| 'h6'` | `'h3'` |
|
||||
|
||||
### Link
|
||||
|
||||
Ссылка. Под капотом MUI Link с цветом `color.action.primary`.
|
||||
|
||||
| Свойство | Тип | По умолчанию |
|
||||
|----------|-----|--------------|
|
||||
| `href` | `string` | — |
|
||||
| `underline` | `'none' \| 'hover' \| 'always'` | `'hover'` |
|
||||
|
||||
### Button
|
||||
|
||||
Кнопка действия. Обёртка MUI Button.
|
||||
|
||||
| Свойство | Тип | По умолчанию |
|
||||
|----------|-----|--------------|
|
||||
| `variant` | `'primary' \| 'secondary' \| 'danger'` | `'primary'` |
|
||||
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` |
|
||||
| `loading` | `boolean` | `false` |
|
||||
|
||||
### IconButton
|
||||
|
||||
Кнопка-иконка. **Требует `label`** (aria-label).
|
||||
|
||||
| Свойство | Тип | По умолчанию |
|
||||
|----------|-----|--------------|
|
||||
| `label` | `string` | — |
|
||||
| `size` | `'sm' \| 'md'` | `'md'` |
|
||||
|
||||
### TextField
|
||||
|
||||
Текстовое поле ввода.
|
||||
|
||||
| Свойство | Тип | По умолчанию |
|
||||
|----------|-----|--------------|
|
||||
| `size` | `'sm' \| 'md'` | `'md'` |
|
||||
| `fullWidth` | `boolean` | `true` |
|
||||
|
||||
### Select
|
||||
|
||||
Выпадающий список.
|
||||
|
||||
| Свойство | Тип | По умолчанию |
|
||||
|----------|-----|--------------|
|
||||
| `size` | `'sm' \| 'md'` | `'md'` |
|
||||
| `fullWidth` | `boolean` | `true` |
|
||||
|
||||
### Checkbox
|
||||
|
||||
Чекбокс.
|
||||
|
||||
| Свойство | Тип | По умолчанию |
|
||||
|----------|-----|--------------|
|
||||
| `label` | `string` | — |
|
||||
|
||||
### Surface
|
||||
|
||||
Базовый контейнер с фоном и скруглением.
|
||||
|
||||
| Свойство | Тип | По умолчанию |
|
||||
|----------|-----|--------------|
|
||||
| `variant` | `'default' \| 'subtle' \| 'raised'` | `'default'` |
|
||||
|
||||
### Card
|
||||
|
||||
Карточка. Поверхность с тенью.
|
||||
|
||||
| Свойство | Тип | По умолчанию |
|
||||
|----------|-----|--------------|
|
||||
| `padding` | `'sm' \| 'md' \| 'lg'` | `'md'` |
|
||||
|
||||
### Chip
|
||||
|
||||
Компактный элемент для отображения тега или статуса.
|
||||
|
||||
| Свойство | Тип | По умолчанию |
|
||||
|----------|-----|--------------|
|
||||
| `variant` | `'filled' \| 'outlined'` | `'filled'` |
|
||||
| `color` | `'default' \| 'info' \| 'success' \| 'warning' \| 'error'` | `'default'` |
|
||||
|
||||
### Badge
|
||||
|
||||
Бейдж с числовым или текстовым значением.
|
||||
|
||||
| Свойство | Тип | По умолчанию |
|
||||
|----------|-----|--------------|
|
||||
| `variant` | `'dot' \| 'standard'` | `'standard'` |
|
||||
| `color` | `'info' \| 'success' \| 'warning' \| 'error'` | `'info'` |
|
||||
|
||||
### Alert
|
||||
|
||||
Уведомление. Использует `role="alert"`.
|
||||
|
||||
| Свойство | Тип | По умолчанию |
|
||||
|----------|-----|--------------|
|
||||
| `severity` | `'info' \| 'success' \| 'warning' \| 'error'` | `'info'` |
|
||||
| `title` | `string` | — |
|
||||
|
||||
### Dialog
|
||||
|
||||
Модальное окно. **Требует `title`**, содержит focus trap, закрывается по Escape.
|
||||
|
||||
| Свойство | Тип | По умолчанию |
|
||||
|----------|-----|--------------|
|
||||
| `open` | `boolean` | — |
|
||||
| `title` | `string` | — |
|
||||
| `onClose` | `() => void` | — |
|
||||
|
||||
### Skeleton
|
||||
|
||||
Скелетон загрузки. `aria-hidden` по умолчанию.
|
||||
|
||||
| Свойство | Тип | По умолчанию |
|
||||
|----------|-----|--------------|
|
||||
| `width` | `string \| number` | `'100%'` |
|
||||
| `height` | `string \| number` | `20` |
|
||||
|
||||
### Progress
|
||||
|
||||
Индикатор прогресса. Поддерживает indeterminate-режим с `aria-busy`.
|
||||
|
||||
| Свойство | Тип | По умолчанию |
|
||||
|----------|-----|--------------|
|
||||
| `variant` | `'determinate' \| 'indeterminate'` | `'indeterminate'` |
|
||||
| `value` | `number` (0–100) | `0` |
|
||||
|
||||
### DataTable
|
||||
|
||||
Таблица данных на основе TanStack Table.
|
||||
|
||||
| Свойство | Тип | По умолчанию |
|
||||
|----------|-----|--------------|
|
||||
| `columns` | `ColumnDef<T>[]` | — |
|
||||
| `data` | `T[]` | — |
|
||||
| `caption` | `string` | — |
|
||||
| `density` | `'balanced' \| 'compact'` | `'balanced'` |
|
||||
|
||||
### Money
|
||||
|
||||
Финансовое значение с форматированием через `Intl.NumberFormat`.
|
||||
|
||||
| Свойство | Тип | По умолчанию |
|
||||
|----------|-----|--------------|
|
||||
| `value` | `number` | — |
|
||||
| `currency` | `string` | `'RUB'` |
|
||||
| `locale` | `string` | `'ru-RU'` |
|
||||
|
||||
### Metric
|
||||
|
||||
Метрика: лейбл + значение + опционально supporting/trend.
|
||||
|
||||
| Свойство | Тип | По умолчанию |
|
||||
|----------|-----|--------------|
|
||||
| `label` | `string` | — |
|
||||
| `value` | `ReactNode` | — |
|
||||
| `supporting` | `ReactNode` | — |
|
||||
| `trend` | `'up' \| 'down' \| 'neutral'` | — |
|
||||
|
||||
### PriceChange
|
||||
|
||||
Изменение цены. Использует **текстовое направление** (не только цвет).
|
||||
|
||||
| Свойство | Тип | По умолчанию |
|
||||
|----------|-----|--------------|
|
||||
| `value` | `number` | — |
|
||||
| `percent` | `number` | — |
|
||||
| `variant` | `'absolute' \| 'percent' \| 'both'` | `'both'` |
|
||||
|
||||
### FormField
|
||||
|
||||
Обёртка для поля формы: label + helperText + error.
|
||||
|
||||
| Свойство | Тип | По умолчанию |
|
||||
|----------|-----|--------------|
|
||||
| `label` | `string` | — |
|
||||
| `error` | `string` | — |
|
||||
| `helperText` | `string` | — |
|
||||
|
||||
### FilterBar
|
||||
|
||||
Панель фильтров с responsive-обёрткой.
|
||||
|
||||
| Свойство | Тип | По умолчанию |
|
||||
|----------|-----|--------------|
|
||||
| `children` | `ReactNode` | — |
|
||||
|
||||
### EmptyState
|
||||
|
||||
Пустое состояние. **Требует `title`**.
|
||||
|
||||
| Свойство | Тип | По умолчанию |
|
||||
|----------|-----|--------------|
|
||||
| `title` | `string` | — |
|
||||
| `description` | `string` | — |
|
||||
| `action` | `ReactNode` | — |
|
||||
|
||||
### ErrorState
|
||||
|
||||
Состояние ошибки. **Требует `title`**.
|
||||
|
||||
| Свойство | Тип | По умолчанию |
|
||||
|----------|-----|--------------|
|
||||
| `title` | `string` | — |
|
||||
| `description` | `string` | — |
|
||||
| `onRetry` | `() => void` | — |
|
||||
|
||||
### LoadingState
|
||||
|
||||
Состояние загрузки. `aria-live="polite"`.
|
||||
|
||||
| Свойство | Тип | По умолчанию |
|
||||
|----------|-----|--------------|
|
||||
| `title` | `string` | — |
|
||||
52
apps/docs/docs/design-system/foundations.md
Normal file
52
apps/docs/docs/design-system/foundations.md
Normal file
@ -0,0 +1,52 @@
|
||||
# Фундаментальные токены
|
||||
|
||||
## Архитектура
|
||||
|
||||
Система токенов состоит из трёх уровней:
|
||||
|
||||
```text
|
||||
Primitives ──► Semantic ──► Component
|
||||
(сырые (алиасы (алиасы для
|
||||
значения) назначения) компонентов)
|
||||
```
|
||||
|
||||
### Primitives
|
||||
|
||||
Хранят абсолютные значения: конкретные цвета, размеры, шрифты. Не несут семантической нагрузки.
|
||||
|
||||
Пример: `color.neutral.900` → `#1a1a1a`, `space.4` → `32px`.
|
||||
|
||||
### Semantic
|
||||
|
||||
Алиасы, ссылающиеся на примитивы и описывающие назначение. Используются в приложении и компонентах.
|
||||
|
||||
Пример: `color.text.primary` → `{color.neutral.900}` → `#1a1a1a`.
|
||||
|
||||
### Component
|
||||
|
||||
Алиасы для конкретных компонентов. Позволяют переопределять токены на уровне компонента без изменения семантических токенов.
|
||||
|
||||
Пример: `button.bg` → `{color.action.primary}` → `{color.green.700}`.
|
||||
|
||||
## Резолвер
|
||||
|
||||
Используется DTCG-подобный резолвер (Design Tokens Community Group):
|
||||
|
||||
- Цепочная резолюция: `component → semantic → primitive`
|
||||
- Проверка циклов
|
||||
- Проверка типов (`$type` должен совпадать)
|
||||
- Кэширование результатов
|
||||
|
||||
## Токены v1
|
||||
|
||||
В версии 1 все токены светлые (light-only). Ключевые группы:
|
||||
|
||||
- **color** — цвета (canvas, surface, text, border, action, feedback, finance)
|
||||
- **typography** — шрифты (family, weight)
|
||||
- **spacing** — отступы (inset, stack, inline)
|
||||
- **shape** — скругления (в примитивах)
|
||||
- **shadow** — тени (в примитивах)
|
||||
- **duration** — длительности анимаций (в примитивах)
|
||||
- **easing** — функции сглаживания (в примитивах)
|
||||
|
||||
Полный список семантических токенов — [Токены](tokens).
|
||||
38
apps/docs/docs/design-system/governance.md
Normal file
38
apps/docs/docs/design-system/governance.md
Normal file
@ -0,0 +1,38 @@
|
||||
# Управление (Governance)
|
||||
|
||||
## Режим v1
|
||||
|
||||
- **Только светлая тема**. Тёмная тема отложена до v2.
|
||||
- Изменения, затрагивающие цветовую палитру или контрастность, должны проверяться на WCAG 2.2 AA.
|
||||
|
||||
## Процесс добавления компонентов
|
||||
|
||||
Новый компонент проходит полный цикл:
|
||||
|
||||
1. **Spec** — спецификация API компонента
|
||||
2. **Plan** — план реализации
|
||||
3. **TDD** — тесты пишутся до реализации
|
||||
4. **Storybook** — интерактивный каталог с a11y-аддоном
|
||||
5. **Review** — код-ревью с проверкой accessibility
|
||||
|
||||
## Breaking changes
|
||||
|
||||
Любое изменение публичного API компонента или токена требует:
|
||||
|
||||
- Обновления мажорной версии
|
||||
- Миграционной заметки в `CHANGELOG.md`
|
||||
|
||||
## Импорты MUI
|
||||
|
||||
Прямые импорты из MUI в коде приложения (`apps/frontend`) запрещены, за исключением allowlist:
|
||||
|
||||
| Компонент | Разрешён |
|
||||
|-----------|----------|
|
||||
| Box | ✅ |
|
||||
| Stack | ✅ |
|
||||
| Grid | ✅ |
|
||||
| Typography | ❌ → использовать Text / Heading |
|
||||
| Button | ❌ → использовать Button |
|
||||
| Остальные MUI | ❌ |
|
||||
|
||||
Нарушение контролируется ESLint-правилом `no-restricted-imports` (уровень `warn`).
|
||||
42
apps/docs/docs/design-system/overview.md
Normal file
42
apps/docs/docs/design-system/overview.md
Normal file
@ -0,0 +1,42 @@
|
||||
# Дизайн-система
|
||||
|
||||
## Что это
|
||||
|
||||
`@moex-vibe/design-system` — внутренний пакет дизайн-системы (v0.1.0). Построен на [MUI 6.5](https://mui.com/material-ui/). Поддерживает только светлую тему (light-only).
|
||||
|
||||
## Архитектура токенов
|
||||
|
||||
Трёхуровневая система токенов:
|
||||
|
||||
1. **Primitives** — сырые значения (цвета, размеры, шрифты)
|
||||
2. **Semantic** — алиасы, описывающие назначение (`color.text.primary`)
|
||||
3. **Component** — алиасы для конкретных компонентов (`button.bg`)
|
||||
|
||||
Подробнее — [Токены](foundations).
|
||||
|
||||
## Компоненты
|
||||
|
||||
Библиотека включает 25 компонентов:
|
||||
|
||||
| Категория | Компоненты |
|
||||
|-----------|------------|
|
||||
| Typography | Text, Heading, Link |
|
||||
| Actions | Button, IconButton |
|
||||
| Inputs | TextField, Select, Checkbox |
|
||||
| Surfaces | Surface, Card |
|
||||
| Feedback | Chip, Badge, Alert, Dialog, Skeleton, Progress |
|
||||
| Financial | Money, Metric, PriceChange |
|
||||
| Form | FormField, FilterBar |
|
||||
| Page States | EmptyState, ErrorState, LoadingState |
|
||||
| Data | DataTable |
|
||||
|
||||
Подробнее — [Компоненты](components).
|
||||
|
||||
## Инструменты
|
||||
|
||||
- **Storybook** — инженерный стенд для разработки и визуального ревью
|
||||
- **Docusaurus** — опубликованная документация (этот сайт)
|
||||
|
||||
## ADR
|
||||
|
||||
Архитектурное решение описано в [ADR-016](../adr/ADR-016-design-system).
|
||||
94
apps/docs/docs/design-system/patterns.md
Normal file
94
apps/docs/docs/design-system/patterns.md
Normal file
@ -0,0 +1,94 @@
|
||||
# Паттерны
|
||||
|
||||
## Финансовые данные
|
||||
|
||||
### Money
|
||||
|
||||
Форматирование через `Intl.NumberFormat`:
|
||||
|
||||
- Локаль: `ru-RU`
|
||||
- Валюта по умолчанию: `RUB`
|
||||
|
||||
```tsx
|
||||
<Money value={1234.5} /> // 1 234,50 ₽
|
||||
<Money value={1234.5} currency="USD" /> // 1 234,50 $
|
||||
```
|
||||
|
||||
### PriceChange
|
||||
|
||||
Отображает изменение цены. Обязательное правило: **никогда не использовать только цвет**. Всегда добавлять текстовый индикатор направления (`+`, `−`, `—`).
|
||||
|
||||
| Направление | Индикатор | Цвет токена |
|
||||
|-------------|-----------|-------------|
|
||||
| Рост | `+` | `color.finance.positive` |
|
||||
| Падение | `−` | `color.finance.negative` |
|
||||
| Нейтрально | `—` | `color.finance.neutral` |
|
||||
|
||||
### Metric
|
||||
|
||||
Композитный компонент: label + value + опционально supporting (доп. текст) и trend (направление).
|
||||
|
||||
```tsx
|
||||
<Metric
|
||||
label="Общая доходность"
|
||||
value={<Money value={12345} />}
|
||||
trend="up"
|
||||
/>
|
||||
```
|
||||
|
||||
## Формы
|
||||
|
||||
### FormField
|
||||
|
||||
Обёртка для поля, связывающая label, helperText и error через ассоциацию `htmlFor`/`id`.
|
||||
|
||||
```tsx
|
||||
<FormField label="Название" error="Обязательное поле">
|
||||
<TextField />
|
||||
</FormField>
|
||||
```
|
||||
|
||||
### FilterBar
|
||||
|
||||
Responsive-панель фильтров с автоматическим переносом (wrap).
|
||||
|
||||
```tsx
|
||||
<FilterBar>
|
||||
<Select label="Тип" />
|
||||
<TextField label="Поиск" />
|
||||
</FilterBar>
|
||||
```
|
||||
|
||||
## Состояния страницы
|
||||
|
||||
### EmptyState, ErrorState, LoadingState
|
||||
|
||||
Три компонента для трёх состояний любой страницы или секции:
|
||||
|
||||
- **EmptyState** — данных нет, `title` обязателен
|
||||
- **ErrorState** — ошибка загрузки, `title` обязателен, `onRetry` для повтора
|
||||
- **LoadingState** — загрузка, `title` обязателен, `aria-live="polite"`
|
||||
|
||||
```tsx
|
||||
{isLoading && <LoadingState title="Загрузка портфеля" />}
|
||||
{error && <ErrorState title="Ошибка загрузки" onRetry={refetch} />}
|
||||
{data && data.length === 0 && <EmptyState title="Нет операций" />}
|
||||
```
|
||||
|
||||
## Таблицы
|
||||
|
||||
### DataTable
|
||||
|
||||
Обёртка над TanStack Table с обязательным `caption` для доступности. Два режима плотности:
|
||||
|
||||
- **balanced** (по умолчанию) — отступы md
|
||||
- **compact** — отступы sm, для плотных таблиц
|
||||
|
||||
```tsx
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={rows}
|
||||
caption="Список операций"
|
||||
density="compact"
|
||||
/>
|
||||
```
|
||||
106
apps/docs/docs/design-system/tokens.md
Normal file
106
apps/docs/docs/design-system/tokens.md
Normal file
@ -0,0 +1,106 @@
|
||||
# Семантические токены
|
||||
|
||||
Компонентные токены документированы на страницах соответствующих компонентов.
|
||||
|
||||
## Color
|
||||
|
||||
### Canvas
|
||||
|
||||
| Токен | Значение | Разрешение |
|
||||
|-------|----------|------------|
|
||||
| `color.canvas` | `{color.neutral.50}` | `#f5f5f5` |
|
||||
|
||||
### Surface
|
||||
|
||||
| Токен | Значение | Разрешение |
|
||||
|-------|----------|------------|
|
||||
| `color.surface.default` | `{color.neutral.0}` | `#ffffff` |
|
||||
| `color.surface.subtle` | `{color.neutral.50}` | `#f5f5f5` |
|
||||
| `color.surface.raised` | `{color.neutral.0}` | `#ffffff` |
|
||||
|
||||
### Text
|
||||
|
||||
| Токен | Значение | Разрешение |
|
||||
|-------|----------|------------|
|
||||
| `color.text.primary` | `{color.neutral.900}` | `#1a1a1a` |
|
||||
| `color.text.secondary` | `{color.neutral.600}` | `#666666` |
|
||||
| `color.text.disabled` | `{color.neutral.400}` | `#999999` |
|
||||
| `color.text.inverse` | `{color.neutral.0}` | `#ffffff` |
|
||||
|
||||
### Border
|
||||
|
||||
| Токен | Значение | Разрешение |
|
||||
|-------|----------|------------|
|
||||
| `color.border.subtle` | `{color.neutral.100}` | `#e0e0e0` |
|
||||
| `color.border.default` | `{color.neutral.200}` | `#cccccc` |
|
||||
| `color.border.strong` | `{color.neutral.400}` | `#999999` |
|
||||
| `color.border.focus` | `{color.blue.600}` | `#1e88e5` |
|
||||
|
||||
### Action
|
||||
|
||||
| Токен | Значение | Разрешение |
|
||||
|-------|----------|------------|
|
||||
| `color.action.primary` | `{color.green.700}` | `#388e3c` |
|
||||
| `color.action.primaryHover` | `{color.green.800}` | `#2e7d32` |
|
||||
| `color.action.secondary` | `{color.neutral.600}` | `#666666` |
|
||||
| `color.action.danger` | `{color.red.600}` | `#e53935` |
|
||||
|
||||
### Feedback
|
||||
|
||||
| Токен | Значение | Разрешение |
|
||||
|-------|----------|------------|
|
||||
| `color.feedback.info` | `{color.blue.600}` | `#1e88e5` |
|
||||
| `color.feedback.success` | `{color.green.600}` | `#43a047` |
|
||||
| `color.feedback.warning` | `{color.amber.600}` | `#ffb300` |
|
||||
| `color.feedback.error` | `{color.red.600}` | `#e53935` |
|
||||
|
||||
### Finance
|
||||
|
||||
| Токен | Значение | Разрешение |
|
||||
|-------|----------|------------|
|
||||
| `color.finance.positive` | `{color.green.700}` | `#388e3c` |
|
||||
| `color.finance.negative` | `{color.red.700}` | `#d32f2f` |
|
||||
| `color.finance.neutral` | `{color.neutral.600}` | `#666666` |
|
||||
|
||||
## Typography
|
||||
|
||||
| Токен | Значение | Разрешение |
|
||||
|-------|----------|------------|
|
||||
| `font.family.body` | `{font.family.sans}` | `Inter, system-ui, sans-serif` |
|
||||
| `font.weight.body` | `{font.weight.regular}` | `400` |
|
||||
| `font.weight.heading` | `{font.weight.semibold}` | `600` |
|
||||
| `font.weight.strong` | `{font.weight.bold}` | `700` |
|
||||
|
||||
## Spacing
|
||||
|
||||
### Inset (внутренние отступы)
|
||||
|
||||
| Токен | Значение | Разрешение |
|
||||
|-------|----------|------------|
|
||||
| `space.inset.sm` | `{space.2}` | `8px` |
|
||||
| `space.inset.md` | `{space.3}` | `12px` |
|
||||
| `space.inset.lg` | `{space.4}` | `16px` |
|
||||
|
||||
### Stack (вертикальные отступы)
|
||||
|
||||
| Токен | Значение | Разрешение |
|
||||
|-------|----------|------------|
|
||||
| `space.stack.sm` | `{space.1}` | `4px` |
|
||||
| `space.stack.md` | `{space.2}` | `8px` |
|
||||
| `space.stack.lg` | `{space.4}` | `16px` |
|
||||
|
||||
### Inline (горизонтальные отступы)
|
||||
|
||||
| Токен | Значение | Разрешение |
|
||||
|-------|----------|------------|
|
||||
| `space.inline.sm` | `{space.1}` | `4px` |
|
||||
| `space.inline.md` | `{space.2}` | `8px` |
|
||||
| `space.inline.lg` | `{space.3}` | `12px` |
|
||||
|
||||
## Size / Focus
|
||||
|
||||
| Токен | Значение | Разрешение |
|
||||
|-------|----------|------------|
|
||||
| `focus.ring.width` | `{size.focus.ring}` | `2px` |
|
||||
| `focus.ring.offset` | `{size.focus.offset}` | `2px` |
|
||||
| `focus.ring.color` | `{color.blue.600}` | `#1e88e5` |
|
||||
@ -2,7 +2,17 @@
|
||||
|
||||
## Подход
|
||||
|
||||
CSS через единый `styles.css` с CSS custom properties. Без CSS-in-JS или Tailwind.
|
||||
Управление стилями осуществляется через пакет [дизайн-системы](../design-system/overview) `@moex-vibe/design-system`, который предоставляет:
|
||||
|
||||
- Систему токенов (primitives → semantic → component)
|
||||
- MUI 6.5 тему, построенную на токенах
|
||||
- CSS-переменные `--mv-*` для доступа из обычного CSS
|
||||
|
||||
Все новые компоненты должны использовать токены дизайн-системы. Подробнее — [Дизайн-система](../design-system/overview).
|
||||
|
||||
## Legacy: CSS custom properties
|
||||
|
||||
Ранее стили определялись через единый `styles.css` с CSS custom properties. Этот подход считается устаревшим — новые страницы должны использовать токены дизайн-системы.
|
||||
|
||||
## CSS custom properties
|
||||
|
||||
|
||||
@ -39,6 +39,19 @@ const sidebars: SidebarsConfig = {
|
||||
label: 'Инфраструктура',
|
||||
items: ['infrastructure/docker', 'infrastructure/ci'],
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Дизайн-система',
|
||||
items: [
|
||||
'design-system/overview',
|
||||
'design-system/foundations',
|
||||
'design-system/tokens',
|
||||
'design-system/components',
|
||||
'design-system/patterns',
|
||||
'design-system/accessibility',
|
||||
'design-system/governance',
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'category',
|
||||
label: 'Разработка',
|
||||
|
||||
11
packages/design-system/CHANGELOG.md
Normal file
11
packages/design-system/CHANGELOG.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Changelog
|
||||
|
||||
## 0.1.0 (2026-06-21)
|
||||
|
||||
### Added
|
||||
|
||||
- Token system: primitives, semantic (light), and component tokens with DTCG-like resolver
|
||||
- Theme adapter: MUI 6.5 theme with CSS variables (`--mv-*`)
|
||||
- Components: 20+ production-ready wrappers (Typography, Actions, Inputs, Surfaces, Feedback, Financial Data, Form, Page States)
|
||||
- Storybook: interactive catalog with a11y checks
|
||||
- First stable public API
|
||||
Loading…
x
Reference in New Issue
Block a user