forked from templates/nextjs-template
166 lines
7.9 KiB
Markdown
166 lines
7.9 KiB
Markdown
---
|
||
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<ComponentPropsWithoutRef<'span'>, '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 (
|
||
<span
|
||
{...rootAttrs}
|
||
className={cl(styles.root, isOnline && styles.online, className)}
|
||
>
|
||
{label}
|
||
</span>
|
||
)
|
||
}
|
||
```
|
||
|
||
### Стили
|
||
|
||
`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'
|
||
```
|