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.
- package/LICENSE +9 -0
- package/README.md +320 -0
- package/dist/ChevronIcon.svelte +22 -0
- package/dist/ChevronIcon.svelte.d.ts +26 -0
- package/dist/ClearIcon.svelte +22 -0
- package/dist/ClearIcon.svelte.d.ts +26 -0
- package/dist/LoadingIcon.svelte +33 -0
- package/dist/LoadingIcon.svelte.d.ts +26 -0
- package/dist/Select.svelte +1461 -0
- package/dist/Select.svelte.d.ts +4 -0
- package/dist/aria-handlers.svelte.d.ts +19 -0
- package/dist/aria-handlers.svelte.js +36 -0
- package/dist/filter.d.ts +2 -0
- package/dist/filter.js +30 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +10 -0
- package/dist/keyboard-navigation.svelte.d.ts +12 -0
- package/dist/keyboard-navigation.svelte.js +124 -0
- package/dist/styles/default.css +387 -0
- package/dist/tailwind.css +130 -0
- package/dist/types.d.ts +134 -0
- package/dist/types.js +1 -0
- package/dist/utils.d.ts +10 -0
- package/dist/utils.js +28 -0
- package/package.json +86 -0
|
@@ -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>
|