# REPAINT-MAP — перекраска форм CT/OID/KPS на @tnsu/ui-kit Живая карта работ по переводу форм портала на общий UI-пакет. Ведётся по ходу. Связано: `docs/BEHAVIORS.md` (инвентарь поведения форм). ## Принцип Красим **один раз** в ui-kit через токены, утверждаем в Storybook. В проекте — только композиция + узкодоменное. «Все цвета в ui-kit» = ui-kit это источник правды по токенам; потребитель (ct-forms-portal) держит **зеркало** `src/styles/_design-tokens.scss` (heft не резолвит scss из node_modules), формы красятся из него. Компоненты не «для KPS», а «для семейства СТ-форм»: API проектируем сразу под 3 формы (CT/OID используют те же Fluent-примитивы). Правило аддитивности: не хватает пропа для CT/OID → добавляем **опциональный** (не ломает KPS, semver minor/patch). Escape hatch: не ложится на 3 формы без уродства → оставляем локальным. ## Архитектура токенов ``` @tnsu/ui-kit src/tokens/_tokens.scss ← ИСТОЧНИК ПРАВДЫ (navy/gold, radius, shadow, bp, миксины) │ (копия при изменении) ▼ ct-forms-portal src/styles/_design-tokens.scss ← зеркало для SPFx-сборки ▲ (импортят свои .scss: Dashboard, CtFormsPortal, …) │ forms/kps/components/common/_theme.scss ← МОСТ: семантика формы ($accent,$ok,$supplier-bg…) ▲ → бренд-токены. Имена сохранены. │ @import '../common/theme' 12 доменных *.module.scss шагов ← перекрашиваются БЕЗ своих правок ``` ## Три корзины (по инвентарю KPS-формы) ### A. Уже есть в ui-kit → заменить импорт (мгновенная перекраска) | Было (Fluent/локальное) | Стало (ui-kit) | | --- | --- | | `TextField` | `TextInput` / `TextArea` / `MoneyInput` (числа) | | `DefaultButton` / `PrimaryButton` | `Button` (variant secondary/primary) | | низ `StepShell` (кнопки Назад/Далее) | `FormActions` | | `MessageBar` (+Type) | `Alert` (map severity) | | `Icon` | `Icon` / `IconSprite` | | локальный `Pill` | `Badge` | | локальный `Breadcrumbs` | `Stepper` | | локальный `common/FormHeader` | `FormHeader` | ### B. Создать в ui-kit (нужны и CT/OID) | Новый компонент | Драйвер / где нужен | | --- | --- | | `Checkbox` (+ строчный вариант) | RequestRow, RequestLines, Step1ReadOnlyView (Шаг 1) | | `Spinner` / `Loader` | KpFileList, CurrencyRatesForm, AiCommentBlock, Step4Approval | | `IconButton` | UploadedKpList, AiCommentBlock, CurrencyRatesForm, Step4Approval | | `Dialog` / `Modal` (generic, с телом+полями) | Step3BuildCt, Step4Approval, InlineApprovalChain (ConfirmDialog не тянет) | | `Link` | UploadedKpList (скачать) | ### C. Доменное — остаётся в проекте (красим токенами + примитивами ui-kit) - `Step3BuildCt/ComparisonMatrix`, `MatrixRowView`, `OfferCells` — матрица сравнения СТ. - `Step3BuildCt/CriteriaTable` — таблица критериев. - `common/ApprovalChain`, `Step4Approval/InlineApprovalChain` — цепочки (пилюли из `Badge`). - `Step2LoadKp/KpFileList`, `UploadedKpList` — список файлов КП (статусы обработки Syntex/поток). Загрузку можно частично на `FileDropzone` + `AttachmentList`. ## Семантические токены формы (мост `_theme.scss`) | Переменная | Бренд-токен | Было (Fluent) | | --- | --- | --- | | `$accent` | `$navy-800` | #0078d4 | | `$accent-bg` | `$navy-50` | #eff6fc | | `$accent-border` | `$navy-100` | #c7e0f4 | | `$accent-dark` | `$navy-950` | #004578 | | `$accent-hover` | `$navy-700` | #106ebe | | `$ok` / `$ok-bg` | `$green-600` / `$green-50` | #107c10 / #dff6dd | | `$danger` / `$danger-bg` | `$red-500` / `$red-50` | #a4262c / #fde7e9 | | `$warn-fg` / `$warn-bg` | `$amber-700` / `$amber-50` | #7d5900 / — | | `$text` / `$muted` / `$muted-2` | `$gray-900` / `$gray-500` / `$gray-400` | #323130 / #605e5c / #a19f9d | | `$border` / `$border-strong` | `$gray-200` / `$gray-300` | #edebe9 / #c8c6c4 | | `$head-bg` / `$hover` / `$surface` | `$gray-50` / `$gray-100` / `$white` | #faf9f8 / #f3f2f1 / #fff | | `$supplier-bg` / `$supplier-border` | `$gold-50` / `$gold-100` | #fffdf0 / #f2e9b8 | ## Роадмап и статус - [x] **Фаза 0 — Токены.** `$amber-50` в ui-kit; зеркало `src/styles/_design-tokens.scss`; мост `forms/kps/components/common/_theme.scss` → бренд. heft build ок. _Осталось в рамках гигиены: перевести `Dashboard.module.scss`/`CtFormsPortal.module.scss` (шелл) с хардкодов на зеркало — не блокер._ - [x] **Фаза 1 — Примитивы (корзина B) собраны в ui-kit** (build ок, 68 модулей): `Checkbox` (checked/indeterminate/disabled/readOnly/label/ariaLabel), `Spinner` (xSmall/small/medium/large, label, block), `IconButton` (icon: IconName, title, danger, size), `Dialog` (open/title/subText/onDismiss/footer/width, Esc+overlay close), `Link` (href/onClick/target/download). В спрайт добавлены иконки `arrow-up`, `arrow-down`, `swap`, `refresh`. _Осталось: Storybook-утверждение дизайна → релиз ui-kit (skill publish-ui-kit) → `npm i @tnsu/ui-kit@latest` в ct-forms-portal._ - [~] **Фаза 2 — Перекраска KPS** (по шагам; heft build после каждого): - [x] **Шаг 1** (`Step1SelectPositions`): Checkbox/Icon → ui-kit (+ariaLabel), `Pill`→адаптер над `Badge` (перекрасил все 6 мест сразу), `#ffffff`→`$surface`. build ок. - [x] **Шаг 2** (`Step2LoadKp/*`): MessageBar→Alert, Spinner/IconButton/Link/Icon→ui-kit, DefaultButton→Button, TextField→TextInput (в обёртке для className), литералы→токены. build ок. _Косметика: TextInput без suffix/ariaLabel (KZT→placeholder); dropzone оставлен доменным._ _Долг: перед Шагом 4 добавить в Alert вариант `info` (MessageBarType.info) + переиздать ui-kit._ - [x] **Шаг 3** (`Step3BuildCt/*`): AiCommentBlock (IconButton/Spinner/Alert), AddExtraRow + supplier toolbar (Button/TextInput), OfferCells/CriteriaTable (borderless TextInput/TextArea в обёртке `.input`), Dialog AI-промпта (ui-kit Dialog + footer). Матрица/критерии — домен, все литералы→токены ($accent-border/-bg/-dark/-hover, $supplier-bg, $warn-bg/-fg, $surface, $danger). Микро-кнопки в ячейках (×/+/удалить поставщика) оставлены доменными. build ок. Потребовало ui-kit **0.11.0**: TextInput/TextArea `borderless`+`ariaLabel`+`onKeyDown`+`autoFocus`, Alert вариант `info`, иконка `info`. - [x] **Шаг 4** (`Step4Approval.tsx` + `InlineApprovalChain.tsx`): MessageBar→Alert (ok/err/info/warn), IconButton (arrow-up/down/trash/swap), Button (approve=primary, reject=danger, send/refresh с иконками), Dialog×2 (решение/замена) → ui-kit Dialog+footer, TextField→TextInput/TextArea, литералы→токены ($surface,$sh-2). Цепочки — домен, пилюли через Pill→Badge. build ок. - [x] **common**: `StepShell` кнопки→`Button` (split-раскладка сохранена), `common/FormHeader`→адаптер над ui-kit `FormHeader` (right=Pill→Badge), `Breadcrumbs`→адаптер над `Stepper` (адаптивный), убран `@fluentui References.scss` из `KpsCtForm.module.scss`, #a4262c→$danger. Осиротевшие `FormHeader.module.scss`/`Breadcrumbs.module.scss` удалены. - ✅ **Fluent полностью удалён из KPS-формы (0 импортов @fluentui). Фаза 2 завершена, build ок.** - _KPS = двойной эталон (структура + примитивы)._ - [ ] **Фаза 3 — CT, затем OID.** НЕ только перекраска: **декомпозиция god-компонентов** (`Step3ComparisonTable.tsx` ~2200–2500 стр) в структуру KPS + сборка из ui-kit + сохранить 100% поведения. Инвентарь поведения → резка → build/workbench на каждом шаге. ## Заметки / риски - Декомпозиция CT/OID — самая рискованная часть; KPS = готовый чертёж (тот же скелет Step1→Step2→Step3 матрица→Step4; отличия доменные: CT disciplineCode/SMR/agskCode, OID parentGroup/priceSmeta). - При изменении токенов в ui-kit — синхронизировать зеркало `src/styles/_design-tokens.scss`.