--- title: Компонент description: Как должен выглядеть сгенерированный React-компонент внутри SLM-модуля. --- # Компонент Как должен выглядеть сгенерированный React-компонент внутри SLM-модуля. ## Назначение Архитектурное определение компонента описано в разделе [Модули → Компонент](../basics/architecture/modules.md#компонент), а структура сегмента `ui/` — в разделе [Сегменты → ui/](../basics/architecture/segments.md#сегмент-ui). Эта страница не повторяет архитектурные ограничения. Она показывает, каким должен быть результат генерации компонента: структура папки, `.tsx`, типы, стили и локальный экспорт. ::: danger Компоненты не создаются вручную Компоненты в проекте создаются только через кодогенератор: через [VS Code](./templates/templates-usage.md#через-vs-code) или [CLI](./templates/templates-usage.md#через-cli). Ручное создание компонента запрещено. Это грубое нарушение правил работы в проекте для разработчика и AI-ассистента. Если в проекте нет шаблона `.templates/component`, сначала создайте шаблон по разделу [Создание шаблонов](./templates/templates-create.md), и только потом генерируйте компонент на его основе. ::: ## Создание 1. Проверьте, что в проекте есть шаблон `.templates/component`. 2. Если шаблона нет — создайте его по разделу [Создание шаблонов](./templates/templates-create.md). 3. Сгенерируйте компонент через [VS Code или CLI](./templates/templates-usage.md). Структура и код ниже показывают ожидаемый результат генерации. Их нельзя использовать как инструкцию для ручного создания файлов. ## Структура Компонент размещается в `ui/{component-name}/` родительского модуля. Для каждого компонента обязательны `.tsx`, типы, стили и локальный `index.ts`. ```text user-card/ └── ui/ └── user-status/ ├── styles/ │ └── user-status.module.css ├── types/ │ └── user-status-props.type.ts ├── user-status.tsx └── index.ts ``` ## Реализация Пример ниже показывает файлы базового компонента. ### Типы Файл типов делится на три части: - `UserStatusParams` — собственные параметры компонента. Здесь лежат только данные, которые нужны именно этому компоненту. - `RootAttrs` — параметры корневой обёртки: `div`, `span`, `a`, `button` или другого HTML-элемента. Если компонент сам управляет `children`, они исключаются через `Omit`. - `UserStatusProps` — итоговые пропсы компонента. Тип объединяет собственные параметры и параметры корневой обёртки. Собственные параметры и их поля документируются по правилам раздела [Документирование → Типы, интерфейсы, enum](../basics/documentation.md#типы-интерфейсы-enum). `user-card/ui/user-status/types/user-status-props.type.ts` ```ts import type { ComponentPropsWithoutRef } from 'react' /** * Параметры UserStatus. */ export type UserStatusParams = { /** Текст статуса пользователя. */ label: string /** Доступен ли пользователь сейчас. */ isOnline: boolean } /** Атрибуты корневого элемента без children. */ type RootAttrs = Omit, 'children'> export type UserStatusProps = RootAttrs & UserStatusParams ``` ### TSX В `.tsx` лежит только сам компонент: - Компонент объявляется через `const` и именованный экспорт. - `React.FC` не используется. - Параметры компонента типизируются через `Props`. - Возвращаемый тип не указывается: TypeScript корректно выводит JSX-результат, а явный `ReactElement` сужает допустимые варианты возврата. - JSDoc-комментарий обязателен и пишется по правилам раздела [Документирование → Компоненты](../basics/documentation.md#компоненты). - Пропсы деструктурируются в теле компонента, а не в сигнатуре. - Из пропсов обязательно выделяются `className` и `...rootAttrs`. - Функция конкатенации CSS-классов импортируется и именуется `cl`. - Корневой CSS-класс всегда называется `.root`. Комментарий описывает назначение и сценарии применения компонента, а не DOM-разметку или внутреннюю реализацию. `className` — внешний CSS-класс, который родитель может передать компоненту. `rootAttrs` — остальные атрибуты корневой обёртки: `id`, `aria-*`, `data-*`, обработчики событий и другие HTML-атрибуты. Они прокидываются на корневой DOM-элемент компонента. `.root` нужен, чтобы в DevTools быстро находить корневой DOM-узел компонента и одинаково подключать внешний `className` к реальному корню. `user-card/ui/user-status/user-status.tsx` ```tsx import cl from 'clsx' import type { UserStatusProps } from './types/user-status-props.type' import styles from './styles/user-status.module.css' /** * Статус пользователя в карточке профиля. * * Используется для: * - отображения текущей доступности пользователя * - визуального выделения онлайн- и офлайн-состояний */ export const UserStatus = (props: UserStatusProps) => { const { label, isOnline, className, ...rootAttrs } = props return ( {label} ) } ``` ### Стили `user-card/ui/user-status/styles/user-status.module.css` ```css .root { display: inline-flex; align-items: center; gap: 6px; color: var(--color-text-muted); } .root::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: currentColor; } .online { color: var(--color-success); } ``` ### Локальный экспорт `user-card/ui/user-status/index.ts` ```ts export { UserStatus } from './user-status' export type { UserStatusProps } from './types/user-status-props.type' ```