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

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

Цель и область применения

Этот документ охватывает пять основополагающих примитивов в Слое 1 архитектуры: Block, Box, Grid, Flex и Stack. Эти компоненты служат строительными блоками для всех компонентов UI и макетов более высокого уровня в библиотеке. Они предоставляют прямой доступ к системе вариантов CVA и реализуют фундаментальные паттерны React, включая forwardRef, композицию типов TypeScript и пересылку HTML-атрибутов. Для документации по составным компонентам, расширяющим эти примитивы (Button, Card и др.), см. UI-компоненты. Для подробностей о системе вариантов см. Система вариантов. Источники: README.md81-103 .devin/wiki.json56-63

Архитектурная роль

Базовые компоненты формируют основу трехслойной архитектуры. Они являются единственными компонентами, которые напрямую применяют систему вариантов CVA и рендерят семантические HTML5-элементы. Все компоненты Слоя 2 (UI-компоненты) и Слоя 3 (Макеты) в конечном итоге компонуют или расширяют эти пять примитивов.
Вывод

Паттерны React

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

Слой 1: Базовые компоненты (этот документ)

Block
component='section' | 'article' | 'nav' | и т.д.
data-class='block'

Box
component='div' | 'span' | любой ElementType
data-class='box'

Grid
CSS Grid макет
props: cols, rows, gap

Flex
Flexbox макет
props: direction, align, justify

Stack
Вертикальное/горизонтальное расположение
props: gap, direction

class-variance-authority
Разрешение вариантов

spacingVariants()
p, m, px, py и т.д.

colorVariants()
bg, c, borderColor

layoutVariants()
w, h, minH, position

roundedVariants()
rounded

shadowVariants()
shadow

borderVariants()
border, borderTop и т.д.

forwardRef()
Пересылка ref в DOM

Интерфейсы TypeScript
HTMLAttributes + VariantProps

...props
Пересылка HTML-атрибутов

Семантический HTML5
section, article, nav, header, footer

Атрибуты data-class
для обращения к DOM

Классы Tailwind CSS
применяются к className
Источники: README.md62-103 src/components/ui/Block/Block.tsx1-88

Пять основных примитивов

Обзорная таблица

КомпонентОсновное назначениеПоддержка семантического HTMLКлючевые вариантыШирина по умолчанию
BlockСемантические блочные контейнерыsection, article, nav, header, footer, aside, main, divspacing, color, layout, rounded, shadow, borderw='full'
BoxУниверсальный гибкий контейнерЛюбой ElementType (div, span, p и т.д.)spacing, color, layoutНет по умолчанию
GridМакеты CSS Griddiv с display: gridspacing, layout, cols, rows, gapНет по умолчанию
FlexМакеты Flexboxdiv с display: flexspacing, layout, direction, align, justifyНет по умолчанию
StackВертикальное/горизонтальное расположениеdiv с flexbox-расположениемspacing, gap, directionНет по умолчанию
Источники: README.md81-103

Фундаментальные паттерны React

Реализация forwardRef

Все базовые компоненты реализуют forwardRef для предоставления ссылки на базовый DOM-элемент родительским компонентам. Это позволяет выполнять императивные операции с DOM и интегрироваться со сторонними библиотеками.
ref={blockRef}

пересылка ref

blockRef.current?.scrollIntoView()

Родительский компонент
const blockRef = useRef(null)

Block
forwardRef

DOM-элемент
section | article | nav | и т.д.
Пример структуры из компонента Block: src/components/ui/Block/Block.tsx33-36
export const Block = forwardRef<HTMLElement, BlockProps>(
  ({ children, className, component, variant = 'div', ...props }, ref) => {
    // Реализация компонента
  }
);
Источники: src/components/ui/Block/Block.tsx33-86

Композиция типов TypeScript

Базовые компоненты компонуют множество интерфейсов TypeScript для достижения типобезопасности между HTML-атрибутами, пропсами вариантов и кастомными пропсами компонента.
extends

extends

extends

Pick<..., 'w' | 'h' | 'minH' | 'position'>

extends

extends

extends

включает

BlockProps
Интерфейс компонента

React.HTMLAttributes
Стандартные HTML-атрибуты

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 и т.д.

Кастомные пропсы
children: ReactNode
component?: ElementType
variant?: 'section' | 'article' | ...
Паттерн композиции типов из Block: src/components/ui/Block/Block.tsx20-31
export interface BlockProps 
  extends React.HTMLAttributes<HTMLElement>,
    VariantSpacingProps,
    ColorProps,
    Pick<VariantLayoutProps, 'w' | 'h' | 'minH' | 'position'>,
    RoundedProps,
    ShadowProps,
    BorderProps {
  children: ReactNode;
  component?: ElementType;
  variant?: 'section' | 'main' | 'nav' | 'article' | 'header' | 'footer' | 'aside' | 'div';
}
Источники: src/components/ui/Block/Block.tsx20-31

Деструктуризация пропсов и пересылка HTML-атрибутов

Базовые компоненты явно деструктурируют пропсы вариантов и пересылают оставшиеся HTML-атрибуты в базовый DOM-элемент, используя оператор spread (...props).
Входящие пропсы
p='lg', onClick, data-testid и т.д.

Деструктурированные пропсы вариантов
p, px, py, m, bg, c, w, h, rounded, shadow, border

Остальные пропсы (...props)
onClick, data-testid, aria-label и т.д.

Функции вариантов
spacingVariants({ p, px, py, ... })
colorVariants({ bg, c })
layoutVariants({ w, h })

prop className
cn(варианты, кастомный className)

Базовый компонент
Block/Box/Grid/Flex/Stack

Отрендеренный DOM-элемент
с className + ...props
Паттерн деструктуризации пропсов из Block: src/components/ui/Block/Block.tsx34-61
({ 
  children, 
  className,
  component,
  variant = 'div',
  // Пропсы отступов
  p, px, py, pt, pb, pl, pr,
  m, mx, my, mt, mb, ml, mr,
  // Пропсы цвета
  bg, c, borderColor,
  // Пропсы макета
  w = 'full', h, minH, position,
  // Визуальные пропсы
  rounded, shadow,
  // Пропсы границ
  border, borderTop, borderBottom, borderLeft, borderRight,
  ...props  // Оставшиеся HTML-атрибуты
}, ref)
Источники: src/components/ui/Block/Block.tsx34-86

Специфичные возможности компонентов

Block: семантический HTML-контейнер

Block разработан для семантических блочных элементов. По умолчанию имеет w='full' (полная ширина) и предоставляет проп variant для выбора семантических HTML5-элементов. Ключевые характеристики:
  • Выбор семантического элемента через проп variant
  • Полная ширина по умолчанию (w='full')
  • Поддерживает все варианты spacing, color, layout, rounded, shadow и border
  • Использует data-class="block" для обращения к DOM
Разрешение типа элемента: src/components/ui/Block/Block.tsx62-68
// Использовать variant как component, если component не указан явно
const elementType = component || variant;

return (
  <BaseBlock
    ref={ref}
    component={elementType}
    data-class="block"
Примеры использования:
// Рендерится как <section> с полной шириной
<Block variant="section" p="lg" rounded="xl">
  Содержимое секции
</Block>

// Рендерится как <nav> с кастомным фоном
<Block variant="nav" bg="primary" c="white">
  Навигационные ссылки
</Block>

// Переопределение кастомным компонентом
<Block component="article" p="md">
  Содержимое статьи
</Block>
Источники: src/components/ui/Block/Block.tsx1-88 README.md85-87

Box: гибкий универсальный контейнер

Box является самым гибким примитивом, принимающим любой ElementType через проп component. Не имеет ширины по умолчанию и минимальных дефолтных настроек, что делает его подходящим для инлайн-элементов и кастомных макетов. Ключевые характеристики:
  • Принимает любой React ElementType (div, span, p, a, button, кастомные компоненты)
  • Нет ширины или высоты по умолчанию
  • Поддерживает варианты spacing, color и layout
  • Использует data-class="box" для обращения к DOM
Примеры использования:
// Рендерится как <div>
<Box p="md" bg="card">
  Универсальный контейнер
</Box>

// Рендерится как <span> (инлайн)
<Box component="span" c="primary" weight="bold">
  Инлайн-текст
</Box>

// Рендерится как кастомный элемент
<Box component="input" w="full" p="sm" border="default" />
Источники: README.md85 src/components/ui/Box/index.ts1

Grid: CSS Grid макет

Grid предоставляет возможности CSS Grid макета с пропсами для колонок, строк и промежутков. Ключевые характеристики:
  • display: grid применяется по умолчанию
  • Проп cols для количества колонок
  • Проп rows для количества строк
  • Проп gap для промежутков в сетке
  • Поддерживает варианты spacing и layout
Примеры использования:
// Сетка с 2 колонками и промежутками
<Grid cols={2} gap="md" p="lg">
  <Box>Элемент 1</Box>
  <Box>Элемент 2</Box>
  <Box>Элемент 3</Box>
  <Box>Элемент 4</Box>
</Grid>

// Адаптивная сетка с 3 колонками
<Grid cols={3} gap="lg" w="full">
  {items.map(item => <Card key={item.id}>{item.name}</Card>)}
</Grid>
Источники: README.md88

Flex: Flexbox макет

Flex предоставляет возможности Flexbox макета с пропсами для направления, выравнивания и распределения. Ключевые характеристики:
  • display: flex применяется по умолчанию
  • Проп direction для flex-direction
  • Проп align для align-items
  • Проп justify для justify-content
  • Поддерживает варианты spacing и layout
Примеры использования:
// Горизонтальный flex с центрированными элементами
<Flex direction="row" align="center" justify="between" p="md">
  <Text>Левое содержимое</Text>
  <Button>Правое действие</Button>
</Flex>

// Вертикальный flex
<Flex direction="column" gap="md">
  <Box>Элемент 1</Box>
  <Box>Элемент 2</Box>
</Flex>
Источники: README.md88

Stack: упрощенное расположение

Stack — это специализированный flex-контейнер для вертикального или горизонтального расположения с постоянными промежутками. Ключевые характеристики:
  • Упрощенный API по сравнению с Flex
  • Проп direction: ‘vertical’ (по умолчанию) или ‘horizontal’
  • Проп gap для промежутков между дочерними элементами
  • Автоматический flex-макет
Примеры использования:
// Вертикальное расположение (по умолчанию)
<Stack gap="md" p="lg">
  <Text>Элемент 1</Text>
  <Text>Элемент 2</Text>
  <Text>Элемент 3</Text>
</Stack>

// Горизонтальное расположение
<Stack direction="horizontal" gap="sm">
  <Button>Отмена</Button>
  <Button variant="primary">Отправить</Button>
</Stack>
Источники: README.md89

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

Базовые компоненты применяют варианты, используя утилиту cn(), которая объединяет сгенерированные вариантами классы с кастомными пропсами className, используя tw-merge для разрешения конфликтов.
валидируется через

Пропсы вариантов
p='lg', bg='card', rounded='xl'

Функции вариантов
spacingVariants({ p: 'lg' })
colorVariants({ bg: 'card' })
roundedVariants({ rounded: 'xl' })

Сгенерированные классы
'p-8' (из p='lg')
'bg-card' (из bg='card')
'rounded-xl' (из rounded='xl')

Кастомный className
(опциональное переопределение пользователем)

утилита cn()
tw-merge для разрешения конфликтов

Финальный className
применяется к компоненту

core-classes.json
белый список из 618 классов
предотвращает очистку Tailwind
Паттерн применения из Block: src/components/ui/Block/Block.tsx70-79
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.tsx70-79

Паттерн импорта и экспорта

Базовые компоненты следуют единообразной структуре импорта/экспорта для tree-shaking и типобезопасности.

Структура файлов компонента

Каждый базовый компонент имеет отдельную директорию с двумя файлами:
src/core/ui/Block/
├── Block.tsx          # Реализация компонента
└── index.ts           # Публичные экспорты

Паттерн импорта в файлах компонентов

src/components/ui/Block/Block.tsx3-18
import {
  Block as BaseBlock,           // Базовый компонент из core
  spacingVariants,              // Функции вариантов
  colorVariants,
  layoutVariants,
  roundedVariants,
  shadowVariants,
  borderVariants,
  type VariantSpacingProps,     // Типы TypeScript
  type ColorProps,
  type VariantLayoutProps,
  type RoundedProps,
  type ShadowProps,
  type BorderProps,
  cn                            // Утилитная функция
} from "@ui8kit/core";

Паттерн экспорта в index-файлах

src/components/ui/Box/index.ts1
export { Box, type BoxProps } from "./Box";
Структура экспорта:
  • Именованный экспорт для компонента
  • Именованный экспорт для интерфейса пропсов TypeScript с использованием ключевого слова type
  • Нет экспортов по умолчанию (обеспечивает единообразный синтаксис импорта)
Источники: src/components/ui/Block/Block.tsx1-18 src/components/ui/Box/index.ts1

Атрибуты data-class

Все базовые компоненты включают атрибут data-class для единообразного обращения к DOM в тестах, CSS-селекторах и инструментах отладки.
Block
data-class='block'

Box
data-class='box'

Grid
data-class='grid'

Flex
data-class='flex'

Stack
data-class='stack'

Запросы к DOM
document.querySelector('[data-class=block]')
screen.getByTestId('block')

CSS-селекторы
[data-class='block'] { ... }

Инструменты браузера
фильтрация по data-class
Использование из компонента Block: src/components/ui/Block/Block.tsx69
data-class="block"
Пример тестирования у потребителя:
// React Testing Library
const blockElement = screen.getByTestId('block');

// Прямой запрос к DOM
const allBlocks = document.querySelectorAll('[data-class="block"]');

// Cypress
cy.get('[data-class="block"]').should('exist');
Источники: src/components/ui/Block/Block.tsx69

Соглашение displayName

Все базовые компоненты устанавливают displayName для улучшения опыта отладки в React DevTools и сообщениях об ошибках. src/components/ui/Block/Block.tsx88
Block.displayName = "Block";
Преимущества:
  • Четкие имена компонентов в дереве компонентов React DevTools
  • Улучшенные трассировки стека ошибок
  • Лучшая отладка с предупреждениями React.StrictMode
Источники: src/components/ui/Block/Block.tsx88

Связь с верхними слоями

Базовые компоненты служат основой для Слоя 2 (UI-компоненты) и Слоя 3 (Макеты). Компоненты более высокого уровня либо расширяют базовые компоненты дополнительными пропсами, либо компонуют несколько базовых компонентов вместе.
Слой 1: Базовые компоненты

Слой 2: UI-компоненты

Слой 3: Макеты

использует

использует

использует

использует

использует

использует

расширяет

расширяет

использует

DashLayout
Компонует: Container, Grid, Flex

LayoutBlock
Использует: Grid или Flex

SplitBlock
Использует: Container

Card
Расширяет: Block
Пересылает пропсы вариантов

Button
Расширяет: Box
Добавляет специфичные для кнопки варианты

Container
Использует: Block
Добавляет логику max-width

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

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

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

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

Stack
Прямое применение вариантов
Паттерн расширения (Card расширяет Block):
// Компонент Card внутренне использует Block
<Block
  component="div"
  data-class="card"
  className={cn(cardVariants({ variant }), className)}
  {...variantProps}  // Пересылает пропсы spacing, color, layout
>
  {children}
</Block>
Паттерн композиции (DashLayout использует Grid):
// DashLayout компонует несколько базовых компонентов
<Block component="div" className="dashboard-layout">
  <Grid cols={12} gap="md">
    <Block component="aside" className="sidebar">
      {sidebar}
    </Block>
    <Block component="main" className="content">
      {children}
    </Block>
  </Grid>
</Block>
Источники: README.md62-168

Резюме

Базовые компоненты реализуют пять фундаментальных паттернов:
  1. forwardRef - предоставляют ссылки на DOM родительским компонентам
  2. Композиция типов - комбинируют React.HTMLAttributes с типами пропсов вариантов
  3. Деструктуризация пропсов - извлекают пропсы вариантов и пересылают HTML-атрибуты
  4. Применение вариантов - применяют варианты CVA через утилиту cn()
  5. Семантический HTML - рендерят соответствующие HTML5-элементы через проп component
Эти паттерны обеспечивают:
  • Типобезопасные API компонентов с полным выводом типов TypeScript
  • Прямой доступ к системе вариантов без накладных расходов на пересылку пропсов
  • Гибкую семантическую HTML-структуру для доступности
  • Единообразное обращение к DOM через атрибуты data-class
  • Чистую отладку в React DevTools с displayName
Все компоненты более высокого уровня в библиотеке либо расширяют, либо компонуют эти пять примитивов, обеспечивая архитектурную согласованность во всей системе. Источники: README.md62-103 src/components/ui/Block/Block.tsx1-88 .devin/wiki.json56-63