|
1 | 1 | <script lang="ts">
|
2 |
| - import { fly } from 'svelte/transition'; |
3 |
| - import { onMount } from 'svelte'; |
4 |
| - import { clickoutside } from '../actions/clickoutside'; |
5 |
| - |
| 2 | + import { fly } from 'svelte/transition' |
| 3 | + import { onMount } from 'svelte' |
| 4 | + import { clickoutside } from '../actions/clickoutside' |
| 5 | +
|
6 | 6 | interface SelectOption {
|
7 |
| - value: string; |
8 |
| - name: string; |
| 7 | + value: string |
| 8 | + name: string |
9 | 9 | }
|
10 | 10 |
|
11 |
| - export let selectedOptions: Record<string, SelectOption>; |
12 |
| - export let options: SelectOption[]; |
13 |
| - export let placeholder = 'Select...'; |
14 |
| - export let canWriteIn = false; |
15 |
| - export let autofocus = false; |
| 11 | + export let selectedOptions: Record<string, SelectOption> |
| 12 | + export let options: SelectOption[] |
| 13 | + export let placeholder = 'Select...' |
| 14 | + export let canWriteIn = false |
| 15 | + export let autofocus = false |
16 | 16 |
|
17 |
| - let input: HTMLInputElement; |
18 |
| - let inputValue: string; |
19 |
| - let activeOption: SelectOption; |
20 |
| - let showOptions = false; |
| 17 | + let input: HTMLInputElement |
| 18 | + let inputValue: string |
| 19 | + let activeOption: SelectOption |
| 20 | + let showOptions = false |
21 | 21 |
|
22 | 22 | onMount(() => {
|
23 |
| - if (autofocus) input.focus(); |
| 23 | + if (autofocus) input.focus() |
24 | 24 | })
|
25 | 25 |
|
26 |
| - $: filtered = options.filter((o) => |
27 |
| - inputValue ? o.name.toLowerCase().includes(inputValue.trim().toLowerCase()) : o |
28 |
| - ); |
| 26 | + $: filtered = options.filter(o => |
| 27 | + inputValue ? o.name.toLowerCase().includes(inputValue.trim().toLowerCase()) : o, |
| 28 | + ) |
29 | 29 | $: if ((activeOption && !filtered.includes(activeOption)) || (!activeOption && inputValue))
|
30 |
| - [activeOption] = filtered; |
| 30 | + [activeOption] = filtered |
31 | 31 |
|
32 | 32 | function add(option: SelectOption) {
|
33 |
| - selectedOptions[option.value] = option; |
34 |
| - input.focus(); |
35 |
| - inputValue = ''; |
| 33 | + selectedOptions[option.value] = option |
| 34 | + input.focus() |
| 35 | + inputValue = '' |
36 | 36 | }
|
37 | 37 |
|
38 | 38 | function remove(value: string) {
|
39 |
| - const { [value]: option, ...restOfOptions } = selectedOptions; |
40 |
| - selectedOptions = restOfOptions; |
| 39 | + const { [value]: _option, ...restOfOptions } = selectedOptions |
| 40 | + selectedOptions = restOfOptions |
41 | 41 | }
|
42 | 42 |
|
43 | 43 | function setShowOptions(show: boolean) {
|
44 |
| - showOptions = show; |
45 |
| - if (show) input.focus(); |
46 |
| - if (!show) activeOption = undefined; |
| 44 | + showOptions = show |
| 45 | + if (show) input.focus() |
| 46 | + if (!show) activeOption = undefined |
47 | 47 | }
|
48 | 48 |
|
49 | 49 | function handleKeydown(e: KeyboardEvent) {
|
|
52 | 52 | if (e.key === ' ' && activeOption)
|
53 | 53 | add(activeOption)
|
54 | 54 | if (e.key === 'Backspace' && !inputValue)
|
55 |
| - remove(Object.keys(selectedOptions).pop()); |
| 55 | + remove(Object.keys(selectedOptions).pop()) |
56 | 56 | if (e.key === 'Enter') {
|
57 |
| - e.preventDefault(); // keep form from submitting and closing modal |
| 57 | + e.preventDefault() // keep form from submitting and closing modal |
58 | 58 | if (activeOption)
|
59 | 59 | selectOption(activeOption)
|
60 | 60 | else
|
61 | 61 | addWriteInIfApplicable()
|
62 | 62 | }
|
63 | 63 | if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {
|
64 |
| - const increment = e.key === 'ArrowUp' ? -1 : 1; |
65 |
| - const calcIndex = filtered.indexOf(activeOption) + increment; |
66 |
| - activeOption = |
67 |
| - calcIndex < 0 |
| 64 | + const increment = e.key === 'ArrowUp' ? -1 : 1 |
| 65 | + const calcIndex = filtered.indexOf(activeOption) + increment |
| 66 | + activeOption |
| 67 | + = calcIndex < 0 |
68 | 68 | ? filtered[filtered.length - 1]
|
69 | 69 | : calcIndex === filtered.length
|
70 | 70 | ? filtered[0]
|
71 |
| - : filtered[calcIndex]; |
| 71 | + : filtered[calcIndex] |
72 | 72 | }
|
73 | 73 | }
|
74 | 74 |
|
75 | 75 | function addWriteInIfApplicable() {
|
76 | 76 | if (!canWriteIn) return
|
77 |
| - const value = inputValue.trim(); |
| 77 | + const value = inputValue.trim() |
78 | 78 | if (value)
|
79 |
| - add({name: value, value}) |
| 79 | + add({ name: value, value }) |
80 | 80 | }
|
81 | 81 |
|
82 | 82 | function selectOption(option: SelectOption) {
|
83 | 83 | if (selectedOptions[option.value])
|
84 |
| - remove(option.value); |
| 84 | + remove(option.value) |
85 | 85 | else
|
86 |
| - add(option); |
| 86 | + add(option) |
87 | 87 | }
|
88 | 88 | </script>
|
89 | 89 |
|
90 |
| -<div class="multiselect" use:clickoutside on:clickoutside={() => { |
91 |
| - setShowOptions(false) |
92 |
| - addWriteInIfApplicable() |
93 |
| -}}> |
| 90 | +<div |
| 91 | + class="multiselect" |
| 92 | + use:clickoutside |
| 93 | + on:clickoutside={() => { |
| 94 | + setShowOptions(false) |
| 95 | + addWriteInIfApplicable() |
| 96 | + }}> |
94 | 97 | <div class="tokens" class:showOptions on:click={() => setShowOptions(true)}>
|
95 | 98 | {#each Object.values(selectedOptions) as option}
|
96 | 99 | <div
|
|
0 commit comments