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.
Макеты
Этот документ охватывает компоненты макетов уровня 3 в архитектуре @ui8kit/core: DashLayout, LayoutBlock и SplitBlock. Это компоненты уровня шаблонов (организмы), которые организуют UI-компоненты уровня 2 и примитивы уровня 1 в структурные макеты страниц. Эта страница фокусируется на паттернах композиции макетов, системах хуков контента и особых соображениях при создании структур приложений.
Для базовых примитивов макетов (Grid, Flex, Stack) см. Базовые компоненты.
Для UI-компонентов, используемых внутри макетов, см. UI-компоненты.
Для деталей API и справки по пропсам см. API компонентов макетов.
Обзор архитектуры макетов
Система макетов работает на самом высоком архитектурном уровне, компонуя UI-компоненты и примитивы в полные структуры страниц. Три компонента макетов служат различным структурным целям:
Внешние зависимости
Уровень 1: Используемые примитивы
Уровень 2: Используемые UI-компоненты
Уровень 3: Компоненты макетов
использует
использует
использует
использует
использует
использует
требует
использует
использует
использует
использует
использует
использует
использует
использует
использует
использует
использует
использует
использует
опциональные иконки
опциональные иконки
DashLayout
(Структура дашборда)
LayoutBlock
(Секции контента)
SplitBlock
(Двухколоночные макеты)
Card
Button
Text
Title
Badge
Icon
Image
Container
Group
Block
(Семантические секции)
Box
(Общий контейнер)
Grid
(CSS Grid)
Stack
(Вертикальный/горизонтальный)
react-resizable-panels
(PanelGroup, Panel)
lucide-react
(Компоненты иконок)
Источники: src/layouts/DashLayout.tsx1-99 src/layouts/LayoutBlock.tsx1-389 src/layouts/SplitBlock.tsx1-145 README.md147-168
DashLayout - Шаблон дашборда
DashLayout предоставляет полную структуру дашборда с изменяемыми панелями, навигационным заголовком и сворачиваемой боковой панелью. Он использует react-resizable-panels для интерактивного управления панелями.
Структура компонента
рендерит
рендерит
содержит
содержит
содержит
оборачивает
оборачивает
использует
использует
использует
использует
использует
использует
использует
использует
Dashboard
(Основной компонент)
Navbar
(Заголовок с брендом + переключатель темы)
Sidebar
(Сворачиваемая навигация)
Main Panel
(Область контента)
PanelGroup
(direction: horizontal)
Panel
(Контейнер боковой панели)
PanelResizeHandle
(Ручка перетаскивания)
Panel
(Контейнер контента)
Block component='nav'
Group
Button variant='ghost'
Icon
Text
Block component='aside'
Stack
Container
Ключевые интерфейсы и пропсы
| Интерфейс | Назначение | Ключевые пропсы |
DashboardProps | Конфигурация основного макета | page, children, sidebar, navbarProps |
NavbarProps | Конфигурация заголовка | isDarkMode, toggleDarkMode, brand |
SidebarProps | Конфигурация боковой панели | children, title, dataClass |
Детали реализации
Компонент Dashboard в src/layouts/DashLayout.tsx64-91 организует макет:
- Navbar рендерится вверху с переключателем темы в src/layouts/DashLayout.tsx34-49
- PanelGroup с
direction="horizontal" создает изменяемый макет в src/layouts/DashLayout.tsx75-88
- Panel компоненты определяют боковую панель (20% по умолчанию, диапазон 10-40%) и область контента (80% по умолчанию, минимум 50%) в src/layouts/DashLayout.tsx76-86
- PanelResizeHandle обеспечивает интерактивное изменение размера в src/layouts/DashLayout.tsx80
- Container оборачивает основной контент с адаптивным размером в src/layouts/DashLayout.tsx84
Паттерн использования
import { DashLayout } from '@ui8kit/core';
<DashLayout
sidebar={<NavSidebar />}
navbarProps={{
brand: "MyApp",
isDarkMode: true,
toggleDarkMode: handleToggle
}}
>
<Container>
<Card p="lg">Content</Card>
</Container>
</DashLayout>
Макет автоматически сохраняет размеры панелей через autoSaveId="dashlayout-panels" в src/layouts/DashLayout.tsx75
Источники: src/layouts/DashLayout.tsx1-99 README.md155-168
LayoutBlock - Гибкие секции контента
LayoutBlock - это универсальный компонент макета, который рендерит секции контента с тремя режимами макета (grid, flex, stack) и мощной системой хуков контента для динамического рендеринга.
Режимы макета и конфигурация
рендерит
рендерит
рендерит
использует
использует
использует
оборачивает с
оборачивает в
LayoutBlock
Режим Grid
(layout='grid')
Режим Flex
(layout='flex')
Режим Stack
(layout='stack')
Компонент Grid
cols, gap, align, justify
Компонент Group
gap, align, justify, wrap
Компонент Stack
gap, align
Container
(опциональная обертка)
Block component='section'
Система хуков контента
Система хуков контента в src/layouts/LayoutBlock.tsx22-30 позволяет заменить любую часть рендерящегося контента:
| Хук | Назначение | Сигнатура |
beforeHeader | Контент перед секцией заголовка | (content: any) => ReactNode |
header | Кастомный рендерер заголовка | (content: any) => ReactNode |
afterHeader | Контент после секции заголовка | (content: any) => ReactNode |
beforeItems | Контент перед списком элементов | (content: any) => ReactNode |
item | Кастомный рендерер элемента | (item: any, index: number) => ReactNode |
afterItems | Контент после списка элементов | (content: any) => ReactNode |
Рендереры по умолчанию
Компонент предоставляет рендереры по умолчанию в src/layouts/LayoutBlock.tsx123-227:
Пропсы конфигурации
| Категория пропсов | Пропсы | Назначение |
| Управление макетом | layout, useContainer, containerSize | Режим и настройки контейнера |
| Настройки Grid | cols, gridCols, gap, align, justify | Конфигурация CSS Grid |
| Настройки Flex | wrap, flexWrap | Поведение переноса Flexbox |
| Настройки Stack | stackAlign | Вертикальное выравнивание |
| Настройки заголовка | showHeader, headerAlign | Отображение и выравнивание заголовка |
| Данные контента | content, content.items | Структура данных для рендеринга |
| Кастомизация | contentHooks | Кастомные функции рендеринга |
Структура данных контента
Пропс content в src/layouts/LayoutBlock.tsx61-77 следует этой схеме:
content: {
badge?: string; // Опциональный текст бейджа
title?: string; // Заголовок секции
description?: string; // Описание секции
items?: Array<{
id: string; // Обязательный уникальный идентификатор
title?: string; // Заголовок элемента
description: string; // Описание элемента (обязательно)
image?: { // Опциональное изображение
src: string;
alt: string;
};
lucideIcon?: any; // Опциональный компонент иконки Lucide
[key: string]: any; // Дополнительные кастомные данные
}>;
}
Рендеринг режимов макета
Логика рендеринга в src/layouts/LayoutBlock.tsx298-353 выбирает соответствующий компонент макета:
grid
flex
stack
renderItems()
тип layout?
Компонент Grid
cols, gap, align, justify
data-class='layout-grid'
Компонент Group
gap, align, justify, wrap
data-class='layout-flex'
Компонент Stack
gap, align
data-class='layout-stack'
itemRenderer(item, index)
Каждый макет оборачивает элементы в соответствующий примитивный компонент с атрибутами data-class для таргетинга DOM в src/layouts/LayoutBlock.tsx320-348
Примеры использования
Grid с карточками:
<LayoutBlock
layout="grid"
cols="1-2-3"
gap="lg"
content={{
badge: "Features",
title: "Why Choose Us",
description: "Discover our advantages",
items: [
{
id: "1",
title: "Fast",
description: "Lightning speed",
lucideIcon: Zap
}
]
}}
/>
Flex с кастомными хуками:
<LayoutBlock
layout="flex"
wrap="wrap"
contentHooks={{
header: (content) => <CustomHeader {...content} />,
item: (item, index) => <CustomCard key={item.id} {...item} />
}}
content={data}
/>
Источники: src/layouts/LayoutBlock.tsx1-389 README.md149-154
SplitBlock - Двухколоночный разделенный макет
SplitBlock создает двухколоночные макеты с гибкими медиа и контентными секциями, обычно используемые для героических секций, демонстрации функций и комбинаций контента/изображений.
Режимы макета
SplitBlock
Режим Container
(splitSection=false)
Режим на всю ширину
(splitSection=true)
Block component='section'
Обертка Container
Grid cols='1-2'
Grid cols='1-2'
data-class='split-grid'
leftMedia=true
leftMedia=false
Система хуков контента
Подобно LayoutBlock, SplitBlock поддерживает хуки контента в src/layouts/SplitBlock.tsx11-15:
| Хук | Назначение | Сигнатура |
beforeContent | Контент перед основной секцией | (content: any) => ReactNode |
content | Рендерер основного контента | (content: any) => ReactNode |
afterContent | Контент после основной секции | (content: any) => ReactNode |
API слотов
API слотов в src/layouts/SplitBlock.tsx36-42 предоставляет именованные переопределения:
slots?: {
media?: ReactNode; // Переопределить медиа секцию
header?: ReactNode; // Будущее: Слот заголовка
body?: ReactNode; // Будущее: Слот тела
actions?: ReactNode; // Будущее: Слот действий
}
Разрешение медиа-слота в src/layouts/SplitBlock.tsx91 приоритизирует переопределения слотов над прямыми пропсами.
Пропсы конфигурации
| Пропс | Тип | По умолчанию | Назначение |
mediaSection | ReactNode | - | Контент для медиа-колонки |
contentSection | ReactNode | - | Контент для контентной колонки |
leftMedia | boolean | false | Позиционировать медиа слева |
splitSection | boolean | true | Использовать grid на всю ширину vs контейнер |
containerSize | ContainerSizingProps["size"] | "lg" | Размер контейнера (когда splitSection=false) |
gap | VariantGridProps["gap"] | "lg" | Промежуток между колонками |
align | VariantGridProps["align"] | "center" | Вертикальное выравнивание |
Логика рендеринга макета
Логика рендеринга в src/layouts/SplitBlock.tsx94-136 создает два различных макета:
Режим Container (splitSection=false) в src/layouts/SplitBlock.tsx96-111:
- Оборачивает grid в адаптивный
Container
- Применяет пропсы
containerSize и padding
- Подходит для стандартных секций страниц
Режим на всю ширину (splitSection=true) в src/layouts/SplitBlock.tsx115-135:
- Grid непосредственно после
Block без контейнера
- Использует
data-class="split-grid" для идентификации в src/layouts/SplitBlock.tsx129
- Применяет
flex-1 items-center для высоты на весь viewport
Порядок колонок
Порядок колонок определяется пропсом leftMedia в src/layouts/SplitBlock.tsx106-107 и src/layouts/SplitBlock.tsx131-132:
leftMedia=true: [mediaSection, contentSection]
leftMedia=false: [contentSection, mediaSection]
Примеры использования
Базовый Split с медиа:
<SplitBlock
mediaSection={
<Image src="/hero.jpg" alt="Hero" fit="cover" />
}
contentSection={
<Stack gap="lg">
<Title order={1}>Welcome</Title>
<Text>Description text</Text>
<Button>Get Started</Button>
</Stack>
}
leftMedia
/>
С хуками контента:
<SplitBlock
content={{ title: "Feature", description: "Details" }}
contentHooks={{
beforeContent: (content) => <Badge>{content.badge}</Badge>,
content: (content) => (
<Stack gap="md">
<Title>{content.title}</Title>
<Text>{content.description}</Text>
</Stack>
),
afterContent: () => <Button>Learn More</Button>
}}
slots={{
media: <Image src="/feature.jpg" />
}}
/>
Hero на всю ширину:
<SplitBlock
splitSection
leftMedia={false}
mediaSection={<HeroImage />}
contentSection={<HeroContent />}
/>
Источники: src/layouts/SplitBlock.tsx1-145 README.md149-154
Интеграция с примитивами макетов
Компоненты макетов активно используют примитивы уровня 1 для структуры. Понимание этих примитивов важно для работы с макетами.
Компонент Grid
Используется LayoutBlock (режим grid) и SplitBlock для макетов CSS Grid:
применяет
применяет
применяет
применяет
'1-2-3' создает
Grid
(CSS Grid)
вариант cols
'1-2-3', '2', '3', '4'
вариант gap
'sm', 'md', 'lg', 'xl'
вариант align
'start', 'center', 'end'
вариант justify
'start', 'center', 'between'
Адаптивные колонки
1 колонка мобильная
2 колонки планшет
3 колонки десктоп
Общие конфигурации Grid:
cols="1-2-3" - Адаптивные 1/2/3 колонки
cols="2" - Фиксированные 2 колонки
gap="lg" - Большой промежуток между элементами
align="center" - Центрировать элементы вертикально
Компонент Stack
Используется LayoutBlock (режим stack) и внутри контентных секций для вертикальных макетов:
| Пропс | Значения | Назначение |
gap | "sm", "md", "lg", "xl", "2xl", "3xl" | Вертикальный интервал |
align | "start", "center", "end" | Горизонтальное выравнивание |
ta | "left", "center", "right" | Выравнивание текста |
Компонент Block
Все компоненты макетов используют Block как корневой семантический контейнер:
<Block
component="section" // Семантический HTML5 тег
w="full" // Полная ширина
py="xl" // Вертикальный padding
data-class="layout-block" // Идентификация DOM
>
{/* Контент макета */}
</Block>
Пропс component в src/layouts/DashLayout.tsx16 src/layouts/DashLayout.tsx36 и src/layouts/DashLayout.tsx74 обеспечивает семантическую HTML структуру (<section>, <nav>, <aside>, <main>).
Источники: src/layouts/LayoutBlock.tsx3-16 src/layouts/SplitBlock.tsx3-8 src/layouts/DashLayout.tsx2
Паттерны композиции
Компоненты макетов следуют специфическим паттернам композиции для построения сложных структур.
Паттерн 1: Вложенная композиция макетов
Макеты могут быть вложены для создания сложных структур страниц:
children
children
children
рендерит
рендерит
рендерит
DashLayout
(Оболочка приложения)
LayoutBlock layout='grid'
(Секция Hero)
LayoutBlock layout='flex'
(Секция Features)
SplitBlock
(Секция контента)
Card
Card
Card
Пример:
<DashLayout sidebar={<Navigation />}>
<LayoutBlock layout="grid" cols="1-2-3" content={heroData} />
<SplitBlock mediaSection={<Image />} contentSection={<Content />} />
<LayoutBlock layout="stack" content={testimonialsData} />
</DashLayout>
Паттерн 2: Управление контейнером
Макеты используют компонент Container для адаптивного контроля ширины:
| Макет | Использование Container | Когда используется |
DashLayout | Всегда использует Container в src/layouts/DashLayout.tsx84 | Оборачивает основную панель контента |
LayoutBlock | Опционально через пропс useContainer в src/layouts/LayoutBlock.tsx259 | По умолчанию true, можно отключить для полной ширины |
SplitBlock | Условно через пропс splitSection в src/layouts/SplitBlock.tsx94-112 | Используется когда splitSection=false |
Паттерн 3: Переопределение хука контента
Система хуков контента обеспечивает прогрессивное улучшение:
переопределяет
fallback
Рендерер по умолчанию
(Встроенный)
Кастомный хук
(Предоставленный пользователем)
Финальный рендер
(Вывод)
Данные контента
Цепочка fallback:
- Проверить наличие кастомного
contentHooks.item в src/layouts/LayoutBlock.tsx302
- Откатиться к рендереру по умолчанию в src/layouts/LayoutBlock.tsx285
- Применить умолчания специфичные для макета в src/layouts/LayoutBlock.tsx230-254
Паттерн 4: Переопределения на основе слотов
Слоты SplitBlock предоставляют целенаправленную кастомизацию без полных хуков контента:
<SplitBlock
// Базовые пропсы
leftMedia
gap="xl"
// Оригинальные секции
mediaSection={<DefaultImage />}
contentSection={<DefaultContent />}
// Переопределения слотов
slots={{
media: <CustomVideo /> // Переопределяет mediaSection
}}
/>
Разрешение в src/layouts/SplitBlock.tsx91 приоритизирует слоты над прямыми пропсами.
Паттерн 5: Рендеринг на основе данных
Макеты принимают структурированные данные и рендерят автоматически:
const pageData = {
badge: "New",
title: "Feature Section",
description: "Amazing features",
items: [
{ id: "1", title: "Fast", description: "Speed", lucideIcon: Zap },
{ id: "2", title: "Secure", description: "Safe", lucideIcon: Lock }
]
};
<LayoutBlock layout="grid" cols="2" content={pageData} />
Конвейер рендеринга в src/layouts/LayoutBlock.tsx288-361 обрабатывает:
- Рендеринг заголовка из
content.badge/title/description
- Итерацию и рендеринг элементов из
content.items
- Обертку макета на основе режима
layout
Источники: src/layouts/LayoutBlock.tsx256-386 src/layouts/SplitBlock.tsx67-143 src/layouts/DashLayout.tsx64-91
Особые соображения
Семантическая HTML структура
Компоненты макетов обеспечивают семантическую HTML5 структуру:
| Компонент | Корневой элемент | Назначение |
DashLayout | <nav> + <main> | Навигационный заголовок + основной контент в src/layouts/DashLayout.tsx36-74 |
DashLayout.Sidebar | <aside> | Боковая навигация в src/layouts/DashLayout.tsx16 |
LayoutBlock | <section> | Контентные секции в src/layouts/LayoutBlock.tsx366 |
SplitBlock | <section> | Разделенные контентные секции в src/layouts/SplitBlock.tsx97-117 |
Это обеспечивает доступность и SEO соответствие без дополнительной конфигурации.
Атрибуты Data-Class
Все макеты применяют атрибуты data-class для консистентного таргетинга DOM:
| Компонент | Значение Data-Class | Расположение |
DashLayout.Navbar | data-role="dash-navbar" | src/layouts/DashLayout.tsx36 |
DashLayout.Sidebar | Кастомный через пропс | src/layouts/DashLayout.tsx16 |
LayoutBlock | data-class="layout-block" | src/layouts/LayoutBlock.tsx371 |
LayoutBlock Grid | data-class="layout-grid" | src/layouts/LayoutBlock.tsx320 |
LayoutBlock Flex | data-class="layout-flex" | src/layouts/LayoutBlock.tsx333 |
LayoutBlock Stack | data-class="layout-stack" | src/layouts/LayoutBlock.tsx344 |
SplitBlock Grid | data-class="split-grid" | src/layouts/SplitBlock.tsx129 |
Это обеспечивает надежное тестирование и стилизацию без зависимости от className.
Адаптивное поведение
Макеты обрабатывают адаптивный дизайн через пропсы вариантов:
Адаптивные колонки Grid:
cols="1-2-3" создает брейкпоинты мобильная→планшет→десктоп
- Автоматически сворачивается в 1 колонку на мобильных
- Масштабируется до 2 колонок на планшете (
md:)
- Расширяется до 3 колонок на десктопе (
lg:)
Адаптивный размер Container:
containerSize="lg" применяет max-w-7xl с корректировками брейкпоинтов
- Автоматически добавляет горизонтальный padding на мобильных
- Центрирует контент с
mx="auto"
Изменение размера панелей (DashLayout):
Соображения производительности
Управление ключами элементов: Компонент LayoutBlock требует уникальный id в элементах контента в src/layouts/LayoutBlock.tsx66 для эффективной reconciliation React. Ключи применяются в src/layouts/LayoutBlock.tsx306
Возможности мемоизации: Хуки и рендереры контента оцениваются при каждом рендере. Для дорогих вычислений оберните в useMemo:
const contentHooks = useMemo(() => ({
item: (item, index) => <ExpensiveComponent {...item} />
}), [dependencies]);
Сохранение состояния панели: DashLayout автоматически сохраняет размеры панелей в localStorage через react-resizable-panels, уменьшая сдвиг макета при перезагрузке.
Внешние зависимости
| Компонент | Зависимость | Назначение | Установка |
DashLayout | react-resizable-panels | Система изменяемых панелей | npm install react-resizable-panels |
| Все макеты | lucide-react | Опциональные компоненты иконок | npm install lucide-react |
Они перечислены как peer зависимости и должны быть установлены отдельно при использовании макетов.
Источники: src/layouts/DashLayout.tsx4 src/layouts/LayoutBlock.tsx366-383 src/layouts/SplitBlock.tsx94-136
Примеры использования
Приложение дашборд
Полный дашборд с навигацией, изменяемыми панелями и контентными секциями:
import { DashLayout, LayoutBlock, Card } from '@ui8kit/core';
import { Home, Settings, Users } from 'lucide-react';
function DashboardApp() {
const [darkMode, setDarkMode] = useState(false);
return (
<DashLayout
navbarProps={{
brand: "Admin Panel",
isDarkMode: darkMode,
toggleDarkMode: () => setDarkMode(!darkMode)
}}
sidebar={
<Stack gap="md">
<Button variant="ghost" leftSection={<Home />}>
Dashboard
</Button>
<Button variant="ghost" leftSection={<Users />}>
Users
</Button>
<Button variant="ghost" leftSection={<Settings />}>
Settings
</Button>
</Stack>
}
>
<LayoutBlock
layout="grid"
cols="1-2-3"
gap="lg"
content={{
title: "Overview",
description: "Key metrics",
items: statsData
}}
/>
</DashLayout>
);
}
Маркетинговая целевая страница
Hero секция с разделенным макетом и сеткой функций:
import { SplitBlock, LayoutBlock } from '@ui8kit/core';
import { Zap, Shield, Globe } from 'lucide-react';
function LandingPage() {
return (
<>
<SplitBlock
leftMedia={false}
splitSection
mediaSection={
<Image
src="/hero.jpg"
alt="Hero"
fit="cover"
h="full"
/>
}
contentSection={
<Stack gap="xl" align="start" p="2xl">
<Badge variant="secondary">New Release</Badge>
<Title order={1} size="4xl" fw="bold">
Build Faster
</Title>
<Text size="xl" c="secondary-foreground">
Create amazing interfaces with minimal code
</Text>
<Group gap="md">
<Button variant="primary" size="lg">
Get Started
</Button>
<Button variant="outline" size="lg">
Learn More
</Button>
</Group>
</Stack>
}
/>
<LayoutBlock
layout="grid"
cols="1-2-3"
gap="xl"
py="3xl"
content={{
badge: "Features",
title: "Why Choose Us",
description: "Everything you need to succeed",
items: [
{
id: "fast",
title: "Lightning Fast",
description: "Optimized for performance",
lucideIcon: Zap
},
{
id: "secure",
title: "Secure by Default",
description: "Built with security in mind",
lucideIcon: Shield
},
{
id: "global",
title: "Global Scale",
description: "Deploy worldwide instantly",
lucideIcon: Globe
}
]
}}
/>
</>
);
}
Макет статьи с насыщенным контентом
Макет Stack с кастомными хуками контента для богатого контента:
import { LayoutBlock, createLayoutContentHook } from '@ui8kit/core';
const articleHooks = createLayoutContentHook({
header: (content) => (
<Stack gap="md" align="center" ta="center">
<Badge>{content.category}</Badge>
<Title order={1} size="4xl">{content.title}</Title>
<Text c="muted" size="sm">
{content.author} • {content.date}
</Text>
</Stack>
),
item: (item, index) => (
<Card p="xl" rounded="lg" shadow="sm">
<Stack gap="lg">
<Title order={2} size="2xl">{item.title}</Title>
<Text>{item.content}</Text>
{item.quote && (
<Box p="lg" bg="muted" rounded="md" border="1px solid border">
<Text size="lg" fw="medium">"{item.quote}"</Text>
</Box>
)}
</Stack>
</Card>
)
});
function ArticlePage() {
return (
<LayoutBlock
layout="stack"
gap="2xl"
containerSize="md"
contentHooks={articleHooks}
content={articleData}
/>
);
}
Источники: README.md36-168 src/layouts/DashLayout.tsx53-96 src/layouts/LayoutBlock.tsx256-389 src/layouts/SplitBlock.tsx67-143