svelte-5-select 1.0.0-beta.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.
@@ -0,0 +1,1461 @@
1
+ <svelte:options runes={true} />
2
+ <script lang="ts">
3
+ import { onDestroy, onMount, untrack } from 'svelte';
4
+ import { offset, flip, shift } from 'svelte-floating-ui/dom';
5
+ import { createFloatingActions } from 'svelte-floating-ui';
6
+ import type { FloatingConfig, SelectProps } from './types';
7
+ import { useAriaHandlers } from './aria-handlers.svelte';
8
+
9
+ import _filter from './filter';
10
+
11
+ import ChevronIcon from './ChevronIcon.svelte';
12
+ import ClearIcon from './ClearIcon.svelte';
13
+ import LoadingIcon from './LoadingIcon.svelte';
14
+ import type { SelectItem } from './types';
15
+ import type { HTMLInputAttributes } from 'svelte/elements';
16
+ import { useKeyboardNavigation } from './keyboard-navigation.svelte';
17
+ import { areItemsEqual, hasValueChanged, isItemSelectableCheck, createGroupHeaderItem as _createGroupHeaderItem } from './utils';
18
+
19
+ const defaultItemFilter = (label: string, filterText: string, option: SelectItem): boolean =>
20
+ `${label}`.toLowerCase().includes(filterText?.toLowerCase());
21
+
22
+ const defaultOnError = (error: any): void => {};
23
+ const defaultOnLoaded = (options: SelectItem[]): void => {};
24
+ const defaultHandleClear = (e?: MouseEvent): void => {};
25
+
26
+ let timeout = $state<ReturnType<typeof setTimeout>>();
27
+ let clearState = $state(false);
28
+
29
+ let {
30
+ // Core data props
31
+ filterText = $bindable(''),
32
+ itemId = 'value',
33
+ items = $bindable<SelectItem[] | string[] | null>(null),
34
+ justValue = $bindable(),
35
+ label = 'label',
36
+ value = $bindable(),
37
+
38
+ // UI props
39
+ disabled = false,
40
+ focused = $bindable(false),
41
+ hasError = false,
42
+ id = null,
43
+ listOpen = $bindable(false),
44
+ loading = $bindable(false),
45
+ name = null,
46
+ placeholder = 'Please select',
47
+ placeholderAlwaysShow = false,
48
+ showChevron = false,
49
+
50
+ // Behavior props
51
+ clearable = true,
52
+ clearFilterTextOnBlur = true,
53
+ closeListOnChange = true,
54
+ filterSelectedItems = true,
55
+ groupHeaderSelectable = false,
56
+ multiFullItemClearable = false,
57
+ multiple = false,
58
+ required = false,
59
+ searchable = true,
60
+ useJustValue = false,
61
+
62
+ // Styling props
63
+ containerStyles = '',
64
+ inputStyles = '',
65
+ listStyle = '',
66
+ hideEmptyState = false,
67
+
68
+ // Advanced props
69
+ debounceWait = 300,
70
+ floatingConfig = {},
71
+ hoverItemIndex = $bindable(0),
72
+ inputAttributes = {},
73
+ listAutoWidth = true,
74
+ listOffset = 5,
75
+ loadOptionsDeps = [],
76
+
77
+ // Function props
78
+ createGroupHeaderItem = (groupValue: string, item: SelectItem) => {
79
+ return _createGroupHeaderItem(groupValue, item, label);
80
+ },
81
+ debounce = (fn: () => void, wait = 1) => {
82
+ clearTimeout(timeout);
83
+ timeout = setTimeout(fn, wait);
84
+ },
85
+ filter = _filter,
86
+ getFilteredItems = () => {
87
+ return filteredItems;
88
+ },
89
+ groupBy = undefined,
90
+ groupFilter = (groups: string[]) => groups,
91
+ itemFilter = defaultItemFilter,
92
+ loadOptions = undefined,
93
+
94
+ // ARIA props
95
+ ariaFocused = () => {
96
+ return `Select is focused, type to refine list, press down to open the menu.`;
97
+ },
98
+ ariaListOpen = (label: string, count: number) => {
99
+ return `You are currently focused on option ${label}. There are ${count} results available.`;
100
+ },
101
+ ariaValues = (values: string) => {
102
+ return `Option ${values}, selected.`;
103
+ },
104
+
105
+ // Custom behavior
106
+ handleClear = defaultHandleClear,
107
+
108
+ // Event handlers
109
+ onblur = () => {},
110
+ onchange = () => {},
111
+ onclear = () => {},
112
+ onerror = defaultOnError,
113
+ onfilter = () => {},
114
+ onfocus = () => {},
115
+ onhoveritem = () => {},
116
+ oninput = () => {},
117
+ onloaded = defaultOnLoaded,
118
+ onselect = () => {},
119
+
120
+ // Snippet props
121
+ chevronIconSnippet,
122
+ clearIconSnippet,
123
+ emptySnippet,
124
+ inputHiddenSnippet,
125
+ itemSnippet,
126
+ listAppendSnippet,
127
+ listPrependSnippet,
128
+ listSnippet,
129
+ prependSnippet,
130
+ loadingIconSnippet,
131
+ multiClearIconSnippet,
132
+ requiredSnippet,
133
+ selectionSnippet,
134
+
135
+ // DOM references (for binding)
136
+ container = undefined,
137
+ input = undefined,
138
+ ...rest
139
+ }: SelectProps = $props();
140
+
141
+ let normalizedValue = $derived<SelectItem | SelectItem[] | null>(
142
+ !value
143
+ ? null
144
+ : typeof value === 'string'
145
+ ? { value, label: value }
146
+ : value
147
+ );
148
+
149
+ const DEFAULT_INPUT_ATTRS = {
150
+ autocapitalize: 'none',
151
+ autocomplete: 'off',
152
+ autocorrect: 'off',
153
+ spellcheck: false,
154
+ tabindex: 0,
155
+ type: 'text',
156
+ 'aria-autocomplete': 'list',
157
+ } as const;
158
+
159
+ const ariaHandlers = useAriaHandlers({
160
+ ariaValues,
161
+ ariaListOpen,
162
+ ariaFocused,
163
+ });
164
+
165
+ handleClear = (e?: MouseEvent): void => {
166
+ clearState = true;
167
+ onclear(value);
168
+ value = undefined;
169
+ closeList();
170
+ handleFocus();
171
+ };
172
+
173
+ let list = $state<HTMLDivElement | undefined>();
174
+ let _inputAttributes = $derived<HTMLInputAttributes>({
175
+ ...DEFAULT_INPUT_ATTRS,
176
+ role: multiple ? 'combobox' : 'combobox',
177
+ 'aria-controls': listOpen ? `listbox-${id}` : undefined,
178
+ 'aria-expanded': listOpen,
179
+ 'aria-haspopup': 'listbox',
180
+ tabindex: 0,
181
+ readonly: !searchable,
182
+ id: id ? id : undefined,
183
+ ...inputAttributes,
184
+ });
185
+ let activeValue = $state<number | undefined>(undefined);
186
+ let prev_value = $state<SelectItem | SelectItem[] | string | null | undefined>();
187
+ let prev_filterText = $state();
188
+ let prev_multiple = $state();
189
+ let isScrollingTimer = $state<ReturnType<typeof setTimeout>>();
190
+ let isScrolling = $state(false);
191
+ let prefloat = $state(true);
192
+ let hasValue = $state(false);
193
+ let placeholderText = $derived(
194
+ placeholderAlwaysShow && multiple
195
+ ? placeholder
196
+ : multiple && value?.length === 0
197
+ ? placeholder
198
+ : value ? '' : placeholder
199
+ );
200
+ let showClear = $derived(
201
+ hasValue && clearable && !disabled && !loading
202
+ );
203
+ let hideSelectedItem = $derived(
204
+ hasValue && filterText.length > 0
205
+ );
206
+ let filteredItems = $state<SelectItem[]>([]);
207
+
208
+ let ariaContext = $derived(
209
+ ariaHandlers.handleAriaContent({
210
+ value,
211
+ filteredItems,
212
+ hoverItemIndex,
213
+ listOpen,
214
+ multiple,
215
+ label,
216
+ })
217
+ );
218
+ let ariaSelection = $derived(
219
+ value ? ariaHandlers.handleAriaSelection({
220
+ value,
221
+ filteredItems,
222
+ hoverItemIndex,
223
+ listOpen,
224
+ multiple,
225
+ label,
226
+ }) : ''
227
+ );
228
+
229
+ let _floatingConfig = $state<FloatingConfig>({
230
+ strategy: 'absolute',
231
+ placement: 'bottom-start',
232
+ middleware: [offset(listOffset), flip(), shift()],
233
+ autoUpdate: false,
234
+ });
235
+
236
+ const keyboardNav = useKeyboardNavigation({
237
+ getState: () => ({
238
+ listOpen,
239
+ filteredItems,
240
+ hoverItemIndex,
241
+ multiple,
242
+ value,
243
+ filterText,
244
+ activeValue,
245
+ itemId,
246
+ focused,
247
+ }),
248
+ setListOpen: (v) => listOpen = v,
249
+ setHoverItemIndex: (v) => hoverItemIndex = v,
250
+ setActiveValue: (v) => activeValue = v,
251
+ closeList,
252
+ setHoverIndex,
253
+ handleSelect,
254
+ handleMultiItemClear,
255
+ });
256
+ const handleKeyDown = keyboardNav.handleKeyDown;
257
+
258
+ const [floatingRef, floatingContent, floatingUpdate] = createFloatingActions(_floatingConfig);
259
+
260
+ onMount(() => {
261
+ if (listOpen) focused = true;
262
+ if (focused && input) input.focus();
263
+ });
264
+ $effect.pre(() => {
265
+ filterText;
266
+ value;
267
+ items;
268
+ untrack(
269
+ () =>
270
+ (filteredItems = filter({
271
+ loadOptions: undefined, // Don't pass loadOptions - items are already loaded
272
+ filterText,
273
+ items,
274
+ multiple,
275
+ value: normalizedValue,
276
+ itemId,
277
+ groupBy,
278
+ label,
279
+ filterSelectedItems,
280
+ itemFilter,
281
+ convertStringItemsToObjects,
282
+ filterGroupedItems,
283
+ })),
284
+ );
285
+ });
286
+ $effect(() => {
287
+ hasValue;
288
+ untrack(() => {
289
+ if (items) setValue();
290
+ });
291
+ });
292
+ $effect(() => {
293
+ // Used when multiple is dynamically set
294
+ if (multiple) {
295
+ untrack(() => setupMulti());
296
+ }
297
+ });
298
+ $effect(() => {
299
+ // Check BEFORE updating prev_multiple
300
+ if (prev_multiple && !multiple && value) {
301
+ value = null;
302
+ }
303
+ // Update prev_multiple AFTER the check
304
+ prev_multiple = multiple;
305
+ });
306
+ $effect(() => {
307
+ if (multiple && value && value.length > 1) checkValueForDuplicates();
308
+ });
309
+ $effect(() => {
310
+ if (value) dispatchSelectedItem();
311
+ });
312
+ $effect(() => {
313
+ if (prev_value && !value) {
314
+ oninput?.(value || []);
315
+ }
316
+ });
317
+ $effect(() => {
318
+ if (!focused && input) closeList();
319
+ });
320
+ $effect(() => {
321
+ filterText;
322
+ untrack(() => {
323
+ if (filterText !== prev_filterText) setupFilterText();
324
+ });
325
+ });
326
+ $effect(() => {
327
+ if (!multiple && listOpen && value && filteredItems) setValueIndexAsHoverIndex();
328
+ });
329
+ $effect(() => {
330
+ onhoveritem?.(hoverItemIndex);
331
+ });
332
+ $effect(() => {
333
+ multiple;
334
+ value;
335
+ untrack(() => {
336
+ hasValue = multiple
337
+ ? !!(value && value.length > 0)
338
+ : !!value;
339
+ });
340
+ });
341
+ $effect(() => {
342
+ multiple;
343
+ itemId;
344
+ value;
345
+ untrack(() => {
346
+ justValue = computeJustValue();
347
+ });
348
+ });
349
+
350
+ $effect(() => {
351
+ filteredItems;
352
+ value;
353
+ multiple;
354
+ listOpen;
355
+ untrack(() => {
356
+ if (listOpen && filteredItems.length > 0) {
357
+ if (!isItemSelectableCheck(filteredItems[hoverItemIndex])) {
358
+ checkHoverSelectable();
359
+ }
360
+ // Or always check when list opens with groupBy
361
+ else if (groupBy && hoverItemIndex === 0) {
362
+ checkHoverSelectable();
363
+ }
364
+ }
365
+ });
366
+ });
367
+ $effect(() => {
368
+ if (filteredItems && listOpen) onfilter?.(filteredItems);
369
+ });
370
+ $effect(() => {
371
+ if (container && floatingConfig) floatingUpdate({..._floatingConfig, ...floatingConfig});
372
+ });
373
+ $effect(() => {
374
+ listOpen;
375
+ untrack(() => {
376
+ listMounted(list, listOpen);
377
+ if (listOpen && container && list) setListWidth();
378
+ });
379
+ });
380
+ $effect(() => {
381
+ if (input && listOpen && !focused) handleFocus();
382
+ });
383
+ $effect(() => {
384
+ if (filterText) {
385
+ untrack(() => {
386
+ hoverItemIndex = getFirstSelectableIndex();
387
+ });
388
+ }
389
+ });
390
+ $effect(() => {
391
+ if (container && floatingConfig?.autoUpdate === undefined) {
392
+ _floatingConfig.autoUpdate = true;
393
+ }
394
+ });
395
+ $effect(() => {
396
+ if (disabled) {
397
+ listOpen = false;
398
+ filterText = '';
399
+ }
400
+ });
401
+ $effect(() => {
402
+ // Watch both filterText and loadOptionsDeps for changes
403
+ const currentFilterText = filterText;
404
+ loadOptionsDeps.forEach(dep => dep);
405
+
406
+ if (loadOptions && !disabled) {
407
+ // Use untrack to prevent infinite loops when setting items/value/loading
408
+ untrack(() => {
409
+ loading = true;
410
+
411
+ // Determine if this is a filterText change (needs debounce) or deps change (immediate)
412
+ const isFilterTextChange = currentFilterText !== prev_filterText;
413
+
414
+ const executeLoad = async () => {
415
+ try {
416
+ const result = await loadOptions(currentFilterText);
417
+
418
+ // Check if result is string array and convert to SelectItem objects
419
+ if (result && result.length > 0 && typeof result[0] === 'string') {
420
+ items = convertStringItemsToObjects(result as string[]);
421
+ } else {
422
+ // Force reactivity with a new reference and proper typing
423
+ items = result ? (result.slice() as typeof items) : null;
424
+ }
425
+
426
+ // Clear value if it's not in the new items list
427
+ if (value && items && items.length > 0) {
428
+ const valueExists = multiple
429
+ ? Array.isArray(value) && value.every((v: any) =>
430
+ items?.some((item: any) =>
431
+ (typeof item === 'string' ? item : item[itemId]) === (typeof v === 'string' ? v : v[itemId])
432
+ )
433
+ )
434
+ : items.some((item: any) =>
435
+ (typeof item === 'string' ? item : item[itemId]) === (typeof value === 'string' ? value : (value as any)[itemId])
436
+ );
437
+
438
+ if (!valueExists) {
439
+ value = multiple ? [] : undefined;
440
+ }
441
+ } else if (value && (!items || items.length === 0)) {
442
+ // Clear value if items is empty
443
+ value = multiple ? [] : undefined;
444
+ }
445
+
446
+ loading = false;
447
+ // Ensure items is SelectItem[] for onloaded callback
448
+ onloaded((items || []) as SelectItem[]);
449
+ } catch (err) {
450
+ console.error('loadOptions error:', err);
451
+ // Pass the raw error to match expected behavior
452
+ onerror(err as any);
453
+ items = null;
454
+ loading = false;
455
+ }
456
+ };
457
+
458
+ // Use debounce for filterText changes, immediate for deps changes
459
+ if (isFilterTextChange) {
460
+ debounce(executeLoad, debounceWait);
461
+ } else {
462
+ executeLoad();
463
+ }
464
+ });
465
+
466
+ // Set listOpen outside untrack so it triggers reactivity
467
+ if (currentFilterText.length > 0 && !listOpen) {
468
+ listOpen = true;
469
+ }
470
+ }
471
+ });
472
+
473
+ function getFirstSelectableIndex(): number {
474
+ if (!groupBy || filteredItems.length === 0) return 0;
475
+
476
+ if (!isItemSelectableCheck(filteredItems[0])) {
477
+ const firstSelectable = filteredItems.findIndex(isItemSelectableCheck);
478
+ return firstSelectable >= 0 ? firstSelectable : 0;
479
+ }
480
+
481
+ return 0;
482
+ }
483
+
484
+ function findItemByValue(id: any): SelectItem | undefined {
485
+ return (items as SelectItem[])?.find(item => item[itemId] === id);
486
+ }
487
+
488
+ function itemSelected(selection: SelectItem) {
489
+ if (selection) {
490
+ filterText = '';
491
+ const item = Object.assign({}, selection);
492
+
493
+ if (item.groupHeader && !item.selectable) return;
494
+ setValue();
495
+ updateValueDisplay(items);
496
+ value = multiple ? (value ? value.concat([item]) : [item]) : (value = item);
497
+
498
+ if (closeListOnChange) closeList();
499
+ activeValue = undefined;
500
+ onchange?.(value);
501
+ onselect?.(selection);
502
+ }
503
+ }
504
+
505
+ function setValue() {
506
+ prev_value = value;
507
+ if (typeof value === 'string') {
508
+ let item = findItemByValue(value);
509
+ value = item || {
510
+ [itemId]: value,
511
+ label: value,
512
+ };
513
+ } else if (multiple && Array.isArray(value) && value.length > 0) {
514
+ value = value.map((val) => {
515
+ if (typeof val === 'string') {
516
+ // Look up each string value in items
517
+ let item = findItemByValue(val);
518
+ return item || { value: val, label: val };
519
+ }
520
+ return val;
521
+ });
522
+ }
523
+ }
524
+
525
+ function updateValueDisplay(items?: SelectItem[] | string[] | null): void {
526
+ if (!items || items.length === 0 || items.some((item) => typeof item !== 'object')) return;
527
+ if (!value) return; // Change back to value
528
+
529
+ if (Array.isArray(value)) { // Change back to value
530
+ if (value.some((selection: SelectItem) => !selection || !(selection as Record<string, any>)[itemId])) return;
531
+ value = value.map((selection) => findItem(selection) || selection);
532
+ } else if (typeof value === 'object') {
533
+ if (!(value as Record<string, any>)[itemId]) return;
534
+ value = findItem() || value;
535
+ }
536
+ }
537
+
538
+ function assignInputAttributes() {
539
+ _inputAttributes = { ...DEFAULT_INPUT_ATTRS, ...inputAttributes };
540
+ if (id) _inputAttributes['id'] = id;
541
+ if (!searchable) _inputAttributes['readonly'] = true;
542
+ }
543
+
544
+ function convertStringItemsToObjects(_items: string[]): SelectItem[] {
545
+ return _items.map((item, index) => {
546
+ return {
547
+ index,
548
+ value: item,
549
+ label: `${item}`,
550
+ };
551
+ });
552
+ }
553
+
554
+ function filterGroupedItems(_items: SelectItem[]): SelectItem[] {
555
+ if (!groupBy) return _items;
556
+
557
+ const groupValues: string[] = [];
558
+ const groups: Record<string, SelectItem[]> = {};
559
+
560
+ _items.forEach((item) => {
561
+ const groupValue: string = groupBy(item);
562
+
563
+ if (!groupValues.includes(groupValue)) {
564
+ groupValues.push(groupValue);
565
+ groups[groupValue] = [];
566
+ if (groupValue) {
567
+ groups[groupValue].push(
568
+ Object.assign(createGroupHeaderItem(groupValue, item), {
569
+ id: groupValue,
570
+ groupHeader: true,
571
+ selectable: groupHeaderSelectable,
572
+ }),
573
+ );
574
+ }
575
+ }
576
+
577
+ groups[groupValue].push(Object.assign({ groupItem: !!groupValue }, item));
578
+ });
579
+
580
+ const sortedGroupedItems: SelectItem[] = [];
581
+
582
+ groupFilter(groupValues).forEach((groupValue: string) => {
583
+ if (groups[groupValue]) sortedGroupedItems.push(...groups[groupValue]);
584
+ });
585
+
586
+ return sortedGroupedItems;
587
+ }
588
+
589
+ function dispatchSelectedItem() {
590
+ if (multiple) {
591
+ if (hasValueChanged(value, prev_value)) {
592
+ if (checkValueForDuplicates()) {
593
+ oninput?.(value || []);
594
+ }
595
+ }
596
+ return;
597
+ }
598
+
599
+ if (!prev_value || hasValueChanged((value as SelectItem)[itemId], (prev_value as SelectItem)[itemId])) {
600
+ oninput?.(value);
601
+ }
602
+ }
603
+
604
+ function setupMulti() {
605
+ if (value) {
606
+ if (Array.isArray(value)) {
607
+ value = [...value];
608
+ } else {
609
+ value = [value];
610
+ }
611
+ }
612
+ }
613
+
614
+ function setValueIndexAsHoverIndex() {
615
+ if (!normalizedValue || Array.isArray(normalizedValue)) return;
616
+
617
+ const singleValue: SelectItem = normalizedValue;
618
+
619
+ const valueIndex = filteredItems.findIndex((i: SelectItem) => {
620
+ return (i as Record<string, any>)[itemId] === (singleValue as Record<string, any>)[itemId];
621
+ });
622
+
623
+ checkHoverSelectable(valueIndex, true);
624
+ }
625
+
626
+ function checkHoverSelectable(startingIndex = 0, ignoreGroup?: boolean) {
627
+ hoverItemIndex = startingIndex < 0 ? 0 : startingIndex;
628
+ if (!ignoreGroup && groupBy && filteredItems[hoverItemIndex] && !filteredItems[hoverItemIndex].selectable) {
629
+ setHoverIndex(1);
630
+ }
631
+ }
632
+
633
+ function setupFilterText() {
634
+ // When loadOptions is defined, the unified $effect handles everything
635
+ // This function now only handles non-loadOptions cases
636
+ if (loadOptions) {
637
+ // loadOptions is handled by the unified $effect that watches filterText and loadOptionsDeps
638
+ // Just ensure the list opens if there's filter text
639
+ if (filterText.length > 0 && !listOpen) {
640
+ listOpen = true;
641
+ }
642
+ return;
643
+ }
644
+
645
+ if (filterText.length === 0) return;
646
+
647
+ // Non-loadOptions case: just open the list
648
+ listOpen = true;
649
+
650
+ if (multiple) {
651
+ activeValue = undefined;
652
+ }
653
+ }
654
+
655
+ function computeJustValue(): any {
656
+ if (useJustValue && !value && !clearState) { // Change back to value
657
+ const typedItems = (items as SelectItem[]) || [];
658
+ if (multiple) {
659
+ value = typedItems.filter((item: SelectItem) =>
660
+ justValue.includes((item as Record<string, any>)[itemId])
661
+ );
662
+ } else {
663
+ value = typedItems.filter((item: SelectItem) => // Change back to value
664
+ (item as Record<string, any>)[itemId] === justValue
665
+ )[0];
666
+ }
667
+ }
668
+
669
+ clearState = false;
670
+
671
+ // Handle multiple selection
672
+ if (multiple && Array.isArray(value)) {
673
+ return value ? value.map((item: SelectItem) =>
674
+ (item as Record<string, any>)[itemId]
675
+ ) : null;
676
+ }
677
+
678
+ // Handle single selection
679
+ if (!value || typeof value === 'string' || Array.isArray(value)) {
680
+ return value;
681
+ }
682
+
683
+ return (value as Record<string, any>)[itemId];
684
+ }
685
+
686
+ function checkValueForDuplicates(): boolean {
687
+ if (!Array.isArray(value) || value.length === 0) return true;
688
+
689
+ const seen = new Set();
690
+ const uniqueValues = value.filter((val: SelectItem) => {
691
+ const id = val[itemId];
692
+ if (seen.has(id)) return false;
693
+ seen.add(id);
694
+ return true;
695
+ });
696
+
697
+ const noDuplicates = uniqueValues.length === value.length;
698
+ if (!noDuplicates) value = uniqueValues;
699
+
700
+ return noDuplicates;
701
+ }
702
+
703
+ function findItem(selection?: SelectItem): SelectItem | undefined {
704
+ let matchTo = selection ? selection[itemId] : (normalizedValue as SelectItem)[itemId];
705
+ return (items as SelectItem[])?.find(item => item[itemId] === matchTo);
706
+ }
707
+
708
+ async function handleMultiItemClear(i:number): Promise<void> {
709
+ if (!Array.isArray(value)) return;
710
+
711
+ const itemToRemove = value[i];
712
+
713
+ clearState = true;
714
+ if (value.length === 1) {
715
+ value = undefined;
716
+ } else {
717
+ value = value.filter((item: SelectItem) => {
718
+ return item !== itemToRemove;
719
+ });
720
+ }
721
+ onclear(itemToRemove);
722
+ }
723
+
724
+ function handleFocus(e?: FocusEvent): void {
725
+ if (focused && input === document?.activeElement) return;
726
+ if (e) {
727
+ onfocus?.(e);
728
+ }
729
+ input?.focus();
730
+ focused = true;
731
+ }
732
+
733
+ async function handleBlur(e?: FocusEvent): Promise<void> {
734
+ if (isScrolling) return;
735
+ if (listOpen || focused) {
736
+ if (e) onblur?.(e);
737
+ closeList();
738
+ focused = false;
739
+ activeValue = undefined;
740
+ input?.blur();
741
+ }
742
+ }
743
+
744
+ function handleClick(ev: MouseEvent) {
745
+ ev.preventDefault();
746
+ if (disabled) return;
747
+ if (filterText && filterText.length > 0) return (listOpen = true);
748
+ listOpen = !listOpen;
749
+ }
750
+
751
+ function closeList() {
752
+ if (clearFilterTextOnBlur) {
753
+ filterText = '';
754
+ }
755
+ listOpen = false;
756
+ }
757
+
758
+ function handleListScroll() {
759
+ clearTimeout(isScrollingTimer);
760
+ isScrollingTimer = setTimeout(() => {
761
+ isScrolling = false;
762
+ }, 100);
763
+ }
764
+
765
+ function handleClickOutside(event: MouseEvent): void {
766
+ const target = event.target as Node;
767
+ if (!listOpen && !focused && container && !container.contains(target) && !list?.contains(target)) {
768
+ handleBlur();
769
+ }
770
+ }
771
+
772
+ onDestroy(() => {
773
+ list?.remove();
774
+ });
775
+
776
+ function handleSelect(item: SelectItem): void {
777
+ if (!item || item.selectable === false) return;
778
+ itemSelected(item);
779
+ }
780
+
781
+ function handleHover(i: number): void {
782
+ if (isScrolling) return;
783
+ hoverItemIndex = i;
784
+ }
785
+
786
+ function handleItemClick(item: SelectItem, i: number): void {
787
+ if (item?.selectable === false) return;
788
+ if (!multiple && areItemsEqual(normalizedValue, item, itemId)) return closeList();
789
+ if (isItemSelectable(item)) {
790
+ hoverItemIndex = i;
791
+ handleSelect(item);
792
+ }
793
+ }
794
+
795
+ function setHoverIndex(increment: number) {
796
+ let selectableFilteredItems = filteredItems.filter(
797
+ (item) => !Object.hasOwn(item, 'selectable') || item.selectable === true,
798
+ );
799
+
800
+ if (selectableFilteredItems.length === 0) {
801
+ return (hoverItemIndex = 0);
802
+ }
803
+
804
+ // Get current item
805
+ const currentItem = filteredItems[hoverItemIndex];
806
+ const isCurrentSelectable = isItemSelectableCheck(currentItem);
807
+
808
+ // Find position in selectable items array
809
+ let currentSelectableIndex;
810
+
811
+ if (isCurrentSelectable) {
812
+ currentSelectableIndex = selectableFilteredItems.findIndex(item => item === currentItem);
813
+ } else {
814
+ // Starting from non-selectable item - treat as before first/after last depending on direction
815
+ currentSelectableIndex = increment > 0 ? -1 : selectableFilteredItems.length;
816
+ }
817
+
818
+ // Calculate new position with wrapping
819
+ let newSelectableIndex;
820
+ if (increment > 0) {
821
+ newSelectableIndex = (currentSelectableIndex + 1) % selectableFilteredItems.length;
822
+ } else {
823
+ newSelectableIndex = (currentSelectableIndex - 1 + selectableFilteredItems.length) % selectableFilteredItems.length;
824
+ }
825
+
826
+ // Map back to filteredItems
827
+ const newItem = selectableFilteredItems[newSelectableIndex];
828
+ hoverItemIndex = filteredItems.findIndex(item => item === newItem);
829
+ }
830
+
831
+ function isItemActive(item: SelectItem, val: SelectItem | SelectItem[] | null | undefined, itemId: string): boolean | undefined {
832
+ if (multiple) return;
833
+ const normalized = !val ? null : typeof val === 'string' ? { value: val, label: val } : val;
834
+ return areItemsEqual(normalized, item, itemId);
835
+ }
836
+
837
+ function isItemSelectable(item: SelectItem) {
838
+ return (item.groupHeader && item.selectable) || isItemSelectableCheck(item);
839
+ }
840
+
841
+ function setListWidth():void {
842
+ if (!container || !list) return;
843
+ const { width } = container.getBoundingClientRect();
844
+ list.style.width = listAutoWidth ? width + 'px' : 'auto';
845
+ }
846
+
847
+ function listMounted(list: HTMLDivElement | undefined, listOpen: boolean) {
848
+ if (!list || !listOpen) return (prefloat = true);
849
+ setTimeout(() => {
850
+ prefloat = false;
851
+ }, 0);
852
+ }
853
+
854
+ function handleInput(ev: Event): void {
855
+ const target = ev.target as HTMLInputElement;
856
+ listOpen = true;
857
+ prev_filterText = filterText;
858
+ filterText = target.value;
859
+ }
860
+ </script>
861
+
862
+ <svelte:window onclick={handleClickOutside} onkeydown={handleKeyDown} />
863
+
864
+ <div
865
+ class="svelte-select {rest.class}"
866
+ class:multi={multiple}
867
+ class:disabled
868
+ class:focused
869
+ class:list-open={listOpen}
870
+ class:show-chevron={showChevron}
871
+ class:error={hasError}
872
+ style={containerStyles}
873
+ onpointerup={handleClick}
874
+ bind:this={container}
875
+ use:floatingRef
876
+ role="none">
877
+ {#if listOpen}
878
+ <div
879
+ use:floatingContent
880
+ bind:this={list}
881
+ class="svelte-select-list"
882
+ class:prefloat
883
+ style={listStyle}
884
+ onscroll={handleListScroll}
885
+ onpointerup={(ev) => {
886
+ ev.preventDefault();
887
+ ev.stopPropagation();
888
+ }}
889
+ onmousedown={(ev) => {
890
+ ev.preventDefault();
891
+ ev.stopPropagation();
892
+ }}
893
+ role="none">
894
+ {#if listPrependSnippet}
895
+ {@render listPrependSnippet()}
896
+ {/if}
897
+ {#if listSnippet}
898
+ {@render listSnippet(filteredItems)}
899
+ {:else if filteredItems?.length > 0}
900
+ {#each filteredItems as item, i}
901
+ <div
902
+ onmouseover={() => handleHover(i)}
903
+ onfocus={() => handleHover(i)}
904
+ onclick={(ev) => {
905
+ ev.stopPropagation();
906
+ handleItemClick(item, i);
907
+ }}
908
+ onkeydown={(ev) => {
909
+ ev.preventDefault();
910
+ ev.stopPropagation();
911
+ }}
912
+ class="list-item"
913
+ tabindex="-1"
914
+ role="none">
915
+ <div
916
+ class="item"
917
+ class:list-group-title={item.groupHeader}
918
+ class:active={isItemActive(item, normalizedValue, itemId)}
919
+ class:first={i === 0}
920
+ class:hover={hoverItemIndex === i}
921
+ class:group-item={item.groupItem}
922
+ class:not-selectable={item?.selectable === false}>
923
+ {#if itemSnippet}
924
+ {@render itemSnippet(item, i)}
925
+ {:else}
926
+ {item?.[label]}
927
+ {/if}
928
+ </div>
929
+ </div>
930
+ {/each}
931
+ {:else if !hideEmptyState}
932
+ {#if emptySnippet}
933
+ {@render emptySnippet()}
934
+ {:else if !loading}
935
+ <div class="empty">No options</div>
936
+ {:else}
937
+ <div class="empty">Loading Data</div>
938
+ {/if}
939
+ {/if}
940
+ {#if listAppendSnippet}
941
+ {@render listAppendSnippet()}
942
+ {/if}
943
+ </div>
944
+ {/if}
945
+
946
+ <span aria-live="polite" aria-atomic="false" aria-relevant="additions" class="a11y-text">
947
+ {#if focused}
948
+ <span id="aria-selection">{ariaSelection}</span>
949
+ <span id="aria-context">
950
+ {ariaContext}
951
+ </span>
952
+ {/if}
953
+ </span>
954
+
955
+ <div class="prepend">
956
+ {#if prependSnippet}
957
+ {@render prependSnippet()}
958
+ {/if}
959
+ </div>
960
+
961
+ <div class="value-container">
962
+ {#if hasValue}
963
+ {#if multiple}
964
+ {#each (Array.isArray(value) ? value : []) as item, i}
965
+ <div
966
+ class="multi-item"
967
+ class:active={activeValue === i}
968
+ class:disabled
969
+ onclick={(ev) => {
970
+ ev.preventDefault();
971
+ return multiFullItemClearable ? handleMultiItemClear(i) : {};
972
+ }}
973
+ onkeydown={(ev) => {
974
+ ev.preventDefault();
975
+ ev.stopPropagation();
976
+ }}
977
+ role="none">
978
+ <span class="multi-item-text">
979
+ {#if selectionSnippet}
980
+ {@render selectionSnippet(item, i)}
981
+ {:else}
982
+ {item[label]}
983
+ {/if}
984
+ </span>
985
+
986
+ {#if !disabled && !multiFullItemClearable && ClearIcon}
987
+ <div
988
+ class="multi-item-clear"
989
+ onpointerup={(ev) => {
990
+ ev.preventDefault();
991
+ ev.stopPropagation();
992
+ handleMultiItemClear(i);
993
+ }}>
994
+ {#if multiClearIconSnippet}
995
+ {@render multiClearIconSnippet()}
996
+ {:else}
997
+ <ClearIcon />
998
+ {/if}
999
+ </div>
1000
+ {/if}
1001
+ </div>
1002
+ {/each}
1003
+ {:else}
1004
+ <div class="selected-item" class:hide-selected-item={hideSelectedItem}>
1005
+ {#if selectionSnippet}
1006
+ {@render selectionSnippet(value)}
1007
+ {:else}
1008
+ {!Array.isArray(normalizedValue) ? normalizedValue?.[label] : ''}
1009
+ {/if}
1010
+ </div>
1011
+ {/if}
1012
+ {/if}
1013
+
1014
+ <input
1015
+ onkeydown={handleKeyDown}
1016
+ onblur={handleBlur}
1017
+ oninput={handleInput}
1018
+ onfocus={handleFocus}
1019
+ readOnly={!searchable}
1020
+ {..._inputAttributes}
1021
+ bind:this={input}
1022
+ value={filterText}
1023
+ placeholder={placeholderText}
1024
+ style={inputStyles}
1025
+ {disabled} />
1026
+ </div>
1027
+
1028
+ <div class="indicators">
1029
+ {#if loading}
1030
+ <div class="icon loading" aria-hidden="true">
1031
+ {#if loadingIconSnippet}
1032
+ {@render loadingIconSnippet()}
1033
+ {:else}
1034
+ <LoadingIcon />
1035
+ {/if}
1036
+ </div>
1037
+ {/if}
1038
+
1039
+ {#if showClear}
1040
+ <button type="button" class="icon clear-select" onclick={handleClear}>
1041
+ {#if clearIconSnippet}
1042
+ {@render clearIconSnippet()}
1043
+ {:else}
1044
+ <ClearIcon />
1045
+ {/if}
1046
+ </button>
1047
+ {/if}
1048
+
1049
+ {#if showChevron}
1050
+ <div class="icon chevron" aria-hidden="true">
1051
+ {#if chevronIconSnippet}
1052
+ {@render chevronIconSnippet(listOpen)}
1053
+ {:else}
1054
+ <ChevronIcon />
1055
+ {/if}
1056
+ </div>
1057
+ {/if}
1058
+ </div>
1059
+ {#if inputHiddenSnippet}
1060
+ {@render inputHiddenSnippet(value)}
1061
+ {:else}
1062
+ <input {name} type="hidden" value={useJustValue ? justValue : value ? JSON.stringify(value) : null} />
1063
+ {/if}
1064
+
1065
+ {#if required && (!value || value.length === 0)}
1066
+ {#if requiredSnippet}
1067
+ {@render requiredSnippet(value)}
1068
+ {:else}
1069
+ <select class="required" required tabindex="-1" aria-hidden="true"></select>
1070
+ {/if}
1071
+ {/if}
1072
+ </div>
1073
+
1074
+ <style>.svelte-select {
1075
+ /* deprecating camelCase custom props in favour of kebab-case for v5 */
1076
+ --borderRadius: var(--border-radius);
1077
+ --clearSelectColor: var(--clear-select-color);
1078
+ --clearSelectWidth: var(--clear-select-width);
1079
+ --disabledBackground: var(--disabled-background);
1080
+ --disabledBorderColor: var(--disabled-border-color);
1081
+ --disabledColor: var(--disabled-color);
1082
+ --disabledPlaceholderColor: var(--disabled-placeholder-color);
1083
+ --disabledPlaceholderOpacity: var(--disabled-placeholder-opacity);
1084
+ --errorBackground: var(--error-background);
1085
+ --errorBorder: var(--error-border);
1086
+ --groupItemPaddingLeft: var(--group-item-padding-left);
1087
+ --groupTitleColor: var(--group-title-color);
1088
+ --groupTitleFontSize: var(--group-title-font-size);
1089
+ --groupTitleFontWeight: var(--group-title-font-weight);
1090
+ --groupTitlePadding: var(--group-title-padding);
1091
+ --groupTitleTextTransform: var(--group-title-text-transform);
1092
+ --groupTitleBorderColor: var(--group-title-border-color);
1093
+ --groupTitleBorderWidth: var(--group-title-border-width);
1094
+ --groupTitleBorderStyle: var(--group-title-border-style);
1095
+ --indicatorColor: var(--chevron-color);
1096
+ --indicatorHeight: var(--chevron-height);
1097
+ --indicatorWidth: var(--chevron-width);
1098
+ --inputColor: var(--input-color);
1099
+ --inputLeft: var(--input-left);
1100
+ --inputLetterSpacing: var(--input-letter-spacing);
1101
+ --inputMargin: var(--input-margin);
1102
+ --inputPadding: var(--input-padding);
1103
+ --itemActiveBackground: var(--item-active-background);
1104
+ --itemColor: var(--item-color);
1105
+ --itemFirstBorderRadius: var(--item-first-border-radius);
1106
+ --itemHoverBG: var(--item-hover-bg);
1107
+ --itemHoverColor: var(--item-hover-color);
1108
+ --itemIsActiveBG: var(--item-is-active-bg);
1109
+ --itemIsActiveColor: var(--item-is-active-color);
1110
+ --itemIsNotSelectableColor: var(--item-is-not-selectable-color);
1111
+ --itemPadding: var(--item-padding);
1112
+ --listBackground: var(--list-background);
1113
+ --listBorder: var(--list-border);
1114
+ --listBorderRadius: var(--list-border-radius);
1115
+ --listEmptyColor: var(--list-empty-color);
1116
+ --listEmptyPadding: var(--list-empty-padding);
1117
+ --listEmptyTextAlign: var(--list-empty-text-align);
1118
+ --listMaxHeight: var(--list-max-height);
1119
+ --listPosition: var(--list-position);
1120
+ --listShadow: var(--list-shadow);
1121
+ --listZIndex: var(--list-z-index);
1122
+ --multiItemBG: var(--multi-item-bg);
1123
+ --multiItemBorderRadius: var(--multi-item-border-radius);
1124
+ --multiItemDisabledHoverBg: var(--multi-item-disabled-hover-bg);
1125
+ --multiItemDisabledHoverColor: var(--multi-item-disabled-hover-color);
1126
+ --multiItemHeight: var(--multi-item-height);
1127
+ --multiItemMargin: var(--multi-item-margin);
1128
+ --multiItemPadding: var(--multi-item-padding);
1129
+ --multiSelectInputMargin: var(--multi-select-input-margin);
1130
+ --multiSelectInputPadding: var(--multi-select-input-padding);
1131
+ --multiSelectPadding: var(--multi-select-padding);
1132
+ --placeholderColor: var(--placeholder-color);
1133
+ --placeholderOpacity: var(--placeholder-opacity);
1134
+ --selectedItemPadding: var(--selected-item-padding);
1135
+ --spinnerColor: var(--spinner-color);
1136
+ --spinnerHeight: var(--spinner-height);
1137
+ --spinnerWidth: var(--spinner-width);
1138
+
1139
+ --internal-padding: 0 0 0 16px;
1140
+
1141
+ border: var(--border, 1px solid #d8dbdf);
1142
+ border-radius: var(--border-radius, 6px);
1143
+ min-height: var(--height, 42px);
1144
+ position: relative;
1145
+ display: flex;
1146
+ align-items: stretch;
1147
+ padding: var(--padding, var(--internal-padding));
1148
+ background: var(--background, #fff);
1149
+ margin: var(--margin, 0);
1150
+ width: var(--width, 100%);
1151
+ font-size: var(--font-size, 16px);
1152
+ max-height: var(--max-height);
1153
+ }
1154
+
1155
+ * {
1156
+ box-sizing: var(--box-sizing, border-box);
1157
+ }
1158
+
1159
+ .svelte-select:hover {
1160
+ border: var(--border-hover, 1px solid #b2b8bf);
1161
+ }
1162
+
1163
+ .value-container {
1164
+ display: flex;
1165
+ flex: 1 1 0%;
1166
+ flex-wrap: wrap;
1167
+ align-items: center;
1168
+ gap: 5px 10px;
1169
+ padding: var(--value-container-padding, 5px 0);
1170
+ position: relative;
1171
+ overflow: var(--value-container-overflow, hidden);
1172
+ align-self: stretch;
1173
+ }
1174
+
1175
+ .prepend,
1176
+ .indicators {
1177
+ display: flex;
1178
+ flex-shrink: 0;
1179
+ align-items: center;
1180
+ }
1181
+
1182
+ .indicators {
1183
+ position: var(--indicators-position);
1184
+ top: var(--indicators-top);
1185
+ right: var(--indicators-right);
1186
+ bottom: var(--indicators-bottom);
1187
+ }
1188
+
1189
+ input {
1190
+ position: absolute;
1191
+ cursor: default;
1192
+ border: none;
1193
+ color: var(--input-color, var(--item-color));
1194
+ padding: var(--input-padding, 0);
1195
+ letter-spacing: var(--input-letter-spacing, inherit);
1196
+ margin: var(--input-margin, 0);
1197
+ min-width: 10px;
1198
+ top: 0;
1199
+ right: 0;
1200
+ bottom: 0;
1201
+ left: 0;
1202
+ background: transparent;
1203
+ font-size: var(--font-size, 16px);
1204
+ }
1205
+
1206
+ :not(.multi) > .value-container > input {
1207
+ width: 100%;
1208
+ height: 100%;
1209
+ }
1210
+
1211
+ input::placeholder {
1212
+ color: var(--placeholder-color, #78848f);
1213
+ opacity: var(--placeholder-opacity, 1);
1214
+ }
1215
+
1216
+ input:focus {
1217
+ outline: none;
1218
+ }
1219
+
1220
+ .svelte-select.focused {
1221
+ border: var(--border-focused, 1px solid #006fe8);
1222
+ border-radius: var(--border-radius-focused, var(--border-radius, 6px));
1223
+ }
1224
+
1225
+ .disabled {
1226
+ background: var(--disabled-background, #ebedef);
1227
+ border-color: var(--disabled-border-color, #ebedef);
1228
+ color: var(--disabled-color, #c1c6cc);
1229
+ }
1230
+
1231
+ .disabled input::placeholder {
1232
+ color: var(--disabled-placeholder-color, #c1c6cc);
1233
+ opacity: var(--disabled-placeholder-opacity, 1);
1234
+ }
1235
+
1236
+ .selected-item {
1237
+ position: relative;
1238
+ overflow: var(--selected-item-overflow, hidden);
1239
+ padding: var(--selected-item-padding, 0 20px 0 0);
1240
+ text-overflow: ellipsis;
1241
+ white-space: nowrap;
1242
+ color: var(--selected-item-color, inherit);
1243
+ font-size: var(--font-size, 16px);
1244
+ }
1245
+
1246
+ .multi .selected-item {
1247
+ position: absolute;
1248
+ line-height: var(--height, 42px);
1249
+ height: var(--height, 42px);
1250
+ }
1251
+
1252
+ .selected-item:focus {
1253
+ outline: none;
1254
+ }
1255
+
1256
+ .hide-selected-item {
1257
+ opacity: 0;
1258
+ }
1259
+
1260
+ .icon {
1261
+ display: flex;
1262
+ align-items: center;
1263
+ justify-content: center;
1264
+ }
1265
+
1266
+ .clear-select {
1267
+ all: unset;
1268
+ display: flex;
1269
+ align-items: center;
1270
+ justify-content: center;
1271
+ width: var(--clear-select-width, 40px);
1272
+ height: var(--clear-select-height, 100%);
1273
+ color: var(--clear-select-color, var(--icons-color));
1274
+ margin: var(--clear-select-margin, 0);
1275
+ pointer-events: all;
1276
+ flex-shrink: 0;
1277
+ }
1278
+
1279
+ .clear-select:focus {
1280
+ outline: var(--clear-select-focus-outline, 1px solid #006fe8);
1281
+ }
1282
+
1283
+ .loading {
1284
+ width: var(--loading-width, 40px);
1285
+ height: var(--loading-height);
1286
+ color: var(--loading-color, var(--icons-color));
1287
+ margin: var(--loading--margin, 0);
1288
+ flex-shrink: 0;
1289
+ }
1290
+
1291
+ .chevron {
1292
+ width: var(--chevron-width, 40px);
1293
+ height: var(--chevron-height, 40px);
1294
+ background: var(--chevron-background, transparent);
1295
+ pointer-events: var(--chevron-pointer-events, none);
1296
+ color: var(--chevron-color, var(--icons-color));
1297
+ border: 0;
1298
+ border-left: var(--chevron-border-left, 1px solid #d8dbdf);
1299
+ flex-shrink: 0;
1300
+ }
1301
+
1302
+ .multi {
1303
+ padding: var(--multi-select-padding, var(--internal-padding));
1304
+ }
1305
+
1306
+ .multi input {
1307
+ padding: var(--multi-select-input-padding, 0);
1308
+ position: relative;
1309
+ margin: var(--multi-select-input-margin, 5px 0);
1310
+ flex: 1 1 40px;
1311
+ }
1312
+
1313
+ .svelte-select.error {
1314
+ border: var(--error-border, 1px solid #ff2d55);
1315
+ background: var(--error-background, #fff);
1316
+ }
1317
+
1318
+ .a11y-text {
1319
+ z-index: 9999;
1320
+ border: 0px;
1321
+ clip: rect(1px, 1px, 1px, 1px);
1322
+ height: 1px;
1323
+ width: 1px;
1324
+ position: absolute;
1325
+ overflow: hidden;
1326
+ padding: 0px;
1327
+ white-space: nowrap;
1328
+ }
1329
+
1330
+ .multi-item {
1331
+ background: var(--multi-item-bg, #ebedef);
1332
+ margin: var(--multi-item-margin, 0);
1333
+ outline: var(--multi-item-outline, 1px solid #ddd);
1334
+ border-radius: var(--multi-item-border-radius, 4px);
1335
+ height: var(--multi-item-height, 25px);
1336
+ line-height: var(--multi-item-height, 25px);
1337
+ display: flex;
1338
+ cursor: default;
1339
+ padding: var(--multi-item-padding, 0 5px);
1340
+ overflow: hidden;
1341
+ gap: var(--multi-item-gap, 4px);
1342
+ outline-offset: -1px;
1343
+ max-width: var(--multi-max-width, none);
1344
+ color: var(--multi-item-color, var(--item-color));
1345
+ }
1346
+
1347
+ .multi-item.disabled:hover {
1348
+ background: var(--multi-item-disabled-hover-bg, #ebedef);
1349
+ color: var(--multi-item-disabled-hover-color, #c1c6cc);
1350
+ }
1351
+
1352
+ .multi-item-text {
1353
+ overflow: hidden;
1354
+ text-overflow: ellipsis;
1355
+ white-space: nowrap;
1356
+ }
1357
+
1358
+ .multi-item-clear {
1359
+ display: flex;
1360
+ align-items: center;
1361
+ justify-content: center;
1362
+ --clear-icon-color: var(--multi-item-clear-icon-color, #000);
1363
+ }
1364
+
1365
+ .multi-item.active {
1366
+ outline: var(--multi-item-active-outline, 1px solid #006fe8);
1367
+ }
1368
+
1369
+ .svelte-select-list {
1370
+ box-shadow: var(--list-shadow, 0 2px 3px 0 rgba(44, 62, 80, 0.24));
1371
+ border-radius: var(--list-border-radius, 4px);
1372
+ max-height: var(--list-max-height, 252px);
1373
+ overflow-y: auto;
1374
+ background: var(--list-background, #fff);
1375
+ position: var(--list-position, absolute);
1376
+ z-index: var(--list-z-index, 2);
1377
+ border: var(--list-border);
1378
+ }
1379
+
1380
+ .prefloat {
1381
+ opacity: 0;
1382
+ pointer-events: none;
1383
+ }
1384
+
1385
+ .list-group-title {
1386
+ color: var(--group-title-color, #000000);
1387
+ cursor: default;
1388
+ font-size: var(--group-title-font-size, 16px);
1389
+ font-weight: var(--group-title-font-weight, 600);
1390
+ height: var(--height, 42px);
1391
+ line-height: var(--height, 42px);
1392
+ padding: var(--group-title-padding, 0 20px);
1393
+ text-overflow: ellipsis;
1394
+ overflow-x: hidden;
1395
+ white-space: nowrap;
1396
+ text-transform: var(--group-title-text-transform, uppercase);
1397
+ border-width: var(--group-title-border-width, medium);
1398
+ border-style: var(--group-title-border-style, none);
1399
+ border-color: var(--group-title-border-color, transparent);
1400
+ }
1401
+
1402
+ .empty {
1403
+ text-align: var(--list-empty-text-align, center);
1404
+ padding: var(--list-empty-padding, 20px 0);
1405
+ color: var(--list-empty-color, #78848f);
1406
+ }
1407
+
1408
+ .item {
1409
+ cursor: default;
1410
+ height: var(--item-height, var(--height, 42px));
1411
+ line-height: var(--item-line-height, var(--height, 42px));
1412
+ padding: var(--item-padding, 0 20px);
1413
+ color: var(--item-color, inherit);
1414
+ text-overflow: ellipsis;
1415
+ overflow: hidden;
1416
+ white-space: nowrap;
1417
+ transition: var(--item-transition, all 0.2s);
1418
+ align-items: center;
1419
+ width: 100%;
1420
+ }
1421
+
1422
+ .item.group-item {
1423
+ padding-left: var(--group-item-padding-left, 40px);
1424
+ }
1425
+
1426
+ .item:active {
1427
+ background: var(--item-active-background, #b9daff);
1428
+ }
1429
+
1430
+ .item.active {
1431
+ background: var(--item-is-active-bg, #007aff);
1432
+ color: var(--item-is-active-color, #fff);
1433
+ }
1434
+
1435
+ .item.first {
1436
+ border-radius: var(--item-first-border-radius, 4px 4px 0 0);
1437
+ }
1438
+
1439
+ .item.hover:not(.active) {
1440
+ background: var(--item-hover-bg, #e7f2ff);
1441
+ color: var(--item-hover-color, inherit);
1442
+ }
1443
+
1444
+ .item.not-selectable,
1445
+ .item.hover.item.not-selectable,
1446
+ .item.active.item.not-selectable,
1447
+ .item.not-selectable:active {
1448
+ color: var(--item-is-not-selectable-color, #999);
1449
+ background: transparent;
1450
+ }
1451
+
1452
+ .required {
1453
+ opacity: 0;
1454
+ z-index: -1;
1455
+ position: absolute;
1456
+ top: 0;
1457
+ left: 0;
1458
+ bottom: 0;
1459
+ right: 0;
1460
+ }
1461
+ </style>