@massimo-cassandro/minimo 1.42.4 → 1.43.1
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 +2 -0
- package/design-tokens/_src/table.minimo.tokens.mjs +16 -2
- package/dev-tools/starter-kit/source_files/app/CLAUDE.md +1 -0
- package/dev-tools/starter-kit/source_files/root/CLAUDE.md +1 -0
- package/dev-tools/starter-kit/source_files/root/_gitignore +1 -0
- package/dev-tools/starter-kit/source_files/root/_reports/.hintrc +12 -0
- package/dev-tools/starter-kit/source_files/root/_reports/README.md +45 -0
- package/dev-tools/starter-kit/source_files/root/_reports/_package.json +9 -0
- package/dev-tools/starter-kit/source_files/root/package-tpl.json +1 -1
- package/dev-tools/starter-kit/starter-install.sh +32 -6
- package/package.json +11 -5
- package/src/css/table.css +12 -9
- package/src/custom-properties.css +8 -5
- package/src/index.js +1 -0
- package/src/utilities/dom-builder-helpers/table-tag.js +259 -0
- package/src/web-components/json-table/json-table.minimo.tokens.mjs +1 -1
- package/src/web-components/json-table/jt-docs.md +1 -1
- package/types/classes.d.ts +0 -1
- /package/src/utilities/dom-builder-helpers/{README.md → _README.md} +0 -0
package/README.md
CHANGED
|
@@ -12,7 +12,11 @@ export default {
|
|
|
12
12
|
$type: 'dimension',
|
|
13
13
|
$value: '3px'
|
|
14
14
|
}
|
|
15
|
-
}
|
|
15
|
+
},
|
|
16
|
+
'vertical-align': {
|
|
17
|
+
$type: 'string',
|
|
18
|
+
$value: 'middle',
|
|
19
|
+
},
|
|
16
20
|
},
|
|
17
21
|
tfoot: {
|
|
18
22
|
background: {
|
|
@@ -32,10 +36,15 @@ export default {
|
|
|
32
36
|
$type: 'fontWeight',
|
|
33
37
|
$value: '{font.weight.semibold}',
|
|
34
38
|
}
|
|
39
|
+
},
|
|
40
|
+
'vertical-align': {
|
|
41
|
+
$type: 'string',
|
|
42
|
+
$value: 'middle',
|
|
43
|
+
|
|
35
44
|
}
|
|
36
45
|
},
|
|
37
46
|
|
|
38
|
-
|
|
47
|
+
tbody: {
|
|
39
48
|
background: {
|
|
40
49
|
color: null
|
|
41
50
|
},
|
|
@@ -45,6 +54,11 @@ export default {
|
|
|
45
54
|
$value: '1px'
|
|
46
55
|
}
|
|
47
56
|
},
|
|
57
|
+
'vertical-align': {
|
|
58
|
+
$type: 'string',
|
|
59
|
+
$value: 'middle',
|
|
60
|
+
|
|
61
|
+
},
|
|
48
62
|
tr: {
|
|
49
63
|
'alt-bg-color': {
|
|
50
64
|
$type: 'color',
|
|
@@ -15,3 +15,4 @@
|
|
|
15
15
|
- nei commenti jsDoc aggiungere sempre dove possibile una sezione example che riepiloghi i vari parametri mostrando i valori di default
|
|
16
16
|
- commenti nel codice (inclusi TODO/FIX e jsDoc) e file README vanno scritti sempre in italiano; gli identificatori restano in inglese
|
|
17
17
|
- nei documenti markdown generati non andare a capo forzatamente alla fine di ogni riga: un paragrafo è una sola riga, così si usa il soft wrap dell'editor ed è più semplice fare correzioni
|
|
18
|
+
- Le tabelle nei file `.md` devono avere le celle allineate con spazi (colonne di larghezza uniforme, separatore `---` della stessa larghezza), in modo da essere leggibili anche in modalità editor.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Report Lighthouse / webhint
|
|
2
|
+
|
|
3
|
+
Cartella ignorata da git. Gli script sono in `package.json` di questa cartella;
|
|
4
|
+
`lighthouse` e `hint` sono devDependencies del progetto (root).
|
|
5
|
+
|
|
6
|
+
## Installazione
|
|
7
|
+
|
|
8
|
+
```
|
|
9
|
+
npm i -D lighthouse hint
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Step
|
|
13
|
+
|
|
14
|
+
Dalla root del progetto (o dentro `_reports`, senza `--prefix`):
|
|
15
|
+
|
|
16
|
+
1. Build di produzione: `npm run --prefix _reports "webpack PROD"`
|
|
17
|
+
2. Avvio PHP in prod (porta 8100): `npm run --prefix _reports "server PROD"`
|
|
18
|
+
(a fine test chiudere il terminale con il pulsante cestino di VS Code, per liberare la porta)
|
|
19
|
+
3. In un altro terminale:
|
|
20
|
+
- `npm run --prefix _reports "lighthouse mobile"` → `mobile.html`
|
|
21
|
+
- `npm run --prefix _reports "lighthouse desktop"` → `desktop.html`
|
|
22
|
+
- `npm run --prefix _reports webhint` → `hint-report/http-localhost-8100.html`
|
|
23
|
+
|
|
24
|
+
## Note
|
|
25
|
+
|
|
26
|
+
- Lanciare i test sempre sulla build prod, non sul dev server di webpack.
|
|
27
|
+
- webhint usa il connector `puppeteer` con il Chrome installato (`.hintrc` in questa cartella, `executablePath` di macOS; il finder automatico non lo trova), in modalità headless: render reale, quindi anche le regole sul layout sono attendibili. Gli avvisi iniziali su `typescript-config/*` sono normali (regole non applicabili).
|
|
28
|
+
- `.hintrc` va letto dalla directory corrente: lanciare webhint da `_reports` (lo script `--prefix` lo fa).
|
|
29
|
+
- Usare gli stessi dati nel database locale tra un run e l'altro: la home cambia con i gruppi disponibili e rende i punteggi non confrontabili.
|
|
30
|
+
- Lighthouse oscilla di qualche punto tra un run e l'altro: fare 3 run e prendere la mediana.
|
|
31
|
+
- Per i numeri definitivi (rete, compressione, CDN) ripetere su staging/produzione.
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
## Caratteristiche del server
|
|
35
|
+
|
|
36
|
+
Lo script prod usa il server integrato di PHP (`php -S`). Rispetto al server reale tenere presente che:
|
|
37
|
+
|
|
38
|
+
* esegue un solo processo per volta, più richieste vanno in coda
|
|
39
|
+
* non esegue compressione gzip/brotli
|
|
40
|
+
|
|
41
|
+
Note:
|
|
42
|
+
|
|
43
|
+
- `APP_ENV=prod APP_DEBUG=0` sono variabili d'ambiente lette da Symfony (non dal server): con `php -S` vengono ereditate dal processo e hanno la precedenza sui file `.env` / `.env.local`.
|
|
44
|
+
- `php -S` usa il `php.ini` della CLI, che può differire da quello di `php-cgi`.
|
|
45
|
+
- Con richieste in coda i tempi di caricamento di asset e immagini possono risultare peggiori: i numeri di performance locali sono indicativi.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"scripts": {
|
|
3
|
+
"webpack PROD": "cd .. && NODE_ENV=production webpack --config ./webpack.config.mjs --stats minimal",
|
|
4
|
+
"server PROD": "cd .. && APP_ENV=prod APP_DEBUG=0 php -S 127.0.0.1:8100 -t public public/index.php # http://localhost:8100 (server integrato php: la CLI symfony ammette un solo server per progetto)",
|
|
5
|
+
"lighthouse mobile": "npx lighthouse http://localhost:8100/ --form-factor=mobile --output=html --output-path=./mobile.html --view",
|
|
6
|
+
"lighthouse desktop": "npx lighthouse http://localhost:8100/ --preset=desktop --output=html --output-path=./desktop.html --view",
|
|
7
|
+
"webhint": "npx hint http://localhost:8100/"
|
|
8
|
+
}
|
|
9
|
+
}
|
|
@@ -23,7 +23,6 @@
|
|
|
23
23
|
"symfony server": "symfony serve --port=[[port8000]] --listen-ip=0.0.0.0 # http://192.168.1.135:[[port8000]] # -d (deamon): rimane aperto anche dopo la chiusura del terminale, terminare con `symfony server:stop`",
|
|
24
24
|
"launchChrome": "open -n -a 'Google Chrome' --args --profile-directory='Profile 3' # mbn: 1 / mg2: 3",
|
|
25
25
|
"webpack PROD": "npm run 'UPD-version' && NODE_ENV=production webpack --config ./webpack.config.mjs --stats minimal",
|
|
26
|
-
"UPD-version": "npx update-version --no-log-v0 --log-file=./changelog.md # --log-patch --pkg=alt/path/to/package.json --default-patch-log=__log_text__",
|
|
27
26
|
"email sass": "npx sass ./app/email:./templates/email/css --no-source-map --style=compressed --watch",
|
|
28
27
|
"postcss email": "postcss ./app/email/[!_]*.css --dir ./templates/email/css --no-map --verbose --config ./app/email --watch",
|
|
29
28
|
"eslint-check": "npx eslint app/",
|
|
@@ -35,6 +34,7 @@
|
|
|
35
34
|
"build tokens": "npx buildTokens --config ./app/css/tokens-config.mjs",
|
|
36
35
|
"check unresolved props": "npx checkUnresolvedProps --config ./app/css/tokens-config.mjs",
|
|
37
36
|
"find orphan css classes": "npx findOrphanCssClasses --config ./app/css/orphan-css-classes.config.mjs",
|
|
37
|
+
"UPD-version": "npx update-version --no-log-v0 --log-file=./changelog.md # --log-patch --pkg=alt/path/to/package.json --default-patch-log=__log_text__",
|
|
38
38
|
"npm-outdated": "npm outdated",
|
|
39
39
|
"upd@m": "npx upd@m",
|
|
40
40
|
"npm-upd": "npm update --save"
|
|
@@ -39,6 +39,21 @@ if [ -z "$ZSH_VERSION" ]; then
|
|
|
39
39
|
exit 1
|
|
40
40
|
fi
|
|
41
41
|
|
|
42
|
+
# Package manager da utilizzare per l'installazione dei pacchetti: 1 = pnpm
|
|
43
|
+
# (default), 2 = npm. Il valore viene usato più sotto (sezione NODE MODULES)
|
|
44
|
+
# per scegliere il comando di installazione.
|
|
45
|
+
read "PM_INPUT?Package manager da utilizzare (1 = npm, 2 = pnpm) [1]: "
|
|
46
|
+
PM_INPUT=${PM_INPUT:-1}
|
|
47
|
+
case "$PM_INPUT" in
|
|
48
|
+
1) PKG_MANAGER="npm" ;;
|
|
49
|
+
2) PKG_MANAGER="pnpm" ;;
|
|
50
|
+
*)
|
|
51
|
+
printf "${RED}Errore: inserire 1 (npm) oppure 2 (pnpm).${NC}\n" >&2
|
|
52
|
+
exit 1
|
|
53
|
+
;;
|
|
54
|
+
esac
|
|
55
|
+
echo -e "${DIM}Package manager: ${PKG_MANAGER}${NC}"
|
|
56
|
+
|
|
42
57
|
# Porta da utilizzare: l'utente inserisce un numero da 0 a 99 (default 0), che
|
|
43
58
|
# viene normalizzato a due cifre e usato come suffisso delle porte 80xx e 57xx.
|
|
44
59
|
# I valori sostituiscono i segnaposto [[port8000]] e [[port5700]] presenti in
|
|
@@ -65,9 +80,10 @@ echo -e "${DIM}Porte: ${PORT_8000} (server), ${PORT_5700} (webpack dev server)${
|
|
|
65
80
|
# La colonna <pacchetto> può contenere più pacchetti separati da spazio: in tal
|
|
66
81
|
# caso vengono proposti con un'unica domanda e, se confermati, installati tutti
|
|
67
82
|
# (uno per uno) con la stessa modalità indicata dalla colonna <dev>.
|
|
68
|
-
# La colonna <dev> vale "dev" se il pacchetto va installato
|
|
69
|
-
# (
|
|
70
|
-
# vera
|
|
83
|
+
# La colonna <dev> vale "dev" se il pacchetto va installato come
|
|
84
|
+
# devDependency (`npm i -D` / `pnpm add -D`), stringa vuota se va installato
|
|
85
|
+
# come dependency vera (`npm i -S` / `pnpm add`, es. peer dependency di minimo
|
|
86
|
+
# usata a runtime).
|
|
71
87
|
optionalPackages=(
|
|
72
88
|
"dotenv-webpack | dev | gestione variabili d'ambiente (.env) nel bundle webpack"
|
|
73
89
|
"@principalstudio/html-webpack-inject-preload | dev | injection dei tag <link rel=preload> nell'html generato"
|
|
@@ -286,7 +302,7 @@ echo -e "${GREEN}Files will be installed in: '${FRONTEND_INSTALL_PATH}'${NC}"
|
|
|
286
302
|
|
|
287
303
|
|
|
288
304
|
# package.json va creato dal template PRIMA di installare qualunque pacchetto:
|
|
289
|
-
# se non esistesse ancora, i comandi
|
|
305
|
+
# se non esistesse ancora, i comandi di installazione più sotto ne genererebbero uno
|
|
290
306
|
# "al volo" privo di scripts/metadati del template, e le dipendenze verrebbero
|
|
291
307
|
# registrate lì; alla successiva install_tree su source_files/root (più sotto)
|
|
292
308
|
# quel package.json risulterebbe diverso dal template e verrebbe spostato in
|
|
@@ -352,14 +368,24 @@ if [ "$DEBUG" = "TRUE" ]; then
|
|
|
352
368
|
devDependencies=()
|
|
353
369
|
fi
|
|
354
370
|
|
|
371
|
+
# comandi di installazione in base al package manager scelto a inizio script:
|
|
372
|
+
# pnpm add -D / pnpm add (dependency), npm i -D / npm i -S
|
|
373
|
+
if [ "$PKG_MANAGER" = "pnpm" ]; then
|
|
374
|
+
INSTALL_DEV_CMD=(pnpm add -D)
|
|
375
|
+
INSTALL_DEP_CMD=(pnpm add)
|
|
376
|
+
else
|
|
377
|
+
INSTALL_DEV_CMD=(npm i -D)
|
|
378
|
+
INSTALL_DEP_CMD=(npm i -S)
|
|
379
|
+
fi
|
|
380
|
+
|
|
355
381
|
for pkg in "${devDependencies[@]}"; do
|
|
356
382
|
echo -e "${DIM}...installing "$pkg"${NC}"
|
|
357
|
-
|
|
383
|
+
"${INSTALL_DEV_CMD[@]}" "$pkg"
|
|
358
384
|
done
|
|
359
385
|
|
|
360
386
|
for pkg in "${dependencies[@]}"; do
|
|
361
387
|
echo -e "${DIM}...installing "$pkg"${NC}"
|
|
362
|
-
|
|
388
|
+
"${INSTALL_DEP_CMD[@]}" "$pkg"
|
|
363
389
|
done
|
|
364
390
|
|
|
365
391
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@massimo-cassandro/minimo",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.43.1",
|
|
4
4
|
"description": "Light css framework & utilities",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -22,6 +22,10 @@
|
|
|
22
22
|
"publishConfig": {
|
|
23
23
|
"access": "public"
|
|
24
24
|
},
|
|
25
|
+
"workspaces": [
|
|
26
|
+
"demo",
|
|
27
|
+
"dev-tools-web-apps"
|
|
28
|
+
],
|
|
25
29
|
"bin": {
|
|
26
30
|
"buildTokens": "dev-tools/design-tokens-builder/build-tokens.mjs",
|
|
27
31
|
"checkUnresolvedProps": "dev-tools/design-tokens-builder/check-unresolved-custom-props.mjs",
|
|
@@ -48,9 +52,9 @@
|
|
|
48
52
|
"test sideEffects tree-shaking": "node ./test/sideEffects-tree-shaking/run-test.mjs",
|
|
49
53
|
"checkJS": "npx tsc --noEmit -p jsconfig.json",
|
|
50
54
|
"checkJS ./src": "npx tsc --noEmit --allowJs --checkJs --target ES2023 --module ESNext --allowSyntheticDefaultImports --moduleResolution bundler declarations.d.ts types/global.d.ts src/**/*.js",
|
|
51
|
-
"npm outdated": "
|
|
55
|
+
"npm outdated": "npm outdated --omit=peer",
|
|
52
56
|
"upd@m": "npx upd@m",
|
|
53
|
-
"npm upd": "
|
|
57
|
+
"npm upd": "npm update"
|
|
54
58
|
},
|
|
55
59
|
"license": "MIT",
|
|
56
60
|
"author": "Massimo Cassandro",
|
|
@@ -97,7 +101,7 @@
|
|
|
97
101
|
}
|
|
98
102
|
},
|
|
99
103
|
"devDependencies": {
|
|
100
|
-
"@massimo-cassandro/eslint-config": "^3.0.
|
|
104
|
+
"@massimo-cassandro/eslint-config": "^3.0.19",
|
|
101
105
|
"@types/node": "^26.2.0",
|
|
102
106
|
"jsdom": "^30.0.1",
|
|
103
107
|
"style-dictionary": "^5.5.1"
|
|
@@ -124,5 +128,7 @@
|
|
|
124
128
|
"doc": "docs",
|
|
125
129
|
"test": "test"
|
|
126
130
|
},
|
|
127
|
-
"
|
|
131
|
+
"allowScripts": {
|
|
132
|
+
"fsevents@2.3.3": true
|
|
133
|
+
}
|
|
128
134
|
}
|
package/src/css/table.css
CHANGED
|
@@ -24,6 +24,10 @@
|
|
|
24
24
|
tr:last-child {
|
|
25
25
|
border-width: var(--table-thead-border-width);
|
|
26
26
|
}
|
|
27
|
+
|
|
28
|
+
th {
|
|
29
|
+
vertical-align: var(--table-thead-vertical-align, top);
|
|
30
|
+
}
|
|
27
31
|
}
|
|
28
32
|
|
|
29
33
|
tfoot {
|
|
@@ -33,31 +37,30 @@
|
|
|
33
37
|
}
|
|
34
38
|
th, td {
|
|
35
39
|
font-weight: var(--table-tfoot-font-weight);
|
|
40
|
+
vertical-align: var(--table-tfoot-vertical-align, top);
|
|
36
41
|
}
|
|
37
42
|
}
|
|
38
43
|
|
|
39
44
|
tbody {
|
|
40
45
|
tr:nth-child(even) {
|
|
41
|
-
background-color: var(--table-
|
|
46
|
+
background-color: var(--table-tbody-tr-alt-bg-color);
|
|
42
47
|
}
|
|
43
48
|
|
|
44
49
|
@media (hover: hover) {
|
|
45
50
|
tr:hover {
|
|
46
|
-
background-color: var(--table-
|
|
51
|
+
background-color: var(--table-tbody-tr-hover-bg-color);
|
|
47
52
|
}
|
|
48
53
|
}
|
|
54
|
+
th {
|
|
55
|
+
vertical-align: var(--table-tbody-vertical-align, top);
|
|
56
|
+
}
|
|
49
57
|
}
|
|
50
58
|
|
|
51
59
|
|
|
52
60
|
th, td {
|
|
53
61
|
padding: var(--table-cell-padding-block) var(--table-cell-padding-inline);
|
|
54
62
|
line-height: var(--table-cell-line-height);
|
|
55
|
-
vertical-align: top;
|
|
56
63
|
text-align: start;
|
|
57
|
-
|
|
58
|
-
.valign-middle &, &.valign-middle {
|
|
59
|
-
vertical-align: middle;
|
|
60
|
-
}
|
|
61
64
|
}
|
|
62
65
|
|
|
63
66
|
&.table-bordered {
|
|
@@ -76,8 +79,8 @@
|
|
|
76
79
|
@media (prefers-color-scheme: dark) {
|
|
77
80
|
.table {
|
|
78
81
|
--table-border-color: var(--_stone-8);
|
|
79
|
-
--table-
|
|
80
|
-
--table-
|
|
82
|
+
--table-tbody-tr-alt-bg-color: color-mix(in srgb, var(--_stone-12) 60%, transparent);
|
|
83
|
+
--table-tbody-tr-hover-bg-color: color-mix(in srgb, var(--_blue-12) 60%, transparent);
|
|
81
84
|
}
|
|
82
85
|
}
|
|
83
86
|
*/
|
|
@@ -227,7 +227,7 @@
|
|
|
227
227
|
--jt-caption-font-size: var(--font-size-sm);
|
|
228
228
|
--jt-empty-color: var(--text-muted);
|
|
229
229
|
--jt-empty-padding-block: var(--size-sm);
|
|
230
|
-
--jt-info-color: var(--text-
|
|
230
|
+
--jt-info-color: var(--text-color);
|
|
231
231
|
--jt-info-font-size: var(--font-size-sm);
|
|
232
232
|
--jt-info-gap: var(--size-sm);
|
|
233
233
|
--jt-info-outer-padding-block-end: var(--size-xs);
|
|
@@ -240,7 +240,7 @@
|
|
|
240
240
|
--jt-pagination-current-font-weight: var(--font-weight-semibold);
|
|
241
241
|
--jt-pagination-disabled-opacity: .5;
|
|
242
242
|
--jt-pagination-font-size: var(--font-size-sm);
|
|
243
|
-
--jt-pagination-hover-background-color: var(--table-
|
|
243
|
+
--jt-pagination-hover-background-color: var(--table-tbody-tr-hover-bg-color);
|
|
244
244
|
--jt-pagination-icon-size: 1em;
|
|
245
245
|
--jt-pagination-line-height: var(--table-cell-line-height);
|
|
246
246
|
--jt-pagination-radius: var(--radius-xxs);
|
|
@@ -420,18 +420,21 @@
|
|
|
420
420
|
--status-warning-color: #fc0;
|
|
421
421
|
--status-warning-fg: #4f2900;
|
|
422
422
|
|
|
423
|
-
--table-body-border-width: 1px;
|
|
424
|
-
--table-body-tr-alt-bg-color: #efefef;
|
|
425
|
-
--table-body-tr-hover-bg-color: #cbcbcb;
|
|
426
423
|
--table-border-color: #333;
|
|
427
424
|
--table-cell-line-height: 1.3;
|
|
428
425
|
--table-cell-padding-block: .3rem;
|
|
429
426
|
--table-cell-padding-inline: .6rem;
|
|
427
|
+
--table-tbody-border-width: 1px;
|
|
428
|
+
--table-tbody-tr-alt-bg-color: #efefef;
|
|
429
|
+
--table-tbody-tr-hover-bg-color: #cbcbcb;
|
|
430
|
+
--table-tbody-vertical-align: middle;
|
|
430
431
|
--table-tfoot-background-color: var(--table-thead-background-color);
|
|
431
432
|
--table-tfoot-border-width: var(--table-thead-border-width);
|
|
432
433
|
--table-tfoot-font-weight: var(--font-weight-semibold);
|
|
434
|
+
--table-tfoot-vertical-align: middle;
|
|
433
435
|
--table-thead-background-color: #ddd;
|
|
434
436
|
--table-thead-border-width: 3px;
|
|
437
|
+
--table-thead-vertical-align: middle;
|
|
435
438
|
|
|
436
439
|
--text-color: #000;
|
|
437
440
|
--text-dim: var(--text-muted);
|
package/src/index.js
CHANGED
|
@@ -23,6 +23,7 @@ export { ValidationError } from './utilities/validation-error-class.js';
|
|
|
23
23
|
// domBuilder helpers
|
|
24
24
|
export { buildPictureTag } from './utilities/dom-builder-helpers/picture-tag.js';
|
|
25
25
|
export { buildInput, buildCheckbox, buildTextarea, buildFakeField, buildSelect, buildButton } from './utilities/dom-builder-helpers/form-tags.js';
|
|
26
|
+
export { buildTableTag } from './utilities/dom-builder-helpers/table-tag.js';
|
|
26
27
|
|
|
27
28
|
// components
|
|
28
29
|
export { dismissAlerts } from './components/dismiss-alerts.js';
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
* @typedef {string | number | Node | Function | DomBuilderItem | DomBuilderItem[] | null} TableCellContent
|
|
4
|
+
* Contenuto di una cella: testo, stringa html, `Node`, funzione che restituisce una stringa o un `Node`,
|
|
5
|
+
* singolo oggetto domBuilder o array di oggetti domBuilder.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @typedef {Object} TableCell
|
|
10
|
+
* @property {string | string[] | null} [class=null] - Classname della cella (default: null)
|
|
11
|
+
* @property {TableCellContent} [content=null] - Contenuto della cella: testo, html, `Node`, funzione, oggetto o array domBuilder (default: null)
|
|
12
|
+
* @property {boolean} [heading=false] - La cella è un th? (NB: parametro ignorato nel thead, dove è sempre true) (default: false)
|
|
13
|
+
* @property {Record<string, any>} [attrs] - Attributi opzionali della cella (default: null)
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @typedef {string | number | Node | Function | DomBuilderItem[] | TableCell | null} TableCellInput
|
|
18
|
+
* Cella in forma abbreviata o estesa: stringa, numero, `Node`, funzione o array domBuilder sono interpretati come
|
|
19
|
+
* `content`; un oggetto semplice è un `TableCell` esteso. Per usare un singolo oggetto domBuilder come contenuto
|
|
20
|
+
* indicarlo in forma estesa: `{ content: { tag: ... } }`.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @typedef {Object} TableRow
|
|
25
|
+
* @property {string | string[] | null} [class=null] - Classname del tr (default: null)
|
|
26
|
+
* @property {Record<string, any>} [attrs] - Attributi opzionali del tr (default: null)
|
|
27
|
+
* @property {TableCellInput[]} cells - Celle della riga.
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @typedef {TableCellInput[] | TableRow} TableRowInput
|
|
32
|
+
* Riga in forma abbreviata (array di celle) o estesa (oggetto `TableRow`).
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @typedef {Object} TableSection
|
|
37
|
+
* @property {string | string[] | null} [class=null] - Classname della sezione (thead, tbody o tfoot) (default: null)
|
|
38
|
+
* @property {Record<string, any>} [attrs] - Attributi opzionali della sezione (default: null)
|
|
39
|
+
* @property {TableRowInput[]} [rows] - Righe della sezione.
|
|
40
|
+
* @property {TableCellInput[]} [cells] - Scorciatoia per una sezione con una sola riga (ignorata se è presente `rows`).
|
|
41
|
+
*/
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @typedef {TableCellInput[] | TableRowInput[] | TableSection} TableSectionInput
|
|
45
|
+
* Sezione in forma abbreviata o estesa:
|
|
46
|
+
* - array piatto di celle → una sola riga
|
|
47
|
+
* - array di righe (ogni riga è un array di celle o un oggetto `{ cells }`)
|
|
48
|
+
* - oggetto `TableSection` con `rows` oppure `cells`
|
|
49
|
+
*
|
|
50
|
+
* NB: un array è interpretato come array di righe se il primo elemento è a sua volta un array
|
|
51
|
+
* o un oggetto con la proprietà `cells`. Per una singola riga il cui primo contenuto è un array domBuilder
|
|
52
|
+
* usare la forma estesa `{ content: [...] }`.
|
|
53
|
+
*/
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Normalizza il contenuto di una cella: un singolo oggetto domBuilder viene racchiuso in un array,
|
|
58
|
+
* dato che `domBuilder` accetta come `content` solo stringhe, numeri, `Node`, funzioni e array.
|
|
59
|
+
*
|
|
60
|
+
* @param {TableCellContent} [content]
|
|
61
|
+
* @returns {string | number | Node | Function | DomBuilderItem[] | null}
|
|
62
|
+
*/
|
|
63
|
+
function normalizeCellContent(content = null) {
|
|
64
|
+
if (content != null && typeof content === 'object' && !Array.isArray(content) && !(content instanceof Node)) {
|
|
65
|
+
return [content];
|
|
66
|
+
}
|
|
67
|
+
return content ?? null;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* @param {unknown} value
|
|
73
|
+
* @returns {boolean} `true` per un oggetto semplice (non `null`, non array, non `Node`).
|
|
74
|
+
*/
|
|
75
|
+
function isPlainObject(value) {
|
|
76
|
+
return value != null && typeof value === 'object' && !Array.isArray(value) && !(value instanceof Node);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Porta una cella in forma estesa.
|
|
82
|
+
*
|
|
83
|
+
* @param {TableCellInput} cell
|
|
84
|
+
* @returns {TableCell}
|
|
85
|
+
*/
|
|
86
|
+
function normalizeCell(cell) {
|
|
87
|
+
return isPlainObject(cell)
|
|
88
|
+
? /** @type {TableCell} */ (cell)
|
|
89
|
+
: { content: /** @type {TableCellContent} */ (cell) };
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Porta una riga in forma estesa.
|
|
95
|
+
*
|
|
96
|
+
* @param {TableRowInput} row
|
|
97
|
+
* @returns {TableRow}
|
|
98
|
+
*/
|
|
99
|
+
function normalizeRow(row) {
|
|
100
|
+
return Array.isArray(row)
|
|
101
|
+
? { cells: row }
|
|
102
|
+
: row;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Porta una sezione in forma estesa (`{ class, attrs, rows: [{ cells }] }`).
|
|
108
|
+
*
|
|
109
|
+
* @param {TableSectionInput} section
|
|
110
|
+
* @returns {{ class?: string | string[] | null, attrs?: Record<string, any>, rows: TableRow[] }}
|
|
111
|
+
*/
|
|
112
|
+
function normalizeSection(section) {
|
|
113
|
+
|
|
114
|
+
if (Array.isArray(section)) {
|
|
115
|
+
const first = section[0];
|
|
116
|
+
const isRowsArray = Array.isArray(first) || (isPlainObject(first) && 'cells' in /** @type {object} */ (first));
|
|
117
|
+
|
|
118
|
+
return {
|
|
119
|
+
rows: isRowsArray
|
|
120
|
+
? /** @type {TableRowInput[]} */ (section).map(normalizeRow)
|
|
121
|
+
: [{ cells: /** @type {TableCellInput[]} */ (section) }]
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const { rows, cells, ...rest } = section;
|
|
126
|
+
|
|
127
|
+
return {
|
|
128
|
+
...rest,
|
|
129
|
+
rows: (rows ?? (cells ? [{ cells }] : [])).map(normalizeRow)
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Costruisce l'item domBuilder di una sezione della tabella (thead, tbody o tfoot).
|
|
136
|
+
*
|
|
137
|
+
* @param {'thead' | 'tbody' | 'tfoot'} tag
|
|
138
|
+
* @param {TableSectionInput | null} sectionInput
|
|
139
|
+
* @returns {DomBuilderItem | null} `null` se la sezione non è definita.
|
|
140
|
+
*/
|
|
141
|
+
function buildSection(tag, sectionInput) {
|
|
142
|
+
|
|
143
|
+
if (sectionInput == null) {
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const section = normalizeSection(sectionInput);
|
|
148
|
+
const isHead = tag === 'thead';
|
|
149
|
+
|
|
150
|
+
return {
|
|
151
|
+
tag,
|
|
152
|
+
class: section.class ?? undefined,
|
|
153
|
+
attrs: section.attrs,
|
|
154
|
+
children: section.rows.map(row => ({
|
|
155
|
+
tag: 'tr',
|
|
156
|
+
class: row.class ?? undefined,
|
|
157
|
+
attrs: row.attrs,
|
|
158
|
+
children: (row.cells ?? []).map(cellInput => {
|
|
159
|
+
|
|
160
|
+
const cell = normalizeCell(cellInput);
|
|
161
|
+
const isTh = isHead || cell.heading === true;
|
|
162
|
+
|
|
163
|
+
return {
|
|
164
|
+
tag: isTh ? 'th' : 'td',
|
|
165
|
+
class: cell.class ?? undefined,
|
|
166
|
+
attrs: {
|
|
167
|
+
// scope: sempre `col` nel thead, `row` per i th di tbody/tfoot (sovrascrivibile da `attrs`)
|
|
168
|
+
...(isTh && !isHead ? { scope: 'row' } : {}),
|
|
169
|
+
...(cell.attrs ?? {}),
|
|
170
|
+
...(isHead ? { scope: 'col' } : {})
|
|
171
|
+
},
|
|
172
|
+
content: normalizeCellContent(cell.content)
|
|
173
|
+
};
|
|
174
|
+
})
|
|
175
|
+
}))
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Table builder
|
|
182
|
+
* Restituisce un oggetto domBuilder per una tabella.
|
|
183
|
+
*
|
|
184
|
+
* Ogni sezione (`thead`, `tbody`, `tfoot`) accetta sia una forma abbreviata sia una estesa:
|
|
185
|
+
* - cella: stringa, numero, `Node`, funzione o array domBuilder (= `content`), oppure oggetto `{ content, class, attrs, heading }`
|
|
186
|
+
* - riga: array di celle, oppure oggetto `{ cells, class, attrs }`
|
|
187
|
+
* - sezione: array piatto di celle (una sola riga), array di righe, oppure oggetto `{ rows | cells, class, attrs }`
|
|
188
|
+
*
|
|
189
|
+
* @param {Object} args
|
|
190
|
+
* @param {string | string[]} [args.classname='table'] - Classe del tag table (default: 'table')
|
|
191
|
+
* @param {Record<string, any>} [args.attrs] - Oggetto opzionale di attributi del tag table (default: null)
|
|
192
|
+
* @param {TableSectionInput | null} [args.thead=null] - Oggetto opzionale per il tag thead (default: null)
|
|
193
|
+
* @param {TableSectionInput | null} [args.tbody=null] - Oggetto opzionale per il tag tbody (default: null)
|
|
194
|
+
* @param {TableSectionInput | null} [args.tfoot=null] - Oggetto opzionale per il tag tfoot (default: null)
|
|
195
|
+
*
|
|
196
|
+
* @example
|
|
197
|
+
* buildTableTag({
|
|
198
|
+
* classname: 'table', // default: 'table'
|
|
199
|
+
* attrs: { id: 'my-table' }, // default: null
|
|
200
|
+
*
|
|
201
|
+
* // array piatto di celle: una sola riga (caso più comune)
|
|
202
|
+
* thead: ['Nome', 'Email', { content: 'Importo', class: 'text-end' }],
|
|
203
|
+
*
|
|
204
|
+
* // array di righe; ogni riga è un array di celle o un oggetto { cells }
|
|
205
|
+
* tbody: [
|
|
206
|
+
* [
|
|
207
|
+
* { content: 'Mario', heading: true }, // th scope="row"
|
|
208
|
+
* 'mario@x.it', // testo
|
|
209
|
+
* { content: '<strong>10</strong>', class: 'text-end' }, // html
|
|
210
|
+
* { content: { tag: 'a', attrs: { href: '#' }, content: 'dettagli' } } // singolo oggetto domBuilder
|
|
211
|
+
* ],
|
|
212
|
+
* {
|
|
213
|
+
* class: 'is-selected',
|
|
214
|
+
* attrs: { 'data-id': 2 },
|
|
215
|
+
* cells: [
|
|
216
|
+
* 'Anna',
|
|
217
|
+
* 'anna@x.it',
|
|
218
|
+
* '12',
|
|
219
|
+
* [{ tag: 'em', content: 'a' }, { tag: 'em', content: 'b' }] // array domBuilder
|
|
220
|
+
* ]
|
|
221
|
+
* }
|
|
222
|
+
* ],
|
|
223
|
+
*
|
|
224
|
+
* // forma estesa della sezione: { class, attrs, rows | cells }
|
|
225
|
+
* tfoot: { class: 'table-light', cells: ['Totale', '', '', { content: '22', class: 'text-end' }] }
|
|
226
|
+
* // oppure: tfoot: null (default)
|
|
227
|
+
* });
|
|
228
|
+
*
|
|
229
|
+
* @example
|
|
230
|
+
* // thead con più righe (es. colspan nella prima)
|
|
231
|
+
* buildTableTag({
|
|
232
|
+
* thead: [
|
|
233
|
+
* [{ content: 'Contatti', attrs: { colspan: 2 } }, 'Importo'],
|
|
234
|
+
* ['Nome', 'Email', 'Importo']
|
|
235
|
+
* ]
|
|
236
|
+
* });
|
|
237
|
+
*
|
|
238
|
+
* @returns {DomBuilderItem} L'item domBuilder del tag `table`.
|
|
239
|
+
*/
|
|
240
|
+
export function buildTableTag({
|
|
241
|
+
classname = 'table',
|
|
242
|
+
attrs,
|
|
243
|
+
thead = null,
|
|
244
|
+
tbody = null,
|
|
245
|
+
tfoot = null
|
|
246
|
+
} = {}) {
|
|
247
|
+
|
|
248
|
+
return {
|
|
249
|
+
tag: 'table',
|
|
250
|
+
class: classname,
|
|
251
|
+
attrs: attrs,
|
|
252
|
+
children: [
|
|
253
|
+
buildSection('thead', thead),
|
|
254
|
+
buildSection('tbody', tbody),
|
|
255
|
+
buildSection('tfoot', tfoot)
|
|
256
|
+
].filter(/** @returns {item is DomBuilderItem} */ item => item != null)
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
}
|
|
@@ -506,7 +506,7 @@ Definite in `json-table.minimo.tokens.mjs` (namespace `--jt-*`):
|
|
|
506
506
|
| `--jt-pagination-icon-size` | `1em` |
|
|
507
507
|
| `--jt-pagination-current-background-color` | `{table.thead.background.color}` |
|
|
508
508
|
| `--jt-pagination-current-font-weight` | `{font.weight.semibold}` |
|
|
509
|
-
| `--jt-pagination-hover-background-color` | `{table.
|
|
509
|
+
| `--jt-pagination-hover-background-color` | `{table.tbody.tr.hover-bg-color}` |
|
|
510
510
|
| `--jt-pagination-disabled-opacity` | `.5` |
|
|
511
511
|
| `--jt-bool-icon-size` | `1.1em` |
|
|
512
512
|
| `--jt-bool-true-color` | `{status.success.color}` |
|
package/types/classes.d.ts
CHANGED
|
File without changes
|