Inventura nativních <input>/<textarea>/<select> v apps/web/src — matice A/B/C

Zdroj: node /root/.claude/jobs/d1322dc8/tmp/inputs/scan.mjs — parser strhne /* / a // komentáře (stavový průchod znak po znaku, řetězce/šablony ponechá), pak regexem sesbírá <input …>, <textarea …> a <select …> ve všech .tsx mimo __tests__/.test.tsx/ .stories.tsx. Naměřeno na aktuálním origin/main (worktree button-compact-split): 393 <input>, 13 <textarea>, 1 <select>, 538 souborů, 120 souborů s aspoň jedním <input>. (Zadání uvádělo orientační „~281 input"; grep na <input bez rozlišení komentářů dává 394 — číslo v zadání bylo hrubý odhad, tahle inventura čte přímo z mainu.)

Kanonické reference (packages/ui/src/components, apps/web/src/ds.css, apps/web/src/ds/inputs.css):

  • <Input> (Input.tsx) — tenký obal, jen přidá .acrm-input; <Textarea> totéž s .acrm-textarea; <Field> — label/hint/error obal; <Checkbox> — .acrm-check (+ .acrm-check-label s popiskem). <Radio> v @acrm/ui NEEXISTUJE — packages/ui/src/index.ts neexportuje žádnou Radio komponentu, jen třídu .acrm-radio-input/.acrm-radio-dot. <Select>, <MultiSelect>, <Combobox>, <RecordSelect> existují; MaskedDateInput a MaskedPhoneInput žijí v apps/web/src/components/multivalue/ (ne v packages/ui).
  • .acrm-input (ds.css:32-98): výška --field-h=32px, padding 0 var(--sp-3)=8px, border 1px --border-strong, radius --radius-sm=8px, font var(--p). Aliasy se STEJNÝM pravidlem (jedna definice, ds.css:32-98): .sgb-input, .dlr-input, .nastaveni-page .finput. .au-input (auth) je záměrně NEALIASOVANÝ — 46px, AD rozhodnutí 31. 7. 2026 (komentář ds.css:27-30). Modifikátory --num=88px, --code=132px, --short=210px, --email=280px (ds.css:76-91). .acrm-textarea (ds.css:135-153): min-height 72px, padding var(--sp-2) var(--sp-3), jinak stejný box jako .acrm-input. .acrm-check (ds.css:155-161): 16×16, accent-color: var(--accent). .acrm-inputwrap (ds/inputs.css:31-108) — kanonický wrapper pro pole s ikonou/kbd: box chrome nese SPAN, samotný <input> uvnitř je bez třídy (viz DsInputsPage.tsx:187, demo „S ikonou + kbd"). .acrm-recordselect-search (ds/inputs.css:490-520) — kanonický borderless vyhledávací řádek popoveru/menu, hairline dole; sdílený mnoha pickery.

Klasifikace: A — bespoke nebo raw prvek, který má jít přes DS komponentu/kanonickou třídu (u textových polí i tam, kde třída už JE .acrm-input/.acrm-textarea — cílem je <Input>/ <Textarea>, ne jen správná třída); B — legitimně nativní/součást primitivu (skrytý file input za DS tlačítkem, součást vlastní implementace Comboboxu/RecordSelectu/Multi-value editoru, color picker, vyhledávací řádek uvnitř kanonického popoveru…); C — nejasné, na stůl AD.


Nejdůležitější nález: strukturované údaje bez masky

Pravidlo ~/.claude/CLAUDE.md „Vstupy a mobil" §1: datum/telefon/IČO/DIČ/RČ/PSČ/čas/částka musí být maska, nikdy volný text. V appce existují funkční masky (MaskedDateInput — 2 místa: RelationDialog.tsx, NewContactDialog.tsx; MaskedPhoneInput — 1 místo: ChannelsPopoverEditor.tsx), ale mimo tato místa se stejné typy údajů zapisují volným textem:

ÚdajMísto (file:line)Jak je to dnesPoznámka
IČOpages/FirmyPage.tsx:464<input className="acrm-input" inputMode="numeric" value={f.ico}>volný text, jen numerická klávesnice — žádná maska/kontrola délky
DIČpages/FirmyPage.tsx:490<input className="acrm-input" placeholder="CZ…" value={f.dic}>volný text
PSČpages/FirmyPage.tsx:594<input className="acrm-input" value={f.psc}>volný text, žádný formát NNN NN
Telefon (firma)pages/FirmyPage.tsx:548<input className="acrm-input" value={f.phone}>volný text; MaskedPhoneInput existuje, ale jen pro kontaktní kanály osoby
Telefon (nová objednávka)components/orders/NewOrderForm.tsx:649<input className="acrm-input" placeholder="Telefon" value={phone}>volný text
Telefon (uživatel, Nastavení)pages/NastaveniPage.tsx:424,434<input className="finput" type="tel" maxLength={40}> (×2 — hlavní/druhý telefon)nativní type="tel" ≠ maska; jen ořízne délku
Telefon (evidence SIM)pages/TelefonyPage.tsx:126<input className="acrm-input" placeholder="+420 601 123 456" value={f.number}>volný text
Rodné číslocomponents/person/NewContactDialog.tsx:688 (text('birthNumber', …) → fl-text)generický fl-text bez maskyve stejném souboru MaskedDateInput pro datum narození JE nasazený (řádek ~ import) — RČ vedle něj zůstalo volným textem
Datum (opačné porušení — jen kalendář, žádná psaná maska)components/projects/ProjectRail.tsx:1068,1075<input readOnly value={formatDate(range.from)}> otevírá Calendar/PickerPanelpravidlo §4 „kalendář je doplněk, ne jediný vstup" — tady je JEDINÝ vstup
Částka (16 míst)viz nížetype="number" nebo inputMode="decimal"/"numeric" na holém .acrm-inputžádné tisícové oddělovače, žádná měnová maska; typicky minor units /100

Částka — všech 16 míst bez masky: components/clen-tymu/AdvanceSection.tsx:151, BenefitSection.tsx:170, ExpenseSection.tsx:286, KpiSection.tsx:120, pages/TeamDetailPage.tsx:344, components/costs/CostDialog.tsx:351,394, pages/DokumentyPage.tsx:397, components/products/PricingSections.tsx:119, pages/MajetekPage.tsx:243, pages/OrderDetailPage.tsx:350, pages/PokladnaDetailPage.tsx:150, pages/RozpoctyPage.tsx:215, pages/VozidlaPage.tsx:233, pages/ObchodDetailPage.tsx:184 (inline buňka tabulky položek), pages/TelefonyPage.tsx:154 (měsíční paušál).

Kontrast: mimo tato místa je maskovaný vstup nasazen jen bodově (2× datum, 1× telefon) — pravidlo platí plošně „ve VŠECH dialozích", ale reálně pokrývá jen novou osobu/vztah a jeden kanál kontaktu. Firemní IČO/DIČ/PSČ/telefon (hlavní vstupní bod dat o firmě), telefon uživatele v Nastavení, evidence SIM karet a všechny peněžní částky v appce jdou mimo masku.


A — raw prvek/bespoke třída → DS komponenta (18 skupin, 337 výskytů)

Třída / vzorPočetUmístění (file:line, resp. soubory)CSS pravidloCílVizuální změna
acrm-input (raw <input>)225 (231 −6 file-type řešené zvlášť)63 souborů, nejvíc NastaveniPage.tsx(14), FirmyPage.tsx(13), VozidlaPage.tsx(13), ConnectMailboxPopup.tsx(8), VehicleDetailPage.tsx(8), NewOrderForm.tsx(7), PricingSections.tsx(7), CostDialog.tsx(6), MajetekPage.tsx(6), PortfolioBuilderPage.tsx(6), TelefonyPage.tsx(6), ZasedackyPage.tsx(6) … (plný seznam file:line v raw.json)ds.css:32-98<Input>ne — třída už je kanonická, jde jen o obal komponentou (ref/props se 1:1 propouští)
sgb-input (raw <input>)41ManageSegmentDialog.tsx(18), PruvodceFirmyPage.tsx(13), PruvodcePage.tsx(8), MergeDialog.tsx(1), SegmentBuilder.tsx(1)ds.css:32-98 (alias .acrm-input)<Input>ne — sdílená definice s .acrm-input
finput (raw <input>)20NastaveniPage.tsx(16), settings/InlineName.tsx(1), settings/StitkyTab.tsx(1), settings/TypyCiselTab.tsx(1), settings/napojeni/TokenyBlock.tsx(1)ds.css:35 (.nastaveni-page .finput, alias potvrzen — vše leží pod SettingsLayout/.nastaveni-page)<Input>ne
dlr-input (raw <input>)1pages/DialerPage.tsx:1250ds.css:34 (alias .acrm-input)<Input>ne
acrm-input na type="file" (viditelný)6components/clen-tymu/ExpenseSection.tsx:212, HrSections.tsx:519,643, pages/AssetDetailPage.tsx:459, DokumentyPage.tsx:466, MajetekPage.tsx:370— (.acrm-input box se na file inputu nevykreslí, prohlížeč kreslí vlastní „Vybrat soubor")skrytý <input type=file hidden> + spouštěcí <Button>/<IconButton>, stejný vzor jako zbylých 23 skrytých file inputů v appceano — dnes nekonzistentní nativní widget uprostřed DS formuláře
radio se třídou checkboxu1components/callwrapup/FollowupMail.tsx:49 (type="radio" className="acrm-check")ds.css:155-161 (.acrm-check je čtvercový 16×16, ne kulaté radio).acrm-radio-input (skupina name="fu-mode" je fakticky radio)ano — čtvercový glyf místo kulatého u vzájemně vylučujících voleb
sel (raw <input>, ImportPage)2pages/ImportPage.tsx:856,868ds/import.css:319-329 — výška --control-h=30px, font 500 13px<Input>ano — 30 px vs. Input 32 px (--field-h)
acrm-check (raw checkbox, už kanonická třída)4components/assistant/AssistantPrompts.tsx:428, components/meetings/RecordMenu.tsx:481, pages/NastaveniPage.tsx:2632,2747ds.css:155-161<Checkbox>ne
acrm-textarea (raw <textarea>)4 (+1 DS katalog, viz níže)components/assistant/AssistantPrompts.tsx:397, components/meetings/RecordMenu.tsx:518, pages/OrderDetailPage.tsx:538ds.css:134-153<Textarea>ne
sgb-input dlg-textarea (raw <textarea>)2components/segment/ManageSegmentDialog.tsx:221, components/segment/SegmentBuilder.tsx:826ds/segment-screen.css:1202-1208 (min-height 76px) vs. .acrm-textarea min-height 72px<Textarea>drobně — 76 px vs. 72 px min-height
sgb-check (checkbox bez třídy na <input>, obal .sgb-check)1pages/PruvodcePage.tsx:1174ds/builder-panels.css:265-281 — input 15×15<Checkbox> / .acrm-checkano, ale malá — 15 px vs. kanon 16 px; drift je zdokumentovaný přímo v ds.css:162-164 jako „známý drift k reconciliaci upstream"
asg-check (checkbox bez třídy, obal .asg-check)2components/mail/AssignPopup.tsx:149,156components/mail/mail.css:1249-1258 — .asg-check > input nemá width/height/accent-color, jede na nativní výchozí vzhled prohlížeče<Checkbox> / .acrm-checkano — jediný skutečně nestylovaný nativní checkbox v appce (žádný accent-color, žádná pevná velikost)

Poznámka k .acrm-check (4×) a .acrm-radio-input (4×) jako kanonickým třídám: obě už sedí na správné DS třídě (žádná vizuální změna), ale u radia dnes není co nasadit — @acrm/ui žádnou <Radio> komponentu neexportuje (jen třídu .acrm-radio-input/ .acrm-radio-dot). Adopce <Checkbox> (4×) je čistě kosmetická component-wrap; adopce <Radio> čeká na to, až komponenta vznikne — mimo rozsah téhle inventury, ale stojí za zápis pro AD.

DS katalogová stránka /ds/inputs (pages/DsInputsPage.tsx, 11 výskytů: 8× input, 1× textarea, 1× slider bez třídy pro ikonu+kbd demo) se do součtů A/B/C nepočítá — je to ukázková stránka samotného kanonu (dema .acrm-input, .acrm-inputwrap, .acrm-slider…), ne appková bespoke implementace. Zajímavost pro dogfooding: i tahle stránka používá raw <input>, ne <Input>.


C — nejasné, patří na stůl AD (5 skupin)

VzorPočetUmístěníProč nejasné
sgb-ck (custom checkbox, native input vizuálně skrytý 1×1px, viditelný glyf je sourozenec .ck)2components/segment/SegmentScreen.tsx:1014 (hlavičkové „vybrat vše"), :1161 (výběr řádku)ds/segment-screen.css:620-649 — úmyslně JINÝ vzhled než .acrm-check (vlastní hranatý box řízený sourozeneckým selektorem, ne accent-color). Nejasné, zda je to schválená datagridová varianta Checkboxu, nebo bespoke k reconciliaci.
ac-input / .ac / .adr-combo (bespoke address-autocomplete combobox)1components/segment/SegmentBuilder.tsx:203 (role="combobox")ds/segment-screen.css:819-848; ds.css:31 dokumentuje .ac-input jako „záměrně NEALIASOVANÝ" borderless field. Nejasné, zda cíl je @acrm/ui <Combobox> (fetch-based návrhy adres by šly přes options), nebo zůstává bespoke kvůli vlastnímu fetch/klávesnicovému chování.
cd-ai-input (AI prompt textarea na dashboardu)1pages/CrmDashboardPage.tsx:109ds/crm-dashboard.css:41-54 — borderless, transparent, min-height 66px. Assistant chat (AssistantChat.tsx) textarea pro prompt nemá — nejasné, zda existuje/má vzniknout sdílený „AI prompt textarea" primitiv, nebo je dashboard záměrně samostatný widget.
sgb-th-edit (inline přejmenování hlavičky sloupce segmentové tabulky)1components/segment/SegmentScreen.tsx:871ds/segment-screen.css:468-478 — 104×22px, vlastní border: 1px solid var(--accent). Kontextově velmi specifické (uvnitř <th>); nejasné, zda cíl je mini varianta <Input>, nebo zůstává bespoke pro tabulkový kontext.
Datum bez psané masky (ProjectRail.tsx:1068,1075)2viz tabulka výšeJe to „opačné" porušení §4 (jen kalendář) — možná AD schválený vzor pro rozsahový filtr railu (ne zápis nové hodnoty), možná mezera k doplnění masky.

B — legitimně nativní / součást primitivu (kompaktní přehled)

  • Skryté file inputy za DS tlačítkem/dropzone (23×): components/IdentityImageDialog.tsx:205, SubjectFilesTab.tsx:139, clen-tymu/HrSections.tsx:241, mail/ComposeForm.tsx:3317, meetings/TranscriptTab.tsx:655,662, notes/NoteAudio.tsx:85, projects/ProjectEntryDialog.tsx:257, tasks/TaskDialog.tsx:1689, pages/AssetDetailPage.tsx:532, BankaPage.tsx:513, DocumentDetailPage.tsx:1140, DokumentyPage.tsx:161, ImportPage.tsx:547, MeetingDetailPage.tsx:557, NastaveniPage.tsx:378, PickPage.tsx:218, PokladnaDetailPage.tsx:203, ProduktDetailPage.tsx:571, SetkaniPage.tsx:308, onboarding/ProfilPage.tsx:78, settings/CompanyKnowledgeSection.tsx:195, settings/TemplateAttachmentsSection.tsx:91 — všechny hidden/style={{display:'none'}} + ref, spouští je viditelné DS tlačítko.
  • Vyhledávací řádek uvnitř kanonického popoveru/menu (borderless, bez vlastní třídy na <input>, chrome nese obal): .acrm-recordselect-search (EntityPicker.tsx:254, FilterBar.tsx:786,894,933,1079, ProductPicker.tsx:122, RecordSearchSelect.tsx:102, dialog/ChipSearchMenu.tsx:99, mail/compose/TemplateMenu.tsx:248, multivalue/DialCodePicker.tsx:90, projects/ProjectMeetingLinkDialog.tsx:70; vlastní pojmenované varianty téhož vzoru: .fb-search (FilterBar.tsx:631), .gsp-q (GlobalSearch.tsx:1499, DealSubjectStep.tsx:199), .mr-search (meetings/TranscriptTab.tsx:821,994), .set-search (settings/SettingsLayout.tsx:232), .aichat-psearch (assistant/AssistantPrompts.tsx:150), .itm-ac (deal/deal-parts.tsx:137).
  • .acrm-inputwrap — kanonický wrapper pro ikonou-prefixované pole, <input> uvnitř bez vlastní třídy (ds/inputs.css:31-108): components/callwrapup/WrapupBand.tsx:226 a sourozenci ve stejném souboru.
  • Multi-value editor rodina (ds/multi-value.css): .phe-num (4× — vlastní guts MaskedPhoneInput.tsx:31/38, plus ChannelsPopoverEditor.tsx:432,625, EntityRowsPopoverEditor.tsx:101), .phe-type (jediný <select> appky, ChannelsPopoverEditor.tsx:655).
  • Formless dialog rodina (ds/dialog-formless.css): .fl-text (8× — hodnotové řádky), .fl-title (2× input + 5× textarea rows=1 — auto-rostoucí titulek), .fl-mask-in (MaskedDateInput.tsx:31 — guts masky samotné).
  • Dialog-doc rodina (ds/dialog-doc.css): .dlg-bare (2×), .dlg-title (1× textarea, 28px, „schválně NEZMENŠUJE").
  • RecordRail rename — .rr-edit (projects/ProjectRail.tsx:871), komentář v ds/project-rail.css:319 výslovně „kanonické aktivní pole railu".
  • Note editor rich-text bubble — .nt-bub-url (notes/NoteEditor.tsx:329), vložení odkazu uvnitř plovoucí bubliny, ds/note-dialog.css:295-304.
  • Auth vrstva — .au-input (4×), AD rozhodnutí 31. 7. 2026 že se NEALIASUJE k .acrm-input (46px, celoplošná brána mimo shell).
  • Color picker — type="color" (segment/SegmentBuilder.tsx:633).
  • OTP kód — pages/onboarding/OtpPage.tsx:97 (vizuální boxy jsou <span>, skutečný <input> je jeden skrytý společný vstup pod nimi).
  • acrm-radio-input (4×, kanonická třída, žádná <Radio> komponenta zatím neexistuje): company/CompanyMergeTable.tsx:278, NastaveniPage.tsx:2723, SouhlasPripojeniPage.tsx:152, settings/AccessPresets.tsx:80.
  • acrm-check/acrm-slider v DS katalogu (DsInputsPage.tsx) — demonstruje kanon, mimo audit appky.

Totals

BucketSkupin (tříd/vzorů)Výskytů
A10 řádků výše (bez DS katalogu)337 (225 + 41 + 20 + 1 + 6 + 1 + 2 + 4 + 4 + 2 [textarea sgb-input] ≈ přesně: 225 acrm-input + 41 sgb-input + 20 finput + 1 dlr-input + 6 file-type + 1 radio-jako-checkbox + 2 sel + 4 acrm-check + 4 acrm-textarea + 2 sgb-input-textarea + 1 sgb-check + 2 asg-check = 309 input/textarea prvků, viz poznámka níže)
B20+ rodin/tříd~55 input/textarea/select výskytů (skryté file inputy 23, vyhledávací řádky ~15, .acrm-inputwrap 4, multi-value 7, formless 15, dialog-doc 3, rr-edit 1, nt-bub-url 1, au-input 4, color 1, OTP 1, acrm-radio-input 4, select 1)
C5 skupin7 výskytů
DS katalog (DsInputsPage.tsx, mimo audit)—11
Celkem (input+textarea+select)393 + 13 + 1 = 407

Pozn. k součtu A: čísla v tabulce výše jsou přesná per-skupina; „225" u acrm-input = 231 celkových výskytů třídy acrm-input na <input> MINUS 6 file-type řešených ve vlastním řádku. Component-adopce (<Input>/<Textarea>/<Checkbox>) bez vizuální změny pokrývá naprostou většinu A (286 z 309 — acrm-input, sgb-input, finput, dlr-input, acrm-check, acrm-textarea); se skutečnou vizuální odchylkou je jen menšina (23: 6 file, 1 radio-jako- checkbox, 2 sel, 1 sgb-check, 2 asg-check, 2 sgb-input-textarea drobně, zbytek).

Nejdůležitější zjištění zůstává mimo tuhle A/B/C mechaniku: 26 míst (10 strukturovaných typů + 16 částek) porušuje pravidlo „strukturovaný údaj = maska" bez ohledu na to, jestli input má, nebo nemá kanonickou třídu — pages/FirmyPage.tsx (IČO/DIČ/PSČ/telefon firmy) je přitom hlavní vstupní bod dat o firmě do CRM.

Source: docs/text-field/INVENTURA-nativni-vstupy-2026-09-28.md · GitLab