@massimo-cassandro/minimo 1.24.12 → 1.26.0
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 +1 -1
- package/design-tokens/tokens-config-sample.mjs +4 -0
- package/dev-tools/starter-kit/starter-install.sh +3 -2
- package/dev-tools/starter-kit/templates/CLAUDE-frontend.md +13 -0
- package/dev-tools/starter-kit/webpack.config.mjs +13 -0
- package/package.json +1 -1
- package/src/utilities/dom-builder/dom-builder.js +44 -10
- /package/dev-tools/starter-kit/templates/{index-critical.css → layout-critical.css} +0 -0
package/README.md
CHANGED
|
@@ -25,7 +25,7 @@ To bootstrap a project **before** installing the whole package, download only th
|
|
|
25
25
|
|
|
26
26
|
```bash
|
|
27
27
|
curl -sL "$(npm view @massimo-cassandro/minimo dist.tarball)" | tar xz package/dev-tools/starter-kit
|
|
28
|
-
zsh package/dev-tools/starter-kit/starter-install.sh
|
|
28
|
+
zsh package/dev-tools/starter-kit/starter-install.sh
|
|
29
29
|
rm -rf package
|
|
30
30
|
```
|
|
31
31
|
|
|
@@ -139,6 +139,7 @@ safe_cat "${TEMPLATES_DIR}/_editorconfig" .editorconfig new
|
|
|
139
139
|
safe_cat "${TEMPLATES_DIR}/_prettierrc" .prettierrc new
|
|
140
140
|
safe_cat "${TEMPLATES_DIR}/_root_htaccess" "${FRONTEND_INSTALL_PATH}/_root_htaccess"
|
|
141
141
|
safe_cat "${TEMPLATES_DIR}/_root_robots.txt" "${FRONTEND_INSTALL_PATH}/_root_robots.txt"
|
|
142
|
+
safe_cat "${TEMPLATES_DIR}/CLAUDE-frontend.md" "${FRONTEND_INSTALL_PATH}/CLAUDE.md"
|
|
142
143
|
|
|
143
144
|
# jsconfig.json: sta SEMPRE nella root del progetto (è anche il file di
|
|
144
145
|
# riferimento di vscode). I suoi path sono quindi relativi alla root: il
|
|
@@ -278,9 +279,9 @@ else
|
|
|
278
279
|
safe_cat "${MINIMO_PKG_DIR}/dev-tools/create-favicons/src/default-params.mjs" "${FRONTEND_INSTALL_PATH}/favicons/create-favicons-cfg.mjs"
|
|
279
280
|
fi
|
|
280
281
|
|
|
281
|
-
# entry css critical (
|
|
282
|
+
# entry css critical (inline nei template html) e entry js, sulla root di
|
|
282
283
|
# installazione accanto a index.css
|
|
283
|
-
safe_cat "${TEMPLATES_DIR}/
|
|
284
|
+
safe_cat "${TEMPLATES_DIR}/layout-critical.css" "${FRONTEND_INSTALL_PATH}/src/css/layout-critical.css"
|
|
284
285
|
safe_cat "${TEMPLATES_DIR}/app_index.js" "${FRONTEND_INSTALL_PATH}/index.js"
|
|
285
286
|
|
|
286
287
|
# favicons: istruzioni d'uso di `npx create-favicons`
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# CLAUDE.md - frontend
|
|
2
|
+
|
|
3
|
+
## Contesto di dominio
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
## Stile di lavoro
|
|
8
|
+
|
|
9
|
+
- Conferma la comprensione prima di agire su richieste ambigue
|
|
10
|
+
- Il progetto usa ES modules (import/export), evitare sioluzioni che utilizzano commonJs
|
|
11
|
+
- In linea di massima non proporre soluzioni che richiedano modifiche alla parte back-end, a meno che non sia esplicitamente richiesto
|
|
12
|
+
- nella chat evitare neologismi come parsare, committare ecc., usare i termini corrispondi in italiano o il termine originale in inglese dove non sia possibile un equivalente in italiano
|
|
13
|
+
- nei commenti su più righe preferire `/* ... */` piuttosto che ripetere `//` ad igni inizio riga
|
|
@@ -252,6 +252,19 @@ const config = {
|
|
|
252
252
|
directory: path.join(__dirname, '/'),
|
|
253
253
|
serveIndex: true
|
|
254
254
|
},
|
|
255
|
+
/*
|
|
256
|
+
proxy: [
|
|
257
|
+
{
|
|
258
|
+
// /login, /logout (redirect Google) e /api/... (fetch AJAX) vanno
|
|
259
|
+
// inoltrati al server PHP reale (npm run "php server", vedi
|
|
260
|
+
// package.json e app/router.php), che webpack-dev-server non può
|
|
261
|
+
// eseguire da solo.
|
|
262
|
+
context: ['/api', '/login', '/logout'],
|
|
263
|
+
target: process.env.PHP_BASE_URL || 'http://localhost:8000'
|
|
264
|
+
}
|
|
265
|
+
],
|
|
266
|
+
static: false,
|
|
267
|
+
*/
|
|
255
268
|
open: { app: { name: 'Google Chrome' } },
|
|
256
269
|
compress: true,
|
|
257
270
|
hot: true,
|
package/package.json
CHANGED
|
@@ -14,17 +14,18 @@ import { parseDomString } from './parseDomString.js';
|
|
|
14
14
|
* @property {string | string[]} [classname] - Alias for `className`.
|
|
15
15
|
* @property {string | null} [id] - Unique element ID.
|
|
16
16
|
* @property {[string, *] | [string, *][] | Object<string, *>} [attrs] - Attributes: a `[name, value]` pair, array of pairs, or `{name: value}` object.
|
|
17
|
-
* @property {string | number | Function |
|
|
17
|
+
* @property {string | number | Function | Node | DomBuilderItem[] | null} [content] - Element content.
|
|
18
18
|
* A string or number is set as plain text (`textContent`) unless it contains `<`, in which case it is
|
|
19
19
|
* treated as markup: sanitized and inserted via the native Sanitizer API (`Element.setHTML`) where
|
|
20
|
-
* supported, falling back to raw `innerHTML` on browsers without it.
|
|
20
|
+
* supported, falling back to raw `innerHTML` on browsers without it. A `Node` (an `Element`, a
|
|
21
|
+
* `DocumentFragment`, ...) is appended as-is, either directly or returned from a function.
|
|
21
22
|
* @property {string | number} [text] - Literal text node shorthand: inserts a plain `Text` node (never
|
|
22
23
|
* parsed as markup) in place of an element, so it can sit as a sibling of tags within `children`/`content`
|
|
23
24
|
* arrays. Mutually exclusive with `tag`/`content`/`children`: when set (and `tag` is absent), every other
|
|
24
25
|
* property except `condition` and `callback` is ignored.
|
|
25
26
|
* @property {boolean} [condition=true] - When false, the element (or text node) is skipped.
|
|
26
27
|
* @property {(function(HTMLElement|Text): void) | null} [callback] - Callback invoked after the element (or text node) is created.
|
|
27
|
-
* @property {Array<DomBuilderItem|string>} [children] - Configuration array for child elements. Accepts strings (shorthand per `parseDomString`) and/or
|
|
28
|
+
* @property {Array<DomBuilderItem|string|Node>} [children] - Configuration array for child elements. Accepts strings (shorthand per `parseDomString`), configuration objects, and/or `Node`s (an `Element`, a `DocumentFragment`, ...) inserted as-is.
|
|
28
29
|
*/
|
|
29
30
|
|
|
30
31
|
/**
|
|
@@ -44,7 +45,7 @@ import { parseDomString } from './parseDomString.js';
|
|
|
44
45
|
* className: 'xxx' | ['class1', 'class2'], // also `class`
|
|
45
46
|
* id: 'element-id',
|
|
46
47
|
* attrs: [attr_name, attr_value] | [[...], [...]] | {name: value},
|
|
47
|
-
* content: 'xxx' | 'xxx <strong>yyy</strong>' | 123 | domBuilder Array | function |
|
|
48
|
+
* content: 'xxx' | 'xxx <strong>yyy</strong>' | 123 | domBuilder Array | function | Node, // see DomBuilderItem.content above
|
|
48
49
|
* condition: true | false,
|
|
49
50
|
* callback: el => ...,
|
|
50
51
|
* children: [...]
|
|
@@ -84,16 +85,16 @@ import { parseDomString } from './parseDomString.js';
|
|
|
84
85
|
* object-level properties take precedence.
|
|
85
86
|
*
|
|
86
87
|
* @function domBuilder
|
|
87
|
-
* @param {Array<DomBuilderItem|string>} [structureArray=[]] - Configuration array. Accepts strings (shorthand per `parseDomString`) and/or
|
|
88
|
+
* @param {Array<DomBuilderItem|string|Node>} [structureArray=[]] - Configuration array. Accepts strings (shorthand per `parseDomString`), configuration objects, and/or `Node`s (an `Element`, a `DocumentFragment`, ...) inserted as-is; each configuration object supports:
|
|
88
89
|
* - `tag` / `tagName` {string | string[]} - HTML tag name, or array of nested tags (each is parent of the next). Default `'div'`.
|
|
89
90
|
* - `className` / `class` / `classname` {string | string[]} - CSS class(es): a single string or an array (falsy values filtered out).
|
|
90
91
|
* - `id` {string | null} - Unique element ID.
|
|
91
92
|
* - `attrs` {[string, *] | [string, *][] | Object<string, *>} - Attributes: a `[name, value]` pair, array of pairs, or `{name: value}` object.
|
|
92
|
-
* - `content` {string | number | Function |
|
|
93
|
+
* - `content` {string | number | Function | Node | DomBuilderItem[] | null} - Element content. A string/number is set as `textContent` unless it contains `<`, in which case it's sanitized and inserted as markup (`Element.setHTML`, falling back to `innerHTML`). A `Node` (`Element`, `DocumentFragment`, ...), passed directly or returned from a function, is appended as-is.
|
|
93
94
|
* - `text` {string | number} - Literal text node shorthand: inserts a plain `Text` node (never parsed as markup) as a sibling of other items, in place of an element. Mutually exclusive with `tag`/`content`/`children`.
|
|
94
95
|
* - `condition` {boolean} - When false, the element (or text node) is skipped. Default `true`.
|
|
95
96
|
* - `callback` {(function(HTMLElement|Text): void) | null} - Invoked after the element (or text node) is created.
|
|
96
|
-
* - `children` {Array<DomBuilderItem|string>} - Configuration array for child elements (same format, nested).
|
|
97
|
+
* - `children` {Array<DomBuilderItem|string|Node>} - Configuration array for child elements (same format, nested; also accepts `Node`s inserted as-is).
|
|
97
98
|
*
|
|
98
99
|
* IDs and classes can be specified either as top-level object keys or inside `attrs`; top-level properties take precedence.
|
|
99
100
|
* @param {HTMLElement} [parent] - Parent element the structure is attached to (see `options.insertMode`).
|
|
@@ -105,7 +106,7 @@ import { parseDomString } from './parseDomString.js';
|
|
|
105
106
|
*/
|
|
106
107
|
|
|
107
108
|
|
|
108
|
-
export function domBuilder(structureArray = [], parent, options = {}) {
|
|
109
|
+
export function domBuilder(/** @type {Array<DomBuilderItem|string|Node>} */ structureArray = [], parent, options = {}) {
|
|
109
110
|
|
|
110
111
|
options = {
|
|
111
112
|
emptyParent: false,
|
|
@@ -143,6 +144,34 @@ export function domBuilder(structureArray = [], parent, options = {}) {
|
|
|
143
144
|
|
|
144
145
|
structureArray.forEach(inputItem => {
|
|
145
146
|
|
|
147
|
+
// A DOM Node (Element, DocumentFragment, ...) passed directly: inserted as-is,
|
|
148
|
+
// bypassing element creation and config parsing entirely.
|
|
149
|
+
if (inputItem instanceof Node) {
|
|
150
|
+
|
|
151
|
+
elaboratedStructureArray.push(/** @type {DomBuilderItem} */ (/** @type {unknown} */ (inputItem)));
|
|
152
|
+
|
|
153
|
+
if (target) {
|
|
154
|
+
if (options.insertMode === 'before') {
|
|
155
|
+
const anchor = /** @type {HTMLElement} */ (target);
|
|
156
|
+
anchor.parentNode?.insertBefore(inputItem, anchor);
|
|
157
|
+
|
|
158
|
+
} else if (options.insertMode === 'after') {
|
|
159
|
+
const anchor = afterAnchors.get(/** @type {HTMLElement} */ (target)) ?? /** @type {HTMLElement} */ (target);
|
|
160
|
+
anchor.parentNode?.insertBefore(inputItem, anchor.nextSibling);
|
|
161
|
+
afterAnchors.set(/** @type {HTMLElement} */ (target), inputItem);
|
|
162
|
+
|
|
163
|
+
} else {
|
|
164
|
+
target.appendChild(inputItem);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (mainElement == null && inputItem instanceof Element) {
|
|
169
|
+
mainElement = /** @type {HTMLElement} */ (inputItem);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
|
|
146
175
|
/** @type {DomBuilderItem | null} */
|
|
147
176
|
let item;
|
|
148
177
|
if (inputItem != null && typeof inputItem === 'string' && inputItem !== '') {
|
|
@@ -232,16 +261,21 @@ export function domBuilder(structureArray = [], parent, options = {}) {
|
|
|
232
261
|
|
|
233
262
|
} else {
|
|
234
263
|
|
|
235
|
-
/** @type {string |
|
|
264
|
+
/** @type {string | Node | null} */
|
|
236
265
|
let content = null;
|
|
237
266
|
if (typeof safeItem.content === 'function') {
|
|
238
267
|
content = safeItem.content();
|
|
239
268
|
|
|
269
|
+
} else if (safeItem.content instanceof Node) {
|
|
270
|
+
content = safeItem.content;
|
|
271
|
+
|
|
240
272
|
} else if (safeItem.content != null) {
|
|
241
273
|
content = String(safeItem.content);
|
|
242
274
|
}
|
|
243
275
|
|
|
244
|
-
if (content instanceof
|
|
276
|
+
if (content instanceof Node) {
|
|
277
|
+
// Element, DocumentFragment, Text, ... appended as-is (a DocumentFragment's
|
|
278
|
+
// children are moved into `el`, emptying the fragment, per native DOM behavior)
|
|
245
279
|
el.appendChild(content);
|
|
246
280
|
|
|
247
281
|
} else if (content != null) {
|
|
File without changes
|