@wemake4u/form-controls 2.0.0 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -15,6 +15,258 @@ Requisiti: Angular 22 (`@angular/core`, `@angular/common`, `@angular/forms`) e i
15
15
  La libreria **non include e non distribuisce** il Sirio web kit: genera il markup e le classi del kit, ma CSS,
16
16
  font e immagini li deve fornire l'applicazione. Versione richiesta: **`sirio-kit-web` 9.1.0** (ultima versione rilasciata).
17
17
 
18
+ ## Sola lettura: aspetto dei campi
19
+
20
+ Nel kit un campo in sola lettura ha lo stesso aspetto di un campo disabilitato (sfondo e bordo grigi). Con
21
+ `readonlyAppearance` i campi in sola lettura possono avere invece lo sfondo bianco e il bordo chiaro del kit, così
22
+ si distinguono dai disabilitati (che restano grigi):
23
+
24
+ | Valore | Aspetto in sola lettura |
25
+ | --- | --- |
26
+ | `filled` (default) | come il kit: sfondo e bordo grigi, uguale al disabilitato (anche la select, che il kit non copre) |
27
+ | `outline` | sfondo bianco, bordo chiaro del kit (`#e3e5e8`), testo nel colore normale del campo |
28
+
29
+ ```ts
30
+ // Default per tutta l'applicazione (app.config.ts) o per un componente (providers)
31
+ providers: [provideSirioReadonlyAppearance('outline')]
32
+ ```
33
+
34
+ ```html
35
+ <!-- Override per il singolo controllo -->
36
+ <wm-sirio-select label="Provincia" readonly readonlyAppearance="outline" ... />
37
+ ```
38
+
39
+ Vale per textbox, textarea, number, date, time, datetime, select (anche `searchable`), autocomplete, searchbar e
40
+ slider (campo numerico); prefissi e suffissi dei campi seguono lo stesso aspetto. Con `outline` restano invariati i
41
+ bordi degli stati di validazione (errore, valido, avviso) e del focus da tastiera. Checkbox, radio, checklist e
42
+ file upload non hanno un campo con sfondo: l'impostazione non li modifica.
43
+
44
+ ## Select con ricerca: pulsante di azzeramento
45
+
46
+ Di default la select con `searchable` non mostra il pulsante "X" del kit: il valore si cambia scegliendo un'altra
47
+ opzione, o si azzera da codice. Con `clearable` il pulsante viene mostrato e svuota ricerca e selezione.
48
+
49
+ ```html
50
+ <wm-sirio-select label="Comune" searchable clearable [options]="comuni" formControlName="comune" />
51
+ ```
52
+
53
+
54
+ ## Select: opzioni in caricamento
55
+
56
+ Con `loading` la select mostra che le opzioni stanno arrivando (es. da un servizio): il campo chiuso mostra
57
+ `loadingText` ("Caricamento in corso") al posto del placeholder con lo spinner del kit, la lista contiene solo la riga
58
+ "Caricamento in corso" con lo spinner, il combobox ha `aria-busy` e il messaggio è annunciato agli screen reader.
59
+
60
+ ```html
61
+ <wm-sirio-select label="Provincia" [loading]="province() === null" [options]="province() ?? []" formControlName="prov" />
62
+ ```
63
+
64
+ ## Data grid
65
+
66
+ `wm-sirio-data-grid` genera la **tabella del kit** (`table.sirio-table`); filtri, ordinamento e paginazione dei dati
67
+ sono elaborati da [TanStack Table](https://tanstack.com/table) (`@tanstack/angular-table` 9, dipendenza installata con la
68
+ libreria; l'istanza è esposta come `table` per usi avanzati). La griglia ha ordinamento anche su più colonne,
69
+ paginazione (`wm-sirio-pagination`), selezione delle righe, colonne ridimensionabili e riordinabili, righe espandibili
70
+ (dettaglio e dati ad albero), raggruppamento con totali e i layout del kit. Le colonne si dichiarano con
71
+ `wm-sirio-grid-column`; celle e intestazioni personalizzate con i template `wmSirioGridCell` e
72
+ `wmSirioGridHeader`, la riga vuota con `wmSirioGridEmpty`, il dettaglio delle righe con `wmSirioGridDetail`.
73
+ Import unico: `imports: [SIRIO_DATA_GRID]`.
74
+
75
+ ```html
76
+ <wm-sirio-data-grid caption="Pratiche" [data]="pratiche" rowId="id" selection="multiple" [(selected)]="scelte">
77
+ <wm-sirio-grid-column field="numero" header="Numero" sortable filter="text" />
78
+ <wm-sirio-grid-column field="importo" header="Importo" align="end" sortable [format]="euro" filter="number" />
79
+ <wm-sirio-grid-column field="stato" header="Stato">
80
+ <ng-template wmSirioGridCell let-row><span [wmSirioTag]="tipo(row)">{{ row.stato }}</span></ng-template>
81
+ </wm-sirio-grid-column>
82
+ </wm-sirio-data-grid>
83
+ ```
84
+
85
+ - **Dati in memoria** (`[data]`): la griglia ordina (confronto numerico, per data o testo con le regole della lingua di
86
+ `LOCALE_ID`) e pagina.
87
+ - **Formati predefiniti**: `format` accetta una funzione `(valore, riga) => testo` oppure il nome di un formato, con le
88
+ opzioni in `formatOptions` (tutti seguono `LOCALE_ID`; `empty` = testo dei valori vuoti):
89
+ `number` (`decimals`, `minDecimals`/`maxDecimals`, `grouping`), `currency` (`currency`, default EUR), `percentage`
90
+ (`decimals`, `scale: 'percent'` se il valore è già 15), `date` (`precision`: `day`, `month`, `year`), `dateTime` e
91
+ `time` (`seconds`), `boolean` (`trueLabel`, `falseLabel`, default Sì/No), `map` (`values`: oggetto o `SirioOption[]`).
92
+ Numeri e date si leggono anche da testo (`'89.9'`, `'2026-01-31'`, `'2026-01-31T14:30'`). I formati numerici sono
93
+ allineati a destra (se `align` non è indicato), numeri e date usano il font del kit e si ordinano per valore; con `map`
94
+ il filtro `select` elenca tutti i codici con la loro etichetta. `provideSirioGridFormats({ defaults, formatDefaults,
95
+ formats })` imposta le opzioni di default e registra formati propri per nome (o sostituisce quelli predefiniti).
96
+ - **Formati di `LOCALE_ID`**: senza `format`, i numeri delle celle usano il separatore decimale della lingua (senza
97
+ separatore delle migliaia, così codici e anni restano invariati) e i valori `Date` il formato data; conteggi, numeri
98
+ e date nei chip dei filtri e nei risultati seguono `LOCALE_ID` (es. `it-IT`: "1234,5", "31/01/2026", "10.000").
99
+ - **Font dei numeri del kit**: le celle numeriche e di data (colonne con filtro `number`/`date`, o con valori numero o
100
+ `Date`), i numeri di riga, i conteggi e i totali dei gruppi usano la classe del kit `font-mono` (Roboto Mono, come
101
+ campi numerici, date e paginazione del kit); `mono` sulla colonna lo forza (`true`) o lo toglie (`false`).
102
+ - **Intestazioni su una riga**: il titolo è tagliato con i puntini (testo completo nel tooltip), l'indice di
103
+ ordinamento e l'imbuto del filtro restano visibili. `filterButton="hover"` mostra l'imbuto solo al passaggio del
104
+ mouse, con il focus o quando il filtro è attivo (come ag-grid); `filterButton="none"` toglie i controlli di filtro
105
+ dalla griglia (anche il pannello del layout a card): i filtri si impostano solo da codice (`[(filters)]`, `setFilter`); default `always`.
106
+ - **Riga di filtri** (`filterRow`): una riga sotto le intestazioni, come il floating filter di ag-grid. Ogni colonna
107
+ con filtro ha un campo per la condizione semplice (testo: contiene, numero e data: uguale, select e booleano: un
108
+ valore; con `filterOperators` l'operatore scelto) e l'imbuto con il popover degli operatori; una condizione che non
109
+ sta nel campo (es. "compreso tra", "vuoto", più valori) è mostrata come riepilogo. Esc svuota il filtro della
110
+ colonna. Il campo si chiama "Filtra per <colonna>" (`filterLabel`), l'imbuto "Altre condizioni per <colonna>"
111
+ (`filterMoreLabel`). Con la riga di filtri i chip dei filtri non sono mostrati; nel layout a card resta il pannello "Filtri".
112
+ - **Testo su una riga**: i testi lunghi vanno a capo (default); `[wrap]="false"` sulla colonna tiene il testo su una
113
+ riga (la colonna si allarga, o il testo è tagliato con i puntini se la colonna ha una larghezza). Lo stesso `field`
114
+ può comparire in più colonne (es. una data mostrata come data e come ora), ognuna con il proprio filtro: in `filters` la
115
+ prima colonna usa il `field`, le altre `field~2`, `field~3` (o il loro `filterKey`).
116
+ - **Colonna larga quanto il contenuto**: `fit` sulla colonna (es. una colonna di azioni): non prende parte dello
117
+ spazio libero della tabella, le celle restano su una riga e il titolo non viene tagliato.
118
+ - **Dati da un FormArray** (`[formArray]`): un `FormGroup` per riga; la griglia mostra `getRawValue()` di ogni gruppo
119
+ e segue le modifiche del FormArray (valori, righe aggiunte o tolte da codice). Le righe si modificano in una finestra
120
+ di dialogo del kit con il form di `<ng-template wmSirioGridEditor let-group>`, aperta da "Modifica" nella colonna
121
+ azioni (fissa a destra) o con il doppio clic (`editOnDoubleClick`). Il form lavora su una **copia** della riga creata
122
+ da `rowFactory(valore)` (senza `rowFactory`: copia generica con gli stessi controlli, valori e validatori): "Annulla"
123
+ scarta tutto, "Salva" segna i campi come toccati, attende i validatori asincroni e applica i valori solo se la copia è
124
+ valida (la riga diventa dirty). `saveHandler` / `deleteHandler` (funzioni che restituiscono un valore, una Promise o
125
+ un Observable) controllano la modifica prima di applicarla, ad esempio con una chiamata al server: `false` o un errore
126
+ la bloccano e il messaggio d'errore compare nella finestra. `addable` aggiunge "Aggiungi" (nuova riga da
127
+ `rowFactory(null)`, o `addRow(valoriIniziali)`, aggiunta in fondo), `deletable` "Elimina" sulle righe (con conferma,
128
+ `confirmDelete`) ed "Elimina selezionati" con la selezione multipla; `rowEditable` / `rowDeletable` scelgono le righe.
129
+ Con il FormArray disabilitato le righe si aprono in sola lettura ("Visualizza"). Dopo `markAllAsTouched()` le righe non
130
+ valide hanno il marcatore e l'icona di errore, gli errori del FormArray compaiono sotto la griglia
131
+ (`errorMessages`; per "almeno una riga" usare `Validators.required`, perché `Validators.minLength` ignora un array
132
+ vuoto). Eventi `(rowSave)` e `(rowDelete)`; metodi `editRow`, `addRow`, `deleteRow`, `deleteSelected`, `groupOf(riga)`.
133
+ Senza `rowId` la selezione segue il FormGroup della riga. Non si usa insieme a `[dataSource]`.
134
+
135
+ ```html
136
+ <wm-sirio-data-grid [formArray]="righe" [rowFactory]="creaRiga" addable deletable (rowSave)="salvata($event)">
137
+ <wm-sirio-grid-column field="descrizione" header="Descrizione" />
138
+ <wm-sirio-grid-column field="importo" header="Importo" format="currency" />
139
+ <ng-template wmSirioGridEditor let-group let-isNew="isNew">
140
+ <div [formGroup]="group">
141
+ <wm-sirio-textbox formControlName="descrizione" label="Descrizione" />
142
+ <wm-sirio-number formControlName="importo" label="Importo" />
143
+ </div>
144
+ </ng-template>
145
+ </wm-sirio-data-grid>
146
+ ```
147
+ - **Dati lato server** (`[dataSource]`): una funzione che riceve `{ page, pageSize, offset, sort, filters }` e restituisce
148
+ `{ rows, total }` (Observable, Promise o valore). Viene richiamata a ogni cambio di pagina o ordinamento e con
149
+ `reload()`; le risposte superate vengono ignorate (un Observable precedente viene annullato).
150
+ - **Totale facoltativo**: senza `total` il totale si ricava dalle pagine, come lo scroll infinito di ag-grid. Una
151
+ pagina piena significa che ce ne sono altre: "Successiva" resta attiva, la paginazione mostra "di 30+ elementi"
152
+ ("oltre 30" per gli screen reader, testo `moreLabel`) e il conteggio dei risultati "oltre 30". Una pagina più corta
153
+ è l'ultima e fissa il totale. Cambiando ordinamento, filtri o righe per pagina si riparte da capo.
154
+ `wm-sirio-pagination` ha lo stesso comportamento con `hasMore`.
155
+ - **Errori**: oltre a `(loadError)`, la tabella mostra `loadErrorText` ("Non è stato possibile caricare i dati.") con
156
+ il pulsante "Riprova" (`retryLabel`), che richiama il data source; la paginazione resta per tornare indietro. Con
157
+ `<ng-template wmSirioGridError let-error let-retry="retry">` il contenuto è personalizzato.
158
+ - **Filtri per colonna** (`filter` sulla colonna): pulsante nell'intestazione che apre il popover del kit con i
159
+ controlli della libreria. Tipi: `text` (contiene, senza distinzione di maiuscole e accenti), `number` e `date`
160
+ (intervallo Da / A), `select` (con `filterOptions`, anche `filterMultiple`; **senza `filterOptions` la scelta è tra i
161
+ valori presenti nella colonna, con il numero di righe**, calcolati con gli altri filtri applicati), `boolean` (Sì / No). I filtri attivi
162
+ compaiono sopra la tabella come chip del kit, rimovibili uno a uno o tutti insieme; nel layout a card sono in un
163
+ pannello "Filtri". Stato two-way `[(filters)]` (per chiave di colonna, es. `{ comune: 'Roma', importo: { from: 1000 } }`),
164
+ filtro personalizzato con `filterPredicate`, ritardo dei filtri di testo con `filterDebounce` (300 ms).
165
+ Con `[dataSource]` i filtri attivi arrivano nella query (`query.filters`).
166
+ - **Operatori dei filtri**: con `filterOperators` sulla griglia (o sulla colonna: `true`, `false` o l'elenco degli
167
+ operatori ammessi) il popover ha una scelta "Condizione" sopra il valore e il filtro diventa
168
+ `{ operator, value, to? }` (`SirioGridFilterCondition`). Testo: contiene, non contiene, uguale a, diverso da, inizia
169
+ con, finisce con; numero: uguale a, diverso da, maggiore di, maggiore o uguale a, minore di, minore o uguale a,
170
+ compreso tra; data: uguale a, diverso da, prima del, dopo il, compreso tra; elenco: è uno di, non è uno di; per tutti
171
+ vuoto e non vuoto. Chip come "Importo: compreso tra 10.000 e 30.000"; etichette in `filterOperatorLabels`,
172
+ `filterConditionLabel`, `filterValueLabel`, `filterAndLabel`. Un valore semplice (es. uno stato salvato) viene letto
173
+ come condizione equivalente (testo → contiene, intervallo → compreso tra, elenco → è uno di).
174
+ - **Ordinamento**: `[(sort)]` è l'elenco dei criteri in ordine di priorità (`[{ field: 'comune', direction: 'asc' }]`).
175
+ Con `sortMode="multiple"` Maiusc+clic (o Maiusc+Invio) aggiunge una colonna ai criteri, mostrando la priorità
176
+ nell'intestazione; il clic semplice sostituisce l'ordinamento.
177
+ - **Colonne ridimensionabili** (`resizable`): maniglia sul bordo destro delle intestazioni per il mouse (trascinamento,
178
+ doppio clic per ripristinare); da tastiera Alt+frecce sull'intestazione, come ag-grid; `minWidth` / `maxWidth` e
179
+ `resizable="false"` sulla colonna; larghezze two-way `[(columnWidths)]` (px per chiave di colonna).
180
+ - **Colonne riordinabili** (`reorderable`): trascinamento delle intestazioni o Shift+frecce su un'intestazione, con
181
+ annuncio della nuova posizione; ordine two-way `[(columnOrder)]`. "Ripristina colonne" nella barra sopra la tabella.
182
+ - **Righe espandibili**: con `<ng-template wmSirioGridDetail let-row>` ogni riga ha un pulsante che apre un pannello di
183
+ dettaglio sotto di essa (`rowExpandable` per sceglierle); con `subRows` (proprietà o funzione) i dati sono un albero,
184
+ con rientro per livello. Stato two-way `[(expanded)]`, `expandAll()`, "Espandi tutto" / "Comprimi tutto".
185
+ - **Numero di riga** (`rowNumbers`): colonna "N." all'inizio, numero continuo tra le pagine nell'ordine e con i filtri
186
+ correnti (lato server dall'offset della query); le righe di gruppo non sono numerate, i figli degli alberi sì per
187
+ livello (1, 1.1, 1.2). È l'intestazione di riga (`role="rowheader"`); testi `rowNumberHeader` e `rowNumberLabel`.
188
+ - **Intestazioni raggruppate**: `group` sulla colonna con i nomi dei gruppi dal livello più alto, separati da `/`
189
+ (`group="Richiedente/Residenza"`); una riga d'intestazione per livello (`scope="colgroup"`), le colonne vicine con gli
190
+ stessi gruppi condividono la cella, un gruppo si divide se le sue colonne non sono vicine o stanno in blocchi fissi
191
+ diversi. Con `stickyHeader` le righe restano impilate.
192
+ - **Colonne flex**: `flex` sulla colonna (`flex="2"`, `flex` senza valore = 1) come in CSS / ag-grid: le colonne con
193
+ `flex` si dividono in proporzione la larghezza lasciata libera dalle altre (che tengono `width` o la larghezza del
194
+ contenuto), entro `minWidth` / `maxWidth`; si ricalcola quando cambia la larghezza della griglia. Una colonna flex
195
+ ridimensionata a mano tiene la sua larghezza fino al doppio clic sulla maniglia o a "Ripristina colonne".
196
+ - **Colonne fisse**: `fixed="left"` o `fixed="right"` sulla colonna la tiene ferma durante lo scroll orizzontale; più
197
+ colonne per lato, mostrate su quel lato della tabella (le colonne si spostano solo all'interno del proprio blocco).
198
+ Selezione, espansione e numero di riga restano fissi con le colonne di sinistra. `fixedFirstColumn` /
199
+ `fixedLastColumn` sono scorciatoie per la prima e l'ultima colonna. Attive nel contenitore responsive, non nel layout
200
+ a card; al bordo del blocco fisso compare l'indicatore di scroll del kit.
201
+ - **Classi e stili**: `rowClass` / `rowStyle` sulla griglia, `cellClass` / `cellStyle` sulla colonna (valori fissi o
202
+ funzioni: della riga e del suo indice per le righe, della riga e del valore per le celle), `headerClass` /
203
+ `headerStyle` sull'intestazione della colonna. Le classi sono come `ngClass` (testo, elenco o `{ classe: condizione }`),
204
+ gli stili come `ngStyle` (testo CSS o oggetto, anche `'width.px': 80`). Uno sfondo di `rowStyle` / `cellStyle` vale
205
+ anche sulle righe a strisce e sulle colonne fisse; la selezione copre lo sfondo della riga, non quello della cella.
206
+ Per gli sfondi è meglio usare gli stili: le classi del kit `sirio-bg-*` sulle righe non battono le strisce del kit.
207
+
208
+ ```html
209
+ <wm-sirio-data-grid [data]="pratiche" [rowClass]="classeRiga" [rowStyle]="stileRiga">
210
+ <wm-sirio-grid-column field="importo" header="Importo" format="currency" headerClass="sirio-text-primary"
211
+ [cellClass]="importoNegativo" />
212
+ </wm-sirio-data-grid>
213
+ ```
214
+
215
+ ```ts
216
+ classeRiga = (riga: Pratica) => ({ 'sirio-text-disabled': riga.stato === 'Chiusa' });
217
+ stileRiga = (riga: Pratica) => (riga.scaduta ? { 'background-color': '#f7e4ea' } : null);
218
+ importoNegativo = (_riga: Pratica, valore: unknown) => ({ 'sirio-text-danger': Number(valore) < 0 });
219
+ ```
220
+ - **Raggruppamento** (solo con `[data]`): colonne `groupable` e "Raggruppa per" sopra la tabella (`[(grouping)]`); le
221
+ righe di gruppo mostrano valore e numero di righe, le altre colonne il valore di `aggregate` (`sum`, `mean`, `min`,
222
+ `max`, `count`). Con gruppi o alberi la paginazione conta le righe di primo livello.
223
+ - **Paginazione**: `pageable`, `[(page)]`, `[(pageSize)]`, `pageSizeOptions`; aspetto di `wm-sirio-pagination` con
224
+ `paginationVariant` (`full`, `numbers` con i numeri di pagina e i puntini, oppure `compact`, una barra sottile con "Pagina 1 di 6" e i pulsanti prima / precedente / successiva / ultima), `paginationSiblings` e `paginationShowItems`.
225
+ - **Stato two-way**: `[(sort)]`, `[(page)]`, `[(pageSize)]`, `[(filters)]`, `[(grouping)]`, `[(expanded)]`,
226
+ `[(columnWidths)]`, `[(columnOrder)]`, `[(selected)]` (righe confrontate per `rowId`).
227
+ - **Salvataggio dello stato**: `getState()` restituisce lo stato scelto dall'utente come JSON (`SirioGridState`:
228
+ ordinamento, filtri, pagina e righe per pagina, ordine e larghezze delle colonne, raggruppamento, righe espanse,
229
+ `rowId` delle righe selezionate), `setState(stato)` lo ripristina (anche in parte; i filtri si applicano subito senza
230
+ tornare alla prima pagina, criteri di colonne non più presenti vengono ignorati), `resetState()` torna allo stato
231
+ iniziale; `(stateChange)` e il signal `state` seguono ogni modifica, per il salvataggio automatico.
232
+ - **Selezione**: `selection="single"` (radio) o `"multiple"` (checkbox del kit con "seleziona tutte"; `selectAll` sceglie
233
+ le righe prese: `page` quelle della pagina, default, `filtered` tutte quelle che passano i filtri su tutte le pagine,
234
+ come `selectAll: 'filtered'` di ag-grid, `all` tutte; con `[dataSource]` sempre la pagina caricata);
235
+ `selectOnRowClick` seleziona anche al clic sulla riga; con `[selectionColumn]="false"` niente colonna di checkbox:
236
+ si seleziona con il clic sulla riga (in `multiple` ogni clic aggiunge o toglie la riga) o con Spazio/Invio sulla riga
237
+ con il focus; `rowSelectable` (funzione della riga, come `isRowSelectable` di ag-grid) indica le righe selezionabili:
238
+ le altre hanno la casella disabilitata (nascosta con `hideUnselectable`), sono escluse da "seleziona tutte" e dalla
239
+ selezione con clic o tastiera; `(rowClick)` per il dettaglio. Con la selezione singola l'intestazione della colonna
240
+ di selezione è letta dagli screen reader come `selectionHeaderLabel` ("Selezione"). I campi dei filtri non si
241
+ registrano nel form che contiene la griglia.
242
+ - **Altezza**: senza impostazioni la griglia è alta quanto il contenuto (tutte le righe); `height` (come `style.height`)
243
+ la fissa, `minHeight` e `maxHeight` la limitano. Con un'altezza impostata le righe scorrono dentro la griglia con
244
+ l'intestazione sempre visibile, mentre "Raggruppa per", chip dei filtri e paginazione restano fuori dallo scroll e
245
+ contano nell'altezza. Con `stickyHeader` e senza altezza vale l'altezza del kit (450px per le righe).
246
+ - **Aspetto del kit**: `variant` (`default`, `dark`, `striped`), `size` (`xs`, `sm`, `md`, `lg`), contenitore
247
+ responsive con gli indicatori di scroll, `stickyHeader`, `fixedFirstColumn`, `fixedLastColumn`,
248
+ `cardOnMobile` (righe a card fino a 768px, con l'intestazione come etichetta di ogni cella).
249
+ - **Accessibilità**: `caption` (nascosta di default; dà anche il nome al paginatore, "Paginazione della tabella <caption>",
250
+ per distinguere più griglie nella stessa pagina), `aria-sort` e tastiera (Invio/Spazio) sulle intestazioni
251
+ ordinabili, `aria-selected`, `aria-expanded` sui pulsanti di espansione, `aria-level` per alberi e gruppi,
252
+ `aria-busy` durante il caricamento; numero di risultati, criteri di ordinamento e spostamenti di colonna annunciati.
253
+ - **Navigazione da tastiera** (`keyboardNavigation`, default `true`, come ag-grid e il pattern ARIA "grid"): la
254
+ griglia è una sola tappa del Tab (si entra sulla prima intestazione, poi sull'ultima cella visitata); le frecce si spostano tra intestazioni e celle, Home/Fine all'inizio e alla fine
255
+ della riga, Ctrl+Home/Ctrl+Fine alla prima e all'ultima cella; Tab esce dalla griglia. Una cella con pulsanti o
256
+ campi (es. le azioni, un template di cella) passa il focus ai suoi controlli, uno per tappa. La cella raggiunta viene
257
+ portata in vista fuori dalle colonne fisse e dall'intestazione fissa; Spazio/Invio su una cella seleziona la riga
258
+ quando non c'è la colonna di selezione. I campi della riga dei filtri restano tappe del Tab (usano le frecce); con
259
+ la riga dei filtri la griglia ha due tappe, intestazioni e righe: Tab va dall'intestazione ai filtri e dai filtri
260
+ alle righe, poi esce (Shift+Tab al contrario). Sull'intestazione, come
261
+ ag-grid: Invio/Spazio ordina (Shift+Invio ordinamento multiplo), Alt+frecce cambia la larghezza, Shift+frecce sposta la
262
+ colonna, Ctrl+Invio apre il filtro; Alt+frecce non arriva mai al browser (Alt+← è "Indietro" e farebbe lasciare la pagina). La tabella ha
263
+ `role="grid"` (`treegrid` con alberi e raggruppamenti, con `aria-level` sulle righe) e `aria-multiselectable` con la
264
+ selezione multipla. Con `[keyboardNavigation]="false"` è una tabella semplice: tappe del Tab solo le intestazioni
265
+ interattive e i controlli.
266
+ - **Pannelli dei filtri**: il calendario dei filtri data e l'elenco dei filtri a scelta si aprono sopra la pagina,
267
+ sotto il campo (sopra quando sotto non c'è spazio), senza essere tagliati dal contenitore scorrevole della griglia.
268
+ Vale per `wm-sirio-date` e `wm-sirio-select` dentro qualsiasi contenitore che ritaglia il contenuto.
269
+
18
270
  ## Browser supportati
19
271
 
20
272
  Gli stessi di Angular 22: Chrome ed Edge 119+, Firefox 119+, Safari 17+ (macOS e iOS),
@@ -63,3 +63,32 @@ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
63
63
  COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
64
64
  IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
65
65
  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
66
+
67
+ --------------------------------------------------------------------------------
68
+ @tanstack/angular-table 9.3.1 (with @tanstack/table-core, @tanstack/angular-store,
69
+ @tanstack/store)
70
+ https://github.com/TanStack/table
71
+ License: MIT
72
+ --------------------------------------------------------------------------------
73
+
74
+ MIT License
75
+
76
+ Copyright (c) 2016 Tanner Linsley
77
+
78
+ Permission is hereby granted, free of charge, to any person obtaining a copy
79
+ of this software and associated documentation files (the "Software"), to deal
80
+ in the Software without restriction, including without limitation the rights
81
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
82
+ copies of the Software, and to permit persons to whom the Software is
83
+ furnished to do so, subject to the following conditions:
84
+
85
+ The above copyright notice and this permission notice shall be included in all
86
+ copies or substantial portions of the Software.
87
+
88
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
89
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
90
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
91
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
92
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
93
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
94
+ SOFTWARE.