@adia-ai/web-components 0.8.20 → 0.8.22
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.
- package/CHANGELOG.md +24 -0
- package/components/card/card.a2ui.json +6 -3
- package/components/card/card.css +15 -1
- package/components/card/card.yaml +5 -3
- package/components/combobox/combobox.a2ui.json +1 -1
- package/components/combobox/combobox.class.js +14 -4
- package/components/combobox/combobox.css +52 -4
- package/components/combobox/combobox.yaml +5 -1
- package/components/select/select.a2ui.json +3 -2
- package/components/select/select.class.js +28 -4
- package/components/select/select.css +13 -1
- package/components/select/select.yaml +5 -4
- package/components/table/table.class.js +7 -3
- package/components/table/table.css +7 -5
- package/dist/theme-provider.min.js +1 -1
- package/dist/web-components.min.css +1 -1
- package/dist/web-components.min.js +17 -17
- package/dist/web-components.sheet.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# Changelog — @adia-ai/web-components
|
|
2
2
|
|
|
3
|
+
## [0.8.22] — 2026-07-29
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
- **`select-ui` action rows no longer read as selected in an uncommitted select** (`components/select/`; independent-review finding, 2026-07-29). Action rows stamped `data-value=""`, and since `value` defaults to `''`, the aria-selected sync marked every command row selected whenever nothing was committed — the default state of a user menu, so screen readers announced "Log out, selected" and the row rendered at selected weight. Action rows now carry no `data-value` at all, both aria-selected paths (initial stamp + sync loop) skip them, and the regression test covers the sync loop the original tests missed.
|
|
7
|
+
|
|
8
|
+
### Changed
|
|
9
|
+
- **`combobox-ui` single-select rows carry a radio indicator** (`components/combobox/`; operator ruling 2026-07-27, extended). `select-ui` adopted the indicator treatment in 0.8.17 — "selection rides the control, not a row tint" — but combobox was left tinting the committed row with `--a-ui-bg-selected`, so two sibling single-select surfaces disagreed about what *selected* looks like (the same divergence class gh#474 fixed between `form-popover-ui` and `select-ui`). Rows now stamp `[data-single-option]` + a leading `[data-radio]` (bordered circle, primary ring + centre dot when committed), mirroring select-ui's structure and CSS exactly. `--combobox-option-bg-selected` / `-fg-selected` remain consumer-overridable API, but their DEFAULTS move to the plain row colors — set `--combobox-option-bg-selected` to re-enable a tinted row. Hover/active feedback is restated on the selected row, since the 2-attribute selected rule outweighs the single-attribute `[data-active]` one (the trap select-ui hit when its tint was removed). Tests 15 → 17.
|
|
10
|
+
|
|
11
|
+
### Maintenance
|
|
12
|
+
- **`dist/` bundles rebuilt** in this cut's window (4 file(s)) — regenerated from the source changes described above, not independent edits.
|
|
13
|
+
|
|
14
|
+
## [0.8.21] — 2026-07-28
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
- **`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.
|
|
18
|
+
- **`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.
|
|
19
|
+
- **`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.
|
|
20
|
+
- **`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).
|
|
21
|
+
- **`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.
|
|
22
|
+
- **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.
|
|
23
|
+
|
|
24
|
+
### Maintenance
|
|
25
|
+
- **`dist/` bundles rebuilt** in this cut's window (4 file(s)) — regenerated from the source changes described above, not independent edits.
|
|
26
|
+
|
|
3
27
|
## [0.8.20] — 2026-07-28
|
|
4
28
|
|
|
5
29
|
### Fixed
|
|
@@ -244,11 +244,14 @@
|
|
|
244
244
|
"--card-divider-color": {
|
|
245
245
|
"description": "Override divider border color"
|
|
246
246
|
},
|
|
247
|
-
"--card-heading-
|
|
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"
|
package/components/card/card.css
CHANGED
|
@@ -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-
|
|
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:
|
|
@@ -342,7 +342,7 @@
|
|
|
342
342
|
"description": "Background for the currently active (arrow-navigated) option"
|
|
343
343
|
},
|
|
344
344
|
"--combobox-option-bg-selected": {
|
|
345
|
-
"description": "Background for the currently committed option"
|
|
345
|
+
"description": "Background for the currently committed option. Defaults to `transparent`: selection is shown by the leading radio indicator rather than a row tint, matching select-ui. Set this to re-enable a tinted selected row."
|
|
346
346
|
},
|
|
347
347
|
"--combobox-option-fg-active": {
|
|
348
348
|
"description": "Foreground for the currently active option"
|
|
@@ -394,10 +394,20 @@ export class UICombobox extends UIFormElement {
|
|
|
394
394
|
el.dataset.value = opt.value ?? '';
|
|
395
395
|
if (opt.disabled) el.setAttribute('aria-disabled', 'true');
|
|
396
396
|
if (opt.value === this.value) el.setAttribute('aria-selected', 'true');
|
|
397
|
-
//
|
|
398
|
-
//
|
|
399
|
-
//
|
|
400
|
-
|
|
397
|
+
// Selection rides a RADIO indicator, not a row tint (operator ruling
|
|
398
|
+
// 2026-07-27, the same one select-ui's single-select rows follow) —
|
|
399
|
+
// combobox was the last single-select surface still speaking the old
|
|
400
|
+
// language, which made two sibling controls disagree about what
|
|
401
|
+
// "selected" looks like. [data-single-option] is the structural hook
|
|
402
|
+
// CSS keys off, mirroring select-ui exactly.
|
|
403
|
+
//
|
|
404
|
+
// Single wrapping span for the LABEL: [role="option"] is display:flex,
|
|
405
|
+
// and a bare <mark> + text-run pair become SEPARATE flex items — flex
|
|
406
|
+
// drops the whitespace between them ("Ada Lovelace" → "AdaLovelace").
|
|
407
|
+
el.setAttribute('data-single-option', '');
|
|
408
|
+
el.innerHTML =
|
|
409
|
+
`<span data-radio aria-hidden="true"></span>` +
|
|
410
|
+
`<span data-option-label>${this.#renderOptionLabel(opt.label ?? opt.value)}</span>`;
|
|
401
411
|
el.addEventListener('click', this.#onOptionClick);
|
|
402
412
|
el.addEventListener('mouseenter', this.#onOptionMouseEnter);
|
|
403
413
|
return el;
|
|
@@ -41,8 +41,12 @@
|
|
|
41
41
|
--combobox-option-py: var(--a-space-1);
|
|
42
42
|
--combobox-option-bg-active: var(--a-ui-bg-hover);
|
|
43
43
|
--combobox-option-fg-active: var(--a-ui-text-hover);
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
/* Selection rides the RADIO indicator, not a row tint (operator ruling
|
|
45
|
+
2026-07-27) — so these DEFAULT to the plain row colors, matching
|
|
46
|
+
select-ui. Both remain consumer-overridable API: set
|
|
47
|
+
--combobox-option-bg-selected to re-enable a tinted selected row. */
|
|
48
|
+
--combobox-option-bg-selected: transparent;
|
|
49
|
+
--combobox-option-fg-selected: var(--a-ui-text-subtle);
|
|
46
50
|
|
|
47
51
|
/* ── Match highlight ── */
|
|
48
52
|
--combobox-match-bg: var(--md-sys-color-primary-container);
|
|
@@ -242,10 +246,54 @@ combobox-ui [data-listbox] [role="option"][data-active] {
|
|
|
242
246
|
}
|
|
243
247
|
|
|
244
248
|
combobox-ui [data-listbox] [role="option"][aria-selected="true"] {
|
|
245
|
-
background: var(--
|
|
246
|
-
color: var(--
|
|
249
|
+
background: var(--combobox-option-bg-selected);
|
|
250
|
+
color: var(--combobox-option-fg-selected);
|
|
247
251
|
font-weight: var(--a-ui-weight);
|
|
248
252
|
}
|
|
253
|
+
/* Hover/active feedback restated on the selected row: the 2-attribute rule
|
|
254
|
+
above outweighs the single-attribute [data-active] rule, so without this a
|
|
255
|
+
selected row would stop responding to keyboard/pointer highlight (the same
|
|
256
|
+
trap select-ui hit when its row tint was removed). */
|
|
257
|
+
combobox-ui [data-listbox] [role="option"][aria-selected="true"][data-active] {
|
|
258
|
+
background: var(--a-ui-bg-hover);
|
|
259
|
+
color: var(--a-ui-text-hover);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/* ── Radio indicator (mirrors select-ui's single-select rows) ── */
|
|
263
|
+
combobox-ui [data-listbox] [role="option"][data-single-option] {
|
|
264
|
+
gap: var(--a-space-2);
|
|
265
|
+
}
|
|
266
|
+
combobox-ui [data-listbox] [role="option"][data-single-option] [data-radio] {
|
|
267
|
+
flex-shrink: 0;
|
|
268
|
+
display: inline-flex;
|
|
269
|
+
align-items: center;
|
|
270
|
+
justify-content: center;
|
|
271
|
+
width: 1rem;
|
|
272
|
+
height: 1rem;
|
|
273
|
+
border: 1px solid var(--a-ui-border);
|
|
274
|
+
border-radius: 50%;
|
|
275
|
+
background: var(--md-sys-color-neutral-surface-bright);
|
|
276
|
+
transition: border-color var(--a-duration-fast) var(--a-easing);
|
|
277
|
+
}
|
|
278
|
+
combobox-ui [data-listbox] [role="option"][data-single-option] [data-radio]::after {
|
|
279
|
+
content: '';
|
|
280
|
+
width: 0.5rem;
|
|
281
|
+
height: 0.5rem;
|
|
282
|
+
border-radius: 50%;
|
|
283
|
+
background: var(--md-sys-color-primary);
|
|
284
|
+
transform: scale(0);
|
|
285
|
+
transition: transform var(--a-duration-fast) var(--a-easing);
|
|
286
|
+
}
|
|
287
|
+
combobox-ui [data-listbox] [role="option"][data-single-option][aria-selected="true"] [data-radio] {
|
|
288
|
+
border-color: var(--md-sys-color-primary);
|
|
289
|
+
}
|
|
290
|
+
combobox-ui [data-listbox] [role="option"][data-single-option][aria-selected="true"] [data-radio]::after {
|
|
291
|
+
transform: scale(1);
|
|
292
|
+
}
|
|
293
|
+
combobox-ui [data-listbox] [role="option"][data-single-option] [data-option-label] {
|
|
294
|
+
flex: 1;
|
|
295
|
+
min-width: 0;
|
|
296
|
+
}
|
|
249
297
|
|
|
250
298
|
combobox-ui [data-listbox] [role="option"][aria-disabled="true"] {
|
|
251
299
|
color: var(--a-ui-text-disabled);
|
|
@@ -247,7 +247,11 @@ tokens:
|
|
|
247
247
|
--combobox-option-fg-active:
|
|
248
248
|
description: Foreground for the currently active option
|
|
249
249
|
--combobox-option-bg-selected:
|
|
250
|
-
description:
|
|
250
|
+
description: >-
|
|
251
|
+
Background for the currently committed option. Defaults to
|
|
252
|
+
`transparent`: selection is shown by the leading radio indicator
|
|
253
|
+
rather than a row tint, matching select-ui. Set this to re-enable a
|
|
254
|
+
tinted selected row.
|
|
251
255
|
--combobox-match-bg:
|
|
252
256
|
description: Background for `<mark>` spans that highlight matched substrings
|
|
253
257
|
requiredIcons:
|
|
@@ -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": {
|
|
@@ -541,8 +541,12 @@ export class UISelect extends UIFormElement {
|
|
|
541
541
|
? new Set(this.value.split(',').map((s) => s.trim()).filter(Boolean))
|
|
542
542
|
: null;
|
|
543
543
|
for (const opt of this.#listbox.querySelectorAll('[role="option"]')) {
|
|
544
|
+
// Action rows have no data-value (they are commands — see the
|
|
545
|
+
// stamping note); null must never compare equal to a value, and
|
|
546
|
+
// `null === ''` is already false, but the explicit guard keeps a
|
|
547
|
+
// future `v ?? ''` normalization from resurrecting the leak.
|
|
544
548
|
const v = opt.getAttribute('data-value');
|
|
545
|
-
const selected = selSet ? selSet.has(v) : v === this.value;
|
|
549
|
+
const selected = v !== null && (selSet ? selSet.has(v) : v === this.value);
|
|
546
550
|
if (selected) opt.setAttribute('aria-selected', 'true');
|
|
547
551
|
else opt.removeAttribute('aria-selected');
|
|
548
552
|
}
|
|
@@ -766,19 +770,39 @@ export class UISelect extends UIFormElement {
|
|
|
766
770
|
}
|
|
767
771
|
const el = document.createElement('div');
|
|
768
772
|
el.setAttribute('role', 'option');
|
|
769
|
-
|
|
773
|
+
// Action rows carry NO [data-value]: they are commands, not values.
|
|
774
|
+
// Stamping `opt.value || ''` gave them data-value="" — and since
|
|
775
|
+
// `this.value` ALSO defaults to '', the aria-selected sync marked
|
|
776
|
+
// every action row selected whenever nothing was committed (the
|
|
777
|
+
// default state of a user menu — reviewer finding, 2026-07-29).
|
|
778
|
+
// With the attribute absent, getAttribute() returns null and no
|
|
779
|
+
// value comparison can ever match.
|
|
780
|
+
if (!opt.action) el.setAttribute('data-value', opt.value || '');
|
|
770
781
|
// §FB-46: [multiple] value is comma-separated — use Set membership.
|
|
771
782
|
const selSet = this.multiple
|
|
772
783
|
? new Set(this.value.split(',').map((s) => s.trim()).filter(Boolean))
|
|
773
784
|
: null;
|
|
774
|
-
const isSelected = selSet ? selSet.has(opt.value) : opt.value === this.value;
|
|
785
|
+
const isSelected = !opt.action && (selSet ? selSet.has(opt.value) : opt.value === this.value);
|
|
775
786
|
// SPEC-040 — multi-select option rows render a leading checkbox
|
|
776
787
|
// indicator (CSS-driven via [data-multi-option]); the `check` icon
|
|
777
788
|
// shows when aria-selected="true".
|
|
778
789
|
// Per-option leading glyph — mark (adia-mark-ui) wins over avatar
|
|
779
790
|
// (img), which wins over icon (icon-ui).
|
|
780
791
|
const lead = UISelect.#optionLeadHTML(opt);
|
|
781
|
-
|
|
792
|
+
// Action rows are COMMANDS in BOTH modes — this branch must precede
|
|
793
|
+
// the [multiple] one, or a {action} entry in a multi-select renders
|
|
794
|
+
// with a checkbox while #onOptionClick already treats it as a command
|
|
795
|
+
// (CodeRabbit, PR #467). They dispatch `action` and never become the
|
|
796
|
+
// value, so they carry no indicator at all: the 2026-07-27 radio
|
|
797
|
+
// ruling covers selection rows only (operator report 2026-07-28).
|
|
798
|
+
if (opt.action) {
|
|
799
|
+
el.setAttribute('data-action-option', '');
|
|
800
|
+
const label = document.createElement('span');
|
|
801
|
+
label.setAttribute('data-option-label', '');
|
|
802
|
+
if (lead) label.innerHTML = `${lead}${escapeHTML(opt.label)}`;
|
|
803
|
+
else label.textContent = opt.label;
|
|
804
|
+
el.appendChild(label);
|
|
805
|
+
} else if (this.multiple) {
|
|
782
806
|
el.setAttribute('data-multi-option', '');
|
|
783
807
|
const box = document.createElement('span');
|
|
784
808
|
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
|
|
29
|
-
- tag-ui
|
|
30
|
-
- button-ui
|
|
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
|
-
|
|
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
|
-
|
|
302
|
-
|
|
303
|
-
|
|
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:
|
|
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:
|
|
321
|
+
overflow-wrap: break-word;
|
|
320
322
|
}
|
|
321
323
|
|
|
322
324
|
[data-align="right"] {
|