@incursa/ui-kit 1.7.0 → 1.9.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/NOTICE +8 -0
- package/README.md +18 -0
- package/dist/icons/index.js +371 -0
- package/dist/icons/package.json +3 -0
- package/dist/inc-design-language.css +115 -1
- package/dist/inc-design-language.css.map +1 -1
- package/dist/inc-design-language.js +1558 -1462
- package/dist/inc-design-language.min.css +1 -1
- package/dist/inc-design-language.min.css.map +1 -1
- package/dist/mcp/components/cards.json +3 -3
- package/dist/mcp/components/metrics.json +3 -3
- package/dist/mcp/components/states.json +3 -3
- package/dist/mcp/examples/data-grid-advanced.json +2 -2
- package/dist/mcp/examples/demo.json +2 -2
- package/dist/mcp/examples/overlay-workflows.json +2 -2
- package/dist/mcp/examples/reference.json +2 -2
- package/dist/mcp/examples/states.json +2 -2
- package/dist/mcp/examples/web-components.json +2 -2
- package/dist/mcp/guides/allowed-web-component-families.json +2 -2
- package/dist/mcp/guides/latest.json +2 -2
- package/dist/mcp/guides/package-metadata.json +2 -2
- package/dist/mcp/guides/update.json +2 -2
- package/dist/mcp/install.json +1 -1
- package/dist/mcp/patterns/data-grid-advanced.json +2 -2
- package/dist/mcp/patterns/demo.json +2 -2
- package/dist/mcp/patterns/overlay-workflows.json +2 -2
- package/dist/mcp/patterns/reference.json +2 -2
- package/dist/mcp/patterns/states.json +2 -2
- package/dist/mcp/patterns/web-components.json +2 -2
- package/dist/mcp/resources.json +81 -78
- package/dist/mcp/search-index.json +22 -22
- package/dist/mcp/update.json +2 -2
- package/dist/mcp/worker.mjs +331 -286
- package/dist/mcp/worker.mjs.map +2 -2
- package/dist/web-components/README.md +7 -0
- package/dist/web-components/RUNTIME-NOTES.md +2 -0
- package/dist/web-components/components/actions.js +149 -2
- package/dist/web-components/components/feedback.js +63 -12
- package/dist/web-components/components/visualizations.js +629 -0
- package/dist/web-components/index.js +3642 -139
- package/package.json +13 -3
- package/src/icons/index.js +229 -0
- package/src/icons/package.json +3 -0
- package/src/inc-design-language.js +12 -11
- package/src/inc-design-language.scss +132 -1
- package/src/web-components/README.md +7 -0
- package/src/web-components/RUNTIME-NOTES.md +2 -0
- package/src/web-components/components/actions.js +149 -2
- package/src/web-components/components/feedback.js +63 -12
- package/src/web-components/components/visualizations.js +629 -0
- package/src/web-components/index.js +8 -0
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import {
|
|
2
|
+
normalizeIconName,
|
|
3
|
+
replaceIconContents,
|
|
4
|
+
} from "../../icons/index.js";
|
|
1
5
|
import {
|
|
2
6
|
addClass,
|
|
3
7
|
ensureNode,
|
|
@@ -28,6 +32,14 @@ const ALERT_DEFAULT_ROLE_BY_TONE = new Map([
|
|
|
28
32
|
["info", "status"],
|
|
29
33
|
["secondary", "status"],
|
|
30
34
|
]);
|
|
35
|
+
const ALERT_ICON_BY_TONE = new Map([
|
|
36
|
+
["success", "success"],
|
|
37
|
+
["danger", "error"],
|
|
38
|
+
["warning", "warning"],
|
|
39
|
+
["info", "info"],
|
|
40
|
+
["secondary", "info"],
|
|
41
|
+
["primary", "info"],
|
|
42
|
+
]);
|
|
31
43
|
|
|
32
44
|
const HostElement = typeof HTMLElement === "undefined" ? class {} : HTMLElement;
|
|
33
45
|
|
|
@@ -53,6 +65,29 @@ function emit(host, type, detail = {}, options = {}) {
|
|
|
53
65
|
}));
|
|
54
66
|
}
|
|
55
67
|
|
|
68
|
+
function getDirectIconSlot(host) {
|
|
69
|
+
return Array.from(host.children || []).find((node) => (
|
|
70
|
+
node instanceof HTMLElement
|
|
71
|
+
&& node.getAttribute("slot") === "icon"
|
|
72
|
+
)) || null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function hasConsumerIcon(container) {
|
|
76
|
+
return Array.from(container.children || []).some((node) => (
|
|
77
|
+
node instanceof HTMLElement
|
|
78
|
+
&& !node.hasAttribute("data-inc-generated-icon")
|
|
79
|
+
));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function renderDecorativeIcon(container, name, options = {}) {
|
|
83
|
+
replaceIconContents(container, name, {
|
|
84
|
+
className: "inc-icon",
|
|
85
|
+
decorative: true,
|
|
86
|
+
size: options.size || 16,
|
|
87
|
+
});
|
|
88
|
+
container.hidden = false;
|
|
89
|
+
}
|
|
90
|
+
|
|
56
91
|
class IncElement extends HostElement {
|
|
57
92
|
emit(type, detail = {}, options = {}) {
|
|
58
93
|
return emit(this, type, detail, options);
|
|
@@ -61,7 +96,7 @@ class IncElement extends HostElement {
|
|
|
61
96
|
|
|
62
97
|
export class IncButtonElement extends IncElement {
|
|
63
98
|
static get observedAttributes() {
|
|
64
|
-
return ["tone", "variant", "size", "loading", "href", "type", "disabled", "label", "target", "rel", "download"];
|
|
99
|
+
return ["tone", "variant", "size", "loading", "href", "type", "disabled", "label", "target", "rel", "download", "icon"];
|
|
65
100
|
}
|
|
66
101
|
|
|
67
102
|
connectedCallback() {
|
|
@@ -166,6 +201,8 @@ export class IncButtonElement extends IncElement {
|
|
|
166
201
|
this.removeLoadingSpinner(control);
|
|
167
202
|
}
|
|
168
203
|
|
|
204
|
+
this.syncIcon(control);
|
|
205
|
+
|
|
169
206
|
const label = this.getAttribute("label");
|
|
170
207
|
if (label) {
|
|
171
208
|
control.setAttribute("aria-label", label);
|
|
@@ -220,6 +257,53 @@ export class IncButtonElement extends IncElement {
|
|
|
220
257
|
|
|
221
258
|
control.querySelectorAll(":scope > [data-inc-button-spinner]").forEach((node) => node.remove());
|
|
222
259
|
}
|
|
260
|
+
|
|
261
|
+
syncIcon(control) {
|
|
262
|
+
if (!(control instanceof HTMLElement)) {
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const explicitIcon = normalizeIconName(this.getAttribute("icon"));
|
|
267
|
+
const inferredIcon = this.getAttribute("download") != null
|
|
268
|
+
? "download"
|
|
269
|
+
: this.getAttribute("target") === "_blank"
|
|
270
|
+
? "external-link"
|
|
271
|
+
: "";
|
|
272
|
+
const iconName = explicitIcon || inferredIcon;
|
|
273
|
+
let icon = control.querySelector(":scope > [data-inc-button-icon]");
|
|
274
|
+
const slotted = getDirectIconSlot(control);
|
|
275
|
+
|
|
276
|
+
if (!icon && (iconName || slotted)) {
|
|
277
|
+
icon = document.createElement("span");
|
|
278
|
+
icon.className = "inc-btn__icon";
|
|
279
|
+
icon.setAttribute("data-inc-button-icon", "true");
|
|
280
|
+
icon.setAttribute("aria-hidden", "true");
|
|
281
|
+
control.prepend(icon);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (!(icon instanceof HTMLElement)) {
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
if (slotted) {
|
|
289
|
+
slotted.removeAttribute("slot");
|
|
290
|
+
icon.replaceChildren(slotted);
|
|
291
|
+
icon.hidden = false;
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
if (hasConsumerIcon(icon)) {
|
|
296
|
+
icon.hidden = false;
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
if (iconName && iconName !== "none") {
|
|
301
|
+
renderDecorativeIcon(icon, iconName, { size: 16 });
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
icon.remove();
|
|
306
|
+
}
|
|
223
307
|
}
|
|
224
308
|
|
|
225
309
|
export class IncButtonGroupElement extends IncElement {
|
|
@@ -350,7 +434,7 @@ export class IncCloseButtonElement extends IncElement {
|
|
|
350
434
|
|
|
351
435
|
export class IncAlertElement extends IncElement {
|
|
352
436
|
static get observedAttributes() {
|
|
353
|
-
return ["tone", "variant", "dismissible", "dismiss-label", "timeout"];
|
|
437
|
+
return ["tone", "variant", "dismissible", "dismiss-label", "timeout", "icon"];
|
|
354
438
|
}
|
|
355
439
|
|
|
356
440
|
connectedCallback() {
|
|
@@ -398,6 +482,7 @@ export class IncAlertElement extends IncElement {
|
|
|
398
482
|
const tone = normalizeToken(this.getAttribute("tone") || this.getAttribute("variant")) || "info";
|
|
399
483
|
const resolvedTone = BADGE_TONES.has(tone) ? tone : "info";
|
|
400
484
|
this.classList.add(`inc-alert--${resolvedTone}`);
|
|
485
|
+
this.syncIcon(resolvedTone);
|
|
401
486
|
|
|
402
487
|
if (toBoolean(this.getAttribute("dismissible"))) {
|
|
403
488
|
this.classList.add("inc-alert--dismissible");
|
|
@@ -465,6 +550,44 @@ export class IncAlertElement extends IncElement {
|
|
|
465
550
|
this.querySelectorAll(":scope > .inc-alert__progress").forEach((node) => node.remove());
|
|
466
551
|
}
|
|
467
552
|
|
|
553
|
+
syncIcon(tone) {
|
|
554
|
+
const explicitIcon = normalizeIconName(this.getAttribute("icon"));
|
|
555
|
+
const iconName = explicitIcon || ALERT_ICON_BY_TONE.get(tone) || "info";
|
|
556
|
+
let icon = this.querySelector(":scope > .inc-alert__icon");
|
|
557
|
+
const slotted = getDirectIconSlot(this);
|
|
558
|
+
|
|
559
|
+
if (!icon && (iconName !== "none" || slotted)) {
|
|
560
|
+
icon = document.createElement("span");
|
|
561
|
+
icon.className = "inc-alert__icon";
|
|
562
|
+
icon.setAttribute("part", "icon");
|
|
563
|
+
icon.setAttribute("aria-hidden", "true");
|
|
564
|
+
this.prepend(icon);
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
if (!(icon instanceof HTMLElement)) {
|
|
568
|
+
return;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
if (slotted) {
|
|
572
|
+
slotted.removeAttribute("slot");
|
|
573
|
+
icon.replaceChildren(slotted);
|
|
574
|
+
icon.hidden = false;
|
|
575
|
+
return;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
if (hasConsumerIcon(icon)) {
|
|
579
|
+
icon.hidden = false;
|
|
580
|
+
return;
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
if (iconName === "none") {
|
|
584
|
+
icon.remove();
|
|
585
|
+
return;
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
renderDecorativeIcon(icon, iconName, { size: 18 });
|
|
589
|
+
}
|
|
590
|
+
|
|
468
591
|
startDismissTimer(timeoutMs) {
|
|
469
592
|
const progress = this.ensureProgressBar();
|
|
470
593
|
this.stopDismissTimer();
|
|
@@ -514,11 +637,21 @@ export class IncAlertElement extends IncElement {
|
|
|
514
637
|
}
|
|
515
638
|
|
|
516
639
|
export class IncEmptyStateElement extends IncElement {
|
|
640
|
+
static get observedAttributes() {
|
|
641
|
+
return ["icon"];
|
|
642
|
+
}
|
|
643
|
+
|
|
517
644
|
connectedCallback() {
|
|
518
645
|
addClass(this, "inc-empty-state");
|
|
519
646
|
this.sync();
|
|
520
647
|
}
|
|
521
648
|
|
|
649
|
+
attributeChangedCallback() {
|
|
650
|
+
if (this.isConnected) {
|
|
651
|
+
this.sync();
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
|
|
522
655
|
sync() {
|
|
523
656
|
addClass(this, "inc-empty-state");
|
|
524
657
|
this.setAttribute("part", "empty-state content icon body actions");
|
|
@@ -572,6 +705,20 @@ export class IncEmptyStateElement extends IncElement {
|
|
|
572
705
|
|
|
573
706
|
body.append(node);
|
|
574
707
|
});
|
|
708
|
+
|
|
709
|
+
if (hasConsumerIcon(icon)) {
|
|
710
|
+
icon.hidden = false;
|
|
711
|
+
return;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
const iconName = normalizeIconName(this.getAttribute("icon")) || "empty";
|
|
715
|
+
if (iconName === "none") {
|
|
716
|
+
icon.replaceChildren();
|
|
717
|
+
icon.hidden = true;
|
|
718
|
+
return;
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
renderDecorativeIcon(icon, iconName, { size: 34 });
|
|
575
722
|
}
|
|
576
723
|
}
|
|
577
724
|
|
|
@@ -1,15 +1,30 @@
|
|
|
1
|
+
import {
|
|
2
|
+
incIconNames,
|
|
3
|
+
normalizeIconName,
|
|
4
|
+
replaceIconContents,
|
|
5
|
+
} from "../../icons/index.js";
|
|
6
|
+
|
|
1
7
|
const THEME_MODES = ["light", "dark", "system"];
|
|
2
8
|
const DEFAULT_THEME_STORAGE_KEY = "inc-theme-mode";
|
|
3
9
|
const BADGE_TONES = new Set(["primary", "secondary", "success", "danger", "warning", "info"]);
|
|
4
10
|
const SPINNER_VARIANTS = new Set(["border", "grow"]);
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
const ICON_NAME_SET = new Set(incIconNames);
|
|
12
|
+
const STATE_ICON_BY_VARIANT = new Map([
|
|
13
|
+
["empty", "empty"],
|
|
14
|
+
["results", "no-results"],
|
|
15
|
+
["loading", "loading"],
|
|
16
|
+
["error", "error"],
|
|
17
|
+
["danger", "error"],
|
|
18
|
+
["warning", "warning"],
|
|
19
|
+
["success", "success"],
|
|
20
|
+
["info", "info"],
|
|
21
|
+
]);
|
|
22
|
+
const STATE_ICON_BY_STATUS = new Map([
|
|
23
|
+
["+", "empty"],
|
|
24
|
+
["?", "no-results"],
|
|
25
|
+
["!", "error"],
|
|
26
|
+
["...", "loading"],
|
|
27
|
+
]);
|
|
13
28
|
const HostElement = typeof HTMLElement === "undefined" ? class {} : HTMLElement;
|
|
14
29
|
const themeSubscribers = new Set();
|
|
15
30
|
|
|
@@ -46,6 +61,33 @@ function normalizeToken(value) {
|
|
|
46
61
|
return String(value ?? "").trim().toLowerCase();
|
|
47
62
|
}
|
|
48
63
|
|
|
64
|
+
function resolveStateIconName(icon, status, variant) {
|
|
65
|
+
const explicitIcon = normalizeIconName(icon);
|
|
66
|
+
if (explicitIcon) {
|
|
67
|
+
return explicitIcon;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const normalizedStatus = normalizeIconName(status);
|
|
71
|
+
if (STATE_ICON_BY_STATUS.has(String(status || "").trim())) {
|
|
72
|
+
return STATE_ICON_BY_STATUS.get(String(status || "").trim());
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (ICON_NAME_SET.has(normalizedStatus)) {
|
|
76
|
+
return normalizedStatus;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return STATE_ICON_BY_VARIANT.get(normalizeToken(variant)) || "info";
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function renderDecorativeIcon(container, name, size = 18) {
|
|
83
|
+
replaceIconContents(container, name, {
|
|
84
|
+
className: "inc-icon",
|
|
85
|
+
decorative: true,
|
|
86
|
+
size,
|
|
87
|
+
});
|
|
88
|
+
container.hidden = false;
|
|
89
|
+
}
|
|
90
|
+
|
|
49
91
|
function getSystemTheme() {
|
|
50
92
|
if (!window.matchMedia) {
|
|
51
93
|
return "light";
|
|
@@ -206,7 +248,7 @@ function formatRemaining(totalSeconds) {
|
|
|
206
248
|
}
|
|
207
249
|
|
|
208
250
|
export class IncStatePanel extends HostElement {
|
|
209
|
-
static observedAttributes = ["tone", "variant", "title", "body", "status", "open"];
|
|
251
|
+
static observedAttributes = ["tone", "variant", "title", "body", "status", "icon", "open"];
|
|
210
252
|
|
|
211
253
|
#fallback = null;
|
|
212
254
|
#appliedVariantClass = "";
|
|
@@ -246,6 +288,7 @@ export class IncStatePanel extends HostElement {
|
|
|
246
288
|
actions.className = "inc-state-panel__actions";
|
|
247
289
|
|
|
248
290
|
icon.setAttribute("part", "icon");
|
|
291
|
+
icon.setAttribute("aria-hidden", "true");
|
|
249
292
|
title.setAttribute("part", "title");
|
|
250
293
|
body.setAttribute("part", "body");
|
|
251
294
|
actions.setAttribute("part", "actions");
|
|
@@ -282,11 +325,19 @@ export class IncStatePanel extends HostElement {
|
|
|
282
325
|
const title = this.getAttribute("title") || "";
|
|
283
326
|
const body = this.getAttribute("body") || "";
|
|
284
327
|
const status = this.getAttribute("status") || "";
|
|
328
|
+
const iconName = resolveStateIconName(this.getAttribute("icon"), status, nextVariant);
|
|
285
329
|
|
|
286
330
|
this.#fallback.title.textContent = title;
|
|
287
331
|
this.#fallback.body.textContent = body;
|
|
288
|
-
|
|
289
|
-
|
|
332
|
+
if (iconName === "none") {
|
|
333
|
+
this.#fallback.icon.replaceChildren();
|
|
334
|
+
this.#fallback.icon.hidden = true;
|
|
335
|
+
} else if (ICON_NAME_SET.has(iconName)) {
|
|
336
|
+
renderDecorativeIcon(this.#fallback.icon, iconName, 22);
|
|
337
|
+
} else {
|
|
338
|
+
this.#fallback.icon.textContent = status;
|
|
339
|
+
this.#fallback.icon.hidden = !status;
|
|
340
|
+
}
|
|
290
341
|
this.#fallback.actions.hidden = true;
|
|
291
342
|
}
|
|
292
343
|
|
|
@@ -872,7 +923,7 @@ export class IncAutoRefresh extends HostElement {
|
|
|
872
923
|
}
|
|
873
924
|
|
|
874
925
|
if (this.#parts.toggleIcon instanceof HTMLElement) {
|
|
875
|
-
this.#parts.toggleIcon
|
|
926
|
+
renderDecorativeIcon(this.#parts.toggleIcon, this.#isPaused ? "play" : "pause", 16);
|
|
876
927
|
}
|
|
877
928
|
}
|
|
878
929
|
|