@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.
Files changed (51) hide show
  1. package/NOTICE +8 -0
  2. package/README.md +18 -0
  3. package/dist/icons/index.js +371 -0
  4. package/dist/icons/package.json +3 -0
  5. package/dist/inc-design-language.css +115 -1
  6. package/dist/inc-design-language.css.map +1 -1
  7. package/dist/inc-design-language.js +1558 -1462
  8. package/dist/inc-design-language.min.css +1 -1
  9. package/dist/inc-design-language.min.css.map +1 -1
  10. package/dist/mcp/components/cards.json +3 -3
  11. package/dist/mcp/components/metrics.json +3 -3
  12. package/dist/mcp/components/states.json +3 -3
  13. package/dist/mcp/examples/data-grid-advanced.json +2 -2
  14. package/dist/mcp/examples/demo.json +2 -2
  15. package/dist/mcp/examples/overlay-workflows.json +2 -2
  16. package/dist/mcp/examples/reference.json +2 -2
  17. package/dist/mcp/examples/states.json +2 -2
  18. package/dist/mcp/examples/web-components.json +2 -2
  19. package/dist/mcp/guides/allowed-web-component-families.json +2 -2
  20. package/dist/mcp/guides/latest.json +2 -2
  21. package/dist/mcp/guides/package-metadata.json +2 -2
  22. package/dist/mcp/guides/update.json +2 -2
  23. package/dist/mcp/install.json +1 -1
  24. package/dist/mcp/patterns/data-grid-advanced.json +2 -2
  25. package/dist/mcp/patterns/demo.json +2 -2
  26. package/dist/mcp/patterns/overlay-workflows.json +2 -2
  27. package/dist/mcp/patterns/reference.json +2 -2
  28. package/dist/mcp/patterns/states.json +2 -2
  29. package/dist/mcp/patterns/web-components.json +2 -2
  30. package/dist/mcp/resources.json +81 -78
  31. package/dist/mcp/search-index.json +22 -22
  32. package/dist/mcp/update.json +2 -2
  33. package/dist/mcp/worker.mjs +331 -286
  34. package/dist/mcp/worker.mjs.map +2 -2
  35. package/dist/web-components/README.md +7 -0
  36. package/dist/web-components/RUNTIME-NOTES.md +2 -0
  37. package/dist/web-components/components/actions.js +149 -2
  38. package/dist/web-components/components/feedback.js +63 -12
  39. package/dist/web-components/components/visualizations.js +629 -0
  40. package/dist/web-components/index.js +3642 -139
  41. package/package.json +13 -3
  42. package/src/icons/index.js +229 -0
  43. package/src/icons/package.json +3 -0
  44. package/src/inc-design-language.js +12 -11
  45. package/src/inc-design-language.scss +132 -1
  46. package/src/web-components/README.md +7 -0
  47. package/src/web-components/RUNTIME-NOTES.md +2 -0
  48. package/src/web-components/components/actions.js +149 -2
  49. package/src/web-components/components/feedback.js +63 -12
  50. package/src/web-components/components/visualizations.js +629 -0
  51. package/src/web-components/index.js +8 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@incursa/ui-kit",
3
- "version": "1.7.0",
3
+ "version": "1.9.0",
4
4
  "private": false,
5
5
  "description": "Reusable UI kit for data-heavy business applications.",
6
6
  "keywords": [
@@ -33,6 +33,9 @@
33
33
  "style": "./dist/web-components/style.css",
34
34
  "default": "./dist/web-components/index.js"
35
35
  },
36
+ "./icons": {
37
+ "default": "./dist/icons/index.js"
38
+ },
36
39
  "./web-components/style.css": "./dist/web-components/style.css",
37
40
  "./dist/inc-design-language.css": "./dist/inc-design-language.css",
38
41
  "./dist/inc-design-language.min.css": "./dist/inc-design-language.min.css",
@@ -52,11 +55,12 @@
52
55
  "scripts": {
53
56
  "build:css": "sass --load-path=node_modules --quiet-deps --silence-deprecation=import src/inc-design-language.scss dist/inc-design-language.css --style=expanded",
54
57
  "build:css:min": "sass --load-path=node_modules --quiet-deps --silence-deprecation=import src/inc-design-language.scss dist/inc-design-language.min.css --style=compressed",
55
- "build:js": "node -e \"require('fs').copyFileSync('src/inc-design-language.js', 'dist/inc-design-language.js')\"",
58
+ "build:icons": "node scripts/build-icons.mjs",
59
+ "build:js": "esbuild src/inc-design-language.js --bundle --format=iife --platform=browser --outfile=dist/inc-design-language.js",
56
60
  "build:wc": "node scripts/build-web-components.mjs",
57
61
  "build:mcp:manifests": "node scripts/generate-mcp.mjs",
58
62
  "build:mcp": "node scripts/build-mcp.mjs",
59
- "build": "npm run build:css && npm run build:css:min && npm run build:js && npm run build:wc && npm run build:mcp",
63
+ "build": "npm run build:icons && npm run build:css && npm run build:css:min && npm run build:js && npm run build:wc && npm run build:mcp",
60
64
  "test:browser:install": "playwright install chromium",
61
65
  "test:browser": "playwright test",
62
66
  "test:mcp": "node --test tests/mcp/transport.test.mjs tests/mcp/search.test.mjs tests/mcp/installation.test.mjs tests/mcp/markup.test.mjs tests/mcp/freshness.test.mjs",
@@ -70,6 +74,12 @@
70
74
  "pack:tarball": "npm pack",
71
75
  "package": "npm run build && npm run smoke && npm run pack:tarball"
72
76
  },
77
+ "dependencies": {
78
+ "d3-array": "^3.2.4",
79
+ "d3-scale": "^4.0.2",
80
+ "d3-shape": "^3.2.0",
81
+ "lucide": "^1.17.0"
82
+ },
73
83
  "devDependencies": {
74
84
  "@modelcontextprotocol/sdk": "^1.29.0",
75
85
  "@playwright/test": "^1.58.2",
@@ -0,0 +1,229 @@
1
+ import createLucideElement from "lucide/dist/esm/createElement.mjs";
2
+ import CircleCheck from "lucide/dist/esm/icons/circle-check.mjs";
3
+ import CircleHelp from "lucide/dist/esm/icons/circle-question-mark.mjs";
4
+ import CircleX from "lucide/dist/esm/icons/circle-x.mjs";
5
+ import Download from "lucide/dist/esm/icons/download.mjs";
6
+ import ExternalLink from "lucide/dist/esm/icons/external-link.mjs";
7
+ import FileText from "lucide/dist/esm/icons/file-text.mjs";
8
+ import FolderPlus from "lucide/dist/esm/icons/folder-plus.mjs";
9
+ import Info from "lucide/dist/esm/icons/info.mjs";
10
+ import Lock from "lucide/dist/esm/icons/lock.mjs";
11
+ import Pause from "lucide/dist/esm/icons/pause.mjs";
12
+ import Play from "lucide/dist/esm/icons/play.mjs";
13
+ import RefreshCw from "lucide/dist/esm/icons/refresh-cw.mjs";
14
+ import SearchX from "lucide/dist/esm/icons/search-x.mjs";
15
+ import Settings from "lucide/dist/esm/icons/settings.mjs";
16
+ import ShieldCheck from "lucide/dist/esm/icons/shield-check.mjs";
17
+ import TriangleAlert from "lucide/dist/esm/icons/triangle-alert.mjs";
18
+ import Upload from "lucide/dist/esm/icons/upload.mjs";
19
+
20
+ const ICON_NODES = Object.freeze({
21
+ info: Info,
22
+ help: CircleHelp,
23
+ success: CircleCheck,
24
+ warning: TriangleAlert,
25
+ error: CircleX,
26
+ upload: Upload,
27
+ document: FileText,
28
+ download: Download,
29
+ settings: Settings,
30
+ "external-link": ExternalLink,
31
+ empty: FolderPlus,
32
+ "no-results": SearchX,
33
+ loading: RefreshCw,
34
+ lock: Lock,
35
+ pause: Pause,
36
+ play: Play,
37
+ permission: ShieldCheck,
38
+ });
39
+
40
+ const ICON_NAMES = Object.freeze(Object.keys(ICON_NODES));
41
+ const DEFAULT_SIZE = 16;
42
+
43
+ function getNamespace() {
44
+ if (typeof globalThis === "undefined") {
45
+ return null;
46
+ }
47
+
48
+ const root = globalThis.IncWebComponents || (globalThis.IncWebComponents = {});
49
+ const icons = root.icons || (root.icons = {});
50
+
51
+ if (!icons.names) {
52
+ icons.names = ICON_NAMES;
53
+ }
54
+
55
+ if (!icons.defaultRenderer) {
56
+ icons.defaultRenderer = renderDefaultIcon;
57
+ }
58
+
59
+ if (!icons.render) {
60
+ icons.render = renderIncIcon;
61
+ }
62
+
63
+ if (!icons.setRenderer) {
64
+ icons.setRenderer = setIconRenderer;
65
+ }
66
+
67
+ return icons;
68
+ }
69
+
70
+ function normalizeIconName(name) {
71
+ return String(name || "")
72
+ .trim()
73
+ .toLowerCase()
74
+ .replace(/[_\s]+/g, "-");
75
+ }
76
+
77
+ function normalizeSize(value) {
78
+ const parsed = Number.parseFloat(value);
79
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_SIZE;
80
+ }
81
+
82
+ function buildIconAttributes(name, options = {}) {
83
+ const size = normalizeSize(options.size);
84
+ const className = options.className || "inc-icon";
85
+ const attrs = {
86
+ width: size,
87
+ height: size,
88
+ "data-inc-icon": name,
89
+ class: className,
90
+ focusable: "false",
91
+ };
92
+
93
+ if (options.decorative !== false) {
94
+ attrs["aria-hidden"] = "true";
95
+ } else {
96
+ attrs.role = "img";
97
+ attrs["aria-label"] = options.label || name;
98
+ }
99
+
100
+ return attrs;
101
+ }
102
+
103
+ function renderDefaultIcon(name, options = {}) {
104
+ const normalizedName = normalizeIconName(name);
105
+ const iconNode = ICON_NODES[normalizedName] || ICON_NODES.info;
106
+
107
+ if (typeof document === "undefined") {
108
+ return "";
109
+ }
110
+
111
+ return createLucideElement(iconNode, buildIconAttributes(normalizedName, options));
112
+ }
113
+
114
+ function coerceIconResult(result) {
115
+ if (!result || typeof document === "undefined") {
116
+ return null;
117
+ }
118
+
119
+ if (result instanceof Node) {
120
+ return result;
121
+ }
122
+
123
+ if (typeof result === "string") {
124
+ const template = document.createElement("template");
125
+ template.innerHTML = result.trim();
126
+ return template.content.firstElementChild || null;
127
+ }
128
+
129
+ return null;
130
+ }
131
+
132
+ function getIconRenderer() {
133
+ const namespace = getNamespace();
134
+ return typeof namespace?.renderer === "function"
135
+ ? namespace.renderer
136
+ : renderDefaultIcon;
137
+ }
138
+
139
+ function setIconRenderer(renderer) {
140
+ const namespace = getNamespace();
141
+ if (!namespace) {
142
+ return null;
143
+ }
144
+
145
+ if (renderer == null) {
146
+ delete namespace.renderer;
147
+ return null;
148
+ }
149
+
150
+ if (typeof renderer !== "function") {
151
+ throw new TypeError("Inc icon renderer must be a function.");
152
+ }
153
+
154
+ namespace.renderer = renderer;
155
+ return renderer;
156
+ }
157
+
158
+ function renderIncIcon(name, options = {}) {
159
+ const normalizedName = normalizeIconName(name) || "info";
160
+ const renderer = getIconRenderer();
161
+ const rendered = renderer(normalizedName, options);
162
+ const icon = coerceIconResult(rendered) || coerceIconResult(renderDefaultIcon(normalizedName, options));
163
+
164
+ if (icon instanceof Element && options.decorative !== false) {
165
+ icon.setAttribute("aria-hidden", "true");
166
+ icon.removeAttribute("aria-label");
167
+ icon.removeAttribute("role");
168
+ }
169
+
170
+ return icon;
171
+ }
172
+
173
+ function replaceIconContents(container, name, options = {}) {
174
+ if (!(container instanceof Element)) {
175
+ return null;
176
+ }
177
+
178
+ container.replaceChildren();
179
+ const icon = renderIncIcon(name, options);
180
+ if (icon) {
181
+ icon.setAttribute("data-inc-generated-icon", "true");
182
+ icon.setAttribute("data-inc-icon-upgraded", "true");
183
+ container.append(icon);
184
+ }
185
+
186
+ return icon;
187
+ }
188
+
189
+ function upgradeIconPlaceholders(root = typeof document !== "undefined" ? document : null) {
190
+ if (!root || typeof root.querySelectorAll !== "function") {
191
+ return [];
192
+ }
193
+
194
+ const upgraded = [];
195
+ root.querySelectorAll("[data-inc-icon]").forEach((node) => {
196
+ if (!(node instanceof Element)) {
197
+ return;
198
+ }
199
+
200
+ const name = node.getAttribute("data-inc-icon");
201
+ if (!name || node.hasAttribute("data-inc-icon-upgraded") || node.hasAttribute("data-inc-generated-icon")) {
202
+ return;
203
+ }
204
+
205
+ replaceIconContents(node, name, {
206
+ className: node.getAttribute("data-inc-icon-class") || "inc-icon",
207
+ decorative: node.getAttribute("aria-hidden") !== "false",
208
+ label: node.getAttribute("aria-label") || undefined,
209
+ size: node.getAttribute("data-inc-icon-size") || undefined,
210
+ });
211
+ node.setAttribute("data-inc-icon-upgraded", "true");
212
+ upgraded.push(node);
213
+ });
214
+
215
+ return upgraded;
216
+ }
217
+
218
+ getNamespace();
219
+
220
+ export {
221
+ ICON_NAMES as incIconNames,
222
+ getIconRenderer,
223
+ normalizeIconName,
224
+ renderDefaultIcon,
225
+ renderIncIcon,
226
+ replaceIconContents,
227
+ setIconRenderer,
228
+ upgradeIconPlaceholders,
229
+ };
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "module"
3
+ }
@@ -1,3 +1,8 @@
1
+ import {
2
+ replaceIconContents,
3
+ upgradeIconPlaceholders,
4
+ } from "./icons/index.js";
5
+
1
6
  (function () {
2
7
  "use strict";
3
8
 
@@ -12,6 +17,7 @@
12
17
  themeLabel: "[data-inc-theme-label]",
13
18
  themeSwitcher: "[data-inc-theme-switcher], details.inc-theme-switcher",
14
19
  nativeDialogOpen: "[data-inc-native-dialog-open]",
20
+ icon: "[data-inc-icon]",
15
21
  autoRefresh: "[data-inc-auto-refresh]",
16
22
  autoRefreshToggle: '[data-inc-action="auto-refresh-toggle"]',
17
23
  fileExample: "[data-inc-file-example]",
@@ -1132,16 +1138,6 @@
1132
1138
  return `${minutes}m ${seconds}s`;
1133
1139
  }
1134
1140
 
1135
- const AUTO_REFRESH_PAUSE_ICON = `
1136
- <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true">
1137
- <path d="M4 3h3v10H4zM9 3h3v10H9z"></path>
1138
- </svg>`.trim();
1139
-
1140
- const AUTO_REFRESH_PLAY_ICON = `
1141
- <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true">
1142
- <path d="M4 3.5v9l8-4.5-8-4.5z"></path>
1143
- </svg>`.trim();
1144
-
1145
1141
  function getAutoRefreshParts(root) {
1146
1142
  const toggle = root.querySelector(".inc-auto-refresh__toggle");
1147
1143
 
@@ -1183,7 +1179,11 @@
1183
1179
  }
1184
1180
 
1185
1181
  if (parts.toggleIcon instanceof HTMLElement) {
1186
- parts.toggleIcon.innerHTML = isPaused ? AUTO_REFRESH_PLAY_ICON : AUTO_REFRESH_PAUSE_ICON;
1182
+ replaceIconContents(parts.toggleIcon, isPaused ? "play" : "pause", {
1183
+ className: "inc-icon",
1184
+ decorative: true,
1185
+ size: 16,
1186
+ });
1187
1187
  }
1188
1188
  }
1189
1189
 
@@ -1848,6 +1848,7 @@
1848
1848
  initializeMenus();
1849
1849
  initializeCollapses();
1850
1850
  initializeTabs();
1851
+ upgradeIconPlaceholders(document);
1851
1852
  initializeFileExamples();
1852
1853
  initializeAutoRefresh();
1853
1854
  attachEventHandlers();
@@ -448,6 +448,12 @@
448
448
  // Buttons, badges, alerts, and form primitives
449
449
  // -----------------------------------------------------------------------------
450
450
 
451
+ .inc-icon {
452
+ display: block;
453
+ flex: 0 0 auto;
454
+ stroke: currentColor;
455
+ }
456
+
451
457
  .inc-btn {
452
458
  @extend .btn;
453
459
  display: inline-flex;
@@ -457,6 +463,15 @@
457
463
  vertical-align: middle;
458
464
  transition: color 0.18s ease, background-color 0.18s ease, border-color 0.18s ease, box-shadow 0.18s ease;
459
465
 
466
+ &__icon {
467
+ display: inline-flex;
468
+ align-items: center;
469
+ justify-content: center;
470
+ width: 1rem;
471
+ height: 1rem;
472
+ flex: 0 0 auto;
473
+ }
474
+
460
475
  &--primary {
461
476
  @extend .btn-primary;
462
477
  }
@@ -736,6 +751,17 @@
736
751
  @extend .alert-dismissible;
737
752
  }
738
753
 
754
+ &__icon {
755
+ display: inline-flex;
756
+ align-items: center;
757
+ justify-content: center;
758
+ width: 1.125rem;
759
+ height: 1.125rem;
760
+ margin-inline-end: 0.5rem;
761
+ vertical-align: -0.2em;
762
+ color: currentColor;
763
+ }
764
+
739
765
  &__heading {
740
766
  @extend .alert-heading;
741
767
  }
@@ -1175,6 +1201,12 @@
1175
1201
  display: inline-flex;
1176
1202
  align-items: center;
1177
1203
  justify-content: center;
1204
+
1205
+ svg {
1206
+ display: block;
1207
+ width: 2.125rem;
1208
+ height: 2.125rem;
1209
+ }
1178
1210
  }
1179
1211
 
1180
1212
  &__form {
@@ -3238,7 +3270,6 @@ dialog.inc-native-dialog.inc-native-dialog--drawer .inc-native-dialog__body {
3238
3270
  display: block;
3239
3271
  width: 1rem;
3240
3272
  height: 1rem;
3241
- fill: currentColor;
3242
3273
  }
3243
3274
  }
3244
3275
 
@@ -3363,6 +3394,100 @@ dialog.inc-native-dialog.inc-native-dialog--drawer .inc-native-dialog__body {
3363
3394
  }
3364
3395
  }
3365
3396
 
3397
+ .inc-sparkline {
3398
+ --inc-sparkline-stroke: var(--inc-text-secondary);
3399
+ --inc-sparkline-fill: rgba(var(--inc-text-secondary-rgb), 0.12);
3400
+ --inc-sparkline-marker: var(--inc-sparkline-stroke);
3401
+ --inc-sparkline-reference: rgba(var(--inc-text-muted-rgb), 0.68);
3402
+ --inc-sparkline-muted: rgba(var(--inc-text-muted-rgb), 0.54);
3403
+ display: inline-flex;
3404
+ align-items: center;
3405
+ justify-content: center;
3406
+ inline-size: var(--inc-sparkline-width, 7.5rem);
3407
+ block-size: var(--inc-sparkline-height, 2rem);
3408
+ min-inline-size: 1rem;
3409
+ min-block-size: 1rem;
3410
+ vertical-align: middle;
3411
+ color: var(--inc-sparkline-stroke);
3412
+ contain: paint;
3413
+
3414
+ &--tone-positive {
3415
+ --inc-sparkline-stroke: var(--bs-success);
3416
+ --inc-sparkline-fill: rgba(var(--bs-success-rgb), 0.16);
3417
+ --inc-sparkline-marker: var(--bs-success-text-emphasis);
3418
+ }
3419
+
3420
+ &--tone-negative {
3421
+ --inc-sparkline-stroke: var(--bs-danger);
3422
+ --inc-sparkline-fill: rgba(var(--bs-danger-rgb), 0.14);
3423
+ --inc-sparkline-marker: var(--bs-danger-text-emphasis);
3424
+ }
3425
+
3426
+ &--tone-muted {
3427
+ --inc-sparkline-stroke: var(--inc-text-muted);
3428
+ --inc-sparkline-fill: rgba(var(--inc-text-muted-rgb), 0.1);
3429
+ --inc-sparkline-marker: var(--inc-text-secondary);
3430
+ }
3431
+
3432
+ &--tone-accent {
3433
+ --inc-sparkline-stroke: var(--bs-primary);
3434
+ --inc-sparkline-fill: rgba(var(--bs-primary-rgb), 0.14);
3435
+ --inc-sparkline-marker: var(--bs-primary);
3436
+ }
3437
+
3438
+ &__svg {
3439
+ display: block;
3440
+ inline-size: 100%;
3441
+ block-size: 100%;
3442
+ overflow: visible;
3443
+ }
3444
+
3445
+ &__line,
3446
+ &__empty-line {
3447
+ fill: none;
3448
+ stroke: var(--inc-sparkline-stroke);
3449
+ stroke-width: 1.6;
3450
+ stroke-linecap: round;
3451
+ stroke-linejoin: round;
3452
+ }
3453
+
3454
+ &__area {
3455
+ fill: var(--inc-sparkline-fill);
3456
+ stroke: none;
3457
+ }
3458
+
3459
+ &__bar {
3460
+ fill: var(--inc-sparkline-stroke);
3461
+ opacity: 0.82;
3462
+ }
3463
+
3464
+ &__marker {
3465
+ fill: var(--inc-sparkline-marker);
3466
+ stroke: var(--inc-surface-primary);
3467
+ stroke-width: 1.5;
3468
+ }
3469
+
3470
+ &__reference {
3471
+ stroke: var(--inc-sparkline-reference);
3472
+ stroke-width: 1;
3473
+ stroke-dasharray: 3 3;
3474
+ }
3475
+
3476
+ &__empty-line {
3477
+ stroke: var(--inc-sparkline-muted);
3478
+ stroke-dasharray: 2 4;
3479
+ }
3480
+
3481
+ &__empty {
3482
+ fill: var(--inc-text-muted);
3483
+ font-family: $font-family-sans-serif;
3484
+ font-size: 0.625rem;
3485
+ font-weight: 600;
3486
+ letter-spacing: 0;
3487
+ pointer-events: none;
3488
+ }
3489
+ }
3490
+
3366
3491
  .inc-alert-container {
3367
3492
  @extend .container-xxl;
3368
3493
  position: relative;
@@ -4644,6 +4769,12 @@ body.inc-offcanvas-open {
4644
4769
  font-size: 1.25rem;
4645
4770
  font-weight: 700;
4646
4771
  flex: 0 0 auto;
4772
+
4773
+ svg {
4774
+ display: block;
4775
+ width: 1.375rem;
4776
+ height: 1.375rem;
4777
+ }
4647
4778
  }
4648
4779
 
4649
4780
  &__title {
@@ -8,9 +8,11 @@ The CSS-first [`inc-*`](../../reference.html) class surface remains the canonica
8
8
 
9
9
  - Package entrypoint: `@incursa/ui-kit/web-components`
10
10
  - Style entrypoint: `@incursa/ui-kit/web-components/style.css`
11
+ - Icon entrypoint: `@incursa/ui-kit/icons`
11
12
  - Built output: `dist/web-components/`
12
13
  - Package export: `./web-components` resolves to `dist/web-components/index.js`
13
14
  - Package export: `./web-components/style.css` resolves to `dist/web-components/style.css`
15
+ - Package export: `./icons` resolves to `dist/icons/index.js`
14
16
  - Module boundary: `src/web-components/package.json` sets this subtree to `type: module`
15
17
 
16
18
  Load these entrypoints only when the consuming app wants the custom elements and their default look. CSS-only consumers should not pay for the runtime.
@@ -45,6 +47,8 @@ The runtime auto-defines the shipped elements on load. If a consumer needs expli
45
47
  The `IncElement` base class, including reflected attribute/property wiring and slot helpers.
46
48
  - [`registry.js`](registry.js)
47
49
  Idempotent registration helpers and the `IncWebComponents.registry` namespace.
50
+ - [`../icons/index.js`](../icons/index.js)
51
+ Semantic Incursa icon names, default Lucide-backed rendering, and the global renderer override used by component fallbacks.
48
52
  - [`components/dom-helpers.js`](components/dom-helpers.js)
49
53
  Shared DOM helpers used by the action and collection modules.
50
54
  - [`controllers/focus.js`](controllers/focus.js)
@@ -67,6 +71,8 @@ The runtime auto-defines the shipped elements on load. If a consumer needs expli
67
71
  Button, button-group, button-toolbar, close-button, alert, and empty-state custom elements.
68
72
  - [`components/collections.js`](components/collections.js)
69
73
  List-group, key-value-grid, and key-value custom elements.
74
+ - [`components/visualizations.js`](components/visualizations.js)
75
+ D3-backed sparkline custom element and small path/data helpers.
70
76
  - [`components/overlays.js`](components/overlays.js)
71
77
  Disclosure, dialog, and drawer custom elements.
72
78
  - [`index.js`](index.js)
@@ -82,6 +88,7 @@ The Web Component layer should mirror the current CSS kit, not reinterpret it.
82
88
  - Form wrappers should keep native controls native.
83
89
  - Navigation components should reflect keyboard and focus state in the DOM.
84
90
  - Feedback and status shells should announce state accessibly, badge/spinner atoms should standardize the common tone and loading defaults, and action/detail plus collection hosts should keep buttons, alerts, list groups, and description-list pairs declarative without inventing a second styling vocabulary.
91
+ - Visualization components should stay compact, accessible, and evidence-supporting. Use D3 for geometry and scales, not DOM mutation.
85
92
  - Overlays should prefer native `<details>` and `<dialog>` behavior when that satisfies the contract.
86
93
  - Tables, data presentation, utility atoms, and the remaining presentation-only surfaces should remain CSS-first until the component contract is explicit and worth the runtime cost.
87
94
 
@@ -12,6 +12,7 @@ The runtime defines the approved v1 host family set:
12
12
  - feedback and status: `inc-state-panel`, `inc-live-region`, `inc-auto-refresh`, `inc-theme-switcher`, `inc-badge`, `inc-spinner`
13
13
  - actions and detail shells: `inc-button`, `inc-button-group`, `inc-button-toolbar`, `inc-close-button`, `inc-alert`, `inc-empty-state`
14
14
  - collections: `inc-list-group`, `inc-key-value-grid`, `inc-key-value`
15
+ - data visualization: `inc-sparkline`
15
16
  - overlays: `inc-disclosure`, `inc-dialog`, `inc-drawer`
16
17
 
17
18
  ## Contract shape
@@ -28,6 +29,7 @@ The runtime defines the approved v1 host family set:
28
29
  - `components/feedback.js`
29
30
  - `components/actions.js`
30
31
  - `components/collections.js`
32
+ - `components/visualizations.js`
31
33
  - `components/overlays.js`
32
34
  - Public registration API is idempotent:
33
35
  - `window.IncWebComponents.defineAll()`