Documentation Index
Fetch the complete documentation index at: https://ui8kit.buildy.tw/llms.txt
Use this file to discover all available pages before exploring further.
Лучшие практики
Этот документ содержит общие рекомендации и указания по эффективному использованию библиотеки компонентов @ui8kit/core. Он охватывает стратегии выбора компонентов, использование системы вариантов, практики семантического HTML, доступность, оптимизацию производительности и паттерны композиции.
Для общих паттернов разработки и типичных примеров использования см. Базовый рабочий процесс. Для обработки граничных случаев, требующих пользовательских решений, см. Продвинутый рабочий процесс.
Стратегия выбора компонентов
Выбор правильного уровня компонента является основой для написания поддерживаемого кода. Трёхслойная архитектура обеспечивает чёткие границы для различных уровней абстракции.
Схема принятия решений для выбора компонентов
Да
Нет
Да
Нет
Да
Нет
Grid макет
Flex макет
Стек элементов
Универсальный
Необходимо отрисовать
UI элемент
Создание структуры
страницы или
дашборда?
Нужен готовый
компонент с
вариантами?
Нужен семантический
HTML элемент?
Нужен контроль
макета?
Использовать DashLayout
src/layouts/DashLayout.tsx
Использовать LayoutBlock
src/layouts/LayoutBlock.tsx
Использовать SplitBlock
src/layouts/SplitBlock.tsx
Использовать UI компонент
Button, Card, Badge и т.д.
src/components/ui/
Использовать Block
с пропом component
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
Источники: README.md64-89 README.md105-120 README.md147-168 src/components/README.md1-19
Использование Уровня 1: Базовые примитивы
Используйте базовые примитивы, когда вам нужен максимальный контроль над макетом и семантической структурой:
| Компонент | Когда использовать | Пример сценария |
Block | Нужен семантический HTML5 элемент с вариантами | <Block component="section">, <Block component="nav"> |
Box | Нужен универсальный контейнер без семантического значения | Обёрточные div’ы, flex элементы, ячейки сетки |
Grid | Нужен CSS Grid макет | Сетки товаров, галереи изображений, макеты карточек |
Flex | Нужен flexbox макет с явным контролем | Пользовательские панели инструментов, сложное выравнивание |
Stack | Нужна вертикальная/горизонтальная укладка с промежутком | Поля форм, группы кнопок, секции контента |
Источники: README.md81-103 src/components/README.md23-92
Использование Уровня 2: UI компоненты
Используйте UI компоненты для готовых, предварительно стилизованных элементов:
// ✅ Хорошо: Использование UI компонента для обычных элементов
<Button variant="primary" size="lg" p="md" rounded="lg">
Submit
</Button>
// ❌ Плохо: Воссоздание UI компонента с примитивами
<Box
component="button"
className="inline-flex items-center justify-center bg-primary text-primary-foreground..."
>
Submit
</Box>
Источники: README.md105-145 src/components/README.md94-204
Использование Уровня 3: Компоненты макетов
Используйте компоненты макетов для структурной организации страницы:
// ✅ Хорошо: DashLayout для структуры дашборда
<DashLayout
sidebar={<NavigationSidebar />}
header={<DashboardHeader />}
>
<Container>
<Card p="lg">Content</Card>
</Container>
</DashLayout>
// ❌ Плохо: Ручная реконструкция макета
<Box className="flex min-h-screen">
<Box className="w-64 border-r">
<NavigationSidebar />
</Box>
{/* Сложная ручная логика макета */}
</Box>
Источники: README.md147-168 src/layouts/DashLayout.tsx1-99
Использование системы вариантов
Система вариантов устраняет ~80% использования className через 12 композируемых вариантов. Следуйте этим рекомендациям, чтобы максимизировать её эффективность.
Поток применения вариантов
Разработчик пишет JSX
Пропы вариантов
p='lg'
rounded='xl'
shadow='md'
bg='card'
class-variance-authority
Преобразует варианты в классы
core-classes.json
618 валидированных классов
Tailwind CSS
Применяет утилитарные классы
Отрисованный DOM
с семантическими элементами
Источники: README.md170-217 src/lib/core-classes.json1-619 scripts/cva-extractor.ts223-260
Рекомендации по композиции вариантов
| Категория вариантов | Пропы | Значения | Случай использования |
| Spacing | p, px, py, pt, pb, pl, pr, m, mx, my, mt, mb, ml, mr | none, xs, sm, md, lg, xl, 2xl, auto | Контроль отступов и полей |
| Colors | bg, c, borderColor | Цвета дизайн-системы | Цвета фона, текста, границ |
| Layout | w, h, minH, maxW, position | auto, full, screen, fit, min, max | Контроль размеров и позиционирования |
| Typography | size, weight, align, leading | Значения для шрифтов | Стилизация текста |
| Effects | rounded, shadow, border | Предустановленные значения | Визуальные улучшения |
// ✅ Хорошо: Композиция вариантов для сложной стилизации
<Card
p="xl"
rounded="2xl"
shadow="lg"
bg="card"
border="default"
w="full"
maxW="2xl"
mx="auto"
>
Content
</Card>
// ❌ Плохо: Использование className для стилей, покрываемых вариантами
<Card className="p-12 rounded-2xl shadow-lg bg-card border w-full max-w-2xl mx-auto">
Content
</Card>
// ⚠️ Допустимо: className для 20% граничных случаев
<Card
p="xl"
rounded="2xl"
className="animate-pulse hover:scale-105 transition-transform"
>
Пользовательская анимация
</Card>
Источники: README.md171-217 src/components/README.md206-222
Когда использовать className
Система вариантов покрывает ~80% потребностей в стилизации. Используйте className для:
- Анимаций и переходов (не покрывается вариантами)
- Псевдоклассов таких как
:hover, :focus, :active
- Пользовательских grid/flex паттернов за пределами базовых макетов
- Специфичных для проекта утилитарных классов, не входящих в дизайн-систему
// ✅ Хорошо: Использование className для анимаций
<Box
p="lg"
rounded="xl"
className="hover:scale-105 transition-transform duration-200"
>
Интерактивный элемент
</Box>
// ✅ Хорошо: Использование className для псевдоклассов
<Button
variant="primary"
size="md"
className="focus-visible:ring-2 focus-visible:ring-offset-2"
>
Доступная кнопка
</Button>
Источники: README.md278-304 src/components/README.md237-244
Лучшие практики семантического HTML
Библиотека делает акцент на семантических элементах HTML5 для доступности и SEO. Всегда используйте наиболее подходящий семантический элемент.
Выбор семантического элемента
Да
Нет
Да
Нет
Да
Нет
Да
Нет
Да
Нет
Да
Нет
Да
Нет
Рендеринг контента
Меню навигации
или ссылки?
Самодостаточный
синдицированный контент?
Тематическая
группировка?
Косвенно связанный
контент?
Вводный
контент?
Контент футера?
Основная область
контента?
Block component='nav'
Block component='article'
Block component='section'
Block component='aside'
Block component='header'
Block component='footer'
Block component='main'
Box
универсальный контейнер
Источники: README.md14 src/components/README.md239 src/core/ui/Block.tsx1-15
Примеры семантического HTML
// ✅ Хорошо: Семантическая структура страницы
<Block component="main" py="xl">
<Block component="section" py="lg">
<Container>
<Block component="header" mb="lg">
<Title order={1}>Заголовок страницы</Title>
</Block>
<Block component="article">
<Text>Контент статьи...</Text>
</Block>
</Container>
</Block>
</Block>
// ❌ Плохо: Универсальные div'ы повсюду
<Box py="xl">
<Box py="lg">
<Container>
<Box mb="lg">
<Title order={1}>Заголовок страницы</Title>
</Box>
<Box>
<Text>Контент статьи...</Text>
</Box>
</Container>
</Box>
</Box>
// ✅ Хорошо: Навигация с семантическим nav элементом
<Block component="nav" p="md" bg="background" border="default">
<Stack gap="sm">
<a href="/">Главная</a>
<a href="/about">О нас</a>
</Stack>
</Block>
// ✅ Хорошо: Правильная иерархия заголовков
<Block component="article">
<Title order={1}>Главный заголовок</Title>
<Title order={2}>Заголовок секции</Title>
<Title order={3}>Заголовок подсекции</Title>
</Block>
Источники: README.md14 src/components/README.md28-64 src/core/ui/Block.tsx1-15
Лучшие практики доступности
Убедитесь, что все компоненты доступны для пользователей с ограниченными возможностями, следуя рекомендациям WCAG.
Основные принципы доступности
| Принцип | Реализация | Пример |
| Навигация с клавиатуры | Обеспечьте доступность всех интерактивных элементов с клавиатуры | Используйте семантический <button> вместо <div onClick> |
| ARIA метки | Предоставьте метки для программ чтения с экрана | aria-label, aria-labelledby, aria-describedby |
| Управление фокусом | Видимые индикаторы фокуса | Стили :focus-visible |
| Цветовой контраст | Минимальное соотношение 4.5:1 для текста | Используйте цвета дизайн-системы |
| Альтернативный текст | Описательный текст для изображений | Всегда предоставляйте проп alt |
// ✅ Хорошо: Доступная кнопка
<Button
variant="primary"
size="md"
aria-label="Отправить форму"
className="focus-visible:ring-2 focus-visible:ring-primary"
>
Отправить
</Button>
// ✅ Хорошо: Доступное изображение
<Image
src="/product.jpg"
alt="Синие кроссовки с белыми полосками"
rounded="lg"
/>
// ✅ Хорошо: Доступная навигация
<Block component="nav" aria-label="Основная навигация">
<Stack gap="md" role="list">
<a href="/" role="listitem">Главная</a>
<a href="/about" role="listitem">О нас</a>
</Stack>
</Block>
// ❌ Плохо: Несемантический интерактивный элемент
<Box
onClick={handleClick}
className="cursor-pointer"
>
Нажми меня
</Box>
// ✅ Хорошо: Использование компонента Button
<Button onClick={handleClick}>
Нажми меня
</Button>
Источники: README.md14 src/components/ui/Button.tsx1-40 src/components/ui/Image.tsx1-20
Доступность форм
// ✅ Хорошо: Доступная форма с семантической структурой
<Block component="form" onSubmit={handleSubmit}>
<Stack gap="md">
<Box>
<Text as="label" htmlFor="email" weight="medium" mb="xs">
Email
</Text>
<Box
component="input"
id="email"
type="email"
aria-required="true"
aria-describedby="email-error"
p="sm"
rounded="md"
border="default"
w="full"
/>
<Text id="email-error" size="sm" c="destructive" mt="xs">
{emailError}
</Text>
</Box>
<Button type="submit" variant="primary">
Отправить
</Button>
</Stack>
</Block>
Источники: src/components/GUIDE_CREATE_FORM.md1-50 src/components/README.md239
Оптимизация производительности
Следуйте этим паттернам для поддержания оптимальной производительности в больших приложениях.
Композиция компонентов против передачи пропов
// ✅ Хорошо: Естественная композиция компонентов
<Card p="lg" rounded="xl">
<Card.Header>
<Title order={2}>Товар</Title>
</Card.Header>
<Card.Content>
<Stack gap="md">
<Image src="/product.jpg" alt="Товар" />
<Text>Описание</Text>
</Stack>
</Card.Content>
<Card.Footer>
<Button variant="primary">Купить сейчас</Button>
</Card.Footer>
</Card>
// ❌ Плохо: Избыточная передача пропов
<ProductCard
title="Товар"
imageSrc="/product.jpg"
imageAlt="Товар"
description="Описание"
buttonText="Купить сейчас"
buttonVariant="primary"
cardPadding="lg"
cardRounded="xl"
/>
Источники: README.md306-338 src/components/ui/Card.tsx1-80
Рекомендации по мемоизации
import { memo } from 'react';
// ✅ Хорошо: Мемоизация дорогих элементов списка
const ProductCard = memo(({ product }) => (
<Card p="md" rounded="lg">
<Card.Content>
<Stack gap="sm">
<Image src={product.image} alt={product.name} />
<Text>{product.name}</Text>
<Text size="sm" c="muted-foreground">
${product.price}
</Text>
</Stack>
</Card.Content>
</Card>
));
// ✅ Хорошо: Использование forwardRef для передачи ref
import { forwardRef } from 'react';
const CustomInput = forwardRef((props, ref) => (
<Box
component="input"
ref={ref}
p="sm"
rounded="md"
border="default"
{...props}
/>
));
Источники: src/core/ui/Box.tsx1-30 src/components/ui/Button.tsx1-40
Избегайте ненужных повторных рендеров
// ✅ Хорошо: Использование примитивных значений в качестве зависимостей
const [count, setCount] = useState(0);
useEffect(() => {
// Логика эффекта
}, [count]);
// ❌ Плохо: Зависимости-объекты/массивы вызывают ненужные повторные рендеры
const config = { theme: 'dark' };
useEffect(() => {
// Это выполняется при каждом рендере
}, [config]);
// ✅ Хорошо: Извлечение примитивных значений
const theme = config.theme;
useEffect(() => {
// Это выполняется только при изменении theme
}, [theme]);
Источники: README.md341-359
Паттерны композиции
Библиотека поддерживает несколько паттернов композиции. Выберите подходящий паттерн для вашего случая использования.
Сравнение паттернов
Паттерн 4: Композиция через Children
Stack
Дочерний компонент 1
Дочерний компонент 2
Дочерний компонент 3
Паттерн 3: Хуки контента
LayoutBlock
функция beforeContent
функция content
функция afterContent
Паттерн 2: Передача пропов
Button
расширяет BaseButton
spacingVariants
roundedVariants
shadowVariants
Паттерн 1: Составные компоненты
Card
Card.Header
Card.Content
Card.Footer
Источники: README.md15-17 src/layouts/LayoutBlock.tsx15-22 src/components/ui/Card.tsx1-80
Паттерн составных компонентов
Используйте для гибких структур компонентов с предопределёнными подкомпонентами:
// ✅ Хорошо: Гибкая композиция карточки
<Card p="lg" rounded="xl" shadow="md">
<Card.Header>
<Card.Title>Заголовок</Card.Title>
<Card.Description>Описание</Card.Description>
</Card.Header>
<Card.Content>
<Stack gap="md">
{/* Контент */}
</Stack>
</Card.Content>
<Card.Footer>
<Group gap="md" justify="end">
<Button variant="secondary">Отмена</Button>
<Button variant="primary">Сохранить</Button>
</Group>
</Card.Footer>
</Card>
// ✅ Хорошо: Опциональные части
<Card p="lg">
<Card.Content>
{/* Только контент, без header/footer */}
</Card.Content>
</Card>
Источники: README.md38-59 README.md121-145 src/components/ui/Card.tsx1-80
Паттерн передачи пропов
Все UI компоненты передают пропы вариантов от базовых компонентов:
// ✅ Хорошо: Button с переданными вариантами отступов и визуальными вариантами
<Button
variant="primary"
size="lg"
p="md" // Из spacingVariants
rounded="lg" // Из roundedVariants
shadow="sm" // Из shadowVariants
>
Нажми меня
</Button>
// ✅ Хорошо: Card с переданными вариантами макета
<Card
p="xl" // Из spacingVariants
rounded="2xl" // Из roundedVariants
shadow="lg" // Из shadowVariants
w="full" // Из layoutVariants
maxW="2xl" // Из layoutVariants
mx="auto" // Из spacingVariants
>
Контент
</Card>
Источники: README.md16 src/components/README.md12-18 src/components/ui/Button.tsx1-40
Паттерн хуков контента
Используйте для динамического рендеринга в компонентах макетов:
// ✅ Хорошо: LayoutBlock с хуками контента
<LayoutBlock
layout="grid"
cols={3}
gap="lg"
contentHooks={{
beforeContent: () => (
<Block component="header" mb="lg">
<Title order={1}>Заголовок страницы</Title>
</Block>
),
content: () => products.map(product => (
<Card key={product.id} p="md">
{/* Карточка товара */}
</Card>
)),
afterContent: () => (
<Block component="footer" mt="lg">
<Button>Загрузить ещё</Button>
</Block>
)
}}
/>
Источники: src/layouts/LayoutBlock.tsx15-22 src/layouts/LayoutBlock.tsx1-50
Распространённые антипаттерны
Избегайте этих распространённых ошибок при использовании библиотеки.
Антипаттерн 1: Чрезмерное использование className
// ❌ Плохо: Использование className для стилей, покрываемых вариантами
<Card className="p-12 rounded-2xl shadow-lg bg-card w-full max-w-2xl">
Контент
</Card>
// ✅ Хорошо: Использование вариантов
<Card p="xl" rounded="2xl" shadow="lg" bg="card" w="full" maxW="2xl">
Контент
</Card>
Антипаттерн 2: Обход семантического HTML
// ❌ Плохо: Универсальные div'ы для навигации
<Box className="nav-container">
<Box className="nav-item">Главная</Box>
<Box className="nav-item">О нас</Box>
</Box>
// ✅ Хорошо: Семантическая навигация
<Block component="nav" aria-label="Основная навигация">
<Stack gap="md" component="ul" role="list">
<li><a href="/">Главная</a></li>
<li><a href="/about">О нас</a></li>
</Stack>
</Block>
Антипаттерн 3: Воссоздание существующих компонентов
// ❌ Плохо: Воссоздание компонента Button
const CustomButton = ({ children, ...props }) => (
<Box
component="button"
className="inline-flex items-center justify-center rounded-md px-4 py-2 bg-primary text-white"
{...props}
>
{children}
</Box>
);
// ✅ Хорошо: Расширение существующего Button
import { Button } from '@ui8kit/core';
const CustomButton = ({ children, ...props }) => (
<Button
variant="primary"
size="md"
className="custom-animation" // Добавляем только пользовательские стили
{...props}
>
{children}
</Button>
);
Антипаттерн 4: Избыточная вложенность
// ❌ Плохо: Ненужная вложенность обёрток
<Box>
<Box>
<Box>
<Box>
<Text>Контент</Text>
</Box>
</Box>
</Box>
</Box>
// ✅ Хорошо: Минимальная вложенность
<Box>
<Text>Контент</Text>
</Box>
// ✅ Хорошо: Использование Stack для отступов вместо обёрток
<Stack gap="md">
<Text>Элемент 1</Text>
<Text>Элемент 2</Text>
<Text>Элемент 3</Text>
</Stack>
Антипаттерн 5: Игнорирование data-class атрибутов
// ❌ Плохо: Пользовательские селекторы без data-class
<Card className="my-custom-card">
<div className="my-custom-header">Заголовок</div>
</Card>
// ✅ Хорошо: Использование data-class атрибутов для таргетинга
<Card data-class="product-card">
<Card.Header data-class="product-card-header">
Заголовок
</Card.Header>
</Card>
// В CSS или тестировании:
// [data-class="product-card"] { ... }
// screen.getByTestId('product-card')
Источники: src/components/README.md223-235 src/components/README.md237-244
Итоговый контрольный список
Используйте этот контрольный список при создании интерфейсов с @ui8kit/core:
Источники: README.md388-402 src/components/README.md237-244