@cfasim-ui/components 0.7.7 → 0.8.0

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 (89) hide show
  1. package/dist/Box/Box.d.ts +7 -11
  2. package/dist/Button/Button.d.ts +7 -11
  3. package/dist/ButtonGroup/ButtonGroup.d.ts +8 -12
  4. package/dist/Container/Container.d.ts +7 -11
  5. package/dist/Expander/Expander.d.ts +12 -14
  6. package/dist/Grid/Grid.d.ts +6 -5
  7. package/dist/Hint/Hint.d.ts +2 -1
  8. package/dist/Icon/Icon.d.ts +3 -2
  9. package/dist/LightDarkToggle/LightDarkToggle.d.ts +2 -1
  10. package/dist/MultiSelect/MultiSelect.d.ts +6 -6
  11. package/dist/NumberInput/NumberInput.d.ts +13 -11
  12. package/dist/ParamEditor/ParamEditor.d.ts +3 -2
  13. package/dist/ParamEditor/ParamEditorImpl.d.ts +3 -5
  14. package/dist/{ParamEditorImpl-D0xZTyAN.js → ParamEditorImpl-CkElC6PI.js} +3075 -3041
  15. package/dist/SelectBox/SelectBox.d.ts +8 -6
  16. package/dist/{SelectBox-CByXZfaC.js → SelectBox-Df8dE2r-.js} +6 -6
  17. package/dist/SidebarLayout/SidebarLayout.d.ts +21 -20
  18. package/dist/Spinner/Spinner.d.ts +3 -2
  19. package/dist/TextInput/TextInput.d.ts +7 -5
  20. package/dist/Toggle/Toggle.d.ts +8 -6
  21. package/dist/ToggleGroup/ToggleGroup.d.ts +8 -6
  22. package/dist/_internal/FieldLabel.d.ts +2 -1
  23. package/dist/index.js +20 -20
  24. package/docs/Box.md +49 -0
  25. package/docs/Button.md +67 -0
  26. package/docs/ButtonGroup.md +64 -0
  27. package/docs/Container.md +103 -0
  28. package/docs/Expander.md +34 -0
  29. package/docs/Grid.md +170 -0
  30. package/docs/Hint.md +29 -0
  31. package/docs/Icon.md +188 -0
  32. package/docs/MultiSelect.md +143 -0
  33. package/docs/NumberInput.md +485 -0
  34. package/docs/ParamEditor.md +97 -0
  35. package/docs/SelectBox.md +182 -0
  36. package/docs/SidebarLayout.md +106 -0
  37. package/docs/Spinner.md +51 -0
  38. package/docs/TextInput.md +83 -0
  39. package/docs/Toggle.md +81 -0
  40. package/docs/ToggleGroup.md +163 -0
  41. package/docs/index.json +194 -0
  42. package/package.json +24 -20
  43. package/src/Box/Box.md +41 -0
  44. package/src/Box/Box.vue +52 -0
  45. package/src/Button/Button.md +59 -0
  46. package/src/Button/Button.vue +81 -0
  47. package/src/ButtonGroup/ButtonGroup.md +62 -0
  48. package/src/ButtonGroup/ButtonGroup.vue +91 -0
  49. package/src/Container/Container.md +99 -0
  50. package/src/Container/Container.vue +62 -0
  51. package/src/Expander/Expander.md +23 -0
  52. package/src/Expander/Expander.vue +95 -0
  53. package/src/Grid/Grid.md +175 -0
  54. package/src/Grid/Grid.vue +145 -0
  55. package/src/Hint/Hint.md +24 -0
  56. package/src/Hint/Hint.vue +83 -0
  57. package/src/Icon/Icon.md +176 -0
  58. package/src/Icon/Icon.vue +104 -0
  59. package/src/Icon/defaultIcons.ts +92 -0
  60. package/src/Icon/github.svg +1 -0
  61. package/src/Icon/registry.ts +68 -0
  62. package/src/LightDarkToggle/LightDarkToggle.vue +49 -0
  63. package/src/MultiSelect/MultiSelect.md +142 -0
  64. package/src/MultiSelect/MultiSelect.vue +279 -0
  65. package/src/NumberInput/NumberInput.md +455 -0
  66. package/src/NumberInput/NumberInput.vue +575 -0
  67. package/src/ParamEditor/ParamEditor.md +87 -0
  68. package/src/ParamEditor/ParamEditor.vue +43 -0
  69. package/src/ParamEditor/ParamEditorImpl.vue +358 -0
  70. package/src/SelectBox/SelectBox.md +169 -0
  71. package/src/SelectBox/SelectBox.vue +260 -0
  72. package/src/SidebarLayout/SidebarLayout.md +106 -0
  73. package/src/SidebarLayout/SidebarLayout.vue +468 -0
  74. package/src/Spinner/Spinner.md +45 -0
  75. package/src/Spinner/Spinner.vue +55 -0
  76. package/src/TextInput/TextInput.md +68 -0
  77. package/src/TextInput/TextInput.vue +54 -0
  78. package/src/Toggle/Toggle.md +68 -0
  79. package/src/Toggle/Toggle.vue +81 -0
  80. package/src/ToggleGroup/ToggleGroup.md +158 -0
  81. package/src/ToggleGroup/ToggleGroup.vue +138 -0
  82. package/src/_internal/FieldLabel.vue +27 -0
  83. package/src/_internal/field.ts +27 -0
  84. package/src/_internal/gap.ts +17 -0
  85. package/src/_internal/input.css +54 -0
  86. package/src/_internal/listbox.css +53 -0
  87. package/src/env.d.ts +4 -0
  88. package/src/index.ts +33 -0
  89. package/src/svg.d.ts +5 -0
@@ -0,0 +1,34 @@
1
+ # Expander
2
+
3
+ A collapsible section that toggles content visibility.
4
+
5
+ ## Examples
6
+
7
+ <ComponentDemo>
8
+ <Expander label="Show advanced options">
9
+ <p style="margin: 0">Here is the hidden content.</p>
10
+ </Expander>
11
+
12
+ <template #code>
13
+
14
+ ```vue
15
+ <Expander label="Show advanced options">
16
+ <p>Here is the hidden content.</p>
17
+ </Expander>
18
+ ```
19
+
20
+ </template>
21
+ </ComponentDemo>
22
+
23
+ ## Model
24
+
25
+ | Name | Type |
26
+ |------|------|
27
+ | `v-model:open` | `boolean` |
28
+
29
+ ## Props
30
+
31
+ | Prop | Type | Required | Default |
32
+ |------|------|----------|---------|
33
+ | `label` | `string` | No | — |
34
+
package/docs/Grid.md ADDED
@@ -0,0 +1,170 @@
1
+ # Grid
2
+
3
+ A CSS-grid wrapper for arranging elements in equal, proportional, or auto-fitting columns.
4
+
5
+ For single-direction stacks (vertical or a flex row that wraps), use [Container](./container) instead.
6
+
7
+ ## Examples
8
+
9
+ ### Equal columns
10
+
11
+ Pass a number for N equal-width columns.
12
+
13
+ <ComponentDemo>
14
+ <Grid :cols="3" gap="medium">
15
+ <Box variant="info">Column 1</Box>
16
+ <Box variant="info">Column 2</Box>
17
+ <Box variant="info">Column 3</Box>
18
+ </Grid>
19
+
20
+ <template #code>
21
+
22
+ ```vue
23
+ <Grid :cols="3" gap="medium">
24
+ <Box variant="info">Column 1</Box>
25
+ <Box variant="info">Column 2</Box>
26
+ <Box variant="info">Column 3</Box>
27
+ </Grid>
28
+ ```
29
+
30
+ </template>
31
+ </ComponentDemo>
32
+
33
+ ### Proportional widths
34
+
35
+ Pass an array of `fr` weights for asymmetric layouts.
36
+
37
+ <ComponentDemo>
38
+ <Grid :cols="[2, 3, 1]" gap="medium">
39
+ <Box variant="info">2fr</Box>
40
+ <Box variant="success">3fr</Box>
41
+ <Box variant="warning">1fr</Box>
42
+ </Grid>
43
+
44
+ <template #code>
45
+
46
+ ```vue
47
+ <Grid :cols="[2, 3, 1]" gap="medium">
48
+ <Box variant="info">2fr</Box>
49
+ <Box variant="success">3fr</Box>
50
+ <Box variant="warning">1fr</Box>
51
+ </Grid>
52
+ ```
53
+
54
+ </template>
55
+ </ComponentDemo>
56
+
57
+ ### Mixed track sizes
58
+
59
+ Strings pass through unchanged, so you can combine fixed and flexible tracks.
60
+
61
+ <ComponentDemo>
62
+ <Grid :cols="['200px', '1fr']" gap="medium">
63
+ <Box variant="info">Fixed 200px</Box>
64
+ <Box variant="info">Fills remaining space</Box>
65
+ </Grid>
66
+
67
+ <template #code>
68
+
69
+ ```vue
70
+ <Grid :cols="['200px', '1fr']" gap="medium">
71
+ <Box variant="info">Fixed 200px</Box>
72
+ <Box variant="info">Fills remaining space</Box>
73
+ </Grid>
74
+ ```
75
+
76
+ </template>
77
+ </ComponentDemo>
78
+
79
+ ### Small-width breakpoint
80
+
81
+ `colsSmall` overrides `cols` when the grid's own width is at or below `breakpoint`. The default breakpoint is `640px` unless you specify it. The check is a CSS container query against the grid itself, so it triggers based on the grid's available width (e.g. when nested inside a sidebar), not the viewport.
82
+
83
+ <ComponentDemo>
84
+ <Grid :cols="3" :cols-small="1" breakpoint="480px" gap="small">
85
+ <Box variant="info">Card 1</Box>
86
+ <Box variant="info">Card 2</Box>
87
+ <Box variant="info">Card 3</Box>
88
+ </Grid>
89
+
90
+ <template #code>
91
+
92
+ ```vue
93
+ <Grid :cols="3" :cols-small="1" breakpoint="480px" gap="small">
94
+ <Box variant="info">Card 1</Box>
95
+ <Box variant="info">Card 2</Box>
96
+ <Box variant="info">Card 3</Box>
97
+ </Grid>
98
+ ```
99
+
100
+ </template>
101
+ </ComponentDemo>
102
+
103
+ ### Responsive auto-fit
104
+
105
+ `minColWidth` switches to `repeat(auto-fit, minmax(...))` so items reflow to fit the viewport without media queries. Great for metric tiles and card grids.
106
+
107
+ <ComponentDemo>
108
+ <Grid min-col-width="180px" gap="medium">
109
+ <Box variant="info">Card 1</Box>
110
+ <Box variant="info">Card 2</Box>
111
+ <Box variant="info">Card 3</Box>
112
+ <Box variant="info">Card 4</Box>
113
+ <Box variant="info">Card 5</Box>
114
+ </Grid>
115
+
116
+ <template #code>
117
+
118
+ ```vue
119
+ <Grid min-col-width="180px" gap="medium">
120
+ <Box variant="info">Card 1</Box>
121
+ <Box variant="info">Card 2</Box>
122
+ <Box variant="info">Card 3</Box>
123
+ <Box variant="info">Card 4</Box>
124
+ <Box variant="info">Card 5</Box>
125
+ </Grid>
126
+ ```
127
+
128
+ </template>
129
+ </ComponentDemo>
130
+
131
+ ### Nested grids
132
+
133
+ <ComponentDemo>
134
+ <Grid :cols="2" gap="medium">
135
+ <Box variant="info">Left</Box>
136
+ <Grid :cols="2" gap="small">
137
+ <Box variant="success">a</Box>
138
+ <Box variant="success">b</Box>
139
+ <Box variant="success">c</Box>
140
+ <Box variant="success">d</Box>
141
+ </Grid>
142
+ </Grid>
143
+
144
+ <template #code>
145
+
146
+ ```vue
147
+ <Grid :cols="2" gap="medium">
148
+ <Box variant="info">Left</Box>
149
+ <Grid :cols="2" gap="small">
150
+ <Box variant="success">a</Box>
151
+ <Box variant="success">b</Box>
152
+ <Box variant="success">c</Box>
153
+ <Box variant="success">d</Box>
154
+ </Grid>
155
+ </Grid>
156
+ ```
157
+
158
+ </template>
159
+ </ComponentDemo>
160
+
161
+ ## Props
162
+
163
+ | Prop | Type | Required | Default |
164
+ |------|------|----------|---------|
165
+ | `cols` | `GridCols` | No | — |
166
+ | `colsSmall` | `GridCols` | No | — |
167
+ | `breakpoint` | `string` | No | — |
168
+ | `gap` | `GridGap \| string` | No | — |
169
+ | `minColWidth` | `string` | No | — |
170
+
package/docs/Hint.md ADDED
@@ -0,0 +1,29 @@
1
+ # Hint
2
+
3
+ An info icon that shows a tooltip on hover. Used alongside form labels to provide additional context.
4
+
5
+ ## Examples
6
+
7
+ <ComponentDemo>
8
+ <span style="display: flex; align-items: center; gap: 8px;">
9
+ Population size <Hint text="The total number of individuals in the simulation." />
10
+ </span>
11
+
12
+ <template #code>
13
+
14
+ ```vue
15
+ <span style="display: flex; align-items: center; gap: 8px;">
16
+ Population size
17
+ <Hint text="The total number of individuals in the simulation." />
18
+ </span>
19
+ ```
20
+
21
+ </template>
22
+ </ComponentDemo>
23
+
24
+ ## Props
25
+
26
+ | Prop | Type | Required | Default |
27
+ |------|------|----------|---------|
28
+ | `text` | `string` | Yes | — |
29
+
package/docs/Icon.md ADDED
@@ -0,0 +1,188 @@
1
+ # Icon
2
+
3
+ Renders a [Material Symbols](https://fonts.google.com/icons) icon as an inline
4
+ SVG. Icons are resolved from a registry by name, so you reference them exactly as
5
+ before — `<Icon icon="help" />` — but no webfont is loaded: only the SVGs you
6
+ actually use end up in your bundle.
7
+
8
+ A [base set](#base-set) of common icons is pre-registered and works with zero
9
+ setup. These SVGs are bundled inside `cfasim-ui`, so they need no extra install
10
+ or config — just `<Icon icon="help" />`. To use any other icon,
11
+ [register it](#registering-icons).
12
+
13
+ ## Examples
14
+
15
+ ### Sizes
16
+
17
+ <ComponentDemo>
18
+ <Icon icon="help" size="sm" aria-label="help" />
19
+ <Icon icon="help" size="md" aria-label="help" />
20
+ <Icon icon="help" size="lg" aria-label="help" />
21
+
22
+ <template #code>
23
+
24
+ ```vue
25
+ <Icon icon="help" size="sm" aria-label="help" />
26
+ <Icon icon="help" size="md" aria-label="help" />
27
+ <Icon icon="help" size="lg" aria-label="help" />
28
+ ```
29
+
30
+ </template>
31
+ </ComponentDemo>
32
+
33
+ ### Filled
34
+
35
+ <ComponentDemo>
36
+ <Icon icon="favorite" size="lg" aria-label="favorite" />
37
+ <Icon icon="favorite" size="lg" :fill="true" aria-label="favorite filled" />
38
+
39
+ <template #code>
40
+
41
+ ```vue
42
+ <Icon icon="favorite" size="lg" aria-label="favorite" />
43
+ <Icon icon="favorite" size="lg" :fill="true" aria-label="favorite filled" />
44
+ ```
45
+
46
+ </template>
47
+ </ComponentDemo>
48
+
49
+ ### Inline in text
50
+
51
+ <ComponentDemo>
52
+ <p style="margin: 0">Click the <Icon icon="help" size="sm" :inline="true" aria-label="help" /> icon for more info.</p>
53
+
54
+ <template #code>
55
+
56
+ ```vue
57
+ <p>Click the <Icon icon="help" size="sm" :inline="true" aria-label="help" /> icon for more info.</p>
58
+ ```
59
+
60
+ </template>
61
+ </ComponentDemo>
62
+
63
+ ## Base set
64
+
65
+ These icons are bundled with `cfasim-ui` and need no install or registration —
66
+ just pass the name to `icon`. Anything not listed here must be
67
+ [registered](#registering-icons).
68
+
69
+ <script setup>
70
+ const baseIcons = [
71
+ "help", "favorite", "dark_mode", "light_mode",
72
+ "chevron_left", "chevron_right", "keyboard_arrow_up", "keyboard_arrow_down",
73
+ "keyboard_double_arrow_left", "keyboard_double_arrow_right",
74
+ "arrow_upward", "arrow_downward", "arrow_back", "arrow_forward",
75
+ "menu", "more_vert", "more_horiz",
76
+ "add", "edit", "delete", "close", "check", "search", "tune", "download",
77
+ "github",
78
+ ];
79
+ </script>
80
+
81
+ <Grid class="base-icons" :cols="4" :colsSmall="2" gap="sm">
82
+ <div v-for="name in baseIcons" :key="name" class="base-icons__cell">
83
+ <Icon :icon="name" size="lg" :aria-label="name" />
84
+ <code>{{ name }}</code>
85
+ </div>
86
+ </Grid>
87
+
88
+ <style>
89
+ .base-icons__cell {
90
+ display: flex;
91
+ flex-direction: column;
92
+ align-items: center;
93
+ gap: 0.5rem;
94
+ padding: 0.75rem 0.5rem;
95
+ border: 1px solid var(--vp-c-divider);
96
+ border-radius: 8px;
97
+ text-align: center;
98
+ }
99
+ .base-icons__cell code {
100
+ font-size: 0.65rem;
101
+ word-break: break-word;
102
+ }
103
+ </style>
104
+
105
+ `favorite` also has a filled variant via `:fill="true"`.
106
+
107
+ ## Registering icons
108
+
109
+ The base set above is bundled with `cfasim-ui` and needs none of the steps below
110
+ — this section is only for additional icons. `cfasim-ui` does not depend on
111
+ `@material-symbols/svg-400`, so you install the icons yourself; each one you
112
+ import is inlined into _your_ bundle (still no webfont).
113
+
114
+ ### 1. Install the icons and the Vite SVG loader
115
+
116
+ ```sh
117
+ pnpm add -D @material-symbols/svg-400 vite-svg-loader
118
+ ```
119
+
120
+ ### 2. Add `svgLoader` to your Vite config
121
+
122
+ Add it to your existing `plugins` array — leave the other plugins in place:
123
+
124
+ ```ts
125
+ // vite.config.ts
126
+ import svgLoader from "vite-svg-loader";
127
+
128
+ export default defineConfig({
129
+ plugins: [
130
+ // ...your existing plugins
131
+ svgLoader(),
132
+ ],
133
+ });
134
+ ```
135
+
136
+ ### 3. Register the icons once at startup
137
+
138
+ Import each SVG from the `outlined` style with the `?component` query, then pass
139
+ them to `registerIcons`. The key you register is the name you pass to `icon`.
140
+
141
+ ```ts
142
+ // main.ts
143
+ import rocket from "@material-symbols/svg-400/outlined/rocket.svg?component";
144
+ import settings from "@material-symbols/svg-400/outlined/settings.svg?component";
145
+ import { registerIcons } from "@cfasim-ui/components";
146
+
147
+ registerIcons({ rocket, settings });
148
+ ```
149
+
150
+ ### 4. Use them by name
151
+
152
+ ```vue
153
+ <Icon icon="rocket" />
154
+ <Icon icon="settings" size="lg" />
155
+ ```
156
+
157
+ An unregistered name renders nothing and logs a one-time console warning with the
158
+ exact code to register it.
159
+
160
+ ### Filled variants
161
+
162
+ To support `:fill="true"` on a registered icon, register both the outline and
163
+ `-fill` files:
164
+
165
+ ```ts
166
+ import favorite from "@material-symbols/svg-400/outlined/favorite.svg?component";
167
+ import favoriteFill from "@material-symbols/svg-400/outlined/favorite-fill.svg?component";
168
+
169
+ registerIcons({ favorite: { outline: favorite, fill: favoriteFill } });
170
+ ```
171
+
172
+ > The `weight` and `grade` props are deprecated no-ops — static SVGs ship at
173
+ > weight 400, grade 0. `size`, `fill`, `inline`, and color (`currentColor`) work
174
+ > as before.
175
+
176
+ ## Props
177
+
178
+ | Prop | Type | Required | Default |
179
+ |------|------|----------|---------|
180
+ | `icon` | `string` | Yes | — |
181
+ | `size` | `IconSize \| number` | No | `"md"` |
182
+ | `fill` | `boolean` | No | `false` |
183
+ | `weight` | `number` | No | — |
184
+ | `grade` | `number` | No | — |
185
+ | `decorative` | `boolean` | No | `true` |
186
+ | `ariaLabel` | `string` | No | — |
187
+ | `inline` | `boolean` | No | `false` |
188
+
@@ -0,0 +1,143 @@
1
+ # MultiSelect
2
+
3
+ A multi-select combobox with autocomplete. Built on reka-ui's Combobox: type to
4
+ filter the options, click to add them, and selected values appear as removable
5
+ chips. Binds to a `string[]` via `v-model`.
6
+
7
+ ## Examples
8
+
9
+ <script setup>
10
+ import { ref } from 'vue'
11
+ const states = ref(['ca'])
12
+ const stationery = ref([])
13
+ </script>
14
+
15
+ <ComponentDemo>
16
+ <div style="width: 280px">
17
+ <MultiSelect
18
+ v-model="states"
19
+ label="States"
20
+ placeholder="Search states…"
21
+ :options="[
22
+ { value: 'ca', label: 'California' },
23
+ { value: 'ny', label: 'New York' },
24
+ { value: 'tx', label: 'Texas' },
25
+ { value: 'wa', label: 'Washington' },
26
+ { value: 'fl', label: 'Florida' },
27
+ ]"
28
+ />
29
+ </div>
30
+
31
+ <template #code>
32
+
33
+ ```vue
34
+ <script setup>
35
+ import { ref } from "vue";
36
+ const states = ref(["ca"]);
37
+ </script>
38
+
39
+ <MultiSelect
40
+ v-model="states"
41
+ label="States"
42
+ placeholder="Search states…"
43
+ :options="[
44
+ { value: 'ca', label: 'California' },
45
+ { value: 'ny', label: 'New York' },
46
+ { value: 'tx', label: 'Texas' },
47
+ { value: 'wa', label: 'Washington' },
48
+ { value: 'fl', label: 'Florida' },
49
+ ]"
50
+ />
51
+ ```
52
+
53
+ </template>
54
+ </ComponentDemo>
55
+
56
+ Type in the field to filter, click an option to add it, and use a chip's `✕`
57
+ button (or press Backspace in an empty input) to remove a selection.
58
+
59
+ ### Hidden label
60
+
61
+ Use `hide-label` to visually hide the label while keeping it available to screen
62
+ readers. Prefer this over `aria-label` whenever you have label text.
63
+
64
+ <ComponentDemo>
65
+ <div style="width: 280px">
66
+ <MultiSelect
67
+ v-model="stationery"
68
+ label="Supplies"
69
+ hide-label
70
+ placeholder="Add supplies…"
71
+ :options="[
72
+ { value: 'pen', label: 'Pen' },
73
+ { value: 'pencil', label: 'Pencil' },
74
+ { value: 'marker', label: 'Marker' },
75
+ { value: 'eraser', label: 'Eraser' },
76
+ ]"
77
+ />
78
+ </div>
79
+
80
+ <template #code>
81
+
82
+ ```vue
83
+ <MultiSelect
84
+ v-model="supplies"
85
+ label="Supplies"
86
+ hide-label
87
+ placeholder="Add supplies…"
88
+ :options="[
89
+ { value: 'pen', label: 'Pen' },
90
+ { value: 'pencil', label: 'Pencil' },
91
+ { value: 'marker', label: 'Marker' },
92
+ { value: 'eraser', label: 'Eraser' },
93
+ ]"
94
+ />
95
+ ```
96
+
97
+ </template>
98
+ </ComponentDemo>
99
+
100
+ ## Accessibility
101
+
102
+ MultiSelect is built on reka-ui's Combobox, which implements the
103
+ [ARIA combobox pattern](https://www.w3.org/WAI/ARIA/apg/patterns/combobox/):
104
+
105
+ - The text field has `role="combobox"` with `aria-expanded`, `aria-controls`,
106
+ `aria-autocomplete="list"`, and `aria-activedescendant` tracking the
107
+ highlighted option as you arrow through the list.
108
+ - The popup is a `role="listbox"` with `aria-multiselectable="true"`; each option
109
+ is a `role="option"` and reflects its state via `aria-selected`.
110
+ - Keyboard support is handled for you: type to filter, ↑/↓ to move, Enter to
111
+ toggle the highlighted option, Escape to close, and Backspace in an empty input
112
+ removes the last chip.
113
+ - Pass `label` so the field is named by a real `<label>` (associated via
114
+ `aria-labelledby`); use `hide-label` to keep it for screen readers while hiding
115
+ it visually, or `aria-label` when there's no visible label text.
116
+ - Each chip's remove button has an `aria-label` (e.g. "Remove California").
117
+
118
+ ## Model
119
+
120
+ | Name | Type |
121
+ |------|------|
122
+ | `v-model` | `string[]` |
123
+
124
+ ## Props
125
+
126
+ | Prop | Type | Required | Default |
127
+ |------|------|----------|---------|
128
+ | `label` | `string` | No | — |
129
+ | `hideLabel` | `boolean` | No | — |
130
+ | `ariaLabel` | `string` | No | — |
131
+ | `hint` | `string` | No | — |
132
+ | `options` | `MultiSelectOption[]` | Yes | — |
133
+ | `placeholder` | `string` | No | — |
134
+
135
+
136
+ ### MultiSelectOption
137
+
138
+ ```ts
139
+ interface MultiSelectOption {
140
+ value: string;
141
+ label: string;
142
+ }
143
+ ```