@efficiency-point/design-system
v0.0.19
Published
Efficiency-point react design system
Readme
Efficiency Point Design System
React/TypeScript дизайн-система с CSS Modules, публичными типами, Storybook и библиотечной сборкой ESM/CJS.
Требования
- Node.js, совместимый с Vite 8;
- React и React DOM
>=18 <20в приложении-потребителе; - npm как пакетный менеджер.
Подключение
npm install @efficiency-point/design-systemimport { DSButton, DSInfoBlock } from '@efficiency-point/design-system';
import '@efficiency-point/design-system/styles.css';
export function Example() {
return (
<DSInfoBlock title="Информация">
<DSButton>Продолжить</DSButton>
</DSInfoBlock>
);
}Компоненты форм контролируемые: value/checked хранится у приложения и обновляется через callback.
Темизация
Компоненты используют CSS custom properties из tokens.css. Их можно переопределить после импорта библиотечного CSS:
:root {
--color-primary: #2563eb;
--border-radius: 12px;
--ds-dropdown-menu-max-height: 280px;
}Компоненты
DSButton
Кнопка с вариантами primary, secondary, outline, ghost, empty, destructive, destructiveOutline и размерами sm, md, lg.
<DSButton variant="primary" isLoading={saving} onClick={save}>
Сохранить
</DSButton>type по умолчанию равен button. При isLoading кнопка блокируется и получает aria-busy.
DSInput
Текстовое или числовое контролируемое поле с label, hint, error, required и очисткой.
<DSInput
label="Название"
value={name}
onChange={(value) => setName(String(value))}
error={nameError}
required
/>DSCheckbox
Поддерживает controlled state, indeterminate, readOnly, disabled, hint/error и нативные form-атрибуты.
<DSCheckbox checked={enabled} onChange={setEnabled} label="Активен" />DSRadioButton
Двухпозиционный switch. Несмотря на историческое имя, в DOM используется checkbox с role="switch".
<DSRadioButton checked={enabled} onChange={setEnabled} label="Уведомления" />DSDropDown
Одиночный выбор. Поддерживаются disabled options, hint/error, disabled display и клавиши ArrowUp/ArrowDown, Home, End, Enter, Space, Escape и Tab.
<DSDropDown
label="Статус"
options={[{ label: 'Активен', value: 'active' }]}
value={status}
onChange={setStatus}
maxMenuHeight={280}
/>Высота списка по умолчанию задаётся --ds-dropdown-menu-max-height: 240px; содержимое прокручивается, активная keyboard-опция подводится в видимую область.
DSDropDownMultiple
Множественный controlled dropdown. onChange возвращает массив значений и выбранные объекты. По умолчанию меню остаётся открытым после выбора.
<DSDropDownMultiple
options={options}
value={selectedIds}
onChange={setSelectedIds}
closeOnSelect={false}
/>DSDateTimePicker
Контролируемое поле для date, time или datetime. Использует нативные browser controls и принимает Date | null, min и max.
<DSDateTimePicker mode="datetime" value={date} onChange={setDate} />DSDateRange
Контролируемый диапазон дат или локальных даты/времени. onChange получает только завершённую валидную пару Date; промежуточное состояние доступно через onDraftChange.
<DSDateRange mode="datetime" value={range} onChange={setRange} onDraftChange={setDraftRange} />DSDataTable и DSSort
Типизированная таблица на стабильной @tanstack/react-table с обязательной сортировкой. По умолчанию мобильный вид отображает строки карточками; tableOnMobile сохраняет таблицу. breakpoint="default" переключает вид ниже 640 px, breakpoint="wide" — ниже 1280 px.
<DSDataTable columns={columns} data={rows} breakpoint="wide" />DSSort можно использовать отдельно для сортировки по полям объектов или строковым значениям.
DSFilters
Контролируемая композиция фильтров типов input, dropdown, multiple, checkbox, radio и dateRange, построенная из компонентов дизайн-системы.
<DSFilters filters={filters} values={values} onChange={setValues} />DSVideoPlayerFrame
Адаптивная оболочка нативного видеоплеера с несколькими sources/tracks, poster, media-настройками и loading/error-состояниями.
<DSVideoPlayerFrame title="Обучение" sources={[{ src: '/video.mp4', type: 'video/mp4' }]} />DSInfoBlock
Постоянно видимая карточка-виджет с заголовком и произвольным содержимым. dismissible только показывает кнопку; скрытием управляет приложение через onDismiss.
{visible && (
<DSInfoBlock title="Сводка" dismissible onDismiss={() => setVisible(false)}>
Контент
</DSInfoBlock>
)}DSBadge
Неинтерактивная метка. Варианты: neutral, info, success, warning, error; размеры sm, md; доступны dot и icon.
<DSBadge variant="success" dot>Готово</DSBadge>DSSkeleton
Декоративный placeholder с вариантами text, rectangular, circular, несколькими строками и отключаемой анимацией. Skeleton скрыт от accessibility tree; aria-busy должен задавать родитель.
<section aria-busy="true"><DSSkeleton lines={3} /></section>DSTooltip
Короткая неинтерактивная подсказка. Открывается по hover/focus/touch, закрывается по blur, pointer leave и Escape. Для кнопок и ссылок внутри содержимого используйте popover, а не tooltip.
<DSTooltip content="Редактировать" placement="top">
<button type="button">...</button>
</DSTooltip>DSLoader и DSPageLoader
DSLoader — компактный индикатор с role="status" или декоративным режимом. DSPageLoader — центрированный loading-state области страницы.
DSIcon
Типизированный registry иконок. Публичен union DSIconName. Без title иконка декоративная; с title получает роль изображения и доступное имя.
<DSIcon name="approve" title="Подтверждено" />Field primitives
DSFieldLabel и DSFieldMessage унифицируют label, required marker, optional text, hint/error/success сообщения. Публичны все props и DSFieldMessageVariant.
Toast
Toast использует внутренний Zustand store и публичный useToast. Provider обычно подключается один раз рядом с корнем приложения.
function Root() {
return (
<>
<App />
<DSToastProvider position="top-right" />
</>
);
}
function SaveButton() {
const { successToast } = useToast();
return (
<DSButton onClick={() => successToast({ message: 'Сохранено' })}>
Сохранить
</DSButton>
);
}Расширенный API экспортирует useToastStore, ToastStoreState, ToastItem, ShowToastPayload, ToastAction и ToastVariant.
Modal и реестр приложения
Библиотека не импортирует файлы consumer-проекта. Каждый проект хранит реестр по принятому пути, например src/shared/ui/modal/modal.registry.tsx, и явно передаёт его provider.
// src/shared/ui/modal/modal.registry.tsx
import {
builtInModalRegistry,
defineModalRegistry,
type ModalControls,
} from '@efficiency-point/design-system';
import { EmployeeModal } from './EmployeeModal';
export type EmployeeModalPayload = {
employeeId: string;
};
export const modalRegistry = defineModalRegistry({
...builtInModalRegistry,
EmployeeModal: ({ employeeId, modalId, close }: EmployeeModalPayload & ModalControls) => (
<div data-modal-id={modalId}>
Сотрудник: {employeeId}
<button onClick={close}>Закрыть</button>
</div>
),
});
export type AppModalRegistry = typeof modalRegistry;// app providers
import { ModalSystemProvider } from '@efficiency-point/design-system';
import { modalRegistry } from '@/shared/ui/modal/modal.registry';
<ModalSystemProvider registry={modalRegistry}>
<App />
</ModalSystemProvider>const { openModal } = useModals<typeof modalRegistry>();
openModal('EmployeeModal', { employeeId: '42' });Modal host поддерживает stack, закрытие верхней модалки по Escape, backdrop-close, focus trap и восстановление focus. Поведение Escape/backdrop настраивается в openModal.
Встроенные ConfirmModal и ErrorModal доступны через builtInModalRegistry, useConfirmModal и useErrorModal.
Публичные типы
Все component props, callback signatures, variant unions, store states, hook results, modal registry contracts и payload-типы экспортируются из корневого entry point.
Разработка и проверки
npm run lint
npm run typecheck
npm run test
npm run test:coverage
npm run build
npm run test:package
npm run build-storybook
npm run pack:checkПодготовка пакета
- Установить зависимости:
npm ci. - Запустить
npm run lint. - Запустить
npm run typecheck. - Запустить
npm run testи сохранить результаты в отчёт. - Запустить
npm run test:package. - Собрать Storybook:
npm run build-storybook. - Проверить содержимое архива:
npm run pack:check. - Указать финальные
name,version,license,repositoryи при необходимостиpublishConfigвpackage.json. - Создать архив:
npm pack. - Установить
.tgzв чистое React-приложение и проверить ESM/CJS, типы и CSS. - После проверки выполнить
npm publishв выбранный registry. Публикация и изменение версии выполняются отдельно и в текущую задачу не входят.
Подключение к другому проекту
- Установить опубликованный пакет или локальный tarball.
- Один раз импортировать
@efficiency-point/design-system/styles.cssв entry приложения. - Убедиться, что React/React DOM удовлетворяют peer range.
- Подключить
DSToastProvider, если используются toast. - Создать
shared/ui/modal/modal.registry.tsxи подключитьModalSystemProvider, если используются модалки. - Заменять локальные UI-компоненты постепенно, сохраняя controlled state и импортируя публичные props/payload-типы из пакета.
