@cocoar/vue-ui 3.1.0 → 3.2.0-beta.6
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/dist/components/checkbox/CoarCheckbox.vue.d.ts +1 -1
- package/dist/components/checkbox/CoarCheckbox.vue.d.ts.map +1 -1
- package/dist/components/code-block/CoarCodeBlock.vue.d.ts +1 -1
- package/dist/components/code-block/CoarCodeBlock.vue.d.ts.map +1 -1
- package/dist/components/data-list/CoarDataList.vue.d.ts +158 -0
- package/dist/components/data-list/CoarDataList.vue.d.ts.map +1 -0
- package/dist/components/data-list/CoarDataListToolbar.vue.d.ts +30 -0
- package/dist/components/data-list/CoarDataListToolbar.vue.d.ts.map +1 -0
- package/dist/components/data-list/data-list-builder.d.ts +288 -0
- package/dist/components/data-list/data-list-builder.d.ts.map +1 -0
- package/dist/components/data-list/index.d.ts +12 -0
- package/dist/components/data-list/index.d.ts.map +1 -0
- package/dist/components/data-list/internal/compare.d.ts +14 -0
- package/dist/components/data-list/internal/compare.d.ts.map +1 -0
- package/dist/components/data-list/internal/reorder-core.d.ts +46 -0
- package/dist/components/data-list/internal/reorder-core.d.ts.map +1 -0
- package/dist/components/data-list/internal/search.d.ts +16 -0
- package/dist/components/data-list/internal/search.d.ts.map +1 -0
- package/dist/components/data-list/internal/useDataListLines.d.ts +92 -0
- package/dist/components/data-list/internal/useDataListLines.d.ts.map +1 -0
- package/dist/components/data-list/internal/useDataListReorder.d.ts +68 -0
- package/dist/components/data-list/internal/useDataListReorder.d.ts.map +1 -0
- package/dist/components/data-list/internal/useSearchHighlight.d.ts +19 -0
- package/dist/components/data-list/internal/useSearchHighlight.d.ts.map +1 -0
- package/dist/components/data-list/types.d.ts +185 -0
- package/dist/components/data-list/types.d.ts.map +1 -0
- package/dist/components/data-list/useDataListModel.d.ts +79 -0
- package/dist/components/data-list/useDataListModel.d.ts.map +1 -0
- package/dist/components/date-time/_shared/maskito-config.d.ts +7 -2
- package/dist/components/date-time/_shared/maskito-config.d.ts.map +1 -1
- package/dist/components/date-time/_shared/time-helpers.d.ts +11 -4
- package/dist/components/date-time/_shared/time-helpers.d.ts.map +1 -1
- package/dist/components/date-time/_shared/use-date-picker-base.d.ts +1 -1
- package/dist/components/date-time/plain-date-picker/CoarPlainDatePicker.vue.d.ts +1 -1
- package/dist/components/date-time/plain-date-picker/CoarPlainDatePicker.vue.d.ts.map +1 -1
- package/dist/components/date-time/plain-date-time-picker/CoarPlainDateTimePicker.vue.d.ts +1 -1
- package/dist/components/date-time/plain-date-time-picker/CoarPlainDateTimePicker.vue.d.ts.map +1 -1
- package/dist/components/date-time/zoned-date-time-picker/CoarZonedDateTimePicker.vue.d.ts +1 -1
- package/dist/components/date-time/zoned-date-time-picker/CoarZonedDateTimePicker.vue.d.ts.map +1 -1
- package/dist/components/dual-listbox/CoarDualListbox.vue.d.ts +3 -0
- package/dist/components/dual-listbox/CoarDualListbox.vue.d.ts.map +1 -1
- package/dist/components/form-field/CoarFormField.vue.d.ts +1 -1
- package/dist/components/form-field/CoarFormField.vue.d.ts.map +1 -1
- package/dist/components/icon/CoarIcon.vue.d.ts +2 -2
- package/dist/components/icon/CoarIcon.vue.d.ts.map +1 -1
- package/dist/components/listbox/CoarListbox.vue.d.ts +7 -0
- package/dist/components/listbox/CoarListbox.vue.d.ts.map +1 -1
- package/dist/components/number-input/CoarNumberInput.vue.d.ts +1 -1
- package/dist/components/number-input/CoarNumberInput.vue.d.ts.map +1 -1
- package/dist/components/otp-input/CoarOtpInput.vue.d.ts +1 -1
- package/dist/components/otp-input/CoarOtpInput.vue.d.ts.map +1 -1
- package/dist/components/password-input/CoarPasswordInput.vue.d.ts +1 -1
- package/dist/components/password-input/CoarPasswordInput.vue.d.ts.map +1 -1
- package/dist/components/switch/CoarSwitch.vue.d.ts +1 -1
- package/dist/components/switch/CoarSwitch.vue.d.ts.map +1 -1
- package/dist/components/text-input/CoarTextInput.vue.d.ts +1 -1
- package/dist/components/text-input/CoarTextInput.vue.d.ts.map +1 -1
- package/dist/composables/dragRegistry.d.ts +12 -0
- package/dist/composables/dragRegistry.d.ts.map +1 -1
- package/dist/composables/index.d.ts +2 -2
- package/dist/composables/index.d.ts.map +1 -1
- package/dist/composables/useDragDrop.d.ts +62 -6
- package/dist/composables/useDragDrop.d.ts.map +1 -1
- package/dist/composables/useVirtualList.d.ts +21 -1
- package/dist/composables/useVirtualList.d.ts.map +1 -1
- package/dist/index.css +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4508 -2039
- package/package.json +5 -3
- package/skills/cocoar-vue-ui/SKILL.md +244 -0
- package/skills/cocoar-vue-ui/references/components/avatar.md +178 -0
- package/skills/cocoar-vue-ui/references/components/badge.md +290 -0
- package/skills/cocoar-vue-ui/references/components/breadcrumb.md +238 -0
- package/skills/cocoar-vue-ui/references/components/button.md +252 -0
- package/skills/cocoar-vue-ui/references/components/calendar/agenda-view.md +353 -0
- package/skills/cocoar-vue-ui/references/components/calendar/coar-calendar.md +1645 -0
- package/skills/cocoar-vue-ui/references/components/calendar/day-view.md +361 -0
- package/skills/cocoar-vue-ui/references/components/calendar/index.md +312 -0
- package/skills/cocoar-vue-ui/references/components/calendar/month-view.md +475 -0
- package/skills/cocoar-vue-ui/references/components/calendar/performance.md +186 -0
- package/skills/cocoar-vue-ui/references/components/calendar/timeline-view.md +301 -0
- package/skills/cocoar-vue-ui/references/components/calendar/week-view.md +382 -0
- package/skills/cocoar-vue-ui/references/components/calendar/work-week-view.md +145 -0
- package/skills/cocoar-vue-ui/references/components/calendar/year-view.md +63 -0
- package/skills/cocoar-vue-ui/references/components/card.md +151 -0
- package/skills/cocoar-vue-ui/references/components/checkbox-group.md +103 -0
- package/skills/cocoar-vue-ui/references/components/checkbox.md +279 -0
- package/skills/cocoar-vue-ui/references/components/code-block.md +241 -0
- package/skills/cocoar-vue-ui/references/components/context-menu.md +355 -0
- package/skills/cocoar-vue-ui/references/components/data-grid/checkbox.md +213 -0
- package/skills/cocoar-vue-ui/references/components/data-grid/date-columns.md +272 -0
- package/skills/cocoar-vue-ui/references/components/data-grid/editing.md +236 -0
- package/skills/cocoar-vue-ui/references/components/data-grid/multi-select.md +193 -0
- package/skills/cocoar-vue-ui/references/components/data-grid/number.md +147 -0
- package/skills/cocoar-vue-ui/references/components/data-grid/select.md +202 -0
- package/skills/cocoar-vue-ui/references/components/data-grid/text.md +127 -0
- package/skills/cocoar-vue-ui/references/components/data-grid.md +1225 -0
- package/skills/cocoar-vue-ui/references/components/data-list.md +2121 -0
- package/skills/cocoar-vue-ui/references/components/date-or-time-picker.md +200 -0
- package/skills/cocoar-vue-ui/references/components/date-picker.md +203 -0
- package/skills/cocoar-vue-ui/references/components/date-time-picker.md +154 -0
- package/skills/cocoar-vue-ui/references/components/date-views.md +212 -0
- package/skills/cocoar-vue-ui/references/components/dialog.md +148 -0
- package/skills/cocoar-vue-ui/references/components/divider.md +157 -0
- package/skills/cocoar-vue-ui/references/components/document-viewer/annotations.md +400 -0
- package/skills/cocoar-vue-ui/references/components/document-viewer/coar-document-viewer.md +327 -0
- package/skills/cocoar-vue-ui/references/components/document-viewer/index.md +234 -0
- package/skills/cocoar-vue-ui/references/components/document-viewer/toolbar.md +221 -0
- package/skills/cocoar-vue-ui/references/components/drag-drop.md +267 -0
- package/skills/cocoar-vue-ui/references/components/dual-listbox.md +449 -0
- package/skills/cocoar-vue-ui/references/components/file-explorer/asset-store.md +327 -0
- package/skills/cocoar-vue-ui/references/components/file-explorer/in-memory-store.md +176 -0
- package/skills/cocoar-vue-ui/references/components/file-explorer/index.md +311 -0
- package/skills/cocoar-vue-ui/references/components/file-explorer/use-file-explorer.md +300 -0
- package/skills/cocoar-vue-ui/references/components/form-field.md +1025 -0
- package/skills/cocoar-vue-ui/references/components/fragment-parser.md +298 -0
- package/skills/cocoar-vue-ui/references/components/link.md +235 -0
- package/skills/cocoar-vue-ui/references/components/listbox.md +575 -0
- package/skills/cocoar-vue-ui/references/components/map/editor.md +448 -0
- package/skills/cocoar-vue-ui/references/components/map/index.md +351 -0
- package/skills/cocoar-vue-ui/references/components/markdown-diagrams.md +210 -0
- package/skills/cocoar-vue-ui/references/components/markdown-editor.md +1478 -0
- package/skills/cocoar-vue-ui/references/components/markdown-embeds.md +387 -0
- package/skills/cocoar-vue-ui/references/components/markdown-form.md +447 -0
- package/skills/cocoar-vue-ui/references/components/markdown.md +276 -0
- package/skills/cocoar-vue-ui/references/components/menu.md +380 -0
- package/skills/cocoar-vue-ui/references/components/mermaid.md +172 -0
- package/skills/cocoar-vue-ui/references/components/navbar.md +147 -0
- package/skills/cocoar-vue-ui/references/components/note.md +96 -0
- package/skills/cocoar-vue-ui/references/components/notice.md +131 -0
- package/skills/cocoar-vue-ui/references/components/number-input.md +215 -0
- package/skills/cocoar-vue-ui/references/components/otp-input.md +324 -0
- package/skills/cocoar-vue-ui/references/components/page-builder/authoring-contract.md +271 -0
- package/skills/cocoar-vue-ui/references/components/page-builder/coar-page-builder.md +476 -0
- package/skills/cocoar-vue-ui/references/components/page-builder/coar-page-renderer.md +677 -0
- package/skills/cocoar-vue-ui/references/components/page-builder/custom-elements.md +441 -0
- package/skills/cocoar-vue-ui/references/components/page-builder/idp-integration.md +122 -0
- package/skills/cocoar-vue-ui/references/components/page-builder/index.md +573 -0
- package/skills/cocoar-vue-ui/references/components/pagination.md +150 -0
- package/skills/cocoar-vue-ui/references/components/panel-layout.md +372 -0
- package/skills/cocoar-vue-ui/references/components/password-input.md +175 -0
- package/skills/cocoar-vue-ui/references/components/popconfirm.md +186 -0
- package/skills/cocoar-vue-ui/references/components/popover.md +173 -0
- package/skills/cocoar-vue-ui/references/components/progress-bar.md +178 -0
- package/skills/cocoar-vue-ui/references/components/radio-group.md +225 -0
- package/skills/cocoar-vue-ui/references/components/script-editor.md +1271 -0
- package/skills/cocoar-vue-ui/references/components/segmented-control.md +238 -0
- package/skills/cocoar-vue-ui/references/components/select.md +463 -0
- package/skills/cocoar-vue-ui/references/components/sidebar.md +421 -0
- package/skills/cocoar-vue-ui/references/components/spinner.md +132 -0
- package/skills/cocoar-vue-ui/references/components/switch.md +195 -0
- package/skills/cocoar-vue-ui/references/components/table.md +170 -0
- package/skills/cocoar-vue-ui/references/components/tabs.md +382 -0
- package/skills/cocoar-vue-ui/references/components/tag.md +178 -0
- package/skills/cocoar-vue-ui/references/components/text-input.md +256 -0
- package/skills/cocoar-vue-ui/references/components/toast.md +160 -0
- package/skills/cocoar-vue-ui/references/components/tooltip.md +121 -0
- package/skills/cocoar-vue-ui/references/components/transitions.md +193 -0
- package/skills/cocoar-vue-ui/references/components/tree.md +2388 -0
- package/skills/cocoar-vue-ui/references/components/virtual-list.md +212 -0
- package/skills/cocoar-vue-ui/references/components/wizard.md +251 -0
- package/skills/cocoar-vue-ui/references/components/zoned-date-time-picker.md +177 -0
- package/skills/cocoar-vue-ui/references/foundations/colors.md +708 -0
- package/skills/cocoar-vue-ui/references/foundations/design-principles.md +115 -0
- package/skills/cocoar-vue-ui/references/foundations/icons.md +381 -0
- package/skills/cocoar-vue-ui/references/foundations/localization/formatting.md +530 -0
- package/skills/cocoar-vue-ui/references/foundations/localization/setup.md +86 -0
- package/skills/cocoar-vue-ui/references/foundations/localization/timezones.md +182 -0
- package/skills/cocoar-vue-ui/references/foundations/localization/translations.md +305 -0
- package/skills/cocoar-vue-ui/references/foundations/motion.md +549 -0
- package/skills/cocoar-vue-ui/references/foundations/spacing.md +330 -0
- package/skills/cocoar-vue-ui/references/foundations/theming.md +140 -0
- package/skills/cocoar-vue-ui/references/foundations/typography.md +206 -0
- package/skills/cocoar-vue-ui/references/guide/error-handling.md +162 -0
- package/skills/cocoar-vue-ui/references/guide/getting-started.md +119 -0
- package/skills/cocoar-vue-ui/references/guide/migration-page-builder-3.md +207 -0
- package/skills/cocoar-vue-ui/references/guide/migration.md +140 -0
- package/skills/cocoar-vue-ui/references/guide/theming.md +98 -0
|
@@ -0,0 +1,575 @@
|
|
|
1
|
+
<!-- Generated from apps/docs/components/listbox.md by apps/docs/scripts/sync-skill.mjs. Do not edit; edit the docs page. -->
|
|
2
|
+
|
|
3
|
+
# Listbox
|
|
4
|
+
|
|
5
|
+
A single-column list of selectable items with grouping, search, custom renderers, and multi-select highlighting. Use it as a form control (v-model of highlighted values), as a display-only roster, or as the foundation for [`CoarDualListbox`](./dual-listbox.md).
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { CoarListbox } from '@cocoar/vue-ui';
|
|
9
|
+
import type { CoarListboxOption } from '@cocoar/vue-ui';
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Basic
|
|
13
|
+
|
|
14
|
+
Multi-select highlight via click, `Ctrl+Click`, `Shift+Click`, and keyboard (arrows, `Space`, `Ctrl+A`). Double-click (or `Enter`) emits `item-activate` — wire this up to move items, open a detail view, etc.
|
|
15
|
+
|
|
16
|
+
**Demo — `listbox/demos/BasicListbox.vue`**
|
|
17
|
+
|
|
18
|
+
```vue
|
|
19
|
+
<template>
|
|
20
|
+
<div style="max-width: 320px; height: 260px;">
|
|
21
|
+
<CoarListbox
|
|
22
|
+
v-model="highlighted"
|
|
23
|
+
:options="options"
|
|
24
|
+
label="Fruit"
|
|
25
|
+
show-count
|
|
26
|
+
searchable
|
|
27
|
+
/>
|
|
28
|
+
<p style="margin-top: 8px; font-size: 13px; color: #64748b;">
|
|
29
|
+
Highlighted: {{ highlighted.join(', ') || 'none' }}
|
|
30
|
+
</p>
|
|
31
|
+
</div>
|
|
32
|
+
</template>
|
|
33
|
+
|
|
34
|
+
<script setup lang="ts">
|
|
35
|
+
import { ref } from 'vue';
|
|
36
|
+
import { CoarListbox } from '@cocoar/vue-ui';
|
|
37
|
+
import type { CoarListboxOption } from '@cocoar/vue-ui';
|
|
38
|
+
|
|
39
|
+
const options: CoarListboxOption<string>[] = [
|
|
40
|
+
{ value: 'apple', label: 'Apple' },
|
|
41
|
+
{ value: 'banana', label: 'Banana' },
|
|
42
|
+
{ value: 'cherry', label: 'Cherry' },
|
|
43
|
+
{ value: 'date', label: 'Date' },
|
|
44
|
+
{ value: 'elderberry', label: 'Elderberry' },
|
|
45
|
+
{ value: 'fig', label: 'Fig' },
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
const highlighted = ref<string[]>([]);
|
|
49
|
+
</script>
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Display only
|
|
53
|
+
|
|
54
|
+
Set `display-only` to render a static roster — for example, "current group members". Clicks don't highlight, keyboard navigation is off, ARIA role drops to `list`, but search and grouping still work.
|
|
55
|
+
|
|
56
|
+
**Demo — `listbox/demos/DisplayOnlyListbox.vue`**
|
|
57
|
+
|
|
58
|
+
```vue
|
|
59
|
+
<template>
|
|
60
|
+
<div style="max-width: 320px; height: 240px;">
|
|
61
|
+
<CoarListbox
|
|
62
|
+
:options="members"
|
|
63
|
+
display-only
|
|
64
|
+
label="Team members"
|
|
65
|
+
show-count
|
|
66
|
+
:searchable="members.length > 5"
|
|
67
|
+
/>
|
|
68
|
+
</div>
|
|
69
|
+
</template>
|
|
70
|
+
|
|
71
|
+
<script setup lang="ts">
|
|
72
|
+
import { CoarListbox } from '@cocoar/vue-ui';
|
|
73
|
+
import type { CoarListboxOption } from '@cocoar/vue-ui';
|
|
74
|
+
|
|
75
|
+
const members: CoarListboxOption<string>[] = [
|
|
76
|
+
{ value: 'alice', label: 'Alice Müller', subtitle: 'Engineer · Zürich', icon: 'user' },
|
|
77
|
+
{ value: 'bob', label: 'Bob Meier', subtitle: 'Designer · Basel', icon: 'user' },
|
|
78
|
+
{ value: 'clara', label: 'Clara Schmid', subtitle: 'PM · Bern', icon: 'user' },
|
|
79
|
+
{ value: 'dan', label: 'Dan Roth', subtitle: 'Engineer · Remote', icon: 'user' },
|
|
80
|
+
];
|
|
81
|
+
</script>
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Grouped
|
|
85
|
+
|
|
86
|
+
Items with a `group` field render under sticky headings. Group order is controlled by `sortGroups` ('asc' by default); item order within a group by `sortOptions` ('none' by default).
|
|
87
|
+
|
|
88
|
+
**Demo — `listbox/demos/GroupedListbox.vue`**
|
|
89
|
+
|
|
90
|
+
```vue
|
|
91
|
+
<template>
|
|
92
|
+
<div style="max-width: 320px; height: 300px;">
|
|
93
|
+
<CoarListbox
|
|
94
|
+
v-model="highlighted"
|
|
95
|
+
:options="options"
|
|
96
|
+
label="Items"
|
|
97
|
+
searchable
|
|
98
|
+
:search-fields="['label', 'group']"
|
|
99
|
+
/>
|
|
100
|
+
</div>
|
|
101
|
+
</template>
|
|
102
|
+
|
|
103
|
+
<script setup lang="ts">
|
|
104
|
+
import { ref } from 'vue';
|
|
105
|
+
import { CoarListbox } from '@cocoar/vue-ui';
|
|
106
|
+
import type { CoarListboxOption } from '@cocoar/vue-ui';
|
|
107
|
+
|
|
108
|
+
const options: CoarListboxOption<string>[] = [
|
|
109
|
+
{ value: 'apple', label: 'Apple', group: 'Fruit' },
|
|
110
|
+
{ value: 'banana', label: 'Banana', group: 'Fruit' },
|
|
111
|
+
{ value: 'cherry', label: 'Cherry', group: 'Fruit' },
|
|
112
|
+
{ value: 'carrot', label: 'Carrot', group: 'Vegetable' },
|
|
113
|
+
{ value: 'potato', label: 'Potato', group: 'Vegetable' },
|
|
114
|
+
{ value: 'broccoli', label: 'Broccoli', group: 'Vegetable' },
|
|
115
|
+
];
|
|
116
|
+
|
|
117
|
+
const highlighted = ref<string[]>([]);
|
|
118
|
+
</script>
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Custom item components
|
|
122
|
+
|
|
123
|
+
For per-kind polymorphic rendering, register Vue components via `itemComponents`. The component resolution order is:
|
|
124
|
+
|
|
125
|
+
1. `itemComponents[item.kind]` if provided
|
|
126
|
+
2. `#item-<kind>` slot if present
|
|
127
|
+
3. `#item` slot if present
|
|
128
|
+
4. Built-in `icon + label + subtitle` layout
|
|
129
|
+
|
|
130
|
+
Each renderer receives `{ item, highlighted, selectable, side }` as props / slot scope. Set `kindBy` if `kind` lives on a different field than `item.kind`.
|
|
131
|
+
|
|
132
|
+
**Demo — `listbox/demos/CustomItemComponent.vue`**
|
|
133
|
+
|
|
134
|
+
```vue
|
|
135
|
+
<template>
|
|
136
|
+
<div style="max-width: 360px; height: 320px;">
|
|
137
|
+
<CoarListbox
|
|
138
|
+
v-model="highlighted"
|
|
139
|
+
:options="items"
|
|
140
|
+
:item-components="{ user: UserItem, invite: InviteItem }"
|
|
141
|
+
label="Mixed entries"
|
|
142
|
+
searchable
|
|
143
|
+
:search-by="(i) => `${i.label} ${(i.value as any).email ?? ''}`"
|
|
144
|
+
/>
|
|
145
|
+
</div>
|
|
146
|
+
</template>
|
|
147
|
+
|
|
148
|
+
<script setup lang="ts">
|
|
149
|
+
import { ref } from 'vue';
|
|
150
|
+
import { CoarListbox } from '@cocoar/vue-ui';
|
|
151
|
+
import type { CoarListboxOption } from '@cocoar/vue-ui';
|
|
152
|
+
import UserItem from './UserItem.vue';
|
|
153
|
+
import InviteItem from './InviteItem.vue';
|
|
154
|
+
|
|
155
|
+
interface UserRow { id: string; name: string; email: string; role: string }
|
|
156
|
+
interface InviteRow { id: string; email: string; expiresInDays: number }
|
|
157
|
+
|
|
158
|
+
const items: CoarListboxOption<UserRow | InviteRow>[] = [
|
|
159
|
+
{ value: { id: '1', name: 'Alice Müller', email: 'alice@x.com', role: 'Admin' }, label: 'Alice Müller', kind: 'user' },
|
|
160
|
+
{ value: { id: '2', name: 'Bob Meier', email: 'bob@x.com', role: 'Editor' }, label: 'Bob Meier', kind: 'user' },
|
|
161
|
+
{ value: { id: 'inv-1', email: 'carol@new.com', expiresInDays: 3 }, label: 'carol@new.com', kind: 'invite' },
|
|
162
|
+
{ value: { id: 'inv-2', email: 'dan@new.com', expiresInDays: 7 }, label: 'dan@new.com', kind: 'invite' },
|
|
163
|
+
];
|
|
164
|
+
|
|
165
|
+
const highlighted = ref<unknown[]>([]);
|
|
166
|
+
</script>
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
```ts
|
|
170
|
+
// UserItem.vue
|
|
171
|
+
const props = defineProps<{
|
|
172
|
+
item: CoarListboxOption<UserRow>
|
|
173
|
+
highlighted: boolean
|
|
174
|
+
selectable: boolean
|
|
175
|
+
}>()
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Flexible search
|
|
179
|
+
|
|
180
|
+
Three levels of control, from simplest to most powerful — set only one:
|
|
181
|
+
|
|
182
|
+
```ts
|
|
183
|
+
// (a) Extend the built-in search to additional fields
|
|
184
|
+
searchFields: ['label', 'subtitle', 'group']
|
|
185
|
+
|
|
186
|
+
// (b) Provide the searchable text for each item
|
|
187
|
+
searchBy: (item) => `${item.label} ${item.value.email}`
|
|
188
|
+
|
|
189
|
+
// (c) Full control — arbitrary matching logic
|
|
190
|
+
filterWith: (item, query) => fuse.search(query).includes(item)
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
`filterWith` wins over `searchBy` wins over `searchFields`. Items can also carry a `searchText` field to override the default per-item.
|
|
194
|
+
|
|
195
|
+
## Item API (inline actions)
|
|
196
|
+
|
|
197
|
+
Every item renderer — whether a component from `itemComponents` or the `#item` / `#item-<kind>` slot — receives a scoped `api` handle. Use it to trigger listbox behavior from inside the row: remove it from a trash button, toggle highlight from a checkbox, fire a custom action from a context menu.
|
|
198
|
+
|
|
199
|
+
**Demo — `listbox/demos/RemovableItems.vue`**
|
|
200
|
+
|
|
201
|
+
```vue
|
|
202
|
+
<template>
|
|
203
|
+
<div style="max-width: 400px; height: 280px;">
|
|
204
|
+
<CoarListbox
|
|
205
|
+
:options="rows"
|
|
206
|
+
:item-components="{ tag: TagRow }"
|
|
207
|
+
label="Keywords"
|
|
208
|
+
show-count
|
|
209
|
+
@item-remove="remove"
|
|
210
|
+
@item-action="onAction"
|
|
211
|
+
/>
|
|
212
|
+
<p style="margin-top: 8px; font-size: 13px; color: #64748b;">
|
|
213
|
+
Last action: {{ lastAction || '—' }}
|
|
214
|
+
</p>
|
|
215
|
+
</div>
|
|
216
|
+
</template>
|
|
217
|
+
|
|
218
|
+
<script setup lang="ts">
|
|
219
|
+
import { ref } from 'vue';
|
|
220
|
+
import { CoarListbox } from '@cocoar/vue-ui';
|
|
221
|
+
import type { CoarListboxOption } from '@cocoar/vue-ui';
|
|
222
|
+
import TagRow from './TagRow.vue';
|
|
223
|
+
|
|
224
|
+
const rows = ref<CoarListboxOption<string>[]>([
|
|
225
|
+
{ value: 'vue', label: 'vue', kind: 'tag' },
|
|
226
|
+
{ value: 'typescript', label: 'typescript', kind: 'tag' },
|
|
227
|
+
{ value: 'design-system', label: 'design-system', kind: 'tag' },
|
|
228
|
+
{ value: 'dnd', label: 'drag-and-drop', kind: 'tag' },
|
|
229
|
+
]);
|
|
230
|
+
|
|
231
|
+
const lastAction = ref('');
|
|
232
|
+
|
|
233
|
+
function remove(p: { item: CoarListboxOption<string> }) {
|
|
234
|
+
rows.value = rows.value.filter((r) => r.value !== p.item.value);
|
|
235
|
+
lastAction.value = `removed ${p.item.label}`;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function onAction(p: { item: CoarListboxOption<string>; name: string }) {
|
|
239
|
+
lastAction.value = `${p.name} on ${p.item.label}`;
|
|
240
|
+
}
|
|
241
|
+
</script>
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
The listbox emits the resulting event — `item-remove` or `item-action` with the name + payload — so the parent stays in charge of the data:
|
|
245
|
+
|
|
246
|
+
```ts
|
|
247
|
+
interface CoarListboxItemApi<T> {
|
|
248
|
+
item: CoarListboxOption<T>
|
|
249
|
+
highlighted: boolean
|
|
250
|
+
highlight(): void
|
|
251
|
+
unhighlight(): void
|
|
252
|
+
toggleHighlight(): void
|
|
253
|
+
activate(): void // emits `item-activate`
|
|
254
|
+
remove(): void // emits `item-remove` → parent updates `options`
|
|
255
|
+
action(name: string, payload?: unknown): void // emits `item-action`
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
Inside custom components:
|
|
260
|
+
|
|
261
|
+
```vue
|
|
262
|
+
<script setup lang="ts">
|
|
263
|
+
import type { CoarListboxOption, CoarListboxItemApi } from '@cocoar/vue-ui'
|
|
264
|
+
defineProps<{
|
|
265
|
+
item: CoarListboxOption<Row>
|
|
266
|
+
api: CoarListboxItemApi<Row>
|
|
267
|
+
}>()
|
|
268
|
+
</script>
|
|
269
|
+
|
|
270
|
+
<template>
|
|
271
|
+
<div class="row">
|
|
272
|
+
<span>{{ item.label }}</span>
|
|
273
|
+
<button @click.stop="api.remove()">×</button>
|
|
274
|
+
</div>
|
|
275
|
+
</template>
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
Use `@click.stop` on inline buttons so the click doesn't also trigger the row's click/highlight handler.
|
|
279
|
+
|
|
280
|
+
## Drag & drop between lists
|
|
281
|
+
|
|
282
|
+
Set `draggable` on lists items can leave, `droppable` on lists items can enter, and a shared `drag-group` name to link them. Use it for any layout — source/destination (one-way) or bidirectional peers (this Kanban-style example uses three lists):
|
|
283
|
+
|
|
284
|
+
**Demo — `listbox/demos/DragDropTwoLists.vue`**
|
|
285
|
+
|
|
286
|
+
```vue
|
|
287
|
+
<template>
|
|
288
|
+
<div style="display: flex; gap: 16px; height: 300px;">
|
|
289
|
+
<CoarListbox
|
|
290
|
+
:options="waiting"
|
|
291
|
+
label="Backlog"
|
|
292
|
+
show-count
|
|
293
|
+
draggable
|
|
294
|
+
droppable
|
|
295
|
+
drag-group="tasks"
|
|
296
|
+
@items-add="receive('waiting', $event)"
|
|
297
|
+
@items-remove="remove('waiting', $event)"
|
|
298
|
+
/>
|
|
299
|
+
<CoarListbox
|
|
300
|
+
:options="doing"
|
|
301
|
+
label="In progress"
|
|
302
|
+
show-count
|
|
303
|
+
draggable
|
|
304
|
+
droppable
|
|
305
|
+
drag-group="tasks"
|
|
306
|
+
@items-add="receive('doing', $event)"
|
|
307
|
+
@items-remove="remove('doing', $event)"
|
|
308
|
+
/>
|
|
309
|
+
<CoarListbox
|
|
310
|
+
:options="done"
|
|
311
|
+
label="Done"
|
|
312
|
+
show-count
|
|
313
|
+
draggable
|
|
314
|
+
droppable
|
|
315
|
+
drag-group="tasks"
|
|
316
|
+
@items-add="receive('done', $event)"
|
|
317
|
+
@items-remove="remove('done', $event)"
|
|
318
|
+
/>
|
|
319
|
+
</div>
|
|
320
|
+
</template>
|
|
321
|
+
|
|
322
|
+
<script setup lang="ts">
|
|
323
|
+
import { ref } from 'vue';
|
|
324
|
+
import { CoarListbox } from '@cocoar/vue-ui';
|
|
325
|
+
import type { CoarListboxOption } from '@cocoar/vue-ui';
|
|
326
|
+
|
|
327
|
+
type Lane = 'waiting' | 'doing' | 'done';
|
|
328
|
+
|
|
329
|
+
const waiting = ref<CoarListboxOption<string>[]>([
|
|
330
|
+
{ value: 't1', label: 'Design migration plan' },
|
|
331
|
+
{ value: 't2', label: 'Spec compare-with API' },
|
|
332
|
+
{ value: 't3', label: 'Audit stale PRs' },
|
|
333
|
+
]);
|
|
334
|
+
const doing = ref<CoarListboxOption<string>[]>([
|
|
335
|
+
{ value: 't4', label: 'Ship script-editor v2' },
|
|
336
|
+
]);
|
|
337
|
+
const done = ref<CoarListboxOption<string>[]>([
|
|
338
|
+
{ value: 't5', label: 'Upgrade to Vue 3.5' },
|
|
339
|
+
]);
|
|
340
|
+
|
|
341
|
+
const laneRef = { waiting, doing, done };
|
|
342
|
+
|
|
343
|
+
function receive(to: Lane, payload: { items: CoarListboxOption<string>[] }) {
|
|
344
|
+
laneRef[to].value = [...laneRef[to].value, ...payload.items];
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
function remove(from: Lane, payload: { items: CoarListboxOption<string>[] }) {
|
|
348
|
+
const toRemove = new Set(payload.items.map((i) => i.value));
|
|
349
|
+
laneRef[from].value = laneRef[from].value.filter((o) => !toRemove.has(o.value));
|
|
350
|
+
}
|
|
351
|
+
</script>
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
- **Events:** the source emits `items-remove`, the target emits `items-add`. The parent updates each list's `options` accordingly. Both fire synchronously on drop — no flicker.
|
|
355
|
+
- **Selection-aware:** if the dragged item is part of the multi-highlight, the whole highlighted set is carried along.
|
|
356
|
+
- **Groups:** lists with different `drag-group` values reject each other's drops. No group at all = self-drops only.
|
|
357
|
+
- For a built-in two-column experience, see [`CoarDualListbox`'s `drag-drop` prop](./dual-listbox.md#drag-drop).
|
|
358
|
+
- The drag logic comes from the [`useDragDrop`](./drag-drop.md) composable — use it directly if you need the same semantics in a custom component that isn't a listbox.
|
|
359
|
+
|
|
360
|
+
### Directional flows
|
|
361
|
+
|
|
362
|
+
When `drag-group` is too coarse — e.g. *box1 can go to box2 or box3, but nothing can return to box1* — each list gets a stable `drag-id` and the targets whitelist sources via `drag-accept`:
|
|
363
|
+
|
|
364
|
+
**Demo — `listbox/demos/DirectionalDnd.vue`**
|
|
365
|
+
|
|
366
|
+
```vue
|
|
367
|
+
<template>
|
|
368
|
+
<div style="display: flex; gap: 16px; height: 280px;">
|
|
369
|
+
<CoarListbox
|
|
370
|
+
:options="backlog"
|
|
371
|
+
label="Backlog"
|
|
372
|
+
show-count
|
|
373
|
+
draggable
|
|
374
|
+
drag-group="tickets"
|
|
375
|
+
drag-id="backlog"
|
|
376
|
+
@items-remove="remove('backlog', $event)"
|
|
377
|
+
/>
|
|
378
|
+
<CoarListbox
|
|
379
|
+
:options="inReview"
|
|
380
|
+
label="In review"
|
|
381
|
+
show-count
|
|
382
|
+
draggable
|
|
383
|
+
droppable
|
|
384
|
+
drag-group="tickets"
|
|
385
|
+
drag-id="review"
|
|
386
|
+
:drag-accept="['backlog']"
|
|
387
|
+
@items-add="receive('inReview', $event)"
|
|
388
|
+
@items-remove="remove('inReview', $event)"
|
|
389
|
+
/>
|
|
390
|
+
<CoarListbox
|
|
391
|
+
:options="done"
|
|
392
|
+
label="Done"
|
|
393
|
+
show-count
|
|
394
|
+
droppable
|
|
395
|
+
drag-group="tickets"
|
|
396
|
+
drag-id="done"
|
|
397
|
+
:drag-accept="['backlog', 'review']"
|
|
398
|
+
@items-add="receive('done', $event)"
|
|
399
|
+
/>
|
|
400
|
+
</div>
|
|
401
|
+
<p style="margin-top: 8px; font-size: 13px; color: #64748b;">
|
|
402
|
+
Backlog → In review, Backlog → Done, In review → Done. No drops back onto Backlog (it's not droppable), and Done is a dead-end (not draggable).
|
|
403
|
+
</p>
|
|
404
|
+
</template>
|
|
405
|
+
|
|
406
|
+
<script setup lang="ts">
|
|
407
|
+
import { ref } from 'vue';
|
|
408
|
+
import { CoarListbox } from '@cocoar/vue-ui';
|
|
409
|
+
import type { CoarListboxOption } from '@cocoar/vue-ui';
|
|
410
|
+
|
|
411
|
+
type Lane = 'backlog' | 'inReview' | 'done';
|
|
412
|
+
|
|
413
|
+
const backlog = ref<CoarListboxOption<string>[]>([
|
|
414
|
+
{ value: 't1', label: 'Spec the drag API' },
|
|
415
|
+
{ value: 't2', label: 'Audit stale PRs' },
|
|
416
|
+
{ value: 't3', label: 'Upgrade Vue minor' },
|
|
417
|
+
]);
|
|
418
|
+
const inReview = ref<CoarListboxOption<string>[]>([
|
|
419
|
+
{ value: 't4', label: 'Tokens v2' },
|
|
420
|
+
]);
|
|
421
|
+
const done = ref<CoarListboxOption<string>[]>([
|
|
422
|
+
{ value: 't5', label: 'Script editor v1' },
|
|
423
|
+
]);
|
|
424
|
+
|
|
425
|
+
const lanes = { backlog, inReview, done };
|
|
426
|
+
|
|
427
|
+
function receive(to: Lane, payload: { items: CoarListboxOption<string>[] }) {
|
|
428
|
+
lanes[to].value = [...lanes[to].value, ...payload.items];
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
function remove(from: Lane, payload: { items: CoarListboxOption<string>[] }) {
|
|
432
|
+
const r = new Set(payload.items.map((i) => i.value));
|
|
433
|
+
lanes[from].value = lanes[from].value.filter((o) => !r.has(o.value));
|
|
434
|
+
}
|
|
435
|
+
</script>
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
```vue
|
|
439
|
+
<CoarListbox drag-id="box1" draggable drag-group="flow" /> <!-- source only -->
|
|
440
|
+
<CoarListbox drag-id="box2" draggable droppable drag-group="flow"
|
|
441
|
+
:drag-accept="['box1']" /> <!-- only box1 → box2 -->
|
|
442
|
+
<CoarListbox drag-id="box3" droppable drag-group="flow"
|
|
443
|
+
:drag-accept="['box1', 'box2']" /> <!-- box1 + box2 → box3, dead-end -->
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
### Per-item validation
|
|
447
|
+
|
|
448
|
+
`can-drag` controls which items can leave the source (applies per-item, also trims the multi-highlight payload). `can-drop` validates incoming drops at runtime — the cursor shows "not allowed" when it refuses:
|
|
449
|
+
|
|
450
|
+
```vue
|
|
451
|
+
<!-- Only users can be dragged; groups stay put. -->
|
|
452
|
+
<CoarListbox :options="principals" draggable :can-drag="p => p.value.kind === 'user'" />
|
|
453
|
+
|
|
454
|
+
<!-- Admin group caps at 5 members, no bulk drops exceeding that. -->
|
|
455
|
+
<CoarListbox
|
|
456
|
+
v-model="admins"
|
|
457
|
+
:options="admins"
|
|
458
|
+
droppable
|
|
459
|
+
:can-drop="p => admins.length + p.items.length <= 5"
|
|
460
|
+
/>
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
## Virtual scrolling
|
|
464
|
+
|
|
465
|
+
For very long lists (thousands of items), enable `virtual` — only the rows in/near the viewport are rendered. Group headings scroll naturally in this mode (they are not sticky; the non-virtual mode keeps sticky headings). Search, keyboard nav, highlight, drag & drop, and custom item components all still work.
|
|
466
|
+
|
|
467
|
+
```vue
|
|
468
|
+
<CoarListbox
|
|
469
|
+
:options="tenThousand"
|
|
470
|
+
virtual
|
|
471
|
+
:item-height="32"
|
|
472
|
+
:group-heading-height="28"
|
|
473
|
+
:overscan="5"
|
|
474
|
+
/>
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
All items must have the same height (`item-height`). Headings can use a different height (`group-heading-height`). For a concrete example with 10k entries see the [DualListbox virtual demo](./dual-listbox.md#virtual-scrolling-large-datasets).
|
|
478
|
+
|
|
479
|
+
Virtual scrolling is built on top of the exported [`useVirtualList`](./virtual-list.md) composable — use it standalone in your own components.
|
|
480
|
+
|
|
481
|
+
## Options Format
|
|
482
|
+
|
|
483
|
+
```ts
|
|
484
|
+
interface CoarListboxOption<T> {
|
|
485
|
+
value: T;
|
|
486
|
+
label: string; // required — used for default rendering, search, a11y
|
|
487
|
+
kind?: string; // drives itemComponents / #item-<kind>
|
|
488
|
+
group?: string;
|
|
489
|
+
icon?: string; // default renderer only
|
|
490
|
+
subtitle?: string; // default renderer only
|
|
491
|
+
tooltip?: string; // native `title` attribute
|
|
492
|
+
disabled?: boolean;
|
|
493
|
+
searchText?: string; // per-item override for default search
|
|
494
|
+
}
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
## Slots
|
|
498
|
+
|
|
499
|
+
| Slot | Scope | Purpose |
|
|
500
|
+
|------|-------|---------|
|
|
501
|
+
| `header` | `{ label, count, total }` | Replace the entire header row |
|
|
502
|
+
| `search` | `{ query, update }` | Replace the search input |
|
|
503
|
+
| `item` | `{ item, highlighted, selectable, side?, api }` | Render every item. `api` exposes `remove()`, `toggleHighlight()`, `activate()`, `action(name, payload?)` |
|
|
504
|
+
| `item-<kind>` | `{ item, highlighted, selectable, side?, api }` | Render items whose `kind` matches |
|
|
505
|
+
| `group-heading` | `{ group, items }` | Replace the group heading |
|
|
506
|
+
| `empty` | — | Replace the empty state |
|
|
507
|
+
| `footer` | — | Add a footer below the list |
|
|
508
|
+
|
|
509
|
+
## API
|
|
510
|
+
|
|
511
|
+
### Props
|
|
512
|
+
|
|
513
|
+
| Prop | Type | Default | Description |
|
|
514
|
+
|------|------|---------|-------------|
|
|
515
|
+
| `v-model` | `T[]` | `[]` | Currently highlighted values |
|
|
516
|
+
| `options` | `CoarListboxOption<T>[]` | `[]` | Items to display |
|
|
517
|
+
| `label` | `string` | `''` | Header label |
|
|
518
|
+
| `showCount` | `boolean` | `false` | Show a count badge in the header |
|
|
519
|
+
| `showHeader` | `boolean` | *auto* | Override header visibility |
|
|
520
|
+
| `height` | `string` | *flex* | Fixed list height (e.g. `'280px'`); otherwise the list fills its parent |
|
|
521
|
+
| `displayOnly` | `boolean` | `false` | Disable click/keyboard interaction — render a static list. Downgrades ARIA role to `list` |
|
|
522
|
+
| `disabled` | `boolean` | `false` | Dim and ignore input |
|
|
523
|
+
| `readonly` | `boolean` | `false` | Keep appearance but ignore input |
|
|
524
|
+
| `searchable` | `boolean` | `false` | Render a search input above the list |
|
|
525
|
+
| `searchPlaceholder` | `string` | `'Search…'` | Search input placeholder |
|
|
526
|
+
| `searchFields` | `('label' \| 'subtitle' \| 'group')[]` | `['label']` | Fields searched by default |
|
|
527
|
+
| `searchBy` | `(item) => string` | — | Override the searchable text per item |
|
|
528
|
+
| `filterWith` | `(item, query) => boolean` | — | Full control over matching |
|
|
529
|
+
| `sortGroups` | `'asc' \| 'desc' \| 'none' \| (a,b) => number` | `'asc'` | Group order |
|
|
530
|
+
| `sortOptions` | `'asc' \| 'desc' \| 'none' \| (a,b) => number` | `'none'` | Item order |
|
|
531
|
+
| `hideGroupHeadings` | `boolean` | `false` | Omit group labels even when items have a `group` |
|
|
532
|
+
| `itemComponents` | `Record<string, Component>` | `{}` | Map of `kind` → renderer component |
|
|
533
|
+
| `kindBy` | `(item) => string` | `(i) => i.kind ?? ''` | Derive kind from a custom field |
|
|
534
|
+
| `compareWith` | `(a: T, b: T) => boolean` | `===` | Equality for values |
|
|
535
|
+
| `emptyText` | `string` | `'No items'` | Fallback empty state text |
|
|
536
|
+
| `draggable` | `boolean` | `false` | Allow items to be dragged out of this list |
|
|
537
|
+
| `droppable` | `boolean` | `false` | Accept drops from compatible listboxes |
|
|
538
|
+
| `dragEngine` | `'native' \| 'pointer' \| 'auto'` | `'native'` | HTML5 drag events, or Pointer Events for touch — see [Drag & Drop → Engines](./drag-drop.md#engines) |
|
|
539
|
+
| `dragGroup` | `string` | — | Shared name linking lists that can exchange items |
|
|
540
|
+
| `dragId` | `string` | auto | Stable identifier — pair with other lists' `dragAccept` for directional flow |
|
|
541
|
+
| `dragAccept` | `string[]` | — | Whitelist of source `dragId`s this list accepts. Unset = accept any source in the same `dragGroup`; empty array = accept nothing |
|
|
542
|
+
| `canDrag` | `(item) => boolean` | — | Per-item source permission. Items returning `false` are not draggable |
|
|
543
|
+
| `canDrop` | `(payload) => boolean` | — | Runtime drop validation; `payload` is `{ items, fromId, fromGroup, fromSelf }` |
|
|
544
|
+
| `virtual` | `boolean` | `false` | Enable virtual scrolling — only rows in/near the viewport are rendered |
|
|
545
|
+
| `itemHeight` | `number` | `32` | Row height in pixels (used only when `virtual` is on) |
|
|
546
|
+
| `groupHeadingHeight` | `number` | `28` | Heading height when `virtual` is on |
|
|
547
|
+
| `overscan` | `number` | `5` | Extra rows rendered above/below the viewport |
|
|
548
|
+
|
|
549
|
+
### Events
|
|
550
|
+
|
|
551
|
+
| Event | Payload | When |
|
|
552
|
+
|-------|---------|------|
|
|
553
|
+
| `update:modelValue` | `T[]` | Highlight changed |
|
|
554
|
+
| `item-click` | `{ item, event }` | Single click on an item |
|
|
555
|
+
| `item-dblclick` | `{ item, event }` | Double click on an item |
|
|
556
|
+
| `item-activate` | `{ item }` | Double-click or `Enter` on a highlighted item — idiomatic "move this / open this" hook |
|
|
557
|
+
| `item-remove` | `{ item }` | A custom renderer called `api.remove()` — parent should drop the item from `options` |
|
|
558
|
+
| `item-action` | `{ item, name, payload? }` | A custom renderer called `api.action(name, payload?)` — escape hatch for any custom inline operation |
|
|
559
|
+
| `drag-start` | `{ items }` | Drag has started on this list. `items` includes the whole highlighted set when the grabbed item was part of it, else just the one item |
|
|
560
|
+
| `drag-end` | `{ items, dropped }` | Drag ended — `dropped: true` if a target consumed it |
|
|
561
|
+
| `items-add` | `{ items, insertIndex, fromGroup, fromSelf }` | Drop accepted here. Parent should add `items` to its source of truth. `insertIndex` is the position of the item dropped on (or `null` if dropped in empty space) |
|
|
562
|
+
| `items-remove` | `{ items, toGroup }` | The dragged items were consumed by a target. Parent should remove them from this list's source of truth |
|
|
563
|
+
|
|
564
|
+
### Exposed methods
|
|
565
|
+
|
|
566
|
+
Accessible via template ref:
|
|
567
|
+
|
|
568
|
+
```ts
|
|
569
|
+
const box = useTemplateRef<CoarListboxExposed<string>>('box')
|
|
570
|
+
box.value?.clearHighlight()
|
|
571
|
+
box.value?.highlightAll()
|
|
572
|
+
box.value?.focus()
|
|
573
|
+
box.value?.clearSearch()
|
|
574
|
+
box.value?.visibleItems // current filtered + sorted items
|
|
575
|
+
```
|