Files
nextjs-fetch-data-example/ai/nextjs-style-guide/applied/component.md

7.9 KiB
Raw Blame History

title, description
title description
Компонент Как должен выглядеть сгенерированный React-компонент внутри SLM-модуля.

Компонент

Как должен выглядеть сгенерированный React-компонент внутри SLM-модуля.

Назначение

Архитектурное определение компонента описано в разделе Модули → Компонент, а структура сегмента ui/ — в разделе Сегменты → ui/.

Эта страница не повторяет архитектурные ограничения. Она показывает, каким должен быть результат генерации компонента: структура папки, .tsx, типы, стили и локальный экспорт.

::: danger Компоненты не создаются вручную Компоненты в проекте создаются только через кодогенератор: через VS Code или CLI.

Ручное создание компонента запрещено. Это грубое нарушение правил работы в проекте для разработчика и AI-ассистента.

Если в проекте нет шаблона .templates/component, сначала создайте шаблон по разделу Создание шаблонов, и только потом генерируйте компонент на его основе. :::

Создание

  1. Проверьте, что в проекте есть шаблон .templates/component.
  2. Если шаблона нет — создайте его по разделу Создание шаблонов.
  3. Сгенерируйте компонент через VS Code или CLI.

Структура и код ниже показывают ожидаемый результат генерации. Их нельзя использовать как инструкцию для ручного создания файлов.

Структура

Компонент размещается в ui/{component-name}/ родительского модуля.

Для каждого компонента обязательны .tsx, типы, стили и локальный index.ts.

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.

user-card/ui/user-status/types/user-status-props.type.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-комментарий обязателен и пишется по правилам раздела Документирование → Компоненты.
  • Пропсы деструктурируются в теле компонента, а не в сигнатуре.
  • Из пропсов обязательно выделяются 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

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

.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

export { UserStatus } from './user-status'
export type { UserStatusProps } from './types/user-status-props.type'