Masked input
canonStructured value typed straight into a visible mask (IČO, DIČ, PSČ, rodné číslo) with inline check-digit validation; input holds the typed text, a muted ghost draws the rest of the template.
Merged to origin/main 28 September 2026 (acrm MR !4082, "fix(web): IČO, DIČ, PSČ a rodné číslo jako maska (MaskedInput v @acrm/ui)"), under the owner's binding rule of 14 Sep 2026 (".claude/rules/design-system.md" §"Vstupy a mobil"): a structured value is a mask, never free text — only valid characters, separators added automatically, the template stays visible, the error is reported while typing. Unlike "masked-date-input", this component IS exported from @acrm/ui (source=package) and ships four masks as pure functions in `field-masks.ts`: IČO (8 digits, mod-11 check digit), DIČ (digits-first = Czech, "CZ" is added automatically; letters-first = the typed country code, CZ is never forced; mod-11 check only for CZ), PSČ ("### ##", Czech/Slovak only — a foreign address falls back to a plain Input in the host), rodné číslo ("######/####" or 9 digits before 1953, date part validated per segment, +50 on the month for women, 10-digit form checked mod 11 with the pre-1985 exception). Two host shapes, no new look: `variant="field"` (default) wraps `.acrm-inputwrap` (`.acrm-mask`/`.acrm-mask-ghost` inside, `.acrm-maskwrap.is-error` colours the typed text `--critical-ink` in addition to the wrapper's usual red border+ring) — e.g. IČO/DIČ in the "Nová firma" drawer (`FirmyPage.tsx`); `variant="formless"` reuses the exact `.fl-mask`/`.fl-mask-in`/`.fl-mask-ghost`/`.fl-mask.bad` classes `masked-date-input` already established in `dialog-formless.css` — e.g. rodné číslo in the "Nová osoba" dialog (`NewContactDialog.tsx`). Save gate: the host reads the value out only when `mask.complete(text)` is true (`ico: mask.complete(f.ico) ? f.ico : null`); an incomplete or invalid field is simply not saved, it never blocks the rest of the form (AD 28 Sep 2026) — same rule as `masked-date-input`'s ISO gate. An old invalid stored value (recorded before the mask existed) is loaded through `applyMask()` and shown as-is, editable, not rejected. `describedBy` links the error text via `aria-describedby` when the caller passes an id — the formless caller (`NewContactDialog`, rodné číslo) wires it; the field-variant callers in `FirmyPage` (IČO, DIČ, PSČ) do not, leaving the same label/error linking gap `text-field/input.a11y.md` documents for `<Field>`. Sibling pattern `MaskedPhoneInput` (phone, dial codes) moved into `packages/ui` 28 September 2026 (acrm MR !4085) alongside the new `PhoneInput` form field and `DialCodePicker`; it now has its own registry card, `phone-input`.
Used in 2 files · 2 areas · 2× — components/org, components/person
@acrm/ui <MaskedInput>.acrm-maskwrap .acrm-maskwrap.is-error .acrm-mask .acrm-mask-ghost +4SourceStoryChangelog since 28. 9. 2026
- 28. 10. 2026polish(ds): volby (optchip, dialer chip) mají na dotyku výšku --tap-minapps/web/src/ds/inputs.cssŠtěpán · 1aeb472bc
- 17. 10. 2026refactor(ds): tokeny podle významu — vrstvy, pohyb, focus ring, text na barvě (beze změny vzhledu)apps/web/src/ds/inputs.cssŠtěpán · 8cda81b26
- 4. 10. 2026fix(ui): upozornění červeně se čtvercovým glyfem, žádná hnědá (A3a — sdílené, komunikace, nastavení, veřejné)apps/web/src/ds/inputs.cssŠtěpán · 0a39047cc
- 4. 10. 2026fix(ds): form-less hover jen pro myš — na telefonu nezůstane šedý řádekapps/web/src/ds/dialog-formless.cssŠtěpán · 2f213f80e
- 3. 10. 2026refactor(ds): nové vozidlo = form-less dialog s „Další údaje" + masky SPZ/VINpackages/ui/src/lib/field-masks.tsŠtěpán · d6efd875f
- 3. 10. 2026feat(ucetnictvi): vysvětlivky W4a — účetnictví do (i); Field: doplněk popisku vedle <label>apps/web/src/ds/inputs.cssŠtěpán · 716aabc80
- 3. 10. 2026chore(ds): pryč slider (deprecated, 0 použití) a poslední mrtvé pravidlo .pp-atapps/web/src/ds/inputs.cssŠtěpán · 416bc2c09
- 3. 10. 2026refactor(ds): MultiSelect → Select multiple (kanon nahrazuje, vizuál 1:1)apps/web/src/ds/inputs.cssŠtěpán · 898e1e106
- 3. 10. 2026refactor(ds): majetek + telefony = form-less dialog s „Další údaje"apps/web/src/ds/dialog-formless.cssŠtěpán · ed6a142b2
- 2. 10. 2026polish(ds): glyfy railu, přepínače navigace a × štítku na --ico-* (parita s boxem)apps/web/src/ds/inputs.cssŠtěpán · 566eec74c
- 2. 10. 2026fix(ds): ikona řádku form-less dialogu na ose kanonického poleapps/web/src/ds/dialog-formless.cssŠtěpán · f8e22faa2
- 2. 10. 2026chore(ds): validátor adopce — výjimky z triáže AD + ds-ok panelu dostupnostiapps/web/src/ds/dialog-formless.cssŠtěpán · e46fba481
- 1. 10. 2026fix(web): výběr záznamu bez Dialogu — rail schůzky, intro, obchod u objednávky, přidat obchod v poštěapps/web/src/ds/inputs.cssŠtěpán · b56c5c03b
- 1. 10. 2026refactor(ui): Combobox pryč — poslední volání na RecordSelect, smazán z @acrm/uiapps/web/src/ds/inputs.cssŠtěpán · aedeca283
- 1. 10. 2026fix(web): radky pod seznamem s hledanim licuji se sloupcem radku (akce PickerMenu, CheckMenu)apps/web/src/ds/inputs.cssŠtěpán · fca0ca71e
- 1. 10. 2026fix(ui): suplik roste i kdyz panel naroste po otevreni; bez Zadne vysledky u nabidnute akceapps/web/src/ds/inputs.cssŠtěpán · 7970f5145
- 1. 10. 2026fix(ui): muted radek - ztlumi se jen znacka, jmeno zustava citelne (AD: kontrast 2,85:1)apps/web/src/ds/inputs.cssŠtěpán · 09c55a7b3
- 1. 10. 2026feat(ui): RecordOption muted + subTone warn - tlumeny radek a varovny druhy udaj z kanonuapps/web/src/ds/inputs.cssŠtěpán · 7e686deb9
- 1. 10. 2026refactor(ui): holy Popover -> kanon (vlna 3) + nabidka v dialogu = panel v suplikuapps/web/src/ds/inputs.cssŠtěpán · 5a55c030f
- 29. 9. 2026fix(ui): „×" v Record selectu je tlačítko vedle triggeru, ne span role=button uvnitřapps/web/src/ds/inputs.cssŠtěpán · 2ea16ab8c
- 28. 9. 2026fix(ds-stories): audit DS — stories 1:1 s appkouapps/web/src/ds/inputs.cssŠtěpán · 251278e32
- 28. 9. 2026fix(ui): položka nabídky = jeden řádek, bez šedé vysvětlivky (ACRM-375–377)apps/web/src/ds/inputs.cssŠtěpán · 1a87decfc
- 28. 9. 2026fix(ds): zaškrtnutý checkbox (is-on/is-mixed) v tmavé = akcentní výplňapps/web/src/ds/inputs.cssŠtěpán · 0ee663488