docs: simplify conventions layout
Frontend security / security (pull_request) Successful in 8s
Frontend verify / verify (pull_request) Successful in 3m53s
Conventional commits / commits (pull_request) Successful in 19s
Frontend security / security (push) Successful in 8s
Frontend verify / verify (push) Successful in 3m53s
Frontend security / security (pull_request) Successful in 8s
Frontend verify / verify (pull_request) Successful in 3m53s
Conventional commits / commits (pull_request) Successful in 19s
Frontend security / security (push) Successful in 8s
Frontend verify / verify (push) Successful in 3m53s
This commit was merged in pull request #14.
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
# Frontend UI
|
||||
|
||||
## Выбор компонента и state
|
||||
|
||||
Сначала переиспользуй подходящий component проекта; иначе используй готовый
|
||||
Mantine component и общую тему. Для выпадающего выбора используй `Select` или
|
||||
`MultiSelect`, а не браузерный `<select>` / `NativeSelect` по умолчанию.
|
||||
Нативный control или собственная реализация допустимы, когда готовые components
|
||||
не покрывают конкретное продуктовое требование или доступность; укажи причину
|
||||
в результате работы. Краткость кода и удобство тестирования не являются причиной:
|
||||
ограничения JSDOM решай в test setup, сохраняя production UI.
|
||||
Семантический HTML для структуры страницы остаётся уместным.
|
||||
|
||||
Icons ищи у существующего owner (например,
|
||||
[BankOperationIcon](../../src/entities/bank-card/ui/BankOperationIcon.tsx));
|
||||
общая icon library сейчас не принята. Не добавляй пакет ради одного символа. Business/domain
|
||||
components живут у feature/entity/page, даже при повторном использовании.
|
||||
|
||||
Wrapper нужен для проектной ответственности, а не ради нового имени
|
||||
для Button. Локальный CSS module принадлежит component; общий token вводи для
|
||||
реально общей роли через [design system](../../../docs/design/overview.md).
|
||||
|
||||
| Состояние | Владелец |
|
||||
| --- | --- |
|
||||
| Ответ сервера / query lifecycle | TanStack Query, [data rules](data.md) |
|
||||
| Ввод и ошибки формы | React Hook Form + Zod, container/VM |
|
||||
| Параметр навигации, который должен переживать переход/ссылку | Router/URL |
|
||||
| Локальное открытие, focus, rendering fallback | React UI state |
|
||||
| Значение, вычисляемое из уже доступных inputs | Вычисление при render/в VM, без копирования через effect в state |
|
||||
|
||||
State, который нужен в ссылке, back/forward или после navigation, хранится в URL
|
||||
через existing router search params. Остальной UI state остаётся у ближайшего
|
||||
owner. Shared client store нужен только нескольким consumers без подходящего
|
||||
общего owner; наличие двух компонентов само по себе его не требует.
|
||||
Hooks/effects/derived state — по [TypeScript/React](typescript-react.md#hooks-и-derived-state).
|
||||
|
||||
## Container, VM и view
|
||||
|
||||
Для data-driven finance page container вызывает один page VM и выбирает
|
||||
Loading/Error/Empty/Loaded view. VM владеет data/auth/route inputs, state selection,
|
||||
retry callbacks, domain grouping и derived presentation data. View получает props.
|
||||
|
||||
| Файл | Ответственность |
|
||||
| --- | --- |
|
||||
| `Component.tsx` | Container или публичный component |
|
||||
| `Component.vm.ts` | Page VM, данные и действия |
|
||||
| `Component.view.tsx` | Presentation |
|
||||
| `Component.types.ts` | Переиспользуемые props/local types, когда отдельный owner полезен |
|
||||
| `Component.module.css` | Локальные стили |
|
||||
|
||||
Во view нет data/auth/router/navigation/VM hooks и вычислений по domain collection.
|
||||
Допустимы `useTranslation`, form-context hooks, UI-only state (например failed
|
||||
image fallback) и formatter одного переданного значения. Группировка/доли
|
||||
коллекции готовятся в VM. Перенос fetch во view ради меньшего container нарушает границу.
|
||||
|
||||
Отдельный state/section с самостоятельной responsibility выноси в flat
|
||||
`components/*.view.tsx`. Небольшой tightly-coupled renderer оставляй рядом.
|
||||
Не создавай folder/barrel/test/CSS для каждого view и не дроби по line count.
|
||||
Пример: [AccountIncomePage](../../src/pages/account-income/ui/AccountIncomePage.tsx)
|
||||
и [его VM](../../src/pages/account-income/ui/AccountIncomePage.vm.ts).
|
||||
|
||||
## Формы
|
||||
|
||||
Используй `react-hook-form`, `zodResolver`, `FormProvider`. Container/VM создаёт
|
||||
form state, view получает `onSubmit`/`disabled`, fields используют `useFormContext`.
|
||||
Во время submit блокируй все действия формы. Zod errors показывай у поля;
|
||||
network error — отдельным Alert с сохранением ввода. Невалидная форма не отправляет request.
|
||||
|
||||
## Состояния и recovery
|
||||
|
||||
Без успешных данных выбирай loading → error → empty → loaded. При наличии query
|
||||
данных сохраняй их во время refetch и его ошибки: progress, локальное предупреждение,
|
||||
retry. Это Client Cached Snapshot, отдельный от server stale/fallback.
|
||||
Known API errors принадлежат local view; непойманные route errors — route-keyed
|
||||
ErrorBoundary. Сброс query cache после смены session/connection задают data rules.
|
||||
|
||||
Initial loading использует page-owned structural skeleton по semantic regions,
|
||||
не одиночный spinner/StateView. Partial loading принадлежит section. Busy-область
|
||||
доступна assistive technology, shapes декоративны, без данных, интерактивности
|
||||
и focus. Route fallback сохраняет shell; до auth ready — neutral shell skeleton.
|
||||
Button loading при mutation и компактный cached-snapshot progress остаются
|
||||
контекстными indicators. Проверяй keyboard access к actions и безопасный retry.
|
||||
|
||||
## Код и components
|
||||
|
||||
Types, props, hooks и memoization — в [TypeScript/React](typescript-react.md).
|
||||
|
||||
## Domain literals and magic values
|
||||
|
||||
Правило и generated API exception — в
|
||||
[TypeScript/React](typescript-react.md#domain-literals-and-magic-values).
|
||||
|
||||
## Строки и валидация
|
||||
|
||||
Продуктовый текст хранится в `src/shared/i18n/locales/ru.ts`, читается через
|
||||
`useTranslation()`. В Zod используй `validationMessage(key)` из i18n/zod, без
|
||||
пользовательских literal messages. Это mandatory semantic review: общего запрета
|
||||
непереведённых JSX-строк в Biome/TypeScript нет. Synthetic story fixtures и
|
||||
описания историй допустимы; они не заменяют продуктовую локализацию.
|
||||
|
||||
## Проверка
|
||||
|
||||
Type/style: `npm run typecheck`, `npm run lint`. Для risk behavior/изменения тестов
|
||||
используй [Testing](testing.md). UI: keyboard, narrow viewport,
|
||||
loading/error/empty/loaded и recovery по применимости. [Storybook](storybook.md) задаёт выбор stories и изоляцию каталога;
|
||||
сверяй UI с задачей отдельно от build.
|
||||
Reference in New Issue
Block a user