svelte-multiselect 6.0.2 → 6.1.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/MultiSelect.svelte +53 -40
- package/MultiSelect.svelte.d.ts +3 -1
- package/index.d.ts +18 -2
- package/package.json +11 -11
- package/readme.md +45 -23
package/MultiSelect.svelte
CHANGED
|
@@ -37,7 +37,7 @@ export let options;
|
|
|
37
37
|
export let outerDiv = null;
|
|
38
38
|
export let outerDivClass = ``;
|
|
39
39
|
export let parseLabelsAsHtml = false; // should not be combined with allowUserOptions!
|
|
40
|
-
export let placeholder =
|
|
40
|
+
export let placeholder = null;
|
|
41
41
|
export let removeAllTitle = `Remove all`;
|
|
42
42
|
export let removeBtnTitle = `Remove`;
|
|
43
43
|
export let required = false;
|
|
@@ -48,6 +48,8 @@ export let selectedValues = [];
|
|
|
48
48
|
export let sortSelected = false;
|
|
49
49
|
export let ulOptionsClass = ``;
|
|
50
50
|
export let ulSelectedClass = ``;
|
|
51
|
+
export let inputmode = ``;
|
|
52
|
+
export let pattern = ``;
|
|
51
53
|
if (!(options?.length > 0)) {
|
|
52
54
|
if (allowUserOptions) {
|
|
53
55
|
options = []; // initializing as array avoids errors when component mounts
|
|
@@ -67,7 +69,7 @@ if (!Array.isArray(selected)) {
|
|
|
67
69
|
console.error(`selected prop must be an array, got ${selected}`);
|
|
68
70
|
}
|
|
69
71
|
const dispatch = createEventDispatcher();
|
|
70
|
-
let
|
|
72
|
+
let add_option_msg_is_active = false; // controls active state of <li>{addOptionMsg}</li>
|
|
71
73
|
let window_width;
|
|
72
74
|
let wiggle = false; // controls wiggle animation when user tries to exceed maxSelect
|
|
73
75
|
$: selectedLabels = selected.map(get_label);
|
|
@@ -85,9 +87,9 @@ if (activeIndex !== null && !matchingOptions[activeIndex]) {
|
|
|
85
87
|
throw `Run time error, activeIndex=${activeIndex} is out of bounds, matchingOptions.length=${matchingOptions.length}`;
|
|
86
88
|
}
|
|
87
89
|
// update activeOption when activeIndex changes
|
|
88
|
-
$: activeOption = activeIndex ? matchingOptions[activeIndex] : null;
|
|
90
|
+
$: activeOption = activeIndex !== null ? matchingOptions[activeIndex] : null;
|
|
89
91
|
// add an option to selected list
|
|
90
|
-
function add(label) {
|
|
92
|
+
function add(label, event) {
|
|
91
93
|
if (maxSelect && maxSelect > 1 && selected.length >= maxSelect)
|
|
92
94
|
wiggle = true;
|
|
93
95
|
// to prevent duplicate selection, we could add `&& !selectedLabels.includes(label)`
|
|
@@ -139,7 +141,7 @@ function add(label) {
|
|
|
139
141
|
}
|
|
140
142
|
}
|
|
141
143
|
if (selected.length === maxSelect)
|
|
142
|
-
close_dropdown();
|
|
144
|
+
close_dropdown(event);
|
|
143
145
|
else if (focusInputOnSelect === true ||
|
|
144
146
|
(focusInputOnSelect === `desktop` && window_width > breakpoint)) {
|
|
145
147
|
input?.focus();
|
|
@@ -165,24 +167,27 @@ function remove(label) {
|
|
|
165
167
|
dispatch(`remove`, { option });
|
|
166
168
|
dispatch(`change`, { option, type: `remove` });
|
|
167
169
|
}
|
|
168
|
-
function open_dropdown() {
|
|
170
|
+
function open_dropdown(event) {
|
|
169
171
|
if (disabled)
|
|
170
172
|
return;
|
|
171
173
|
open = true;
|
|
172
|
-
|
|
173
|
-
|
|
174
|
+
if (!(event instanceof FocusEvent)) {
|
|
175
|
+
// avoid double-focussing input when event that opened dropdown was already input FocusEvent
|
|
176
|
+
input?.focus();
|
|
177
|
+
}
|
|
178
|
+
dispatch(`open`, { event });
|
|
174
179
|
}
|
|
175
|
-
function close_dropdown() {
|
|
180
|
+
function close_dropdown(event) {
|
|
176
181
|
open = false;
|
|
177
182
|
input?.blur();
|
|
178
183
|
activeOption = null;
|
|
179
|
-
dispatch(`
|
|
184
|
+
dispatch(`close`, { event });
|
|
180
185
|
}
|
|
181
186
|
// handle all keyboard events this component receives
|
|
182
187
|
async function handle_keydown(event) {
|
|
183
188
|
// on escape or tab out of input: dismiss options dropdown and reset search text
|
|
184
189
|
if (event.key === `Escape` || event.key === `Tab`) {
|
|
185
|
-
close_dropdown();
|
|
190
|
+
close_dropdown(event);
|
|
186
191
|
searchText = ``;
|
|
187
192
|
}
|
|
188
193
|
// on enter key: toggle active option and reset search text
|
|
@@ -190,49 +195,41 @@ async function handle_keydown(event) {
|
|
|
190
195
|
event.preventDefault(); // prevent enter key from triggering form submission
|
|
191
196
|
if (activeOption) {
|
|
192
197
|
const label = get_label(activeOption);
|
|
193
|
-
selectedLabels.includes(label) ? remove(label) : add(label);
|
|
198
|
+
selectedLabels.includes(label) ? remove(label) : add(label, event);
|
|
194
199
|
searchText = ``;
|
|
195
200
|
}
|
|
196
201
|
else if (allowUserOptions && searchText.length > 0) {
|
|
197
202
|
// user entered text but no options match, so if allowUserOptions is truthy, we create new option
|
|
198
|
-
add(searchText);
|
|
203
|
+
add(searchText, event);
|
|
199
204
|
}
|
|
200
205
|
// no active option and no search text means the options dropdown is closed
|
|
201
206
|
// in which case enter means open it
|
|
202
207
|
else
|
|
203
|
-
open_dropdown();
|
|
208
|
+
open_dropdown(event);
|
|
204
209
|
}
|
|
205
210
|
// on up/down arrow keys: update active option
|
|
206
211
|
else if ([`ArrowDown`, `ArrowUp`].includes(event.key)) {
|
|
207
212
|
// if no option is active yet, but there are matching options, make first one active
|
|
208
|
-
if (
|
|
209
|
-
|
|
213
|
+
if (activeIndex === null && matchingOptions.length > 0) {
|
|
214
|
+
activeIndex = 0;
|
|
210
215
|
return;
|
|
211
216
|
}
|
|
212
217
|
else if (allowUserOptions && searchText.length > 0) {
|
|
213
218
|
// if allowUserOptions is truthy and user entered text but no options match, we make
|
|
214
219
|
// <li>{addUserMsg}</li> active on keydown (or toggle it if already active)
|
|
215
|
-
|
|
220
|
+
add_option_msg_is_active = !add_option_msg_is_active;
|
|
216
221
|
return;
|
|
217
222
|
}
|
|
218
|
-
else if (
|
|
223
|
+
else if (activeIndex === null) {
|
|
219
224
|
// if no option is active and no options are matching, do nothing
|
|
220
225
|
return;
|
|
221
226
|
}
|
|
222
227
|
const increment = event.key === `ArrowUp` ? -1 : 1;
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
else if (newActiveIdx === matchingOptions.length) {
|
|
229
|
-
// wrap around bottom
|
|
230
|
-
activeOption = matchingOptions[0];
|
|
231
|
-
}
|
|
232
|
-
else {
|
|
233
|
-
// default case: select next/previous in item list
|
|
234
|
-
activeOption = matchingOptions[newActiveIdx];
|
|
235
|
-
}
|
|
228
|
+
activeIndex = (activeIndex + increment) % matchingOptions.length;
|
|
229
|
+
// % in JS behaves like remainder operator, not real modulo, so negative numbers stay negative
|
|
230
|
+
// need to do manual wrap around at 0
|
|
231
|
+
if (activeIndex < 0)
|
|
232
|
+
activeIndex = matchingOptions.length - 1;
|
|
236
233
|
if (autoScroll) {
|
|
237
234
|
// TODO This ugly timeout hack is needed to properly scroll element into view when wrapping
|
|
238
235
|
// around start/end of option list. Find a better solution than waiting 10 ms to.
|
|
@@ -265,7 +262,7 @@ const if_enter_or_space = (handler) => (event) => {
|
|
|
265
262
|
};
|
|
266
263
|
function on_click_outside(event) {
|
|
267
264
|
if (outerDiv && !outerDiv.contains(event.target)) {
|
|
268
|
-
close_dropdown();
|
|
265
|
+
close_dropdown(event);
|
|
269
266
|
}
|
|
270
267
|
}
|
|
271
268
|
</script>
|
|
@@ -329,13 +326,29 @@ function on_click_outside(event) {
|
|
|
329
326
|
bind:value={searchText}
|
|
330
327
|
on:mouseup|self|stopPropagation={open_dropdown}
|
|
331
328
|
on:keydown={handle_keydown}
|
|
329
|
+
on:focus
|
|
332
330
|
on:focus={open_dropdown}
|
|
333
331
|
{id}
|
|
334
332
|
{name}
|
|
335
333
|
{disabled}
|
|
334
|
+
{inputmode}
|
|
335
|
+
{pattern}
|
|
336
336
|
placeholder={selectedLabels.length ? `` : placeholder}
|
|
337
337
|
aria-invalid={invalid ? `true` : null}
|
|
338
|
+
on:blur
|
|
339
|
+
on:change
|
|
340
|
+
on:click
|
|
341
|
+
on:keydown
|
|
342
|
+
on:keyup
|
|
343
|
+
on:mousedown
|
|
344
|
+
on:mouseenter
|
|
345
|
+
on:mouseleave
|
|
346
|
+
on:touchcancel
|
|
347
|
+
on:touchend
|
|
348
|
+
on:touchmove
|
|
349
|
+
on:touchstart
|
|
338
350
|
/>
|
|
351
|
+
<!-- the above on:* lines forward potentially useful DOM events -->
|
|
339
352
|
</li>
|
|
340
353
|
</ul>
|
|
341
354
|
{#if loading}
|
|
@@ -383,8 +396,8 @@ function on_click_outside(event) {
|
|
|
383
396
|
{@const active = activeIndex === idx}
|
|
384
397
|
<li
|
|
385
398
|
on:mousedown|stopPropagation
|
|
386
|
-
on:mouseup|stopPropagation={() => {
|
|
387
|
-
if (!disabled) is_selected(label) ? remove(label) : add(label)
|
|
399
|
+
on:mouseup|stopPropagation={(event) => {
|
|
400
|
+
if (!disabled) is_selected(label) ? remove(label) : add(label, event)
|
|
388
401
|
}}
|
|
389
402
|
title={disabled
|
|
390
403
|
? disabledTitle
|
|
@@ -415,13 +428,13 @@ function on_click_outside(event) {
|
|
|
415
428
|
{#if allowUserOptions && searchText}
|
|
416
429
|
<li
|
|
417
430
|
on:mousedown|stopPropagation
|
|
418
|
-
on:mouseup|stopPropagation={() => add(searchText)}
|
|
431
|
+
on:mouseup|stopPropagation={(event) => add(searchText, event)}
|
|
419
432
|
title={addOptionMsg}
|
|
420
|
-
class:active={
|
|
421
|
-
on:mouseover={() => (
|
|
422
|
-
on:focus={() => (
|
|
423
|
-
on:mouseout={() => (
|
|
424
|
-
on:blur={() => (
|
|
433
|
+
class:active={add_option_msg_is_active}
|
|
434
|
+
on:mouseover={() => (add_option_msg_is_active = true)}
|
|
435
|
+
on:focus={() => (add_option_msg_is_active = true)}
|
|
436
|
+
on:mouseout={() => (add_option_msg_is_active = false)}
|
|
437
|
+
on:blur={() => (add_option_msg_is_active = false)}
|
|
425
438
|
aria-selected="false"
|
|
426
439
|
>
|
|
427
440
|
{addOptionMsg}
|
package/MultiSelect.svelte.d.ts
CHANGED
|
@@ -32,7 +32,7 @@ declare const __propDef: {
|
|
|
32
32
|
outerDiv?: HTMLDivElement | null | undefined;
|
|
33
33
|
outerDivClass?: string | undefined;
|
|
34
34
|
parseLabelsAsHtml?: boolean | undefined;
|
|
35
|
-
placeholder?: string | undefined;
|
|
35
|
+
placeholder?: string | null | undefined;
|
|
36
36
|
removeAllTitle?: string | undefined;
|
|
37
37
|
removeBtnTitle?: string | undefined;
|
|
38
38
|
required?: boolean | undefined;
|
|
@@ -43,6 +43,8 @@ declare const __propDef: {
|
|
|
43
43
|
sortSelected?: boolean | ((op1: Option, op2: Option) => number) | undefined;
|
|
44
44
|
ulOptionsClass?: string | undefined;
|
|
45
45
|
ulSelectedClass?: string | undefined;
|
|
46
|
+
inputmode?: string | undefined;
|
|
47
|
+
pattern?: string | undefined;
|
|
46
48
|
};
|
|
47
49
|
slots: {
|
|
48
50
|
selected: {
|
package/index.d.ts
CHANGED
|
@@ -25,11 +25,27 @@ export declare type DispatchEvents = {
|
|
|
25
25
|
options?: Option[];
|
|
26
26
|
type: 'add' | 'remove' | 'removeAll';
|
|
27
27
|
};
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
open: {
|
|
29
|
+
event: Event;
|
|
30
|
+
};
|
|
31
|
+
close: {
|
|
32
|
+
event: Event;
|
|
33
|
+
};
|
|
30
34
|
};
|
|
31
35
|
export declare type MultiSelectEvents = {
|
|
32
36
|
[key in keyof DispatchEvents]: CustomEvent<DispatchEvents[key]>;
|
|
37
|
+
} & {
|
|
38
|
+
blur: FocusEvent;
|
|
39
|
+
click: MouseEvent;
|
|
40
|
+
focus: FocusEvent;
|
|
41
|
+
keydown: KeyboardEvent;
|
|
42
|
+
keyup: KeyboardEvent;
|
|
43
|
+
mouseenter: MouseEvent;
|
|
44
|
+
mouseleave: MouseEvent;
|
|
45
|
+
touchcancel: TouchEvent;
|
|
46
|
+
touchend: TouchEvent;
|
|
47
|
+
touchmove: TouchEvent;
|
|
48
|
+
touchstart: TouchEvent;
|
|
33
49
|
};
|
|
34
50
|
export declare const get_label: (op: Option) => string | number;
|
|
35
51
|
export declare const get_value: (op: Option) => {};
|
package/package.json
CHANGED
|
@@ -5,20 +5,20 @@
|
|
|
5
5
|
"homepage": "https://svelte-multiselect.netlify.app",
|
|
6
6
|
"repository": "https://github.com/janosh/svelte-multiselect",
|
|
7
7
|
"license": "MIT",
|
|
8
|
-
"version": "6.0
|
|
8
|
+
"version": "6.1.0",
|
|
9
9
|
"type": "module",
|
|
10
10
|
"svelte": "index.js",
|
|
11
11
|
"main": "index.js",
|
|
12
12
|
"bugs": "https://github.com/janosh/svelte-multiselect/issues",
|
|
13
13
|
"devDependencies": {
|
|
14
|
-
"@playwright/test": "^1.
|
|
14
|
+
"@playwright/test": "^1.26.0",
|
|
15
15
|
"@sveltejs/adapter-static": "^1.0.0-next.43",
|
|
16
|
-
"@sveltejs/kit": "^1.0.0-next.
|
|
17
|
-
"@sveltejs/package": "^1.0.0-next.
|
|
18
|
-
"@sveltejs/vite-plugin-svelte": "^1.0.
|
|
19
|
-
"@typescript-eslint/eslint-plugin": "^5.
|
|
20
|
-
"@typescript-eslint/parser": "^5.
|
|
21
|
-
"eslint": "^8.
|
|
16
|
+
"@sveltejs/kit": "^1.0.0-next.502",
|
|
17
|
+
"@sveltejs/package": "^1.0.0-next.5",
|
|
18
|
+
"@sveltejs/vite-plugin-svelte": "^1.0.8",
|
|
19
|
+
"@typescript-eslint/eslint-plugin": "^5.38.0",
|
|
20
|
+
"@typescript-eslint/parser": "^5.38.0",
|
|
21
|
+
"eslint": "^8.24.0",
|
|
22
22
|
"eslint-plugin-svelte3": "^4.0.0",
|
|
23
23
|
"hastscript": "^7.0.2",
|
|
24
24
|
"jsdom": "^20.0.0",
|
|
@@ -32,11 +32,11 @@
|
|
|
32
32
|
"svelte-github-corner": "^0.1.0",
|
|
33
33
|
"svelte-preprocess": "^4.10.6",
|
|
34
34
|
"svelte-toc": "^0.4.0",
|
|
35
|
-
"svelte2tsx": "^0.5.
|
|
35
|
+
"svelte2tsx": "^0.5.18",
|
|
36
36
|
"tslib": "^2.4.0",
|
|
37
37
|
"typescript": "^4.8.3",
|
|
38
|
-
"vite": "^3.1.
|
|
39
|
-
"vitest": "^0.23.
|
|
38
|
+
"vite": "^3.1.3",
|
|
39
|
+
"vitest": "^0.23.4"
|
|
40
40
|
},
|
|
41
41
|
"keywords": [
|
|
42
42
|
"svelte",
|
package/readme.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
[](https://app.netlify.com/sites/svelte-multiselect/deploys)
|
|
10
10
|
[](https://npmjs.com/package/svelte-multiselect)
|
|
11
11
|
[](https://github.com/sveltejs/svelte/blob/master/CHANGELOG.md)
|
|
12
|
-
[](https://svelte.dev/repl/a5a14b8f15d64cb083b567292480db05)
|
|
12
|
+
[](https://svelte.dev/repl/a5a14b8f15d64cb083b567292480db05)
|
|
13
13
|
[](https://stackblitz.com/github/janosh/svelte-multiselect)
|
|
14
14
|
|
|
15
15
|
</h4>
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
- **v6.0.0** The prop `showOptions` which controls whether the list of dropdown options is currently open or closed was renamed to `open`. See [PR 103](https://github.com/janosh/svelte-multiselect/pull/103).
|
|
41
41
|
- **v6.0.1** The prop `disabledTitle` which sets the title of the `<MultiSelect>` `<input>` node if in `disabled` mode was renamed to `disabledInputTitle`. See [PR 105](https://github.com/janosh/svelte-multiselect/pull/105).
|
|
42
42
|
- **v6.0.1** The default margin of `1em 0` on the wrapper `div.multiselect` was removed. Instead, there is now a new CSS variable `--sms-margin`. Set it to `--sms-margin: 1em 0;` to restore the old appearance. See [PR 105](https://github.com/janosh/svelte-multiselect/pull/105).
|
|
43
|
+
- **6.1.0** The `dispatch` events `focus` and `blur` were renamed to `open` and `close`, respectively. These actions refer to the dropdown list, i.e. `<MultiSelect on:open={(event) => console.log(event)}>` will trigger when the dropdown list opens. The focus and blur events are now regular DOM (not Svelte `dispatch`) events emitted by the `<input>` node. See [PR 120](https://github.com/janosh/svelte-multiselect/pull/120).
|
|
43
44
|
|
|
44
45
|
## Installation
|
|
45
46
|
|
|
@@ -76,7 +77,7 @@ import type { Option } from 'svelte-multiselect'
|
|
|
76
77
|
```
|
|
77
78
|
|
|
78
79
|
1. ```ts
|
|
79
|
-
activeIndex:
|
|
80
|
+
activeIndex: number | null = null
|
|
80
81
|
```
|
|
81
82
|
|
|
82
83
|
Zero-based index of currently active option in the array of currently matching options, i.e. if the user typed a search string into the input and only a subset of options match, this index refers to the array position of the matching subset of options
|
|
@@ -88,22 +89,23 @@ import type { Option } from 'svelte-multiselect'
|
|
|
88
89
|
Currently active option, i.e. the one the user currently hovers or navigated to with arrow keys.
|
|
89
90
|
|
|
90
91
|
1. ```ts
|
|
91
|
-
addOptionMsg: string =
|
|
92
|
+
addOptionMsg: string = `Create this option...`
|
|
92
93
|
```
|
|
93
94
|
|
|
94
95
|
Message shown to users after entering text when no options match their query and `allowUserOptions` is truthy.
|
|
95
96
|
|
|
96
97
|
1. ```ts
|
|
97
|
-
allowUserOptions: boolean = false
|
|
98
|
+
allowUserOptions: boolean | 'append' = false
|
|
98
99
|
```
|
|
99
100
|
|
|
100
|
-
Whether users
|
|
101
|
+
Whether users can enter values that are not in the dropdown list. `true` means add user-defined options to the selected list only, `'append'` means add to both options and selected.
|
|
102
|
+
If `allowUserOptions` is `true` or `'append'` then the type `object | number | string` of entered value is determined from the first option of the list to keep type homogeneity.
|
|
101
103
|
|
|
102
104
|
1. ```ts
|
|
103
|
-
autocomplete: string =
|
|
105
|
+
autocomplete: string = `off`
|
|
104
106
|
```
|
|
105
107
|
|
|
106
|
-
Applied to the `<input>`. Specifies if browser is permitted to auto-fill this form field.
|
|
108
|
+
Applied to the `<input>`. Specifies if browser is permitted to auto-fill this form field. Should usually be one of `'on'` or `'off'` but see [MDN docs](https://developer.mozilla.org/docs/Web/HTML/Attributes/autocomplete) for other admissible values.
|
|
107
109
|
|
|
108
110
|
1. ```ts
|
|
109
111
|
autoScroll: boolean = true
|
|
@@ -112,13 +114,13 @@ import type { Option } from 'svelte-multiselect'
|
|
|
112
114
|
`false` disables keeping the active dropdown items in view when going up/down the list of options with arrow keys.
|
|
113
115
|
|
|
114
116
|
1. ```ts
|
|
115
|
-
breakpoint:
|
|
117
|
+
breakpoint: number = 800
|
|
116
118
|
```
|
|
117
119
|
|
|
118
120
|
Screens wider than `breakpoint` in pixels will be considered `'desktop'`, everything narrower as `'mobile'`.
|
|
119
121
|
|
|
120
122
|
1. ```ts
|
|
121
|
-
defaultDisabledTitle: string =
|
|
123
|
+
defaultDisabledTitle: string = `This option is disabled`
|
|
122
124
|
```
|
|
123
125
|
|
|
124
126
|
Title text to display when user hovers over a disabled option. Each option can override this through its `disabledTitle` attribute.
|
|
@@ -130,13 +132,13 @@ import type { Option } from 'svelte-multiselect'
|
|
|
130
132
|
Disable the component. It will still be rendered but users won't be able to interact with it.
|
|
131
133
|
|
|
132
134
|
1. ```ts
|
|
133
|
-
disabledInputTitle: string =
|
|
135
|
+
disabledInputTitle: string = `This input is disabled`
|
|
134
136
|
```
|
|
135
137
|
|
|
136
138
|
Tooltip text to display on hover when the component is in `disabled` state.
|
|
137
139
|
|
|
138
140
|
1. ```ts
|
|
139
|
-
filterFunc
|
|
141
|
+
filterFunc = (op: Option, searchText: string): boolean => {
|
|
140
142
|
if (!searchText) return true
|
|
141
143
|
return `${get_label(op)}`.toLowerCase().includes(searchText.toLowerCase())
|
|
142
144
|
}
|
|
@@ -187,7 +189,7 @@ import type { Option } from 'svelte-multiselect'
|
|
|
187
189
|
Positive integer to limit the number of options users can pick. `null` means no limit.
|
|
188
190
|
|
|
189
191
|
1. ```ts
|
|
190
|
-
maxSelectMsg: (current: number, max: number)
|
|
192
|
+
maxSelectMsg: ((current: number, max: number) => string) | null = null
|
|
191
193
|
```
|
|
192
194
|
|
|
193
195
|
Inform users how many of the maximum allowed options they have already selected. Set `maxSelectMsg={null}` to not show a message. Defaults to `null` when `maxSelect={1}` or `maxSelect={null}`. Else if `maxSelect > 1`, defaults to:
|
|
@@ -203,7 +205,7 @@ import type { Option } from 'svelte-multiselect'
|
|
|
203
205
|
Applied to the `<input>` element. Sets the key of this field in a submitted form data object. Not useful at the moment since the value is stored in Svelte state, not on the `<input>` node.
|
|
204
206
|
|
|
205
207
|
1. ```ts
|
|
206
|
-
noOptionsMsg: string =
|
|
208
|
+
noOptionsMsg: string = `No matching options`
|
|
207
209
|
```
|
|
208
210
|
|
|
209
211
|
What message to show if no options match the user-entered search string.
|
|
@@ -239,13 +241,13 @@ import type { Option } from 'svelte-multiselect'
|
|
|
239
241
|
String shown in the text input when no option is selected.
|
|
240
242
|
|
|
241
243
|
1. ```ts
|
|
242
|
-
removeAllTitle: string =
|
|
244
|
+
removeAllTitle: string = `Remove all`
|
|
243
245
|
```
|
|
244
246
|
|
|
245
247
|
Title text to display when user hovers over remove-all button.
|
|
246
248
|
|
|
247
249
|
1. ```ts
|
|
248
|
-
removeBtnTitle: string =
|
|
250
|
+
removeBtnTitle: string = `Remove`
|
|
249
251
|
```
|
|
250
252
|
|
|
251
253
|
Title text to display when user hovers over button to remove selected option (which defaults to a cross icon).
|
|
@@ -257,7 +259,7 @@ import type { Option } from 'svelte-multiselect'
|
|
|
257
259
|
Whether forms can be submitted without selecting any options. Aborts submission, is scrolled into view and shows help "Please fill out" message when true and user tries to submit with no options selected.
|
|
258
260
|
|
|
259
261
|
1. ```ts
|
|
260
|
-
searchText: string =
|
|
262
|
+
searchText: string = ``
|
|
261
263
|
```
|
|
262
264
|
|
|
263
265
|
Text the user-entered to filter down on the list of options. Binds both ways, i.e. can also be used to set the input text.
|
|
@@ -287,11 +289,16 @@ import type { Option } from 'svelte-multiselect'
|
|
|
287
289
|
Default behavior is to render selected items in the order they were chosen. `sortSelected={true}` uses default JS array sorting. A compare function enables custom logic for sorting selected options. See the [`/sort-selected`](https://svelte-multiselect.netlify.app/sort-selected) example.
|
|
288
290
|
|
|
289
291
|
1. ```ts
|
|
290
|
-
|
|
291
|
-
options.length > 0 ? (typeof options[0] as 'object' | 'string' | 'number') : 'string'
|
|
292
|
+
inputmode: string = ``
|
|
292
293
|
```
|
|
293
294
|
|
|
294
|
-
|
|
295
|
+
The `inputmode` attribute hints at the type of data the user may enter. Values like `'numeric' | 'tel' | 'email'` allow browsers to display an appropriate virtual keyboard. See [MDN](https://developer.mozilla.org/docs/Web/HTML/Global_attributes/inputmode) for details.
|
|
296
|
+
|
|
297
|
+
1. ```ts
|
|
298
|
+
pattern: string = ``
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
The pattern attribute specifies a regular expression which the input's value must match. If a non-null value doesn't match the `pattern` regex, the read-only `patternMismatch` property will be `true`. See [MDN](https://developer.mozilla.org/docs/Web/HTML/Attributes/pattern) for details.
|
|
295
302
|
|
|
296
303
|
## Slots
|
|
297
304
|
|
|
@@ -353,10 +360,16 @@ Example:
|
|
|
353
360
|
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.
|
|
354
361
|
|
|
355
362
|
1. ```ts
|
|
356
|
-
on:
|
|
363
|
+
on:open={(event) => console.log(`Multiselect dropdown was opened by ${event}`)}
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
Triggers when the dropdown list of options appears. Event is the DOM's `FocusEvent`,`KeyboardEvent` or `ClickEvent` that initiated this Svelte `dispatch` event.
|
|
367
|
+
|
|
368
|
+
1. ```ts
|
|
369
|
+
on:close={(event) => console.log(`Multiselect dropdown was closed by ${event}`)}
|
|
357
370
|
```
|
|
358
371
|
|
|
359
|
-
Triggers when the
|
|
372
|
+
Triggers when the dropdown list of options disappears. Event is the DOM's `FocusEvent`, `KeyboardEvent` or `ClickEvent` that initiated this Svelte `dispatch` event.
|
|
360
373
|
|
|
361
374
|
For example, here's how you might annoy your users with an alert every time one or more options are added or removed:
|
|
362
375
|
|
|
@@ -372,6 +385,15 @@ For example, here's how you might annoy your users with an alert every time one
|
|
|
372
385
|
|
|
373
386
|
> Note: Depending on the data passed to the component the `options(s)` payload will either be objects or simple strings/numbers.
|
|
374
387
|
|
|
388
|
+
This component also forwards many DOM events from the `<input>` node: `blur`, `change`, `click`, `keydown`, `keyup`, `mousedown`, `mouseenter`, `mouseleave`, `touchcancel`, `touchend`, `touchmove`, `touchstart`. You can register listeners for these just like for the above [Svelte `dispatch` events](https://svelte.dev/tutorial/component-events):
|
|
389
|
+
|
|
390
|
+
```svelte
|
|
391
|
+
<MultiSelect
|
|
392
|
+
options={[1, 2, 3]}
|
|
393
|
+
on:keyup={(event) => console.log('key', event.target.value)}
|
|
394
|
+
/>
|
|
395
|
+
```
|
|
396
|
+
|
|
375
397
|
## TypeScript
|
|
376
398
|
|
|
377
399
|
TypeScript users can import the types used for internal type safety:
|
|
@@ -486,9 +508,9 @@ This simplified version of the DOM structure of the component shows where these
|
|
|
486
508
|
</div>
|
|
487
509
|
```
|
|
488
510
|
|
|
489
|
-
###
|
|
511
|
+
### With global CSS
|
|
490
512
|
|
|
491
|
-
|
|
513
|
+
Odd as it may seem, you get the most fine-grained control over the styling of every part of this component by using the following `:global()` CSS selectors. `ul.selected` is the list of currently selected options rendered inside the component's input whereas `ul.options` is the list of available options that slides out when the component is in its `open` state. See also [simplified DOM structure](#styling).
|
|
492
514
|
|
|
493
515
|
```css
|
|
494
516
|
:global(div.multiselect) {
|