diff --git a/.agents/skills/ui-kit-figma/SKILL.md b/.agents/skills/ui-kit-figma/SKILL.md new file mode 100644 index 00000000..56709c71 --- /dev/null +++ b/.agents/skills/ui-kit-figma/SKILL.md @@ -0,0 +1,83 @@ +--- +name: ui-kit-figma +description: > + Implement or sync React Native Prime UI Kit components from Figma + specifications. Use when a Figma node is provided, or when component variants, + local theme-token bindings, documentation links, or Storybook states must be + aligned with Figma. This is read-only toward Figma. +--- + +# UI Kit Figma + +Translate Figma component specifications into this repository's public API, +Unistyles implementation, local tokens, tests, and Storybook conventions. Use +the Figma design-to-code skill for tool workflow and `ui-kit-testing` when tests +change. + +## Workflow + +1. Inspect the component source, public types and barrels, nearest tests and + stories, and relevant files under `src/theme/tokens`. +2. Call Figma design context on the exact component or variant frame. If a page + or section returns sparse context, use metadata only to locate the inner + frame, then call design context on that frame. +3. Read variable definitions for the target frame and map each relevant Figma + variable to the existing runtime theme path. +4. Implement the smallest compatible source change, following the nearest + component pattern and root `AGENTS.md`. +5. Update focused behavioral tests and representative Storybook scenarios when + the public contract or material variants change. +6. Update the component documentation link when its exact Figma frame is known. +7. Run the verification required by root `AGENTS.md`. + +## Token Mapping + +- Treat Figma variable bindings as the source of token intent. Treat resolved + pixel and color values as inspection data, not values to copy into source. +- Treat `design-tokens/input/tokens.json` as the latest immutable export from + the designer. Never edit it during component or Figma synchronization work. +- Treat `src/theme/tokens/**` as immutable generated output. Never edit or + regenerate these files during component or Figma synchronization work. +- Reuse tokens from `src/theme/tokens`; do not hardcode a resolved value when a + matching local token exists. +- Prefer a component token when Figma explicitly binds the property to that + component variable. Use a semantic token only when the design intent is + semantic or no component binding exists. +- If an exact Figma value has no matching existing token, do not hardcode it, + change token files, or silently substitute an approximate token. Report the + gap and explain which part cannot be matched exactly with the current tokens. +- Apply severity, size, state, and theme bindings to every affected layer, not + only the outer container. Check text, background, border, icon, and shape + tokens independently. + +## Documentation Links + +- Link a component to its exact Figma component or variant frame, not merely the + file, page, or broad section containing it. +- In a bulk link update, inventory the component documentation first. Update + only confidently matched frames and keep unresolved components explicit. +- Before a requested commit, report updated links first and unresolved links + second. Commit only when the user explicitly asks. + +## Storybook + +- Model independently meaningful usage scenarios and interactions. Use controls + for simple variant axes that do not need dedicated documentation. +- Create separate stories or a composed comparison only when the scenario or + comparison itself adds documentation value. Do not impose a fixed number or + layout of stories per component. +- Keep every story's props valid for discriminated unions. Do not expose a + control that can create an invalid prop combination. +- Hide non-editable or internally composed props with + `parameters.controls.exclude`. Do not use `control: false` with React Native + on-device controls because it renders as `Invalid type`. +- Prefer `.tsx` when a story needs JSX composition. If an existing `.ts` file + must remain `.ts`, use `createElement` and construct typed discriminated props + before passing them to the component. + +## Tests + +Use `ui-kit-testing`. Assert rendered data, interaction logic, callbacks, +controlled behavior, accessibility, and public contracts. Do not assert exact +theme-token values, dimensions, colors, or style objects to prove a Figma +mapping. diff --git a/.agents/skills/ui-kit-figma/agents/openai.yaml b/.agents/skills/ui-kit-figma/agents/openai.yaml new file mode 100644 index 00000000..d5c000d2 --- /dev/null +++ b/.agents/skills/ui-kit-figma/agents/openai.yaml @@ -0,0 +1,6 @@ +interface: + display_name: 'UI Kit Figma' + short_description: 'Sync UI Kit components from Figma tokens' + default_prompt: + 'Use $ui-kit-figma to implement or sync a UI Kit component from its Figma + specification.' diff --git a/.agents/skills/ui-kit-testing/SKILL.md b/.agents/skills/ui-kit-testing/SKILL.md index 7f89c652..31ef73ae 100644 --- a/.agents/skills/ui-kit-testing/SKILL.md +++ b/.agents/skills/ui-kit-testing/SKILL.md @@ -2,9 +2,8 @@ name: ui-kit-testing description: > Write or refactor React Native Prime UI Kit Jest and RNTL tests for - components, hooks, controlled behavior, timers, animations, snapshots, - accessibility, and public TypeScript contracts. Do not use for whole-suite - audits + components, hooks, controlled behavior, timers, animations, accessibility, and + public TypeScript contracts. Do not use for whole-suite audits --- # UI Kit Testing @@ -18,8 +17,8 @@ inspect the implementation and nearest tests before choosing helpers or mocks. 1. Search existing tests and Jest setup before adding a helper, mock, provider, timer utility, or console suppression 2. Load only the references required by the test: - - test cases, render helpers, selectors, accessibility, snapshots, types, or - naming: `references/test-authoring.md` + - test cases, render helpers, selectors, accessibility, types, or naming: + `references/test-authoring.md` - child, external, native, animated, or console mocks: `references/mocks-and-native-ui.md` - timers, debounce, animations, delayed updates, or manual promises: @@ -34,6 +33,15 @@ inspect the implementation and nearest tests before choosing helpers or mocks. 5. Before finishing, remove avoidable mocks, oversized helpers, redundant waits, and assertions that do not prove the public contract +## Assertion Boundaries + +- Assert rendered data, presence or absence, callbacks, controlled behavior, + accessibility, and public contracts +- Do not assert exact colors, dimensions, theme-token values, or style objects +- Do not add or update snapshots to verify component appearance or structure. + Replace affected visual snapshots with explicit behavioral assertions +- Use the normal build to validate public TypeScript contracts and token access + ## Verification Run focused Jest and the applicable build or lint checks from `AGENTS.md`. diff --git a/.agents/skills/ui-kit-testing/references/test-authoring.md b/.agents/skills/ui-kit-testing/references/test-authoring.md index a8de0471..726bb857 100644 --- a/.agents/skills/ui-kit-testing/references/test-authoring.md +++ b/.agents/skills/ui-kit-testing/references/test-authoring.md @@ -1,7 +1,8 @@ # Test Authoring Read this reference when creating or changing test cases, render helpers, -selectors, accessibility assertions, snapshots, public types, or test names. +selectors, accessibility assertions, public types, test names, or replacing +snapshots with behavioral assertions. ## Placement And Helpers @@ -37,7 +38,9 @@ normal build. ## Snapshots -Snapshot only small, stable output whose complete structure is the behavior. -Prefer explicit assertions for interaction, state, accessibility, layout, and -animations. Update snapshots only for intentional UI changes. Do not snapshot -mocked child trees, large style objects, or ordinary prop forwarding. +Do not add or update snapshots for component appearance, structure, styles, or +theme-token values. When a change invalidates a visual snapshot, replace it with +explicit assertions for rendered data, presence or absence, interaction, +controlled state, callbacks, or accessibility. Use a snapshot only when the user +explicitly requests one and the contract cannot be stated more clearly with +behavioral assertions. diff --git a/.github/actions/typecheck/action.yml b/.github/actions/typecheck/action.yml index be5114d9..5b74884c 100644 --- a/.github/actions/typecheck/action.yml +++ b/.github/actions/typecheck/action.yml @@ -1,5 +1,5 @@ -name: Run Typecheck -description: Run typecheck +name: Run Typechecks +description: Typecheck the project and check generated tokens runs: using: composite @@ -9,3 +9,11 @@ runs: - name: Run Typecheck shell: bash run: yarn tsc --noEmit + + - name: Typecheck Token Generator + shell: bash + run: yarn tokens:typecheck + + - name: Check Generated Tokens + shell: bash + run: yarn tokens:check diff --git a/AGENTS.md b/AGENTS.md index e1dd105d..2f3d317c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -15,8 +15,11 @@ Use only top-level skills under `.agents/skills/`; nested `vendor/` skills are source material, not runtime instructions. - Use `$ui-kit-testing` to write or refactor focused Jest/RNTL tests, including - controlled behavior, accessibility, mocks, timers, animations, snapshots, and - public TypeScript contracts. + controlled behavior, accessibility, mocks, timers, animations, and public + TypeScript contracts. +- Use `$ui-kit-figma` to implement or sync components from Figma, map design + variables to local theme tokens, and align material variants and Storybook + scenarios. - Use `$ui-kit-review` for diffs and local changes or explicit architecture, onboarding, test-suite, debt, health, agent-instruction, and diagnostic audits. It is read-only unless the user requests fixes. @@ -33,6 +36,9 @@ Do not load every skill preemptively; use the one matching the request. controlling prop changes. - In new source and test files, use `UpperPascalCase` `testID` values. Existing IDs are compatibility-sensitive; do not flag or rename them only for format. +- Story files containing JSX must use the `.stories.tsx` extension and JSX. Do + not use `createElement` to keep them as `.stories.ts`; reserve `.stories.ts` + for stories without JSX. - A new public component or material variant normally needs typed source, a barrel export, focused tests, and representative Storybook states. @@ -49,7 +55,8 @@ Do not load every skill preemptively; use the one matching the request. ## Git Do not commit or push unless explicitly asked. Use Conventional Commits for -requested commits. +requested commits. Keep the conventional type and optional scope in English; +write the commit subject in Russian. ## Safety diff --git a/CHANGELOG.md b/CHANGELOG.md index 62a4ed71..87b13ae7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,57 @@ ### ♻️ Рефакторинг +## [1.1.0-beta.0](https://github.com/cdek-it/react-native-ui-kit/compare/v1.0.3...v1.1.0-beta.0) (2026-08-06) + +### 🚀 Новый функционал + +* **Accordion:** подключены сгенерированные токены ([1f05446](https://github.com/cdek-it/react-native-ui-kit/commit/1f05446129b7a224d6417cf700e5ea75f9de196a)) +* **Avatar:** подключены сгенерированные токены ([da7550e](https://github.com/cdek-it/react-native-ui-kit/commit/da7550e4be7bd49f900d17ebe84d10ab90764cb8)) +* **Badge:** подключены сгенерированные токены ([5f534f3](https://github.com/cdek-it/react-native-ui-kit/commit/5f534f326fe44c53b6211ca8c4518540cd160baf)) +* **Button:** подключены сгенерированные токены ([5a619a7](https://github.com/cdek-it/react-native-ui-kit/commit/5a619a7670d0eb56e7591e135c932cd41d7c8a01)) +* **Checkbox:** подключены сгенерированные токены ([706d49f](https://github.com/cdek-it/react-native-ui-kit/commit/706d49fc9e25773dab1cd063d767391b2d6495ac)) +* **Chip:** подключены сгенерированные токены ([7940416](https://github.com/cdek-it/react-native-ui-kit/commit/7940416299438daa6b6cf67f157b2297514bbe30)) +* **Dialog:** подключены сгенерированные токены ([f9acf57](https://github.com/cdek-it/react-native-ui-kit/commit/f9acf579c693ebc7ca62d8d41845eb3369b2e7d2)) +* **Divider:** подключены сгенерированные токены ([55d672f](https://github.com/cdek-it/react-native-ui-kit/commit/55d672f25676d15ac2d8110a554c166730aa602f)) +* **InputSwitch:** подключены сгенерированные токены ([ec5030f](https://github.com/cdek-it/react-native-ui-kit/commit/ec5030fce28a5de6385df38f3564c8c372b32d7d)) +* **Input:** подключены сгенерированные токены ([9e63339](https://github.com/cdek-it/react-native-ui-kit/commit/9e63339502e7ef6e377178b22c93b4bcffd60146)) +* **List:** подключены сгенерированные токены ([1c58202](https://github.com/cdek-it/react-native-ui-kit/commit/1c58202e36086865b9ee5164bd235c4a3fb099e4)) +* **MenuItem:** подключены сгенерированные токены ([74355e6](https://github.com/cdek-it/react-native-ui-kit/commit/74355e666247e0205aacb55f2f6cf2a6552c9a9a)) +* **Message:** подключены сгенерированные токены ([bb9c8de](https://github.com/cdek-it/react-native-ui-kit/commit/bb9c8de54fd30a6c69eef9c3e9716876939f465e)) +* **ProgressBar:** подключены сгенерированные токены ([1628475](https://github.com/cdek-it/react-native-ui-kit/commit/1628475a30b7bc16842b34b14c2998b2612805cb)) +* **ProgressSpinner:** подключены сгенерированные токены ([04fe461](https://github.com/cdek-it/react-native-ui-kit/commit/04fe46136a8ddf3f62c231641ff2ace6dbc85dfe)) +* **RadioButton:** подключены сгенерированные токены ([32bc17f](https://github.com/cdek-it/react-native-ui-kit/commit/32bc17fb083c36e4c830451e125fcd4bb6177643)) +* **Rating:** подключены сгенерированные токены ([1219e43](https://github.com/cdek-it/react-native-ui-kit/commit/1219e43a9068d081a19bcd96021d3d99b36e0f81)) +* **SelectButton:** подключены сгенерированные токены ([5e170ba](https://github.com/cdek-it/react-native-ui-kit/commit/5e170bae3e97cfe7f3604bc819c13f8d00602358)) +* **Skeleton:** подключены сгенерированные токены ([552b857](https://github.com/cdek-it/react-native-ui-kit/commit/552b8572912884b994bfe087c296a86d073868f3)) +* **Slider:** подключены сгенерированные токены ([1be33c0](https://github.com/cdek-it/react-native-ui-kit/commit/1be33c03f156b013228064db2dd2151e08f9f5b1)) +* **Tabs:** подключены сгенерированные токены ([42bf812](https://github.com/cdek-it/react-native-ui-kit/commit/42bf812b09da68e6023c3029749ff6f435007ea5)) +* **Tag:** подключены сгенерированные токены ([6cfc335](https://github.com/cdek-it/react-native-ui-kit/commit/6cfc335f6e06373f320b8d4d30865a30dd75aa05)) +* **Theme:** подключены сгенерированные токены ([8e5a257](https://github.com/cdek-it/react-native-ui-kit/commit/8e5a257cc2c1d90e27ab4e591a9a0ed969d2619b)) +* **Timer:** подключены сгенерированные токены ([0b74c4a](https://github.com/cdek-it/react-native-ui-kit/commit/0b74c4a5b5f030d3797eb4b29e48404af2f2ce3d)) +* **ToggleButton:** подключены сгенерированные токены ([82a4f40](https://github.com/cdek-it/react-native-ui-kit/commit/82a4f409fdda0641dcf001e2704850808e897def)) +* **Typography:** подключены сгенерированные токены ([b5e0ca1](https://github.com/cdek-it/react-native-ui-kit/commit/b5e0ca14ae4a9e77a2efff4e654dc2c937d223a2)) +* добавлен генератор дизайн-токенов ([83048a7](https://github.com/cdek-it/react-native-ui-kit/commit/83048a7bac41a41b516490aab4423f47b2fcd1e5)) +* добавлена генерация токенов шрифтов ([6838bb3](https://github.com/cdek-it/react-native-ui-kit/commit/6838bb37d6e25e2fd7911a55d71ba880648d1cbb)) +* добавлена поддержка focusRing-токенов ([566f0ec](https://github.com/cdek-it/react-native-ui-kit/commit/566f0ecf8b3fe7d0a57f97da04b609abb198309f)) +* добавлена поддержка токенов анимации ([6e81a29](https://github.com/cdek-it/react-native-ui-kit/commit/6e81a2951d00266371a3e4e0060e6139f541414b)) +* добавлены и подключены дизайн-токены ([a6ac14d](https://github.com/cdek-it/react-native-ui-kit/commit/a6ac14dceedd5d29de808896349e9606fce75548)) + +### 🐛 Исправления багов + +* доработан генератор дизайн-токенов ([d5c0ed5](https://github.com/cdek-it/react-native-ui-kit/commit/d5c0ed5be85c5cf6e403132dc1d0e48ef597f191)) +* исправлена нормализация радиусов в токенах ([b1b2b19](https://github.com/cdek-it/react-native-ui-kit/commit/b1b2b197a0e18e9bb3714597856a4ee1d62df2c3)) + +### 🧹 Другое + +* актуализирована документация тем и токенов ([0206449](https://github.com/cdek-it/react-native-ui-kit/commit/020644980ee011cacfcbaf23b2ebee9a5af9f34b)) + +### ♻️ Рефакторинг + +* **theme:** добавлен слой legacy-совместимости ([d55fbde](https://github.com/cdek-it/react-native-ui-kit/commit/d55fbde0f0d058b09bb152d696580845a76d68f2)) +* **tokens:** component-токены скрыты из публичного API ([5c4e4bd](https://github.com/cdek-it/react-native-ui-kit/commit/5c4e4bd087d2b407c498f5100a72a90b1f54b69a)) +* **tokens:** объединены проверка и форматирование генерации ([f60cbd6](https://github.com/cdek-it/react-native-ui-kit/commit/f60cbd61b01dd4d2d8c79247a191fb8f1ab1f5c6)) +* **tokens:** разделены semantic-токены ([8ab1759](https://github.com/cdek-it/react-native-ui-kit/commit/8ab17593587bf96488f9f41a7fae80e395f33431)) * улучшена читаемость конфигурации плагинов ([7e6bba9](https://github.com/cdek-it/react-native-ui-kit/commit/7e6bba95b87d1dc1b3a1fcf2414b6dee91b86c64)) ## [1.0.3](https://github.com/cdek-it/react-native-ui-kit/compare/v1.0.2...v1.0.3) (2026-07-30) diff --git a/MIGRATION.md b/MIGRATION.md index 42303352..de792443 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -1,18 +1,14 @@ # Миграция на Unistyles V3 -Стили переведены на `react-native-unistyles`. `ThemeContextProvider` доступен -как внешний конфигуратор тем и шрифтов, но чтение темы и шрифтов теперь идет -через API `unistyles`. +Стили переведены на `react-native-unistyles`. UI kit предоставляет провайдер и +хуки для настройки темы и шрифтов, а стили создаются через API `unistyles`. ## Изменения -### `ThemeContextProvider` — доступен +### Настройка темы и шрифтов -UI kit по-прежнему использует `react-native-unistyles` внутри, но для внешнего -потребителя снова доступен `ThemeContextProvider` как единая точка конфигурации -тем и шрифтов. - -Если приложению нужны кастомные шрифты, настройте их через провайдер: +Оберните приложение в `ThemeContextProvider`. Через `initialTheme` задаётся +начальная тема, через `fonts` — используемые семейства шрифтов: ```tsx import { @@ -22,7 +18,7 @@ import { export const Root = () => ( @@ -30,18 +26,17 @@ export const Root = () => ( ) ``` -Провайдер также принимает `lightTheme` и `darkTheme`, если нужно передать -полностью кастомные темы. +Провайдер не принимает пользовательские объекты тем. Он настраивает +зарегистрированные внутри UI kit темы `light` и `dark`. ### `useFonts` -Используйте `useUnistyles`: +Для получения настроенных шрифтов используйте экспортируемый UI kit хук: ```tsx -import { useUnistyles } from '@cdek-it/react-native-ui-kit' +import { useFonts } from '@cdek-it/react-native-ui-kit' -const { theme } = useUnistyles() -theme.fonts +const fonts = useFonts() ``` Или прямо в стилях через `StyleSheet.create(...)`: @@ -50,29 +45,41 @@ theme.fonts import { StyleSheet } from 'react-native-unistyles' const styles = StyleSheet.create(({ fonts }) => ({ - title: { fontFamily: fonts.primary }, + title: { fontFamily: fonts.fontFamily.heading }, })) ``` -### `useTheme()` / `useChangeTheme()` +### Чтение и переключение темы + +Для чтения и переключения темы используйте публичные хуки UI kit: + +```tsx +import { + ThemeVariant, + useChangeTheme, + useTheme, +} from '@cdek-it/react-native-ui-kit' + +const theme = useTheme() +const changeTheme = useChangeTheme() -`ThemeContextProvider` больше не является источником `theme/fonts` через React -context. Он только конфигурирует `react-native-unistyles`. +changeTheme(ThemeVariant.Dark) +``` -- `useTheme()` читает `UnistylesRuntime.themeName` -- `useFonts()` читает `useUnistyles().theme.fonts` -- `ThemeContext` остается пустым и имеет значение `null` -- `useChangeTheme()` всегда вызывает `UnistylesRuntime.setTheme(...)` +`ThemeContextProvider` не хранит тему и шрифты в React Context: `ThemeContext` +имеет значение `null`, а источником состояния остаётся Unistyles. ### `makeStyles` — removed Используйте `StyleSheet.create(...)`: ```tsx -import { StyleSheet } from '@cdek-it/react-native-ui-kit' +import { StyleSheet } from 'react-native-unistyles' -const styles = StyleSheet.create((theme) => ({ - container: { backgroundColor: theme.Button.Brand.buttonBg }, +const styles = StyleSheet.create(({ semantic }) => ({ + container: { + backgroundColor: semantic.colorScheme.color.bg.surface.default.default, + }, })) ``` @@ -80,32 +87,9 @@ const styles = StyleSheet.create((theme) => ({ темы. `StyleSheet.create(...)` — нативный путь, обновляет стили **без** ререндеров. -SDK реэкспортирует `StyleSheet`, `useUnistyles`, `UnistylesRuntime` и -`withUnistyles`, поэтому потребителям не нужно импортировать -`react-native-unistyles` напрямую. - -### `useTheme()` — removed - -```tsx -import { UnistylesRuntime, useUnistyles } from '@cdek-it/react-native-ui-kit' - -const themeName = UnistylesRuntime.themeName // 'light' | 'dark' -``` - -Для реактивного поведения используйте `useUnistyles()`: - -```tsx -const { rt } = useUnistyles() -rt.themeName -``` - -### `useChangeTheme()` — removed - -```tsx -import { UnistylesRuntime } from '@cdek-it/react-native-ui-kit' - -UnistylesRuntime.setTheme('dark') -``` +UI kit не реэкспортирует `StyleSheet`, `useUnistyles`, `UnistylesRuntime` и +`withUnistyles`. Если они нужны приложению напрямую, импортируйте их из +`react-native-unistyles`. ## ESLint Правила для Unistyles diff --git a/README.md b/README.md index b74edb56..bf4be666 100644 --- a/README.md +++ b/README.md @@ -36,29 +36,25 @@ npm i @cdek-it/react-native-ui-kit UI kit использует следующие виды шрифтов. -| Тип шрифта | Используемые начертания | Рекомендуемый шрифт | Рекомендуемый аналог | -| ----------- | ---------------------------------------------- | ------------------- | -------------------- | -| `primary` | – regular
– demibold
– demibold italic | TT Fellows | Noto Sans | -| `secondary` | – regular
– bold | Noto Sans | — | +| Тип шрифта | Используемые начертания | Рекомендуемый шрифт | Рекомендуемый аналог | +| ---------- | ---------------------------------------------- | ------------------- | -------------------- | +| `heading` | – regular
– demibold
– demibold italic | TT Fellows | Noto Sans | +| `base` | – regular
– bold | Noto Sans | — | Исходники шрифтов не поставляются вместе с пакетом, их требуется подключать -отдельно. После подключения шрифтов в проект, необходимо указать их в -`ThemeContextProvider`. +отдельно под именами, указанными в токенах. ```tsx - + ``` После этого шрифты доступны через `useUnistyles().theme.fonts` или прямо в `StyleSheet.create(({ fonts }) => ...)`. `ThemeContextProvider` только настраивает темы и шрифты для `unistyles`. -`ThemeContext` остается пустым и всегда имеет значение `null`. - -Провайдер также принимает `lightTheme` и `darkTheme`, если нужно переопределить -темы целиком. +`ThemeContext` остается пустым и всегда имеет значение `null`. Deprecated-формат +`fonts={{ primary, secondary }}` временно сохраняется для обратной +совместимости. ### Пример подключения шрифтов с помощью expo-fonts через плагин @@ -160,6 +156,17 @@ UI kit использует следующие виды шрифтов. ``` +## Токены анимации + +Длительность анимации хранится в `semanticTokens` числом в миллисекундах. +Easing-токен нужно передать в Reanimated через публичный адаптер: + +```ts +import { semanticTokens, toEasing } from '@cdek-it/react-native-ui-kit' + +const easing = toEasing(semanticTokens.effects.transition.easing.standard) +``` + ## Dependencies Для использования данной библиотеки необходимо: diff --git a/design-tokens/README.md b/design-tokens/README.md new file mode 100644 index 00000000..bba3daab --- /dev/null +++ b/design-tokens/README.md @@ -0,0 +1,6 @@ +# Design tokens + +`input/tokens.json` содержит входные токены из Figma, из которых генерируются +токены проекта. + +Подробности: [генератор токенов](../scripts/token-generator/README.md). diff --git a/design-tokens/input/tokens.json b/design-tokens/input/tokens.json new file mode 100644 index 00000000..0b157a6d --- /dev/null +++ b/design-tokens/input/tokens.json @@ -0,0 +1,5220 @@ +{ + "primitive": { + "colors": { + "alpha": { + "white": { + "10": "rgba(255, 255, 255, 0.0100)", + "40": "rgba(255, 255, 255, 0.0400)", + "50": "rgba(255, 255, 255, 0.0500)", + "60": "rgba(255, 255, 255, 0.0600)", + "100": "rgba(255, 255, 255, 0.1000)", + "160": "rgba(255, 255, 255, 0.1600)", + "200": "rgba(255, 255, 255, 0.2000)", + "300": "rgba(255, 255, 255, 0.3000)", + "400": "rgba(255, 255, 255, 0.4000)", + "500": "rgba(255, 255, 255, 0.5000)", + "600": "rgba(255, 255, 255, 0.6000)", + "700": "rgba(255, 255, 255, 0.7000)", + "800": "rgba(255, 255, 255, 0.8000)", + "870": "rgba(255, 255, 255, 0.8700)", + "900": "rgba(255, 255, 255, 0.9000)", + "1000": "#ffffff" + }, + "black": { + "40": "rgba(0, 0, 0, 0.0400)", + "100": "rgba(0, 0, 0, 0.1000)", + "200": "rgba(0, 0, 0, 0.2000)", + "300": "rgba(0, 0, 0, 0.3000)", + "400": "rgba(0, 0, 0, 0.4000)", + "500": "rgba(0, 0, 0, 0.5000)", + "600": "rgba(0, 0, 0, 0.6000)", + "700": "rgba(0, 0, 0, 0.7000)", + "800": "rgba(0, 0, 0, 0.8000)", + "900": "rgba(0, 0, 0, 0.9000)", + "1000": "#000000" + }, + "green": { + "40": "rgba(68, 232, 88, 0.04)", + "100": "rgba(68, 232, 88, 0.1)", + "200": "rgba(68, 232, 88, 0.2)", + "400": "rgba(68, 232, 88, 0.4)", + "600": "rgba(68, 232, 88, 0.6)" + }, + "blue": { + "40": "rgba(68, 150, 232, 0.04)", + "100": "rgba(68, 150, 232, 0.1)", + "200": "rgba(68, 150, 232, 0.2)", + "400": "rgba(68, 150, 232, 0.4)", + "600": "rgba(68, 150, 232, 0.6)" + }, + "yellow": { + "40": "rgba(245, 184, 61, 0.04)", + "100": "rgba(245, 184, 61, 0.1)", + "200": "rgba(245, 184, 61, 0.2)", + "400": "rgba(245, 184, 61, 0.4)", + "600": "rgba(245, 184, 61, 0.6)" + }, + "red": { + "40": "rgba(232, 82, 68, 0.04)", + "100": "rgba(232, 82, 68, 0.1)", + "200": "rgba(232, 82, 68, 0.2)", + "400": "rgba(232, 82, 68, 0.4)", + "600": "rgba(232, 82, 68, 0.6)" + } + }, + "solid": { + "purple": { + "50": "#faf5ff", + "100": "#f3e8ff", + "200": "#e9d5ff", + "300": "#d8b4fe", + "400": "#c084fc", + "500": "#a855f7", + "600": "#9333ea", + "700": "#7e22ce", + "800": "#6b21a8", + "900": "#581c87", + "950": "#3b0764" + }, + "fuchsia": { + "50": "#fdf4ff", + "100": "#fae8ff", + "200": "#f5d0fe", + "300": "#f0abfc", + "400": "#e879f9", + "500": "#d946ef", + "600": "#c026d3", + "700": "#a21caf", + "800": "#86198f", + "900": "#701a75", + "950": "#4a044e" + }, + "pink": { + "50": "#fdf2f8", + "100": "#fce7f3", + "200": "#fbcfe8", + "300": "#f9a8d4", + "400": "#f472b6", + "500": "#ec4899", + "600": "#db2777", + "700": "#be185d", + "800": "#9d174d", + "900": "#831843", + "950": "#500724" + }, + "rose": { + "50": "#fff1f2", + "100": "#ffe4e6", + "200": "#fecdd3", + "300": "#fda4af", + "400": "#fb7185", + "500": "#f43f5e", + "600": "#e11d48", + "700": "#be123c", + "800": "#9f1239", + "900": "#881337", + "950": "#4c0519" + }, + "teal": { + "50": "#f0fdfa", + "100": "#ccfbf1", + "200": "#99f6e4", + "300": "#5eead4", + "400": "#2dd4bf", + "500": "#14b8a6", + "600": "#0d9488", + "700": "#0f766e", + "800": "#115e59", + "900": "#134e4a", + "950": "#042f2e" + }, + "cyan": { + "50": "#ecfeff", + "100": "#cffafe", + "200": "#a5f3fc", + "300": "#67e8f9", + "400": "#22d3ee", + "500": "#06b6d4", + "600": "#0891b2", + "700": "#0e7490", + "800": "#155e75", + "900": "#164e63", + "950": "#013138" + }, + "sky": { + "50": "#f0f9ff", + "100": "#e0f2fe", + "200": "#bae6fd", + "300": "#7dd3fc", + "400": "#38bdf8", + "500": "#0ea5e9", + "600": "#0284c7", + "700": "#0369a1", + "800": "#075985", + "900": "#0c4a6e", + "950": "#082f49" + }, + "blue": { + "50": "#fafdff", + "100": "#f0f9ff", + "200": "#d4ecfe", + "300": "#aad7fb", + "400": "#77baf4", + "500": "#4496e8", + "600": "#1e76cd", + "700": "#18538d", + "800": "#123a61", + "900": "#0e2a45", + "950": "#0c243b" + }, + "indigo": { + "50": "#eef2ff", + "100": "#e0e7ff", + "200": "#c7d2fe", + "300": "#a5b4fc", + "400": "#818cf8", + "500": "#6366f1", + "600": "#4f46e5", + "700": "#4338ca", + "800": "#3730a3", + "900": "#312e81", + "950": "#1e1b4b" + }, + "violet": { + "50": "#fcfaff", + "100": "#f6f0ff", + "200": "#e5d4fe", + "300": "#cbaafb", + "400": "#b284f5", + "500": "#a265ec", + "600": "#9457ea", + "700": "#48188d", + "800": "#321261", + "900": "#240e45", + "950": "#1f0c3b" + }, + "emerald": { + "50": "#ecfdf5", + "100": "#d1fae5", + "200": "#a7f3d0", + "300": "#6ee7b7", + "400": "#34d399", + "500": "#10b981", + "600": "#059669", + "700": "#047857", + "800": "#065f46", + "900": "#064e3b", + "950": "#022c22" + }, + "green": { + "50": "#fafffb", + "100": "#f0fff3", + "200": "#d4fedc", + "300": "#aafbb7", + "400": "#77f48a", + "500": "#44e858", + "600": "#1dc831", + "700": "#168322", + "800": "#12611b", + "900": "#0e4514", + "950": "#0c3b11" + }, + "lime": { + "50": "#f7fee7", + "100": "#ecfccb", + "200": "#d9f99d", + "300": "#bef264", + "400": "#a3e635", + "500": "#84cc16", + "600": "#65a30d", + "700": "#4d7c0f", + "800": "#3f6212", + "900": "#365314", + "950": "#1a2e05" + }, + "red": { + "50": "#fffafa", + "100": "#fff0f0", + "200": "#fed4d4", + "300": "#fbacaa", + "400": "#f47f77", + "500": "#e85244", + "600": "#db3424", + "700": "#8d2218", + "800": "#611912", + "900": "#45120e", + "950": "#3b100c" + }, + "orange": { + "50": "#fffbfa", + "100": "#fff3f0", + "200": "#ffddd5", + "300": "#ffbca9", + "400": "#ff9273", + "500": "#fe6434", + "600": "#d53f0b", + "700": "#a83107", + "800": "#752506", + "900": "#561c05", + "950": "#4b1905" + }, + "amber": { + "50": "#fffbeb", + "100": "#fef3c7", + "200": "#fde68a", + "300": "#fcd34d", + "400": "#fbbf24", + "500": "#f59e0b", + "600": "#d97706", + "700": "#b45309", + "800": "#92400e", + "900": "#78350f", + "950": "#451a03" + }, + "yellow": { + "50": "#fffdfa", + "100": "#fff9f0", + "200": "#ffeed4", + "300": "#fddeaa", + "400": "#facb75", + "500": "#f5b83d", + "600": "#dc9710", + "700": "#9d6d0e", + "800": "#6d4c0b", + "900": "#4f3709", + "950": "#453008" + }, + "slate": { + "50": "#f8fafc", + "100": "#f1f5f9", + "200": "#e2e8f0", + "300": "#cbd5e1", + "400": "#94a3b8", + "500": "#64748b", + "600": "#475569", + "700": "#334155", + "800": "#1e293b", + "900": "#0f172a", + "950": "#020617" + }, + "gray": { + "50": "#f9fafb", + "100": "#f3f4f6", + "200": "#e5e7eb", + "300": "#d1d5db", + "400": "#9ca3af", + "500": "#6b7280", + "600": "#4b5563", + "700": "#374151", + "800": "#1f2937", + "900": "#111827", + "950": "#030712" + }, + "zinc": { + "50": "#fafafa", + "100": "#f0f0f1", + "200": "#e2e2e4", + "300": "#cecfd2", + "400": "#a2a5a9", + "500": "#85888e", + "600": "#6d7076", + "700": "#56595f", + "800": "#404348", + "900": "#2b2e33", + "950": "#181a1f" + }, + "neutral": { + "50": "#fafafa", + "100": "#f5f5f5", + "200": "#e5e5e5", + "300": "#d4d4d4", + "400": "#a3a3a3", + "500": "#737373", + "600": "#525252", + "700": "#404040", + "800": "#262626", + "900": "#171717", + "950": "#0a0a0a" + }, + "stone": { + "50": "#fafaf9", + "100": "#f5f5f4", + "200": "#e7e5e4", + "300": "#d6d3d1", + "400": "#a8a29e", + "500": "#78716c", + "600": "#57534e", + "700": "#44403c", + "800": "#292524", + "900": "#1c1917", + "950": "#0c0a09" + } + } + }, + "sizing": { + "none": "0rem", + "05x": "0.0625rem", + "1x": "0.125rem", + "2x": "0.25rem", + "3x": "0.375rem", + "4x": "0.5rem", + "5x": "0.625rem", + "6x": "0.75rem", + "7x": "0.875rem", + "8x": "1rem", + "9x": "1.125rem", + "10x": "1.25rem", + "12x": "1.5rem", + "13x": "1.625rem", + "14x": "1.75rem", + "16x": "2rem", + "18x": "2.25rem", + "19x": "2.375rem", + "21x": "2.625rem", + "23x": "2.875rem", + "24x": "3rem", + "26x": "3.25rem", + "28x": "3.5rem", + "30x": "3.75rem", + "32x": "4rem", + "33x": "4.125rem", + "35x": "4.375rem", + "42x": "5.25rem", + "49x": "6.125rem", + "50x": "6.25rem", + "56x": "7rem", + "63x": "7.875rem", + "70x": "8.75rem", + "77x": "9.625rem", + "84x": "10.5rem", + "91x": "11.375rem", + "98x": "12.25rem", + "105x": "13.125rem", + "112x": "14rem", + "119x": "14.875rem", + "126x": "15.75rem", + "133x": "16.625rem", + "140x": "17.5rem", + "147x": "18.375rem", + "154x": "19.25rem", + "161x": "20.125rem", + "168x": "21rem", + "175x": "21.875rem", + "182x": "22.75rem", + "189x": "23.625rem", + "196x": "24.5rem", + "203x": "25.375rem", + "210x": "26.25rem", + "238x": "29.75rem", + "288x": "36rem", + "315x": "39.375rem", + "350x": "43.75rem", + "378x": "47.25rem", + "384x": "48rem", + "406x": "50.75rem", + "420x": "52.5rem", + "496x": "62rem", + "600x": "75rem", + "700x": "87.5rem", + "max": "100rem", + "20x": "2.5rem", + "40x": "5rem", + "120x": "15rem", + "136x": "17rem", + "152x": "19rem", + "200x": "25rem" + }, + "fonts": { + "fontFamily": { "base": "Noto Sans", "heading": "TT Fellows" }, + "fontWeight": { + "regular": "400", + "medium": "500", + "demibold": "600", + "bold": "700" + }, + "fontSize": { + "100": "0.75rem", + "200": "0.875rem", + "300": "1rem", + "400": "1.125rem", + "500": "1.25rem", + "600": "1.5rem", + "650": "1.875rem", + "700": "2.25rem", + "750": "3rem", + "800": "3.75rem", + "900": "4.5rem", + "1000": "6rem" + }, + "lineHeight": { + "100": "0.75rem", + "150": "0.875rem", + "200": "0.875rem", + "250": "1rem", + "300": "1.125rem", + "350": "1.125rem", + "400": "1.25rem", + "450": "1.375rem", + "500": "1.5rem", + "550": "1.625rem", + "600": "1.75rem", + "700": "1.875rem", + "800": "2.25rem", + "850": "2.375rem", + "900": "2.75rem", + "1000": "3.375rem", + "none": "1", + "auto": "auto" + }, + "letterSpacing": { + "200": "-0.02rem", + "400": "-0.03rem", + "500": "0rem", + "600": "0.02rem", + "700": "0.03rem" + } + } + }, + "semantic": { + "colorScheme": { + "light": { + "color": { + "fg": { + "default": "{colors.solid.zinc.900}", + "hover": "{colors.solid.zinc.700}", + "active": "{colors.solid.zinc.950}", + "focus": "{colors.solid.zinc.900}", + "muted": "{colors.solid.zinc.500}", + "subtle": "{colors.solid.zinc.600}", + "brand": { + "default": "{colors.solid.green.500}", + "hover": "{colors.solid.green.600}", + "active": "{colors.solid.green.700}", + "disabled": "{colors.solid.green.300}", + "visited": "{colors.solid.green.800}", + "muted": "{colors.solid.green.400}" + }, + "inverse": { + "default": "{colors.alpha.white.1000}", + "hover": "{colors.alpha.white.1000}", + "active": "{colors.alpha.white.1000}", + "focus": "{colors.alpha.white.1000}", + "muted": "{colors.alpha.white.700}" + }, + "status": { + "danger": { + "default": "{colors.solid.red.500}", + "hover": "{colors.solid.red.600}", + "active": "{colors.solid.red.700}", + "disabled": "{colors.solid.red.300}", + "visited": "{colors.solid.red.800}", + "muted": "{colors.solid.red.400}" + }, + "info": { + "default": "{colors.solid.blue.500}", + "hover": "{colors.solid.blue.600}", + "active": "{colors.solid.blue.700}", + "disabled": "{colors.solid.blue.300}", + "visited": "{colors.solid.blue.800}", + "muted": "{colors.solid.blue.400}" + }, + "warning": { + "default": "{colors.solid.yellow.500}", + "hover": "{colors.solid.yellow.600}", + "active": "{colors.solid.yellow.700}", + "disabled": "{colors.solid.yellow.300}", + "visited": "{colors.solid.yellow.800}", + "muted": "{colors.solid.yellow.400}" + }, + "success": { + "default": "{colors.solid.green.500}", + "hover": "{colors.solid.green.600}", + "active": "{colors.solid.green.700}", + "disabled": "{colors.solid.green.300}", + "visited": "{colors.solid.green.800}", + "muted": "{colors.solid.green.400}" + }, + "help": { + "default": "{colors.solid.purple.500}", + "hover": "{colors.solid.purple.600}", + "active": "{colors.solid.purple.700}", + "disabled": "{colors.solid.purple.300}", + "visited": "{colors.solid.purple.800}", + "muted": "{colors.solid.purple.400}" + } + }, + "on": { + "brand": { + "default": "{colors.solid.zinc.900}", + "hover": "{colors.solid.zinc.900}", + "active": "{colors.solid.zinc.900}" + }, + "fill": { + "default": "{colors.alpha.white.1000}", + "hover": "{colors.alpha.white.1000}", + "active": "{colors.alpha.white.1000}", + "muted": "{colors.solid.zinc.200}" + }, + "status": { + "danger": { + "default": "{colors.solid.red.900}", + "hover": "{colors.solid.red.950}" + }, + "info": { + "default": "{colors.solid.blue.900}", + "hover": "{colors.solid.blue.950}" + }, + "warning": { + "default": "{colors.solid.yellow.900}", + "hover": "{colors.solid.yellow.950}" + }, + "success": { + "default": "{colors.solid.green.900}", + "hover": "{colors.solid.green.950}" + }, + "help": { + "default": "{colors.solid.purple.900}", + "hover": "{colors.solid.purple.950}" + } + } + } + }, + "bg": { + "status": { + "danger": { + "weak": { + "default": "{colors.solid.red.50}", + "hover": "{colors.solid.red.100}", + "active": "{colors.solid.red.200}" + }, + "strong": { + "default": "{colors.solid.red.300}", + "hover": "{colors.solid.red.400}", + "active": "{colors.solid.red.500}" + } + }, + "info": { + "weak": { + "default": "{colors.solid.blue.50}", + "hover": "{colors.solid.blue.100}", + "active": "{colors.solid.blue.200}" + }, + "strong": { + "default": "{colors.solid.blue.300}", + "hover": "{colors.solid.blue.400}", + "active": "{colors.solid.blue.500}" + } + }, + "warning": { + "weak": { + "default": "{colors.solid.yellow.50}", + "hover": "{colors.solid.yellow.100}", + "active": "{colors.solid.yellow.200}" + }, + "strong": { + "default": "{colors.solid.yellow.300}", + "hover": "{colors.solid.yellow.400}", + "active": "{colors.solid.yellow.500}" + } + }, + "success": { + "weak": { + "default": "{colors.solid.green.50}", + "hover": "{colors.solid.green.100}", + "active": "{colors.solid.green.200}" + }, + "strong": { + "default": "{colors.solid.green.300}", + "hover": "{colors.solid.green.400}", + "active": "{colors.solid.green.500}" + } + }, + "help": { + "weak": { + "default": "{colors.solid.purple.50}", + "hover": "{colors.solid.purple.100}", + "active": "{colors.solid.purple.200}" + }, + "strong": { + "default": "{colors.solid.purple.300}", + "hover": "{colors.solid.purple.400}", + "active": "{colors.solid.purple.500}" + } + } + }, + "brand": { + "weak": { + "hover": "{colors.solid.green.50}", + "active": "{colors.solid.green.100}" + }, + "strong": { + "default": "{colors.solid.green.500}", + "hover": "{colors.solid.green.600}", + "active": "{colors.solid.green.700}" + } + }, + "surface": { + "canvas": { + "default": "{colors.solid.zinc.100}", + "hover": "{colors.solid.zinc.200}", + "active": "{colors.solid.zinc.300}", + "selected": "{colors.solid.zinc.200}" + }, + "default": { + "default": "{colors.alpha.white.1000}", + "hover": "{colors.solid.zinc.50}", + "active": "{colors.solid.zinc.100}", + "selected": "{colors.solid.zinc.50}" + }, + "raised": { + "default": "{colors.alpha.white.1000}", + "hover": "{colors.solid.zinc.50}", + "active": "{colors.solid.zinc.100}", + "selected": "{colors.solid.zinc.50}" + }, + "overlay": { + "default": "{colors.alpha.white.1000}", + "hover": "{colors.solid.zinc.50}" + }, + "backdrop": "{colors.alpha.black.400}" + }, + "neutral": { + "weak": { + "default": "{colors.solid.zinc.100}", + "hover": "{colors.solid.zinc.200}", + "active": "{colors.solid.zinc.300}", + "disabled": "{colors.solid.zinc.200}" + }, + "medium": { + "default": "{colors.solid.zinc.200}", + "hover": "{colors.solid.zinc.300}", + "active": "{colors.solid.zinc.400}", + "strong": "{colors.solid.zinc.500}" + }, + "strong": { + "default": "{colors.solid.zinc.900}", + "hover": "{colors.solid.zinc.800}", + "active": "{colors.solid.zinc.700}", + "selected": "{colors.solid.zinc.900}" + } + } + }, + "border": { + "focus": "{colors.solid.green.200}", + "neutral": { + "default": "{colors.solid.zinc.200}", + "strong": "{colors.solid.zinc.300}", + "bold": { + "default": "{colors.solid.zinc.900}", + "hover": "{colors.solid.zinc.800}" + }, + "inverse": "{colors.alpha.white.1000}" + }, + "brand": { + "subtle": "{colors.solid.green.200}", + "default": "{colors.solid.green.500}", + "strong": "{colors.solid.green.600}" + }, + "status": { + "danger": { + "subtle": "{colors.solid.red.400}", + "default": "{colors.solid.red.500}", + "strong": "{colors.solid.red.600}" + }, + "info": { + "default": "{colors.solid.blue.500}", + "strong": "{colors.solid.blue.600}" + }, + "warning": { + "default": "{colors.solid.yellow.500}", + "strong": "{colors.solid.yellow.600}" + }, + "success": { + "default": "{colors.solid.green.500}", + "strong": "{colors.solid.green.600}" + }, + "help": { "strong": "{colors.solid.purple.600}" } + } + } + } + }, + "dark": { + "color": { + "fg": { + "default": "{colors.alpha.white.1000}", + "hover": "{colors.solid.zinc.300}", + "active": "{colors.solid.zinc.100}", + "focus": "{colors.alpha.white.1000}", + "muted": "{colors.solid.zinc.400}", + "subtle": "{colors.solid.zinc.400}", + "brand": { + "default": "{colors.solid.green.400}", + "hover": "{colors.solid.green.300}", + "active": "{colors.solid.green.200}", + "disabled": "{colors.solid.green.700}", + "visited": "{colors.solid.green.300}", + "muted": "{colors.solid.green.500}" + }, + "inverse": { + "default": "{colors.solid.zinc.900}", + "hover": "{colors.solid.zinc.700}", + "active": "{colors.solid.zinc.950}", + "focus": "{colors.solid.zinc.900}", + "muted": "{colors.solid.zinc.500}" + }, + "status": { + "danger": { + "default": "{colors.solid.red.400}", + "hover": "{colors.solid.red.300}", + "active": "{colors.solid.red.200}", + "disabled": "{colors.solid.red.700}", + "visited": "{colors.solid.red.300}", + "muted": "{colors.solid.red.500}" + }, + "info": { + "default": "{colors.solid.blue.400}", + "hover": "{colors.solid.blue.300}", + "active": "{colors.solid.blue.200}", + "disabled": "{colors.solid.blue.700}", + "visited": "{colors.solid.blue.300}", + "muted": "{colors.solid.blue.500}" + }, + "warning": { + "default": "{colors.solid.yellow.400}", + "hover": "{colors.solid.yellow.300}", + "active": "{colors.solid.yellow.200}", + "disabled": "{colors.solid.yellow.700}", + "visited": "{colors.solid.yellow.300}", + "muted": "{colors.solid.yellow.500}" + }, + "success": { + "default": "{colors.solid.green.400}", + "hover": "{colors.solid.green.300}", + "active": "{colors.solid.green.200}", + "disabled": "{colors.solid.green.700}", + "visited": "{colors.solid.green.300}", + "muted": "{colors.solid.green.500}" + }, + "help": { + "default": "{colors.solid.purple.400}", + "hover": "{colors.solid.purple.300}", + "active": "{colors.solid.purple.200}", + "disabled": "{colors.solid.purple.700}", + "visited": "{colors.solid.purple.300}", + "muted": "{colors.solid.purple.500}" + } + }, + "on": { + "brand": { + "default": "{colors.solid.zinc.900}", + "hover": "{colors.solid.zinc.900}", + "active": "{colors.solid.zinc.900}" + }, + "fill": { + "default": "{colors.alpha.white.1000}", + "hover": "{colors.alpha.white.1000}", + "active": "{colors.alpha.white.1000}", + "muted": "{colors.solid.zinc.200}" + }, + "status": { + "danger": { + "default": "{colors.solid.red.100}", + "hover": "{colors.solid.red.50}" + }, + "info": { + "default": "{colors.solid.blue.100}", + "hover": "{colors.solid.blue.50}" + }, + "warning": { + "default": "{colors.solid.yellow.100}", + "hover": "{colors.solid.yellow.50}" + }, + "success": { + "default": "{colors.solid.green.100}", + "hover": "{colors.solid.green.50}" + }, + "help": { + "default": "{colors.solid.purple.100}", + "hover": "{colors.solid.purple.50}" + } + } + } + }, + "bg": { + "status": { + "danger": { + "weak": { + "default": "{colors.solid.red.950}", + "hover": "{colors.solid.red.900}", + "active": "{colors.solid.red.800}" + }, + "strong": { + "default": "{colors.solid.red.700}", + "hover": "{colors.solid.red.600}", + "active": "{colors.solid.red.500}" + } + }, + "info": { + "weak": { + "default": "{colors.solid.blue.950}", + "hover": "{colors.solid.blue.900}", + "active": "{colors.solid.blue.800}" + }, + "strong": { + "default": "{colors.solid.blue.700}", + "hover": "{colors.solid.blue.600}", + "active": "{colors.solid.blue.500}" + } + }, + "warning": { + "weak": { + "default": "{colors.solid.yellow.950}", + "hover": "{colors.solid.yellow.900}", + "active": "{colors.solid.yellow.800}" + }, + "strong": { + "default": "{colors.solid.yellow.700}", + "hover": "{colors.solid.yellow.600}", + "active": "{colors.solid.yellow.500}" + } + }, + "success": { + "weak": { + "default": "{colors.solid.green.950}", + "hover": "{colors.solid.green.900}", + "active": "{colors.solid.green.800}" + }, + "strong": { + "default": "{colors.solid.green.700}", + "hover": "{colors.solid.green.600}", + "active": "{colors.solid.green.500}" + } + }, + "help": { + "weak": { + "default": "{colors.solid.purple.950}", + "hover": "{colors.solid.purple.900}", + "active": "{colors.solid.purple.800}" + }, + "strong": { + "default": "{colors.solid.purple.700}", + "hover": "{colors.solid.purple.600}", + "active": "{colors.solid.purple.500}" + } + } + }, + "brand": { + "weak": { + "hover": "{colors.solid.green.950}", + "active": "{colors.solid.green.900}" + }, + "strong": { + "default": "{colors.solid.green.500}", + "hover": "{colors.solid.green.400}", + "active": "{colors.solid.green.300}" + } + }, + "surface": { + "canvas": { + "default": "{colors.solid.zinc.900}", + "hover": "{colors.solid.zinc.800}", + "active": "{colors.solid.zinc.700}", + "selected": "{colors.solid.zinc.800}" + }, + "default": { + "default": "{colors.solid.zinc.800}", + "hover": "{colors.solid.zinc.700}", + "active": "{colors.solid.zinc.600}", + "selected": "{colors.solid.zinc.700}" + }, + "raised": { + "default": "{colors.solid.zinc.700}", + "hover": "{colors.solid.zinc.600}", + "active": "{colors.solid.zinc.500}", + "selected": "{colors.solid.zinc.600}" + }, + "overlay": { + "default": "{colors.solid.zinc.800}", + "hover": "{colors.solid.zinc.700}" + }, + "backdrop": "{colors.alpha.black.600}" + }, + "neutral": { + "weak": { + "default": "{colors.solid.zinc.900}", + "hover": "{colors.solid.zinc.800}", + "active": "{colors.solid.zinc.700}", + "disabled": "{colors.solid.zinc.800}" + }, + "medium": { + "default": "{colors.solid.zinc.800}", + "hover": "{colors.solid.zinc.700}", + "active": "{colors.solid.zinc.600}", + "strong": "{colors.solid.zinc.500}" + }, + "strong": { + "default": "{colors.solid.zinc.100}", + "hover": "{colors.solid.zinc.200}", + "active": "{colors.solid.zinc.300}", + "selected": "{colors.solid.zinc.100}" + } + } + }, + "border": { + "focus": "{colors.solid.green.200}", + "neutral": { + "default": "{colors.solid.zinc.800}", + "strong": "{colors.solid.zinc.700}", + "bold": { + "default": "{colors.solid.zinc.100}", + "hover": "{colors.solid.zinc.200}" + }, + "inverse": "{colors.solid.zinc.900}" + }, + "brand": { + "subtle": "{colors.solid.green.800}", + "default": "{colors.solid.green.500}", + "strong": "{colors.solid.green.400}" + }, + "status": { + "danger": { + "subtle": "{colors.solid.red.600}", + "default": "{colors.solid.red.500}", + "strong": "{colors.solid.red.400}" + }, + "info": { + "default": "{colors.solid.blue.500}", + "strong": "{colors.solid.blue.400}" + }, + "warning": { + "default": "{colors.solid.yellow.500}", + "strong": "{colors.solid.yellow.400}" + }, + "success": { + "default": "{colors.solid.green.500}", + "strong": "{colors.solid.green.400}" + }, + "help": { "strong": "{colors.solid.purple.400}" } + } + } + } + } + }, + "dimension": { + "space": { + "none": "{sizing.none}", + "100": "{sizing.2x}", + "150": "{sizing.3x}", + "200": "{sizing.4x}", + "300": "{sizing.5x}", + "400": "{sizing.7x}", + "500": "{sizing.9x}", + "600": "{sizing.10x}", + "700": "{sizing.12x}", + "800": "{sizing.14x}", + "negative": { + "50": "-0.125rem", + "200": "-0.5rem", + "300": "-0.75rem", + "600": "-1.5rem" + } + }, + "size": { + "none": "{sizing.none}", + "50": "{sizing.1x}", + "100": "{sizing.2x}", + "150": "{sizing.3x}", + "200": "{sizing.4x}", + "300": "{sizing.5x}", + "350": "{sizing.6x}", + "400": "{sizing.7x}", + "450": "{sizing.8x}", + "500": "{sizing.9x}", + "600": "{sizing.10x}", + "700": "{sizing.12x}", + "750": "{sizing.13x}", + "800": "{sizing.14x}", + "900": "{sizing.16x}", + "1000": "{sizing.18x}", + "1100": "{sizing.20x}", + "1200": "{sizing.24x}", + "1300": "{sizing.28x}", + "1400": "{sizing.32x}", + "1500": "{sizing.40x}", + "1600": "{sizing.120x}", + "1700": "{sizing.136x}", + "1800": "{sizing.152x}", + "1900": "{sizing.168x}", + "2000": "{sizing.200x}", + "max": "{sizing.max}" + }, + "borderRadius": { + "none": "{sizing.none}", + "100": "{sizing.2x}", + "200": "{sizing.4x}", + "300": "{sizing.5x}", + "400": "{sizing.7x}", + "500": "{sizing.10x}", + "max": "{sizing.max}" + }, + "borderWidth": { + "none": "{sizing.none}", + "100": "{sizing.05x}", + "200": "{sizing.1x}", + "300": "{sizing.2x}" + }, + "focusRing": { "width": "{sizing.2x}", "offset": "{sizing.none}" }, + "depth": { + "100": "1000", + "200": "1100", + "300": "1200", + "400": "1300", + "500": "1400", + "600": "1500", + "700": "1600" + }, + "viewport": { + "100": "{sizing.288x}", + "200": "{sizing.384x}", + "300": "{sizing.496x}", + "400": "{sizing.600x}", + "500": "{sizing.700x}" + } + }, + "effects": { + "opacity": { + "0": "0", + "4": "0.04", + "8": "0.08", + "12": "0.12", + "16": "0.16", + "20": "0.2", + "30": "0.3", + "40": "0.4", + "50": "0.5", + "60": "0.6", + "70": "0.7", + "80": "0.8", + "90": "0.9", + "100": "1" + }, + "blur": { + "none": "0", + "100": "4px", + "200": "8px", + "300": "16px", + "400": "24px" + }, + "transition": { + "easing": { + "linear": "linear", + "in": "cubic-bezier(0.55, 0.06, 0.7, 0.2)", + "out": "cubic-bezier(0.2, 0.6, 0.4, 1)", + "inOut": "cubic-bezier(0.65, 0.05, 0.35, 1)", + "standard": "cubic-bezier(0.2, 0, 0, 1)", + "accelerate": "cubic-bezier(0.3, 0, 1, 1)", + "decelerate": "cubic-bezier(0, 0, 0, 1)", + "emphasizedAccelerate": "cubic-bezier(0.3, 0, 0.8, 0.15)", + "emphasizedDecelerate": "cubic-bezier(0.05, 0.7, 0.1, 1)", + "spring": "cubic-bezier(0.34, 1.56, 0.64, 1)" + }, + "duration": { + "100": "140ms", + "200": "180ms", + "300": "240ms", + "400": "320ms", + "500": "400ms" + } + }, + "elevation": { + "none": "none", + "100": "0 0 2px {colors.alpha.black.200}", + "200": "0 0 4px {colors.alpha.black.200}", + "300": "0 2px 4px {colors.alpha.black.200}", + "400": "0 4px 8px {colors.alpha.black.200}", + "500": "0 8px 16px 0 {colors.alpha.black.200}", + "status": { + "info": "0px 4px 8px 0px {colors.alpha.blue.40}", + "success": "0px 4px 8px 0px {colors.alpha.green.40}", + "warning": "0px 4px 8px 0px {colors.alpha.yellow.40}", + "danger": "0px 4px 8px 0px {colors.alpha.red.40}", + "secondary": "0px 4px 8px 0px {colors.alpha.black.40}", + "contrast": "0px 4px 8px 0px {colors.alpha.black.40}" + } + }, + "focusRing": { + "shadow": "inset 0 0 0 {dimension.focusRing.width} {colors.solid.green.200}" + } + } + }, + "components": { + "accordion": { + "extend": { + "extHeader": { + "iconSize": "{dimension.size.600}", + "gap": "{dimension.space.200}" + } + }, + "colorScheme": { + "light": { + "header": { + "background": "transparent", + "hoverBackground": "transparent", + "activeBackground": "transparent", + "activeHoverBackground": "transparent" + } + }, + "dark": { + "header": { + "activeBackground": "transparent", + "activeHoverBackground": "transparent", + "background": "transparent", + "hoverBackground": "transparent" + } + } + }, + "header": { + "color": "{color.fg.default}", + "hoverColor": "{color.fg.hover}", + "activeColor": "{color.fg.default}", + "activeHoverColor": "{color.fg.hover}", + "borderColor": "transparent", + "padding": "{dimension.space.400} {dimension.space.none} {dimension.space.400} {dimension.space.none}", + "fontWeight": "{fonts.fontWeight.bold}", + "borderRadius": "{dimension.borderRadius.none}", + "borderWidth": "{dimension.borderWidth.none}", + "focusRing": { + "width": "{dimension.focusRing.width}", + "style": "none", + "color": "{color.border.focus}", + "offset": "{dimension.focusRing.offset}", + "shadow": "{effects.focusRing.shadow}" + }, + "toggleIcon": { + "color": "{color.fg.default}", + "hoverColor": "{color.fg.hover}", + "activeColor": "{color.fg.default}", + "activeHoverColor": "{color.fg.hover}" + }, + "last": { + "bottomBorderRadius": "{dimension.borderRadius.none}", + "activeBottomBorderRadius": "{dimension.borderRadius.none}" + }, + "first": { + "borderWidth": "{dimension.borderWidth.none}", + "topBorderRadius": "{dimension.borderRadius.none}" + } + }, + "root": { "transitionDuration": "{effects.transition.duration.200}" }, + "panel": { + "borderWidth": "{dimension.borderWidth.none} {dimension.borderWidth.none} {dimension.borderWidth.300} {dimension.borderWidth.none}", + "borderColor": "{color.border.neutral.strong}" + }, + "content": { + "borderWidth": "{dimension.borderWidth.100} {dimension.borderWidth.none} {dimension.borderWidth.none} {dimension.borderWidth.none}", + "borderColor": "transparent", + "background": "transparent", + "color": "{color.fg.default}", + "padding": "{dimension.space.none} {dimension.space.700} {dimension.space.400} {dimension.space.700}" + } + }, + "autocomplete": { + "extend": { + "extOption": { "gap": "{dimension.space.200}" }, + "extOptionGroup": { "gap": "{dimension.space.200}" } + }, + "colorScheme": { + "light": { + "chip": { + "focusBackground": "{color.bg.neutral.medium.default}", + "focusColor": "{color.fg.default}" + }, + "dropdown": { + "background": "{color.bg.surface.default.default}", + "hoverBackground": "{color.bg.surface.default.default}", + "activeBackground": "{color.bg.surface.default.default}", + "color": "{color.fg.active}", + "hoverColor": "{color.fg.active}", + "activeColor": "{color.fg.active}" + } + }, + "dark": { + "chip": { + "focusBackground": "{color.bg.neutral.strong.hover}", + "focusColor": "{color.fg.inverse.focus}" + }, + "dropdown": { + "activeBackground": "{color.bg.surface.default.default}", + "activeColor": "{color.fg.inverse.active}", + "background": "{color.bg.surface.default.default}", + "color": "{color.fg.inverse.active}", + "hoverBackground": "{color.bg.surface.default.default}", + "hoverColor": "{color.fg.inverse.active}" + } + } + }, + "root": { + "background": "{color.bg.surface.default.default}", + "disabledBackground": "{color.bg.surface.canvas.hover}", + "filledBackground": "{color.bg.surface.default.default}", + "filledHoverBackground": "{color.bg.surface.default.default}", + "filledFocusBackground": "{color.bg.surface.default.default}", + "borderColor": "{color.border.neutral.strong}", + "hoverBorderColor": "{color.border.brand.strong}", + "focusBorderColor": "{color.border.brand.strong}", + "invalidBorderColor": "{color.border.status.danger.subtle}", + "color": "{color.fg.active}", + "disabledColor": "{color.fg.muted}", + "placeholderColor": "{color.fg.muted}", + "invalidPlaceholderColor": "{color.fg.status.danger.hover}", + "shadow": "{effects.elevation.none}", + "paddingX": "{dimension.space.400}", + "paddingY": "{dimension.space.400}", + "borderRadius": "{dimension.borderRadius.400}", + "transitionDuration": "{effects.transition.duration.200}", + "focusRing": { + "width": "{dimension.focusRing.width}", + "style": "none", + "color": "{color.border.focus}", + "offset": "{dimension.focusRing.offset}", + "shadow": "{effects.elevation.none}" + } + }, + "overlay": { + "background": "{color.bg.surface.default.default}", + "borderColor": "{color.border.neutral.default}", + "borderRadius": "{dimension.borderRadius.400}", + "color": "{color.fg.default}", + "shadow": "{effects.elevation.200}" + }, + "list": { + "padding": "{dimension.space.100}", + "gap": "{dimension.space.100}" + }, + "option": { + "focusBackground": "{color.bg.neutral.weak.default}", + "selectedBackground": "{color.bg.neutral.strong.selected}", + "selectedFocusBackground": "{color.bg.neutral.strong.active}", + "color": "{color.fg.default}", + "focusColor": "{color.fg.default}", + "selectedColor": "{color.fg.on.fill.default}", + "selectedFocusColor": "{color.fg.on.fill.active}", + "padding": "{dimension.space.200} {dimension.space.400}", + "borderRadius": "{dimension.borderRadius.200}" + }, + "optionGroup": { + "background": "{color.bg.surface.raised.default}", + "color": "{color.fg.muted}", + "fontWeight": "{fonts.fontWeight.demibold}", + "padding": "{dimension.space.200} {dimension.space.400}" + }, + "dropdown": { + "width": "{dimension.size.1700}", + "borderColor": "{color.border.neutral.strong}", + "hoverBorderColor": "{color.border.brand.strong}", + "activeBorderColor": "{color.border.brand.strong}", + "borderRadius": "{dimension.borderRadius.400}", + "focusRing": { + "width": "{dimension.focusRing.width}", + "style": "none", + "color": "{color.border.focus}", + "offset": "{dimension.focusRing.offset}", + "shadow": "{effects.elevation.none}" + }, + "sm": { "width": "{dimension.size.1600}" }, + "lg": { "width": "{dimension.size.1800}" } + }, + "chip": { "borderRadius": "{dimension.borderRadius.200}" }, + "emptyMessage": { + "padding": "{dimension.space.200} {dimension.space.400}" + } + }, + "avatar": { + "extend": { + "borderColor": "{color.border.neutral.strong}", + "circle": { "borderRadius": "{dimension.borderRadius.max}" } + }, + "root": { + "width": "{dimension.size.900}", + "height": "{dimension.size.900}", + "fontSize": "{fonts.fontSize.300}", + "color": "{color.fg.on.brand.default}", + "background": "{color.bg.brand.strong.default}", + "borderRadius": "{dimension.borderRadius.400}" + }, + "icon": { "size": "{dimension.size.450}" }, + "group": { + "borderColor": "{color.border.neutral.inverse}", + "offset": "{dimension.space.negative.300}" + }, + "lg": { + "width": "{dimension.size.1100}", + "height": "{dimension.size.1100}", + "fontSize": "{fonts.fontSize.300}", + "icon": { "size": "{dimension.size.450}" }, + "group": { "offset": "{dimension.space.negative.300}" } + }, + "xl": { + "width": "{dimension.size.1300}", + "height": "{dimension.size.1300}", + "icon": { "size": "{dimension.size.700}" }, + "group": { "offset": "{dimension.space.negative.600}" }, + "fontSize": "{fonts.fontSize.300}" + } + }, + "badge": { + "extend": { + "extDot": { + "success": { "background": "{color.bg.status.success.strong.hover}" }, + "info": { "background": "{color.bg.status.info.strong.hover}" }, + "warn": { "background": "{color.bg.status.warning.strong.hover}" }, + "danger": { "background": "{color.bg.status.danger.strong.hover}" }, + "lg": { "size": "{dimension.size.350}" }, + "xlg": { "size": "{dimension.size.450}" } + }, + "ext": { "padding": "{dimension.space.none}" } + }, + "colorScheme": { + "light": { + "primary": { + "color": "{color.fg.default}", + "background": "{color.bg.brand.strong.default}" + }, + "secondary": { + "color": "{color.fg.on.fill.default}", + "background": "{color.bg.neutral.strong.default}" + }, + "success": { + "color": "{color.fg.on.status.success.default}", + "background": "{color.bg.status.success.strong.default}" + }, + "info": { + "color": "{color.fg.on.status.info.default}", + "background": "{color.bg.status.info.strong.default}" + }, + "warn": { + "color": "{color.fg.on.status.warning.default}", + "background": "{color.bg.status.warning.strong.default}" + }, + "danger": { + "color": "{color.fg.on.status.danger.default}", + "background": "{color.bg.status.danger.strong.default}" + }, + "contrast": { + "background": "{color.bg.neutral.strong.default}", + "color": "{color.fg.on.fill.default}" + } + }, + "dark": { + "contrast": { + "background": "{color.bg.surface.canvas.default}", + "color": "{color.fg.default}" + }, + "danger": { + "background": "{color.bg.status.danger.strong.default}", + "color": "{color.fg.on.status.danger.default}" + }, + "info": { + "background": "{color.bg.status.info.strong.default}", + "color": "{color.fg.on.status.info.default}" + }, + "primary": { + "background": "{color.bg.brand.strong.default}", + "color": "{color.fg.inverse.default}" + }, + "secondary": { + "background": "{color.bg.surface.canvas.default}", + "color": "{color.fg.default}" + }, + "success": { + "background": "{color.bg.status.success.strong.default}", + "color": "{color.fg.on.status.success.default}" + }, + "warn": { + "background": "{color.bg.status.warning.strong.default}", + "color": "{color.fg.on.status.warning.default}" + } + } + }, + "root": { + "borderRadius": "{dimension.borderRadius.200}", + "padding": "{dimension.space.200}", + "fontSize": "{fonts.fontSize.100}", + "fontWeight": "{fonts.fontWeight.regular}", + "minWidth": "{dimension.size.700}", + "height": "{dimension.size.700}" + }, + "dot": { "size": "{dimension.size.200}" }, + "sm": { + "fontSize": "{fonts.fontSize.100}", + "minWidth": "{dimension.size.none}", + "height": "{dimension.size.none}" + }, + "lg": { + "fontSize": "{fonts.fontSize.100}", + "minWidth": "{dimension.size.800}", + "height": "{dimension.size.800}" + }, + "xl": { + "fontSize": "{fonts.fontSize.100}", + "minWidth": "{dimension.size.900}", + "height": "{dimension.size.900}" + } + }, + "breadcrumb": { + "extend": { + "hoverBackground": "{color.bg.neutral.weak.default}", + "iconSize": "{dimension.size.600}", + "extItem": { "padding": "{dimension.space.100}" } + }, + "root": { + "padding": "{dimension.space.none}", + "background": "transparent", + "gap": "{dimension.space.none}", + "transitionDuration": "{effects.transition.duration.200}" + }, + "focusRing": { + "width": "{dimension.focusRing.width}", + "style": "none", + "color": "{color.border.focus}", + "offset": "{dimension.focusRing.offset}", + "shadow": "{effects.elevation.200}" + }, + "item": { + "color": "{color.fg.default}", + "hoverColor": "{color.fg.hover}", + "borderRadius": "{dimension.borderRadius.100}", + "gap": "{dimension.space.200}", + "icon": { + "color": "{color.fg.default}", + "hoverColor": "{color.fg.hover}" + }, + "focusRing": { + "color": "{color.border.focus}", + "offset": "{dimension.focusRing.offset}", + "shadow": "{effects.elevation.none}", + "style": "none", + "width": "{dimension.focusRing.width}" + } + }, + "separator": { "color": "{color.fg.default}" } + }, + "button": { + "extend": { + "disabledBackground": "{color.bg.neutral.weak.disabled}", + "extOutlined": { + "danger": { "focusBackground": "transparent" }, + "warn": { "focusBackground": "transparent" }, + "info": { "focusBackground": "transparent" }, + "help": { "focusBackground": "transparent" }, + "success": { "focusBackground": "transparent" } + }, + "disabledColor": "{color.fg.muted}", + "extText": { + "danger": { "focusBackground": "transparent" }, + "warn": { "focusBackground": "transparent" }, + "info": { "focusBackground": "transparent" }, + "help": { "focusBackground": "transparent" }, + "success": { "focusBackground": "transparent" } + }, + "extLink": { + "background": "transparent", + "colorHover": "{color.fg.hover}", + "paddingX": "{dimension.space.none}", + "paddingY": "{dimension.space.100}", + "sm": { "iconOnlyWidth": "{dimension.size.450}" }, + "base": { "iconOnlyWidth": "{dimension.size.700}" }, + "lg": { "iconOnlyWidth": "{dimension.size.800}" }, + "xlg": { "iconOnlyWidth": "{dimension.size.900}" } + }, + "extSm": { + "borderRadius": "{dimension.borderRadius.400}", + "gap": "{dimension.space.200}" + }, + "extLg": { + "borderRadius": "{dimension.borderRadius.400}", + "gap": "{dimension.space.400}", + "height": "{dimension.size.1300}" + }, + "extXlg": { + "borderRadius": "{dimension.borderRadius.400}", + "gap": "{dimension.space.400}", + "iconOnlyWidth": "{dimension.size.1400}", + "paddingX": "{dimension.space.700}", + "paddingY": "{dimension.space.600}", + "height": "{dimension.size.1400}" + }, + "borderWidth": "{dimension.borderWidth.100}", + "iconSize": { + "sm": "{dimension.size.450}", + "md": "{dimension.size.600}", + "lg": "{dimension.size.700}" + } + }, + "colorScheme": { + "light": { + "root": { + "primary": { + "background": "{color.bg.brand.strong.default}", + "hoverBackground": "{color.bg.brand.strong.hover}", + "activeBackground": "{color.bg.brand.strong.active}", + "borderColor": "transparent", + "hoverBorderColor": "transparent", + "activeBorderColor": "transparent", + "color": "{color.fg.default}", + "hoverColor": "{color.fg.default}", + "activeColor": "{color.fg.default}", + "focusRing": { + "color": "{color.border.focus}", + "shadow": "{effects.elevation.200}" + } + }, + "secondary": { + "background": "{color.bg.neutral.strong.default}", + "hoverBackground": "{color.bg.neutral.strong.hover}", + "activeBackground": "{color.bg.neutral.strong.active}", + "borderColor": "transparent", + "hoverBorderColor": "transparent", + "activeBorderColor": "transparent", + "color": "{color.fg.on.fill.default}", + "hoverColor": "{color.fg.on.fill.hover}", + "activeColor": "{color.fg.on.fill.active}", + "focusRing": { + "color": "{color.border.focus}", + "shadow": "{effects.elevation.200}" + } + }, + "contrast": { + "background": "{color.bg.surface.canvas.hover}", + "hoverBackground": "{color.bg.surface.canvas.active}", + "activeBackground": "{color.bg.neutral.medium.active}", + "borderColor": "transparent", + "hoverBorderColor": "transparent", + "activeBorderColor": "transparent", + "color": "{color.fg.default}", + "hoverColor": "{color.fg.default}", + "activeColor": "{color.fg.default}", + "focusRing": { + "color": "{color.border.focus}", + "shadow": "{effects.elevation.200}" + } + }, + "info": { + "background": "{color.bg.status.info.strong.default}", + "hoverBackground": "{color.bg.status.info.strong.hover}", + "activeBackground": "{color.bg.status.info.strong.active}", + "borderColor": "transparent", + "hoverBorderColor": "transparent", + "activeBorderColor": "transparent", + "color": "{color.fg.on.status.info.default}", + "hoverColor": "{color.fg.on.status.info.hover}", + "activeColor": "{color.fg.on.status.info.default}", + "focusRing": { + "color": "{color.border.focus}", + "shadow": "{effects.elevation.none}" + } + }, + "success": { + "background": "{color.bg.status.success.strong.default}", + "hoverBackground": "{color.bg.status.success.strong.hover}", + "activeBackground": "{color.bg.status.success.strong.active}", + "borderColor": "transparent", + "hoverBorderColor": "transparent", + "activeBorderColor": "transparent", + "color": "{color.fg.on.status.success.default}", + "hoverColor": "{color.fg.on.status.success.hover}", + "activeColor": "{color.fg.on.status.success.default}", + "focusRing": { + "color": "{color.border.focus}", + "shadow": "{effects.elevation.none}" + } + }, + "warn": { + "background": "{color.bg.status.warning.strong.default}", + "hoverBackground": "{color.bg.status.warning.strong.hover}", + "activeBackground": "{color.bg.status.warning.strong.active}", + "borderColor": "transparent", + "hoverBorderColor": "transparent", + "activeBorderColor": "transparent", + "color": "{color.fg.on.status.warning.default}", + "hoverColor": "{color.fg.on.status.warning.hover}", + "activeColor": "{color.fg.on.status.warning.default}", + "focusRing": { + "color": "{color.border.focus}", + "shadow": "{effects.elevation.none}" + } + }, + "help": { + "background": "{color.bg.status.help.strong.default}", + "hoverBackground": "{color.bg.status.help.strong.hover}", + "activeBackground": "{color.bg.status.help.strong.active}", + "borderColor": "transparent", + "hoverBorderColor": "transparent", + "activeBorderColor": "transparent", + "color": "{color.fg.on.status.help.default}", + "hoverColor": "{color.fg.on.status.help.hover}", + "activeColor": "{color.fg.on.status.help.default}", + "focusRing": { + "color": "{color.border.focus}", + "shadow": "{effects.elevation.none}" + } + }, + "danger": { + "background": "{color.bg.status.danger.strong.default}", + "hoverBackground": "{color.bg.status.danger.strong.hover}", + "activeBackground": "{color.bg.status.danger.strong.active}", + "borderColor": "transparent", + "hoverBorderColor": "transparent", + "activeBorderColor": "transparent", + "color": "{color.fg.on.status.danger.default}", + "hoverColor": "{color.fg.on.status.danger.hover}", + "activeColor": "{color.fg.on.status.danger.default}", + "focusRing": { + "color": "{color.border.focus}", + "shadow": "{effects.elevation.none}" + } + } + }, + "outlined": { + "primary": { + "hoverBackground": "{color.bg.brand.weak.hover}", + "activeBackground": "{color.bg.brand.weak.active}", + "borderColor": "{color.border.focus}", + "color": "{color.fg.brand.default}" + }, + "success": { + "hoverBackground": "{color.bg.status.success.weak.hover}", + "activeBackground": "{color.bg.status.success.weak.active}", + "borderColor": "{color.border.brand.strong}", + "color": "{color.fg.status.success.hover}" + }, + "info": { + "hoverBackground": "{color.bg.status.info.weak.hover}", + "activeBackground": "{color.bg.status.info.weak.active}", + "borderColor": "{color.border.status.info.strong}", + "color": "{color.fg.status.info.hover}" + }, + "warn": { + "hoverBackground": "{color.bg.status.warning.weak.hover}", + "activeBackground": "{color.bg.status.warning.weak.active}", + "borderColor": "{color.border.status.warning.strong}", + "color": "{color.fg.status.warning.hover}" + }, + "help": { + "hoverBackground": "{color.bg.status.help.weak.hover}", + "activeBackground": "{color.bg.status.help.weak.active}", + "borderColor": "{color.border.status.help.strong}", + "color": "{color.fg.status.help.hover}" + }, + "danger": { + "hoverBackground": "{color.bg.status.danger.weak.hover}", + "activeBackground": "{color.bg.status.danger.weak.active}", + "borderColor": "{color.border.status.danger.strong}", + "color": "{color.fg.status.danger.hover}" + }, + "contrast": { + "activeBackground": "{color.bg.neutral.strong.active}", + "borderColor": "{color.border.neutral.bold.default}", + "color": "{color.fg.on.fill.default}", + "hoverBackground": "{color.bg.neutral.strong.hover}" + }, + "plain": { + "activeBackground": "{color.bg.neutral.medium.default}", + "borderColor": "{color.border.neutral.strong}", + "color": "{color.fg.default}", + "hoverBackground": "{color.bg.neutral.weak.default}" + }, + "secondary": { + "activeBackground": "{color.bg.neutral.medium.default}", + "borderColor": "{color.border.neutral.strong}", + "color": "{color.fg.default}", + "hoverBackground": "{color.bg.neutral.weak.default}" + } + }, + "text": { + "primary": { + "hoverBackground": "{color.bg.neutral.weak.default}", + "activeBackground": "{color.bg.neutral.medium.default}", + "color": "{color.fg.default}" + }, + "success": { + "hoverBackground": "{color.bg.status.success.weak.hover}", + "activeBackground": "{color.bg.status.success.weak.active}", + "color": "{color.fg.status.success.hover}" + }, + "info": { + "hoverBackground": "{color.bg.status.info.weak.hover}", + "activeBackground": "{color.bg.status.info.weak.active}", + "color": "{color.fg.status.info.hover}" + }, + "warn": { + "hoverBackground": "{color.bg.status.warning.weak.hover}", + "activeBackground": "{color.bg.status.warning.weak.active}", + "color": "{color.fg.status.warning.hover}" + }, + "help": { + "hoverBackground": "{color.bg.status.help.weak.hover}", + "activeBackground": "{color.bg.status.help.weak.active}", + "color": "{color.fg.status.help.hover}" + }, + "danger": { + "hoverBackground": "{color.bg.status.danger.weak.hover}", + "activeBackground": "{color.bg.status.danger.weak.active}", + "color": "{color.fg.status.danger.hover}" + }, + "contrast": { + "activeBackground": "{color.bg.neutral.strong.active}", + "color": "{color.fg.on.fill.default}", + "hoverBackground": "{color.bg.neutral.strong.hover}" + }, + "plain": { + "activeBackground": "{color.bg.neutral.medium.default}", + "color": "{color.fg.default}", + "hoverBackground": "{color.bg.neutral.weak.default}" + }, + "secondary": { + "activeBackground": "{color.bg.neutral.medium.default}", + "color": "{color.fg.default}", + "hoverBackground": "{color.bg.neutral.weak.default}" + } + }, + "link": { + "color": "{color.fg.default}", + "hoverColor": "{color.fg.hover}", + "activeColor": "{color.fg.muted}" + } + }, + "dark": { + "link": { + "activeColor": "{color.fg.inverse.muted}", + "color": "{color.fg.inverse.default}", + "hoverColor": "{color.fg.inverse.hover}" + }, + "outlined": { + "contrast": { + "activeBackground": "{color.bg.surface.canvas.active}", + "borderColor": "{color.border.neutral.inverse}", + "color": "{color.fg.default}", + "hoverBackground": "{color.bg.surface.canvas.hover}" + }, + "danger": { + "activeBackground": "{color.bg.status.danger.weak.active}", + "borderColor": "{color.border.status.danger.subtle}", + "color": "{color.fg.status.danger.hover}", + "hoverBackground": "{color.bg.status.danger.weak.hover}" + }, + "help": { + "activeBackground": "{color.bg.status.help.weak.active}", + "borderColor": "{color.border.status.help.strong}", + "color": "{color.fg.status.help.hover}", + "hoverBackground": "{color.bg.status.help.weak.hover}" + }, + "info": { + "activeBackground": "{color.bg.status.info.weak.active}", + "borderColor": "{color.border.status.info.strong}", + "color": "{color.fg.status.info.hover}", + "hoverBackground": "{color.bg.status.info.weak.hover}" + }, + "plain": { + "activeBackground": "{color.bg.neutral.strong.hover}", + "borderColor": "{color.border.neutral.strong}", + "color": "{color.fg.inverse.default}", + "hoverBackground": "{color.bg.neutral.strong.selected}" + }, + "primary": { + "activeBackground": "{color.bg.brand.weak.active}", + "borderColor": "{color.border.focus}", + "color": "{color.fg.brand.muted}", + "hoverBackground": "{color.bg.brand.weak.hover}" + }, + "secondary": { + "activeBackground": "{color.bg.neutral.strong.hover}", + "borderColor": "{color.border.neutral.strong}", + "color": "{color.fg.inverse.default}", + "hoverBackground": "{color.bg.neutral.strong.selected}" + }, + "success": { + "activeBackground": "{color.bg.status.success.weak.active}", + "borderColor": "{color.border.brand.strong}", + "color": "{color.fg.status.success.hover}", + "hoverBackground": "{color.bg.status.success.weak.hover}" + }, + "warn": { + "activeBackground": "{color.bg.status.warning.weak.active}", + "borderColor": "{color.border.status.warning.strong}", + "color": "{color.fg.status.warning.hover}", + "hoverBackground": "{color.bg.status.warning.weak.hover}" + } + }, + "root": { + "contrast": { + "activeBackground": "{color.bg.neutral.medium.active}", + "activeBorderColor": "transparent", + "activeColor": "{color.fg.on.brand.active}", + "background": "{color.bg.neutral.strong.hover}", + "borderColor": "transparent", + "color": "{color.fg.inverse.default}", + "focusRing": { + "color": "{color.border.focus}", + "shadow": "{effects.elevation.200}" + }, + "hoverBackground": "{color.bg.neutral.strong.active}", + "hoverBorderColor": "transparent", + "hoverColor": "{color.fg.on.brand.hover}" + }, + "danger": { + "activeBackground": "{color.bg.status.danger.strong.active}", + "activeBorderColor": "transparent", + "activeColor": "{color.fg.on.status.danger.default}", + "background": "{color.bg.status.danger.strong.default}", + "borderColor": "transparent", + "color": "{color.fg.on.status.danger.default}", + "focusRing": { + "color": "{color.border.focus}", + "shadow": "{effects.elevation.none}" + }, + "hoverBackground": "{color.bg.status.danger.strong.hover}", + "hoverBorderColor": "transparent", + "hoverColor": "{color.fg.on.status.danger.hover}" + }, + "help": { + "activeBackground": "{color.bg.status.help.strong.active}", + "activeBorderColor": "transparent", + "activeColor": "{color.fg.on.status.help.default}", + "background": "{color.bg.status.help.strong.default}", + "borderColor": "transparent", + "color": "{color.fg.on.status.help.default}", + "focusRing": { + "color": "{color.border.focus}", + "shadow": "{effects.elevation.none}" + }, + "hoverBackground": "{color.bg.status.help.strong.hover}", + "hoverBorderColor": "transparent", + "hoverColor": "{color.fg.on.status.help.hover}" + }, + "info": { + "activeBackground": "{color.bg.status.info.strong.active}", + "activeBorderColor": "transparent", + "activeColor": "{color.fg.on.status.info.default}", + "background": "{color.bg.status.info.strong.default}", + "borderColor": "transparent", + "color": "{color.fg.on.status.info.default}", + "focusRing": { + "color": "{color.border.focus}", + "shadow": "{effects.elevation.none}" + }, + "hoverBackground": "{color.bg.status.info.strong.hover}", + "hoverBorderColor": "transparent", + "hoverColor": "{color.fg.on.status.info.hover}" + }, + "primary": { + "activeBackground": "{color.bg.status.success.strong.default}", + "activeBorderColor": "transparent", + "activeColor": "{color.fg.on.brand.active}", + "background": "{color.bg.brand.strong.default}", + "borderColor": "transparent", + "color": "{color.fg.inverse.default}", + "focusRing": { + "color": "{color.border.focus}", + "shadow": "{effects.elevation.200}" + }, + "hoverBackground": "{color.bg.status.success.strong.hover}", + "hoverBorderColor": "transparent", + "hoverColor": "{color.fg.on.brand.hover}" + }, + "secondary": { + "activeBackground": "{color.bg.surface.canvas.active}", + "activeBorderColor": "transparent", + "activeColor": "{color.fg.on.fill.active}", + "background": "{color.bg.surface.canvas.default}", + "borderColor": "transparent", + "color": "{color.fg.default}", + "focusRing": { + "color": "{color.border.focus}", + "shadow": "{effects.elevation.200}" + }, + "hoverBackground": "{color.bg.surface.canvas.hover}", + "hoverBorderColor": "transparent", + "hoverColor": "{color.fg.on.fill.hover}" + }, + "success": { + "activeBackground": "{color.bg.status.success.strong.active}", + "activeBorderColor": "transparent", + "activeColor": "{color.fg.on.status.success.default}", + "background": "{color.bg.brand.strong.active}", + "borderColor": "transparent", + "color": "{color.fg.on.status.success.default}", + "focusRing": { + "color": "{color.border.focus}", + "shadow": "{effects.elevation.none}" + }, + "hoverBackground": "{color.bg.brand.strong.hover}", + "hoverBorderColor": "transparent", + "hoverColor": "{color.fg.on.status.success.hover}" + }, + "warn": { + "activeBackground": "{color.bg.status.warning.strong.active}", + "activeBorderColor": "transparent", + "activeColor": "{color.fg.on.status.warning.default}", + "background": "{color.bg.status.warning.strong.default}", + "borderColor": "transparent", + "color": "{color.fg.on.status.warning.default}", + "focusRing": { + "color": "{color.border.focus}", + "shadow": "{effects.elevation.none}" + }, + "hoverBackground": "{color.bg.status.warning.strong.hover}", + "hoverBorderColor": "transparent", + "hoverColor": "{color.fg.on.status.warning.hover}" + } + }, + "text": { + "contrast": { + "activeBackground": "{color.bg.surface.canvas.active}", + "color": "{color.fg.default}", + "hoverBackground": "{color.bg.surface.canvas.hover}" + }, + "danger": { + "activeBackground": "{color.bg.status.danger.weak.active}", + "color": "{color.fg.status.danger.hover}", + "hoverBackground": "{color.bg.status.danger.weak.hover}" + }, + "help": { + "activeBackground": "{color.bg.status.help.weak.active}", + "color": "{color.fg.status.help.hover}", + "hoverBackground": "{color.bg.status.help.weak.hover}" + }, + "info": { + "activeBackground": "{color.bg.status.info.weak.active}", + "color": "{color.fg.status.info.hover}", + "hoverBackground": "{color.bg.status.info.weak.hover}" + }, + "plain": { + "activeBackground": "{color.bg.neutral.strong.hover}", + "color": "{color.fg.inverse.default}", + "hoverBackground": "{color.bg.neutral.strong.selected}" + }, + "primary": { + "activeBackground": "{color.bg.neutral.strong.hover}", + "color": "{color.fg.inverse.default}", + "hoverBackground": "{color.bg.neutral.strong.selected}" + }, + "secondary": { + "activeBackground": "{color.bg.neutral.strong.hover}", + "color": "{color.fg.inverse.default}", + "hoverBackground": "{color.bg.neutral.strong.selected}" + }, + "success": { + "activeBackground": "{color.bg.status.success.weak.active}", + "color": "{color.fg.status.success.hover}", + "hoverBackground": "{color.bg.status.success.weak.hover}" + }, + "warn": { + "activeBackground": "{color.bg.status.warning.weak.active}", + "color": "{color.fg.status.warning.hover}", + "hoverBackground": "{color.bg.status.warning.weak.hover}" + } + } + } + }, + "root": { + "borderRadius": "{dimension.borderRadius.400}", + "roundedBorderRadius": "{dimension.borderRadius.max}", + "gap": "{dimension.space.200}", + "paddingX": "{dimension.space.400}", + "paddingY": "{dimension.space.200}", + "iconOnlyWidth": "{dimension.size.1100}", + "raisedShadow": "none", + "badgeSize": "{dimension.size.450}", + "transitionDuration": "{effects.transition.duration.200}", + "focusRing": { + "width": "{dimension.focusRing.width}", + "style": "none", + "offset": "{dimension.focusRing.offset}" + }, + "sm": { + "fontSize": "{fonts.fontSize.200}", + "iconOnlyWidth": "{dimension.size.900}", + "paddingX": "{dimension.space.400}", + "paddingY": "{dimension.space.200}" + }, + "lg": { + "fontSize": "{fonts.fontSize.500}", + "iconOnlyWidth": "{dimension.size.1300}", + "paddingX": "{dimension.space.700}", + "paddingY": "{dimension.space.400}" + }, + "label": { "fontWeight": "{fonts.fontWeight.demibold}" } + } + }, + "card": { + "extend": { + "borderColor": "{color.border.neutral.default}", + "borderWidth": "{dimension.borderWidth.100}" + }, + "root": { + "background": "{color.bg.surface.default.default}", + "borderRadius": "{dimension.borderRadius.400}", + "color": "{color.fg.default}", + "shadow": "{effects.elevation.none}" + }, + "body": { + "padding": "{dimension.space.400}", + "gap": "{dimension.space.400}" + }, + "caption": { "gap": "{dimension.space.100}" }, + "title": { + "fontSize": "{fonts.fontSize.400}", + "fontWeight": "{fonts.fontWeight.demibold}" + }, + "subtitle": { "color": "{color.fg.muted}" } + }, + "carousel": { + "colorScheme": { + "light": { + "indicator": { + "background": "{color.bg.neutral.weak.active}", + "hoverBackground": "{color.bg.neutral.medium.active}", + "activeBackground": "{color.bg.neutral.strong.default}" + } + }, + "dark": { + "indicator": { + "activeBackground": "{color.bg.surface.canvas.default}", + "background": "{color.bg.neutral.strong.active}", + "hoverBackground": "{color.bg.neutral.medium.active}" + } + } + }, + "root": { "transitionDuration": "{effects.transition.duration.200}" }, + "content": { "gap": "{dimension.space.200}" }, + "indicatorList": { + "padding": "{dimension.space.400}", + "gap": "{dimension.space.200}" + }, + "indicator": { + "width": "{dimension.size.200}", + "height": "{dimension.size.200}", + "borderRadius": "{dimension.borderRadius.max}", + "focusRing": { + "width": "{dimension.focusRing.width}", + "style": "none", + "color": "{color.border.focus}", + "offset": "{dimension.focusRing.offset}", + "shadow": "{effects.elevation.200}" + } + } + }, + "checkbox": { + "root": { + "borderRadius": "{dimension.borderRadius.200}", + "extend": { "borderWidth": "{dimension.borderWidth.100}" }, + "width": "{dimension.size.700}", + "height": "{dimension.size.700}", + "background": "{color.bg.surface.default.default}", + "checkedBackground": "{color.bg.neutral.strong.default}", + "checkedHoverBackground": "{color.bg.neutral.strong.hover}", + "disabledBackground": "{color.bg.surface.canvas.hover}", + "filledBackground": "{color.bg.surface.default.default}", + "borderColor": "{color.border.neutral.strong}", + "hoverBorderColor": "{color.border.neutral.bold.default}", + "focusBorderColor": "{color.border.neutral.bold.default}", + "checkedBorderColor": "{color.border.neutral.bold.default}", + "checkedHoverBorderColor": "{color.border.neutral.bold.hover}", + "checkedFocusBorderColor": "{color.border.brand.default}", + "checkedDisabledBorderColor": "{color.border.neutral.strong}", + "invalidBorderColor": "{color.border.status.danger.subtle}", + "shadow": "{effects.elevation.none}", + "focusRing": { + "focusRing": "{dimension.focusRing.width}", + "style": "none", + "color": "{color.border.focus}", + "offset": "{dimension.focusRing.offset}", + "shadow": "{effects.elevation.200}", + "width": "{dimension.focusRing.width}" + }, + "sm": { + "width": "{dimension.size.200}", + "height": "{dimension.size.200}" + }, + "lg": { + "width": "{dimension.size.600}", + "height": "{dimension.size.600}" + }, + "transitionDuration": "{effects.transition.duration.200}" + }, + "icon": { + "size": "{dimension.size.450}", + "color": "{color.fg.active}", + "checkedColor": "{color.fg.on.fill.default}", + "checkedHoverColor": "{color.fg.on.fill.hover}", + "disabledColor": "{color.fg.muted}", + "sm": { "size": "{dimension.size.350}" }, + "lg": { "size": "{dimension.size.600}" } + } + }, + "chip": { + "extend": { + "borderColor": "transparent", + "borderWidth": "{dimension.borderWidth.100}" + }, + "root": { + "borderRadius": "{dimension.borderRadius.200}", + "paddingX": "{dimension.space.200}", + "paddingY": "{dimension.space.100}", + "gap": "{dimension.space.200}", + "transitionDuration": "{effects.transition.duration.200}" + }, + "colorScheme": { + "light": { + "root": { + "background": "{color.bg.surface.canvas.hover}", + "color": "{color.fg.default}" + }, + "icon": { "color": "{color.fg.default}" }, + "removeIcon": { "color": "{color.fg.default}" } + }, + "dark": { + "icon": { "color": "{color.fg.inverse.default}" }, + "removeIcon": { "color": "{color.fg.inverse.default}" }, + "root": { + "background": "{color.bg.neutral.strong.hover}", + "color": "{color.fg.inverse.default}" + } + } + }, + "image": { + "width": "{dimension.size.none}", + "height": "{dimension.size.none}" + }, + "icon": { "size": "{dimension.size.450}" }, + "removeIcon": { + "size": "{dimension.size.450}", + "focusRing": { + "width": "{dimension.focusRing.width}", + "style": "none", + "color": "{color.border.focus}", + "offset": "{dimension.focusRing.offset}", + "shadow": "{effects.elevation.200}" + } + } + }, + "confirmdialog": { + "extend": { + "extIcon": { + "success": "{color.fg.status.success.default}", + "info": "{color.fg.status.info.default}", + "help": "{color.fg.status.help.default}", + "warn": "{color.fg.status.warning.default}", + "danger": "{color.fg.status.danger.default}" + } + }, + "icon": { "size": "{dimension.size.700}", "color": "{color.fg.default}" }, + "content": { "gap": "{dimension.space.none}" } + }, + "confirmpopup": { + "root": { + "background": "{color.bg.surface.default.default}", + "color": "{color.fg.default}", + "shadow": "{effects.elevation.400}", + "gutter": "{dimension.space.400}", + "arrowOffset": "{dimension.space.600}", + "borderColor": "{color.border.neutral.default}", + "borderRadius": "{dimension.borderRadius.400}" + }, + "content": { + "padding": "{dimension.space.400}", + "gap": "{dimension.space.400}" + }, + "icon": { "size": "{dimension.size.700}", "color": "{color.fg.default}" }, + "footer": { + "gap": "{dimension.space.200}", + "padding": "{dimension.space.none} {dimension.space.700} {dimension.space.700} {dimension.space.700}" + } + }, + "contextmenu": { + "root": { + "background": "{color.bg.surface.default.default}", + "color": "{color.fg.default}", + "shadow": "{effects.elevation.400}", + "borderColor": "{color.border.neutral.default}", + "borderRadius": "{dimension.borderRadius.400}", + "transitionDuration": "{effects.transition.duration.200}" + }, + "list": { + "padding": "{dimension.space.200} {dimension.space.none}", + "gap": "{dimension.space.100}" + }, + "item": { + "padding": "{dimension.space.200} {dimension.space.400}", + "gap": "{dimension.space.200}", + "activeBackground": "{color.bg.neutral.medium.default}", + "activeColor": "{color.fg.hover}", + "borderRadius": "{dimension.borderRadius.400}", + "color": "{color.fg.default}", + "focusBackground": "{color.bg.neutral.weak.default}", + "focusColor": "{color.fg.hover}", + "icon": { + "activeColor": "{color.fg.hover}", + "color": "{color.fg.default}", + "focusColor": "{color.fg.hover}" + } + }, + "submenu": { "mobileIndent": "{dimension.space.600}" }, + "separator": { "borderColor": "{color.border.neutral.default}" }, + "submenuIcon": { + "activeColor": "{color.fg.hover}", + "color": "{color.fg.default}", + "focusColor": "{color.fg.hover}", + "size": "{dimension.size.400}" + } + }, + "datatable": { + "colorScheme": { + "light": { + "root": { + "color": "{color.fg.default}", + "borderColor": "{color.border.neutral.default}" + }, + "header": { + "background": "{color.bg.surface.default.hover}", + "color": "{color.fg.default}" + }, + "headerCell": { + "background": "{color.bg.surface.raised.selected}", + "hoverBackground": "{color.bg.neutral.weak.default}", + "color": "{color.fg.default}" + }, + "footer": { + "background": "{color.bg.surface.canvas.default}", + "color": "{color.fg.default}" + }, + "footerCell": { + "background": "{color.bg.neutral.weak.default}", + "color": "{color.fg.default}" + }, + "row": { "stripedBackground": "{color.bg.neutral.weak.default}" }, + "bodyCell": { + "selectedBorderColor": "{color.border.neutral.default}" + } + }, + "dark": { + "bodyCell": { + "selectedBorderColor": "{color.border.neutral.bold.hover}" + }, + "footer": { + "background": "{color.bg.neutral.strong.default}", + "color": "{color.fg.inverse.default}" + }, + "footerCell": { + "background": "{color.bg.neutral.strong.default}", + "color": "{color.fg.inverse.default}" + }, + "header": { + "background": "{color.bg.surface.default.hover}", + "color": "{color.fg.inverse.default}" + }, + "headerCell": { + "background": "{color.bg.surface.raised.selected}", + "color": "{color.fg.inverse.default}", + "hoverBackground": "{color.bg.neutral.strong.selected}" + }, + "root": { + "borderColor": "{color.border.neutral.bold.hover}", + "color": "{color.fg.inverse.default}" + }, + "row": { "stripedBackground": "{color.bg.neutral.strong.default}" } + } + }, + "extended": { + "extHeaderCell": { + "selectedHoverBackground": "{color.bg.neutral.strong.hover}" + }, + "extRow": { + "selectedHoverBackground": "{color.bg.neutral.strong.hover}", + "stripedHoverBackground": "{color.bg.neutral.weak.default}", + "iconSize": "{dimension.size.600}" + } + }, + "root": { "transitionDuration": "{effects.transition.duration.200}" }, + "header": { + "borderColor": "{color.border.neutral.default}", + "borderWidth": "{dimension.borderWidth.100} {dimension.borderWidth.none} {dimension.borderWidth.100} {dimension.borderWidth.none}", + "padding": "{dimension.space.400}", + "sm": { "padding": "{dimension.space.200}" }, + "lg": { "padding": "{dimension.space.600}" } + }, + "headerCell": { + "selectedBackground": "{color.bg.neutral.strong.selected}", + "borderColor": "{color.border.neutral.default}", + "hoverColor": "{color.fg.hover}", + "selectedColor": "{color.fg.on.fill.default}", + "gap": "{dimension.space.200}", + "padding": "{dimension.space.400}", + "focusRing": { + "width": "{dimension.focusRing.width}", + "style": "none", + "color": "{color.border.focus}", + "offset": "{dimension.focusRing.offset}", + "shadow": "{effects.focusRing.shadow}" + }, + "sm": { "padding": "{dimension.space.200}" }, + "lg": { "padding": "{dimension.space.600}" } + }, + "columnTitle": { "fontWeight": "{fonts.fontWeight.bold}" }, + "row": { + "background": "{color.bg.surface.raised.default}", + "hoverBackground": "{color.bg.neutral.weak.default}", + "selectedBackground": "{color.bg.neutral.strong.selected}", + "color": "{color.fg.default}", + "hoverColor": "{color.fg.hover}", + "selectedColor": "{color.fg.on.fill.default}", + "focusRing": { + "width": "{dimension.focusRing.width}", + "style": "none", + "color": "{color.border.focus}", + "offset": "{dimension.focusRing.offset}", + "shadow": "{effects.focusRing.shadow}" + } + }, + "bodyCell": { + "borderColor": "{color.border.neutral.default}", + "padding": "{dimension.space.400}", + "sm": { "padding": "{dimension.space.200}" }, + "lg": { "padding": "{dimension.space.600}" } + }, + "footerCell": { + "borderColor": "{color.border.neutral.default}", + "padding": "{dimension.space.400}", + "sm": { "padding": "{dimension.space.200}" }, + "lg": { "padding": "{dimension.space.600}" } + }, + "columnFooter": { "fontWeight": "{fonts.fontWeight.bold}" }, + "dropPoint": { "color": "{color.fg.default}" }, + "footer": { + "borderColor": "{color.border.neutral.default}", + "borderWidth": "{dimension.borderWidth.none} {dimension.borderWidth.none} {dimension.borderWidth.100} {dimension.borderWidth.none}", + "padding": "{dimension.space.400}", + "sm": { "padding": "{dimension.space.200}" }, + "lg": { "padding": "{dimension.space.600}" } + }, + "columnResizer": { "width": "{dimension.size.200}" }, + "resizeIndicator": { + "width": "{dimension.borderWidth.100}", + "color": "{color.fg.default}" + }, + "sortIcon": { + "color": "{color.fg.default}", + "hoverColor": "{color.fg.hover}", + "size": "{dimension.size.450}" + }, + "loadingIcon": { "size": "{dimension.size.900}" }, + "rowToggleButton": { + "hoverBackground": "{color.bg.neutral.weak.default}", + "selectedHoverBackground": "{color.bg.neutral.weak.default}", + "color": "{color.fg.default}", + "hoverColor": "{color.fg.default}", + "selectedHoverColor": "{color.fg.default}", + "size": "{dimension.size.900}", + "borderRadius": "{dimension.borderRadius.400}", + "focusRing": { + "width": "{dimension.focusRing.width}", + "style": "none", + "color": "{color.border.focus}", + "offset": "{dimension.focusRing.offset}", + "shadow": "{effects.elevation.200}" + } + }, + "filter": { + "inlineGap": "{dimension.space.200}", + "rule": { "borderColor": "{color.border.neutral.default}" }, + "constraintList": { + "padding": "{dimension.space.100}", + "gap": "{dimension.space.100}" + }, + "constraint": { + "focusBackground": "{color.bg.neutral.weak.default}", + "selectedBackground": "{color.bg.neutral.strong.selected}", + "selectedFocusBackground": "{color.bg.neutral.strong.active}", + "color": "{color.fg.default}", + "focusColor": "{color.fg.default}", + "selectedColor": "{color.fg.on.fill.default}", + "selectedFocusColor": "{color.fg.on.fill.active}", + "padding": "{dimension.space.200} {dimension.space.400}", + "borderRadius": "{dimension.borderRadius.200}", + "separator": { "borderColor": "{color.border.neutral.default}" } + }, + "overlaySelect": { + "background": "{color.bg.surface.raised.default}", + "color": "{color.fg.default}", + "borderColor": "{color.border.neutral.default}", + "borderRadius": "{dimension.borderRadius.400}", + "shadow": "{effects.elevation.400}" + }, + "overlayPopover": { + "background": "{color.bg.surface.raised.default}", + "color": "{color.fg.default}", + "borderColor": "{color.border.neutral.default}", + "borderRadius": "{dimension.borderRadius.400}", + "shadow": "{effects.elevation.400}", + "padding": "{dimension.space.400}", + "gap": "{dimension.space.100}" + } + }, + "paginatorTop": { + "borderColor": "{color.border.neutral.strong}", + "borderWidth": "{dimension.borderWidth.none} {dimension.borderWidth.none} {dimension.borderWidth.100} {dimension.borderWidth.none}" + }, + "paginatorBottom": { + "borderWidth": "{dimension.borderWidth.none} {dimension.borderWidth.none} {dimension.borderWidth.100} {dimension.borderWidth.none}", + "borderColor": "{color.border.neutral.default}" + } + }, + "dataview": { + "root": { + "borderWidth": "{dimension.borderWidth.100}", + "borderRadius": "{dimension.borderRadius.100}", + "padding": "{dimension.space.none}", + "borderColor": "{color.border.neutral.default}" + }, + "header": { + "borderWidth": "{dimension.borderWidth.none} {dimension.borderWidth.none} {dimension.borderWidth.100} {dimension.borderWidth.none}", + "padding": "{dimension.space.200} {dimension.space.400}", + "borderRadius": "{dimension.borderRadius.none} {dimension.borderRadius.none} {dimension.borderRadius.none} {dimension.borderRadius.none}", + "color": "{color.fg.default}", + "borderColor": "{color.border.neutral.default}" + }, + "content": { + "background": "{color.bg.surface.default.default}", + "color": "{color.fg.default}", + "borderColor": "{color.border.neutral.default}", + "borderWidth": "{dimension.borderWidth.none}", + "padding": "{dimension.space.none}", + "borderRadius": "{dimension.borderRadius.none}" + }, + "footer": { + "background": "{color.bg.surface.canvas.default}", + "color": "{color.fg.default}", + "borderWidth": "{dimension.borderWidth.100} {dimension.borderWidth.none} {dimension.borderWidth.none} {dimension.borderWidth.none}", + "padding": "{dimension.space.200} {dimension.space.400}", + "borderRadius": "{dimension.borderRadius.none} {dimension.borderRadius.none} {dimension.borderRadius.none} {dimension.borderRadius.none}", + "borderColor": "{color.border.neutral.default}" + }, + "paginatorTop": { + "borderWidth": "{dimension.borderWidth.none} {dimension.borderWidth.none} {dimension.borderWidth.100} {dimension.borderWidth.none}", + "borderColor": "{color.border.neutral.default}" + }, + "paginatorBottom": { + "borderWidth": "{dimension.borderWidth.100} {dimension.borderWidth.none} {dimension.borderWidth.none} {dimension.borderWidth.none}", + "borderColor": "{color.border.neutral.default}" + }, + "colorScheme": { + "dark": { + "header": { + "background": "{color.bg.surface.default.default}", + "color": "{color.fg.inverse.default}" + } + }, + "light": { + "header": { + "background": "{color.bg.surface.default.default}", + "color": "{color.fg.default}" + } + } + } + }, + "datepicker": { + "extend": { + "extDate": { + "selectedHoverBackground": "{color.bg.neutral.strong.hover}" + }, + "extToday": { + "hoverBackground": "{color.bg.neutral.weak.default}", + "borderColor": "{color.border.neutral.bold.hover}" + }, + "extTitle": { "width": "{dimension.size.1900}" }, + "extTimePicker": { + "minWidth": "{dimension.size.1800}", + "color": "{color.fg.default}" + } + }, + "colorScheme": { + "light": { + "dropdown": { + "background": "{color.bg.surface.default.default}", + "hoverBackground": "{color.bg.surface.canvas.default}", + "activeBackground": "{color.bg.neutral.strong.default}", + "color": "{color.fg.default}", + "hoverColor": "{color.fg.default}", + "activeColor": "{color.fg.inverse.active}" + }, + "today": { + "background": "transparent", + "color": "{color.fg.default}" + } + }, + "dark": { + "dropdown": { + "activeBackground": "{color.bg.surface.canvas.default}", + "activeColor": "{color.fg.on.fill.active}", + "background": "{color.bg.surface.default.default}", + "color": "{color.fg.inverse.default}", + "hoverBackground": "{color.bg.neutral.strong.selected}", + "hoverColor": "{color.fg.on.brand.hover}" + }, + "today": { + "background": "transparent", + "color": "{color.fg.inverse.default}" + } + } + }, + "panel": { + "background": "{color.bg.surface.default.default}", + "borderColor": "{color.border.neutral.default}", + "color": "{color.fg.default}", + "borderRadius": "{dimension.borderRadius.400}", + "shadow": "{effects.elevation.400}", + "padding": "{dimension.space.none}" + }, + "header": { + "background": "{color.bg.surface.default.default}", + "borderColor": "{color.border.neutral.default}", + "color": "{color.fg.default}", + "padding": "{dimension.space.400}" + }, + "title": { + "gap": "{dimension.space.200}", + "fontWeight": "{fonts.fontWeight.bold}" + }, + "selectMonth": { + "hoverBackground": "{color.bg.neutral.weak.default}", + "color": "{color.fg.default}", + "hoverColor": "{color.fg.hover}", + "borderRadius": "{dimension.borderRadius.400}", + "padding": "{dimension.space.200}" + }, + "inputIcon": { "color": "{color.fg.muted}" }, + "dropdown": { + "width": "{dimension.size.1700}", + "borderColor": "{color.border.neutral.strong}", + "hoverBorderColor": "{color.border.neutral.strong}", + "activeBorderColor": "{color.border.neutral.strong}", + "borderRadius": "{dimension.borderRadius.400}", + "focusRing": { + "width": "{dimension.focusRing.width}", + "style": "none", + "color": "{color.border.focus}", + "offset": "{dimension.focusRing.offset}", + "shadow": "{effects.elevation.200}" + }, + "sm": { "width": "{dimension.size.none}" }, + "lg": { "width": "{dimension.size.none}" } + }, + "group": { + "borderColor": "{color.border.neutral.default}", + "gap": "{dimension.space.400}" + }, + "selectYear": { + "hoverBackground": "{color.bg.neutral.weak.default}", + "color": "{color.fg.default}", + "hoverColor": "{color.fg.hover}", + "borderRadius": "{dimension.borderRadius.400}", + "padding": "{dimension.space.100}" + }, + "dayView": { "margin": "{dimension.space.400}" }, + "weekDay": { + "padding": "{dimension.space.100}", + "fontWeight": "{fonts.fontWeight.bold}", + "color": "{color.fg.default}" + }, + "date": { + "hoverBackground": "{color.bg.neutral.weak.default}", + "selectedBackground": "{color.bg.neutral.strong.selected}", + "rangeSelectedBackground": "{color.bg.neutral.weak.default}", + "color": "{color.fg.default}", + "hoverColor": "{color.fg.default}", + "selectedColor": "{color.fg.on.fill.default}", + "rangeSelectedColor": "{color.fg.default}", + "width": "{dimension.size.900}", + "height": "{dimension.size.900}", + "borderRadius": "{dimension.borderRadius.200}", + "padding": "{dimension.space.100}", + "focusRing": { + "width": "{dimension.focusRing.width}", + "style": "none", + "color": "{color.border.focus}", + "offset": "{dimension.focusRing.offset}", + "shadow": "{effects.elevation.200}" + } + }, + "monthView": { + "margin": "{dimension.space.none} {dimension.space.none} {dimension.space.none} {dimension.space.none}" + }, + "month": { + "padding": "{dimension.space.none}", + "borderRadius": "{dimension.borderRadius.none}" + }, + "yearView": { + "margin": "{dimension.space.none} {dimension.space.none} {dimension.space.none} {dimension.space.none}" + }, + "year": { + "padding": "{dimension.space.none}", + "borderRadius": "{dimension.borderRadius.none}" + }, + "buttonbar": { + "padding": "{dimension.space.400}", + "borderColor": "{color.border.neutral.default}" + }, + "timePicker": { + "padding": "{dimension.space.400}", + "borderColor": "{color.border.neutral.default}", + "gap": "{dimension.space.200}", + "buttonGap": "{dimension.space.100}" + }, + "root": { "transitionDuration": "{effects.transition.duration.200}" } + }, + "dialog": { + "extend": { + "borderWidth": "{dimension.borderWidth.100}", + "backdrop": "{color.bg.surface.backdrop}" + }, + "root": { + "background": "{color.bg.surface.raised.default}", + "borderColor": "{color.border.neutral.default}", + "color": "{color.fg.default}", + "borderRadius": "{dimension.borderRadius.max}", + "shadow": "{effects.elevation.400}" + }, + "header": { + "padding": "{dimension.space.700} {dimension.space.700} {dimension.space.400} {dimension.space.700}", + "gap": "{dimension.space.200}" + }, + "title": { + "fontSize": "{fonts.fontSize.500}", + "fontWeight": "{fonts.fontWeight.demibold}" + }, + "content": { "padding": "{dimension.space.700}" }, + "footer": { + "padding": "{dimension.space.none} {dimension.space.700} {dimension.space.700} {dimension.space.700}", + "gap": "{dimension.space.200}" + } + }, + "divider": { + "extend": { + "content": { "gap": "{dimension.space.200}" }, + "iconSize": "{dimension.size.450}" + }, + "horizontal": { + "margin": "{dimension.space.400} {dimension.space.none}", + "padding": "{dimension.space.none} {dimension.space.400}", + "content": { "padding": "{dimension.space.none} {dimension.space.200}" } + }, + "vertical": { + "margin": "{dimension.space.none} {dimension.space.400}", + "padding": "{dimension.space.400} {dimension.space.none}", + "content": { "padding": "{dimension.space.200} {dimension.space.none}" } + }, + "content": { + "background": "{color.bg.surface.default.default}", + "color": "{color.fg.default}" + }, + "root": { "borderColor": "{color.border.neutral.default}" } + }, + "drawer": { + "extend": { + "borderRadius": "{dimension.borderRadius.200}", + "borderWidth": "{dimension.borderWidth.100}", + "width": "{dimension.size.2000}", + "extHeader": { + "gap": "{dimension.space.200}", + "borderColor": "{color.border.neutral.default}" + }, + "margin": "{dimension.space.200}", + "scale": "{dimension.size.50}", + "backdrop": "{color.bg.surface.backdrop}" + }, + "root": { + "background": "{color.bg.surface.default.default}", + "borderColor": "{color.border.neutral.default}", + "color": "{color.fg.default}", + "shadow": "{effects.elevation.200}" + }, + "header": { + "padding": "{dimension.space.700} {dimension.space.700} {dimension.space.400} {dimension.space.700}" + }, + "title": { + "fontSize": "{fonts.fontSize.500}", + "fontWeight": "{fonts.fontWeight.demibold}" + }, + "content": { "padding": "{dimension.space.700}" }, + "footer": { + "padding": "{dimension.space.none} {dimension.space.700} {dimension.space.700} {dimension.space.700}" + } + }, + "fileupload": { + "extend": { + "extDragNdrop": { + "background": "{color.bg.surface.raised.default}", + "borderRadius": "{dimension.borderRadius.400}", + "iconSize": "{dimension.size.900}", + "padding": "{dimension.space.400}", + "info": { "gap": "{dimension.space.100}" } + }, + "extFile": { "iconSize": "{dimension.size.600}" }, + "extContent": { + "borderRadius": "{dimension.borderRadius.400}", + "highlightBorderDefault": "{color.border.neutral.strong}" + } + }, + "colorScheme": { + "light": { + "header": { + "background": "{color.bg.surface.default.default}", + "color": "{color.fg.default}" + } + }, + "dark": { + "header": { + "background": "{color.bg.surface.default.default}", + "color": "{color.fg.inverse.default}" + } + } + }, + "root": { + "background": "{color.bg.surface.default.default}", + "borderColor": "{color.border.neutral.default}", + "color": "{color.fg.default}", + "borderRadius": "{dimension.borderRadius.400}", + "transitionDuration": "{effects.transition.duration.200}" + }, + "header": { + "borderColor": "{color.border.neutral.default}", + "borderWidth": "{dimension.borderWidth.none}", + "padding": "{dimension.space.none}", + "borderRadius": "{dimension.borderRadius.none}", + "gap": "{dimension.space.200}" + }, + "content": { + "highlightBorderColor": "{color.border.neutral.bold.default}", + "padding": "{dimension.space.none}", + "gap": "{dimension.space.200}" + }, + "file": { + "padding": "{dimension.space.200}", + "gap": "{dimension.space.200}", + "borderColor": "{color.border.neutral.strong}", + "info": { "gap": "{dimension.space.100}" } + }, + "fileList": { "gap": "{dimension.space.200}" }, + "progressbar": { "height": "{dimension.size.200}" }, + "basic": { "gap": "{dimension.space.200}" } + }, + "floatlabel": { + "extend": { + "height": "{dimension.size.1400}", + "iconSize": "{dimension.size.600}" + }, + "root": { + "color": "{color.fg.muted}", + "focusColor": "{color.fg.muted}", + "activeColor": "{color.fg.muted}", + "invalidColor": "{color.fg.status.danger.hover}", + "transitionDuration": "{effects.transition.duration.200}", + "positionX": "{dimension.space.400}", + "positionY": "{dimension.space.400}", + "fontWeight": "{fonts.fontWeight.regular}", + "active": { + "fontSize": "{fonts.fontSize.100}", + "fontWeight": "{fonts.fontWeight.regular}" + } + }, + "over": { "active": { "top": "{dimension.space.400}" } }, + "inside": { + "input": { + "paddingTop": "{dimension.space.800}", + "paddingBottom": "{dimension.space.400}" + }, + "active": { "top": "{dimension.space.400}" } + }, + "on": { + "borderRadius": "{dimension.borderRadius.none}", + "active": { + "padding": "{dimension.space.none} {dimension.space.100}", + "background": "{color.bg.surface.raised.default}" + } + } + }, + "galleria": { + "extend": { "backdrop": "{color.bg.surface.backdrop}" }, + "colorScheme": { + "light": { + "thumbnailContent": { + "background": "{color.bg.neutral.weak.default}" + }, + "thumbnailNavButton": { + "hoverBackground": "{color.bg.neutral.medium.default}", + "color": "{color.fg.default}", + "hoverColor": "{color.fg.hover}" + }, + "indicatorButton": { + "background": "{color.bg.neutral.weak.active}", + "hoverBackground": "{color.bg.neutral.medium.active}" + }, + "thumbnailsContent": { + "background": "{color.bg.neutral.medium.default}" + } + }, + "dark": { + "indicatorButton": { + "background": "{color.bg.neutral.strong.active}", + "hoverBackground": "{color.bg.neutral.medium.active}" + }, + "thumbnailNavButton": { + "color": "{color.fg.inverse.default}", + "hoverBackground": "{color.bg.neutral.medium.default}", + "hoverColor": "{color.fg.inverse.hover}" + }, + "thumbnailsContent": { + "background": "{color.bg.neutral.medium.default}" + }, + "thumbnailContent": { + "background": "{color.bg.neutral.strong.default}" + } + } + }, + "root": { + "borderWidth": "{dimension.borderWidth.100}", + "borderColor": "{color.border.neutral.default}", + "borderRadius": "{dimension.borderRadius.400}", + "transitionDuration": "{effects.transition.duration.200}" + }, + "navButton": { + "background": "transparent", + "hoverBackground": "{color.bg.neutral.medium.default}", + "color": "{color.fg.inverse.default}", + "hoverColor": "{color.fg.inverse.hover}", + "size": "{dimension.size.1400}", + "gutter": "{dimension.space.200}", + "prev": { "borderRadius": "{dimension.borderRadius.200}" }, + "next": { "borderRadius": "{dimension.borderRadius.200}" }, + "focusRing": { + "width": "{dimension.focusRing.width}", + "style": "none", + "color": "{color.border.focus}", + "offset": "{dimension.focusRing.offset}", + "shadow": "{effects.elevation.200}" + } + }, + "navIcon": { "size": "{dimension.size.900}" }, + "thumbnailsContent": { "padding": "{dimension.space.100}" }, + "thumbnailNavButton": { + "size": "{dimension.size.900}", + "borderRadius": "{dimension.borderRadius.400}", + "gutter": "{dimension.space.200}", + "focusRing": { + "width": "{dimension.focusRing.width}", + "style": "none", + "color": "{color.border.focus}", + "offset": "{dimension.focusRing.offset}", + "shadow": "{effects.elevation.200}" + } + }, + "thumbnailNavButtonIcon": { "size": "{dimension.size.450}" }, + "caption": { + "background": "{color.bg.neutral.medium.default}", + "color": "{color.fg.default}", + "padding": "{dimension.space.200}" + }, + "indicatorList": { + "gap": "{dimension.space.200}", + "padding": "{dimension.space.400}" + }, + "indicatorButton": { + "width": "{dimension.size.200}", + "height": "{dimension.size.200}", + "activeBackground": "{color.bg.neutral.strong.default}", + "borderRadius": "{dimension.borderRadius.400}", + "focusRing": { + "width": "{dimension.focusRing.width}", + "style": "none", + "color": "{color.border.focus}", + "offset": "{dimension.focusRing.offset}", + "shadow": "{effects.elevation.200}" + } + }, + "insetIndicatorList": { "background": "{color.bg.surface.backdrop}" }, + "insetIndicatorButton": { + "background": "{color.bg.neutral.medium.default}", + "hoverBackground": "{color.bg.neutral.medium.default}", + "activeBackground": "{color.bg.neutral.medium.default}" + }, + "closeButton": { + "size": "{dimension.size.1400}", + "gutter": "{dimension.space.200}", + "background": "{color.bg.neutral.medium.default}", + "hoverBackground": "{color.bg.neutral.medium.default}", + "color": "{color.fg.inverse.default}", + "hoverColor": "{color.fg.inverse.hover}", + "borderRadius": "{dimension.borderRadius.400}", + "focusRing": { + "width": "{dimension.focusRing.width}", + "style": "none", + "color": "{color.border.focus}", + "offset": "{dimension.focusRing.offset}", + "shadow": "{effects.elevation.200}" + } + }, + "closeButtonIcon": { "size": "{dimension.size.900}" } + }, + "inputgroup": { + "extend": { + "borderWidth": "{dimension.borderWidth.100}", + "iconSize": "{dimension.size.450}" + }, + "colorScheme": { + "light": { + "addon": { + "background": "{color.bg.surface.raised.default}", + "borderColor": "{color.border.neutral.strong}", + "color": "{color.fg.muted}" + } + }, + "dark": { + "addon": { + "background": "{color.bg.surface.raised.default}", + "borderColor": "{color.border.neutral.strong}", + "color": "{color.fg.inverse.muted}" + } + } + }, + "addon": { + "borderRadius": "{dimension.borderRadius.400}", + "padding": "{dimension.space.400}", + "minWidth": "{dimension.size.1700}" + } + }, + "inputnumber": { + "extend": { + "borderWidth": "{dimension.borderWidth.100}", + "extButton": { + "height": "{dimension.size.1100}", + "iconSize": "{dimension.size.450}" + } + }, + "colorScheme": { + "light": { + "button": { + "background": "{color.bg.surface.raised.default}", + "hoverBackground": "{color.bg.neutral.weak.default}", + "activeBackground": "transparent", + "borderColor": "{color.border.neutral.strong}", + "hoverBorderColor": "{color.border.neutral.strong}", + "activeBorderColor": "{color.border.neutral.strong}", + "color": "{color.fg.default}", + "hoverColor": "{color.fg.hover}", + "activeColor": "{color.fg.default}" + } + }, + "dark": { + "button": { + "activeBackground": "transparent", + "activeBorderColor": "{color.border.neutral.strong}", + "activeColor": "{color.fg.on.brand.active}", + "background": "{color.bg.surface.raised.default}", + "borderColor": "{color.border.neutral.strong}", + "color": "{color.fg.inverse.default}", + "hoverBackground": "{color.bg.neutral.strong.selected}", + "hoverBorderColor": "{color.border.neutral.strong}", + "hoverColor": "{color.fg.inverse.hover}" + } + } + }, + "transitionDuration": { + "transitionDuration": "{effects.transition.duration.200}" + }, + "button": { + "width": "{dimension.size.1700}", + "borderRadius": "{dimension.borderRadius.400}", + "verticalPadding": "{dimension.space.400}" + }, + "root": { "transitionDuration": "{effects.transition.duration.200}" } + }, + "inputotp": { + "extend": { + "height": "{dimension.size.1100}", + "borderWidth": "{dimension.borderWidth.100}" + }, + "root": { "gap": "{dimension.space.200}" }, + "input": { + "width": "{dimension.size.1800}", + "lg": { "width": "{dimension.size.1900}" }, + "sm": { "width": "{dimension.size.1700}" } + }, + "sm": { "width": "{dimension.size.none}" }, + "lg": { "width": "{dimension.size.none}" } + }, + "inputtext": { + "extend": { + "readonlyBackground": "{color.bg.neutral.weak.default}", + "iconSize": "{dimension.size.450}", + "borderWidth": "{dimension.borderWidth.100}", + "extXlg": { + "fontSize": "{fonts.fontSize.300}", + "paddingX": "{dimension.space.400}", + "paddingY": "{dimension.space.400}" + } + }, + "root": { + "background": "{color.bg.surface.default.default}", + "disabledBackground": "{color.bg.surface.canvas.hover}", + "filledBackground": "{color.bg.surface.default.default}", + "filledHoverBackground": "{color.bg.surface.default.default}", + "filledFocusBackground": "{color.bg.surface.default.default}", + "borderColor": "{color.border.neutral.strong}", + "hoverBorderColor": "{color.border.brand.strong}", + "focusBorderColor": "{color.border.brand.strong}", + "invalidBorderColor": "{color.border.status.danger.subtle}", + "color": "{color.fg.default}", + "disabledColor": "{color.fg.muted}", + "placeholderColor": "{color.fg.muted}", + "invalidPlaceholderColor": "{color.fg.status.danger.hover}", + "shadow": "{effects.elevation.none}", + "paddingX": "{dimension.space.400}", + "paddingY": "{dimension.space.400}", + "borderRadius": "{dimension.borderRadius.400}", + "transitionDuration": "{effects.transition.duration.200}", + "sm": { + "fontSize": "{fonts.fontSize.300}", + "paddingX": "{dimension.space.400}", + "paddingY": "{dimension.space.400}" + }, + "lg": { + "fontSize": "{fonts.fontSize.300}", + "paddingX": "{dimension.space.400}", + "paddingY": "{dimension.space.400}" + }, + "focusRing": { + "width": "{dimension.focusRing.width}", + "style": "none", + "color": "{color.border.focus}", + "offset": "{dimension.focusRing.offset}", + "shadow": "{effects.elevation.none}" + } + } + }, + "listbox": { + "extend": { + "extOption": { + "label": { "gap": "{dimension.space.100}" }, + "caption": { + "color": "{color.fg.muted}", + "stripedColor": "{color.fg.muted}" + }, + "gap": "{dimension.space.200}" + } + }, + "colorScheme": { + "light": { + "option": { + "stripedBackground": "{color.bg.surface.raised.selected}" + } + }, + "dark": { + "option": { + "stripedBackground": "{color.bg.surface.raised.selected}" + } + } + }, + "root": { + "background": "{color.bg.surface.default.default}", + "disabledBackground": "{color.bg.surface.canvas.hover}", + "borderColor": "{color.border.neutral.strong}", + "invalidBorderColor": "{color.border.status.danger.subtle}", + "color": "{color.fg.active}", + "disabledColor": "{color.fg.muted}", + "shadow": "{effects.elevation.none}", + "borderRadius": "{dimension.borderRadius.400}", + "transitionDuration": "{effects.transition.duration.200}" + }, + "list": { + "padding": "{dimension.space.100}", + "gap": "{dimension.space.100}", + "header": { + "padding": "{dimension.space.400} {dimension.space.400} {dimension.space.none} {dimension.space.400}" + } + }, + "option": { + "focusBackground": "{color.bg.neutral.weak.default}", + "selectedBackground": "{color.bg.neutral.strong.selected}", + "selectedFocusBackground": "{color.bg.neutral.strong.active}", + "color": "{color.fg.default}", + "focusColor": "{color.fg.default}", + "selectedColor": "{color.fg.on.fill.default}", + "selectedFocusColor": "{color.fg.on.fill.active}", + "padding": "{dimension.space.200} {dimension.space.400}", + "borderRadius": "{dimension.borderRadius.200}" + }, + "optionGroup": { + "background": "{color.bg.surface.raised.default}", + "color": "{color.fg.muted}", + "fontWeight": "{fonts.fontWeight.demibold}", + "padding": "{dimension.space.200} {dimension.space.400}" + }, + "checkmark": { + "color": "{color.fg.default}", + "gutterStart": "{dimension.space.negative.200}", + "gutterEnd": "{dimension.space.200}" + }, + "emptyMessage": { + "padding": "{dimension.space.200} {dimension.space.400}" + } + }, + "megamenu": { + "extend": { + "extItem": { + "caption": { + "color": "{color.fg.muted}", + "gap": "{dimension.space.100}" + } + }, + "iconSize": "{dimension.size.600}" + }, + "colorScheme": { + "light": { "root": { "background": "transparent" } }, + "dark": { "root": { "background": "transparent" } } + }, + "root": { + "borderColor": "transparent", + "borderRadius": "{dimension.borderRadius.400}", + "color": "{color.fg.default}", + "gap": "{dimension.space.100}", + "transitionDuration": "{effects.transition.duration.200}", + "verticalOrientation": { + "padding": "{dimension.space.100}", + "gap": "{dimension.space.100}" + }, + "horizontalOrientation": { + "padding": "{dimension.space.100}", + "gap": "{dimension.space.100}" + } + }, + "baseItem": { + "borderRadius": "{dimension.borderRadius.400}", + "padding": "{dimension.space.200} {dimension.space.400}" + }, + "item": { + "focusBackground": "{color.bg.neutral.weak.default}", + "activeBackground": "{color.bg.neutral.strong.default}", + "color": "{color.fg.default}", + "focusColor": "{color.fg.default}", + "activeColor": "{color.fg.inverse.active}", + "padding": "{dimension.space.200} {dimension.space.400}", + "borderRadius": "{dimension.borderRadius.200}", + "gap": "{dimension.space.200}", + "icon": { + "color": "{color.fg.default}", + "focusColor": "{color.fg.default}", + "activeColor": "{color.fg.inverse.active}" + } + }, + "overlay": { + "padding": "{dimension.space.100}", + "background": "{color.bg.surface.default.default}", + "borderColor": "{color.border.neutral.default}", + "borderRadius": "{dimension.borderRadius.400}", + "color": "{color.fg.default}", + "shadow": "{effects.elevation.400}", + "gap": "{dimension.space.none}" + }, + "submenu": { + "padding": "{dimension.space.100}", + "gap": "{dimension.space.100}" + }, + "submenuLabel": { + "padding": "{dimension.space.200} {dimension.space.400}", + "background": "transparent", + "color": "{color.fg.muted}", + "fontWeight": "{fonts.fontWeight.demibold}" + }, + "submenuIcon": { + "size": "{dimension.size.600}", + "color": "{color.fg.default}", + "focusColor": "{color.fg.default}", + "activeColor": "{color.fg.inverse.active}" + }, + "separator": { "borderColor": "{color.border.neutral.default}" }, + "mobileButton": { + "borderRadius": "{dimension.borderRadius.200}", + "size": "{dimension.size.900}", + "color": "{color.fg.default}", + "hoverColor": "{color.fg.hover}", + "hoverBackground": "{color.bg.neutral.weak.default}", + "focusRing": { + "width": "{dimension.focusRing.width}", + "style": "none", + "color": "{color.border.focus}", + "offset": "{dimension.focusRing.offset}", + "shadow": "{effects.elevation.200}" + } + } + }, + "menu": { + "extend": { + "paddingX": "{dimension.space.100}", + "iconSize": "{dimension.size.600}", + "paddingY": "{dimension.space.100}", + "extItem": { + "caption": { + "gap": "{dimension.space.100}", + "color": "{color.fg.muted}" + }, + "activeBackground": "{color.bg.neutral.strong.default}", + "activeColor": "{color.fg.inverse.active}", + "icon": { "activeColor": "{color.fg.inverse.active}" } + } + }, + "root": { + "borderRadius": "{dimension.borderRadius.400}", + "shadow": "{effects.elevation.400}", + "transitionDuration": "{effects.transition.duration.200}", + "background": "{color.bg.surface.default.default}", + "borderColor": "{color.border.neutral.default}", + "color": "{color.fg.default}" + }, + "list": { + "padding": "{dimension.space.100}", + "gap": "{dimension.space.100}" + }, + "submenuLabel": { + "padding": "{dimension.space.200} {dimension.space.400}", + "fontWeight": "{fonts.fontWeight.demibold}", + "background": "transparent", + "color": "{color.fg.muted}" + }, + "separator": { "borderColor": "{color.border.neutral.default}" }, + "item": { + "padding": "{dimension.space.200} {dimension.space.400}", + "borderRadius": "{dimension.borderRadius.200}", + "gap": "{dimension.space.200}", + "color": "{color.fg.default}", + "focusBackground": "{color.bg.surface.canvas.default}", + "focusColor": "{color.fg.hover}", + "icon": { + "color": "{color.fg.default}", + "focusColor": "{color.fg.hover}" + } + } + }, + "menubar": { + "extend": { + "iconSize": "{dimension.size.600}", + "extItem": { + "caption": { + "color": "{color.fg.muted}", + "gap": "{dimension.space.100}" + } + }, + "extSubmenuLabel": { + "padding": "{dimension.space.200} {dimension.space.400}", + "fontWeight": "{fonts.fontWeight.demibold}", + "background": "transparent", + "color": "{color.fg.muted}" + } + }, + "colorScheme": { + "light": { "root": { "background": "transparent" } }, + "dark": { "root": { "background": "transparent" } } + }, + "root": { + "borderColor": "transparent", + "borderRadius": "{dimension.borderRadius.200}", + "color": "{color.fg.default}", + "gap": "{dimension.space.100}", + "padding": "{dimension.space.100}", + "transitionDuration": "{effects.transition.duration.200}" + }, + "baseItem": { + "borderRadius": "{dimension.borderRadius.200}", + "padding": "{dimension.space.200} {dimension.space.400}" + }, + "item": { + "focusBackground": "{color.bg.neutral.weak.default}", + "activeBackground": "{color.bg.neutral.strong.default}", + "color": "{color.fg.default}", + "focusColor": "{color.fg.default}", + "activeColor": "{color.fg.inverse.active}", + "padding": "{dimension.space.200} {dimension.space.400}", + "borderRadius": "{dimension.borderRadius.200}", + "gap": "{dimension.space.200}", + "icon": { + "color": "{color.fg.default}", + "focusColor": "{color.fg.default}", + "activeColor": "{color.fg.inverse.active}" + } + }, + "submenu": { + "padding": "{dimension.space.100}", + "gap": "{dimension.space.100}", + "background": "{color.bg.surface.raised.default}", + "borderColor": "{color.border.neutral.default}", + "borderRadius": "{dimension.borderRadius.400}", + "shadow": "{effects.elevation.400}", + "mobileIndent": "{dimension.space.400}", + "icon": { + "size": "{dimension.size.600}", + "color": "{color.fg.default}", + "focusColor": "{color.fg.default}", + "activeColor": "{color.fg.inverse.active}" + } + }, + "separator": { "borderColor": "{color.border.neutral.default}" }, + "mobileButton": { + "borderRadius": "{dimension.borderRadius.200}", + "size": "{dimension.size.900}", + "color": "{color.fg.default}", + "hoverColor": "{color.fg.hover}", + "hoverBackground": "{color.bg.neutral.weak.default}", + "focusRing": { + "width": "{dimension.focusRing.width}", + "style": "none", + "color": "{color.border.focus}", + "offset": "{dimension.focusRing.offset}", + "shadow": "{effects.elevation.200}" + } + } + }, + "message": { + "extend": { + "width": "{dimension.size.2000}", + "extText": { "gap": "{dimension.space.100}" }, + "extInfo": { + "color": "{color.fg.status.info.default}", + "closeButton": { + "color": "{color.fg.status.info.default}", + "borderColor": "{color.border.status.info.default}" + }, + "caption": { "color": "{color.fg.default}" } + }, + "extAccentLine": { "width": "{dimension.size.100}" }, + "extCloseButton": { "width": "{dimension.borderWidth.100}" }, + "extSuccess": { + "color": "{color.fg.status.success.default}", + "closeButton": { + "color": "{color.fg.status.success.default}", + "borderColor": "{color.border.brand.default}" + }, + "caption": { "color": "{color.fg.default}" } + }, + "extWarn": { + "color": "{color.fg.status.warning.default}", + "closeButton": { + "color": "{color.fg.status.warning.default}", + "borderColor": "{color.border.status.warning.default}" + }, + "caption": { "color": "{color.fg.default}" } + }, + "extError": { + "color": "{color.fg.status.danger.default}", + "closeButton": { + "color": "{color.fg.status.danger.default}", + "borderColor": "{color.border.status.danger.default}" + }, + "caption": { "color": "{color.fg.default}" } + } + }, + "colorScheme": { + "light": { + "success": { + "background": "{color.bg.status.success.weak.default}", + "borderColor": "{color.border.brand.default}", + "color": "{color.fg.default}", + "shadow": "none", + "outlined": { + "color": "{color.fg.default}", + "borderColor": "{color.border.brand.default}" + }, + "closeButton": { + "hoverBackground": "{color.bg.status.success.weak.active}", + "focusRing": { + "color": "{color.border.focus}", + "shadow": "{effects.elevation.200}" + } + }, + "simple": { "color": "{color.fg.default}" } + }, + "outlined": { + "root": { "borderWidth": "{dimension.borderWidth.none}" }, + "closeButton": { + "hoverBackground": "transparent", + "focusRing": { + "color": "{color.border.focus}", + "shadow": "{effects.elevation.200}" + } + }, + "outlined": { + "color": "transparent", + "borderColor": "transparent" + }, + "simple": { "color": "transparent" } + }, + "simple": { "content": { "padding": "{dimension.space.none}" } }, + "warn": { + "background": "{color.bg.status.warning.weak.default}", + "borderColor": "{color.border.status.warning.default}", + "color": "{color.fg.default}", + "shadow": "none", + "outlined": { + "color": "{color.fg.default}", + "borderColor": "{color.border.status.warning.default}" + }, + "closeButton": { + "hoverBackground": "{color.bg.status.warning.weak.active}", + "focusRing": { + "color": "{color.border.focus}", + "shadow": "{effects.elevation.200}" + } + }, + "simple": { "color": "{color.fg.default}" } + }, + "error": { + "background": "{color.bg.status.danger.weak.default}", + "borderColor": "{color.border.status.danger.default}", + "color": "{color.fg.default}", + "shadow": "none", + "outlined": { + "color": "{color.fg.default}", + "borderColor": "{color.border.status.danger.default}" + }, + "closeButton": { + "hoverBackground": "{color.bg.status.danger.weak.active}", + "focusRing": { + "color": "{color.border.focus}", + "shadow": "{effects.elevation.200}" + } + }, + "simple": { "color": "{color.fg.default}" } + }, + "secondary": { + "borderColor": "transparent", + "shadow": "none", + "closeButton": { + "hoverBackground": "transparent", + "focusRing": { + "color": "{color.border.focus}", + "shadow": "{effects.elevation.200}" + } + }, + "simple": { "color": "transparent" }, + "outlined": { + "color": "transparent", + "borderColor": "transparent" + }, + "background": "{color.bg.neutral.weak.default}", + "color": "{color.fg.default}" + }, + "contrast": { + "borderColor": "transparent", + "shadow": "none", + "closeButton": { + "hoverBackground": "transparent", + "focusRing": { + "color": "{color.border.focus}", + "shadow": "{effects.elevation.200}" + } + }, + "simple": { "color": "transparent" }, + "outlined": { + "color": "transparent", + "borderColor": "transparent" + }, + "background": "{color.bg.neutral.strong.default}", + "color": "{color.fg.on.fill.default}" + }, + "info": { + "background": "{color.bg.status.info.weak.default}", + "borderColor": "{color.border.status.info.default}", + "color": "{color.fg.default}", + "shadow": "none", + "closeButton": { + "hoverBackground": "{color.bg.status.info.weak.active}", + "focusRing": { + "color": "{color.border.focus}", + "shadow": "{effects.elevation.200}" + } + }, + "outlined": { + "color": "{color.fg.default}", + "borderColor": "{color.border.status.info.default}" + }, + "simple": { "color": "{color.fg.default}" } + } + }, + "dark": { + "contrast": { + "background": "{color.bg.surface.canvas.default}", + "borderColor": "transparent", + "closeButton": { + "focusRing": { + "color": "{color.border.focus}", + "shadow": "{effects.elevation.200}" + }, + "hoverBackground": "transparent" + }, + "color": "{color.fg.default}", + "outlined": { + "borderColor": "transparent", + "color": "transparent" + }, + "shadow": "none", + "simple": { "color": "transparent" } + }, + "error": { + "background": "{color.bg.status.danger.weak.default}", + "borderColor": "{color.border.status.danger.default}", + "closeButton": { + "focusRing": { + "color": "{color.border.focus}", + "shadow": "{effects.elevation.200}" + }, + "hoverBackground": "{color.bg.status.danger.weak.active}" + }, + "color": "{color.fg.inverse.default}", + "outlined": { + "borderColor": "{color.border.status.danger.default}", + "color": "{color.fg.inverse.default}" + }, + "shadow": "none", + "simple": { "color": "{color.fg.inverse.default}" } + }, + "info": { + "background": "{color.bg.status.info.weak.default}", + "borderColor": "{color.border.status.info.default}", + "closeButton": { + "focusRing": { + "color": "{color.border.focus}", + "shadow": "{effects.elevation.200}" + }, + "hoverBackground": "{color.bg.status.info.weak.active}" + }, + "color": "{color.fg.inverse.default}", + "outlined": { + "borderColor": "{color.border.status.info.default}", + "color": "{color.fg.inverse.default}" + }, + "shadow": "none", + "simple": { "color": "{color.fg.inverse.default}" } + }, + "secondary": { + "background": "{color.bg.neutral.strong.default}", + "borderColor": "transparent", + "closeButton": { + "focusRing": { + "color": "{color.border.focus}", + "shadow": "{effects.elevation.200}" + }, + "hoverBackground": "transparent" + }, + "color": "{color.fg.inverse.default}", + "outlined": { + "borderColor": "transparent", + "color": "transparent" + }, + "shadow": "none", + "simple": { "color": "transparent" } + }, + "success": { + "background": "{color.bg.status.success.weak.default}", + "borderColor": "{color.border.brand.default}", + "closeButton": { + "focusRing": { + "color": "{color.border.focus}", + "shadow": "{effects.elevation.200}" + }, + "hoverBackground": "{color.bg.status.success.weak.active}" + }, + "color": "{color.fg.inverse.default}", + "outlined": { + "borderColor": "{color.border.brand.default}", + "color": "{color.fg.inverse.default}" + }, + "shadow": "none", + "simple": { "color": "{color.fg.inverse.default}" } + }, + "warn": { + "background": "{color.bg.status.warning.weak.default}", + "borderColor": "{color.border.status.warning.default}", + "closeButton": { + "focusRing": { + "color": "{color.border.focus}", + "shadow": "{effects.elevation.200}" + }, + "hoverBackground": "{color.bg.status.warning.weak.active}" + }, + "color": "{color.fg.inverse.default}", + "outlined": { + "borderColor": "{color.border.status.warning.default}", + "color": "{color.fg.inverse.default}" + }, + "shadow": "none", + "simple": { "color": "{color.fg.inverse.default}" } + }, + "outlined": { + "root": { "borderWidth": "{dimension.borderWidth.none}" }, + "closeButton": { + "hoverBackground": "transparent", + "focusRing": { + "color": "{color.border.focus}", + "shadow": "{effects.elevation.200}" + } + }, + "outlined": { + "color": "transparent", + "borderColor": "transparent" + }, + "simple": { "color": "transparent" } + }, + "simple": { "content": { "padding": "{dimension.space.none}" } } + } + }, + "root": { + "borderRadius": "{dimension.borderRadius.400}", + "borderWidth": "{dimension.borderWidth.100}", + "transitionDuration": "{effects.transition.duration.200}" + }, + "content": { + "padding": "{dimension.space.400}", + "gap": "{dimension.space.400}", + "sm": { "padding": "{dimension.space.400}" }, + "lg": { "padding": "{dimension.space.400}" } + }, + "text": { + "fontSize": "{fonts.fontSize.300}", + "fontWeight": "{fonts.fontWeight.bold}", + "sm": { "fontSize": "{fonts.fontSize.300}" }, + "lg": { "fontSize": "{fonts.fontSize.300}" } + }, + "icon": { + "size": "{dimension.size.1000}", + "sm": { "size": "{dimension.size.1000}" }, + "lg": { "size": "{dimension.size.1000}" } + }, + "closeButton": { + "width": "{dimension.size.900}", + "height": "{dimension.size.900}", + "borderRadius": "{dimension.borderRadius.400}", + "focusRing": { + "width": "{dimension.focusRing.width}", + "style": "none", + "offset": "{dimension.focusRing.offset}" + } + }, + "closeIcon": { + "size": "{dimension.size.450}", + "sm": { "size": "{dimension.size.450}" }, + "lg": { "size": "{dimension.size.450}" } + }, + "outlined": { "root": { "borderWidth": "{dimension.borderWidth.100}" } }, + "simple": { "content": { "padding": "{dimension.space.none}" } } + }, + "metergroup": { + "extend": { "extLabel": { "color": "{color.fg.muted}" } }, + "root": { + "borderRadius": "{dimension.borderRadius.400}", + "gap": "{dimension.space.400}" + }, + "meters": { + "size": "{dimension.size.200}", + "background": "{color.bg.neutral.medium.default}" + }, + "label": { "gap": "{dimension.space.100}" }, + "labelMarker": { "size": "{dimension.size.200}" }, + "labelIcon": { "size": "{dimension.size.450}" }, + "labelList": { + "verticalGap": "{dimension.space.200}", + "horizontalGap": "{dimension.space.400}" + } + }, + "multiselect": { + "extend": { + "paddingX": "{dimension.space.150}", + "paddingY": "{dimension.space.150}", + "borderWidth": "{dimension.borderWidth.100}", + "iconSize": "{dimension.size.450}", + "width": "{dimension.size.1700}", + "readonlyBackground": "{color.bg.neutral.weak.default}" + }, + "root": { + "shadow": "{effects.elevation.none}", + "paddingX": "{dimension.space.400}", + "paddingY": "{dimension.space.400}", + "borderRadius": "{dimension.borderRadius.400}", + "transitionDuration": "{effects.transition.duration.200}", + "sm": { + "fontSize": "{fonts.fontSize.300}", + "paddingX": "{dimension.space.200}", + "paddingY": "{dimension.space.200}" + }, + "lg": { + "fontSize": "{fonts.fontSize.300}", + "paddingX": "{dimension.space.400}", + "paddingY": "{dimension.space.400}" + }, + "focusRing": { + "width": "{dimension.focusRing.width}", + "style": "none", + "offset": "{dimension.focusRing.offset}", + "shadow": "{effects.elevation.none}", + "color": "{color.border.focus}" + }, + "background": "{color.bg.surface.default.default}", + "borderColor": "{color.border.neutral.strong}", + "color": "{color.fg.default}", + "disabledBackground": "{color.bg.surface.canvas.hover}", + "disabledColor": "{color.fg.muted}", + "filledBackground": "{color.bg.surface.default.default}", + "filledFocusBackground": "{color.bg.surface.default.default}", + "filledHoverBackground": "{color.bg.surface.default.default}", + "focusBorderColor": "{color.border.brand.strong}", + "hoverBorderColor": "{color.border.brand.strong}", + "invalidBorderColor": "{color.border.status.danger.subtle}", + "invalidPlaceholderColor": "{color.fg.status.danger.hover}", + "placeholderColor": "{color.fg.muted}" + }, + "dropdown": { + "width": "{dimension.size.1700}", + "color": "{color.fg.active}" + }, + "overlay": { + "borderRadius": "{dimension.borderRadius.400}", + "shadow": "{effects.elevation.400}", + "background": "{color.bg.surface.default.default}", + "borderColor": "{color.border.neutral.default}", + "color": "{color.fg.default}" + }, + "list": { + "padding": "{dimension.space.100}", + "header": { + "padding": "{dimension.space.400} {dimension.space.400} {dimension.space.none} {dimension.space.400}" + }, + "gap": "{dimension.space.100}" + }, + "chip": { "borderRadius": "{dimension.borderRadius.200}" }, + "option": { + "padding": "{dimension.space.200} {dimension.space.400}", + "borderRadius": "{dimension.borderRadius.200}", + "gap": "{dimension.space.200}", + "color": "{color.fg.default}", + "focusBackground": "{color.bg.neutral.weak.default}", + "focusColor": "{color.fg.default}", + "selectedBackground": "{color.bg.neutral.strong.selected}", + "selectedColor": "{color.fg.on.fill.default}", + "selectedFocusBackground": "{color.bg.neutral.strong.active}", + "selectedFocusColor": "{color.fg.on.fill.active}" + }, + "optionGroup": { + "fontWeight": "{fonts.fontWeight.demibold}", + "padding": "{dimension.space.200} {dimension.space.400}", + "background": "{color.bg.surface.raised.default}", + "color": "{color.fg.muted}" + }, + "emptyMessage": { + "padding": "{dimension.space.200} {dimension.space.400}" + }, + "clearIcon": { "color": "{color.fg.active}" } + }, + "paginator": { + "root": { + "padding": "{dimension.space.none} {dimension.space.200}", + "gap": "{dimension.space.200}", + "borderRadius": "{dimension.borderRadius.400}", + "background": "transparent", + "color": "{color.fg.default}", + "transitionDuration": "{effects.transition.duration.200}" + }, + "currentPageReport": { "color": "{color.fg.muted}" }, + "navButton": { + "background": "transparent", + "hoverBackground": "{color.bg.neutral.weak.default}", + "selectedBackground": "{color.bg.neutral.strong.selected}", + "color": "{color.fg.default}", + "hoverColor": "{color.fg.hover}", + "selectedColor": "{color.fg.on.fill.default}", + "width": "{dimension.size.1100}", + "height": "{dimension.size.1100}", + "borderRadius": "{dimension.borderRadius.400}", + "focusRing": { + "width": "{dimension.focusRing.width}", + "style": "none", + "color": "{color.border.focus}", + "offset": "{dimension.focusRing.offset}", + "focus": "{effects.elevation.200}", + "shadow": "{effects.elevation.none}" + } + }, + "jumpToPageInput": { "maxWidth": "{dimension.size.1500}" } + }, + "panelmenu": { + "extend": { + "iconSize": "{dimension.size.600}", + "extPanel": { "gap": "{dimension.space.100}" }, + "extItem": { + "activeBackground": "{color.bg.neutral.strong.default}", + "activeColor": "{color.fg.inverse.active}", + "caption": { + "color": "{color.fg.muted}", + "gap": "{dimension.space.100}" + } + } + }, + "root": { + "gap": "{dimension.space.100}", + "transitionDuration": "{effects.transition.duration.200}" + }, + "panel": { + "background": "transparent", + "borderColor": "transparent", + "borderWidth": "{dimension.borderWidth.100}", + "color": "{color.fg.default}", + "padding": "{dimension.space.100}", + "borderRadius": "{dimension.borderRadius.400}", + "first": { + "borderWidth": "{dimension.borderWidth.100} {dimension.borderWidth.100} {dimension.borderWidth.none} {dimension.borderWidth.100}", + "topBorderRadius": "{dimension.borderRadius.400}" + }, + "last": { + "borderWidth": "{dimension.borderWidth.none} {dimension.borderWidth.100} {dimension.borderWidth.100} {dimension.borderWidth.100}", + "topBorderRadius": "{dimension.borderRadius.400}", + "bottomBorderRadius": "{dimension.borderRadius.400}" + } + }, + "item": { + "focusBackground": "{color.bg.neutral.weak.default}", + "color": "{color.fg.default}", + "focusColor": "{color.fg.default}", + "gap": "{dimension.space.200}", + "padding": "{dimension.space.200} {dimension.space.400}", + "borderRadius": "{dimension.borderRadius.200}", + "icon": { + "color": "{color.fg.default}", + "focusColor": "{color.fg.default}" + } + }, + "submenu": { "indent": "{dimension.space.700}" }, + "separator": { "borderColor": "{color.border.neutral.default}" }, + "submenuIcon": { + "color": "{color.fg.default}", + "focusColor": "{color.fg.default}" + } + }, + "password": { + "extend": { "borderWidth": "{dimension.borderWidth.100}" }, + "colorScheme": { + "light": { + "strength": { + "weakBackground": "{color.bg.status.danger.strong.active}", + "mediumBackground": "{color.bg.status.warning.strong.active}", + "strongBackground": "{color.bg.brand.strong.hover}" + }, + "icon": { "color": "{color.fg.muted}" } + }, + "dark": { + "strength": { + "mediumBackground": "{color.bg.status.warning.strong.active}", + "strongBackground": "{color.bg.status.success.strong.hover}", + "weakBackground": "{color.bg.status.danger.strong.active}" + }, + "icon": { "color": "{color.fg.inverse.muted}" } + } + }, + "meter": { + "background": "{color.bg.neutral.medium.default}", + "borderRadius": "{dimension.borderRadius.400}", + "height": "{dimension.size.200}" + }, + "overlay": { + "background": "{color.bg.surface.default.default}", + "borderColor": "{color.border.neutral.strong}", + "borderRadius": "{dimension.borderRadius.200}", + "color": "{color.fg.default}", + "padding": "{dimension.space.400}", + "shadow": "{effects.elevation.400}" + }, + "content": { "gap": "{dimension.space.200}" }, + "icon": { "color": "{color.fg.default}" } + }, + "popover": { + "extend": { + "borderWidth": "{dimension.borderWidth.100}", + "arrow": { + "width": "{dimension.size.350}", + "height": "{dimension.size.200}" + } + }, + "root": { + "background": "{color.bg.surface.default.default}", + "borderColor": "{color.border.neutral.strong}", + "color": "{color.fg.default}", + "borderRadius": "{dimension.borderRadius.200}", + "shadow": "{effects.elevation.400}", + "gutter": "{dimension.space.100}", + "arrowOffset": "{dimension.space.600}" + }, + "content": { "padding": "{dimension.space.400}" } + }, + "progressbar": { + "label": { + "color": "{color.fg.default}", + "fontSize": "{fonts.fontSize.100}", + "fontWeight": "{fonts.fontWeight.regular}" + }, + "root": { + "background": "{color.bg.surface.canvas.hover}", + "borderRadius": "{dimension.borderRadius.400}", + "height": "{dimension.size.450}" + }, + "value": { "background": "{color.bg.brand.strong.default}" } + }, + "progressspinner": { + "extend": { + "small": "{dimension.size.450}", + "medium": "{dimension.size.900}", + "large": "{dimension.size.1200}", + "xlarge": "{dimension.size.1300}" + }, + "colorScheme": { + "light": { + "root": { + "colorOne": "{color.fg.brand.default}", + "colorTwo": "{color.fg.status.info.default}", + "colorThree": "{color.fg.status.danger.default}", + "colorFour": "{color.fg.status.warning.default}" + } + }, + "dark": { + "root": { + "colorFour": "{color.fg.status.warning.muted}", + "colorOne": "{color.fg.brand.muted}", + "colorThree": "{color.fg.status.danger.muted}", + "colorTwo": "{color.fg.status.info.muted}" + } + } + }, + "root": { "borderWidth": "{dimension.borderWidth.300}" } + }, + "radiobutton": { + "root": { + "width": "{dimension.size.700}", + "height": "{dimension.size.700}", + "background": "{color.bg.surface.default.default}", + "checkedBackground": "{color.bg.neutral.strong.default}", + "checkedHoverBackground": "{color.bg.neutral.strong.hover}", + "disabledBackground": "{color.bg.surface.canvas.hover}", + "filledBackground": "{color.bg.surface.default.default}", + "borderColor": "{color.border.neutral.strong}", + "hoverBorderColor": "{color.border.neutral.bold.default}", + "focusBorderColor": "{color.border.neutral.strong}", + "checkedBorderColor": "{color.border.neutral.bold.default}", + "checkedHoverBorderColor": "{color.border.neutral.bold.default}", + "checkedFocusBorderColor": "{color.border.neutral.bold.default}", + "checkedDisabledBorderColor": "{color.border.neutral.strong}", + "invalidBorderColor": "{color.border.status.danger.subtle}", + "shadow": "{effects.elevation.none}", + "transitionDuration": "{effects.transition.duration.200}", + "focusRing": { + "color": "{color.border.focus}", + "offset": "{dimension.focusRing.offset}", + "shadow": "{effects.elevation.none}", + "style": "none", + "width": "{dimension.focusRing.width}" + }, + "lg": { + "height": "{dimension.size.600}", + "width": "{dimension.size.600}" + }, + "sm": { + "height": "{dimension.size.200}", + "width": "{dimension.size.200}" + } + }, + "focusRing": { + "width": "{dimension.focusRing.width}", + "style": "none", + "color": "{color.border.focus}", + "offset": "{dimension.focusRing.offset}", + "shadow": "{effects.elevation.200}" + }, + "sm": { + "width": "{dimension.size.450}", + "height": "{dimension.size.450}" + }, + "lg": { + "width": "{dimension.size.600}", + "height": "{dimension.size.600}" + }, + "icon": { + "size": "{dimension.size.350}", + "checkedColor": "{color.fg.on.fill.default}", + "checkedHoverColor": "{color.fg.on.fill.hover}", + "disabledColor": "{color.fg.muted}", + "sm": { "size": "{dimension.size.200}" }, + "lg": { "size": "{dimension.size.450}" } + } + }, + "rating": { + "root": { + "gap": "{dimension.space.200}", + "transitionDuration": "{effects.transition.duration.200}", + "focusRing": { + "color": "{color.border.focus}", + "offset": "{dimension.focusRing.offset}", + "shadow": "{effects.elevation.none}", + "style": "none", + "width": "{dimension.focusRing.width}" + } + }, + "focusRing": { + "width": "{dimension.focusRing.width}", + "style": "none", + "color": "{color.border.focus}", + "offset": "{dimension.focusRing.offset}", + "shadow": "{effects.elevation.200}" + }, + "icon": { + "size": "{dimension.size.700}", + "color": "{color.fg.muted}", + "hoverColor": "{color.fg.status.warning.default}", + "activeColor": "{color.fg.status.warning.default}" + } + }, + "ripple": { + "colorScheme": { + "light": { + "root": { "background": "{color.bg.neutral.medium.default}" } + }, + "dark": { + "root": { "background": "{color.bg.neutral.medium.default}" } + } + } + }, + "scrollpanel": { + "colorScheme": { + "light": { "bar": { "background": "{color.bg.neutral.weak.active}" } }, + "dark": { "bar": { "background": "{color.bg.neutral.strong.active}" } } + }, + "root": { "transitionDuration": "{effects.transition.duration.200}" }, + "bar": { + "size": "{dimension.size.200}", + "borderRadius": "{dimension.borderRadius.200}", + "focusRing": { + "width": "{dimension.size.none}", + "style": "none", + "color": "{color.border.focus}", + "offset": "{dimension.focusRing.offset}", + "shadow": "{effects.elevation.200}" + } + } + }, + "select": { + "extend": { + "extOption": { + "background": "{color.bg.surface.raised.default}", + "gap": "{dimension.space.200}" + }, + "extOptionGroup": { "gap": "{dimension.space.200}" }, + "readonlyBackground": "{color.bg.neutral.weak.default}", + "borderWidth": "{dimension.borderWidth.100}", + "iconSize": "{dimension.size.450}" + }, + "root": { + "background": "{color.bg.surface.default.default}", + "disabledBackground": "{color.bg.surface.canvas.hover}", + "filledBackground": "{color.bg.surface.default.default}", + "filledHoverBackground": "{color.bg.surface.default.default}", + "filledFocusBackground": "{color.bg.surface.default.default}", + "borderColor": "{color.border.neutral.strong}", + "hoverBorderColor": "{color.border.brand.strong}", + "focusBorderColor": "{color.border.brand.strong}", + "invalidBorderColor": "{color.border.status.danger.subtle}", + "color": "{color.fg.default}", + "disabledColor": "{color.fg.muted}", + "placeholderColor": "{color.fg.muted}", + "invalidPlaceholderColor": "{color.fg.status.danger.hover}", + "shadow": "{effects.elevation.none}", + "paddingX": "{dimension.space.400}", + "paddingY": "{dimension.space.400}", + "borderRadius": "{dimension.borderRadius.400}", + "transitionDuration": "{effects.transition.duration.200}", + "sm": { + "fontSize": "{fonts.fontSize.300}", + "paddingX": "{dimension.space.400}", + "paddingY": "{dimension.space.400}" + }, + "lg": { + "fontSize": "{fonts.fontSize.300}", + "paddingX": "{dimension.space.400}", + "paddingY": "{dimension.space.400}" + }, + "focusRing": { + "width": "{dimension.focusRing.width}", + "style": "none", + "color": "{color.border.focus}", + "offset": "{dimension.focusRing.offset}", + "shadow": "{effects.elevation.none}" + } + }, + "dropdown": { + "width": "{dimension.size.1700}", + "color": "{color.fg.active}" + }, + "overlay": { + "background": "{color.bg.surface.default.default}", + "borderColor": "{color.border.neutral.default}", + "borderRadius": "{dimension.borderRadius.400}", + "color": "{color.fg.default}", + "shadow": "{effects.elevation.400}" + }, + "list": { + "padding": "{dimension.space.100}", + "gap": "{dimension.space.100}", + "header": { + "padding": "{dimension.space.400} {dimension.space.400} {dimension.space.none} {dimension.space.400}" + } + }, + "option": { + "focusBackground": "{color.bg.neutral.weak.default}", + "selectedBackground": "{color.bg.neutral.strong.selected}", + "selectedFocusBackground": "{color.bg.neutral.strong.active}", + "color": "{color.fg.default}", + "focusColor": "{color.fg.default}", + "selectedColor": "{color.fg.on.fill.default}", + "selectedFocusColor": "{color.fg.on.fill.active}", + "padding": "{dimension.space.200} {dimension.space.400}", + "borderRadius": "{dimension.borderRadius.200}" + }, + "optionGroup": { + "background": "{color.bg.surface.raised.default}", + "color": "{color.fg.muted}", + "fontWeight": "{fonts.fontWeight.demibold}", + "padding": "{dimension.space.200} {dimension.space.400}" + }, + "clearIcon": { "color": "{color.fg.active}" }, + "checkmark": { + "color": "{color.fg.default}", + "gutterStart": "{dimension.space.negative.200}", + "gutterEnd": "{dimension.space.200}" + }, + "emptyMessage": { + "padding": "{dimension.space.200} {dimension.space.400}" + } + }, + "selectbutton": { + "extend": { + "gap": "{dimension.space.100}", + "paddingX": "{dimension.space.100}", + "paddingY": "{dimension.space.100}", + "iconSize": { + "sm": "{dimension.size.450}", + "md": "{dimension.size.600}", + "lg": "{dimension.size.700}", + "xlg": "{dimension.size.800}" + }, + "checkedBackground": "{color.bg.surface.raised.default}", + "checkedBorderColor": "{color.border.neutral.inverse}", + "checkedColor": "{color.fg.active}", + "ext": { "borderRadius": "{dimension.borderRadius.200}" } + }, + "colorScheme": { + "light": { + "root": { + "invalidBorderColor": "{color.border.status.danger.subtle}" + }, + "extend": { "background": "{color.bg.neutral.medium.default}" } + }, + "dark": { + "root": { + "invalidBorderColor": "{color.border.status.danger.strong}" + }, + "extend": { "background": "{color.bg.neutral.strong.hover}" } + } + }, + "root": { "borderRadius": "{dimension.borderRadius.400}" } + }, + "skeleton": { + "extend": { + "minWidth": "{dimension.size.900}", + "height": "{dimension.size.900}" + }, + "colorScheme": { + "light": { + "root": { + "background": "{color.bg.surface.canvas.hover}", + "animationBackground": "{color.bg.surface.canvas.default}" + } + }, + "dark": { + "root": { + "background": "{color.bg.surface.raised.default}", + "animationBackground": "{color.bg.surface.raised.selected}" + } + } + }, + "root": { "borderRadius": "{dimension.borderRadius.400}" } + }, + "slider": { + "colorScheme": { + "light": { + "handle": { + "content": { "background": "{color.bg.surface.default.default}" } + } + }, + "dark": { + "handle": { + "content": { "background": "{color.bg.surface.canvas.default}" } + } + } + }, + "root": { "transitionDuration": "{effects.transition.duration.200}" }, + "track": { + "background": "{color.bg.neutral.medium.default}", + "borderRadius": "{dimension.borderRadius.400}", + "size": "{dimension.size.100}" + }, + "range": { "background": "{color.bg.neutral.strong.default}" }, + "handle": { + "width": "{dimension.size.600}", + "height": "{dimension.size.600}", + "borderRadius": "{dimension.borderRadius.max}", + "background": "{color.bg.neutral.strong.default}", + "hoverBackground": "{color.bg.neutral.strong.default}", + "focusRing": { + "width": "{dimension.focusRing.width}", + "style": "none", + "color": "{color.border.focus}", + "offset": "{dimension.focusRing.offset}", + "shadow": "{effects.elevation.200}" + }, + "content": { + "borderRadius": "{dimension.borderRadius.max}", + "hoverBackground": "{color.bg.neutral.strong.default}", + "width": "{dimension.size.350}", + "height": "{dimension.size.350}", + "shadow": "none" + } + } + }, + "splitter": { + "colorScheme": { + "light": { + "handle": { "background": "{color.bg.neutral.strong.default}" } + }, + "dark": { + "handle": { "background": "{color.bg.surface.canvas.default}" } + } + }, + "gutter": { "background": "{color.bg.neutral.weak.default}" }, + "root": { + "background": "{color.bg.surface.default.default}", + "borderColor": "{color.border.neutral.default}", + "color": "{color.fg.default}", + "transitionDuration": "{effects.transition.duration.200}" + }, + "handle": { + "size": "{dimension.size.100}", + "borderRadius": "{dimension.borderRadius.400}", + "focusRing": { + "width": "{dimension.focusRing.width}", + "style": "none", + "color": "{color.border.focus}", + "offset": "{dimension.focusRing.offset}", + "shadow": "{effects.elevation.200}" + } + } + }, + "stepper": { + "extend": { + "extCaption": { "gap": "{dimension.space.100}" }, + "extStepNumber": { + "invalidBackground": "{color.bg.status.danger.strong.hover}", + "invalidColor": "{color.fg.on.status.danger.default}", + "invalidBorderColor": "{color.border.status.danger.subtle}", + "borderWidth": "{dimension.borderWidth.100}", + "iconSize": "{dimension.size.700}" + } + }, + "root": { "transitionDuration": "{effects.transition.duration.200}" }, + "separator": { + "background": "{color.bg.neutral.medium.default}", + "activeBackground": "{color.bg.neutral.strong.default}", + "margin": "{dimension.space.none} {dimension.space.none} {dimension.space.none} {dimension.space.700}", + "size": "{dimension.borderWidth.100}" + }, + "step": { + "padding": "{dimension.space.200}", + "gap": "{dimension.space.200}" + }, + "stepHeader": { + "padding": "{dimension.space.none}", + "borderRadius": "{dimension.borderRadius.none}", + "gap": "{dimension.space.200}", + "focusRing": { + "width": "{dimension.focusRing.width}", + "style": "none", + "color": "{color.border.focus}", + "offset": "{dimension.focusRing.offset}", + "shadow": "{effects.elevation.200}" + } + }, + "stepTitle": { + "color": "{color.fg.default}", + "activeColor": "{color.fg.default}", + "fontWeight": "{fonts.fontWeight.regular}" + }, + "stepNumber": { + "background": "{color.bg.surface.raised.default}", + "activeBackground": "{color.bg.brand.strong.default}", + "borderColor": "{color.border.neutral.default}", + "activeBorderColor": "{color.border.brand.default}", + "color": "{color.fg.default}", + "activeColor": "{color.fg.default}", + "size": "{dimension.size.700}", + "fontSize": "{fonts.fontSize.300}", + "fontWeight": "{fonts.fontWeight.bold}", + "borderRadius": "{dimension.borderRadius.max}", + "shadow": "none" + }, + "steppanels": { "padding": "{dimension.space.400}" }, + "steppanel": { + "background": "{color.bg.surface.raised.default}", + "color": "{color.fg.default}", + "padding": "{dimension.space.none}", + "indent": "{dimension.space.none}" + } + }, + "steps": { + "itemLink": { + "gap": "{dimension.space.200}", + "borderRadius": "{dimension.borderRadius.400}", + "focusRing": { + "color": "{color.border.focus}", + "offset": "{dimension.focusRing.offset}", + "shadow": "{effects.elevation.none}", + "style": "none", + "width": "{dimension.focusRing.width}" + } + }, + "itemLabel": { + "fontWeight": "{fonts.fontWeight.regular}", + "activeColor": "{color.fg.hover}", + "color": "{color.fg.default}" + }, + "itemNumber": { + "background": "{color.bg.surface.raised.default}", + "size": "{dimension.size.900}", + "fontSize": "{fonts.fontSize.300}", + "fontWeight": "{fonts.fontWeight.bold}", + "borderRadius": "{dimension.borderRadius.max}", + "shadow": "none", + "activeBackground": "{color.bg.surface.raised.default}", + "activeBorderColor": "{color.border.neutral.default}", + "activeColor": "{color.fg.hover}", + "borderColor": "{color.border.neutral.default}", + "color": "{color.fg.default}" + }, + "root": { "transitionDuration": "{effects.transition.duration.200}" }, + "separator": { "background": "{color.bg.neutral.medium.default}" } + }, + "tabs": { + "colorScheme": { + "light": { + "navButton": { "shadow": "none" }, + "tab": { + "background": "transparent", + "hoverBackground": "transparent", + "activeBackground": "transparent" + } + }, + "dark": { + "navButton": { "shadow": "none" }, + "tab": { + "activeBackground": "transparent", + "background": "transparent", + "hoverBackground": "transparent" + } + } + }, + "root": { "transitionDuration": "{effects.transition.duration.200}" }, + "tablist": { + "borderWidth": "{dimension.borderWidth.none} {dimension.borderWidth.none} {dimension.borderWidth.100} {dimension.borderWidth.none}", + "background": "transparent", + "borderColor": "{color.border.neutral.default}" + }, + "tab": { + "borderWidth": "{dimension.borderWidth.none}", + "borderColor": "{color.border.neutral.default}", + "hoverBorderColor": "{color.border.neutral.default}", + "activeBorderColor": "{color.border.neutral.bold.hover}", + "color": "{color.fg.muted}", + "hoverColor": "{color.fg.default}", + "activeColor": "{color.fg.default}", + "padding": "{dimension.space.400}", + "fontWeight": "{fonts.fontWeight.demibold}", + "margin": "{dimension.space.none}", + "gap": "{dimension.space.200}", + "focusRing": { + "width": "{dimension.focusRing.width}", + "style": "none", + "color": "{color.border.focus}", + "offset": "{dimension.focusRing.offset}", + "shadow": "{effects.elevation.200}" + } + }, + "tabpanel": { + "background": "transparent", + "color": "{color.fg.default}", + "padding": "{dimension.space.400}", + "focusRing": { + "width": "{dimension.focusRing.width}", + "style": "none", + "color": "{color.border.focus}", + "offset": "{dimension.focusRing.offset}", + "shadow": "{effects.elevation.200}" + } + }, + "navButton": { + "background": "{color.bg.surface.raised.default}", + "color": "{color.fg.default}", + "hoverColor": "{color.fg.hover}", + "width": "{dimension.size.700}", + "focusRing": { + "width": "{dimension.focusRing.width}", + "style": "none", + "color": "{color.border.focus}", + "offset": "{dimension.focusRing.offset}", + "shadow": "{effects.elevation.200}" + } + }, + "activeBar": { + "height": "{dimension.size.50}", + "bottom": "{dimension.space.negative.50}", + "background": "{color.bg.neutral.strong.default}" + } + }, + "toast": { + "extend": { + "extInfo": { + "color": "{color.fg.status.info.default}", + "closeButton": { + "color": "{color.fg.status.info.default}", + "borderColor": "{color.border.status.info.default}" + }, + "caption": { "color": "{color.fg.default}" } + }, + "extAccentLine": { "width": "{dimension.size.100}" }, + "extCloseButton": { "width": "{dimension.borderWidth.100}" }, + "extSuccess": { + "color": "{color.fg.status.success.default}", + "closeButton": { + "color": "{color.fg.status.success.default}", + "borderColor": "{color.border.brand.default}" + }, + "caption": { "color": "{color.fg.default}" } + }, + "extWarn": { + "color": "{color.fg.status.warning.default}", + "closeButton": { + "color": "{color.fg.status.warning.default}", + "borderColor": "{color.border.status.warning.default}" + }, + "caption": { "color": "{color.fg.default}" } + }, + "extError": { + "color": "{color.fg.status.danger.default}", + "closeButton": { + "color": "{color.fg.status.danger.default}", + "borderColor": "{color.border.status.danger.default}" + }, + "caption": { "color": "{color.fg.default}" } + } + }, + "colorScheme": { + "light": { + "info": { + "background": "{color.bg.status.info.weak.default}", + "borderColor": "{color.border.status.info.default}", + "color": "{color.fg.default}", + "detailColor": "{color.fg.default}", + "shadow": "{effects.elevation.400}", + "closeButton": { + "hoverBackground": "{color.bg.status.info.weak.active}", + "focusRing": { + "color": "{color.border.focus}", + "shadow": "{effects.elevation.200}" + } + } + }, + "success": { + "background": "{color.bg.status.success.weak.default}", + "borderColor": "{color.border.brand.default}", + "color": "{color.fg.default}", + "detailColor": "{color.fg.default}", + "shadow": "{effects.elevation.400}", + "closeButton": { + "hoverBackground": "{color.bg.status.success.weak.active}", + "focusRing": { + "color": "{color.border.focus}", + "shadow": "{effects.elevation.200}" + } + } + }, + "warn": { + "background": "{color.bg.status.warning.weak.default}", + "borderColor": "{color.border.status.warning.default}", + "color": "{color.fg.default}", + "detailColor": "{color.fg.default}", + "shadow": "{effects.elevation.400}", + "closeButton": { + "hoverBackground": "{color.bg.status.warning.weak.active}", + "focusRing": { "color": "{color.border.focus}", "shadow": "none" } + } + }, + "error": { + "background": "{color.bg.status.danger.weak.default}", + "borderColor": "{color.border.status.danger.default}", + "color": "{color.fg.default}", + "detailColor": "{color.fg.default}", + "shadow": "{effects.elevation.400}", + "closeButton": { + "hoverBackground": "{color.bg.status.danger.weak.active}", + "focusRing": { + "color": "{color.border.focus}", + "shadow": "{effects.elevation.200}" + } + } + }, + "secondary": { + "shadow": "{effects.elevation.400}", + "background": "{color.bg.neutral.weak.default}", + "borderColor": "{color.border.neutral.strong}", + "closeButton": { + "focusRing": { + "color": "{color.border.focus}", + "shadow": "{effects.elevation.none}" + }, + "hoverBackground": "{color.bg.neutral.weak.default}" + }, + "color": "{color.fg.default}", + "detailColor": "{color.fg.subtle}" + }, + "contrast": { + "shadow": "{effects.elevation.400}", + "background": "{color.bg.neutral.strong.default}", + "borderColor": "{color.border.neutral.bold.default}", + "closeButton": { + "focusRing": { + "color": "{color.border.focus}", + "shadow": "{effects.elevation.none}" + }, + "hoverBackground": "{color.bg.neutral.strong.hover}" + }, + "color": "{color.fg.on.fill.default}", + "detailColor": "{color.fg.on.fill.muted}" + }, + "root": { "blur": "{effects.blur.none}" } + }, + "dark": { + "contrast": { + "background": "{color.bg.surface.canvas.default}", + "borderColor": "{color.border.neutral.inverse}", + "closeButton": { + "focusRing": { + "color": "{color.border.focus}", + "shadow": "{effects.elevation.none}" + }, + "hoverBackground": "{color.bg.surface.canvas.hover}" + }, + "color": "{color.fg.default}", + "detailColor": "{color.fg.on.fill.muted}", + "shadow": "{effects.elevation.400}" + }, + "error": { + "background": "{color.bg.status.danger.weak.default}", + "borderColor": "{color.border.status.danger.default}", + "closeButton": { + "focusRing": { + "color": "{color.border.focus}", + "shadow": "{effects.elevation.200}" + }, + "hoverBackground": "{color.bg.status.danger.weak.active}" + }, + "color": "{color.fg.inverse.default}", + "detailColor": "{color.fg.inverse.default}", + "shadow": "{effects.elevation.400}" + }, + "info": { + "background": "{color.bg.status.info.weak.default}", + "borderColor": "{color.border.status.info.default}", + "closeButton": { + "focusRing": { + "color": "{color.border.focus}", + "shadow": "{effects.elevation.200}" + }, + "hoverBackground": "{color.bg.status.info.weak.active}" + }, + "color": "{color.fg.inverse.default}", + "detailColor": "{color.fg.inverse.default}", + "shadow": "{effects.elevation.400}" + }, + "root": { "blur": "{effects.blur.none}" }, + "secondary": { + "background": "{color.bg.neutral.strong.default}", + "borderColor": "{color.border.neutral.strong}", + "closeButton": { + "focusRing": { + "color": "{color.border.focus}", + "shadow": "{effects.elevation.none}" + }, + "hoverBackground": "{color.bg.neutral.strong.selected}" + }, + "color": "{color.fg.inverse.default}", + "detailColor": "{color.fg.subtle}", + "shadow": "{effects.elevation.400}" + }, + "success": { + "background": "{color.bg.status.success.weak.default}", + "borderColor": "{color.border.brand.default}", + "closeButton": { + "focusRing": { + "color": "{color.border.focus}", + "shadow": "{effects.elevation.200}" + }, + "hoverBackground": "{color.bg.status.success.weak.active}" + }, + "color": "{color.fg.inverse.default}", + "detailColor": "{color.fg.inverse.default}", + "shadow": "{effects.elevation.400}" + }, + "warn": { + "background": "{color.bg.status.warning.weak.default}", + "borderColor": "{color.border.status.warning.default}", + "closeButton": { + "focusRing": { + "color": "{color.border.focus}", + "shadow": "none" + }, + "hoverBackground": "{color.bg.status.warning.weak.active}" + }, + "color": "{color.fg.inverse.default}", + "detailColor": "{color.fg.inverse.default}", + "shadow": "{effects.elevation.400}" + } + } + }, + "root": { + "width": "{dimension.size.2000}", + "borderWidth": "{dimension.borderWidth.100}", + "borderRadius": "{dimension.borderRadius.400}", + "transitionDuration": "{effects.transition.duration.200}" + }, + "icon": { "size": "{dimension.size.1000}" }, + "content": { + "padding": "{dimension.space.400}", + "gap": "{dimension.space.400}" + }, + "text": { "gap": "{dimension.space.100}" }, + "summary": { + "fontWeight": "{fonts.fontWeight.bold}", + "fontSize": "{fonts.fontSize.300}" + }, + "detail": { + "fontWeight": "{fonts.fontWeight.regular}", + "fontSize": "{fonts.fontSize.200}" + }, + "closeButton": { + "width": "{dimension.size.900}", + "height": "{dimension.size.900}", + "borderRadius": "{dimension.borderRadius.400}", + "focusRing": { + "width": "{dimension.focusRing.width}", + "style": "none", + "offset": "{dimension.focusRing.offset}" + } + }, + "closeIcon": { "size": "{dimension.size.450}" } + }, + "tag": { + "colorScheme": { + "light": { + "primary": { + "background": "{color.bg.brand.strong.default}", + "color": "{color.fg.default}" + }, + "secondary": { + "background": "{color.bg.neutral.medium.default}", + "color": "{color.fg.default}" + }, + "success": { + "background": "{color.bg.status.success.strong.hover}", + "color": "{color.fg.on.status.success.default}" + }, + "info": { + "background": "{color.bg.status.info.strong.default}", + "color": "{color.fg.on.status.info.default}" + }, + "warn": { + "background": "{color.bg.status.warning.strong.default}", + "color": "{color.fg.on.status.warning.default}" + }, + "danger": { + "background": "{color.bg.status.danger.strong.default}", + "color": "{color.fg.on.status.danger.default}" + }, + "contrast": { + "background": "{color.bg.neutral.strong.default}", + "color": "{color.fg.on.fill.default}" + } + }, + "dark": { + "contrast": { + "background": "{color.bg.surface.canvas.default}", + "color": "{color.fg.default}" + }, + "danger": { + "background": "{color.bg.status.danger.strong.default}", + "color": "{color.fg.on.status.danger.default}" + }, + "info": { + "background": "{color.bg.status.info.strong.default}", + "color": "{color.fg.on.status.info.default}" + }, + "primary": { + "background": "{color.bg.brand.strong.default}", + "color": "{color.fg.inverse.default}" + }, + "secondary": { + "background": "{color.bg.neutral.strong.hover}", + "color": "{color.fg.inverse.default}" + }, + "success": { + "background": "{color.bg.brand.strong.hover}", + "color": "{color.fg.on.status.success.default}" + }, + "warn": { + "background": "{color.bg.status.warning.strong.default}", + "color": "{color.fg.on.status.warning.default}" + } + } + }, + "root": { + "fontSize": "{fonts.fontSize.100}", + "fontWeight": "{fonts.fontWeight.regular}", + "padding": "{dimension.space.100} {dimension.space.200}", + "gap": "{dimension.space.100}", + "borderRadius": "{dimension.borderRadius.200}", + "roundedBorderRadius": "{dimension.borderRadius.max}" + }, + "icon": { "size": "{dimension.size.450}" } + }, + "textarea": { + "extend": { + "readonlyBackground": "{color.bg.neutral.weak.default}", + "borderWidth": "{dimension.borderWidth.100}", + "iconSize": "{dimension.size.450}", + "minHeight": "{dimension.size.1500}" + }, + "root": { + "background": "{color.bg.surface.default.default}", + "disabledBackground": "{color.bg.surface.canvas.hover}", + "filledBackground": "{color.bg.surface.default.default}", + "filledHoverBackground": "{color.bg.surface.default.default}", + "filledFocusBackground": "{color.bg.surface.default.default}", + "borderColor": "{color.border.neutral.strong}", + "hoverBorderColor": "{color.border.brand.strong}", + "focusBorderColor": "{color.border.brand.strong}", + "invalidBorderColor": "{color.border.status.danger.subtle}", + "color": "{color.fg.active}", + "disabledColor": "{color.fg.muted}", + "placeholderColor": "{color.fg.muted}", + "invalidPlaceholderColor": "{color.fg.status.danger.hover}", + "shadow": "{effects.elevation.none}", + "paddingX": "{dimension.space.400}", + "paddingY": "{dimension.space.400}", + "borderRadius": "{dimension.borderRadius.400}", + "transitionDuration": "{effects.transition.duration.200}", + "focusRing": { + "width": "{dimension.focusRing.width}", + "style": "none", + "color": "{color.border.focus}", + "offset": "{dimension.focusRing.offset}", + "shadow": "{effects.elevation.none}" + }, + "lg": { + "fontSize": "{fonts.fontSize.300}", + "paddingX": "{dimension.space.400}", + "paddingY": "{dimension.space.400}" + }, + "sm": { + "fontSize": "{fonts.fontSize.300}", + "paddingX": "{dimension.space.400}", + "paddingY": "{dimension.space.400}" + } + }, + "sm": { + "fontSize": "{fonts.fontSize.300}", + "paddingX": "{dimension.space.200}", + "paddingY": "{dimension.space.200}" + }, + "lg": { + "fontSize": "{fonts.fontSize.300}", + "paddingX": "{dimension.space.400}", + "paddingY": "{dimension.space.400}" + } + }, + "tieredmenu": { + "extend": { + "iconSize": "{dimension.size.600}", + "extSubmenu": { + "borderColor": "{color.border.neutral.default}", + "background": "{color.bg.surface.raised.default}" + }, + "extItem": { + "caption": { + "gap": "{dimension.space.100}", + "color": "{color.fg.muted}" + } + } + }, + "root": { + "background": "{color.bg.surface.default.default}", + "borderColor": "transparent", + "color": "{color.fg.default}", + "borderRadius": "{dimension.borderRadius.400}", + "shadow": "{effects.elevation.400}", + "transitionDuration": "{effects.transition.duration.200}" + }, + "list": { + "padding": "{dimension.space.100}", + "gap": "{dimension.space.100}" + }, + "item": { + "focusBackground": "{color.bg.neutral.weak.default}", + "activeBackground": "{color.bg.neutral.strong.default}", + "color": "{color.fg.default}", + "focusColor": "{color.fg.default}", + "activeColor": "{color.fg.inverse.active}", + "padding": "{dimension.space.200} {dimension.space.400}", + "borderRadius": "{dimension.borderRadius.200}", + "gap": "{dimension.space.200}", + "icon": { + "color": "{color.fg.default}", + "focusColor": "{color.fg.default}", + "activeColor": "{color.fg.inverse.active}" + } + }, + "submenu": { "mobileIndent": "{dimension.space.400}" }, + "separator": { "borderColor": "{color.border.neutral.default}" }, + "submenuIcon": { + "activeColor": "{color.fg.hover}", + "color": "{color.fg.default}", + "focusColor": "{color.fg.hover}", + "size": "{dimension.size.400}" + } + }, + "timeline": { + "extend": { "extEvent": { "gap": "{dimension.space.100}" } }, + "event": { "minHeight": "{dimension.size.1400}" }, + "vertical": { + "eventContent": { + "padding": "{dimension.space.none} {dimension.space.600}" + } + }, + "horizontal": { + "eventContent": { + "padding": "{dimension.space.600} {dimension.space.none}" + } + }, + "eventMarker": { + "size": "{dimension.size.450}", + "borderRadius": "{dimension.borderRadius.400}", + "borderWidth": "{dimension.borderWidth.300}", + "background": "{color.bg.surface.raised.default}", + "borderColor": "{color.border.brand.default}", + "content": { + "borderRadius": "{dimension.borderRadius.400}", + "size": "{dimension.size.350}", + "background": "transparent", + "insetShadow": "none" + } + }, + "eventConnector": { + "color": "{color.border.neutral.default}", + "size": "{dimension.borderWidth.100}" + } + }, + "togglebutton": { + "extend": { + "ext": { "gap": "{dimension.space.400}" }, + "iconSize": { + "sm": "{dimension.size.450}", + "md": "{dimension.size.600}", + "lg": "{dimension.size.700}" + }, + "iconOnlyWidth": "{dimension.size.1100}", + "hoverBorderColor": "{color.border.neutral.strong}", + "checkedHoverColor": "{color.fg.on.fill.hover}", + "checkedHoverBackground": "{color.bg.neutral.strong.hover}", + "checkedHoverBorderColor": "{color.border.neutral.bold.hover}", + "extXlg": { + "padding": "{dimension.space.600} {dimension.space.600}", + "iconOnlyWidth": "{dimension.size.1400}" + }, + "extSm": { "iconOnlyWidth": "{dimension.size.900}" }, + "extLg": { "iconOnlyWidth": "{dimension.size.1300}" } + }, + "colorScheme": { + "light": { + "root": { + "background": "{color.bg.surface.canvas.hover}", + "hoverBackground": "{color.bg.surface.canvas.active}", + "borderColor": "{color.border.neutral.default}", + "color": "{color.fg.default}", + "hoverColor": "{color.fg.default}", + "checkedBackground": "{color.bg.neutral.strong.default}", + "checkedColor": "{color.fg.on.fill.default}", + "checkedBorderColor": "{color.border.neutral.bold.default}", + "disabledBackground": "{color.bg.surface.canvas.hover}", + "disabledBorderColor": "{color.border.neutral.default}", + "disabledColor": "{color.fg.muted}", + "invalidBorderColor": "{color.border.status.danger.subtle}" + }, + "icon": { + "color": "{color.fg.default}", + "hoverColor": "{color.fg.default}", + "checkedColor": "{color.fg.on.fill.default}", + "disabledColor": "{color.fg.muted}" + }, + "content": { "checkedBackground": "transparent" } + }, + "dark": { + "root": { + "hoverBackground": "{color.bg.neutral.strong.active}", + "background": "{color.bg.neutral.strong.hover}", + "borderColor": "{color.border.neutral.bold.hover}", + "color": "{color.fg.inverse.default}", + "hoverColor": "{color.fg.on.brand.hover}", + "checkedBackground": "{color.bg.surface.canvas.default}", + "checkedColor": "{color.fg.focus}", + "checkedBorderColor": "{color.border.neutral.inverse}", + "disabledBackground": "{color.bg.neutral.strong.hover}", + "disabledBorderColor": "{color.border.neutral.bold.hover}", + "disabledColor": "{color.fg.inverse.muted}", + "invalidBorderColor": "{color.border.status.danger.strong}" + }, + "icon": { + "color": "{color.fg.inverse.default}", + "hoverColor": "{color.fg.on.brand.hover}", + "checkedColor": "{color.fg.focus}", + "disabledColor": "{color.fg.inverse.muted}" + }, + "content": { "checkedBackground": "transparent" } + } + }, + "root": { + "padding": "{dimension.space.200} {dimension.space.400}", + "borderRadius": "{dimension.borderRadius.max}", + "gap": "{dimension.space.200}", + "fontWeight": "{fonts.fontWeight.demibold}", + "focusRing": { + "width": "{dimension.focusRing.width}", + "style": "none", + "color": "{color.border.focus}", + "offset": "{dimension.focusRing.offset}", + "shadow": "{effects.elevation.200}" + }, + "sm": { + "fontSize": "{fonts.fontSize.200}", + "padding": "{dimension.space.100} {dimension.space.400}" + }, + "lg": { + "fontSize": "{fonts.fontSize.500}", + "padding": "{dimension.space.400} {dimension.space.700}" + }, + "transitionDuration": "{effects.transition.duration.200}", + "background": "{color.bg.surface.default.default}", + "borderColor": "{color.border.neutral.default}", + "checkedBackground": "{color.bg.surface.default.default}", + "checkedBorderColor": "{color.border.neutral.default}", + "checkedColor": "{color.fg.default}", + "color": "{color.fg.default}", + "disabledBackground": "{color.bg.surface.canvas.hover}", + "disabledBorderColor": "{color.border.neutral.default}", + "disabledColor": "{color.fg.muted}", + "hoverColor": "{color.fg.hover}", + "invalidBorderColor": "{color.border.status.danger.subtle}" + }, + "content": { + "checkedShadow": "none", + "padding": "{dimension.space.none}", + "borderRadius": "{dimension.borderRadius.none}", + "sm": { "padding": "{dimension.space.none}" }, + "lg": { "padding": "{dimension.space.none}" }, + "checkedBackground": "{color.bg.surface.default.default}" + }, + "icon": { + "checkedColor": "{color.fg.default}", + "color": "{color.fg.default}", + "disabledColor": "{color.fg.muted}", + "hoverColor": "{color.fg.hover}" + } + }, + "toggleswitch": { + "colorScheme": { + "light": { + "root": { + "background": "{color.bg.neutral.medium.active}", + "hoverBackground": "{color.bg.neutral.medium.strong}", + "disabledBackground": "{color.bg.surface.canvas.hover}", + "checkedBackground": "{color.bg.neutral.strong.default}", + "checkedHoverBackground": "{color.bg.neutral.strong.hover}" + }, + "handle": { + "background": "{color.bg.surface.raised.default}", + "hoverBackground": "{color.bg.surface.raised.default}", + "disabledBackground": "{color.bg.neutral.medium.strong}", + "checkedBackground": "{color.bg.surface.raised.default}", + "checkedHoverBackground": "{color.bg.surface.raised.default}", + "color": "{color.fg.default}", + "hoverColor": "{color.fg.default}", + "checkedColor": "{color.fg.default}", + "checkedHoverColor": "{color.fg.default}" + } + }, + "dark": { + "handle": { + "background": "{color.bg.surface.raised.default}", + "checkedBackground": "{color.bg.surface.raised.default}", + "checkedColor": "{color.fg.inverse.focus}", + "checkedHoverBackground": "{color.bg.surface.raised.default}", + "checkedHoverColor": "{color.fg.on.brand.hover}", + "color": "{color.fg.inverse.default}", + "disabledBackground": "{color.bg.surface.raised.active}", + "hoverBackground": "{color.bg.surface.raised.default}", + "hoverColor": "{color.fg.on.brand.hover}" + }, + "root": { + "background": "{color.bg.neutral.medium.active}", + "checkedBackground": "{color.bg.surface.canvas.default}", + "checkedHoverBackground": "{color.bg.surface.canvas.hover}", + "disabledBackground": "{color.bg.neutral.strong.hover}", + "hoverBackground": "{color.bg.surface.raised.active}" + } + } + }, + "root": { + "width": "{dimension.size.1100}", + "height": "{dimension.size.700}", + "borderRadius": "{dimension.borderRadius.max}", + "gap": "{dimension.space.100}", + "borderWidth": "{dimension.borderWidth.100}", + "shadow": "none", + "focusRing": { + "width": "{dimension.focusRing.width}", + "style": "none", + "color": "{color.border.focus}", + "offset": "{dimension.focusRing.offset}", + "shadow": "{effects.elevation.none}" + }, + "borderColor": "transparent", + "hoverBorderColor": "transparent", + "checkedBorderColor": "transparent", + "checkedHoverBorderColor": "transparent", + "invalidBorderColor": "{color.border.status.danger.subtle}", + "transitionDuration": "{effects.transition.duration.200}", + "slideDuration": "{effects.transition.duration.200}" + }, + "handle": { + "borderRadius": "{dimension.borderRadius.max}", + "size": "{dimension.size.450}" + } + }, + "tooltip": { + "colorScheme": { + "light": { + "root": { + "background": "{color.bg.neutral.strong.default}", + "color": "{color.fg.inverse.default}" + } + }, + "dark": { + "root": { + "background": "{color.bg.surface.canvas.default}", + "color": "{color.fg.default}" + } + } + }, + "root": { + "maxWidth": "{dimension.size.2000}", + "gutter": "{dimension.space.100}", + "shadow": "{effects.elevation.400}", + "padding": "{dimension.space.200} {dimension.space.400}", + "borderRadius": "{dimension.borderRadius.200}" + } + }, + "tree": { + "root": { + "background": "{color.bg.surface.default.default}", + "color": "{color.fg.default}", + "padding": "{dimension.space.400}", + "gap": "{dimension.space.100}", + "indent": "{dimension.space.400}", + "transitionDuration": "{effects.transition.duration.200}" + }, + "node": { + "padding": "{dimension.space.200} {dimension.space.400}", + "color": "{color.fg.default}", + "selectedColor": "{color.fg.on.fill.default}", + "gap": "{dimension.space.100}", + "borderRadius": "{dimension.borderRadius.400}", + "focusRing": { + "color": "{color.border.focus}", + "offset": "{dimension.focusRing.offset}", + "shadow": "{effects.elevation.none}", + "style": "none", + "width": "{dimension.focusRing.width}" + }, + "hoverBackground": "{color.bg.neutral.weak.default}", + "hoverColor": "{color.fg.default}", + "selectedBackground": "{color.bg.neutral.strong.selected}" + }, + "nodeIcon": { + "selectedColor": "{color.fg.on.fill.default}", + "color": "{color.fg.default}", + "hoverColor": "{color.fg.hover}" + }, + "nodeToggleButton": { + "borderRadius": "{dimension.borderRadius.100}", + "size": "{dimension.size.800}", + "selectedHoverBackground": "{color.bg.neutral.strong.default}", + "color": "{color.fg.default}", + "focusRing": { + "color": "{color.border.focus}", + "offset": "{dimension.focusRing.offset}", + "shadow": "{effects.elevation.none}", + "style": "none", + "width": "{dimension.focusRing.width}" + }, + "hoverBackground": "{color.bg.neutral.weak.default}", + "hoverColor": "{color.fg.hover}", + "selectedHoverColor": "{color.fg.hover}" + }, + "loadingIcon": { "size": "{dimension.size.450}" }, + "filter": { + "margin": "{dimension.space.none} {dimension.space.none} {dimension.space.200} {dimension.space.none}" + } + }, + "overlaybadge": { + "root": { + "outline": { "width": "{dimension.size.none}", "color": "transparent" } + } + } + } +} diff --git a/eslint.config.ts b/eslint.config.ts index 8b9966fb..29583883 100644 --- a/eslint.config.ts +++ b/eslint.config.ts @@ -5,6 +5,10 @@ import { MobileConfig } from './configs/eslint' export default defineConfig([ ...MobileConfig, { files: ['configs/eslint/**/*'], rules: { 'max-lines': 'off' } }, + { + files: ['scripts/**/*.ts'], + rules: { 'import-x/no-nodejs-modules': 'off' }, + }, { ignores: [ 'node_modules/**/*', diff --git a/ios/CDEKUI/Info.plist b/ios/CDEKUI/Info.plist index 654712ad..a9671707 100644 --- a/ios/CDEKUI/Info.plist +++ b/ios/CDEKUI/Info.plist @@ -68,4 +68,4 @@ UIViewControllerBasedStatusBarAppearance - \ No newline at end of file + diff --git a/jest.setup.ts b/jest.setup.ts index 8c1471d8..850baa92 100644 --- a/jest.setup.ts +++ b/jest.setup.ts @@ -13,8 +13,12 @@ jest.mock('react-native-worklets', () => ) interface MockedUnistylesModule { - StyleSheet: { create: (...args: unknown[]) => unknown } + StyleSheet: { + configure: jest.Mock + create: (...args: unknown[]) => unknown + } UnistylesRuntime: { + getTheme: jest.Mock miniRuntime: unknown setTheme: jest.Mock updateTheme: jest.Mock unknown]> @@ -32,23 +36,28 @@ const unistyles = jest.requireMock( // загрузки src/theme (и как следствие — src/utils/SvgUniversal с // `withUnistyles(...)` на top-level) в модуле уже стояли наши моки, а не // исходные identity-заглушки. -const themeRef: { - current: { darkTheme: unknown; lightTheme: unknown } | null -} = { current: null } +const themeRef: { current: { dark: unknown; light: unknown } | null } = { + current: null, +} const getTheme = (themeName: ThemeName | undefined) => - themeName === 'dark' - ? themeRef.current?.darkTheme - : themeRef.current?.lightTheme + themeName === 'dark' ? themeRef.current?.dark : themeRef.current?.light const runtime = unistyles.UnistylesRuntime runtime.themeName = 'light' +runtime.getTheme = jest.fn(getTheme) runtime.setTheme = jest.fn((themeName: ThemeName) => { runtime.themeName = themeName }) runtime.updateTheme = jest.fn() +unistyles.StyleSheet.configure = jest.fn(({ themes }) => { + if (themes) { + themeRef.current = themes + } +}) + unistyles.useUnistyles = jest.fn(() => ({ theme: getTheme(runtime.themeName), rt: runtime, @@ -174,11 +183,16 @@ unistyles.withUnistyles = jest.fn( } ) -themeRef.current = require('./src/theme') as { +const publicThemes = require('./src/theme') as { darkTheme: unknown lightTheme: unknown } +themeRef.current ??= { + dark: publicThemes.darkTheme, + light: publicThemes.lightTheme, +} + generatePropsCombinations = (properties: PropertyCombinations): T[] => { const keys = Object.keys(properties) as Array diff --git a/lefthook.yml b/lefthook.yml index c0ea5595..9f70f8e1 100644 --- a/lefthook.yml +++ b/lefthook.yml @@ -70,6 +70,8 @@ pre-push: exit 1 fi eslint: - run: npx yarn eslint . + run: yarn eslint . type-check: - run: npx yarn tsc --noEmit + run: yarn tsc --noEmit + tokens-check: + run: yarn tokens:typecheck && yarn tokens:check diff --git a/package.json b/package.json index fc50f07e..4957e810 100644 --- a/package.json +++ b/package.json @@ -31,12 +31,15 @@ } }, "scripts": { - "build": "rm -rf dist && tsc -p tsconfig.build.json", + "build": "yarn tokens:typecheck && yarn tokens:check && rm -rf dist && tsc -p tsconfig.build.json", "test": "jest", "start": "expo start --dev-client --clear", "android": "expo run:android", "ios": "expo run:ios --no-install", "storybook-generate": "sb-rn-get-stories --config-path .storybook && sed -i -e 's/export const view = global.view/export const view: ReturnType = global.view/' .storybook/storybook.requires.ts && prettier .storybook --write", + "tokens:generate": "ts-node --project scripts/token-generator/tsconfig.json scripts/token-generator/build.ts", + "tokens:check": "ts-node --transpile-only --project scripts/token-generator/tsconfig.json scripts/token-generator/build.ts --check", + "tokens:typecheck": "tsc --noEmit -p scripts/token-generator/tsconfig.json", "doctor": "expo-doctor", "check": "expo install --check", "lint:check": "eslint --cache .", @@ -75,6 +78,7 @@ "@testing-library/react-native": "13.3.3", "@types/jest": "29.5.14", "@types/lodash.map": "4.6.13", + "@types/node": "22.7.7", "@types/react": "19.2.14", "babel-loader": "8.2.3", "chalk": "4.1.2", diff --git a/scripts/token-generator/README.md b/scripts/token-generator/README.md new file mode 100644 index 00000000..e179f802 --- /dev/null +++ b/scripts/token-generator/README.md @@ -0,0 +1,145 @@ +# Генератор токенов + +Генератор преобразует входные токены из Figma в JSON для React Native. + +## Обновление токенов + +1. Обновить `design-tokens/input/tokens.json`. +2. Запустить `yarn tokens:generate`. +3. Проверить изменения в `src/theme/tokens`. +4. Закоммитить входные и сгенерированные токены вместе. + +`tokens:generate` сначала собирает и валидирует весь результат в памяти. При +ошибке файлы не изменяются. После успешной проверки команда удаляет лишние JSON +и записывает отформатированный результат. + +## Использование токенов + +Component-токены предназначены только для реализации компонентов UI Kit. Они не +входят в темы и публичные экспорты библиотеки. + +В `semantic` темы находится только `colorScheme`: Unistyles подставляет +соответствующие light- или dark-токены при переключении темы. Не зависящие от +темы `dimension` и `effects` доступны в статическом `semanticTokens`. + +## Результат генерации + +Из `design-tokens/input/tokens.json` создаются семь файлов: + +```text +src/theme/tokens +├── fonts.json +├── semantic +│ ├── colorScheme +│ │ ├── light.json +│ │ └── dark.json +│ ├── dimensions.json +│ └── effects.json +└── components + ├── light.json + └── dark.json +``` + +Для `semantic/colorScheme` и component-файлов выбирается соответствующая ветка +`colorScheme.light` или `colorScheme.dark`, а уровень `light`/`dark` удаляется. +Semantic-файл подключается в тему как `semantic.colorScheme`; в component-файлах +ключ `colorScheme` сохраняется: + +```text +semantic.colorScheme.light.color +→ semantic/colorScheme/light.json: color + +components.button.colorScheme.light.outlined +→ components/light.json: button.colorScheme.outlined +``` + +`semantic.dimension` записывается в `semantic/dimensions.json`, а +`semantic.effects` — в `semantic/effects.json`. Эти секции генерируются один раз +и не входят в тему. Если их итоговые значения зависят от `colorScheme`, +генератор завершится с ошибкой. + +`fonts.json` собирается из `primitive.fonts`, нормализуется по общим правилам и +не разделяется по цветовым схемам. Пока файл не экспортируется из библиотеки. + +Остальная часть `primitive` нужна только для подстановки ссылок и не +записывается в результат. Light- и dark-файлы должны иметь одинаковую структуру +и типы значений. + +## Преобразование значений + +Ссылки разрешаются до нормализации. Поддерживаются ссылки на всё значение и +вставки внутри поддерживаемых shorthand и `boxShadow`: + +```text +"{dimension.space.400}" -> "0.875rem" -> 14 +``` + +```text +"1.5rem" -> 24 +"4px" -> 4 +"150ms" -> 150 +"0.4" -> 0.4 +"0" -> 0 +``` + +Числовые строки преобразуются в числа, включая `fontWeight`. + +Animation duration преобразуется из `ms` в число. Easing записывается как +коэффициенты для `Easing.bezier`: + +```text +"linear" -> { x1: 0, y1: 0, x2: 1, y2: 1 } +"cubic-bezier(0.2, 0, 0, 1)" -> { x1: 0.2, y1: 0, x2: 0, y2: 1 } +``` + +Коэффициенты `x1` и `x2` должны находиться в диапазоне от `0` до `1`. + +CSS shorthand из 2–4 значений раскрывается в поля React Native: + +```text +padding: "8px 14px" +-> paddingTop: 8 +-> paddingRight: 14 +-> paddingBottom: 8 +-> paddingLeft: 14 +``` + +Для `borderRadius` одинаковые значения сворачиваются в число. Разные значения +сохраняются в объекте в порядке углов CSS: + +```text +borderRadius: "0 0 0 0" +-> borderRadius: 0 + +borderRadius: "4 8 12 16" +-> borderRadius: { left: 16, top: 4, right: 8, bottom: 12 } +``` + +Значения `boxShadow` сохраняются строками. Размеры внутри строки записываются в +`px`, поэтому ссылка на `0.25rem` превращается в `4px`. `boxShadow` требует New +Architecture. На Android обычные тени поддерживаются с API 28, `inset` — с +API 29. Fallback для более ранних версий намеренно не предусмотрен. + +`focusRing` сохраняет исходную структуру. Его размеры нормализуются, а `shadow` +обрабатывается по правилам `boxShadow`. Значение `style: "none"` отключает +только применение `width`, `color` и `offset` как outline-свойств: генератор не +зануляет эти токены. `shadow` остаётся независимым и может использоваться как +`boxShadow`. + +Генерация завершается с ошибкой при отсутствующей или циклической ссылке, +неподдерживаемом shorthand, непреобразованных числовых значениях и единицах, +составных `rem`/`px` вне `boxShadow`, `NaN` или `Infinity`. + +## Автоматические проверки + +`yarn tokens:check` ничего не изменяет и отдельно показывает отсутствующие, +изменённые и лишние JSON. `yarn tokens:typecheck` проверяет TypeScript-код +генератора. Обе команды запускаются при сборке и в CI. Если проверка файлов не +прошла, нужно выполнить `yarn tokens:generate` и проверить diff. + +## Устройство генератора + +Для изменения генератора: `core/compiler.ts` собирает темы, `core/resolution.ts` +разрешает ссылки, `core/normalization.ts` преобразует значения, +`core/validation.ts` проверяет результат. CLI и запись файлов находятся в +`build.ts` и `io.ts`. diff --git a/scripts/token-generator/__tests__/compiler.test.ts b/scripts/token-generator/__tests__/compiler.test.ts new file mode 100644 index 00000000..4094276c --- /dev/null +++ b/scripts/token-generator/__tests__/compiler.test.ts @@ -0,0 +1,634 @@ +import { + accessSync, + readdirSync, + mkdtempSync, + writeFileSync, + rmSync, +} from 'node:fs' +import { tmpdir } from 'node:os' +import { join } from 'node:path' + +import { + INPUT_DIRECTORY, + INPUT_FILE, + TOKENS_DIRECTORY, + parseArgs, +} from '../build' +import { compileTokens } from '../core/compiler' +import { + convertUnit, + normalizeEasing, + normalizeTree, + parseBoxShorthand, +} from '../core/normalization' +import { resolveReferences } from '../core/resolution' +import { + isTokenTree, + type CompiledTokens, + type TokenTree, + type TokenValue, +} from '../core/types' +import { assertValidOutput } from '../core/validation' +import { + OUTPUT_FILES, + findGeneratedTokenIssues, + loadTokenTree, + writeGeneratedTokens, +} from '../io' + +const listJsonFiles = (directory: string, prefix = ''): string[] => + readdirSync(directory, { withFileTypes: true }) + .flatMap((entry) => { + const relativePath = join(prefix, entry.name) + + return entry.isDirectory() + ? listJsonFiles(join(directory, entry.name), relativePath) + : entry.name.endsWith('.json') + ? [relativePath] + : [] + }) + .sort() + +const expectedOutputFiles = [ + OUTPUT_FILES.fonts, + ...Object.values(OUTPUT_FILES.semantic.colorScheme), + OUTPUT_FILES.semantic.dimensions, + OUTPUT_FILES.semantic.effects, + ...Object.values(OUTPUT_FILES.components), +].sort() + +const containsColorSchemeThemeBranch = (node: TokenValue): boolean => { + if (Array.isArray(node)) return node.some(containsColorSchemeThemeBranch) + + if (!isTokenTree(node)) return false + + return Object.entries(node).some(([key, value]) => { + if ( + key === 'colorScheme' && + isTokenTree(value) && + ('light' in value || 'dark' in value) + ) { + return true + } + + return containsColorSchemeThemeBranch(value) + }) +} + +describe('token compiler', () => { + describe('normalizeEasing', () => { + test.each([ + { + name: 'linear', + value: 'linear', + expected: { x1: 0, y1: 0, x2: 1, y2: 1 }, + }, + { + name: 'cubic-bezier', + value: 'cubic-bezier(0.2, 0, 0, 1)', + expected: { x1: 0.2, y1: 0, x2: 0, y2: 1 }, + }, + { + name: 'spring с y больше единицы', + value: 'cubic-bezier(0.34, 1.56, 0.64, 1)', + expected: { x1: 0.34, y1: 1.56, x2: 0.64, y2: 1 }, + }, + ])('$name преобразуется в коэффициенты', ({ value, expected }) => { + expect(normalizeEasing(value)).toStrictEqual(expected) + }) + + test('отклоняет неподдерживаемый формат', () => { + expect(() => normalizeEasing('ease-in')).toThrow('Unsupported easing') + }) + + test('отклоняет объект вместо easing-строки при нормализации дерева', () => { + expect(() => + normalizeTree( + { + effects: { + transition: { easing: { standard: { unexpected: 'value' } } }, + }, + }, + 'semantic' + ) + ).toThrow( + 'Expected easing string at "semantic.effects.transition.easing.standard"' + ) + }) + + test.each([ + { name: 'x1 меньше нуля', value: 'cubic-bezier(-0.1, 0, 1, 1)' }, + { name: 'x2 больше единицы', value: 'cubic-bezier(0, 0, 1.1, 1)' }, + ])('$name отклоняется', ({ value }) => { + expect(() => normalizeEasing(value)).toThrow( + 'Easing x coordinates must be between 0 and 1' + ) + }) + }) + + describe('convertUnit', () => { + test.each([ + { name: 'положительный rem', value: '1.5rem', expected: 24 }, + { name: 'отрицательный rem', value: '-0.5rem', expected: -8 }, + { name: 'миллисекунды', value: '150ms', expected: 150 }, + { name: 'пиксели', value: '4px', expected: 4 }, + { name: 'числовая строка', value: '0.4', expected: 0.4 }, + { name: 'строковый ноль', value: '0', expected: 0 }, + { + name: 'rem внутри составной строки', + value: 'inset 0 0 0 0.25rem #fff', + expected: 'inset 0 0 0 4px #fff', + }, + { name: 'обычная строка', value: 'auto', expected: 'auto' }, + ])('$name преобразуется в ожидаемое значение', ({ value, expected }) => { + expect(convertUnit(value)).toBe(expected) + }) + + test('отклоняет rem внутри неподдерживаемой составной строки', () => { + expect(() => convertUnit('blur(1rem)', 'semantic.effects.blur')).toThrow( + 'Unsupported composite unit value "blur(1rem)" at "semantic.effects.blur"' + ) + }) + }) + + describe('parseBoxShorthand', () => { + test.each([ + { + name: 'одно значение', + value: '8', + expected: { top: 8, right: 8, bottom: 8, left: 8 }, + }, + { + name: 'два значения', + value: '8 14', + expected: { top: 8, right: 14, bottom: 8, left: 14 }, + }, + { + name: 'три значения', + value: '8 14 10', + expected: { top: 8, right: 14, bottom: 10, left: 14 }, + }, + { + name: 'четыре значения с rem', + value: '0rem 1.5rem 0.875rem 1.5rem', + expected: { top: 0, right: 24, bottom: 14, left: 24 }, + }, + { + name: 'значения с px', + value: '4px 8px 12px 16px', + expected: { top: 4, right: 8, bottom: 12, left: 16 }, + }, + ])('$name раскрывается по правилам CSS', ({ value, expected }) => { + expect(parseBoxShorthand(value)).toStrictEqual(expected) + }) + + test.each([ + { name: 'пустая строка', value: '', message: 'Expected 1-4 box values' }, + { + name: 'пять значений', + value: '1 2 3 4 5', + message: 'Expected 1-4 box values', + }, + { + name: 'неподдерживаемая единица', + value: '1em 2em', + message: 'Invalid box value', + }, + { + name: 'нечисловое значение', + value: 'auto', + message: 'Invalid box value', + }, + ])('$name отклоняется', ({ value, message }) => { + expect(() => parseBoxShorthand(value)).toThrow(message) + }) + }) + + describe('normalizeTree', () => { + test('одинаковые радиусы сворачивает в одно значение', () => { + expect( + normalizeTree({ borderRadius: '0rem 0rem 0rem 0rem' }) + ).toStrictEqual({ borderRadius: 0 }) + }) + + test('разные радиусы сохраняет отдельными значениями', () => { + expect( + normalizeTree({ borderRadius: '0.25rem 0.5rem 0.75rem 1rem' }) + ).toStrictEqual({ + borderRadius: { left: 16, top: 4, right: 8, bottom: 12 }, + }) + }) + + test('преобразует числовые строки, включая fontWeight', () => { + expect( + normalizeTree({ depth: '1000', opacity: '0.4', fontWeight: '600' }) + ).toStrictEqual({ depth: 1000, opacity: 0.4, fontWeight: 600 }) + }) + }) + + describe('assertValidOutput', () => { + test.each(['4px', '0.4', 'blur(4px)'])( + 'отклоняет непреобразованное значение %s', + (value) => { + expect(() => assertValidOutput(value, 'semantic.value')).toThrow( + 'Unconverted token' + ) + } + ) + + test('разрешает boxShadow', () => { + expect(() => + assertValidOutput('0 0 4px #000', 'components.button.shadow') + ).not.toThrow() + }) + }) + + test('разделяет один источник на темы, разрешает ссылки и нормализует значения', () => { + const source: TokenTree = { + primitive: { + fonts: { + fontFamily: { base: 'Noto Sans' }, + fontWeight: { regular: '400' }, + fontSize: { base: '1rem' }, + }, + sizing: { small: '0.5rem', base: '1rem' }, + motion: { fast: '150ms' }, + }, + semantic: { + dimension: { + spacing: { small: '{sizing.small}', base: '{sizing.base}' }, + }, + effects: { duration: '{motion.fast}' }, + colorScheme: { + light: { color: { text: '#111111' } }, + dark: { color: { text: '#eeeeee' } }, + }, + }, + components: { + demo: { + extend: { + padding: '{dimension.spacing.small} {dimension.spacing.base}', + }, + root: { + margin: '{dimension.spacing.base}', + duration: '{effects.duration}', + borderWidth: '0rem 0rem {dimension.spacing.small} 0rem', + }, + icon: { size: '{dimension.spacing.base}' }, + colorScheme: { + light: { color: '{color.text}' }, + dark: { color: '{color.text}' }, + }, + }, + }, + } + + const compiled = compileTokens(source) + + expect(compiled).not.toHaveProperty('primitive') + expect(compiled.fonts).toStrictEqual({ + fontFamily: { base: 'Noto Sans' }, + fontWeight: { regular: 400 }, + fontSize: { base: 16 }, + }) + expect(compiled.semantic).toStrictEqual({ + colorScheme: { + light: { color: { text: '#111111' } }, + dark: { color: { text: '#eeeeee' } }, + }, + dimension: { spacing: { small: 8, base: 16 } }, + effects: { duration: 150 }, + }) + expect(compiled.components.light).toStrictEqual({ + demo: { + extend: { + paddingTop: 8, + paddingRight: 16, + paddingBottom: 8, + paddingLeft: 16, + }, + root: { + margin: 16, + duration: 150, + borderTopWidth: 0, + borderRightWidth: 0, + borderBottomWidth: 8, + borderLeftWidth: 0, + }, + icon: { size: 16 }, + colorScheme: { color: '#111111' }, + }, + }) + expect(compiled.components.dark.demo).toHaveProperty( + 'colorScheme.color', + '#eeeeee' + ) + expect(compiled.components.light.demo).not.toHaveProperty( + 'colorScheme.light' + ) + expect(compiled.components.dark.demo).not.toHaveProperty('colorScheme.dark') + }) + + test('сохраняет focusRing и нормализует его значения', () => { + const source: TokenTree = { + primitive: { + fonts: {}, + sizing: { focusRing: '0.25rem' }, + colors: { focus: '#d4fedc' }, + }, + semantic: { + dimension: { + focusRing: { width: '{sizing.focusRing}', offset: '0px' }, + }, + effects: { + focusRing: { + shadow: 'inset 0 0 0 {dimension.focusRing.width} {colors.focus}', + }, + }, + colorScheme: { light: {}, dark: {} }, + }, + components: { + demo: { + root: { + focusRing: { + width: '{dimension.focusRing.width}', + style: 'none', + color: '{colors.focus}', + offset: '{dimension.focusRing.offset}', + shadow: '{effects.focusRing.shadow}', + }, + }, + }, + }, + } + + const compiled = compileTokens(source) + + expect(compiled.semantic).toStrictEqual({ + colorScheme: { light: {}, dark: {} }, + dimension: { focusRing: { width: 4, offset: 0 } }, + effects: { focusRing: { shadow: 'inset 0 0 0 4px #d4fedc' } }, + }) + expect(compiled.components.light.demo).toStrictEqual({ + root: { + focusRing: { + width: 4, + style: 'none', + color: '#d4fedc', + offset: 0, + shadow: 'inset 0 0 0 4px #d4fedc', + }, + }, + }) + expect(compiled.components.dark).toStrictEqual(compiled.components.light) + }) + + test('отклоняет источник без одной из цветовых схем semantic', () => { + const source: TokenTree = { + primitive: { fonts: {} }, + semantic: { colorScheme: { light: {} } }, + components: {}, + } + + expect(() => compileTokens(source)).toThrow( + 'Expected an object at "semantic.colorScheme.dark"' + ) + }) + + test('отклоняет общие semantic-токены, зависящие от цветовой схемы', () => { + const source: TokenTree = { + primitive: { fonts: {} }, + semantic: { + colorScheme: { + light: { color: { spacing: '1rem' } }, + dark: { color: { spacing: '2rem' } }, + }, + dimension: { spacing: '{color.spacing}' }, + effects: {}, + }, + components: {}, + } + + expect(() => compileTokens(source)).toThrow( + 'Semantic "dimension" tokens must not depend on colorScheme' + ) + }) + + test('отклоняет циклические ссылки', () => { + const references: TokenTree = { first: '{second}', second: '{first}' } + + expect(() => resolveReferences('{first}', references)).toThrow( + 'Circular token reference' + ) + }) +}) + +describe('production input tokens', () => { + const source = loadTokenTree(INPUT_FILE) + const compiled: CompiledTokens = compileTokens(source) + + test('использует единственный входной tokens-файл', () => { + const tokenFiles = readdirSync(INPUT_DIRECTORY) + .filter((fileName) => /\.json$/.test(fileName)) + .sort() + + expect(tokenFiles).toStrictEqual(['tokens.json']) + }) + + test('экспортирует fonts без primitive и убирает темы из colorScheme', () => { + expect(Object.keys(compiled)).toStrictEqual([ + 'fonts', + 'semantic', + 'components', + ]) + expect(compiled).not.toHaveProperty('primitive') + + const inputComponents = source.components + const lightOutputComponents = compiled.components.light + const darkOutputComponents = compiled.components.dark + + if ( + !isTokenTree(inputComponents) || + !isTokenTree(inputComponents.button) || + !isTokenTree(lightOutputComponents.button) + ) { + throw new Error('Expected component namespaces') + } + + expect(Object.keys(lightOutputComponents).sort()).toStrictEqual( + Object.keys(inputComponents).sort() + ) + expect(Object.keys(darkOutputComponents).sort()).toStrictEqual( + Object.keys(inputComponents).sort() + ) + expect(lightOutputComponents.button).toHaveProperty('extend') + expect(lightOutputComponents.button).toHaveProperty('root') + expect(lightOutputComponents.button).toHaveProperty('colorScheme') + expect(darkOutputComponents.button).toHaveProperty('colorScheme') + expect(compiled.semantic.colorScheme.light).toHaveProperty('color') + expect(compiled.semantic.colorScheme.dark).toHaveProperty('color') + expect( + [ + compiled.semantic.colorScheme.light, + compiled.semantic.colorScheme.dark, + compiled.components.light, + compiled.components.dark, + ].filter(containsColorSchemeThemeBranch) + ).toHaveLength(0) + }) + + test('собирает и нормализует primitive.fonts без цветовой схемы', () => { + expect(compiled.fonts).toHaveProperty('fontFamily.base', 'Noto Sans') + expect(compiled.fonts).toHaveProperty('fontWeight.demibold', 600) + expect(compiled.fonts).toHaveProperty('fontSize.300', 16) + expect(compiled.fonts).toHaveProperty('lineHeight.auto', 'auto') + expect(compiled.fonts).toHaveProperty('letterSpacing.400', -0.48) + }) + + test('содержит только целевые файлы', () => { + const tokenFiles = listJsonFiles(TOKENS_DIRECTORY) + + expect(tokenFiles).toStrictEqual(expectedOutputFiles) + }) + + test('не содержит неразрешённых ссылок и CSS-единиц', () => { + const serialized = JSON.stringify(compiled) + + expect(serialized).not.toMatch(/\{[a-z][^}]*\}/i) + expect(serialized).not.toMatch(/-?\d*\.?\d+(?:rem|ms)\b/) + }) + + test('преобразует animation-токены в runtime-формат', () => { + expect(compiled.semantic.effects).toHaveProperty( + 'transition.easing.linear', + { x1: 0, y1: 0, x2: 1, y2: 1 } + ) + expect(compiled.semantic.effects).toHaveProperty( + 'transition.easing.spring', + { x1: 0.34, y1: 1.56, x2: 0.64, y2: 1 } + ) + expect(compiled.semantic.effects).toHaveProperty( + 'transition.duration.200', + 180 + ) + expect(compiled.components.light).toHaveProperty( + 'button.root.transitionDuration', + 180 + ) + expect(compiled.components.dark).toHaveProperty( + 'toggleswitch.root.slideDuration', + 180 + ) + expect(JSON.stringify(compiled)).not.toMatch(/cubic-bezier\s*\(/) + }) + + test('экспортирует focusRing без изменения его структуры', () => { + expect(compiled.semantic.effects).toHaveProperty( + 'focusRing.shadow', + 'inset 0 0 0 4px #d4fedc' + ) + expect(compiled.components.light).toHaveProperty( + 'accordion.header.focusRing', + { + width: 4, + style: 'none', + color: '#d4fedc', + offset: 0, + shadow: 'inset 0 0 0 4px #d4fedc', + } + ) + }) + + test('совпадает с закоммиченными сгенерированными токенами', async () => { + await expect( + findGeneratedTokenIssues(compiled, TOKENS_DIRECTORY) + ).resolves.toStrictEqual({ missing: [], changed: [], unexpected: [] }) + }) + + test('преобразует числовые RN-значения', () => { + expect(compiled.semantic.dimension).toHaveProperty('depth.100', 1000) + expect(compiled.semantic.effects).toHaveProperty('opacity.4', 0.04) + expect(compiled.semantic.effects).toHaveProperty('blur.100', 4) + expect(compiled.components.light).toHaveProperty( + 'button.root.label.fontWeight', + 600 + ) + }) + + test('component-токены содержат выбранную схему на исходных путях', () => { + expect(compiled.components.light.accordion).toHaveProperty('root') + expect(compiled.components.light.accordion).toHaveProperty('extend') + expect(compiled.components.light.accordion).toHaveProperty( + 'colorScheme.header.background' + ) + expect(compiled.components.dark.accordion).toHaveProperty( + 'colorScheme.header.background' + ) + expect(compiled.components.light.dataview).toHaveProperty( + 'header.borderRadius', + 0 + ) + expect(compiled.components.dark.dataview).toHaveProperty( + 'footer.borderRadius', + 0 + ) + }) + + test('check находит расхождения, а generate приводит файлы к актуальному состоянию', async () => { + const temporaryDirectory = mkdtempSync(join(tmpdir(), 'token-generator-')) + const unexpectedFile = join(temporaryDirectory, 'common.json') + const preservedFile = join(temporaryDirectory, 'README.md') + const missingFile = OUTPUT_FILES.semantic.colorScheme.dark + const changedFile = OUTPUT_FILES.semantic.dimensions + + try { + await writeGeneratedTokens(compiled, temporaryDirectory) + + expect(listJsonFiles(temporaryDirectory)).toStrictEqual( + expectedOutputFiles + ) + await expect( + findGeneratedTokenIssues(compiled, temporaryDirectory) + ).resolves.toStrictEqual({ missing: [], changed: [], unexpected: [] }) + + writeFileSync(unexpectedFile, '{}\n') + writeFileSync(preservedFile, '# Generated tokens\n') + rmSync(join(temporaryDirectory, missingFile)) + const changedPath = join(temporaryDirectory, changedFile) + + writeFileSync(changedPath, JSON.stringify(loadTokenTree(changedPath))) + + await expect( + findGeneratedTokenIssues(compiled, temporaryDirectory) + ).resolves.toStrictEqual({ + missing: [missingFile], + changed: [changedFile], + unexpected: ['common.json'], + }) + expect(() => accessSync(unexpectedFile)).not.toThrow() + expect(() => accessSync(preservedFile)).not.toThrow() + + await writeGeneratedTokens(compiled, temporaryDirectory) + + await expect( + findGeneratedTokenIssues(compiled, temporaryDirectory) + ).resolves.toStrictEqual({ missing: [], changed: [], unexpected: [] }) + expect(() => accessSync(unexpectedFile)).toThrow('ENOENT') + expect(() => accessSync(preservedFile)).not.toThrow() + } finally { + rmSync(temporaryDirectory, { recursive: true, force: true }) + } + }) +}) + +describe('token generator CLI', () => { + test('распознаёт check-режим', () => { + expect(parseArgs(['--check'])).toStrictEqual({ check: true, help: false }) + }) + + test('отклоняет неизвестный аргумент', () => { + expect(() => parseArgs(['--unknown'])).toThrow( + 'Неизвестный аргумент "--unknown"' + ) + }) +}) diff --git a/scripts/token-generator/build.ts b/scripts/token-generator/build.ts new file mode 100644 index 00000000..3c8f2531 --- /dev/null +++ b/scripts/token-generator/build.ts @@ -0,0 +1,97 @@ +import { resolve, join } from 'node:path' + +import { compileTokens } from './core/compiler' +import type { CompiledTokens } from './core/types' +import { + findGeneratedTokenIssues, + type GeneratedTokenIssues, + loadTokenTree, + writeGeneratedTokens, +} from './io' + +export const DESIGN_TOKENS_DIRECTORY = resolve(__dirname, '../../design-tokens') +export const INPUT_DIRECTORY = join(DESIGN_TOKENS_DIRECTORY, 'input') +export const TOKENS_DIRECTORY = resolve(__dirname, '../../src/theme/tokens') +export const INPUT_FILE = join(INPUT_DIRECTORY, 'tokens.json') + +interface CliOptions { + check: boolean + help: boolean +} + +const HELP = `Использование: + yarn tokens:generate + yarn tokens:check + +Опции: + --check проверить актуальность сгенерированных токенов без записи + --help показать эту справку` + +export const parseArgs = (arguments_: string[]): CliOptions => { + const options: CliOptions = { check: false, help: false } + + for (const argument of arguments_) { + if (argument === '--check') options.check = true + else if (argument === '--help') options.help = true + else { + throw new Error(`Неизвестный аргумент "${argument}"`) + } + } + + return options +} + +export const compileInputTokens = (): CompiledTokens => + compileTokens(loadTokenTree(INPUT_FILE)) + +const formatTokenIssues = (issues: GeneratedTokenIssues): string => + [ + issues.missing.length > 0 + ? `Отсутствуют: ${issues.missing.join(', ')}` + : '', + issues.changed.length > 0 ? `Изменены: ${issues.changed.join(', ')}` : '', + issues.unexpected.length > 0 + ? `Лишние: ${issues.unexpected.join(', ')}` + : '', + ] + .filter(Boolean) + .join('\n') + +export const run = async (arguments_: string[]): Promise => { + const options = parseArgs(arguments_) + + if (options.help) { + console.log(HELP) + + return + } + + const compiled = compileInputTokens() + + if (options.check) { + const issues = await findGeneratedTokenIssues(compiled, TOKENS_DIRECTORY) + const issueDescription = formatTokenIssues(issues) + + if (issueDescription) { + throw new Error( + `Сгенерированные токены неактуальны:\n${issueDescription}\n` + + 'Запустите yarn tokens:generate.' + ) + } + + console.log('Сгенерированные токены актуальны.') + + return + } + + await writeGeneratedTokens(compiled, TOKENS_DIRECTORY) + console.log(`Сгенерированные токены записаны в ${TOKENS_DIRECTORY}`) +} + +if (require.main === module) { + void run(process.argv.slice(2)).catch((error: unknown) => { + const message = error instanceof Error ? error.message : String(error) + console.error(message) + process.exitCode = 1 + }) +} diff --git a/scripts/token-generator/core/compiler.ts b/scripts/token-generator/core/compiler.ts new file mode 100644 index 00000000..4dfe18c0 --- /dev/null +++ b/scripts/token-generator/core/compiler.ts @@ -0,0 +1,272 @@ +import { isDeepStrictEqual } from 'node:util' + +import { normalizeTree } from './normalization' +import { resolveReferences } from './resolution' +import { mergeTrees, resolvePath } from './tree' +import { + isTokenTree, + type CompiledTokens, + type SemanticTokens, + type ThemeTokens, + type TokenTree, + type TokenValue, +} from './types' +import { assertSameShape, assertValidOutput } from './validation' + +type ColorScheme = keyof ThemeTokens + +const compileGroup = ( + input: TokenValue, + group: 'semantic' | 'components', + scheme: 'light' | 'dark' +): TokenTree => { + const normalized = normalizeTree(input, group) + + if (!isTokenTree(normalized)) { + throw new Error( + `Expected an object at "${group}" in ${scheme} input tokens` + ) + } + + assertValidOutput(normalized, `${scheme}.${group}`) + + return normalized +} + +const getGroup = ( + source: TokenTree, + group: 'primitive' | 'semantic' | 'components' +): TokenTree => { + const value = resolvePath(source, group) + + if (!isTokenTree(value)) { + throw new Error(`Expected an object at "${group}" in input tokens`) + } + + return value +} + +const compileFonts = (primitive: TokenTree): TokenTree => { + const fonts = resolvePath(primitive, 'fonts') + + if (!isTokenTree(fonts)) { + throw new Error('Expected an object at "primitive.fonts" in input tokens') + } + + const resolvedFonts = resolveReferences(fonts, primitive, 'fonts') + const normalizedFonts = normalizeTree(resolvedFonts, 'fonts') + + if (!isTokenTree(normalizedFonts)) { + throw new Error('Expected an object at "fonts" in output tokens') + } + + assertValidOutput(normalizedFonts, 'fonts') + + return normalizedFonts +} + +const selectColorScheme = ( + group: TokenTree, + scheme: ColorScheme, + tokenPath: string +): TokenTree => { + const { colorScheme } = group + const selectedScheme = isTokenTree(colorScheme) + ? colorScheme[scheme] + : undefined + + if (!isTokenTree(selectedScheme)) { + throw new Error( + `Expected an object at "${tokenPath}.colorScheme.${scheme}"` + ) + } + + return Object.fromEntries( + Object.entries(group).map(([key, value]) => [ + key, + key === 'colorScheme' ? mergeTrees({}, selectedScheme) : value, + ]) + ) +} + +const selectComponentColorSchemes = ( + components: TokenTree, + scheme: ColorScheme +): TokenTree => + Object.fromEntries( + Object.entries(components).map(([componentName, component]) => { + if (!isTokenTree(component)) { + throw new Error(`Expected an object at "components.${componentName}"`) + } + + const { colorScheme, ...base } = component + + if (colorScheme === undefined) { + return [componentName, mergeTrees({}, base)] + } + + const selectedScheme = isTokenTree(colorScheme) + ? colorScheme[scheme] + : undefined + + if (!isTokenTree(selectedScheme)) { + throw new Error( + `Expected an object at "components.${componentName}.colorScheme.${scheme}"` + ) + } + + return [ + componentName, + Object.fromEntries( + Object.entries(component).map(([key, value]) => [ + key, + key === 'colorScheme' ? mergeTrees({}, selectedScheme) : value, + ]) + ), + ] + }) + ) + +const unwrapColorScheme = (group: TokenTree, tokenPath: string): TokenTree => { + const { colorScheme, ...base } = group + + if (!isTokenTree(colorScheme)) { + throw new Error(`Expected an object at "${tokenPath}.colorScheme"`) + } + + return mergeTrees(base, colorScheme) +} + +const createReferenceRoot = ( + primitive: TokenTree, + semantic: TokenTree +): TokenTree => { + const duplicateKeys = Object.keys(primitive).filter((key) => key in semantic) + + if (duplicateKeys.length > 0) { + throw new Error( + `Duplicate primitive and semantic namespaces: ${duplicateKeys.join(', ')}` + ) + } + + return { ...primitive, ...semantic } +} + +const compileScheme = ( + primitive: TokenTree, + semanticSource: TokenTree, + componentsSource: TokenTree, + scheme: ColorScheme +): { semantic: TokenTree; components: TokenTree } => { + const selectedSemantic = selectColorScheme(semanticSource, scheme, 'semantic') + const semanticForReferences = unwrapColorScheme(selectedSemantic, 'semantic') + const semanticReferences = createReferenceRoot( + primitive, + semanticForReferences + ) + const resolvedSemanticForReferences = resolveReferences( + semanticForReferences, + semanticReferences, + `${scheme}.semantic` + ) + const resolvedSemantic = resolveReferences( + selectedSemantic, + semanticReferences, + `${scheme}.semantic` + ) + + if ( + !isTokenTree(resolvedSemantic) || + !isTokenTree(resolvedSemanticForReferences) + ) { + throw new Error(`Expected resolved semantic tokens for "${scheme}"`) + } + + const componentReferences = createReferenceRoot( + primitive, + resolvedSemanticForReferences + ) + const selectedComponents = selectComponentColorSchemes( + componentsSource, + scheme + ) + const resolvedComponents = resolveReferences( + selectedComponents, + componentReferences, + `${scheme}.components` + ) + + return { + semantic: compileGroup(resolvedSemantic, 'semantic', scheme), + components: compileGroup(resolvedComponents, 'components', scheme), + } +} + +const getSemanticGroup = ( + semantic: TokenTree, + group: 'colorScheme' | 'dimension' | 'effects', + scheme: ColorScheme +): TokenTree => { + const value = semantic[group] + + if (!isTokenTree(value)) { + throw new Error(`Expected an object at "${scheme}.semantic.${group}"`) + } + + return value +} + +const splitSemantic = (light: TokenTree, dark: TokenTree): SemanticTokens => { + const dimension = getSemanticGroup(light, 'dimension', 'light') + const darkDimension = getSemanticGroup(dark, 'dimension', 'dark') + const effects = getSemanticGroup(light, 'effects', 'light') + const darkEffects = getSemanticGroup(dark, 'effects', 'dark') + + if (!isDeepStrictEqual(dimension, darkDimension)) { + throw new Error( + 'Semantic "dimension" tokens must not depend on colorScheme' + ) + } + + if (!isDeepStrictEqual(effects, darkEffects)) { + throw new Error('Semantic "effects" tokens must not depend on colorScheme') + } + + return { + colorScheme: { + light: getSemanticGroup(light, 'colorScheme', 'light'), + dark: getSemanticGroup(dark, 'colorScheme', 'dark'), + }, + dimension, + effects, + } +} + +export const compileTokens = (source: TokenTree): CompiledTokens => { + const primitive = getGroup(source, 'primitive') + const semanticSource = getGroup(source, 'semantic') + const componentsSource = getGroup(source, 'components') + const fonts = compileFonts(primitive) + const light = compileScheme( + primitive, + semanticSource, + componentsSource, + 'light' + ) + const dark = compileScheme( + primitive, + semanticSource, + componentsSource, + 'dark' + ) + const components = { light: light.components, dark: dark.components } + + assertSameShape(light.semantic, dark.semantic) + assertSameShape(components.light, components.dark) + + return { + fonts, + semantic: splitSemantic(light.semantic, dark.semantic), + components, + } +} diff --git a/scripts/token-generator/core/normalization.ts b/scripts/token-generator/core/normalization.ts new file mode 100644 index 00000000..ee351b77 --- /dev/null +++ b/scripts/token-generator/core/normalization.ts @@ -0,0 +1,273 @@ +import { + isTokenTree, + type BoxEdges, + type TokenPrimitive, + type TokenTree, + type TokenValue, +} from './types' + +const REM_BASE = 16 +const NUMBER_SOURCE = '[+-]?(?:\\d+(?:\\.\\d*)?|\\.\\d+)' +const NUMBER_PATTERN = /^-?\d*\.?\d+$/ +const PIXEL_PATTERN = /^-?\d*\.?\d+px$/ +const SHADOW_LENGTH_PATTERN = /^(?:0|-?\d*\.?\d+(?:rem|px))$/ +const CUBIC_BEZIER_PATTERN = new RegExp( + `^cubic-bezier\\(\\s*(${NUMBER_SOURCE})\\s*,\\s*(${NUMBER_SOURCE})\\s*,\\s*(${NUMBER_SOURCE})\\s*,\\s*(${NUMBER_SOURCE})\\s*\\)$` +) +export const BOX_PROPERTIES = ['padding', 'margin', 'borderWidth'] as const + +export type BoxProperty = (typeof BOX_PROPERTIES)[number] + +export const isEasingTokenPath = (tokenPath: string): boolean => + /\.effects\.transition\.easing\.[^.]+$/.test(tokenPath) + +export const normalizeEasing = ( + value: TokenValue, + tokenPath = 'semantic.effects.transition.easing' +): TokenTree => { + if (typeof value !== 'string') { + throw new Error(`Expected easing string at "${tokenPath}"`) + } + + const easing = value.trim() + + if (easing === 'linear') return { x1: 0, y1: 0, x2: 1, y2: 1 } + + const match = CUBIC_BEZIER_PATTERN.exec(easing) + + if (!match) { + throw new Error(`Unsupported easing "${value}" at "${tokenPath}"`) + } + + const [, x1Source, y1Source, x2Source, y2Source] = match + const coordinates = [x1Source, y1Source, x2Source, y2Source].map(Number) + const [x1, y1, x2, y2] = coordinates + + if ( + coordinates.some((coordinate) => !Number.isFinite(coordinate)) || + x1 === undefined || + y1 === undefined || + x2 === undefined || + y2 === undefined + ) { + throw new Error(`Invalid easing "${value}" at "${tokenPath}"`) + } + + if (x1 < 0 || x1 > 1 || x2 < 0 || x2 > 1) { + throw new Error( + `Easing x coordinates must be between 0 and 1 at "${tokenPath}"` + ) + } + + return { x1, y1, x2, y2 } +} + +export const isBoxShadowValue = (value: string): boolean => { + const parts = value + .trim() + .split(/\s+(?![^(]*\))/) + .filter(Boolean) + const insetIndex = parts.indexOf('inset') + + if (insetIndex > 0 && insetIndex < parts.length - 1) return false + + const shadowParts = parts.filter((_, index) => index !== insetIndex) + const colorIndexes = shadowParts + .map((part, index) => (SHADOW_LENGTH_PATTERN.test(part) ? -1 : index)) + .filter((index) => index !== -1) + + if (colorIndexes.length !== 1) return false + + const [colorIndex] = colorIndexes + + if (colorIndex !== 0 && colorIndex !== shadowParts.length - 1) return false + + const lengths = shadowParts.filter((_, index) => index !== colorIndex) + + return ( + lengths.length >= 2 && + lengths.length <= 4 && + lengths.every((part) => SHADOW_LENGTH_PATTERN.test(part)) + ) +} + +export const convertUnit = ( + value: TokenPrimitive, + tokenPath = 'root' +): TokenPrimitive => { + if (typeof value !== 'string') return value + + const isRem = /^-?\d*\.?\d+rem$/.test(value) + + if (isRem) return Number(value.slice(0, -3)) * REM_BASE + + const isMilliseconds = /^-?\d*\.?\d+ms$/.test(value) + + if (isMilliseconds) return Number(value.slice(0, -2)) + + if (PIXEL_PATTERN.test(value)) return Number(value.slice(0, -2)) + + if (NUMBER_PATTERN.test(value)) return Number(value) + + const converted = value.replace(/-?\d*\.?\d+rem\b/g, (token) => { + const pixels = Number(token.slice(0, -3)) * REM_BASE + + return `${pixels}px` + }) + + if (converted !== value && !isBoxShadowValue(converted)) { + throw new Error( + `Unsupported composite unit value "${value}" at "${tokenPath}"` + ) + } + + return converted +} + +const parseBoxPart = (part: string, tokenPath: string): number => { + if (!/^-?\d*\.?\d+(?:rem|px)?$/.test(part)) { + throw new Error(`Invalid box value "${part}" at "${tokenPath}"`) + } + + const unit = part.endsWith('rem') ? 'rem' : part.endsWith('px') ? 'px' : '' + const value = Number(unit ? part.slice(0, -unit.length) : part) + const isRem = unit === 'rem' + const normalized = isRem ? value * REM_BASE : value + + if (!Number.isFinite(normalized)) { + throw new Error(`Non-finite box value "${part}" at "${tokenPath}"`) + } + + return normalized +} + +export const parseBoxShorthand = ( + value: string | number, + tokenPath = 'box' +): BoxEdges => { + const parts = + typeof value === 'number' + ? [value] + : value + .trim() + .split(/\s+/) + .filter(Boolean) + .map((part) => parseBoxPart(part, tokenPath)) + + if (parts.length === 0 || parts.length > 4) { + throw new Error(`Expected 1-4 box values at "${tokenPath}"`) + } + + const [top, right = top, bottom = top, left = right] = parts + + if ( + top === undefined || + right === undefined || + bottom === undefined || + left === undefined + ) { + throw new Error(`Unable to expand box value at "${tokenPath}"`) + } + + return { top, right, bottom, left } +} + +const normalizeBorderRadius = ( + value: string | number, + tokenPath: string +): number | TokenTree => { + const corners = parseBoxShorthand(value, tokenPath) + const values = Object.values(corners) + + if (values.every((corner) => corner === corners.top)) { + return corners.top + } + + return { + left: corners.left, + top: corners.top, + right: corners.right, + bottom: corners.bottom, + } +} + +const edgePropertyName = ( + property: BoxProperty, + edge: keyof BoxEdges +): string => { + const capitalizedEdge = `${edge[0].toUpperCase()}${edge.slice(1)}` + + return property === 'borderWidth' + ? `border${capitalizedEdge}Width` + : `${property}${capitalizedEdge}` +} + +const assignBoxEdges = ( + target: TokenTree, + source: TokenTree, + property: BoxProperty, + edges: BoxEdges, + tokenPath: string +): void => { + for (const [edge, edgeValue] of Object.entries(edges) as Array< + [keyof BoxEdges, number] + >) { + const edgeKey = edgePropertyName(property, edge) + + if (edgeKey in source || edgeKey in target) { + throw new Error(`Duplicate generated token "${tokenPath}.${edgeKey}"`) + } + + target[edgeKey] = edgeValue + } +} + +export const normalizeTree = ( + node: TokenValue, + tokenPath = 'root' +): TokenValue => { + if (isEasingTokenPath(tokenPath)) { + return normalizeEasing(node, tokenPath) + } + + if (Array.isArray(node)) { + return node.map((item, index) => + normalizeTree(item, `${tokenPath}.${index}`) + ) + } + + if (!isTokenTree(node)) return convertUnit(node, tokenPath) + + const normalized: TokenTree = {} + + for (const [key, value] of Object.entries(node)) { + const currentPath = `${tokenPath}.${key}` + const boxProperty = BOX_PROPERTIES.find((property) => property === key) + + if ( + key === 'borderRadius' && + (typeof value === 'string' || typeof value === 'number') + ) { + normalized[key] = normalizeBorderRadius(value, currentPath) + } else if ( + boxProperty && + (typeof value === 'string' || typeof value === 'number') + ) { + const edges = parseBoxShorthand(value, currentPath) + const partCount = + typeof value === 'number' + ? 1 + : value.trim().split(/\s+/).filter(Boolean).length + + if (partCount === 1) { + normalized[key] = edges.top + } else { + assignBoxEdges(normalized, node, boxProperty, edges, currentPath) + } + } else { + normalized[key] = normalizeTree(value, currentPath) + } + } + + return normalized +} diff --git a/scripts/token-generator/core/resolution.ts b/scripts/token-generator/core/resolution.ts new file mode 100644 index 00000000..42078ff6 --- /dev/null +++ b/scripts/token-generator/core/resolution.ts @@ -0,0 +1,99 @@ +import { resolvePath } from './tree' +import { isTokenTree, type TokenTree, type TokenValue } from './types' + +const EXACT_REFERENCE_PATTERN = /^\{[^{}]+\}$/ +const REFERENCE_PATTERN = /\{[^{}]+\}/g + +const stringifyReference = ( + value: TokenValue, + reference: string, + tokenPath: string +): string => { + if (value === null || Array.isArray(value) || isTokenTree(value)) { + throw new Error( + `Reference "${reference}" at "${tokenPath}" cannot be embedded in a string` + ) + } + + return String(value) +} + +export const resolveReferences = ( + node: TokenValue, + referenceRoot: TokenTree, + tokenPath = 'root' +): TokenValue => { + const cache = new Map() + + const resolveReference = ( + reference: string, + sourcePath: string, + stack: string[] + ): TokenValue => { + if (stack.includes(reference)) { + throw new Error( + `Circular token reference at "${sourcePath}": ${[ + ...stack, + reference, + ].join(' -> ')}` + ) + } + + const cached = cache.get(reference) + + if (cached !== undefined) return cached + + const referencedValue = resolvePath( + referenceRoot, + reference, + `references for "${sourcePath}"` + ) + const resolved = resolveNode(referencedValue, reference, [ + ...stack, + reference, + ]) + + cache.set(reference, resolved) + + return resolved + } + + const resolveNode = ( + value: TokenValue, + currentPath: string, + stack: string[] + ): TokenValue => { + if (Array.isArray(value)) { + return value.map((item, index) => + resolveNode(item, `${currentPath}.${index}`, stack) + ) + } + + if (isTokenTree(value)) { + return Object.fromEntries( + Object.entries(value).map(([key, nestedValue]) => [ + key, + resolveNode(nestedValue, `${currentPath}.${key}`, stack), + ]) + ) + } + + if (typeof value !== 'string') return value + + if (EXACT_REFERENCE_PATTERN.test(value)) { + return resolveReference(value.slice(1, -1), currentPath, stack) + } + + return value.replace(REFERENCE_PATTERN, (token) => { + const reference = token.slice(1, -1) + + return stringifyReference( + resolveReference(reference, currentPath, stack), + reference, + currentPath + ) + }) + } + + return resolveNode(node, tokenPath, []) +} diff --git a/scripts/token-generator/core/tree.ts b/scripts/token-generator/core/tree.ts new file mode 100644 index 00000000..e8141baa --- /dev/null +++ b/scripts/token-generator/core/tree.ts @@ -0,0 +1,49 @@ +import { isTokenTree, type TokenTree, type TokenValue } from './types' + +const cloneValue = (value: TokenValue): TokenValue => { + if (Array.isArray(value)) return value.map(cloneValue) + + if (isTokenTree(value)) { + return Object.fromEntries( + Object.entries(value).map(([key, nestedValue]) => [ + key, + cloneValue(nestedValue), + ]) + ) + } + + return value +} + +export const mergeTrees = (base: TokenTree, override: TokenTree): TokenTree => { + const result = cloneValue(base) as TokenTree + + for (const [key, value] of Object.entries(override)) { + const current = result[key] + + result[key] = + isTokenTree(current) && isTokenTree(value) + ? mergeTrees(current, value) + : cloneValue(value) + } + + return result +} + +export const resolvePath = ( + source: TokenTree, + tokenPath: string, + context = 'input tokens' +): TokenValue => { + let current: TokenValue = source + + for (const segment of tokenPath.split('.')) { + if (!isTokenTree(current) || !(segment in current)) { + throw new Error(`Missing "${tokenPath}" in ${context}`) + } + + current = current[segment] + } + + return current +} diff --git a/scripts/token-generator/core/types.ts b/scripts/token-generator/core/types.ts new file mode 100644 index 00000000..89522e41 --- /dev/null +++ b/scripts/token-generator/core/types.ts @@ -0,0 +1,33 @@ +export type TokenPrimitive = string | number | boolean | null +export type TokenValue = TokenPrimitive | TokenTree | TokenValue[] + +export interface TokenTree { + [key: string]: TokenValue +} + +export interface BoxEdges { + top: number + right: number + bottom: number + left: number +} + +export interface CompiledTokens { + fonts: TokenTree + semantic: SemanticTokens + components: ThemeTokens +} + +export interface SemanticTokens { + colorScheme: ThemeTokens + dimension: TokenTree + effects: TokenTree +} + +export interface ThemeTokens { + light: TokenTree + dark: TokenTree +} + +export const isTokenTree = (value: unknown): value is TokenTree => + typeof value === 'object' && value !== null && !Array.isArray(value) diff --git a/scripts/token-generator/core/validation.ts b/scripts/token-generator/core/validation.ts new file mode 100644 index 00000000..d93dcdec --- /dev/null +++ b/scripts/token-generator/core/validation.ts @@ -0,0 +1,97 @@ +import { + BOX_PROPERTIES, + isEasingTokenPath, + isBoxShadowValue, + type BoxProperty, +} from './normalization' +import { isTokenTree, type TokenTree, type TokenValue } from './types' + +const REFERENCE_PATTERN = /\{[^}]+\}/ +const UNCONVERTED_UNIT_PATTERN = /-?\d*\.?\d+(?:rem|ms)\b/ +const PIXEL_PATTERN = /-?\d*\.?\d+px\b/ +const NUMERIC_STRING_PATTERN = /^-?\d*\.?\d+$/ +const CUBIC_BEZIER_PATTERN = /cubic-bezier\s*\(/ + +export const assertValidOutput = ( + node: TokenValue, + tokenPath: string +): void => { + if (Array.isArray(node)) { + node.forEach((item, index) => + assertValidOutput(item, `${tokenPath}.${index}`) + ) + + return + } + + if (isTokenTree(node)) { + for (const [key, value] of Object.entries(node)) { + if ( + (BOX_PROPERTIES.includes(key as BoxProperty) || + key === 'borderRadius') && + typeof value === 'string' + ) { + throw new Error(`Unconverted box shorthand at "${tokenPath}.${key}"`) + } + + assertValidOutput(value, `${tokenPath}.${key}`) + } + + return + } + + if (typeof node === 'number' && !Number.isFinite(node)) { + throw new Error(`Non-finite number at "${tokenPath}"`) + } + + if (typeof node === 'string') { + const hasUnconvertedValue = + REFERENCE_PATTERN.test(node) || + UNCONVERTED_UNIT_PATTERN.test(node) || + (PIXEL_PATTERN.test(node) && !isBoxShadowValue(node)) || + NUMERIC_STRING_PATTERN.test(node) || + CUBIC_BEZIER_PATTERN.test(node) || + (node === 'linear' && isEasingTokenPath(tokenPath)) + + if (hasUnconvertedValue) { + throw new Error(`Unconverted token "${node}" at "${tokenPath}"`) + } + } +} + +const collectShape = ( + node: TokenValue, + tokenPath = 'root', + shape: string[] = [] +): string[] => { + if (Array.isArray(node)) { + shape.push(`${tokenPath}:array`) + node.forEach((item, index) => + collectShape(item, `${tokenPath}.${index}`, shape) + ) + + return shape + } + + if (isTokenTree(node)) { + shape.push(`${tokenPath}:object`) + Object.entries(node).forEach(([key, value]) => + collectShape(value, `${tokenPath}.${key}`, shape) + ) + + return shape + } + + shape.push(`${tokenPath}:${node === null ? 'null' : typeof node}`) + + return shape +} + +export const assertSameShape = (light: TokenTree, dark: TokenTree): void => { + const lightShape = collectShape(light).sort() + const darkShape = collectShape(dark).sort() + + if (JSON.stringify(lightShape) !== JSON.stringify(darkShape)) { + throw new Error('Light and dark runtime tokens have different shapes') + } +} diff --git a/scripts/token-generator/io.ts b/scripts/token-generator/io.ts new file mode 100644 index 00000000..63974c4b --- /dev/null +++ b/scripts/token-generator/io.ts @@ -0,0 +1,160 @@ +import { + readFileSync, + readdirSync, + mkdirSync, + writeFileSync, + renameSync, + existsSync, + unlinkSync, +} from 'node:fs' +import { dirname, join } from 'node:path' + +import { format, resolveConfig, type Options } from 'prettier' + +import { isTokenTree, type CompiledTokens, type TokenTree } from './core/types' + +export const OUTPUT_FILES = { + fonts: 'fonts.json', + semantic: { + colorScheme: { + light: join('semantic', 'colorScheme', 'light.json'), + dark: join('semantic', 'colorScheme', 'dark.json'), + }, + dimensions: join('semantic', 'dimensions.json'), + effects: join('semantic', 'effects.json'), + }, + components: { + light: join('components', 'light.json'), + dark: join('components', 'dark.json'), + }, +} as const + +export const parseTokenTree = ( + contents: string, + filePath: string +): TokenTree => { + const parsed: unknown = JSON.parse(contents) + + if (!isTokenTree(parsed)) { + throw new Error(`Expected an object in "${filePath}"`) + } + + return parsed +} + +export const loadTokenTree = (filePath: string): TokenTree => + parseTokenTree(readFileSync(filePath, 'utf8'), filePath) + +export const renderJson = ( + value: TokenTree, + options: Options = {} +): Promise => + format(JSON.stringify(value), { ...options, parser: 'json' }) + +const outputEntries = ( + compiled: CompiledTokens +): Array<[string, TokenTree]> => [ + [OUTPUT_FILES.fonts, compiled.fonts], + [ + OUTPUT_FILES.semantic.colorScheme.light, + compiled.semantic.colorScheme.light, + ], + [OUTPUT_FILES.semantic.colorScheme.dark, compiled.semantic.colorScheme.dark], + [OUTPUT_FILES.semantic.dimensions, compiled.semantic.dimension], + [OUTPUT_FILES.semantic.effects, compiled.semantic.effects], + [OUTPUT_FILES.components.light, compiled.components.light], + [OUTPUT_FILES.components.dark, compiled.components.dark], +] + +const renderOutputEntries = async ( + compiled: CompiledTokens, + outputDirectory: string +): Promise> => { + const options = + (await resolveConfig(join(outputDirectory, OUTPUT_FILES.fonts))) ?? {} + + return Promise.all( + outputEntries(compiled).map(async ([fileName, value]) => [ + fileName, + await renderJson(value, options), + ]) + ) +} + +export const writeGeneratedTokens = async ( + compiled: CompiledTokens, + outputDirectory: string +): Promise => { + const entries = await renderOutputEntries(compiled, outputDirectory) + + mkdirSync(outputDirectory, { recursive: true }) + + const expectedFiles = new Set(entries.map(([fileName]) => fileName)) + + for (const fileName of findJsonFiles(outputDirectory)) { + if (!expectedFiles.has(fileName)) { + unlinkSync(join(outputDirectory, fileName)) + } + } + + for (const [fileName, contents] of entries) { + const outputPath = join(outputDirectory, fileName) + const temporaryPath = `${outputPath}.tmp` + + mkdirSync(dirname(outputPath), { recursive: true }) + writeFileSync(temporaryPath, contents) + renameSync(temporaryPath, outputPath) + } +} + +const findJsonFiles = (directory: string, prefix = ''): string[] => { + if (!existsSync(directory)) return [] + + return readdirSync(directory, { withFileTypes: true }) + .flatMap((entry) => { + const relativePath = join(prefix, entry.name) + + if (entry.isDirectory()) { + return findJsonFiles(join(directory, entry.name), relativePath) + } + + return entry.isFile() && entry.name.endsWith('.json') + ? [relativePath] + : [] + }) + .sort() +} + +export interface GeneratedTokenIssues { + missing: string[] + changed: string[] + unexpected: string[] +} + +export const findGeneratedTokenIssues = async ( + compiled: CompiledTokens, + outputDirectory: string +): Promise => { + const entries = await renderOutputEntries(compiled, outputDirectory) + const expectedFiles = new Set(entries.map(([fileName]) => fileName)) + const missing: string[] = [] + const changed: string[] = [] + + for (const [fileName, contents] of entries) { + const outputPath = join(outputDirectory, fileName) + + if (existsSync(outputPath)) { + if (readFileSync(outputPath, 'utf8') !== contents) { + changed.push(fileName) + } + } else { + missing.push(fileName) + } + } + + const unexpected = findJsonFiles(outputDirectory).filter( + (fileName) => !expectedFiles.has(fileName) + ) + + return { missing, changed, unexpected } +} diff --git a/scripts/token-generator/tsconfig.json b/scripts/token-generator/tsconfig.json new file mode 100644 index 00000000..e2005382 --- /dev/null +++ b/scripts/token-generator/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "module": "NodeNext", + "moduleResolution": "NodeNext", + "noEmit": true, + "types": ["jest", "node"] + }, + "include": ["**/*.ts"], + "exclude": [] +} diff --git a/src/components/Accordion/Accordion.tsx b/src/components/Accordion/Accordion.tsx index 76ffb39e..64b220bf 100644 --- a/src/components/Accordion/Accordion.tsx +++ b/src/components/Accordion/Accordion.tsx @@ -39,6 +39,7 @@ export interface AccordionProps extends ViewProps { * @param withSeparator - Наличие разделитель. Когда true, верхняя граница заголовка становится разделителем * @param disabled - Отключенное состояние. Когда true компонент рендерится в соответствии со значением isInitiallyExpanded и не реагирует на нажатия * @link https://www.figma.com/design/4TYeki0MDLhfPGJstbIicf/UI-kit-PrimeFace--DS-?node-id=1207-1852&m=dev + * @link https://www.figma.com/design/Q1BWgZ7zoV5UzlBOnjW0cM/UI-Kit--DS--v2.1?node-id=24043-1592 */ export const Accordion: React.FC = ({ Icon, @@ -109,9 +110,9 @@ export const Accordion: React.FC = ({ ({ - color: theme.Panel.Accordion.accordionHeaderTextColor, - })} + uniProps={({ components }) => { + return { color: components.accordion.header.color } + }} /> {Icon ? ( @@ -119,9 +120,9 @@ export const Accordion: React.FC = ({ {...styles.icon} source={Icon} testID={AccordionTestIds.icon} - uniProps={({ theme }) => ({ - color: theme.Panel.Accordion.accordionHeaderTextColor, - })} + uniProps={({ components }) => { + return { color: components.accordion.header.color } + }} /> ) : null} {title} @@ -159,36 +160,42 @@ export const AccordionTestIds = { separator: 'Separator', } -const styles = StyleSheet.create(({ theme, fonts }) => ({ +const styles = StyleSheet.create(({ components, semantic, fonts }) => ({ component: { width: '100%' }, header: { - paddingVertical: theme.Panel.Accordion.accordionHeaderPaddingTopBottom, - gap: 7, + paddingVertical: semantic.dimension.space[400], + gap: components.accordion.extend.extHeader.gap, flexDirection: 'row', alignItems: 'center', - backgroundColor: theme.Panel.Accordion.accordionHeaderBg, + backgroundColor: components.accordion.colorScheme.header.background, + }, + icon: { + width: components.accordion.extend.extHeader.iconSize, + height: components.accordion.extend.extHeader.iconSize, }, - icon: { width: 17.5, height: 17.5 }, title: { - fontSize: 15.75, + fontSize: fonts.fontSize[400], includeFontPadding: false, verticalAlign: 'middle', - fontWeight: 700, - color: theme.Panel.Accordion.accordionHeaderTextColor, - fontFamily: fonts.secondary, + fontWeight: fonts.fontWeight.bold, + color: components.accordion.header.color, + fontFamily: fonts.fontFamily.base, }, contentAnimated: { overflow: 'hidden' }, contentWrapper: { position: 'absolute', width: '100%', - paddingLeft: theme.Panel.Accordion.accordionContentPaddingLeft, - paddingTop: theme.Panel.Accordion.accordionContentPaddingTop, - paddingRight: theme.Panel.Accordion.accordionContentPaddingRight, - paddingBottom: theme.Panel.Accordion.accordionContentPaddingBottom, + paddingLeft: components.accordion.content.paddingLeft, + paddingTop: semantic.dimension.space.none, + paddingRight: components.accordion.content.paddingRight, + paddingBottom: semantic.dimension.space[400], }, separator: { - borderTopColor: theme.Panel.Accordion.accordionHeaderBorderColor, + borderTopColor: components.accordion.panel.borderColor, borderTopWidth: 1, }, - disabled: { mixBlendMode: 'luminosity', opacity: 0.6 }, + disabled: { + mixBlendMode: 'luminosity', + opacity: semantic.effects.opacity[60], + }, })) diff --git a/src/components/Accordion/__tests__/__snapshots__/Accordion.test.tsx.snap b/src/components/Accordion/__tests__/__snapshots__/Accordion.test.tsx.snap index 04669b17..a1483e18 100644 --- a/src/components/Accordion/__tests__/__snapshots__/Accordion.test.tsx.snap +++ b/src/components/Accordion/__tests__/__snapshots__/Accordion.test.tsx.snap @@ -8,7 +8,7 @@ exports[`Accordion Header elements maximal 1`] = ` "width": "100%", }, { - "borderTopColor": "#e2e2e4", + "borderTopColor": "#cecfd2", "borderTopWidth": 1, }, ] @@ -51,9 +51,9 @@ exports[`Accordion Header elements maximal 1`] = ` [ { "alignItems": "center", - "backgroundColor": "rgba(255, 255, 255, 0.0001)", + "backgroundColor": "transparent", "flexDirection": "row", - "gap": 7, + "gap": 8, "paddingVertical": 14, }, {}, @@ -95,15 +95,15 @@ exports[`Accordion Header elements maximal 1`] = ` > ( ({ @@ -188,9 +189,9 @@ export const Avatar = memo( height={iconSize} source={Icon} testID={AvatarTestId.icon} - uniProps={({ theme }) => ({ - color: iconColor ?? theme.Misc.Avatar.avatarTextColor, - })} + uniProps={({ components }) => { + return { color: iconColor ?? components.avatar.root.color } + }} width={iconSize} /> ) @@ -257,30 +258,30 @@ export const Avatar = memo( } ) -const styles = StyleSheet.create(({ theme, border, typography, fonts }) => ({ +const styles = StyleSheet.create(({ components, semantic, fonts }) => ({ container: { justifyContent: 'center', alignItems: 'center', - borderRadius: theme.General.borderRadiusXL, - borderWidth: 1, - borderColor: theme.Misc.Avatar.avatarBorderColor, - backgroundColor: theme.Misc.Avatar.avatarBg, + borderRadius: components.avatar.root.borderRadius, + borderWidth: semantic.dimension.borderWidth[100], + borderColor: components.avatar.extend.borderColor, + backgroundColor: components.avatar.root.background, overflow: 'hidden', }, - backgroundFill: { backgroundColor: theme.Misc.Avatar.avatarBg }, - circle: { borderRadius: border.Radius['rounded-full'] }, + backgroundFill: { backgroundColor: components.avatar.root.background }, + circle: { borderRadius: components.avatar.extend.circle.borderRadius }, text: { - fontSize: typography.Size['text-base'], + fontSize: components.avatar.root.fontSize, textTransform: 'uppercase', - color: theme.Misc.Avatar.avatarTextColor, + color: components.avatar.root.color, includeFontPadding: false, verticalAlign: 'middle', - fontFamily: fonts.secondary, + fontFamily: fonts.fontFamily.base, }, badgeContainer: { position: 'absolute', right: 0, top: -7 }, badgeMeasureContainer: { alignSelf: 'flex-start' }, - icon: { width: typography.Size['text-base'] }, - iconXLarge: { width: typography.Size['text-2xl'] }, + icon: { width: components.avatar.icon.size }, + iconXLarge: { width: components.avatar.xl.icon.size }, })) export const AvatarTestId = { diff --git a/src/components/Avatar/__tests__/__snapshots__/Avatar.test.tsx.snap b/src/components/Avatar/__tests__/__snapshots__/Avatar.test.tsx.snap index 81e73a20..e1133de7 100644 --- a/src/components/Avatar/__tests__/__snapshots__/Avatar.test.tsx.snap +++ b/src/components/Avatar/__tests__/__snapshots__/Avatar.test.tsx.snap @@ -11,8 +11,8 @@ exports[`Avatar component tests Size: custom, shape: circle, type: icon, with cu { "alignItems": "center", "backgroundColor": "#44e858", - "borderColor": "#e2e2e4", - "borderRadius": 10.5, + "borderColor": "#ffffff", + "borderRadius": 14, "borderWidth": 1, "justifyContent": "center", "overflow": "hidden", @@ -25,7 +25,7 @@ exports[`Avatar component tests Size: custom, shape: circle, type: icon, with cu "backgroundColor": "#44e858", }, { - "borderRadius": 100, + "borderRadius": 1600, }, undefined, ] @@ -149,8 +149,8 @@ exports[`Avatar component tests Size: large, shape: circle, type: icon 1`] = ` { "alignItems": "center", "backgroundColor": "#44e858", - "borderColor": "#e2e2e4", - "borderRadius": 10.5, + "borderColor": "#ffffff", + "borderRadius": 14, "borderWidth": 1, "justifyContent": "center", "overflow": "hidden", @@ -163,7 +163,7 @@ exports[`Avatar component tests Size: large, shape: circle, type: icon 1`] = ` "backgroundColor": "#44e858", }, { - "borderRadius": 100, + "borderRadius": 1600, }, undefined, ] @@ -172,15 +172,15 @@ exports[`Avatar component tests Size: large, shape: circle, type: icon 1`] = ` > = { - title: 'Misc/Badge', - component: Badge, - args: { severity: 'basic', dot: false, children: 'Test' }, - argTypes: { - severity: { - control: 'radio', - options: ['basic', 'info', 'success', 'warning', 'danger'], - }, - }, -} - -export default meta - -type Story = StoryObj - -const BadgeStory: Story = { args: { children: 'Test' }, argTypes: {} } - -export { BadgeStory as Badge } diff --git a/src/components/Badge/Badge.stories.tsx b/src/components/Badge/Badge.stories.tsx new file mode 100644 index 00000000..e6111955 --- /dev/null +++ b/src/components/Badge/Badge.stories.tsx @@ -0,0 +1,48 @@ +import type { Meta, StoryObj } from '@storybook/react' +import { StyleSheet, View } from 'react-native' + +import { Body } from '../Typography' + +import { Badge } from './Badge' + +const styles = StyleSheet.create({ + container: { gap: 16 }, + example: { gap: 8 }, +}) + +const meta: Meta = { + title: 'Misc/Badge', + component: Badge, + args: { children: 'Badge', severity: 'basic', size: 'base' }, + argTypes: { + children: { control: 'text' }, + severity: { + control: 'radio', + options: ['basic', 'info', 'success', 'warning', 'danger'], + }, + size: { control: 'radio', options: ['base', 'large', 'xlarge'] }, + }, + parameters: { controls: { exclude: ['dot'] } }, + render: ({ children = 'Badge', severity, size }) => ( + + + Severity + + {children} + + + + Dot + + + + ), +} + +export default meta + +type Story = StoryObj + +const BadgeStory: Story = {} + +export { BadgeStory as Badge } diff --git a/src/components/Badge/Badge.tsx b/src/components/Badge/Badge.tsx index 8b0e5f6a..eac73773 100644 --- a/src/components/Badge/Badge.tsx +++ b/src/components/Badge/Badge.tsx @@ -22,6 +22,11 @@ export interface BadgeBase * @default 'basic' */ severity?: BadgeSeverity + /** + * Выбор размера компонента + * @default 'base' + */ + size?: 'base' | 'large' | 'xlarge' /** Дополнительная стилизация для контейнера компонента */ style?: StyleProp } @@ -46,13 +51,22 @@ export type BadgeProps = BadgeText | BadgeDot * Компонент Badge * @param children - Текст внутри бейджа * @param dot - Отображать бейдж в форме точки - * @param severiy - Выбор варианта стиля компонента + * @param severity - Выбор варианта стиля компонента + * @param size - Выбор размера компонента * @param style - Дополнительная стилизация для контейнера компонента - * @link https://www.figma.com/design/4TYeki0MDLhfPGJstbIicf/UI-kit-PrimeFace-(DS)?node-id=484-4871&m=dev + * @link https://www.figma.com/design/Q1BWgZ7zoV5UzlBOnjW0cM/UI-Kit--DS--v2.1?node-id=24043-13668 */ export const Badge = memo( - ({ children, dot, severity = 'basic', style, testID, ...rest }) => { - badgeStyles.useVariants({ severity }) + ({ + children, + dot, + severity = 'basic', + size = 'base', + style, + testID, + ...rest + }) => { + badgeStyles.useVariants({ severity, size }) const [textLayout, setTextLayout] = useState() const onTextLayout = useCallback((e: LayoutChangeEvent) => { @@ -68,10 +82,7 @@ export const Badge = memo( /> ) : ( <> - + ( } ) -const badgeStyles = StyleSheet.create( - ({ theme, border, typography, fonts }) => ({ - container: { alignItems: 'flex-start' }, - dot: { - variants: { - severity: { - basic: { backgroundColor: theme.Misc.Badge.badgeBg }, - info: { - backgroundColor: theme.Button.Severity.Info.Basic.infoButtonBg, - }, - success: { - backgroundColor: - theme.Button.Severity.Success.Basic.successButtonBg, - }, - warning: { - backgroundColor: - theme.Button.Severity.Warning.Basic.warningButtonBg, - }, - danger: { - backgroundColor: theme.Button.Severity.Danger.Basic.dangerButtonBg, - }, +const badgeStyles = StyleSheet.create(({ components, semantic, fonts }) => ({ + container: { alignItems: 'flex-start' }, + dot: { + variants: { + severity: { + basic: { + backgroundColor: components.badge.colorScheme.primary.background, + }, + info: { + backgroundColor: components.badge.extend.extDot.info.background, + }, + success: { + backgroundColor: components.badge.extend.extDot.success.background, + }, + warning: { + backgroundColor: components.badge.extend.extDot.warn.background, + }, + danger: { + backgroundColor: components.badge.extend.extDot.danger.background, }, }, }, - dotShape: { - width: theme.Misc.Badge.badgeDotSize, - height: theme.Misc.Badge.badgeDotSize, - borderRadius: border.Radius['rounded-full'], - }, - textBadgeContainer: { - height: theme.Misc.Badge.badgeHeight, - paddingHorizontal: theme.Misc.Tag.tagPadding, - justifyContent: 'center', - borderRadius: border.Radius['rounded-full'], + }, + dotShape: { + width: components.badge.dot.size, + height: components.badge.dot.size, + borderRadius: semantic.dimension.borderRadius.max, + borderWidth: components.overlaybadge.root.outline.width, + borderColor: components.overlaybadge.root.outline.color, + variants: { + size: { + base: {}, + large: { + width: components.badge.extend.extDot.lg.size, + height: components.badge.extend.extDot.lg.size, + }, + xlarge: { + width: components.badge.extend.extDot.xlg.size, + height: components.badge.extend.extDot.xlg.size, + }, + }, }, - textBadge: { - color: theme.Misc.Badge.badgeTextColor, - fontSize: typography.Size['text-xs'], - includeFontPadding: false, - verticalAlign: 'middle', - fontFamily: fonts.primary, + }, + textBadgeContainer: { + height: components.badge.root.height, + minWidth: components.badge.root.minWidth, + paddingHorizontal: components.badge.root.padding, + justifyContent: 'center', + borderRadius: components.badge.root.borderRadius, + borderWidth: components.overlaybadge.root.outline.width, + borderColor: components.overlaybadge.root.outline.color, + variants: { + severity: { + basic: { + backgroundColor: components.badge.colorScheme.primary.background, + }, + info: { backgroundColor: components.badge.colorScheme.info.background }, + success: { + backgroundColor: components.badge.colorScheme.success.background, + }, + warning: { + backgroundColor: components.badge.colorScheme.warn.background, + }, + danger: { + backgroundColor: components.badge.colorScheme.danger.background, + }, + }, + size: { + base: {}, + large: { + height: components.badge.lg.height, + minWidth: components.badge.lg.minWidth, + }, + xlarge: { + height: components.badge.xl.height, + minWidth: components.badge.xl.minWidth, + }, + }, }, - hiddenContainer: { - width: Dimensions.get('window').width, - height: 0, - flexDirection: 'row', - position: 'absolute', + }, + textBadge: { + color: components.badge.colorScheme.primary.color, + fontSize: components.badge.root.fontSize, + fontWeight: fonts.fontWeight.regular, + lineHeight: fonts.lineHeight[100], + letterSpacing: fonts.letterSpacing[500], + includeFontPadding: false, + verticalAlign: 'middle', + fontFamily: fonts.fontFamily.heading, + variants: { + severity: { + basic: { color: components.badge.colorScheme.primary.color }, + info: { color: components.badge.colorScheme.info.color }, + success: { color: components.badge.colorScheme.success.color }, + warning: { color: components.badge.colorScheme.warn.color }, + danger: { color: components.badge.colorScheme.danger.color }, + }, + size: { + base: {}, + large: {}, + xlarge: { lineHeight: fonts.lineHeight[350] }, + }, }, - }) -) + }, + hiddenContainer: { + width: Dimensions.get('window').width, + height: 0, + flexDirection: 'row', + position: 'absolute', + }, +})) diff --git a/src/components/Badge/__tests__/Badge.test.tsx b/src/components/Badge/__tests__/Badge.test.tsx index 0fcac425..8f3e605a 100644 --- a/src/components/Badge/__tests__/Badge.test.tsx +++ b/src/components/Badge/__tests__/Badge.test.tsx @@ -1,29 +1,53 @@ import { render } from '@testing-library/react-native' -import { Badge, type BadgeProps } from '../Badge' - -describe('Badge component tests', () => { - const snapshotCases: Array<[string, BadgeProps]> = [ - ['dot, severity: basic', { dot: true, severity: 'basic' }], - ['dot, severity: info', { dot: true, severity: 'info' }], - ['dot, severity: success', { dot: true, severity: 'success' }], - ['dot, severity: warning', { dot: true, severity: 'warning' }], - ['dot, severity: danger', { dot: true, severity: 'danger' }], - ['severity: basic', { children: '12', severity: 'basic' }], - ['severity: basic', { children: '12', severity: 'info' }], - ['severity: basic', { children: '12', severity: 'success' }], - ['severity: basic', { children: '12', severity: 'warning' }], - ['severity: basic', { children: '12', severity: 'danger' }], - ['severity: default', { children: '12' }], - [ - 'with custom style', - { dot: true, severity: 'basic', style: { margin: 10 } }, - ], +import { Badge, type BadgeSeverity } from '../Badge' + +describe('Badge', () => { + const severities: BadgeSeverity[] = [ + 'basic', + 'info', + 'success', + 'warning', + 'danger', ] - test.each(snapshotCases)('%s', (_, props) => { - const renderedBadge = render() + test.each(severities)( + 'отображает переданный текст для severity %s', + (severity) => { + const { getByText } = render(12) + + expect(getByText('12')).toBeOnTheScreen() + } + ) - expect(renderedBadge.toJSON()).toMatchSnapshot() + test.each(severities)('отображает dot для severity %s', (severity) => { + const { getByTestId, queryByText } = render( + + ) + + expect(getByTestId('Badge')).toBeOnTheScreen() + expect(queryByText('12')).not.toBeOnTheScreen() }) + + test.each(['large', 'xlarge'] as const)( + 'отображает переданный текст для размера %s', + (size) => { + const { getByText } = render( + + 12 + + ) + + expect(getByText('12')).toBeOnTheScreen() + } + ) + + test.each(['large', 'xlarge'] as const)( + 'отображает dot-вариант для размера %s', + (size) => { + const { getByTestId } = render() + + expect(getByTestId('Badge')).toBeOnTheScreen() + } + ) }) diff --git a/src/components/Badge/__tests__/__snapshots__/Badge.test.tsx.snap b/src/components/Badge/__tests__/__snapshots__/Badge.test.tsx.snap deleted file mode 100644 index e4b181ae..00000000 --- a/src/components/Badge/__tests__/__snapshots__/Badge.test.tsx.snap +++ /dev/null @@ -1,657 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Badge component tests dot, severity: basic 1`] = ` - - - -`; - -exports[`Badge component tests dot, severity: danger 1`] = ` - - - -`; - -exports[`Badge component tests dot, severity: info 1`] = ` - - - -`; - -exports[`Badge component tests dot, severity: success 1`] = ` - - - -`; - -exports[`Badge component tests dot, severity: warning 1`] = ` - - - -`; - -exports[`Badge component tests severity: basic 1`] = ` - - - - 12 - - - - - - 12 - - - - -`; - -exports[`Badge component tests severity: basic 2`] = ` - - - - 12 - - - - - - 12 - - - - -`; - -exports[`Badge component tests severity: basic 3`] = ` - - - - 12 - - - - - - 12 - - - - -`; - -exports[`Badge component tests severity: basic 4`] = ` - - - - 12 - - - - - - 12 - - - - -`; - -exports[`Badge component tests severity: basic 5`] = ` - - - - 12 - - - - - - 12 - - - - -`; - -exports[`Badge component tests severity: default 1`] = ` - - - - 12 - - - - - - 12 - - - - -`; - -exports[`Badge component tests with custom style 1`] = ` - - - -`; diff --git a/src/components/Button/Button.stories.ts b/src/components/Button/Button.stories.tsx similarity index 53% rename from src/components/Button/Button.stories.ts rename to src/components/Button/Button.stories.tsx index 7c3d9298..24dac296 100644 --- a/src/components/Button/Button.stories.ts +++ b/src/components/Button/Button.stories.tsx @@ -3,10 +3,18 @@ import { IconArrowDownRight, IconArrowDownLeft, } from '@tabler/icons-react-native' +import { StyleSheet, View } from 'react-native' + +import { Body } from '../Typography' import { Button } from './Button' +import type { ButtonBaseVariant, ButtonProps } from './types' const Icons = { IconArrowDownRight, IconArrowDownLeft, undefined } +const styles = StyleSheet.create({ + container: { gap: 16 }, + example: { gap: 8 }, +}) const meta: Meta = { title: 'Button', @@ -31,13 +39,41 @@ const meta: Meta = { disabled: { control: 'boolean' }, iconPosition: { control: 'radio', options: ['prefix', 'postfix'] }, onPress: { action: 'OnPress' }, - iconOnly: { - control: 'radio', - options: ['IconOnly', 'Not IconOnly'], - mapping: { IconOnly: true, 'Not IconOnly': undefined }, - }, Icon: { control: 'select', options: Object.keys(Icons), mapping: Icons }, }, + parameters: { controls: { exclude: ['iconOnly'] } }, + render: ({ + iconOnly: _iconOnly, + Icon, + iconPosition, + label = 'Button', + ...args + }) => { + const buttonProps: ButtonProps = { + ...args, + Icon, + iconPosition, + label, + } + const iconOnlyButtonProps: ButtonProps = { + ...args, + iconOnly: true, + Icon: Icon ?? IconArrowDownRight, + } + + return ( + + + С текстом +