@massimo-cassandro/minimo 1.27.1 → 1.27.3

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": "1.27.1",
3
+ "version": "1.27.3",
4
4
  "description": "Light css framework & utilities",
5
5
  "type": "module",
6
6
  "main": "./index.js",
@@ -284,8 +284,7 @@ export default function (params = {}) {
284
284
  }
285
285
  }); // end autoComplete
286
286
 
287
- // TODO[epic=autocomplete]
288
- // improve and make the callback invocation more efficient
287
+ // TODO improve and make the callback invocation more efficient
289
288
 
290
289
  // reset hidden field when the autocomplete value is cleared or mismatched
291
290
  const check_ac = () => {
@@ -1,11 +1,20 @@
1
1
  /*! minimo - Symfony Macro Manager */
2
2
  import './sf-macro.css';
3
3
 
4
+ // TODO[epic=v2] in una v. 2 di minimo, rinominare wrapper_selector e row_selector in
5
+ // wrapperClass e rowClass (NB: classi, non selettori, per uniformità con closeBtnClass/addBtnClass/containerClass
6
+ // aggiunti sotto) e rendere tutti i parametri camelCase.
7
+ // TODO[epic=v2] valutare se rendere opzionale, tramite parametro, l'importazione statica
8
+ // di sf-macro.css qui sopra (questione lasciata in sospeso).
9
+
4
10
  /**
5
11
  * Initialises Symfony macro collection fields (repeatable fieldsets).
6
12
  * @param {Object} [options={}]
7
13
  * @param {string} [options.wrapper_selector='.sf-macro-wrapper'] - Selector for the outer wrapper element.
8
14
  * @param {string} [options.row_selector='.sf-macro-riga'] - Selector for each repeatable row.
15
+ * @param {string} [options.closeBtnClass='sf-macro-close-btn'] - Class name of the row-remove button.
16
+ * @param {string} [options.addBtnClass='sf-macro-riga-add'] - Class name of the row-add button.
17
+ * @param {string} [options.containerClass='sf-macro-container'] - Class name of the rows container.
9
18
  * @param {((newRow: Element | null, addBtn: Element | null) => void) | null} [options.add_callback=null] - Called after a row is added; receives the new row and the add button.
10
19
  * @param {(() => void) | null} [options.del_callback=null] - Called after a row is removed.
11
20
  * @param {boolean} [options.insertAtTop=false] - When true, new rows are inserted at the top.
@@ -14,46 +23,63 @@ import './sf-macro.css';
14
23
  export function sf_macro({
15
24
  wrapper_selector = '.sf-macro-wrapper',
16
25
  row_selector = '.sf-macro-riga',
26
+ // Change closeBtnClass/addBtnClass/containerClass only if you don't want to use
27
+ // the default sf-macro.css: unused default classes are not stripped by this
28
+ // component, that cleanup is delegated to PurgeCSS (or equivalent) downstream.
29
+ closeBtnClass = 'sf-macro-close-btn',
30
+ addBtnClass = 'sf-macro-riga-add',
31
+ containerClass = 'sf-macro-container',
17
32
  add_callback = null,
18
33
  del_callback = null,
19
34
  insertAtTop = false
20
35
  }={}) {
21
36
 
22
- document.querySelectorAll(wrapper_selector).forEach(fset => {
23
- const macro_container = /** @type {HTMLElement | null} */ (fset.querySelector('.sf-macro-container'));
24
- if (!macro_container) return;
25
- const macro_template = macro_container.dataset.template ?? '';
37
+ // Single delegated listener: resolves the nearest wrapper_selector ancestor
38
+ // of the click target at click time, instead of binding one listener per
39
+ // wrapper found at init time. This is required for wrapper_selector to be
40
+ // shared by nested wrapper instances (the nearest one always wins, with no
41
+ // propagation to outer ones) and to work on wrappers created dynamically
42
+ // after this call (e.g. a nested wrapper inside a newly added row), which
43
+ // would otherwise never get their own listener.
44
+ document.addEventListener('click', e => {
45
+ const target = /** @type {HTMLElement} */ (e.target);
26
46
 
27
- // event listeners
28
- fset.addEventListener('click', e => {
29
- const target = /** @type {HTMLElement} */ (e.target);
47
+ const action_btn = /** @type {HTMLElement | null} */ (
48
+ target.closest(`.${addBtnClass}, .${closeBtnClass}`)
49
+ );
50
+ if (!action_btn) return;
30
51
 
31
- if(target.closest('.sf-macro-riga-add')) {
52
+ const fset = /** @type {HTMLElement | null} */ (target.closest(wrapper_selector));
53
+ if (!fset) return;
32
54
 
33
- const righe_macro = macro_container.querySelectorAll(row_selector).length;
55
+ const macro_container = /** @type {HTMLElement | null} */ (fset.querySelector(`.${containerClass}`));
56
+ if (!macro_container) return;
34
57
 
35
- macro_container.insertAdjacentHTML(insertAtTop? 'afterbegin' : 'beforeend',
36
- macro_template.replace(/__indice\d?__/g, String(righe_macro + 1))
37
- );
58
+ if(action_btn.matches(`.${addBtnClass}`)) {
38
59
 
39
- if(add_callback && typeof add_callback === 'function') {
40
- add_callback(
41
- insertAtTop
42
- ? macro_container.querySelector('.sf-macro-riga:first-child')
43
- : macro_container.querySelector('.sf-macro-riga:last-child'),
44
- target.closest('.sf-macro-riga-add')
45
- );
46
- }
60
+ const macro_template = macro_container.dataset.template ?? '';
61
+ const righe_macro = macro_container.querySelectorAll(row_selector).length;
47
62
 
63
+ macro_container.insertAdjacentHTML(insertAtTop? 'afterbegin' : 'beforeend',
64
+ macro_template.replace(/__indice\d?__/g, String(righe_macro + 1))
65
+ );
66
+
67
+ if(add_callback && typeof add_callback === 'function') {
68
+ add_callback(
69
+ insertAtTop
70
+ ? macro_container.querySelector(`${row_selector}:first-child`)
71
+ : macro_container.querySelector(`${row_selector}:last-child`),
72
+ action_btn
73
+ );
74
+ }
48
75
 
49
- } else if(target.closest('.sf-macro-close-btn')) {
50
- target.closest(row_selector)?.remove();
76
+ } else {
77
+ target.closest(row_selector)?.remove();
51
78
 
52
- if(del_callback && typeof del_callback === 'function') {
53
- del_callback();
54
- }
79
+ if(del_callback && typeof del_callback === 'function') {
80
+ del_callback();
55
81
  }
82
+ }
56
83
 
57
- }, false);
58
- });
84
+ }, false);
59
85
  }