@adia-ai/web-components 0.5.7 → 0.5.9

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 (134) hide show
  1. package/USAGE.md +218 -0
  2. package/components/accordion/accordion.d.ts +22 -1
  3. package/components/action-list/action-list.d.ts +14 -1
  4. package/components/agent-artifact/agent-artifact.d.ts +1 -1
  5. package/components/agent-feedback-bar/agent-feedback-bar.d.ts +1 -1
  6. package/components/agent-questions/agent-questions.d.ts +1 -1
  7. package/components/agent-reasoning/agent-reasoning.d.ts +1 -1
  8. package/components/agent-suggestions/agent-suggestions.d.ts +1 -1
  9. package/components/agent-trace/agent-trace.d.ts +1 -1
  10. package/components/alert/alert.d.ts +1 -1
  11. package/components/avatar/avatar.d.ts +8 -1
  12. package/components/badge/badge.d.ts +1 -1
  13. package/components/block/block.d.ts +1 -1
  14. package/components/breadcrumb/breadcrumb.d.ts +1 -1
  15. package/components/button/button.d.ts +1 -1
  16. package/components/canvas/canvas.d.ts +1 -1
  17. package/components/card/card.d.ts +1 -1
  18. package/components/chart/chart.d.ts +1 -1
  19. package/components/chart-legend/chart-legend.d.ts +1 -1
  20. package/components/chat-thread/chat-thread.d.ts +40 -1
  21. package/components/code/code.css +1 -1
  22. package/components/col/col.a2ui.json +4 -4
  23. package/components/col/col.d.ts +2 -2
  24. package/components/col/col.yaml +2 -2
  25. package/components/command/command.d.ts +1 -1
  26. package/components/demo-toggle/demo-toggle.a2ui.json +3 -1
  27. package/components/demo-toggle/demo-toggle.d.ts +1 -1
  28. package/components/demo-toggle/demo-toggle.yaml +2 -0
  29. package/components/description-list/description-list.d.ts +1 -1
  30. package/components/divider/divider.d.ts +1 -1
  31. package/components/drawer/drawer.d.ts +1 -1
  32. package/components/embed/embed.d.ts +1 -1
  33. package/components/empty-state/class.js +10 -4
  34. package/components/empty-state/empty-state.a2ui.json +5 -0
  35. package/components/empty-state/empty-state.css +36 -0
  36. package/components/empty-state/empty-state.d.ts +6 -1
  37. package/components/empty-state/empty-state.test.js +77 -0
  38. package/components/empty-state/empty-state.yaml +9 -0
  39. package/components/feed/feed.css +2 -2
  40. package/components/feed/feed.d.ts +29 -5
  41. package/components/field/field.d.ts +1 -1
  42. package/components/fields/fields.a2ui.json +3 -1
  43. package/components/fields/fields.d.ts +1 -1
  44. package/components/fields/fields.yaml +2 -0
  45. package/components/grid/grid.d.ts +1 -1
  46. package/components/heatmap/heatmap.d.ts +1 -1
  47. package/components/icon/icon.d.ts +1 -1
  48. package/components/image/image.d.ts +1 -1
  49. package/components/input/class.js +2 -1
  50. package/components/input/input.a2ui.json +5 -0
  51. package/components/input/input.test.js +99 -0
  52. package/components/input/input.yaml +14 -0
  53. package/components/inspector/inspector.d.ts +1 -1
  54. package/components/kbd/kbd.d.ts +1 -1
  55. package/components/link/link.d.ts +1 -1
  56. package/components/list/list.d.ts +10 -1
  57. package/components/menu/menu-divider.a2ui.json +41 -0
  58. package/components/menu/menu-divider.yaml +15 -0
  59. package/components/menu/menu-item.a2ui.json +77 -0
  60. package/components/menu/menu-item.yaml +45 -0
  61. package/components/menu/menu.d.ts +17 -1
  62. package/components/modal/modal.d.ts +1 -1
  63. package/components/nav/nav.a2ui.json +6 -1
  64. package/components/nav/nav.css +1 -1
  65. package/components/nav/nav.d.ts +1 -1
  66. package/components/nav/nav.yaml +6 -0
  67. package/components/nav-group/nav-group.a2ui.json +5 -1
  68. package/components/nav-group/nav-group.css +1 -1
  69. package/components/nav-group/nav-group.d.ts +1 -1
  70. package/components/nav-group/nav-group.yaml +5 -0
  71. package/components/nav-item/nav-item.a2ui.json +4 -1
  72. package/components/nav-item/nav-item.css +1 -1
  73. package/components/nav-item/nav-item.d.ts +1 -1
  74. package/components/nav-item/nav-item.yaml +4 -0
  75. package/components/noodles/noodles.d.ts +1 -1
  76. package/components/page/page.d.ts +1 -1
  77. package/components/pagination/pagination.d.ts +1 -1
  78. package/components/pane/pane.d.ts +1 -1
  79. package/components/pipeline-status/pipeline-status.d.ts +1 -1
  80. package/components/popover/popover.d.ts +1 -1
  81. package/components/progress/progress.d.ts +1 -1
  82. package/components/progress-row/progress-row.d.ts +1 -1
  83. package/components/range/range.css +1 -1
  84. package/components/richtext/richtext.a2ui.json +4 -4
  85. package/components/richtext/richtext.d.ts +2 -2
  86. package/components/richtext/richtext.yaml +2 -2
  87. package/components/row/row.d.ts +1 -1
  88. package/components/segment/segment.d.ts +1 -1
  89. package/components/select/class.js +28 -0
  90. package/components/select/select.css +1 -1
  91. package/components/select/select.yaml +28 -0
  92. package/components/skeleton/skeleton.d.ts +1 -1
  93. package/components/slider/class.js +20 -50
  94. package/components/slider/slider.css +1 -1
  95. package/components/stack/stack.d.ts +1 -1
  96. package/components/step-progress/step-progress.d.ts +1 -1
  97. package/components/stepper/stepper-item.a2ui.json +74 -0
  98. package/components/stepper/stepper-item.yaml +45 -0
  99. package/components/stepper/stepper.d.ts +13 -1
  100. package/components/stream/stream.d.ts +1 -1
  101. package/components/swatch/swatch.css +1 -1
  102. package/components/swatch/swatch.d.ts +1 -1
  103. package/components/swiper/swiper.d.ts +1 -1
  104. package/components/switch/switch.css +1 -1
  105. package/components/table/table.d.ts +1 -1
  106. package/components/table-toolbar/table-toolbar.d.ts +1 -1
  107. package/components/tabs/tabs.d.ts +12 -1
  108. package/components/tag/tag.d.ts +1 -1
  109. package/components/text/text.d.ts +1 -1
  110. package/components/textarea/class.js +7 -1
  111. package/components/textarea/textarea.a2ui.json +5 -0
  112. package/components/textarea/textarea.yaml +14 -0
  113. package/components/timeline/timeline.d.ts +20 -1
  114. package/components/toast/class.js +9 -0
  115. package/components/toast/toast.d.ts +9 -5
  116. package/components/toast/toast.yaml +16 -0
  117. package/components/toggle-group/toggle-group.d.ts +12 -1
  118. package/components/toggle-group/toggle-option.a2ui.json +61 -0
  119. package/components/toggle-group/toggle-option.yaml +33 -0
  120. package/components/toggle-scheme/toggle-scheme.d.ts +1 -1
  121. package/components/toolbar/toolbar-group.a2ui.json +41 -0
  122. package/components/toolbar/toolbar-group.yaml +16 -0
  123. package/components/toolbar/toolbar.d.ts +4 -1
  124. package/components/tooltip/tooltip.css +2 -2
  125. package/components/tooltip/tooltip.d.ts +1 -1
  126. package/components/tree/tree.css +1 -1
  127. package/components/tree/tree.d.ts +18 -1
  128. package/core/form.js +93 -0
  129. package/core/signals.d.ts +28 -0
  130. package/index.d.ts +2 -2
  131. package/package.json +1 -1
  132. package/styles/colors/semantics.css +6 -0
  133. package/styles/tokens.css +3 -0
  134. package/styles/typography.css +5 -1
@@ -4,7 +4,7 @@
4
4
  * @see https://ui-kit.exe.xyz/site/components/drawer
5
5
  *
6
6
  * Type declarations generated by scripts/build/dts-codegen.mjs from
7
- * the component's `.a2ui.json` sidecar. Edit the source `.yaml`,
7
+ * the component's `.a2ui.json` sidecar(s). Edit the source `.yaml`,
8
8
  * run `npm run build:components`, then `npm run codegen:dts` to
9
9
  * regenerate; or hand-author this file fully if rich event types are
10
10
  * needed beyond what the yaml `events:` block can express.
@@ -4,7 +4,7 @@
4
4
  * @see https://ui-kit.exe.xyz/site/components/embed
5
5
  *
6
6
  * Type declarations generated by scripts/build/dts-codegen.mjs from
7
- * the component's `.a2ui.json` sidecar. Edit the source `.yaml`,
7
+ * the component's `.a2ui.json` sidecar(s). Edit the source `.yaml`,
8
8
  * run `npm run build:components`, then `npm run codegen:dts` to
9
9
  * regenerate; or hand-author this file fully if rich event types are
10
10
  * needed beyond what the yaml `events:` block can express.
@@ -26,9 +26,13 @@ import { UIElement } from '../../core/element.js';
26
26
 
27
27
  export class UIEmptyState extends UIElement {
28
28
  static properties = {
29
- icon: { type: String, default: '', reflect: true },
30
- heading: { type: String, default: '', reflect: true },
31
- description: { type: String, default: '', reflect: true },
29
+ icon: { type: String, default: '', reflect: true },
30
+ heading: { type: String, default: '', reflect: true },
31
+ description: { type: String, default: '', reflect: true },
32
+ // §223 (v0.5.9): minimal layout — single-line muted (no centered column,
33
+ // no padding bump, no icon-size lg). Use for inline empty-table-row /
34
+ // inline placeholder cells where the canvas placeholder is too loud.
35
+ minimal: { type: Boolean, default: false, reflect: true },
32
36
  };
33
37
 
34
38
  static template = () => null;
@@ -47,7 +51,9 @@ export class UIEmptyState extends UIElement {
47
51
  if (!this.#iconEl) {
48
52
  this.#iconEl = this.#stampMark(document.createElement('icon-ui'));
49
53
  this.#iconEl.setAttribute('slot', 'icon');
50
- this.#iconEl.setAttribute('size', 'lg');
54
+ // §223 (v0.5.9): minimal layout sizes the icon inline; non-minimal
55
+ // keeps the canonical lg badge.
56
+ if (!this.minimal) this.#iconEl.setAttribute('size', 'lg');
51
57
  this.insertBefore(this.#iconEl, this.firstChild);
52
58
  }
53
59
 
@@ -30,6 +30,11 @@
30
30
  "description": "Icon name displayed above the heading",
31
31
  "type": "string",
32
32
  "default": ""
33
+ },
34
+ "minimal": {
35
+ "description": "§223 (v0.5.9). Single-line muted layout — drops centered-column chrome\n(no vertical padding, no row-stack, no icon-size bump). Useful for\ninline empty-table-row / inline empty-list / placeholder cells where\nthe full-canvas placeholder is too prominent.",
36
+ "type": "boolean",
37
+ "default": false
33
38
  }
34
39
  },
35
40
  "required": [
@@ -55,4 +55,40 @@
55
55
  [slot="action"] {
56
56
  margin-top: var(--empty-state-action-mt);
57
57
  }
58
+
59
+ /* ── §223 (v0.5.9): [minimal] — single-line muted layout ──
60
+ Drops centered-column chrome (no canvas-style padding, no flex-column
61
+ stack). Renders as `[icon] heading [description]` inline in muted-fg.
62
+ Useful for inline placeholder rows / cells where the full placeholder
63
+ would be too loud. */
64
+ :scope[minimal] {
65
+ flex-direction: row;
66
+ align-items: baseline;
67
+ text-align: start;
68
+ padding: var(--a-space-2) var(--a-space-3);
69
+ gap: var(--a-space-2);
70
+ color: var(--a-fg-muted);
71
+ font-size: var(--a-ui-size);
72
+ }
73
+ :scope[minimal] [slot="icon"] {
74
+ font-size: 1em;
75
+ color: inherit;
76
+ flex-shrink: 0;
77
+ }
78
+ :scope[minimal] [slot="heading"] {
79
+ font-size: inherit;
80
+ font-weight: var(--a-weight-normal);
81
+ color: inherit;
82
+ line-height: inherit;
83
+ }
84
+ :scope[minimal] [slot="description"] {
85
+ font-size: inherit;
86
+ color: inherit;
87
+ line-height: inherit;
88
+ max-width: none;
89
+ }
90
+ :scope[minimal] [slot="action"] {
91
+ margin-top: 0;
92
+ margin-inline-start: auto;
93
+ }
58
94
  }
@@ -4,7 +4,7 @@
4
4
  * @see https://ui-kit.exe.xyz/site/components/empty-state
5
5
  *
6
6
  * Type declarations generated by scripts/build/dts-codegen.mjs from
7
- * the component's `.a2ui.json` sidecar. Edit the source `.yaml`,
7
+ * the component's `.a2ui.json` sidecar(s). Edit the source `.yaml`,
8
8
  * run `npm run build:components`, then `npm run codegen:dts` to
9
9
  * regenerate; or hand-author this file fully if rich event types are
10
10
  * needed beyond what the yaml `events:` block can express.
@@ -19,4 +19,9 @@ export class UIEmptyState extends UIElement {
19
19
  heading: string;
20
20
  /** Icon name displayed above the heading */
21
21
  icon: string;
22
+ /** §223 (v0.5.9). Single-line muted layout — drops centered-column chrome
23
+ (no vertical padding, no row-stack, no icon-size bump). Useful for
24
+ inline empty-table-row / inline empty-list / placeholder cells where
25
+ the full-canvas placeholder is too prominent. */
26
+ minimal: boolean;
22
27
  }
@@ -0,0 +1,77 @@
1
+ /**
2
+ * empty-state-ui — focused unit tests for the §223 (v0.5.9) `minimal`
3
+ * boolean prop.
4
+ *
5
+ * Pre-§223 only the centered-column canvas layout existed. §223 adds
6
+ * an inline single-row muted layout for placeholder cells / table rows
7
+ * where the full-canvas placeholder is too prominent (R13 §4).
8
+ */
9
+
10
+ import { describe, it, expect, beforeEach } from 'vitest';
11
+ import '../../core/element.js';
12
+ import './empty-state.js';
13
+
14
+ const tick = () => new Promise((r) => queueMicrotask(r));
15
+
16
+ function mount(html) {
17
+ const wrap = document.createElement('div');
18
+ wrap.innerHTML = html;
19
+ document.body.appendChild(wrap);
20
+ return wrap.firstElementChild;
21
+ }
22
+
23
+ describe('empty-state-ui — §223 (v0.5.9) minimal mode', () => {
24
+ beforeEach(() => { document.body.innerHTML = ''; });
25
+
26
+ it('defaults to non-minimal (canvas-style placeholder)', () => {
27
+ const el = mount('<empty-state-ui heading="No results"></empty-state-ui>');
28
+ expect(el.minimal).toBe(false);
29
+ expect(el.hasAttribute('minimal')).toBe(false);
30
+ });
31
+
32
+ it('reflects [minimal] attribute to the property', () => {
33
+ const el = mount('<empty-state-ui minimal heading="No matches"></empty-state-ui>');
34
+ expect(el.minimal).toBe(true);
35
+ expect(el.hasAttribute('minimal')).toBe(true);
36
+ });
37
+
38
+ it('stamps icon WITHOUT size="lg" when minimal', async () => {
39
+ const el = mount('<empty-state-ui minimal icon="search" heading="No matches"></empty-state-ui>');
40
+ await tick();
41
+ const icon = el.querySelector(':scope > [slot="icon"]');
42
+ expect(icon).not.toBeNull();
43
+ // Minimal layout uses 1em inherited font-size; non-minimal stamps lg.
44
+ expect(icon.hasAttribute('size')).toBe(false);
45
+ });
46
+
47
+ it('stamps icon WITH size="lg" when not minimal (no regression)', async () => {
48
+ const el = mount('<empty-state-ui icon="search" heading="No matches"></empty-state-ui>');
49
+ await tick();
50
+ const icon = el.querySelector(':scope > [slot="icon"]');
51
+ expect(icon).not.toBeNull();
52
+ expect(icon.getAttribute('size')).toBe('lg');
53
+ });
54
+
55
+ it('stamps heading + description slots in both modes', async () => {
56
+ const minimal = mount('<empty-state-ui minimal heading="Empty" description="No rows"></empty-state-ui>');
57
+ const canvas = mount('<empty-state-ui heading="Empty" description="No rows"></empty-state-ui>');
58
+ await tick();
59
+
60
+ for (const el of [minimal, canvas]) {
61
+ const h = el.querySelector(':scope > [slot="heading"]');
62
+ const d = el.querySelector(':scope > [slot="description"]');
63
+ expect(h?.textContent).toBe('Empty');
64
+ expect(d?.textContent).toBe('No rows');
65
+ }
66
+ });
67
+
68
+ it('honors a consumer-provided [slot="action"] child in either mode', () => {
69
+ const el = mount(`
70
+ <empty-state-ui minimal heading="Empty">
71
+ <button slot="action" data-test="reset">Reset</button>
72
+ </empty-state-ui>
73
+ `);
74
+ const action = el.querySelector(':scope > [slot="action"][data-test="reset"]');
75
+ expect(action).not.toBeNull();
76
+ });
77
+ });
@@ -24,6 +24,15 @@ props:
24
24
  description: Icon name displayed above the heading
25
25
  type: string
26
26
  default: ""
27
+ minimal:
28
+ description: |-
29
+ §223 (v0.5.9). Single-line muted layout — drops centered-column chrome
30
+ (no vertical padding, no row-stack, no icon-size bump). Useful for
31
+ inline empty-table-row / inline empty-list / placeholder cells where
32
+ the full-canvas placeholder is too prominent.
33
+ type: boolean
34
+ default: false
35
+ reflect: true
27
36
  events: {}
28
37
  slots:
29
38
  action:
@@ -102,7 +102,7 @@ feed-item-ui[data-closing] {
102
102
  --feed-item-duration: var(--a-duration);
103
103
  --feed-item-easing: var(--a-easing-out);
104
104
  --feed-item-gap: var(--a-space-3);
105
- --feed-item-max-width: var(--a-feed-max-width, 22rem);
105
+ --feed-item-max-width: 22rem; /* §230-bundle (v0.5.9): component-local. Was orphaned --a-feed-max-width — hoisted per RESPONSE-21 guidance. */
106
106
  }
107
107
  :scope[variant="info"] { --feed-item-fg: var(--a-info-fg); --feed-item-bg: var(--a-info-muted); }
108
108
  :scope[variant="success"] { --feed-item-fg: var(--a-success-fg); --feed-item-bg: var(--a-success-muted); }
@@ -133,7 +133,7 @@ feed-item-ui[data-closing] {
133
133
  gap: 0.125rem;
134
134
  }
135
135
  :scope > [slot="body"] strong {
136
- font-weight: var(--a-font-weight-strong, 600);
136
+ font-weight: var(--a-weight-semibold);
137
137
  }
138
138
  :scope > [data-feed-close] {
139
139
  flex-shrink: 0;
@@ -4,7 +4,7 @@
4
4
  * @see https://ui-kit.exe.xyz/site/components/feed
5
5
  *
6
6
  * Type declarations generated by scripts/build/dts-codegen.mjs from
7
- * the component's `.a2ui.json` sidecar. Edit the source `.yaml`,
7
+ * the component's `.a2ui.json` sidecar(s). Edit the source `.yaml`,
8
8
  * run `npm run build:components`, then `npm run codegen:dts` to
9
9
  * regenerate; or hand-author this file fully if rich event types are
10
10
  * needed beyond what the yaml `events:` block can express.
@@ -12,9 +12,9 @@
12
12
 
13
13
  import { UIElement } from '../../core/element.js';
14
14
 
15
- export type FeedCloseEvent = CustomEvent<unknown>;
15
+ export type FeedContainerCloseEvent = CustomEvent<unknown>;
16
16
 
17
- export class UIFeed extends UIElement {
17
+ export class UIFeedContainer extends UIElement {
18
18
  /** Cap on simultaneously visible items per lane */
19
19
  max: number;
20
20
  /** Lane the feed renders into */
@@ -22,8 +22,32 @@ export class UIFeed extends UIElement {
22
22
 
23
23
  addEventListener<K extends keyof HTMLElementEventMap>(
24
24
  type: K,
25
- listener: (this: UIFeed, ev: HTMLElementEventMap[K]) => unknown,
25
+ listener: (this: UIFeedContainer, ev: HTMLElementEventMap[K]) => unknown,
26
26
  options?: boolean | AddEventListenerOptions,
27
27
  ): void;
28
- addEventListener(type: 'close', listener: (ev: FeedCloseEvent) => unknown, options?: boolean | AddEventListenerOptions): void;
28
+ addEventListener(type: 'close', listener: (ev: FeedContainerCloseEvent) => unknown, options?: boolean | AddEventListenerOptions): void;
29
+ }
30
+
31
+ export type FeedItemCloseEvent = CustomEvent<unknown>;
32
+
33
+ export class UIFeedItem extends UIElement {
34
+ /** Render an x close button (default true for sticky, false for auto-fade) */
35
+ dismissible: boolean;
36
+ /** Auto-fade timer in ms; null/0 = sticky (requires user input) */
37
+ duration: number;
38
+ /** Optional emphasis line above text */
39
+ heading: string;
40
+ /** Optional leading icon name */
41
+ icon: string;
42
+ /** Body copy */
43
+ text: string;
44
+ /** Semantic variant */
45
+ variant: 'default' | 'info' | 'success' | 'warning' | 'danger';
46
+
47
+ addEventListener<K extends keyof HTMLElementEventMap>(
48
+ type: K,
49
+ listener: (this: UIFeedItem, ev: HTMLElementEventMap[K]) => unknown,
50
+ options?: boolean | AddEventListenerOptions,
51
+ ): void;
52
+ addEventListener(type: 'close', listener: (ev: FeedItemCloseEvent) => unknown, options?: boolean | AddEventListenerOptions): void;
29
53
  }
@@ -4,7 +4,7 @@
4
4
  * @see https://ui-kit.exe.xyz/site/components/field
5
5
  *
6
6
  * Type declarations generated by scripts/build/dts-codegen.mjs from
7
- * the component's `.a2ui.json` sidecar. Edit the source `.yaml`,
7
+ * the component's `.a2ui.json` sidecar(s). Edit the source `.yaml`,
8
8
  * run `npm run build:components`, then `npm run codegen:dts` to
9
9
  * regenerate; or hand-author this file fully if rich event types are
10
10
  * needed beyond what the yaml `events:` block can express.
@@ -43,7 +43,9 @@
43
43
  }
44
44
  ],
45
45
  "category": "form",
46
- "composes": [],
46
+ "composes": [
47
+ "field-ui"
48
+ ],
47
49
  "events": {},
48
50
  "examples": [
49
51
  {
@@ -4,7 +4,7 @@
4
4
  * @see https://ui-kit.exe.xyz/site/components/fields
5
5
  *
6
6
  * Type declarations generated by scripts/build/dts-codegen.mjs from
7
- * the component's `.a2ui.json` sidecar. Edit the source `.yaml`,
7
+ * the component's `.a2ui.json` sidecar(s). Edit the source `.yaml`,
8
8
  * run `npm run build:components`, then `npm run codegen:dts` to
9
9
  * regenerate; or hand-author this file fully if rich event types are
10
10
  * needed beyond what the yaml `events:` block can express.
@@ -14,6 +14,8 @@ description: >-
14
14
  The grid alignment lets siblings on the same row line up cleanly —
15
15
  consistent label columns + consistent control columns — without
16
16
  the wrap-flex jitter of <row-ui wrap>.
17
+ composes:
18
+ - field-ui
17
19
  props:
18
20
  inline:
19
21
  description: >-
@@ -4,7 +4,7 @@
4
4
  * @see https://ui-kit.exe.xyz/site/components/grid
5
5
  *
6
6
  * Type declarations generated by scripts/build/dts-codegen.mjs from
7
- * the component's `.a2ui.json` sidecar. Edit the source `.yaml`,
7
+ * the component's `.a2ui.json` sidecar(s). Edit the source `.yaml`,
8
8
  * run `npm run build:components`, then `npm run codegen:dts` to
9
9
  * regenerate; or hand-author this file fully if rich event types are
10
10
  * needed beyond what the yaml `events:` block can express.
@@ -4,7 +4,7 @@
4
4
  * @see https://ui-kit.exe.xyz/site/components/heatmap
5
5
  *
6
6
  * Type declarations generated by scripts/build/dts-codegen.mjs from
7
- * the component's `.a2ui.json` sidecar. Edit the source `.yaml`,
7
+ * the component's `.a2ui.json` sidecar(s). Edit the source `.yaml`,
8
8
  * run `npm run build:components`, then `npm run codegen:dts` to
9
9
  * regenerate; or hand-author this file fully if rich event types are
10
10
  * needed beyond what the yaml `events:` block can express.
@@ -4,7 +4,7 @@
4
4
  * @see https://ui-kit.exe.xyz/site/components/icon
5
5
  *
6
6
  * Type declarations generated by scripts/build/dts-codegen.mjs from
7
- * the component's `.a2ui.json` sidecar. Edit the source `.yaml`,
7
+ * the component's `.a2ui.json` sidecar(s). Edit the source `.yaml`,
8
8
  * run `npm run build:components`, then `npm run codegen:dts` to
9
9
  * regenerate; or hand-author this file fully if rich event types are
10
10
  * needed beyond what the yaml `events:` block can express.
@@ -4,7 +4,7 @@
4
4
  * @see https://ui-kit.exe.xyz/site/components/image
5
5
  *
6
6
  * Type declarations generated by scripts/build/dts-codegen.mjs from
7
- * the component's `.a2ui.json` sidecar. Edit the source `.yaml`,
7
+ * the component's `.a2ui.json` sidecar(s). Edit the source `.yaml`,
8
8
  * run `npm run build:components`, then `npm run codegen:dts` to
9
9
  * regenerate; or hand-author this file fully if rich event types are
10
10
  * needed beyond what the yaml `events:` block can express.
@@ -601,7 +601,8 @@ export class UIInput extends UIFormElement {
601
601
  this.value = text;
602
602
  if (!this.#isNativePassword) this.#textEl.toggleAttribute('data-empty', !text);
603
603
  this.syncValue(text);
604
- this.dispatchEvent(new CustomEvent('input', { bubbles: true, detail: { value: this.value } }));
604
+ // §220 (v0.5.9, FEEDBACK-14 §3): trailing-debounce when `throttle > 0`.
605
+ this.scheduleThrottledInput();
605
606
  };
606
607
 
607
608
  #onBeforeInput = (e) => {
@@ -146,6 +146,11 @@
146
146
  "type": "string",
147
147
  "default": ""
148
148
  },
149
+ "throttle": {
150
+ "description": "§220 (v0.5.9, FEEDBACK-14 §3). Trailing-debounce on the `input`\nevent in milliseconds. When > 0, value mutates immediately + the UI\nstays responsive, but `input` dispatch is collapsed so only the\nfinal value in the throttle window emits. Useful for expensive\n`input`-driven computation (palette regen, large list filter,\nserver-side autocomplete). `change` fires unthrottled on blur /\nEnter / stepper commit; any pending `input` flushes before `change`\nso consumers see input→input→…→input→change ordering. Default 0\npreserves synchronous emission.",
151
+ "type": "number",
152
+ "default": 0
153
+ },
149
154
  "value": {
150
155
  "description": "Current input value, synced with contenteditable text surface. For `type=\"number\"`, this is the formatted numeric string; read `el.valueAsNumber` for the parsed Number.",
151
156
  "type": "string",
@@ -121,3 +121,102 @@ describe('input-ui — §199 leading/trailing affordance slots', () => {
121
121
  expect(text.textContent).toBe('Theme 1');
122
122
  });
123
123
  });
124
+
125
+ describe('input-ui — §220 (v0.5.9) throttle parity', () => {
126
+ beforeEach(() => { document.body.innerHTML = ''; });
127
+
128
+ it('inherits `throttle` property default 0 from UIFormElement', () => {
129
+ const el = mount('<input-ui></input-ui>');
130
+ expect(el.throttle).toBe(0);
131
+ });
132
+
133
+ it('reflects [throttle] attribute to the property', () => {
134
+ const el = mount('<input-ui throttle="150"></input-ui>');
135
+ expect(el.throttle).toBe(150);
136
+ });
137
+
138
+ it('dispatches `input` synchronously when throttle=0 (default)', async () => {
139
+ const el = mount('<input-ui></input-ui>');
140
+ await tick();
141
+ let count = 0;
142
+ // Filter for host-emitted CustomEvents (have detail.value); surface
143
+ // InputEvents bubble up too but have no detail property.
144
+ el.addEventListener('input', (e) => {
145
+ if (e.detail?.value !== undefined) count++;
146
+ });
147
+
148
+ // Simulate user typing — set value + dispatch DOM input on the
149
+ // contenteditable surface so the host's #onInput handler fires.
150
+ const surface = el.querySelector('[slot="text"]');
151
+ surface.textContent = 'a';
152
+ surface.dispatchEvent(new InputEvent('input', { bubbles: true }));
153
+ surface.textContent = 'ab';
154
+ surface.dispatchEvent(new InputEvent('input', { bubbles: true }));
155
+ surface.textContent = 'abc';
156
+ surface.dispatchEvent(new InputEvent('input', { bubbles: true }));
157
+
158
+ expect(count).toBe(3);
159
+ });
160
+
161
+ it('collapses burst dispatches to one trailing `input` when throttle>0', async () => {
162
+ const el = mount('<input-ui throttle="20"></input-ui>');
163
+ await tick();
164
+ const events = [];
165
+ // Filter for host-emitted CustomEvents (have detail.value); surface
166
+ // InputEvents bubble up too but have no detail property.
167
+ el.addEventListener('input', (e) => {
168
+ if (e.detail?.value !== undefined) events.push(e.detail.value);
169
+ });
170
+
171
+ const surface = el.querySelector('[slot="text"]');
172
+ surface.textContent = 'a';
173
+ surface.dispatchEvent(new InputEvent('input', { bubbles: true }));
174
+ surface.textContent = 'ab';
175
+ surface.dispatchEvent(new InputEvent('input', { bubbles: true }));
176
+ surface.textContent = 'abc';
177
+ surface.dispatchEvent(new InputEvent('input', { bubbles: true }));
178
+
179
+ expect(events).toEqual([]);
180
+
181
+ await new Promise((r) => setTimeout(r, 35));
182
+ expect(events).toEqual(['abc']);
183
+ });
184
+
185
+ it('flushPendingInput() fires the pending dispatch synchronously', async () => {
186
+ const el = mount('<input-ui throttle="50"></input-ui>');
187
+ await tick();
188
+ const events = [];
189
+ // Filter for host-emitted CustomEvents (have detail.value); surface
190
+ // InputEvents bubble up too but have no detail property.
191
+ el.addEventListener('input', (e) => {
192
+ if (e.detail?.value !== undefined) events.push(e.detail.value);
193
+ });
194
+
195
+ const surface = el.querySelector('[slot="text"]');
196
+ surface.textContent = 'pending';
197
+ surface.dispatchEvent(new InputEvent('input', { bubbles: true }));
198
+
199
+ expect(events).toEqual([]);
200
+ el.flushPendingInput();
201
+ expect(events).toEqual(['pending']);
202
+ });
203
+
204
+ it('dropPendingInput() prevents the dispatch (used by disconnected)', async () => {
205
+ const el = mount('<input-ui throttle="20"></input-ui>');
206
+ await tick();
207
+ const events = [];
208
+ // Filter for host-emitted CustomEvents (have detail.value); surface
209
+ // InputEvents bubble up too but have no detail property.
210
+ el.addEventListener('input', (e) => {
211
+ if (e.detail?.value !== undefined) events.push(e.detail.value);
212
+ });
213
+
214
+ const surface = el.querySelector('[slot="text"]');
215
+ surface.textContent = 'gone';
216
+ surface.dispatchEvent(new InputEvent('input', { bubbles: true }));
217
+
218
+ el.dropPendingInput();
219
+ await new Promise((r) => setTimeout(r, 30));
220
+ expect(events).toEqual([]);
221
+ });
222
+ });
@@ -139,6 +139,20 @@ props:
139
139
  description: Suffix text rendered after the text surface (e.g., unit like 'kg')
140
140
  type: string
141
141
  default: ''
142
+ throttle:
143
+ description: |-
144
+ §220 (v0.5.9, FEEDBACK-14 §3). Trailing-debounce on the `input`
145
+ event in milliseconds. When > 0, value mutates immediately + the UI
146
+ stays responsive, but `input` dispatch is collapsed so only the
147
+ final value in the throttle window emits. Useful for expensive
148
+ `input`-driven computation (palette regen, large list filter,
149
+ server-side autocomplete). `change` fires unthrottled on blur /
150
+ Enter / stepper commit; any pending `input` flushes before `change`
151
+ so consumers see input→input→…→input→change ordering. Default 0
152
+ preserves synchronous emission.
153
+ type: number
154
+ default: 0
155
+ reflect: true
142
156
  value:
143
157
  description: Current input value, synced with contenteditable text surface. For `type="number"`, this is the formatted
144
158
  numeric string; read `el.valueAsNumber` for the parsed Number.
@@ -4,7 +4,7 @@
4
4
  * @see https://ui-kit.exe.xyz/site/components/inspector
5
5
  *
6
6
  * Type declarations generated by scripts/build/dts-codegen.mjs from
7
- * the component's `.a2ui.json` sidecar. Edit the source `.yaml`,
7
+ * the component's `.a2ui.json` sidecar(s). Edit the source `.yaml`,
8
8
  * run `npm run build:components`, then `npm run codegen:dts` to
9
9
  * regenerate; or hand-author this file fully if rich event types are
10
10
  * needed beyond what the yaml `events:` block can express.
@@ -4,7 +4,7 @@
4
4
  * @see https://ui-kit.exe.xyz/site/components/kbd
5
5
  *
6
6
  * Type declarations generated by scripts/build/dts-codegen.mjs from
7
- * the component's `.a2ui.json` sidecar. Edit the source `.yaml`,
7
+ * the component's `.a2ui.json` sidecar(s). Edit the source `.yaml`,
8
8
  * run `npm run build:components`, then `npm run codegen:dts` to
9
9
  * regenerate; or hand-author this file fully if rich event types are
10
10
  * needed beyond what the yaml `events:` block can express.
@@ -28,7 +28,7 @@ wiring. ARIA role is "link" (set automatically by `<a>` element).
28
28
  * @see https://ui-kit.exe.xyz/site/components/link
29
29
  *
30
30
  * Type declarations generated by scripts/build/dts-codegen.mjs from
31
- * the component's `.a2ui.json` sidecar. Edit the source `.yaml`,
31
+ * the component's `.a2ui.json` sidecar(s). Edit the source `.yaml`,
32
32
  * run `npm run build:components`, then `npm run codegen:dts` to
33
33
  * regenerate; or hand-author this file fully if rich event types are
34
34
  * needed beyond what the yaml `events:` block can express.
@@ -4,7 +4,7 @@
4
4
  * @see https://ui-kit.exe.xyz/site/components/list
5
5
  *
6
6
  * Type declarations generated by scripts/build/dts-codegen.mjs from
7
- * the component's `.a2ui.json` sidecar. Edit the source `.yaml`,
7
+ * the component's `.a2ui.json` sidecar(s). Edit the source `.yaml`,
8
8
  * run `npm run build:components`, then `npm run codegen:dts` to
9
9
  * regenerate; or hand-author this file fully if rich event types are
10
10
  * needed beyond what the yaml `events:` block can express.
@@ -38,3 +38,12 @@ export class UIList extends UIElement {
38
38
  ): void;
39
39
  addEventListener(type: 'selection-change', listener: (ev: ListSelectionChangeEvent) => unknown, options?: boolean | AddEventListenerOptions): void;
40
40
  }
41
+
42
+ export class UIListItem extends UIElement {
43
+ /** Secondary line below the primary text. Subtle color. */
44
+ description: string;
45
+ /** Optional leading icon name (Phosphor). */
46
+ icon: string;
47
+ /** Primary text. Renders as semibold inline body. */
48
+ text: string;
49
+ }
@@ -0,0 +1,41 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://adiaui.dev/a2ui/v0_9/components/MenuDivider.json",
4
+ "title": "MenuDivider",
5
+ "description": "Visual separator between groups of `<menu-item-ui>` rows. Renders as a horizontal rule with role=\"separator\".",
6
+ "type": "object",
7
+ "allOf": [
8
+ {
9
+ "$ref": "common_types.json#/$defs/ComponentCommon"
10
+ },
11
+ {
12
+ "$ref": "common_types.json#/$defs/CatalogComponentCommon"
13
+ }
14
+ ],
15
+ "properties": {
16
+ "component": {
17
+ "const": "MenuDivider"
18
+ }
19
+ },
20
+ "required": [
21
+ "component"
22
+ ],
23
+ "unevaluatedProperties": false,
24
+ "x-adiaui": {
25
+ "anti_patterns": [],
26
+ "category": "navigation",
27
+ "composes": [],
28
+ "events": {},
29
+ "examples": [],
30
+ "keywords": [],
31
+ "name": "UIMenuDivider",
32
+ "related": [],
33
+ "slots": {},
34
+ "states": [],
35
+ "synonyms": {},
36
+ "tag": "menu-divider-ui",
37
+ "tokens": {},
38
+ "traits": [],
39
+ "version": 1
40
+ }
41
+ }
@@ -0,0 +1,15 @@
1
+ # Edit this file; run `npm run build:components` to regenerate a2ui.json.
2
+ #
3
+ # §228 (v0.5.9): authored to close the §229 baseline class-export-undeclared
4
+ # drift for UIMenuDivider. Ships as a sibling class in menu/class.js +
5
+ # is registered alongside UIMenu + UIMenuItem.
6
+
7
+ # Child component of <menu-ui>. Surface only inside that parent.
8
+ $schema: ../../../../scripts/schemas/component.yaml.schema.json
9
+ name: UIMenuDivider
10
+ tag: menu-divider-ui
11
+ component: MenuDivider
12
+ category: navigation
13
+ version: 1
14
+ description: |-
15
+ Visual separator between groups of `<menu-item-ui>` rows. Renders as a horizontal rule with role="separator".