svelte-multiselect 10.1.0 → 10.3.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/dist/CmdPalette.svelte +3 -3
- package/dist/MultiSelect.svelte +37 -15
- package/dist/MultiSelect.svelte.d.ts +11 -3
- package/dist/utils.d.ts +1 -1
- package/dist/utils.js +9 -5
- package/package.json +30 -29
- package/readme.md +53 -13
package/dist/CmdPalette.svelte
CHANGED
|
@@ -28,8 +28,8 @@ function close_if_outside(event) {
|
|
|
28
28
|
open = false;
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
|
-
function
|
|
32
|
-
event.detail.option.action();
|
|
31
|
+
function trigger_action_and_close(event) {
|
|
32
|
+
event.detail.option.action(event.detail.option.label);
|
|
33
33
|
open = false;
|
|
34
34
|
}
|
|
35
35
|
</script>
|
|
@@ -42,7 +42,7 @@ function run_and_close(event) {
|
|
|
42
42
|
options={actions}
|
|
43
43
|
bind:input
|
|
44
44
|
{placeholder}
|
|
45
|
-
on:add={
|
|
45
|
+
on:add={trigger_action_and_close}
|
|
46
46
|
on:keydown={toggle}
|
|
47
47
|
{...$$restProps}
|
|
48
48
|
let:option
|
package/dist/MultiSelect.svelte
CHANGED
|
@@ -26,17 +26,22 @@ export let filterFunc = (opt, searchText) => {
|
|
|
26
26
|
return true;
|
|
27
27
|
return `${get_label(opt)}`.toLowerCase().includes(searchText.toLowerCase());
|
|
28
28
|
};
|
|
29
|
-
export let
|
|
29
|
+
export let closeDropdownOnSelect = `desktop`;
|
|
30
30
|
export let form_input = null;
|
|
31
31
|
export let highlightMatches = true;
|
|
32
32
|
export let id = null;
|
|
33
33
|
export let input = null;
|
|
34
34
|
export let inputClass = ``;
|
|
35
|
+
export let inputStyle = null;
|
|
35
36
|
export let inputmode = null;
|
|
36
37
|
export let invalid = false;
|
|
37
38
|
export let liActiveOptionClass = ``;
|
|
39
|
+
export let liActiveUserMsgClass = ``;
|
|
38
40
|
export let liOptionClass = ``;
|
|
41
|
+
export let liOptionStyle = null;
|
|
39
42
|
export let liSelectedClass = ``;
|
|
43
|
+
export let liSelectedStyle = null;
|
|
44
|
+
export let liUserMsgClass = ``;
|
|
40
45
|
export let loading = false;
|
|
41
46
|
export let matchingOptions = [];
|
|
42
47
|
export let maxOptions = undefined;
|
|
@@ -63,8 +68,11 @@ export let selected = options
|
|
|
63
68
|
.slice(0, maxSelect ?? undefined) ?? []; // don't allow more than maxSelect preselected options
|
|
64
69
|
export let sortSelected = false;
|
|
65
70
|
export let selectedOptionsDraggable = !sortSelected;
|
|
71
|
+
export let style = null;
|
|
66
72
|
export let ulOptionsClass = ``;
|
|
67
73
|
export let ulSelectedClass = ``;
|
|
74
|
+
export let ulSelectedStyle = null;
|
|
75
|
+
export let ulOptionsStyle = null;
|
|
68
76
|
export let value = null;
|
|
69
77
|
const selected_to_value = (selected) => {
|
|
70
78
|
value = maxSelect === 1 ? selected[0] ?? null : selected;
|
|
@@ -186,10 +194,13 @@ function add(option, event) {
|
|
|
186
194
|
selected = selected.sort(sortSelected);
|
|
187
195
|
}
|
|
188
196
|
}
|
|
189
|
-
|
|
197
|
+
const reached_max_select = selected.length === maxSelect;
|
|
198
|
+
const dropdown_should_close = closeDropdownOnSelect === true ||
|
|
199
|
+
(closeDropdownOnSelect === `desktop` && window_width < breakpoint);
|
|
200
|
+
if (reached_max_select || dropdown_should_close) {
|
|
190
201
|
close_dropdown(event);
|
|
191
|
-
|
|
192
|
-
|
|
202
|
+
}
|
|
203
|
+
else if (!dropdown_should_close) {
|
|
193
204
|
input?.focus();
|
|
194
205
|
}
|
|
195
206
|
dispatch(`add`, { option });
|
|
@@ -302,10 +313,10 @@ async function handle_keydown(event) {
|
|
|
302
313
|
}
|
|
303
314
|
}
|
|
304
315
|
function remove_all() {
|
|
305
|
-
selected = [];
|
|
306
|
-
searchText = ``;
|
|
307
316
|
dispatch(`removeAll`, { options: selected });
|
|
308
317
|
dispatch(`change`, { options: selected, type: `removeAll` });
|
|
318
|
+
selected = [];
|
|
319
|
+
searchText = ``;
|
|
309
320
|
}
|
|
310
321
|
$: is_selected = (label) => selected.map(get_label).includes(label);
|
|
311
322
|
const if_enter_or_space = (handler) => (event) => {
|
|
@@ -350,7 +361,7 @@ let ul_options;
|
|
|
350
361
|
// highlight text matching user-entered search text in available options
|
|
351
362
|
function highlight_matching_options(event) {
|
|
352
363
|
if (!highlightMatches || typeof CSS == `undefined` || !CSS.highlights)
|
|
353
|
-
return; //
|
|
364
|
+
return; // abort if CSS highlight API not supported
|
|
354
365
|
// clear previous ranges from HighlightRegistry
|
|
355
366
|
CSS.highlights.clear();
|
|
356
367
|
// get input's search query
|
|
@@ -392,9 +403,11 @@ function highlight_matching_options(event) {
|
|
|
392
403
|
});
|
|
393
404
|
});
|
|
394
405
|
// create Highlight object from ranges and add to registry
|
|
395
|
-
// eslint-disable-next-line no-undef
|
|
396
406
|
CSS.highlights.set(`sms-search-matches`, new Highlight(...ranges.flat()));
|
|
397
407
|
}
|
|
408
|
+
// reset form validation when required prop changes
|
|
409
|
+
// https://github.com/janosh/svelte-multiselect/issues/285
|
|
410
|
+
$: required, form_input?.setCustomValidity(``);
|
|
398
411
|
</script>
|
|
399
412
|
|
|
400
413
|
<svelte:window
|
|
@@ -415,12 +428,13 @@ function highlight_matching_options(event) {
|
|
|
415
428
|
data-id={id}
|
|
416
429
|
role="searchbox"
|
|
417
430
|
tabindex="-1"
|
|
431
|
+
{style}
|
|
418
432
|
>
|
|
419
433
|
<!-- form control input invisible to the user, only purpose is to abort form submission if this component fails data validation -->
|
|
420
434
|
<!-- bind:value={selected} prevents form submission if required prop is true and no options are selected -->
|
|
421
435
|
<input
|
|
422
436
|
{name}
|
|
423
|
-
|
|
437
|
+
{required}
|
|
424
438
|
value={selected.length >= Number(required) ? JSON.stringify(selected) : null}
|
|
425
439
|
tabindex="-1"
|
|
426
440
|
aria-hidden="true"
|
|
@@ -443,7 +457,11 @@ function highlight_matching_options(event) {
|
|
|
443
457
|
<slot name="expand-icon" {open}>
|
|
444
458
|
<ExpandIcon width="15px" style="min-width: 1em; padding: 0 1pt; cursor: pointer;" />
|
|
445
459
|
</slot>
|
|
446
|
-
<ul
|
|
460
|
+
<ul
|
|
461
|
+
class="selected {ulSelectedClass}"
|
|
462
|
+
aria-label="selected options"
|
|
463
|
+
style={ulSelectedStyle}
|
|
464
|
+
>
|
|
447
465
|
{#each selected as option, idx (duplicates ? [key(option), idx] : key(option))}
|
|
448
466
|
<li
|
|
449
467
|
class={liSelectedClass}
|
|
@@ -456,7 +474,7 @@ function highlight_matching_options(event) {
|
|
|
456
474
|
on:dragenter={() => (drag_idx = idx)}
|
|
457
475
|
on:dragover|preventDefault
|
|
458
476
|
class:active={drag_idx === idx}
|
|
459
|
-
style={get_style(option, `selected`)}
|
|
477
|
+
style="{get_style(option, `selected`)} {liSelectedStyle}"
|
|
460
478
|
>
|
|
461
479
|
<!-- on:dragover|preventDefault needed for the drop to succeed https://stackoverflow.com/a/31085796 -->
|
|
462
480
|
<slot name="selected" {option} {idx}>
|
|
@@ -485,6 +503,7 @@ function highlight_matching_options(event) {
|
|
|
485
503
|
{/each}
|
|
486
504
|
<input
|
|
487
505
|
class={inputClass}
|
|
506
|
+
style={inputStyle}
|
|
488
507
|
bind:this={input}
|
|
489
508
|
bind:value={searchText}
|
|
490
509
|
on:mouseup|self|stopPropagation={open_dropdown}
|
|
@@ -567,6 +586,7 @@ function highlight_matching_options(event) {
|
|
|
567
586
|
aria-expanded={open}
|
|
568
587
|
aria-disabled={disabled ? `true` : null}
|
|
569
588
|
bind:this={ul_options}
|
|
589
|
+
style={ulOptionsStyle}
|
|
570
590
|
>
|
|
571
591
|
{#each matchingOptions.slice(0, Math.max(0, maxOptions ?? 0) || Infinity) as option, idx}
|
|
572
592
|
{@const {
|
|
@@ -599,7 +619,7 @@ function highlight_matching_options(event) {
|
|
|
599
619
|
on:blur={() => (activeIndex = null)}
|
|
600
620
|
role="option"
|
|
601
621
|
aria-selected="false"
|
|
602
|
-
style={get_style(option, `option`)}
|
|
622
|
+
style="{get_style(option, `option`)} {liOptionStyle}"
|
|
603
623
|
>
|
|
604
624
|
<slot name="option" {option} {idx}>
|
|
605
625
|
<slot {option} {idx}>
|
|
@@ -615,9 +635,9 @@ function highlight_matching_options(event) {
|
|
|
615
635
|
{#if searchText}
|
|
616
636
|
{@const text_input_is_duplicate = selected.map(get_label).includes(searchText)}
|
|
617
637
|
{@const is_dupe = !duplicates && text_input_is_duplicate && `dupe`}
|
|
618
|
-
{@const can_create = allowUserOptions && createOptionMsg && `create`}
|
|
638
|
+
{@const can_create = Boolean(allowUserOptions && createOptionMsg) && `create`}
|
|
619
639
|
{@const no_match =
|
|
620
|
-
matchingOptions?.length == 0 && noMatchingOptionsMsg && `no-match`}
|
|
640
|
+
Boolean(matchingOptions?.length == 0 && noMatchingOptionsMsg) && `no-match`}
|
|
621
641
|
{@const msgType = is_dupe || can_create || no_match}
|
|
622
642
|
{#if msgType}
|
|
623
643
|
{@const msg = {
|
|
@@ -638,7 +658,9 @@ function highlight_matching_options(event) {
|
|
|
638
658
|
on:blur={() => (option_msg_is_active = false)}
|
|
639
659
|
role="option"
|
|
640
660
|
aria-selected="false"
|
|
641
|
-
class="user-msg
|
|
661
|
+
class="user-msg {liUserMsgClass} {option_msg_is_active
|
|
662
|
+
? liActiveUserMsgClass
|
|
663
|
+
: ``}"
|
|
642
664
|
style:cursor={{
|
|
643
665
|
dupe: `not-allowed`,
|
|
644
666
|
create: `pointer`,
|
|
@@ -17,17 +17,22 @@ declare class __sveltets_Render<Option extends T> {
|
|
|
17
17
|
duplicates?: boolean | undefined;
|
|
18
18
|
key?: ((opt: T) => unknown) | undefined;
|
|
19
19
|
filterFunc?: ((opt: Option, searchText: string) => boolean) | undefined;
|
|
20
|
-
|
|
20
|
+
closeDropdownOnSelect?: boolean | "desktop" | undefined;
|
|
21
21
|
form_input?: HTMLInputElement | null | undefined;
|
|
22
22
|
highlightMatches?: boolean | undefined;
|
|
23
23
|
id?: string | null | undefined;
|
|
24
24
|
input?: HTMLInputElement | null | undefined;
|
|
25
25
|
inputClass?: string | undefined;
|
|
26
|
+
inputStyle?: string | null | undefined;
|
|
26
27
|
inputmode?: string | null | undefined;
|
|
27
28
|
invalid?: boolean | undefined;
|
|
28
29
|
liActiveOptionClass?: string | undefined;
|
|
30
|
+
liActiveUserMsgClass?: string | undefined;
|
|
29
31
|
liOptionClass?: string | undefined;
|
|
32
|
+
liOptionStyle?: string | null | undefined;
|
|
30
33
|
liSelectedClass?: string | undefined;
|
|
34
|
+
liSelectedStyle?: string | null | undefined;
|
|
35
|
+
liUserMsgClass?: string | undefined;
|
|
31
36
|
loading?: boolean | undefined;
|
|
32
37
|
matchingOptions?: Option[] | undefined;
|
|
33
38
|
maxOptions?: number | undefined;
|
|
@@ -52,8 +57,11 @@ declare class __sveltets_Render<Option extends T> {
|
|
|
52
57
|
selected?: Option[] | undefined;
|
|
53
58
|
sortSelected?: boolean | ((op1: Option, op2: Option) => number) | undefined;
|
|
54
59
|
selectedOptionsDraggable?: boolean | undefined;
|
|
60
|
+
style?: string | null | undefined;
|
|
55
61
|
ulOptionsClass?: string | undefined;
|
|
56
62
|
ulSelectedClass?: string | undefined;
|
|
63
|
+
ulSelectedStyle?: string | null | undefined;
|
|
64
|
+
ulOptionsStyle?: string | null | undefined;
|
|
57
65
|
value?: Option | Option[] | null | undefined;
|
|
58
66
|
};
|
|
59
67
|
events(): MultiSelectEvents;
|
|
@@ -93,8 +101,8 @@ declare class __sveltets_Render<Option extends T> {
|
|
|
93
101
|
};
|
|
94
102
|
}
|
|
95
103
|
export type MultiSelectProps<Option extends T> = ReturnType<__sveltets_Render<Option>['props']>;
|
|
96
|
-
export type
|
|
104
|
+
export type MultiSelectEvents_<Option extends T> = ReturnType<__sveltets_Render<Option>['events']>;
|
|
97
105
|
export type MultiSelectSlots<Option extends T> = ReturnType<__sveltets_Render<Option>['slots']>;
|
|
98
|
-
export default class MultiSelect<Option extends T> extends SvelteComponent<MultiSelectProps<Option>,
|
|
106
|
+
export default class MultiSelect<Option extends T> extends SvelteComponent<MultiSelectProps<Option>, MultiSelectEvents_<Option>, MultiSelectSlots<Option>> {
|
|
99
107
|
}
|
|
100
108
|
export {};
|
package/dist/utils.d.ts
CHANGED
|
@@ -3,4 +3,4 @@ export declare const get_label: (opt: Option) => string | number;
|
|
|
3
3
|
export declare function get_style(option: {
|
|
4
4
|
style?: OptionStyle;
|
|
5
5
|
[key: string]: unknown;
|
|
6
|
-
} | string | number, key?: 'selected' | 'option' | null): string
|
|
6
|
+
} | string | number, key?: 'selected' | 'option' | null): string;
|
package/dist/utils.js
CHANGED
|
@@ -8,23 +8,27 @@ export const get_label = (opt) => {
|
|
|
8
8
|
}
|
|
9
9
|
return `${opt}`;
|
|
10
10
|
};
|
|
11
|
+
// this function is used extract CSS strings from a {selected, option} style object to be used in the style attribute of the option
|
|
12
|
+
// if the style is a string, it will be returned as is
|
|
11
13
|
export function get_style(option, key = null) {
|
|
12
|
-
|
|
13
|
-
return null;
|
|
14
|
+
let css_str = ``;
|
|
14
15
|
if (![`selected`, `option`, null].includes(key)) {
|
|
15
16
|
console.error(`MultiSelect: Invalid key=${key} for get_style`);
|
|
16
|
-
return;
|
|
17
17
|
}
|
|
18
18
|
if (typeof option == `object` && option.style) {
|
|
19
19
|
if (typeof option.style == `string`) {
|
|
20
|
-
|
|
20
|
+
css_str = option.style;
|
|
21
21
|
}
|
|
22
22
|
if (typeof option.style == `object`) {
|
|
23
23
|
if (key && key in option.style)
|
|
24
|
-
return option.style[key]
|
|
24
|
+
return option.style[key] ?? ``;
|
|
25
25
|
else {
|
|
26
26
|
console.error(`Invalid style object for option=${JSON.stringify(option)}`);
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
|
+
// ensure css_str ends with a semicolon
|
|
31
|
+
if (css_str.trim() && !css_str.trim().endsWith(`;`))
|
|
32
|
+
css_str += `;`;
|
|
33
|
+
return css_str;
|
|
30
34
|
}
|
package/package.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"homepage": "https://janosh.github.io/svelte-multiselect",
|
|
6
6
|
"repository": "https://github.com/janosh/svelte-multiselect",
|
|
7
7
|
"license": "MIT",
|
|
8
|
-
"version": "10.
|
|
8
|
+
"version": "10.3.0",
|
|
9
9
|
"type": "module",
|
|
10
10
|
"svelte": "./dist/index.js",
|
|
11
11
|
"bugs": "https://github.com/janosh/svelte-multiselect/issues",
|
|
@@ -23,37 +23,38 @@
|
|
|
23
23
|
"update-coverage": "vitest tests/unit --run --coverage && npx istanbul-badges-readme"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"svelte": "
|
|
26
|
+
"svelte": "4.2.12"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
|
-
"@iconify/svelte": "^3.1.
|
|
30
|
-
"@playwright/test": "^1.
|
|
31
|
-
"@sveltejs/adapter-static": "^
|
|
32
|
-
"@sveltejs/kit": "^
|
|
33
|
-
"@sveltejs/package": "2.
|
|
34
|
-
"@sveltejs/vite-plugin-svelte": "
|
|
35
|
-
"@
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"jsdom": "^22.1.0",
|
|
29
|
+
"@iconify/svelte": "^3.1.6",
|
|
30
|
+
"@playwright/test": "^1.43.0",
|
|
31
|
+
"@sveltejs/adapter-static": "^3.0.1",
|
|
32
|
+
"@sveltejs/kit": "^2.5.5",
|
|
33
|
+
"@sveltejs/package": "2.3.1",
|
|
34
|
+
"@sveltejs/vite-plugin-svelte": "3.0.2",
|
|
35
|
+
"@vitest/coverage-v8": "^1.4.0",
|
|
36
|
+
"eslint": "^9.0.0",
|
|
37
|
+
"eslint-plugin-svelte": "^2.36.0",
|
|
38
|
+
"globals": "^15.0.0",
|
|
39
|
+
"hastscript": "^9.0.0",
|
|
40
|
+
"highlight.js": "^11.9.0",
|
|
41
|
+
"jsdom": "^24.0.0",
|
|
43
42
|
"mdsvex": "^0.11.0",
|
|
44
|
-
"mdsvexamples": "^0.
|
|
45
|
-
"prettier": "^2.
|
|
46
|
-
"prettier-plugin-svelte": "^2.
|
|
47
|
-
"rehype-autolink-headings": "^
|
|
48
|
-
"rehype-slug": "^
|
|
49
|
-
"svelte-check": "^3.
|
|
50
|
-
"svelte-
|
|
51
|
-
"svelte-
|
|
52
|
-
"svelte-
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
"
|
|
43
|
+
"mdsvexamples": "^0.4.1",
|
|
44
|
+
"prettier": "^3.2.5",
|
|
45
|
+
"prettier-plugin-svelte": "^3.2.2",
|
|
46
|
+
"rehype-autolink-headings": "^7.1.0",
|
|
47
|
+
"rehype-slug": "^6.0.0",
|
|
48
|
+
"svelte-check": "^3.6.9",
|
|
49
|
+
"svelte-multiselect": "^10.2.0",
|
|
50
|
+
"svelte-preprocess": "^5.1.3",
|
|
51
|
+
"svelte-toc": "^0.5.8",
|
|
52
|
+
"svelte-zoo": "^0.4.10",
|
|
53
|
+
"svelte2tsx": "^0.7.6",
|
|
54
|
+
"typescript": "5.4.4",
|
|
55
|
+
"typescript-eslint": "^7.5.0",
|
|
56
|
+
"vite": "^5.1.5",
|
|
57
|
+
"vitest": "^1.4.0"
|
|
57
58
|
},
|
|
58
59
|
"keywords": [
|
|
59
60
|
"svelte",
|
package/readme.md
CHANGED
|
@@ -194,10 +194,10 @@ Full list of props/bindable variables for this component. The `Option` type you
|
|
|
194
194
|
Customize how dropdown options are filtered when user enters search string into `<MultiSelect />`. Defaults to:
|
|
195
195
|
|
|
196
196
|
1. ```ts
|
|
197
|
-
|
|
197
|
+
closeDropdownOnSelect: boolean | 'desktop' = `desktop`
|
|
198
198
|
```
|
|
199
199
|
|
|
200
|
-
One of `true`, `false` or `'desktop'`. Whether to
|
|
200
|
+
One of `true`, `false` or `'desktop'`. Whether to close the dropdown list after selecting a dropdown item. If `true`, component will loose focus and `dropdown` is closed. `'desktop'` means `false` if current window width is larger than the current value of `breakpoint` prop (default is 800, meaning screen width in pixels). This is to align with the default behavior of many mobile browsers like Safari which close dropdowns after selecting an option while desktop browsers facilitate multi-selection by leaving dropdowns open.
|
|
201
201
|
|
|
202
202
|
1. ```ts
|
|
203
203
|
form_input: HTMLInputElement | null = null
|
|
@@ -229,12 +229,30 @@ Full list of props/bindable variables for this component. The `Option` type you
|
|
|
229
229
|
|
|
230
230
|
The `inputmode` attribute hints at the type of data the user may enter. Values like `'numeric' | 'tel' | 'email'` allow mobile browsers to display an appropriate virtual on-screen keyboard. See [MDN](https://developer.mozilla.org/docs/Web/HTML/Global_attributes/inputmode) for details. If you want to suppress the on-screen keyboard to leave full-screen real estate for the dropdown list of options, set `inputmode="none"`.
|
|
231
231
|
|
|
232
|
+
1. ```ts
|
|
233
|
+
inputStyle: string | null = null
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
One-off CSS rules applied to the `<input>` element.
|
|
237
|
+
|
|
232
238
|
1. ```ts
|
|
233
239
|
invalid: boolean = false
|
|
234
240
|
```
|
|
235
241
|
|
|
236
242
|
If `required = true, 1, 2, ...` and user tries to submit form but `selected = []` is empty/`selected.length < required`, `invalid` is automatically set to `true` and CSS class `invalid` applied to the top-level `div.multiselect`. `invalid` class is removed as soon as any change to `selected` is registered. `invalid` can also be controlled externally by binding to it `<MultiSelect bind:invalid />` and setting it to `true` based on outside events or custom validation.
|
|
237
243
|
|
|
244
|
+
1. ```ts
|
|
245
|
+
liOptionStyle: string | null = null
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
One-off CSS rules applied to the `<li>` elements that wrap the dropdown options.
|
|
249
|
+
|
|
250
|
+
1. ```ts
|
|
251
|
+
liSelectedStyle: string | null = null
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
One-off CSS rules applied to the `<li>` elements that wrap the selected options.
|
|
255
|
+
|
|
238
256
|
1. ```ts
|
|
239
257
|
loading: boolean = false
|
|
240
258
|
```
|
|
@@ -304,7 +322,7 @@ Full list of props/bindable variables for this component. The `Option` type you
|
|
|
304
322
|
options: Option[]
|
|
305
323
|
```
|
|
306
324
|
|
|
307
|
-
**The only required prop** (no default). Array of strings/numbers or `Option` objects to be listed in the dropdown. The only required key on objects is `label` which must also be unique. An object's `value` defaults to `label` if `undefined`. You can add arbitrary additional keys to your option objects. A few keys like `preselected` and `title` have special meaning though. See type `ObjectOption` in [
|
|
325
|
+
**The only required prop** (no default). Array of strings/numbers or `Option` objects to be listed in the dropdown. The only required key on objects is `label` which must also be unique. An object's `value` defaults to `label` if `undefined`. You can add arbitrary additional keys to your option objects. A few keys like `preselected` and `title` have special meaning though. See type `ObjectOption` in [`/src/lib/types.ts`](https://github.com/janosh/svelte-multiselect/blob/main/src/lib/types.ts) for all special keys and their purpose.
|
|
308
326
|
|
|
309
327
|
1. ```ts
|
|
310
328
|
outerDiv: HTMLDivElement | null = null
|
|
@@ -381,6 +399,24 @@ Full list of props/bindable variables for this component. The `Option` type you
|
|
|
381
399
|
|
|
382
400
|
Whether selected options are draggable so users can change their order.
|
|
383
401
|
|
|
402
|
+
1. ```ts
|
|
403
|
+
style: string | null = null
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
One-off CSS rules applied to the outer `<div class="multiselect">` that wraps the whole component for passing one-off CSS.
|
|
407
|
+
|
|
408
|
+
1. ```ts
|
|
409
|
+
ulSelectedStyle: string | null = null
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
One-off CSS rules applied to the `<ul class="selected">` that wraps the list of selected options.
|
|
413
|
+
|
|
414
|
+
1. ```ts
|
|
415
|
+
ulOptionsStyle: string | null = null
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
One-off CSS rules applied to the `<ul class="options">` that wraps the list of selected options.
|
|
419
|
+
|
|
384
420
|
1. ```ts
|
|
385
421
|
value: Option | Option[] | null = null
|
|
386
422
|
```
|
|
@@ -397,13 +433,11 @@ Full list of props/bindable variables for this component. The `Option` type you
|
|
|
397
433
|
1. `slot="disabled-icon"`: Custom icon to display inside the input when in `disabled` state. Receives no props. Use an empty `<span slot="disabled-icon" />` or `div` to remove the default disabled icon.
|
|
398
434
|
1. `slot="expand-icon"`: Allows setting a custom icon to indicate to users that the Multiselect text input field is expandable into a dropdown list. Receives prop `open: boolean` which is true if the Multiselect dropdown is visible and false if it's hidden.
|
|
399
435
|
1. `slot="remove-icon"`: Custom icon to display as remove button. Will be used both by buttons to remove individual selected options and the 'remove all' button that clears all options at once. Receives no props.
|
|
400
|
-
1. `slot="user-msg"`: Displayed like a dropdown item when the list is empty and user is allowed to create custom options based on text input (or if the user's text input clashes with an existing option).
|
|
401
|
-
- `
|
|
402
|
-
- `
|
|
403
|
-
- `
|
|
404
|
-
|
|
405
|
-
- `msg: string`: `duplicateOptionMsg` if user input is a duplicate else `createOptionMsg`.
|
|
406
|
-
1. `slot='after-input'`: ForPlaced after the search input. For arbitrary content like icons or temporary messages. Receives props `selected`, `disabled`, `invalid`, `id`, `placeholder`, `open`, `required`.
|
|
436
|
+
1. `slot="user-msg"`: Displayed like a dropdown item when the list is empty and user is allowed to create custom options based on text input (or if the user's text input clashes with an existing option). Receives props:
|
|
437
|
+
- `searchText`: The text user typed into search input.
|
|
438
|
+
- `msgType: false | 'create' | 'dupe' | 'no-match'`: `'dupe'` means user input is a duplicate of an existing option. `'create'` means user is allowed to convert their input into a new option not previously in the dropdown. `'no-match'` means user input doesn't match any dropdown items and users are not allowed to create new options. `false` means none of the above.
|
|
439
|
+
- `msg`: Will be `duplicateOptionMsg` or `createOptionMsg` (see [props](#🔣-props)) based on whether user input is a duplicate or can be created as new option. Note this slot replaces the default UI for displaying these messages so the slot needs to render them instead (unless purposely not showing a message).
|
|
440
|
+
1. `slot='after-input'`: Placed after the search input. For arbitrary content like icons or temporary messages. Receives props `selected: Option[]`, `disabled: boolean`, `invalid: boolean`, `id: string | null`, `placeholder: string`, `open: boolean`, `required: boolean`. Can serve as a more dynamic, more customizable alternative to the `placeholder` prop.
|
|
407
441
|
|
|
408
442
|
Example using several slots:
|
|
409
443
|
|
|
@@ -429,13 +463,13 @@ Example using several slots:
|
|
|
429
463
|
on:add={(event) => console.log(event.detail.option)}
|
|
430
464
|
```
|
|
431
465
|
|
|
432
|
-
Triggers when a new option is selected.
|
|
466
|
+
Triggers when a new option is selected. The newly selected option is provided as `event.detail.option`.
|
|
433
467
|
|
|
434
468
|
1. ```ts
|
|
435
469
|
on:remove={(event) => console.log(event.detail.option)}`
|
|
436
470
|
```
|
|
437
471
|
|
|
438
|
-
Triggers when
|
|
472
|
+
Triggers when a single selected option is removed. The removed option is provided as `event.detail.option`.
|
|
439
473
|
|
|
440
474
|
1. ```ts
|
|
441
475
|
on:removeAll={(event) => console.log(event.detail.options)}`
|
|
@@ -447,7 +481,7 @@ Example using several slots:
|
|
|
447
481
|
on:change={(event) => console.log(`${event.detail.type}: '${event.detail.option}'`)}
|
|
448
482
|
```
|
|
449
483
|
|
|
450
|
-
Triggers when an option is either added or removed, or all options are removed at once. `type` is one of `'add' | 'remove' | 'removeAll'` and payload will be `option: Option` or `options: Option[]`, respectively.
|
|
484
|
+
Triggers when an option is either added (selected) or removed from selected, or all selected options are removed at once. `type` is one of `'add' | 'remove' | 'removeAll'` and payload will be `option: Option` or `options: Option[]`, respectively.
|
|
451
485
|
|
|
452
486
|
1. ```ts
|
|
453
487
|
on:open={(event) => console.log(`Multiselect dropdown was opened by ${event}`)}
|
|
@@ -607,6 +641,8 @@ The second method allows you to pass in custom classes to the important DOM elem
|
|
|
607
641
|
- `ulOptionsClass`: available options listed in the dropdown when component is in `open` state
|
|
608
642
|
- `liOptionClass`: list items selectable from dropdown list
|
|
609
643
|
- `liActiveOptionClass`: the currently active dropdown list item (i.e. hovered or navigated to with arrow keys)
|
|
644
|
+
- `liUserMsgClass`: user message (last child of dropdown list when no options match user input)
|
|
645
|
+
- `liActiveUserMsgClass`: user message when active (i.e. hovered or navigated to with arrow keys)
|
|
610
646
|
- `maxSelectMsgClass`: small span towards the right end of the input field displaying to the user how many of the allowed number of options they've already selected
|
|
611
647
|
|
|
612
648
|
This simplified version of the DOM structure of the component shows where these classes are inserted:
|
|
@@ -624,6 +660,10 @@ This simplified version of the DOM structure of the component shows where these
|
|
|
624
660
|
<li class="{liOptionClass} {liActiveOptionClass}">
|
|
625
661
|
Option 2 (currently active)
|
|
626
662
|
</li>
|
|
663
|
+
...
|
|
664
|
+
<li class="{liUserMsgClass} {liActiveUserMsgClass}">
|
|
665
|
+
Create this option...
|
|
666
|
+
</li>
|
|
627
667
|
</ul>
|
|
628
668
|
</div>
|
|
629
669
|
```
|