@potokgm/ui-kit
v0.1.21
Published
Potok atomic UI components with theming via React Context
Readme
@potokgm/ui-kit
Атомарные UI-компоненты для приложений Potok. Без бизнес-логики — темизация через ThemeProvider и CSS-переменные (--pui-*).
Установка
yarn add @potokgm/ui-kitPeer-зависимости: react и react-dom ^19.
Подключение
import {
ThemeProvider,
Button,
Input,
OTPInput,
Spinner,
Typography,
} from "@potokgm/ui-kit";
import "@potokgm/ui-kit/styles.css";
function App() {
return (
<ThemeProvider testId="app-theme" theme={{ colorPrimary: "#0f766e" }}>
<Typography testId="title" variant="display2">
Добро пожаловать
</Typography>
<Button testId="continue">Продолжить</Button>
</ThemeProvider>
);
}Всегда оборачивайте дерево в ThemeProvider и передавайте обязательный testId на каждый компонент kit. Переопределение бренд-токенов в приложении:
:root {
--pui-color-primary: #0f766e;
}Рантайм-оверрайды — через проп theme у ThemeProvider (camelCase-ключи → переменные --pui-*).
Компоненты
| Экспорт | Описание |
|--------|--------|
| Button | primary / secondary / ghost, размеры, isLoading, disabled, asChild, startContent / endContent |
| Input | label, hint, error, size, startContent / endContent |
| OTPInput | N ячеек (по умолчанию 6), paste, placeholder, onChange / onFinish, inputMode="numeric" |
| Spinner | size в px (мин. 12, по умолчанию 20), role="status" |
| Avatar | фото / инициалы / fallback; size, radius, color |
| Toaster / toast | singleton-уведомления из любой точки; variants; WAAPI-анимация |
| Typography | variant (display1–6, subtitle1/2, body1/2, button, caption, overline), as, color, align, weight, truncate / lineClamp |
| SiteShell / useSiteShell | header на всю ширину сверху; ниже — sidebar + опциональный sidebarSecondary + контент; collapse | overlay; storageKey |
| Stack / Row / Grid | layout-примитивы с as и style-пропсами (gap, align, justify, padding/margin, columns, …) |
| Tooltip | подсказка на Floating UI: content, placement, hover/focus, delay, стрелка, controlled open |
| Popover | панель на Floating UI: click + dismiss, мягкий scale (как Tooltip), опциональный modal |
| DropdownMenu | меню из items; пружинное открытие scaleY; Esc / клик снаружи / выбор |
| Modal | диалог: portal, WAAPI open/close, focus trap, scroll lock, Esc / overlay |
| useLocalStorage | сохранение состояния в localStorage |
| ThemeProvider / useTheme | контекст темы |
Tooltip
<Tooltip testId="save-tip" content="Сохранить изменения" placement="top">
<Button testId="save">Сохранить</Button>
</Tooltip>Использует @floating-ui/react (hover + focus, portal, опциональная стрелка).
Popover
<Popover testId="actions" content={<ActionsPanel />} placement="bottom">
<Button testId="open">Открыть</Button>
</Popover>Клик переключает; Esc / клик снаружи закрывает.
DropdownMenu
<DropdownMenu
testId="file-menu"
items={[
{ key: "edit", label: "Изменить", onSelect: () => {} },
{ type: "separator", key: "s1" },
{ key: "delete", label: "Удалить", danger: true, onSelect: () => {} },
]}
>
<Button testId="open">Действия</Button>
</DropdownMenu>Открывается пружинным растягиванием по оси Y (scaleY(0 → 1)).
Modal
const [open, setOpen] = useState(false);
<Button testId="open" onClick={() => setOpen(true)}>
Открыть
</Button>
<Modal
testId="edit"
open={open}
onOpenChange={setOpen}
onClose={() => console.log("closed")}
title="Редактировать профиль"
description="Обновите данные."
footer={<Button testId="save">Сохранить</Button>}
>
<Input testId="name" label="Имя" />
</Modal>animation="scale" (по умолчанию) или animation="fade". Диалог в portal с Web Animations API, focus trap, блокировкой скролла, закрытием по Escape и overlay.
Avatar
<Avatar
testId="user"
name="Alex Rixten"
src="https://example.com/photo.jpg"
size="md"
color="primary"
/>При ошибке загрузки изображения показываются инициалы из name или кастомный fallback.
Toast
Один раз смонтируйте viewport:
<Toaster testId="toaster" position="bottom-right" />Вызывайте из любой точки приложения:
import { toast } from "@potokgm/ui-kit";
toast.success("Сохранено");
toast.error("Ошибка", { description: "Попробуйте снова" });
toast.dismiss(); // закрыть всеПодход OTPInput
Отдельный <input> на каждую цифру. Paste заполняет весь код; onChange получает склеенную строку цифр.
const [code, setCode] = useState("");
<OTPInput
length={6}
value={code}
onChange={setCode}
onFinish={(value) => console.log("complete", value)}
placeholder="0"
autoFocus
/>Скрипты
yarn test
yarn storybook
yarn buildyarn build собирает dist/index.js, dist/index.cjs, dist/index.d.ts и dist/styles.css.
Стили
- Внутри пакета — SCSS Modules + BEM
- Потребители используют только CSS-переменные (
--pui-*) и экспортируемыйstyles.css
