@adia-ai/web-components 0.8.18 → 0.8.20
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 +26 -0
- package/components/nav-group/nav-group.a2ui.json +5 -0
- package/components/nav-group/nav-group.class.js +14 -6
- package/components/nav-group/nav-group.css +5 -2
- package/components/nav-group/nav-group.d.ts +2 -0
- package/components/nav-group/nav-group.yaml +4 -0
- package/components/select/select.a2ui.json +6 -1
- package/components/select/select.class.js +34 -7
- package/components/select/select.d.ts +2 -0
- package/components/select/select.yaml +16 -1
- package/dist/host.min.css +1 -1
- package/dist/host.sheet.js +1 -1
- package/dist/theme-provider.min.js +1 -1
- package/dist/web-components.min.css +1 -1
- package/dist/web-components.min.js +18 -18
- package/dist/web-components.sheet.js +1 -1
- package/package.json +2 -1
- package/styles/colors/semantics/core.css +10 -4
- package/components/adia-mark/adia-mark.test.js +0 -69
- package/components/adia-wordmark/adia-wordmark.test.js +0 -69
- package/components/agent-artifact/agent-artifact.test.js +0 -61
- package/components/alert/alert.test.js +0 -364
- package/components/color-picker/color-picker.test.js +0 -96
- package/components/combobox/combobox.test.js +0 -256
- package/components/command/command.test.js +0 -99
- package/components/date-range-picker/date-range-picker.test.js +0 -387
- package/components/datetime-picker/datetime-picker.test.js +0 -454
- package/components/demo-toggle/demo-toggle.test.js +0 -102
- package/components/description-list/description-list.test.js +0 -72
- package/components/display-field/display-field.test.js +0 -115
- package/components/empty-state/empty-state.test.js +0 -77
- package/components/field/field.test.js +0 -260
- package/components/fields/fields.test.js +0 -88
- package/components/inline-message/inline-message.test.js +0 -203
- package/components/input/input.test.js +0 -335
- package/components/integration-card/integration-card.test.js +0 -318
- package/components/link/link.test.js +0 -143
- package/components/list/list.test.js +0 -106
- package/components/list-window/list-window.test.js +0 -303
- package/components/loading-overlay/loading-overlay.test.js +0 -257
- package/components/menu/menu.test.js +0 -176
- package/components/nav/nav.test.js +0 -428
- package/components/nav-group/nav-group.test.js +0 -67
- package/components/option-card/option-card.test.js +0 -32
- package/components/pagination/pagination.test.js +0 -195
- package/components/select/select.test.js +0 -453
- package/components/slider/slider.test.js +0 -202
- package/components/spinner/spinner.test.js +0 -272
- package/components/stat/stat.test.js +0 -108
- package/components/step-progress/step-progress.test.js +0 -129
- package/components/swatch/swatch.test.js +0 -563
- package/components/table/table.test.js +0 -479
- package/components/table-toolbar/table-toolbar.test.js +0 -152
- package/components/tag/tag.test.js +0 -137
- package/components/tags-input/tags-input.test.js +0 -477
- package/components/text/text.test.js +0 -202
- package/components/theme-provider/theme-provider.test.js +0 -94
- package/components/time-picker/time-picker.test.js +0 -287
- package/components/timeline/timeline.test.js +0 -31
- package/components/toggle-scheme/toggle-scheme.test.js +0 -110
- package/components/tree/tree.test.js +0 -312
- package/core/element.test.js +0 -389
- package/core/icons.test.js +0 -187
- package/core/logical-children.test.js +0 -54
- package/core/markdown.test.js +0 -47
- package/core/responsive.test.js +0 -121
- package/core/template.test.js +0 -611
- package/traits/active-state/active-state.test.js +0 -28
- package/traits/anchor-positioning/anchor-positioning.test.js +0 -122
- package/traits/announcer/announcer.test.js +0 -268
- package/traits/arrow-grid-nav/arrow-grid-nav.test.js +0 -375
- package/traits/attention-pulse/attention-pulse.test.js +0 -26
- package/traits/confetti/confetti.test.js +0 -46
- package/traits/confetti-burst/confetti-burst.test.js +0 -46
- package/traits/count-up/count-up.test.js +0 -54
- package/traits/declarative.test.js +0 -138
- package/traits/dirty-state/dirty-state.test.js +0 -45
- package/traits/drag-ghost/drag-ghost.test.js +0 -19
- package/traits/draggable/draggable.test.js +0 -60
- package/traits/draggable-list-item/draggable-list-item.test.js +0 -51
- package/traits/drop-target/drop-target.test.js +0 -241
- package/traits/droppable/droppable.test.js +0 -54
- package/traits/droppable-collection/droppable-collection.test.js +0 -99
- package/traits/error-shake/error-shake.test.js +0 -114
- package/traits/fade-presence/fade-presence.test.js +0 -20
- package/traits/focus-restore/focus-restore.test.js +0 -202
- package/traits/focus-trap/focus-trap.test.js +0 -42
- package/traits/focusable/focusable.test.js +0 -53
- package/traits/glow-focus/glow-focus.test.js +0 -31
- package/traits/gradient-shift/gradient-shift.test.js +0 -22
- package/traits/haptic-feedback/haptic-feedback.test.js +0 -52
- package/traits/hotkey/hotkey.test.js +0 -61
- package/traits/hoverable/hoverable.test.js +0 -24
- package/traits/inertia-drag/inertia-drag.test.js +0 -33
- package/traits/input-mask/input-mask.test.js +0 -151
- package/traits/intersection-observer/intersection-observer.test.js +0 -38
- package/traits/keyboard-nav/keyboard-nav.test.js +0 -41
- package/traits/keyboard-reorderable/keyboard-reorderable.test.js +0 -45
- package/traits/layout-animation/layout-animation.test.js +0 -114
- package/traits/long-press/long-press.test.js +0 -244
- package/traits/magnetic-hover/magnetic-hover.test.js +0 -30
- package/traits/noise-texture/noise-texture.test.js +0 -20
- package/traits/parallax/parallax.test.js +0 -26
- package/traits/portal/portal.test.js +0 -30
- package/traits/pressable/pressable.test.js +0 -73
- package/traits/resettable/resettable.test.js +0 -100
- package/traits/resizable/resizable.test.js +0 -39
- package/traits/resize-observer/resize-observer.test.js +0 -38
- package/traits/ripple/ripple.test.js +0 -32
- package/traits/roving-tabindex/roving-tabindex.test.js +0 -28
- package/traits/scale-press/scale-press.test.js +0 -39
- package/traits/scroll-lock/scroll-lock.test.js +0 -45
- package/traits/scroll-progress/scroll-progress.test.js +0 -182
- package/traits/shimmer-loading/shimmer-loading.test.js +0 -43
- package/traits/smoke.test.js +0 -111
- package/traits/snap-to-grid/snap-to-grid.test.js +0 -40
- package/traits/sound-feedback/sound-feedback.test.js +0 -26
- package/traits/spring-animate/spring-animate.test.js +0 -28
- package/traits/success-checkmark/success-checkmark.test.js +0 -120
- package/traits/tilt-hover/tilt-hover.test.js +0 -32
- package/traits/tossable/tossable.test.js +0 -31
- package/traits/traits-host.test.js +0 -73
- package/traits/typeahead/typeahead.test.js +0 -38
- package/traits/typewriter/typewriter.test.js +0 -47
- package/traits/validation/validation.test.js +0 -93
- 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.20] — 2026-07-28
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
- **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.
|
|
7
|
+
|
|
8
|
+
### Changed
|
|
9
|
+
- **`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.
|
|
10
|
+
- **`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.
|
|
11
|
+
|
|
12
|
+
### Maintenance
|
|
13
|
+
- **`components/` touched in this release window** (6 file(s), e.g. `nav-group/nav-group.a2ui.json`) — carried by the entries above.
|
|
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.19] — 2026-07-27
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
- **`select-ui[summary-label]` — multi-select trigger as one text line, not chips** (gh#442, ruled from the adiav2 admin dashboard filter bar). With the attribute set, a single selection shows its own label and N > 1 shows "Label (N)" ("Organizations (2)"); none shows the placeholder. The popover's checkbox rows, Backspace-removes-last, the comma-separated form value, `[select-all]`, and `[clearable]` semantics are unchanged, and chip mode stays the default when the attribute is absent (`[data-multi-chips]` is simply not set in summary mode, so the trigger keeps the plain single-line layout). Motivation: in a narrow filter-bar trigger, three selected organizations wrapped into a vertically ballooning chip stack; `max-chips` still renders chips and could not express the ruling. Entry re-homed from the root CHANGELOG (package-local change; PR #445 filed it there mid-flight while #452's re-home was landing).
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
- **Row hover no longer goes near-black — `--a-bg-hover`/`--a-bg-active` (and the `--a-canvas-*` twins) move off the fill ladder onto the container alpha ladder** (`styles/colors/semantics/core.css`; operator directive 2026-07-27). The roles pointed at `neutral-hover`/`neutral-active` — the FILLED-BUTTON stops, opaque 650/700 — so all ten row/option/cell consumers (list, tree, select, command, calendar-grid, calendar-picker, date-range-picker, tag, agent-artifact) tinted toward black on hover, while the adjacent `--a-bg-selected` note already prescribed "hover = container-low". Now: hover = `container-low` (10%), active = `container` (20%, the selected/tonal tier). The fill ladder itself is untouched — filled buttons keep 600/650/700.
|
|
23
|
+
- **The unit suite can no longer touch real network** (`test-setup.js`) — happy-dom's `fetch` does real I/O against its default `http://localhost:3000` base URL, so test outcomes depended on which dev servers happened to be running (the v0.8.17 cut lost a gate run to an ECONNREFUSED flake in `onboarding-checklist.test.js`). A fast-rejecting guard now replaces `globalThis.fetch`; tests exercising fetch paths keep installing their own per-file mocks, which override it.
|
|
24
|
+
|
|
25
|
+
### Maintenance
|
|
26
|
+
- **`components/` touched in this release window** (6 file(s), e.g. `select/select.a2ui.json`) — carried by the entries above.
|
|
27
|
+
- **`dist/` bundles rebuilt** in this cut's window (6 file(s)) — regenerated from the source changes described above, not independent edits.
|
|
28
|
+
|
|
3
29
|
## [0.8.18] — 2026-07-27
|
|
4
30
|
|
|
5
31
|
### Maintenance
|
|
@@ -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:
|
|
91
|
-
//
|
|
92
|
-
//
|
|
93
|
-
//
|
|
94
|
-
//
|
|
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)
|
|
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
|
-
|
|
53
|
-
|
|
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
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id": "https://adiaui.dev/a2ui/v0_9/components/Select.json",
|
|
4
4
|
"title": "Select",
|
|
5
|
-
"description": "Single- and multi-select dropdown primitive — the canonical AdiaUI\nselect control. Form-bearing via UIFormElement: [name], [value],\n[required], [disabled], fires `change`. Options via native\n<option> / <optgroup> children, programmatic `.options` array, or\nJSON [data-options] (hydrated by <editor-shell>'s wireSelects).\nUse for single-select with > 4 options; for ≤ 4 options use\n<segmented-ui> or <radio-ui>. Multi-select via [multiple]: trigger\nrenders <tag-ui> chips per selection, popover shows checkbox-style\noption list, Backspace removes the last chip, [select-all] adds\nbulk controls, [max-chips] caps the visible chip count with a\n\"+N more\" pill
|
|
5
|
+
"description": "Single- and multi-select dropdown primitive — the canonical AdiaUI\nselect control. Form-bearing via UIFormElement: [name], [value],\n[required], [disabled], fires `change`. Options via native\n<option> / <optgroup> children, programmatic `.options` array, or\nJSON [data-options] (hydrated by <editor-shell>'s wireSelects).\nUse for single-select with > 4 options; for ≤ 4 options use\n<segmented-ui> or <radio-ui>. Multi-select via [multiple]: trigger\nrenders <tag-ui> chips per selection, popover shows checkbox-style\noption list, Backspace removes the last chip, [select-all] adds\nbulk controls, [max-chips] caps the visible chip count with a\n\"+N more\" pill, and [summary-label] swaps the chip trigger for one\ntext line — the single selection's label, or \"Label (N)\" for more.\nForm value stays a comma-separated string under\n[name] for native <form> compatibility (parse with .split(',')).\n",
|
|
6
6
|
"type": "object",
|
|
7
7
|
"allOf": [
|
|
8
8
|
{
|
|
@@ -150,6 +150,11 @@
|
|
|
150
150
|
],
|
|
151
151
|
"default": "md"
|
|
152
152
|
},
|
|
153
|
+
"summary-label": {
|
|
154
|
+
"description": "Multi-select only (gh#442). Replaces the chip trigger with one\ntext line: a single selection shows its own label; N > 1 shows\n\"<summary-label> (N)\" — e.g. \"Organizations (2)\"; none shows the\nplaceholder. Popover checkbox rows, Backspace-removes-last, the\ncomma-separated form value, [select-all], and [clearable] are\nunchanged. Absent (default) = tag-ui chip trigger. Prefer this\nform for narrow triggers (filter bars) where wrapping chips\nwould balloon the control.\n",
|
|
155
|
+
"type": "string",
|
|
156
|
+
"default": null
|
|
157
|
+
},
|
|
153
158
|
"value": {
|
|
154
159
|
"description": "Currently selected option value. With declarative <option> children, a child carrying the native `selected` attribute sets the initial value when this attribute is absent (native <select> parity).",
|
|
155
160
|
"type": "string",
|
|
@@ -60,6 +60,10 @@ export class UISelect extends UIFormElement {
|
|
|
60
60
|
// These are no-ops without [multiple] but reflect so [maxChips]
|
|
61
61
|
// selectors etc. work in CSS even when authored declaratively.
|
|
62
62
|
maxChips: { type: Number, default: 0, reflect: true, attribute: 'max-chips' },
|
|
63
|
+
// gh#442: summary trigger for [multiple] — when set, the trigger shows
|
|
64
|
+
// one text line (a single selection's own label, or "Label (N)" for
|
|
65
|
+
// N > 1) instead of tag-ui chips. Absent = chip mode, unchanged.
|
|
66
|
+
summaryLabel: { type: String, default: '', reflect: true, attribute: 'summary-label' },
|
|
63
67
|
min: { type: Number, default: 0, reflect: true },
|
|
64
68
|
max: { type: Number, default: 0, reflect: true },
|
|
65
69
|
selectAll: { type: Boolean, default: false, reflect: true, attribute: 'select-all' },
|
|
@@ -404,7 +408,9 @@ export class UISelect extends UIFormElement {
|
|
|
404
408
|
// optional clear-x + optional "+N more" pill alongside the usual
|
|
405
409
|
// leading / display / caret. We toggle host attribute [data-multi-chips]
|
|
406
410
|
// so CSS can switch layout from single-line text to flex-wrap chip row.
|
|
407
|
-
|
|
411
|
+
// gh#442 — [summary-label] keeps the single-line text layout: the
|
|
412
|
+
// summary renders through [slot="display"], no chip row.
|
|
413
|
+
if (this.multiple && !this.summaryLabel) this.setAttribute('data-multi-chips', '');
|
|
408
414
|
else this.removeAttribute('data-multi-chips');
|
|
409
415
|
|
|
410
416
|
// A11y (FB-88): name a placeholder-only select from its placeholder, like
|
|
@@ -859,17 +865,18 @@ export class UISelect extends UIFormElement {
|
|
|
859
865
|
#stampChips() {
|
|
860
866
|
const slot = this.querySelector('[slot="trigger"] [data-chips]');
|
|
861
867
|
if (!slot) return;
|
|
868
|
+
// gh#442 — summary mode renders no chips; clear any stamped ones so a
|
|
869
|
+
// dynamic switch out of chip mode leaves no stale tag-ui behind.
|
|
870
|
+
if (this.summaryLabel) {
|
|
871
|
+
while (slot.firstChild) slot.removeChild(slot.firstChild);
|
|
872
|
+
return;
|
|
873
|
+
}
|
|
862
874
|
const values = this.#values();
|
|
863
875
|
const cap = Number(this.maxChips) || 0;
|
|
864
876
|
const cappedValues = cap > 0 && values.length > cap ? values.slice(0, cap) : values;
|
|
865
877
|
const overflow = cap > 0 && values.length > cap ? values.length - cap : 0;
|
|
866
878
|
// Label lookup from internal options model (handles grouped form too).
|
|
867
|
-
const
|
|
868
|
-
.filter((o) => !o.separator && !o.header && o.value != null);
|
|
869
|
-
const labelOf = (v) => {
|
|
870
|
-
const found = flat.find((o) => String(o.value) === String(v));
|
|
871
|
-
return found ? found.label : String(v);
|
|
872
|
-
};
|
|
879
|
+
const labelOf = (v) => this.#labelOf(v);
|
|
873
880
|
// Rebuild — chips are cheap and reconciliation gets us correct order
|
|
874
881
|
// + correct labels with no per-chip tracking state.
|
|
875
882
|
while (slot.firstChild) slot.removeChild(slot.firstChild);
|
|
@@ -893,8 +900,28 @@ export class UISelect extends UIFormElement {
|
|
|
893
900
|
}
|
|
894
901
|
}
|
|
895
902
|
|
|
903
|
+
/**
|
|
904
|
+
* Label for one value from the internal options model (grouped form
|
|
905
|
+
* included); falls back to the raw value string. Shared by the chip
|
|
906
|
+
* stamper and the gh#442 summary trigger.
|
|
907
|
+
*/
|
|
908
|
+
#labelOf(v) {
|
|
909
|
+
const flat = this.#options.flatMap((o) => o.options || [o])
|
|
910
|
+
.filter((o) => !o.separator && !o.header && o.value != null);
|
|
911
|
+
const found = flat.find((o) => String(o.value) === String(v));
|
|
912
|
+
return found ? found.label : String(v);
|
|
913
|
+
}
|
|
914
|
+
|
|
896
915
|
#displayText() {
|
|
897
916
|
if (this.multiple) {
|
|
917
|
+
// gh#442 — [summary-label]: one selection shows its own label, more
|
|
918
|
+
// show "Label (N)", none shows the placeholder.
|
|
919
|
+
if (this.summaryLabel) {
|
|
920
|
+
const values = this.#values();
|
|
921
|
+
if (values.length === 0) return this.placeholder;
|
|
922
|
+
if (values.length === 1) return this.#labelOf(values[0]);
|
|
923
|
+
return `${this.summaryLabel} (${values.length})`;
|
|
924
|
+
}
|
|
898
925
|
// SPEC-040 — chips render the selection; display element holds the
|
|
899
926
|
// placeholder when empty and is otherwise empty (CSS sees [data-multi-chips]).
|
|
900
927
|
return this.value ? '' : this.placeholder;
|
|
@@ -58,6 +58,8 @@ export class UISelect extends UIFormElement {
|
|
|
58
58
|
divider: boolean;
|
|
59
59
|
/** SPEC-040 — cap visible chips in multi-select trigger. 0 = unlimited. */
|
|
60
60
|
maxChips: number;
|
|
61
|
+
/** gh#442 — multi-select summary trigger: one selection shows its label, N > 1 shows "Label (N)"; empty string = chip mode. */
|
|
62
|
+
summaryLabel: string;
|
|
61
63
|
/** SPEC-040 — minimum required selections in multi-select mode. */
|
|
62
64
|
min: number;
|
|
63
65
|
/** SPEC-040 — maximum allowed selections in multi-select mode. 0 = unlimited. */
|
|
@@ -18,7 +18,9 @@ description: |
|
|
|
18
18
|
renders <tag-ui> chips per selection, popover shows checkbox-style
|
|
19
19
|
option list, Backspace removes the last chip, [select-all] adds
|
|
20
20
|
bulk controls, [max-chips] caps the visible chip count with a
|
|
21
|
-
"+N more" pill
|
|
21
|
+
"+N more" pill, and [summary-label] swaps the chip trigger for one
|
|
22
|
+
text line — the single selection's label, or "Label (N)" for more.
|
|
23
|
+
Form value stays a comma-separated string under
|
|
22
24
|
[name] for native <form> compatibility (parse with .split(',')).
|
|
23
25
|
# Per ADR-0027 — primitives that programmatically create other primitives
|
|
24
26
|
# do NOT auto-import them. Consumer (or demo shell) must explicitly import.
|
|
@@ -120,6 +122,19 @@ props:
|
|
|
120
122
|
type: number
|
|
121
123
|
default: 0
|
|
122
124
|
reflect: true
|
|
125
|
+
summary-label:
|
|
126
|
+
description: |
|
|
127
|
+
Multi-select only (gh#442). Replaces the chip trigger with one
|
|
128
|
+
text line: a single selection shows its own label; N > 1 shows
|
|
129
|
+
"<summary-label> (N)" — e.g. "Organizations (2)"; none shows the
|
|
130
|
+
placeholder. Popover checkbox rows, Backspace-removes-last, the
|
|
131
|
+
comma-separated form value, [select-all], and [clearable] are
|
|
132
|
+
unchanged. Absent (default) = tag-ui chip trigger. Prefer this
|
|
133
|
+
form for narrow triggers (filter bars) where wrapping chips
|
|
134
|
+
would balloon the control.
|
|
135
|
+
type: string
|
|
136
|
+
default: null
|
|
137
|
+
reflect: true
|
|
123
138
|
min:
|
|
124
139
|
description: |
|
|
125
140
|
Multi-select only. Minimum required selections. Below this floor
|