@incursa/ui-kit 1.5.0 → 1.6.1

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 (78) hide show
  1. package/LLMS.txt +4 -4
  2. package/README.md +46 -6
  3. package/dist/inc-design-language.css +192 -35
  4. package/dist/inc-design-language.css.map +1 -1
  5. package/dist/inc-design-language.min.css +1 -1
  6. package/dist/inc-design-language.min.css.map +1 -1
  7. package/dist/mcp/ai/agent-instructions.json +21 -0
  8. package/dist/mcp/ai/llms-txt.json +21 -0
  9. package/dist/mcp/components/buttons.json +29 -0
  10. package/dist/mcp/components/cards.json +29 -0
  11. package/dist/mcp/components/filter-bars.json +28 -0
  12. package/dist/mcp/components/form-choices.json +29 -0
  13. package/dist/mcp/components/forms.json +29 -0
  14. package/dist/mcp/components/interaction.json +28 -0
  15. package/dist/mcp/components/layout.json +28 -0
  16. package/dist/mcp/components/metrics.json +28 -0
  17. package/dist/mcp/components/states.json +28 -0
  18. package/dist/mcp/components/status.json +28 -0
  19. package/dist/mcp/components/tables.json +32 -0
  20. package/dist/mcp/components/utilities.json +28 -0
  21. package/dist/mcp/examples/data-grid-advanced.json +22 -0
  22. package/dist/mcp/examples/demo.json +24 -0
  23. package/dist/mcp/examples/forms-and-validation.json +21 -0
  24. package/dist/mcp/examples/native-patterns.json +21 -0
  25. package/dist/mcp/examples/overlay-workflows.json +22 -0
  26. package/dist/mcp/examples/record-detail.json +21 -0
  27. package/dist/mcp/examples/reference.json +23 -0
  28. package/dist/mcp/examples/states.json +21 -0
  29. package/dist/mcp/examples/web-components.json +24 -0
  30. package/dist/mcp/examples/work-queue.json +21 -0
  31. package/dist/mcp/guides/allowed-web-component-families.json +19 -0
  32. package/dist/mcp/guides/choose-css-vs-scss-vs-js-vs-web-components.json +20 -0
  33. package/dist/mcp/guides/customization-order.json +20 -0
  34. package/dist/mcp/guides/decision-tree.json +28 -0
  35. package/dist/mcp/guides/guardrails.json +20 -0
  36. package/dist/mcp/guides/install.json +31 -0
  37. package/dist/mcp/guides/latest.json +25 -0
  38. package/dist/mcp/guides/overview.json +26 -0
  39. package/dist/mcp/guides/package-metadata.json +25 -0
  40. package/dist/mcp/guides/update.json +26 -0
  41. package/dist/mcp/guides/when-to-use-css-first.json +20 -0
  42. package/dist/mcp/install.json +36 -0
  43. package/dist/mcp/patterns/data-grid-advanced.json +22 -0
  44. package/dist/mcp/patterns/demo.json +24 -0
  45. package/dist/mcp/patterns/forms-and-validation.json +21 -0
  46. package/dist/mcp/patterns/native-patterns.json +21 -0
  47. package/dist/mcp/patterns/overlay-workflows.json +22 -0
  48. package/dist/mcp/patterns/record-detail.json +21 -0
  49. package/dist/mcp/patterns/reference.json +24 -0
  50. package/dist/mcp/patterns/states.json +21 -0
  51. package/dist/mcp/patterns/web-components.json +24 -0
  52. package/dist/mcp/patterns/work-queue.json +21 -0
  53. package/dist/mcp/resources.json +2100 -0
  54. package/dist/mcp/search-index.json +827 -0
  55. package/dist/mcp/specs/control-conventions.json +21 -0
  56. package/dist/mcp/specs/public-surface.json +21 -0
  57. package/dist/mcp/specs/requirements-index.json +21 -0
  58. package/dist/mcp/specs/verification-index.json +21 -0
  59. package/dist/mcp/update.json +24 -0
  60. package/dist/mcp/worker.mjs +59959 -0
  61. package/dist/mcp/worker.mjs.map +7 -0
  62. package/dist/web-components/README.md +10 -4
  63. package/dist/web-components/RUNTIME-NOTES.md +7 -2
  64. package/dist/web-components/components/actions.js +557 -0
  65. package/dist/web-components/components/collections.js +272 -0
  66. package/dist/web-components/components/dom-helpers.js +46 -0
  67. package/dist/web-components/components/feedback.js +165 -0
  68. package/dist/web-components/index.js +4350 -813
  69. package/package.json +19 -8
  70. package/src/inc-design-language.scss +193 -35
  71. package/src/mcp/worker.ts +858 -0
  72. package/src/web-components/README.md +10 -4
  73. package/src/web-components/RUNTIME-NOTES.md +7 -2
  74. package/src/web-components/components/actions.js +557 -0
  75. package/src/web-components/components/collections.js +272 -0
  76. package/src/web-components/components/dom-helpers.js +46 -0
  77. package/src/web-components/components/feedback.js +165 -0
  78. package/src/web-components/index.js +53 -847
@@ -0,0 +1,272 @@
1
+ import { IncElement } from "../base-element.js";
2
+ import {
3
+ addClass,
4
+ ensureNode,
5
+ normalizeToken,
6
+ removeMatchingClasses,
7
+ } from "./dom-helpers.js";
8
+
9
+ const FALSE_TOKENS = new Set(["false", "0", "off", "no"]);
10
+
11
+ function toBoolean(value, fallback = false) {
12
+ if (value == null) {
13
+ return fallback;
14
+ }
15
+
16
+ return !FALSE_TOKENS.has(String(value).toLowerCase());
17
+ }
18
+
19
+ export class IncListGroupElement extends IncElement {
20
+ static get observedAttributes() {
21
+ return ["flush", "numbered", "dense", "interactive", "label"];
22
+ }
23
+
24
+ connectedCallback() {
25
+ addClass(this, "inc-list-group");
26
+ this.sync();
27
+ }
28
+
29
+ attributeChangedCallback() {
30
+ if (this.isConnected) {
31
+ this.sync();
32
+ }
33
+ }
34
+
35
+ sync() {
36
+ addClass(this, "inc-list-group");
37
+ this.setAttribute("part", "list-group");
38
+ removeMatchingClasses(this, (token) => token.startsWith("inc-list-group--"));
39
+
40
+ if (toBoolean(this.getAttribute("flush"))) {
41
+ this.classList.add("inc-list-group--flush");
42
+ }
43
+ if (toBoolean(this.getAttribute("numbered"))) {
44
+ this.classList.add("inc-list-group--numbered");
45
+ }
46
+ if (toBoolean(this.getAttribute("dense"))) {
47
+ this.classList.add("inc-list-group--dense");
48
+ }
49
+ if (toBoolean(this.getAttribute("interactive"))) {
50
+ this.classList.add("inc-list-group--interactive");
51
+ }
52
+
53
+ this.setAttribute("role", "list");
54
+ const label = this.getAttribute("label") || this.getAttribute("aria-label") || "";
55
+ if (label) {
56
+ this.setAttribute("aria-label", label);
57
+ } else {
58
+ this.removeAttribute("aria-label");
59
+ }
60
+
61
+ Array.from(this.children).forEach((node) => {
62
+ if (!(node instanceof Element)) {
63
+ return;
64
+ }
65
+
66
+ if (node.getAttribute("slot") === "item") {
67
+ node.removeAttribute("slot");
68
+ }
69
+
70
+ node.classList.add("inc-list-group__item");
71
+ if (toBoolean(this.getAttribute("interactive")) || node.matches("a[href], button:not([disabled])")) {
72
+ node.classList.add("inc-list-group__item--action");
73
+ }
74
+ if (!node.hasAttribute("role") && !node.matches("a[href], button")) {
75
+ node.setAttribute("role", "listitem");
76
+ }
77
+ });
78
+ }
79
+ }
80
+
81
+ export class IncKeyValueGridElement extends IncElement {
82
+ static get observedAttributes() {
83
+ return ["columns", "dense"];
84
+ }
85
+
86
+ connectedCallback() {
87
+ addClass(this, "inc-key-value-grid");
88
+ this.sync();
89
+ }
90
+
91
+ attributeChangedCallback() {
92
+ if (this.isConnected) {
93
+ this.sync();
94
+ }
95
+ }
96
+
97
+ sync() {
98
+ addClass(this, "inc-key-value-grid");
99
+ this.setAttribute("part", "grid");
100
+ const columns = Number.parseInt(this.getAttribute("columns") || "", 10);
101
+ if (Number.isFinite(columns) && columns > 0) {
102
+ this.style.gridTemplateColumns = `repeat(${columns}, minmax(0, 1fr))`;
103
+ } else {
104
+ this.style.removeProperty("grid-template-columns");
105
+ }
106
+
107
+ if (toBoolean(this.getAttribute("dense"))) {
108
+ this.style.rowGap = "0.5rem";
109
+ this.style.columnGap = "1rem";
110
+ } else {
111
+ this.style.removeProperty("row-gap");
112
+ this.style.removeProperty("column-gap");
113
+ }
114
+ }
115
+ }
116
+
117
+ export class IncKeyValueElement extends IncElement {
118
+ static get observedAttributes() {
119
+ return ["label", "value", "meta", "inline", "dense", "card", "variant"];
120
+ }
121
+
122
+ connectedCallback() {
123
+ addClass(this, "inc-key-value");
124
+ this.sync();
125
+ }
126
+
127
+ attributeChangedCallback() {
128
+ if (this.isConnected) {
129
+ this.sync();
130
+ }
131
+ }
132
+
133
+ sync() {
134
+ addClass(this, "inc-key-value");
135
+ this.setAttribute("part", "key-value");
136
+ removeMatchingClasses(this, (token) => token.startsWith("inc-key-value--"));
137
+
138
+ const variant = normalizeToken(this.getAttribute("variant"));
139
+ const card = toBoolean(this.getAttribute("card")) || variant === "card";
140
+ if (card) {
141
+ this.classList.add("inc-key-value--card");
142
+ }
143
+ if (toBoolean(this.getAttribute("inline"))) {
144
+ this.classList.add("inc-key-value--inline");
145
+ }
146
+ if (toBoolean(this.getAttribute("dense"))) {
147
+ this.classList.add("inc-key-value--dense");
148
+ }
149
+
150
+ const definition = ensureNode(this, ".inc-key-value__definition", () => {
151
+ const node = document.createElement("dl");
152
+ node.className = "inc-key-value__definition";
153
+ node.innerHTML = [
154
+ '<dt class="inc-key-value__label" part="label"></dt>',
155
+ '<dd class="inc-key-value__value" part="value"></dd>',
156
+ '<div class="inc-key-value__meta" part="meta"></div>',
157
+ ].join("");
158
+ return node;
159
+ });
160
+ const label = ensureNode(definition, ".inc-key-value__label", () => {
161
+ const node = document.createElement("dt");
162
+ node.className = "inc-key-value__label";
163
+ node.setAttribute("part", "label");
164
+ return node;
165
+ });
166
+ const value = ensureNode(definition, ".inc-key-value__value", () => {
167
+ const node = document.createElement("dd");
168
+ node.className = "inc-key-value__value";
169
+ node.setAttribute("part", "value");
170
+ return node;
171
+ });
172
+ const meta = ensureNode(definition, ".inc-key-value__meta", () => {
173
+ const node = document.createElement("div");
174
+ node.className = "inc-key-value__meta";
175
+ node.setAttribute("part", "meta");
176
+ return node;
177
+ });
178
+
179
+ Array.from(this.childNodes).forEach((node) => {
180
+ if (node === definition) {
181
+ return;
182
+ }
183
+
184
+ if (node.nodeType === Node.ELEMENT_NODE && node.getAttribute("slot") === "label") {
185
+ node.removeAttribute("slot");
186
+ label.append(node);
187
+ return;
188
+ }
189
+
190
+ if (node.nodeType === Node.ELEMENT_NODE && node.getAttribute("slot") === "value") {
191
+ node.removeAttribute("slot");
192
+ value.append(node);
193
+ return;
194
+ }
195
+
196
+ if (node.nodeType === Node.ELEMENT_NODE && node.getAttribute("slot") === "meta") {
197
+ node.removeAttribute("slot");
198
+ meta.append(node);
199
+ return;
200
+ }
201
+
202
+ if (value.childNodes.length === 0 || node.nodeType === Node.TEXT_NODE) {
203
+ value.append(node);
204
+ return;
205
+ }
206
+
207
+ meta.append(node);
208
+ });
209
+
210
+ const labelText = this.getAttribute("label") || "";
211
+ const valueText = this.getAttribute("value") || "";
212
+ const metaText = this.getAttribute("meta") || "";
213
+
214
+ if (!label.childNodes.length) {
215
+ label.textContent = labelText;
216
+ }
217
+ if (!value.childNodes.length) {
218
+ value.textContent = valueText;
219
+ }
220
+ if (!meta.childNodes.length) {
221
+ meta.textContent = metaText;
222
+ }
223
+ }
224
+ }
225
+
226
+ export const collectionDefinitions = [
227
+ ["inc-list-group", IncListGroupElement],
228
+ ["inc-key-value-grid", IncKeyValueGridElement],
229
+ ["inc-key-value", IncKeyValueElement],
230
+ ];
231
+
232
+ export const collectionComponents = {
233
+ IncListGroupElement,
234
+ IncKeyValueGridElement,
235
+ IncKeyValueElement,
236
+ };
237
+
238
+ function defineCollectionComponents(registry = globalThis.customElements) {
239
+ if (!registry || typeof registry.define !== "function" || typeof registry.get !== "function") {
240
+ return [];
241
+ }
242
+
243
+ const defined = [];
244
+ for (const [tagName, ctor] of collectionDefinitions) {
245
+ if (!registry.get(tagName)) {
246
+ registry.define(tagName, ctor);
247
+ defined.push(tagName);
248
+ }
249
+ }
250
+
251
+ return defined;
252
+ }
253
+
254
+ if (typeof module !== "undefined" && module.exports) {
255
+ module.exports = {
256
+ defineCollectionComponents,
257
+ collectionDefinitions,
258
+ collectionComponents,
259
+ IncListGroupElement,
260
+ IncKeyValueGridElement,
261
+ IncKeyValueElement,
262
+ };
263
+ }
264
+
265
+ if (typeof globalThis !== "undefined") {
266
+ const namespace = globalThis.IncWebComponents || (globalThis.IncWebComponents = {});
267
+ namespace.collections = Object.assign({}, namespace.collections, {
268
+ defineCollectionComponents,
269
+ collectionDefinitions,
270
+ components: collectionComponents,
271
+ });
272
+ }
@@ -0,0 +1,46 @@
1
+ const ElementRef = typeof Element === "undefined" ? null : Element;
2
+
3
+ function normalizeToken(value) {
4
+ return String(value ?? "").trim().toLowerCase();
5
+ }
6
+
7
+ function addClass(node, className) {
8
+ if (ElementRef && node instanceof ElementRef && className) {
9
+ node.classList.add(className);
10
+ }
11
+ }
12
+
13
+ function removeMatchingClasses(node, predicate) {
14
+ if (!ElementRef || !(node instanceof ElementRef)) {
15
+ return;
16
+ }
17
+
18
+ Array.from(node.classList)
19
+ .filter((token) => predicate(token))
20
+ .forEach((token) => node.classList.remove(token));
21
+ }
22
+
23
+ function moveChildNodes(source, target, predicate = () => true) {
24
+ Array.from(source.childNodes)
25
+ .filter((node) => predicate(node))
26
+ .forEach((node) => target.append(node));
27
+ }
28
+
29
+ function ensureNode(parent, selector, build) {
30
+ const existing = parent.querySelector(`:scope > ${selector}`);
31
+ if (existing) {
32
+ return existing;
33
+ }
34
+
35
+ const node = build();
36
+ parent.append(node);
37
+ return node;
38
+ }
39
+
40
+ export {
41
+ addClass,
42
+ ensureNode,
43
+ moveChildNodes,
44
+ normalizeToken,
45
+ removeMatchingClasses,
46
+ };
@@ -1,5 +1,7 @@
1
1
  const THEME_MODES = ["light", "dark", "system"];
2
2
  const DEFAULT_THEME_STORAGE_KEY = "inc-theme-mode";
3
+ const BADGE_TONES = new Set(["primary", "secondary", "success", "danger", "warning", "info"]);
4
+ const SPINNER_VARIANTS = new Set(["border", "grow"]);
3
5
  const HostElement = typeof HTMLElement === "undefined" ? class {} : HTMLElement;
4
6
  const themeSubscribers = new Set();
5
7
 
@@ -32,6 +34,10 @@ function toPositiveInt(value) {
32
34
  return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
33
35
  }
34
36
 
37
+ function normalizeToken(value) {
38
+ return String(value ?? "").trim().toLowerCase();
39
+ }
40
+
35
41
  function getSystemTheme() {
36
42
  if (!window.matchMedia) {
37
43
  return "light";
@@ -281,6 +287,59 @@ export class IncStatePanel extends HostElement {
281
287
  }
282
288
  }
283
289
 
290
+ export class IncBadgeElement extends HostElement {
291
+ static observedAttributes = ["tone", "variant", "pill"];
292
+
293
+ connectedCallback() {
294
+ this.classList.add("inc-badge");
295
+ this.#sync();
296
+ }
297
+
298
+ attributeChangedCallback() {
299
+ this.#sync();
300
+ }
301
+
302
+ get tone() {
303
+ return this.getAttribute("tone") || this.getAttribute("variant") || "";
304
+ }
305
+
306
+ set tone(value) {
307
+ if (value == null || value === "") {
308
+ this.removeAttribute("tone");
309
+ return;
310
+ }
311
+
312
+ this.setAttribute("tone", String(value));
313
+ }
314
+
315
+ get pill() {
316
+ return this.hasAttribute("pill");
317
+ }
318
+
319
+ set pill(value) {
320
+ if (value) {
321
+ this.setAttribute("pill", "");
322
+ } else {
323
+ this.removeAttribute("pill");
324
+ }
325
+ }
326
+
327
+ #sync() {
328
+ this.classList.add("inc-badge");
329
+ BADGE_TONES.forEach((tone) => this.classList.remove(`inc-badge--${tone}`));
330
+ this.classList.remove("inc-badge--pill");
331
+
332
+ const tone = normalizeToken(this.tone);
333
+ if (BADGE_TONES.has(tone)) {
334
+ this.classList.add(`inc-badge--${tone}`);
335
+ }
336
+
337
+ if (this.pill) {
338
+ this.classList.add("inc-badge--pill");
339
+ }
340
+ }
341
+ }
342
+
284
343
  export class IncLiveRegion extends HostElement {
285
344
  static observedAttributes = ["politeness", "atomic", "busy"];
286
345
 
@@ -356,6 +415,107 @@ export class IncLiveRegion extends HostElement {
356
415
  }
357
416
  }
358
417
 
418
+ export class IncSpinnerElement extends HostElement {
419
+ static observedAttributes = ["variant", "tone", "size", "label"];
420
+
421
+ connectedCallback() {
422
+ this.#sync();
423
+ }
424
+
425
+ attributeChangedCallback() {
426
+ this.#sync();
427
+ }
428
+
429
+ get variant() {
430
+ return this.getAttribute("variant") || "";
431
+ }
432
+
433
+ set variant(value) {
434
+ if (value == null || value === "") {
435
+ this.removeAttribute("variant");
436
+ return;
437
+ }
438
+
439
+ this.setAttribute("variant", String(value));
440
+ }
441
+
442
+ get tone() {
443
+ return this.getAttribute("tone") || "";
444
+ }
445
+
446
+ set tone(value) {
447
+ if (value == null || value === "") {
448
+ this.removeAttribute("tone");
449
+ return;
450
+ }
451
+
452
+ this.setAttribute("tone", String(value));
453
+ }
454
+
455
+ get size() {
456
+ return this.getAttribute("size") || "";
457
+ }
458
+
459
+ set size(value) {
460
+ if (value == null || value === "") {
461
+ this.removeAttribute("size");
462
+ return;
463
+ }
464
+
465
+ this.setAttribute("size", String(value));
466
+ }
467
+
468
+ get label() {
469
+ return this.getAttribute("label") || "";
470
+ }
471
+
472
+ set label(value) {
473
+ if (value == null || value === "") {
474
+ this.removeAttribute("label");
475
+ return;
476
+ }
477
+
478
+ this.setAttribute("label", String(value));
479
+ }
480
+
481
+ #sync() {
482
+ this.classList.add("inc-spinner");
483
+
484
+ SPINNER_VARIANTS.forEach((variant) => {
485
+ this.classList.remove(`inc-spinner--${variant}`);
486
+ this.classList.remove(`inc-spinner--${variant}--sm`);
487
+ BADGE_TONES.forEach((tone) => this.classList.remove(`inc-spinner--${variant}--${tone}`));
488
+ });
489
+
490
+ const variant = normalizeToken(this.variant) || "border";
491
+ const resolvedVariant = SPINNER_VARIANTS.has(variant) ? variant : "border";
492
+ this.classList.add(`inc-spinner--${resolvedVariant}`);
493
+
494
+ if (normalizeToken(this.size) === "sm") {
495
+ this.classList.add(`inc-spinner--${resolvedVariant}--sm`);
496
+ }
497
+
498
+ const tone = normalizeToken(this.tone);
499
+ if (BADGE_TONES.has(tone)) {
500
+ this.classList.add(`inc-spinner--${resolvedVariant}--${tone}`);
501
+ }
502
+
503
+ const label = this.label.trim();
504
+ if (label) {
505
+ this.removeAttribute("aria-hidden");
506
+ this.setAttribute("role", "status");
507
+ this.setAttribute("aria-live", "polite");
508
+ this.setAttribute("aria-label", label);
509
+ return;
510
+ }
511
+
512
+ this.setAttribute("aria-hidden", "true");
513
+ this.removeAttribute("role");
514
+ this.removeAttribute("aria-live");
515
+ this.removeAttribute("aria-label");
516
+ }
517
+ }
518
+
359
519
  export class IncAutoRefresh extends HostElement {
360
520
  static observedAttributes = [
361
521
  "seconds",
@@ -525,6 +685,7 @@ export class IncAutoRefresh extends HostElement {
525
685
  <span class="inc-auto-refresh__status-text"></span>
526
686
  </span>
527
687
  <button type="button" class="inc-auto-refresh__toggle inc-btn inc-btn--outline-secondary inc-btn--micro" part="toggle">
688
+ <span class="inc-auto-refresh__toggle-icon" aria-hidden="true"></span>
528
689
  <span class="inc-auto-refresh__toggle-text"></span>
529
690
  </button>
530
691
  `.trim();
@@ -1041,8 +1202,10 @@ export class IncThemeSwitcher extends HostElement {
1041
1202
  }
1042
1203
 
1043
1204
  export const feedbackDefinitions = [
1205
+ ["inc-badge", IncBadgeElement],
1044
1206
  ["inc-state-panel", IncStatePanel],
1045
1207
  ["inc-live-region", IncLiveRegion],
1208
+ ["inc-spinner", IncSpinnerElement],
1046
1209
  ["inc-auto-refresh", IncAutoRefresh],
1047
1210
  ["inc-theme-switcher", IncThemeSwitcher],
1048
1211
  ];
@@ -1065,6 +1228,8 @@ if (typeof globalThis !== "undefined") {
1065
1228
  defineFeedbackComponents,
1066
1229
  feedbackDefinitions,
1067
1230
  components: {
1231
+ IncBadgeElement,
1232
+ IncSpinnerElement,
1068
1233
  IncStatePanel,
1069
1234
  IncLiveRegion,
1070
1235
  IncAutoRefresh,