@mozaic-ds/web-components 1.6.0 → 1.7.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/dist/Condition20.js +1 -1
- package/dist/attributes.js +1 -1
- package/dist/branches.js +1 -1
- package/dist/branches.js.map +1 -1
- package/dist/bundle.d.ts +2 -0
- package/dist/bundle.d.ts.map +1 -1
- package/dist/bundle.js +2 -0
- package/dist/components/accordionlist/AccordionList.js +2 -2
- package/dist/components/accordionlistItem/AccordionListItem.js +2 -2
- package/dist/components/actionbottombar/ActionBottomBar.js +2 -2
- package/dist/components/actionlistbox/ActionListbox.js +2 -2
- package/dist/components/actionlistbox/ActionListbox.svelte +1 -1
- package/dist/components/actionlistboxitem/ActionListboxItem.js +1 -1
- package/dist/components/avatar/Avatar.js +1 -1
- package/dist/components/breadcrumb/Breadcrumb.js +2 -2
- package/dist/components/builtinmenu/BuiltInMenu.js +2 -2
- package/dist/components/builtinmenuitem/BuiltInMenuItem.js +2 -2
- package/dist/components/button/Button.js +1 -1
- package/dist/components/callout/Callout.js +2 -2
- package/dist/components/carousel/Carousel.js +2 -2
- package/dist/components/checkbox/Checkbox.js +1 -1
- package/dist/components/checkboxgroup/CheckboxGroup.js +1 -1
- package/dist/components/checklistmenu/CheckListMenu.js +1 -1
- package/dist/components/circularprogressbar/CircularProgressbar.js +2 -2
- package/dist/components/combobox/Combobox.js +4 -0
- package/dist/components/combobox/Combobox.js.map +1 -0
- package/dist/components/combobox/Combobox.spec.js +186 -0
- package/dist/components/combobox/Combobox.stories.d.ts +17 -0
- package/dist/components/combobox/Combobox.stories.d.ts.map +1 -0
- package/dist/components/combobox/Combobox.stories.js +126 -0
- package/dist/components/combobox/Combobox.svelte +415 -0
- package/dist/components/combobox/Combobox.svelte.d.ts +99 -0
- package/dist/components/combobox/Combobox.svelte.d.ts.map +1 -0
- package/dist/components/combobox/README.md +38 -0
- package/dist/components/container/Container.js +2 -2
- package/dist/components/datepicker/Datepicker.js +3 -3
- package/dist/components/datepicker/Datepicker.js.map +1 -1
- package/dist/components/datepicker/Datepicker.svelte +2 -1
- package/dist/components/divider/Divider.js +1 -1
- package/dist/components/drawer/Drawer.js +4 -4
- package/dist/components/drawer/Drawer.svelte +2 -1
- package/dist/components/field/Field.js +1 -1
- package/dist/components/fileuploader/FileUploader.js +2 -2
- package/dist/components/fileuploader/FileUploader.js.map +1 -1
- package/dist/components/fileuploader/FileUploader.svelte +1 -4
- package/dist/components/fileuploaderitem/FileUploaderItem.js +3 -3
- package/dist/components/fileuploaderitem/FileUploaderItem.svelte +1 -4
- package/dist/components/flag/Flag.js +2 -2
- package/dist/components/iconbutton/IconButton.js +2 -2
- package/dist/components/kpiitem/KpiItem.js +1 -1
- package/dist/components/linearprogressbarbuffer/LinearProgressbarBuffer.js +2 -2
- package/dist/components/linearprogressbarpercentage/LinearProgressbarPercentage.js +2 -2
- package/dist/components/link/Link.js +1 -1
- package/dist/components/loader/Loader.js +2 -2
- package/dist/components/loadingoverlay/LoadingOverlay.js +2 -2
- package/dist/components/loadingoverlay/LoadingOverlay.svelte +1 -1
- package/dist/components/modal/Modal.js +4 -4
- package/dist/components/modal/Modal.js.map +1 -1
- package/dist/components/modal/Modal.spec.js +3 -1
- package/dist/components/modal/Modal.svelte +9 -3
- package/dist/components/modal/Modal.svelte.d.ts +4 -0
- package/dist/components/modal/Modal.svelte.d.ts.map +1 -1
- package/dist/components/modal/README.md +1 -0
- package/dist/components/navigationindicator/NavigationIndicator.js +2 -2
- package/dist/components/numberbadge/NumberBadge.js +2 -2
- package/dist/components/optionlistbox/OptionListbox.js +23 -0
- package/dist/components/optionlistbox/OptionListbox.js.map +1 -0
- package/dist/components/optionlistbox/OptionListbox.spec.js +350 -0
- package/dist/components/optionlistbox/OptionListbox.svelte +566 -0
- package/dist/components/optionlistbox/OptionListbox.svelte.d.ts +92 -0
- package/dist/components/optionlistbox/OptionListbox.svelte.d.ts.map +1 -0
- package/dist/components/optionlistbox/README.md +38 -0
- package/dist/components/overlay/Overlay.js +2 -2
- package/dist/components/overlay/Overlay.svelte +2 -2
- package/dist/components/pageheader/PageHeader.js +1 -1
- package/dist/components/pagination/Pagination.js +4 -4
- package/dist/components/passwordinput/PasswordInput.js +3 -3
- package/dist/components/passwordinput/PasswordInput.js.map +1 -1
- package/dist/components/passwordinput/PasswordInput.svelte +2 -1
- package/dist/components/phonenumber/PhoneNumber.js +4 -4
- package/dist/components/phonenumber/PhoneNumber.js.map +1 -1
- package/dist/components/phonenumber/PhoneNumber.svelte +3 -2
- package/dist/components/pincode/Pincode.js +2 -2
- package/dist/components/popover/Popover.js +1 -1
- package/dist/components/quantityselector/QuantitySelector.js +2 -2
- package/dist/components/quantityselector/QuantitySelector.svelte +1 -1
- package/dist/components/radio/Radio.js +2 -2
- package/dist/components/radiogroup/RadioGroup.js +2 -2
- package/dist/components/segmentedcontrol/README.md +6 -3
- package/dist/components/segmentedcontrol/SegmentedControl.js +2 -2
- package/dist/components/segmentedcontrol/SegmentedControl.js.map +1 -1
- package/dist/components/segmentedcontrol/SegmentedControl.spec.js +60 -23
- package/dist/components/segmentedcontrol/SegmentedControl.stories.d.ts.map +1 -1
- package/dist/components/segmentedcontrol/SegmentedControl.stories.js +6 -1
- package/dist/components/segmentedcontrol/SegmentedControl.svelte +23 -10
- package/dist/components/segmentedcontrol/SegmentedControl.svelte.d.ts +10 -3
- package/dist/components/segmentedcontrol/SegmentedControl.svelte.d.ts.map +1 -1
- package/dist/components/select/Select.js +1 -1
- package/dist/components/sidebar/Sidebar.js +1 -1
- package/dist/components/sidebarexpandableitem/SidebarExpandableItem.js +2 -2
- package/dist/components/sidebarfooter/SidebarFooter.js +1 -1
- package/dist/components/sidebarfooter/_SidebarFooterMenu.js +2 -2
- package/dist/components/sidebarheader/SidebarHeader.js +1 -1
- package/dist/components/sidebarnavitem/SidebarNavItem.js +2 -2
- package/dist/components/sidebarshortcutitem/SidebarShortcutItem.js +1 -1
- package/dist/components/sidebarshortcuts/SidebarShortcuts.js +2 -2
- package/dist/components/starrating/StarRating.js +2 -2
- package/dist/components/statusbadge/StatusBadge.js +2 -2
- package/dist/components/statusdot/StatusDot.js +2 -2
- package/dist/components/statusmessage/StatusMessage.js +2 -2
- package/dist/components/statusmessage/StatusMessage.js.map +1 -1
- package/dist/components/statusmessage/StatusMessage.svelte +5 -0
- package/dist/components/statusnotification/StatusNotification.js +2 -2
- package/dist/components/statusnotification/StatusNotification.js.map +1 -1
- package/dist/components/statusnotification/StatusNotification.svelte +5 -0
- package/dist/components/stepperbottombar/StepperBottomBar.js +1 -1
- package/dist/components/steppercompact/StepperCompact.js +2 -2
- package/dist/components/stepperinline/README.md +6 -2
- package/dist/components/stepperinline/StepperInline.js +2 -2
- package/dist/components/stepperinline/StepperInline.js.map +1 -1
- package/dist/components/stepperinline/StepperInline.spec.js +57 -23
- package/dist/components/stepperinline/StepperInline.stories.d.ts.map +1 -1
- package/dist/components/stepperinline/StepperInline.stories.js +6 -11
- package/dist/components/stepperinline/StepperInline.svelte +23 -10
- package/dist/components/stepperinline/StepperInline.svelte.d.ts +10 -2
- package/dist/components/stepperinline/StepperInline.svelte.d.ts.map +1 -1
- package/dist/components/stepperstacked/README.md +15 -0
- package/dist/components/stepperstacked/StepperStacked.js +18 -0
- package/dist/components/stepperstacked/StepperStacked.js.map +1 -0
- package/dist/components/stepperstacked/StepperStacked.spec.js +138 -0
- package/dist/components/stepperstacked/StepperStacked.stories.d.ts +8 -0
- package/dist/components/stepperstacked/StepperStacked.stories.d.ts.map +1 -0
- package/dist/components/stepperstacked/StepperStacked.stories.js +33 -0
- package/dist/components/stepperstacked/StepperStacked.svelte +214 -0
- package/dist/components/stepperstacked/StepperStacked.svelte.d.ts +35 -0
- package/dist/components/stepperstacked/StepperStacked.svelte.d.ts.map +1 -0
- package/dist/components/tab/README.md +1 -0
- package/dist/components/tab/Tab.js +2 -2
- package/dist/components/tab/Tab.js.map +1 -1
- package/dist/components/tab/Tab.svelte +17 -1
- package/dist/components/tab/Tab.svelte.d.ts +4 -0
- package/dist/components/tab/Tab.svelte.d.ts.map +1 -1
- package/dist/components/tabs/Tabs.js +1 -1
- package/dist/components/tabs/Tabs.stories.d.ts +1 -0
- package/dist/components/tabs/Tabs.stories.d.ts.map +1 -1
- package/dist/components/tabs/Tabs.stories.js +10 -0
- package/dist/components/tag/README.md +1 -0
- package/dist/components/tag/Tag.js +2 -2
- package/dist/components/tag/Tag.js.map +1 -1
- package/dist/components/tag/Tag.svelte +7 -0
- package/dist/components/tag/Tag.svelte.d.ts +4 -0
- package/dist/components/tag/Tag.svelte.d.ts.map +1 -1
- package/dist/components/textarea/Textarea.js +2 -2
- package/dist/components/textarea/Textarea.js.map +1 -1
- package/dist/components/textarea/Textarea.svelte +1 -0
- package/dist/components/textinput/README.md +1 -0
- package/dist/components/textinput/Textinput.js +4 -4
- package/dist/components/textinput/Textinput.js.map +1 -1
- package/dist/components/textinput/Textinput.stories.d.ts.map +1 -1
- package/dist/components/textinput/Textinput.stories.js +1 -0
- package/dist/components/textinput/Textinput.svelte +5 -1
- package/dist/components/textinput/Textinput.svelte.d.ts +2 -1
- package/dist/components/textinput/Textinput.svelte.d.ts.map +1 -1
- package/dist/components/tile/Tile.js +1 -1
- package/dist/components/tileclickable/TileClickable.js +1 -1
- package/dist/components/tileexpandable/TileExpandable.js +1 -1
- package/dist/components/tileselectable/TileSelectable.js +2 -2
- package/dist/components/toaster/Toaster.js +3 -3
- package/dist/components/toaster/Toaster.js.map +1 -1
- package/dist/components/toaster/Toaster.svelte +6 -1
- package/dist/components/toggle/Toggle.js +1 -1
- package/dist/components/togglegroup/ToggleGroup.js +2 -2
- package/dist/components/tooltip/Tooltip.js +2 -2
- package/dist/custom-element.js +3 -3
- package/dist/custom-element.js.map +1 -1
- package/dist/documentation/DarkMode.mdx +115 -0
- package/dist/each.js +1 -1
- package/dist/each.js.map +1 -1
- package/dist/floating-item.svelte.js +1 -1
- package/dist/if.js +1 -1
- package/dist/if.js.map +1 -1
- package/dist/index-client.js +1 -1
- package/dist/input.js +1 -1
- package/dist/main.d.ts +3 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +3 -1
- package/dist/svelte-component.js +1 -1
- package/dist/svelte-component.js.map +1 -1
- package/dist/svelte-element.js +1 -1
- package/dist/this.js +1 -1
- package/package.json +3 -2
|
@@ -0,0 +1,566 @@
|
|
|
1
|
+
<svelte:options
|
|
2
|
+
customElement={{
|
|
3
|
+
tag: 'm-option-listbox',
|
|
4
|
+
props: {
|
|
5
|
+
open: { reflect: true, type: 'Boolean', attribute: 'open' },
|
|
6
|
+
multiple: { reflect: true, type: 'Boolean', attribute: 'multiple' },
|
|
7
|
+
search: { reflect: true, type: 'Boolean', attribute: 'search' },
|
|
8
|
+
actions: { reflect: true, type: 'Boolean', attribute: 'actions' },
|
|
9
|
+
checkablesections: { reflect: true, type: 'Boolean', attribute: 'checkablesections' },
|
|
10
|
+
},
|
|
11
|
+
}}
|
|
12
|
+
/>
|
|
13
|
+
|
|
14
|
+
<script lang="ts">
|
|
15
|
+
/**
|
|
16
|
+
* An Option Listbox is a customizable, accessible listbox component designed to power dropdowns and comboboxes with advanced value capabilities. It supports single or multiple value, optional search, grouped options with section headers, and full keyboard navigation.
|
|
17
|
+
* @slot optionPrefix - Use this slot to add a prefix to options.
|
|
18
|
+
* @event open {CustomEvent<void>} - Emits when the listbox should open.
|
|
19
|
+
* @event close {CustomEvent<void>} - Emits when the listbox should close.
|
|
20
|
+
*/
|
|
21
|
+
import { Check20, CheckCircleFilled24, Less20, Search24 } from '@mozaic-ds/icons-svelte';
|
|
22
|
+
import { debounce } from 'lodash';
|
|
23
|
+
import Button from '../button/Button.svelte';
|
|
24
|
+
import Textinput from '../textinput/Textinput.svelte';
|
|
25
|
+
import { SvelteMap } from 'svelte/reactivity';
|
|
26
|
+
|
|
27
|
+
export type ListboxOption = {
|
|
28
|
+
label: string;
|
|
29
|
+
content?: string;
|
|
30
|
+
value?: string | number;
|
|
31
|
+
disabled?: boolean;
|
|
32
|
+
type?: 'option' | 'section';
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
interface Props {
|
|
36
|
+
/**
|
|
37
|
+
* The current selected value(s) of the listbox.
|
|
38
|
+
*/
|
|
39
|
+
value: string | number | null | (string | number)[];
|
|
40
|
+
/**
|
|
41
|
+
* Unique identifier for the listbox.
|
|
42
|
+
*/
|
|
43
|
+
id: string;
|
|
44
|
+
/**
|
|
45
|
+
* Whether the listbox is open.
|
|
46
|
+
*/
|
|
47
|
+
open?: boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Enable multiple value.
|
|
50
|
+
*/
|
|
51
|
+
multiple?: boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Make the listbox read-only.
|
|
54
|
+
*/
|
|
55
|
+
readonly?: boolean;
|
|
56
|
+
/**
|
|
57
|
+
* Show a search input above the options.
|
|
58
|
+
*/
|
|
59
|
+
search?: boolean;
|
|
60
|
+
/**
|
|
61
|
+
* Show select all / clear buttons when multiple.
|
|
62
|
+
*/
|
|
63
|
+
actions?: boolean;
|
|
64
|
+
/**
|
|
65
|
+
* Enable checkable section headers.
|
|
66
|
+
*/
|
|
67
|
+
checkablesections?: boolean;
|
|
68
|
+
/**
|
|
69
|
+
* Placeholder text for the search input.
|
|
70
|
+
*/
|
|
71
|
+
searchplaceholder?: string;
|
|
72
|
+
/**
|
|
73
|
+
* Label for the "Select all" button.
|
|
74
|
+
*/
|
|
75
|
+
selectlabel?: string;
|
|
76
|
+
/**
|
|
77
|
+
* Label for the "Clear value" button.
|
|
78
|
+
*/
|
|
79
|
+
clearlabel?: string;
|
|
80
|
+
/**
|
|
81
|
+
* Array of options and sections to display in the listbox.
|
|
82
|
+
*/
|
|
83
|
+
options: Array<ListboxOption>;
|
|
84
|
+
/**
|
|
85
|
+
* Callback to trigge when the listbox should open.
|
|
86
|
+
*/
|
|
87
|
+
onopen?: () => void;
|
|
88
|
+
/**
|
|
89
|
+
* Callback to trigge when the listbox should close.
|
|
90
|
+
*/
|
|
91
|
+
onclose?: () => void;
|
|
92
|
+
activeindex: number;
|
|
93
|
+
element?: HTMLElement | null;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
let {
|
|
97
|
+
value = $bindable(),
|
|
98
|
+
id,
|
|
99
|
+
open = $bindable(),
|
|
100
|
+
multiple,
|
|
101
|
+
readonly,
|
|
102
|
+
search,
|
|
103
|
+
actions,
|
|
104
|
+
checkablesections,
|
|
105
|
+
searchplaceholder = 'Find an option...',
|
|
106
|
+
selectlabel = 'Select all',
|
|
107
|
+
clearlabel = 'Clear',
|
|
108
|
+
options,
|
|
109
|
+
onopen,
|
|
110
|
+
onclose,
|
|
111
|
+
activeindex = $bindable(),
|
|
112
|
+
element = $bindable(),
|
|
113
|
+
}: Props = $props();
|
|
114
|
+
|
|
115
|
+
let textInput: HTMLElement | null = $state(null);
|
|
116
|
+
|
|
117
|
+
let searchText = $state('');
|
|
118
|
+
|
|
119
|
+
let filteredResults = $state<ListboxOption[]>(options);
|
|
120
|
+
|
|
121
|
+
const activeDescendantId = $derived.by(() => {
|
|
122
|
+
return activeindex >= 0 ? `option-${id}-${activeindex}` : undefined;
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
const updateFilteredResults = debounce(() => {
|
|
126
|
+
const search = searchText.toLowerCase().trim();
|
|
127
|
+
if (!search) {
|
|
128
|
+
filteredResults = options;
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
filteredResults = options.filter((option) => option.label.toLowerCase().includes(search));
|
|
133
|
+
|
|
134
|
+
activeindex = filteredResults.length ? 0 : -1;
|
|
135
|
+
}, 200);
|
|
136
|
+
|
|
137
|
+
const sectionMap = $derived.by(() => {
|
|
138
|
+
const map = new SvelteMap<string, ListboxOption[]>();
|
|
139
|
+
let currentSection: ListboxOption | null = null;
|
|
140
|
+
|
|
141
|
+
options.forEach((option) => {
|
|
142
|
+
if (option.type === 'section') {
|
|
143
|
+
currentSection = option;
|
|
144
|
+
map.set(currentSection?.value?.toString() || currentSection.label, []);
|
|
145
|
+
} else if (currentSection) {
|
|
146
|
+
map.get(currentSection?.value?.toString() || currentSection.label)!.push(option);
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
return map;
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
function toggleSection(item: ListboxOption) {
|
|
154
|
+
if (!checkablesections || !multiple) return;
|
|
155
|
+
|
|
156
|
+
const sectionItems = sectionMap.get(item.value?.toString() || item.label) || [];
|
|
157
|
+
const selectedItems = value as (string | number)[];
|
|
158
|
+
|
|
159
|
+
if (isSectionSelected(item)) {
|
|
160
|
+
value = selectedItems.filter((opt) => !sectionItems.find((item) => item.value === opt));
|
|
161
|
+
} else {
|
|
162
|
+
value = [
|
|
163
|
+
...selectedItems,
|
|
164
|
+
...sectionItems
|
|
165
|
+
.filter((opt) => !selectedItems.includes(opt.value!))
|
|
166
|
+
.map((item) => item.value!),
|
|
167
|
+
];
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export function toggleValue(item?: ListboxOption) {
|
|
172
|
+
if (!item || !isSelectable(item)) return;
|
|
173
|
+
|
|
174
|
+
if (Array.isArray(value)) {
|
|
175
|
+
if (isOptionSelected(item)) {
|
|
176
|
+
value = (value as (string | number)[]).filter((el) => el !== item.value);
|
|
177
|
+
} else {
|
|
178
|
+
value = [...value, item.value!];
|
|
179
|
+
}
|
|
180
|
+
} else {
|
|
181
|
+
value = isOptionSelected(item) ? null : item.value!;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function selectAll() {
|
|
186
|
+
value = [
|
|
187
|
+
...options
|
|
188
|
+
.filter((option) => !!option.value && !option.disabled && option.type !== 'section')
|
|
189
|
+
.map((item) => item.value!),
|
|
190
|
+
];
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export function clearSelection() {
|
|
194
|
+
if (Array.isArray(value)) {
|
|
195
|
+
value = [];
|
|
196
|
+
} else {
|
|
197
|
+
value = null;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function isSelectable(item: ListboxOption) {
|
|
202
|
+
return (
|
|
203
|
+
(item.type !== 'section' && !item.disabled) ||
|
|
204
|
+
(item.type === 'section' && checkablesections && multiple)
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function isSectionSelected(item: ListboxOption) {
|
|
209
|
+
if (!checkablesections || !multiple) return false;
|
|
210
|
+
|
|
211
|
+
const sectionItems = sectionMap.get(item.value?.toString() || item.label) || [];
|
|
212
|
+
const selectedItems = value as (string | number)[];
|
|
213
|
+
|
|
214
|
+
return sectionItems.every((opt) => selectedItems.includes(opt.value!));
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function isOptionSelected(item: ListboxOption) {
|
|
218
|
+
if (!item.value) return false;
|
|
219
|
+
|
|
220
|
+
if (Array.isArray(value)) {
|
|
221
|
+
return (value as (string | number)[])?.includes(item.value!);
|
|
222
|
+
} else {
|
|
223
|
+
return item.value === value;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function isIndeterminate(item: ListboxOption) {
|
|
228
|
+
const section = sectionMap.get(item.value?.toString() || item.label);
|
|
229
|
+
return (
|
|
230
|
+
section?.some((option) => isOptionSelected(option)) &&
|
|
231
|
+
!section?.every((option) => isOptionSelected(option))
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function moveActive(delta: number) {
|
|
236
|
+
if (!open || filteredResults.length === 0) return;
|
|
237
|
+
|
|
238
|
+
let nextIndex = activeindex + delta;
|
|
239
|
+
|
|
240
|
+
if (nextIndex < 0) nextIndex = filteredResults.length - 1;
|
|
241
|
+
if (nextIndex >= filteredResults.length) nextIndex = 0;
|
|
242
|
+
|
|
243
|
+
while (!isSelectable(filteredResults[nextIndex])) {
|
|
244
|
+
nextIndex += delta > 0 ? 1 : -1;
|
|
245
|
+
if (nextIndex < 0) nextIndex = filteredResults.length - 1;
|
|
246
|
+
if (nextIndex >= filteredResults.length) nextIndex = 0;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
activeindex = nextIndex;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function selectActive() {
|
|
253
|
+
const item = filteredResults[activeindex];
|
|
254
|
+
if (!item || !isSelectable(item)) return;
|
|
255
|
+
|
|
256
|
+
if (item.type === 'section') {
|
|
257
|
+
toggleSection(item);
|
|
258
|
+
} else {
|
|
259
|
+
toggleValue(item);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
function handleOpen() {
|
|
264
|
+
onopen?.();
|
|
265
|
+
element?.dispatchEvent(new CustomEvent('open', { bubbles: true, composed: true }));
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
function handleClose() {
|
|
269
|
+
onclose?.();
|
|
270
|
+
element?.dispatchEvent(new CustomEvent('close', { bubbles: true, composed: true }));
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
export function handleKeydown(event: KeyboardEvent) {
|
|
274
|
+
switch (event.key) {
|
|
275
|
+
case 'ArrowDown':
|
|
276
|
+
event.preventDefault();
|
|
277
|
+
if (!open) {
|
|
278
|
+
handleOpen();
|
|
279
|
+
activeindex = 0;
|
|
280
|
+
} else {
|
|
281
|
+
moveActive(1);
|
|
282
|
+
}
|
|
283
|
+
break;
|
|
284
|
+
case 'ArrowUp':
|
|
285
|
+
event.preventDefault();
|
|
286
|
+
if (!open) {
|
|
287
|
+
handleOpen();
|
|
288
|
+
activeindex = filteredResults.length - 1;
|
|
289
|
+
} else {
|
|
290
|
+
moveActive(-1);
|
|
291
|
+
}
|
|
292
|
+
break;
|
|
293
|
+
case 'Enter':
|
|
294
|
+
event.preventDefault();
|
|
295
|
+
if (!open) {
|
|
296
|
+
handleOpen();
|
|
297
|
+
activeindex = 0;
|
|
298
|
+
}
|
|
299
|
+
selectActive();
|
|
300
|
+
break;
|
|
301
|
+
case 'Escape':
|
|
302
|
+
event.preventDefault();
|
|
303
|
+
handleClose();
|
|
304
|
+
break;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
$effect(() => {
|
|
309
|
+
if (open) {
|
|
310
|
+
setTimeout(() => {
|
|
311
|
+
textInput?.focus();
|
|
312
|
+
}, 50);
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
</script>
|
|
316
|
+
|
|
317
|
+
<div bind:this={element} class="mc-option-listbox mc-listbox__content mc-combobox__listbox">
|
|
318
|
+
{#if search}
|
|
319
|
+
<div class="mc-option-listbox__search">
|
|
320
|
+
<Textinput
|
|
321
|
+
bind:element={textInput}
|
|
322
|
+
bind:value={searchText}
|
|
323
|
+
role="combobox"
|
|
324
|
+
id={`search-${id}`}
|
|
325
|
+
size="s"
|
|
326
|
+
placeholder={searchplaceholder}
|
|
327
|
+
autocomplete="off"
|
|
328
|
+
aria-expanded={open}
|
|
329
|
+
aria-controls={`listbox-${id}`}
|
|
330
|
+
aria-autocomplete="list"
|
|
331
|
+
aria-activedescendant={activeDescendantId}
|
|
332
|
+
oninput={updateFilteredResults}
|
|
333
|
+
onkeydown={handleKeydown}
|
|
334
|
+
>
|
|
335
|
+
<Search24 slot="icon" />
|
|
336
|
+
</Textinput>
|
|
337
|
+
</div>
|
|
338
|
+
|
|
339
|
+
<hr class="mc-option-listbox__separator" />
|
|
340
|
+
{/if}
|
|
341
|
+
|
|
342
|
+
{#if multiple && actions}
|
|
343
|
+
<div class="mc-option-listbox__actions">
|
|
344
|
+
<Button appearance="accent" ghost size="s" onclick={selectAll}>
|
|
345
|
+
{selectlabel}
|
|
346
|
+
</Button>
|
|
347
|
+
<Button appearance="standard" ghost size="s" onclick={clearSelection}>
|
|
348
|
+
{clearlabel}
|
|
349
|
+
</Button>
|
|
350
|
+
</div>
|
|
351
|
+
<hr class="mc-option-listbox__separator" />
|
|
352
|
+
{/if}
|
|
353
|
+
|
|
354
|
+
<ul
|
|
355
|
+
class="mc-option-listbox__list"
|
|
356
|
+
role="listbox"
|
|
357
|
+
id={`listbox-${id}`}
|
|
358
|
+
tabindex={-1}
|
|
359
|
+
aria-label="Suggestions"
|
|
360
|
+
aria-multiselectable={multiple}
|
|
361
|
+
>
|
|
362
|
+
{#each filteredResults as item, index (index)}
|
|
363
|
+
<li
|
|
364
|
+
id={`option-${id}-${index}`}
|
|
365
|
+
class={{
|
|
366
|
+
'mc-option-listbox__item': true,
|
|
367
|
+
'mc-option-listbox__item--section': item.type === 'section',
|
|
368
|
+
'mc-option-listbox__item--readonly': readonly,
|
|
369
|
+
'mc-option-listbox__item--disabled': item.disabled,
|
|
370
|
+
'mc-option-listbox__item--selectable': isSelectable(item),
|
|
371
|
+
'mc-option-listbox__item--active': activeindex === index,
|
|
372
|
+
'mc-option-listbox__item--selected':
|
|
373
|
+
item.type === 'section'
|
|
374
|
+
? isSectionSelected(item) || isIndeterminate(item)
|
|
375
|
+
: isOptionSelected(item),
|
|
376
|
+
}}
|
|
377
|
+
{...item.type === 'section' && !checkablesections
|
|
378
|
+
? {
|
|
379
|
+
role: 'presentation',
|
|
380
|
+
}
|
|
381
|
+
: {
|
|
382
|
+
role: 'option',
|
|
383
|
+
['aria-disabled']: item.disabled,
|
|
384
|
+
['aria-selected']: isOptionSelected(item),
|
|
385
|
+
onclick: () => (item.type === 'section' ? toggleSection(item) : toggleValue(item)),
|
|
386
|
+
}}
|
|
387
|
+
>
|
|
388
|
+
<div class="mc-option-listbox__label">
|
|
389
|
+
{#if item.type !== 'section'}
|
|
390
|
+
<slot name="optionPrefix" />
|
|
391
|
+
{/if}
|
|
392
|
+
|
|
393
|
+
<div class="mc-option-listbox__content">
|
|
394
|
+
<span
|
|
395
|
+
class={item.type === 'section'
|
|
396
|
+
? 'mc-option-listbox__section-title'
|
|
397
|
+
: 'mc-option-listbox__text'}
|
|
398
|
+
>
|
|
399
|
+
{item.label}
|
|
400
|
+
</span>
|
|
401
|
+
|
|
402
|
+
{#if item.content}
|
|
403
|
+
<span class="mc-option-listbox__additional">
|
|
404
|
+
{item.content}
|
|
405
|
+
</span>
|
|
406
|
+
{/if}
|
|
407
|
+
</div>
|
|
408
|
+
|
|
409
|
+
<div class="mc-option-listbox__spacer"></div>
|
|
410
|
+
|
|
411
|
+
{#if isSelectable(item)}
|
|
412
|
+
{#if item.type === 'section'}
|
|
413
|
+
<span class="mc-option-listbox__checkbox">
|
|
414
|
+
{#if isSectionSelected(item) || isIndeterminate(item)}
|
|
415
|
+
{@const Icon = isIndeterminate(item) ? Less20 : Check20}
|
|
416
|
+
<Icon />
|
|
417
|
+
{/if}
|
|
418
|
+
</span>
|
|
419
|
+
{:else if multiple}
|
|
420
|
+
<span class="mc-option-listbox__checkbox">
|
|
421
|
+
{#if isOptionSelected(item)}
|
|
422
|
+
<Check20 />
|
|
423
|
+
{/if}
|
|
424
|
+
</span>
|
|
425
|
+
{:else}
|
|
426
|
+
<span class="mc-option-listbox__selection-icon">
|
|
427
|
+
<CheckCircleFilled24 />
|
|
428
|
+
</span>
|
|
429
|
+
{/if}
|
|
430
|
+
{/if}
|
|
431
|
+
</div>
|
|
432
|
+
</li>
|
|
433
|
+
{/each}
|
|
434
|
+
</ul>
|
|
435
|
+
</div>
|
|
436
|
+
|
|
437
|
+
<style>/**
|
|
438
|
+
* Do not edit directly, this file was auto-generated.
|
|
439
|
+
*/
|
|
440
|
+
.mc-option-listbox__list {
|
|
441
|
+
overflow: auto;
|
|
442
|
+
display: flex;
|
|
443
|
+
flex-direction: column;
|
|
444
|
+
gap: 0.125rem;
|
|
445
|
+
margin: 0;
|
|
446
|
+
padding: 0.5rem;
|
|
447
|
+
max-height: 18.75rem;
|
|
448
|
+
}
|
|
449
|
+
.mc-option-listbox__item {
|
|
450
|
+
display: block;
|
|
451
|
+
border-radius: var(--border-radius-s, 0.25rem);
|
|
452
|
+
}
|
|
453
|
+
.mc-option-listbox__item--disabled {
|
|
454
|
+
color: var(--option-listbox-color-text-disabled, #b3b3b3);
|
|
455
|
+
}
|
|
456
|
+
.mc-option-listbox__item--disabled .mc-option-listbox__label {
|
|
457
|
+
pointer-events: none;
|
|
458
|
+
color: var(--option-listbox-color-text-disabled, #b3b3b3);
|
|
459
|
+
}
|
|
460
|
+
.mc-option-listbox__item--disabled .mc-option-listbox__additional {
|
|
461
|
+
color: var(--option-listbox-color-text-disabled, #b3b3b3);
|
|
462
|
+
}
|
|
463
|
+
.mc-option-listbox__item--disabled .mc-option-listbox__checkbox {
|
|
464
|
+
border: none;
|
|
465
|
+
background-color: var(--forms-color-background-disabled, #d9d9d9);
|
|
466
|
+
}
|
|
467
|
+
.mc-option-listbox__item--readonly .mc-option-listbox__label {
|
|
468
|
+
pointer-events: none;
|
|
469
|
+
}
|
|
470
|
+
.mc-option-listbox__item--selected:not(.mc-option-listbox__item--section) {
|
|
471
|
+
background-color: var(--option-listbox-color-background-checked, #ebf5de);
|
|
472
|
+
}
|
|
473
|
+
.mc-option-listbox__item--selected .mc-option-listbox__selection-icon {
|
|
474
|
+
opacity: 1;
|
|
475
|
+
color: var(--option-listbox-color-selection-indicator-default, #117f03);
|
|
476
|
+
fill: currentcolor;
|
|
477
|
+
}
|
|
478
|
+
.mc-option-listbox__item--selected .mc-option-listbox__checkbox {
|
|
479
|
+
border: none;
|
|
480
|
+
background-color: var(--forms-color-background-checked, #117f03);
|
|
481
|
+
color: var(--forms-color-icon-inverse, #ffffff);
|
|
482
|
+
fill: currentcolor;
|
|
483
|
+
}
|
|
484
|
+
.mc-option-listbox__item--selected .mc-option-listbox__checkbox svg {
|
|
485
|
+
display: block;
|
|
486
|
+
}
|
|
487
|
+
.mc-option-listbox__item--readonly.mc-option-listbox__item--selected {
|
|
488
|
+
background-color: var(--option-listbox-color-background-checked-read-only, #eff1f6);
|
|
489
|
+
}
|
|
490
|
+
.mc-option-listbox__item--readonly.mc-option-listbox__item--selected .mc-option-listbox__selection-icon {
|
|
491
|
+
color: var(--option-listbox-color-selection-indicator-read-only, #000000);
|
|
492
|
+
}
|
|
493
|
+
.mc-option-listbox__item--readonly.mc-option-listbox__item--selected .mc-option-listbox__checkbox {
|
|
494
|
+
border: 2px solid var(--forms-color-border-read-only, #cccccc);
|
|
495
|
+
background-color: var(--forms-color-background-default, #ffffff);
|
|
496
|
+
color: var(--option-listbox-color-selection-indicator-read-only, #000000);
|
|
497
|
+
}
|
|
498
|
+
.mc-option-listbox__item--selectable {
|
|
499
|
+
cursor: pointer;
|
|
500
|
+
}
|
|
501
|
+
.mc-option-listbox__item--selectable:not(.mc-option-listbox__item--disabled):hover, .mc-option-listbox__item--selectable:not(.mc-option-listbox__item--disabled).mc-option-listbox__item--active {
|
|
502
|
+
background-color: var(--option-listbox-color-background-hover, rgba(0, 0, 0, 0.05));
|
|
503
|
+
}
|
|
504
|
+
.mc-option-listbox__content {
|
|
505
|
+
display: flex;
|
|
506
|
+
flex-direction: column;
|
|
507
|
+
gap: 0.125rem;
|
|
508
|
+
}
|
|
509
|
+
.mc-option-listbox__additional {
|
|
510
|
+
font-weight: var(--font-weight-regular, 400);
|
|
511
|
+
font-size: var(--font-size-50, 0.75rem);
|
|
512
|
+
color: var(--option-listbox-color-text-information, #666666);
|
|
513
|
+
}
|
|
514
|
+
.mc-option-listbox__label {
|
|
515
|
+
display: flex;
|
|
516
|
+
align-items: center;
|
|
517
|
+
gap: 0.5rem;
|
|
518
|
+
height: 3rem;
|
|
519
|
+
padding: 0.5rem;
|
|
520
|
+
border-radius: var(--border-radius-s, 0.25rem);
|
|
521
|
+
line-height: var(--line-height-s, 1.3);
|
|
522
|
+
box-sizing: border-box;
|
|
523
|
+
}
|
|
524
|
+
.mc-option-listbox__checkbox {
|
|
525
|
+
display: flex;
|
|
526
|
+
align-items: center;
|
|
527
|
+
justify-content: center;
|
|
528
|
+
height: 1.25rem;
|
|
529
|
+
width: 1.25rem;
|
|
530
|
+
border: 0.125rem solid var(--forms-color-border-default, #666666);
|
|
531
|
+
border-radius: 0.25rem;
|
|
532
|
+
box-sizing: border-box;
|
|
533
|
+
}
|
|
534
|
+
.mc-option-listbox__checkbox svg {
|
|
535
|
+
display: none;
|
|
536
|
+
}
|
|
537
|
+
.mc-option-listbox__spacer {
|
|
538
|
+
flex-grow: 1;
|
|
539
|
+
}
|
|
540
|
+
.mc-option-listbox__selection-icon {
|
|
541
|
+
opacity: 0;
|
|
542
|
+
}
|
|
543
|
+
.mc-option-listbox__section-title {
|
|
544
|
+
font-size: var(--font-size-100, 0.875rem);
|
|
545
|
+
font-weight: var(--font-weight-semi-bold, 600);
|
|
546
|
+
margin: 0;
|
|
547
|
+
color: var(--option-listbox-color-text-section-title, #666666);
|
|
548
|
+
}
|
|
549
|
+
.mc-option-listbox__search {
|
|
550
|
+
margin: 0.5rem;
|
|
551
|
+
width: unset;
|
|
552
|
+
}
|
|
553
|
+
.mc-option-listbox__separator {
|
|
554
|
+
display: block;
|
|
555
|
+
height: 1px;
|
|
556
|
+
border: 0;
|
|
557
|
+
border-top: 1px solid var(--color-border-primary, #cccccc);
|
|
558
|
+
margin: 0;
|
|
559
|
+
padding: 0;
|
|
560
|
+
}
|
|
561
|
+
.mc-option-listbox__actions {
|
|
562
|
+
display: flex;
|
|
563
|
+
align-items: center;
|
|
564
|
+
justify-content: space-between;
|
|
565
|
+
padding: 0.5rem 1rem;
|
|
566
|
+
}</style>
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
export type ListboxOption = {
|
|
2
|
+
label: string;
|
|
3
|
+
content?: string;
|
|
4
|
+
value?: string | number;
|
|
5
|
+
disabled?: boolean;
|
|
6
|
+
type?: 'option' | 'section';
|
|
7
|
+
};
|
|
8
|
+
interface Props {
|
|
9
|
+
/**
|
|
10
|
+
* The current selected value(s) of the listbox.
|
|
11
|
+
*/
|
|
12
|
+
value: string | number | null | (string | number)[];
|
|
13
|
+
/**
|
|
14
|
+
* Unique identifier for the listbox.
|
|
15
|
+
*/
|
|
16
|
+
id: string;
|
|
17
|
+
/**
|
|
18
|
+
* Whether the listbox is open.
|
|
19
|
+
*/
|
|
20
|
+
open?: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Enable multiple value.
|
|
23
|
+
*/
|
|
24
|
+
multiple?: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Make the listbox read-only.
|
|
27
|
+
*/
|
|
28
|
+
readonly?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Show a search input above the options.
|
|
31
|
+
*/
|
|
32
|
+
search?: boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Show select all / clear buttons when multiple.
|
|
35
|
+
*/
|
|
36
|
+
actions?: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Enable checkable section headers.
|
|
39
|
+
*/
|
|
40
|
+
checkablesections?: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Placeholder text for the search input.
|
|
43
|
+
*/
|
|
44
|
+
searchplaceholder?: string;
|
|
45
|
+
/**
|
|
46
|
+
* Label for the "Select all" button.
|
|
47
|
+
*/
|
|
48
|
+
selectlabel?: string;
|
|
49
|
+
/**
|
|
50
|
+
* Label for the "Clear value" button.
|
|
51
|
+
*/
|
|
52
|
+
clearlabel?: string;
|
|
53
|
+
/**
|
|
54
|
+
* Array of options and sections to display in the listbox.
|
|
55
|
+
*/
|
|
56
|
+
options: Array<ListboxOption>;
|
|
57
|
+
/**
|
|
58
|
+
* Callback to trigge when the listbox should open.
|
|
59
|
+
*/
|
|
60
|
+
onopen?: () => void;
|
|
61
|
+
/**
|
|
62
|
+
* Callback to trigge when the listbox should close.
|
|
63
|
+
*/
|
|
64
|
+
onclose?: () => void;
|
|
65
|
+
activeindex: number;
|
|
66
|
+
element?: HTMLElement | null;
|
|
67
|
+
}
|
|
68
|
+
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
69
|
+
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
70
|
+
$$bindings?: Bindings;
|
|
71
|
+
} & Exports;
|
|
72
|
+
(internal: unknown, props: Props & {
|
|
73
|
+
$$events?: Events;
|
|
74
|
+
$$slots?: Slots;
|
|
75
|
+
}): Exports & {
|
|
76
|
+
$set?: any;
|
|
77
|
+
$on?: any;
|
|
78
|
+
};
|
|
79
|
+
z_$$bindings?: Bindings;
|
|
80
|
+
}
|
|
81
|
+
declare const OptionListbox: $$__sveltets_2_IsomorphicComponent<Props, {
|
|
82
|
+
[evt: string]: CustomEvent<any>;
|
|
83
|
+
}, {
|
|
84
|
+
optionPrefix: {};
|
|
85
|
+
}, {
|
|
86
|
+
toggleValue: (item?: ListboxOption) => void;
|
|
87
|
+
clearSelection: () => void;
|
|
88
|
+
handleKeydown: (event: KeyboardEvent) => void;
|
|
89
|
+
}, "value" | "open" | "element" | "activeindex">;
|
|
90
|
+
type OptionListbox = InstanceType<typeof OptionListbox>;
|
|
91
|
+
export default OptionListbox;
|
|
92
|
+
//# sourceMappingURL=OptionListbox.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OptionListbox.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/optionlistbox/OptionListbox.svelte.ts"],"names":[],"mappings":"AAgBE,MAAM,MAAM,aAAa,GAAG;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;CAC7B,CAAC;AAEF,UAAU,KAAK;IACb;;OAEG;IACH,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;IACpD;;OAEG;IACH,EAAE,EAAE,MAAM,CAAC;IACX;;OAEG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IACf;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;OAEG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B;;OAEG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;OAEG;IACH,OAAO,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC;IAC9B;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;CAC9B;AAoVH,UAAU,kCAAkC,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,OAAO,GAAG,EAAE,EAAE,QAAQ,GAAG,MAAM;IACpM,KAAK,OAAO,EAAE,OAAO,QAAQ,EAAE,2BAA2B,CAAC,KAAK,CAAC,GAAG,OAAO,QAAQ,EAAE,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,GAAG;QAAE,UAAU,CAAC,EAAE,QAAQ,CAAA;KAAE,GAAG,OAAO,CAAC;IACjK,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,GAAG;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,KAAK,CAAA;KAAC,GAAG,OAAO,GAAG;QAAE,IAAI,CAAC,EAAE,GAAG,CAAC;QAAC,GAAG,CAAC,EAAE,GAAG,CAAA;KAAE,CAAC;IAC9G,YAAY,CAAC,EAAE,QAAQ,CAAC;CAC3B;AAUD,QAAA,MAAM,aAAa;;;;;yBA5QY,aAAa;;2BAsGX,aAAa;gDAsK0D,CAAC;AACvF,KAAK,aAAa,GAAG,YAAY,CAAC,OAAO,aAAa,CAAC,CAAC;AAC1D,eAAe,aAAa,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# `m-option-listbox`
|
|
2
|
+
|
|
3
|
+
An Option Listbox is a customizable, accessible listbox component designed to power dropdowns and comboboxes with advanced value capabilities. It supports single or multiple value, optional search, grouped options with section headers, and full keyboard navigation.
|
|
4
|
+
|
|
5
|
+
## Props
|
|
6
|
+
|
|
7
|
+
| Name | Description | Type | Default |
|
|
8
|
+
|------|-------------|------|---------|
|
|
9
|
+
| `value*` | The current selected value(s) of the listbox. | `string` `number` `null` `(string` `number)[]` | `$bindable()` |
|
|
10
|
+
| `id*` | Unique identifier for the listbox. | `string` | |
|
|
11
|
+
| `open` | Whether the listbox is open. | `boolean` | `$bindable()` |
|
|
12
|
+
| `multiple` | Enable multiple value. | `boolean` | |
|
|
13
|
+
| `readonly` | Make the listbox read-only. | `boolean` | |
|
|
14
|
+
| `search` | Show a search input above the options. | `boolean` | |
|
|
15
|
+
| `actions` | Show select all / clear buttons when multiple. | `boolean` | |
|
|
16
|
+
| `checkablesections` | Enable checkable section headers. | `boolean` | |
|
|
17
|
+
| `searchplaceholder` | Placeholder text for the search input. | `string` | `Find an option...` |
|
|
18
|
+
| `selectlabel` | Label for the "Select all" button. | `string` | `Select all` |
|
|
19
|
+
| `clearlabel` | Label for the "Clear value" button. | `string` | `Clear` |
|
|
20
|
+
| `options*` | Array of options and sections to display in the listbox. | `Array<ListboxOption>` | |
|
|
21
|
+
| `onopen` | Callback to trigge when the listbox should open. | `() => void` | |
|
|
22
|
+
| `onclose` | Callback to trigge when the listbox should close. | `() => void` | |
|
|
23
|
+
| `activeindex*` | | `number` | `$bindable()` |
|
|
24
|
+
| `element` | | `HTMLElement` `null` | `$bindable()` |
|
|
25
|
+
|
|
26
|
+
## Slots
|
|
27
|
+
|
|
28
|
+
| Name | Description |
|
|
29
|
+
|------|-------------|
|
|
30
|
+
| `optionPrefix` | Use this slot to add a prefix to options. |
|
|
31
|
+
|
|
32
|
+
## Events
|
|
33
|
+
|
|
34
|
+
| Name | Description | Type |
|
|
35
|
+
|------|------|-------------|
|
|
36
|
+
| `open` | Emits when the listbox should open. | `CustomEvent<void>` |
|
|
37
|
+
| `close` | Emits when the listbox should close. | `CustomEvent<void>` |
|
|
38
|
+
|