Перейти к основному содержанию

Базовые компоненты

Эта страница представляет полный справочник API для пяти фундаментальных примитивных компонентов в src/core/ui/. Это компоненты уровня 1 (атомы), которые служат основными строительными блоками для всех компонентов более высокого уровня в библиотеке. Область применения: Эта страница охватывает только базовые примитивы: Block, Box, Grid, Flex и Stack. Для расширенных UI-компонентов (Button, Card, Badge и т.д.) см. UI-компоненты. Для архитектурных объяснений и паттернов композиции см. Базовые компоненты.

Обзор компонентов

Базовые примитивы предоставляют низкоуровневые возможности рендеринга с прямым доступом к системе вариантов CVA. Они рендерят семантические HTML5-элементы, принимая пропсы вариантов для стилизации.
Ядро React

Система вариантов

Слой базовых примитивов

Block
(src/core/ui/Block.tsx)

Box
(src/core/ui/Box.tsx)

Grid
(src/core/ui/Grid.tsx)

Flex
(src/core/ui/Flex.tsx)

Stack
(src/core/ui/Stack.tsx)

spacingVariants
(src/core/variants/)

colorVariants

layoutVariants

roundedVariants

shadowVariants

borderVariants

React.forwardRef

HTMLElement
Источники: README.md82-103 Диаграмма 1 из высокоуровневой архитектуры

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

КомпонентОсновное назначениеСемантический элементТип макетаКлючевые варианты
BlockСемантические секцииsection, article, nav, header, footer, aside, main, divБлочный контейнерВсе варианты (отступы, цвета, макет, эффекты)
BoxУниверсальный контейнерdiv, span, любой HTML-элементГибкий примитивВсе варианты (отступы, цвета, макет, эффекты)
GridCSS Grid макетыdiv с display: gridCSS GridСпецифичные для Grid (cols, rows, areas) + варианты макета
FlexFlexbox макетыdiv с display: flexFlexboxСпецифичные для Flex (direction, align, justify) + варианты макета
StackВертикальное/горизонтальное размещениеdiv с flexСтековый макетСпецифичные для Stack (gap, direction) + варианты отступов
Источники: README.md82-103 Диаграмма 1

Компонент Block

Компонент Block рендерит семантические HTML5 структурные элементы с полной поддержкой системы вариантов. Это основной контейнер для создания секций страницы с семантическим значением.

Определение типа

interface BlockProps 
  extends React.HTMLAttributes<HTMLElement>,
    VariantSpacingProps,
    ColorProps,
    VariantLayoutProps,
    RoundedProps,
    ShadowProps,
    BorderProps {
  children: ReactNode;
  component?: ElementType;
  variant?: 'section' | 'main' | 'nav' | 'article' | 'header' | 'footer' | 'aside' | 'div';
}

Справочник пропсов

ПропсТипПо умолчаниюОписание
childrenReactNodeОбязательныйСодержимое для рендеринга внутри блока
componentElementType-Переопределить рендерящийся HTML-элемент
variant'section' | 'main' | 'nav' | 'article' | 'header' | 'footer' | 'aside' | 'div''div'Семантический HTML-элемент для рендеринга
p, px, py, pt, pb, pl, prЗначения отступов-Варианты padding
m, mx, my, mt, mb, ml, mrЗначения отступов-Варианты margin
bgТокен цвета-Цвет фона
cТокен цвета-Цвет текста
borderColorТокен цвета-Цвет границы
wЗначение макета'full'Ширина
hЗначение макета-Высота
minHЗначение макета-Минимальная высота
position'relative' | 'absolute' | 'fixed' | 'sticky'-CSS position
roundedЗначение rounded-Радиус границы
shadowЗначение shadow-Тень элемента
border, borderTop, borderBottom, borderLeft, borderRightЗначение border-Стили границ
classNamestring-Дополнительные CSS-классы
refRef<HTMLElement>-Пробрасываемая ссылка на базовый DOM-элемент

Реализация forwardRef

Компонент Block использует паттерн React forwardRef для предоставления ссылки на базовый DOM-элемент:
export const Block = forwardRef<HTMLElement, BlockProps>(
  ({ children, component, variant = 'div', ...props }, ref) => {
    const elementType = component || variant;
    return <BaseElement ref={ref} component={elementType} {...props}>{children}</BaseElement>;
  }
);
Ключевые моменты:
  • Обобщенный тип forwardRef<HTMLElement, BlockProps> обеспечивает типобезопасный доступ к ref
  • Параметр ref автоматически типизируется как Ref<HTMLElement>
  • ref передается базовому DOM-элементу
  • displayName устанавливается для отладки в React DevTools

Поток применения вариантов

Пропсы компонента
{p: 'lg', bg: 'card', rounded: 'md'}

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

spacingVariants({p: 'lg'})

colorVariants({bg: 'card'})

roundedVariants({rounded: 'md'})

Движок CVA

Сгенерированные классы
'p-8 bg-card rounded-md'

утилита cn()
Слияние с className

DOM-элемент
<section class='...' />
Источники: src/components/ui/Block/Block.tsx33-86

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

Базовая семантическая секция:
<Block variant="section" p="lg" bg="background">
  <h2>Заголовок секции</h2>
  <p>Содержимое секции</p>
</Block>
Навигация с позиционированием:
<Block variant="nav" position="sticky" bg="primary" c="white" p="md">
  <NavLinks />
</Block>
Статья с тенью и скругленными углами:
<Block variant="article" p="xl" rounded="lg" shadow="md" bg="card">
  <ArticleContent />
</Block>
Переопределение пользовательского элемента:
<Block component="form" variant="div" p="lg" onSubmit={handleSubmit}>
  <FormFields />
</Block>

Атрибуты данных

Все экземпляры Block автоматически получают data-class="block" для согласованного таргетирования DOM:
<BaseBlock
  data-class="block"
  className={/* объединенные классы вариантов */}
  {...props}
/>
Источники: src/components/ui/Block/Block.tsx1-88 README.md82-103

Компонент Box

Компонент Box является наиболее гибким примитивом, способным рендерить любой HTML-элемент с полной поддержкой вариантов. Он служит низкоуровневым строительным блоком для пользовательских компонентов.

Определение типа

interface BoxProps 
  extends React.HTMLAttributes<HTMLElement>,
    VariantSpacingProps,
    ColorProps,
    VariantLayoutProps,
    RoundedProps,
    ShadowProps,
    BorderProps {
  children?: ReactNode;
  component?: ElementType;
  as?: ElementType; // Алиас для component
}

Справочник пропсов

ПропсТипПо умолчаниюОписание
childrenReactNode-Содержимое для рендеринга (опционально для пустых элементов)
componentElementType'div'HTML-элемент или компонент для рендеринга
asElementType-Алиас для пропса component
Все пропсы отступовЗначения отступов-Варианты padding и margin
Все пропсы цветовТокены цветов-Цвета фона, текста, границы
Все пропсы макетаЗначения макета-Ширина, высота, позиция, отображение
Все пропсы эффектовЗначения эффектов-Скругление, тень, граница
classNamestring-Дополнительные CSS-классы
refRef<HTMLElement>-Пробрасываемая ссылка на DOM-элемент

Полиморфизм компонента

Компонент Box поддерживает полиморфный рендеринг через пропс component или as:
Box component='button'

Полиморфная логика

React.createElement(component, props)

<button class='...' />

Box as='a'

Полиморфная логика

React.createElement('a', props)

<a class='...' />

Box (по умолчанию)

Полиморфная логика

React.createElement('div', props)

<div class='...' />

Проброс атрибутов TypeScript

Компонент Box расширяет React.HTMLAttributes<HTMLElement>, что означает:
  1. Все стандартные HTML-атрибуты типобезопасны: onClick, onMouseOver, data-*, aria-* и т.д.
  2. Атрибуты пробрасываются базовому элементу: Пропсы, не используемые вариантами, передаются дальше
  3. Вывод типов работает с пропсом component: TypeScript сужает типы атрибутов на основе элемента
// ✅ Валидно: div принимает onClick
<Box onClick={handler}>Нажми на меня</Box>

// ✅ Валидно: input принимает value
<Box component="input" value={inputValue} />

// ✅ Валидно: button принимает type
<Box component="button" type="submit">Отправить</Box>

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

Универсальный контейнер:
<Box p="md" bg="muted" rounded="sm">
  Общее содержимое
</Box>
Элемент button:
<Box component="button" p="md" bg="primary" c="white" rounded="md" onClick={handleClick}>
  Пользовательская кнопка
</Box>
Элемент ссылки:
<Box as="a" href="/page" p="sm" c="blue" hover:underline>
  Текст ссылки
</Box>
Встроенный span:
<Box component="span" c="muted" size="sm">
  Встроенный текст
</Box>
Обертка для input:
<Box component="input" type="text" w="full" p="sm" border="default" rounded="md" />
Источники: README.md85-103 src/components/ui/Box/index.ts1

Компонент Grid

Компонент Grid предоставляет возможности макета CSS Grid с декларативными пропсами для специфичной конфигурации сетки.

Определение типа

interface GridProps
  extends React.HTMLAttributes<HTMLDivElement>,
    Pick<VariantSpacingProps, 'p' | 'px' | 'py' | 'gap'>,
    Pick<VariantLayoutProps, 'w' | 'h' | 'minH'> {
  children: ReactNode;
  cols?: number | string;
  rows?: number | string;
  areas?: string;
  autoFlow?: 'row' | 'column' | 'dense' | 'row dense' | 'column dense';
  alignItems?: 'start' | 'end' | 'center' | 'stretch';
  justifyItems?: 'start' | 'end' | 'center' | 'stretch';
  justifyContent?: 'start' | 'end' | 'center' | 'stretch' | 'space-between' | 'space-around' | 'space-evenly';
  alignContent?: 'start' | 'end' | 'center' | 'stretch' | 'space-between' | 'space-around' | 'space-evenly';
}

Справочник пропсов

ПропсТипПо умолчаниюОписание
childrenReactNodeОбязательныйЭлементы сетки для размещения
colsnumber | string-Значение grid-template-columns (например, 2, ‘1fr 2fr’, ‘repeat(3, 1fr)‘)
rowsnumber | string-Значение grid-template-rows
areasstring-Значение grid-template-areas
autoFlowЗначения auto-flow Grid'row'Направление для автоматически размещаемых элементов
gapЗначение отступа-Промежуток между элементами сетки
alignItemsЗначение выравнивания-Вертикальное выравнивание элементов внутри ячеек
justifyItemsЗначение выравнивания-Горизонтальное выравнивание элементов внутри ячеек
alignContentЗначение выравнивания-Вертикальное выравнивание сетки внутри контейнера
justifyContentЗначение выравнивания-Горизонтальное выравнивание сетки внутри контейнера
p, px, pyЗначения отступов-Варианты padding
w, h, minHЗначения макета-Размеры контейнера
refRef<HTMLDivElement>-Пробрасываемая ссылка на контейнер сетки

Паттерны макета Grid

Сетка с Auto-Flow

Grid autoFlow='dense' cols={4}

Автоматически размещенные элементы

Автоматическое заполнение пробелов

Именованные области Grid

Grid areas='header header | nav main | footer footer'

Область header

Область nav

Область main

Область footer

Простая колоночная сетка

Grid cols={3} gap='md'

Элемент 1

Элемент 2

Элемент 3

Элемент 4

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

Простая колоночная сетка:
<Grid cols={3} gap="md" p="lg">
  <Box bg="muted" p="md">Элемент 1</Box>
  <Box bg="muted" p="md">Элемент 2</Box>
  <Box bg="muted" p="md">Элемент 3</Box>
</Grid>
Адаптивная сетка с пользовательскими колонками:
<Grid cols="repeat(auto-fit, minmax(250px, 1fr))" gap="lg">
  {items.map(item => <GridItem key={item.id} />)}
</Grid>
Именованные области сетки:
<Grid
  areas={`
    "header header header"
    "nav main aside"
    "footer footer footer"
  `}
  cols="200px 1fr 200px"
  rows="auto 1fr auto"
  gap="md"
  minH="screen"
>
  <Box style={{ gridArea: 'header' }}>Шапка</Box>
  <Box style={{ gridArea: 'nav' }}>Навигация</Box>
  <Box style={{ gridArea: 'main' }}>Основное содержимое</Box>
  <Box style={{ gridArea: 'aside' }}>Боковая панель</Box>
  <Box style={{ gridArea: 'footer' }}>Подвал</Box>
</Grid>
Источники: README.md91-103

Компонент Flex

Компонент Flex предоставляет возможности макета Flexbox с декларативными пропсами для специфичной конфигурации flex.

Определение типа

interface FlexProps
  extends React.HTMLAttributes<HTMLDivElement>,
    Pick<VariantSpacingProps, 'p' | 'px' | 'py' | 'gap'>,
    Pick<VariantLayoutProps, 'w' | 'h' | 'minH'> {
  children: ReactNode;
  direction?: 'row' | 'row-reverse' | 'column' | 'column-reverse';
  align?: 'start' | 'end' | 'center' | 'stretch' | 'baseline';
  justify?: 'start' | 'end' | 'center' | 'between' | 'around' | 'evenly';
  wrap?: 'nowrap' | 'wrap' | 'wrap-reverse';
  inline?: boolean;
}

Справочник пропсов

ПропсТипПо умолчаниюОписание
childrenReactNodeОбязательныйFlex-элементы для размещения
direction'row' | 'row-reverse' | 'column' | 'column-reverse''row'Направление главной оси
align'start' | 'end' | 'center' | 'stretch' | 'baseline'-Выравнивание по поперечной оси (align-items)
justify'start' | 'end' | 'center' | 'between' | 'around' | 'evenly'-Выравнивание по главной оси (justify-content)
wrap'nowrap' | 'wrap' | 'wrap-reverse''nowrap'Переносятся ли элементы на несколько строк
inlinebooleanfalseИспользовать display: inline-flex вместо display: flex
gapЗначение отступа-Промежуток между flex-элементами
p, px, pyЗначения отступов-Варианты padding
w, h, minHЗначения макета-Размеры контейнера
refRef<HTMLDivElement>-Пробрасываемая ссылка на flex-контейнер

Модель осей Flexbox

direction='column' (Главная ось: Вертикальная)

Flex direction='column' justify='center' align='start'

Элемент 1

Элемент 2

Элемент 3

direction='row' (Главная ось: Горизонтальная)

Flex direction='row' justify='between' align='center'

Элемент 1

Элемент 2

Элемент 3

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

Горизонтальный макет с отступами:
<Flex direction="row" justify="between" align="center" gap="md" p="lg">
  <Box>Левое содержимое</Box>
  <Box>Центральное содержимое</Box>
  <Box>Правое содержимое</Box>
</Flex>
Вертикальный стек:
<Flex direction="column" gap="sm" w="full">
  <Box>Первый элемент</Box>
  <Box>Второй элемент</Box>
  <Box>Третий элемент</Box>
</Flex>
Центрированное содержимое:
<Flex justify="center" align="center" minH="screen">
  <Box>Центрированное содержимое</Box>
</Flex>
Альтернатива переносящейся сетки:
<Flex wrap="wrap" gap="md" justify="start">
  {items.map(item => (
    <Box key={item.id} w="200px">
      {item.content}
    </Box>
  ))}
</Flex>
Источники: README.md91-103

Компонент Stack

Компонент Stack упрощает вертикальное или горизонтальное размещение с автоматическими промежутками. Это специализированная версия Flex, оптимизированная для распространенных паттернов размещения.

Определение типа

interface StackProps
  extends Omit<FlexProps, 'wrap' | 'inline'> {
  children: ReactNode;
  direction?: 'vertical' | 'horizontal';
  spacing?: Spacing value;
  gap?: Spacing value; // Алиас для spacing
}

Справочник пропсов

ПропсТипПо умолчаниюОписание
childrenReactNodeОбязательныйЭлементы для размещения
direction'vertical' | 'horizontal''vertical'Направление размещения
spacingЗначение отступа-Промежуток между элементами (внутренне соответствует gap)
gapЗначение отступа-Альтернативное название пропса для spacing
alignЗначение выравнивания-Выравнивание по поперечной оси
justifyЗначение выравнивания-Выравнивание по главной оси
p, px, pyЗначения отступов-Варианты padding
w, h, minHЗначения макета-Размеры контейнера
refRef<HTMLDivElement>-Пробрасываемая ссылка на контейнер стека

Сравнение Stack и Flex

ХарактеристикаStackFlex
API направления'vertical' | 'horizontal''row' | 'column' | 'row-reverse' | 'column-reverse'
ПереносНе поддерживаетсяДоступен пропс wrap
Основное назначениеПростые паттерны размещенияСложные макеты, требующие полного контроля flex
Пропс gapspacing или gapТолько gap
Простота APIУпрощенный для распространенных случаевПолный API flexbox

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

Вертикальный стек (по умолчанию):
<Stack gap="md" p="lg">
  <Box>Элемент 1</Box>
  <Box>Элемент 2</Box>
  <Box>Элемент 3</Box>
</Stack>
Горизонтальный стек:
<Stack direction="horizontal" gap="sm" align="center">
  <Button>Отмена</Button>
  <Button variant="primary">Сохранить</Button>
</Stack>
Макет формы:
<Stack gap="lg" w="full">
  <Box>
    <Text weight="medium" mb="xs">Email</Text>
    <Box component="input" type="email" w="full" p="sm" border="default" />
  </Box>
  <Box>
    <Text weight="medium" mb="xs">Пароль</Text>
    <Box component="input" type="password" w="full" p="sm" border="default" />
  </Box>
  <Button variant="primary" w="full">Войти</Button>
</Stack>
Источники: README.md91-103

Система типов TypeScript

Композиция типов пропсов вариантов

Все базовые компоненты составляют свои интерфейсы пропсов из общих определений типов вариантов:
Пропсы компонентов

Определения типов вариантов

VariantSpacingProps
{p, px, py, pt, pb, pl, pr,
m, mx, my, mt, mb, ml, mr}

ColorProps
{bg, c, borderColor}

VariantLayoutProps
{w, h, minH, maxW, position}

RoundedProps
{rounded}

ShadowProps
{shadow}

BorderProps
{border, borderTop, borderBottom,
borderLeft, borderRight}

BlockProps
extends VariantSpacingProps,
ColorProps, VariantLayoutProps,
RoundedProps, ShadowProps, BorderProps

BoxProps
extends VariantSpacingProps,
ColorProps, VariantLayoutProps,
RoundedProps, ShadowProps, BorderProps
Источники: src/components/ui/Block/Block.tsx1-18

Обобщенные параметры типа

Сигнатура обобщенного типа forwardRef обеспечивает типобезопасность как для пропсов, так и для ссылок:
// Паттерн, используемый всеми базовыми компонентами
forwardRef<RefType, PropsType>(
  (props: PropsType, ref: Ref<RefType>) => ReactElement
)

// Пример: компонент Block
forwardRef<HTMLElement, BlockProps>(
  ({ children, component, variant, ...props }, ref) => {
    // Реализация
  }
)
Гарантии типобезопасности:
  1. Пропсы полностью типизированы: Автодополнение работает для всех пропсов вариантов
  2. Тип ref соответствует элементу: ref.current типизируется как HTMLElement
  3. HTML-атрибуты валидируются: Некорректные атрибуты вызывают ошибки TypeScript
  4. Полиморфизм компонента безопасен: Пропс component сужает типы атрибутов
Источники: src/components/ui/Block/Block.tsx33-34

Типы пересечения пропсов

Базовые компоненты используют типы пересечения TypeScript (&) для объединения нескольких интерфейсов пропсов:
interface BlockProps 
  extends React.HTMLAttributes<HTMLElement>,    // HTML-атрибуты
    VariantSpacingProps,                        // Варианты отступов
    ColorProps,                                 // Варианты цветов
    VariantLayoutProps,                         // Варианты макета
    RoundedProps,                               // Варианты скругления
    ShadowProps,                                // Варианты теней
    BorderProps {                               // Варианты границ
  // Специфичные для компонента пропсы
  children: ReactNode;
  component?: ElementType;
  variant?: 'section' | 'main' | 'nav' | /* ... */;
}
Преимущества:
  • Слияние пропсов: Все пропсы вариантов доступны в компоненте
  • Отсутствие коллизий пропсов: TypeScript гарантирует отсутствие перекрывающихся имен пропсов
  • Поддержка IntelliSense: Автодополнение IDE показывает все доступные пропсы
  • Сужение типов: Опциональные пропсы правильно типизируются как T | undefined
Источники: src/components/ui/Block/Block.tsx20-31

Руководство по выбору компонента

Дерево решений

Да

Нет

Grid

Flexbox

Да

Нет

Ни то, ни другое

Нужен контейнер макета?

Нужен семантический
HTML-элемент?

Использовать Block
variant='section/nav/article/и т.д.'

Нужен CSS Grid
или Flexbox?

Использовать Grid
cols, rows, areas

Сложные flex
требования?

Использовать Flex
wrap, reverse, inline

Использовать Stack
Простое вертикальное/горизонтальное

Использовать Box
Универсальный контейнер

Рекомендации по использованию

СценарийРекомендуемый компонентОбоснование
Секция страницы с семантическим значениемBlock variant="section"Преимущества для SEO и доступности от семантического HTML
Навигационная панельBlock variant="nav"Правильная метка для программ чтения с экрана
Содержимое статьиBlock variant="article"Семантическая структура для контента
Контейнер формыBlock component="form"Семантический элемент формы с поддержкой вариантов
Универсальный div-контейнерBoxНаиболее гибкий примитив, любой элемент
Кнопка или ссылка со стилизациейBox component="button"Полный контроль над типом элемента и стилизацией
Многоколоночный макетGrid cols={3}Декларативный API Grid
Сетка карточек (адаптивная)Grid cols="repeat(auto-fit, ...)"Адаптивная сетка без медиа-запросов
Горизонтальная группа кнопокStack direction="horizontal"Простой API для горизонтальных отступов
Вертикальные поля формыStack gap="lg"Чистое размещение с согласованными промежутками
Навбар с space-betweenFlex justify="between"Контроль выравнивания Flexbox
Сложный адаптивный макетFlex wrap="wrap"Перенос с полным контролем flex
Источники: README.md82-103 Диаграмма 1

Лучшие практики

1. Предпочитайте семантические элементы

Используйте Block с семантическими вариантами вместо универсальных элементов div, когда структура имеет значение:
// ✅ Хорошо: Семантическая структура
<Block variant="article" p="lg">
  <Block variant="header" mb="md">
    <Title>Заголовок статьи</Title>
  </Block>
  <Block component="p">Содержимое статьи...</Block>
  <Block variant="footer" mt="md">
    Содержимое подвала
  </Block>
</Block>

// ❌ Избегайте: Несемантическая структура
<Box p="lg">
  <Box mb="md">
    <Title>Заголовок статьи</Title>
  </Box>
  <Box>Содержимое статьи...</Box>
  <Box mt="md">Содержимое подвала</Box>
</Box>

2. Используйте полиморфизм компонента

Используйте пропс component для рендеринга правильного HTML-элемента с сохранением пропсов вариантов:
// ✅ Хорошо: Правильный семантический элемент
<Box component="button" onClick={handleClick} p="md" bg="primary">
  Нажми на меня
</Box>

// ❌ Избегайте: div с onClick (проблемы доступности)
<Box onClick={handleClick} p="md" bg="primary">
  Нажми на меня
</Box>

3. Выбирайте правильный компонент макета

Не используйте Flex для простого размещения; Stack более читаем:
// ✅ Хорошо: Простой стек
<Stack gap="md">
  <Item1 />
  <Item2 />
  <Item3 />
</Stack>

// ❌ Избегайте: Излишне усложнено
<Flex direction="column" gap="md">
  <Item1 />
  <Item2 />
  <Item3 />
</Flex>

4. Используйте пропсы вариантов

Используйте пропсы вариантов вместо className для распространенных стилей:
// ✅ Хорошо: Пропсы вариантов
<Block p="lg" bg="card" rounded="md" shadow="sm">
  Содержимое
</Block>

// ❌ Избегайте: Строки className
<Block className="p-8 bg-card rounded-md shadow-sm">
  Содержимое
</Block>

5. Пробрасывайте ссылки для доступа к DOM

Всегда указывайте типы ссылок при доступе к DOM-элементам:
// ✅ Хорошо: Типизированная ссылка
const blockRef = useRef<HTMLElement>(null);

useEffect(() => {
  if (blockRef.current) {
    blockRef.current.scrollIntoView();
  }
}, []);

return <Block ref={blockRef}>Содержимое</Block>;
Источники: README.md278-359 Диаграмма 6

Интеграция с системой вариантов

Паттерн импорта вариантов

Все базовые компоненты импортируют и применяют варианты из src/core/variants/:
import {
  spacingVariants,
  colorVariants,
  layoutVariants,
  roundedVariants,
  shadowVariants,
  borderVariants,
  cn
} from "@ui8kit/core";

// Применение вариантов в className
className={cn(
  spacingVariants({ p, px, py, pt, pb, pl, pr, m, mx, my, mt, mb, ml, mr }),
  colorVariants({ bg, c, borderColor }),
  layoutVariants({ w, h, minH, position }),
  roundedVariants({ rounded }),
  shadowVariants({ shadow }),
  borderVariants({ border, borderTop, borderBottom, borderLeft, borderRight }),
  className // Пользовательский className последним (наивысшая специфичность)
)}
Источники: src/components/ui/Block/Block.tsx3-18 src/components/ui/Block/Block.tsx70-78

Слияние классов с cn()

Утилита cn() (из class-variance-authority) интеллектуально объединяет классы Tailwind:
  1. Дедуплицирует конфликтующие классы: cn('p-4', 'p-8')'p-8' (последний побеждает)
  2. Сохраняет неконфликтующие классы: cn('p-4 bg-red', 'mt-4')'p-4 bg-red mt-4'
  3. Обрабатывает условные классы: cn('base', condition && 'conditional') → условное включение
Источники: src/components/ui/Block/Block.tsx70

Покрытие вариантов

Базовые компоненты предоставляют доступ к следующим категориям вариантов:
Категория вариантовПропсыЗначенияПокрытие
Отступыp, px, py, pt, pb, pl, pr, m, mx, my, mt, mb, ml, mrnone, xs, sm, md, lg, xl, 2xl, auto~80% потребностей в отступах
Цветаbg, c, borderColorТокены дизайн-системыПолная цветовая палитра
Макетw, h, minH, maxW, positionАдаптивные размерыРаспространенные размеры
Эффектыrounded, shadowПредопределенные шкалыВизуальные улучшения
Границыborder, borderTop, borderBottom, borderLeft, borderRightСтили границДекорирование краев
Для полной документации по вариантам см. Система вариантов. Источники: README.md170-217 Диаграмма 3

Распространенные паттерны

Паттерн 1: Макет формы с Block и Box

<Block component="form" p="lg" bg="card" rounded="lg" onSubmit={handleSubmit}>
  <Stack gap="md">
    <Box>
      <Text weight="medium" mb="xs">Email</Text>
      <Box component="input" type="email" w="full" p="sm" border="default" rounded="md" />
    </Box>
    <Box>
      <Text weight="medium" mb="xs">Пароль</Text>
      <Box component="input" type="password" w="full" p="sm" border="default" rounded="md" />
    </Box>
    <Button type="submit" variant="primary" w="full">Войти</Button>
  </Stack>
</Block>

Паттерн 2: Сеточный макет панели управления

<Grid cols="repeat(auto-fit, minmax(300px, 1fr))" gap="lg" p="lg">
  <Card>
    <Card.Header>Метрика 1</Card.Header>
    <Card.Content>Значение</Card.Content>
  </Card>
  <Card>
    <Card.Header>Метрика 2</Card.Header>
    <Card.Content>Значение</Card.Content>
  </Card>
  <Card>
    <Card.Header>Метрика 3</Card.Header>
    <Card.Content>Значение</Card.Content>
  </Card>
</Grid>

Паттерн 3: Шапка страницы с Flex

<Block variant="header" bg="background" border="default" borderBottom>
  <Container>
    <Flex justify="between" align="center" p="md">
      <Flex align="center" gap="md">
        <Image src="/logo.png" w="32px" h="32px" />
        <Title order={1} size="lg">Название приложения</Title>
      </Flex>
      <Stack direction="horizontal" gap="sm">
        <Button variant="ghost">Документация</Button>
        <Button variant="primary">Войти</Button>
      </Stack>
    </Flex>
  </Container>
</Block>

Паттерн 4: Боковая навигация

<Block variant="nav" bg="muted" w="250px" h="screen" position="fixed">
  <Stack gap="xs" p="md">
    <Box component="a" href="/dashboard" p="sm" rounded="md" bg="primary" c="white">
      Панель управления
    </Box>
    <Box component="a" href="/analytics" p="sm" rounded="md" hover:bg="muted">
      Аналитика
    </Box>
    <Box component="a" href="/settings" p="sm" rounded="md" hover:bg="muted">
      Настройки
    </Box>
  </Stack>
</Block>
Источники: README.md310-359 Диаграмма 6

Соображения производительности

1. Извлечение пропсов вариантов

Пропсы вариантов извлекаются и обрабатываются при каждом рендере. Для критичных по производительности компонентов с множеством пропсов вариантов:
// ✅ Мемоизируйте пропсы вариантов, если они получены из сложных вычислений
const variantProps = useMemo(() => ({
  p: computedPadding,
  bg: computedBackground,
  rounded: computedRadius
}), [computedPadding, computedBackground, computedRadius]);

<Block {...variantProps}>Содержимое</Block>

2. Накладные расходы проброса ссылок

Паттерн forwardRef добавляет минимальные накладные расходы, но необходим для доступа к DOM. Если вам не нужны ссылки, обычные компоненты были бы незначительно быстрее (но базовые компоненты всегда используют forwardRef для согласованности).

3. Стоимость слияния классов

Утилита cn() выполняет разбор строк при каждом рендере. Для статических строк className, которые не меняются:
// ✅ Извлекайте статические классы за пределы компонента
const staticClasses = cn('base-class', 'another-class');

function MyComponent() {
  return <Block className={staticClasses}>Содержимое</Block>;
}

4. Компромисс между компонентом и элементом

Использование базовых компонентов добавляет тонкий слой абстракции поверх чистого HTML. Для критичных по производительности сценариев с тысячами элементов (например, виртуализированные списки), рассмотрите использование чистого HTML с классами Tailwind:
// Базовый компонент: ~1мс накладных расходов на 100 элементов
<Block p="md">Элемент</Block>

// Чистый HTML: Без накладных расходов абстракции
<div className="p-4">Элемент</div>
Источники: README.md398-403

Связанная документация

Источники: Выведено из структуры wiki.json