Review rodiny Text field — novým postupem (inventura · matice · port · brána)

Datum: 2. 9. 2026 večer · reviewer: Claude (jako senior UX/UI) · zadal Štěpán (AD) Předmět: rodina text-field (7 podkomponent v registru), stories MR !2825 (už v mainu — opravy jdou follow-up MR). Každý nález ověřen proti kódu na origin/main acrm (4f9af7c, klon /root/acrm-main — na dotčených cestách shodný), registru site/registry.json, docs docs/text-field/* a renderu webu /ds/components/text-field/<sub>?tab=examples (screenshoty review-text-field-<sub>.png). Postup = §4 z REVIEW-ACRM-76-81-button-family.md: (1) tabulka použití, (2) stavová matice z CSS/props, (3) story = port, (4) design gate, (5) web nelže, (6) validator, (7) tikety.

0. Shrnutí

Rodina Text field opakuje chyby pilotu Button, jen ve větším: ze 7 podkomponent jsou v appce skutečně používané 4 (Input, Textarea, Field, Mention input). Slider má 0 použití (jen demo routa /ds/inputs), Input with icon and kbd má 1 použití bez ikony a bez kbd (WrapupBand.tsx), zatímco vyhledávací pole — účel, pro který vznikl — appka staví 13× v 8 jiných obalech (.fb-search, .set-search, .mr-search, .aichat-psearch, .itm-ac, .sgb-search, holý input v GlobalSearch, tlačítko .as-search). Tag input má 1 kanonické použití a 3 bespoke editory vedle (.sgb-tags, AiZamestnanci, .mr-taginput).

Nejzávažnější věc není ve stories, ale v appce: kanonická komponenta <Input> je použita 57× v 19 souborech, holé <input className="acrm-input"> 273× v 72 souborech (komponentou prochází 17 % polí); k tomu 4 aliasové názvy téhož boxu v JSX (.sgb-input 44×, .finput 20×, .dlr-input, .ac-input). Chybový stav pole se v appce nikdy nekreslí: <Field error> je 31× ve 12 souborech, .is-error na inputu 0× — uživatel vidí červený text pod polem a neutrální rámeček. readOnly je na .acrm-input 10× a CSS pro něj nemá pravidlo; Textarea nemá :disabled ani .is-error; Slider nemá fokus (outline: none) — a story mu ho přesto připisuje.

Stories: ani jedna ze 7 kompozic není port konkrétního místa appky (žádný komentář soubor:řádek), 4 Sizes mění obsah spolu s rozměrem, 3 States ukazují stav, který CSS nemá, a web u 4 podkomponent stále vypisuje vypůjčenou legacy story (components--inputs--fields / --textarea) NAD vlastní Default — u „Input with icon and kbd" tak stránka zase začíná poli bez ikony a kbd (přesně ACRM-76). Iframes příkladů drží 260 px bílé plochy, protože oprava D5 měří dokument, kterému Ladle provider dává min-height: 100vh — nikdy se nezmenší.

1. Nálezy per podkomponenta (ověřeno v kódu)

Legenda použití: „komponenta" = React export z @acrm/ui, „raw" = holý HTML element s DS třídou; počty = soubory / výskyty v apps/web/src + packages/ui/src bez stories a testů; DsInputsPage.tsx (routa /ds/inputs, App.tsx:517) je demo, ne použití.

1.1 Input — <Input> · .acrm-input (ds.css:36–96, inputs.css:92–111, 162–182)

KrokFakt
Použití<Input> 19 souborů / 57× (AccountingInvoiceEditPage.tsx, ImportPage.tsx); raw <input class="acrm-input"> 72 souborů / 273× (DocumentDetailPage.tsx, ProduktyPage.tsx). Šířky: --num 3 soubory (NastaveniPage, DochazkaPage, ZasedackyPage); --code, --short, --email 0. .acrm-range 2 soubory (PruvodceFirmyPage.tsx:860, PruvodcePage.tsx). .is-error na inputu 0 (jen DsInputsPage); .is-disabled 0; readOnly na .acrm-input 10× / 7 souborů.
Verdiktcanon — ale kanon je třída, ne komponenta (17 % přes <Input>).
Matice z CSSrest ✓ (:36) · hover ✗ · active ✗ · focus ✓ (:55, accent + ring 16 %) · open — · disabled ✓ (:disabled/.is-disabled :64) · loading — · selected — · error ✓ (.is-error :75) · readonly ✗ (žádné :read-only, appka ho používá 10×).
Story Statesplaceholder · filled · disabled · error. Disabled má hodnotu „Read only" — míchá disabled a readonly, přičemž readonly CSS nemá (D6). Focus jen textem — v pořádku (nejde simulovat), ale chybí :focus snímek přes autoFocus.
Story Sizes4 modifikátory + 100 % — každý s jiným obsahem („12", „CZ12345678", „Jane Doe", e-mail) → porušuje „stejný obsah, mění se jen rozměr" (D7); 3 ze 4 modifikátorů mají 0 použití (A12). Popisky v px ✓.
Story Composition.acrm-range — v appce existuje (PruvodceFirmyPage.tsx:860 — dva input.acrm-input type=number), ale story nemá soubor:řádek a používá <Input> bez type="number" (D8).
Docsinput.usage.md cituje „Related: legacy overview components--inputs--fields" (D3); „Do: šířka podle obsahu" popisuje praxi, kterou appka nedělá (--code/--email 0×) — AD rozhodne A12. input.a11y.md sedí s kódem (bez htmlFor, .is-error jen vizuál, kontrasty z tokenů).

1.2 Textarea — <Textarea> · .acrm-textarea (ds.css:148–166, 190)

KrokFakt
Použití<Textarea> 26 souborů / 34× (NastaveniPage.tsx, MeetingDetailPage.tsx); raw .acrm-textarea 4 soubory (OrderDetailPage, AssistantPrompts). Bespoke textarey vedle: .sgb-input ×2 (SegmentBuilder.tsx), .cd-ai-input (CrmDashboardPage), .dlg-title (NoteDialog), .rr-edit (RecordRail.tsx).
Verdiktcanon.
Matice z CSSrest ✓ (:148) · focus ✓ (:162) · disabled ✗ · error ✗ · readonly ✗ · hover ✗.
Story Statesplaceholder · filled · „disabled (native)" — ukazuje stav, který CSS nemá; story to přiznává popiskem, ale prezentuje ho jako stav (D9 ↔ A5).
Story Sizesrows=3 vs rows=6 s jiným placeholderem („Short note" / „Longer description") → porušuje pravidlo Sizes (D7).
Story CompositionField + Textarea — obecný tvar bez soubor:řádek (D8).
Docstextarea.usage.md pravdivě říká „no DS rule for :disabled/.is-error" — to je A-bug, ne vlastnost; po opravě A5 přepsat.

1.3 Field — <Field> · .acrm-field* (Field.tsx, ds.css:105–127)

KrokFakt
Použití<Field> 24 souborů / 193×; raw div.acrm-field 18 souborů / 83× (OrderDetailPage, DochazkaPage); raw .acrm-field-label 25 souborů; error= 31× / 12 souborů; labelExtra= 4× / 1 soubor (PostDocumentDialog.tsx:511 — OCR odznak zOcr(...), ne ikona).
Verdiktcanon.
Matice z propslabel · labelExtra · hint · error (error vítězí — Field.tsx:66) · bez id/htmlFor · bez required/disabled. Label má inline style přímo v komponentě (Field.tsx:57 display:flex; gap) — styl patří do .acrm-field-label (A8).
Story Variantslabel · label+hint · label+error · labelExtra = <Icon info-circle> — v appce je jediný labelExtra OCR odznak; ikona „i" je vymyšlená (D10) · no label.
Story States„hint + error → error wins" ✓ (kód) · „disabled control" = stav Inputu, ne Fieldu.
Story Compositionsloupec formuláře + Checkbox + Cancel(Esc)/Save(⌘↵) — vymyšlený formulář, žádné soubor:řádek; reálný tvar = DrawerForm / patička Dialogu (D8).
Docsfield.usage.md a field.a11y.md sedí s kódem (flex label, žádné htmlFor, hint/error bez id).

1.4 Input with icon and kbd — .acrm-inputwrap + .acrm-kbd (inputs.css:31–89)

KrokFakt
Použití.acrm-inputwrap 1 soubor: WrapupBand.tsx:225, 288 — jako div, bez ikony, bez kbd, uvnitř <Field> (tedy „Input s obalem navíc"). .acrm-kbd mimo <Button kbd> 0. .is-error/.is-disabled na wrapperu 0. Vyhledávací pole v appce (ikona search + input): 13 míst, 0× .acrm-inputwrap — obaly .fb-search (FilterBar ×5), .set-search (SettingsLayout), .mr-search (MeetingDetail), .aichat-psearch, .itm-ac (deal-parts), .sgb-search (SegmentScreen), holý input (GlobalSearch.tsx:266 + <kbd style> Esc), .acrm-recordselect-search ×2 (kanon rodiny Select); AppShell má tlačítko .as-search s holým <kbd>⌘K</kbd> (AppShell.tsx:1257, app-shell.css:170 — commit DS a6112aa změnil jen legacy/, appka je beze změny).
Verdiktnení kanon (kandidát) — třída bez použití pro svůj účel; účel v appce žije v 7 bespoke obalech (A3).
Matice z CSSrest ✓ · focus-within ✓ (:61) · error ✓ (:65) · disabled ✓ (:69) · hover ✗ — všechny stavy kromě rest mají 0 použití.
Stories6 sekcí, všechny ukazují markup, který appka nikde nemá. Default/Variants/With icon & kbd = tři story stejného obsahu (search · ⌘K). Sizes = jiná ikona i obsah na každém řádku (D7). Composition = vymyšlený toolbar (search + ghost Filter + „128 contacts"), reálný toolbar je FilterBar.tsx .fb-search (D8). Web navíc nad Default vypisuje legacy components--inputs--fields = pole bez ikony a kbd — opakování ACRM-76 (D1).
Docsinput-with-icon-kbd.usage.md popisuje „the search field pattern … markup as in DsInputsPage" — demo, ne obrazovka; po A3 přepsat podle rozhodnutí.

1.5 Slider — .acrm-slider (inputs.css:187–217)

KrokFakt
Použití0 (jen DsInputsPage.tsx); type="range" v appce jinde 0.
Verdiktnení kanon (kandidát).
Matice z CSSrest ✓ (track + thumb) · focus ✗ (outline: none :194, foundation ring inputy nekryje) · disabled ✗ · hover ✗.
Story States„value 0 / 45 / 100" = hodnoty, ne stavy; „disabled (native)" = stav bez CSS (D9). Popisek „Focus: keyboard focus draws the foundation ring on the thumb" je nepravda — slider.a11y.md sám říká „no visible focus state" (D11).
Story Compositionslider + --num readout — v appce neexistuje (D8).
Docsslider.a11y.md je přesný; slider.usage.md cituje demo DsInputsPage jako vzor.

1.6 Tag input — .acrm-taginput · .acrm-tag · .acrm-tag-x (inputs.css:802–860)

KrokFakt
Použití.acrm-taginput 1 soubor: ProduktDetailPage.tsx:979 (uvnitř DrawerField, ne Field). .acrm-tag+.acrm-tag-x bez kontejneru: AiZamestnanciPage.tsx:81 (flex + vlastní input), PruvodceFirmyPage.tsx:341 (.sgb-tags + vlastní input). Bespoke: mr-taginput (MeetingDetailPage.tsx:1093, témata schůzky). Logika (Enter přidá, × odebere, dedup) je opsaná 4×.
Verdiktcanon s 1 použitím — drží se jen díky ProduktDetailPage; bez React komponenty se rozpadá (A9).
Matice z CSSrest ✓ · focus-within ✓ (:813) · tag-x hover ✓ (:838) · disabled ✗ · error ✗.
Story Statesempty · filled · wrapping — to je obsah, ne stavy; matice má jen rest/focus/hover-× (chybí focus snímek).
Story CompositionField + taginput — reálné místo je DrawerField (ProduktDetailPage:978); bez soubor:řádek (D8). Story si píše vlastní TagInput state-holder = důkaz, že komponenta v balíčku chybí.
Docstag-input.usage.md cituje ProduktDetailPage ✓; „Backspace removes the last one (screen behaviour, as in the story)" — chování story, ne appky.

1.7 Mention input — MentionInput · .mi-* (MentionInput.tsx, mention-input.css)

KrokFakt
Použití<MentionInput> 18 souborů / 25× (DialerPage, TaskDialog, MeetingDetailPage, AssistantChat); MentionText pro čtení.
Verdiktcanon (app-side kompozice; balíček nese jen CSS).
Matice z props+CSSrest ✓ (s --shadow-xs :22 — jediné pole s klidovou elevací) · focus ✓ (:31, ring 15 % vs 16 % Inputu) · placeholder ✓ (:empty::before :36) · open ✓ (aria-expanded, menu :101) · disabled ✗ (prop neexistuje) · readonly ✗ (řeší MentionText) · error ✗ · dark: zůstává --surface-100 (Input --surface-50). Mrtvé .mi-chip-* (:43–86, smazáno acrm !4058, 28. 9. 2026).
Storiesstatický markup — sedí s emitovaným (MentionInput.tsx:604–614, menu :647–690, řádek .acrm-recordselect-opt + .mi-opt-ic.ic-tone-*). Sizes = jiný text v single vs multiline (D7). Composition = otevřené menu — správný port, ale bez soubor:řádek (D8).
Docsmention-input.a11y.md ověřeno proti kódu: role=combobox, aria-expanded/haspopup/controls/activedescendant/multiline/label (:607–613), listbox + option + aria-selected (:658–670), .mi-sr role=status aria-live=polite (:698) — přesné. usage.md props sedí s MentionInputProps (:198–227).

1.8 Web (společné)

  • Stránky vypisují jen sekce se story (D2 z Button review platí ✓); coverage „stories" počítá jen vlastní story (D4 ✓).
  • Legacy story se stále renderuje jako první blok Default u Input, Field, Input with icon and kbd (components--inputs--fields) a Textarea (components--inputs--textarea) — registr ji má v poli Default (D1).
  • Iframe 260 px s bílou plochou u každého příkladu (site.css:84 height: 260px). Skript D5 (ds-catalog.mjs:525) měří documentElement.scrollHeight, ale Ladle GlobalProvider (packages/ui/.ladle/components.tsx:47) dává obalu minHeight: 100vh → scrollHeight = výška iframu → fit() nikdy nezmenší (D4).
  • Hlavička ukazuje „acrm main e4418f3b5", origin/main je 4f9af7c — zrcadlo acrm-main-sync.timer zaostává (na dotčených cestách bez rozdílu; jen poznámka).

2. Bug list — DS (web, registr, stories, docs)

#KdeChybaOpravaRozhoduje
D1registr + weblegacy components--inputs--fields / --textarea v poli Default u input, field, input-with-icon-kbd, textarea → web je vypisuje nad vlastní Default (u icon+kbd = pole bez ikony a kbd, opakování ACRM-76)z registru odstranit; baseline legacy story přesunout mimo rodinu (jako D10 u Buttonu)—
D2registrslider status canon/app-css→ candidate (0 použití); stories components--slider--* z registru pryč, soubor do candidates/ nebo smazatAD (A10)
D3registrinput-with-icon-kbd status canon→ candidate, stories components--input-with-icon-and-kbd--* z registru, dokud AD nerozhodne A3; docs „Related: legacy …" odstranit u input, textarea, field, icon+kbdAD (A3)
D4webiframes 260 px bílé plochy — fit() měří dokument s min-height: 100vhměřit první dítě obalu providera (story root) nebo v mode=preview minHeight neaplikovat; min 72 px zůstává—
D5storiesžádná kompozice (7×) nemá komentář soubor:řádekkaždá Composition = port: Input → PruvodceFirmyPage.tsx:860 (.acrm-range, type=number); Field → patička DrawerForm; Textarea → Field+Textarea z reálného dialogu; Tag input → ProduktDetailPage.tsx:978 (DrawerField); Mention → TaskDialog; icon+kbd → až po A3 (FilterBar.tsx); Slider → žádná (D2)—
D6stories Input Statesdisabled s hodnotou „Read only"disabled = „Locked value"; readonly až po A7 jako vlastní stav—
D7stories SizesInput, Textarea, icon+kbd, Mention mění obsah spolu s rozměremjeden obsah, mění se jen šířka/rows/výška; popisek px—
D8stories Compositionvymyšlené tvary (Field: formulář s checkboxem a Cancel/Save; icon+kbd: toolbar „128 contacts"; Slider: slider + num)nahradit porty z D5; toolbar s countem neukazovat vůbec—
D9stories StatesTextarea „disabled (native)", Slider „disabled (native)" = stav bez CSSpo A5 Textarea disabled/error ukázat; Slider viz D2—
D10stories Field VariantslabelExtra = ikona info-circle, v appce je jediný labelExtra OCR odznak (PostDocumentDialog.tsx:511)port OCR odznaku, nebo sekci vynechat—
D11stories Slider Statespopisek tvrdí fokusový ring, který neexistuje (outline: none)odstranit s D2; obecně: popisek story nesmí popisovat stav, který CSS nemá—
D12docsinput.usage.md, slider.usage.md, input-with-icon-kbd.usage.md, tag-input.usage.md citují DsInputsPage.tsx (demo routa) jako vzor markupucitovat reálné obrazovky (ProduktDetailPage, PruvodceFirmyPage…), demo nikdy—
D13docsindex.usage.md vede .acrm-stepper jako kanon „no sub page yet" — 0 použití v appcepřepsat na kandidáta; řádek „Small integer stepped ±1" odkázat na Input --num do rozhodnutí—
D14docstextarea.usage.md/.a11y.md popisují chybějící disabled/error jako vlastnostpo A5 přepsat na paritu s Inputem—
D15storiesTag input si nese vlastní state-holder TagInput (story-only komponenta)po A9 story používá <TagInput> z balíčku—
D16registrinput-with-icon-kbd má sekci „With icon & kbd" i Default i Variants se stejným obsahem (3 story téhož)po A3: jedna sekce „With icon & kbd" u Inputu (jak navrhl Button review D1)—

3. Bug list — aplikace (kanon v kódu)

#KdeChybaOpravaRozhoduje
A172 souborů raw <input className="acrm-input"> (273×) vs <Input> 57×komponenta obcházena v 83 % polí; raw prvky nemají jednotné props/refmigrace na <Input>; validator input-raw-acrm-class (warn → hard po vlně)—
A2JSX aliasy .sgb-input 42 inputů + 2 textarey (6 souborů), .finput 20× (4), .dlr-input (DialerPage), .ac-input, .prof-input4 názvy téhož boxu; ds.css je aliasuje, markup je drží naživupřepsat na <Input>/<Textarea>, aliasy z ds.css:36–70 smazat; validator input-alias-class (.au-input 46 px = záměr AD 31. 7., mimo)—
A313 vyhledávacích polí: .fb-search ×5, .set-search, .mr-search, .aichat-psearch, .itm-ac, .sgb-search, holý input GlobalSearch, tlačítko .as-search7 bespoke obalů pro jeden účel; .acrm-inputwrap pro něj 0×AD: kanon vyhledávacího pole = .acrm-inputwrap (+ nový <SearchInput> v @acrm/ui: ikona · input · kbd · Esc clear) a migrace 7 obalů, nebo kanon = FilterBar .fb-search a .acrm-inputwrap smazatAD
A4GlobalSearch.tsx:268 <kbd style>, NoteComposer.tsx:179,200 .nc-kbd, SegmentBuilder.tsx:797,940 .dlg-kbd, AppShell.tsx:1257 + app-shell.css:170 .as-search kbd4 styly kbd vedle .acrm-kbd (Button review A5 pokryl jen .as-search; DS commit a6112aa změnil jen legacy/, appka beze změny)vše na .acrm-kbd (nebo <Button kbd>); validator kbd-without-acrm-kbd—
A5ds.css:148 .acrm-textareachybí :disabled a .is-error (Input je má)doplnit paritu (--surface-75/--border/--fg-muted; critical ring); bespoke .cd-ai-input, .dlg-title, .rr-edit textarea, .sgb-input textarea → <Textarea>—
A6<Field error> 31× / 12 souborů, .is-error na inputu 0×, aria-invalid 3 souborychybový rámeček se v appce nikdy nekreslí — jen text pod polemField předá invalid do kontrolu (context) → .is-error + aria-invalid + aria-describedby; validator field-error-without-invalid—
A7readOnly na .acrm-input 10× / 7 souborů (CommissionRatesPage, ImportPage, KalkulackaVynosuPage, NastaveniPage)CSS nemá :read-only — jen-pro-čtení pole vypadá editovatelněAD: vizuál readonly (návrh: --surface-75 + rámeček --border, text zůstává --fg; disabled má --fg-muted)AD
A8Field.tsx:57 inline style labelu; raw div.acrm-field 83× / 18 souborů, .acrm-field-label 25 souborů; bez id/htmlForstyl v TSX; polovina polí obchází komponentu; label není spojen s kontrolem (a11y.md to přiznává)styl do .acrm-field-label; useId → htmlFor + aria-describedby na hint/error přes context; migrace raw .acrm-field; validator field-raw-classAD jen API (A6+A8 = jedna změna Fieldu)
A9Tag input: ProduktDetailPage.tsx:979 (kanon) + AiZamestnanciPage.tsx:79, PruvodceFirmyPage.tsx:339 .sgb-tags, MeetingDetailPage.tsx:1093 .mr-taginput (CSS .mr-taginput mezitím smazáno jako mrtvý kód, acrm !4058, 28. 9. 2026 — téma schůzky se dnes renderuje jako .acrm-pill, viz pill.usage.md)4 editory tagů, logika opsaná 4×<TagInput value onChange> v @acrm/ui (Enter/blur přidá, × odebere, dedup, aria-label na ×), migrace zbylých míst, .sgb-tags smazat; doplnit .is-disabled/.is-errorAD (potvrdit komponentu)
A10inputs.css:187–217 .acrm-slider0 použití; outline: none bez fokusu = a11y díra i pro budoucí použitísmazat CSS + z DsInputsPage, nebo do candidates/ s pravidlem fokusu (thumb ring 30 % jako checkbox)AD
A11mention-input.css:22 --shadow-xs v klidu, :31 ring 15 %, dark bez --surface-50 (:43–86 mrtvé .mi-chip-* mezitím smazáno, acrm !4058, 28. 9. 2026); MentionInputProps bez disabledjediné pole s klidovou elevací; 2 zbylé drifty od Inputu; nejde zamknoutsrovnat na Input (bez stínu, 16 %, dark surface-50), přidat disabled (contentEditable=false + vizuál disabled)—
A12.acrm-input--code/--short/--email + .acrm-inputwrap--* (0 použití), .acrm-input.is-disabled, .acrm-inputwrap.is-error/.is-disabled (0)mrtvé CSS; docs předepisují „šířka = obsah", appka pole roztahuje na sloupecAD: šířkovou škálu vymáhat (validator: type=email/kód bez modifikátoru = warn) nebo zúžit na --num + 100 % a zbytek smazat; .is-disabled na inputu smazat (nativní :disabled stačí)AD
A13inputs.css:120–157 .acrm-stepper0 použití, v docs veden jako kanondo candidates/; z index.usage.md pryč (D13)—
A1450 holých <input> bez DS třídy mimo checkbox/radio/range (MeetingDetailPage, FilterBar, GlobalSearch, RailPickerMenu…)většina = vnitřky bespoke obalů z A3/A9; zbytek textová pole bez kanonupo A3/A9 zbytek migrovat; validator input-no-ds-class (warn)—

4. Rozhodnutí pro AD

Jen otázky, které nejde rozhodnout z kódu — ostatní se opraví bez dotazů.

  1. A3 — kanon vyhledávacího pole. .acrm-inputwrap (DS karta Inputs, 0 použití) → nový <SearchInput> a migrace 7 obalů, nebo FilterBar .fb-search (5 použití, živý) povýšit a .acrm-inputwrap smazat. Bez rozhodnutí zůstává podkomponenta kandidátem bez stories.
  2. A10 — Slider. Smazat (0 použití), nebo držet jako kandidáta s doplněným fokusem pro budoucí použití (které? — dnes žádné plánované).
  3. A12 — šířková škála --num/--code/--short/--email. Vymáhat validatorem (appka dnes kód a e-mail nikdy nezužuje), nebo zúžit na --num + plná šířka.
  4. A7 — readonly stav Inputu. Vizuál pro 10 míst, která ho už používají (návrh v tabulce).
  5. A9 — <TagInput> jako komponenta balíčku (sloučení 4 editorů) — potvrdit, že tag input zůstává kanon i s jedním dnešním použitím.
  6. A6+A8 — API Fieldu (context: id/htmlFor, invalid → .is-error + aria-invalid, aria-describedby) — jedna změna komponenty, dotkne se 24 souborů jen pozitivně (bez změny volání); potvrdit směr.

5. Co teď

  1. Follow-up MR acrm (stories, bez AD): D1 (registr/baseline legacy), D5–D11 (porty kompozic, Sizes se stejným obsahem, States jen z matice), D15 po A9; MR dostane no-auto-merge, AD picky na /ds/components/text-field/*.
  2. Follow-up MR acrm (kanon, bez AD): A5 (Textarea disabled/error), A11 (Mention parita), A4 (kbd), A13 (stepper → candidates), A2 (aliasy → <Input>), A1 (migrace raw .acrm-input — po vlnách, validator warn → hard).
  3. DS repo: D2, D3, D12–D14, D16 (registr status candidate, docs bez DsInputsPage a bez legacy odkazů); D4 (web: měření výšky story rootu).
  4. AD kolo (§4, 6 otázek — jedna po druhé); teprve pak A3/A6–A10/A12 a stories icon+kbd, Slider, Tag input.
  5. Validator po každé opravě: input-raw-acrm-class, input-alias-class, kbd-without-acrm-kbd, field-error-without-invalid, field-raw-class, input-no-ds-class, (po A12) input-width-modifier.
  6. Tikety rodiny Text field se nezavírají — čekají na merge oprav a potvrzení AD na webu (§4 bod 7).

Source: docs/REVIEW-text-field-family.md · GitLab