@adia-ai/web-components 0.8.19 → 0.8.21

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 (128) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/components/card/card.a2ui.json +6 -3
  3. package/components/card/card.css +15 -1
  4. package/components/card/card.yaml +5 -3
  5. package/components/nav-group/nav-group.a2ui.json +5 -0
  6. package/components/nav-group/nav-group.class.js +14 -6
  7. package/components/nav-group/nav-group.css +5 -2
  8. package/components/nav-group/nav-group.d.ts +2 -0
  9. package/components/nav-group/nav-group.yaml +4 -0
  10. package/components/select/select.a2ui.json +3 -2
  11. package/components/select/select.class.js +14 -1
  12. package/components/select/select.css +13 -1
  13. package/components/select/select.yaml +5 -4
  14. package/components/table/table.class.js +7 -3
  15. package/components/table/table.css +7 -5
  16. package/dist/theme-provider.min.js +1 -1
  17. package/dist/web-components.min.css +1 -1
  18. package/dist/web-components.min.js +19 -19
  19. package/dist/web-components.sheet.js +1 -1
  20. package/package.json +2 -1
  21. package/components/adia-mark/adia-mark.test.js +0 -69
  22. package/components/adia-wordmark/adia-wordmark.test.js +0 -69
  23. package/components/agent-artifact/agent-artifact.test.js +0 -61
  24. package/components/alert/alert.test.js +0 -364
  25. package/components/color-picker/color-picker.test.js +0 -96
  26. package/components/combobox/combobox.test.js +0 -256
  27. package/components/command/command.test.js +0 -99
  28. package/components/date-range-picker/date-range-picker.test.js +0 -387
  29. package/components/datetime-picker/datetime-picker.test.js +0 -454
  30. package/components/demo-toggle/demo-toggle.test.js +0 -102
  31. package/components/description-list/description-list.test.js +0 -72
  32. package/components/display-field/display-field.test.js +0 -115
  33. package/components/empty-state/empty-state.test.js +0 -77
  34. package/components/field/field.test.js +0 -260
  35. package/components/fields/fields.test.js +0 -88
  36. package/components/inline-message/inline-message.test.js +0 -203
  37. package/components/input/input.test.js +0 -335
  38. package/components/integration-card/integration-card.test.js +0 -318
  39. package/components/link/link.test.js +0 -143
  40. package/components/list/list.test.js +0 -106
  41. package/components/list-window/list-window.test.js +0 -303
  42. package/components/loading-overlay/loading-overlay.test.js +0 -257
  43. package/components/menu/menu.test.js +0 -176
  44. package/components/nav/nav.test.js +0 -428
  45. package/components/nav-group/nav-group.test.js +0 -67
  46. package/components/option-card/option-card.test.js +0 -32
  47. package/components/pagination/pagination.test.js +0 -195
  48. package/components/select/select.test.js +0 -481
  49. package/components/slider/slider.test.js +0 -202
  50. package/components/spinner/spinner.test.js +0 -272
  51. package/components/stat/stat.test.js +0 -108
  52. package/components/step-progress/step-progress.test.js +0 -129
  53. package/components/swatch/swatch.test.js +0 -563
  54. package/components/table/table.test.js +0 -479
  55. package/components/table-toolbar/table-toolbar.test.js +0 -152
  56. package/components/tag/tag.test.js +0 -137
  57. package/components/tags-input/tags-input.test.js +0 -477
  58. package/components/text/text.test.js +0 -202
  59. package/components/theme-provider/theme-provider.test.js +0 -94
  60. package/components/time-picker/time-picker.test.js +0 -287
  61. package/components/timeline/timeline.test.js +0 -31
  62. package/components/toggle-scheme/toggle-scheme.test.js +0 -110
  63. package/components/tree/tree.test.js +0 -312
  64. package/core/element.test.js +0 -389
  65. package/core/icons.test.js +0 -187
  66. package/core/logical-children.test.js +0 -54
  67. package/core/markdown.test.js +0 -47
  68. package/core/responsive.test.js +0 -121
  69. package/core/template.test.js +0 -611
  70. package/traits/active-state/active-state.test.js +0 -28
  71. package/traits/anchor-positioning/anchor-positioning.test.js +0 -122
  72. package/traits/announcer/announcer.test.js +0 -268
  73. package/traits/arrow-grid-nav/arrow-grid-nav.test.js +0 -375
  74. package/traits/attention-pulse/attention-pulse.test.js +0 -26
  75. package/traits/confetti/confetti.test.js +0 -46
  76. package/traits/confetti-burst/confetti-burst.test.js +0 -46
  77. package/traits/count-up/count-up.test.js +0 -54
  78. package/traits/declarative.test.js +0 -138
  79. package/traits/dirty-state/dirty-state.test.js +0 -45
  80. package/traits/drag-ghost/drag-ghost.test.js +0 -19
  81. package/traits/draggable/draggable.test.js +0 -60
  82. package/traits/draggable-list-item/draggable-list-item.test.js +0 -51
  83. package/traits/drop-target/drop-target.test.js +0 -241
  84. package/traits/droppable/droppable.test.js +0 -54
  85. package/traits/droppable-collection/droppable-collection.test.js +0 -99
  86. package/traits/error-shake/error-shake.test.js +0 -114
  87. package/traits/fade-presence/fade-presence.test.js +0 -20
  88. package/traits/focus-restore/focus-restore.test.js +0 -202
  89. package/traits/focus-trap/focus-trap.test.js +0 -42
  90. package/traits/focusable/focusable.test.js +0 -53
  91. package/traits/glow-focus/glow-focus.test.js +0 -31
  92. package/traits/gradient-shift/gradient-shift.test.js +0 -22
  93. package/traits/haptic-feedback/haptic-feedback.test.js +0 -52
  94. package/traits/hotkey/hotkey.test.js +0 -61
  95. package/traits/hoverable/hoverable.test.js +0 -24
  96. package/traits/inertia-drag/inertia-drag.test.js +0 -33
  97. package/traits/input-mask/input-mask.test.js +0 -151
  98. package/traits/intersection-observer/intersection-observer.test.js +0 -38
  99. package/traits/keyboard-nav/keyboard-nav.test.js +0 -41
  100. package/traits/keyboard-reorderable/keyboard-reorderable.test.js +0 -45
  101. package/traits/layout-animation/layout-animation.test.js +0 -114
  102. package/traits/long-press/long-press.test.js +0 -244
  103. package/traits/magnetic-hover/magnetic-hover.test.js +0 -30
  104. package/traits/noise-texture/noise-texture.test.js +0 -20
  105. package/traits/parallax/parallax.test.js +0 -26
  106. package/traits/portal/portal.test.js +0 -30
  107. package/traits/pressable/pressable.test.js +0 -73
  108. package/traits/resettable/resettable.test.js +0 -100
  109. package/traits/resizable/resizable.test.js +0 -39
  110. package/traits/resize-observer/resize-observer.test.js +0 -38
  111. package/traits/ripple/ripple.test.js +0 -32
  112. package/traits/roving-tabindex/roving-tabindex.test.js +0 -28
  113. package/traits/scale-press/scale-press.test.js +0 -39
  114. package/traits/scroll-lock/scroll-lock.test.js +0 -45
  115. package/traits/scroll-progress/scroll-progress.test.js +0 -182
  116. package/traits/shimmer-loading/shimmer-loading.test.js +0 -43
  117. package/traits/smoke.test.js +0 -111
  118. package/traits/snap-to-grid/snap-to-grid.test.js +0 -40
  119. package/traits/sound-feedback/sound-feedback.test.js +0 -26
  120. package/traits/spring-animate/spring-animate.test.js +0 -28
  121. package/traits/success-checkmark/success-checkmark.test.js +0 -120
  122. package/traits/tilt-hover/tilt-hover.test.js +0 -32
  123. package/traits/tossable/tossable.test.js +0 -31
  124. package/traits/traits-host.test.js +0 -73
  125. package/traits/typeahead/typeahead.test.js +0 -38
  126. package/traits/typewriter/typewriter.test.js +0 -47
  127. package/traits/validation/validation.test.js +0 -93
  128. package/traits/view-transition/view-transition.test.js +0 -268
package/CHANGELOG.md CHANGED
@@ -1,5 +1,31 @@
1
1
  # Changelog — @adia-ai/web-components
2
2
 
3
+ ## [0.8.21] — 2026-07-28
4
+
5
+ ### Fixed
6
+ - **`card-ui`: a `<span slot="heading">` finally reads as a heading** (gh issue 471, from the adiav2 admin modal-patterns gallery). Only the FOOTER heading rule set size/weight/color; the header's heading slot got grid placement and flex layout but no typography, so a bare span inherited body text while an `<h3 slot="heading">` looked right — the same slot, two different results depending on the tag. The header slot now carries `--card-heading-size` / `--card-heading-weight` (defaulting to modal-ui and drawer-ui's pair, so a card title, a dialog title, and a drawer title read at one weight) plus `--card-heading-fg`; native `h1`–`h6` and the `text-ui` heading variants are exempt from the size/weight so they keep their own scale.
7
+ - **`card-ui` yaml↔CSS token drift** — the yaml documented `--card-heading-color` and `--card-heading-size`, neither of which existed in the CSS (the real color token is `--card-heading-fg`). The yaml now names the tokens that ship.
8
+ - **`table-ui`: `col.minWidth`/`col.maxWidth` now reach the grid template** (gh issue 463, from the adiav2 admin table audit ADIA2-6847). Both props were parsed from `<col-def>` and documented in the yaml since the initial table cut, but `#buildGridTemplate()` only ever emitted `minmax(6rem, Nfr)` — so a flexible column could collapse to 96px and consumers routed around it with fixed px widths that overflow the container instead of distributing slack. Flexible tracks now render `minmax(minWidth ?? 6rem, maxWidth ?? (flex ?? 1)fr)`; explicit `width` and user resize still win.
9
+ - **`table-ui[wrap]` breaks at word boundaries** — the wrap opt-in used `overflow-wrap: anywhere`, which both broke words mid-glyph ("deficienc / y") and collapsed the cell's min-content contribution to one glyph, letting flexible tracks shrink to their floor. Now `break-word`: whole words wrap first, and a token only breaks when it alone overflows the cell (URLs, ids).
10
+ - **`select-ui` action rows no longer wear radio indicators** (`components/select/`; operator report 2026-07-28 from adia-v2). The 0.8.17 radio ruling stamps every single-select row `[data-radio]` — including `{action}` rows, which are COMMANDS (they dispatch the `action` event and never become the value), so user menus grew radios on "Account" / "Log out". Action rows now render `[data-action-option]`: icon + label, no indicator at all; selection rows beside them keep theirs. The branch precedes the `[multiple]` one, so a command row in a multi-select doesn't get a checkbox either (it never becomes part of the value — `#onOptionClick` always treated it as a command). The yaml documents the entry shape.
11
+ - **Option-row leads can't stack above their label anymore** (`components/select/select.css`; the second adia-v2 report). The lead (`mark`/`avatar`/`icon`) is injected inside `[data-option-label]`, which was a plain block — `icon-ui` (inline-flex) and `<img>` (inline) rode the text line by accident, but `adia-mark-ui` is block-level per ADR-0037 and stacked above the text in the workspace switcher. The label span is now a centered flex row with the trigger's leading gap, which also makes lead-to-label spacing uniform across all three lead types.
12
+
13
+ ### Maintenance
14
+ - **`dist/` bundles rebuilt** in this cut's window (4 file(s)) — regenerated from the source changes described above, not independent edits.
15
+
16
+ ## [0.8.20] — 2026-07-28
17
+
18
+ ### Fixed
19
+ - **The npm tarball no longer ships `*.test.js`** (gh#462) — the `files` roster excluded examples/html but never unit tests, so 108 test file(s) rode the 0.8.19 tarball. `!**/*.test.js` appended as the roster's LAST entry (npm's files globbing is order-sensitive — a leading exclude is overridden by later directory includes). Proof: `npm pack --dry-run` → 0 test files, runtime files intact.
20
+
21
+ ### Changed
22
+ - **`nav-group-ui`: the selected-look header color also keys on `[selected]`** — the CSS half of the gh#459 ruling (PR #460 corrected the icon weight, but the `--nav-group-fg-selected` header treatment still keyed on `[open]`, so an expanded-but-inactive group read as the active section while a collapsed-but-active one read plain — the exact screenshot that reopened this). The `[open]` indent rail stays structural.
23
+ - **`nav-group-ui`: the filled header glyph tracks `[selected]`, not `[open]`** (gh#459, operator ruling) — the fill marks the group containing the selected route; a merely-expanded group stays regular, and a collapsed-but-active one fills. `selected` becomes a declared reflected prop (yaml + types); `[open]` keeps driving `aria-expanded` only. Consumers that already set `[selected]` from active-route logic (the adiav2 admin shell does) get the corrected behavior with no changes.
24
+
25
+ ### Maintenance
26
+ - **`components/` touched in this release window** (6 file(s), e.g. `nav-group/nav-group.a2ui.json`) — carried by the entries above.
27
+ - **`dist/` bundles rebuilt** in this cut's window (4 file(s)) — regenerated from the source changes described above, not independent edits.
28
+
3
29
  ## [0.8.19] — 2026-07-27
4
30
 
5
31
  ### Added
@@ -244,11 +244,14 @@
244
244
  "--card-divider-color": {
245
245
  "description": "Override divider border color"
246
246
  },
247
- "--card-heading-color": {
248
- "description": "Override heading color"
247
+ "--card-heading-fg": {
248
+ "description": "Override heading color (header and footer heading slots)"
249
249
  },
250
250
  "--card-heading-size": {
251
- "description": "Override heading text size"
251
+ "description": "Override header heading text size — applies to a generic slot=\"heading\" container; native h1–h6 and text-ui heading variants keep their own scale"
252
+ },
253
+ "--card-heading-weight": {
254
+ "description": "Override header heading font weight — same scope as --card-heading-size"
252
255
  },
253
256
  "--card-inset": {
254
257
  "description": "Override --inset for all children"
@@ -18,6 +18,10 @@
18
18
  /* ── Typography ── */
19
19
  --card-font-size: var(--a-body-size);
20
20
  --card-description-size: var(--a-caption-size);
21
+ /* Header heading — matches modal-ui/drawer-ui's heading pair so a card
22
+ title, a dialog title, and a drawer title read at one weight. */
23
+ --card-heading-size: var(--a-ui-lg);
24
+ --card-heading-weight: var(--a-weight-semibold);
21
25
 
22
26
  /* ── Colors ── */
23
27
  --card-bg: var(--md-sys-color-neutral-surface);
@@ -246,11 +250,21 @@
246
250
  line-height: 1.3;
247
251
  margin: 0;
248
252
  }
249
- /* Heading slot is a flex container — can hold title + inline badges/metadata */
253
+ /* Heading slot is a flex container — can hold title + inline badges/metadata.
254
+ It also carries the heading's own typography: the slot is routinely a bare
255
+ <span slot="heading">Title</span>, which inherited body text because only
256
+ the FOOTER heading rule set size/weight/color (gh issue 471). Native
257
+ h1–h6 and the text-ui heading variants bring their own scale, so they keep
258
+ it — the tokens apply to the generic container only. */
250
259
  & > header > [slot="heading"] {
251
260
  display: flex;
252
261
  align-items: center;
253
262
  gap: var(--card-header-gap);
263
+ color: var(--card-heading-fg);
264
+ }
265
+ & > header > [slot="heading"]:not(:is(h1, h2, h3, h4, h5, h6, text-ui)) {
266
+ font-size: var(--card-heading-size);
267
+ font-weight: var(--card-heading-weight);
254
268
  }
255
269
  & > header:has(> [slot="icon"]) > :is([slot="heading"], h1, h2, h3, h4, h5, h6) { grid-column: 2; }
256
270
  & > header:has(> [slot="icon"]) > :is(text-ui[variant="display"], text-ui[variant="title"], text-ui[variant="heading"], text-ui[variant="subsection"]):not([slot]) { grid-column: 2; }
@@ -111,10 +111,12 @@ tokens:
111
111
  description: Override description color
112
112
  --card-divider-color:
113
113
  description: Override divider border color
114
- --card-heading-color:
115
- description: Override heading color
114
+ --card-heading-fg:
115
+ description: Override heading color (header and footer heading slots)
116
116
  --card-heading-size:
117
- description: Override heading text size
117
+ description: Override header heading text size — applies to a generic slot="heading" container; native h1–h6 and text-ui heading variants keep their own scale
118
+ --card-heading-weight:
119
+ description: Override header heading font weight — same scope as --card-heading-size
118
120
  --card-inset:
119
121
  description: Override --inset for all children
120
122
  --card-radius:
@@ -36,6 +36,11 @@
36
36
  "type": "boolean",
37
37
  "default": false
38
38
  },
39
+ "selected": {
40
+ "description": "Marks the group containing the selected route (consumers set it from active-route logic). Drives the filled header glyph — selection, never mere expansion (gh#459).",
41
+ "type": "boolean",
42
+ "default": false
43
+ },
39
44
  "text": {
40
45
  "description": "Visible group label.",
41
46
  "type": "string",
@@ -35,6 +35,10 @@ export class UINavGroup extends UIElement {
35
35
  icon: { type: String, default: '', reflect: true },
36
36
  badge: { type: String, default: '', reflect: true },
37
37
  open: { type: Boolean, default: false, reflect: true },
38
+ // gh#459: marks the group that CONTAINS the selected route — drives the
39
+ // filled header glyph (selection, never mere expansion) and the CSS
40
+ // selected treatment. Consumers set it from their active-route logic.
41
+ selected: { type: Boolean, default: false, reflect: true },
38
42
  collapsible: { type: Boolean, default: true, reflect: true },
39
43
  variant: { type: String, default: '', reflect: true },
40
44
  };
@@ -87,13 +91,17 @@ export class UINavGroup extends UIElement {
87
91
 
88
92
  this.setAttribute('aria-expanded', String(this.open));
89
93
 
90
- // Mirrors nav-item-ui's selected → fill convention: an open group
91
- // reads as the active section via the same filled-glyph treatment
92
- // [open] already drives (nav-group.css's [open] > [slot=header] color
93
- // rule) a state-driven weight swap, not a CSS color change, since
94
- // Phosphor ships filled/regular as distinct SVGs.
94
+ // Mirrors nav-item-ui's selected → fill convention: the filled glyph
95
+ // marks SELECTION, not expansion (gh#459, operator ruling 2026-07-27)
96
+ // the group CONTAINING the selected route fills (consumers set [selected]
97
+ // on it), while a merely-expanded group stays regular. Keyed on the
98
+ // attribute so it works whether or not a consumer uses the property
99
+ // path; [open] keeps driving aria-expanded only. A state-driven weight
100
+ // swap, not a CSS color change, since Phosphor ships filled/regular as
101
+ // distinct SVGs.
95
102
  const iconEl = this.querySelector('[slot="header"] [slot="icon"] icon-ui');
96
- if (iconEl) iconEl.setAttribute('weight', this.open ? 'fill' : 'regular');
103
+ if (iconEl)
104
+ iconEl.setAttribute('weight', this.hasAttribute('selected') ? 'fill' : 'regular');
97
105
  }
98
106
 
99
107
  showPopover() {
@@ -49,8 +49,11 @@
49
49
  background: var(--nav-group-indent-rail-bg);
50
50
  pointer-events: none;
51
51
  }
52
- :scope[open] > [slot="header"],
53
- :scope[open] > [slot="header"] [slot="icon"] {
52
+ /* Selected-look header treatment keys on [selected] the CSS half of
53
+ gh issue 459 (PR 460 corrected the icon weight): the group CONTAINING
54
+ the selected route reads strong; a merely-expanded group does not. */
55
+ :scope[selected] > [slot="header"],
56
+ :scope[selected] > [slot="header"] [slot="icon"] {
54
57
  color: var(--nav-group-fg-selected);
55
58
  }
56
59
 
@@ -38,6 +38,8 @@ export class UINavGroup extends UIElement {
38
38
  icon: string;
39
39
  /** Inline-expanded state. Toggled by header click when [collapsible]. */
40
40
  open: boolean;
41
+ /** Marks the group containing the selected route (consumers set it from active-route logic). Drives the filled header glyph — selection, never mere expansion (gh#459). */
42
+ selected: boolean;
41
43
  /** Visible group label. */
42
44
  text: string;
43
45
  /** Visual treatment. Default ('') renders as a primary-rail group (icon row, caret, collapsible). 'section' renders the header as a static kicker label with always-visible children. When the parent <nav-ui> carries variant="section", this group inherits it via CSS cascade unless an explicit variant is set on the group. */
@@ -37,6 +37,10 @@ props:
37
37
  type: boolean
38
38
  default: false
39
39
  description: "Inline-expanded state. Toggled by header click when [collapsible]."
40
+ selected:
41
+ type: boolean
42
+ default: false
43
+ description: "Marks the group containing the selected route (consumers set it from active-route logic). Drives the filled header glyph — selection, never mere expansion (gh#459)."
40
44
  collapsible:
41
45
  type: boolean
42
46
  default: true
@@ -112,7 +112,7 @@
112
112
  "default": false
113
113
  },
114
114
  "options": {
115
- "description": "Option list. Array of {value, label, disabled?, icon?, avatar?, mark?} or grouped {label, options: [...]}. Alternative to declarative <option> / <optgroup> children. Per-option icon/avatar/mark render in the list AND reflect in the trigger's selected state (mark takes precedence over avatar, which takes precedence over icon).",
115
+ "description": "Option list. Array of {value, label, disabled?, icon?, avatar?, mark?} or grouped {label, options: [...]}. Alternative to declarative <option> / <optgroup> children. Per-option icon/avatar/mark render in the list AND reflect in the trigger's selected state (mark takes precedence over avatar, which takes precedence over icon). An {action, label} entry is a COMMAND row, not a selection: it dispatches the `action` event, never becomes the value, and renders without the single-select radio indicator (user menus: Account / Log out).",
116
116
  "$ref": "common_types.json#/$defs/DynamicStringList"
117
117
  },
118
118
  "pattern": {
@@ -180,7 +180,8 @@
180
180
  "composes": [
181
181
  "icon-ui",
182
182
  "tag-ui",
183
- "button-ui"
183
+ "button-ui",
184
+ "adia-mark-ui"
184
185
  ],
185
186
  "events": {
186
187
  "change": {
@@ -778,7 +778,20 @@ export class UISelect extends UIFormElement {
778
778
  // Per-option leading glyph — mark (adia-mark-ui) wins over avatar
779
779
  // (img), which wins over icon (icon-ui).
780
780
  const lead = UISelect.#optionLeadHTML(opt);
781
- if (this.multiple) {
781
+ // Action rows are COMMANDS in BOTH modes — this branch must precede
782
+ // the [multiple] one, or a {action} entry in a multi-select renders
783
+ // with a checkbox while #onOptionClick already treats it as a command
784
+ // (CodeRabbit, PR #467). They dispatch `action` and never become the
785
+ // value, so they carry no indicator at all: the 2026-07-27 radio
786
+ // ruling covers selection rows only (operator report 2026-07-28).
787
+ if (opt.action) {
788
+ el.setAttribute('data-action-option', '');
789
+ const label = document.createElement('span');
790
+ label.setAttribute('data-option-label', '');
791
+ if (lead) label.innerHTML = `${lead}${escapeHTML(opt.label)}`;
792
+ else label.textContent = opt.label;
793
+ el.appendChild(label);
794
+ } else if (this.multiple) {
782
795
  el.setAttribute('data-multi-option', '');
783
796
  const box = document.createElement('span');
784
797
  box.setAttribute('data-checkbox', '');
@@ -487,10 +487,22 @@ select-ui [role="option"][data-single-option][aria-selected="true"] [data-radio]
487
487
  select-ui [role="option"][data-single-option][aria-selected="true"] [data-radio]::after {
488
488
  transform: scale(1);
489
489
  }
490
- select-ui [role="option"][data-single-option] [data-option-label] {
490
+ select-ui [role="option"][data-single-option] [data-option-label],
491
+ select-ui [role="option"][data-action-option] [data-option-label] {
491
492
  flex: 1;
492
493
  min-width: 0;
493
494
  }
495
+ /* The lead (mark/avatar/icon) is injected INSIDE the label span, which was
496
+ a plain block: icon-ui (inline-flex) and <img> (inline) ride the text
497
+ line by accident, but adia-mark-ui is block-level per ADR-0037 and
498
+ stacked ABOVE the label (bit adia-v2's workspace switcher, 2026-07-28).
499
+ A centered flex row makes every lead type an inline flex item; the gap
500
+ mirrors the trigger's leading gap. */
501
+ select-ui [role="option"] [data-option-label] {
502
+ display: inline-flex;
503
+ align-items: center;
504
+ gap: var(--select-trigger-gap);
505
+ }
494
506
  select-ui [role="option"][data-multi-option] [data-checkbox] {
495
507
  flex-shrink: 0;
496
508
  display: inline-flex;
@@ -25,9 +25,10 @@ description: |
25
25
  # Per ADR-0027 — primitives that programmatically create other primitives
26
26
  # do NOT auto-import them. Consumer (or demo shell) must explicitly import.
27
27
  composes:
28
- - icon-ui # caret + option-row affixes (created in render)
29
- - tag-ui # multi-select chip per selected option in the trigger
30
- - button-ui # clear-all / select-all / +N-overflow affordances (gh issue 276 — no native <button> in stamped DOM)
28
+ - icon-ui # caret + option-row affixes (created in render)
29
+ - tag-ui # multi-select chip per selected option in the trigger
30
+ - button-ui # clear-all / select-all / +N-overflow affordances (gh issue 276 — no native <button> in stamped DOM)
31
+ - adia-mark-ui # [mark] trigger/option leading (created in render, gh#339)
31
32
  props:
32
33
  name:
33
34
  description: Form control name for form data submission
@@ -173,7 +174,7 @@ props:
173
174
  default: false
174
175
  reflect: true
175
176
  options:
176
- description: "Option list. Array of {value, label, disabled?, icon?, avatar?, mark?} or grouped {label, options: [...]}. Alternative to declarative <option> / <optgroup> children. Per-option icon/avatar/mark render in the list AND reflect in the trigger's selected state (mark takes precedence over avatar, which takes precedence over icon)."
177
+ description: "Option list. Array of {value, label, disabled?, icon?, avatar?, mark?} or grouped {label, options: [...]}. Alternative to declarative <option> / <optgroup> children. Per-option icon/avatar/mark render in the list AND reflect in the trigger's selected state (mark takes precedence over avatar, which takes precedence over icon). An {action, label} entry is a COMMAND row, not a selection: it dispatches the `action` event, never becomes the value, and renders without the single-select radio indicator (user menus: Account / Log out)."
177
178
  type: array
178
179
  default: []
179
180
  dynamic: true # JS-set collection prop with a custom setter — deliberately not in static properties
@@ -474,10 +474,14 @@ export class UITable extends UIElement {
474
474
  parts.push(`${this.#columnWidths.get(col.key)}px`);
475
475
  } else if (col.width) {
476
476
  parts.push(`${col.width}px`);
477
- } else if (col.flex) {
478
- parts.push(`minmax(6rem, ${col.flex}fr)`);
479
477
  } else {
480
- parts.push('minmax(6rem, 1fr)');
478
+ // Flexible track: col.minWidth raises the 6rem floor (gh issue 463 —
479
+ // the prop was parsed and documented but never reached the template,
480
+ // so flex columns could collapse to 96px); col.maxWidth caps the
481
+ // track instead of letting the fr grow unbounded.
482
+ const min = col.minWidth ? `${col.minWidth}px` : '6rem';
483
+ const max = col.maxWidth ? `${col.maxWidth}px` : `${col.flex || 1}fr`;
484
+ parts.push(`minmax(${min}, ${max})`);
481
485
  }
482
486
  }
483
487
 
@@ -298,15 +298,17 @@
298
298
  }
299
299
 
300
300
  /* Wrap opt-in: per-table (all body cells) or per-cell (one column).
301
- Restores the legacy `overflow-wrap: anywhere` behavior so wrapped
302
- content can break inside long unbroken tokens (URLs, IDs). Row
303
- height auto-grows to fit. */
301
+ `break-word` wraps at word boundaries and only breaks inside a token
302
+ when that single token alone overflows the cell (URLs, IDs). The
303
+ previous `anywhere` also collapsed the cell's min-content width to
304
+ one glyph, so flexible tracks shrank to their floor and words broke
305
+ mid-glyph (gh issue 463). Row height auto-grows to fit. */
304
306
  :scope[wrap] [data-body] [role="gridcell"],
305
307
  [data-body] [role="gridcell"][data-wrap] {
306
308
  white-space: normal;
307
309
  overflow: visible;
308
310
  text-overflow: clip;
309
- overflow-wrap: anywhere;
311
+ overflow-wrap: break-word;
310
312
  }
311
313
 
312
314
  :scope[wrap] [data-body] [role="gridcell"] > span,
@@ -316,7 +318,7 @@
316
318
  white-space: normal;
317
319
  overflow: visible;
318
320
  text-overflow: clip;
319
- overflow-wrap: anywhere;
321
+ overflow-wrap: break-word;
320
322
  }
321
323
 
322
324
  [data-align="right"] {