svelte-multiselect 4.0.1 → 4.0.2
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 +40 -21
- package/MultiSelect.svelte.d.ts +1 -0
- package/icons/ChevronExpand.svelte +1 -6
- package/icons/ChevronExpand.svelte.d.ts +13 -8
- package/icons/Cross.svelte +1 -6
- package/icons/Cross.svelte.d.ts +13 -8
- package/icons/Disabled.svelte +1 -6
- package/icons/Disabled.svelte.d.ts +13 -8
- package/index.d.ts +1 -0
- package/package.json +13 -13
- package/readme.md +37 -51
package/MultiSelect.svelte
CHANGED
|
@@ -38,6 +38,7 @@ export let autoScroll = true;
|
|
|
38
38
|
export let loading = false;
|
|
39
39
|
export let required = false;
|
|
40
40
|
export let autocomplete = `off`;
|
|
41
|
+
export let invalid = false;
|
|
41
42
|
if (maxSelect !== null && maxSelect < 0) {
|
|
42
43
|
console.error(`maxSelect must be null or positive integer, got ${maxSelect}`);
|
|
43
44
|
}
|
|
@@ -48,10 +49,6 @@ if (!Array.isArray(selected))
|
|
|
48
49
|
onMount(() => {
|
|
49
50
|
selected = _options.filter((op) => op?.preselected) ?? [];
|
|
50
51
|
});
|
|
51
|
-
let wiggle = false;
|
|
52
|
-
// formValue binds to input.form-control to prevent form submission if required
|
|
53
|
-
// prop is true and no options are selected
|
|
54
|
-
$: formValue = selectedValues.join(`,`);
|
|
55
52
|
const dispatch = createEventDispatcher();
|
|
56
53
|
function isObject(item) {
|
|
57
54
|
return typeof item === `object` && !Array.isArray(item) && item !== null;
|
|
@@ -77,8 +74,14 @@ $: labels = _options.map((op) => op.label);
|
|
|
77
74
|
$: if (new Set(labels).size !== options.length) {
|
|
78
75
|
console.error(`Option labels must be unique. Duplicates found: ${labels.filter((label, idx) => labels.indexOf(label) !== idx)}`);
|
|
79
76
|
}
|
|
77
|
+
let wiggle = false;
|
|
80
78
|
$: selectedLabels = selected.map((op) => op.label);
|
|
81
79
|
$: selectedValues = selected.map((op) => op.value);
|
|
80
|
+
// formValue binds to input.form-control to prevent form submission if required
|
|
81
|
+
// prop is true and no options are selected
|
|
82
|
+
$: formValue = selectedValues.join(`,`);
|
|
83
|
+
$: if (formValue)
|
|
84
|
+
invalid = false; // reset error status whenever component state changes
|
|
82
85
|
// options matching the current search text
|
|
83
86
|
$: matchingOptions = _options.filter((op) => filterFunc(op, searchText) && !selectedLabels.includes(op.label));
|
|
84
87
|
$: matchingEnabledOptions = matchingOptions.filter((op) => !op.disabled);
|
|
@@ -121,11 +124,14 @@ function setOptionsVisible(show) {
|
|
|
121
124
|
if (disabled)
|
|
122
125
|
return;
|
|
123
126
|
showOptions = show;
|
|
124
|
-
if (show)
|
|
127
|
+
if (show) {
|
|
125
128
|
input?.focus();
|
|
129
|
+
dispatch(`focus`);
|
|
130
|
+
}
|
|
126
131
|
else {
|
|
127
132
|
input?.blur();
|
|
128
133
|
activeOption = null;
|
|
134
|
+
dispatch(`blur`);
|
|
129
135
|
}
|
|
130
136
|
}
|
|
131
137
|
// handle all keyboard events this component receives
|
|
@@ -208,20 +214,28 @@ display above those of another following shortly after it -->
|
|
|
208
214
|
class:disabled
|
|
209
215
|
class:single={maxSelect === 1}
|
|
210
216
|
class:open={showOptions}
|
|
217
|
+
aria-expanded={showOptions}
|
|
218
|
+
aria-multiselectable={maxSelect === null || maxSelect > 1}
|
|
219
|
+
class:invalid
|
|
211
220
|
class="multiselect {outerDivClass}"
|
|
212
221
|
on:mouseup|stopPropagation={() => setOptionsVisible(true)}
|
|
213
|
-
on:focusout={() =>
|
|
214
|
-
setOptionsVisible(false)
|
|
215
|
-
dispatch(`blur`)
|
|
216
|
-
}}
|
|
222
|
+
on:focusout={() => setOptionsVisible(false)}
|
|
217
223
|
title={disabled ? disabledTitle : null}
|
|
224
|
+
aria-disabled={disabled ? `true` : null}
|
|
218
225
|
>
|
|
219
226
|
<!-- invisible input, used only to prevent form submission if required=true and no options selected -->
|
|
220
|
-
<input
|
|
221
|
-
|
|
227
|
+
<input
|
|
228
|
+
{required}
|
|
229
|
+
bind:value={formValue}
|
|
230
|
+
tabindex="-1"
|
|
231
|
+
aria-hidden="true"
|
|
232
|
+
class="form-control"
|
|
233
|
+
on:invalid={() => (invalid = true)}
|
|
234
|
+
/>
|
|
235
|
+
<ExpandIcon width="15px" style="min-width: 1em; padding: 0 1pt;" />
|
|
222
236
|
<ul class="selected {ulSelectedClass}">
|
|
223
237
|
{#each selected as option, idx}
|
|
224
|
-
<li class={liSelectedClass}>
|
|
238
|
+
<li class={liSelectedClass} aria-selected="true">
|
|
225
239
|
<slot name="selected" {option} {idx}>
|
|
226
240
|
{option.label}
|
|
227
241
|
</slot>
|
|
@@ -232,7 +246,7 @@ display above those of another following shortly after it -->
|
|
|
232
246
|
type="button"
|
|
233
247
|
title="{removeBtnTitle} {option.label}"
|
|
234
248
|
>
|
|
235
|
-
<CrossIcon
|
|
249
|
+
<CrossIcon width="15px" />
|
|
236
250
|
</button>
|
|
237
251
|
{/if}
|
|
238
252
|
</li>
|
|
@@ -250,6 +264,7 @@ display above those of another following shortly after it -->
|
|
|
250
264
|
{name}
|
|
251
265
|
{disabled}
|
|
252
266
|
placeholder={selectedLabels.length ? `` : placeholder}
|
|
267
|
+
aria-invalid={invalid ? `true` : null}
|
|
253
268
|
/>
|
|
254
269
|
</li>
|
|
255
270
|
</ul>
|
|
@@ -260,7 +275,7 @@ display above those of another following shortly after it -->
|
|
|
260
275
|
{/if}
|
|
261
276
|
{#if disabled}
|
|
262
277
|
<slot name="disabled-icon">
|
|
263
|
-
<DisabledIcon
|
|
278
|
+
<DisabledIcon width="15px" />
|
|
264
279
|
</slot>
|
|
265
280
|
{:else if selected.length > 0}
|
|
266
281
|
{#if maxSelect && (maxSelect > 1 || maxSelectMsg)}
|
|
@@ -271,7 +286,7 @@ display above those of another following shortly after it -->
|
|
|
271
286
|
</span>
|
|
272
287
|
</Wiggle>
|
|
273
288
|
{/if}
|
|
274
|
-
{#if maxSelect !== 1}
|
|
289
|
+
{#if maxSelect !== 1 && selected.length > 1}
|
|
275
290
|
<button
|
|
276
291
|
type="button"
|
|
277
292
|
class="remove-all"
|
|
@@ -279,7 +294,7 @@ display above those of another following shortly after it -->
|
|
|
279
294
|
on:mouseup|stopPropagation={removeAll}
|
|
280
295
|
on:keydown={handleEnterAndSpaceKeys(removeAll)}
|
|
281
296
|
>
|
|
282
|
-
<CrossIcon
|
|
297
|
+
<CrossIcon width="15px" />
|
|
283
298
|
</button>
|
|
284
299
|
{/if}
|
|
285
300
|
{/if}
|
|
@@ -315,6 +330,7 @@ display above those of another following shortly after it -->
|
|
|
315
330
|
}}
|
|
316
331
|
on:mouseout={() => (activeOption = null)}
|
|
317
332
|
on:blur={() => (activeOption = null)}
|
|
333
|
+
aria-selected="false"
|
|
318
334
|
>
|
|
319
335
|
<slot name="option" {option} {idx}>
|
|
320
336
|
{option.label}
|
|
@@ -383,13 +399,13 @@ display above those of another following shortly after it -->
|
|
|
383
399
|
cursor: pointer;
|
|
384
400
|
outline: none;
|
|
385
401
|
padding: 0;
|
|
386
|
-
margin: 0 0 0
|
|
402
|
+
margin: 0 0 0 3pt; /* CSS reset */
|
|
387
403
|
}
|
|
388
|
-
:where(
|
|
389
|
-
|
|
404
|
+
:where(div.multiselect button.remove-all) {
|
|
405
|
+
margin: 0 3pt;
|
|
390
406
|
}
|
|
391
|
-
:where(
|
|
392
|
-
|
|
407
|
+
:where(ul.selected > li button:hover, button.remove-all:hover, button:focus) {
|
|
408
|
+
color: var(--sms-button-hover-color, lightskyblue);
|
|
393
409
|
}
|
|
394
410
|
|
|
395
411
|
:where(div.multiselect input) {
|
|
@@ -406,6 +422,9 @@ display above those of another following shortly after it -->
|
|
|
406
422
|
font-size: inherit;
|
|
407
423
|
cursor: inherit; /* needed for disabled state */
|
|
408
424
|
}
|
|
425
|
+
:where(div.multiselect > ul.selected > li > input)::placeholder {
|
|
426
|
+
color: var(--sms-placeholder-color);
|
|
427
|
+
}
|
|
409
428
|
:where(div.multiselect > input.form-control) {
|
|
410
429
|
width: 2em;
|
|
411
430
|
position: absolute;
|
package/MultiSelect.svelte.d.ts
CHANGED
|
@@ -1,9 +1,4 @@
|
|
|
1
|
-
<
|
|
2
|
-
export let height = width;
|
|
3
|
-
export let style = ``;
|
|
4
|
-
</script>
|
|
5
|
-
|
|
6
|
-
<svg {width} {height} {style} fill="currentColor" viewBox="0 0 16 16">
|
|
1
|
+
<svg {...$$props} fill="currentColor" viewBox="0 0 16 16">
|
|
7
2
|
<path
|
|
8
3
|
d="M3.646 9.146a.5.5 0 0 1 .708 0L8 12.793l3.646-3.647a.5.5 0 0 1 .708.708l-4 4a.5.5 0 0 1-.708 0l-4-4a.5.5 0 0 1 0-.708zm0-2.292a.5.5 0 0 0 .708 0L8 3.207l3.646 3.647a.5.5 0 0 0 .708-.708l-4-4a.5.5 0 0 0-.708 0l-4 4a.5.5 0 0 0 0 .708z"
|
|
9
4
|
/>
|
|
@@ -1,18 +1,23 @@
|
|
|
1
|
+
/** @typedef {typeof __propDef.props} ChevronExpandProps */
|
|
2
|
+
/** @typedef {typeof __propDef.events} ChevronExpandEvents */
|
|
3
|
+
/** @typedef {typeof __propDef.slots} ChevronExpandSlots */
|
|
4
|
+
export default class ChevronExpand extends SvelteComponentTyped<{
|
|
5
|
+
[x: string]: any;
|
|
6
|
+
}, {
|
|
7
|
+
[evt: string]: CustomEvent<any>;
|
|
8
|
+
}, {}> {
|
|
9
|
+
}
|
|
10
|
+
export type ChevronExpandProps = typeof __propDef.props;
|
|
11
|
+
export type ChevronExpandEvents = typeof __propDef.events;
|
|
12
|
+
export type ChevronExpandSlots = typeof __propDef.slots;
|
|
1
13
|
import { SvelteComponentTyped } from "svelte";
|
|
2
14
|
declare const __propDef: {
|
|
3
15
|
props: {
|
|
4
|
-
|
|
5
|
-
height?: string | number | undefined;
|
|
6
|
-
style?: string | undefined;
|
|
16
|
+
[x: string]: any;
|
|
7
17
|
};
|
|
8
18
|
events: {
|
|
9
19
|
[evt: string]: CustomEvent<any>;
|
|
10
20
|
};
|
|
11
21
|
slots: {};
|
|
12
22
|
};
|
|
13
|
-
export declare type ChevronExpandProps = typeof __propDef.props;
|
|
14
|
-
export declare type ChevronExpandEvents = typeof __propDef.events;
|
|
15
|
-
export declare type ChevronExpandSlots = typeof __propDef.slots;
|
|
16
|
-
export default class ChevronExpand extends SvelteComponentTyped<ChevronExpandProps, ChevronExpandEvents, ChevronExpandSlots> {
|
|
17
|
-
}
|
|
18
23
|
export {};
|
package/icons/Cross.svelte
CHANGED
|
@@ -1,9 +1,4 @@
|
|
|
1
|
-
<
|
|
2
|
-
export let height = width;
|
|
3
|
-
export let style = ``;
|
|
4
|
-
</script>
|
|
5
|
-
|
|
6
|
-
<svg {width} {height} {style} viewBox="0 0 20 20" fill="currentColor">
|
|
1
|
+
<svg {...$$props} viewBox="0 0 20 20" fill="currentColor">
|
|
7
2
|
<path
|
|
8
3
|
d="M10 1.6a8.4 8.4 0 100 16.8 8.4 8.4 0 000-16.8zm4.789 11.461L13.06 14.79 10 11.729l-3.061 3.06L5.21 13.06 8.272 10 5.211 6.939 6.94 5.211 10 8.271l3.061-3.061 1.729 1.729L11.728 10l3.061 3.061z"
|
|
9
4
|
/>
|
package/icons/Cross.svelte.d.ts
CHANGED
|
@@ -1,18 +1,23 @@
|
|
|
1
|
+
/** @typedef {typeof __propDef.props} CrossProps */
|
|
2
|
+
/** @typedef {typeof __propDef.events} CrossEvents */
|
|
3
|
+
/** @typedef {typeof __propDef.slots} CrossSlots */
|
|
4
|
+
export default class Cross extends SvelteComponentTyped<{
|
|
5
|
+
[x: string]: any;
|
|
6
|
+
}, {
|
|
7
|
+
[evt: string]: CustomEvent<any>;
|
|
8
|
+
}, {}> {
|
|
9
|
+
}
|
|
10
|
+
export type CrossProps = typeof __propDef.props;
|
|
11
|
+
export type CrossEvents = typeof __propDef.events;
|
|
12
|
+
export type CrossSlots = typeof __propDef.slots;
|
|
1
13
|
import { SvelteComponentTyped } from "svelte";
|
|
2
14
|
declare const __propDef: {
|
|
3
15
|
props: {
|
|
4
|
-
|
|
5
|
-
height?: string | number | undefined;
|
|
6
|
-
style?: string | undefined;
|
|
16
|
+
[x: string]: any;
|
|
7
17
|
};
|
|
8
18
|
events: {
|
|
9
19
|
[evt: string]: CustomEvent<any>;
|
|
10
20
|
};
|
|
11
21
|
slots: {};
|
|
12
22
|
};
|
|
13
|
-
export declare type CrossProps = typeof __propDef.props;
|
|
14
|
-
export declare type CrossEvents = typeof __propDef.events;
|
|
15
|
-
export declare type CrossSlots = typeof __propDef.slots;
|
|
16
|
-
export default class Cross extends SvelteComponentTyped<CrossProps, CrossEvents, CrossSlots> {
|
|
17
|
-
}
|
|
18
23
|
export {};
|
package/icons/Disabled.svelte
CHANGED
|
@@ -1,9 +1,4 @@
|
|
|
1
|
-
<
|
|
2
|
-
export let height = width;
|
|
3
|
-
export let style = ``;
|
|
4
|
-
</script>
|
|
5
|
-
|
|
6
|
-
<svg {width} {height} {style} viewBox="0 0 24 24" fill="currentColor">
|
|
1
|
+
<svg {...$$props} viewBox="0 0 24 24" fill="currentColor">
|
|
7
2
|
<path fill="none" d="M0 0h24v24H0V0z" />
|
|
8
3
|
<path
|
|
9
4
|
d="M14.48 11.95c.17.02.34.05.52.05 2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4c0 .18.03.35.05.52l3.43 3.43zm2.21 2.21L22.53 20H23v-2c0-2.14-3.56-3.5-6.31-3.84zM0 3.12l4 4V10H1v2h3v3h2v-3h2.88l2.51 2.51C9.19 15.11 7 16.3 7 18v2h9.88l4 4 1.41-1.41L1.41 1.71 0 3.12zM6.88 10H6v-.88l.88.88z"
|
|
@@ -1,18 +1,23 @@
|
|
|
1
|
+
/** @typedef {typeof __propDef.props} DisabledProps */
|
|
2
|
+
/** @typedef {typeof __propDef.events} DisabledEvents */
|
|
3
|
+
/** @typedef {typeof __propDef.slots} DisabledSlots */
|
|
4
|
+
export default class Disabled extends SvelteComponentTyped<{
|
|
5
|
+
[x: string]: any;
|
|
6
|
+
}, {
|
|
7
|
+
[evt: string]: CustomEvent<any>;
|
|
8
|
+
}, {}> {
|
|
9
|
+
}
|
|
10
|
+
export type DisabledProps = typeof __propDef.props;
|
|
11
|
+
export type DisabledEvents = typeof __propDef.events;
|
|
12
|
+
export type DisabledSlots = typeof __propDef.slots;
|
|
1
13
|
import { SvelteComponentTyped } from "svelte";
|
|
2
14
|
declare const __propDef: {
|
|
3
15
|
props: {
|
|
4
|
-
|
|
5
|
-
height?: string | number | undefined;
|
|
6
|
-
style?: string | undefined;
|
|
16
|
+
[x: string]: any;
|
|
7
17
|
};
|
|
8
18
|
events: {
|
|
9
19
|
[evt: string]: CustomEvent<any>;
|
|
10
20
|
};
|
|
11
21
|
slots: {};
|
|
12
22
|
};
|
|
13
|
-
export declare type DisabledProps = typeof __propDef.props;
|
|
14
|
-
export declare type DisabledEvents = typeof __propDef.events;
|
|
15
|
-
export declare type DisabledSlots = typeof __propDef.slots;
|
|
16
|
-
export default class Disabled extends SvelteComponentTyped<DisabledProps, DisabledEvents, DisabledSlots> {
|
|
17
|
-
}
|
|
18
23
|
export {};
|
package/index.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -5,23 +5,23 @@
|
|
|
5
5
|
"homepage": "https://svelte-multiselect.netlify.app",
|
|
6
6
|
"repository": "https://github.com/janosh/svelte-multiselect",
|
|
7
7
|
"license": "MIT",
|
|
8
|
-
"version": "4.0.
|
|
8
|
+
"version": "4.0.2",
|
|
9
9
|
"type": "module",
|
|
10
10
|
"svelte": "index.js",
|
|
11
11
|
"bugs": "https://github.com/janosh/svelte-multiselect/issues",
|
|
12
12
|
"devDependencies": {
|
|
13
|
-
"@sveltejs/adapter-static": "^1.0.0-next.
|
|
14
|
-
"@sveltejs/kit": "^1.0.0-next.
|
|
15
|
-
"@sveltejs/vite-plugin-svelte": "^1.0.0-next.
|
|
16
|
-
"@
|
|
17
|
-
"@typescript-eslint/
|
|
18
|
-
"@
|
|
19
|
-
"
|
|
20
|
-
"eslint": "^8.9.0",
|
|
13
|
+
"@sveltejs/adapter-static": "^1.0.0-next.29",
|
|
14
|
+
"@sveltejs/kit": "^1.0.0-next.295",
|
|
15
|
+
"@sveltejs/vite-plugin-svelte": "^1.0.0-next.39",
|
|
16
|
+
"@typescript-eslint/eslint-plugin": "^5.14.0",
|
|
17
|
+
"@typescript-eslint/parser": "^5.14.0",
|
|
18
|
+
"@vitest/ui": "^0.6.0",
|
|
19
|
+
"eslint": "^8.11.0",
|
|
21
20
|
"eslint-plugin-svelte3": "^3.4.1",
|
|
22
21
|
"hastscript": "^7.0.2",
|
|
23
22
|
"jsdom": "^19.0.0",
|
|
24
23
|
"mdsvex": "^0.10.5",
|
|
24
|
+
"playwright": "^1.19.2",
|
|
25
25
|
"prettier": "^2.5.1",
|
|
26
26
|
"prettier-plugin-svelte": "^2.6.0",
|
|
27
27
|
"rehype-autolink-headings": "^6.1.1",
|
|
@@ -30,12 +30,12 @@
|
|
|
30
30
|
"svelte-check": "^2.4.5",
|
|
31
31
|
"svelte-github-corner": "^0.1.0",
|
|
32
32
|
"svelte-preprocess": "^4.10.4",
|
|
33
|
-
"svelte-toc": "^0.2.
|
|
33
|
+
"svelte-toc": "^0.2.7",
|
|
34
34
|
"svelte2tsx": "^0.5.5",
|
|
35
35
|
"tslib": "^2.3.1",
|
|
36
|
-
"typescript": "^4.
|
|
37
|
-
"vite": "^2.8.
|
|
38
|
-
"vitest": "^0.
|
|
36
|
+
"typescript": "^4.6.2",
|
|
37
|
+
"vite": "^2.8.6",
|
|
38
|
+
"vitest": "^0.6.0"
|
|
39
39
|
},
|
|
40
40
|
"keywords": [
|
|
41
41
|
"svelte",
|
package/readme.md
CHANGED
|
@@ -9,19 +9,13 @@
|
|
|
9
9
|
[](https://app.netlify.com/sites/svelte-multiselect/deploys)
|
|
10
10
|
[](https://npmjs.com/package/svelte-multiselect)
|
|
11
11
|
[](https://results.pre-commit.ci/latest/github/janosh/svelte-multiselect/main)
|
|
12
|
-

|
|
12
|
+
[](https://github.com/sveltejs/svelte/blob/master/CHANGELOG.md)
|
|
13
13
|
|
|
14
14
|
</h4>
|
|
15
15
|
|
|
16
|
-
<
|
|
16
|
+
**Keyboard-friendly, zero-dependency multi-select Svelte component.** <strong class="hide-in-docs"><a href="https://svelte-multiselect.netlify.app">Live demo</a></strong>
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
</div>
|
|
21
|
-
|
|
22
|
-
**Keyboard-friendly, zero-dependency multi-select Svelte component.**
|
|
23
|
-
|
|
24
|
-
<slot />
|
|
18
|
+
<slot name="examples" />
|
|
25
19
|
|
|
26
20
|
## Key features
|
|
27
21
|
|
|
@@ -34,6 +28,8 @@
|
|
|
34
28
|
- **No dependencies:** needs only Svelte as dev dependency
|
|
35
29
|
- **Keyboard friendly** for mouse-less form completion
|
|
36
30
|
|
|
31
|
+
<slot name="nav" />
|
|
32
|
+
|
|
37
33
|
## Recent breaking changes
|
|
38
34
|
|
|
39
35
|
- v3.0.0 changed the `event.detail` payload for `'add'`, `'remove'` and `'change'` events from `token` to `option`, e.g.
|
|
@@ -64,28 +60,16 @@ yarn add -D svelte-multiselect
|
|
|
64
60
|
<script>
|
|
65
61
|
import MultiSelect from 'svelte-multiselect'
|
|
66
62
|
|
|
67
|
-
const
|
|
68
|
-
`Svelte`,
|
|
69
|
-
`React`,
|
|
70
|
-
`Vue`,
|
|
71
|
-
`Angular`,
|
|
72
|
-
`Polymer`,
|
|
73
|
-
`Ruby on Rails`,
|
|
74
|
-
`ASP.net`,
|
|
75
|
-
`Laravel`,
|
|
76
|
-
`Django`,
|
|
77
|
-
`Express`,
|
|
78
|
-
`Spring`,
|
|
79
|
-
]
|
|
63
|
+
const ui_libs = [`Svelte`, `React`, `Vue`, `Angular`, `...`]
|
|
80
64
|
|
|
81
65
|
let selected = []
|
|
82
66
|
</script>
|
|
83
67
|
|
|
84
|
-
Favorite
|
|
68
|
+
Favorite Frontend Frameworks?
|
|
85
69
|
|
|
86
70
|
<code>selected = {JSON.stringify(selected)}</code>
|
|
87
71
|
|
|
88
|
-
<MultiSelect bind:selected options={
|
|
72
|
+
<MultiSelect bind:selected options={ui_libs} />
|
|
89
73
|
```
|
|
90
74
|
|
|
91
75
|
## Props
|
|
@@ -95,31 +79,32 @@ Full list of props/bindable variables for this component:
|
|
|
95
79
|
<div class="table">
|
|
96
80
|
|
|
97
81
|
<!-- prettier-ignore -->
|
|
98
|
-
| name | default | description
|
|
99
|
-
| :--------------------- | :-------------------------- |
|
|
100
|
-
| `options` | required prop | Array of strings/numbers or `Option` objects that will be listed in the dropdown. See `src/lib/index.ts` for admissible fields. The `label` is the only mandatory one. It must also be unique.
|
|
101
|
-
| `showOptions` | `false` | Bindable boolean that controls whether the options dropdown is visible.
|
|
102
|
-
| `searchText` | `` | 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.
|
|
103
|
-
| `activeOption` | `null` | Currently active option, i.e. the one the user currently hovers or navigated to with arrow keys.
|
|
104
|
-
| `maxSelect` | `null` | Positive integer to limit the number of options users can pick. `null` means no limit.
|
|
105
|
-
| `selected` | `[]` | Array of currently/pre-selected options when binding/passing as props respectively.
|
|
106
|
-
| `selectedLabels` | `[]` | Labels of currently selected options.
|
|
107
|
-
| `selectedValues` | `[]` | Values of currently selected options.
|
|
108
|
-
| `noOptionsMsg` | `'No matching options'` | What message to show if no options match the user-entered search string.
|
|
109
|
-
| `disabled` | `false` | Disable the component. It will still be rendered but users won't be able to interact with it.
|
|
110
|
-
| `disabledTitle` | `This field is disabled` | Tooltip text to display on hover when the component is in `disabled` state.
|
|
111
|
-
| `placeholder` | `undefined` | String shown in the text input when no option is selected.
|
|
112
|
-
| `input` | `undefined` | Handle to the `<input>` DOM node.
|
|
113
|
-
| `id` | `undefined` | Applied to the `<input>` element for associating HTML form `<label>`s with this component for accessibility. Also, clicking a `<label>` with same `for` attribute as `id` will focus this component.
|
|
114
|
-
| `name` | `id` | Applied to the `<input>` element. If not provided, will be set to the value of `id`. 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>`.
|
|
115
|
-
| `required` | `false` | 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.
|
|
116
|
-
| `autoScroll` | `true` | `false` disables keeping the active dropdown items in view when going up/down the list of options with arrow keys.
|
|
117
|
-
| `allowUserOptions` | `false` | Whether users are allowed to enter values not in the dropdown list. `true` means add user-defined options to the selected list only, `'append'` means add to both options and selected.
|
|
118
|
-
| `loading` | `false` | Whether the component should display a spinner to indicate it's in loading state. Use `<slot name='spinner'>` to specify a custom spinner.
|
|
119
|
-
| `removeBtnTitle` | `'Remove'` | Title text to display when user hovers over button (cross icon) to remove selected option.
|
|
120
|
-
| `removeAllTitle` | `'Remove all'` | Title text to display when user hovers over remove-all button.
|
|
121
|
-
| `defaultDisabledTitle` | `'This option is disabled'` | Title text to display when user hovers over a disabled option. Each option can override this through its `disabledTitle` attribute.
|
|
122
|
-
| `autocomplete` | `'off'` | Applied to the `<input>`. Specifies if browser is permitted to auto-fill this form field. See [MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete) for other admissible values.
|
|
82
|
+
| name | default | description |
|
|
83
|
+
| :--------------------- | :-------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
84
|
+
| `options` | required prop | Array of strings/numbers or `Option` objects that will be listed in the dropdown. See `src/lib/index.ts` for admissible fields. The `label` is the only mandatory one. It must also be unique. |
|
|
85
|
+
| `showOptions` | `false` | Bindable boolean that controls whether the options dropdown is visible. |
|
|
86
|
+
| `searchText` | `` | 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. |
|
|
87
|
+
| `activeOption` | `null` | Currently active option, i.e. the one the user currently hovers or navigated to with arrow keys. |
|
|
88
|
+
| `maxSelect` | `null` | Positive integer to limit the number of options users can pick. `null` means no limit. |
|
|
89
|
+
| `selected` | `[]` | Array of currently/pre-selected options when binding/passing as props respectively. |
|
|
90
|
+
| `selectedLabels` | `[]` | Labels of currently selected options. |
|
|
91
|
+
| `selectedValues` | `[]` | Values of currently selected options. |
|
|
92
|
+
| `noOptionsMsg` | `'No matching options'` | What message to show if no options match the user-entered search string. |
|
|
93
|
+
| `disabled` | `false` | Disable the component. It will still be rendered but users won't be able to interact with it. |
|
|
94
|
+
| `disabledTitle` | `This field is disabled` | Tooltip text to display on hover when the component is in `disabled` state. |
|
|
95
|
+
| `placeholder` | `undefined` | String shown in the text input when no option is selected. |
|
|
96
|
+
| `input` | `undefined` | Handle to the `<input>` DOM node. |
|
|
97
|
+
| `id` | `undefined` | Applied to the `<input>` element for associating HTML form `<label>`s with this component for accessibility. Also, clicking a `<label>` with same `for` attribute as `id` will focus this component. |
|
|
98
|
+
| `name` | `id` | Applied to the `<input>` element. If not provided, will be set to the value of `id`. 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>`. |
|
|
99
|
+
| `required` | `false` | 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. |
|
|
100
|
+
| `autoScroll` | `true` | `false` disables keeping the active dropdown items in view when going up/down the list of options with arrow keys. |
|
|
101
|
+
| `allowUserOptions` | `false` | Whether users are allowed to enter values 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
|
+
| `loading` | `false` | Whether the component should display a spinner to indicate it's in loading state. Use `<slot name='spinner'>` to specify a custom spinner. |
|
|
103
|
+
| `removeBtnTitle` | `'Remove'` | Title text to display when user hovers over button (cross icon) to remove selected option. |
|
|
104
|
+
| `removeAllTitle` | `'Remove all'` | Title text to display when user hovers over remove-all button. |
|
|
105
|
+
| `defaultDisabledTitle` | `'This option is disabled'` | Title text to display when user hovers over a disabled option. Each option can override this through its `disabledTitle` attribute. |
|
|
106
|
+
| `autocomplete` | `'off'` | Applied to the `<input>`. Specifies if browser is permitted to auto-fill this form field. See [MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete) for other admissible values. |
|
|
107
|
+
| `invalid` | `false` | If `required=true` and user tries to submit but `selected = []` is empty, `invalid` is automatically set to `true` and CSS class `invalid` applied to the top-level `div.multiselect`. `invalid` class is removed again as soon as the user selects an option. `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. |
|
|
123
108
|
|
|
124
109
|
</div>
|
|
125
110
|
|
|
@@ -239,6 +224,7 @@ If you only want to make small adjustments, you can pass the following CSS varia
|
|
|
239
224
|
- `background: var(--sms-input-bg)`
|
|
240
225
|
- `height: var(--sms-input-height, 2em)`
|
|
241
226
|
- `color: var(--sms-text-color)`
|
|
227
|
+
- `color: var(--sms-placeholder-color)`
|
|
242
228
|
- `div.multiselect.open`
|
|
243
229
|
- `z-index: var(--sms-open-z-index, 4)`: Increase this if needed to ensure the dropdown list is displayed atop all other page elements.
|
|
244
230
|
- `div.multiselect:focus-within`
|
|
@@ -250,7 +236,7 @@ If you only want to make small adjustments, you can pass the following CSS varia
|
|
|
250
236
|
- `height: var(--sms-selected-li-height)`: Height of selected options.
|
|
251
237
|
- `color: var(--sms-selected-text-color, var(--sms-text-color))`: Text color for selected options.
|
|
252
238
|
- `ul.selected > li button:hover, button.remove-all:hover, button:focus`
|
|
253
|
-
- `color: var(--sms-
|
|
239
|
+
- `color: var(--sms-button-hover-color, lightskyblue)`: Color of the cross-icon buttons for removing all or individual selected options when in `:focus` or `:hover` state.
|
|
254
240
|
- `div.multiselect > ul.options`
|
|
255
241
|
- `background: var(--sms-options-bg, white)`: Background of dropdown list.
|
|
256
242
|
- `max-height: var(--sms-options-max-height, 50vh)`: Maximum height of options dropdown.
|
|
@@ -353,7 +339,7 @@ You can alternatively style every part of this component with more fine-grained
|
|
|
353
339
|
|
|
354
340
|
## Downstream testing
|
|
355
341
|
|
|
356
|
-
To test a Svelte component which imports `svelte-multiselect`, you need to configure your test runner to avoid [transpiling issues](https://github.com/
|
|
342
|
+
To test a Svelte component which imports `svelte-multiselect`, you need to configure your test runner to avoid [transpiling issues](https://github.com/janosh/svelte-multiselect/issues/48).
|
|
357
343
|
|
|
358
344
|
For Jest, exclude `svelte-multiselect` from `transformIgnorePatterns` in your `jest.config.json`:
|
|
359
345
|
|