@massimo-cassandro/minimo 0.11.7 → 0.11.9

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@massimo-cassandro/minimo",
3
- "version": "0.11.7",
3
+ "version": "0.11.9",
4
4
  "description": "Light css framework & utilities",
5
5
  "type": "module",
6
6
  "homepage": "https://github.com/massimo-cassandro/minimo#readme",
@@ -25,21 +25,29 @@ import caretRightIcon from '../../icons/caret-right.svg?inline';
25
25
  * @property {string} [_renderTpl] Template HTML per il contenuto della cella.
26
26
  * I segnaposto `[[key]]` vengono sostituiti con i
27
27
  * valori corrispondenti dell'oggetto riga.
28
- * @property {string} [_sortValue] Percorso del campo da usare per l'ordinamento al posto
29
- * del contenuto visualizzato (es. 'owner.cognome').
30
- * Supporta valori annidati con la notazione punto.
31
- * Implementato tramite `data-order` sull'attributo della cella.
32
- * @property {string} [_searchValue] Percorso del campo da usare per la ricerca al posto
33
- * del contenuto visualizzato (es. 'owner.cognome owner.nome').
34
- * Supporta valori annidati con la notazione punto.
35
- * Implementato tramite una funzione `search` personalizzata
36
- * sulla colonna (API simple-datatables).
37
- * @property {'id'|'email'|'boolean'|'sf_datetime'} [_renderMode]
28
+ * @property {string|Function} [_sortValue] Percorso del campo da usare per l'ORDINAMENTO al posto
29
+ * del contenuto visualizzato, oppure una funzione
30
+ * `(row) => string|number` per casi complessi
31
+ * (es. booleani, valori calcolati).
32
+ * Stringa: percorso con notazione punto (es. 'owner.cognome').
33
+ * Funzione: riceve l'oggetto riga originale.
34
+ * @property {string|Function} [_searchValue] Percorso/i del campo da usare per la RICERCA al posto
35
+ * del contenuto visualizzato, oppure una funzione
36
+ * `(row) => string` per casi complessi (es. booleani).
37
+ * Stringa: uno o più percorsi separati da spazio.
38
+ * Funzione: riceve l'oggetto riga originale.
39
+ * @property {string} [_renderNullAs] Stringa da mostrare al posto di valori null/undefined.
40
+ * Default: `'—'` (trattino em).
41
+ * Applicato al valore della cella e ai segnaposto
42
+ * di `_renderTpl` che si risolvono a null.
43
+ * @property {'id'|'email'|'sf_datetime'} [_renderMode]
38
44
  * Modalità di visualizzazione predefinita:
39
45
  * - `id` – colonna numerica, non ricercabile, allineata a destra
40
46
  * - `email` – inserisce andate a capo prima e dopo la `@`
41
- * - `boolean` – icona segno di spunta / croce con colore semantico
42
47
  * - `sf_datetime` – data e ora da oggetto Symfony (con pre-elaborazione in `_load`)
48
+ * Per i booleani usare `type: 'boolean'` (proprietà nativa
49
+ * simple-datatables): parseCols aggiunge automaticamente
50
+ * l'icona spunta/croce con colore semantico.
43
51
  *
44
52
  * @param {string} json URL da cui recuperare i dati (struttura attesa: `{ data: [...] }`).
45
53
  * Ignorato se `data` è presente.
@@ -56,8 +64,13 @@ import caretRightIcon from '../../icons/caret-right.svg?inline';
56
64
  * direttamente a simple-datatables (es. `sortable`, `searchable`).
57
65
  * Default: `[]`
58
66
  *
59
- * @param {number} perPage Numero di righe per pagina.
60
- * Default: `25`
67
+ * @param {number} perPage Numero di righe per pagina.
68
+ * Default: `25`
69
+ *
70
+ * @param {string} renderNullAs Stringa globale da mostrare al posto di valori null/undefined
71
+ * in tutte le colonne. Può essere sovrascritto per singola
72
+ * colonna con `_renderNullAs`.
73
+ * Default: `'—'`
61
74
  */
62
75
 
63
76
 
@@ -305,9 +318,10 @@ class SimpleDatatableAdapter extends HTMLElement {
305
318
 
306
319
  this.innerHTML = '<div class="spinner"><span class="visually-hidden">Caricamento dati...</span></div>';
307
320
 
308
- const inlineData = this._getParam('data');
309
- const jsonUrl = this._getParam('json');
310
- const cols = this._getParam('cols', []);
321
+ const inlineData = this._getParam('data');
322
+ const jsonUrl = this._getParam('json');
323
+ const cols = this._getParam('cols', []);
324
+ const globalNullAs = this._getParam('renderNullAs', '&mdash;');
311
325
 
312
326
  if (inlineData == null && !jsonUrl) {
313
327
  if (this._initCalledProgrammatically) {
@@ -341,10 +355,18 @@ class SimpleDatatableAdapter extends HTMLElement {
341
355
  cells: cols.map((col_item, col_idx) => {
342
356
  let value = getNestedValue(row, col_item._field);
343
357
 
344
- // _sortValue: valore alternativo per l'ordinamento
345
- // simple-datatables lo legge da cell.attributes['data-order']
358
+ // _renderNullAs: stringa da mostrare quando il valore è null/undefined.
359
+ // Precedenza: _renderNullAs di colonna > renderNullAs globale > '&mdash;'
360
+ const nullAs = col_item._renderNullAs !== undefined
361
+ ? col_item._renderNullAs
362
+ : globalNullAs;
363
+
364
+ // _sortValue: valore alternativo per l'ordinamento.
365
+ // Accetta un percorso stringa o una funzione (row) => string|number.
346
366
  const sortValue = col_item._sortValue
347
- ? (getNestedValue(row, col_item._sortValue) ?? '')
367
+ ? typeof col_item._sortValue === 'function'
368
+ ? (col_item._sortValue(row) ?? '')
369
+ : (getNestedValue(row, col_item._sortValue) ?? '')
348
370
  : null;
349
371
 
350
372
  if (col_item._renderTpl) {
@@ -365,7 +387,7 @@ class SimpleDatatableAdapter extends HTMLElement {
365
387
  console.error(`[s-datatable] Chiave "${key}" non trovata nella struttura dati (colonna ${col_idx})`);
366
388
  }
367
389
 
368
- return resolved ?? '';
390
+ return resolved ?? nullAs;
369
391
  }
370
392
  );
371
393
  } else if (col_item._renderMode === 'sf_datetime' && value != null) {
@@ -373,31 +395,36 @@ class SimpleDatatableAdapter extends HTMLElement {
373
395
  (value.timezone === 'UTC' ? 'Z' : '');
374
396
  }
375
397
 
398
+ // Applica _renderNullAs al valore della cella se null/undefined
399
+ // e la cella non ha già un template che gestisce la visualizzazione.
400
+ if (value == null && !col_item._renderTpl) {
401
+ value = nullAs;
402
+ }
403
+
376
404
  // _searchValue: valore alternativo per la ricerca
377
405
  // Viene scritto come testo nascosto nella cella così la funzione
378
406
  // search personalizzata della colonna può leggerlo direttamente
379
407
  // dal contenuto, senza dipendere da attributi non supportati.
380
408
  const searchValue = col_item._searchValue
381
- ? col_item._searchValue.split(' ')
382
- .map(path => getNestedValue(row, path.trim()) ?? '')
383
- .filter(Boolean)
384
- .join(' ')
409
+ ? typeof col_item._searchValue === 'function'
410
+ ? (col_item._searchValue(row) ?? '')
411
+ : col_item._searchValue.split(' ')
412
+ .map(path => getNestedValue(row, path.trim()) ?? '')
413
+ .filter(Boolean)
414
+ .join(' ')
385
415
  : null;
386
416
 
387
-
388
- console.log('col:', col_item._heading, '| value:', value, '| sortValue:', sortValue, '| searchValue:', searchValue);
389
-
390
-
391
- // Se sono definiti _sortValue o _searchValue, restituisce un
392
- // oggetto cella strutturato; altrimenti il valore grezzo.
393
417
  // Se sono definiti _sortValue o _searchValue, restituisce un
394
- // oggetto cella strutturato con attributi data-order / data-search
395
- // che simple-datatables può leggere in modo affidabile.
418
+ // oggetto cellType secondo le API di simple-datatables:
419
+ // { data, order?, attributes? }
420
+ // - `data` → contenuto visualizzato (obbligatorio)
421
+ // - `order` → valore alternativo per l'ordinamento (campo nativo)
422
+ // - `attributes['data-search']` → stringa su cui opera searchMethod
396
423
  if (sortValue !== null || searchValue !== null) {
397
- const attrs = {};
398
- if (sortValue !== null) attrs['data-order'] = sortValue;
399
- if (searchValue !== null) attrs['data-search'] = searchValue;
400
- return { text: value ?? '', attributes: attrs };
424
+ const cellObj = { data: value ?? '' };
425
+ if (sortValue !== null) cellObj.order = sortValue;
426
+ if (searchValue !== null) cellObj.attributes = { 'data-search': searchValue };
427
+ return cellObj;
401
428
  }
402
429
 
403
430
  return value;