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.
@@ -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 {required} bind:value={formValue} tabindex="-1" class="form-control" />
221
- <ExpandIcon style="min-width: 1em; padding: 0 1pt;" />
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 height="12pt" />
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 height="14pt" />
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 height="14pt" />
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 4pt; /* CSS reset */
402
+ margin: 0 0 0 3pt; /* CSS reset */
387
403
  }
388
- :where(ul.selected > li button:hover, button.remove-all:hover, button:focus) {
389
- color: var(--sms-remove-x-hover-focus-color, lightskyblue);
404
+ :where(div.multiselect button.remove-all) {
405
+ margin: 0 3pt;
390
406
  }
391
- :where(div.multiselect > button:focus) {
392
- transform: scale(1.04);
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;
@@ -33,6 +33,7 @@ declare const __propDef: {
33
33
  loading?: boolean | undefined;
34
34
  required?: boolean | undefined;
35
35
  autocomplete?: string | undefined;
36
+ invalid?: boolean | undefined;
36
37
  };
37
38
  events: {
38
39
  mouseup: MouseEvent;
@@ -1,9 +1,4 @@
1
- <script >export let width = `1em`;
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
- width?: string | number | undefined;
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 {};
@@ -1,9 +1,4 @@
1
- <script >export let width = `1em`;
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
  />
@@ -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
- width?: string | number | undefined;
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 {};
@@ -1,9 +1,4 @@
1
- <script >export let width = `1em`;
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
- width?: string | number | undefined;
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
@@ -28,5 +28,6 @@ export declare type DispatchEvents = {
28
28
  options?: Option[];
29
29
  type: 'add' | 'remove' | 'removeAll';
30
30
  };
31
+ focus: undefined;
31
32
  blur: undefined;
32
33
  };
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.1",
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.28",
14
- "@sveltejs/kit": "^1.0.0-next.287",
15
- "@sveltejs/vite-plugin-svelte": "^1.0.0-next.38",
16
- "@testing-library/svelte": "^3.0.3",
17
- "@typescript-eslint/eslint-plugin": "^5.12.1",
18
- "@typescript-eslint/parser": "^5.12.0",
19
- "@vitest/ui": "^0.5.7",
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.6",
33
+ "svelte-toc": "^0.2.7",
34
34
  "svelte2tsx": "^0.5.5",
35
35
  "tslib": "^2.3.1",
36
- "typescript": "^4.5.5",
37
- "vite": "^2.8.4",
38
- "vitest": "^0.5.7"
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
  [![Netlify Status](https://api.netlify.com/api/v1/badges/a45b62c3-ea45-4cfd-9912-77ec4fc8d7e8/deploy-status)](https://app.netlify.com/sites/svelte-multiselect/deploys)
10
10
  [![NPM version](https://img.shields.io/npm/v/svelte-multiselect?color=blue&logo=NPM)](https://npmjs.com/package/svelte-multiselect)
11
11
  [![pre-commit.ci status](https://results.pre-commit.ci/badge/github/janosh/svelte-multiselect/main.svg)](https://results.pre-commit.ci/latest/github/janosh/svelte-multiselect/main)
12
- ![Needs Svelte version](https://img.shields.io/npm/dependency-version/svelte-multiselect/dev/svelte)
12
+ [![Needs Svelte version](https://img.shields.io/npm/dependency-version/svelte-multiselect/dev/svelte)](https://github.com/sveltejs/svelte/blob/master/CHANGELOG.md)
13
13
 
14
14
  </h4>
15
15
 
16
- <div class="hide-in-docs">
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
- **[Live demo](https://svelte-multiselect.netlify.app)**.
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 webFrameworks = [
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 Web Frameworks?
68
+ Favorite Frontend Frameworks?
85
69
 
86
70
  <code>selected = {JSON.stringify(selected)}</code>
87
71
 
88
- <MultiSelect bind:selected options={webFrameworks} />
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-remove-x-hover-focus-color, lightskyblue)`: Color of the cross-icon buttons for removing all or individual selected options when in `:focus` or `:hover` state.
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/EmilTholin/svelte-routing/issues/140#issuecomment-661682571).
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