|
58 | 58 | options |
59 | 59 | ?.filter((op) => (op as ObjectOption)?.preselected) |
60 | 60 | .slice(0, maxSelect ?? undefined) ?? [] |
61 | | - export let selectedLabels: (string | number)[] | string | number | null = [] |
62 | | - export let selectedValues: unknown[] | unknown | null = [] |
63 | 61 | export let sortSelected: boolean | ((op1: Option, op2: Option) => number) = false |
64 | 62 | export let ulOptionsClass: string = `` |
65 | 63 | export let ulSelectedClass: string = `` |
66 | 64 |
|
67 | 65 | // get the label key from an option object or the option itself if it's a string or number |
68 | 66 | const get_label = (op: Option) => (op instanceof Object ? op.label : op) |
69 | 67 |
|
70 | | - // fallback on label if option is object and value is undefined |
71 | | - const get_value = (op: Option) => (op instanceof Object ? op.value ?? op.label : op) |
72 | | -
|
73 | 68 | // selected and _selected are identical except if maxSelect=1, selected will be the single item (or null) |
74 | 69 | // in _selected which will always be an array for easier component internals. selected then solves |
75 | 70 | // https://github.com/janosh/svelte-multiselect/issues/86 |
76 | 71 | let _selected = (selected ?? []) as Option[] |
77 | 72 | $: selected = maxSelect === 1 ? _selected[0] ?? null : _selected |
78 | 73 |
|
79 | 74 | let wiggle = false // controls wiggle animation when user tries to exceed maxSelect |
80 | | - $: _selectedLabels = _selected?.map(get_label) ?? [] |
81 | | - $: selectedLabels = maxSelect === 1 ? _selectedLabels[0] ?? null : _selectedLabels |
82 | | - $: _selectedValues = _selected?.map(get_value) ?? [] |
83 | | - $: selectedValues = maxSelect === 1 ? _selectedValues[0] ?? null : _selectedValues |
84 | 75 |
|
85 | 76 | type $$Events = MultiSelectEvents // for type-safe event listening on this component |
86 | 77 |
|
|
112 | 103 |
|
113 | 104 | // options matching the current search text |
114 | 105 | $: matchingOptions = options.filter( |
115 | | - (op) => filterFunc(op, searchText) && !_selectedLabels.includes(get_label(op)) // remove already selected options from dropdown list |
| 106 | + (op) => |
| 107 | + filterFunc(op, searchText) && !_selected.map(get_label).includes(get_label(op)) // remove already selected options from dropdown list |
116 | 108 | ) |
117 | 109 | // raise if matchingOptions[activeIndex] does not yield a value |
118 | 110 | if (activeIndex !== null && !matchingOptions[activeIndex]) { |
|
124 | 116 | // add an option to selected list |
125 | 117 | function add(label: string | number, event: Event) { |
126 | 118 | if (maxSelect && maxSelect > 1 && _selected.length >= maxSelect) wiggle = true |
127 | | - if (!isNaN(Number(label)) && typeof _selectedLabels[0] === `number`) |
| 119 | + if (!isNaN(Number(label)) && typeof _selected.map(get_label)[0] === `number`) |
128 | 120 | label = Number(label) // convert to number if possible |
129 | 121 |
|
130 | 122 | const is_duplicate = _selected.some((option) => duplicateFunc(option, label)) |
|
200 | 192 | function remove(label: string | number) { |
201 | 193 | if (_selected.length === 0) return |
202 | 194 |
|
203 | | - _selected.splice(_selectedLabels.lastIndexOf(label), 1) |
| 195 | + _selected.splice(_selected.map(get_label).lastIndexOf(label), 1) |
204 | 196 | _selected = _selected // Svelte rerender after in-place splice |
205 | 197 |
|
206 | 198 | const option = |
|
249 | 241 |
|
250 | 242 | if (activeOption) { |
251 | 243 | const label = get_label(activeOption) |
252 | | - selectedLabels?.includes(label) ? remove(label) : add(label, event) |
| 244 | + _selected.map(get_label).includes(label) ? remove(label) : add(label, event) |
253 | 245 | searchText = `` |
254 | 246 | } else if (allowUserOptions && searchText.length > 0) { |
255 | 247 | // user entered text but no options match, so if allowUserOptions is truthy, we create new option |
|
293 | 285 | } |
294 | 286 | } |
295 | 287 | // on backspace key: remove last selected option |
296 | | - else if (event.key === `Backspace` && _selectedLabels.length > 0 && !searchText) { |
297 | | - remove(_selectedLabels.at(-1) as string | number) |
| 288 | + else if (event.key === `Backspace` && _selected.length > 0 && !searchText) { |
| 289 | + remove(_selected.map(get_label).at(-1) as string | number) |
298 | 290 | } |
299 | 291 | } |
300 | 292 |
|
|
305 | 297 | searchText = `` |
306 | 298 | } |
307 | 299 |
|
308 | | - $: is_selected = (label: string | number) => _selectedLabels.includes(label) |
| 300 | + $: is_selected = (label: string | number) => _selected.map(get_label).includes(label) |
309 | 301 |
|
310 | 302 | const if_enter_or_space = (handler: () => void) => (event: KeyboardEvent) => { |
311 | 303 | if ([`Enter`, `Space`].includes(event.code)) { |
|
0 commit comments