@massimo-cassandro/minimo 1.32.3 → 1.33.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/dev-tools/starter-kit/package-tpl.json +1 -1
- package/dev-tools/starter-kit/source_files/CLAUDE-frontend.md +1 -0
- package/dev-tools/starter-kit/source_files/_private/pwd.md +16 -0
- package/dev-tools/starter-kit/source_files/_private/sf.md +12 -0
- package/dev-tools/starter-kit/source_files/stylelint.config.mjs +1 -1
- package/dev-tools/starter-kit/starter-install.sh +102 -8
- package/dev-tools/starter-kit/webpack.config.mjs +6 -14
- package/dev-tools/stylelint-config/README.md +45 -0
- package/dev-tools/stylelint-config/index.js +184 -0
- package/package.json +11 -2
- package/src/custom-properties.css +7 -0
- package/src/web-components/json-table/json-table-component.js +283 -0
- package/src/web-components/json-table/json-table-component.module.css +57 -0
- package/src/web-components/json-table/json-table.minimo.tokens.mjs +48 -0
- package/src/web-components/json-table/readme.md +243 -0
- package/src/web-components/json-table/src/defaults.js +105 -0
- package/src/web-components/json-table/src/get-data.js +57 -0
- package/src/web-components/json-table/src/info-section.js +72 -0
- package/src/web-components/json-table/src/main-builder.js +95 -0
- package/src/web-components/json-table/src/resolve-params.js +96 -0
- package/src/web-components/json-table/src/update-info.js +48 -0
- package/src/web-components/s-datatable-component/docs.md +62 -0
- package/src/web-components/s-datatable-component/s-datatable-component.js +9 -1
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
/*! minimo - json-table */
|
|
2
|
+
|
|
3
|
+
import { defaults } from './src/defaults.js';
|
|
4
|
+
import { resolveParams } from './src/resolve-params.js';
|
|
5
|
+
import { getData } from './src/get-data.js';
|
|
6
|
+
import { mainBuilder } from './src/main-builder.js';
|
|
7
|
+
import { updateInfo } from './src/update-info.js';
|
|
8
|
+
|
|
9
|
+
/** @typedef {import('./src/defaults.js').JsonTableParams} JsonTableParams */
|
|
10
|
+
/** @typedef {import('./src/main-builder.js').JsonTableElements} JsonTableElements */
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Project-wide defaults, set via `JsonTable.setDefaults()`.
|
|
14
|
+
* Module-level so they are shared by every instance.
|
|
15
|
+
* @type {Partial<JsonTableParams>}
|
|
16
|
+
*/
|
|
17
|
+
let projectDefaults = {};
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* `<json-table>` – HTML table generator from JSON data (inline or fetched), light DOM custom element.
|
|
22
|
+
*
|
|
23
|
+
* WORK IN PROGRESS: at this stage only the outer structure is generated (info section, search
|
|
24
|
+
* input, empty table with caption). Columns, rows rendering, sorting, search and pagination
|
|
25
|
+
* are not implemented yet.
|
|
26
|
+
*
|
|
27
|
+
* Parameters (see `src/defaults.js` → `JsonTableParams`) can be set as HTML attributes or via
|
|
28
|
+
* `init()`; precedence: `init()` > HTML attribute > `JsonTable.setDefaults()` > built-in default.
|
|
29
|
+
*
|
|
30
|
+
* Events: `jt:ready` (bubbles) is dispatched on the element once the structure has been built;
|
|
31
|
+
* `event.detail.jsonTable` is the component instance.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* // markup only
|
|
35
|
+
* // <json-table jsonurl="/api/rows.json" caption="Utenti"></json-table>
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* // script
|
|
39
|
+
* import { JsonTable } from '@massimo-cassandro/minimo/src/web-components/json-table/json-table-component.js';
|
|
40
|
+
*
|
|
41
|
+
* JsonTable.setDefaults({ tableClass: 'table' }); // optional, project-wide
|
|
42
|
+
*
|
|
43
|
+
* const el = document.querySelector('json-table');
|
|
44
|
+
* el.addEventListener('jt:ready', e => console.log(e.detail.jsonTable.data));
|
|
45
|
+
* el.init({
|
|
46
|
+
* debug: false, // default: false
|
|
47
|
+
* jsonUrl: '/api/rows.json', // default: null
|
|
48
|
+
* jsonDataField: 'data', // default: 'data'
|
|
49
|
+
* data: null, // default: null (takes precedence over jsonUrl when set)
|
|
50
|
+
* caption: 'Utenti', // default: null
|
|
51
|
+
* search: true, // default: true
|
|
52
|
+
* searchInputClass: 'form-control', // default: 'form-control'
|
|
53
|
+
* tableId: null, // default: null
|
|
54
|
+
* tableWrapperClass: 'table-responsive', // default: 'table-responsive'
|
|
55
|
+
* tableClass: 'table table-bordered', // default: 'table table-bordered'
|
|
56
|
+
* mainWrapperExtraClass: null, // default: null
|
|
57
|
+
* outerInfoExtraClass: null, // default: null
|
|
58
|
+
* infoExtraClass: null, // default: null
|
|
59
|
+
* infoText: (shown, total) => `${shown} / ${total}` // default: Italian "Visualizzate N righe su M"
|
|
60
|
+
* });
|
|
61
|
+
*/
|
|
62
|
+
export class JsonTable extends HTMLElement {
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Sets project-wide defaults, shared by every instance created afterwards
|
|
66
|
+
* (instances already rendered are not updated). Call it once, before the instances
|
|
67
|
+
* are created, e.g. in a shared script. Values are merged with the previous ones.
|
|
68
|
+
*
|
|
69
|
+
* @param {Partial<JsonTableParams>} [newDefaults={}] - Parameters to override (default: {})
|
|
70
|
+
* @returns {void}
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* JsonTable.setDefaults({
|
|
74
|
+
* searchInputClass: 'form-control form-control-sm', // default: 'form-control'
|
|
75
|
+
* tableClass: 'table', // default: 'table table-bordered'
|
|
76
|
+
* infoText: (shown, total) => `${shown} di ${total}`
|
|
77
|
+
* });
|
|
78
|
+
*/
|
|
79
|
+
static setDefaults(newDefaults = {}) {
|
|
80
|
+
projectDefaults = { ...projectDefaults, ...newDefaults };
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Clears the project-wide defaults set via `setDefaults()`.
|
|
85
|
+
* @returns {void}
|
|
86
|
+
*/
|
|
87
|
+
static resetDefaults() {
|
|
88
|
+
projectDefaults = {};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Returns the built-in defaults merged with the project-wide ones.
|
|
93
|
+
* @returns {JsonTableParams}
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* JsonTable.getDefaults().tableWrapperClass; // → 'table-responsive'
|
|
97
|
+
*/
|
|
98
|
+
static getDefaults() {
|
|
99
|
+
return { ...defaults, ...projectDefaults };
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
constructor() {
|
|
104
|
+
super();
|
|
105
|
+
// light DOM: no attachShadow
|
|
106
|
+
|
|
107
|
+
/** @type {Partial<JsonTableParams>|null} config passed via init()/reload() */
|
|
108
|
+
this._config = null;
|
|
109
|
+
this._initCalledProgrammatically = false;
|
|
110
|
+
this._isConnected = false;
|
|
111
|
+
this._loadStarted = false;
|
|
112
|
+
/** incremented on every init()/reload()/destroy(): a pending _load() whose generation is stale gives up */
|
|
113
|
+
this._loadGeneration = 0;
|
|
114
|
+
|
|
115
|
+
/** Resolved params, available after the first load. @type {JsonTableParams|null} */
|
|
116
|
+
this.params = null;
|
|
117
|
+
|
|
118
|
+
/** Raw rows, available after the first load. @type {Array<Object>|null} */
|
|
119
|
+
this.data = null;
|
|
120
|
+
|
|
121
|
+
/** Generated elements, available after the first load. @type {JsonTableElements} */
|
|
122
|
+
this.elements = {};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
// ─── Lifecycle ──────────────────────────────────────────────────────────────
|
|
127
|
+
|
|
128
|
+
connectedCallback() {
|
|
129
|
+
this._isConnected = true;
|
|
130
|
+
if (!this._loadStarted) {
|
|
131
|
+
this._load();
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
disconnectedCallback() {
|
|
136
|
+
this._isConnected = false;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
// ─── Public API ─────────────────────────────────────────────────────────────
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Starts the component via script, passing the configuration as an object.
|
|
144
|
+
* Can be called before or after the element is attached to the DOM.
|
|
145
|
+
*
|
|
146
|
+
* Parameters not included in `config` are read from the corresponding HTML attribute
|
|
147
|
+
* (if present), then from the project defaults, then from the built-in defaults.
|
|
148
|
+
* To explicitly ignore an existing attribute pass `null` in the config.
|
|
149
|
+
*
|
|
150
|
+
* @param {Partial<JsonTableParams>} [config={}] - See `JsonTableParams` (default: {})
|
|
151
|
+
* @returns {void}
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* // <json-table caption="Utenti" search="false"></json-table>
|
|
155
|
+
* el.init({ jsonUrl: '/api/rows.json' }); // jsonUrl from script, caption and search from attributes
|
|
156
|
+
* el.init({ jsonUrl: '/api/rows.json', search: null }); // search → default (true), the attribute is ignored
|
|
157
|
+
*/
|
|
158
|
+
init(config = {}) {
|
|
159
|
+
this._config = config;
|
|
160
|
+
this._initCalledProgrammatically = true;
|
|
161
|
+
|
|
162
|
+
// an explicit init() must always restart, even if connectedCallback already
|
|
163
|
+
// ran a premature _load() (e.g. when domBuilder appends the element before init())
|
|
164
|
+
this._loadStarted = false;
|
|
165
|
+
this._loadGeneration++;
|
|
166
|
+
|
|
167
|
+
if (this._isConnected) {
|
|
168
|
+
this._load();
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Empties the component and resets its state. `init()` can be called again afterwards
|
|
174
|
+
* to re-initialize it with new params, without recreating the element.
|
|
175
|
+
* @returns {void}
|
|
176
|
+
*/
|
|
177
|
+
destroy() {
|
|
178
|
+
this._loadStarted = false;
|
|
179
|
+
this._loadGeneration++;
|
|
180
|
+
this.elements = {};
|
|
181
|
+
this.data = null;
|
|
182
|
+
this.innerHTML = '';
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Reloads the data and rebuilds the structure, optionally overriding some params
|
|
187
|
+
* (merged with the config passed to `init()`, if any).
|
|
188
|
+
*
|
|
189
|
+
* @param {Partial<JsonTableParams>} [overrides={}] - Params to override (default: {})
|
|
190
|
+
* @returns {Promise<void>}
|
|
191
|
+
*
|
|
192
|
+
* @example
|
|
193
|
+
* await el.reload(); // same source
|
|
194
|
+
* await el.reload({ jsonUrl: '/api/rows.json?y=2025' }); // new URL
|
|
195
|
+
* await el.reload({ data: [{ id: 1 }] }); // inline data (takes precedence over jsonUrl)
|
|
196
|
+
*/
|
|
197
|
+
async reload(overrides = {}) {
|
|
198
|
+
this._config = { ...(this._config ?? {}), ...overrides };
|
|
199
|
+
this._loadStarted = false;
|
|
200
|
+
this._loadGeneration++;
|
|
201
|
+
await this._load();
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
// ─── Load & build ───────────────────────────────────────────────────────────
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Resolves params, retrieves the data and builds the structure.
|
|
209
|
+
* Guarded against concurrent/stale calls via `_loadStarted` and `_loadGeneration`.
|
|
210
|
+
* @returns {Promise<void>}
|
|
211
|
+
*/
|
|
212
|
+
async _load() {
|
|
213
|
+
if (this._loadStarted) {
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
this._loadStarted = true;
|
|
217
|
+
const generation = this._loadGeneration;
|
|
218
|
+
|
|
219
|
+
const params = resolveParams(this, this._config, projectDefaults);
|
|
220
|
+
this.params = params;
|
|
221
|
+
|
|
222
|
+
// loading placeholder (minimo spinner)
|
|
223
|
+
this.innerHTML = '<div class="spinner"><span class="visually-hidden">Caricamento dati...</span></div>';
|
|
224
|
+
|
|
225
|
+
/** @type {Array<Object>|null} */
|
|
226
|
+
let rows = null;
|
|
227
|
+
let failed = false;
|
|
228
|
+
|
|
229
|
+
try {
|
|
230
|
+
rows = await getData(params);
|
|
231
|
+
} catch (err) {
|
|
232
|
+
failed = true;
|
|
233
|
+
// eslint-disable-next-line no-console
|
|
234
|
+
console.error(err);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// a newer init()/reload()/destroy() superseded this load
|
|
238
|
+
if (generation !== this._loadGeneration) {
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (failed) {
|
|
243
|
+
this.innerHTML = '';
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (rows === null) {
|
|
248
|
+
// no source: silent when created from markup without attributes (init() may follow)
|
|
249
|
+
if (this._initCalledProgrammatically) {
|
|
250
|
+
// eslint-disable-next-line no-console
|
|
251
|
+
console.error('[json-table] Nessuna sorgente dati: specificare `data` o `jsonUrl`.');
|
|
252
|
+
}
|
|
253
|
+
this.innerHTML = '';
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
this.data = rows;
|
|
258
|
+
this.elements = mainBuilder(this, params);
|
|
259
|
+
|
|
260
|
+
// TODO `shown` dovrà riflettere righe filtrate/paginate quando ricerca e paginazione saranno implementate
|
|
261
|
+
updateInfo(this.elements, params, rows.length, rows.length);
|
|
262
|
+
|
|
263
|
+
if (params.debug) {
|
|
264
|
+
/* eslint-disable no-console */
|
|
265
|
+
console.groupCollapsed('[json-table] params, data & elements', this);
|
|
266
|
+
console.log('params', params);
|
|
267
|
+
console.log('data', rows);
|
|
268
|
+
console.log('elements', this.elements);
|
|
269
|
+
console.groupEnd();
|
|
270
|
+
/* eslint-enable no-console */
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// dispatched in the next microtask so listeners registered right after init() still catch it
|
|
274
|
+
const event = new CustomEvent('jt:ready', { detail: { jsonTable: this }, bubbles: true });
|
|
275
|
+
Promise.resolve().then(() => this.dispatchEvent(event));
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
} // end component
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
if (!customElements.get('json-table')) {
|
|
282
|
+
customElements.define('json-table', JsonTable);
|
|
283
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/*! minimo - json-table */
|
|
2
|
+
|
|
3
|
+
/* Custom properties (`--jt-*`) are defined in `json-table.minimo.tokens.mjs`
|
|
4
|
+
and compiled into minimo's custom-properties.css by build-tokens */
|
|
5
|
+
|
|
6
|
+
/* purgecss start ignore */
|
|
7
|
+
|
|
8
|
+
json-table {
|
|
9
|
+
display: block;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.wrapper {
|
|
13
|
+
position: relative;
|
|
14
|
+
display: block;
|
|
15
|
+
margin-block: var(--jt-wrapper-margin-block);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.infoOuter {
|
|
19
|
+
padding-block-end: var(--jt-info-outer-padding-block-end);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.info {
|
|
23
|
+
display: flex;
|
|
24
|
+
flex-flow: column wrap;
|
|
25
|
+
gap: var(--jt-info-gap);
|
|
26
|
+
justify-content: stretch;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.resultInfo {
|
|
30
|
+
font-size: var(--jt-info-font-size);
|
|
31
|
+
color: var(--jt-info-color);
|
|
32
|
+
text-align: center;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
@media (--media-medium-viewport-up) {
|
|
36
|
+
.info {
|
|
37
|
+
flex-direction: row;
|
|
38
|
+
align-items: center;
|
|
39
|
+
justify-content: space-between;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.resultInfo {
|
|
43
|
+
flex: 1;
|
|
44
|
+
text-align: start;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.search {
|
|
48
|
+
flex: 0 1 var(--jt-search-max-width);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.table {
|
|
53
|
+
/* vertical spacing is handled by the wrapper */
|
|
54
|
+
margin-block: 0;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/* purgecss end ignore */
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
jt: {
|
|
3
|
+
wrapper: {
|
|
4
|
+
margin: {
|
|
5
|
+
block: {
|
|
6
|
+
$type: 'dimension',
|
|
7
|
+
$value: '{size.md}'
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
},
|
|
11
|
+
|
|
12
|
+
info: {
|
|
13
|
+
gap: {
|
|
14
|
+
$type: 'dimension',
|
|
15
|
+
$value: '{size.sm}'
|
|
16
|
+
},
|
|
17
|
+
font: {
|
|
18
|
+
size: {
|
|
19
|
+
$type: 'dimension',
|
|
20
|
+
$value: '{font.size.sm}'
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
color: {
|
|
24
|
+
$type: 'color',
|
|
25
|
+
$value: '{text.muted}'
|
|
26
|
+
},
|
|
27
|
+
outer: {
|
|
28
|
+
padding: {
|
|
29
|
+
block: {
|
|
30
|
+
end: {
|
|
31
|
+
$type: 'dimension',
|
|
32
|
+
$value: '{size.xs}'
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
search: {
|
|
40
|
+
max: {
|
|
41
|
+
width: {
|
|
42
|
+
$type: 'dimension',
|
|
43
|
+
$value: '20rem'
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
};
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
# `<json-table>` – tabelle HTML da dati JSON
|
|
2
|
+
|
|
3
|
+
> **Work in progress.** In questa fase il componente genera solo la **struttura esterna**
|
|
4
|
+
> (sezione info, input di ricerca, wrapper con `<table>` vuota e caption). Colonne (`cols`),
|
|
5
|
+
> rendering delle righe, ordinamento, ricerca e paginazione **non sono ancora implementati**.
|
|
6
|
+
> Il piano di sviluppo è in `src/web-components/TODO json-table/TODO.md`.
|
|
7
|
+
|
|
8
|
+
Sostituisce `s-datatable-component`: nessuna dipendenza esterna, custom element
|
|
9
|
+
light DOM (`<json-table>`).
|
|
10
|
+
|
|
11
|
+
## Installazione
|
|
12
|
+
|
|
13
|
+
Nessuna peer dependency. Basta importare il file del componente (registra il custom element):
|
|
14
|
+
|
|
15
|
+
```javascript
|
|
16
|
+
import '@massimo-cassandro/minimo/src/web-components/json-table/json-table-component.js';
|
|
17
|
+
// oppure, se serve la classe (es. per setDefaults):
|
|
18
|
+
import { JsonTable } from '@massimo-cassandro/minimo/src/web-components/json-table/json-table-component.js';
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Il CSS (`json-table-component.module.css`) è importato dal componente stesso; le custom
|
|
22
|
+
properties `--jt-*` sono definite in `json-table.minimo.tokens.mjs` e compilate in
|
|
23
|
+
`custom-properties.css` da `build-tokens`.
|
|
24
|
+
|
|
25
|
+
## Utilizzo da markup
|
|
26
|
+
|
|
27
|
+
```html
|
|
28
|
+
<json-table
|
|
29
|
+
jsonurl="/api/rows.json"
|
|
30
|
+
caption="Utenti"
|
|
31
|
+
></json-table>
|
|
32
|
+
|
|
33
|
+
<!-- dati inline (JSON serializzato, utile in contesti SSR: Twig, Blade, ...) -->
|
|
34
|
+
<json-table
|
|
35
|
+
data='[{"name":"Mario","city":"Roma"}, ...]'
|
|
36
|
+
search="false"
|
|
37
|
+
></json-table>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
I nomi degli attributi sono case-insensitive (`jsonurl` e `jsonUrl` sono equivalenti).
|
|
41
|
+
Gli attributi booleani accettano i formati HTML idiomatici: `search` (presente senza valore),
|
|
42
|
+
`search="true"`, `search="1"` → true; `search="false"`, `search="0"` → false.
|
|
43
|
+
I valori che iniziano con `[` o `{` vengono interpretati come JSON (un JSON malformato viene
|
|
44
|
+
segnalato in console e ignorato).
|
|
45
|
+
|
|
46
|
+
## Utilizzo da script
|
|
47
|
+
|
|
48
|
+
```javascript
|
|
49
|
+
const el = document.querySelector('json-table');
|
|
50
|
+
// oppure: const el = document.createElement('json-table');
|
|
51
|
+
|
|
52
|
+
el.init({
|
|
53
|
+
jsonUrl: '/api/rows.json',
|
|
54
|
+
caption: 'Utenti'
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// dati inline al posto di jsonUrl (se presenti entrambi, `data` prevale)
|
|
58
|
+
el.init({
|
|
59
|
+
data: [{ name: 'Mario', city: 'Roma' }, ...]
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// se appena creato, appendere dopo init():
|
|
63
|
+
document.body.appendChild(el);
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Con `domBuilder`
|
|
67
|
+
|
|
68
|
+
```javascript
|
|
69
|
+
domBuilder([
|
|
70
|
+
{
|
|
71
|
+
tag: 'json-table',
|
|
72
|
+
attrs: { caption: 'Utenti' },
|
|
73
|
+
callback: el => el.init({ jsonUrl: '/api/rows.json' })
|
|
74
|
+
}
|
|
75
|
+
], container);
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Utilizzo misto – attributi HTML + script
|
|
79
|
+
|
|
80
|
+
I parametri non inclusi in `init()` vengono letti dall'attributo HTML corrispondente:
|
|
81
|
+
|
|
82
|
+
```html
|
|
83
|
+
<json-table caption="Utenti" search="false"></json-table>
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
```javascript
|
|
87
|
+
el.init({ jsonUrl: '/api/rows.json' }); // jsonUrl da script, caption e search da attributo
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**Ordine di precedenza:** `init()` > attributo HTML > `JsonTable.setDefaults()` > default interno.
|
|
91
|
+
|
|
92
|
+
Per ignorare esplicitamente un attributo e ricadere sui default, passare `null` nel config:
|
|
93
|
+
|
|
94
|
+
```javascript
|
|
95
|
+
el.init({ jsonUrl: '/api/rows.json', search: null }); // search → default (true)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Default di progetto – `JsonTable.setDefaults()`
|
|
99
|
+
|
|
100
|
+
Imposta valori validi per tutte le istanze create successivamente, evitando di ripetere gli
|
|
101
|
+
stessi parametri. Da invocare una sola volta, in uno script condiviso eseguito prima degli altri.
|
|
102
|
+
I valori vengono uniti a quelli impostati in chiamate precedenti.
|
|
103
|
+
|
|
104
|
+
```javascript
|
|
105
|
+
import { JsonTable } from '.../json-table-component.js';
|
|
106
|
+
|
|
107
|
+
JsonTable.setDefaults({
|
|
108
|
+
searchInputClass: 'form-control form-control-sm',
|
|
109
|
+
tableClass: 'table',
|
|
110
|
+
infoText: (shown, total) => `${shown} di ${total} record`
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
JsonTable.getDefaults(); // default interni + default di progetto
|
|
114
|
+
JsonTable.resetDefaults(); // azzera i default di progetto
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## API dell'istanza
|
|
118
|
+
|
|
119
|
+
| Metodo | Descrizione |
|
|
120
|
+
|---|---|
|
|
121
|
+
| `init(config)` | Avvia il componente (prima o dopo l'inserimento nel DOM) |
|
|
122
|
+
| `reload(overrides)` | Ricarica i dati e ricostruisce la struttura, con eventuali parametri sovrascritti (`Promise`) |
|
|
123
|
+
| `destroy()` | Svuota il componente; `init()` può essere richiamato in seguito |
|
|
124
|
+
|
|
125
|
+
Proprietà disponibili dopo il caricamento: `params` (parametri risolti), `data` (righe grezze),
|
|
126
|
+
`elements` (elementi generati: `wrapper`, `infoOuter`, `info`, `resultInfo`, `searchInput`,
|
|
127
|
+
`tableWrapper`, `table`).
|
|
128
|
+
|
|
129
|
+
```javascript
|
|
130
|
+
await el.reload({ jsonUrl: '/api/rows.json?anno=2025' });
|
|
131
|
+
await el.reload({ data: [...] });
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Evento `jt:ready`
|
|
135
|
+
|
|
136
|
+
Emesso sull'elemento (con `bubbles`) al termine della costruzione; `event.detail.jsonTable`
|
|
137
|
+
è l'istanza. Viene emesso nel microtask successivo, quindi un listener registrato subito dopo
|
|
138
|
+
`init()` lo intercetta comunque.
|
|
139
|
+
|
|
140
|
+
```javascript
|
|
141
|
+
el.addEventListener('jt:ready', e => {
|
|
142
|
+
console.log(e.detail.jsonTable.data);
|
|
143
|
+
});
|
|
144
|
+
el.init({ jsonUrl: '/api/rows.json' });
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Parametri
|
|
148
|
+
|
|
149
|
+
Tutti i parametri sono impostabili sia da attributo HTML che da `init()`. I valori di tipo
|
|
150
|
+
funzione (`caption`, `infoText`) solo da `init()`.
|
|
151
|
+
|
|
152
|
+
```javascript
|
|
153
|
+
{
|
|
154
|
+
debug, // boolean – log in console di parametri, dati ed elementi generati.
|
|
155
|
+
// Default: false
|
|
156
|
+
|
|
157
|
+
jsonUrl, // string – URL del JSON da caricare. Ignorato se `data` è presente.
|
|
158
|
+
// Default: null
|
|
159
|
+
|
|
160
|
+
jsonDataField, // string|null – chiave del JSON che contiene l'array delle righe
|
|
161
|
+
// (es. 'data' per { data: [...] }); null o '' = la root del JSON è
|
|
162
|
+
// l'array stesso. Default: 'data'
|
|
163
|
+
|
|
164
|
+
data, // Array<Object> – righe inline; prevale su `jsonUrl`. Da attributo va
|
|
165
|
+
// passato come stringa JSON ed è sempre inteso come array delle righe
|
|
166
|
+
// (`jsonDataField` ignorato). Default: null
|
|
167
|
+
|
|
168
|
+
caption, // string|Function – caption della tabella (testo o HTML), oppure
|
|
169
|
+
// funzione che restituisce stringa o Node. Default: null
|
|
170
|
+
|
|
171
|
+
search, // boolean – genera l'input di ricerca. Default: true
|
|
172
|
+
searchInputClass, // string – classi dell'input di ricerca (sostituisce il default).
|
|
173
|
+
// Default: 'form-control'
|
|
174
|
+
searchInputTitle, // string – attributo title dell'input.
|
|
175
|
+
// Default: 'Filtra record: inserisci un termine per eseguire la ricerca'
|
|
176
|
+
searchInputPlaceholder, // string – placeholder dell'input.
|
|
177
|
+
// Default: 'Inserisci il termine da cercare'
|
|
178
|
+
searchInputAriaLabel, // string – aria-label dell'input. Default: 'Filtra risultati'
|
|
179
|
+
|
|
180
|
+
tableId, // string – id del tag <table>. Default: null
|
|
181
|
+
tableWrapperClass, // string – classi del div che racchiude la tabella (sostituisce il
|
|
182
|
+
// default). Default: 'table-responsive'
|
|
183
|
+
tableClass, // string – classi del tag <table> (sostituisce il default).
|
|
184
|
+
// Default: 'table table-bordered'
|
|
185
|
+
|
|
186
|
+
mainWrapperExtraClass, // string – classi aggiuntive per il contenitore principale
|
|
187
|
+
// (info + tabella). Default: null
|
|
188
|
+
outerInfoExtraClass, // string – classi aggiuntive per il contenitore esterno della
|
|
189
|
+
// sezione info. Default: null
|
|
190
|
+
infoExtraClass, // string – classi aggiuntive per la sezione info. Default: null
|
|
191
|
+
|
|
192
|
+
infoText, // (shown, total) => string|Node – testo dell'area info (testo,
|
|
193
|
+
// stringa HTML o Node).
|
|
194
|
+
// Default: "Visualizzate N righe su M" / "Nessun record"
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
I parametri `*ExtraClass` si **aggiungono** alle classi interne di layout; i parametri
|
|
199
|
+
`*Class` (`searchInputClass`, `tableWrapperClass`, `tableClass`) **sostituiscono** interamente
|
|
200
|
+
il valore di default, ferme restando le eventuali classi interne di layout del componente.
|
|
201
|
+
|
|
202
|
+
### In sviluppo
|
|
203
|
+
|
|
204
|
+
`cols`, data-types, `locale` e opzioni di formattazione, icone (booleani e ordinamento),
|
|
205
|
+
ordinamento, ricerca, paginazione, `trCallback`, `footerRender`, `refs`: vedi il TODO del componente.
|
|
206
|
+
|
|
207
|
+
## Struttura generata
|
|
208
|
+
|
|
209
|
+
```html
|
|
210
|
+
<json-table>
|
|
211
|
+
<section class="[wrapper] [mainWrapperExtraClass]">
|
|
212
|
+
<div class="[infoOuter] [outerInfoExtraClass]">
|
|
213
|
+
<div class="[info] [infoExtraClass]">
|
|
214
|
+
<div class="[resultInfo]" aria-live="polite">Visualizzate <strong>N</strong> righe su <strong>M</strong></div>
|
|
215
|
+
<div class="[search]"> <!-- solo se search: true -->
|
|
216
|
+
<input type="search" class="form-control" ...>
|
|
217
|
+
</div>
|
|
218
|
+
</div>
|
|
219
|
+
</div>
|
|
220
|
+
<div class="table-responsive"> <!-- tableWrapperClass -->
|
|
221
|
+
<table class="[table] table table-bordered"> <!-- tableClass -->
|
|
222
|
+
<caption>...</caption> <!-- solo se caption -->
|
|
223
|
+
<!-- thead / tbody / tfoot: in sviluppo -->
|
|
224
|
+
</table>
|
|
225
|
+
</div>
|
|
226
|
+
</section>
|
|
227
|
+
</json-table>
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
Le classi tra parentesi quadre sono quelle interne del CSS module.
|
|
231
|
+
|
|
232
|
+
## Custom properties CSS
|
|
233
|
+
|
|
234
|
+
Definite in `json-table.minimo.tokens.mjs` (namespace `--jt-*`):
|
|
235
|
+
|
|
236
|
+
| Proprietà | Default (token minimo) |
|
|
237
|
+
|---|---|
|
|
238
|
+
| `--jt-wrapper-margin-block` | `{size.md}` |
|
|
239
|
+
| `--jt-info-gap` | `{size.sm}` |
|
|
240
|
+
| `--jt-info-font-size` | `{font.size.sm}` |
|
|
241
|
+
| `--jt-info-color` | `{text.muted}` |
|
|
242
|
+
| `--jt-info-outer-padding-block-end` | `{size.xs}` |
|
|
243
|
+
| `--jt-search-max-width` | `20rem` |
|