Input group

Trei componente, o singură cutie. .field deține ce e în afara bordurii — etichetă, ajutor, eroare, orientare. .input-group deține ce e în interiorul ei — iconiță, text static, buton, scurtătură. .input e controlul gol. Se cuibăresc, nu concurează: .field > .input-group > .input.

Markup canonic · components/input-group.json

sursa = JSON · generat de scripts/build-catalog.py
https://

Anatomie · addon-uri în interiorul bordurii

Iconiță, text static, buton, spinner, scurtătură — lipite de control, în aceeași bordură. Regula: bordura trece pe carcasă, controlul o pierde. Echivalentul lui InputGroup din shadcn; din v8.2 are contract propriu (components/input-group.json), fiindcă are clase, variante, stări și o componentă React ale lui.

Granița e cea din capul paginii: eticheta, ajutorul și eroarea sunt ale câmpului; ce e aici e în bordură. Căutarea din topbar n-are etichetă, deci e .input-group singur.

.input-group                    carcasa · h 40 · padding 0 16 · gap 8 · r --r-lg
├── .input  sau  textarea.input   controlul, copil direct — fără bordură, fundal, înălțime
├── .input-group-addon            slotul · 14px fog · svg 16 · implicit inline-start
│   ├── .input-group-text         text static (Lei · https:// · 0/280) · .ink pentru unități
│   ├── .badge.sm.outline         scurtătură — badge alb, pe un <kbd>
│   ├── .btn.xs / .btn.sm         buton PLAT: .ghost · .outline · .outline-pink — o ACȚIUNE
│   └── .select-anchor            o VALOARE din listă (moneda): .select-trigger.sm.bare
└── .input-group-addon.inline-end al doilea slot

în carcasă — padding 16, gap 8 între addon și control · scurtătura la capăt: 8 sus, dreapta și jos

16
svg
8
.input
8
badge
8

Aliniere

Pe input: inline-start (implicit) și inline-end. block-start și block-end — o bară pe rând propriu; carcasa devine coloană: toolbar pe textarea, sau eticheta în bordură când bara ține un .field-label. Addon-ul se scrie după control în DOM: poziția o face order, ordinea de tab rămâne cea corectă.

inline-start · inline-end
Lei
block-start · block-end pe textarea — bare pe rând propriu, .ruled pune linia
mentiuni-factura.md 0/280

Ce intră în addon

iconiță · text prefix și sufix · kbd
⌘K
https:// .ro
buton plat · .btn.ghost.xs.icon-only · .btn.outline.xs
@

Butonul din addon e o acțiune a câmpului, nu CTA-ul ecranului — de asta e plat și nu se ridică la hover; grupul anulează ridicarea chiar și pe o variantă plină pusă din greșeală. Stările (hover, focus, eroare, disabled) sunt pe carcasă, cu valorile inputului. O valoare nu e buton: moneda aleasă dintr-o listă e .select-anchor + .select-trigger.sm.bare, cu lista select-ului — Select spune că un declanșator care poartă o valoare nu e niciodată .btn.

sumă cu monedă, la mărime normală · .select-trigger.sm.bare în addon + .popover.align-end — mărimea normală a lui Money input. Deschis, carcasa se aprinde, iar trigger-ul își ține doar fill-ul bej: halo-ul e al carcasei
Migrare v8: .input-group însemna până acum un rând de câmpuri — ăla e .field-row. .field.input-em a dispărut: eticheta din bordură e .input-group cu un addon block-start care ține .field-label, iar eticheta trece după input în DOM (ordinea de tab). .search-wrap e deprecat: iconița lui era position: absolute și nu rezerva spațiu. Rămâne în CSS doar cât îl folosește referința Dublin (oglinda producției); dispare odată cu sync-ul în BFF. Focusul la click pe addon e un handler în aplicație (carcasa e <div>, ca la shadcn, fiindcă addon-ul poate conține butoane).

Eticheta în interiorul bordurii

Un input group cu eticheta ca bară block-start — forma din shadcn. Eticheta e pink în repaus, pink-deep pe focus; bordura rămâne neutră. Doar client-facing (Dublin, landing) — formularele interne folosesc .field neutru. Se recunoaște prin conținut, .block-start > .field-label, nu printr-o clasă nouă.

repaus · label pink
focus · label pink-deep, halo neutru
eroare · label iese din brand, devine ink
textarea · scroll intern, resize vertical, label rămâne deasupra

În eroare, eticheta nu devine roșie și nu rămâne pink: brandul nu poartă sens negativ, iar pink lângă roșu pe tint roșu măsoară 3.33:1. Devine ink (17.48:1).

React · react/input-group.tsx

Split din react/input.tsx în v8.2, în același pas cu contractul. Exportă InputGroup, InputGroupAddon, InputGroupText. Mărimea și tonul sunt props (size="lg", tone="tonal"), nu clase scrise la call-site.

<InputGroup size="lg">
  <Input size="lg" placeholder="exemplu.ro" />
  <InputGroupAddon align="inline-start">
    <InputGroupText>https://</InputGroupText>
  </InputGroupAddon>
</InputGroup>

Carcasa e un <div role="group">, nu un <label>: un addon poate conține butoane, iar un buton într-un label ar fura click-ul câmpului. Sub 1024px carcasa e obligatoriu lg, în pereche cu controlul — o carcasă de 40px în jurul unui control de 44px taie controlul.