@kpmi/lumen
v0.8.0
Published
React component library built on shadcn/ui patterns with a custom KPMI design system.
Readme
@kpmi/lumen
React component library built on shadcn/ui patterns with a custom KPMI design system.
Инструкция по добавлению нового компонента
Структура каждого компонента
Каждый компонент живёт в своей директории src/components/<component-name>/ и содержит хотя бы три файла:
src/components/my-component/
├── my-component.tsx # Сам компонент
├── my-component.stories.tsx # Stories для Storybook
└── index.ts # Barrel-экспортШаг 1. Создать файл компонента
Есть два варианта:
Вариант А — Установить через shadcn/ui
Если компонент уже есть в библиотеке shadcn:
npx shadcn@latest add <component-name>shadcn сам создаст директорию src/components/<component-name>/ с файлом компонента и установит нужные Radix-зависимости. После установки — адаптировать стили под дизайн-систему KPMI.
Вариант Б — Создать с нуля
Создать директорию вручную и добавить файл компонента:
import * as React from "react";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils/index";
const myComponentVariants = cva("base-classes", {
variants: {
variant: {
default: "...",
},
},
defaultVariants: {
variant: "default",
},
});
export interface MyComponentProps
extends
React.HTMLAttributes<HTMLDivElement>,
VariantProps<typeof myComponentVariants> {}
const MyComponent = React.forwardRef<HTMLDivElement, MyComponentProps>(
({ className, variant, ...props }, ref) => (
<div
className={cn(myComponentVariants({ variant, className }))}
ref={ref}
{...props}
/>
),
);
MyComponent.displayName = "MyComponent";
export { MyComponent, myComponentVariants };Важные паттерны:
React.forwardRef— обязателен для всех компонентовdisplayName— обязателен для отображения в DevToolscn()— всегда использовать для объединения классов- Если нужна поддержка
asChild, добавитьSlotиз@radix-ui/react-slot
Шаг 2. Создать barrel-экспорт
src/components/my-component/index.ts
export * from "./my-component";Шаг 3. Создать Storybook stories
src/components/my-component/my-component.stories.tsx
import type { Meta, StoryObj } from "@storybook/react";
import { MyComponent } from "./my-component";
const meta = {
title: "UI/MyComponent",
component: MyComponent,
parameters: {
layout: "centered",
},
tags: ["autodocs"],
argTypes: {
variant: {
control: { type: "select" },
options: ["default"],
},
},
} satisfies Meta<typeof MyComponent>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
args: {
children: "Пример",
variant: "default",
},
};
export const Variants: Story = {
render: () => (
<div style={{ display: "flex", gap: "1rem" }}>
<MyComponent variant="default">Вариант 1</MyComponent>
</div>
),
};Шаг 4. Зарегистрировать в общем экспорте
Добавить строку в src/components/index.ts:
export * from "./my-component";Шаг 5. Добавить subpath export в package.json
В раздел "exports" добавить запись для прямого импорта (@kpmi/lumen/my-component):
"./my-component": {
"types": "./dist/types/components/my-component/index.d.ts",
"import": "./dist/esm/components/my-component/index.js"
}Шаг 6. Проверить результат
# Запустить Storybook для визуальной проверки
npm run storybook
# Проверить типы
npm run typecheck
# Проверить линтер
npm run lint:all
# Полная сборка для финальной проверки
npm run buildИтоговый чеклист
| # | Задача | Обязательно |
| --- | -------------------------------------------------------- | -------------- |
| 1 | Создан my-component.tsx с forwardRef и displayName | ✅ |
| 2 | Создан index.ts с barrel-экспортом | ✅ |
| 3 | Создан my-component.stories.tsx с Default story | ✅ |
| 4 | Добавлен экспорт в src/components/index.ts | ✅ |
| 5 | Добавлен subpath в package.json → "exports" | ✅ |
| 6 | Пройдена проверка typecheck и lint:all | ✅ |
| 7 | Установлен shadcn-примитив (если нужен) | ⬜ опционально |
