@massimo-cassandro/minimo 1.41.4 → 1.41.5
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 +12 -12
- package/charts/src/node-helpers/create-svg-canvas-node.mjs +2 -2
- package/charts/src/node-helpers/svg-text-to-path.js +9 -9
- package/charts/src/rating-display/index.js +1 -1
- package/charts/src/rating-display/ratindDisplayAnimation.js +3 -3
- package/design-tokens/README.md +2 -2
- package/design-tokens/_src/_readme.md +26 -26
- package/dev-tools/README.md +16 -16
- package/dev-tools/create-favicons/README.md +31 -31
- package/dev-tools/create-favicons/src/create-ico.mjs +2 -2
- package/dev-tools/create-favicons/src/default-params.mjs +1 -1
- package/dev-tools/create-favicons/src/init.mjs +1 -1
- package/dev-tools/design-tokens-builder/README.md +102 -102
- package/dev-tools/design-tokens-builder/build-tokens-src/build-source-modes.mjs +85 -73
- package/dev-tools/design-tokens-builder/build-tokens-src/config.mjs +109 -85
- package/dev-tools/design-tokens-builder/build-tokens-src/formats/css.mjs +113 -90
- package/dev-tools/design-tokens-builder/build-tokens-src/formats/json.mjs +107 -95
- package/dev-tools/design-tokens-builder/build-tokens-src/legacy-tokens-parser.mjs +71 -64
- package/dev-tools/design-tokens-builder/build-tokens-src/light-dark.mjs +75 -65
- package/dev-tools/design-tokens-builder/build-tokens-src/merge-css.mjs +113 -102
- package/dev-tools/design-tokens-builder/build-tokens-src/platforms.mjs +36 -30
- package/dev-tools/design-tokens-builder/build-tokens-src/resolve-source-paths.mjs +15 -13
- package/dev-tools/design-tokens-builder/build-tokens-src/source-prefixes.mjs +44 -42
- package/dev-tools/design-tokens-builder/build-tokens-src/source-transforms.mjs +89 -83
- package/dev-tools/design-tokens-builder/build-tokens-src/token-rename-parser.mjs +99 -86
- package/dev-tools/design-tokens-builder/build-tokens-src/transforms.mjs +64 -48
- package/dev-tools/design-tokens-builder/build-tokens.mjs +80 -68
- package/dev-tools/design-tokens-builder/check-unresolved-custom-props.mjs +103 -77
- package/dev-tools/design-tokens-builder/tokens-config-sample.mjs +275 -238
- package/dev-tools/find-orphan-css-classes/find-orphan-css-classes.mjs +2 -2
- package/dev-tools/starter-kit/source_files/app/CLAUDE.md +4 -2
- package/dev-tools/starter-kit/source_files/app/{css/index.css → index.css} +2 -2
- package/dev-tools/starter-kit/source_files/app/index.js +1 -1
- package/dev-tools/starter-kit/source_files/root/_sf/controller/ImgViewerController.php +3 -3
- package/dev-tools/starter-kit/source_files/root/_sf/controller/ViewerController.php +2 -2
- package/dev-tools/starter-kit/source_files/root/stylelint.config.mjs +1 -1
- package/dev-tools/starter-kit/source_files/root/webpack-config-modules/css-rules.mjs +1 -1
- package/dev-tools/stylelint-config/README.md +7 -7
- package/dev-tools/svg-icons-tools/README.md +32 -32
- package/dev-tools/svg-icons-tools/src/config-manager.mjs +1 -1
- package/dev-tools/svg-icons-tools/src/default-config.mjs +118 -118
- package/dev-tools/svg-icons-tools/src/jsx-icon-file-builder.mjs +24 -24
- package/dev-tools/svg-icons-tools/src/parse-svg-filename.mjs +3 -3
- package/dev-tools/svg-icons-tools/src/parse-svg-files.mjs +1 -1
- package/dev-tools/svg-icons-tools/src/parse-svg-markup.mjs +4 -4
- package/dev-tools/svg-icons-tools/src/svg-to-jsx.mjs +2 -2
- package/dev-tools/svg-icons-tools/src/svg-to-optimized.mjs +2 -2
- package/dev-tools/svg-icons-tools/src/svg-to-symbols.mjs +2 -2
- package/dev-tools/upd@m/README.md +1 -1
- package/dev-tools/upd@m/index.mjs +1 -1
- package/dev-tools/update-version/README.md +9 -9
- package/package.json +1 -1
- package/snippets/unsplash-browser-app/README.md +1 -1
- package/snippets/unsplash-browser-app/unsplash-utilities.js +9 -9
- package/src/components/autocomplete/README.md +3 -3
- package/src/components/autocomplete/autocomplete-engine.js +75 -63
- package/src/components/autocomplete/check-autocomplete.js +3 -3
- package/src/components/dismiss-alerts.js +3 -3
- package/src/components/form-reset-submit.js +6 -6
- package/src/components/inner-nav/inner-nav.js +2 -2
- package/src/components/modal-alert/modal-alert.js +67 -65
- package/src/components/modal-alert/modal-alert.minimo.tokens.mjs +1 -1
- package/src/components/modal-popup/modal-popup.js +56 -56
- package/src/components/overlay/overlay.js +3 -3
- package/src/components/sf-macro/readme.md +1 -1
- package/src/components/sf-macro/sf-macro.js +27 -23
- package/src/components/slide-up-down-toggle/slide-up-down-toggle.js +83 -79
- package/src/components/slide-up-down-toggle/slide-up-down-toggle.module.css +44 -44
- package/src/components/snackbar/snackbar.js +19 -19
- package/src/components/spinner/spinner.js +3 -3
- package/src/components/unsplash-page/README.md +8 -8
- package/src/components/unsplash-page/fetch-unsplash-data.js +3 -3
- package/src/components/unsplash-page/unsplash-page.js +33 -33
- package/src/components/unsplash-page/unsplash-page.module.css +1 -1
- package/src/css/alerts.css +2 -2
- package/src/css/forms/forms.css +4 -4
- package/src/css/forms/validation.css +1 -1
- package/src/css/margin-padding-media.css +4 -4
- package/src/css/margin-padding.css +4 -4
- package/src/css/reset.css +11 -11
- package/src/icons/read-me.md +1 -1
- package/src/minimo.css +3 -3
- package/src/utilities/better-text-with-places.js +22 -22
- package/src/utilities/better-text.js +42 -35
- package/src/utilities/classnames.js +8 -8
- package/src/utilities/cookies.js +6 -6
- package/src/utilities/create-id.js +3 -3
- package/src/utilities/disable-btns-on-submit.js +2 -2
- package/src/utilities/dom-builder/dom-builder.js +89 -86
- package/src/utilities/dom-builder/domBuilderBasicSetup.js +9 -9
- package/src/utilities/dom-builder/parseDomString.js +23 -23
- package/src/utilities/dom-builder-helpers/README.md +2 -2
- package/src/utilities/dom-builder-helpers/form-tags.js +100 -100
- package/src/utilities/dom-builder-helpers/picture-tag.js +39 -39
- package/src/utilities/enable-submit-btns.js +1 -1
- package/src/utilities/escape-html.js +2 -2
- package/src/utilities/generate-pwd.js +4 -4
- package/src/utilities/linked-dates.js +13 -13
- package/src/utilities/parse-file-size.js +6 -6
- package/src/utilities/random-id.js +3 -3
- package/src/utilities/relative-date.js +40 -40
- package/src/utilities/sentence-case.js +1 -1
- package/src/utilities/strip-tags.js +1 -1
- package/src/utilities/title-case.js +1 -1
- package/src/utilities/truncate-string.js +5 -5
- package/src/utilities/validation-error-class.js +12 -12
- package/src/web-components/json-table/json-table-component.js +123 -121
- package/src/web-components/json-table/json-table-component.module.css +6 -6
- package/src/web-components/json-table/json-table.minimo.tokens.mjs +6 -6
- package/src/web-components/json-table/readme.md +72 -108
- package/src/web-components/json-table/src/cell-content.js +25 -25
- package/src/web-components/json-table/src/content-utils.js +21 -21
- package/src/web-components/json-table/src/data-types.js +32 -32
- package/src/web-components/json-table/src/defaults.js +230 -191
- package/src/web-components/json-table/src/get-data.js +55 -38
- package/src/web-components/json-table/src/icons.js +17 -17
- package/src/web-components/json-table/src/info-section.js +18 -18
- package/src/web-components/json-table/src/main-builder.js +45 -45
- package/src/web-components/json-table/src/pagination.js +32 -32
- package/src/web-components/json-table/src/parse-cols.js +18 -18
- package/src/web-components/json-table/src/parse-rows.js +17 -17
- package/src/web-components/json-table/src/resolve-params.js +53 -41
- package/src/web-components/json-table/src/search.js +13 -13
- package/src/web-components/json-table/src/sorting.js +20 -20
- package/src/web-components/json-table/src/table-body.js +13 -13
- package/src/web-components/json-table/src/table-builder.js +34 -34
- package/src/web-components/json-table/src/table-tfoot.js +8 -8
- package/src/web-components/json-table/src/table-thead.js +21 -21
- package/src/web-components/json-table/src/update-info.js +11 -11
- package/types/classes.d.ts +2 -2
- package/types/global.d.ts +18 -12
|
@@ -6,27 +6,27 @@ import * as styles from './slide-up-down-toggle.module.css';
|
|
|
6
6
|
/**
|
|
7
7
|
* @module slide-up-down-toggle
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
9
|
+
* Animazione di chiusura/apertura gestita via CSS — il JS si limita a commutare un attributo data
|
|
10
|
+
* e a gestire un leggero elemento wrapper. Nessuna misurazione in pixel.
|
|
11
11
|
*
|
|
12
|
-
* ───
|
|
12
|
+
* ─── Come funziona ────────────────────────────────────────────────────────────
|
|
13
13
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* `@starting-style` (
|
|
17
|
-
*
|
|
14
|
+
* Il CSS module usa `interpolate-size: allow-keywords` (transizioni verso height: auto),
|
|
15
|
+
* `allow-discrete` (transizione di display: none) e
|
|
16
|
+
* `@starting-style` (animazione di ingresso da display: none). Vedi il file CSS
|
|
17
|
+
* per una spiegazione completa di ciascuna funzionalità.
|
|
18
18
|
*
|
|
19
19
|
* ─── wrap: true (default) ─────────────────────────────────────────────────────
|
|
20
20
|
*
|
|
21
|
-
* JS
|
|
22
|
-
* wrapper.
|
|
23
|
-
* display
|
|
21
|
+
* Il JS racchiude il target in un <div class="slide"> generato e anima quel
|
|
22
|
+
* wrapper. L'elemento target resta del tutto intatto e può avere qualsiasi
|
|
23
|
+
* valore di display, padding, margin o layout flex/grid.
|
|
24
24
|
*
|
|
25
|
-
* // target
|
|
25
|
+
* // il target può essere flex, avere padding, ecc.
|
|
26
26
|
* slideToggle(document.querySelector('#panel'));
|
|
27
27
|
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
28
|
+
* Stato iniziale chiuso — aggiungere data-slide="closed" al TARGET nell'HTML
|
|
29
|
+
* prima di qualsiasi chiamata JS. La prima chiamata lo trasferisce al wrapper generato:
|
|
30
30
|
*
|
|
31
31
|
* <div id="panel" data-slide="closed">
|
|
32
32
|
* <div class="d-flex p-3">…content…</div>
|
|
@@ -34,39 +34,39 @@ import * as styles from './slide-up-down-toggle.module.css';
|
|
|
34
34
|
*
|
|
35
35
|
* ─── wrap: false ──────────────────────────────────────────────────────────────
|
|
36
36
|
*
|
|
37
|
-
* JS
|
|
38
|
-
* block
|
|
39
|
-
*
|
|
37
|
+
* Il JS aggiunge la classe .slide direttamente al target. Il target deve essere un semplice
|
|
38
|
+
* contenitore block, senza padding, flex o grid propri. Tutto il layout deve
|
|
39
|
+
* stare su un elemento figlio interno.
|
|
40
40
|
*
|
|
41
|
-
* <!-- target:
|
|
41
|
+
* <!-- target: semplice wrapper, senza padding -->
|
|
42
42
|
* <div id="panel" data-slide="closed">
|
|
43
|
-
* <!--
|
|
43
|
+
* <!-- interno: tutto il layout va qui -->
|
|
44
44
|
* <div class="d-flex p-3">…content…</div>
|
|
45
45
|
* </div>
|
|
46
46
|
*
|
|
47
47
|
* slideToggle(document.querySelector('#panel'), { wrap: false });
|
|
48
48
|
*
|
|
49
|
-
* ───
|
|
49
|
+
* ─── Opzioni ──────────────────────────────────────────────────────────────────
|
|
50
50
|
*
|
|
51
51
|
* @typedef {{ wrap?: boolean, duration?: number, callback?: (() => void) | null }} SlideOptions
|
|
52
52
|
*
|
|
53
|
-
* wrap {boolean} default true —
|
|
54
|
-
* duration {number} ms —
|
|
55
|
-
*
|
|
56
|
-
* callback {() => void|null} default null —
|
|
53
|
+
* wrap {boolean} default true — genera automaticamente il wrapper (vedi sopra)
|
|
54
|
+
* duration {number} ms — sovrascrive la variabile CSS --slide-duration;
|
|
55
|
+
* se omesso viene usato il valore CSS
|
|
56
|
+
* callback {() => void|null} default null — invocata al termine della transizione
|
|
57
57
|
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
58
|
+
* Mantenuto qui come riferimento: le tre funzioni esportate qui sotto ridichiarano queste stesse proprietà
|
|
59
|
+
* come voci `@param` con notazione puntata e tipo base `object` invece di `SlideOptions`, dato che TypeScript
|
|
60
|
+
* espande le proprietà `@param` con notazione puntata (necessarie perché IntelliSense dell'editor elenchi
|
|
61
|
+
* ogni proprietà) solo quando il tipo base è il letterale `object`; un typedef con nome darebbe errore (TS8032).
|
|
62
62
|
*
|
|
63
|
-
* ───
|
|
63
|
+
* ─── Valore restituito ────────────────────────────────────────────────────────
|
|
64
64
|
*
|
|
65
|
-
*
|
|
65
|
+
* Tutte e tre le funzioni restituiscono una Promise<void> che si risolve al termine della transizione.
|
|
66
66
|
*/
|
|
67
67
|
|
|
68
68
|
/**
|
|
69
|
-
*
|
|
69
|
+
* Valori di default delle opzioni — unica fonte di verità usata in ogni funzione slide.
|
|
70
70
|
* @type {Required<SlideOptions>}
|
|
71
71
|
*/
|
|
72
72
|
const DEFAULT_OPTIONS = {
|
|
@@ -76,27 +76,27 @@ const DEFAULT_OPTIONS = {
|
|
|
76
76
|
};
|
|
77
77
|
|
|
78
78
|
/**
|
|
79
|
-
*
|
|
80
|
-
* target
|
|
79
|
+
* Associa ogni elemento target al proprio elemento slide (wrapper generato o il
|
|
80
|
+
* target stesso). Controllato a ogni chiamata così che il setup venga eseguito una sola volta per target.
|
|
81
81
|
* @type {WeakMap<HTMLElement, HTMLElement>}
|
|
82
82
|
*/
|
|
83
83
|
const registry = new WeakMap();
|
|
84
84
|
|
|
85
85
|
/**
|
|
86
|
-
*
|
|
86
|
+
* Restituisce l'elemento slide per `target`, creandolo alla prima chiamata.
|
|
87
87
|
*
|
|
88
|
-
* wrap: true —
|
|
89
|
-
* target
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
* wrap: false —
|
|
95
|
-
*
|
|
88
|
+
* wrap: true — inserisce un <div class="slide"> prima del target, sposta il
|
|
89
|
+
* target al suo interno e trasferisce l'eventuale valore data-slide esistente.
|
|
90
|
+
* Si risolve dopo un requestAnimationFrame così che il browser disegni
|
|
91
|
+
* lo stato iniziale del wrapper prima di qualsiasi cambio di
|
|
92
|
+
* attributo che attivi la transizione. (offsetHeight forza il layout ma non il paint —
|
|
93
|
+
* solo rAF garantisce un frame renderizzato come origine della transizione.)
|
|
94
|
+
* wrap: false — aggiunge la classe .slide direttamente al target. Si risolve subito
|
|
95
|
+
* dato che l'elemento era già nel DOM.
|
|
96
96
|
*
|
|
97
97
|
* @param {HTMLElement} target
|
|
98
98
|
* @param {boolean} wrap
|
|
99
|
-
* @returns {Promise<HTMLElement>}
|
|
99
|
+
* @returns {Promise<HTMLElement>} l'elemento che porta .slide e data-slide
|
|
100
100
|
*/
|
|
101
101
|
async function getSlideEl(target, wrap) {
|
|
102
102
|
if (registry.has(target)) return /** @type {HTMLElement} */ (registry.get(target));
|
|
@@ -105,30 +105,34 @@ async function getSlideEl(target, wrap) {
|
|
|
105
105
|
if (wrap) {
|
|
106
106
|
el = document.createElement('div');
|
|
107
107
|
el.classList.add(styles.slide);
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
108
|
+
/*
|
|
109
|
+
trasferisce al wrapper solo lo stato 'closed'; 'open' è il default per gli
|
|
110
|
+
elementi visibili e NON va impostato — attiverebbe @starting-style
|
|
111
|
+
all'inserimento, causando un'animazione di ingresso indesiderata da height:0
|
|
112
|
+
*/
|
|
111
113
|
if ('slide' in target.dataset) {
|
|
112
114
|
if (target.dataset.slide === 'closed') el.dataset.slide = 'closed';
|
|
113
115
|
delete target.dataset.slide;
|
|
114
116
|
}
|
|
115
117
|
target.replaceWith(el);
|
|
116
118
|
el.appendChild(target);
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
119
|
+
/*
|
|
120
|
+
servono due rAF annidati: quello esterno scatta prima del primo paint
|
|
121
|
+
(wrapper inserito ma non ancora renderizzato), quello interno scatta dopo quel
|
|
122
|
+
paint — solo allora il browser ha uno "stile precedente" consolidato da
|
|
123
|
+
usare come origine della transizione. Un solo rAF o offsetHeight non basta
|
|
124
|
+
perché entrambi vengono comunque eseguiti prima del completamento del primo paint.
|
|
125
|
+
*/
|
|
122
126
|
await new Promise(r => requestAnimationFrame(() => requestAnimationFrame(r)));
|
|
123
127
|
} else {
|
|
124
|
-
//
|
|
128
|
+
// legge il display calcolato PRIMA di aggiungere .slide, che lo altererebbe
|
|
125
129
|
const startsHidden = window.getComputedStyle(target).display === 'none';
|
|
126
130
|
target.classList.add(styles.slide);
|
|
127
131
|
el = target;
|
|
128
132
|
|
|
129
133
|
if (startsHidden && !('slide' in target.dataset)) {
|
|
130
|
-
//
|
|
131
|
-
//
|
|
134
|
+
// rimuove il display: none inline così che .slide e le sue regole [data-slide] gestiscano la visibilità;
|
|
135
|
+
// un display: none basato su CSS da altre regole potrebbe comunque confliggere — wrap: true lo evita
|
|
132
136
|
if (target.style.display === 'none') {
|
|
133
137
|
target.style.removeProperty('display');
|
|
134
138
|
}
|
|
@@ -141,10 +145,10 @@ async function getSlideEl(target, wrap) {
|
|
|
141
145
|
}
|
|
142
146
|
|
|
143
147
|
/**
|
|
144
|
-
*
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
+
* Attende il completamento della transizione di `height` su `el`.
|
|
149
|
+
* Chiamata DOPO l'impostazione dell'attributo di stato, così che la transizione sia già
|
|
150
|
+
* in corso; transitionend scatta alla fine della durata dell'animazione.
|
|
151
|
+
* Facoltativamente imposta --slide-duration per sovrascrivere il default CSS.
|
|
148
152
|
*
|
|
149
153
|
* @param {HTMLElement} el
|
|
150
154
|
* @param {number | undefined} duration
|
|
@@ -167,14 +171,14 @@ async function awaitHeight(el, duration) {
|
|
|
167
171
|
}
|
|
168
172
|
|
|
169
173
|
/**
|
|
170
|
-
*
|
|
174
|
+
* Smonta il setup slide per `target`.
|
|
171
175
|
*
|
|
172
|
-
* wrap
|
|
173
|
-
*
|
|
174
|
-
* wrap
|
|
175
|
-
*
|
|
176
|
+
* wrap era true — rimuove il wrapper generato e riporta il target
|
|
177
|
+
* nella sua posizione originale nel DOM.
|
|
178
|
+
* wrap era false — rimuove la classe .slide e l'attributo data-slide
|
|
179
|
+
* dal target.
|
|
176
180
|
*
|
|
177
|
-
* In
|
|
181
|
+
* In entrambi i casi --slide-duration viene rimosso dall'elemento slide.
|
|
178
182
|
*
|
|
179
183
|
* @param {HTMLElement} target
|
|
180
184
|
*/
|
|
@@ -185,7 +189,7 @@ export function disposeSliding(target) {
|
|
|
185
189
|
el.style.removeProperty('--slide-duration');
|
|
186
190
|
|
|
187
191
|
if (el !== target) {
|
|
188
|
-
el.replaceWith(target); //
|
|
192
|
+
el.replaceWith(target); // rimuove il wrapper, rimette il target al suo posto
|
|
189
193
|
} else {
|
|
190
194
|
target.classList.remove(styles.slide);
|
|
191
195
|
delete target.dataset.slide;
|
|
@@ -195,14 +199,14 @@ export function disposeSliding(target) {
|
|
|
195
199
|
}
|
|
196
200
|
|
|
197
201
|
/**
|
|
198
|
-
*
|
|
199
|
-
* CSS
|
|
202
|
+
* Chiude `target`.
|
|
203
|
+
* Il CSS anima height fino a 0, poi imposta di scatto display su none.
|
|
200
204
|
*
|
|
201
205
|
* @param {HTMLElement} target
|
|
202
206
|
* @param {object} [options] (default: {})
|
|
203
|
-
* @param {boolean} [options.wrap=true] -
|
|
204
|
-
* @param {number} [options.duration] -
|
|
205
|
-
* @param {(() => void) | null} [options.callback] -
|
|
207
|
+
* @param {boolean} [options.wrap=true] - genera automaticamente un wrapper `<div class="slide">` attorno a `target` (vedi la documentazione del modulo sopra); se `false`, la classe `.slide` viene aggiunta direttamente a `target` (default: true)
|
|
208
|
+
* @param {number} [options.duration] - sovrascrive la variabile CSS `--slide-duration` (ms); se omesso viene usato il valore CSS.
|
|
209
|
+
* @param {(() => void) | null} [options.callback] - invocata al termine della transizione (default: null)
|
|
206
210
|
* @returns {Promise<void>}
|
|
207
211
|
*/
|
|
208
212
|
export async function slideUp(target, options = {}) {
|
|
@@ -214,14 +218,14 @@ export async function slideUp(target, options = {}) {
|
|
|
214
218
|
}
|
|
215
219
|
|
|
216
220
|
/**
|
|
217
|
-
*
|
|
218
|
-
* display
|
|
221
|
+
* Apre `target`.
|
|
222
|
+
* display passa di scatto a block, poi il CSS anima height da 0 (tramite @starting-style) ad auto.
|
|
219
223
|
*
|
|
220
224
|
* @param {HTMLElement} target
|
|
221
225
|
* @param {object} [options] (default: {})
|
|
222
|
-
* @param {boolean} [options.wrap=true] -
|
|
223
|
-
* @param {number} [options.duration] -
|
|
224
|
-
* @param {(() => void) | null} [options.callback] -
|
|
226
|
+
* @param {boolean} [options.wrap=true] - genera automaticamente un wrapper `<div class="slide">` attorno a `target` (vedi la documentazione del modulo sopra); se `false`, la classe `.slide` viene aggiunta direttamente a `target` (default: true)
|
|
227
|
+
* @param {number} [options.duration] - sovrascrive la variabile CSS `--slide-duration` (ms); se omesso viene usato il valore CSS.
|
|
228
|
+
* @param {(() => void) | null} [options.callback] - invocata al termine della transizione (default: null)
|
|
225
229
|
* @returns {Promise<void>}
|
|
226
230
|
*/
|
|
227
231
|
export async function slideDown(target, options = {}) {
|
|
@@ -233,14 +237,14 @@ export async function slideDown(target, options = {}) {
|
|
|
233
237
|
}
|
|
234
238
|
|
|
235
239
|
/**
|
|
236
|
-
*
|
|
237
|
-
*
|
|
240
|
+
* Commuta lo stato chiuso/aperto di `target`.
|
|
241
|
+
* Legge il valore data-slide corrente sull'elemento slide per decidere la direzione.
|
|
238
242
|
*
|
|
239
243
|
* @param {HTMLElement} target
|
|
240
244
|
* @param {object} [options] (default: {})
|
|
241
|
-
* @param {boolean} [options.wrap=true] -
|
|
242
|
-
* @param {number} [options.duration] -
|
|
243
|
-
* @param {(() => void) | null} [options.callback] -
|
|
245
|
+
* @param {boolean} [options.wrap=true] - genera automaticamente un wrapper `<div class="slide">` attorno a `target` (vedi la documentazione del modulo sopra); se `false`, la classe `.slide` viene aggiunta direttamente a `target` (default: true)
|
|
246
|
+
* @param {number} [options.duration] - sovrascrive la variabile CSS `--slide-duration` (ms); se omesso viene usato il valore CSS.
|
|
247
|
+
* @param {(() => void) | null} [options.callback] - invocata al termine della transizione (default: null)
|
|
244
248
|
* @returns {Promise<void>}
|
|
245
249
|
*/
|
|
246
250
|
export async function slideToggle(target, options = {}) {
|
|
@@ -1,56 +1,56 @@
|
|
|
1
1
|
/*! minimo - Slide Up/Down Toggle */
|
|
2
2
|
/*
|
|
3
|
-
* CSS Module
|
|
3
|
+
* CSS Module per slide-up-down-toggle.js
|
|
4
4
|
*
|
|
5
|
-
*
|
|
5
|
+
* Tre funzionalità CSS moderne lavorano insieme per animare l'altezza senza misurazioni JS:
|
|
6
6
|
*
|
|
7
7
|
* interpolate-size: allow-keywords
|
|
8
|
-
*
|
|
9
|
-
*
|
|
8
|
+
* Consente le transizioni verso/da `height: auto` — il browser risolve la
|
|
9
|
+
* dimensione intrinseca, quindi il JS non legge mai offsetHeight o scrollHeight.
|
|
10
10
|
*
|
|
11
|
-
* transition-behavior: allow-discrete (
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* `display: block`
|
|
11
|
+
* transition-behavior: allow-discrete (tramite `allow-discrete` nella shorthand)
|
|
12
|
+
* Permette a `display` di partecipare a una transizione. In chiusura: height
|
|
13
|
+
* si anima fino a 0, poi `display: none` scatta proprio alla fine. In apertura:
|
|
14
|
+
* `display: block` scatta proprio all'inizio, poi height si anima fino ad auto.
|
|
15
15
|
*
|
|
16
16
|
* @starting-style
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
17
|
+
* Definisce lo stato iniziale per gli elementi che entrano da `display: none`.
|
|
18
|
+
* Senza di esso il browser non ha un valore "precedente" da cui far partire la transizione e
|
|
19
|
+
* l'animazione di apertura non verrebbe eseguita.
|
|
20
20
|
*
|
|
21
|
-
* ───
|
|
21
|
+
* ─── Utilizzo ─────────────────────────────────────────────────────────────────
|
|
22
22
|
*
|
|
23
23
|
* wrap: true (default)
|
|
24
|
-
* JS
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
24
|
+
* Il JS genera un wrapper <div class="slide"> attorno al target.
|
|
25
|
+
* L'elemento target è completamente libero — qualsiasi display, padding, margin.
|
|
26
|
+
* Non servono modifiche all'HTML; lo stato iniziale aperto è il default.
|
|
27
|
+
* Per un elemento che deve partire chiuso, aggiungere data-slide="closed" al
|
|
28
|
+
* target PRIMA di chiamare qualsiasi funzione slide — il JS lo trasferisce al wrapper.
|
|
29
29
|
*
|
|
30
30
|
* wrap: false
|
|
31
|
-
* JS
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
31
|
+
* Il JS aggiunge .slide direttamente all'elemento target.
|
|
32
|
+
* Il target deve essere un semplice wrapper block (senza padding, senza flex/grid).
|
|
33
|
+
* Tutto il layout, il padding e il margin devono stare su un elemento figlio interno.
|
|
34
|
+
* Stato iniziale chiuso: aggiungere data-slide="closed" direttamente al target nell'HTML.
|
|
35
35
|
*
|
|
36
|
-
* ─── FOUC
|
|
36
|
+
* ─── Prevenzione del FOUC ─────────────────────────────────────────────────────
|
|
37
37
|
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
38
|
+
* Gli elementi con data-slide="closed" vengono nascosti da una regola :global qui sotto,
|
|
39
|
+
* quindi partono invisibili anche prima che il JS aggiunga la classe .slide.
|
|
40
40
|
*
|
|
41
|
-
* ───
|
|
41
|
+
* ─── Override della durata ────────────────────────────────────────────────────
|
|
42
42
|
*
|
|
43
|
-
*
|
|
43
|
+
* Impostare --slide-duration sull'elemento oppure passare `duration` nelle opzioni JS:
|
|
44
44
|
* style="--slide-duration: 300ms"
|
|
45
45
|
*/
|
|
46
46
|
|
|
47
|
-
/*
|
|
47
|
+
/* applicato al wrapper dell'animazione (generato o il target stesso) */
|
|
48
48
|
.slide {
|
|
49
49
|
interpolate-size: allow-keywords;
|
|
50
50
|
/*
|
|
51
|
-
* !important
|
|
52
|
-
* .slide[data-slide='closed']
|
|
53
|
-
* display: none !important
|
|
51
|
+
* !important sovrascrive qualsiasi display: none esterno (inline o regola CSS senza !important).
|
|
52
|
+
* .slide[data-slide='closed'] qui sotto ha una specificità maggiore (0,2,0 contro 0,1,0), quindi il suo
|
|
53
|
+
* display: none !important vince comunque quando l'elemento è chiuso.
|
|
54
54
|
*/
|
|
55
55
|
/* stylelint-disable-next-line declaration-no-important */
|
|
56
56
|
display: block !important;
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
/*
|
|
67
|
+
/* stato chiuso: height si anima fino a 0, poi display passa di scatto a none */
|
|
68
68
|
.slide[data-slide='closed'] {
|
|
69
69
|
/* stylelint-disable-next-line declaration-no-important */
|
|
70
70
|
display: none !important;
|
|
@@ -72,18 +72,18 @@
|
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
/*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
75
|
+
* Stato di ingresso per la transizione di apertura.
|
|
76
|
+
* Quando .slide passa da display:none → display:block, il browser ha bisogno
|
|
77
|
+
* di un valore iniziale per height. @starting-style fornisce height:0 così che
|
|
78
|
+
* l'animazione parta da zero fino ad auto invece di scattare istantaneamente.
|
|
79
79
|
*/
|
|
80
80
|
/*
|
|
81
|
-
* @starting-style
|
|
82
|
-
*
|
|
83
|
-
* data-slide
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
* slideDown(),
|
|
81
|
+
* @starting-style ha come bersaglio solo [data-slide='open'] — non :not([data-slide='closed']).
|
|
82
|
+
* Il selettore più ampio corrisponderebbe anche ai wrapper appena inseriti (che non hanno
|
|
83
|
+
* l'attributo data-slide), causando un'animazione di ingresso indesiderata da height:0 che
|
|
84
|
+
* confligge con la prima chiamata di chiusura e rende invisibile la transizione.
|
|
85
|
+
* Usare [data-slide='open'] la limita all'animazione di apertura attivata da
|
|
86
|
+
* slideDown(), che imposta sempre data-slide="open" su un elemento in precedenza nascosto.
|
|
87
87
|
*/
|
|
88
88
|
@starting-style {
|
|
89
89
|
.slide[data-slide='open'] {
|
|
@@ -92,9 +92,9 @@
|
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
/*
|
|
95
|
-
* FOUC
|
|
96
|
-
*
|
|
97
|
-
*
|
|
95
|
+
* Prevenzione del FOUC — globale, non richiede alcuna classe.
|
|
96
|
+
* Nasconde gli elementi con data-slide="closed" prima che il JS sia eseguito e abbia aggiunto .slide.
|
|
97
|
+
* Usa :global così che CSS Modules non applichi l'hash a questo selettore.
|
|
98
98
|
*/
|
|
99
99
|
:global([data-slide='closed']) {
|
|
100
100
|
display: none;
|
|
@@ -4,7 +4,7 @@ import { classnames } from '../../utilities/classnames.js';
|
|
|
4
4
|
import * as styles from './snackbar.module.css';
|
|
5
5
|
|
|
6
6
|
/*
|
|
7
|
-
|
|
7
|
+
Riferimenti
|
|
8
8
|
* https://web.dev/learn/css/popover-and-dialog
|
|
9
9
|
* https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/popover
|
|
10
10
|
* https://developer.mozilla.org/en-US/docs/Web/API/Popover_API
|
|
@@ -14,19 +14,19 @@ References
|
|
|
14
14
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
// TODO snackbar
|
|
18
|
-
// TODO
|
|
17
|
+
// TODO azione della snackbar
|
|
18
|
+
// TODO gestire più snackbar simultanee (senza stacking)
|
|
19
19
|
// TODO test con prefers-reduced-motion
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
|
-
*
|
|
23
|
-
* @param {string} message -
|
|
22
|
+
* Mostra una notifica snackbar / toast usando la Popover API.
|
|
23
|
+
* @param {string} message - Il messaggio da mostrare.
|
|
24
24
|
* @param {Object} [options={}] (default: {})
|
|
25
|
-
* @param {string | null} [options.status=null] -
|
|
26
|
-
* @param {number | false | null} [options.duration=4000] -
|
|
27
|
-
* @param {boolean} [options.close_btn=true] -
|
|
28
|
-
* @param {Function | null} [options.action=null] -
|
|
29
|
-
* @param {string | null} [options.action_text=null] -
|
|
25
|
+
* @param {string | null} [options.status=null] - Variante di stato: `danger`, `warning`, `info` o `success` (default: null)
|
|
26
|
+
* @param {number | false | null} [options.duration=4000] - Ritardo di chiusura automatica in ms; `false` o `null` disattiva la chiusura automatica (default: 4000)
|
|
27
|
+
* @param {boolean} [options.close_btn=true] - Se mostrare il pulsante di chiusura (default: true)
|
|
28
|
+
* @param {Function | null} [options.action=null] - Callback dell'azione (default: null)
|
|
29
|
+
* @param {string | null} [options.action_text=null] - Etichetta del pulsante di azione (default: null)
|
|
30
30
|
* @returns {{ close: function(): void }}
|
|
31
31
|
*/
|
|
32
32
|
export function snackbar(message, options = {}){
|
|
@@ -34,11 +34,11 @@ export function snackbar(message, options = {}){
|
|
|
34
34
|
options = {
|
|
35
35
|
|
|
36
36
|
status : null, // danger, warning, info, success
|
|
37
|
-
duration : 4000, // ms
|
|
37
|
+
duration : 4000, // ms oppure false/null per evitare la chiusura automatica
|
|
38
38
|
close_btn : true, // true | false
|
|
39
39
|
|
|
40
|
-
action : null, // null
|
|
41
|
-
action_text : null, // null
|
|
40
|
+
action : null, // null o funzione
|
|
41
|
+
action_text : null, // null o stringa
|
|
42
42
|
|
|
43
43
|
...options
|
|
44
44
|
};
|
|
@@ -51,7 +51,7 @@ export function snackbar(message, options = {}){
|
|
|
51
51
|
|
|
52
52
|
const removePopover = () => {
|
|
53
53
|
if (_isRemoving || !_popover?.matches(':popover-open')) return;
|
|
54
|
-
_isRemoving = true; //
|
|
54
|
+
_isRemoving = true; // evita la doppia rimozione se chiamata più volte durante l'animazione di chiusura
|
|
55
55
|
|
|
56
56
|
if (_timeoutID) clearTimeout(_timeoutID);
|
|
57
57
|
|
|
@@ -62,10 +62,10 @@ export function snackbar(message, options = {}){
|
|
|
62
62
|
|
|
63
63
|
_popover?.classList.add(styles.isHiding);
|
|
64
64
|
|
|
65
|
-
//
|
|
66
|
-
//
|
|
65
|
+
// con `prefers-reduced-motion` (o qualsiasi override che disattivi le animazioni) non parte
|
|
66
|
+
// alcuna animazione e `animationend` non scatterebbe mai: in tal caso rimuove subito
|
|
67
67
|
if (_popover?.getAnimations().length) {
|
|
68
|
-
// 'once'
|
|
68
|
+
// 'once' evita listener duplicati; il flag protegge dalle chiamate prima della fine dell'animazione
|
|
69
69
|
_popover.addEventListener('animationend', remove, { once: true });
|
|
70
70
|
}
|
|
71
71
|
else {
|
|
@@ -115,10 +115,10 @@ export function snackbar(message, options = {}){
|
|
|
115
115
|
|
|
116
116
|
|
|
117
117
|
if(options.duration) {
|
|
118
|
-
const duration = options.duration; // const
|
|
118
|
+
const duration = options.duration; // const mantiene il narrowing dentro le closure
|
|
119
119
|
_timeoutID = setTimeout(removePopover, duration);
|
|
120
120
|
|
|
121
|
-
//
|
|
121
|
+
// mette in pausa il timeout di chiusura automatica al passaggio del mouse
|
|
122
122
|
_popover?.addEventListener('mouseenter', () => clearTimeout(_timeoutID));
|
|
123
123
|
_popover?.addEventListener('mouseleave', () => {
|
|
124
124
|
_timeoutID = setTimeout(removePopover, duration);
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import * as styles from './spinner.module.css';
|
|
2
2
|
|
|
3
|
-
//
|
|
4
|
-
// TODO:
|
|
3
|
+
// La classe dello spinner dipende dal tipo di spinner in uso; deve essere incluso il file CSS corrispondente.
|
|
4
|
+
// TODO: sistema per configurare il tipo di spinner, così da consentire più tipi di spinner nello stesso progetto
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
7
|
+
* Restituisce il markup HTML di uno spinner di caricamento.
|
|
8
8
|
* @returns {string}
|
|
9
9
|
*/
|
|
10
10
|
export function spinner() {
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
# Unsplash page
|
|
2
|
-
|
|
2
|
+
Pagina singola con una foto casuale da [Unsplash](https://unsplash.com/) per mostrare alcuni messaggi (utile per le pagine di errore).
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
Questo componente nasce da alcuni esperimenti fatti con le API di Unsplash. Lo scopo iniziale era mostrare pagine di errore più accattivanti, ma si può usare per qualsiasi altro scopo.
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
Per ottenere i risultati migliori è consigliabile mostrare immagini da una collezione di foto preparata su Unsplash. Le demo di questo repository usano la mia collezione ["World"](https://unsplash.com/collections/3660951/world).
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Serve uno script lato server per recuperare i dati JSON di un'immagine casuale da Unsplash (vedi [Get a Random Photo](https://unsplash.com/documentation#get-a-random-photo) nella documentazione delle API di Unsplash).
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
Lo script implementa anche [BlurHash](https://blurha.sh/), per mostrare un placeholder dell'immagine fino al suo caricamento.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
Per maggiori dettagli ed esempi vedi:
|
|
13
13
|
|
|
14
14
|
* <https://unsplash.com/developers>
|
|
15
15
|
* [A Random Image Slideshow With Unsplash and React](https://betterprogramming.pub/a-random-image-slideshow-with-unsplash-and-react-1b6aee698652)
|
|
@@ -18,6 +18,6 @@ For more details and examples take a look at:
|
|
|
18
18
|
* [A Split Image Effect in React](https://medium.com/better-programming/a-split-image-effect-in-react-beb2baa3fe5f) and [split image](https://github.com/massimo-cassandro/area-test/tree/main/2023-07-split-image)
|
|
19
19
|
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
Le icone SVG usate nello script provengono da [Phosphor Icon](https://phosphoricons.com/). Al momento non è possibile usarne di diverse senza modificare il codice sorgente.
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
La directory `snippets` contiene un esempio di implementazione di Unsplash Page per un sistema di pagine di errore in twig/Symfony
|