sveltacular 0.0.21 → 0.0.23
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.
|
@@ -5,6 +5,7 @@ import { uniqueId } from "../../helpers/unique-id.js";
|
|
|
5
5
|
import Menu from "../../generic/menu/menu.svelte";
|
|
6
6
|
import AngleUpIcon from "../../icons/angle-up-icon.svelte";
|
|
7
7
|
import debounce from "../../helpers/debounce.js";
|
|
8
|
+
import { browser } from "$app/environment";
|
|
8
9
|
export let value = "";
|
|
9
10
|
export let items = [];
|
|
10
11
|
export let size = "full";
|
|
@@ -12,24 +13,34 @@ export let disabled = false;
|
|
|
12
13
|
export let required = false;
|
|
13
14
|
export let searchable = false;
|
|
14
15
|
export let search = void 0;
|
|
16
|
+
const id = uniqueId();
|
|
17
|
+
const dispatch = createEventDispatcher();
|
|
15
18
|
const getText = () => items.find((item) => item.value == value)?.name || "";
|
|
19
|
+
let text = getText();
|
|
20
|
+
let open = false;
|
|
21
|
+
let highlightIndex = -1;
|
|
22
|
+
let filteredItems = [];
|
|
16
23
|
const onSelect = (e) => {
|
|
17
24
|
value = e.detail.value;
|
|
18
25
|
dispatch("change", value);
|
|
19
26
|
text = getText();
|
|
27
|
+
applyFilter();
|
|
20
28
|
open = false;
|
|
21
29
|
};
|
|
30
|
+
const focusOnInput = () => {
|
|
31
|
+
if (browser)
|
|
32
|
+
document.getElementById(id)?.focus();
|
|
33
|
+
};
|
|
22
34
|
const toggle = () => {
|
|
23
35
|
open = !open;
|
|
24
|
-
|
|
25
|
-
document.getElementById(id)?.focus();
|
|
36
|
+
focusOnInput();
|
|
26
37
|
};
|
|
27
38
|
const onInputKeyPress = (e) => {
|
|
28
39
|
if (e.key == "Escape") {
|
|
29
40
|
open = false;
|
|
30
41
|
return;
|
|
31
42
|
}
|
|
32
|
-
if (e.key == "Enter") {
|
|
43
|
+
if (e.key == "Enter" || e.key == "Tab") {
|
|
33
44
|
open = false;
|
|
34
45
|
if (highlightIndex > -1) {
|
|
35
46
|
onSelect(new CustomEvent("select", { detail: filteredItems[highlightIndex] }));
|
|
@@ -47,35 +58,39 @@ const onInputKeyPress = (e) => {
|
|
|
47
58
|
open = false;
|
|
48
59
|
return;
|
|
49
60
|
}
|
|
50
|
-
if (e.key.length == 1) {
|
|
61
|
+
if (e.key.length == 1 || e.key == "Backspace" || e.key == "Delete") {
|
|
51
62
|
open = true;
|
|
52
63
|
highlightIndex = 0;
|
|
53
64
|
triggerSearch();
|
|
54
65
|
}
|
|
55
66
|
};
|
|
56
67
|
const triggerSearch = debounce(async () => {
|
|
57
|
-
dispatch("search", searchText);
|
|
58
68
|
if (search) {
|
|
59
|
-
items = await search(
|
|
60
|
-
|
|
69
|
+
items = await search(text);
|
|
70
|
+
console.log(items);
|
|
61
71
|
}
|
|
72
|
+
updateText();
|
|
73
|
+
applyFilter();
|
|
74
|
+
open = true;
|
|
62
75
|
}, 300);
|
|
63
|
-
const
|
|
76
|
+
const applyFilter = () => {
|
|
77
|
+
const searchText = text.trim().toLowerCase();
|
|
78
|
+
filteredItems = searchText ? items.map((item, index) => ({ ...item, index })).filter((item) => item.name.toLowerCase().includes(searchText)) : items.map((item, index) => ({ ...item, index }));
|
|
79
|
+
};
|
|
80
|
+
const clear = () => {
|
|
81
|
+
text = "";
|
|
82
|
+
value = "";
|
|
83
|
+
triggerSearch();
|
|
84
|
+
focusOnInput();
|
|
85
|
+
};
|
|
64
86
|
const updateText = async () => {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
87
|
+
if (browser) {
|
|
88
|
+
const textBox = document.getElementById(id);
|
|
89
|
+
if (document.activeElement != textBox)
|
|
90
|
+
text = getText();
|
|
91
|
+
open = true;
|
|
92
|
+
}
|
|
68
93
|
};
|
|
69
|
-
const id = uniqueId();
|
|
70
|
-
let text = getText();
|
|
71
|
-
let open = false;
|
|
72
|
-
let highlightIndex = -1;
|
|
73
|
-
$:
|
|
74
|
-
searchText = searchable ? text : "";
|
|
75
|
-
$:
|
|
76
|
-
filteredItems = searchText ? items.map((item, index) => ({ ...item, index })).filter((item) => item.name.toLowerCase().includes(searchText.toLowerCase())) : items.map((item, index) => ({ ...item, index }));
|
|
77
|
-
$:
|
|
78
|
-
items && updateText();
|
|
79
94
|
triggerSearch();
|
|
80
95
|
</script>
|
|
81
96
|
|
|
@@ -99,12 +114,13 @@ triggerSearch();
|
|
|
99
114
|
<button type="button" class="icon" on:click={toggle} on:keydown={toggle}>
|
|
100
115
|
<AngleUpIcon />
|
|
101
116
|
</button>
|
|
117
|
+
<button type="button" class="clear" on:click={clear} on:keydown={clear}> X </button>
|
|
102
118
|
<div class="dropdown">
|
|
103
119
|
<Menu
|
|
104
120
|
items={filteredItems}
|
|
105
121
|
{open}
|
|
106
122
|
closeAfterSelect={false}
|
|
107
|
-
{
|
|
123
|
+
searchText={text}
|
|
108
124
|
on:select={onSelect}
|
|
109
125
|
size="full"
|
|
110
126
|
bind:highlightIndex
|
|
@@ -131,7 +147,7 @@ div input {
|
|
|
131
147
|
user-select: none;
|
|
132
148
|
white-space: nowrap;
|
|
133
149
|
}
|
|
134
|
-
div button
|
|
150
|
+
div button {
|
|
135
151
|
border: 0;
|
|
136
152
|
appearance: none;
|
|
137
153
|
background: transparent;
|
|
@@ -139,14 +155,19 @@ div button.icon {
|
|
|
139
155
|
margin: 0;
|
|
140
156
|
position: absolute;
|
|
141
157
|
top: 0.65rem;
|
|
142
|
-
right: 1rem;
|
|
143
158
|
width: 1rem;
|
|
144
159
|
height: 1rem;
|
|
145
|
-
transition: transform 0.3s linear;
|
|
146
160
|
z-index: 2;
|
|
147
161
|
color: var(--form-input-fg, black);
|
|
162
|
+
}
|
|
163
|
+
div button.icon {
|
|
164
|
+
right: 1rem;
|
|
165
|
+
transition: transform 0.3s linear;
|
|
148
166
|
transform: rotate(180deg);
|
|
149
167
|
}
|
|
168
|
+
div button.clear {
|
|
169
|
+
right: 3rem;
|
|
170
|
+
}
|
|
150
171
|
div.open .icon {
|
|
151
172
|
transform: rotate(0deg);
|
|
152
173
|
}
|