@jsswift/ui 1.0.45 → 1.0.47
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/dist/min-ui.js +4 -4
- package/dist/ui.js +10562 -14121
- package/dist/ui.min.js +4 -4
- package/package.json +2 -2
- package/src/01-foundation-helpers.js +0 -402
- package/src/10-primitives-layout.js +15 -1014
- package/src/20-display-content.js +484 -718
- package/src/21-list-content.js +246 -341
- package/src/22-banner-content.js +3 -116
- package/src/23-tooltip.js +276 -326
- package/src/31-form-advanced.js +2638 -3003
- package/src/40-navigation.js +1262 -1454
- package/src/41-tab-panel.js +896 -1090
- package/src/50-feedback.js +999 -1209
- package/src/60-shell-app.js +5 -265
- package/src/61-form-service.js +304 -386
- package/src/70-dialog.js +209 -277
- package/src/71-menu-overlays.js +1175 -1400
- package/src/80-data.js +433 -503
- package/src/modules.json +59 -23
|
@@ -1,48 +1,48 @@
|
|
|
1
1
|
UI.Icon = (...args) => {
|
|
2
|
-
let props = {};
|
|
3
|
-
let children = [];
|
|
4
|
-
let name = "home";
|
|
5
|
-
let hasName = false;
|
|
6
|
-
const a = args[0];
|
|
7
|
-
const b = args[1];
|
|
8
|
-
const isPlainObject = (v) => v && typeof v === "object" && !v.nodeType && !Array.isArray(v) && !(v instanceof Function);
|
|
9
|
-
|
|
10
|
-
if (typeof a === "string") {
|
|
11
|
-
name = a;
|
|
12
|
-
hasName = true;
|
|
13
|
-
if (isPlainObject(b)) {
|
|
14
|
-
props = b;
|
|
15
|
-
if (args.length > 2) children = args.slice(2);
|
|
16
|
-
} else if (args.length > 1) {
|
|
17
|
-
children = args.slice(1);
|
|
18
|
-
}
|
|
19
|
-
} else if (isPlainObject(a)) {
|
|
20
|
-
props = a;
|
|
21
|
-
if (a.name != null) {
|
|
22
|
-
name = a.name;
|
|
23
|
-
hasName = true;
|
|
24
|
-
}
|
|
25
|
-
if (args.length > 1) children = args.slice(1);
|
|
26
|
-
} else if (args.length) {
|
|
27
|
-
children = args;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
if (!hasName && children.length) {
|
|
31
|
-
name = children.length === 1 ? children[0] : children;
|
|
32
|
-
}
|
|
33
|
-
applyCommonProps(props);
|
|
34
|
-
|
|
35
|
-
const slots = props.slots || {};
|
|
36
|
-
|
|
37
|
-
const size = uiUnwrap(props.size);
|
|
38
|
-
const color = uiUnwrap(props.color);
|
|
39
|
-
const isFill = String(name).endsWith("-fill");
|
|
40
|
-
const style = { ...(props.style || {}) };
|
|
41
|
-
const sizeClass = uiComputed(props.size, () => {
|
|
42
|
-
const v = uiUnwrap(props.size);
|
|
43
|
-
return (typeof v === "string" && sizeMap[v]) ? v : "";
|
|
44
|
-
});
|
|
45
|
-
|
|
2
|
+
let props = {};
|
|
3
|
+
let children = [];
|
|
4
|
+
let name = "home";
|
|
5
|
+
let hasName = false;
|
|
6
|
+
const a = args[0];
|
|
7
|
+
const b = args[1];
|
|
8
|
+
const isPlainObject = (v) => v && typeof v === "object" && !v.nodeType && !Array.isArray(v) && !(v instanceof Function);
|
|
9
|
+
|
|
10
|
+
if (typeof a === "string") {
|
|
11
|
+
name = a;
|
|
12
|
+
hasName = true;
|
|
13
|
+
if (isPlainObject(b)) {
|
|
14
|
+
props = b;
|
|
15
|
+
if (args.length > 2) children = args.slice(2);
|
|
16
|
+
} else if (args.length > 1) {
|
|
17
|
+
children = args.slice(1);
|
|
18
|
+
}
|
|
19
|
+
} else if (isPlainObject(a)) {
|
|
20
|
+
props = a;
|
|
21
|
+
if (a.name != null) {
|
|
22
|
+
name = a.name;
|
|
23
|
+
hasName = true;
|
|
24
|
+
}
|
|
25
|
+
if (args.length > 1) children = args.slice(1);
|
|
26
|
+
} else if (args.length) {
|
|
27
|
+
children = args;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (!hasName && children.length) {
|
|
31
|
+
name = children.length === 1 ? children[0] : children;
|
|
32
|
+
}
|
|
33
|
+
applyCommonProps(props);
|
|
34
|
+
|
|
35
|
+
const slots = props.slots || {};
|
|
36
|
+
|
|
37
|
+
const size = uiUnwrap(props.size);
|
|
38
|
+
const color = uiUnwrap(props.color);
|
|
39
|
+
const isFill = String(name).endsWith("-fill");
|
|
40
|
+
const style = { ...(props.style || {}) };
|
|
41
|
+
const sizeClass = uiComputed(props.size, () => {
|
|
42
|
+
const v = uiUnwrap(props.size);
|
|
43
|
+
return (typeof v === "string" && sizeMap[v]) ? v : "";
|
|
44
|
+
});
|
|
45
|
+
|
|
46
46
|
const hasVisualSurface = !!(props.color || props.clickable || props.border || props.glossy || props.glow || props.glass || props.shadow || props.outline || props.gradient || props.textGradient || props.lightShadow || props.radius);
|
|
47
47
|
const builtInSpriteIcons = {
|
|
48
48
|
"chevron-down": {
|
|
@@ -86,7 +86,7 @@
|
|
|
86
86
|
setPropertyProps(icon, props);
|
|
87
87
|
return wrapIcon(icon);
|
|
88
88
|
}
|
|
89
|
-
|
|
89
|
+
|
|
90
90
|
const nameStr = String(name);
|
|
91
91
|
const useHref = nameStr.includes("#") ? nameStr : "";
|
|
92
92
|
let icon = null;
|
|
@@ -107,422 +107,351 @@
|
|
|
107
107
|
);
|
|
108
108
|
if (isFill) svg.style.fill = "currentColor";
|
|
109
109
|
icon = _.span({ ...p, "data-icon": nameStr }, svg, ...children);
|
|
110
|
-
} else {
|
|
111
|
-
icon = _.span({ ...p, "data-icon": nameStr }, nameStr, ...children);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
if (size != null) {
|
|
115
|
-
let v = size;
|
|
116
|
-
if (JSswift.uiSizes.includes(size)) {
|
|
117
|
-
v = `var(--cms-icon-size-${size})`;
|
|
118
|
-
}
|
|
119
|
-
v = typeof v === "number" ? v + "px" : String(v);
|
|
120
|
-
icon.style.setProperty("--set-icon-size", v);
|
|
121
|
-
}
|
|
110
|
+
} else {
|
|
111
|
+
icon = _.span({ ...p, "data-icon": nameStr }, nameStr, ...children);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (size != null) {
|
|
115
|
+
let v = size;
|
|
116
|
+
if (JSswift.uiSizes.includes(size)) {
|
|
117
|
+
v = `var(--cms-icon-size-${size})`;
|
|
118
|
+
}
|
|
119
|
+
v = typeof v === "number" ? v + "px" : String(v);
|
|
120
|
+
icon.style.setProperty("--set-icon-size", v);
|
|
121
|
+
}
|
|
122
122
|
|
|
123
123
|
setPropertyProps(icon, props);
|
|
124
124
|
return wrapIcon(icon);
|
|
125
125
|
};
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
const
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
"
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
"
|
|
187
|
-
"
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
);
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
if (
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
.
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
const
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
const
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
if (
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
if (
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
if (
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
return
|
|
403
|
-
});
|
|
404
|
-
const
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
const
|
|
430
|
-
const
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
const
|
|
441
|
-
|
|
442
|
-
:
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
if (radiusStyle != null) style["--set-border-radius"] = radiusStyle;
|
|
456
|
-
p.style = style;
|
|
457
|
-
|
|
458
|
-
const ctx = { props };
|
|
459
|
-
const altText = uiComputed([props.alt, props.label, props.name, props.text], () => {
|
|
460
|
-
const raw = uiUnwrap(props.alt) || uiUnwrap(props.label) || uiUnwrap(props.name) || uiUnwrap(props.text) || "avatar";
|
|
461
|
-
return String(raw);
|
|
462
|
-
});
|
|
463
|
-
const iconFallback = props.icon != null
|
|
464
|
-
? (typeof props.icon === "string"
|
|
465
|
-
? UI.Icon({ name: props.icon, size: props.iconSize || props.size || "sm" })
|
|
466
|
-
: JSswift.ui.slot(props.icon, { as: "icon" }))
|
|
467
|
-
: null;
|
|
468
|
-
const labelFallback = uiComputed([props.initials, props.text, props.label, props.name], () => {
|
|
469
|
-
const explicit = uiUnwrap(props.initials) ?? uiUnwrap(props.text);
|
|
470
|
-
if (explicit != null) return explicit;
|
|
471
|
-
const rawLabel = uiUnwrap(props.label) ?? uiUnwrap(props.name);
|
|
472
|
-
if (typeof rawLabel === "string") return avatarGetInitials(rawLabel);
|
|
473
|
-
return rawLabel;
|
|
474
|
-
});
|
|
475
|
-
const badgeFallback = avatarPrimitiveBadge(uiUnwrap(props.badge ?? props.notification));
|
|
476
|
-
const statusFallback = avatarPrimitiveStatus(
|
|
477
|
-
uiUnwrap(props.status ?? props.presence),
|
|
478
|
-
uiUnwrap(props.statusColor)
|
|
479
|
-
);
|
|
480
|
-
|
|
481
|
-
let mediaNodes = renderSlotToArray(slots, "media", ctx, props.media);
|
|
482
|
-
if (!mediaNodes.length && props.src) {
|
|
483
|
-
const imgProps = {
|
|
484
|
-
class: "cms-avatar-img",
|
|
485
|
-
src: props.src,
|
|
486
|
-
alt: altText,
|
|
487
|
-
sizes: props.sizes,
|
|
488
|
-
style: {}
|
|
489
|
-
};
|
|
490
|
-
if (props.srcset != null) imgProps.srcset = props.srcset;
|
|
491
|
-
if (props.srcSet != null) imgProps.srcset = props.srcSet;
|
|
492
|
-
const fitStyle = uiStyleValue(props.fit);
|
|
493
|
-
if (fitStyle != null) imgProps.style.objectFit = fitStyle;
|
|
494
|
-
mediaNodes = [_.img(imgProps)];
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
const defaultNodes = renderSlotToArray(slots, "default", ctx, children);
|
|
498
|
-
const fallbackNodes = renderSlotToArray(slots, "fallback", ctx, null);
|
|
499
|
-
const labelNodes = renderSlotToArray(slots, "label", ctx, labelFallback);
|
|
500
|
-
const iconNodes = renderSlotToArray(slots, "icon", ctx, iconFallback);
|
|
501
|
-
const mainNodes = mediaNodes.length
|
|
502
|
-
? mediaNodes
|
|
503
|
-
: (defaultNodes.length
|
|
504
|
-
? defaultNodes
|
|
505
|
-
: (fallbackNodes.length
|
|
506
|
-
? fallbackNodes
|
|
507
|
-
: (labelNodes.length
|
|
508
|
-
? labelNodes
|
|
509
|
-
: (iconNodes.length ? iconNodes : ["?"]))));
|
|
510
|
-
|
|
511
|
-
const bodyClass = mediaNodes.length ? "cms-avatar-media" : "cms-avatar-fallback";
|
|
512
|
-
const body = _.span({ class: "cms-avatar-body" },
|
|
513
|
-
_.span({ class: bodyClass }, ...mainNodes)
|
|
514
|
-
);
|
|
515
|
-
|
|
516
|
-
let topLeftNodes = renderSlotToArray(slots, "topLeft", ctx, props.topLeft);
|
|
517
|
-
let topRightNodes = renderSlotToArray(slots, "topRight", ctx, props.topRight);
|
|
518
|
-
let bottomLeftNodes = renderSlotToArray(slots, "bottomLeft", ctx, props.bottomLeft);
|
|
519
|
-
let bottomRightNodes = renderSlotToArray(slots, "bottomRight", ctx, props.bottomRight);
|
|
520
|
-
const badgeNodes = renderSlotToArray(slots, "badge", ctx, badgeFallback);
|
|
521
|
-
const statusNodes = renderSlotToArray(slots, "status", ctx, statusFallback);
|
|
522
|
-
|
|
523
|
-
if (!topRightNodes.length && badgeNodes.length) topRightNodes = badgeNodes;
|
|
524
|
-
if (!bottomRightNodes.length && statusNodes.length) bottomRightNodes = statusNodes;
|
|
525
|
-
|
|
126
|
+
|
|
127
|
+
// Esempio: JSswift.ui.Icon({ name: "home", size: 18 })
|
|
128
|
+
|
|
129
|
+
UI.Badge = (...args) => {
|
|
130
|
+
const { props, children } = JSswift.uiNormalizeArgs(args);
|
|
131
|
+
const slots = props.slots || {};
|
|
132
|
+
const sizeClass = uiComputed(props.size, () => {
|
|
133
|
+
const v = uiUnwrap(props.size);
|
|
134
|
+
return (typeof v === "string" && sizeMap[v]) ? `cms-size-${v}` : "";
|
|
135
|
+
});
|
|
136
|
+
const cls = uiClass([
|
|
137
|
+
"cms-clear-set",
|
|
138
|
+
"cms-badge",
|
|
139
|
+
"cms-singularity",
|
|
140
|
+
sizeClass,
|
|
141
|
+
uiWhen(props.outline, "outline"),
|
|
142
|
+
props.class
|
|
143
|
+
]);
|
|
144
|
+
const p = JSswift.omit(props, [
|
|
145
|
+
"label",
|
|
146
|
+
"color",
|
|
147
|
+
"outline",
|
|
148
|
+
"size",
|
|
149
|
+
"slots",
|
|
150
|
+
"notification",
|
|
151
|
+
"iconSize",
|
|
152
|
+
"topLeft",
|
|
153
|
+
"topRight",
|
|
154
|
+
"bottomLeft",
|
|
155
|
+
"bottomRight",
|
|
156
|
+
"left",
|
|
157
|
+
"right"
|
|
158
|
+
]);
|
|
159
|
+
p.class = cls;
|
|
160
|
+
|
|
161
|
+
const style = {
|
|
162
|
+
...(props.style || {})
|
|
163
|
+
};
|
|
164
|
+
if (props.size) {
|
|
165
|
+
const size = uiUnwrap(props.size);
|
|
166
|
+
if (!(typeof size === "string" && sizeMap[size])) {
|
|
167
|
+
style.fontSize = toCssSize(props.size);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
p.style = style;
|
|
171
|
+
|
|
172
|
+
const renderNamedSlotToArray = (names, ctx, fallback) => {
|
|
173
|
+
const list = Array.isArray(names) ? names : [names];
|
|
174
|
+
for (const name of list) {
|
|
175
|
+
if (JSswift.ui.getSlot(slots, name) != null) {
|
|
176
|
+
return renderSlotToArray(slots, name, ctx, fallback);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return fallback == null || fallback === false || fallback === ""
|
|
180
|
+
? []
|
|
181
|
+
: renderSlotToArray(null, "default", ctx, fallback);
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
const resolveIconSize = () => {
|
|
185
|
+
const raw = uiUnwrap(props.iconSize ?? props.size);
|
|
186
|
+
if (typeof raw === "number") return Math.max(10, Math.round(raw * 0.85));
|
|
187
|
+
if (typeof raw === "string") {
|
|
188
|
+
const map = {
|
|
189
|
+
xxs: 10,
|
|
190
|
+
xs: 11,
|
|
191
|
+
sm: 12,
|
|
192
|
+
md: 13,
|
|
193
|
+
lg: 14,
|
|
194
|
+
xl: 16,
|
|
195
|
+
xxl: 18,
|
|
196
|
+
xxxl: 20
|
|
197
|
+
};
|
|
198
|
+
return map[raw] || 14;
|
|
199
|
+
}
|
|
200
|
+
return 14;
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
const resolveIconFallback = (source, as) => {
|
|
204
|
+
const raw = uiUnwrap(source);
|
|
205
|
+
if (raw == null || raw === false || raw === "") return null;
|
|
206
|
+
if (typeof raw === "string") return UI.Icon({ name: raw, size: resolveIconSize() });
|
|
207
|
+
return JSswift.ui.slot(raw, { as });
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
const renderIconAnchor = (slotNames, propKey, position) => _.dynamic(() => {
|
|
211
|
+
const iconFallback = resolveIconFallback(props[propKey], position);
|
|
212
|
+
const nodes = renderNamedSlotToArray(slotNames, { position }, iconFallback);
|
|
213
|
+
if (!nodes.length) return null;
|
|
214
|
+
return _.span({
|
|
215
|
+
class: `cms-badge-anchor cms-badge-anchor-${position}`,
|
|
216
|
+
"data-badge-slot": position
|
|
217
|
+
}, ...nodes);
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
const content = _.dynamic(() => {
|
|
221
|
+
const labelFallback = uiUnwrap(props.label);
|
|
222
|
+
let labelNodes = renderNamedSlotToArray(["label"], {}, labelFallback);
|
|
223
|
+
if (!labelNodes.length) labelNodes = renderNamedSlotToArray(["default"], {}, children);
|
|
224
|
+
return _.span(
|
|
225
|
+
{ class: "cms-badge-content" },
|
|
226
|
+
_.span({ class: "cms-badge-label" }, ...(labelNodes.length ? labelNodes : [""]))
|
|
227
|
+
);
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
const notification = _.dynamic(() => {
|
|
231
|
+
const rawNotification = uiUnwrap(props.notification);
|
|
232
|
+
const fallback = rawNotification == null || rawNotification === false || rawNotification === ""
|
|
233
|
+
? null
|
|
234
|
+
: rawNotification;
|
|
235
|
+
const nodes = renderNamedSlotToArray(["notification"], { notification: rawNotification }, fallback);
|
|
236
|
+
if (!nodes.length) return null;
|
|
237
|
+
return _.span({
|
|
238
|
+
class: "cms-badge-notification",
|
|
239
|
+
"data-badge-slot": "notification",
|
|
240
|
+
"aria-label": typeof rawNotification === "number" ? `${rawNotification} notifications` : null
|
|
241
|
+
}, ...nodes);
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
const wrap = _.span(
|
|
245
|
+
renderIconAnchor(["left"], "left", "left"),
|
|
246
|
+
renderIconAnchor(["centerLeft", "center-left"], "centerLeft", "center-left"),
|
|
247
|
+
p,
|
|
248
|
+
content,
|
|
249
|
+
renderIconAnchor(["topLeft", "top-left"], "topLeft", "top-left"),
|
|
250
|
+
renderIconAnchor(["topRight", "top-right"], "topRight", "top-right"),
|
|
251
|
+
renderIconAnchor(["bottomLeft", "bottom-left"], "bottomLeft", "bottom-left"),
|
|
252
|
+
renderIconAnchor(["bottomRight", "bottom-right"], "bottomRight", "bottom-right"),
|
|
253
|
+
renderIconAnchor(["centerRight", "center-right"], "centerRight", "center-right"),
|
|
254
|
+
renderIconAnchor(["right"], "right", "right"),
|
|
255
|
+
notification
|
|
256
|
+
);
|
|
257
|
+
// se esiste un props con left o right
|
|
258
|
+
if (props.topLeft || props.centerLeft || props.bottomLeft) {
|
|
259
|
+
wrap.style.setProperty("padding-left", "15px");
|
|
260
|
+
}
|
|
261
|
+
if (props.topRight || props.centerRight || props.bottomRight) {
|
|
262
|
+
wrap.style.setProperty("padding-right", "15px");
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
setPropertyProps(wrap, props);
|
|
266
|
+
return wrap;
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
// Esempio: JSswift.ui.Badge({ label: "New" })
|
|
270
|
+
|
|
271
|
+
const avatarGetInitials = (value) => {
|
|
272
|
+
if (value == null || value === false) return "";
|
|
273
|
+
const text = String(value)
|
|
274
|
+
.replace(/[._-]+/g, " ")
|
|
275
|
+
.replace(/\s+/g, " ")
|
|
276
|
+
.trim();
|
|
277
|
+
if (!text) return "";
|
|
278
|
+
const words = text.split(" ").filter(Boolean);
|
|
279
|
+
if (!words.length) return "";
|
|
280
|
+
if (words.length === 1) {
|
|
281
|
+
const token = words[0].replace(/[^a-z0-9]/gi, "");
|
|
282
|
+
return token.slice(0, 2).toUpperCase();
|
|
283
|
+
}
|
|
284
|
+
return words.slice(0, 2).map((part) => part.charAt(0).toUpperCase()).join("");
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
const avatarStatusState = (value, fallback) => {
|
|
288
|
+
const raw = value == null || value === true ? fallback : value;
|
|
289
|
+
if (raw == null || raw === false) return normalizeState(fallback);
|
|
290
|
+
const token = String(raw).toLowerCase();
|
|
291
|
+
if (token === "online" || token === "available" || token === "active") return "success";
|
|
292
|
+
if (token === "away" || token === "pending") return "warning";
|
|
293
|
+
if (token === "busy" || token === "dnd" || token === "blocked") return "danger";
|
|
294
|
+
if (token === "offline" || token === "idle") return "secondary";
|
|
295
|
+
return normalizeState(token) || normalizeState(fallback);
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
const avatarPrimitiveBadge = (value, className = "cms-avatar-badge") => {
|
|
299
|
+
if (value == null || value === false) return null;
|
|
300
|
+
if (value instanceof Node || Array.isArray(value)) return value;
|
|
301
|
+
if (typeof value === "function") return value;
|
|
302
|
+
if (value === true) return _.span({ class: className });
|
|
303
|
+
return _.span({ class: className }, String(value));
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
const avatarPrimitiveStatus = (value, color) => {
|
|
307
|
+
if (value == null || value === false) {
|
|
308
|
+
if (!color) return null;
|
|
309
|
+
const fallbackState = avatarStatusState(null, color);
|
|
310
|
+
return _.span({ class: uiClass(["cms-avatar-status", fallbackState ? `cms-state-${fallbackState}` : ""]) });
|
|
311
|
+
}
|
|
312
|
+
if (value instanceof Node || Array.isArray(value)) return value;
|
|
313
|
+
if (typeof value === "function") return value;
|
|
314
|
+
const state = avatarStatusState(value, color);
|
|
315
|
+
if (value === true || state) {
|
|
316
|
+
return _.span({ class: uiClass(["cms-avatar-status", state ? `cms-state-${state}` : ""]) });
|
|
317
|
+
}
|
|
318
|
+
return avatarPrimitiveBadge(value, "cms-avatar-badge");
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
const avatarRenderAnchor = (className, nodes) => {
|
|
322
|
+
if (!nodes || !nodes.length) return null;
|
|
323
|
+
return _.span({ class: uiClass(["cms-avatar-anchor", className]) }, ...nodes);
|
|
324
|
+
};
|
|
325
|
+
|
|
326
|
+
UI.Avatar = (...args) => {
|
|
327
|
+
const { props, children } = JSswift.uiNormalizeArgs(args);
|
|
328
|
+
const slots = props.slots || {};
|
|
329
|
+
const sizeClass = uiComputed(props.size, () => {
|
|
330
|
+
const v = uiUnwrap(props.size);
|
|
331
|
+
return (typeof v === "string" && JSswift.uiSizes?.includes(v)) ? `cms-size-${v}` : "";
|
|
332
|
+
});
|
|
333
|
+
const stateClass = uiComputed([props.color, props.state], () => {
|
|
334
|
+
const v = uiUnwrap(props.color) || uiUnwrap(props.state) || "";
|
|
335
|
+
const state = normalizeState(v);
|
|
336
|
+
return state ? `cms-state-${state}` : "";
|
|
337
|
+
});
|
|
338
|
+
const cls = uiClass([
|
|
339
|
+
"cms-clear-set",
|
|
340
|
+
"cms-avatar",
|
|
341
|
+
"cms-singularity",
|
|
342
|
+
sizeClass,
|
|
343
|
+
stateClass,
|
|
344
|
+
uiWhen(props.square, "cms-avatar-square"),
|
|
345
|
+
uiWhen(props.elevated, "elevated"),
|
|
346
|
+
props.class
|
|
347
|
+
]);
|
|
348
|
+
|
|
349
|
+
const p = JSswift.omit(props, [
|
|
350
|
+
"src", "srcset", "srcSet", "sizes", "alt", "label", "name", "initials", "text",
|
|
351
|
+
"size", "fontSize", "textSize", "radius", "rounded", "square", "elevated",
|
|
352
|
+
"icon", "iconSize", "media", "fit", "badge", "notification", "status",
|
|
353
|
+
"statusColor", "presence", "topLeft", "topRight", "bottomLeft", "bottomRight",
|
|
354
|
+
"slots"
|
|
355
|
+
]);
|
|
356
|
+
p.class = cls;
|
|
357
|
+
|
|
358
|
+
const style = { ...(props.style || {}) };
|
|
359
|
+
const sizeStyle = uiStyleValue(props.size, (value) => {
|
|
360
|
+
if (typeof value === "string" && JSswift.uiSizes?.includes(value)) return "";
|
|
361
|
+
return toCssSize(value);
|
|
362
|
+
}, "");
|
|
363
|
+
if (sizeStyle != null) {
|
|
364
|
+
style.width = sizeStyle;
|
|
365
|
+
style.height = sizeStyle;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
const fontSizeValue = props.fontSize ?? props.textSize;
|
|
369
|
+
const fontSizeStyle = fontSizeValue != null
|
|
370
|
+
? uiStyleValue(fontSizeValue, toCssSize)
|
|
371
|
+
: uiStyleValue(props.size, (value) => {
|
|
372
|
+
if (typeof value === "string" && JSswift.uiSizes?.includes(value)) return "";
|
|
373
|
+
return `clamp(11px, calc(${toCssSize(value)} * 0.34), 28px)`;
|
|
374
|
+
}, "");
|
|
375
|
+
if (fontSizeStyle != null) style.fontSize = fontSizeStyle;
|
|
376
|
+
|
|
377
|
+
const radiusStyle = uiStyleValue(props.radius, (value) => {
|
|
378
|
+
const normalized = normalizeRadius(value);
|
|
379
|
+
if (normalized === "xxxl") return "999px";
|
|
380
|
+
if (normalized) return `var(--cms-r-${normalized})`;
|
|
381
|
+
if (typeof value === "number") return `${value}px`;
|
|
382
|
+
return String(value);
|
|
383
|
+
});
|
|
384
|
+
if (radiusStyle != null) style["--set-border-radius"] = radiusStyle;
|
|
385
|
+
p.style = style;
|
|
386
|
+
|
|
387
|
+
const ctx = { props };
|
|
388
|
+
const altText = uiComputed([props.alt, props.label, props.name, props.text], () => {
|
|
389
|
+
const raw = uiUnwrap(props.alt) || uiUnwrap(props.label) || uiUnwrap(props.name) || uiUnwrap(props.text) || "avatar";
|
|
390
|
+
return String(raw);
|
|
391
|
+
});
|
|
392
|
+
const iconFallback = props.icon != null
|
|
393
|
+
? (typeof props.icon === "string"
|
|
394
|
+
? UI.Icon({ name: props.icon, size: props.iconSize || props.size || "sm" })
|
|
395
|
+
: JSswift.ui.slot(props.icon, { as: "icon" }))
|
|
396
|
+
: null;
|
|
397
|
+
const labelFallback = uiComputed([props.initials, props.text, props.label, props.name], () => {
|
|
398
|
+
const explicit = uiUnwrap(props.initials) ?? uiUnwrap(props.text);
|
|
399
|
+
if (explicit != null) return explicit;
|
|
400
|
+
const rawLabel = uiUnwrap(props.label) ?? uiUnwrap(props.name);
|
|
401
|
+
if (typeof rawLabel === "string") return avatarGetInitials(rawLabel);
|
|
402
|
+
return rawLabel;
|
|
403
|
+
});
|
|
404
|
+
const badgeFallback = avatarPrimitiveBadge(uiUnwrap(props.badge ?? props.notification));
|
|
405
|
+
const statusFallback = avatarPrimitiveStatus(
|
|
406
|
+
uiUnwrap(props.status ?? props.presence),
|
|
407
|
+
uiUnwrap(props.statusColor)
|
|
408
|
+
);
|
|
409
|
+
|
|
410
|
+
let mediaNodes = renderSlotToArray(slots, "media", ctx, props.media);
|
|
411
|
+
if (!mediaNodes.length && props.src) {
|
|
412
|
+
const imgProps = {
|
|
413
|
+
class: "cms-avatar-img",
|
|
414
|
+
src: props.src,
|
|
415
|
+
alt: altText,
|
|
416
|
+
sizes: props.sizes,
|
|
417
|
+
style: {}
|
|
418
|
+
};
|
|
419
|
+
if (props.srcset != null) imgProps.srcset = props.srcset;
|
|
420
|
+
if (props.srcSet != null) imgProps.srcset = props.srcSet;
|
|
421
|
+
const fitStyle = uiStyleValue(props.fit);
|
|
422
|
+
if (fitStyle != null) imgProps.style.objectFit = fitStyle;
|
|
423
|
+
mediaNodes = [_.img(imgProps)];
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
const defaultNodes = renderSlotToArray(slots, "default", ctx, children);
|
|
427
|
+
const fallbackNodes = renderSlotToArray(slots, "fallback", ctx, null);
|
|
428
|
+
const labelNodes = renderSlotToArray(slots, "label", ctx, labelFallback);
|
|
429
|
+
const iconNodes = renderSlotToArray(slots, "icon", ctx, iconFallback);
|
|
430
|
+
const mainNodes = mediaNodes.length
|
|
431
|
+
? mediaNodes
|
|
432
|
+
: (defaultNodes.length
|
|
433
|
+
? defaultNodes
|
|
434
|
+
: (fallbackNodes.length
|
|
435
|
+
? fallbackNodes
|
|
436
|
+
: (labelNodes.length
|
|
437
|
+
? labelNodes
|
|
438
|
+
: (iconNodes.length ? iconNodes : ["?"]))));
|
|
439
|
+
|
|
440
|
+
const bodyClass = mediaNodes.length ? "cms-avatar-media" : "cms-avatar-fallback";
|
|
441
|
+
const body = _.span({ class: "cms-avatar-body" },
|
|
442
|
+
_.span({ class: bodyClass }, ...mainNodes)
|
|
443
|
+
);
|
|
444
|
+
|
|
445
|
+
let topLeftNodes = renderSlotToArray(slots, "topLeft", ctx, props.topLeft);
|
|
446
|
+
let topRightNodes = renderSlotToArray(slots, "topRight", ctx, props.topRight);
|
|
447
|
+
let bottomLeftNodes = renderSlotToArray(slots, "bottomLeft", ctx, props.bottomLeft);
|
|
448
|
+
let bottomRightNodes = renderSlotToArray(slots, "bottomRight", ctx, props.bottomRight);
|
|
449
|
+
const badgeNodes = renderSlotToArray(slots, "badge", ctx, badgeFallback);
|
|
450
|
+
const statusNodes = renderSlotToArray(slots, "status", ctx, statusFallback);
|
|
451
|
+
|
|
452
|
+
if (!topRightNodes.length && badgeNodes.length) topRightNodes = badgeNodes;
|
|
453
|
+
if (!bottomRightNodes.length && statusNodes.length) bottomRightNodes = statusNodes;
|
|
454
|
+
|
|
526
455
|
const wrap = _.div(
|
|
527
456
|
p,
|
|
528
457
|
body,
|
|
@@ -534,140 +463,57 @@
|
|
|
534
463
|
setPropertyProps(wrap, props);
|
|
535
464
|
return wrap;
|
|
536
465
|
};
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
},
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
},
|
|
589
|
-
returns: "HTMLDivElement",
|
|
590
|
-
description: "Flexible avatar with image, smart fallbacks, states, badge, and overlay slots."
|
|
591
|
-
};
|
|
592
|
-
}
|
|
593
|
-
// Esempio: JSswift.ui.Avatar({ label: "CM" })
|
|
594
|
-
|
|
595
|
-
UI.Chip = (...args) => {
|
|
596
|
-
const { props, children } = JSswift.uiNormalizeArgs(args);
|
|
597
|
-
const slots = props.slots || {};
|
|
598
|
-
const sizeClass = uiComputed(props.size, () => {
|
|
599
|
-
const v = uiUnwrap(props.size);
|
|
600
|
-
return (typeof v === "string" && sizeMap[v]) ? v : "";
|
|
601
|
-
});
|
|
602
|
-
const cls = uiClass([
|
|
603
|
-
"cms-clear-set",
|
|
604
|
-
"cms-chip",
|
|
605
|
-
"cms-singularity",
|
|
606
|
-
sizeClass,
|
|
607
|
-
props.class
|
|
608
|
-
]);
|
|
609
|
-
const p = JSswift.omit(props, ["label", "border", "color", "icon", "iconRight", "removable", "onRemove", "dense", "flat", "glossy", "outline", "slots"]);
|
|
610
|
-
p.class = cls;
|
|
611
|
-
p.style = {
|
|
612
|
-
...(props.style || {})
|
|
613
|
-
};
|
|
614
|
-
|
|
615
|
-
const iconFallback = props.icon
|
|
616
|
-
? (typeof props.icon === "string" ? UI.Icon({ name: props.icon, size: props?.size ?? null }) : JSswift.ui.slot(props.icon, { as: "icon" }))
|
|
617
|
-
: null;
|
|
618
|
-
const iconRightFallback = props.iconRight
|
|
619
|
-
? (typeof props.iconRight === "string" ? UI.Icon({ name: props.iconRight, size: props?.size ?? null }) : JSswift.ui.slot(props.iconRight, { as: "iconRight" }))
|
|
620
|
-
: null;
|
|
621
|
-
const iconNode = JSswift.ui.renderSlot(slots, "icon", {}, iconFallback);
|
|
622
|
-
const iconRightNode = JSswift.ui.renderSlot(slots, "iconRight", {}, iconRightFallback);
|
|
623
|
-
const labelNodes = renderSlotToArray(slots, "label", {}, props.label);
|
|
624
|
-
const labelNode = labelNodes.length ? labelNodes : renderSlotToArray(slots, "default", {}, children);
|
|
625
|
-
|
|
626
|
-
const iconNodes = renderSlotToArray(null, "default", {}, iconNode);
|
|
627
|
-
const iconRightNodes = renderSlotToArray(null, "default", {}, iconRightNode);
|
|
628
|
-
const wrap = _.span(p, ...iconNodes, ...(labelNode.length ? labelNode : [""]), ...iconRightNodes);
|
|
629
|
-
if (props.removable) {
|
|
630
|
-
const btn = UI.Btn({ class: "cms-chip-remove", onClick: props.onRemove, size: props?.size ?? null }, UI.Icon({ size: props?.size ?? null, name: "close" }));
|
|
631
|
-
wrap.appendChild(btn);
|
|
632
|
-
btn.onclick = () => {
|
|
633
|
-
if (props.onRemove) {
|
|
634
|
-
props.onRemove();
|
|
635
|
-
}
|
|
636
|
-
wrap.remove();
|
|
637
|
-
}
|
|
638
|
-
}
|
|
639
|
-
setPropertyProps(wrap, props);
|
|
640
|
-
return wrap;
|
|
641
|
-
};
|
|
642
|
-
if (JSswift.isDev?.()) {
|
|
643
|
-
UI.meta = UI.meta || {};
|
|
644
|
-
UI.meta.Chip = {
|
|
645
|
-
signature: "UI.Chip(...children) | UI.Chip(props, ...children)",
|
|
646
|
-
props: {
|
|
647
|
-
label: "String|Node|Function|Array",
|
|
648
|
-
icon: "String|Node|Function|Array",
|
|
649
|
-
iconRight: "String|Node|Function|Array",
|
|
650
|
-
removable: "boolean",
|
|
651
|
-
onRemove: "function",
|
|
652
|
-
dense: "boolean",
|
|
653
|
-
outline: "boolean|string|number",
|
|
654
|
-
slots: "{ icon?, label?, default? }",
|
|
655
|
-
class: "string",
|
|
656
|
-
style: "object"
|
|
657
|
-
},
|
|
658
|
-
slots: {
|
|
659
|
-
icon: "Chip icon content",
|
|
660
|
-
iconRight: "Chip right icon content",
|
|
661
|
-
label: "Chip label content",
|
|
662
|
-
default: "Fallback content"
|
|
663
|
-
},
|
|
664
|
-
events: {
|
|
665
|
-
onRemove: "MouseEvent"
|
|
666
|
-
},
|
|
667
|
-
returns: "HTMLSpanElement",
|
|
668
|
-
description: "Chip with optional icon and removal."
|
|
669
|
-
};
|
|
670
|
-
}
|
|
466
|
+
|
|
467
|
+
// Esempio: JSswift.ui.Avatar({ label: "CM" })
|
|
468
|
+
|
|
469
|
+
UI.Chip = (...args) => {
|
|
470
|
+
const { props, children } = JSswift.uiNormalizeArgs(args);
|
|
471
|
+
const slots = props.slots || {};
|
|
472
|
+
const sizeClass = uiComputed(props.size, () => {
|
|
473
|
+
const v = uiUnwrap(props.size);
|
|
474
|
+
return (typeof v === "string" && sizeMap[v]) ? v : "";
|
|
475
|
+
});
|
|
476
|
+
const cls = uiClass([
|
|
477
|
+
"cms-clear-set",
|
|
478
|
+
"cms-chip",
|
|
479
|
+
"cms-singularity",
|
|
480
|
+
sizeClass,
|
|
481
|
+
props.class
|
|
482
|
+
]);
|
|
483
|
+
const p = JSswift.omit(props, ["label", "border", "color", "icon", "iconRight", "removable", "onRemove", "dense", "flat", "glossy", "outline", "slots"]);
|
|
484
|
+
p.class = cls;
|
|
485
|
+
p.style = {
|
|
486
|
+
...(props.style || {})
|
|
487
|
+
};
|
|
488
|
+
|
|
489
|
+
const iconFallback = props.icon
|
|
490
|
+
? (typeof props.icon === "string" ? UI.Icon({ name: props.icon, size: props?.size ?? null }) : JSswift.ui.slot(props.icon, { as: "icon" }))
|
|
491
|
+
: null;
|
|
492
|
+
const iconRightFallback = props.iconRight
|
|
493
|
+
? (typeof props.iconRight === "string" ? UI.Icon({ name: props.iconRight, size: props?.size ?? null }) : JSswift.ui.slot(props.iconRight, { as: "iconRight" }))
|
|
494
|
+
: null;
|
|
495
|
+
const iconNode = JSswift.ui.renderSlot(slots, "icon", {}, iconFallback);
|
|
496
|
+
const iconRightNode = JSswift.ui.renderSlot(slots, "iconRight", {}, iconRightFallback);
|
|
497
|
+
const labelNodes = renderSlotToArray(slots, "label", {}, props.label);
|
|
498
|
+
const labelNode = labelNodes.length ? labelNodes : renderSlotToArray(slots, "default", {}, children);
|
|
499
|
+
|
|
500
|
+
const iconNodes = renderSlotToArray(null, "default", {}, iconNode);
|
|
501
|
+
const iconRightNodes = renderSlotToArray(null, "default", {}, iconRightNode);
|
|
502
|
+
const wrap = _.span(p, ...iconNodes, ...(labelNode.length ? labelNode : [""]), ...iconRightNodes);
|
|
503
|
+
if (props.removable) {
|
|
504
|
+
const btn = UI.Btn({ class: "cms-chip-remove", onClick: props.onRemove, size: props?.size ?? null }, UI.Icon({ size: props?.size ?? null, name: "close" }));
|
|
505
|
+
wrap.appendChild(btn);
|
|
506
|
+
btn.onclick = () => {
|
|
507
|
+
if (props.onRemove) {
|
|
508
|
+
props.onRemove();
|
|
509
|
+
}
|
|
510
|
+
wrap.remove();
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
setPropertyProps(wrap, props);
|
|
514
|
+
return wrap;
|
|
515
|
+
};
|
|
516
|
+
|
|
671
517
|
// Esempio: JSswift.ui.Chip({ label: "Tag", removable: true })
|
|
672
518
|
|
|
673
519
|
UI.Stat = (...args) => {
|
|
@@ -777,46 +623,7 @@
|
|
|
777
623
|
setPropertyProps(stat, rawProps);
|
|
778
624
|
return stat;
|
|
779
625
|
};
|
|
780
|
-
|
|
781
|
-
UI.meta = UI.meta || {};
|
|
782
|
-
UI.meta.Stat = {
|
|
783
|
-
signature: "UI.Stat(...children) | UI.Stat(props, ...children)",
|
|
784
|
-
props: {
|
|
785
|
-
eyebrow: "String|Node|Function|Array",
|
|
786
|
-
label: "String|Node|Function|Array",
|
|
787
|
-
title: "Alias of label",
|
|
788
|
-
value: "String|Number|Node|Function|Array",
|
|
789
|
-
delta: "String|Node|Function|Array",
|
|
790
|
-
trend: "up|down|flat|positive|negative|neutral",
|
|
791
|
-
note: "String|Node|Function|Array",
|
|
792
|
-
subtitle: "Alias of note",
|
|
793
|
-
meta: "Node|Function|Array",
|
|
794
|
-
icon: "String|Node|Function|Array",
|
|
795
|
-
aside: "Node|Function|Array",
|
|
796
|
-
footer: "Node|Function|Array",
|
|
797
|
-
actions: "Node|Function|Array",
|
|
798
|
-
state: "primary|secondary|success|warning|danger|info|light|dark",
|
|
799
|
-
slots: "{ eyebrow?, label?, value?, delta?, note?, meta?, icon?, aside?, footer?, actions?, default? }",
|
|
800
|
-
class: "string",
|
|
801
|
-
style: "object"
|
|
802
|
-
},
|
|
803
|
-
slots: {
|
|
804
|
-
eyebrow: "Small kicker above the stat label",
|
|
805
|
-
label: "Main stat label",
|
|
806
|
-
value: "Primary metric value",
|
|
807
|
-
delta: "Trend / delta content",
|
|
808
|
-
note: "Supporting note",
|
|
809
|
-
meta: "Extra meta badges or info",
|
|
810
|
-
icon: "Leading icon or avatar",
|
|
811
|
-
aside: "Right-side support content",
|
|
812
|
-
footer: "Footer/supporting bottom content",
|
|
813
|
-
actions: "Footer actions cluster",
|
|
814
|
-
default: "Extra body content"
|
|
815
|
-
},
|
|
816
|
-
returns: "HTMLElement",
|
|
817
|
-
description: "Compact surface for single metrics, trends, and operational metadata."
|
|
818
|
-
};
|
|
819
|
-
}
|
|
626
|
+
|
|
820
627
|
// Esempio: JSswift.ui.Stat({ label: "Revenue", value: "€ 128k", delta: "+18%" })
|
|
821
628
|
|
|
822
629
|
UI.Kpi = (...args) => {
|
|
@@ -922,93 +729,52 @@
|
|
|
922
729
|
setPropertyProps(kpi, rawProps);
|
|
923
730
|
return kpi;
|
|
924
731
|
};
|
|
925
|
-
|
|
926
|
-
UI.meta = UI.meta || {};
|
|
927
|
-
UI.meta.Kpi = {
|
|
928
|
-
signature: "UI.Kpi(...children) | UI.Kpi(props, ...children)",
|
|
929
|
-
props: {
|
|
930
|
-
eyebrow: "String|Node|Function|Array",
|
|
931
|
-
title: "String|Node|Function|Array",
|
|
932
|
-
label: "Alias of title",
|
|
933
|
-
value: "String|Number|Node|Function|Array",
|
|
934
|
-
delta: "String|Node|Function|Array",
|
|
935
|
-
trend: "up|down|flat|positive|negative|neutral",
|
|
936
|
-
note: "String|Node|Function|Array",
|
|
937
|
-
subtitle: "Alias of note",
|
|
938
|
-
meta: "Node|Function|Array",
|
|
939
|
-
media: "Node|Function|Array",
|
|
940
|
-
icon: "String|Node|Function|Array",
|
|
941
|
-
aside: "Node|Function|Array",
|
|
942
|
-
footer: "Node|Function|Array",
|
|
943
|
-
actions: "Node|Function|Array",
|
|
944
|
-
state: "primary|secondary|success|warning|danger|info|light|dark",
|
|
945
|
-
slots: "{ eyebrow?, title?, value?, delta?, note?, meta?, media?, icon?, aside?, footer?, actions?, default? }",
|
|
946
|
-
class: "string",
|
|
947
|
-
style: "object"
|
|
948
|
-
},
|
|
949
|
-
slots: {
|
|
950
|
-
eyebrow: "Kicker content",
|
|
951
|
-
title: "KPI title content",
|
|
952
|
-
value: "Primary KPI value",
|
|
953
|
-
delta: "Delta/trend content",
|
|
954
|
-
note: "Supporting note",
|
|
955
|
-
meta: "Extra meta badges or inline info",
|
|
956
|
-
media: "Secondary data view or mini-visual content",
|
|
957
|
-
icon: "Leading icon or avatar",
|
|
958
|
-
aside: "Top-right support content",
|
|
959
|
-
footer: "Bottom support content",
|
|
960
|
-
actions: "Footer actions cluster",
|
|
961
|
-
default: "Extra body content"
|
|
962
|
-
},
|
|
963
|
-
returns: "HTMLElement",
|
|
964
|
-
description: "Richer surface for KPIs, headline metrics, and mini dashboard summaries."
|
|
965
|
-
};
|
|
966
|
-
}
|
|
732
|
+
|
|
967
733
|
// Esempio: JSswift.ui.Kpi({ title: "Orders", value: "342", delta: "+12%" })
|
|
968
734
|
|
|
969
735
|
const overlayAnimDuration = (el, fallback = 180) => {
|
|
970
|
-
const d = getComputedStyle(el).transitionDuration;
|
|
971
|
-
if (!d) return fallback;
|
|
972
|
-
const first = d.split(",")[0].trim();
|
|
973
|
-
if (!first) return fallback;
|
|
974
|
-
const ms = first.includes("ms") ? parseFloat(first) : parseFloat(first) * 1000;
|
|
975
|
-
return Number.isFinite(ms) ? ms : fallback;
|
|
976
|
-
};
|
|
977
|
-
|
|
978
|
-
const overlayEnter = (entry) => {
|
|
979
|
-
if (!entry?.overlay || !entry?.panel) return;
|
|
980
|
-
entry.overlay.classList.add("enter");
|
|
981
|
-
entry.panel.classList.add("enter");
|
|
982
|
-
requestAnimationFrame(() => {
|
|
983
|
-
if (!entry?.overlay || !entry?.panel) return;
|
|
984
|
-
entry.overlay.classList.add("entered");
|
|
985
|
-
entry.panel.classList.add("entered");
|
|
986
|
-
entry.overlay.classList.remove("enter");
|
|
987
|
-
entry.panel.classList.remove("enter");
|
|
988
|
-
});
|
|
989
|
-
};
|
|
990
|
-
|
|
991
|
-
const overlayLeave = (entry, done) => {
|
|
992
|
-
if (!entry?.overlay || !entry?.panel) {
|
|
993
|
-
done?.();
|
|
994
|
-
return;
|
|
995
|
-
}
|
|
996
|
-
if (entry._closing) return;
|
|
997
|
-
entry._closing = true;
|
|
998
|
-
entry.overlay.classList.add("leave");
|
|
999
|
-
entry.panel.classList.add("leave");
|
|
1000
|
-
const finish = () => {
|
|
1001
|
-
if (entry._closed) return;
|
|
1002
|
-
entry._closed = true;
|
|
1003
|
-
done?.();
|
|
1004
|
-
};
|
|
1005
|
-
const onEnd = (e) => {
|
|
1006
|
-
if (e.target !== entry.panel) return;
|
|
1007
|
-
entry.panel.removeEventListener("transitionend", onEnd);
|
|
1008
|
-
finish();
|
|
1009
|
-
};
|
|
1010
|
-
entry.panel.addEventListener("transitionend", onEnd);
|
|
1011
|
-
const ms = overlayAnimDuration(entry.panel, 180);
|
|
1012
|
-
setTimeout(finish, ms + 40);
|
|
1013
|
-
};
|
|
1014
|
-
|
|
736
|
+
const d = getComputedStyle(el).transitionDuration;
|
|
737
|
+
if (!d) return fallback;
|
|
738
|
+
const first = d.split(",")[0].trim();
|
|
739
|
+
if (!first) return fallback;
|
|
740
|
+
const ms = first.includes("ms") ? parseFloat(first) : parseFloat(first) * 1000;
|
|
741
|
+
return Number.isFinite(ms) ? ms : fallback;
|
|
742
|
+
};
|
|
743
|
+
|
|
744
|
+
const overlayEnter = (entry) => {
|
|
745
|
+
if (!entry?.overlay || !entry?.panel) return;
|
|
746
|
+
entry.overlay.classList.add("enter");
|
|
747
|
+
entry.panel.classList.add("enter");
|
|
748
|
+
requestAnimationFrame(() => {
|
|
749
|
+
if (!entry?.overlay || !entry?.panel) return;
|
|
750
|
+
entry.overlay.classList.add("entered");
|
|
751
|
+
entry.panel.classList.add("entered");
|
|
752
|
+
entry.overlay.classList.remove("enter");
|
|
753
|
+
entry.panel.classList.remove("enter");
|
|
754
|
+
});
|
|
755
|
+
};
|
|
756
|
+
|
|
757
|
+
const overlayLeave = (entry, done) => {
|
|
758
|
+
if (!entry?.overlay || !entry?.panel) {
|
|
759
|
+
done?.();
|
|
760
|
+
return;
|
|
761
|
+
}
|
|
762
|
+
if (entry._closing) return;
|
|
763
|
+
entry._closing = true;
|
|
764
|
+
entry.overlay.classList.add("leave");
|
|
765
|
+
entry.panel.classList.add("leave");
|
|
766
|
+
const finish = () => {
|
|
767
|
+
if (entry._closed) return;
|
|
768
|
+
entry._closed = true;
|
|
769
|
+
done?.();
|
|
770
|
+
};
|
|
771
|
+
const onEnd = (e) => {
|
|
772
|
+
if (e.target !== entry.panel) return;
|
|
773
|
+
entry.panel.removeEventListener("transitionend", onEnd);
|
|
774
|
+
finish();
|
|
775
|
+
};
|
|
776
|
+
entry.panel.addEventListener("transitionend", onEnd);
|
|
777
|
+
const ms = overlayAnimDuration(entry.panel, 180);
|
|
778
|
+
setTimeout(finish, ms + 40);
|
|
779
|
+
};
|
|
780
|
+
|