@kws3/ui 1.8.3 → 1.8.4
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/CHANGELOG.mdx +5 -0
- package/forms/AutoComplete.svelte +426 -0
- package/forms/select/MultiSelect.svelte +9 -1
- package/index.js +1 -0
- package/package.json +2 -2
- package/styles/AutoComplete.scss +132 -0
package/CHANGELOG.mdx
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
## 1.8.4
|
|
2
|
+
- New `AutoComplete` component
|
|
3
|
+
- Make options text size match the input `size` in `MultiSelect` and `SearchableSelect`.
|
|
4
|
+
- Prevent default arrow up/down behaviour on `MultiSelect` and `SearchableSelect` when options dropdown is open.
|
|
5
|
+
|
|
1
6
|
## 1.8.3
|
|
2
7
|
- Allow `clickableRows` and `bulk_actions` to work at the same time on `GridView`
|
|
3
8
|
- Various bugfixes on `GridRow`
|
|
@@ -0,0 +1,426 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
@component
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
@param {string} [value=""] - Value of the Input
|
|
6
|
+
|
|
7
|
+
This property can be bound to, to fetch the current value, Default: `""`
|
|
8
|
+
@param {string} [placeholder=""] - Placeholder text for the input, Default: `""`
|
|
9
|
+
@param {array} [options=[]] - Array of strings, or objects.
|
|
10
|
+
Used to populate the list of options in the dropdown, Default: `[]`
|
|
11
|
+
@param {function|null} [search=null] - Async function to fetch options
|
|
12
|
+
|
|
13
|
+
Only send this prop if you want to fetch `options` asynchronously.
|
|
14
|
+
`options` prop will be ignored if this prop is set., Default: `null`
|
|
15
|
+
@param {'fuzzy'|'strict'} [search_strategy="fuzzy"] - Filtered options to be displayed strictly based on search text or perform a fuzzy match.
|
|
16
|
+
Fuzzy match will not work if `search` function is set, as the backend service is meant to do the matching., Default: `"fuzzy"`
|
|
17
|
+
@param {boolean} [highlighted_results=true] - Whether to show the highlighted or plain results in the dropdown., Default: `true`
|
|
18
|
+
@param {''|'small'|'medium'|'large'} [size=""] - Size of the input, Default: `""`
|
|
19
|
+
@param {''|'primary'|'success'|'warning'|'info'|'danger'|'dark'|'light'} [color=""] - Color of the input, Default: `""`
|
|
20
|
+
@param {string} [style=""] - Inline CSS for input container, Default: `""`
|
|
21
|
+
@param {boolean} [readonly=false] - Marks component as read-only, Default: `false`
|
|
22
|
+
@param {boolean} [disabled=false] - Disables the component, Default: `false`
|
|
23
|
+
@param {HTMLElement|string} [dropdown_portal=undefined] - Where to render the dropdown list.
|
|
24
|
+
Can be a DOM element or a `string` with the CSS selector of the element.
|
|
25
|
+
|
|
26
|
+
By default it renders in a custom container appended to `document.body`., Default: `undefined`
|
|
27
|
+
@param {string} [class=""] - CSS classes for input container, Default: `""`
|
|
28
|
+
|
|
29
|
+
### Events
|
|
30
|
+
- `change`
|
|
31
|
+
- `blur` - Triggered when the input loses focus
|
|
32
|
+
|
|
33
|
+
### Slots
|
|
34
|
+
- `<slot name="default" {option} />` - Slot containing text for each selectable item
|
|
35
|
+
|
|
36
|
+
Default value: `<span>{option.label}</span>`
|
|
37
|
+
|
|
38
|
+
-->
|
|
39
|
+
<div
|
|
40
|
+
bind:this={el}
|
|
41
|
+
class="
|
|
42
|
+
kws-autocomplete input
|
|
43
|
+
{disabled ? 'is-disabled' : ''}
|
|
44
|
+
{readonly ? 'is-readonly' : ''}
|
|
45
|
+
is-{size} is-{color} {klass}
|
|
46
|
+
"
|
|
47
|
+
class:readonly
|
|
48
|
+
{style}
|
|
49
|
+
on:click|stopPropagation={() => input && input.focus()}>
|
|
50
|
+
<input
|
|
51
|
+
class="input is-{size}"
|
|
52
|
+
bind:this={input}
|
|
53
|
+
autocomplete="off"
|
|
54
|
+
{disabled}
|
|
55
|
+
{readonly}
|
|
56
|
+
bind:value
|
|
57
|
+
on:keydown={handleKeydown}
|
|
58
|
+
on:blur={blurEvent}
|
|
59
|
+
on:blur={() => setOptionsVisible(false)}
|
|
60
|
+
{placeholder} />
|
|
61
|
+
{#if search && options_loading}
|
|
62
|
+
<button
|
|
63
|
+
type="button"
|
|
64
|
+
style="border: none;"
|
|
65
|
+
class="button is-paddingless delete is-medium is-loading" />
|
|
66
|
+
{/if}
|
|
67
|
+
{#if rootContainer}
|
|
68
|
+
<div class="kws-autocomplete" use:portal={dropdown_portal}>
|
|
69
|
+
<ul bind:this={dropdown} class="options" class:hidden={!show_options}>
|
|
70
|
+
{#each filtered_options as option}
|
|
71
|
+
<li
|
|
72
|
+
on:mousedown|preventDefault|stopPropagation={() =>
|
|
73
|
+
handleOptionMouseDown(option)}
|
|
74
|
+
on:mouseenter|preventDefault|stopPropagation={() => {
|
|
75
|
+
active_option = option;
|
|
76
|
+
}}
|
|
77
|
+
class="is-size-{list_text_size[size]}"
|
|
78
|
+
class:active={active_option === option}>
|
|
79
|
+
<!--
|
|
80
|
+
Slot containing text for each selectable item
|
|
81
|
+
|
|
82
|
+
Default value: `<span>{option.label}</span>`
|
|
83
|
+
-->
|
|
84
|
+
<slot {option}>
|
|
85
|
+
<!-- eslint-disable-next-line @ota-meshi/svelte/no-at-html-tags -->
|
|
86
|
+
{@html option.label}
|
|
87
|
+
</slot>
|
|
88
|
+
</li>
|
|
89
|
+
{/each}
|
|
90
|
+
</ul>
|
|
91
|
+
</div>
|
|
92
|
+
{/if}
|
|
93
|
+
</div>
|
|
94
|
+
|
|
95
|
+
<script>
|
|
96
|
+
import { portal } from "@kws3/ui";
|
|
97
|
+
import { debounce } from "@kws3/ui/utils";
|
|
98
|
+
import { createEventDispatcher, onMount, tick } from "svelte";
|
|
99
|
+
import { createPopper } from "@popperjs/core";
|
|
100
|
+
import fuzzysearch from "@kws3/ui/utils/fuzzysearch";
|
|
101
|
+
|
|
102
|
+
const sameWidthPopperModifier = {
|
|
103
|
+
name: "sameWidth",
|
|
104
|
+
enabled: true,
|
|
105
|
+
phase: "beforeWrite",
|
|
106
|
+
requires: ["computeStyles"],
|
|
107
|
+
fn: ({ state }) => {
|
|
108
|
+
state.styles.popper.width = `${Math.max(
|
|
109
|
+
200,
|
|
110
|
+
state.rects.reference.width
|
|
111
|
+
)}px`;
|
|
112
|
+
},
|
|
113
|
+
effect: ({ state }) => {
|
|
114
|
+
state.elements.popper.style.width = `${state.elements.reference.offsetWidth}px`;
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
const rootContainerId = "kws-overlay-root";
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Value of the Input
|
|
122
|
+
*
|
|
123
|
+
* This property can be bound to, to fetch the current value
|
|
124
|
+
*/
|
|
125
|
+
export let value = "";
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Placeholder text for the input
|
|
129
|
+
*/
|
|
130
|
+
export let placeholder = "";
|
|
131
|
+
/**
|
|
132
|
+
* Array of strings, or objects.
|
|
133
|
+
* Used to populate the list of options in the dropdown
|
|
134
|
+
*/
|
|
135
|
+
export let options = [];
|
|
136
|
+
/**
|
|
137
|
+
* Async function to fetch options
|
|
138
|
+
*
|
|
139
|
+
* Only send this prop if you want to fetch `options` asynchronously.
|
|
140
|
+
* `options` prop will be ignored if this prop is set.
|
|
141
|
+
*
|
|
142
|
+
* @type {function|null}
|
|
143
|
+
*/
|
|
144
|
+
export let search = null;
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Filtered options to be displayed strictly based on search text or perform a fuzzy match.
|
|
148
|
+
* Fuzzy match will not work if `search` function is set, as the backend service is meant to do the matching.
|
|
149
|
+
* @type {'fuzzy'|'strict'}
|
|
150
|
+
*/
|
|
151
|
+
export let search_strategy = "fuzzy";
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Whether to show the highlighted or plain results in the dropdown.
|
|
155
|
+
*/
|
|
156
|
+
export let highlighted_results = true;
|
|
157
|
+
/**
|
|
158
|
+
* Size of the input
|
|
159
|
+
* @type {''|'small'|'medium'|'large'}
|
|
160
|
+
*/
|
|
161
|
+
export let size = "";
|
|
162
|
+
/**
|
|
163
|
+
* Color of the input
|
|
164
|
+
* @type {''|'primary'|'success'|'warning'|'info'|'danger'|'dark'|'light'}
|
|
165
|
+
*/
|
|
166
|
+
export let color = "";
|
|
167
|
+
/**
|
|
168
|
+
* Inline CSS for input container
|
|
169
|
+
*/
|
|
170
|
+
export let style = "";
|
|
171
|
+
/**
|
|
172
|
+
* Marks component as read-only
|
|
173
|
+
*/
|
|
174
|
+
export let readonly = false;
|
|
175
|
+
/**
|
|
176
|
+
* Disables the component
|
|
177
|
+
*/
|
|
178
|
+
export let disabled = false;
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Where to render the dropdown list.
|
|
182
|
+
* Can be a DOM element or a `string` with the CSS selector of the element.
|
|
183
|
+
*
|
|
184
|
+
* By default it renders in a custom container appended to `document.body`.
|
|
185
|
+
*
|
|
186
|
+
* @type { HTMLElement|string}
|
|
187
|
+
*/
|
|
188
|
+
export let dropdown_portal = "#" + rootContainerId;
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* CSS classes for input container
|
|
192
|
+
*/
|
|
193
|
+
let klass = "";
|
|
194
|
+
export { klass as class };
|
|
195
|
+
|
|
196
|
+
if (!search && (!options || !options.length))
|
|
197
|
+
console.error(`Missing options`);
|
|
198
|
+
|
|
199
|
+
//ensure we have a root container for all our hoisitng related stuff
|
|
200
|
+
|
|
201
|
+
let rootContainer = document.getElementById(rootContainerId);
|
|
202
|
+
if (!rootContainer) {
|
|
203
|
+
rootContainer = document.createElement("div");
|
|
204
|
+
rootContainer.id = rootContainerId;
|
|
205
|
+
document.body.appendChild(rootContainer);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const fire = createEventDispatcher();
|
|
209
|
+
|
|
210
|
+
let el, //whole wrapping element
|
|
211
|
+
dropdown, //dropdown ul
|
|
212
|
+
input, //the textbox to type in
|
|
213
|
+
POPPER,
|
|
214
|
+
active_option = "",
|
|
215
|
+
searching = true,
|
|
216
|
+
show_options = false,
|
|
217
|
+
filtered_options = [], //list of options filtered by search query
|
|
218
|
+
normalised_options = [], //list of options normalised
|
|
219
|
+
options_loading = false, //indictaes whether async search function is running
|
|
220
|
+
mounted = false; //indicates whether component is mounted
|
|
221
|
+
|
|
222
|
+
let list_text_size = {
|
|
223
|
+
small: "7",
|
|
224
|
+
medium: "5",
|
|
225
|
+
large: "4",
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
$: asyncMode = search && typeof search === "function";
|
|
229
|
+
|
|
230
|
+
$: options, normaliseOptions();
|
|
231
|
+
$: searching, updateFilteredOptions(value);
|
|
232
|
+
|
|
233
|
+
$: allow_fuzzy_match = !search && search_strategy === "fuzzy";
|
|
234
|
+
|
|
235
|
+
//convert arrays of strings into normalised arrays of objects
|
|
236
|
+
function normaliseOptions() {
|
|
237
|
+
let _items = options || [];
|
|
238
|
+
if (!_items || !(_items instanceof Array)) {
|
|
239
|
+
normalised_options = [];
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
normalised_options = normaliseArraysToObjects(_items);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function updateFilteredOptions(value) {
|
|
247
|
+
if (!mounted) return;
|
|
248
|
+
|
|
249
|
+
if (asyncMode) {
|
|
250
|
+
searching && debouncedTriggerSearch(sanitizeFilters(value));
|
|
251
|
+
} else {
|
|
252
|
+
searching && triggerSearch(sanitizeFilters(value));
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function triggerSearch(filters) {
|
|
257
|
+
let cache = {};
|
|
258
|
+
//TODO - can optimize more for very long lists
|
|
259
|
+
filters.forEach((word, idx) => {
|
|
260
|
+
// iterate over each word in the search query
|
|
261
|
+
let opts = [];
|
|
262
|
+
if (word) {
|
|
263
|
+
opts = [...normalised_options].filter((item) => {
|
|
264
|
+
// filter out items that don't match `filter`
|
|
265
|
+
if (typeof item === "object" && item.value) {
|
|
266
|
+
return typeof item.value === "string" && match(word, item.value);
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
cache[idx] = opts; // storing options to current index on cache
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
filtered_options = Object.values(cache) // get values from cache
|
|
275
|
+
.flat() // flatten array
|
|
276
|
+
.filter((v, i, self) => self.indexOf(v) === i); // remove duplicates
|
|
277
|
+
|
|
278
|
+
if (highlighted_results) {
|
|
279
|
+
filtered_options = highlightMatches(filtered_options, filters);
|
|
280
|
+
}
|
|
281
|
+
setOptionsVisible(true);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
function triggerExternalSearch(filters) {
|
|
285
|
+
if (!filters.length) {
|
|
286
|
+
//do not trigger async search if filters are empty
|
|
287
|
+
clearDropDownResults();
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
options_loading = true;
|
|
291
|
+
// filtered_options = [];
|
|
292
|
+
search(filters).then((_options) => {
|
|
293
|
+
searching = false;
|
|
294
|
+
options_loading = false;
|
|
295
|
+
tick().then(() => {
|
|
296
|
+
filtered_options = normaliseArraysToObjects(_options);
|
|
297
|
+
|
|
298
|
+
if (highlighted_results) {
|
|
299
|
+
filtered_options = highlightMatches(filtered_options, filters);
|
|
300
|
+
}
|
|
301
|
+
setOptionsVisible(true);
|
|
302
|
+
});
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const debouncedTriggerSearch = debounce(triggerExternalSearch, 150, false);
|
|
307
|
+
|
|
308
|
+
onMount(() => {
|
|
309
|
+
POPPER = createPopper(el, dropdown, {
|
|
310
|
+
strategy: "fixed",
|
|
311
|
+
placement: "bottom-start",
|
|
312
|
+
modifiers: [sameWidthPopperModifier],
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
//normalize value
|
|
316
|
+
if (value === null || typeof value == "undefined") {
|
|
317
|
+
value = null;
|
|
318
|
+
}
|
|
319
|
+
mounted = true;
|
|
320
|
+
|
|
321
|
+
return () => {
|
|
322
|
+
POPPER.destroy();
|
|
323
|
+
};
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
function setOptionsVisible(show) {
|
|
327
|
+
if (readonly || disabled || show === show_options) return;
|
|
328
|
+
if (!value || !filtered_options.length) {
|
|
329
|
+
show = false;
|
|
330
|
+
}
|
|
331
|
+
show_options = show;
|
|
332
|
+
if (!show) {
|
|
333
|
+
clearDropDownResults();
|
|
334
|
+
}
|
|
335
|
+
POPPER && POPPER.update();
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
function handleKeydown(event) {
|
|
339
|
+
if (event.key === `Enter`) {
|
|
340
|
+
show_options && event.preventDefault();
|
|
341
|
+
|
|
342
|
+
if (active_option) {
|
|
343
|
+
handleOptionMouseDown(active_option);
|
|
344
|
+
} else {
|
|
345
|
+
// no active option means no option is selected and the actual value should be what typed in input.
|
|
346
|
+
setOptionsVisible(false);
|
|
347
|
+
}
|
|
348
|
+
} else if ([`ArrowDown`, `ArrowUp`].includes(event.key)) {
|
|
349
|
+
show_options && event.preventDefault();
|
|
350
|
+
|
|
351
|
+
const increment = event.key === `ArrowUp` ? -1 : 1;
|
|
352
|
+
const newActiveIdx = filtered_options.indexOf(active_option) + increment;
|
|
353
|
+
|
|
354
|
+
if (newActiveIdx < 0) {
|
|
355
|
+
active_option = filtered_options[filtered_options.length - 1];
|
|
356
|
+
} else {
|
|
357
|
+
if (newActiveIdx === filtered_options.length)
|
|
358
|
+
active_option = filtered_options[0];
|
|
359
|
+
else active_option = filtered_options[newActiveIdx];
|
|
360
|
+
}
|
|
361
|
+
} else {
|
|
362
|
+
active_option = "";
|
|
363
|
+
searching = true;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
function handleOptionMouseDown(option) {
|
|
368
|
+
add(option);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
function add(token) {
|
|
372
|
+
if (readonly || disabled) {
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
value = token.value;
|
|
377
|
+
fire("change", { token, type: `add` });
|
|
378
|
+
|
|
379
|
+
setOptionsVisible(false);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
function blurEvent() {
|
|
383
|
+
/**
|
|
384
|
+
* Triggered when the input loses focus
|
|
385
|
+
*/
|
|
386
|
+
fire("blur");
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
const match = (needle, haystack) => {
|
|
390
|
+
let _hayStack = haystack.toLowerCase();
|
|
391
|
+
return allow_fuzzy_match
|
|
392
|
+
? fuzzysearch(needle, _hayStack)
|
|
393
|
+
: _hayStack.indexOf(needle) > -1;
|
|
394
|
+
};
|
|
395
|
+
|
|
396
|
+
const normaliseArraysToObjects = (arr) =>
|
|
397
|
+
[...arr].map((item) =>
|
|
398
|
+
typeof item === "object" ? item : { label: item, value: item }
|
|
399
|
+
);
|
|
400
|
+
|
|
401
|
+
const highlightMatches = (options, filters) => {
|
|
402
|
+
if (!filters.length) return options;
|
|
403
|
+
// join all filter parts and split into chars and filter out duplicates
|
|
404
|
+
let common_chars = [...filters.join("")].filter(
|
|
405
|
+
(v, i, self) => self.indexOf(v) === i
|
|
406
|
+
);
|
|
407
|
+
let pattern = new RegExp(`[${common_chars.join("")}]`, "gi");
|
|
408
|
+
return options.map((item) => {
|
|
409
|
+
return {
|
|
410
|
+
...item,
|
|
411
|
+
label: item.value.replace(
|
|
412
|
+
pattern,
|
|
413
|
+
(match) => `<span class="h">${match}</span>`
|
|
414
|
+
),
|
|
415
|
+
};
|
|
416
|
+
});
|
|
417
|
+
};
|
|
418
|
+
|
|
419
|
+
const clearDropDownResults = () => {
|
|
420
|
+
filtered_options = [];
|
|
421
|
+
searching = false;
|
|
422
|
+
};
|
|
423
|
+
function sanitizeFilters(v) {
|
|
424
|
+
return v && v.trim() ? v.toLowerCase().trim().split(/\s+/) : [];
|
|
425
|
+
}
|
|
426
|
+
</script>
|
|
@@ -131,6 +131,7 @@ Default value: `<span>{option[search_key] || option}</span>`
|
|
|
131
131
|
on:mouseenter|preventDefault|stopPropagation={() => {
|
|
132
132
|
activeOption = option;
|
|
133
133
|
}}
|
|
134
|
+
class="is-size-{list_text_size[size]}"
|
|
134
135
|
class:selected={isSelected(option)}
|
|
135
136
|
class:active={activeOption === option}>
|
|
136
137
|
<span class="kws-selected-icon"
|
|
@@ -145,7 +146,7 @@ Default value: `<span>{option[search_key] || option}</span>`
|
|
|
145
146
|
</li>
|
|
146
147
|
{:else}
|
|
147
148
|
{#if !options_loading}
|
|
148
|
-
<li class="no-options">
|
|
149
|
+
<li class="no-options is-size-{list_text_size[size]}">
|
|
149
150
|
{searchText ? no_options_msg : async_search_prompt}
|
|
150
151
|
</li>
|
|
151
152
|
{/if}
|
|
@@ -322,6 +323,12 @@ Default value: `<span>{option[search_key] || option}</span>`
|
|
|
322
323
|
selectedOptions = [], //list of options that are selected
|
|
323
324
|
options_loading = false; //indictaes whether async search function is running
|
|
324
325
|
|
|
326
|
+
let list_text_size = {
|
|
327
|
+
small: "7",
|
|
328
|
+
medium: "5",
|
|
329
|
+
large: "4",
|
|
330
|
+
};
|
|
331
|
+
|
|
325
332
|
$: single = max === 1;
|
|
326
333
|
$: asyncMode = search && typeof search === "function";
|
|
327
334
|
$: hasValue = single
|
|
@@ -603,6 +610,7 @@ Default value: `<span>{option[search_key] || option}</span>`
|
|
|
603
610
|
setOptionsVisible(true);
|
|
604
611
|
}
|
|
605
612
|
} else if ([`ArrowDown`, `ArrowUp`].includes(event.key)) {
|
|
613
|
+
showOptions && event.preventDefault();
|
|
606
614
|
const increment = event.key === `ArrowUp` ? -1 : 1;
|
|
607
615
|
const newActiveIdx = filteredOptions.indexOf(activeOption) + increment;
|
|
608
616
|
|
package/index.js
CHANGED
|
@@ -49,6 +49,7 @@ export { default as Transition } from "./transitions/Transition.svelte";
|
|
|
49
49
|
export { default as SlidingPane } from "./sliding-panes/SlidingPane.svelte";
|
|
50
50
|
export { default as SlidingPaneSet } from "./sliding-panes/SlidingPaneSet.svelte";
|
|
51
51
|
|
|
52
|
+
export { default as AutoComplete } from "./forms/AutoComplete.svelte";
|
|
52
53
|
export { default as SearchableSelect } from "./forms/select/SearchableSelect.svelte";
|
|
53
54
|
export { default as MultiSelect } from "./forms/select/MultiSelect.svelte";
|
|
54
55
|
export { default as MaskedInput } from "./forms/MaskedInput.svelte";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kws3/ui",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.4",
|
|
4
4
|
"description": "UI components for use with Svelte v3 applications.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -29,5 +29,5 @@
|
|
|
29
29
|
"text-mask-core": "^5.1.2",
|
|
30
30
|
"tippy.js": "^6.3.1"
|
|
31
31
|
},
|
|
32
|
-
"gitHead": "
|
|
32
|
+
"gitHead": "440bdaf5e02a0a7ab0b69c2122c2c56da3485c1f"
|
|
33
33
|
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
$kws-theme-colors: $colors !default;
|
|
2
|
+
$kws-autocomplete-radius: $radius !default;
|
|
3
|
+
$kws-autocomplete-border-color: $input-border-color !default;
|
|
4
|
+
$kws-autocomplete-box-shadow: 0 0.5em 1em -0.125em rgb(10 10 10 / 10%),
|
|
5
|
+
0 0px 0 1px rgb(10 10 10 / 2%) !default;
|
|
6
|
+
$kws-autocomplete-focus-border-color: $input-focus-border-color !default;
|
|
7
|
+
$kws-autocomplete-focus-box-shadow-size: $input-focus-box-shadow-size !default;
|
|
8
|
+
$kws-autocomplete-focus-box-shadow-color: $input-focus-box-shadow-color !default;
|
|
9
|
+
$kws-autocomplete-disabled-background-color: $input-disabled-background-color !default;
|
|
10
|
+
$kws-autocomplete-disabled-border-color: $input-disabled-border-color !default;
|
|
11
|
+
$kws-autocomplete-disabled-color: $input-disabled-color !default;
|
|
12
|
+
$kws-autocomplete-selecting-color: $primary-invert !default;
|
|
13
|
+
$kws-autocomplete-selecting-background: $primary !default;
|
|
14
|
+
$kws-autocomplete-text-matches-color: currentColor !default;
|
|
15
|
+
$kws-autocomplete-text-matches-background: transparent !default;
|
|
16
|
+
$kws-autocomplete-text-matches-font-weight: $weight-bold !default;
|
|
17
|
+
|
|
18
|
+
$__modal-z: 41 !default;
|
|
19
|
+
@if $modal-z {
|
|
20
|
+
$__modal-z: $modal-z;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
$kws-autocomplete-options-z-index: $__modal-z + 1 !default;
|
|
24
|
+
|
|
25
|
+
.kws-autocomplete {
|
|
26
|
+
position: relative;
|
|
27
|
+
align-items: center;
|
|
28
|
+
display: flex;
|
|
29
|
+
cursor: text;
|
|
30
|
+
height: auto;
|
|
31
|
+
min-height: 2.5em;
|
|
32
|
+
padding-top: calc(0.4em - 1px);
|
|
33
|
+
padding-bottom: calc(0.4em - 1px);
|
|
34
|
+
&:focus-within {
|
|
35
|
+
border-color: $kws-autocomplete-focus-border-color;
|
|
36
|
+
box-shadow: $kws-autocomplete-focus-box-shadow-size
|
|
37
|
+
$kws-autocomplete-focus-box-shadow-color;
|
|
38
|
+
}
|
|
39
|
+
&.is-disabled {
|
|
40
|
+
background-color: $kws-autocomplete-disabled-background-color;
|
|
41
|
+
border-color: $kws-autocomplete-disabled-border-color;
|
|
42
|
+
color: $kws-autocomplete-disabled-color;
|
|
43
|
+
cursor: not-allowed;
|
|
44
|
+
}
|
|
45
|
+
&.is-readonly {
|
|
46
|
+
box-shadow: none;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
input {
|
|
50
|
+
border: none !important;
|
|
51
|
+
outline: none !important;
|
|
52
|
+
background: none !important;
|
|
53
|
+
/* needed to hide red shadow around required inputs in some browsers */
|
|
54
|
+
box-shadow: none !important;
|
|
55
|
+
color: inherit;
|
|
56
|
+
flex: 1;
|
|
57
|
+
padding: 1pt;
|
|
58
|
+
height: auto;
|
|
59
|
+
min-height: 0;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
ul.options {
|
|
63
|
+
list-style: none;
|
|
64
|
+
max-height: 50vh;
|
|
65
|
+
padding: 0;
|
|
66
|
+
cursor: pointer;
|
|
67
|
+
overflow: auto;
|
|
68
|
+
background: #fff;
|
|
69
|
+
border: 1px solid $kws-autocomplete-border-color;
|
|
70
|
+
box-shadow: $kws-autocomplete-box-shadow;
|
|
71
|
+
position: relative;
|
|
72
|
+
z-index: 4;
|
|
73
|
+
&[data-popper-placement="top"] {
|
|
74
|
+
border-radius: $kws-autocomplete-radius $kws-autocomplete-radius 0 0;
|
|
75
|
+
box-shadow: 0 -1px 6px rgba(0, 0, 0, 0.4);
|
|
76
|
+
}
|
|
77
|
+
&.hidden {
|
|
78
|
+
display: none;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
li {
|
|
82
|
+
padding: 0.3em 0.5em;
|
|
83
|
+
position: relative;
|
|
84
|
+
word-break: break-all;
|
|
85
|
+
&.active {
|
|
86
|
+
// keyboard focused item
|
|
87
|
+
color: $kws-autocomplete-selecting-color;
|
|
88
|
+
background: $kws-autocomplete-selecting-background;
|
|
89
|
+
}
|
|
90
|
+
span.h {
|
|
91
|
+
// highlight text matches
|
|
92
|
+
font-weight: $kws-autocomplete-text-matches-font-weight;
|
|
93
|
+
color: $kws-autocomplete-text-matches-color;
|
|
94
|
+
background: $kws-autocomplete-text-matches-background;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
@each $name, $pair in $kws-theme-colors {
|
|
101
|
+
$color: nth($pair, 1);
|
|
102
|
+
$color-invert: nth($pair, 2);
|
|
103
|
+
$color-light: findLightColor($color);
|
|
104
|
+
$color-dark: findDarkColor($color);
|
|
105
|
+
.kws-autocomplete {
|
|
106
|
+
&.is-#{$name} {
|
|
107
|
+
border-color: $color;
|
|
108
|
+
&:focus-within {
|
|
109
|
+
box-shadow: $input-focus-box-shadow-size bulmaRgba($color, 0.25);
|
|
110
|
+
}
|
|
111
|
+
ul.options {
|
|
112
|
+
li {
|
|
113
|
+
&.selected {
|
|
114
|
+
color: $color-dark;
|
|
115
|
+
background: $color-light;
|
|
116
|
+
}
|
|
117
|
+
&.active {
|
|
118
|
+
color: $color-invert;
|
|
119
|
+
background: $color;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
#kws-overlay-root {
|
|
128
|
+
.kws-autocomplete {
|
|
129
|
+
position: absolute;
|
|
130
|
+
z-index: $kws-autocomplete-options-z-index;
|
|
131
|
+
}
|
|
132
|
+
}
|