You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
refactor: replace GroupOptionList with OptionList in GroupSelect and related components
- Updated GroupSelect.vue to use OptionList for rendering options, improving consistency across components.
- Modified MultiSelect, MultiCombobox, and SingleSelect to utilize rows instead of labels for options.
- Enhanced OptionList to handle both flat and grouped options, collapsing group headers appropriately.
- Adjusted tests for GroupSelect and GroupCombobox to reflect changes in option rendering and interaction.
- Removed GroupOptionList component and updated related test utilities for clarity and maintainability.
Copy file name to clipboardExpand all lines: docs/packages/ui-inputs.md
+85-4Lines changed: 85 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -110,6 +110,52 @@ Models an **array of option ids**. Committing an option toggles its membership a
110
110
</FormField>
111
111
```
112
112
113
+
### GroupSelect & GroupCombobox
114
+
115
+
When options arrive **already partitioned** — active sprints above the backlog, tropical fruit above stone fruit — `GroupSelect` and `GroupCombobox` are `SingleSelect` / `Combobox` over **`groups`** instead of `options`. Each group renders a `role="group"` header; a single `v-model` selects across the whole set, and groups stay in **caller order** (there is no `alphabeticalSort` — the partition _is_ the order). `GroupCombobox` filters within groups and drops any group its filter empties. Try typing `a` in the searchable one:
The `groups` prop replaces `options` — each group carries its own `options`, a header `text`, and an optional `header` flag:
137
+
138
+
```ts
139
+
const fruitGroups = [
140
+
{
141
+
text: 'Tropical',
142
+
options: [
143
+
{id: 'mango', name: 'Mango'},
144
+
{id: 'kiwi', name: 'Kiwi'},
145
+
],
146
+
},
147
+
{
148
+
text: 'Stone',
149
+
options: [
150
+
{id: 'apricot', name: 'Apricot'},
151
+
{id: 'peach', name: 'Peach'},
152
+
],
153
+
},
154
+
];
155
+
```
156
+
157
+
Pass `header: false` on a group to render its options **flat** (a leading "ungrouped" run above the named groups); an empty group renders nothing, so a header never outlives its options.
158
+
113
159
### The checkbox family
114
160
115
161
`Checkbox`, `Switch`, `CheckboxGroup`, and `RadioGroup` sit on a **native input chassis** — a real `<input type="checkbox">` / `<input type="radio">` restyled through the same `--ui-*` contract, never a div-with-role — so keyboard and assistive-tech behaviour come from the platform. The radio group's arrow-key selection below is the **browser's own** roving focus; the component hand-rolls none of it.
@@ -199,6 +245,8 @@ Models an **array of option ids**. Committing an option toggles its membership a
199
245
|`Combobox`| Accessible searchable/filtering single-select; exposes an imperative `focus()` handle |
200
246
|`MultiSelect`| Accessible multi-value select — models an array of option ids; toggle-in-place listbox, inline chip bar with per-chip remove |
201
247
|`MultiCombobox`| Accessible **searchable** multi-value select — MultiSelect's model + chips with Combobox's filtering input as the trigger |
248
+
|`GroupSelect`| Accessible **grouped** single-select — `SingleSelect` over caller-ordered `groups` with `role="group"` headers; models `T['id'] \| null`|
|`Pressable`| A real `<button>` for a control that carries **no value** — replaces `<span @click>` / `<div @click>`; optional `aria-pressed` toggle mode |
203
251
|`Disclosure`| Show/hide a region from a real button (`aria-expanded` + `aria-controls`), optionally wrapped in a real heading — replaces `<h2 @click>`|
204
252
@@ -304,6 +352,22 @@ danger-toned by default (`--ui-clear-text`, chaining to `--ui-danger-text`).
- Groups render in caller order; a single `T['id'] | null` model selects across the flattened option set.
368
+
- A named group renders `text` as a `role="group"` header labelling its options; `header: false` renders the group's options flat (with a boundary so they never fold into the preceding group) — a leading ungrouped run.
369
+
- An empty group renders nothing — a header never outlives its options, including when `GroupCombobox`'s filter drains a group.
370
+
307
371
### The checkbox family
308
372
309
373
`Checkbox` and `Switch` share `id` (required), `label` (inline label text; the default slot overrides it for rich content), `disabled`, `required`, `invalid`, and `describedby`. Both model a **non-nullable `boolean`**. `Checkbox` adds `indeterminate` (visual prop → the element's DOM property). Native `required` is never set — `aria-required` is the conveyance, as everywhere in the family.
@@ -609,7 +673,7 @@ No file or range atoms; no date _picker_ (`DateInput` wraps the native control);
|`Combobox`| Accessible **searchable/filtering** single-select — a text input that filters the listbox as you type; exposes an imperative `focus()` handle |
36
36
|`MultiSelect`| Accessible **multi-value** select — models an array of option ids; toggle-in-place listbox that stays open on commit, inline chip bar with per-chip remove |
37
37
|`MultiCombobox`| Accessible **searchable multi-value** select — MultiSelect's array model + chips with Combobox's filter-as-you-type input as the trigger |
38
+
|`GroupSelect`| Accessible **grouped** single-select — `SingleSelect` over caller-ordered `groups` with `role="group"` headers; models `T['id'] \| null`|
|`Pressable`| A real `<button>` for an interactive control that carries **no value** — the keyboard-correct replacement for `<span @click>` / `<div @click>`; optional `aria-pressed` toggle mode |
39
41
|`Disclosure`| Show/hide a region from a real `<button>` carrying `aria-expanded` + `aria-controls`; optionally wrapped in a real heading — the replacement for `<h2 @click>`|
40
42
@@ -190,6 +192,48 @@ Like `Combobox` it exposes an imperative `focus()` handle. `clearLabel` / `empty
190
192
deliberately do not transfer — an empty array is the multi "nothing", so there is no `null`
0 commit comments