@adia-ai/web-components 0.8.43 → 0.8.45

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 (113) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/components/avatar/avatar.class.js +12 -1
  3. package/components/button/button.d.ts +4 -0
  4. package/components/chart/chart.a2ui.json +26 -0
  5. package/components/chart/chart.class.js +1304 -222
  6. package/components/chart/chart.css +151 -1
  7. package/components/chart/chart.d.ts +6 -0
  8. package/components/chart/chart.yaml +57 -0
  9. package/components/chart-legend/chart-legend.a2ui.json +17 -2
  10. package/components/chart-legend/chart-legend.class.js +69 -4
  11. package/components/chart-legend/chart-legend.css +65 -1
  12. package/components/chart-legend/chart-legend.d.ts +4 -2
  13. package/components/chart-legend/chart-legend.examples.md +4 -4
  14. package/components/chart-legend/chart-legend.yaml +43 -3
  15. package/components/combobox/combobox.a2ui.json +3 -0
  16. package/components/combobox/combobox.class.js +9 -8
  17. package/components/combobox/combobox.css +25 -4
  18. package/components/combobox/combobox.yaml +6 -0
  19. package/components/command/command.css +17 -1
  20. package/components/context-menu/context-menu.a2ui.json +8 -3
  21. package/components/context-menu/context-menu.class.js +46 -5
  22. package/components/context-menu/context-menu.d.ts +8 -3
  23. package/components/context-menu/context-menu.examples.md +2 -2
  24. package/components/context-menu/context-menu.yaml +22 -5
  25. package/components/heatmap/heatmap.a2ui.json +5 -0
  26. package/components/heatmap/heatmap.d.ts +2 -0
  27. package/components/heatmap/heatmap.yaml +8 -0
  28. package/components/input/input.a2ui.json +2 -2
  29. package/components/input/input.class.js +12 -7
  30. package/components/input/input.yaml +6 -5
  31. package/components/integration-card/integration-card.d.ts +2 -0
  32. package/components/nav/nav.a2ui.json +2 -2
  33. package/components/nav/nav.css +1 -1
  34. package/components/nav/nav.d.ts +1 -1
  35. package/components/nav/nav.yaml +14 -3
  36. package/components/nav-group/nav-group.css +37 -3
  37. package/components/noodles/noodles.a2ui.json +0 -15
  38. package/components/noodles/noodles.yaml +0 -12
  39. package/components/number-format/number-format.class.js +10 -0
  40. package/components/pagination/pagination.class.js +140 -26
  41. package/components/popover/popover.d.ts +2 -0
  42. package/components/progress/progress.class.js +11 -6
  43. package/components/range/range.class.js +9 -1
  44. package/components/search/search.class.js +39 -5
  45. package/components/select/select.a2ui.json +10 -1
  46. package/components/select/select.class.js +34 -14
  47. package/components/select/select.css +39 -1
  48. package/components/select/select.d.ts +2 -0
  49. package/components/select/select.yaml +19 -1
  50. package/components/stream/stream.d.ts +2 -0
  51. package/components/table/cell-types.js +9 -0
  52. package/components/table/table.a2ui.json +6 -1
  53. package/components/table/table.class.js +265 -34
  54. package/components/table/table.css +38 -10
  55. package/components/table/table.d.ts +3 -1
  56. package/components/table/table.examples.md +2 -2
  57. package/components/table/table.yaml +15 -2
  58. package/components/table-toolbar/table-toolbar.a2ui.json +43 -4
  59. package/components/table-toolbar/table-toolbar.class.js +407 -28
  60. package/components/table-toolbar/table-toolbar.css +299 -0
  61. package/components/table-toolbar/table-toolbar.d.ts +15 -1
  62. package/components/table-toolbar/table-toolbar.yaml +162 -15
  63. package/components/tag/tag.class.js +13 -1
  64. package/components/text/text.a2ui.json +3 -3
  65. package/components/text/text.d.ts +5 -3
  66. package/components/text/text.yaml +3 -3
  67. package/components/textarea/textarea.class.js +9 -1
  68. package/components/tour/tour.d.ts +10 -0
  69. package/core/a11y.d.ts +22 -0
  70. package/core/a11y.js +64 -0
  71. package/core/anchor.js +9 -5
  72. package/core/data-stream.js +37 -2
  73. package/core/element.js +1 -1
  74. package/core/index.d.ts +1 -0
  75. package/core/index.js +1 -0
  76. package/core/provider.d.ts +9 -13
  77. package/core/provider.js +9 -113
  78. package/core/store.d.ts +46 -0
  79. package/core/store.js +89 -0
  80. package/custom-elements.json +127 -33
  81. package/dist/host.min.css +1 -1
  82. package/dist/host.sheet.js +1 -1
  83. package/dist/theme-provider.min.js +1 -1
  84. package/dist/web-components.min.css +1 -1
  85. package/dist/web-components.min.js +119 -119
  86. package/dist/web-components.sheet.js +1 -1
  87. package/package.json +1 -1
  88. package/patterns/access-requests/access-requests.examples.html +1 -1
  89. package/patterns/admin-keys-and-export/admin-keys-and-export.examples.html +7 -7
  90. package/patterns/agent-cost/agent-cost.examples.html +6 -6
  91. package/patterns/agent-memory/agent-memory.examples.html +3 -3
  92. package/patterns/agent-prompt-library/agent-prompt-library.examples.html +8 -8
  93. package/patterns/agent-tool-call/agent-tool-call.examples.html +1 -1
  94. package/patterns/approvals/approvals.examples.html +6 -6
  95. package/patterns/audit-log/audit-log.examples.html +1 -1
  96. package/patterns/bulk-action-toolbar/bulk-action-toolbar.examples.html +4 -4
  97. package/patterns/chart-in-card/chart-in-card.examples.html +114 -0
  98. package/patterns/chart-in-card/chart-in-card.examples.js +37 -0
  99. package/patterns/comments-and-collaboration/comments-and-collaboration.examples.html +5 -5
  100. package/patterns/data-tables-inline-edit-and-tree/data-tables-inline-edit-and-tree.examples.html +2 -2
  101. package/patterns/diff-review/diff-review.examples.html +6 -6
  102. package/patterns/export-flow/export-flow.examples.html +2 -2
  103. package/patterns/filter-bar/filter-bar.examples.html +2 -2
  104. package/patterns/forms-conditional-and-autocomplete/forms-conditional-and-autocomplete.examples.html +2 -2
  105. package/patterns/inline-dialog/inline-dialog.examples.html +2 -2
  106. package/patterns/marketing-engagement/marketing-engagement.examples.html +4 -4
  107. package/patterns/notifications-bell-and-digest/notifications-bell-and-digest.examples.html +1 -1
  108. package/patterns/permissions-matrix/permissions-matrix.examples.html +1 -1
  109. package/patterns/permissions-sharing/permissions-sharing.examples.html +2 -2
  110. package/patterns/profile-public-and-verification/profile-public-and-verification.examples.html +4 -4
  111. package/patterns/search-discovery/search-discovery.examples.html +2 -2
  112. package/styles/api/sizing.css +46 -0
  113. package/styles/type/roles.css +29 -9
@@ -14,6 +14,7 @@
14
14
  import { UIFormElement } from '../../core/form.js';
15
15
  import { anchorPopover } from '../../core/anchor.js';
16
16
  import { untracked } from '../../core/signals.js';
17
+ import { syncAutoAriaLabel } from '../../core/a11y.js';
17
18
 
18
19
  function escapeHTML(s) {
19
20
  return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
@@ -46,6 +47,11 @@ export class UISelect extends UIFormElement {
46
47
  size: { type: String, default: 'md', reflect: true },
47
48
  open: { type: Boolean, default: false, reflect: true },
48
49
  label: { type: String, default: '', reflect: true },
50
+ // gh#1748: keeps [label] as the accessible name (bridged to an explicit
51
+ // aria-label in #syncAccessibleName below) while suppressing the VISIBLE
52
+ // `::before` text (select.css) — for compositions that already show the
53
+ // name elsewhere. Mirrors check-ui's [label-hidden] (gh#1010).
54
+ labelHidden: { type: Boolean, default: false, reflect: true, attribute: 'label-hidden' },
49
55
  icon: { type: String, default: '', reflect: true },
50
56
  avatar: { type: String, default: '', reflect: true },
51
57
  mark: { type: Boolean, default: false, reflect: true },
@@ -337,17 +343,22 @@ export class UISelect extends UIFormElement {
337
343
  else this.selectAllOptions();
338
344
  };
339
345
 
340
- // FB-88: tracks whether the host's current aria-label was derived from
341
- // `placeholder` (vs author-supplied), so re-renders refresh/clear OUR name
342
- // without ever clobbering an author's aria-label.
343
- #placeholderNamed = false;
346
+ // FB-88: tracks the aria-label VALUE this element itself last derived from
347
+ // `placeholder` (undefined when none), so re-renders refresh/clear OUR name
348
+ // without ever clobbering a consumer's own aria-label (gh#1646: a boolean
349
+ // flag couldn't detect a consumer's setAttribute between batched renders).
350
+ // The compare-against-what-we-last-wrote guard lives in core/a11y.js's
351
+ // `syncAutoAriaLabel` (gh#1647 / gh#1651); this field is its state.
352
+ #lastAutoAriaLabel = undefined;
344
353
 
345
354
  /**
346
355
  * Derive an accessible name from `placeholder` when the select is otherwise
347
356
  * unnamed — mirrors input-ui so a placeholder-only select (the idiomatic
348
357
  * filter-bar shape) still has a name for assistive tech (WCAG 4.1.2, FB-88).
349
358
  *
350
- * Guards (a placeholder-only fix must NOT clobber a real label):
359
+ * Guards (a placeholder-only fix must NOT clobber a real label) — the
360
+ * per-component policy stays HERE, resolved into the source string
361
+ * (`''` = no auto name this render); the helper only reconciles it:
351
362
  * • an author `aria-label`, a visible `label`, or an `aria-labelledby` wins;
352
363
  * • the default 'Select...' prompt is NOT used as a name — otherwise every
353
364
  * field-ui-wrapped select (named by a sibling `<label for>`, which aria-label
@@ -355,17 +366,26 @@ export class UISelect extends UIFormElement {
355
366
  */
356
367
  #syncAccessibleName() {
357
368
  const DEFAULT_PLACEHOLDER = 'Select...'; // matches static properties.placeholder.default
358
- const authoredAria = this.hasAttribute('aria-label') && !this.#placeholderNamed;
369
+ // gh#1748: [label-hidden] suppresses the visible `::before` text
370
+ // (select.css's `attr(label)` content) but [label] must still name the
371
+ // control — bridge it through the SAME tracked-ownership pipeline used
372
+ // below for the placeholder-only case, so a consumer's own directly-set
373
+ // aria-label is never clobbered (gh#1646 guarantee extends for free) and
374
+ // toggling [label-hidden] back off cleanly releases the bridged value
375
+ // (falls through to the visible-label path, which sets no aria-label —
376
+ // the generated `::before` content supplies the name instead, unchanged
377
+ // from today). Mirrors check-ui's [label-hidden] (gh#1010), which
378
+ // instead sets aria-label unconditionally since check-ui never relies
379
+ // on generated-content naming.
380
+ if (this.labelHidden && this.label) {
381
+ this.#lastAutoAriaLabel = syncAutoAriaLabel(this, this.#lastAutoAriaLabel, this.label);
382
+ return;
383
+ }
359
384
  const labeledElsewhere = !!this.label || this.hasAttribute('aria-labelledby');
360
- const namable = !authoredAria && !labeledElsewhere
385
+ const namable = !labeledElsewhere
361
386
  && this.placeholder && this.placeholder !== DEFAULT_PLACEHOLDER;
362
- if (namable) {
363
- this.setAttribute('aria-label', this.placeholder);
364
- this.#placeholderNamed = true;
365
- } else if (this.#placeholderNamed) {
366
- this.removeAttribute('aria-label');
367
- this.#placeholderNamed = false;
368
- }
387
+ const source = namable ? this.placeholder : '';
388
+ this.#lastAutoAriaLabel = syncAutoAriaLabel(this, this.#lastAutoAriaLabel, source);
369
389
  }
370
390
 
371
391
  connected() {
@@ -7,6 +7,15 @@
7
7
  --select-px: var(--a-ui-px);
8
8
  --select-radius: var(--a-radius);
9
9
  --select-leading-radius: var(--a-radius-full);
10
+ /* gh#1633 / ADIA2-9136 (adiav2#12791) — the host's own `min-width: 0`
11
+ below (the ellipsis-reset trick, kept for the trigger/display text
12
+ inside this floor) had no intrinsic lower bound, so a select in a
13
+ shrinking flex/grid cell crushed to unusable width — the same gap
14
+ already fixed on --input-min-width (this family's reference; see
15
+ input.css, gh#781). Same ch-based UA-baseline derivation, applied
16
+ to select-ui's own trigger surface. Override to 0 to opt back into
17
+ full collapse. */
18
+ --select-min-width: 20ch;
10
19
 
11
20
  /* ── Typography ── */
12
21
  --select-font-size: var(--a-ui-size);
@@ -62,7 +71,11 @@
62
71
  display: flex;
63
72
  flex-direction: column;
64
73
  gap: var(--select-gap);
65
- min-width: 0;
74
+ /* Floored, not zeroed — see --select-min-width above (gh#1633). The
75
+ trigger's own `min-width: 0` further down stays 0: that one exists
76
+ so the display text can ellipsis-truncate INSIDE this floor, not to
77
+ guard the host's own collapse. */
78
+ min-width: var(--select-min-width);
66
79
  /* font-family floor on the host — trigger/native-select/options inherit it. */
67
80
  font-family: var(--select-font-family, var(--a-font-family-ui));
68
81
  font-size: var(--select-font-size);
@@ -85,6 +98,31 @@
85
98
  :scope:not([label])::before,
86
99
  :scope[label=""]::before { display: none; }
87
100
 
101
+ /* Visually-hidden label (gh#1748) — [label-hidden] keeps the a11y name
102
+ (aria-label, bridged from [label] in select.class.js's
103
+ #syncAccessibleName()) but drops the visible text, for compositions
104
+ that already show the name elsewhere (e.g. a table-toolbar-ui
105
+ [slot="scope"] select whose scope/view name is redundant chrome next
106
+ to the toolbar's own title). Same canonical sr-only recipe as
107
+ <visually-hidden-ui> (visually-hidden.css) and check-ui's own
108
+ [label-hidden] (gh#1010) — clip-path does the real hiding, the rest is
109
+ belt-and-suspenders for cross-UA. More specific than the bare
110
+ `::before` rule above, so it wins whenever both [label] and
111
+ [label-hidden] are set. */
112
+ :scope[label][label-hidden]::before {
113
+ content: attr(label);
114
+ position: absolute !important;
115
+ width: 1px !important;
116
+ height: 1px !important;
117
+ padding: 0 !important;
118
+ margin: -1px !important;
119
+ overflow: hidden !important;
120
+ clip: rect(0, 0, 0, 0) !important;
121
+ clip-path: inset(100%) !important;
122
+ white-space: nowrap !important;
123
+ border: 0 !important;
124
+ }
125
+
88
126
  /* Trigger */
89
127
  [slot="trigger"] {
90
128
  display: flex;
@@ -45,6 +45,8 @@ export class UISelect extends UIFormElement {
45
45
  /** Open/closed reflected attribute — toggled by trigger click / keyboard. */
46
46
  open: boolean;
47
47
  label: string;
48
+ /** When true, [label] still sets the accessible name but the visible text is sr-only hidden (gh#1748, mirrors check-ui's [label-hidden], gh#1010). */
49
+ labelHidden: boolean;
48
50
  /** Leading icon name (Phosphor registry). */
49
51
  icon: string;
50
52
  /** Leading avatar URL or name. */
@@ -104,6 +104,18 @@ props:
104
104
  description: Label text above the trigger
105
105
  type: string
106
106
  default: ""
107
+ label-hidden:
108
+ description: >-
109
+ When true, [label] still sets the accessible name (aria-label) but the
110
+ visible `::before` text is suppressed via the canonical sr-only
111
+ technique (gh#1748, mirrors check-ui's [label-hidden], gh#1010). Use
112
+ when a sibling/ancestor composition already conveys the same name
113
+ visually (e.g. a scope/view-switcher select in a table-toolbar-ui
114
+ [slot="scope"], where the toolbar's own title already names the
115
+ view) and a second visible "Scope"-style label would paint it twice.
116
+ type: boolean
117
+ default: false
118
+ reflect: true
107
119
  hint:
108
120
  description: |-
109
121
  §184 (v0.5.5, FEEDBACK-08 §7): small caption rendered beneath the select. Sets `aria-describedby` on the host so screen readers announce it as a description (distinct from `aria-label`, which comes from `label`). Does not conflict with the in-component `label`.
@@ -280,7 +292,13 @@ states:
280
292
  description: Non-interactive; dimmed.
281
293
  attribute: disabled
282
294
  traits: []
283
- tokens: {}
295
+ tokens:
296
+ --select-min-width:
297
+ description: >-
298
+ Intrinsic min-width floor on the host (default `20ch`, matching
299
+ input-ui's own `--input-min-width` UA-baseline derivation) so a
300
+ select in a shrinking flex/grid cell doesn't crush to unusable
301
+ width. Set to `0` to opt back into full collapse (gh#1633).
284
302
  requiredIcons:
285
303
  - caret-down
286
304
  - check # checkbox indicator on each option in [multiple] mode
@@ -22,6 +22,8 @@ export type StreamErrorEvent = CustomEvent<StreamErrorEventDetail>;
22
22
  export type StreamStartEvent = CustomEvent<unknown>;
23
23
 
24
24
  export class UIStream extends UIElement {
25
+ /** When true, suppress the blinking cursor during active streaming */
26
+ hideCursor: boolean;
25
27
  /** Milliseconds between character renders. 0 = real-time. */
26
28
  pace: number;
27
29
  /** Read-only reflected state, true while stream is active */
@@ -312,6 +312,15 @@ registerCellType('progress', {
312
312
 
313
313
  // 13. actions
314
314
  registerCellType('actions', {
315
+ // gh#1678 CodeRabbit follow-up: this render() calls addEventListener()
316
+ // directly on a plain node it creates — unlike every other cell type
317
+ // above (which only set attributes on custom elements, safe to adopt
318
+ // structurally), a discarded 'actions' cell loses a real listener with
319
+ // no way for isEqualNode() to see the loss. `attachesListeners: true`
320
+ // tells table.class.js's adoptOrDiffChildren() (via RENDERER_OWNED) to
321
+ // always replace this cell rather than ever adopt it on structural
322
+ // equality alone. See ssr-compatibility's references/guard-patterns.md §4.1.
323
+ attachesListeners: true,
315
324
  render(value, row, cell, meta) {
316
325
  const actions = meta?.actions || [];
317
326
  let wrapper = cell.querySelector('row-ui');
@@ -13,8 +13,13 @@
13
13
  }
14
14
  ],
15
15
  "properties": {
16
+ "clickable-rows": {
17
+ "description": "Renders body rows with `cursor: pointer`. `row-click` fires unconditionally whether or not a listener is attached, so the cursor can't be inferred from listener presence — set this explicitly when row-click behavior is wired up (master-detail, open-flyout, navigation) so rows read as actionable.",
18
+ "type": "boolean",
19
+ "default": false
20
+ },
16
21
  "columns": {
17
- "description": "Column definitions. Array of {key, label, type?, width?, minWidth?, maxWidth?, flex?, sortable?, resizable?, filterable?, pinned?, hidden?, wrap?, valign?, accessor?, format?, render?, sortFn?, filterType?, meta?}. `valign` ('top'|'center') overrides the host [valign] for that column's body cells only — header cells always stay centered. Alternative to declarative <col-def> children (<col-def valign=\"top\">); col-def also accepts `meta` as a JSON attribute (gh#925) — e.g. <col-def type=\"badge\" meta='{\"variants\":{\"Online\":\"success\"}}'> — so cell-type meta (badge variant maps, currency codes) is expressible in static HTML.",
22
+ "description": "Column definitions. Array of {key, label, type?, width?, minWidth?, maxWidth?, flex?, sortable?, resizable?, filterable?, pinned?, hidden?, wrap?, valign?, accessor?, format?, render?, sortFn?, filterType?, meta?}. `valign` ('top'|'center') overrides the host [valign] for that column's body cells only — header cells always stay centered. Alternative to declarative <col-def> children (<col-def valign=\"top\">); col-def also accepts `meta` as a JSON attribute (gh#925) — e.g. <col-def type=\"badge\" meta='{\"variants\":{\"Online\":\"success\"}}'> — so cell-type meta (badge variant maps, currency codes) is expressible in static HTML. Truncation contract for `render` cells (gh#1681) — a `render(value, row, cell, dataIndex)` function's returned markup isn't guaranteed to be a bare <span>/<a> the way built-in cell types are, so single-line ellipsis truncation isn't automatic; set `data-truncate` on whichever rendered element (any tag, including a custom element) should single-line-ellipsis to opt it into the same contract built-in cells get for free. `[wrap]` (host) / `[data-wrap]` (per-column) override it back to multi-line, matching built-in cells.",
18
23
  "$ref": "common_types.json#/$defs/DynamicStringList"
19
24
  },
20
25
  "component": {