npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@donkit-ai/design-system

v1.4.51

Published

Donkit Design System - minimal design tokens and React components

Downloads

14,959

Readme

Donkit Design System

Минимальная дизайн система на основе дизайн токенов с поддержкой светлой и темной темы.

🚀 Установка

Установите пакет из npm:

npm install @donkit-ai/design-system

или

yarn add @donkit-ai/design-system

Готово! Дизайн-система установлена и готова к использованию.

Обновление до последней версии

npm update @donkit-ai/design-system
# или
npm install @donkit-ai/design-system@latest

Особенности

  • 🎨 Дизайн токены - семантические CSS переменные для цветов, отступов, типографики
  • 🌓 Две темы - автоматическое переключение между светлой и темной темой
  • 📱 Адаптивность - responsive spacing и typography для mobile/tablet/desktop
  • ⚛️ React компоненты - готовые к использованию компоненты
  • 🎯 Lucide Icons - фиксированные размеры иконок (20/24/28px, stroke 1.5)
  • 📖 Интерактивная документация - страница с примерами всех компонентов

Компоненты

  • Button - кнопки с вариантами (primary, secondary, ghost) и размерами (xs, s, m, l). Поддерживает href для рендера как ссылка
  • Tabs - вкладки с состоянием selected в четырех размерах (xs, s, m, l). Поддерживает href для рендера как ссылка
  • Input - текстовые поля с поддержкой иконок, ошибок и подсказок (xs, s, m)
  • Textarea - многострочное текстовое поле (xs, s, m)
  • Select - выпадающий список с кастомным дизайном (xs, s, m)
  • Stepper - числовое поле с кнопками +/- для изменения значения (xs, s, m)
  • Toggle - переключатель для включения/выключения опций (xs, s, m, l)
  • Checkbox - чекбокс для выбора опций (xs, s, m, l)
  • Radio - радиокнопка для выбора одного варианта из группы (xs, s, m, l)
  • Card - карточки двух типов: info (информационная, прозрачный фон) и interactive (интерактивная с hover эффектом). Поддерживает href для рендера как ссылка
  • Typography - H1-H4, P1-P3 компоненты
  • Code - inline и block код с monospace шрифтом
  • Link - ссылки акцентным цветом, при hover цвет меняется и появляется подчеркивание
  • Badge - бейджи для статусов (success, error, warning, accent) в двух размерах (s, m)
  • Modal - модальные окна с header и footer
  • Select - выпадающий список с кастомным дизайном (s, m)

Использование в проекте

1. Импорт токенов (обязательно в корне приложения)

В главном файле вашего приложения (например, main.tsx или App.tsx):

// Подключите CSS токены ОДИН РАЗ в корне приложения
import '@donkit-ai/design-system/tokens.css';

2. Использование компонентов

import { Button, Tabs, Tab, Input, Card, H1, P1, P3, Badge, Code, Link } from '@donkit-ai/design-system';
import { Mail } from 'lucide-react';

function MyComponent() {
  return (
    <Card padding="m">
      <H1>Welcome</H1>
      <P1 secondary>This is a demo</P1>
      <Button
        variant="primary"
        size="m"
        icon={<Mail size={24} strokeWidth={1.5} />}
      >
        Send Email
      </Button>
    </Card>
  );
}

// Button как ссылка (рендерит <a> вместо <button>)
// При обычном клике: вызывается onClick (preventDefault автоматический)
// При Cmd/Ctrl+Click или Middle Click: открывается новая вкладка
<Button variant="primary" href="/dashboard" onClick={() => navigate('/dashboard')}>
  Go to Dashboard
</Button>

<Button variant="secondary" href="https://example.com">
  Visit Example
</Button>

3. Иконки

Все иконки используются из библиотеки lucide-react (уже включена в зависимости).

Размеры иконок

Размеры иконок стандартизированы с помощью констант:

import { iconSizes } from '@donkit-ai/design-system';

// iconSizes = { 1: 16, 2: 20, 3: 24, 4: 28, 5: 48 }

Соответствие размеров компонентам:

  • 16px (iconSizes[1]) — XS-кнопки, XS-табы
  • 20px (iconSizes[2]) — S-кнопки, S-табы, Modal, Accordion
  • 24px (iconSizes[3]) — M-кнопки (default), Input, Alert, Select
  • 28px (iconSizes[4]) — L-кнопки, L-табы
  • 48px (iconSizes[5]) — крупные декоративные иконки

Всегда используется strokeWidth={1.5} для единообразия дизайна.

Примеры использования

import { Mail, Search, Eye, EyeOff, AlertCircle, Check, X } from 'lucide-react';
import { iconSizes } from '@donkit-ai/design-system';

// Small button / Tabs / Modal
<Button size="s" icon={<Mail size={iconSizes[2]} strokeWidth={1.5} />}>
  Send
</Button>

// Medium button / Input / Alert (default)
<Button size="m" icon={<Search size={iconSizes[3]} strokeWidth={1.5} />}>
  Search
</Button>
<Input icon={<Search size={iconSizes[3]} strokeWidth={1.5} />} placeholder="Search..." />

// Large button
<Button size="l" icon={<Mail size={iconSizes[4]} strokeWidth={1.5} />}>
  Send Email
</Button>

// Крупные декоративные
<Mail size={iconSizes[5]} strokeWidth={1.5} />

3. Переключение темы

// Темная тема (по умолчанию)
document.documentElement.setAttribute('data-theme', 'dark');

// Светлая тема
document.documentElement.setAttribute('data-theme', 'light');

Дизайн токены

Цвета

Примитивы (не использовать напрямую)

  • --color-white: #F8F9FA
  • --color-black: #0E0F11
  • --color-red: #EA6464

Поверхности — solid (меняются в зависимости от темы)

  • --color-surface-0 — page background
  • --color-surface-1 — card, panel, sidebar
  • --color-surface-2 — input, nested element
  • --color-surface-3 — dropdown, tooltip, popover

Foreground

  • --color-fg-primary — основной текст и иконки
  • --color-fg-secondary — вторичный текст
  • --color-fg-disabled — disabled состояние

Interactive States

Прозрачные наложения. В компонентах реализованы через ::before псевдоэлемент с z-index: -1 + isolation: isolate на родителе — оверлей рисуется поверх базового фона, но под контентом (текст, иконки).

  • --color-state-hover — hover (dark: white/7%, light: black/5%)
  • --color-state-active — pressed/active (dark: white/12%, light: black/10%)
  • --color-state-selected — selected/checked (dark: white/10%, light: black/8%)

Borders

  • --color-border-default — стандартная граница
  • --color-border-strong — hover/выделенная
  • --color-border-focus — focus ring

Accent

  • --color-accent-default — акцентный цвет (#EA6464)
  • --color-accent-hover — акцент при hover
  • --color-accent-fg — текст/иконки на акцентном фоне
  • --color-accent-bg — subtle акцентный фон (бейджи)

Status/Alert

  • --color-status-info/success/warning/error — адаптивные цвета для статусов
  • --color-status-*-bg — фон для статусных бейджей и алертов

Elevation / Shadows

  • --shadow-1 — dropdown, select, popover
  • --shadow-2 — modal, drawer
  • --shadow-3 — toast, критические оверлеи

Z-index Scale

  • --z-dropdown: 100
  • --z-sticky: 200
  • --z-drawer: 300
  • --z-modal: 400
  • --z-toast: 500
  • --z-tooltip: 600

Отступы — 4px grid

  • --space-1: 4px
  • --space-2: 8px
  • --space-3: 12px
  • --space-4: 16px
  • --space-5: 20px
  • --space-6: 24px
  • --space-8: 32px
  • --space-10: 40px
  • --space-12: 48px
  • --space-16: 64px

Border Radius

  • --radius-1: 2px
  • --radius-2: 4px
  • --radius-3: 6px — кнопки, inputs
  • --radius-4: 8px — карточки, модалки
  • --radius-6: 12px — drawer, панели
  • --radius-8: 16px — крупные контейнеры
  • --radius-full: 9999px — pill, аватары

Component Heights

| Токен | comfortable | compact | Size | |----------------|-------------|---------|------| | --height-1 | 24px | 20px | xs | | --height-2 | 32px | 28px | s | | --height-2-5 | 36px | 32px | sm | | --height-3 | 44px | 36px | m | | --height-4 | 56px | 44px | l |

Все компоненты с поддержкой size="sm": Button, Input, Tab, SegmentedControl.

Variant attributes

Три независимых атрибута — можно вешать на любой контейнер и комбинировать:

| Атрибут | Эффект | Токены | |---------|--------|--------| | data-corners="sharp" | Все скругления → 0 | --radius-1..8: 0 | | data-typography="editorial" | Mono UI, uppercase, tracking | --font-ui, --ui-tracking, --ui-text-transform, --btn-*, --badge-* | | data-density="airy" | Карточки всплывают при hover | --card-hover-transform: translateY(-3px) | | data-variant="edgy" | Shorthand для всех трёх + тёмные поверхности, атмосферные тени | все выше + --color-surface-*, --shadow-*, --color-border-* |

Правила сочетания

data-variant="edgy"
  = data-corners="sharp"
  + data-typography="editorial"
  + data-density="airy"
  + surface/border/shadow overrides (landing-specific)

Атрибуты не зависят друг от друга и применяются к любому вложенному поддереву:

// Sharp corners без uppercase — product UI с landing-аккуратностью
<div data-corners="sharp">
  <Button>Get started</Button>
  <Card>...</Card>
</div>

// Editorial типографика без острых углов — editorial overlay
<div data-typography="editorial">
  <Tabs>...</Tabs>
</div>

// Полный edgy — landing page
<div data-variant="edgy">
  <Nav />
  <Hero />
</div>

Как это работает

data-corners="sharp" переопределяет CSS-токены --radius-*: 0 на уровне контейнера. Все компоненты внутри используют border-radius: var(--radius-N), поэтому скругления обнуляются каскадом — без component-level override'ов.

--radius-full (pill-формы: Toggle, Badge) намеренно не переопределяется.


Density mode

Глобальный компактный режим применяется на уровне контейнера через data-density:

<div data-density="compact">
  {/* все компоненты внутри становятся компактнее */}
</div>

Правила использования:

  • compact только на контейнерном уровне (страница, dashboard, side-panel) — не на отдельных компонентах
  • Не использовать на mobile — режим автоматически сбрасывается на viewport < 768px
  • Минимальный hit-area в compact: 28px (--height-2) — достаточно для desktop

Что меняется в compact:

| Токен | comfortable | compact | |-------------|-------------|---------| | --space-3 | 12px | 8px | | --space-4 | 16px | 12px | | --space-5 | 20px | 16px | | --space-6 | 24px | 20px | | --text-md | 14px | 13px | | --text-sm | 12px | 11px |

Типографика (adaptive mobile → tablet+)

Font weights:

  • --font-weight-regular: 400
  • --font-weight-medium: 500
  • --font-weight-semibold: 600

Размеры:

  • --text-4xl: 32px → 40px (H1)
  • --text-3xl: 28px → 36px (H2)
  • --text-2xl: 24px → 28px (H3)
  • --text-xl: 20px → 24px (H4)
  • --text-lg: 16px → 18px (P1, основной текст)
  • --text-md: 14px → 16px (P2)
  • --text-sm: 12px → 14px (P3, метки)

Letter Spacing:

  • --tracking-4xl/3xl/2xl/xl: 0 (крупные кегли — без трекинга)
  • --tracking-lg: 0.02em
  • --tracking-md: 0.04em → 0.02em
  • --tracking-sm: 0.06em → 0.04em

Переходы

  • --transition-fast: 0.15s ease
  • --transition-normal: 0.20s ease
  • --transition-slow: 0.30s ease

Disabled States (состояния недоступности)

Правила

  • Button disabled — нейтральный стиль вместо opacity на акцентном цвете: прозрачный фон, --color-fg-disabled, стандартная рамка
  • Input/Select/Textarea disabled — применяется к wrapper целиком (label + поле + hint/error)
  • Курсор: cursor: not-allowed
  • Hover эффекты: отключаются через :hover:not(:disabled)

Примеры

<Button variant="primary" disabled>Disabled Button</Button>
<Input label="Name" value="Cannot edit" disabled />
<Select label="Choose" options={[...]} disabled />

Структура проекта

/src
  /styles
    tokens.css           # Дизайн токены
  /components
    Button.jsx/.css      # Компонент кнопки
    Tabs.jsx/.css        # Компонент вкладок
    Input.jsx/.css       # Компонент input
    Card.jsx/.css        # Компонент карточки
    Typography.jsx/.css  # Типографика
    Code.jsx/.css        # Inline и block код
    Link.jsx/.css        # Ссылки
    Badge.jsx/.css       # Бейджи
    Modal.jsx/.css       # Модальное окно
    Select.jsx/.css      # Выпадающий список
  /docs
    App.jsx              # Страница документации
    main.jsx             # Точка входа
    docs.css             # Стили документации
  index.js               # Экспорт всех компонентов

Примеры использования

Кнопки

<Button variant="primary">Primary</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="ghost">Ghost</Button>

// Размеры с соответствующими иконками
<Button size="xs" icon={<Mail size={16} strokeWidth={1.5} />}>
  Extra Small
</Button>
<Button size="s" icon={<Mail size={20} strokeWidth={1.5} />}>
  Small
</Button>
<Button size="m" icon={<Mail size={24} strokeWidth={1.5} />}>
  Medium
</Button>
<Button size="l" icon={<Mail size={28} strokeWidth={1.5} />}>
  Large
</Button>

// С fullWidth
<Button
  variant="primary"
  size="m"
  icon={<Mail size={24} strokeWidth={1.5} />}
  fullWidth
>
  Send Email
</Button>

Tabs

Вкладки с минималистичным дизайном без border.

import { Tabs, Tab } from '@donkit-ai/design-system';
import { AlertCircle } from 'lucide-react';

// Basic tabs
<Tabs size="m">
  <Tab selected={selectedTab === 'tab1'} onClick={() => setSelectedTab('tab1')}>
    Overview
  </Tab>
  <Tab selected={selectedTab === 'tab2'} onClick={() => setSelectedTab('tab2')}>
    Details
  </Tab>
  <Tab selected={selectedTab === 'tab3'} onClick={() => setSelectedTab('tab3')}>
    Settings
  </Tab>
</Tabs>

// With icons (размер иконки соответствует размеру таба)
// xs: 16px, small: 20px, medium: 24px, large: 28px
<Tabs size="s">
  <Tab
    selected={selectedTab === 'alerts'}
    onClick={() => setSelectedTab('alerts')}
    icon={<AlertCircle size={20} strokeWidth={1.5} />}
  >
    Alerts
  </Tab>
  <Tab selected={selectedTab === 'other'} onClick={() => setSelectedTab('other')}>
    Other
  </Tab>
</Tabs>

// Disabled tab
<Tabs size="m">
  <Tab selected>Active</Tab>
  <Tab disabled>Disabled</Tab>
</Tabs>

// As links (с href) - рендерит <a> вместо <button>
// При обычном клике: вызывается onClick (preventDefault автоматический)
// При Cmd/Ctrl+Click или Middle Click: открывается новая вкладка
<Tabs size="m">
  <Tab selected href="/overview" onClick={() => navigate('/overview')}>
    Overview
  </Tab>
  <Tab href="/details" onClick={() => navigate('/details')}>
    Details
  </Tab>
  <Tab href="/settings" onClick={() => navigate('/settings')}>
    Settings
  </Tab>
</Tabs>

Стили:

  • Selected: фон --color-item-bg-selected, текст --color-txt-icon-1
  • Hover: фон --color-item-bg-hover, текст --color-txt-icon-1
  • Default: текст --color-txt-icon-2

Размеры: xs, small, medium, large

Дополнительно: поддержка иконок и disabled состояния

Input

// Basic input
<Input
  label="Email"
  size="m"
  type="email"
  placeholder="[email protected]"
  hint="We'll never share your email"
/>

// Left icon (informational) - size small
<Input
  label="Search"
  size="s"
  icon={<Search size={20} strokeWidth={1.5} />}
  placeholder="Search..."
/>

// Left icon - size medium
<Input
  label="Search"
  size="m"
  icon={<Search size={24} strokeWidth={1.5} />}
  placeholder="Search..."
/>

// Right icon (action with hover) - size medium
<Input
  label="Password"
  size="m"
  type={showPassword ? 'text' : 'password'}
  iconRight={showPassword ? <EyeOff size={24} strokeWidth={1.5} /> : <Eye size={24} strokeWidth={1.5} />}
  onIconRightClick={() => setShowPassword(!showPassword)}
/>

// Error state
<Input
  label="Name"
  error="This field is required"
/>

Работа с иконками:

  • Иконки слева (icon) - информационные, не интерактивные (email, phone, user, search)
  • Иконки справа (iconRight) - действия с hover (показать/скрыть пароль, копировать)
  • Цвет: по умолчанию --color-txt-icon-2, при hover --color-txt-icon-1
  • Обработчик: используйте onIconRightClick для действий правой иконки

Select

<Select
  label="Choose option"
  size="m"
  value={value}
  onChange={setValue}
  options={[
    { value: 'opt1', label: 'Option 1' },
    { value: 'opt2', label: 'Option 2' },
  ]}
  placeholder="Select..."
/>

Stepper

Числовое поле с кнопками увеличения и уменьшения значения.

// Basic stepper
<Stepper
  label="Quantity"
  size="m"
  value={quantity}
  onChange={setQuantity}
  min={1}
  max={10}
  step={1}
/>

// Small size
<Stepper
  label="Price"
  size="s"
  value={price}
  onChange={setPrice}
  min={0}
  max={1000}
  step={10}
  hint="In increments of 10"
/>

// With error
<Stepper
  label="Age"
  value={age}
  onChange={setAge}
  min={0}
  max={120}
  error="Age is required"
/>

// Disabled
<Stepper
  label="Fixed value"
  value={50}
  disabled
/>

Параметры:

  • value - текущее значение (число)
  • onChange - функция обработки изменения значения
  • min - минимальное значение (default: 0)
  • max - максимальное значение (default: 100)
  • step - шаг изменения (default: 1)
  • size - размер: "s" или "m" (default: "medium")
  • label - подпись поля
  • hint - подсказка под полем
  • error - текст ошибки (показывается вместо hint)
  • disabled - отключить поле

Иконки в кнопках:

  • Small: 16px (Minus, Plus)
  • Medium: 20px (Minus, Plus)

Toggle

Переключатель для включения/выключения опций. Размеры привязаны к размерам иконок.

// Basic toggle
<Toggle
  checked={isEnabled}
  onChange={setIsEnabled}
  label="Enable notifications"
/>

// Extra Small size (16px)
<Toggle
  size="xs"
  checked={isCompact}
  onChange={setIsCompact}
  label="Compact mode"
/>

// Small size (20px)
<Toggle
  size="s"
  checked={isEnabled}
  onChange={setIsEnabled}
  label="Auto-save"
/>

// Medium size (24px, default)
<Toggle
  size="m"
  checked={darkMode}
  onChange={setDarkMode}
  label="Dark mode"
/>

// Large size (28px)
<Toggle
  size="l"
  checked={isEnabled}
  onChange={setIsEnabled}
  label="Enable feature"
/>

// Without label (for tables/cards where context is clear)
<Toggle
  checked={isEnabled}
  onChange={setIsEnabled}
/>

// Disabled states
<Toggle
  checked={false}
  onChange={() => {}}
  label="Disabled unchecked"
  disabled
/>

<Toggle
  checked={true}
  onChange={() => {}}
  label="Disabled checked"
  disabled
/>

Параметры:

  • checked - состояние переключателя (true/false)
  • onChange - функция обработки изменения состояния, получает новое значение (boolean)
  • size - размер: "xs", "small", "medium" или "large" (default: "medium")
  • label - текст подписи (опционально)
  • disabled - отключить переключатель
  • id - пользовательский ID (по умолчанию генерируется автоматически)

Стиль:

  • Размеры привязаны к иконкам: xs (16px), small (20px), medium (24px), large (28px)
  • Ширина трека: 1.75x от высоты
  • Включенное состояние: фон --color-status-success, border --color-status-success (зеленый)
  • Выключенное состояние: фон --color-item-bg, border --color-border, hover --color-border-hover

Checkbox

Чекбокс для выбора опций. Размеры привязаны к размерам иконок.

// Basic checkbox
<Checkbox
  checked={isAccepted}
  onChange={setIsAccepted}
  label="Accept terms and conditions"
/>

// Extra Small size (16px)
<Checkbox
  size="xs"
  checked={isCompact}
  onChange={setIsCompact}
  label="Compact view"
/>

// Small size (20px)
<Checkbox
  size="s"
  checked={isEnabled}
  onChange={setIsEnabled}
  label="Enable feature"
/>

// Medium size (24px, default)
<Checkbox
  size="m"
  checked={isSubscribed}
  onChange={setIsSubscribed}
  label="Subscribe to newsletter"
/>

// Large size (28px)
<Checkbox
  size="l"
  checked={isAccepted}
  onChange={setIsAccepted}
  label="I accept the terms"
/>

// Without label (for tables/lists where context is clear)
<Checkbox
  checked={isSelected}
  onChange={setIsSelected}
/>

// Disabled states
<Checkbox
  checked={false}
  onChange={() => {}}
  label="Disabled unchecked"
  disabled
/>

<Checkbox
  checked={true}
  onChange={() => {}}
  label="Disabled checked"
  disabled
/>

Параметры:

  • checked - состояние чекбокса (true/false)
  • onChange - функция обработки изменения состояния, получает новое значение (boolean)
  • size - размер: "xs", "small", "medium" или "large" (default: "medium")
  • label - текст подписи (опционально)
  • disabled - отключить чекбокс
  • id - пользовательский ID (по умолчанию генерируется автоматически)

Стиль:

  • Размеры привязаны к иконкам: xs (16px), small (20px), medium (24px), large (28px)
  • Выбранное состояние: фон --color-status-success, border --color-status-success (зеленый)
  • Невыбранное состояние: фон --color-item-bg, border --color-border, hover --color-border-hover
  • Иконка галочки (Check) белого цвета при checked

Radio

Радиокнопка для выбора одного варианта из группы. Размеры привязаны к размерам иконок.

// Basic radio
<Radio
  checked={selectedOption === 'option1'}
  onChange={() => setSelectedOption('option1')}
  name="options"
  value="option1"
  label="Option 1"
/>

// Extra Small size (16px)
<Radio
  size="xs"
  checked={size === 'xs'}
  onChange={() => setSize('xs')}
  name="size"
  value="xs"
  label="Extra Small"
/>

// Small size (20px)
<Radio
  size="s"
  checked={size === 'small'}
  onChange={() => setSize('small')}
  name="size"
  value="small"
  label="Small"
/>

// Medium size (24px, default)
<Radio
  size="m"
  checked={size === 'medium'}
  onChange={() => setSize('medium')}
  name="size"
  value="medium"
  label="Medium"
/>

// Large size (28px)
<Radio
  size="l"
  checked={size === 'large'}
  onChange={() => setSize('large')}
  name="size"
  value="large"
  label="Large"
/>

// Radio group example
<div>
  <Radio
    checked={paymentMethod === 'card'}
    onChange={() => setPaymentMethod('card')}
    name="payment"
    value="card"
    label="Credit Card"
  />
  <Radio
    checked={paymentMethod === 'paypal'}
    onChange={() => setPaymentMethod('paypal')}
    name="payment"
    value="paypal"
    label="PayPal"
  />
  <Radio
    checked={paymentMethod === 'bank'}
    onChange={() => setPaymentMethod('bank')}
    name="payment"
    value="bank"
    label="Bank Transfer"
  />
</div>

// Without label (for tables/lists where context is clear)
<Radio
  checked={isSelected}
  onChange={() => setIsSelected(true)}
  name="selection"
  value="item1"
/>

// Disabled states
<Radio
  checked={false}
  onChange={() => {}}
  name="disabled-group"
  value="disabled1"
  label="Disabled unchecked"
  disabled
/>

<Radio
  checked={true}
  onChange={() => {}}
  name="disabled-group"
  value="disabled2"
  label="Disabled checked"
  disabled
/>

Параметры:

  • checked - состояние радиокнопки (true/false)
  • onChange - функция обработки изменения состояния, получает новое значение (boolean)
  • name - имя группы радиокнопок (обязательно для группировки)
  • value - значение радиокнопки
  • size - размер: "xs", "small", "medium" или "large" (default: "medium")
  • label - текст подписи (опционально)
  • disabled - отключить радиокнопку
  • id - пользовательский ID (по умолчанию генерируется автоматически)

Стиль:

  • Размеры привязаны к иконкам: xs (16px), small (20px), medium (24px), large (28px)
  • Выбранное состояние: фон --color-status-success, border --color-status-success (зеленый), белая точка внутри
  • Невыбранное состояние: фон --color-item-bg, border --color-border, hover --color-border-hover
  • Круглая форма (border-radius: 50%)

Card

Карточки бывают двух типов:

// Card Info (по умолчанию)
// Информационная карточка без интерактивности
// Прозрачный фон, только border
<Card padding="m" variant="info">
  <H4>Card Title</H4>
  <P1>Information content</P1>
</Card>

// Card Interactive
// Интерактивная карточка с hover эффектом
// При hover меняется фон и border
<Card padding="l" variant="interactive" onClick={handleClick}>
  <H4>Clickable Card</H4>
  <P1>Interactive content</P1>
</Card>

// Размеры padding
<Card padding="s">s padding</Card>
<Card padding="m">m padding</Card>
<Card padding="l">l padding</Card>

// Card как ссылка (рендерит <a> вместо <div>)
// При обычном клике: вызывается onClick (preventDefault автоматический)
// При Cmd/Ctrl+Click или Middle Click: открывается новая вкладка
<Card
  padding="m"
  variant="interactive"
  href="/dashboard"
  onClick={() => navigate('/dashboard')}
>
  <H4>Dashboard</H4>
  <P1>Go to dashboard page</P1>
</Card>

<Card
  padding="m"
  variant="interactive"
  href="https://example.com"
>
  <H4>External Link</H4>
  <P1>Visit external site</P1>
</Card>

// Disabled Card Link
<Card
  padding="m"
  variant="interactive"
  href="/disabled"
  disabled
>
  <H4>Disabled</H4>
  <P1>This card is disabled</P1>
</Card>

Стиль:

  • variant="info" (по умолчанию): прозрачный фон, border --color-border
  • variant="interactive": фон --color-item-bg, при hover фон --color-item-bg-hover, курсор pointer
  • Поддержка href для рендера как ссылка с умной обработкой кликов

Code

// Inline code
<p>Use <Code>--color-accent</Code> variable</p>

// Code block
<Code block>{`function example() {
  return "Hello World";
}`}</Code>

Link

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

Стиль:

  • Цвет: --color-accent
  • Без подчеркивания по умолчанию
  • При hover: цвет меняется на --color-accent-hover + появляется подчеркивание
  • При active: цвет --color-accent-hover

Badge

Бейджи для отображения статусов и категорий в двух размерах.

// Medium size (default)
<Badge variant="success" size="m">Success</Badge>
<Badge variant="error" size="m">Error</Badge>
<Badge variant="warning" size="m">Warning</Badge>
<Badge variant="info" size="m">Info</Badge>

// Small size
<Badge variant="success" size="s">Success</Badge>
<Badge variant="error" size="s">Error</Badge>
<Badge variant="warning" size="s">Warning</Badge>

// Variants
<Badge variant="default">Default</Badge>
<Badge variant="accent">Accent</Badge>

Размеры:

  • small - компактный размер (font-size: p3, padding: 0 4px, radius: xs)
  • medium - стандартный размер (font-size: p2, padding: 2px 8px, radius: s)

Варианты:

  • default - серый с border
  • info - синий (информация)
  • success - зелёный (успех)
  • warning - жёлтый (предупреждение)
  • error - красный (ошибка)
  • accent - красный акцентный

Цвета адаптируются для светлой и тёмной темы для обеспечения контраста минимум 4.5:1.

Modal

<Modal
  title="Modal Title"
  onClose={handleClose}
  size="m"
>
  <P1>Modal content here...</P1>
  <Input label="Name" placeholder="Enter name" />

  <ModalFooter>
    <Button variant="secondary" size="m" onClick={handleClose}>
      Cancel
    </Button>
    <Button variant="primary" size="m">
      Submit
    </Button>
  </ModalFooter>
</Modal>

{/* Modal использует иконку закрытия 20px (автоматически) */}

🛠 Для мейнтейнеров дизайн-системы

Публикация в npm

  1. Внесите изменения в компоненты или токены

  2. Обновите версию в package.json:

npm version patch   # 0.2.3 → 0.2.4 (багфиксы)
npm version minor   # 0.2.3 → 0.3.0 (новые фичи)
npm version major   # 0.2.3 → 1.0.0 (breaking changes)
  1. Создайте тег и запушьте:
git push --follow-tags

Готово! GitLab CI автоматически опубликует новую версию в публичный npm registry.

Команда получит обновления

npm update @donkit-ai/design-system
# или
npm install @donkit-ai/design-system@latest

Локальная разработка

Для тестирования изменений локально используйте npm link:

# В папке Donkit-desing-tokens
npm link

# В папке вашего проекта (agent-platform/frontend)
npm link @donkit-ai/design-system

Теперь изменения в дизайн-системе сразу видны в вашем проекте без переустановки.

Структура версионирования

  • Главная ветка: main - стабильная версия
  • Теги: v0.1.0, v0.1.2 - релизные версии
  • Фичи: создавайте ветки для больших изменений, мерджите в main после ревью

Adding a theme

Donkit DS ships dark (default, always in :root) plus light and high-contrast in src/styles/themes/. To add your own:

7 шагов

  1. Скопировать шаблон

    cp src/styles/themes/_template.css src/styles/themes/my-theme.css
  2. Переименовать атрибут — заменить my-theme на kebab-case название в selector [data-theme="my-theme"]

  3. Заполнить REQUIRED-токены — 14 обязательных переменных (surface, fg, border, state-overlay, overlay). Без них тема не будет работать: | Группа | Токены | |--------|--------| | Surface | --color-surface-0..3 | | Foreground | --color-fg-primary/secondary/disabled | | Border | --color-border-light/default/strong/focus | | State overlay | --color-state-hover/active/selected | | Backdrop | --color-overlay |

  4. Оставить OPTIONAL — shadow, accent, status, data-palette, focus-ring. Не переопределяешь — наследуется от тёмной базы в :root.

  5. Импортировать в проект после tokens.css:

    import '@donkit-ai/design-system/src/styles/tokens.css';
    import '@donkit-ai/design-system/src/styles/themes/my-theme.css';

    Или через CSS:

    @import '@donkit-ai/design-system/src/styles/tokens.css';
    @import '@donkit-ai/design-system/src/styles/themes/my-theme.css';
  6. Добавить в preview — скопировать колонку в preview/themes.html, вставить data-theme="my-theme" на .surface.

  7. Прогнать a11y-чеклист:

    • [ ] Контраст текста ≥ 4.5:1 (AA), лучше ≥ 7:1 (AAA)
    • [ ] UI-элементы (бордеры, иконки) ≥ 3:1
    • [ ] Focus ring чётко виден на всех поверхностях
    • [ ] Hover overlay различим, но не агрессивен
    • [ ] Selected отличается от hover визуально
    • [ ] Overlay/backdrop не слишком плотный и не прозрачный

Архитектурный контракт

:root            ← dark (всегда загружен, база для наследования)
[data-theme="light"]         ← src/styles/themes/light.css
[data-theme="high-contrast"] ← src/styles/themes/high-contrast.css
[data-theme="my-theme"]      ← твой файл

[data-variant="edgy"]        ← structural, не тема — живёт в tokens.css
[data-density="compact"]     ← density mode — живёт в tokens.css

Темы загружаются unlayered → всегда побеждают @layer base из tokens.css.


Token resilience

Все структурные токены в компонентах имеют встроенный фолбэк-значение:

/* вместо */
height: var(--height-3);

/* теперь */
height: var(--height-3, 44px);

Это гарантирует корректный рендер даже если tokens.css не подключён или загружается с задержкой.

Категории токенов

| Категория | Примеры | Фолбэк | |-----------|---------|--------| | Radius | --radius-1..8, --radius-full | 2px..9999px | | Space | --space-1..16 | 4px..64px | | Height | --height-1..4, --height-2-5 | 24px..56px | | Motion | --motion-enter/exit/hover | 0.3s ease, 0.2s ease | | Typography | --text-sm..4xl, --font-weight-* | 12px..32px, 400/500/600 | | Component | --btn-*, --tab-*, --badge-radius | см. tokens.css |

Что НЕ имеет фолбэка

Цветовые (--color-*) и тень (--shadow-*) токены — намеренно без фолбэка. Отсутствующий цвет должно быть видно сразу, а не скрыто дефолтом.


Лицензия

MIT