Filter bar
Rândul de filtre de deasupra unei liste — un singur model în toate aplicațiile. Filtrele se aplică pe loc, fiecare se golește cu ✕-ul lui, iar ✕-ul de la capătul barei le golește pe toate. Nu e o familie nouă de controale: toate cele opt feluri de filtru sunt controale care existau deja în DS.
Markup canonic · components/filter-bar.json
Facturi emise
31 de rezultateAnatomie
.filter-hd titlul + numărul; numărul doar cât lista e filtrată
┌──────────────────────────────────────────────────────────────────┐
│ Facturi emise │ 31 de rezultate │
└──────────────────────────────────────────────────────────────────┘
.filter-bar 16px sub antet · 8px între filtre
┌──────────────────────────────────────────────────────────────────┐
│ [Toate|Încasate|…] [Emisă +1 ✕] [1 sep – 30 sep ✕] │
│ [Orice sumă ▾] ☐ Doar restante [omv ✕] (✕) │
└──────────────────────────────────────────────────────────────────┘
(✕) = .filter-reset, ✕-ul general: la capătul rândului,
doar de la două filtre aplicate; căutarea îi face loc
.tbl-wrap bara stă ÎN carcasa tabelului (.tbl-filters), peste un
.tbl.compact — un gutter de 14px: titlul, primul filtru
și prima coloană pe aceeași linie (table.json → filtered)
carcasa e bej-1: filtrele albe se văd pe ea; ✕-ul general
trece pe alb, șina segmentului primește contur
ordinea segment → alegeri (o valoare, mai multe, entitate)
→ intervale (perioadă, sumă) → da/nu → căutarea → ✕-ul general
câte cel mult 6 filtre pe o listă, căutarea inclusă
lățimi părți egale din rând, oricare ar fi valoarea (peste, elipsă);
rupere sub 120px; căutarea umple rândul până la capăt, cel mult
480px, și se strânge cu 48px când apare ✕-ul general — restul
nu se mișcă; segmentul are 2–7 opțiuni și derulează peste rând
mobil sub 1024px două pe rând; segmentul și căutarea pe rând întreg
Cele opt filtre
Fiecare are o stare neutră — cea care nu filtrează, numită de placeholder — și o stare aleasă. Tot ce ține o valoare primește ✕; segmentul și checkbox-ul nu, fiindcă neutrul lor e deja la un click.
variants.searchvariants.selectvariants.multi-selectvariants.entityvariants.periodvariants.amountvariants.segmentvariants.boolean| Filtru | Când | Controlul | Neutru | Golire | Aplicare |
|---|---|---|---|---|---|
| Căutare | text liber, în mai multe câmpuri | .input-group + type=search | „Caută client sau descriere…" | ✕ în addon | debounce 500ms |
| O valoare | listă închisă, o alegere | .select-anchor + .select-trigger | „Toate tipurile" | ✕ în locul săgeții | pe loc |
| Mai multe valori | listă închisă, mai multe (statusuri) | același + .popover-item.check-item | „Toate statusurile" | ✕ în locul săgeții | pe loc, la fiecare bifă |
| Entitate | UN client / furnizor din mii | .typeahead + .input-group | „Toți clienții" | ✕ în addon | pe loc, la alegere |
| Perioadă | o zi sau un interval de date | .select-trigger + .calendar | „Oricând" | ✕ în locul săgeții | pe loc, la fiecare click |
| Sumă | de la / până la | .select-trigger + .filter-range | „Orice sumă" | ✕ în locul săgeții | debounce 500ms |
| Segment | împărțirea principală, 2–7 opțiuni (peste rând, derulează) | .tabs ca radiogroup | „Toate" (prima) | —, neutrul e la un click | pe loc |
| Da / nu | o întrebare pusă listei | .check-item | nebifat | —, debifarea | pe loc |
Deschise
Listele sunt cele ale controalelor de bază — .popover cu bifa de brand pe rândul ales, .calendar în interval cu scurtături, .typeahead cu rândul de meta pentru cod. Nimic din popover nu are buton de „Aplică": fiecare click filtrează lista din spate.
Golire și resetare
Facturi emise
| Client | Dată | Sumă |
|---|
| Ce | Regula |
|---|---|
| ✕ | Apare doar cât controlul ține o valoare. Golește doar filtrul lui, pe loc — sare debounce-ul, altfel lista ar mai rula 500ms căutarea veche — și întoarce focusul pe control. |
| „Filtrat" | Cel puțin un filtru aplicat diferit de neutru. Se citește de pe filtrul aplicat, după debounce — nu de pe textul din câmp —, deci numărul apare în clipa în care lista îl urmează. |
| Numărul | Doar cât lista e filtrată și prima pagină a venit: „1 rezultat", „4 rezultate", „31 de rezultate". Nefiltrată ar număra tot ce s-a înregistrat vreodată. |
| ✕-ul general | .filter-reset: .btn.secondary.icon-only de 40px cu tooltip, ultimul în bară, la capătul rândului, doar de la două filtre aplicate — cu unul singur ar dubla ✕-ul acelui filtru. Căutarea se strânge ca să-i facă loc. Readuce toate controalele la neutru — segmentul și checkbox-ul inclusiv. Focusul trece pe primul control din bară: butonul dispare odată cu filtrarea. Secondary — acțiunea neutră, o treaptă peste ✕-ul ghost al unui câmp; nu .danger (negrul e al ștergerii) și nu .primary (acțiunea principală a ecranului e alta). |
| Combinare | ȘI între filtre; SAU între valorile aceluiași filtru cu mai multe valori. |
| Persistență | Niciuna: filtrele trăiesc cât pagina, iar revenirea pe pagină pornește nefiltrată. Mutarea lor în URL e o decizie pentru toate listele deodată, nu pe ecran. |
| Încărcare | Lista își arată singură încărcarea; bara rămâne activă. Un select ale cărui opțiuni vin de la server e :disabled cu „Se încarcă…" până sosesc. |
Zero rezultate · .tbl-empty
Trei motive, trei propoziții. Doar lista goală din cauza filtrelor primește ieșirea — pe o listă goală fiindcă nu există încă nimic, „Resetează filtrele" n-ar avea ce face.
Mobil · sub 1024px
aceeași bară, același model — fără foaie de filtre, fără „Aplică" [ Toate | Încasate | Neîncasate ] segmentul: rând întreg [ Emisă +1 ✕ ] [ Oricând ▾ ] două pe rând, câte o jumătate [ Orice sumă ▾ ] [ ☐ Doar restante ] [ Caută client sau descriere… ] (✕) căutarea + ✕-ul general câmpurile de text urcă la 16px (bono-ds.css, regula de zoom iOS)