diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml
index 13b9c91..fa9f736 100644
--- a/.gitea/workflows/ci.yml
+++ b/.gitea/workflows/ci.yml
@@ -40,3 +40,29 @@ jobs:
- name: Build frontend
run: npm run build:frontend
+
+ - name: Setup Playwright browsers
+ run: npx playwright install --with-deps chromium
+
+ - name: Test design system
+ run: npm run test:design-system
+
+ - name: Build design system
+ run: npm run build:design-system
+
+ - name: Build Storybook
+ run: npm run build:storybook
+
+ - name: Test Storybook (browser)
+ run: npm run test:storybook
+
+ - name: Build docs
+ run: npm run build:docs
+
+ - name: Upload Storybook build (if failed)
+ if: failure()
+ uses: actions/upload-artifact@v4
+ with:
+ name: storybook-static
+ path: packages/design-system/storybook-static
+ retention-days: 3
diff --git a/README.md b/README.md
index dce1318..379051f 100644
--- a/README.md
+++ b/README.md
@@ -21,9 +21,10 @@ npm workspaces монорепозиторий:
| Пакет | Назначение |
| --------------- | -------------------------------------------------- |
-| `apps/backend` | NestJS API (единственная точка доступа к MOEX ISS) |
-| `apps/frontend` | React SPA на Vite |
-| `apps/docs` | Сайт документации Docusaurus |
+| `apps/backend` | NestJS API (единственная точка доступа к MOEX ISS) |
+| `apps/frontend` | React SPA на Vite |
+| `apps/docs` | Сайт документации Docusaurus |
+| `packages/design-system` | Дизайн-система (Storybook, MUI-адаптер, UI-компоненты) |
---
@@ -31,6 +32,7 @@ npm workspaces монорепозиторий:
- **Бэкенд:** NestJS, TypeScript, OpenAPI (Swagger)
- **Фронтенд:** React, TypeScript, Vite, TanStack Query, lightweight-charts
+- **Дизайн-система:** MUI v7, Storybook 10, lightweight-charts
- **Документация:** Docusaurus
- **Инфраструктура:** Docker, docker-compose
@@ -87,9 +89,11 @@ npm run test:integration -w apps/backend
```
apps/
- backend/ — NestJS API, единая точка доступа к MOEX ISS
- frontend/ — React SPA на Vite
- docs/ — сайт документации Docusaurus
+ backend/ — NestJS API, единая точка доступа к MOEX ISS
+ frontend/ — React SPA на Vite
+ docs/ — сайт документации Docusaurus
+packages/
+ design-system/ — дизайн-система (MUI-адаптер, UI-компоненты, Storybook)
docs/
features/ — спецификации и планы реализации (SDD)
epics/ — продуктовые эпики
@@ -105,16 +109,24 @@ docs/
| ---------------------------------- | --------------------------------------------------------------------------- |
| `npm run dev:backend` | Запуск NestJS в режиме watch на :3000 |
| `npm run dev:frontend` | Vite dev-сервер на :5173, проксирует `/api` → :3000 |
-| `npm run dev:docs` | Docusaurus dev-сервер |
+| `npm run dev:docs` | Docusaurus dev-сервер (опубликованная документация) |
| `npm run build:backend` | `nest build` |
| `npm run build:frontend` | `tsc -b && vite build` (в две фазы) |
| `npm run build:docs` | `docusaurus build` |
+| `npm run build:design-system` | Сборка дизайн-системы (`tsc`) |
+| `npm run build:storybook` | Статическая сборка Storybook |
| `npm run test:backend` | `vitest run` (SWC, не ts-jest) |
| `npm run test:frontend` | Frontend Vitest suite |
-| `npm run lint` | ESLint для backend и frontend |
+| `npm run test:design-system` | Unit-тесты дизайн-системы (Vitest) |
+| `npm run test:storybook` | Браузерные тесты Storybook (Vitest browser mode + Playwright) |
+| `npm run storybook` | Storybook dev-сервер на :6006 (инженерный workbench, не docs) |
+| `npm run lint` | ESLint для backend, frontend и design-system |
+| `npm run lint:design-system` | ESLint для дизайн-системы |
| `npm run format` | Prettier для всех `*.{ts,tsx}` |
| `npm run codegen -w apps/frontend` | `openapi-typescript` из запущенного локального Swagger → `src/api/types.ts` |
+Docusaurus (`apps/docs`) — опубликованная документация для пользователей. Storybook (`packages/design-system`) — инженерный workbench для разработки компонентов.
+
Интеграционные тесты с MOEX: `npm run test:integration -w apps/backend`.
Один backend-тест: `npm exec -w apps/backend -- vitest run src/path/to/test.spec.ts`
diff --git a/apps/docs/docs/adr/ADR-016-design-system.md b/apps/docs/docs/adr/ADR-016-design-system.md
new file mode 100644
index 0000000..8402226
--- /dev/null
+++ b/apps/docs/docs/adr/ADR-016-design-system.md
@@ -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-адаптеры для нативных приложений.
+- Расширение компонентной базы.
diff --git a/apps/docs/docs/adr/index.md b/apps/docs/docs/adr/index.md
index 66378c7..ac259c5 100644
--- a/apps/docs/docs/adr/index.md
+++ b/apps/docs/docs/adr/index.md
@@ -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-разделе.
diff --git a/apps/docs/docs/design-system/accessibility.md b/apps/docs/docs/design-system/accessibility.md
new file mode 100644
index 0000000..e4f104f
--- /dev/null
+++ b/apps/docs/docs/design-system/accessibility.md
@@ -0,0 +1,49 @@
+# Доступность (Accessibility)
+
+## Целевой уровень
+
+WCAG 2.2 AA.
+
+## Требования к компонентам
+
+### IconButton
+
+**Требует `label`** — свойство `aria-label` обязательно для всех иконок без текста.
+
+```tsx
+
+
+
+```
+
+### Dialog
+
+- **Требует `title`** — заголовок, используемый как `aria-labelledby`
+- Содержит focus trap (фокус не покидает диалог)
+- Закрывается по Escape
+
+### Progress
+
+- `indeterminate`-режим выставляет `aria-busy` на контейнере
+
+### PriceChange
+
+- Использует **текстовый индикатор направления** (`+`, `−`, `—`), а не только цвет
+- Скринридеры получают знак перед числом
+
+### DataTable
+
+- **Требует `caption`** — описание таблицы для скринридеров
+- Семантические заголовки через `
`
+
+### Skeleton
+
+- `aria-hidden` по умолчанию — скелетоны не должны озвучиваться
+
+### Alert
+
+- Использует `role="alert"` для немедленного объявления скринридером
+
+### LoadingState
+
+- `aria-live="polite"` — скринридер объявит об изменении после завершения текущей речи
diff --git a/apps/docs/docs/design-system/components.md b/apps/docs/docs/design-system/components.md
new file mode 100644
index 0000000..73b98cb
--- /dev/null
+++ b/apps/docs/docs/design-system/components.md
@@ -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[]` | — |
+| `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` | — |
diff --git a/apps/docs/docs/design-system/foundations.md b/apps/docs/docs/design-system/foundations.md
new file mode 100644
index 0000000..62703dd
--- /dev/null
+++ b/apps/docs/docs/design-system/foundations.md
@@ -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).
diff --git a/apps/docs/docs/design-system/governance.md b/apps/docs/docs/design-system/governance.md
new file mode 100644
index 0000000..4f7045b
--- /dev/null
+++ b/apps/docs/docs/design-system/governance.md
@@ -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`).
diff --git a/apps/docs/docs/design-system/overview.md b/apps/docs/docs/design-system/overview.md
new file mode 100644
index 0000000..fb92c7c
--- /dev/null
+++ b/apps/docs/docs/design-system/overview.md
@@ -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).
diff --git a/apps/docs/docs/design-system/patterns.md b/apps/docs/docs/design-system/patterns.md
new file mode 100644
index 0000000..ecc7418
--- /dev/null
+++ b/apps/docs/docs/design-system/patterns.md
@@ -0,0 +1,94 @@
+# Паттерны
+
+## Финансовые данные
+
+### Money
+
+Форматирование через `Intl.NumberFormat`:
+
+- Локаль: `ru-RU`
+- Валюта по умолчанию: `RUB`
+
+```tsx
+ // 1 234,50 ₽
+ // 1 234,50 $
+```
+
+### PriceChange
+
+Отображает изменение цены. Обязательное правило: **никогда не использовать только цвет**. Всегда добавлять текстовый индикатор направления (`+`, `−`, `—`).
+
+| Направление | Индикатор | Цвет токена |
+|-------------|-----------|-------------|
+| Рост | `+` | `color.finance.positive` |
+| Падение | `−` | `color.finance.negative` |
+| Нейтрально | `—` | `color.finance.neutral` |
+
+### Metric
+
+Композитный компонент: label + value + опционально supporting (доп. текст) и trend (направление).
+
+```tsx
+}
+ trend="up"
+/>
+```
+
+## Формы
+
+### FormField
+
+Обёртка для поля, связывающая label, helperText и error через ассоциацию `htmlFor`/`id`.
+
+```tsx
+
+
+
+```
+
+### FilterBar
+
+Responsive-панель фильтров с автоматическим переносом (wrap).
+
+```tsx
+
+
+
+
+```
+
+## Состояния страницы
+
+### EmptyState, ErrorState, LoadingState
+
+Три компонента для трёх состояний любой страницы или секции:
+
+- **EmptyState** — данных нет, `title` обязателен
+- **ErrorState** — ошибка загрузки, `title` обязателен, `onRetry` для повтора
+- **LoadingState** — загрузка, `title` обязателен, `aria-live="polite"`
+
+```tsx
+{isLoading && }
+{error && }
+{data && data.length === 0 && }
+```
+
+## Таблицы
+
+### DataTable
+
+Обёртка над TanStack Table с обязательным `caption` для доступности. Два режима плотности:
+
+- **balanced** (по умолчанию) — отступы md
+- **compact** — отступы sm, для плотных таблиц
+
+```tsx
+
+```
diff --git a/apps/docs/docs/design-system/tokens.md b/apps/docs/docs/design-system/tokens.md
new file mode 100644
index 0000000..02a4e83
--- /dev/null
+++ b/apps/docs/docs/design-system/tokens.md
@@ -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` |
diff --git a/apps/docs/docs/frontend/styling.md b/apps/docs/docs/frontend/styling.md
index c566103..77f4f36 100644
--- a/apps/docs/docs/frontend/styling.md
+++ b/apps/docs/docs/frontend/styling.md
@@ -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
diff --git a/apps/docs/sidebars.ts b/apps/docs/sidebars.ts
index 41c75ae..001d74c 100644
--- a/apps/docs/sidebars.ts
+++ b/apps/docs/sidebars.ts
@@ -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: 'Разработка',
diff --git a/apps/frontend/.eslintrc.cjs b/apps/frontend/.eslintrc.cjs
index 6d96ee8..22f9c0a 100644
--- a/apps/frontend/.eslintrc.cjs
+++ b/apps/frontend/.eslintrc.cjs
@@ -29,6 +29,12 @@ module.exports = {
},
ignorePatterns: ['.eslintrc.cjs', 'vite.config.ts', 'vitest.config.ts', 'dist/'],
rules: {
+ 'no-restricted-imports': ['warn', {
+ paths: [{
+ name: '@mui/material',
+ message: 'Import from @moex-vibe/design-system instead.',
+ }],
+ }],
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
'@typescript-eslint/no-explicit-any': 'off',
'react/react-in-jsx-scope': 'off',
diff --git a/apps/frontend/package.json b/apps/frontend/package.json
index 9d09f79..cef656f 100644
--- a/apps/frontend/package.json
+++ b/apps/frontend/package.json
@@ -15,7 +15,8 @@
"dependencies": {
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.1",
- "@fontsource/roboto": "^5.2.10",
+ "@fontsource/inter": "^5.2.8",
+ "@moex-vibe/design-system": "*",
"@hookform/resolvers": "^3.10.0",
"@mui/icons-material": "^6.5.0",
"@mui/material": "^6.5.0",
diff --git a/apps/frontend/src/app/providers/AppProviders.tsx b/apps/frontend/src/app/providers/AppProviders.tsx
index 63f073b..2c24c08 100644
--- a/apps/frontend/src/app/providers/AppProviders.tsx
+++ b/apps/frontend/src/app/providers/AppProviders.tsx
@@ -1,9 +1,11 @@
import { type ReactNode } from 'react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
-import { ThemeProvider } from '@mui/material/styles';
-import CssBaseline from '@mui/material/CssBaseline';
+import '@fontsource/inter/400.css';
+import '@fontsource/inter/500.css';
+import '@fontsource/inter/600.css';
+import '@fontsource/inter/700.css';
+import { MoexVibeThemeProvider } from '@moex-vibe/design-system/theme';
import { SessionProvider } from './SessionProvider';
-import { theme } from '@/app/styles/theme';
const queryClient = new QueryClient({
defaultOptions: {
@@ -17,11 +19,10 @@ const queryClient = new QueryClient({
export function AppProviders({ children }: { children: ReactNode }) {
return (
-
-
+
{children}
-
+
);
}
diff --git a/apps/frontend/src/app/styles/theme.ts b/apps/frontend/src/app/styles/theme.ts
deleted file mode 100644
index 50e3776..0000000
--- a/apps/frontend/src/app/styles/theme.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-import { createTheme } from '@mui/material/styles';
-
-export const theme = createTheme({
- cssVariables: true,
- colorSchemes: {
- light: {
- palette: {
- primary: { main: '#1976d2' },
- success: { main: '#2e7d32' },
- error: { main: '#c62828' },
- background: { default: '#f5f5f5', paper: '#ffffff' },
- },
- },
- },
- typography: {
- fontFamily: ['-apple-system', 'BlinkMacSystemFont', "'Segoe UI'", 'Roboto', 'sans-serif'].join(
- ',',
- ),
- },
-});
diff --git a/docs/features/design-system-foundation/plan.md b/docs/features/design-system-foundation/plan.md
new file mode 100644
index 0000000..5f6454c
--- /dev/null
+++ b/docs/features/design-system-foundation/plan.md
@@ -0,0 +1,643 @@
+# Design System Foundation Implementation Plan
+
+> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
+
+**Goal:** Создать внутренний пакет `@moex-vibe/design-system` с трёхуровневыми токенами, MUI light theme, согласованным UI-каталогом, Storybook и опубликованными правилами.
+
+**Architecture:** Platform-neutral токены хранятся как JSON-compatible TypeScript records и разрешаются собственным проверяемым resolver. MUI-адаптер переводит semantic/component tokens в CSS-variable theme; React-компоненты доступны только через public exports пакета. Storybook служит локальным/CI workbench, Docusaurus — единственной опубликованной документацией.
+
+**Tech Stack:** TypeScript 5, React 18, MUI 6.5, TanStack Table 8, Vitest 4 browser mode, Storybook 10.2 (`@storybook/react-vite`), Playwright Chromium, Docusaurus 3.7.
+
+---
+
+## Зафиксированные интерфейсы
+
+Пакет предоставляет subpath exports:
+
+```json
+{
+ ".": "./dist/index.js",
+ "./tokens": "./dist/tokens/index.js",
+ "./theme": "./dist/theme/index.js"
+}
+```
+
+Token source использует плоские DTCG-подобные записи:
+
+```ts
+type TokenType = 'color' | 'dimension' | 'fontFamily' | 'fontWeight' | 'duration' | 'cubicBezier' | 'shadow';
+type TokenValue = string | number | readonly number[] | readonly string[];
+type TokenDefinition = { readonly $type: TokenType; readonly $value: TokenValue };
+type TokenCollection = Readonly>;
+
+// Primitive содержит абсолютное значение.
+'color.green.700': { $type: 'color', $value: '#176747' }
+// Semantic/component содержит alias и никогда не дублирует primitive.
+'color.action.primary': { $type: 'color', $value: '{color.green.700}' }
+```
+
+Публичный React API:
+
+```ts
+type Tone = 'default' | 'secondary' | 'positive' | 'negative' | 'muted';
+type Density = 'balanced' | 'compact';
+type ActionVariant = 'primary' | 'secondary' | 'tertiary' | 'danger';
+
+type TextProps = { variant?: 'body' | 'caption' | 'label' | 'numeric'; tone?: Tone };
+type HeadingProps = { level: 1 | 2 | 3 | 4 | 5 | 6; size?: 'display' | 'title' | 'section' | 'subsection' };
+type ButtonProps = { variant?: ActionVariant; size?: 'small' | 'medium'; loading?: boolean };
+type IconButtonProps = { label: string; size?: 'small' | 'medium' };
+type SurfaceProps = { padding?: 'none' | 'sm' | 'md' | 'lg'; elevation?: 'none' | 'sm' | 'md' };
+type DataTableProps = { table: Table; density?: Density; loading?: boolean; empty?: ReactNode; caption: string };
+type MoneyProps = { value: number; currency?: string; locale?: string; signDisplay?: 'auto' | 'always' | 'never' };
+type PriceChangeProps = { value: number; format?: 'percent' | 'money'; currency?: string; locale?: string };
+type MetricProps = { label: string; value: ReactNode; supportingText?: ReactNode; trend?: ReactNode };
+```
+
+Остальные контракты фиксированы так:
+
+- `Link`: MUI Link без `color`, `variant`, `sx`; добавляет `tone` и сохраняет polymorphic `component`.
+- `TextField`: MUI TextField без `color`, `variant`, `size`, `sx`; всегда `variant="outlined"` и
+ `size="medium"`.
+- `Select`: `label`, `value`, `onChange(value: string)`, `options: { value; label; disabled? }[]`,
+ `error?`, `helperText?`, `disabled?`.
+- `Checkbox`: `label`, `checked`, `onChange(checked: boolean)`, `disabled?`, `error?`.
+- `Card`: Surface props плюс `header?`, `actions?`, `children`; не знает маршруты и домен.
+- `Chip`: `label`, `tone: neutral|info|success|warning|error`, `onDelete?`.
+- `Badge`: `value`, `max?`, `label`; decorative badge запрещён без accessible label.
+- `Alert`: `severity: info|success|warning|error`, `title?`, `children`, `action?`.
+- `Dialog`: `open`, `onClose`, обязательные `title`, `children`, `actions?`.
+- `Skeleton`: `width?`, `height?`, `shape: text|rectangular|rounded|circular`.
+- `Progress`: `label`, `value?`; отсутствие value означает indeterminate.
+- `FormField`: `label`, `htmlFor`, `helperText?`, `error?`, `required?`, `children`.
+- `FilterBar`: `children`, `actions?`; отвечает только за responsive layout.
+- Page states: обязательный `title`, optional `description/action`; `LoadingState` дополнительно имеет
+ `label` и `size: section|page`.
+
+Все wrappers запрещают произвольные `color`, `variant`, `size` и `sx`, где они обходят контракт.
+`Box`, `Stack`, `Grid` остаются полным и единственным прямым MUI allowlist во frontend.
+
+## Карта файлов
+
+- `packages/design-system/src/tokens/` — schema, три token collections, resolver и guards.
+- `packages/design-system/src/theme/` — MUI augmentation, theme factory, provider, component overrides.
+- `packages/design-system/src/components/` — Core UI и product patterns; один каталог на компонент.
+- `packages/design-system/.storybook/` — единый provider, a11y и browser-test annotations.
+- `apps/frontend/src/app/providers/AppProviders.tsx` — подключение provider пакета без миграции страниц.
+- `apps/docs/docs/design-system/` — канонические правила; `apps/docs/docs/adr/ADR-016-design-system.md` — архитектурное решение.
+
+### Task 1: Pre-flight и workspace shell
+
+**Files:**
+- Modify: `package.json`
+- Create: `packages/design-system/package.json`
+- Create: `packages/design-system/tsconfig.json`
+- Create: `packages/design-system/vitest.config.ts`
+- Create: `packages/design-system/.eslintrc.cjs`
+- Create: `packages/design-system/src/test/setup.ts`
+- Create: `packages/design-system/src/index.ts`
+
+- [ ] **Step 1: Проверить pre-flight до любых implementation edits**
+
+Run:
+
+```bash
+git branch --show-current
+git status --short
+npm run test:backend
+npm run test:frontend
+npm run lint
+npm run build:backend
+npm run build:frontend
+```
+
+Expected: ветка `codex/design-system-foundation`, чистый worktree и все команды PASS. При сбое
+остановиться и классифицировать его до изменения кода.
+
+- [ ] **Step 2: Добавить workspace и root scripts**
+
+В `package.json` добавить `packages/design-system` в `workspaces` и scripts:
+
+```json
+{
+ "build:design-system": "npm run build -w packages/design-system",
+ "test:design-system": "npm run test -w packages/design-system",
+ "lint:design-system": "npm run lint -w packages/design-system",
+ "storybook": "npm run storybook -w packages/design-system",
+ "build:storybook": "npm run build-storybook -w packages/design-system",
+ "test:storybook": "npm run test:storybook -w packages/design-system"
+}
+```
+
+- [ ] **Step 3: Создать package manifest и TypeScript build**
+
+`packages/design-system/package.json` должен быть private ESM package версии `0.1.0`, иметь `files:
+["dist"]`, exports из раздела выше, peer dependencies на React 18, MUI 6 и TanStack Table 8, dev
+dependencies Storybook `^10.2.9`, `@vitest/browser-playwright`/Vitest `^4.1.8` и Playwright, scripts
+`build: tsc -p tsconfig.json`, `test: vitest run --project unit`, `storybook: storybook dev -p 6006
+--no-open`, `build-storybook: storybook build`, `test:storybook: vitest run --project storybook`,
+`lint: eslint "src/**/*.{ts,tsx}"`.
+
+`tsconfig.json` компилирует `src` в `dist`, включает declarations, `jsx: react-jsx`, strict и
+`moduleResolution: bundler`. `vitest.config.ts` сначала содержит unit project с jsdom и
+`passWithNoTests: true`; флаг удаляется после Task 2. Test setup подключает jest-dom и matchMedia mock.
+Package ESLint config проверяет TypeScript/React hooks, но не включает frontend FSD zones. Root `lint`
+дополняется `lint:design-system`.
+
+- [ ] **Step 4: Установить зависимости и проверить пустой пакет**
+
+Run:
+
+```bash
+npm install
+npm run build:design-system
+npm run test:design-system
+```
+
+Expected: package-lock обновлён, build PASS, Vitest PASS с `passWithNoTests: true`.
+
+- [ ] **Step 5: Commit**
+
+```bash
+git add package.json package-lock.json packages/design-system
+git commit -m "build(design-system): add workspace package"
+```
+
+### Task 2: Token schema и resolver (TDD)
+
+**Files:**
+- Create: `packages/design-system/src/tokens/types.ts`
+- Create: `packages/design-system/src/tokens/resolveToken.ts`
+- Test: `packages/design-system/src/tokens/resolveToken.test.ts`
+
+- [ ] **Step 1: Написать failing tests**
+
+```ts
+it('resolves an alias chain and preserves the declared type', () => {
+ const tokens = {
+ base: { $type: 'color', $value: '#176747' },
+ semantic: { $type: 'color', $value: '{base}' },
+ component: { $type: 'color', $value: '{semantic}' },
+ } satisfies TokenCollection;
+ expect(resolveToken(tokens, 'component')).toEqual({ type: 'color', value: '#176747' });
+});
+
+it.each([
+ ['missing alias', { a: { $type: 'color', $value: '{missing}' } }, /Unknown token/],
+ ['cycle', { a: { $type: 'color', $value: '{b}' }, b: { $type: 'color', $value: '{a}' } }, /cycle/i],
+ ['type mismatch', { a: { $type: 'color', $value: '#fff' }, b: { $type: 'dimension', $value: '{a}' } }, /type/i],
+])('rejects %s', (_name, tokens, error) => expect(() => resolveToken(tokens, 'a')).toThrow(error));
+```
+
+- [ ] **Step 2: Запустить тест и подтвердить RED**
+
+Run: `npm run test:design-system -- resolveToken.test.ts`
+
+Expected: FAIL, module/functions отсутствуют.
+
+- [ ] **Step 3: Реализовать schema и resolver**
+
+Resolver распознаёт только полную alias-строку `/^\{([^}]+)\}$/`, хранит visited path, проверяет
+существование target и равенство `$type`, возвращает `{ type, value }`. Смешанные строки вроде
+`calc({space.2} * 2)` запрещены.
+
+- [ ] **Step 4: Запустить тест и commit**
+
+Run: `npm run test:design-system -- resolveToken.test.ts`
+
+Expected: PASS.
+
+```bash
+git add packages/design-system/src/tokens
+git commit -m "feat(design-system): add token contracts"
+```
+
+### Task 3: Три уровня токенов
+
+**Files:**
+- Create: `packages/design-system/src/tokens/primitives.ts`
+- Create: `packages/design-system/src/tokens/semantic.light.ts`
+- Create: `packages/design-system/src/tokens/components.ts`
+- Create: `packages/design-system/src/tokens/index.ts`
+- Test: `packages/design-system/src/tokens/tokens.test.ts`
+
+- [ ] **Step 1: Написать token integrity tests**
+
+Тест объединяет три collections, резолвит каждый token, проверяет уникальные имена и инварианты:
+
+```ts
+expect(Object.keys(primitiveTokens).every((name) => !isAlias(primitiveTokens[name].$value))).toBe(true);
+expect(Object.keys(semanticLightTokens).every((name) => isAlias(semanticLightTokens[name].$value))).toBe(true);
+expect(Object.keys(componentTokens).every((name) => isAlias(componentTokens[name].$value))).toBe(true);
+for (const name of Object.keys(allTokens)) expect(() => resolveToken(allTokens, name)).not.toThrow();
+```
+
+- [ ] **Step 2: Запустить тест и подтвердить RED**
+
+Run: `npm run test:design-system -- tokens.test.ts`
+
+Expected: FAIL, collections отсутствуют.
+
+- [ ] **Step 3: Добавить минимальный полный набор foundations**
+
+Primitive groups: `color.neutral.{0,50,100,200,400,600,800,900}`, `color.green.{50,100,600,700,800}`,
+`color.red.{50,600,700}`, `color.amber.{50,600}`, `color.blue.{50,600}`, `space.{0,1,2,3,4,5,6,8,10,12}`
+на 4px grid, `radius.{none,sm,md,lg,pill}`, `font.family.{sans,mono}`, `font.size.{100..700}`,
+`font.weight.{regular,medium,semibold,bold}`, `lineHeight.{tight,normal,relaxed}`, `shadow.{none,sm,md}`,
+`duration.{instant,fast,normal}`, `easing.standard`, `size.control.{sm,md}`.
+
+`font.family.sans` использует Inter с system-ui fallback. Webfont weights 400/500/600/700 подключаются
+один раз во frontend shell в Task 10; Roboto не становится частью нового foundation.
+
+Semantic groups: `color.canvas`, `color.surface.{default,subtle,raised}`, `color.text.{primary,secondary,
+disabled,inverse}`, `color.border.{subtle,default,strong,focus}`, `color.action.{primary,primaryHover,
+secondary,danger}`, `color.feedback.{info,success,warning,error}`, `color.finance.{positive,negative,
+neutral}`, plus semantic typography, focus ring, spacing and control sizes.
+
+Component groups cover только API v1: button, iconButton, field, checkbox, surface, card, chip, badge,
+alert, dialog, skeleton, progress, table, metric и pageState.
+
+- [ ] **Step 4: Проверить GREEN и запрет hardcoded values вне primitives**
+
+Run: `npm run test:design-system -- tokens.test.ts`
+
+Expected: PASS. Дополнительный test scan подтверждает, что `semantic.light.ts` и `components.ts` не
+содержат hex/rgb/px literals.
+
+- [ ] **Step 5: Commit**
+
+```bash
+git add packages/design-system/src/tokens
+git commit -m "feat(design-system): define three-level tokens"
+```
+
+### Task 4: MUI adapter и provider (TDD)
+
+**Files:**
+- Create: `packages/design-system/src/theme/createMoexVibeTheme.ts`
+- Create: `packages/design-system/src/theme/MoexVibeThemeProvider.tsx`
+- Create: `packages/design-system/src/theme/mui.d.ts`
+- Create: `packages/design-system/src/theme/index.ts`
+- Test: `packages/design-system/src/theme/createMoexVibeTheme.test.ts`
+
+- [ ] **Step 1: Написать failing theme contract tests**
+
+```ts
+const theme = createMoexVibeTheme();
+expect(theme.cssVarPrefix).toBe('mv');
+expect(theme.colorSchemes.light.palette.primary.main).toBe(resolveValue('color.action.primary'));
+expect(theme.typography.body1.fontFamily).toContain('Inter');
+expect(theme.shape.borderRadius).toBe(resolveValue('radius.md'));
+expect(theme.components?.MuiButton?.defaultProps).toMatchObject({ disableElevation: true });
+```
+
+- [ ] **Step 2: Подтвердить RED**
+
+Run: `npm run test:design-system -- createMoexVibeTheme.test.ts`
+
+Expected: FAIL, factory отсутствует.
+
+- [ ] **Step 3: Реализовать adapter**
+
+Использовать `createTheme({ cssVariables: { cssVarPrefix: 'mv' }, colorSchemes: { light: ... } })`.
+Theme получает palette, typography, spacing, shape, shadows, transitions и component overrides только
+через `resolveValue`. `mui.d.ts` включает `themeCssVarsAugmentation` и добавляет `finance` palette roles.
+
+- [ ] **Step 4: Реализовать provider**
+
+`MoexVibeThemeProvider` оборачивает MUI `ThemeProvider` и `CssBaseline`, принимает только `children`;
+mode API в v1 не экспортируется.
+
+- [ ] **Step 5: Проверить и commit**
+
+Run: `npm run test:design-system -- createMoexVibeTheme.test.ts && npm run build:design-system`
+
+Expected: PASS.
+
+```bash
+git add packages/design-system/src/theme packages/design-system/src/tokens
+git commit -m "feat(design-system): add MUI theme adapter"
+```
+
+### Task 5: Storybook и automated story checks
+
+**Files:**
+- Create: `packages/design-system/.storybook/main.ts`
+- Create: `packages/design-system/.storybook/preview.tsx`
+- Create: `packages/design-system/.storybook/vitest.setup.ts`
+- Modify: `packages/design-system/vitest.config.ts`
+- Modify: `packages/design-system/package.json`
+
+- [ ] **Step 1: Настроить Storybook 10.2**
+
+```ts
+const config: StorybookConfig = {
+ framework: '@storybook/react-vite',
+ stories: ['../src/**/*.stories.@(ts|tsx)'],
+ addons: ['@storybook/addon-a11y', '@storybook/addon-vitest'],
+};
+```
+
+`preview.tsx` добавляет decorator `MoexVibeThemeProvider`, background `color.canvas` и параметры
+`a11y.test = 'error'`, layout `centered` по умолчанию.
+
+- [ ] **Step 2: Добавить Storybook Vitest browser project**
+
+Использовать `storybookTest`, `@vitest/browser-playwright` и headless Chromium; setup регистрирует
+`@storybook/addon-a11y/preview` и project annotations через `setProjectAnnotations`.
+
+- [ ] **Step 3: Проверить стенд**
+
+Run:
+
+```bash
+npx playwright install chromium
+npm run build:storybook
+```
+
+Expected: static Storybook build PASS. Первый `test:storybook` запускается после появления stories в
+Task 6.
+
+- [ ] **Step 4: Commit**
+
+```bash
+git add package.json package-lock.json packages/design-system
+git commit -m "build(design-system): configure Storybook workbench"
+```
+
+### Task 6: Typography и actions (TDD)
+
+**Files:**
+- Create: `packages/design-system/src/components/{Text,Heading,Link,Button,IconButton}/`
+- Test: colocated `*.test.tsx`
+- Stories: colocated `*.stories.tsx`
+
+- [ ] **Step 1: Написать failing interaction/type tests**
+
+Проверить semantic heading level, tone mapping, external link rel, loading button disabled state и
+progress label, обязательный accessible label IconButton. Type tests отклоняют `color`, произвольный
+`variant` и `sx`.
+
+- [ ] **Step 2: Подтвердить RED**
+
+Run: `npm run test:design-system -- Text Heading Link Button IconButton`
+
+Expected: FAIL, exports отсутствуют.
+
+- [ ] **Step 3: Реализовать компоненты по public contracts**
+
+Каждый каталог содержит component, props и index. `Button loading` сохраняет ширину, блокирует повторный
+click и имеет `aria-busy`; `IconButton` всегда устанавливает `aria-label={label}`.
+
+- [ ] **Step 4: Добавить stories и проверить GREEN**
+
+Stories: все variants/sizes/tones, disabled, loading, long Russian label, keyboard focus reference.
+
+Run: `npm run test:design-system && npm run test:storybook && npm run build:storybook`
+
+Expected: PASS без a11y violations.
+
+- [ ] **Step 5: Commit**
+
+```bash
+git add packages/design-system/src
+git commit -m "feat(design-system): add typography and actions"
+```
+
+### Task 7: Inputs, surfaces и feedback (TDD)
+
+**Files:**
+- Create: `packages/design-system/src/components/{TextField,Select,Checkbox,Surface,Card,Chip,Badge,Alert,Dialog,Skeleton,Progress}/`
+- Test/Stories: colocated `*.test.tsx`, `*.stories.tsx`
+
+- [ ] **Step 1: Написать failing contract tests**
+
+Проверить label/helper/error association, Select options и keyboard opening, Checkbox label click,
+Surface padding/elevation mapping, Dialog focus/escape/label, Alert role, determinate/indeterminate
+Progress accessible name и Skeleton `aria-hidden`.
+
+- [ ] **Step 2: Подтвердить RED**
+
+Run: `npm run test:design-system -- TextField Select Checkbox Surface Card Chip Badge Alert Dialog Skeleton Progress`
+
+Expected: FAIL, components отсутствуют.
+
+- [ ] **Step 3: Реализовать ограниченные wrappers**
+
+`Select` принимает `{ value: string; label: string; disabled?: boolean }[]`; `Checkbox` требует `label`;
+`Dialog` требует `title` и управляется через `open/onClose`; Surface/Card не принимают raw elevation.
+
+- [ ] **Step 4: Stories, GREEN и commit**
+
+Stories покрывают default/focus/disabled/error/loading, длинный русский текст и narrow viewport.
+
+Run: `npm run test:design-system && npm run test:storybook && npm run build:storybook`
+
+Expected: PASS.
+
+```bash
+git add packages/design-system/src
+git commit -m "feat(design-system): add controls and feedback"
+```
+
+### Task 8: Финансовые data patterns (TDD)
+
+**Files:**
+- Create: `packages/design-system/src/components/{DataTable,Metric,Money,PriceChange}/`
+- Test/Stories: colocated `*.test.tsx`, `*.stories.tsx`
+- Test: `packages/design-system/src/visual/financial-patterns.visual.test.ts`
+
+- [ ] **Step 1: Написать failing tests**
+
+Проверить table caption, semantic headers, sortable button `aria-sort`, balanced/compact density, loading
+и empty states; `Money` через `Intl.NumberFormat`; `PriceChange` знак, текстовое направление и не только
+цвет; `Metric` composition.
+
+- [ ] **Step 2: Подтвердить RED**
+
+Run: `npm run test:design-system -- DataTable Metric Money PriceChange`
+
+Expected: FAIL.
+
+- [ ] **Step 3: Реализовать patterns**
+
+`DataTable` принимает готовый TanStack `Table` и не владеет server pagination/sorting. Defaults:
+`density="balanced"`, locale `ru-RU`, currency `RUB`. Negative/positive output включает видимый знак и
+screen-reader label.
+
+- [ ] **Step 4: Stories, visual baselines и commit**
+
+Canonical screenshot cases: balanced table, compact table, positive/negative metrics, empty/loading.
+Browser test запускает portable stories через `composeStories`, затем делает
+`expect(page.getByTestId('visual-root')).toMatchScreenshot('.png')`; baselines коммитятся
+рядом с visual test. Обновление baseline допустимо только вместе с объяснением визуального изменения.
+
+Run: `npm run test:design-system && npm run test:storybook`
+
+Expected: interaction, a11y и screenshot checks PASS.
+
+```bash
+git add packages/design-system/src
+git commit -m "feat(design-system): add financial data patterns"
+```
+
+### Task 9: Form и page-state patterns (TDD)
+
+**Files:**
+- Create: `packages/design-system/src/components/{FormField,FilterBar,EmptyState,ErrorState,LoadingState}/`
+- Test/Stories: colocated `*.test.tsx`, `*.stories.tsx`
+
+- [ ] **Step 1: Написать failing tests**
+
+Проверить `htmlFor`/description/error association FormField, wrapping and action placement FilterBar,
+semantic heading/action для Empty/Error, `aria-live="polite"` LoadingState и reduced-motion rendering.
+
+- [ ] **Step 2: RED, implementation, GREEN**
+
+Run before: `npm run test:design-system -- FormField FilterBar EmptyState ErrorState LoadingState`
+
+Expected before: FAIL. Реализовать только layout/semantics без API/domain knowledge.
+
+Run after: `npm run test:design-system && npm run test:storybook`
+
+Expected after: PASS.
+
+- [ ] **Step 3: Commit**
+
+```bash
+git add packages/design-system/src
+git commit -m "feat(design-system): add form and page-state patterns"
+```
+
+### Task 10: Frontend integration и MUI boundary
+
+**Files:**
+- Modify: `apps/frontend/package.json`
+- Modify: `apps/frontend/tsconfig.json`
+- Modify: `apps/frontend/vite.config.ts`
+- Modify: `apps/frontend/src/app/providers/AppProviders.tsx`
+- Modify: `apps/frontend/.eslintrc.cjs`
+- Delete: `apps/frontend/src/app/styles/theme.ts`
+- Test: `apps/frontend/src/app/providers/AppProviders.test.tsx`
+
+- [ ] **Step 1: Написать failing provider test**
+
+Render `AppProviders`, assert generated `--mv-palette-primary-main` exists and Query/Session providers
+по-прежнему доступны. Test не проверяет редизайн страниц.
+
+- [ ] **Step 2: Подключить workspace package**
+
+Добавить dependency, `@fontsource/inter` и aliases к source для dev/test; заменить MUI
+ThemeProvider/CssBaseline на `MoexVibeThemeProvider`. Удалить старый локальный theme и импортировать
+Inter 400/500/600/700 в provider entry ровно один раз.
+
+- [ ] **Step 3: Зафиксировать ESLint allowlist**
+
+Во frontend запретить root import `@mui/material` и subpaths через `no-restricted-imports`; исключить
+только `@mui/material/Box`, `Stack`, `Grid`. Сам пакет design-system использует отдельный lint config.
+
+- [ ] **Step 4: Проверить отсутствие визуальной миграции**
+
+Run:
+
+```bash
+npm run test:frontend
+npm run lint -w apps/frontend
+npm run build:design-system
+npm run build:frontend
+```
+
+Expected: PASS; legacy `styles.css` и product component markup не изменены.
+
+- [ ] **Step 5: Commit**
+
+```bash
+git add apps/frontend packages/design-system package.json package-lock.json
+git commit -m "feat(frontend): connect design system foundation"
+```
+
+### Task 11: Docusaurus и ADR
+
+**Files:**
+- Create: `apps/docs/docs/design-system/{overview,foundations,tokens,components,patterns,accessibility,governance}.md`
+- Create: `apps/docs/docs/adr/ADR-016-design-system.md`
+- Create: `packages/design-system/CHANGELOG.md`
+- Modify: `apps/docs/sidebars.ts`
+- Modify: `apps/docs/docs/adr/index.md`
+- Modify: `apps/docs/docs/frontend/styling.md`
+
+- [ ] **Step 1: Написать канонические правила**
+
+Документы фиксируют light-only v1, balanced density, три token levels, MUI allowlist, каталог,
+component-card template, WCAG 2.2 AA и promotion/change process. Components page содержит матрицу
+«задача → компонент → не использовать» и полную карточку обязательного шаблона для каждого public
+export. `CHANGELOG.md` начинается с `0.1.0` и документирует public API foundation; governance описывает
+обязательную migration note для будущих breaking changes.
+
+- [ ] **Step 2: Добавить ADR-016**
+
+ADR содержит Context, варианты theme-only/hybrid/full-wrapper, решение hybrid, последствия, Storybook
+роль и будущие DTCG/Android adapters.
+
+- [ ] **Step 3: Обновить sidebar и проверить docs**
+
+Run: `npm run build:docs`
+
+Expected: PASS без broken links; новый раздел виден как отдельная категория «Дизайн-система».
+
+- [ ] **Step 4: Commit**
+
+```bash
+git add apps/docs packages/design-system/CHANGELOG.md
+git commit -m "docs(design-system): publish usage guidelines"
+```
+
+### Task 12: CI, visual checks и финальная верификация
+
+**Files:**
+- Modify: `.gitea/workflows/ci.yml`
+- Modify: `README.md`
+- Modify: `docs/features/design-system-foundation/tasks.md`
+
+- [ ] **Step 1: Добавить CI gates**
+
+После `npm ci` установить Chromium `npx playwright install --with-deps chromium`; добавить design-system
+unit/story tests, Storybook build, design-system build и docs build. Сохранять Storybook static build и
+visual diff через `actions/upload-artifact@v4` с `if: failure()`.
+
+- [ ] **Step 2: Обновить команды README**
+
+Добавить `npm run storybook`, `build:storybook`, `test:design-system`, `test:storybook`,
+`build:design-system` и пояснить, что Docusaurus — published docs, Storybook — engineering workbench.
+
+- [ ] **Step 3: Запустить полный DoD**
+
+```bash
+npm run format:check
+npm run lint
+npm run test:backend
+npm run test:frontend
+npm run test:design-system
+npm run test:storybook
+npm run build:backend
+npm run build:design-system
+npm run build:storybook
+npm run build:frontend
+npm run build:docs
+git diff --check
+git status --short
+```
+
+Expected: все команды PASS; status содержит только намеренные изменения до финального commit.
+
+- [ ] **Step 4: Обновить SDD tasks и запросить code review**
+
+Отметить выполненные checkbox в `tasks.md`, применить `superpowers:requesting-code-review`, исправить
+только подтверждённые scope issues и повторить полный DoD.
+
+- [ ] **Step 5: Final commit**
+
+```bash
+git add .gitea/workflows/ci.yml README.md docs/features/design-system-foundation
+git commit -m "ci(design-system): enforce foundation quality gates"
+```
diff --git a/docs/features/design-system-foundation/spec.md b/docs/features/design-system-foundation/spec.md
new file mode 100644
index 0000000..308f7e3
--- /dev/null
+++ b/docs/features/design-system-foundation/spec.md
@@ -0,0 +1,168 @@
+# Design System Foundation
+
+## Статус
+
+Approved — утверждена пользователем 2026-06-21.
+
+## Цель
+
+Создать внутреннюю дизайн-систему MoexVibe поверх MUI, которая задаёт единый визуальный язык,
+контролируемый набор UI-компонентов и правила их применения. Первая версия должна обслуживать web-
+приложение MoexVibe и сохранять нейтральную к платформе модель токенов для будущих адаптеров,
+включая Android.
+
+## Принципы
+
+- MUI является компонентным и accessibility-движком, но не определяет визуальную идентичность
+ MoexVibe.
+- Визуальное направление: спокойный нейтральный финансовый интерфейс со сбалансированной плотностью.
+- Текущие стили приложения не являются источником дизайн-решений. Их миграция выполняется после
+ foundation отдельными фичами.
+- Дизайн-система не содержит бизнес-логику, API-клиенты, маршрутизацию и доменные компоненты.
+- Docusaurus остаётся единственной опубликованной человекочитаемой документацией проекта.
+
+## Артефакты
+
+### Workspace-пакет
+
+В monorepo должен появиться внутренний пакет `@moex-vibe/design-system` со следующими границами:
+
+- platform-neutral токены без зависимостей от React и MUI;
+- MUI-адаптер, создающий тему и CSS variables из токенов;
+- Core UI и повторяемые product patterns;
+- стабильные subpath exports для токенов, темы и компонентов.
+
+Продуктовый frontend использует компоненты дизайн-системы. Прямые импорты MUI разрешены только для
+компоновки (`Box`, `Stack`, `Grid` и системные layout utilities). Интерактивные и визуально значимые
+компоненты должны поступать из `@moex-vibe/design-system`.
+
+### Storybook
+
+Storybook является локальным и CI-стендом дизайн-системы. Он показывает варианты, состояния,
+адаптивное поведение и accessibility-контракты компонентов, но не считается опубликованной
+документацией для пользователей проекта.
+
+### Docusaurus
+
+В `apps/docs` должен появиться раздел «Дизайн-система» со страницами:
+
+- обзор и принципы;
+- foundations: цвет, типографика, spacing, размеры, радиусы, elevation и motion;
+- модель токенов и правила их изменения;
+- каталог компонентов и product patterns;
+- accessibility;
+- contribution и governance.
+
+Каждая карточка компонента описывает: назначение и запреты, anatomy, разрешённые варианты, состояния,
+keyboard behavior, accessibility, content rules, responsive behavior, корректные примеры и
+антипаттерны.
+
+## Модель токенов
+
+Source of truth первой версии — типизированные TypeScript-объекты. Их схема и имена не должны
+зависеть от MUI, React или CSS. Формат должен оставаться JSON-совместимым, чтобы позднее добавить
+экспорт в DTCG/Android resources без изменения семантических имён.
+
+Токены состоят из трёх уровней с однонаправленными зависимостями:
+
+1. **Primitive/reference** — сырые палитры, шкалы spacing и размеров, типографика, радиусы, тени и
+ motion. Только на этом уровне допустимы абсолютные визуальные значения.
+2. **Semantic/system** — роли: canvas, surface, text, border, action, feedback и финансовая семантика
+ positive/negative/neutral. Будущая тёмная тема переопределяет этот уровень, не меняя компоненты.
+3. **Component** — устойчивые решения конкретных компонентов и вариантов. Они ссылаются на semantic
+ tokens и создаются только для повторяемых или тематизируемых решений, а не для каждого CSS-
+ свойства MUI.
+
+Приложение не должно использовать primitive tokens или произвольные визуальные значения напрямую.
+Цвет не может быть единственным способом сообщить финансовое состояние.
+
+## Тема и визуальные основы
+
+- Первая версия включает только светлую тему. API темы должен допускать добавление новых color schemes
+ без изменения API компонентов.
+- MUI theme использует CSS variables и получает palette, typography, spacing, shape, elevation, motion,
+ defaults, variants и style overrides из токенов.
+- Основная плотность интерфейса — сбалансированная. Компактный вариант допускается как явный вариант
+ data-heavy компонентов, но не как глобальный режим v1.
+- Все состояния focus-visible должны быть заметны; компоненты поддерживают keyboard navigation и
+ `prefers-reduced-motion` там, где используется анимация.
+- Целевой уровень доступности — WCAG 2.2 AA для применимых web-компонентов.
+
+## Компонентная модель
+
+### Core UI v1
+
+- Typography: `Text`, `Heading`, `Link`.
+- Actions: `Button`, `IconButton`.
+- Inputs: `TextField`, `Select`, `Checkbox`.
+- Surfaces and labels: `Surface`, `Card`, `Chip`, `Badge`.
+- Feedback: `Alert`, `Dialog`, `Skeleton`, `Progress`.
+
+Core UI ограничивает разрешённые variants и состояния MUI, сохраняет доступность и не содержит
+доменной логики.
+
+### Product patterns v1
+
+- Data display: `DataTable`, `Metric`, `Money`, `PriceChange`.
+- Forms and filtering: `FormField`, `FilterBar`.
+- Page states: `EmptyState`, `ErrorState`, `LoadingState`.
+
+Product pattern попадает в пакет, если он не знает бизнес-домен и имеет минимум два подтверждённых
+места использования. Исключение — базовые интерактивные Core UI primitives, необходимые для
+целостного API.
+
+Доменные компоненты, включая broker-, portfolio- и screener-specific композиции, остаются в
+соответствующих FSD-слоях frontend.
+
+## Governance
+
+- Изменение значения primitive token не должно молча менять смысл semantic token.
+- Новый token требует описания роли и проверки существующих эквивалентов.
+- Новый variant или компонент требует documented use case; API «на всякий случай» не добавляется.
+- Breaking changes внутреннего пакета фиксируются в changelog и миграционной заметке, даже пока пакет
+ не публикуется во внешний npm registry.
+- Архитектура пакета и граница прямого использования MUI фиксируются отдельным ADR.
+
+## Проверки качества
+
+- Unit-тесты проверяют token contracts, уникальность имён, допустимые ссылки и отсутствие циклов.
+- Type tests проверяют публичные exports и разрешённые component variants.
+- Interaction tests проверяют keyboard и пользовательские состояния интерактивных компонентов.
+- Storybook содержит stories для default, hover/focus reference, disabled, loading, error и responsive
+ состояний, когда они применимы.
+- Автоматические accessibility-проверки выполняются для stories и не допускают серьёзных нарушений.
+- Visual regression покрывает репрезентативные состояния Core UI и product patterns.
+- CI собирает workspace-пакет, Storybook, frontend и Docusaurus; затронутые lint и tests проходят.
+
+## Вне scope
+
+- Тёмная тема и UI-переключатель темы.
+- Android-адаптер, DTCG/JSON export и синхронизация с Figma.
+- Публикация пакета во внешний npm registry.
+- Backend-driven UI.
+- Массовая миграция существующих страниц и удаление legacy CSS.
+- Редизайн доменных экранов, графиков и визуализаций данных.
+
+## Последовательность внедрения
+
+1. Эта фича создаёт Design System Foundation и не переписывает продуктовые экраны.
+2. Отдельная фича мигрирует один репрезентативный pilot-экран и возвращает подтверждённые изменения в
+ tokens/component API.
+3. Остальные области мигрируются отдельными вертикальными срезами; legacy styles удаляются только
+ после миграции всех их потребителей.
+
+## Acceptance Criteria
+
+- [ ] `@moex-vibe/design-system` подключён как внутренний workspace-пакет с документированными public
+ exports.
+- [ ] Реализованы три уровня platform-neutral TypeScript tokens и автоматические проверки их
+ контрактов.
+- [ ] Light MUI theme полностью строится из токенов и предоставляет CSS variables.
+- [ ] Реализован и задокументирован каталог Core UI v1 и product patterns v1.
+- [ ] Прямое использование MUI ограничено documented allowlist для layout utilities.
+- [ ] Storybook локально запускается, собирается в CI и содержит обязательные состояния компонентов.
+- [ ] Accessibility и visual regression checks проходят для согласованного набора stories.
+- [ ] В Docusaurus опубликован полный раздел дизайн-системы и правила выбора компонентов.
+- [ ] Создан ADR о границах пакета, MUI-адаптере и будущих platform adapters.
+- [ ] Frontend, docs и design-system package проходят build, lint и tests.
+- [ ] Существующие продуктовые страницы визуально не мигрированы в рамках этой фичи.
diff --git a/docs/features/design-system-foundation/tasks.md b/docs/features/design-system-foundation/tasks.md
new file mode 100644
index 0000000..0fd3360
--- /dev/null
+++ b/docs/features/design-system-foundation/tasks.md
@@ -0,0 +1,68 @@
+# Design System Foundation — Tasks
+
+Исполнять по `plan.md` последовательно, используя TDD и отмечая checkbox только после успешной
+проверки соответствующего шага.
+
+## 1. Pre-flight и workspace
+
+- [ ] Подтвердить ветку, чистый worktree и зелёные baseline tests/lint/build.
+- [ ] Добавить `packages/design-system` в npm workspaces и root scripts.
+- [ ] Создать package manifest, TypeScript/Vitest/ESLint configs и test setup.
+- [ ] Установить зависимости; проверить пустой package build/test/lint.
+- [ ] Закоммитить workspace shell.
+
+## 2. Tokens
+
+- [ ] Написать RED-тесты alias resolver: chain, missing target, cycle, type mismatch.
+- [ ] Реализовать token schema и resolver; получить GREEN.
+- [ ] Написать RED-тесты целостности трёх token levels.
+- [ ] Добавить primitive/reference tokens.
+- [ ] Добавить light semantic tokens только через aliases.
+- [ ] Добавить component tokens только через semantic aliases.
+- [ ] Проверить guards, build и отсутствие hardcoded values вне primitives.
+- [ ] Закоммитить token foundation.
+
+## 3. MUI adapter и Storybook
+
+- [ ] Написать RED-тесты MUI theme contract.
+- [ ] Реализовать `createMoexVibeTheme`, type augmentation и provider; получить GREEN.
+- [ ] Настроить Storybook React/Vite с общим theme decorator.
+- [ ] Подключить addon-a11y и Vitest browser project с Playwright Chromium.
+- [ ] Проверить package и static Storybook build.
+- [ ] Закоммитить theme adapter и Storybook workbench.
+
+## 4. Core UI
+
+- [ ] Реализовать через TDD `Text`, `Heading`, `Link`, `Button`, `IconButton`.
+- [ ] Добавить их stories, type checks и a11y checks.
+- [ ] Реализовать через TDD `TextField`, `Select`, `Checkbox`.
+- [ ] Реализовать через TDD `Surface`, `Card`, `Chip`, `Badge`.
+- [ ] Реализовать через TDD `Alert`, `Dialog`, `Skeleton`, `Progress`.
+- [ ] Добавить обязательные states, responsive stories и visual baselines.
+- [ ] Проверить unit/story/a11y/build gates и закоммитить Core UI.
+
+## 5. Product patterns
+
+- [ ] Реализовать через TDD `DataTable`, включая caption, sorting semantics и density variants.
+- [ ] Реализовать через TDD `Metric`, `Money`, `PriceChange` без color-only semantics.
+- [ ] Добавить financial stories и стабильные screenshot baselines.
+- [ ] Реализовать через TDD `FormField` и `FilterBar`.
+- [ ] Реализовать через TDD `EmptyState`, `ErrorState`, `LoadingState`.
+- [ ] Проверить unit/story/a11y/visual gates и закоммитить patterns.
+
+## 6. Интеграция и governance
+
+- [ ] Написать RED-тест frontend provider integration.
+- [ ] Подключить workspace package и Inter во frontend shell; удалить локальную MUI theme.
+- [ ] Enforce ESLint allowlist для `Box`, `Stack`, `Grid`.
+- [ ] Подтвердить, что product pages и legacy CSS не мигрированы.
+- [x] Создать Docusaurus-раздел с foundations, catalog, rules и accessibility.
+- [x] Создать ADR-016 и changelog `0.1.0`.
+- [x] Обновить sidebar, styling docs и README; собрать docs.
+
+## 7. CI и завершение
+
+- [x] Добавить design-system, Storybook, Playwright, visual и docs gates в CI.
+- [x] Запустить полный DoD из Task 12 `plan.md`.
+- [ ] Запросить code review и устранить подтверждённые scope issues.
+- [ ] Повторить полный DoD, отметить все tasks и сделать финальный commit.
diff --git a/package-lock.json b/package-lock.json
index 2fbc649..b28608c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,7 +8,8 @@
"workspaces": [
"apps/backend",
"apps/frontend",
- "apps/docs"
+ "apps/docs",
+ "packages/design-system"
],
"devDependencies": {
"husky": "^9.1.7",
@@ -87,8 +88,9 @@
"dependencies": {
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.1",
- "@fontsource/roboto": "^5.2.10",
+ "@fontsource/inter": "^5.2.8",
"@hookform/resolvers": "^3.10.0",
+ "@moex-vibe/design-system": "*",
"@mui/icons-material": "^6.5.0",
"@mui/material": "^6.5.0",
"@tanstack/react-query": "^5.20.0",
@@ -131,420 +133,6 @@
"vitest": "^4.1.8"
}
},
- "apps/frontend/node_modules/@esbuild/aix-ppc64": {
- "version": "0.28.1",
- "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz",
- "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==",
- "cpu": [
- "ppc64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "aix"
- ],
- "peer": true,
- "engines": {
- "node": ">=18"
- }
- },
- "apps/frontend/node_modules/@esbuild/android-arm": {
- "version": "0.28.1",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz",
- "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==",
- "cpu": [
- "arm"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "android"
- ],
- "peer": true,
- "engines": {
- "node": ">=18"
- }
- },
- "apps/frontend/node_modules/@esbuild/android-arm64": {
- "version": "0.28.1",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz",
- "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "android"
- ],
- "peer": true,
- "engines": {
- "node": ">=18"
- }
- },
- "apps/frontend/node_modules/@esbuild/android-x64": {
- "version": "0.28.1",
- "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz",
- "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "android"
- ],
- "peer": true,
- "engines": {
- "node": ">=18"
- }
- },
- "apps/frontend/node_modules/@esbuild/darwin-arm64": {
- "version": "0.28.1",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz",
- "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "darwin"
- ],
- "peer": true,
- "engines": {
- "node": ">=18"
- }
- },
- "apps/frontend/node_modules/@esbuild/darwin-x64": {
- "version": "0.28.1",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz",
- "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "darwin"
- ],
- "peer": true,
- "engines": {
- "node": ">=18"
- }
- },
- "apps/frontend/node_modules/@esbuild/freebsd-arm64": {
- "version": "0.28.1",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz",
- "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "freebsd"
- ],
- "peer": true,
- "engines": {
- "node": ">=18"
- }
- },
- "apps/frontend/node_modules/@esbuild/freebsd-x64": {
- "version": "0.28.1",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz",
- "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "freebsd"
- ],
- "peer": true,
- "engines": {
- "node": ">=18"
- }
- },
- "apps/frontend/node_modules/@esbuild/linux-arm": {
- "version": "0.28.1",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz",
- "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==",
- "cpu": [
- "arm"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "peer": true,
- "engines": {
- "node": ">=18"
- }
- },
- "apps/frontend/node_modules/@esbuild/linux-arm64": {
- "version": "0.28.1",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz",
- "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "peer": true,
- "engines": {
- "node": ">=18"
- }
- },
- "apps/frontend/node_modules/@esbuild/linux-ia32": {
- "version": "0.28.1",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz",
- "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==",
- "cpu": [
- "ia32"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "peer": true,
- "engines": {
- "node": ">=18"
- }
- },
- "apps/frontend/node_modules/@esbuild/linux-loong64": {
- "version": "0.28.1",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz",
- "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==",
- "cpu": [
- "loong64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "peer": true,
- "engines": {
- "node": ">=18"
- }
- },
- "apps/frontend/node_modules/@esbuild/linux-mips64el": {
- "version": "0.28.1",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz",
- "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==",
- "cpu": [
- "mips64el"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "peer": true,
- "engines": {
- "node": ">=18"
- }
- },
- "apps/frontend/node_modules/@esbuild/linux-ppc64": {
- "version": "0.28.1",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz",
- "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==",
- "cpu": [
- "ppc64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "peer": true,
- "engines": {
- "node": ">=18"
- }
- },
- "apps/frontend/node_modules/@esbuild/linux-riscv64": {
- "version": "0.28.1",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz",
- "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==",
- "cpu": [
- "riscv64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "peer": true,
- "engines": {
- "node": ">=18"
- }
- },
- "apps/frontend/node_modules/@esbuild/linux-s390x": {
- "version": "0.28.1",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz",
- "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==",
- "cpu": [
- "s390x"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "peer": true,
- "engines": {
- "node": ">=18"
- }
- },
- "apps/frontend/node_modules/@esbuild/linux-x64": {
- "version": "0.28.1",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz",
- "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "linux"
- ],
- "peer": true,
- "engines": {
- "node": ">=18"
- }
- },
- "apps/frontend/node_modules/@esbuild/netbsd-x64": {
- "version": "0.28.1",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz",
- "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "netbsd"
- ],
- "peer": true,
- "engines": {
- "node": ">=18"
- }
- },
- "apps/frontend/node_modules/@esbuild/openbsd-x64": {
- "version": "0.28.1",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz",
- "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "openbsd"
- ],
- "peer": true,
- "engines": {
- "node": ">=18"
- }
- },
- "apps/frontend/node_modules/@esbuild/sunos-x64": {
- "version": "0.28.1",
- "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz",
- "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "sunos"
- ],
- "peer": true,
- "engines": {
- "node": ">=18"
- }
- },
- "apps/frontend/node_modules/@esbuild/win32-arm64": {
- "version": "0.28.1",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz",
- "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "win32"
- ],
- "peer": true,
- "engines": {
- "node": ">=18"
- }
- },
- "apps/frontend/node_modules/@esbuild/win32-ia32": {
- "version": "0.28.1",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz",
- "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==",
- "cpu": [
- "ia32"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "win32"
- ],
- "peer": true,
- "engines": {
- "node": ">=18"
- }
- },
- "apps/frontend/node_modules/@esbuild/win32-x64": {
- "version": "0.28.1",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz",
- "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "win32"
- ],
- "peer": true,
- "engines": {
- "node": ">=18"
- }
- },
"apps/frontend/node_modules/@hookform/resolvers": {
"version": "3.10.0",
"resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-3.10.0.tgz",
@@ -554,236 +142,6 @@
"react-hook-form": "^7.0.0"
}
},
- "apps/frontend/node_modules/@mui/core-downloads-tracker": {
- "version": "6.5.0",
- "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-6.5.0.tgz",
- "integrity": "sha512-LGb8t8i6M2ZtS3Drn3GbTI1DVhDY6FJ9crEey2lZ0aN2EMZo8IZBZj9wRf4vqbZHaWjsYgtbOnJw5V8UWbmK2Q==",
- "license": "MIT",
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/mui-org"
- }
- },
- "apps/frontend/node_modules/@mui/icons-material": {
- "version": "6.5.0",
- "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-6.5.0.tgz",
- "integrity": "sha512-VPuPqXqbBPlcVSA0BmnoE4knW4/xG6Thazo8vCLWkOKusko6DtwFV6B665MMWJ9j0KFohTIf3yx2zYtYacvG1g==",
- "license": "MIT",
- "dependencies": {
- "@babel/runtime": "^7.26.0"
- },
- "engines": {
- "node": ">=14.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/mui-org"
- },
- "peerDependencies": {
- "@mui/material": "^6.5.0",
- "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
- "react": "^17.0.0 || ^18.0.0 || ^19.0.0"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- }
- }
- },
- "apps/frontend/node_modules/@mui/material": {
- "version": "6.5.0",
- "resolved": "https://registry.npmjs.org/@mui/material/-/material-6.5.0.tgz",
- "integrity": "sha512-yjvtXoFcrPLGtgKRxFaH6OQPtcLPhkloC0BML6rBG5UeldR0nPULR/2E2BfXdo5JNV7j7lOzrrLX2Qf/iSidow==",
- "license": "MIT",
- "dependencies": {
- "@babel/runtime": "^7.26.0",
- "@mui/core-downloads-tracker": "^6.5.0",
- "@mui/system": "^6.5.0",
- "@mui/types": "~7.2.24",
- "@mui/utils": "^6.4.9",
- "@popperjs/core": "^2.11.8",
- "@types/react-transition-group": "^4.4.12",
- "clsx": "^2.1.1",
- "csstype": "^3.1.3",
- "prop-types": "^15.8.1",
- "react-is": "^19.0.0",
- "react-transition-group": "^4.4.5"
- },
- "engines": {
- "node": ">=14.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/mui-org"
- },
- "peerDependencies": {
- "@emotion/react": "^11.5.0",
- "@emotion/styled": "^11.3.0",
- "@mui/material-pigment-css": "^6.5.0",
- "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
- "react": "^17.0.0 || ^18.0.0 || ^19.0.0",
- "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
- },
- "peerDependenciesMeta": {
- "@emotion/react": {
- "optional": true
- },
- "@emotion/styled": {
- "optional": true
- },
- "@mui/material-pigment-css": {
- "optional": true
- },
- "@types/react": {
- "optional": true
- }
- }
- },
- "apps/frontend/node_modules/@mui/material/node_modules/@mui/system": {
- "version": "6.5.0",
- "resolved": "https://registry.npmjs.org/@mui/system/-/system-6.5.0.tgz",
- "integrity": "sha512-XcbBYxDS+h/lgsoGe78ExXFZXtuIlSBpn/KsZq8PtZcIkUNJInkuDqcLd2rVBQrDC1u+rvVovdaWPf2FHKJf3w==",
- "license": "MIT",
- "dependencies": {
- "@babel/runtime": "^7.26.0",
- "@mui/private-theming": "^6.4.9",
- "@mui/styled-engine": "^6.5.0",
- "@mui/types": "~7.2.24",
- "@mui/utils": "^6.4.9",
- "clsx": "^2.1.1",
- "csstype": "^3.1.3",
- "prop-types": "^15.8.1"
- },
- "engines": {
- "node": ">=14.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/mui-org"
- },
- "peerDependencies": {
- "@emotion/react": "^11.5.0",
- "@emotion/styled": "^11.3.0",
- "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
- "react": "^17.0.0 || ^18.0.0 || ^19.0.0"
- },
- "peerDependenciesMeta": {
- "@emotion/react": {
- "optional": true
- },
- "@emotion/styled": {
- "optional": true
- },
- "@types/react": {
- "optional": true
- }
- }
- },
- "apps/frontend/node_modules/@mui/material/node_modules/@mui/system/node_modules/@mui/private-theming": {
- "version": "6.4.9",
- "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-6.4.9.tgz",
- "integrity": "sha512-LktcVmI5X17/Q5SkwjCcdOLBzt1hXuc14jYa7NPShog0GBDCDvKtcnP0V7a2s6EiVRlv7BzbWEJzH6+l/zaCxw==",
- "license": "MIT",
- "dependencies": {
- "@babel/runtime": "^7.26.0",
- "@mui/utils": "^6.4.9",
- "prop-types": "^15.8.1"
- },
- "engines": {
- "node": ">=14.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/mui-org"
- },
- "peerDependencies": {
- "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
- "react": "^17.0.0 || ^18.0.0 || ^19.0.0"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- }
- }
- },
- "apps/frontend/node_modules/@mui/material/node_modules/@mui/system/node_modules/@mui/styled-engine": {
- "version": "6.5.0",
- "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-6.5.0.tgz",
- "integrity": "sha512-8woC2zAqF4qUDSPIBZ8v3sakj+WgweolpyM/FXf8jAx6FMls+IE4Y8VDZc+zS805J7PRz31vz73n2SovKGaYgw==",
- "license": "MIT",
- "dependencies": {
- "@babel/runtime": "^7.26.0",
- "@emotion/cache": "^11.13.5",
- "@emotion/serialize": "^1.3.3",
- "@emotion/sheet": "^1.4.0",
- "csstype": "^3.1.3",
- "prop-types": "^15.8.1"
- },
- "engines": {
- "node": ">=14.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/mui-org"
- },
- "peerDependencies": {
- "@emotion/react": "^11.4.1",
- "@emotion/styled": "^11.3.0",
- "react": "^17.0.0 || ^18.0.0 || ^19.0.0"
- },
- "peerDependenciesMeta": {
- "@emotion/react": {
- "optional": true
- },
- "@emotion/styled": {
- "optional": true
- }
- }
- },
- "apps/frontend/node_modules/@mui/material/node_modules/@mui/types": {
- "version": "7.2.24",
- "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.24.tgz",
- "integrity": "sha512-3c8tRt/CbWZ+pEg7QpSwbdxOk36EfmhbKf6AGZsD1EcLDLTSZoxxJ86FVtcjxvjuhdyBiWKSTGZFaXCnidO2kw==",
- "license": "MIT",
- "peerDependencies": {
- "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- }
- }
- },
- "apps/frontend/node_modules/@mui/material/node_modules/@mui/utils": {
- "version": "6.4.9",
- "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-6.4.9.tgz",
- "integrity": "sha512-Y12Q9hbK9g+ZY0T3Rxrx9m2m10gaphDuUMgWxyV5kNJevVxXYCLclYUCC9vXaIk1/NdNDTcW2Yfr2OGvNFNmHg==",
- "license": "MIT",
- "dependencies": {
- "@babel/runtime": "^7.26.0",
- "@mui/types": "~7.2.24",
- "@types/prop-types": "^15.7.14",
- "clsx": "^2.1.1",
- "prop-types": "^15.8.1",
- "react-is": "^19.0.0"
- },
- "engines": {
- "node": ">=14.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/mui-org"
- },
- "peerDependencies": {
- "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
- "react": "^17.0.0 || ^18.0.0 || ^19.0.0"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- }
- }
- },
"apps/frontend/node_modules/@types/node": {
"version": "25.9.3",
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.3.tgz",
@@ -884,50 +242,6 @@
"dev": true,
"license": "MIT"
},
- "apps/frontend/node_modules/esbuild": {
- "version": "0.28.1",
- "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz",
- "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==",
- "dev": true,
- "hasInstallScript": true,
- "license": "MIT",
- "optional": true,
- "peer": true,
- "bin": {
- "esbuild": "bin/esbuild"
- },
- "engines": {
- "node": ">=18"
- },
- "optionalDependencies": {
- "@esbuild/aix-ppc64": "0.28.1",
- "@esbuild/android-arm": "0.28.1",
- "@esbuild/android-arm64": "0.28.1",
- "@esbuild/android-x64": "0.28.1",
- "@esbuild/darwin-arm64": "0.28.1",
- "@esbuild/darwin-x64": "0.28.1",
- "@esbuild/freebsd-arm64": "0.28.1",
- "@esbuild/freebsd-x64": "0.28.1",
- "@esbuild/linux-arm": "0.28.1",
- "@esbuild/linux-arm64": "0.28.1",
- "@esbuild/linux-ia32": "0.28.1",
- "@esbuild/linux-loong64": "0.28.1",
- "@esbuild/linux-mips64el": "0.28.1",
- "@esbuild/linux-ppc64": "0.28.1",
- "@esbuild/linux-riscv64": "0.28.1",
- "@esbuild/linux-s390x": "0.28.1",
- "@esbuild/linux-x64": "0.28.1",
- "@esbuild/netbsd-arm64": "0.28.1",
- "@esbuild/netbsd-x64": "0.28.1",
- "@esbuild/openbsd-arm64": "0.28.1",
- "@esbuild/openbsd-x64": "0.28.1",
- "@esbuild/openharmony-arm64": "0.28.1",
- "@esbuild/sunos-x64": "0.28.1",
- "@esbuild/win32-arm64": "0.28.1",
- "@esbuild/win32-ia32": "0.28.1",
- "@esbuild/win32-x64": "0.28.1"
- }
- },
"apps/frontend/node_modules/eslint-import-resolver-typescript": {
"version": "4.4.5",
"resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-4.4.5.tgz",
@@ -1005,12 +319,6 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
- "apps/frontend/node_modules/react-is": {
- "version": "19.2.7",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.7.tgz",
- "integrity": "sha512-kZFnouyVv7eP/Phmrlo9FK+zcAdriZJvzxXHF1Sl1P377WSGe2G/JxVolhTrB/jeV47lKImhNUsijjHAAbcl/A==",
- "license": "MIT"
- },
"apps/frontend/node_modules/std-env": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/std-env/-/std-env-4.1.0.tgz",
@@ -1220,24 +528,6 @@
}
}
},
- "apps/frontend/node_modules/yaml": {
- "version": "2.9.0",
- "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz",
- "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==",
- "dev": true,
- "license": "ISC",
- "optional": true,
- "peer": true,
- "bin": {
- "yaml": "bin.mjs"
- },
- "engines": {
- "node": ">= 14.6"
- },
- "funding": {
- "url": "https://github.com/sponsors/eemeli"
- }
- },
"node_modules/@adobe/css-tools": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.5.0.tgz",
@@ -3622,6 +2912,13 @@
"node": ">=6.9.0"
}
},
+ "node_modules/@blazediff/core": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/@blazediff/core/-/core-1.9.1.tgz",
+ "integrity": "sha512-ehg3jIkYKulZh+8om/O25vkvSsXXwC+skXmyA87FFx6A/45eqOkZsBltMw/TVteb0mloiGT8oGRTcjRAz66zaA==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@borewit/text-codec": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/@borewit/text-codec/-/text-codec-0.2.2.tgz",
@@ -6593,24 +5890,6 @@
"node": ">=12"
}
},
- "node_modules/@esbuild/netbsd-arm64": {
- "version": "0.28.1",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz",
- "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "netbsd"
- ],
- "peer": true,
- "engines": {
- "node": ">=18"
- }
- },
"node_modules/@esbuild/netbsd-x64": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz",
@@ -6628,24 +5907,6 @@
"node": ">=12"
}
},
- "node_modules/@esbuild/openbsd-arm64": {
- "version": "0.28.1",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz",
- "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "openbsd"
- ],
- "peer": true,
- "engines": {
- "node": ">=18"
- }
- },
"node_modules/@esbuild/openbsd-x64": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz",
@@ -6663,24 +5924,6 @@
"node": ">=12"
}
},
- "node_modules/@esbuild/openharmony-arm64": {
- "version": "0.28.1",
- "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz",
- "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "license": "MIT",
- "optional": true,
- "os": [
- "openharmony"
- ],
- "peer": true,
- "engines": {
- "node": ">=18"
- }
- },
"node_modules/@esbuild/sunos-x64": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz",
@@ -6878,10 +6121,10 @@
}
}
},
- "node_modules/@fontsource/roboto": {
- "version": "5.2.10",
- "resolved": "https://registry.npmjs.org/@fontsource/roboto/-/roboto-5.2.10.tgz",
- "integrity": "sha512-8HlA5FtSfz//oFSr2eL7GFXAiE7eIkcGOtx7tjsLKq+as702x9+GU7K95iDeWFapHC4M2hv9RrpXKRTGGBI8Zg==",
+ "node_modules/@fontsource/inter": {
+ "version": "5.2.8",
+ "resolved": "https://registry.npmjs.org/@fontsource/inter/-/inter-5.2.8.tgz",
+ "integrity": "sha512-P6r5WnJoKiNVV+zvW2xM13gNdFhAEpQ9dQJHt3naLvfg+LkF2ldgSLiF4T41lf1SQCM9QmkqPTn4TH568IRagg==",
"license": "OFL-1.1",
"funding": {
"url": "https://github.com/sponsors/ayuhito"
@@ -7287,6 +6530,110 @@
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
+ "node_modules/@joshwooding/vite-plugin-react-docgen-typescript": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/@joshwooding/vite-plugin-react-docgen-typescript/-/vite-plugin-react-docgen-typescript-0.7.0.tgz",
+ "integrity": "sha512-qvsTEwEFefhdirGOPnu9Wp6ChfIwy2dBCRuETU3uE+4cC+PFoxMSiiEhxk4lOluA34eARHA0OxqsEUYDqRMgeQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "glob": "^13.0.1",
+ "react-docgen-typescript": "^2.2.2"
+ },
+ "peerDependencies": {
+ "typescript": ">= 4.3.x",
+ "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@joshwooding/vite-plugin-react-docgen-typescript/node_modules/balanced-match": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
+ "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "18 || 20 || >=22"
+ }
+ },
+ "node_modules/@joshwooding/vite-plugin-react-docgen-typescript/node_modules/brace-expansion": {
+ "version": "5.0.6",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz",
+ "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^4.0.2"
+ },
+ "engines": {
+ "node": "18 || 20 || >=22"
+ }
+ },
+ "node_modules/@joshwooding/vite-plugin-react-docgen-typescript/node_modules/glob": {
+ "version": "13.0.6",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz",
+ "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "minimatch": "^10.2.2",
+ "minipass": "^7.1.3",
+ "path-scurry": "^2.0.2"
+ },
+ "engines": {
+ "node": "18 || 20 || >=22"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/@joshwooding/vite-plugin-react-docgen-typescript/node_modules/lru-cache": {
+ "version": "11.5.1",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz",
+ "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": "20 || >=22"
+ }
+ },
+ "node_modules/@joshwooding/vite-plugin-react-docgen-typescript/node_modules/minimatch": {
+ "version": "10.2.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz",
+ "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "brace-expansion": "^5.0.5"
+ },
+ "engines": {
+ "node": "18 || 20 || >=22"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/@joshwooding/vite-plugin-react-docgen-typescript/node_modules/path-scurry": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz",
+ "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "lru-cache": "^11.0.0",
+ "minipass": "^7.1.2"
+ },
+ "engines": {
+ "node": "18 || 20 || >=22"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
"node_modules/@jridgewell/gen-mapping": {
"version": "0.3.13",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
@@ -7640,6 +6987,10 @@
"resolved": "apps/backend",
"link": true
},
+ "node_modules/@moex-vibe/design-system": {
+ "resolved": "packages/design-system",
+ "link": true
+ },
"node_modules/@moex-vibe/docs": {
"resolved": "apps/docs",
"link": true
@@ -7673,6 +7024,248 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@mui/core-downloads-tracker": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-6.5.0.tgz",
+ "integrity": "sha512-LGb8t8i6M2ZtS3Drn3GbTI1DVhDY6FJ9crEey2lZ0aN2EMZo8IZBZj9wRf4vqbZHaWjsYgtbOnJw5V8UWbmK2Q==",
+ "license": "MIT",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui-org"
+ }
+ },
+ "node_modules/@mui/icons-material": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-6.5.0.tgz",
+ "integrity": "sha512-VPuPqXqbBPlcVSA0BmnoE4knW4/xG6Thazo8vCLWkOKusko6DtwFV6B665MMWJ9j0KFohTIf3yx2zYtYacvG1g==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.26.0"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui-org"
+ },
+ "peerDependencies": {
+ "@mui/material": "^6.5.0",
+ "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react": "^17.0.0 || ^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@mui/material": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@mui/material/-/material-6.5.0.tgz",
+ "integrity": "sha512-yjvtXoFcrPLGtgKRxFaH6OQPtcLPhkloC0BML6rBG5UeldR0nPULR/2E2BfXdo5JNV7j7lOzrrLX2Qf/iSidow==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.26.0",
+ "@mui/core-downloads-tracker": "^6.5.0",
+ "@mui/system": "^6.5.0",
+ "@mui/types": "~7.2.24",
+ "@mui/utils": "^6.4.9",
+ "@popperjs/core": "^2.11.8",
+ "@types/react-transition-group": "^4.4.12",
+ "clsx": "^2.1.1",
+ "csstype": "^3.1.3",
+ "prop-types": "^15.8.1",
+ "react-is": "^19.0.0",
+ "react-transition-group": "^4.4.5"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui-org"
+ },
+ "peerDependencies": {
+ "@emotion/react": "^11.5.0",
+ "@emotion/styled": "^11.3.0",
+ "@mui/material-pigment-css": "^6.5.0",
+ "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react": "^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@emotion/react": {
+ "optional": true
+ },
+ "@emotion/styled": {
+ "optional": true
+ },
+ "@mui/material-pigment-css": {
+ "optional": true
+ },
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@mui/material/node_modules/react-is": {
+ "version": "19.2.7",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.7.tgz",
+ "integrity": "sha512-kZFnouyVv7eP/Phmrlo9FK+zcAdriZJvzxXHF1Sl1P377WSGe2G/JxVolhTrB/jeV47lKImhNUsijjHAAbcl/A==",
+ "license": "MIT"
+ },
+ "node_modules/@mui/private-theming": {
+ "version": "6.4.9",
+ "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-6.4.9.tgz",
+ "integrity": "sha512-LktcVmI5X17/Q5SkwjCcdOLBzt1hXuc14jYa7NPShog0GBDCDvKtcnP0V7a2s6EiVRlv7BzbWEJzH6+l/zaCxw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.26.0",
+ "@mui/utils": "^6.4.9",
+ "prop-types": "^15.8.1"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui-org"
+ },
+ "peerDependencies": {
+ "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react": "^17.0.0 || ^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@mui/styled-engine": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-6.5.0.tgz",
+ "integrity": "sha512-8woC2zAqF4qUDSPIBZ8v3sakj+WgweolpyM/FXf8jAx6FMls+IE4Y8VDZc+zS805J7PRz31vz73n2SovKGaYgw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.26.0",
+ "@emotion/cache": "^11.13.5",
+ "@emotion/serialize": "^1.3.3",
+ "@emotion/sheet": "^1.4.0",
+ "csstype": "^3.1.3",
+ "prop-types": "^15.8.1"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui-org"
+ },
+ "peerDependencies": {
+ "@emotion/react": "^11.4.1",
+ "@emotion/styled": "^11.3.0",
+ "react": "^17.0.0 || ^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@emotion/react": {
+ "optional": true
+ },
+ "@emotion/styled": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@mui/system": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@mui/system/-/system-6.5.0.tgz",
+ "integrity": "sha512-XcbBYxDS+h/lgsoGe78ExXFZXtuIlSBpn/KsZq8PtZcIkUNJInkuDqcLd2rVBQrDC1u+rvVovdaWPf2FHKJf3w==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.26.0",
+ "@mui/private-theming": "^6.4.9",
+ "@mui/styled-engine": "^6.5.0",
+ "@mui/types": "~7.2.24",
+ "@mui/utils": "^6.4.9",
+ "clsx": "^2.1.1",
+ "csstype": "^3.1.3",
+ "prop-types": "^15.8.1"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui-org"
+ },
+ "peerDependencies": {
+ "@emotion/react": "^11.5.0",
+ "@emotion/styled": "^11.3.0",
+ "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react": "^17.0.0 || ^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@emotion/react": {
+ "optional": true
+ },
+ "@emotion/styled": {
+ "optional": true
+ },
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@mui/types": {
+ "version": "7.2.24",
+ "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.24.tgz",
+ "integrity": "sha512-3c8tRt/CbWZ+pEg7QpSwbdxOk36EfmhbKf6AGZsD1EcLDLTSZoxxJ86FVtcjxvjuhdyBiWKSTGZFaXCnidO2kw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@mui/utils": {
+ "version": "6.4.9",
+ "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-6.4.9.tgz",
+ "integrity": "sha512-Y12Q9hbK9g+ZY0T3Rxrx9m2m10gaphDuUMgWxyV5kNJevVxXYCLclYUCC9vXaIk1/NdNDTcW2Yfr2OGvNFNmHg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.26.0",
+ "@mui/types": "~7.2.24",
+ "@types/prop-types": "^15.7.14",
+ "clsx": "^2.1.1",
+ "prop-types": "^15.8.1",
+ "react-is": "^19.0.0"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mui-org"
+ },
+ "peerDependencies": {
+ "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react": "^17.0.0 || ^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@mui/utils/node_modules/react-is": {
+ "version": "19.2.7",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.7.tgz",
+ "integrity": "sha512-kZFnouyVv7eP/Phmrlo9FK+zcAdriZJvzxXHF1Sl1P377WSGe2G/JxVolhTrB/jeV47lKImhNUsijjHAAbcl/A==",
+ "license": "MIT"
+ },
"node_modules/@napi-rs/wasm-runtime": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.5.tgz",
@@ -8284,6 +7877,371 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@oxc-parser/binding-android-arm-eabi": {
+ "version": "0.127.0",
+ "resolved": "https://registry.npmjs.org/@oxc-parser/binding-android-arm-eabi/-/binding-android-arm-eabi-0.127.0.tgz",
+ "integrity": "sha512-0LC7ye4hvqbIKxAzThzvswgHLFu2AURKzYLeSVvLdu2TBOYWQDmHnTqPLeA597BcUCxiLqLsS4CJ5uoI5WYWCQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@oxc-parser/binding-android-arm64": {
+ "version": "0.127.0",
+ "resolved": "https://registry.npmjs.org/@oxc-parser/binding-android-arm64/-/binding-android-arm64-0.127.0.tgz",
+ "integrity": "sha512-b5jtVTH6AU5CJXHNdj7Jj9IEiR9yVjjnwHzPJhGyHGPdcsZSzBCkS9GBbV33niRMvKthDwQRFRJfI4a+k4PvYg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@oxc-parser/binding-darwin-arm64": {
+ "version": "0.127.0",
+ "resolved": "https://registry.npmjs.org/@oxc-parser/binding-darwin-arm64/-/binding-darwin-arm64-0.127.0.tgz",
+ "integrity": "sha512-obCE8B7ISKkJidjlhv9xRGJPOSDG2Yu6PRga9Ruaz35uintHxbp1Ki/Yc71wx4rj3Edrm0a1kzG1TAwit0wFpg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@oxc-parser/binding-darwin-x64": {
+ "version": "0.127.0",
+ "resolved": "https://registry.npmjs.org/@oxc-parser/binding-darwin-x64/-/binding-darwin-x64-0.127.0.tgz",
+ "integrity": "sha512-JL6Xb5IwPQT8rUzlpsX7E+AgfcdNklXNPFp8pjCQQ5MQOQo5rtEB2ui+3Hgg9Sn7Y9Egj6YOLLiHhLpdAe12Aw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@oxc-parser/binding-freebsd-x64": {
+ "version": "0.127.0",
+ "resolved": "https://registry.npmjs.org/@oxc-parser/binding-freebsd-x64/-/binding-freebsd-x64-0.127.0.tgz",
+ "integrity": "sha512-SDQ/3MQFw58fqQz3Z1PhSKFF3JoCF4gmlNjziDm8X02tTahCw0qJbd7FGPDKw1i4VTBZene9JPyC3mHtSvi+wA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@oxc-parser/binding-linux-arm-gnueabihf": {
+ "version": "0.127.0",
+ "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.127.0.tgz",
+ "integrity": "sha512-Av+D1MIqzV0YMGPT9we2SIZaMKD7Cxs4CvXSx/yxaWHewZjYEjScpOf5igc8IILASViw4WTnjlwUdI1KzVtDHQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@oxc-parser/binding-linux-arm-musleabihf": {
+ "version": "0.127.0",
+ "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.127.0.tgz",
+ "integrity": "sha512-Cs2fdJ8cPpFdeebj6p4dag8A4+56hPvZ0AhQQzlaLswGz1tz7bXt1nETLeorrM9+AMcWFFkqxcXwDGfTVidY8g==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@oxc-parser/binding-linux-arm64-gnu": {
+ "version": "0.127.0",
+ "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.127.0.tgz",
+ "integrity": "sha512-qdOfTcT6SY8gsJrrV92uyEUyjqMGPpIB5JZUG6QN5dukYd+7/j0kX6MwK1DgQj39jtUYixxPiaRUiEN1+0CXgQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@oxc-parser/binding-linux-arm64-musl": {
+ "version": "0.127.0",
+ "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.127.0.tgz",
+ "integrity": "sha512-EoTCZneNFU/P2qrpEM+RHmQwt+CvDkyGESG6qhr7KaegXLZwePfbrkCDfAk8/rhxbDUVGsZILX+2tqPzFtoFWA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@oxc-parser/binding-linux-ppc64-gnu": {
+ "version": "0.127.0",
+ "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-0.127.0.tgz",
+ "integrity": "sha512-zALjmZYgxFLHjXeudcDF0xFGNydTAtkAeXAr2EuC17ywCyFxcmQra4w0BMde0Yi/re4Bi4iwEoEXtYN7l6eBLQ==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@oxc-parser/binding-linux-riscv64-gnu": {
+ "version": "0.127.0",
+ "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.127.0.tgz",
+ "integrity": "sha512-fPP8M6zQLS7Jz7o9d5ArUSuAuSK3e+WCYVrCpdzeCOejidtZExJ9tjhDrAd3HEPqARBCPmdpqxESPFqy44vkBQ==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@oxc-parser/binding-linux-riscv64-musl": {
+ "version": "0.127.0",
+ "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-0.127.0.tgz",
+ "integrity": "sha512-7IcC4Ao02oGpfnjt+X/oF4U2mllo2qoSkw5xxiXNKL9MCTsTiAC6616beOuehdxGcnz1bRoPC1RQ2f1GQDdN+g==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@oxc-parser/binding-linux-s390x-gnu": {
+ "version": "0.127.0",
+ "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.127.0.tgz",
+ "integrity": "sha512-pbXIhiNFHoqWeqDNLiJ9JkpHz1IM9k4DXa66x+1GTWMG7iLxtkXgE53iiuKSXwmk3zIYmaPVfBvgcAhS583K4Q==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@oxc-parser/binding-linux-x64-gnu": {
+ "version": "0.127.0",
+ "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.127.0.tgz",
+ "integrity": "sha512-MYCguB9RvBvlSd6gbuNI7QwiLoCCAlGnlRJFPrzLI6U1/9wkC/WK6LtBAUln55H1Ctqw45PWmqrobKoMhsYQzQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@oxc-parser/binding-linux-x64-musl": {
+ "version": "0.127.0",
+ "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-x64-musl/-/binding-linux-x64-musl-0.127.0.tgz",
+ "integrity": "sha512-5eY0B/bxf1xIUxb4NOTvOI3KWtBQfPWYyKAzgcrCt0mDibSZygVpO1Pz8bkeiSZ5Jj9+M09dkggG3H8I5d0Uyg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@oxc-parser/binding-openharmony-arm64": {
+ "version": "0.127.0",
+ "resolved": "https://registry.npmjs.org/@oxc-parser/binding-openharmony-arm64/-/binding-openharmony-arm64-0.127.0.tgz",
+ "integrity": "sha512-Gld0ajrFTUXNtdw20fVBuTQx66FA75nIVg+//pPfR3sXkuABB4mTBhl3r9JNzrJpgW//qiwxf0nWXUWGJSL3UQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openharmony"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@oxc-parser/binding-wasm32-wasi": {
+ "version": "0.127.0",
+ "resolved": "https://registry.npmjs.org/@oxc-parser/binding-wasm32-wasi/-/binding-wasm32-wasi-0.127.0.tgz",
+ "integrity": "sha512-T6KVD7rhLzFlwGRXMnxUFfkCZD8FHnb968wVXW1mXzgRFc5RNXOBY2mPPDZ77x5Ln76ltLMgtPg0cOkU1NSrEQ==",
+ "cpu": [
+ "wasm32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/core": "1.9.2",
+ "@emnapi/runtime": "1.9.2",
+ "@napi-rs/wasm-runtime": "^1.1.4"
+ },
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@oxc-parser/binding-wasm32-wasi/node_modules/@emnapi/core": {
+ "version": "1.9.2",
+ "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.2.tgz",
+ "integrity": "sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/wasi-threads": "1.2.1",
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@oxc-parser/binding-wasm32-wasi/node_modules/@emnapi/runtime": {
+ "version": "1.9.2",
+ "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.2.tgz",
+ "integrity": "sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@oxc-parser/binding-win32-arm64-msvc": {
+ "version": "0.127.0",
+ "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.127.0.tgz",
+ "integrity": "sha512-Ujvw4X+LD1CCGULcsQcvb4YNVoBGqt+JHgNNzGGaCImELiZLk477ifUH53gIbE7EKd933NdTi25JWEr9K2HwXw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@oxc-parser/binding-win32-ia32-msvc": {
+ "version": "0.127.0",
+ "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-0.127.0.tgz",
+ "integrity": "sha512-0cwxKO7KHQQQfo4Uf4B2SQrhgm+cJaP9OvFFhx52Tkg4bezsacu83GB2/In5bC415Ueeym+kXdnge/57rbSfTw==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@oxc-parser/binding-win32-x64-msvc": {
+ "version": "0.127.0",
+ "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.127.0.tgz",
+ "integrity": "sha512-rOrnSQSCbhI2kowr9XxE7m9a8oQXnBHjnS6j95LxxAnEZ0+Fz20WlRXG4ondQb+ejjt2KOsa65sE6++L6kUd+w==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
"node_modules/@oxc-project/types": {
"version": "0.133.0",
"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.133.0.tgz",
@@ -8294,6 +8252,311 @@
"url": "https://github.com/sponsors/Boshen"
}
},
+ "node_modules/@oxc-resolver/binding-android-arm-eabi": {
+ "version": "11.21.3",
+ "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-android-arm-eabi/-/binding-android-arm-eabi-11.21.3.tgz",
+ "integrity": "sha512-eNU11A2WNizh04v3uyaJCootrHIaS0B9aHYXvAvVnPNk4xYSjMUjHnhQ6dewPN2MRYDskV85d1N0Aw0WNWhcyg==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@oxc-resolver/binding-android-arm64": {
+ "version": "11.21.3",
+ "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-android-arm64/-/binding-android-arm64-11.21.3.tgz",
+ "integrity": "sha512-8Q+ZjTLvn2dIcWsrmhdrEihm7q+ag/k+mkry7Z+t0QbbHaVxXQfvH9AewyVMh/WrpEKhQ3DDgx9fYbqeCpeOEw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@oxc-resolver/binding-darwin-arm64": {
+ "version": "11.21.3",
+ "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-darwin-arm64/-/binding-darwin-arm64-11.21.3.tgz",
+ "integrity": "sha512-wkh0qKZGHXVUDxFw3oA1TXnU2BDYY/r775oJflGeIr8uDPPoN2pk8gijQIzYRT6hoql/lg3+Tx/SaTn9e2/aGg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@oxc-resolver/binding-darwin-x64": {
+ "version": "11.21.3",
+ "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-darwin-x64/-/binding-darwin-x64-11.21.3.tgz",
+ "integrity": "sha512-HbNc23FAQYbuyDV2vBWMez4u4mrsm5RAkniGZAWqr6lYZ3N4beeqIb776jzwRl8qL2zRhHVXpUj97X0QgogVzg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@oxc-resolver/binding-freebsd-x64": {
+ "version": "11.21.3",
+ "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-freebsd-x64/-/binding-freebsd-x64-11.21.3.tgz",
+ "integrity": "sha512-K6xNsTUPEUdfrn0+kbMq5nOUB5w1C5pavPQngt4TM2FpN91lP0PBe2srSpamb4d69O7h86oAi/qWX/kZNRSjkw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/@oxc-resolver/binding-linux-arm-gnueabihf": {
+ "version": "11.21.3",
+ "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-11.21.3.tgz",
+ "integrity": "sha512-VcFmOpcpWX1zoEy8M58tR2M9YxM+Z9RuQhqAx5q0CTmrruaP7Gveejg75hzd/5sg5nk9G3aLALEa3hE2FsmmTQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@oxc-resolver/binding-linux-arm-musleabihf": {
+ "version": "11.21.3",
+ "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-11.21.3.tgz",
+ "integrity": "sha512-quVoxFLBy43hWaQbbDtQNRwAX5vX76mv7n64icAtQcJ3eNgVeblqmkupF/hAneNthdqSlnd1sTjb3aQSaDPaCQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@oxc-resolver/binding-linux-arm64-gnu": {
+ "version": "11.21.3",
+ "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-11.21.3.tgz",
+ "integrity": "sha512-X0AqNZgcD07Q4V3RDK18/vYOj/HQT/FnmEFGYS2jTWqY7JO13ryE3TEs3eAIgUJhBnNkpEaiXqz3VK8M7qQhWQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@oxc-resolver/binding-linux-arm64-musl": {
+ "version": "11.21.3",
+ "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-arm64-musl/-/binding-linux-arm64-musl-11.21.3.tgz",
+ "integrity": "sha512-YkaQnaKYdbuaXvRt5Qd0GpbihzVnyfR6z1SpYfIUC6RTu4NF7lDKPjVkYb+jRI2gedVO2rVpN35Y6akG6ud4Lw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@oxc-resolver/binding-linux-ppc64-gnu": {
+ "version": "11.21.3",
+ "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-11.21.3.tgz",
+ "integrity": "sha512-gB9HwhrPiFqUzDeEq+y/CgAijz1YdI6BnXz5GaH2Pa9cWdutchlkGFAiAuGb/PjVQpiK6NFKzFuztxrweoit7A==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@oxc-resolver/binding-linux-riscv64-gnu": {
+ "version": "11.21.3",
+ "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-11.21.3.tgz",
+ "integrity": "sha512-zjDWBlYk8QGv0H8dsPUWqkfjYIIjG2TvspGkzXL0eImbgxtZorA/klKeHyolevoT3Kvbi+1iMr9Lhrh7jf54Og==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@oxc-resolver/binding-linux-riscv64-musl": {
+ "version": "11.21.3",
+ "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-11.21.3.tgz",
+ "integrity": "sha512-4UfsQvacV388y1zpXL7C1x1FNYaV52JtuNRiuzrfQA2z1z6ElVrsidkGsrvQ5EgeSq1Pj7kaKqrgGkvFuxJ/tw==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@oxc-resolver/binding-linux-s390x-gnu": {
+ "version": "11.21.3",
+ "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-11.21.3.tgz",
+ "integrity": "sha512-b5uH+HKH0MP5mNBYaK75SKsJbw52URqrx2LavYdq6wb0l3ExAG5niYRP9DWUNHdKilpaBVM2bXk9HNWrH3ew7Q==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@oxc-resolver/binding-linux-x64-gnu": {
+ "version": "11.21.3",
+ "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-x64-gnu/-/binding-linux-x64-gnu-11.21.3.tgz",
+ "integrity": "sha512-PjYlmilBpNRh2ntXNYAK3Am5w/nPfEpnU/96iNx7CI8EzAn12J4JRiec63wHJTH31nLoCNxBg/829pN+3CfG3Q==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@oxc-resolver/binding-linux-x64-musl": {
+ "version": "11.21.3",
+ "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-linux-x64-musl/-/binding-linux-x64-musl-11.21.3.tgz",
+ "integrity": "sha512-QTBAb7JuHlZ7JUEyM8UiQi2f7m/L4swBhP2TNpYIDc9Wp/wRw1G/8sl6i13aIzQAXH7LKIm294LeOHd0lQR8zA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@oxc-resolver/binding-openharmony-arm64": {
+ "version": "11.21.3",
+ "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-openharmony-arm64/-/binding-openharmony-arm64-11.21.3.tgz",
+ "integrity": "sha512-4j1DFwjwv36ec9kds0jU/ucQ5Ha4ERO/H95BxR5JFf0kqUUAJ1kwII7XhTc1vZrkdJkvLGC9Q2MbpObpum8RBg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openharmony"
+ ]
+ },
+ "node_modules/@oxc-resolver/binding-wasm32-wasi": {
+ "version": "11.21.3",
+ "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-wasm32-wasi/-/binding-wasm32-wasi-11.21.3.tgz",
+ "integrity": "sha512-i8oluoel5kru/j1WNrjmQSiA3GQ7wvIYVR1IwIoZtKogAhya2iub+ZKIeSIkcJOrnzQ18Tzl/F+kL3fYOxZLvA==",
+ "cpu": [
+ "wasm32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/core": "1.11.0",
+ "@emnapi/runtime": "1.11.0",
+ "@napi-rs/wasm-runtime": "^1.1.5"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@oxc-resolver/binding-wasm32-wasi/node_modules/@emnapi/core": {
+ "version": "1.11.0",
+ "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.0.tgz",
+ "integrity": "sha512-l9Oo58x0HOP5znGzVhYW9U3e5wVuA4LAZU2AGezTmkhO1CgQRFDhDg4nneHsu/t3WniXg9QrG2nIXL/ZS8ln8Q==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/wasi-threads": "1.2.2",
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@oxc-resolver/binding-wasm32-wasi/node_modules/@emnapi/runtime": {
+ "version": "1.11.0",
+ "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.0.tgz",
+ "integrity": "sha512-55coeOFKHv1ywEcUXJtWU5f+Jr/W5tZDvZig8DLKSwUN1JpROQ4rk/SNOQiFWmaR/VKF4zuFyW1B8JduOSv6Pg==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@oxc-resolver/binding-wasm32-wasi/node_modules/@emnapi/wasi-threads": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz",
+ "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@oxc-resolver/binding-win32-arm64-msvc": {
+ "version": "11.21.3",
+ "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-11.21.3.tgz",
+ "integrity": "sha512-M/8dw8dD6aOs+NlPJax401CZB9I7Aut84isQLgALGGwke4Afvw+/7yYhZb94yXf6t2sPLhQLmSmtSV+2FhsOWg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@oxc-resolver/binding-win32-x64-msvc": {
+ "version": "11.21.3",
+ "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-win32-x64-msvc/-/binding-win32-x64-msvc-11.21.3.tgz",
+ "integrity": "sha512-H7BCt/VnS9hnmMp42eGhZ99izSCRvlnWwy/N71K1/J8QoExwY4262Z8QiEkMDtduRJrztayDxETTckmUuAVL9Q==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
"node_modules/@pkgjs/parseargs": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
@@ -9206,7 +9469,8 @@
"optional": true,
"os": [
"android"
- ]
+ ],
+ "peer": true
},
"node_modules/@rollup/rollup-android-arm64": {
"version": "4.62.0",
@@ -9220,7 +9484,8 @@
"optional": true,
"os": [
"android"
- ]
+ ],
+ "peer": true
},
"node_modules/@rollup/rollup-darwin-arm64": {
"version": "4.62.0",
@@ -9234,7 +9499,8 @@
"optional": true,
"os": [
"darwin"
- ]
+ ],
+ "peer": true
},
"node_modules/@rollup/rollup-darwin-x64": {
"version": "4.62.0",
@@ -9248,7 +9514,8 @@
"optional": true,
"os": [
"darwin"
- ]
+ ],
+ "peer": true
},
"node_modules/@rollup/rollup-freebsd-arm64": {
"version": "4.62.0",
@@ -9262,7 +9529,8 @@
"optional": true,
"os": [
"freebsd"
- ]
+ ],
+ "peer": true
},
"node_modules/@rollup/rollup-freebsd-x64": {
"version": "4.62.0",
@@ -9276,7 +9544,8 @@
"optional": true,
"os": [
"freebsd"
- ]
+ ],
+ "peer": true
},
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
"version": "4.62.0",
@@ -9290,7 +9559,8 @@
"optional": true,
"os": [
"linux"
- ]
+ ],
+ "peer": true
},
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
"version": "4.62.0",
@@ -9304,7 +9574,8 @@
"optional": true,
"os": [
"linux"
- ]
+ ],
+ "peer": true
},
"node_modules/@rollup/rollup-linux-arm64-gnu": {
"version": "4.62.0",
@@ -9318,7 +9589,8 @@
"optional": true,
"os": [
"linux"
- ]
+ ],
+ "peer": true
},
"node_modules/@rollup/rollup-linux-arm64-musl": {
"version": "4.62.0",
@@ -9332,7 +9604,8 @@
"optional": true,
"os": [
"linux"
- ]
+ ],
+ "peer": true
},
"node_modules/@rollup/rollup-linux-loong64-gnu": {
"version": "4.62.0",
@@ -9346,7 +9619,8 @@
"optional": true,
"os": [
"linux"
- ]
+ ],
+ "peer": true
},
"node_modules/@rollup/rollup-linux-loong64-musl": {
"version": "4.62.0",
@@ -9360,7 +9634,8 @@
"optional": true,
"os": [
"linux"
- ]
+ ],
+ "peer": true
},
"node_modules/@rollup/rollup-linux-ppc64-gnu": {
"version": "4.62.0",
@@ -9374,7 +9649,8 @@
"optional": true,
"os": [
"linux"
- ]
+ ],
+ "peer": true
},
"node_modules/@rollup/rollup-linux-ppc64-musl": {
"version": "4.62.0",
@@ -9388,7 +9664,8 @@
"optional": true,
"os": [
"linux"
- ]
+ ],
+ "peer": true
},
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
"version": "4.62.0",
@@ -9402,7 +9679,8 @@
"optional": true,
"os": [
"linux"
- ]
+ ],
+ "peer": true
},
"node_modules/@rollup/rollup-linux-riscv64-musl": {
"version": "4.62.0",
@@ -9416,7 +9694,8 @@
"optional": true,
"os": [
"linux"
- ]
+ ],
+ "peer": true
},
"node_modules/@rollup/rollup-linux-s390x-gnu": {
"version": "4.62.0",
@@ -9430,7 +9709,8 @@
"optional": true,
"os": [
"linux"
- ]
+ ],
+ "peer": true
},
"node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.62.0",
@@ -9444,7 +9724,8 @@
"optional": true,
"os": [
"linux"
- ]
+ ],
+ "peer": true
},
"node_modules/@rollup/rollup-linux-x64-musl": {
"version": "4.62.0",
@@ -9458,7 +9739,8 @@
"optional": true,
"os": [
"linux"
- ]
+ ],
+ "peer": true
},
"node_modules/@rollup/rollup-openbsd-x64": {
"version": "4.62.0",
@@ -9472,7 +9754,8 @@
"optional": true,
"os": [
"openbsd"
- ]
+ ],
+ "peer": true
},
"node_modules/@rollup/rollup-openharmony-arm64": {
"version": "4.62.0",
@@ -9486,7 +9769,8 @@
"optional": true,
"os": [
"openharmony"
- ]
+ ],
+ "peer": true
},
"node_modules/@rollup/rollup-win32-arm64-msvc": {
"version": "4.62.0",
@@ -9500,7 +9784,8 @@
"optional": true,
"os": [
"win32"
- ]
+ ],
+ "peer": true
},
"node_modules/@rollup/rollup-win32-ia32-msvc": {
"version": "4.62.0",
@@ -9514,7 +9799,8 @@
"optional": true,
"os": [
"win32"
- ]
+ ],
+ "peer": true
},
"node_modules/@rollup/rollup-win32-x64-gnu": {
"version": "4.62.0",
@@ -9528,7 +9814,8 @@
"optional": true,
"os": [
"win32"
- ]
+ ],
+ "peer": true
},
"node_modules/@rollup/rollup-win32-x64-msvc": {
"version": "4.62.0",
@@ -9542,7 +9829,8 @@
"optional": true,
"os": [
"win32"
- ]
+ ],
+ "peer": true
},
"node_modules/@rtsao/scc": {
"version": "1.1.0",
@@ -9608,6 +9896,525 @@
"devOptional": true,
"license": "MIT"
},
+ "node_modules/@storybook/addon-a11y": {
+ "version": "10.4.6",
+ "resolved": "https://registry.npmjs.org/@storybook/addon-a11y/-/addon-a11y-10.4.6.tgz",
+ "integrity": "sha512-XCJy+f0DFOiCgUU9knRDlLDxVFI+AAQ3/wE/NF85zB9iDPPS2DwkSN+mas3zDgHt66zhN8Cq3/UiyCDUweV9Zw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@storybook/global": "^5.0.0",
+ "axe-core": "^4.2.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/storybook"
+ },
+ "peerDependencies": {
+ "storybook": "^10.4.6"
+ }
+ },
+ "node_modules/@storybook/builder-vite": {
+ "version": "10.4.6",
+ "resolved": "https://registry.npmjs.org/@storybook/builder-vite/-/builder-vite-10.4.6.tgz",
+ "integrity": "sha512-BHBtD81HiXUiDQz/CaFynLtWmm7AFUQn8VnXuHipZ8KlnUANopa4yqdVuy/Gwz8ub254uFI5NMZsW/KlgWNgNg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@storybook/csf-plugin": "10.4.6",
+ "ts-dedent": "^2.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/storybook"
+ },
+ "peerDependencies": {
+ "storybook": "^10.4.6",
+ "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0"
+ }
+ },
+ "node_modules/@storybook/csf-plugin": {
+ "version": "10.4.6",
+ "resolved": "https://registry.npmjs.org/@storybook/csf-plugin/-/csf-plugin-10.4.6.tgz",
+ "integrity": "sha512-NILLxDqpA/JR/AazGWpsz+4fadJwRU4uhHephGtYpVOWnQA/DkJfKT6zpcJVq8+QA8A2zKMLX3GVKsXIrxjuDA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "unplugin": "^2.3.5"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/storybook"
+ },
+ "peerDependencies": {
+ "esbuild": "*",
+ "rollup": "*",
+ "storybook": "^10.4.6",
+ "vite": "*",
+ "webpack": "*"
+ },
+ "peerDependenciesMeta": {
+ "esbuild": {
+ "optional": true
+ },
+ "rollup": {
+ "optional": true
+ },
+ "vite": {
+ "optional": true
+ },
+ "webpack": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@storybook/global": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/@storybook/global/-/global-5.0.0.tgz",
+ "integrity": "sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@storybook/icons": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/@storybook/icons/-/icons-2.0.2.tgz",
+ "integrity": "sha512-KZBCpXsshAIjczYNXR/rlxEtCUX/eAbpFNwKi8bcOomrLA4t/SyPz5RF+lVPO2oZBUE4sAkt43mfJUevQDSEEw==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ }
+ },
+ "node_modules/@storybook/instrumenter": {
+ "version": "8.6.15",
+ "resolved": "https://registry.npmjs.org/@storybook/instrumenter/-/instrumenter-8.6.15.tgz",
+ "integrity": "sha512-TvHR/+yyIAOp/1bLulFai2kkhIBtAlBw7J6Jd9DKyInoGhTWNE1G1Y61jD5GWXX29AlwaHfzGUaX5NL1K+FJpg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@storybook/global": "^5.0.0",
+ "@vitest/utils": "^2.1.1"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/storybook"
+ },
+ "peerDependencies": {
+ "storybook": "^8.6.15"
+ }
+ },
+ "node_modules/@storybook/instrumenter/node_modules/@vitest/pretty-format": {
+ "version": "2.1.9",
+ "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.9.tgz",
+ "integrity": "sha512-KhRIdGV2U9HOUzxfiHmY8IFHTdqtOhIzCpd8WRdJiE7D/HUcZVD0EgQCVjm+Q9gkUXWgBvMmTtZgIG48wq7sOQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "tinyrainbow": "^1.2.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/@storybook/instrumenter/node_modules/@vitest/utils": {
+ "version": "2.1.9",
+ "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.9.tgz",
+ "integrity": "sha512-v0psaMSkNJ3A2NMrUEHFRzJtDPFn+/VWZ5WxImB21T9fjucJRmS7xCS3ppEnARb9y11OAzaD+P2Ps+b+BGX5iQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/pretty-format": "2.1.9",
+ "loupe": "^3.1.2",
+ "tinyrainbow": "^1.2.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/@storybook/instrumenter/node_modules/loupe": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz",
+ "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@storybook/instrumenter/node_modules/tinyrainbow": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-1.2.0.tgz",
+ "integrity": "sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@storybook/react": {
+ "version": "10.4.6",
+ "resolved": "https://registry.npmjs.org/@storybook/react/-/react-10.4.6.tgz",
+ "integrity": "sha512-9Y7YecrVFe1/01KYjfOLxVqTg2Aq+IO6TEv6sC2U0PfD0AWCSCmQ91QqgBpN/XW4aFFWoiZNinyXMUlU8zxy2w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@storybook/global": "^5.0.0",
+ "@storybook/react-dom-shim": "10.4.6",
+ "react-docgen": "^8.0.2",
+ "react-docgen-typescript": "^2.2.2"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/storybook"
+ },
+ "peerDependencies": {
+ "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
+ "@types/react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
+ "storybook": "^10.4.6",
+ "typescript": ">= 4.9.x"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ },
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@storybook/react-dom-shim": {
+ "version": "10.4.6",
+ "resolved": "https://registry.npmjs.org/@storybook/react-dom-shim/-/react-dom-shim-10.4.6.tgz",
+ "integrity": "sha512-iGNmKzrq9vgl2PDrYAnZKI+yvac3Ym+lJXXuQaqlFRS23zA5MNm4EBX+rAG7WulqchoK6NaZ0KQOs2mAgEpTMg==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/storybook"
+ },
+ "peerDependencies": {
+ "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
+ "@types/react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
+ "storybook": "^10.4.6"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@storybook/react-vite": {
+ "version": "10.4.6",
+ "resolved": "https://registry.npmjs.org/@storybook/react-vite/-/react-vite-10.4.6.tgz",
+ "integrity": "sha512-0arEQtybqGYXHbXpTot+Wv9YtG+V5Vp43QayXavPKQ20M8mpEzhyCPKd0EhqMGSC1Z1UEt0hm365WUBhI9LfKA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@joshwooding/vite-plugin-react-docgen-typescript": "^0.7.0",
+ "@rollup/pluginutils": "^5.0.2",
+ "@storybook/builder-vite": "10.4.6",
+ "@storybook/react": "10.4.6",
+ "empathic": "^2.0.0",
+ "magic-string": "^0.30.0",
+ "react-docgen": "^8.0.0",
+ "resolve": "^1.22.8",
+ "tsconfig-paths": "^4.2.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/storybook"
+ },
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
+ "storybook": "^10.4.6",
+ "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0"
+ }
+ },
+ "node_modules/@storybook/test": {
+ "version": "8.6.15",
+ "resolved": "https://registry.npmjs.org/@storybook/test/-/test-8.6.15.tgz",
+ "integrity": "sha512-EwquDRUDVvWcZds3T2abmB5wSN/Vattal4YtZ6fpBlIUqONV4o/cOBX39cFfQSUCBrIXIjQ6RmapQCHK/PvBYw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@storybook/global": "^5.0.0",
+ "@storybook/instrumenter": "8.6.15",
+ "@testing-library/dom": "10.4.0",
+ "@testing-library/jest-dom": "6.5.0",
+ "@testing-library/user-event": "14.5.2",
+ "@vitest/expect": "2.0.5",
+ "@vitest/spy": "2.0.5"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/storybook"
+ },
+ "peerDependencies": {
+ "storybook": "^8.6.15"
+ }
+ },
+ "node_modules/@storybook/test/node_modules/@testing-library/dom": {
+ "version": "10.4.0",
+ "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz",
+ "integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.10.4",
+ "@babel/runtime": "^7.12.5",
+ "@types/aria-query": "^5.0.1",
+ "aria-query": "5.3.0",
+ "chalk": "^4.1.0",
+ "dom-accessibility-api": "^0.5.9",
+ "lz-string": "^1.5.0",
+ "pretty-format": "^27.0.2"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@storybook/test/node_modules/@testing-library/jest-dom": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.5.0.tgz",
+ "integrity": "sha512-xGGHpBXYSHUUr6XsKBfs85TWlYKpTc37cSBBVrXcib2MkHLboWlkClhWF37JKlDb9KEq3dHs+f2xR7XJEWGBxA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@adobe/css-tools": "^4.4.0",
+ "aria-query": "^5.0.0",
+ "chalk": "^3.0.0",
+ "css.escape": "^1.5.1",
+ "dom-accessibility-api": "^0.6.3",
+ "lodash": "^4.17.21",
+ "redent": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=14",
+ "npm": ">=6",
+ "yarn": ">=1"
+ }
+ },
+ "node_modules/@storybook/test/node_modules/@testing-library/jest-dom/node_modules/chalk": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
+ "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@storybook/test/node_modules/@testing-library/jest-dom/node_modules/dom-accessibility-api": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz",
+ "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@storybook/test/node_modules/@testing-library/user-event": {
+ "version": "14.5.2",
+ "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.5.2.tgz",
+ "integrity": "sha512-YAh82Wh4TIrxYLmfGcixwD18oIjyC1pFQC2Y01F2lzV2HTMiYrI0nze0FD0ocB//CKS/7jIUgae+adPqxK5yCQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12",
+ "npm": ">=6"
+ },
+ "peerDependencies": {
+ "@testing-library/dom": ">=7.21.4"
+ }
+ },
+ "node_modules/@storybook/test/node_modules/@vitest/expect": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.0.5.tgz",
+ "integrity": "sha512-yHZtwuP7JZivj65Gxoi8upUN2OzHTi3zVfjwdpu2WrvCZPLwsJ2Ey5ILIPccoW23dd/zQBlJ4/dhi7DWNyXCpA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/spy": "2.0.5",
+ "@vitest/utils": "2.0.5",
+ "chai": "^5.1.1",
+ "tinyrainbow": "^1.2.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/@storybook/test/node_modules/@vitest/pretty-format": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.0.5.tgz",
+ "integrity": "sha512-h8k+1oWHfwTkyTkb9egzwNMfJAEx4veaPSnMeKbVSjp4euqGSbQlm5+6VHwTr7u4FJslVVsUG5nopCaAYdOmSQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "tinyrainbow": "^1.2.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/@storybook/test/node_modules/@vitest/spy": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.0.5.tgz",
+ "integrity": "sha512-c/jdthAhvJdpfVuaexSrnawxZz6pywlTPe84LUB2m/4t3rl2fTo9NFGBG4oWgaD+FTgDDV8hJ/nibT7IfH3JfA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "tinyspy": "^3.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/@storybook/test/node_modules/@vitest/utils": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.0.5.tgz",
+ "integrity": "sha512-d8HKbqIcya+GR67mkZbrzhS5kKhtp8dQLcmRZLGTscGVg7yImT82cIrhtn2L8+VujWcy6KZweApgNmPsTAO/UQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/pretty-format": "2.0.5",
+ "estree-walker": "^3.0.3",
+ "loupe": "^3.1.1",
+ "tinyrainbow": "^1.2.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/@storybook/test/node_modules/assertion-error": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz",
+ "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@storybook/test/node_modules/chai": {
+ "version": "5.3.3",
+ "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz",
+ "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "assertion-error": "^2.0.1",
+ "check-error": "^2.1.1",
+ "deep-eql": "^5.0.1",
+ "loupe": "^3.1.0",
+ "pathval": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@storybook/test/node_modules/check-error": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.3.tgz",
+ "integrity": "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 16"
+ }
+ },
+ "node_modules/@storybook/test/node_modules/deep-eql": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz",
+ "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/@storybook/test/node_modules/loupe": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz",
+ "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@storybook/test/node_modules/pathval": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz",
+ "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 14.16"
+ }
+ },
+ "node_modules/@storybook/test/node_modules/pretty-format": {
+ "version": "27.5.1",
+ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz",
+ "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^5.0.1",
+ "ansi-styles": "^5.0.0",
+ "react-is": "^17.0.1"
+ },
+ "engines": {
+ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
+ }
+ },
+ "node_modules/@storybook/test/node_modules/pretty-format/node_modules/ansi-styles": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
+ "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/@storybook/test/node_modules/react-is": {
+ "version": "17.0.2",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
+ "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@storybook/test/node_modules/tinyrainbow": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-1.2.0.tgz",
+ "integrity": "sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@storybook/test/node_modules/tinyspy": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.2.tgz",
+ "integrity": "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
"node_modules/@svgr/babel-plugin-add-jsx-attribute": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz",
@@ -10204,7 +11011,6 @@
"integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@babel/code-frame": "^7.10.4",
"@babel/runtime": "^7.12.5",
@@ -10225,7 +11031,6 @@
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
"dev": true,
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=10"
},
@@ -10239,7 +11044,6 @@
"integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"ansi-regex": "^5.0.1",
"ansi-styles": "^5.0.0",
@@ -10254,8 +11058,7 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
"dev": true,
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/@testing-library/jest-dom": {
"version": "6.9.1",
@@ -10366,8 +11169,7 @@
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz",
"integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==",
"dev": true,
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/@types/babel__core": {
"version": "7.20.5",
@@ -10762,6 +11564,13 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@types/doctrine": {
+ "version": "0.0.9",
+ "resolved": "https://registry.npmjs.org/@types/doctrine/-/doctrine-0.0.9.tgz",
+ "integrity": "sha512-eOIHzCUSH7SMfonMG1LsC2f8vxBFtho6NGBznK41R84YzPuvSBzrhEps33IsQiOW9+VL6NQ9DbjQJznk/S4uRA==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@types/eslint": {
"version": "9.6.1",
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz",
@@ -11058,6 +11867,13 @@
"@types/react": "*"
}
},
+ "node_modules/@types/resolve": {
+ "version": "1.20.6",
+ "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.6.tgz",
+ "integrity": "sha512-A4STmOXPhMUtHH+S6ymgE2GiBSMqf4oTvcQZMcHzokuTLVYzXTB8ttjcgxOVaAp2lGwEdzZ0J+cRbbeevQj1UQ==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@types/retry": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz",
@@ -11986,6 +12802,13 @@
"@xtuc/long": "4.2.2"
}
},
+ "node_modules/@webcontainer/env": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@webcontainer/env/-/env-1.1.1.tgz",
+ "integrity": "sha512-6aN99yL695Hi9SuIk1oC88l9o0gmxL1nGWWQ/kNy81HigJ0FoaoTXpytCj6ItzgyCEwA9kF1wixsTuv5cjsgng==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@xtuc/ieee754": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
@@ -11998,20 +12821,6 @@
"integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==",
"license": "Apache-2.0"
},
- "node_modules/accepts": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
- "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "mime-types": "^3.0.0",
- "negotiator": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.6"
- }
- },
"node_modules/acorn": {
"version": "8.17.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz",
@@ -12488,6 +13297,19 @@
"node": "*"
}
},
+ "node_modules/ast-types": {
+ "version": "0.16.1",
+ "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.16.1.tgz",
+ "integrity": "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/astring": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/astring/-/astring-1.9.0.tgz",
@@ -12593,6 +13415,16 @@
"node": ">= 6.0.0"
}
},
+ "node_modules/axe-core": {
+ "version": "4.12.1",
+ "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.12.1.tgz",
+ "integrity": "sha512-s7iGf5GaVMxEG0ENN9x+xTr7GFZCb1ZP/1uATUpCEK2X78nDB3RwbtFCo9pGAf9ru+VwoQ464DkaLEeRM08wJA==",
+ "dev": true,
+ "license": "MPL-2.0",
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/axios": {
"version": "1.17.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.17.0.tgz",
@@ -13108,6 +13940,22 @@
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
"license": "MIT"
},
+ "node_modules/bundle-name": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz",
+ "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "run-applescript": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/busboy": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
@@ -14098,20 +14946,6 @@
"integrity": "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==",
"license": "MIT"
},
- "node_modules/content-disposition": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz",
- "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==",
- "license": "MIT",
- "peer": true,
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/express"
- }
- },
"node_modules/content-type": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
@@ -14155,16 +14989,6 @@
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==",
"license": "MIT"
},
- "node_modules/cookie-signature": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz",
- "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==",
- "license": "MIT",
- "peer": true,
- "engines": {
- "node": ">=6.6.0"
- }
- },
"node_modules/copy-text-to-clipboard": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/copy-text-to-clipboard/-/copy-text-to-clipboard-3.2.2.tgz",
@@ -15617,6 +16441,36 @@
"node": ">=16.0.0"
}
},
+ "node_modules/default-browser": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.5.0.tgz",
+ "integrity": "sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "bundle-name": "^4.1.0",
+ "default-browser-id": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/default-browser-id": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz",
+ "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/default-gateway": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz",
@@ -15998,8 +16852,7 @@
"resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz",
"integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==",
"dev": true,
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/dom-converter": {
"version": "0.2.0",
@@ -17388,151 +18241,6 @@
"node": ">=12.0.0"
}
},
- "node_modules/express": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz",
- "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "accepts": "^2.0.0",
- "body-parser": "^2.2.1",
- "content-disposition": "^1.0.0",
- "content-type": "^1.0.5",
- "cookie": "^0.7.1",
- "cookie-signature": "^1.2.1",
- "debug": "^4.4.0",
- "depd": "^2.0.0",
- "encodeurl": "^2.0.0",
- "escape-html": "^1.0.3",
- "etag": "^1.8.1",
- "finalhandler": "^2.1.0",
- "fresh": "^2.0.0",
- "http-errors": "^2.0.0",
- "merge-descriptors": "^2.0.0",
- "mime-types": "^3.0.0",
- "on-finished": "^2.4.1",
- "once": "^1.4.0",
- "parseurl": "^1.3.3",
- "proxy-addr": "^2.0.7",
- "qs": "^6.14.0",
- "range-parser": "^1.2.1",
- "router": "^2.2.0",
- "send": "^1.1.0",
- "serve-static": "^2.2.0",
- "statuses": "^2.0.1",
- "type-is": "^2.0.1",
- "vary": "^1.1.2"
- },
- "engines": {
- "node": ">= 18"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/express"
- }
- },
- "node_modules/express/node_modules/body-parser": {
- "version": "2.2.2",
- "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz",
- "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "bytes": "^3.1.2",
- "content-type": "^1.0.5",
- "debug": "^4.4.3",
- "http-errors": "^2.0.0",
- "iconv-lite": "^0.7.0",
- "on-finished": "^2.4.1",
- "qs": "^6.14.1",
- "raw-body": "^3.0.1",
- "type-is": "^2.0.1"
- },
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/express"
- }
- },
- "node_modules/express/node_modules/iconv-lite": {
- "version": "0.7.2",
- "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz",
- "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "safer-buffer": ">= 2.1.2 < 3.0.0"
- },
- "engines": {
- "node": ">=0.10.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/express"
- }
- },
- "node_modules/express/node_modules/media-typer": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz",
- "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==",
- "license": "MIT",
- "peer": true,
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/express/node_modules/raw-body": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz",
- "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "bytes": "~3.1.2",
- "http-errors": "~2.0.1",
- "iconv-lite": "~0.7.0",
- "unpipe": "~1.0.0"
- },
- "engines": {
- "node": ">= 0.10"
- }
- },
- "node_modules/express/node_modules/type-is": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.1.0.tgz",
- "integrity": "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "content-type": "^2.0.0",
- "media-typer": "^1.1.0",
- "mime-types": "^3.0.0"
- },
- "engines": {
- "node": ">= 18"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/express"
- }
- },
- "node_modules/express/node_modules/type-is/node_modules/content-type": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz",
- "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==",
- "license": "MIT",
- "peer": true,
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/express"
- }
- },
"node_modules/exsolve": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.8.tgz",
@@ -17836,28 +18544,6 @@
"node": ">=8"
}
},
- "node_modules/finalhandler": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz",
- "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "debug": "^4.4.0",
- "encodeurl": "^2.0.0",
- "escape-html": "^1.0.3",
- "on-finished": "^2.4.1",
- "parseurl": "^1.3.3",
- "statuses": "^2.0.1"
- },
- "engines": {
- "node": ">= 18.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/express"
- }
- },
"node_modules/find-cache-dir": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-4.0.0.tgz",
@@ -18109,16 +18795,6 @@
"url": "https://github.com/sponsors/rawify"
}
},
- "node_modules/fresh": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz",
- "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==",
- "license": "MIT",
- "peer": true,
- "engines": {
- "node": ">= 0.8"
- }
- },
"node_modules/fs-extra": {
"version": "10.1.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz",
@@ -19964,6 +20640,41 @@
"url": "https://github.com/sponsors/wooorm"
}
},
+ "node_modules/is-inside-container": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz",
+ "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-docker": "^3.0.0"
+ },
+ "bin": {
+ "is-inside-container": "cli.js"
+ },
+ "engines": {
+ "node": ">=14.16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-inside-container/node_modules/is-docker": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz",
+ "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "is-docker": "cli.js"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/is-installed-globally": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz",
@@ -20119,13 +20830,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/is-promise": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz",
- "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==",
- "license": "MIT",
- "peer": true
- },
"node_modules/is-property": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz",
@@ -21902,7 +22606,6 @@
"integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==",
"dev": true,
"license": "MIT",
- "peer": true,
"bin": {
"lz-string": "bin/bin.js"
}
@@ -22392,19 +23095,6 @@
"node": ">= 4.0.0"
}
},
- "node_modules/merge-descriptors": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz",
- "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==",
- "license": "MIT",
- "peer": true,
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/merge-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
@@ -24301,23 +24991,6 @@
"node": ">= 0.6"
}
},
- "node_modules/mime-types": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz",
- "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "mime-db": "^1.54.0"
- },
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/express"
- }
- },
"node_modules/mimic-fn": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
@@ -24701,16 +25374,6 @@
"devOptional": true,
"license": "MIT"
},
- "node_modules/negotiator": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz",
- "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==",
- "license": "MIT",
- "peer": true,
- "engines": {
- "node": ">= 0.6"
- }
- },
"node_modules/neo-async": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
@@ -25293,6 +25956,85 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/oxc-parser": {
+ "version": "0.127.0",
+ "resolved": "https://registry.npmjs.org/oxc-parser/-/oxc-parser-0.127.0.tgz",
+ "integrity": "sha512-bkgD4qHlN7WxLdX8bLXdaU54TtQtAIg/ZBAfm0aje/mo3MRDo3P0hZSgr4U7O3xfX+fQmR5AP04JS/TGcZLcFA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@oxc-project/types": "^0.127.0"
+ },
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/Boshen"
+ },
+ "optionalDependencies": {
+ "@oxc-parser/binding-android-arm-eabi": "0.127.0",
+ "@oxc-parser/binding-android-arm64": "0.127.0",
+ "@oxc-parser/binding-darwin-arm64": "0.127.0",
+ "@oxc-parser/binding-darwin-x64": "0.127.0",
+ "@oxc-parser/binding-freebsd-x64": "0.127.0",
+ "@oxc-parser/binding-linux-arm-gnueabihf": "0.127.0",
+ "@oxc-parser/binding-linux-arm-musleabihf": "0.127.0",
+ "@oxc-parser/binding-linux-arm64-gnu": "0.127.0",
+ "@oxc-parser/binding-linux-arm64-musl": "0.127.0",
+ "@oxc-parser/binding-linux-ppc64-gnu": "0.127.0",
+ "@oxc-parser/binding-linux-riscv64-gnu": "0.127.0",
+ "@oxc-parser/binding-linux-riscv64-musl": "0.127.0",
+ "@oxc-parser/binding-linux-s390x-gnu": "0.127.0",
+ "@oxc-parser/binding-linux-x64-gnu": "0.127.0",
+ "@oxc-parser/binding-linux-x64-musl": "0.127.0",
+ "@oxc-parser/binding-openharmony-arm64": "0.127.0",
+ "@oxc-parser/binding-wasm32-wasi": "0.127.0",
+ "@oxc-parser/binding-win32-arm64-msvc": "0.127.0",
+ "@oxc-parser/binding-win32-ia32-msvc": "0.127.0",
+ "@oxc-parser/binding-win32-x64-msvc": "0.127.0"
+ }
+ },
+ "node_modules/oxc-parser/node_modules/@oxc-project/types": {
+ "version": "0.127.0",
+ "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.127.0.tgz",
+ "integrity": "sha512-aIYXQBo4lCbO4z0R3FHeucQHpF46l2LbMdxRvqvuRuW2OxdnSkcng5B8+K12spgLDj93rtN3+J2Vac/TIO+ciQ==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/Boshen"
+ }
+ },
+ "node_modules/oxc-resolver": {
+ "version": "11.21.3",
+ "resolved": "https://registry.npmjs.org/oxc-resolver/-/oxc-resolver-11.21.3.tgz",
+ "integrity": "sha512-2Mx3fKQz7+xgrBONjsxOgCGtMHOn38/HxMzW1I5efwXB5a4lRN0Vp40gYUJFBWJslcrvwoofTrqoTnLbwTd3pA==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/Boshen"
+ },
+ "optionalDependencies": {
+ "@oxc-resolver/binding-android-arm-eabi": "11.21.3",
+ "@oxc-resolver/binding-android-arm64": "11.21.3",
+ "@oxc-resolver/binding-darwin-arm64": "11.21.3",
+ "@oxc-resolver/binding-darwin-x64": "11.21.3",
+ "@oxc-resolver/binding-freebsd-x64": "11.21.3",
+ "@oxc-resolver/binding-linux-arm-gnueabihf": "11.21.3",
+ "@oxc-resolver/binding-linux-arm-musleabihf": "11.21.3",
+ "@oxc-resolver/binding-linux-arm64-gnu": "11.21.3",
+ "@oxc-resolver/binding-linux-arm64-musl": "11.21.3",
+ "@oxc-resolver/binding-linux-ppc64-gnu": "11.21.3",
+ "@oxc-resolver/binding-linux-riscv64-gnu": "11.21.3",
+ "@oxc-resolver/binding-linux-riscv64-musl": "11.21.3",
+ "@oxc-resolver/binding-linux-s390x-gnu": "11.21.3",
+ "@oxc-resolver/binding-linux-x64-gnu": "11.21.3",
+ "@oxc-resolver/binding-linux-x64-musl": "11.21.3",
+ "@oxc-resolver/binding-openharmony-arm64": "11.21.3",
+ "@oxc-resolver/binding-wasm32-wasi": "11.21.3",
+ "@oxc-resolver/binding-win32-arm64-msvc": "11.21.3",
+ "@oxc-resolver/binding-win32-x64-msvc": "11.21.3"
+ }
+ },
"node_modules/p-cancelable": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz",
@@ -25864,6 +26606,53 @@
"node": ">=4"
}
},
+ "node_modules/playwright": {
+ "version": "1.61.0",
+ "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.61.0.tgz",
+ "integrity": "sha512-Z+7BeeqQPRRzklHsVFP4KTGIyMxKUmfeRA4WisM6G3/XW6nwGeX6fX9qYaDa+CiUqpOkb2f6X3nar05R3kSuJQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "playwright-core": "1.61.0"
+ },
+ "bin": {
+ "playwright": "cli.js"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "optionalDependencies": {
+ "fsevents": "2.3.2"
+ }
+ },
+ "node_modules/playwright-core": {
+ "version": "1.61.0",
+ "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.61.0.tgz",
+ "integrity": "sha512-caX7TrY3Ml6egyDX0WUcTHDxodl/b51y5wJOdCEA36QviK/s2g081hvmGs8eaE3DWb6NYZQ6BjO/QkNRPenoPA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "playwright-core": "cli.js"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/playwright/node_modules/fsevents": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+ "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
"node_modules/pluralize": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz",
@@ -25874,6 +26663,16 @@
"node": ">=4"
}
},
+ "node_modules/pngjs": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-7.0.0.tgz",
+ "integrity": "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.19.0"
+ }
+ },
"node_modules/points-on-curve": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/points-on-curve/-/points-on-curve-0.2.0.tgz",
@@ -28028,6 +28827,51 @@
"node": ">=6"
}
},
+ "node_modules/react-docgen": {
+ "version": "8.0.3",
+ "resolved": "https://registry.npmjs.org/react-docgen/-/react-docgen-8.0.3.tgz",
+ "integrity": "sha512-aEZ9qP+/M+58x2qgfSFEWH1BxLyHe5+qkLNJOZQb5iGS017jpbRnoKhNRrXPeA6RfBrZO5wZrT9DMC1UqE1f1w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/core": "^7.28.0",
+ "@babel/traverse": "^7.28.0",
+ "@babel/types": "^7.28.2",
+ "@types/babel__core": "^7.20.5",
+ "@types/babel__traverse": "^7.20.7",
+ "@types/doctrine": "^0.0.9",
+ "@types/resolve": "^1.20.2",
+ "doctrine": "^3.0.0",
+ "resolve": "^1.22.1",
+ "strip-indent": "^4.0.0"
+ },
+ "engines": {
+ "node": "^20.9.0 || >=22"
+ }
+ },
+ "node_modules/react-docgen-typescript": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/react-docgen-typescript/-/react-docgen-typescript-2.4.0.tgz",
+ "integrity": "sha512-ZtAp5XTO5HRzQctjPU0ybY0RRCQO19X/8fxn3w7y2VVTUbGHDKULPTL4ky3vB05euSgG5NpALhEhDPvQ56wvXg==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "typescript": ">= 4.3.x"
+ }
+ },
+ "node_modules/react-docgen/node_modules/strip-indent": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-4.1.1.tgz",
+ "integrity": "sha512-SlyRoSkdh1dYP0PzclLE7r0M9sgbFKKMFXpFRUMNuKhQSbC6VQIGzq3E0qsfvGJaUFJPGv6Ws1NZ/haTAjfbMA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/react-dom": {
"version": "18.3.1",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
@@ -28091,7 +28935,6 @@
"version": "18.3.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
"integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==",
- "dev": true,
"license": "MIT"
},
"node_modules/react-json-view-lite": {
@@ -28250,6 +29093,33 @@
"integrity": "sha512-onYyVhBNr4CmAxFsKS7bz+uTLRakypIe4R+5A824vBSkQy/hB3fZepoVEf8OVAxzLvK+H/jm9TzpI3ETSm64Kg==",
"license": "MIT"
},
+ "node_modules/recast": {
+ "version": "0.23.11",
+ "resolved": "https://registry.npmjs.org/recast/-/recast-0.23.11.tgz",
+ "integrity": "sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ast-types": "^0.16.1",
+ "esprima": "~4.0.0",
+ "source-map": "~0.6.1",
+ "tiny-invariant": "^1.3.3",
+ "tslib": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/recast/node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/rechoir": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
@@ -29135,34 +30005,6 @@
"points-on-path": "^0.2.1"
}
},
- "node_modules/router": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz",
- "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "debug": "^4.4.0",
- "depd": "^2.0.0",
- "is-promise": "^4.0.0",
- "parseurl": "^1.3.3",
- "path-to-regexp": "^8.0.0"
- },
- "engines": {
- "node": ">= 18"
- }
- },
- "node_modules/router/node_modules/path-to-regexp": {
- "version": "8.4.2",
- "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.2.tgz",
- "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==",
- "license": "MIT",
- "peer": true,
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/express"
- }
- },
"node_modules/rtlcss": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/rtlcss/-/rtlcss-4.3.0.tgz",
@@ -29181,6 +30023,19 @@
"node": ">=12.0.0"
}
},
+ "node_modules/run-applescript": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz",
+ "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/run-async": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
@@ -29404,13 +30259,6 @@
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
"license": "MIT"
},
- "node_modules/search-insights": {
- "version": "2.17.3",
- "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.17.3.tgz",
- "integrity": "sha512-RQPdCYTa8A68uM2jwxoY842xDhvx3E5LFL1LxvxCNMev4o5mLuokczhzjAgGwUZBAmOKZknArSxLKmXtIi2AxQ==",
- "license": "MIT",
- "peer": true
- },
"node_modules/section-matter": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz",
@@ -29470,33 +30318,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/send": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz",
- "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "debug": "^4.4.3",
- "encodeurl": "^2.0.0",
- "escape-html": "^1.0.3",
- "etag": "^1.8.1",
- "fresh": "^2.0.0",
- "http-errors": "^2.0.1",
- "mime-types": "^3.0.2",
- "ms": "^2.1.3",
- "on-finished": "^2.4.1",
- "range-parser": "^1.2.1",
- "statuses": "^2.0.2"
- },
- "engines": {
- "node": ">= 18"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/express"
- }
- },
"node_modules/seq-queue": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz",
@@ -29711,26 +30532,6 @@
"node": ">= 0.6"
}
},
- "node_modules/serve-static": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz",
- "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "encodeurl": "^2.0.0",
- "escape-html": "^1.0.3",
- "parseurl": "^1.3.3",
- "send": "^1.2.0"
- },
- "engines": {
- "node": ">= 18"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/express"
- }
- },
"node_modules/set-cookie-parser": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-3.1.0.tgz",
@@ -30288,6 +31089,249 @@
"node": ">= 0.4"
}
},
+ "node_modules/storybook": {
+ "version": "10.4.6",
+ "resolved": "https://registry.npmjs.org/storybook/-/storybook-10.4.6.tgz",
+ "integrity": "sha512-6wkA6LxfDSSilloITsrFOJfsnw0mDUP2h8Ls+lRt8oRsudtz2RWFhLv+Toiwg6NW7hUpdTDc2hzR7DztJid6+A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@storybook/global": "^5.0.0",
+ "@storybook/icons": "^2.0.2",
+ "@testing-library/jest-dom": "^6.9.1",
+ "@testing-library/user-event": "^14.6.1",
+ "@vitest/expect": "3.2.4",
+ "@vitest/spy": "3.2.4",
+ "@webcontainer/env": "^1.1.1",
+ "esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0 || ^0.25.0 || ^0.26.0 || ^0.27.0 || ^0.28.0",
+ "open": "^10.2.0",
+ "oxc-parser": "^0.127.0",
+ "oxc-resolver": "^11.19.1",
+ "recast": "^0.23.5",
+ "semver": "^7.7.3",
+ "use-sync-external-store": "^1.5.0",
+ "ws": "^8.18.0"
+ },
+ "bin": {
+ "storybook": "dist/bin/dispatcher.js"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/storybook"
+ },
+ "peerDependencies": {
+ "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
+ "prettier": "^2 || ^3",
+ "vite-plus": "^0.1.15"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "prettier": {
+ "optional": true
+ },
+ "vite-plus": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/storybook/node_modules/@vitest/expect": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.4.tgz",
+ "integrity": "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/chai": "^5.2.2",
+ "@vitest/spy": "3.2.4",
+ "@vitest/utils": "3.2.4",
+ "chai": "^5.2.0",
+ "tinyrainbow": "^2.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/storybook/node_modules/@vitest/pretty-format": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.4.tgz",
+ "integrity": "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "tinyrainbow": "^2.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/storybook/node_modules/@vitest/spy": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.4.tgz",
+ "integrity": "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "tinyspy": "^4.0.3"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/storybook/node_modules/@vitest/utils": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.4.tgz",
+ "integrity": "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/pretty-format": "3.2.4",
+ "loupe": "^3.1.4",
+ "tinyrainbow": "^2.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/storybook/node_modules/assertion-error": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz",
+ "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/storybook/node_modules/chai": {
+ "version": "5.3.3",
+ "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz",
+ "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "assertion-error": "^2.0.1",
+ "check-error": "^2.1.1",
+ "deep-eql": "^5.0.1",
+ "loupe": "^3.1.0",
+ "pathval": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/storybook/node_modules/check-error": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.3.tgz",
+ "integrity": "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 16"
+ }
+ },
+ "node_modules/storybook/node_modules/deep-eql": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz",
+ "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/storybook/node_modules/define-lazy-prop": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz",
+ "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/storybook/node_modules/loupe": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz",
+ "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/storybook/node_modules/open": {
+ "version": "10.2.0",
+ "resolved": "https://registry.npmjs.org/open/-/open-10.2.0.tgz",
+ "integrity": "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "default-browser": "^5.2.1",
+ "define-lazy-prop": "^3.0.0",
+ "is-inside-container": "^1.0.0",
+ "wsl-utils": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/storybook/node_modules/pathval": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz",
+ "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 14.16"
+ }
+ },
+ "node_modules/storybook/node_modules/tinyrainbow": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz",
+ "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/storybook/node_modules/tinyspy": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.4.tgz",
+ "integrity": "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/storybook/node_modules/ws": {
+ "version": "8.21.0",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz",
+ "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10.0.0"
+ },
+ "peerDependencies": {
+ "bufferutil": "^4.0.1",
+ "utf-8-validate": ">=5.0.2"
+ },
+ "peerDependenciesMeta": {
+ "bufferutil": {
+ "optional": true
+ },
+ "utf-8-validate": {
+ "optional": true
+ }
+ }
+ },
"node_modules/streamsearch": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
@@ -31940,6 +32984,16 @@
"node": ">= 0.6"
}
},
+ "node_modules/use-sync-external-store": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz",
+ "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==",
+ "devOptional": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ }
+ },
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
@@ -33251,6 +34305,38 @@
}
}
},
+ "node_modules/wsl-utils": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.1.0.tgz",
+ "integrity": "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-wsl": "^3.1.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/wsl-utils/node_modules/is-wsl": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz",
+ "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-inside-container": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/xdg-basedir": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-5.1.0.tgz",
@@ -33429,6 +34515,551 @@
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
+ },
+ "packages/design-system": {
+ "name": "@moex-vibe/design-system",
+ "version": "0.1.0",
+ "devDependencies": {
+ "@storybook/addon-a11y": "^10.2.9",
+ "@storybook/addon-vitest": "^10.2.9",
+ "@storybook/react-vite": "^10.2.9",
+ "@storybook/test": "^8.6.0",
+ "@testing-library/dom": "^10.4.0",
+ "@testing-library/jest-dom": "^6.9.1",
+ "@testing-library/react": "^16.3.2",
+ "@testing-library/user-event": "^14.6.1",
+ "@types/react": "^18.3.0",
+ "@types/react-dom": "^18.3.0",
+ "@typescript-eslint/eslint-plugin": "^7.0.0",
+ "@typescript-eslint/parser": "^7.0.0",
+ "@vitest/browser": "^4.1.8",
+ "@vitest/browser-playwright": "^4.1.8",
+ "eslint": "^8.0.0",
+ "eslint-plugin-react": "^7.34.0",
+ "eslint-plugin-react-hooks": "^4.6.0",
+ "playwright": "^1.55.0",
+ "storybook": "^10.2.9",
+ "typescript": "^5.3.0",
+ "vitest": "^4.1.8"
+ },
+ "peerDependencies": {
+ "@emotion/react": "^11.14.0",
+ "@emotion/styled": "^11.14.1",
+ "@mui/icons-material": "^6.5.0",
+ "@mui/material": "^6.5.0",
+ "@tanstack/react-table": "^8.21.3",
+ "react": "^18.3.0",
+ "react-dom": "^18.3.0"
+ }
+ },
+ "packages/design-system/node_modules/@storybook/addon-vitest": {
+ "version": "10.4.6",
+ "resolved": "https://registry.npmjs.org/@storybook/addon-vitest/-/addon-vitest-10.4.6.tgz",
+ "integrity": "sha512-VvskHge0GZy86LG6kcY5Ww34z8rDV8JBxqSdUpcJVsWfIvyX6MfAbqI76LlereSyBIJGZJZsqaLwRXsQoVY+0Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@storybook/global": "^5.0.0",
+ "@storybook/icons": "^2.0.2"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/storybook"
+ },
+ "peerDependencies": {
+ "@vitest/browser": "^3.0.0 || ^4.0.0",
+ "@vitest/browser-playwright": "^4.0.0",
+ "@vitest/runner": "^3.0.0 || ^4.0.0",
+ "storybook": "^10.4.6",
+ "vitest": "^3.0.0 || ^4.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@vitest/browser": {
+ "optional": true
+ },
+ "@vitest/browser-playwright": {
+ "optional": true
+ },
+ "@vitest/runner": {
+ "optional": true
+ },
+ "vitest": {
+ "optional": true
+ }
+ }
+ },
+ "packages/design-system/node_modules/@vitest/browser": {
+ "version": "4.1.9",
+ "resolved": "https://registry.npmjs.org/@vitest/browser/-/browser-4.1.9.tgz",
+ "integrity": "sha512-j1BKtWmPcqpMhmx/L9EPLgAJpCb0zKfwoWLmqBbxaogCXHjOwHFSEoHCBfnGtx93xKQwilZ26m+UOsHqHMkRNg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@blazediff/core": "1.9.1",
+ "@vitest/mocker": "4.1.9",
+ "@vitest/utils": "4.1.9",
+ "magic-string": "^0.30.21",
+ "pngjs": "^7.0.0",
+ "sirv": "^3.0.2",
+ "tinyrainbow": "^3.1.0",
+ "ws": "^8.19.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ },
+ "peerDependencies": {
+ "vitest": "4.1.9"
+ }
+ },
+ "packages/design-system/node_modules/@vitest/browser-playwright": {
+ "version": "4.1.9",
+ "resolved": "https://registry.npmjs.org/@vitest/browser-playwright/-/browser-playwright-4.1.9.tgz",
+ "integrity": "sha512-Bq1rOGf9waevzG3EOkO/dene6bvKTUsZMVg8S1i+WH3JcMjuXEjiahP9rAqZRELUqjBySOJsvvSWqK/B3wjKQw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/browser": "4.1.9",
+ "@vitest/mocker": "4.1.9",
+ "tinyrainbow": "^3.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ },
+ "peerDependencies": {
+ "playwright": "*",
+ "vitest": "4.1.9"
+ },
+ "peerDependenciesMeta": {
+ "playwright": {
+ "optional": false
+ }
+ }
+ },
+ "packages/design-system/node_modules/@vitest/browser-playwright/node_modules/@vitest/mocker": {
+ "version": "4.1.9",
+ "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.9.tgz",
+ "integrity": "sha512-EVkXzBjrPGM+cK8/ANWgBrkUCfJfb38/EfTSO8h7pWvKkyPkpWxvR7BkD2MyItMF62C97zAEoqdpUixwR/e+Rw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/spy": "4.1.9",
+ "estree-walker": "^3.0.3",
+ "magic-string": "^0.30.21"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ },
+ "peerDependencies": {
+ "msw": "^2.4.9",
+ "vite": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "msw": {
+ "optional": true
+ },
+ "vite": {
+ "optional": true
+ }
+ }
+ },
+ "packages/design-system/node_modules/@vitest/browser/node_modules/@vitest/mocker": {
+ "version": "4.1.9",
+ "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.9.tgz",
+ "integrity": "sha512-EVkXzBjrPGM+cK8/ANWgBrkUCfJfb38/EfTSO8h7pWvKkyPkpWxvR7BkD2MyItMF62C97zAEoqdpUixwR/e+Rw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/spy": "4.1.9",
+ "estree-walker": "^3.0.3",
+ "magic-string": "^0.30.21"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ },
+ "peerDependencies": {
+ "msw": "^2.4.9",
+ "vite": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "msw": {
+ "optional": true
+ },
+ "vite": {
+ "optional": true
+ }
+ }
+ },
+ "packages/design-system/node_modules/@vitest/expect": {
+ "version": "4.1.9",
+ "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.9.tgz",
+ "integrity": "sha512-vl/rYsUKcBr3SnQn166+XR5ZQcgMx3DQhFWdfli/cWpLnLUmbxZvyrJZotLFUryib+LtArYMSTJ5RbQ57ZqrlA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@standard-schema/spec": "^1.1.0",
+ "@types/chai": "^5.2.2",
+ "@vitest/spy": "4.1.9",
+ "@vitest/utils": "4.1.9",
+ "chai": "^6.2.2",
+ "tinyrainbow": "^3.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "packages/design-system/node_modules/@vitest/pretty-format": {
+ "version": "4.1.9",
+ "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.9.tgz",
+ "integrity": "sha512-s0iufns3iIFitdgm+YR7g1whCAaGtXz459VS9/PqyKDEEFgYIhsHOQmXgIgDuYCt7DeQmiZT0Qe2OA2p4ZPu5A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "tinyrainbow": "^3.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "packages/design-system/node_modules/@vitest/runner": {
+ "version": "4.1.9",
+ "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.9.tgz",
+ "integrity": "sha512-KXLMDtc7oe70+3mJfGrPUWPesswH+3sTxAMAMl8DG7I8IUQT4XW718dY5ID3vPUcmlu27CcKfY4P3h3I29SLJg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/utils": "4.1.9",
+ "pathe": "^2.0.3"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "packages/design-system/node_modules/@vitest/snapshot": {
+ "version": "4.1.9",
+ "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.9.tgz",
+ "integrity": "sha512-Jc7RKGNBo8Z28WYIm0Niej4xdSPByRf6mU58VpHQkd6Zh05rlnA+twjbK5HyeIGHxrzsc3mJgS43uM0CZKzaIA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/pretty-format": "4.1.9",
+ "@vitest/utils": "4.1.9",
+ "magic-string": "^0.30.21",
+ "pathe": "^2.0.3"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "packages/design-system/node_modules/@vitest/spy": {
+ "version": "4.1.9",
+ "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.9.tgz",
+ "integrity": "sha512-fHpsS6mIi+PiEW+vcRVOMkX1oSaPKne3VOclSFICPcGOmfKgXPU5iAah+wcNcj2xPrCCmfq99IDGf+EojhhvhA==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "packages/design-system/node_modules/@vitest/utils": {
+ "version": "4.1.9",
+ "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.9.tgz",
+ "integrity": "sha512-A51o8ymO5PpqlWNnBP9ZHPXDIpuMtTLlGSjN7la4US+LJzoUMyhwjA5QXlm39JexgwHKW4Xjs8Z2d3dLCXOeuA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/pretty-format": "4.1.9",
+ "convert-source-map": "^2.0.0",
+ "tinyrainbow": "^3.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "packages/design-system/node_modules/chai": {
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz",
+ "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "packages/design-system/node_modules/es-module-lexer": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.1.0.tgz",
+ "integrity": "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "packages/design-system/node_modules/magic-string": {
+ "version": "0.30.21",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
+ "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.5.5"
+ }
+ },
+ "packages/design-system/node_modules/pathe": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz",
+ "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "packages/design-system/node_modules/picomatch": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
+ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "packages/design-system/node_modules/sirv": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz",
+ "integrity": "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@polka/url": "^1.0.0-next.24",
+ "mrmime": "^2.0.0",
+ "totalist": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "packages/design-system/node_modules/std-env": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.1.0.tgz",
+ "integrity": "sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "packages/design-system/node_modules/vite": {
+ "version": "8.0.16",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.16.tgz",
+ "integrity": "sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "lightningcss": "^1.32.0",
+ "picomatch": "^4.0.4",
+ "postcss": "^8.5.15",
+ "rolldown": "1.0.3",
+ "tinyglobby": "^0.2.17"
+ },
+ "bin": {
+ "vite": "bin/vite.js"
+ },
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ },
+ "funding": {
+ "url": "https://github.com/vitejs/vite?sponsor=1"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.3"
+ },
+ "peerDependencies": {
+ "@types/node": "^20.19.0 || >=22.12.0",
+ "@vitejs/devtools": "^0.1.18",
+ "esbuild": "^0.27.0 || ^0.28.0",
+ "jiti": ">=1.21.0",
+ "less": "^4.0.0",
+ "sass": "^1.70.0",
+ "sass-embedded": "^1.70.0",
+ "stylus": ">=0.54.8",
+ "sugarss": "^5.0.0",
+ "terser": "^5.16.0",
+ "tsx": "^4.8.1",
+ "yaml": "^2.4.2"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ },
+ "@vitejs/devtools": {
+ "optional": true
+ },
+ "esbuild": {
+ "optional": true
+ },
+ "jiti": {
+ "optional": true
+ },
+ "less": {
+ "optional": true
+ },
+ "sass": {
+ "optional": true
+ },
+ "sass-embedded": {
+ "optional": true
+ },
+ "stylus": {
+ "optional": true
+ },
+ "sugarss": {
+ "optional": true
+ },
+ "terser": {
+ "optional": true
+ },
+ "tsx": {
+ "optional": true
+ },
+ "yaml": {
+ "optional": true
+ }
+ }
+ },
+ "packages/design-system/node_modules/vitest": {
+ "version": "4.1.9",
+ "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.9.tgz",
+ "integrity": "sha512-nE3/LEyc0z87uHYLZebqCUOaJr2hdtuPp7BQ4BosVFnfltxgAvMG08NyrSGlPpOUWvR27c5flSmYFTNr78L9GQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/expect": "4.1.9",
+ "@vitest/mocker": "4.1.9",
+ "@vitest/pretty-format": "4.1.9",
+ "@vitest/runner": "4.1.9",
+ "@vitest/snapshot": "4.1.9",
+ "@vitest/spy": "4.1.9",
+ "@vitest/utils": "4.1.9",
+ "es-module-lexer": "^2.0.0",
+ "expect-type": "^1.3.0",
+ "magic-string": "^0.30.21",
+ "obug": "^2.1.1",
+ "pathe": "^2.0.3",
+ "picomatch": "^4.0.3",
+ "std-env": "^4.0.0-rc.1",
+ "tinybench": "^2.9.0",
+ "tinyexec": "^1.0.2",
+ "tinyglobby": "^0.2.15",
+ "tinyrainbow": "^3.1.0",
+ "vite": "^6.0.0 || ^7.0.0 || ^8.0.0",
+ "why-is-node-running": "^2.3.0"
+ },
+ "bin": {
+ "vitest": "vitest.mjs"
+ },
+ "engines": {
+ "node": "^20.0.0 || ^22.0.0 || >=24.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ },
+ "peerDependencies": {
+ "@edge-runtime/vm": "*",
+ "@opentelemetry/api": "^1.9.0",
+ "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0",
+ "@vitest/browser-playwright": "4.1.9",
+ "@vitest/browser-preview": "4.1.9",
+ "@vitest/browser-webdriverio": "4.1.9",
+ "@vitest/coverage-istanbul": "4.1.9",
+ "@vitest/coverage-v8": "4.1.9",
+ "@vitest/ui": "4.1.9",
+ "happy-dom": "*",
+ "jsdom": "*",
+ "vite": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@edge-runtime/vm": {
+ "optional": true
+ },
+ "@opentelemetry/api": {
+ "optional": true
+ },
+ "@types/node": {
+ "optional": true
+ },
+ "@vitest/browser-playwright": {
+ "optional": true
+ },
+ "@vitest/browser-preview": {
+ "optional": true
+ },
+ "@vitest/browser-webdriverio": {
+ "optional": true
+ },
+ "@vitest/coverage-istanbul": {
+ "optional": true
+ },
+ "@vitest/coverage-v8": {
+ "optional": true
+ },
+ "@vitest/ui": {
+ "optional": true
+ },
+ "happy-dom": {
+ "optional": true
+ },
+ "jsdom": {
+ "optional": true
+ },
+ "vite": {
+ "optional": false
+ }
+ }
+ },
+ "packages/design-system/node_modules/vitest/node_modules/@vitest/mocker": {
+ "version": "4.1.9",
+ "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.9.tgz",
+ "integrity": "sha512-EVkXzBjrPGM+cK8/ANWgBrkUCfJfb38/EfTSO8h7pWvKkyPkpWxvR7BkD2MyItMF62C97zAEoqdpUixwR/e+Rw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vitest/spy": "4.1.9",
+ "estree-walker": "^3.0.3",
+ "magic-string": "^0.30.21"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ },
+ "peerDependencies": {
+ "msw": "^2.4.9",
+ "vite": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "msw": {
+ "optional": true
+ },
+ "vite": {
+ "optional": true
+ }
+ }
+ },
+ "packages/design-system/node_modules/ws": {
+ "version": "8.21.0",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz",
+ "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10.0.0"
+ },
+ "peerDependencies": {
+ "bufferutil": "^4.0.1",
+ "utf-8-validate": ">=5.0.2"
+ },
+ "peerDependenciesMeta": {
+ "bufferutil": {
+ "optional": true
+ },
+ "utf-8-validate": {
+ "optional": true
+ }
+ }
}
}
}
diff --git a/package.json b/package.json
index 8b3006f..fb6bc5f 100644
--- a/package.json
+++ b/package.json
@@ -4,7 +4,8 @@
"workspaces": [
"apps/backend",
"apps/frontend",
- "apps/docs"
+ "apps/docs",
+ "packages/design-system"
],
"scripts": {
"dev:backend": "npm run start:dev -w apps/backend",
@@ -18,17 +19,29 @@
"format:check": "prettier --check \"**/*.{ts,tsx}\"",
"dev:docs": "npm run dev -w apps/docs",
"build:docs": "npm run build -w apps/docs",
+ "build:design-system": "npm run build -w packages/design-system",
+ "test:design-system": "npm run test -w packages/design-system",
+ "lint:design-system": "npm run lint -w packages/design-system",
+ "storybook": "npm run storybook -w packages/design-system",
+ "build:storybook": "npm run build-storybook -w packages/design-system",
+ "test:storybook": "npm run test:storybook -w packages/design-system",
"prepare": "husky"
},
"lint-staged": {
"apps/backend/src/**/*.ts": ["eslint --max-warnings=0"],
"apps/backend/test/**/*.ts": ["eslint --max-warnings=0"],
"apps/frontend/src/**/*.{ts,tsx}": ["eslint --max-warnings=0"],
+ "packages/design-system/src/**/*.{ts,tsx}": ["eslint --max-warnings=0"],
"**/*.{ts,tsx}": ["prettier --check"]
},
"devDependencies": {
"husky": "^9.1.7",
"lint-staged": "^16.4.0",
"prettier": "^3.0.0"
+ },
+ "overrides": {
+ "@storybook/test": {
+ "storybook": "10.4.6"
+ }
}
}
diff --git a/packages/design-system/.eslintrc.cjs b/packages/design-system/.eslintrc.cjs
new file mode 100644
index 0000000..81b8a39
--- /dev/null
+++ b/packages/design-system/.eslintrc.cjs
@@ -0,0 +1,28 @@
+module.exports = {
+ parser: '@typescript-eslint/parser',
+ parserOptions: {
+ sourceType: 'module',
+ ecmaFeatures: { jsx: true },
+ },
+ plugins: ['@typescript-eslint/eslint-plugin', 'react', 'react-hooks'],
+ extends: [
+ 'plugin:@typescript-eslint/recommended',
+ 'plugin:react/recommended',
+ 'plugin:react-hooks/recommended',
+ ],
+ root: true,
+ env: {
+ browser: true,
+ es2020: true,
+ node: true,
+ },
+ settings: {
+ react: { version: 'detect' },
+ },
+ ignorePatterns: ['.eslintrc.cjs', 'vitest.config.ts', 'dist/', '.storybook/'],
+ rules: {
+ '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
+ '@typescript-eslint/no-explicit-any': 'off',
+ 'react/react-in-jsx-scope': 'off',
+ },
+};
diff --git a/packages/design-system/.gitignore b/packages/design-system/.gitignore
new file mode 100644
index 0000000..1591a0d
--- /dev/null
+++ b/packages/design-system/.gitignore
@@ -0,0 +1 @@
+storybook-static/
diff --git a/packages/design-system/.storybook/main.ts b/packages/design-system/.storybook/main.ts
new file mode 100644
index 0000000..d64c4bb
--- /dev/null
+++ b/packages/design-system/.storybook/main.ts
@@ -0,0 +1,9 @@
+import type { StorybookConfig } from '@storybook/react-vite';
+
+const config: StorybookConfig = {
+ framework: '@storybook/react-vite',
+ stories: ['../src/**/*.stories.@(ts|tsx)'],
+ addons: ['@storybook/addon-a11y', '@storybook/addon-vitest'],
+};
+
+export default config;
diff --git a/packages/design-system/.storybook/preview.tsx b/packages/design-system/.storybook/preview.tsx
new file mode 100644
index 0000000..7335a73
--- /dev/null
+++ b/packages/design-system/.storybook/preview.tsx
@@ -0,0 +1,24 @@
+import type { Preview } from '@storybook/react';
+import { MoexVibeThemeProvider } from '../src/theme';
+
+const preview: Preview = {
+ decorators: [
+ (Story) => (
+
+
+
+ ),
+ ],
+ parameters: {
+ a11y: {
+ test: 'error',
+ },
+ layout: 'centered',
+ backgrounds: {
+ default: 'canvas',
+ values: [{ name: 'canvas', value: '#f5f5f5' }],
+ },
+ },
+};
+
+export default preview;
diff --git a/packages/design-system/.storybook/vitest.setup.ts b/packages/design-system/.storybook/vitest.setup.ts
new file mode 100644
index 0000000..7ea17dc
--- /dev/null
+++ b/packages/design-system/.storybook/vitest.setup.ts
@@ -0,0 +1,5 @@
+import '@storybook/addon-a11y/preview';
+import { setProjectAnnotations } from '@storybook/react';
+import preview from './preview';
+
+setProjectAnnotations(preview);
diff --git a/packages/design-system/CHANGELOG.md b/packages/design-system/CHANGELOG.md
new file mode 100644
index 0000000..fd58626
--- /dev/null
+++ b/packages/design-system/CHANGELOG.md
@@ -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
diff --git a/packages/design-system/package.json b/packages/design-system/package.json
new file mode 100644
index 0000000..ec6d26a
--- /dev/null
+++ b/packages/design-system/package.json
@@ -0,0 +1,52 @@
+{
+ "name": "@moex-vibe/design-system",
+ "version": "0.1.0",
+ "private": true,
+ "type": "module",
+ "files": ["dist"],
+ "exports": {
+ ".": "./dist/index.js",
+ "./tokens": "./dist/tokens/index.js",
+ "./theme": "./dist/theme/index.js"
+ },
+ "scripts": {
+ "build": "tsc -p tsconfig.json",
+ "test": "vitest run --project unit",
+ "storybook": "storybook dev -p 6006 --no-open",
+ "build-storybook": "storybook build",
+ "test:storybook": "vitest run --project storybook",
+ "lint": "eslint \"src/**/*.{ts,tsx}\""
+ },
+ "peerDependencies": {
+ "@emotion/react": "^11.14.0",
+ "@emotion/styled": "^11.14.1",
+ "@mui/icons-material": "^6.5.0",
+ "@mui/material": "^6.5.0",
+ "@tanstack/react-table": "^8.21.3",
+ "react": "^18.3.0",
+ "react-dom": "^18.3.0"
+ },
+ "devDependencies": {
+ "@storybook/addon-a11y": "^10.2.9",
+ "@storybook/addon-vitest": "^10.2.9",
+ "@storybook/react-vite": "^10.2.9",
+ "@storybook/test": "^8.6.0",
+ "@testing-library/dom": "^10.4.0",
+ "@testing-library/jest-dom": "^6.9.1",
+ "@testing-library/react": "^16.3.2",
+ "@testing-library/user-event": "^14.6.1",
+ "@types/react": "^18.3.0",
+ "@types/react-dom": "^18.3.0",
+ "@typescript-eslint/eslint-plugin": "^7.0.0",
+ "@typescript-eslint/parser": "^7.0.0",
+ "@vitest/browser": "^4.1.8",
+ "@vitest/browser-playwright": "^4.1.8",
+ "eslint": "^8.0.0",
+ "eslint-plugin-react": "^7.34.0",
+ "eslint-plugin-react-hooks": "^4.6.0",
+ "playwright": "^1.55.0",
+ "storybook": "^10.2.9",
+ "typescript": "^5.3.0",
+ "vitest": "^4.1.8"
+ }
+}
diff --git a/packages/design-system/src/components/Alert/Alert.stories.tsx b/packages/design-system/src/components/Alert/Alert.stories.tsx
new file mode 100644
index 0000000..aa537e7
--- /dev/null
+++ b/packages/design-system/src/components/Alert/Alert.stories.tsx
@@ -0,0 +1,69 @@
+import type { Meta, StoryObj } from '@storybook/react';
+import { Button } from '../Button/Button';
+import { Alert } from './Alert';
+
+const meta: Meta = {
+ title: 'Feedback/Alert',
+ component: Alert,
+ argTypes: {
+ severity: {
+ control: 'select',
+ options: ['info', 'success', 'warning', 'error'],
+ },
+ title: { control: 'text' },
+ },
+};
+
+export default meta;
+type Story = StoryObj;
+
+export const Info: Story = {
+ args: {
+ severity: 'info',
+ title: 'Информация',
+ children: 'Данные обновляются каждые 15 минут',
+ },
+};
+
+export const Success: Story = {
+ args: {
+ severity: 'success',
+ title: 'Успешно',
+ children: 'Портфель успешно создан',
+ },
+};
+
+export const Warning: Story = {
+ args: {
+ severity: 'warning',
+ title: 'Внимание',
+ children: 'Цена акции превысила лимит',
+ },
+};
+
+export const Error: Story = {
+ args: {
+ severity: 'error',
+ title: 'Ошибка',
+ children: 'Не удалось загрузить данные',
+ },
+};
+
+export const WithAction: Story = {
+ args: {
+ severity: 'warning',
+ children: 'Обновите страницу для получения актуальных данных',
+ action: (
+
+ ),
+ },
+};
+
+export const WithoutTitle: Story = {
+ args: {
+ severity: 'info',
+ children: 'Просто информационное сообщение без заголовка',
+ },
+};
diff --git a/packages/design-system/src/components/Alert/Alert.test.tsx b/packages/design-system/src/components/Alert/Alert.test.tsx
new file mode 100644
index 0000000..3d63b08
--- /dev/null
+++ b/packages/design-system/src/components/Alert/Alert.test.tsx
@@ -0,0 +1,54 @@
+import { describe, it, expect } from 'vitest';
+import { render, screen } from '@testing-library/react';
+import { Alert } from './Alert';
+import { MoexVibeThemeProvider } from '../../theme';
+
+function renderWithTheme(element: React.ReactElement) {
+ return render({element});
+}
+
+describe('Alert', () => {
+ it('has role alert', () => {
+ renderWithTheme(Message);
+ expect(screen.getByRole('alert')).toBeInTheDocument();
+ });
+
+ it('renders severity mapping for info', () => {
+ renderWithTheme(Info message);
+ expect(screen.getByRole('alert')).toBeInTheDocument();
+ });
+
+ it('renders severity mapping for success', () => {
+ renderWithTheme(Success message);
+ expect(screen.getByRole('alert')).toBeInTheDocument();
+ });
+
+ it('renders severity mapping for warning', () => {
+ renderWithTheme(Warning message);
+ expect(screen.getByRole('alert')).toBeInTheDocument();
+ });
+
+ it('renders severity mapping for error', () => {
+ renderWithTheme(Error message);
+ expect(screen.getByRole('alert')).toBeInTheDocument();
+ });
+
+ it('renders title', () => {
+ renderWithTheme(
+
+ Something went wrong
+ ,
+ );
+ expect(screen.getByText('Error')).toBeInTheDocument();
+ expect(screen.getByText('Something went wrong')).toBeInTheDocument();
+ });
+
+ it('renders action', () => {
+ renderWithTheme(
+ Retry}>
+ Failed to load
+ ,
+ );
+ expect(screen.getByRole('button', { name: 'Retry' })).toBeInTheDocument();
+ });
+});
diff --git a/packages/design-system/src/components/Alert/Alert.tsx b/packages/design-system/src/components/Alert/Alert.tsx
new file mode 100644
index 0000000..73a63cc
--- /dev/null
+++ b/packages/design-system/src/components/Alert/Alert.tsx
@@ -0,0 +1,20 @@
+import { Alert as MuiAlert, type AlertProps as MuiAlertProps } from '@mui/material';
+import type { ReactNode } from 'react';
+
+type Severity = 'info' | 'success' | 'warning' | 'error';
+
+export interface AlertProps extends Omit {
+ severity: Severity;
+ title?: string;
+ children?: ReactNode;
+ action?: ReactNode;
+}
+
+export function Alert({ severity, title, children, action, ...props }: AlertProps) {
+ return (
+
+ {title && {title} }
+ {children}
+
+ );
+}
diff --git a/packages/design-system/src/components/Alert/index.ts b/packages/design-system/src/components/Alert/index.ts
new file mode 100644
index 0000000..7a4601f
--- /dev/null
+++ b/packages/design-system/src/components/Alert/index.ts
@@ -0,0 +1,2 @@
+export { Alert } from './Alert';
+export type { AlertProps } from './Alert';
diff --git a/packages/design-system/src/components/Badge/Badge.stories.tsx b/packages/design-system/src/components/Badge/Badge.stories.tsx
new file mode 100644
index 0000000..dd5ad31
--- /dev/null
+++ b/packages/design-system/src/components/Badge/Badge.stories.tsx
@@ -0,0 +1,41 @@
+import type { Meta, StoryObj } from '@storybook/react';
+import MailIcon from '@mui/icons-material/Mail';
+import { Badge } from './Badge';
+
+const meta: Meta = {
+ title: 'Surfaces/Badge',
+ component: Badge,
+ argTypes: {
+ value: { control: 'number' },
+ max: { control: 'number' },
+ label: { control: 'text' },
+ },
+};
+
+export default meta;
+type Story = StoryObj;
+
+export const Default: Story = {
+ args: {
+ value: 5,
+ label: 'Уведомления',
+ children: ,
+ },
+};
+
+export const Overflow: Story = {
+ args: {
+ value: 150,
+ max: 99,
+ label: 'Уведомления',
+ children: ,
+ },
+};
+
+export const Zero: Story = {
+ args: {
+ value: 0,
+ label: 'Уведомления',
+ children: ,
+ },
+};
diff --git a/packages/design-system/src/components/Badge/Badge.test.tsx b/packages/design-system/src/components/Badge/Badge.test.tsx
new file mode 100644
index 0000000..4c95e11
--- /dev/null
+++ b/packages/design-system/src/components/Badge/Badge.test.tsx
@@ -0,0 +1,31 @@
+import { describe, it, expect } from 'vitest';
+import { render, screen } from '@testing-library/react';
+import { Badge } from './Badge';
+import { MoexVibeThemeProvider } from '../../theme';
+
+function renderWithTheme(element: React.ReactElement) {
+ return render({element});
+}
+
+describe('Badge', () => {
+ it('displays value', () => {
+ renderWithTheme();
+ expect(screen.getByText('5')).toBeInTheDocument();
+ });
+
+ it('shows max overflow', () => {
+ renderWithTheme();
+ expect(screen.getByText('99+')).toBeInTheDocument();
+ });
+
+ it('has accessible label', () => {
+ renderWithTheme();
+ const badge = screen.getByLabelText('Notifications');
+ expect(badge).toBeInTheDocument();
+ });
+
+ it('does not render badge without label', () => {
+ const { container } = renderWithTheme();
+ expect(container.querySelector('.MuiBadge-badge')).toBeInTheDocument();
+ });
+});
diff --git a/packages/design-system/src/components/Badge/Badge.tsx b/packages/design-system/src/components/Badge/Badge.tsx
new file mode 100644
index 0000000..1cc1867
--- /dev/null
+++ b/packages/design-system/src/components/Badge/Badge.tsx
@@ -0,0 +1,17 @@
+import { Badge as MuiBadge } from '@mui/material';
+import type { ReactNode } from 'react';
+
+export interface BadgeProps {
+ value: number;
+ max?: number;
+ label: string;
+ children?: ReactNode;
+}
+
+export function Badge({ value, max = 99, label, children }: BadgeProps) {
+ return (
+
+ {children}
+
+ );
+}
diff --git a/packages/design-system/src/components/Badge/index.ts b/packages/design-system/src/components/Badge/index.ts
new file mode 100644
index 0000000..cd3531d
--- /dev/null
+++ b/packages/design-system/src/components/Badge/index.ts
@@ -0,0 +1,2 @@
+export { Badge } from './Badge';
+export type { BadgeProps } from './Badge';
diff --git a/packages/design-system/src/components/Button/Button.stories.tsx b/packages/design-system/src/components/Button/Button.stories.tsx
new file mode 100644
index 0000000..a876afa
--- /dev/null
+++ b/packages/design-system/src/components/Button/Button.stories.tsx
@@ -0,0 +1,105 @@
+import type { Meta, StoryObj } from '@storybook/react';
+import { Button } from './Button';
+
+const meta: Meta = {
+ title: 'Actions/Button',
+ component: Button,
+ argTypes: {
+ variant: {
+ control: 'select',
+ options: ['primary', 'secondary', 'tertiary', 'danger'],
+ },
+ size: {
+ control: 'select',
+ options: ['small', 'medium'],
+ },
+ loading: {
+ control: 'boolean',
+ },
+ disabled: {
+ control: 'boolean',
+ },
+ },
+};
+
+export default meta;
+type Story = StoryObj;
+
+export const Primary: Story = {
+ args: {
+ variant: 'primary',
+ children: 'Купить',
+ },
+};
+
+export const Secondary: Story = {
+ args: {
+ variant: 'secondary',
+ children: 'Отмена',
+ },
+};
+
+export const Tertiary: Story = {
+ args: {
+ variant: 'tertiary',
+ children: 'Подробнее',
+ },
+};
+
+export const Danger: Story = {
+ args: {
+ variant: 'danger',
+ children: 'Удалить портфель',
+ },
+};
+
+export const Small: Story = {
+ args: {
+ size: 'small',
+ children: 'Применить',
+ },
+};
+
+export const Loading: Story = {
+ args: {
+ loading: true,
+ children: 'Отправка...',
+ },
+};
+
+export const Disabled: Story = {
+ args: {
+ disabled: true,
+ children: 'Недоступно',
+ },
+};
+
+export const AllVariants: Story = {
+ render: () => (
+
+
+
+
+
+
+ ),
+};
+
+export const AllSizes: Story = {
+ render: () => (
+
+
+
+
+ ),
+};
+
+export const AllStates: Story = {
+ render: () => (
+
+
+
+
+
+ ),
+};
diff --git a/packages/design-system/src/components/Button/Button.test.tsx b/packages/design-system/src/components/Button/Button.test.tsx
new file mode 100644
index 0000000..6103dd0
--- /dev/null
+++ b/packages/design-system/src/components/Button/Button.test.tsx
@@ -0,0 +1,105 @@
+import { describe, it, expect, vi } from 'vitest';
+import { render, screen } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+import { Button } from './Button';
+import { MoexVibeThemeProvider } from '../../theme';
+
+function renderWithTheme(element: React.ReactElement) {
+ return render({element});
+}
+
+describe('Button', () => {
+ it('renders children', () => {
+ renderWithTheme();
+ expect(screen.getByText('Click me')).toBeInTheDocument();
+ });
+
+ it('renders as a button element by default', () => {
+ renderWithTheme();
+ expect(screen.getByRole('button', { name: /click/i })).toBeInTheDocument();
+ });
+
+ it('renders primary variant by default', () => {
+ renderWithTheme();
+ const btn = screen.getByRole('button');
+ expect(btn.classList.contains('MuiButton-contained')).toBe(true);
+ });
+
+ it('renders secondary variant', () => {
+ renderWithTheme();
+ const btn = screen.getByRole('button');
+ expect(btn.classList.contains('MuiButton-outlined')).toBe(true);
+ });
+
+ it('renders tertiary variant', () => {
+ renderWithTheme();
+ const btn = screen.getByRole('button');
+ expect(btn.classList.contains('MuiButton-text')).toBe(true);
+ });
+
+ it('renders danger variant with contained style', () => {
+ renderWithTheme();
+ const btn = screen.getByRole('button');
+ expect(btn.classList.contains('MuiButton-contained')).toBe(true);
+ });
+
+ it('does not pass color prop to DOM', () => {
+ renderWithTheme();
+ const btn = screen.getByRole('button');
+ expect(btn).not.toHaveAttribute('color');
+ });
+
+ it('accepts className and style props', () => {
+ renderWithTheme(
+ ,
+ );
+ const btn = screen.getByText('Click');
+ expect(btn.classList.contains('custom')).toBe(true);
+ });
+
+ it('calls onClick when clicked', async () => {
+ const handleClick = vi.fn();
+ const user = userEvent.setup();
+ renderWithTheme();
+ await user.click(screen.getByRole('button'));
+ expect(handleClick).toHaveBeenCalledTimes(1);
+ });
+
+ it('shows aria-busy when loading', () => {
+ renderWithTheme();
+ const btn = screen.getByRole('button');
+ expect(btn).toHaveAttribute('aria-busy', 'true');
+ });
+
+ it('disables button when loading', () => {
+ renderWithTheme();
+ const btn = screen.getByRole('button');
+ expect(btn).toBeDisabled();
+ });
+
+ it('does not call onClick when loading', () => {
+ const handleClick = vi.fn();
+ const { container } = renderWithTheme(
+ ,
+ );
+ const btn = container.querySelector('button')!;
+ btn.click();
+ expect(handleClick).not.toHaveBeenCalled();
+ });
+
+ it('renders small size', () => {
+ renderWithTheme();
+ const btn = screen.getByRole('button');
+ expect(btn.classList.contains('MuiButton-sizeSmall')).toBe(true);
+ });
+
+ it('renders medium size by default', () => {
+ renderWithTheme();
+ const btn = screen.getByRole('button');
+ expect(btn.classList.contains('MuiButton-sizeMedium')).toBe(true);
+ });
+});
diff --git a/packages/design-system/src/components/Button/Button.tsx b/packages/design-system/src/components/Button/Button.tsx
new file mode 100644
index 0000000..788c08f
--- /dev/null
+++ b/packages/design-system/src/components/Button/Button.tsx
@@ -0,0 +1,48 @@
+import {
+ Button as MuiButton,
+ CircularProgress,
+ type ButtonProps as MuiButtonProps,
+} from '@mui/material';
+import type { ReactNode } from 'react';
+
+type ActionVariant = 'primary' | 'secondary' | 'tertiary' | 'danger';
+
+export interface ButtonProps extends Omit {
+ variant?: ActionVariant;
+ size?: 'small' | 'medium';
+ loading?: boolean;
+ children: ReactNode;
+}
+
+const VARIANT_MAP: Record = {
+ primary: 'contained',
+ secondary: 'outlined',
+ tertiary: 'text',
+ danger: 'contained',
+};
+
+export function Button({
+ variant = 'primary',
+ size = 'medium',
+ loading = false,
+ disabled,
+ children,
+ ...props
+}: ButtonProps) {
+ const muiVariant = VARIANT_MAP[variant];
+ const muiColor = variant === 'danger' ? 'error' : undefined;
+
+ return (
+
+ {loading && }
+ {children}
+
+ );
+}
diff --git a/packages/design-system/src/components/Button/index.ts b/packages/design-system/src/components/Button/index.ts
new file mode 100644
index 0000000..fa3c8a5
--- /dev/null
+++ b/packages/design-system/src/components/Button/index.ts
@@ -0,0 +1,2 @@
+export { Button } from './Button';
+export type { ButtonProps } from './Button';
diff --git a/packages/design-system/src/components/Card/Card.stories.tsx b/packages/design-system/src/components/Card/Card.stories.tsx
new file mode 100644
index 0000000..c8ad0a9
--- /dev/null
+++ b/packages/design-system/src/components/Card/Card.stories.tsx
@@ -0,0 +1,56 @@
+import type { Meta, StoryObj } from '@storybook/react';
+import { Button } from '../Button/Button';
+import { Card } from './Card';
+
+const meta: Meta = {
+ title: 'Surfaces/Card',
+ component: Card,
+ argTypes: {
+ padding: {
+ control: 'select',
+ options: ['none', 'sm', 'md', 'lg'],
+ },
+ elevation: {
+ control: 'select',
+ options: ['none', 'sm', 'md'],
+ },
+ },
+};
+
+export default meta;
+type Story = StoryObj;
+
+export const Default: Story = {
+ args: {
+ children: 'Основное содержимое карточки',
+ },
+};
+
+export const WithHeader: Story = {
+ args: {
+ header: Заголовок карточки,
+ children: 'Текст внутри карточки с заголовком',
+ },
+};
+
+export const WithActions: Story = {
+ args: {
+ children: 'Карточка с действиями',
+ actions: ,
+ },
+};
+
+export const FullCard: Story = {
+ args: {
+ header: Портфель акций,
+ children: 'Состав портфеля: Сбербанк, Лукойл, Газпром',
+ actions: (
+
+
+
+
+ ),
+ },
+};
diff --git a/packages/design-system/src/components/Card/Card.test.tsx b/packages/design-system/src/components/Card/Card.test.tsx
new file mode 100644
index 0000000..d6866d3
--- /dev/null
+++ b/packages/design-system/src/components/Card/Card.test.tsx
@@ -0,0 +1,39 @@
+import { describe, it, expect } from 'vitest';
+import { render, screen } from '@testing-library/react';
+import { Card } from './Card';
+import { MoexVibeThemeProvider } from '../../theme';
+
+function renderWithTheme(element: React.ReactElement) {
+ return render({element});
+}
+
+describe('Card', () => {
+ it('renders children', () => {
+ renderWithTheme(Body);
+ expect(screen.getByText('Body')).toBeInTheDocument();
+ });
+
+ it('renders header', () => {
+ renderWithTheme(Body);
+ expect(screen.getByText('Header')).toBeInTheDocument();
+ });
+
+ it('renders actions', () => {
+ renderWithTheme(Action}>Body);
+ expect(screen.getByRole('button', { name: 'Action' })).toBeInTheDocument();
+ });
+
+ it('accepts Surface padding prop', () => {
+ renderWithTheme(
+
+ Body
+ ,
+ );
+ expect(screen.getByText('Body').closest('.MuiPaper-root')).toBeInTheDocument();
+ });
+
+ it('renders without header and actions', () => {
+ renderWithTheme(Body);
+ expect(screen.getByText('Body')).toBeInTheDocument();
+ });
+});
diff --git a/packages/design-system/src/components/Card/Card.tsx b/packages/design-system/src/components/Card/Card.tsx
new file mode 100644
index 0000000..17a0fa6
--- /dev/null
+++ b/packages/design-system/src/components/Card/Card.tsx
@@ -0,0 +1,17 @@
+import type { ReactNode } from 'react';
+import { Surface, type SurfaceProps } from '../Surface/Surface';
+
+export interface CardProps extends SurfaceProps {
+ header?: ReactNode;
+ actions?: ReactNode;
+}
+
+export function Card({ header, actions, children, ...surfaceProps }: CardProps) {
+ return (
+
+ {header && {header} }
+ {children}
+ {actions && {actions} }
+
+ );
+}
diff --git a/packages/design-system/src/components/Card/index.ts b/packages/design-system/src/components/Card/index.ts
new file mode 100644
index 0000000..050a95d
--- /dev/null
+++ b/packages/design-system/src/components/Card/index.ts
@@ -0,0 +1,2 @@
+export { Card } from './Card';
+export type { CardProps } from './Card';
diff --git a/packages/design-system/src/components/Checkbox/Checkbox.stories.tsx b/packages/design-system/src/components/Checkbox/Checkbox.stories.tsx
new file mode 100644
index 0000000..040cd4c
--- /dev/null
+++ b/packages/design-system/src/components/Checkbox/Checkbox.stories.tsx
@@ -0,0 +1,51 @@
+import type { Meta, StoryObj } from '@storybook/react';
+import { fn } from '@storybook/test';
+import { Checkbox } from './Checkbox';
+
+const meta: Meta = {
+ title: 'Inputs/Checkbox',
+ component: Checkbox,
+ argTypes: {
+ label: { control: 'text' },
+ checked: { control: 'boolean' },
+ disabled: { control: 'boolean' },
+ error: { control: 'boolean' },
+ },
+};
+
+export default meta;
+type Story = StoryObj;
+
+export const Unchecked: Story = {
+ args: {
+ label: 'Согласен с условиями',
+ checked: false,
+ onChange: fn(),
+ },
+};
+
+export const Checked: Story = {
+ args: {
+ label: 'Согласен с условиями',
+ checked: true,
+ onChange: fn(),
+ },
+};
+
+export const Disabled: Story = {
+ args: {
+ label: 'Недоступно',
+ checked: false,
+ onChange: fn(),
+ disabled: true,
+ },
+};
+
+export const Error: Story = {
+ args: {
+ label: 'Согласен с условиями',
+ checked: false,
+ onChange: fn(),
+ error: true,
+ },
+};
diff --git a/packages/design-system/src/components/Checkbox/Checkbox.test.tsx b/packages/design-system/src/components/Checkbox/Checkbox.test.tsx
new file mode 100644
index 0000000..49af3ba
--- /dev/null
+++ b/packages/design-system/src/components/Checkbox/Checkbox.test.tsx
@@ -0,0 +1,57 @@
+import { describe, it, expect, vi } from 'vitest';
+import { render, screen } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+import { Checkbox } from './Checkbox';
+import { MoexVibeThemeProvider } from '../../theme';
+
+function renderWithTheme(element: React.ReactElement) {
+ return render({element});
+}
+
+describe('Checkbox', () => {
+ it('renders label', () => {
+ renderWithTheme( {}} />);
+ expect(screen.getByText('Agree')).toBeInTheDocument();
+ });
+
+ it('toggles on label click', async () => {
+ const handleChange = vi.fn();
+ const user = userEvent.setup();
+ renderWithTheme();
+ await user.click(screen.getByText('Agree'));
+ expect(handleChange).toHaveBeenCalledWith(true);
+ });
+
+ it('toggles on checkbox click', async () => {
+ const handleChange = vi.fn();
+ const user = userEvent.setup();
+ renderWithTheme();
+ await user.click(screen.getByRole('checkbox'));
+ expect(handleChange).toHaveBeenCalledWith(true);
+ });
+
+ it('calls onChange with false when checked', async () => {
+ const handleChange = vi.fn();
+ const user = userEvent.setup();
+ renderWithTheme();
+ await user.click(screen.getByRole('checkbox'));
+ expect(handleChange).toHaveBeenCalledWith(false);
+ });
+
+ it('can be disabled', () => {
+ renderWithTheme( {}} disabled />);
+ expect(screen.getByRole('checkbox')).toBeDisabled();
+ });
+
+ it('shows error state', () => {
+ renderWithTheme( {}} error />);
+ const checkbox = screen.getByRole('checkbox');
+ expect(checkbox).toHaveAttribute('aria-invalid', 'true');
+ });
+
+ it('does not pass sx to DOM', () => {
+ renderWithTheme( {}} />);
+ const checkbox = screen.getByRole('checkbox');
+ expect(checkbox).not.toHaveAttribute('sx');
+ });
+});
diff --git a/packages/design-system/src/components/Checkbox/Checkbox.tsx b/packages/design-system/src/components/Checkbox/Checkbox.tsx
new file mode 100644
index 0000000..f414b5f
--- /dev/null
+++ b/packages/design-system/src/components/Checkbox/Checkbox.tsx
@@ -0,0 +1,26 @@
+import { FormControlLabel, Checkbox as MuiCheckbox } from '@mui/material';
+
+export interface CheckboxProps {
+ label: string;
+ checked: boolean;
+ onChange: (checked: boolean) => void;
+ disabled?: boolean;
+ error?: boolean;
+}
+
+export function Checkbox({ label, checked, onChange, disabled, error }: CheckboxProps) {
+ return (
+ onChange(ch)}
+ disabled={disabled}
+ inputProps={error ? { 'aria-invalid': 'true' as const } : undefined}
+ />
+ }
+ label={label}
+ disabled={disabled}
+ />
+ );
+}
diff --git a/packages/design-system/src/components/Checkbox/index.ts b/packages/design-system/src/components/Checkbox/index.ts
new file mode 100644
index 0000000..43aaf92
--- /dev/null
+++ b/packages/design-system/src/components/Checkbox/index.ts
@@ -0,0 +1,2 @@
+export { Checkbox } from './Checkbox';
+export type { CheckboxProps } from './Checkbox';
diff --git a/packages/design-system/src/components/Chip/Chip.stories.tsx b/packages/design-system/src/components/Chip/Chip.stories.tsx
new file mode 100644
index 0000000..072a9ab
--- /dev/null
+++ b/packages/design-system/src/components/Chip/Chip.stories.tsx
@@ -0,0 +1,74 @@
+import type { Meta, StoryObj } from '@storybook/react';
+import { fn } from '@storybook/test';
+import { Chip } from './Chip';
+
+const meta: Meta = {
+ title: 'Surfaces/Chip',
+ component: Chip,
+ argTypes: {
+ label: { control: 'text' },
+ tone: {
+ control: 'select',
+ options: ['neutral', 'info', 'success', 'warning', 'error'],
+ },
+ onDelete: { action: 'deleted' },
+ },
+};
+
+export default meta;
+type Story = StoryObj;
+
+export const Neutral: Story = {
+ args: {
+ label: 'Черновик',
+ tone: 'neutral',
+ },
+};
+
+export const Info: Story = {
+ args: {
+ label: 'Новое',
+ tone: 'info',
+ },
+};
+
+export const Success: Story = {
+ args: {
+ label: 'Активно',
+ tone: 'success',
+ },
+};
+
+export const Warning: Story = {
+ args: {
+ label: 'Внимание',
+ tone: 'warning',
+ },
+};
+
+export const Error: Story = {
+ args: {
+ label: 'Ошибка',
+ tone: 'error',
+ },
+};
+
+export const Deletable: Story = {
+ args: {
+ label: 'Акция',
+ tone: 'info',
+ onDelete: fn(),
+ },
+};
+
+export const AllTones: Story = {
+ render: () => (
+
+
+
+
+
+
+
+ ),
+};
diff --git a/packages/design-system/src/components/Chip/Chip.test.tsx b/packages/design-system/src/components/Chip/Chip.test.tsx
new file mode 100644
index 0000000..d5d91ea
--- /dev/null
+++ b/packages/design-system/src/components/Chip/Chip.test.tsx
@@ -0,0 +1,62 @@
+import { describe, it, expect, vi } from 'vitest';
+import { render, screen } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+import { Chip } from './Chip';
+import { MoexVibeThemeProvider } from '../../theme';
+
+function renderWithTheme(element: React.ReactElement) {
+ return render({element});
+}
+
+describe('Chip', () => {
+ it('renders label', () => {
+ renderWithTheme();
+ expect(screen.getByText('Default')).toBeInTheDocument();
+ });
+
+ it('renders with neutral tone by default', () => {
+ renderWithTheme();
+ const chip = screen.getByText('Neutral').closest('.MuiChip-root')!;
+ expect(chip.classList.contains('MuiChip-filled')).toBe(true);
+ });
+
+ it('renders info tone', () => {
+ renderWithTheme();
+ expect(screen.getByText('Info')).toBeInTheDocument();
+ });
+
+ it('renders success tone', () => {
+ renderWithTheme();
+ expect(screen.getByText('Success')).toBeInTheDocument();
+ });
+
+ it('renders warning tone', () => {
+ renderWithTheme();
+ expect(screen.getByText('Warning')).toBeInTheDocument();
+ });
+
+ it('renders error tone', () => {
+ renderWithTheme();
+ expect(screen.getByText('Error')).toBeInTheDocument();
+ });
+
+ it('shows delete button when onDelete provided', () => {
+ renderWithTheme( {}} />);
+ const deleteIcon = screen.getByLabelText('Remove Removable');
+ expect(deleteIcon).toBeInTheDocument();
+ });
+
+ it('calls onDelete when delete clicked', async () => {
+ const handleDelete = vi.fn();
+ const user = userEvent.setup();
+ renderWithTheme();
+ const deleteIcon = screen.getByLabelText('Remove Removable');
+ await user.click(deleteIcon);
+ expect(handleDelete).toHaveBeenCalledTimes(1);
+ });
+
+ it('does not show delete button without onDelete', () => {
+ renderWithTheme();
+ expect(screen.queryByRole('button')).not.toBeInTheDocument();
+ });
+});
diff --git a/packages/design-system/src/components/Chip/Chip.tsx b/packages/design-system/src/components/Chip/Chip.tsx
new file mode 100644
index 0000000..f6b328e
--- /dev/null
+++ b/packages/design-system/src/components/Chip/Chip.tsx
@@ -0,0 +1,29 @@
+import { Chip as MuiChip } from '@mui/material';
+import CancelIcon from '@mui/icons-material/Cancel';
+
+type Tone = 'neutral' | 'info' | 'success' | 'warning' | 'error';
+
+const TONE_MAP: Record = {
+ neutral: 'default',
+ info: 'info',
+ success: 'success',
+ warning: 'warning',
+ error: 'error',
+};
+
+export interface ChipProps {
+ label: string;
+ tone?: Tone;
+ onDelete?: () => void;
+}
+
+export function Chip({ label, tone = 'neutral', onDelete }: ChipProps) {
+ return (
+ } : {})}
+ />
+ );
+}
diff --git a/packages/design-system/src/components/Chip/index.ts b/packages/design-system/src/components/Chip/index.ts
new file mode 100644
index 0000000..cbdcf05
--- /dev/null
+++ b/packages/design-system/src/components/Chip/index.ts
@@ -0,0 +1,2 @@
+export { Chip } from './Chip';
+export type { ChipProps } from './Chip';
diff --git a/packages/design-system/src/components/DataTable/DataTable.stories.tsx b/packages/design-system/src/components/DataTable/DataTable.stories.tsx
new file mode 100644
index 0000000..df90297
--- /dev/null
+++ b/packages/design-system/src/components/DataTable/DataTable.stories.tsx
@@ -0,0 +1,121 @@
+import type { Meta, StoryObj } from '@storybook/react';
+import { DataTable } from './DataTable';
+import { MoexVibeThemeProvider } from '../../theme';
+import {
+ useReactTable,
+ getCoreRowModel,
+ createColumnHelper,
+ getSortedRowModel,
+} from '@tanstack/react-table';
+import type { SortingState } from '@tanstack/react-table';
+import { useState } from 'react';
+
+interface Stock {
+ ticker: string;
+ price: number;
+ change: number;
+}
+
+const data: Stock[] = [
+ { ticker: 'SBER', price: 281.5, change: 1.2 },
+ { ticker: 'GAZP', price: 162.3, change: -0.5 },
+ { ticker: 'LKOH', price: 7_112.0, change: 2.1 },
+ { ticker: 'YNDX', price: 5_413.0, change: -1.8 },
+];
+
+const columnHelper = createColumnHelper();
+
+const columns = [
+ columnHelper.accessor('ticker', { header: 'Тикер' }),
+ columnHelper.accessor('price', { header: 'Цена' }),
+ columnHelper.accessor('change', { header: 'Изменение' }),
+];
+
+function SortableTableStory() {
+ const [sorting, setSorting] = useState([]);
+ const table = useReactTable({
+ data,
+ columns,
+ getCoreRowModel: getCoreRowModel(),
+ getSortedRowModel: getSortedRowModel(),
+ state: { sorting },
+ onSortingChange: setSorting,
+ });
+ return (
+
+
+
+ );
+}
+
+const meta: Meta = {
+ title: 'Data/DataTable',
+ component: DataTable,
+};
+
+export default meta;
+type Story = StoryObj;
+
+export const Default: Story = {
+ render: () => {
+ const table = useReactTable({
+ data,
+ columns,
+ getCoreRowModel: getCoreRowModel(),
+ });
+ return (
+
+
+
+ );
+ },
+};
+
+export const Compact: Story = {
+ render: () => {
+ const table = useReactTable({
+ data,
+ columns,
+ getCoreRowModel: getCoreRowModel(),
+ });
+ return (
+
+
+
+ );
+ },
+};
+
+export const Sortable: Story = {
+ render: () => ,
+};
+
+export const Empty: Story = {
+ render: () => {
+ const table = useReactTable({
+ data: [],
+ columns,
+ getCoreRowModel: getCoreRowModel(),
+ });
+ return (
+
+ Нет данных} />
+
+ );
+ },
+};
+
+export const Loading: Story = {
+ render: () => {
+ const table = useReactTable({
+ data: [],
+ columns,
+ getCoreRowModel: getCoreRowModel(),
+ });
+ return (
+
+
+
+ );
+ },
+};
diff --git a/packages/design-system/src/components/DataTable/DataTable.test.tsx b/packages/design-system/src/components/DataTable/DataTable.test.tsx
new file mode 100644
index 0000000..0787eca
--- /dev/null
+++ b/packages/design-system/src/components/DataTable/DataTable.test.tsx
@@ -0,0 +1,97 @@
+import { describe, it, expect } from 'vitest';
+import { render, screen } from '@testing-library/react';
+import { DataTable } from './DataTable';
+import { MoexVibeThemeProvider } from '../../theme';
+import { useReactTable, getCoreRowModel, createColumnHelper } from '@tanstack/react-table';
+
+interface Item {
+ name: string;
+ price: number;
+}
+
+const data: Item[] = [
+ { name: 'AAPL', price: 250 },
+ { name: 'GOOGL', price: 180 },
+];
+
+const columnHelper = createColumnHelper- ();
+
+const columns = [
+ columnHelper.accessor('name', { header: 'Name' }),
+ columnHelper.accessor('price', { header: 'Price' }),
+];
+
+function TestTable({ caption }: { caption: string }) {
+ const table = useReactTable({
+ data,
+ columns,
+ getCoreRowModel: getCoreRowModel(),
+ });
+ return (
+
+
+
+ );
+}
+
+function TestTableWithProps(props: {
+ caption: string;
+ loading?: boolean;
+ empty?: React.ReactNode;
+ density?: 'balanced' | 'compact';
+}) {
+ const table = useReactTable({
+ data,
+ columns,
+ getCoreRowModel: getCoreRowModel(),
+ });
+ return (
+
+
+
+ );
+}
+
+function EmptyTable() {
+ const table = useReactTable({
+ data: [],
+ columns,
+ getCoreRowModel: getCoreRowModel(),
+ });
+ return (
+
+ No data} />
+
+ );
+}
+
+describe('DataTable', () => {
+ it('renders caption', () => {
+ render();
+ expect(screen.getByText('Test Caption')).toBeInTheDocument();
+ });
+
+ it('renders column headers as th elements', () => {
+ render();
+ const headers = screen.getAllByRole('columnheader');
+ expect(headers).toHaveLength(2);
+ expect(headers[0]).toHaveTextContent('Name');
+ expect(headers[1]).toHaveTextContent('Price');
+ });
+
+ it('renders data rows', () => {
+ render();
+ expect(screen.getByText('AAPL')).toBeInTheDocument();
+ expect(screen.getByText('GOOGL')).toBeInTheDocument();
+ });
+
+ it('renders with compact density', () => {
+ render();
+ expect(screen.getByRole('table')).toBeInTheDocument();
+ });
+
+ it('shows empty state when no data', () => {
+ render();
+ expect(screen.getByText('No data')).toBeInTheDocument();
+ });
+});
diff --git a/packages/design-system/src/components/DataTable/DataTable.tsx b/packages/design-system/src/components/DataTable/DataTable.tsx
new file mode 100644
index 0000000..911e109
--- /dev/null
+++ b/packages/design-system/src/components/DataTable/DataTable.tsx
@@ -0,0 +1,73 @@
+import type { ReactNode } from 'react';
+import {
+ Table,
+ TableContainer,
+ TableHead,
+ TableBody,
+ TableRow,
+ TableCell,
+ type TableProps as MuiTableProps,
+} from '@mui/material';
+import type { Table as TanStackTable } from '@tanstack/react-table';
+import { flexRender } from '@tanstack/react-table';
+
+export type Density = 'balanced' | 'compact';
+
+export interface DataTableProps {
+ table: TanStackTable;
+ density?: Density;
+ loading?: boolean;
+ empty?: ReactNode;
+ caption: string;
+}
+
+const DENSITY_PADDING: Record = {
+ balanced: 'medium',
+ compact: 'small',
+};
+
+export function DataTable({
+ table,
+ density = 'balanced',
+ loading,
+ empty,
+ caption,
+}: DataTableProps) {
+ const rows = table.getRowModel().rows;
+
+ if (!loading && rows.length === 0 && empty) {
+ return <>{empty}>;
+ }
+
+ return (
+
+
+ {caption}
+
+ {table.getHeaderGroups().map((headerGroup) => (
+
+ {headerGroup.headers.map((header) => (
+
+ {header.isPlaceholder
+ ? null
+ : flexRender(header.column.columnDef.header, header.getContext())}
+
+ ))}
+
+ ))}
+
+
+ {rows.map((row) => (
+
+ {row.getVisibleCells().map((cell) => (
+
+ {flexRender(cell.column.columnDef.cell, cell.getContext())}
+
+ ))}
+
+ ))}
+
+
+
+ );
+}
diff --git a/packages/design-system/src/components/DataTable/index.ts b/packages/design-system/src/components/DataTable/index.ts
new file mode 100644
index 0000000..39d6048
--- /dev/null
+++ b/packages/design-system/src/components/DataTable/index.ts
@@ -0,0 +1,2 @@
+export { DataTable } from './DataTable';
+export type { DataTableProps, Density } from './DataTable';
diff --git a/packages/design-system/src/components/Dialog/Dialog.stories.tsx b/packages/design-system/src/components/Dialog/Dialog.stories.tsx
new file mode 100644
index 0000000..1bec21b
--- /dev/null
+++ b/packages/design-system/src/components/Dialog/Dialog.stories.tsx
@@ -0,0 +1,61 @@
+import { useState } from 'react';
+import type { Meta, StoryObj } from '@storybook/react';
+import { fn } from '@storybook/test';
+import { Button } from '../Button/Button';
+import { Dialog } from './Dialog';
+
+const meta: Meta = {
+ title: 'Feedback/Dialog',
+ component: Dialog,
+ argTypes: {
+ open: { control: 'boolean' },
+ title: { control: 'text' },
+ },
+};
+
+export default meta;
+type Story = StoryObj;
+
+export const Default: Story = {
+ args: {
+ open: true,
+ onClose: fn(),
+ title: 'Подтверждение',
+ children: 'Вы уверены, что хотите удалить этот портфель?',
+ },
+};
+
+export const WithActions: Story = {
+ args: {
+ open: true,
+ onClose: fn(),
+ title: 'Удаление портфеля',
+ children: 'Портфель "Акции США" будет безвозвратно удалён',
+ actions: (
+
+
+
+
+ ),
+ },
+};
+
+export const Interactive: Story = {
+ render: () => {
+ // eslint-disable-next-line react-hooks/rules-of-hooks
+ const [open, setOpen] = useState(false);
+ return (
+ <>
+
+
+ >
+ );
+ },
+};
diff --git a/packages/design-system/src/components/Dialog/Dialog.test.tsx b/packages/design-system/src/components/Dialog/Dialog.test.tsx
new file mode 100644
index 0000000..067d915
--- /dev/null
+++ b/packages/design-system/src/components/Dialog/Dialog.test.tsx
@@ -0,0 +1,81 @@
+import { describe, it, expect, vi } from 'vitest';
+import { render, screen } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+import { Dialog } from './Dialog';
+import { MoexVibeThemeProvider } from '../../theme';
+
+function renderWithTheme(element: React.ReactElement) {
+ return render({element});
+}
+
+describe('Dialog', () => {
+ it('renders when open', () => {
+ renderWithTheme(
+ ,
+ );
+ expect(screen.getByRole('dialog')).toBeInTheDocument();
+ });
+
+ it('does not render when closed', () => {
+ renderWithTheme(
+ ,
+ );
+ expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
+ });
+
+ it('has aria-labelledby pointing to title', () => {
+ renderWithTheme(
+ ,
+ );
+ const dialog = screen.getByRole('dialog');
+ const titleId = dialog.getAttribute('aria-labelledby');
+ expect(titleId).toBeTruthy();
+ const titleEl = document.getElementById(titleId!);
+ expect(titleEl).toHaveTextContent('Confirm');
+ });
+
+ it('calls onClose on Escape', async () => {
+ const handleClose = vi.fn();
+ const user = userEvent.setup();
+ renderWithTheme(
+ ,
+ );
+ await user.keyboard('{Escape}');
+ expect(handleClose).toHaveBeenCalledTimes(1);
+ });
+
+ it('renders title', () => {
+ renderWithTheme(
+ ,
+ );
+ expect(screen.getByText('Confirm')).toBeInTheDocument();
+ });
+
+ it('renders children', () => {
+ renderWithTheme(
+ ,
+ );
+ expect(screen.getByText('Are you sure?')).toBeInTheDocument();
+ });
+
+ it('renders actions', () => {
+ renderWithTheme(
+ ,
+ );
+ expect(screen.getByRole('button', { name: 'OK' })).toBeInTheDocument();
+ });
+});
diff --git a/packages/design-system/src/components/Dialog/Dialog.tsx b/packages/design-system/src/components/Dialog/Dialog.tsx
new file mode 100644
index 0000000..af88d10
--- /dev/null
+++ b/packages/design-system/src/components/Dialog/Dialog.tsx
@@ -0,0 +1,23 @@
+import { useId } from 'react';
+import { Dialog as MuiDialog, DialogTitle, DialogContent, DialogActions } from '@mui/material';
+import type { ReactNode } from 'react';
+
+export interface DialogProps {
+ open: boolean;
+ onClose: () => void;
+ title: string;
+ children: ReactNode;
+ actions?: ReactNode;
+}
+
+export function Dialog({ open, onClose, title, children, actions }: DialogProps) {
+ const titleId = useId();
+
+ return (
+
+ {title}
+ {children}
+ {actions && {actions}}
+
+ );
+}
diff --git a/packages/design-system/src/components/Dialog/index.ts b/packages/design-system/src/components/Dialog/index.ts
new file mode 100644
index 0000000..4fdb7d5
--- /dev/null
+++ b/packages/design-system/src/components/Dialog/index.ts
@@ -0,0 +1,2 @@
+export { Dialog } from './Dialog';
+export type { DialogProps } from './Dialog';
diff --git a/packages/design-system/src/components/EmptyState/EmptyState.stories.tsx b/packages/design-system/src/components/EmptyState/EmptyState.stories.tsx
new file mode 100644
index 0000000..5331a49
--- /dev/null
+++ b/packages/design-system/src/components/EmptyState/EmptyState.stories.tsx
@@ -0,0 +1,36 @@
+import type { Meta, StoryObj } from '@storybook/react';
+import { Button } from '../Button';
+import { EmptyState } from './EmptyState';
+
+const meta: Meta = {
+ title: 'Feedback/EmptyState',
+ component: EmptyState,
+ argTypes: {
+ title: { control: 'text' },
+ description: { control: 'text' },
+ },
+};
+
+export default meta;
+type Story = StoryObj;
+
+export const Basic: Story = {
+ args: {
+ title: 'No data available',
+ description: 'Try adjusting your filters or date range.',
+ },
+};
+
+export const WithAction: Story = {
+ args: {
+ title: 'No securities found',
+ description: 'Try a different search query.',
+ action: ,
+ },
+};
+
+export const Minimal: Story = {
+ args: {
+ title: 'Nothing here yet',
+ },
+};
diff --git a/packages/design-system/src/components/EmptyState/EmptyState.test.tsx b/packages/design-system/src/components/EmptyState/EmptyState.test.tsx
new file mode 100644
index 0000000..ab70e44
--- /dev/null
+++ b/packages/design-system/src/components/EmptyState/EmptyState.test.tsx
@@ -0,0 +1,26 @@
+import { describe, it, expect } from 'vitest';
+import { render, screen } from '@testing-library/react';
+import { EmptyState } from './EmptyState';
+import { MoexVibeThemeProvider } from '../../theme';
+
+function renderWithTheme(element: React.ReactElement) {
+ return render({element});
+}
+
+describe('EmptyState', () => {
+ it('renders title as semantic heading', () => {
+ renderWithTheme();
+ const heading = screen.getByText('No data');
+ expect(heading.tagName).toBe('H2');
+ });
+
+ it('renders description', () => {
+ renderWithTheme();
+ expect(screen.getByText('Try adjusting filters')).toBeInTheDocument();
+ });
+
+ it('renders action', () => {
+ renderWithTheme(Refresh} />);
+ expect(screen.getByRole('button', { name: 'Refresh' })).toBeInTheDocument();
+ });
+});
diff --git a/packages/design-system/src/components/EmptyState/EmptyState.tsx b/packages/design-system/src/components/EmptyState/EmptyState.tsx
new file mode 100644
index 0000000..019f708
--- /dev/null
+++ b/packages/design-system/src/components/EmptyState/EmptyState.tsx
@@ -0,0 +1,20 @@
+import type { ReactNode } from 'react';
+import { Stack } from '@mui/material';
+import { Heading } from '../Heading';
+import { Text } from '../Text';
+
+export interface EmptyStateProps {
+ title: string;
+ description?: string;
+ action?: ReactNode;
+}
+
+export function EmptyState({ title, description, action }: EmptyStateProps) {
+ return (
+
+ {title}
+ {description && {description}}
+ {action && {action} }
+
+ );
+}
diff --git a/packages/design-system/src/components/EmptyState/index.ts b/packages/design-system/src/components/EmptyState/index.ts
new file mode 100644
index 0000000..0d24236
--- /dev/null
+++ b/packages/design-system/src/components/EmptyState/index.ts
@@ -0,0 +1,2 @@
+export { EmptyState } from './EmptyState';
+export type { EmptyStateProps } from './EmptyState';
diff --git a/packages/design-system/src/components/ErrorState/ErrorState.stories.tsx b/packages/design-system/src/components/ErrorState/ErrorState.stories.tsx
new file mode 100644
index 0000000..f7efff5
--- /dev/null
+++ b/packages/design-system/src/components/ErrorState/ErrorState.stories.tsx
@@ -0,0 +1,36 @@
+import type { Meta, StoryObj } from '@storybook/react';
+import { Button } from '../Button';
+import { ErrorState } from './ErrorState';
+
+const meta: Meta = {
+ title: 'Feedback/ErrorState',
+ component: ErrorState,
+ argTypes: {
+ title: { control: 'text' },
+ description: { control: 'text' },
+ },
+};
+
+export default meta;
+type Story = StoryObj;
+
+export const Basic: Story = {
+ args: {
+ title: 'Failed to load',
+ description: 'An unexpected error occurred. Please try again.',
+ },
+};
+
+export const WithRetry: Story = {
+ args: {
+ title: 'Connection lost',
+ description: 'Could not reach the server.',
+ action: ,
+ },
+};
+
+export const Minimal: Story = {
+ args: {
+ title: 'Error loading data',
+ },
+};
diff --git a/packages/design-system/src/components/ErrorState/ErrorState.test.tsx b/packages/design-system/src/components/ErrorState/ErrorState.test.tsx
new file mode 100644
index 0000000..699f700
--- /dev/null
+++ b/packages/design-system/src/components/ErrorState/ErrorState.test.tsx
@@ -0,0 +1,26 @@
+import { describe, it, expect } from 'vitest';
+import { render, screen } from '@testing-library/react';
+import { ErrorState } from './ErrorState';
+import { MoexVibeThemeProvider } from '../../theme';
+
+function renderWithTheme(element: React.ReactElement) {
+ return render({element});
+}
+
+describe('ErrorState', () => {
+ it('renders title as semantic heading', () => {
+ renderWithTheme();
+ const heading = screen.getByText('Error loading');
+ expect(heading.tagName).toBe('H2');
+ });
+
+ it('renders description', () => {
+ renderWithTheme();
+ expect(screen.getByText('Something went wrong')).toBeInTheDocument();
+ });
+
+ it('renders action', () => {
+ renderWithTheme(Retry} />);
+ expect(screen.getByRole('button', { name: 'Retry' })).toBeInTheDocument();
+ });
+});
diff --git a/packages/design-system/src/components/ErrorState/ErrorState.tsx b/packages/design-system/src/components/ErrorState/ErrorState.tsx
new file mode 100644
index 0000000..2cbc3e3
--- /dev/null
+++ b/packages/design-system/src/components/ErrorState/ErrorState.tsx
@@ -0,0 +1,20 @@
+import type { ReactNode } from 'react';
+import { Stack } from '@mui/material';
+import { Heading } from '../Heading';
+import { Text } from '../Text';
+
+export interface ErrorStateProps {
+ title: string;
+ description?: string;
+ action?: ReactNode;
+}
+
+export function ErrorState({ title, description, action }: ErrorStateProps) {
+ return (
+
+ {title}
+ {description && {description}}
+ {action && {action} }
+
+ );
+}
diff --git a/packages/design-system/src/components/ErrorState/index.ts b/packages/design-system/src/components/ErrorState/index.ts
new file mode 100644
index 0000000..345d022
--- /dev/null
+++ b/packages/design-system/src/components/ErrorState/index.ts
@@ -0,0 +1,2 @@
+export { ErrorState } from './ErrorState';
+export type { ErrorStateProps } from './ErrorState';
diff --git a/packages/design-system/src/components/FilterBar/FilterBar.stories.tsx b/packages/design-system/src/components/FilterBar/FilterBar.stories.tsx
new file mode 100644
index 0000000..8a81bfb
--- /dev/null
+++ b/packages/design-system/src/components/FilterBar/FilterBar.stories.tsx
@@ -0,0 +1,38 @@
+import type { Meta, StoryObj } from '@storybook/react';
+import { Button } from '../Button';
+import { TextField } from '../TextField';
+import { Select } from '../Select';
+import { FilterBar } from './FilterBar';
+
+const meta: Meta = {
+ title: 'Layout/FilterBar',
+ component: FilterBar,
+};
+
+export default meta;
+type Story = StoryObj;
+
+export const Basic: Story = {
+ args: {
+ children: (
+ <>
+
+ |