@cfasim-ui/docs 0.5.1 → 0.6.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.
- package/charts/BarChart/BarChart.md +3 -0
- package/charts/BarChart/BarChart.vue +342 -317
- package/charts/ChartMenu/ChartMenu.vue +75 -5
- package/charts/ChoroplethMap/ChoroplethMap.md +5 -0
- package/charts/ChoroplethMap/ChoroplethMap.vue +193 -88
- package/charts/LineChart/LineChart.md +21 -4
- package/charts/LineChart/LineChart.vue +398 -367
- package/charts/_shared/chartProps.ts +10 -0
- package/charts/_shared/useChartFoundation.ts +15 -0
- package/charts/_shared/useChartFullscreen.ts +66 -9
- package/charts/_shared/useChartMenu.ts +13 -6
- package/charts/_shared/useChartTooltip.ts +57 -4
- package/charts/index.ts +0 -2
- package/components/ButtonGroup/ButtonGroup.md +64 -0
- package/components/ButtonGroup/ButtonGroup.vue +91 -0
- package/components/MultiSelect/MultiSelect.md +143 -0
- package/components/MultiSelect/MultiSelect.vue +338 -0
- package/components/ParamEditor/ParamEditor.md +19 -0
- package/components/ParamEditor/ParamEditor.vue +4 -0
- package/components/ParamEditor/ParamEditorImpl.vue +3 -3
- package/components/ToggleGroup/ToggleGroup.md +163 -0
- package/components/ToggleGroup/ToggleGroup.vue +143 -0
- package/components/index.ts +5 -0
- package/index.json +47 -1
- package/package.json +1 -1
- package/charts/_shared/fullscreen.css +0 -51
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import {
|
|
3
|
+
ComboboxAnchor,
|
|
4
|
+
ComboboxContent,
|
|
5
|
+
ComboboxEmpty,
|
|
6
|
+
ComboboxInput,
|
|
7
|
+
ComboboxItem,
|
|
8
|
+
ComboboxItemIndicator,
|
|
9
|
+
ComboboxPortal,
|
|
10
|
+
ComboboxRoot,
|
|
11
|
+
ComboboxTrigger,
|
|
12
|
+
ComboboxViewport,
|
|
13
|
+
useId,
|
|
14
|
+
} from "reka-ui";
|
|
15
|
+
import { computed, nextTick, ref, watch } from "vue";
|
|
16
|
+
import Icon from "../Icon/Icon.vue";
|
|
17
|
+
import Hint from "../Hint/Hint.vue";
|
|
18
|
+
|
|
19
|
+
export interface MultiSelectOption {
|
|
20
|
+
value: string;
|
|
21
|
+
label: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const model = defineModel<string[]>({ default: () => [] });
|
|
25
|
+
|
|
26
|
+
const props = defineProps<{
|
|
27
|
+
label?: string;
|
|
28
|
+
hideLabel?: boolean;
|
|
29
|
+
ariaLabel?: string;
|
|
30
|
+
options: MultiSelectOption[];
|
|
31
|
+
placeholder?: string;
|
|
32
|
+
hint?: string;
|
|
33
|
+
}>();
|
|
34
|
+
|
|
35
|
+
const id = useId();
|
|
36
|
+
const fieldRef = ref<HTMLElement | null>(null);
|
|
37
|
+
|
|
38
|
+
// In multiple mode the list stays open after a selection, so reka keeps
|
|
39
|
+
// `isUserInputted` true and suppresses its own `resetSearchTermOnSelect`. Clear
|
|
40
|
+
// the typed text (and the underlying filter) ourselves on every selection
|
|
41
|
+
// change by dispatching a native input event the combobox listens for.
|
|
42
|
+
watch(model, () => {
|
|
43
|
+
nextTick(() => {
|
|
44
|
+
const input = fieldRef.value?.querySelector("input");
|
|
45
|
+
if (input?.value) {
|
|
46
|
+
input.value = "";
|
|
47
|
+
input.dispatchEvent(new Event("input", { bubbles: true }));
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const selectedOptions = computed(() =>
|
|
53
|
+
model.value
|
|
54
|
+
.map((v) => props.options.find((o) => o.value === v))
|
|
55
|
+
.filter((o): o is MultiSelectOption => Boolean(o)),
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
function remove(value: string) {
|
|
59
|
+
model.value = model.value.filter((v) => v !== value);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Backspace in an empty input removes the last selected chip.
|
|
63
|
+
function onInputKeydown(event: KeyboardEvent) {
|
|
64
|
+
const target = event.target as HTMLInputElement;
|
|
65
|
+
if (event.key === "Backspace" && !target.value && model.value.length) {
|
|
66
|
+
remove(model.value[model.value.length - 1]);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
</script>
|
|
70
|
+
|
|
71
|
+
<template>
|
|
72
|
+
<div class="multi-select">
|
|
73
|
+
<label
|
|
74
|
+
v-if="label"
|
|
75
|
+
:id="`${id}-label`"
|
|
76
|
+
class="multi-select-label"
|
|
77
|
+
:class="{ 'visually-hidden': hideLabel }"
|
|
78
|
+
>
|
|
79
|
+
{{ label }}
|
|
80
|
+
<Hint v-if="hint && !hideLabel" :text="hint" />
|
|
81
|
+
</label>
|
|
82
|
+
<ComboboxRoot
|
|
83
|
+
v-model="model"
|
|
84
|
+
multiple
|
|
85
|
+
open-on-click
|
|
86
|
+
class="multi-select-root"
|
|
87
|
+
>
|
|
88
|
+
<ComboboxAnchor class="multi-select-anchor">
|
|
89
|
+
<div ref="fieldRef" class="multi-select-field">
|
|
90
|
+
<ul v-if="selectedOptions.length" class="multi-select-chips">
|
|
91
|
+
<li
|
|
92
|
+
v-for="opt in selectedOptions"
|
|
93
|
+
:key="opt.value"
|
|
94
|
+
class="multi-select-chip"
|
|
95
|
+
>
|
|
96
|
+
<span class="multi-select-chip-label">{{ opt.label }}</span>
|
|
97
|
+
<button
|
|
98
|
+
type="button"
|
|
99
|
+
class="multi-select-chip-remove"
|
|
100
|
+
:aria-label="`Remove ${opt.label}`"
|
|
101
|
+
@click="remove(opt.value)"
|
|
102
|
+
>
|
|
103
|
+
<Icon icon="close" :size="14" />
|
|
104
|
+
</button>
|
|
105
|
+
</li>
|
|
106
|
+
</ul>
|
|
107
|
+
<ComboboxInput
|
|
108
|
+
class="multi-select-input"
|
|
109
|
+
:placeholder="selectedOptions.length ? undefined : placeholder"
|
|
110
|
+
:aria-labelledby="label ? `${id}-label` : undefined"
|
|
111
|
+
:aria-label="!label ? ariaLabel : undefined"
|
|
112
|
+
@keydown="onInputKeydown"
|
|
113
|
+
/>
|
|
114
|
+
</div>
|
|
115
|
+
<ComboboxTrigger
|
|
116
|
+
class="multi-select-trigger"
|
|
117
|
+
aria-label="Toggle options"
|
|
118
|
+
>
|
|
119
|
+
<span class="multi-select-icon" aria-hidden="true">
|
|
120
|
+
<svg
|
|
121
|
+
width="12"
|
|
122
|
+
height="12"
|
|
123
|
+
viewBox="0 0 12 12"
|
|
124
|
+
fill="none"
|
|
125
|
+
stroke="currentColor"
|
|
126
|
+
stroke-width="2"
|
|
127
|
+
stroke-linecap="round"
|
|
128
|
+
stroke-linejoin="round"
|
|
129
|
+
>
|
|
130
|
+
<path d="M3 4.5L6 7.5L9 4.5" />
|
|
131
|
+
</svg>
|
|
132
|
+
</span>
|
|
133
|
+
</ComboboxTrigger>
|
|
134
|
+
</ComboboxAnchor>
|
|
135
|
+
<ComboboxPortal>
|
|
136
|
+
<ComboboxContent
|
|
137
|
+
class="multi-select-content"
|
|
138
|
+
position="popper"
|
|
139
|
+
:side-offset="4"
|
|
140
|
+
:body-lock="false"
|
|
141
|
+
>
|
|
142
|
+
<ComboboxViewport class="multi-select-viewport">
|
|
143
|
+
<ComboboxEmpty class="multi-select-empty">No matches</ComboboxEmpty>
|
|
144
|
+
<ComboboxItem
|
|
145
|
+
v-for="opt in options"
|
|
146
|
+
:key="opt.value"
|
|
147
|
+
:value="opt.value"
|
|
148
|
+
class="multi-select-item"
|
|
149
|
+
>
|
|
150
|
+
<span>{{ opt.label }}</span>
|
|
151
|
+
<ComboboxItemIndicator class="multi-select-indicator">
|
|
152
|
+
<Icon icon="check" :size="14" />
|
|
153
|
+
</ComboboxItemIndicator>
|
|
154
|
+
</ComboboxItem>
|
|
155
|
+
</ComboboxViewport>
|
|
156
|
+
</ComboboxContent>
|
|
157
|
+
</ComboboxPortal>
|
|
158
|
+
</ComboboxRoot>
|
|
159
|
+
</div>
|
|
160
|
+
</template>
|
|
161
|
+
|
|
162
|
+
<style scoped>
|
|
163
|
+
.multi-select {
|
|
164
|
+
display: flex;
|
|
165
|
+
flex-direction: column;
|
|
166
|
+
gap: 0.25em;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
.multi-select-label {
|
|
170
|
+
display: flex;
|
|
171
|
+
align-items: center;
|
|
172
|
+
justify-content: space-between;
|
|
173
|
+
font-size: var(--font-size-sm);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.multi-select-anchor {
|
|
177
|
+
display: flex;
|
|
178
|
+
align-items: center;
|
|
179
|
+
gap: 0.25em;
|
|
180
|
+
min-height: 2.5em;
|
|
181
|
+
padding: 0.25em 0.5em;
|
|
182
|
+
font-size: var(--font-size-sm);
|
|
183
|
+
background: var(--color-bg-0);
|
|
184
|
+
border: 1px solid var(--color-border);
|
|
185
|
+
border-radius: 0.375em;
|
|
186
|
+
transition:
|
|
187
|
+
border-color var(--transition-fast),
|
|
188
|
+
box-shadow var(--transition-fast);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.multi-select-anchor:hover {
|
|
192
|
+
border-color: var(--color-border-hover);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.multi-select-anchor:focus-within {
|
|
196
|
+
outline: none;
|
|
197
|
+
border-color: var(--color-border-focus);
|
|
198
|
+
box-shadow: var(--shadow-focus);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
.multi-select-field {
|
|
202
|
+
display: flex;
|
|
203
|
+
flex-wrap: wrap;
|
|
204
|
+
align-items: center;
|
|
205
|
+
gap: 0.25em;
|
|
206
|
+
flex: 1;
|
|
207
|
+
min-width: 0;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.multi-select-chips {
|
|
211
|
+
display: contents;
|
|
212
|
+
list-style: none;
|
|
213
|
+
margin: 0;
|
|
214
|
+
padding: 0;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
.multi-select-chip {
|
|
218
|
+
display: inline-flex;
|
|
219
|
+
align-items: center;
|
|
220
|
+
gap: 0.25em;
|
|
221
|
+
/* Reset list margins (e.g. a consumer's `li + li` spacing) so chips line up. */
|
|
222
|
+
margin: 0;
|
|
223
|
+
padding: 0.125em 0.25em 0.125em 0.5em;
|
|
224
|
+
background: var(--color-bg-2);
|
|
225
|
+
border: 1px solid var(--color-border);
|
|
226
|
+
border-radius: 0.25em;
|
|
227
|
+
line-height: 1.4;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
.multi-select-chip-remove {
|
|
231
|
+
display: inline-flex;
|
|
232
|
+
align-items: center;
|
|
233
|
+
padding: 0;
|
|
234
|
+
border: none;
|
|
235
|
+
background: none;
|
|
236
|
+
color: var(--color-text-secondary);
|
|
237
|
+
cursor: pointer;
|
|
238
|
+
border-radius: 0.25em;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
.multi-select-chip-remove:hover {
|
|
242
|
+
color: var(--color-text);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
.multi-select-chip-remove:focus-visible {
|
|
246
|
+
outline: 2px solid var(--color-primary);
|
|
247
|
+
outline-offset: 1px;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
.multi-select-input {
|
|
251
|
+
flex: 1;
|
|
252
|
+
min-width: 3em;
|
|
253
|
+
height: 1.75em;
|
|
254
|
+
padding: 0;
|
|
255
|
+
border: none;
|
|
256
|
+
background: none;
|
|
257
|
+
color: var(--color-text);
|
|
258
|
+
font: inherit;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
.multi-select-input:focus {
|
|
262
|
+
outline: none;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
.multi-select-input::placeholder {
|
|
266
|
+
color: var(--color-text-tertiary);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
.multi-select-trigger {
|
|
270
|
+
display: inline-flex;
|
|
271
|
+
align-items: center;
|
|
272
|
+
flex-shrink: 0;
|
|
273
|
+
padding: 0;
|
|
274
|
+
border: none;
|
|
275
|
+
background: none;
|
|
276
|
+
color: inherit;
|
|
277
|
+
cursor: pointer;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
.multi-select-icon {
|
|
281
|
+
display: flex;
|
|
282
|
+
align-items: center;
|
|
283
|
+
}
|
|
284
|
+
</style>
|
|
285
|
+
|
|
286
|
+
<style>
|
|
287
|
+
.multi-select-content {
|
|
288
|
+
z-index: 100;
|
|
289
|
+
background: var(--color-bg-0);
|
|
290
|
+
border: 1px solid var(--color-border);
|
|
291
|
+
border-radius: 0.25em;
|
|
292
|
+
box-shadow:
|
|
293
|
+
0 4px 6px -1px rgba(0, 0, 0, 0.1),
|
|
294
|
+
0 2px 4px -2px rgba(0, 0, 0, 0.1);
|
|
295
|
+
width: var(--reka-combobox-trigger-width);
|
|
296
|
+
max-height: var(--reka-combobox-content-available-height);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
.multi-select-viewport {
|
|
300
|
+
padding: 0.25em;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
.multi-select-empty {
|
|
304
|
+
padding: 0.5em;
|
|
305
|
+
font-size: var(--font-size-sm);
|
|
306
|
+
color: var(--color-text-secondary);
|
|
307
|
+
text-align: center;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
.multi-select-item {
|
|
311
|
+
display: flex;
|
|
312
|
+
align-items: center;
|
|
313
|
+
justify-content: space-between;
|
|
314
|
+
gap: 0.5em;
|
|
315
|
+
padding: 0.25em 0.5em;
|
|
316
|
+
border-radius: 0.25em;
|
|
317
|
+
font-size: var(--font-size-sm);
|
|
318
|
+
white-space: nowrap;
|
|
319
|
+
cursor: pointer;
|
|
320
|
+
user-select: none;
|
|
321
|
+
outline: none;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
.multi-select-item[data-highlighted] {
|
|
325
|
+
background: var(--color-primary);
|
|
326
|
+
color: white;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
.multi-select-item[data-state="checked"] {
|
|
330
|
+
font-weight: 600;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
.multi-select-indicator {
|
|
334
|
+
display: flex;
|
|
335
|
+
align-items: center;
|
|
336
|
+
flex-shrink: 0;
|
|
337
|
+
}
|
|
338
|
+
</style>
|
|
@@ -8,6 +8,8 @@ The editor is **lazy-loaded**: the underlying CodeMirror bundle and YAML/TOML pa
|
|
|
8
8
|
|
|
9
9
|
Users can switch formats from the dropdown; the editor round-trips the current value through the new format. Apply emits an `apply` event with the parsed value — the parent decides what to do with it (typically merge back into its own parameter state).
|
|
10
10
|
|
|
11
|
+
Set the editor font size with the `fontSize` prop (any CSS length, e.g. `"16px"` or `"1rem"`); it defaults to `var(--font-size-sm)`.
|
|
12
|
+
|
|
11
13
|
## Examples
|
|
12
14
|
|
|
13
15
|
<script setup>
|
|
@@ -61,6 +63,22 @@ function onApply(v) {
|
|
|
61
63
|
</template>
|
|
62
64
|
</ComponentDemo>
|
|
63
65
|
|
|
66
|
+
### Custom font size
|
|
67
|
+
|
|
68
|
+
<ComponentDemo>
|
|
69
|
+
<div style="width: 100%">
|
|
70
|
+
<ParamEditor :value="params" font-size="16px" @apply="onApply" />
|
|
71
|
+
</div>
|
|
72
|
+
|
|
73
|
+
<template #code>
|
|
74
|
+
|
|
75
|
+
```vue
|
|
76
|
+
<ParamEditor :value="params" font-size="16px" @apply="onApply" />
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
</template>
|
|
80
|
+
</ComponentDemo>
|
|
81
|
+
|
|
64
82
|
## Props
|
|
65
83
|
|
|
66
84
|
| Prop | Type | Required | Default |
|
|
@@ -68,6 +86,7 @@ function onApply(v) {
|
|
|
68
86
|
| `value` | `ParamEditorValue` | Yes | — |
|
|
69
87
|
| `format` | `ParamEditorFormat` | No | — |
|
|
70
88
|
| `height` | `string` | No | — |
|
|
89
|
+
| `fontSize` | `string` | No | — |
|
|
71
90
|
| `filename` | `string` | No | — |
|
|
72
91
|
|
|
73
92
|
## Events
|
|
@@ -9,6 +9,9 @@ defineProps<{
|
|
|
9
9
|
value: ParamEditorValue;
|
|
10
10
|
format?: ParamEditorFormat;
|
|
11
11
|
height?: string;
|
|
12
|
+
/** Editor font size, as any CSS length (e.g. `"16px"`, `"1rem"`).
|
|
13
|
+
* Defaults to `var(--font-size-sm)`. */
|
|
14
|
+
fontSize?: string;
|
|
12
15
|
/** Basename for the Export download (no extension). Defaults to
|
|
13
16
|
* `params-YYYYMMDD-HHMMSS` computed at click time. */
|
|
14
17
|
filename?: string;
|
|
@@ -33,6 +36,7 @@ const Impl = defineAsyncComponent({
|
|
|
33
36
|
:value="value"
|
|
34
37
|
:format="format"
|
|
35
38
|
:height="height"
|
|
39
|
+
:font-size="fontSize"
|
|
36
40
|
:filename="filename"
|
|
37
41
|
@apply="$emit('apply', $event)"
|
|
38
42
|
/>
|
|
@@ -27,9 +27,10 @@ const props = withDefaults(
|
|
|
27
27
|
value: Value;
|
|
28
28
|
format?: Format;
|
|
29
29
|
height?: string;
|
|
30
|
+
fontSize?: string;
|
|
30
31
|
filename?: string;
|
|
31
32
|
}>(),
|
|
32
|
-
{ format: "json", height: "320px" },
|
|
33
|
+
{ format: "json", height: "320px", fontSize: "var(--font-size-sm)" },
|
|
33
34
|
);
|
|
34
35
|
|
|
35
36
|
const emit = defineEmits<{ apply: [value: Value] }>();
|
|
@@ -264,7 +265,7 @@ async function onFileChange(e: Event) {
|
|
|
264
265
|
<Codemirror
|
|
265
266
|
v-model="text"
|
|
266
267
|
:extensions="extensions"
|
|
267
|
-
:style="{ height }"
|
|
268
|
+
:style="{ height, fontSize }"
|
|
268
269
|
:indent-with-tab="false"
|
|
269
270
|
:tab-size="2"
|
|
270
271
|
class="param-editor-cm"
|
|
@@ -317,7 +318,6 @@ async function onFileChange(e: Event) {
|
|
|
317
318
|
.param-editor-cm {
|
|
318
319
|
border: 1px solid var(--color-border);
|
|
319
320
|
border-radius: 0.375em;
|
|
320
|
-
font-size: var(--font-size-sm);
|
|
321
321
|
overflow: hidden;
|
|
322
322
|
}
|
|
323
323
|
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# ToggleGroup
|
|
2
|
+
|
|
3
|
+
A segmented control that looks like a [`ButtonGroup`](./button-group) but tracks
|
|
4
|
+
which item(s) are pressed. By default it is single-select (like a radio group);
|
|
5
|
+
add `multiple` to let several items be pressed at once. Built on
|
|
6
|
+
[reka-ui's ToggleGroup](https://reka-ui.com/docs/components/toggle-group).
|
|
7
|
+
|
|
8
|
+
## Examples
|
|
9
|
+
|
|
10
|
+
### Single select
|
|
11
|
+
|
|
12
|
+
`v-model` holds the pressed value (a `string`). Clicking the active item again
|
|
13
|
+
clears the selection.
|
|
14
|
+
|
|
15
|
+
<script setup>
|
|
16
|
+
import { ref } from 'vue'
|
|
17
|
+
const interval = ref('weekly')
|
|
18
|
+
const days = ref(['mon', 'wed'])
|
|
19
|
+
</script>
|
|
20
|
+
|
|
21
|
+
<ComponentDemo>
|
|
22
|
+
<ToggleGroup
|
|
23
|
+
v-model="interval"
|
|
24
|
+
label="Interval"
|
|
25
|
+
:options="[
|
|
26
|
+
{ value: 'daily', label: 'Daily' },
|
|
27
|
+
{ value: 'weekly', label: 'Weekly' },
|
|
28
|
+
{ value: 'monthly', label: 'Monthly' },
|
|
29
|
+
]"
|
|
30
|
+
/>
|
|
31
|
+
<p>Selected: {{ interval }}</p>
|
|
32
|
+
|
|
33
|
+
<template #code>
|
|
34
|
+
|
|
35
|
+
```vue
|
|
36
|
+
<script setup>
|
|
37
|
+
import { ref } from "vue";
|
|
38
|
+
const interval = ref("weekly");
|
|
39
|
+
</script>
|
|
40
|
+
|
|
41
|
+
<ToggleGroup
|
|
42
|
+
v-model="interval"
|
|
43
|
+
label="Interval"
|
|
44
|
+
:options="[
|
|
45
|
+
{ value: 'daily', label: 'Daily' },
|
|
46
|
+
{ value: 'weekly', label: 'Weekly' },
|
|
47
|
+
{ value: 'monthly', label: 'Monthly' },
|
|
48
|
+
]"
|
|
49
|
+
/>
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
</template>
|
|
53
|
+
</ComponentDemo>
|
|
54
|
+
|
|
55
|
+
### Multiple select
|
|
56
|
+
|
|
57
|
+
With `multiple`, `v-model` is a `string[]` and any number of items can be
|
|
58
|
+
pressed at once.
|
|
59
|
+
|
|
60
|
+
<ComponentDemo>
|
|
61
|
+
<ToggleGroup
|
|
62
|
+
v-model="days"
|
|
63
|
+
multiple
|
|
64
|
+
label="Active days"
|
|
65
|
+
:options="[
|
|
66
|
+
{ value: 'mon', label: 'Mon' },
|
|
67
|
+
{ value: 'tue', label: 'Tue' },
|
|
68
|
+
{ value: 'wed', label: 'Wed' },
|
|
69
|
+
{ value: 'thu', label: 'Thu' },
|
|
70
|
+
{ value: 'fri', label: 'Fri' },
|
|
71
|
+
]"
|
|
72
|
+
/>
|
|
73
|
+
<p>Selected: {{ days.join(', ') || 'none' }}</p>
|
|
74
|
+
|
|
75
|
+
<template #code>
|
|
76
|
+
|
|
77
|
+
```vue
|
|
78
|
+
<script setup>
|
|
79
|
+
import { ref } from "vue";
|
|
80
|
+
const days = ref(["mon", "wed"]);
|
|
81
|
+
</script>
|
|
82
|
+
|
|
83
|
+
<ToggleGroup
|
|
84
|
+
v-model="days"
|
|
85
|
+
multiple
|
|
86
|
+
label="Active days"
|
|
87
|
+
:options="[
|
|
88
|
+
{ value: 'mon', label: 'Mon' },
|
|
89
|
+
{ value: 'tue', label: 'Tue' },
|
|
90
|
+
{ value: 'wed', label: 'Wed' },
|
|
91
|
+
{ value: 'thu', label: 'Thu' },
|
|
92
|
+
{ value: 'fri', label: 'Fri' },
|
|
93
|
+
]"
|
|
94
|
+
/>
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
</template>
|
|
98
|
+
</ComponentDemo>
|
|
99
|
+
|
|
100
|
+
### Vertical and disabled options
|
|
101
|
+
|
|
102
|
+
Set `orientation="vertical"` to stack the items, and mark individual options
|
|
103
|
+
`disabled`.
|
|
104
|
+
|
|
105
|
+
<ComponentDemo>
|
|
106
|
+
<ToggleGroup
|
|
107
|
+
model-value="map"
|
|
108
|
+
orientation="vertical"
|
|
109
|
+
aria-label="View"
|
|
110
|
+
:options="[
|
|
111
|
+
{ value: 'map', label: 'Map' },
|
|
112
|
+
{ value: 'chart', label: 'Chart' },
|
|
113
|
+
{ value: 'table', label: 'Table', disabled: true },
|
|
114
|
+
]"
|
|
115
|
+
/>
|
|
116
|
+
|
|
117
|
+
<template #code>
|
|
118
|
+
|
|
119
|
+
```vue
|
|
120
|
+
<ToggleGroup
|
|
121
|
+
v-model="view"
|
|
122
|
+
orientation="vertical"
|
|
123
|
+
aria-label="View"
|
|
124
|
+
:options="[
|
|
125
|
+
{ value: 'map', label: 'Map' },
|
|
126
|
+
{ value: 'chart', label: 'Chart' },
|
|
127
|
+
{ value: 'table', label: 'Table', disabled: true },
|
|
128
|
+
]"
|
|
129
|
+
/>
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
</template>
|
|
133
|
+
</ComponentDemo>
|
|
134
|
+
|
|
135
|
+
## Model
|
|
136
|
+
|
|
137
|
+
| Name | Type |
|
|
138
|
+
|------|------|
|
|
139
|
+
| `v-model` | `string \| string[]` |
|
|
140
|
+
|
|
141
|
+
## Props
|
|
142
|
+
|
|
143
|
+
| Prop | Type | Required | Default |
|
|
144
|
+
|------|------|----------|---------|
|
|
145
|
+
| `options` | `ToggleGroupOption[]` | Yes | — |
|
|
146
|
+
| `multiple` | `boolean` | No | — |
|
|
147
|
+
| `label` | `string` | No | — |
|
|
148
|
+
| `hideLabel` | `boolean` | No | — |
|
|
149
|
+
| `ariaLabel` | `string` | No | — |
|
|
150
|
+
| `hint` | `string` | No | — |
|
|
151
|
+
| `disabled` | `boolean` | No | — |
|
|
152
|
+
| `orientation` | `"horizontal" \| "vertical"` | No | `"horizontal"` |
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
### ToggleGroupOption
|
|
156
|
+
|
|
157
|
+
```ts
|
|
158
|
+
interface ToggleGroupOption {
|
|
159
|
+
value: string;
|
|
160
|
+
label: string;
|
|
161
|
+
disabled?: boolean;
|
|
162
|
+
}
|
|
163
|
+
```
|