svelte-multiselect 8.0.4 → 8.2.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.
@@ -10,9 +10,9 @@ declare const __propDef: {
10
10
  };
11
11
  slots: {};
12
12
  };
13
- export declare type CircleSpinnerProps = typeof __propDef.props;
14
- export declare type CircleSpinnerEvents = typeof __propDef.events;
15
- export declare type CircleSpinnerSlots = typeof __propDef.slots;
13
+ export type CircleSpinnerProps = typeof __propDef.props;
14
+ export type CircleSpinnerEvents = typeof __propDef.events;
15
+ export type CircleSpinnerSlots = typeof __propDef.slots;
16
16
  export default class CircleSpinner extends SvelteComponentTyped<CircleSpinnerProps, CircleSpinnerEvents, CircleSpinnerSlots> {
17
17
  }
18
18
  export {};
@@ -1,4 +1,5 @@
1
1
  <script>import { createEventDispatcher, tick } from 'svelte';
2
+ import { flip } from 'svelte/animate';
2
3
  import CircleSpinner from './CircleSpinner.svelte';
3
4
  import { CrossIcon, DisabledIcon, ExpandIcon } from './icons';
4
5
  import Wiggle from './Wiggle.svelte';
@@ -22,6 +23,7 @@ export let filterFunc = (op, searchText) => {
22
23
  return `${get_label(op)}`.toLowerCase().includes(searchText.toLowerCase());
23
24
  };
24
25
  export let focusInputOnSelect = `desktop`;
26
+ export let form_input = null;
25
27
  export let id = null;
26
28
  export let input = null;
27
29
  export let inputClass = ``;
@@ -32,8 +34,9 @@ export let liOptionClass = ``;
32
34
  export let liSelectedClass = ``;
33
35
  export let loading = false;
34
36
  export let matchingOptions = [];
35
- export let maxSelect = null; // null means any number of options are selectable
37
+ export let maxSelect = null; // null means there is no upper limit for selected.length
36
38
  export let maxSelectMsg = (current, max) => (max > 1 ? `${current}/${max}` : ``);
39
+ export let maxSelectMsgClass = ``;
37
40
  export let name = null;
38
41
  export let noMatchingOptionsMsg = `No matching options`;
39
42
  export let open = false;
@@ -45,12 +48,14 @@ export let pattern = null;
45
48
  export let placeholder = null;
46
49
  export let removeAllTitle = `Remove all`;
47
50
  export let removeBtnTitle = `Remove`;
51
+ export let minSelect = null; // null means there is no lower limit for selected.length
48
52
  export let required = false;
49
53
  export let resetFilterOnAdd = true;
50
54
  export let searchText = ``;
51
55
  export let selected = options
52
56
  ?.filter((op) => op?.preselected)
53
57
  .slice(0, maxSelect ?? undefined) ?? [];
58
+ export let selectedOptionsDraggable = true;
54
59
  export let sortSelected = false;
55
60
  export let ulOptionsClass = ``;
56
61
  export let ulSelectedClass = ``;
@@ -76,10 +81,13 @@ if (parseLabelsAsHtml && allowUserOptions) {
76
81
  console.warn(`Don't combine parseLabelsAsHtml and allowUserOptions. It's susceptible to XSS attacks!`);
77
82
  }
78
83
  if (maxSelect !== null && maxSelect < 1) {
79
- console.error(`maxSelect must be null or positive integer, got ${maxSelect}`);
84
+ console.error(`MultiSelect's maxSelect must be null or positive integer, got ${maxSelect}`);
80
85
  }
81
86
  if (!Array.isArray(selected)) {
82
- console.error(`internal variable selected prop should always be an array, got ${selected}`);
87
+ console.error(`MultiSelect's selected prop should always be an array, got ${selected}`);
88
+ }
89
+ if (maxSelect && typeof required === `number` && required > maxSelect) {
90
+ console.error(`MultiSelect maxSelect=${maxSelect} < required=${required}, makes it impossible for users to submit a valid form`);
83
91
  }
84
92
  const dispatch = createEventDispatcher();
85
93
  let add_option_msg_is_active = false; // controls active state of <li>{addOptionMsg}</li>
@@ -161,6 +169,7 @@ function add(label, event) {
161
169
  dispatch(`add`, { option });
162
170
  dispatch(`change`, { option, type: `add` });
163
171
  invalid = false; // reset error status whenever new items are selected
172
+ form_input?.setCustomValidity(``);
164
173
  }
165
174
  }
166
175
  // remove an option from selected list
@@ -180,6 +189,7 @@ function remove(label) {
180
189
  dispatch(`remove`, { option });
181
190
  dispatch(`change`, { option, type: `remove` });
182
191
  invalid = false; // reset error status whenever items are removed
192
+ form_input?.setCustomValidity(``);
183
193
  }
184
194
  function open_dropdown(event) {
185
195
  if (disabled)
@@ -276,6 +286,33 @@ function on_click_outside(event) {
276
286
  close_dropdown(event);
277
287
  }
278
288
  }
289
+ let drag_idx = null;
290
+ // event handlers enable dragging to reorder selected options
291
+ const drop = (target_idx) => (event) => {
292
+ if (!event.dataTransfer)
293
+ return;
294
+ event.dataTransfer.dropEffect = `move`;
295
+ const start_idx = parseInt(event.dataTransfer.getData(`text/plain`));
296
+ const new_selected = selected;
297
+ if (start_idx < target_idx) {
298
+ new_selected.splice(target_idx + 1, 0, new_selected[start_idx]);
299
+ new_selected.splice(start_idx, 1);
300
+ }
301
+ else {
302
+ new_selected.splice(target_idx, 0, new_selected[start_idx]);
303
+ new_selected.splice(start_idx + 1, 1);
304
+ }
305
+ selected = new_selected;
306
+ drag_idx = null;
307
+ };
308
+ const dragstart = (idx) => (event) => {
309
+ if (!event.dataTransfer)
310
+ return;
311
+ // only allow moving, not copying (also affects the cursor during drag)
312
+ event.dataTransfer.effectAllowed = `move`;
313
+ event.dataTransfer.dropEffect = `move`;
314
+ event.dataTransfer.setData(`text/plain`, `${idx}`);
315
+ };
279
316
  </script>
280
317
 
281
318
  <svelte:window
@@ -296,22 +333,45 @@ function on_click_outside(event) {
296
333
  on:mouseup|stopPropagation={open_dropdown}
297
334
  title={disabled ? disabledInputTitle : null}
298
335
  aria-disabled={disabled ? `true` : null}
336
+ data-id={id}
299
337
  >
300
338
  <!-- bind:value={selected} prevents form submission if required prop is true and no options are selected -->
301
339
  <input
302
- {required}
303
340
  {name}
304
- value={selected.length > 0 ? JSON.stringify(selected) : null}
341
+ required={Boolean(required)}
342
+ value={selected.length >= required ? JSON.stringify(selected) : null}
305
343
  tabindex="-1"
306
344
  aria-hidden="true"
307
345
  aria-label="ignore this, used only to prevent form submission if select is required but empty"
308
346
  class="form-control"
309
- on:invalid={() => (invalid = true)}
347
+ bind:this={form_input}
348
+ on:invalid={() => {
349
+ invalid = true
350
+ let msg
351
+ if (maxSelect && maxSelect > 1 && required > 1) {
352
+ msg = `Please select between ${required} and ${maxSelect} options`
353
+ } else if (required > 1) {
354
+ msg = `Please select at least ${required} options`
355
+ } else {
356
+ msg = `Please select an option`
357
+ }
358
+ form_input?.setCustomValidity(msg)
359
+ }}
310
360
  />
311
361
  <ExpandIcon width="15px" style="min-width: 1em; padding: 0 1pt;" />
312
362
  <ul class="selected {ulSelectedClass}">
313
- {#each selected as option, idx}
314
- <li class={liSelectedClass} aria-selected="true">
363
+ {#each selected as option, idx (get_label(option))}
364
+ <li
365
+ class={liSelectedClass}
366
+ aria-selected="true"
367
+ animate:flip={{ duration: 100 }}
368
+ draggable={selectedOptionsDraggable}
369
+ on:dragstart={dragstart(idx)}
370
+ on:drop|preventDefault={drop(idx)}
371
+ on:dragenter={() => (drag_idx = idx)}
372
+ class:active={drag_idx === idx}
373
+ ondragover="return false"
374
+ >
315
375
  <slot name="selected" {option} {idx}>
316
376
  {#if parseLabelsAsHtml}
317
377
  {@html get_label(option)}
@@ -319,7 +379,7 @@ function on_click_outside(event) {
319
379
  {get_label(option)}
320
380
  {/if}
321
381
  </slot>
322
- {#if !disabled}
382
+ {#if !disabled && (minSelect === null || selected.length > minSelect)}
323
383
  <button
324
384
  on:mouseup|stopPropagation={() => remove(get_label(option))}
325
385
  on:keydown={if_enter_or_space(() => remove(get_label(option)))}
@@ -333,38 +393,37 @@ function on_click_outside(event) {
333
393
  {/if}
334
394
  </li>
335
395
  {/each}
336
- <li style="display: contents;">
337
- <input
338
- class={inputClass}
339
- bind:this={input}
340
- {autocomplete}
341
- bind:value={searchText}
342
- on:mouseup|self|stopPropagation={open_dropdown}
343
- on:keydown|stopPropagation={handle_keydown}
344
- on:focus
345
- on:focus={open_dropdown}
346
- {id}
347
- {disabled}
348
- {inputmode}
349
- {pattern}
350
- placeholder={selected.length == 0 ? placeholder : null}
351
- aria-invalid={invalid ? `true` : null}
352
- on:blur
353
- on:change
354
- on:click
355
- on:keydown
356
- on:keyup
357
- on:mousedown
358
- on:mouseenter
359
- on:mouseleave
360
- on:touchcancel
361
- on:touchend
362
- on:touchmove
363
- on:touchstart
364
- />
365
- <!-- the above on:* lines forward potentially useful DOM events -->
366
- </li>
396
+ <input
397
+ class={inputClass}
398
+ bind:this={input}
399
+ {autocomplete}
400
+ bind:value={searchText}
401
+ on:mouseup|self|stopPropagation={open_dropdown}
402
+ on:keydown|stopPropagation={handle_keydown}
403
+ on:focus
404
+ on:focus={open_dropdown}
405
+ {id}
406
+ {disabled}
407
+ {inputmode}
408
+ {pattern}
409
+ placeholder={selected.length == 0 ? placeholder : null}
410
+ aria-invalid={invalid ? `true` : null}
411
+ on:blur
412
+ on:change
413
+ on:click
414
+ on:keydown
415
+ on:keyup
416
+ on:mousedown
417
+ on:mouseenter
418
+ on:mouseleave
419
+ on:touchcancel
420
+ on:touchend
421
+ on:touchmove
422
+ on:touchstart
423
+ style:min-width={open ? `3em` : `0`}
424
+ />
367
425
  </ul>
426
+ <!-- the above on:* lines forward potentially useful DOM events -->
368
427
  {#if loading}
369
428
  <slot name="spinner">
370
429
  <CircleSpinner />
@@ -377,7 +436,7 @@ function on_click_outside(event) {
377
436
  {:else if selected.length > 0}
378
437
  {#if maxSelect && (maxSelect > 1 || maxSelectMsg)}
379
438
  <Wiggle bind:wiggle angle={20}>
380
- <span style="padding: 0 3pt;">
439
+ <span class="max-select-msg {maxSelectMsgClass}">
381
440
  {maxSelectMsg?.(selected.length, maxSelect)}
382
441
  </span>
383
442
  </Wiggle>
@@ -474,7 +533,7 @@ function on_click_outside(event) {
474
533
  border: var(--sms-border, 1pt solid lightgray);
475
534
  border-radius: var(--sms-border-radius, 3pt);
476
535
  background: var(--sms-bg);
477
- width: var(--sms-width);
536
+ width: var(--sms-width, 100%);
478
537
  max-width: var(--sms-max-width);
479
538
  padding: var(--sms-padding, 0 3pt);
480
539
  color: var(--sms-text-color);
@@ -514,6 +573,12 @@ function on_click_outside(event) {
514
573
  padding: var(--sms-selected-li-padding, 1pt 5pt);
515
574
  color: var(--sms-selected-text-color, var(--sms-text-color));
516
575
  }
576
+ :where(div.multiselect > ul.selected > li[draggable]) {
577
+ cursor: grab;
578
+ }
579
+ :where(div.multiselect > ul.selected > li.active) {
580
+ background: var(--sms-li-active-bg, var(--sms-active-color, rgba(0, 0, 0, 0.15)));
581
+ }
517
582
  :where(div.multiselect button) {
518
583
  border-radius: 50%;
519
584
  display: flex;
@@ -538,19 +603,19 @@ function on_click_outside(event) {
538
603
  margin: auto 0; /* CSS reset */
539
604
  padding: 0; /* CSS reset */
540
605
  }
541
- :where(div.multiselect > ul.selected > li > input) {
606
+ :where(div.multiselect > ul.selected > input) {
542
607
  border: none;
543
608
  outline: none;
544
609
  background: none;
545
- flex: 1; /* this + next line fix issue #12 https://git.io/JiDe3 */
546
- min-width: 2em;
547
610
  /* ensure input uses text color and not --sms-selected-text-color */
548
611
  color: var(--sms-text-color);
549
612
  font-size: inherit;
550
613
  cursor: inherit; /* needed for disabled state */
551
614
  border-radius: 0; /* reset ul.selected > li */
615
+ width: 100%;
616
+ flex: 1;
552
617
  }
553
- :where(div.multiselect > ul.selected > li > input::placeholder) {
618
+ :where(div.multiselect > ul.selected > input::placeholder) {
554
619
  padding-left: 5pt;
555
620
  color: var(--sms-placeholder-color);
556
621
  opacity: var(--sms-placeholder-opacity);
@@ -607,4 +672,8 @@ function on_click_outside(event) {
607
672
  background: var(--sms-li-disabled-bg, #f5f5f6);
608
673
  color: var(--sms-li-disabled-text, #b8b8b8);
609
674
  }
675
+
676
+ :where(span.max-select-msg) {
677
+ padding: 0 3pt;
678
+ }
610
679
  </style>
@@ -17,6 +17,7 @@ declare const __propDef: {
17
17
  duplicates?: boolean | undefined;
18
18
  filterFunc?: ((op: Option, searchText: string) => boolean) | undefined;
19
19
  focusInputOnSelect?: boolean | "desktop" | undefined;
20
+ form_input?: HTMLInputElement | null | undefined;
20
21
  id?: string | null | undefined;
21
22
  input?: HTMLInputElement | null | undefined;
22
23
  inputClass?: string | undefined;
@@ -29,6 +30,7 @@ declare const __propDef: {
29
30
  matchingOptions?: Option[] | undefined;
30
31
  maxSelect?: number | null | undefined;
31
32
  maxSelectMsg?: ((current: number, max: number) => string) | null | undefined;
33
+ maxSelectMsgClass?: string | undefined;
32
34
  name?: string | null | undefined;
33
35
  noMatchingOptionsMsg?: string | undefined;
34
36
  open?: boolean | undefined;
@@ -40,10 +42,12 @@ declare const __propDef: {
40
42
  placeholder?: string | null | undefined;
41
43
  removeAllTitle?: string | undefined;
42
44
  removeBtnTitle?: string | undefined;
43
- required?: boolean | undefined;
45
+ minSelect?: number | null | undefined;
46
+ required?: number | boolean | undefined;
44
47
  resetFilterOnAdd?: boolean | undefined;
45
48
  searchText?: string | undefined;
46
49
  selected?: Option[] | undefined;
50
+ selectedOptionsDraggable?: boolean | undefined;
47
51
  sortSelected?: boolean | ((op1: Option, op2: Option) => number) | undefined;
48
52
  ulOptionsClass?: string | undefined;
49
53
  ulSelectedClass?: string | undefined;
@@ -65,9 +69,9 @@ declare const __propDef: {
65
69
  getters: {};
66
70
  events: MultiSelectEvents;
67
71
  };
68
- export declare type MultiSelectProps = typeof __propDef.props;
69
- export declare type MultiSelectEvents = typeof __propDef.events;
70
- export declare type MultiSelectSlots = typeof __propDef.slots;
72
+ export type MultiSelectProps = typeof __propDef.props;
73
+ export type MultiSelectEvents = typeof __propDef.events;
74
+ export type MultiSelectSlots = typeof __propDef.slots;
71
75
  export default class MultiSelect extends SvelteComponentTyped<MultiSelectProps, MultiSelectEvents, MultiSelectSlots> {
72
76
  }
73
77
  export {};
@@ -17,9 +17,9 @@ declare const __propDef: {
17
17
  default: {};
18
18
  };
19
19
  };
20
- export declare type WiggleProps = typeof __propDef.props;
21
- export declare type WiggleEvents = typeof __propDef.events;
22
- export declare type WiggleSlots = typeof __propDef.slots;
20
+ export type WiggleProps = typeof __propDef.props;
21
+ export type WiggleEvents = typeof __propDef.events;
22
+ export type WiggleSlots = typeof __propDef.slots;
23
23
  export default class Wiggle extends SvelteComponentTyped<WiggleProps, WiggleEvents, WiggleSlots> {
24
24
  }
25
25
  export {};
package/changelog.md ADDED
@@ -0,0 +1,470 @@
1
+ ### Changelog
2
+
3
+ All notable changes to this project will be documented in this file. Dates are displayed in UTC.
4
+
5
+ #### [v8.2.0](https://github.com/janosh/svelte-multiselect/compare/v8.1.0...v8.2.0)
6
+
7
+ - Draggable selected options [`#178`](https://github.com/janosh/svelte-multiselect/pull/178)
8
+ - Fix page navigation in GH pages, broken because served from non-apex domain [`#172`](https://github.com/janosh/svelte-multiselect/pull/172)
9
+ - Publish docs to GitHub pages [`#170`](https://github.com/janosh/svelte-multiselect/pull/170)
10
+ - Contributing docs plus issue and PR templates with StackBlitz repro starter [`#169`](https://github.com/janosh/svelte-multiselect/pull/169)
11
+ - add missing about field to bug-report issue template (closes #171) [`#171`](https://github.com/janosh/svelte-multiselect/issues/171)
12
+ - add changelog.md [`236d238`](https://github.com/janosh/svelte-multiselect/commit/236d238c5fa1ce5f07cf08c09861da4d8446acb2)
13
+ - fix prop form_input: set default value null to make it optional [`b150fe0`](https://github.com/janosh/svelte-multiselect/commit/b150fe0032ebde82a319b23bd5e6b573e0c31721)
14
+ - set aliveStatusCodes: [200, 429] in .github/workflows/link-check-config.json [`b34c7bf`](https://github.com/janosh/svelte-multiselect/commit/b34c7bf99d4afa96dcd3c9c322ab4e94b1ef3a39)
15
+ - add changelog script to `package.json` [`c943617`](https://github.com/janosh/svelte-multiselect/commit/c9436171033e06e8098f4443ed40d48ddee35167)
16
+
17
+ <!-- auto-changelog-above -->
18
+
19
+ #### [v8.1.0](https://github.com/janosh/svelte-multiselect/compare/v8.0.4...v8.1.0)
20
+
21
+ > 18 November 2022
22
+
23
+ - Add minSelect prop [`#166`](https://github.com/janosh/svelte-multiselect/pull/166)
24
+ - Add `pnpm test` to readme [`#168`](https://github.com/janosh/svelte-multiselect/pull/168)
25
+ - Add class for maxSelectMsg [`#167`](https://github.com/janosh/svelte-multiselect/pull/167)
26
+ - Allow `required=1 | 2 | ...` to set minimum number of selected options for form submission [`#161`](https://github.com/janosh/svelte-multiselect/pull/161)
27
+ - Add minSelect prop (#166) [`#163`](https://github.com/janosh/svelte-multiselect/issues/163) [`#163`](https://github.com/janosh/svelte-multiselect/issues/163) [`#163`](https://github.com/janosh/svelte-multiselect/issues/163)
28
+ - mv /max-select example to /min-max-select [`9838db8`](https://github.com/janosh/svelte-multiselect/commit/9838db87d044a0d3d261c82ac1d654b9e32310d1)
29
+
30
+ #### [v8.0.4](https://github.com/janosh/svelte-multiselect/compare/v8.0.3...v8.0.4)
31
+
32
+ > 15 November 2022
33
+
34
+ - Form validation docs [`#159`](https://github.com/janosh/svelte-multiselect/pull/159)
35
+ - Don't `console.error` about missing `options` if `disabled=true` [`#158`](https://github.com/janosh/svelte-multiselect/pull/158)
36
+
37
+ #### [v8.0.3](https://github.com/janosh/svelte-multiselect/compare/v8.0.2...v8.0.3)
38
+
39
+ > 15 November 2022
40
+
41
+ - Test uncovered lines [`#157`](https://github.com/janosh/svelte-multiselect/pull/157)
42
+ - Don't `console.error` about missing `options` if `loading=true` [`#156`](https://github.com/janosh/svelte-multiselect/pull/156)
43
+ - Measure `vitest` coverage with `c8` [`#155`](https://github.com/janosh/svelte-multiselect/pull/155)
44
+ - increase --sms-min-height 19-&gt;22pt [`5d0e081`](https://github.com/janosh/svelte-multiselect/commit/5d0e0815d0b488ae23b439a3f085dd083138c326)
45
+
46
+ #### [v8.0.2](https://github.com/janosh/svelte-multiselect/compare/v8.0.1...v8.0.2)
47
+
48
+ > 7 November 2022
49
+
50
+ - Pass JSON.stringified selected options to form submission handlers [`#152`](https://github.com/janosh/svelte-multiselect/pull/152)
51
+ - Link check CI and readme housekeeping [`#149`](https://github.com/janosh/svelte-multiselect/pull/149)
52
+ - REPL links for landing page examples [`#148`](https://github.com/janosh/svelte-multiselect/pull/148)
53
+ - Add Collapsible code blocks to usage examples [`#143`](https://github.com/janosh/svelte-multiselect/pull/143)
54
+ - REPL links for landing page examples (#148) [`#144`](https://github.com/janosh/svelte-multiselect/issues/144) [`#145`](https://github.com/janosh/svelte-multiselect/issues/145) [`#146`](https://github.com/janosh/svelte-multiselect/issues/146) [`#147`](https://github.com/janosh/svelte-multiselect/issues/147)
55
+
56
+ #### [v8.0.1](https://github.com/janosh/svelte-multiselect/compare/v8.0.0...v8.0.1)
57
+
58
+ > 30 October 2022
59
+
60
+ - Revert SCSS preprocessing [`#141`](https://github.com/janosh/svelte-multiselect/pull/141)
61
+ - Add unit tests for 2-/1-way binding of `activeIndex` and `activeOption` [`#139`](https://github.com/janosh/svelte-multiselect/pull/139)
62
+
63
+ ### [v8.0.0](https://github.com/janosh/svelte-multiselect/compare/v7.1.0...v8.0.0)
64
+
65
+ > 22 October 2022
66
+
67
+ - Add new prop `value` [`#138`](https://github.com/janosh/svelte-multiselect/pull/138)
68
+ - New prop resetFilterOnAdd [`#137`](https://github.com/janosh/svelte-multiselect/pull/137)
69
+ - `yarn` to `pnpm` [`#134`](https://github.com/janosh/svelte-multiselect/pull/134)
70
+ - Rename prop `noOptionsMsg`-&gt;`noMatchingOptionsMsg` [`#133`](https://github.com/janosh/svelte-multiselect/pull/133)
71
+ - remove props selectedLabels and selectedValues [`ef6598e`](https://github.com/janosh/svelte-multiselect/commit/ef6598e8b0dc1f2f8cb687074463cb73b2f9ebff)
72
+
73
+ #### [v7.1.0](https://github.com/janosh/svelte-multiselect/compare/v7.0.2...v7.1.0)
74
+
75
+ > 13 October 2022
76
+
77
+ - Allow preventing duplicate options when allowUserOptions is thruthy [`#132`](https://github.com/janosh/svelte-multiselect/pull/132)
78
+
79
+ #### [v7.0.2](https://github.com/janosh/svelte-multiselect/compare/v7.0.1...v7.0.2)
80
+
81
+ > 8 October 2022
82
+
83
+ - Fix TypeError: Cannot read properties of null (reading 'get_label') - take 2 [`#131`](https://github.com/janosh/svelte-multiselect/pull/131)
84
+ - Fix selecting options with falsy labels (like 0) [`#130`](https://github.com/janosh/svelte-multiselect/pull/130)
85
+
86
+ #### [v7.0.1](https://github.com/janosh/svelte-multiselect/compare/v7.0.0...v7.0.1)
87
+
88
+ > 6 October 2022
89
+
90
+ - Fix single select with arrow and enter keys [`#128`](https://github.com/janosh/svelte-multiselect/pull/128)
91
+ - Add SCSS preprocessing [`#126`](https://github.com/janosh/svelte-multiselect/pull/126)
92
+ - [pre-commit.ci] pre-commit autoupdate [`#124`](https://github.com/janosh/svelte-multiselect/pull/124)
93
+ - more unit tests [`1adbc99`](https://github.com/janosh/svelte-multiselect/commit/1adbc994b746b39c4ad081dc2573bf37f27c96c0)
94
+ - test required but empty MultiSelect fails form validity check (i.e. causes unsubmittable form) and filled one passes it [`fd8b377`](https://github.com/janosh/svelte-multiselect/commit/fd8b37782cd508aacfc8125c6647cefe56144b80)
95
+
96
+ ### [v7.0.0](https://github.com/janosh/svelte-multiselect/compare/v6.1.0...v7.0.0)
97
+
98
+ > 3 October 2022
99
+
100
+ - Make selected a single value (not a length-1 array) if maxSelect=1 [`#123`](https://github.com/janosh/svelte-multiselect/pull/123)
101
+ - Fix TypeError: Cannot read properties of null (reading 'get_label') at MultiSelect.svelte:75 [`#122`](https://github.com/janosh/svelte-multiselect/pull/122)
102
+ - add stopPropagation to keydown handler (closes #114) [`#114`](https://github.com/janosh/svelte-multiselect/issues/114)
103
+
104
+ #### [v6.1.0](https://github.com/janosh/svelte-multiselect/compare/v6.0.3...v6.1.0)
105
+
106
+ > 30 September 2022
107
+
108
+ - Forward input DOM events [`#120`](https://github.com/janosh/svelte-multiselect/pull/120)
109
+ - Props to manipulating inputmode and pattern attributes [`#116`](https://github.com/janosh/svelte-multiselect/pull/116)
110
+ - docs: remove `userInputAs` prop reference [`#115`](https://github.com/janosh/svelte-multiselect/pull/115)
111
+ - Fix top option not selectable with enter key [`#113`](https://github.com/janosh/svelte-multiselect/pull/113)
112
+
113
+ #### [v6.0.3](https://github.com/janosh/svelte-multiselect/compare/v6.0.2...v6.0.3)
114
+
115
+ > 20 September 2022
116
+
117
+ - Fix using arrow keys to control active option in dropdown list [`#111`](https://github.com/janosh/svelte-multiselect/pull/111)
118
+ - eslintrc set @typescript-eslint/no-inferrable-types: off [`c688773`](https://github.com/janosh/svelte-multiselect/commit/c6887737871709cdadc2ef0835795d6c1696e34c)
119
+
120
+ #### [v6.0.2](https://github.com/janosh/svelte-multiselect/compare/v6.0.1...v6.0.2)
121
+
122
+ > 17 September 2022
123
+
124
+ - Test readme docs on CSS variables [`#109`](https://github.com/janosh/svelte-multiselect/pull/109)
125
+ - Fix selected array not being initialized to options with preselected=true [`#108`](https://github.com/janosh/svelte-multiselect/pull/108)
126
+
127
+ #### [v6.0.1](https://github.com/janosh/svelte-multiselect/compare/v6.0.0...v6.0.1)
128
+
129
+ > 13 September 2022
130
+
131
+ - Better props docs and test [`#105`](https://github.com/janosh/svelte-multiselect/pull/105)
132
+ - fix breaking change sveltekit:prefetch renamed to data-sveltekit-prefetch [`65ddbb9`](https://github.com/janosh/svelte-multiselect/commit/65ddbb93c720e3d92d7bc3fec232f58e87c0ea6d)
133
+ - fix .svx demo routes [`fde53f1`](https://github.com/janosh/svelte-multiselect/commit/fde53f1225fda928412303256d48b77d122d19f1)
134
+ - revert from adapter-netlify to adapter-static [`224144d`](https://github.com/janosh/svelte-multiselect/commit/224144dce012d1eef515abafa542c6a6b7e063e8)
135
+
136
+ ### [v6.0.0](https://github.com/janosh/svelte-multiselect/compare/v5.0.6...v6.0.0)
137
+
138
+ > 3 September 2022
139
+
140
+ - Better on mobile and better about which option is active [`#103`](https://github.com/janosh/svelte-multiselect/pull/103)
141
+ - SvelteKit routes auto migration [`#101`](https://github.com/janosh/svelte-multiselect/pull/101)
142
+
143
+ #### [v5.0.6](https://github.com/janosh/svelte-multiselect/compare/v5.0.5...v5.0.6)
144
+
145
+ > 2 August 2022
146
+
147
+ - Fix 'Cannot find module `scroll-into-view-if-needed`' [`#99`](https://github.com/janosh/svelte-multiselect/pull/99)
148
+
149
+ #### [v5.0.5](https://github.com/janosh/svelte-multiselect/compare/v5.0.4...v5.0.5)
150
+
151
+ > 2 August 2022
152
+
153
+ - Add `scroll-into-view-if-needed` ponyfill [`#97`](https://github.com/janosh/svelte-multiselect/pull/97)
154
+
155
+ #### [v5.0.4](https://github.com/janosh/svelte-multiselect/compare/v5.0.3...v5.0.4)
156
+
157
+ > 17 July 2022
158
+
159
+ - Convert E2E tests from`vitest` to `@playwright/test` [`#95`](https://github.com/janosh/svelte-multiselect/pull/95)
160
+ - Allow empty Multiselect [`#94`](https://github.com/janosh/svelte-multiselect/pull/94)
161
+ - Add new slot `'remove-icon'` [`#93`](https://github.com/janosh/svelte-multiselect/pull/93)
162
+ - [pre-commit.ci] pre-commit autoupdate [`#92`](https://github.com/janosh/svelte-multiselect/pull/92)
163
+
164
+ #### [v5.0.3](https://github.com/janosh/svelte-multiselect/compare/v5.0.2...v5.0.3)
165
+
166
+ > 1 July 2022
167
+
168
+ - Reset `activeOption` to `null` if not in `matchingOptions` [`#90`](https://github.com/janosh/svelte-multiselect/pull/90)
169
+
170
+ #### [v5.0.2](https://github.com/janosh/svelte-multiselect/compare/v5.0.1...v5.0.2)
171
+
172
+ > 27 June 2022
173
+
174
+ - Replace `li.scrollIntoViewIfNeeded()` with `li.scrollIntoView()` [`#88`](https://github.com/janosh/svelte-multiselect/pull/88)
175
+ - Add new prop `parseLabelsAsHtml` [`#84`](https://github.com/janosh/svelte-multiselect/pull/84)
176
+ - try fix flaky test 'multiselect &gt; can select and remove many options' [`2b0c453`](https://github.com/janosh/svelte-multiselect/commit/2b0c453c794c0b3b82e81c5b994c10bc305a98d6)
177
+ - bump netlify node to v18, update readme + deps [`586c724`](https://github.com/janosh/svelte-multiselect/commit/586c724d471aece2b5a3726bb5eb145e36073fe3)
178
+ - remove plausible.js analytics [`cd4c9f6`](https://github.com/janosh/svelte-multiselect/commit/cd4c9f6e18e13959dfb4fcebe9acba7a875b83a2)
179
+
180
+ #### [v5.0.1](https://github.com/janosh/svelte-multiselect/compare/v5.0.0...v5.0.1)
181
+
182
+ > 23 April 2022
183
+
184
+ - Strongly typed custom events [`#79`](https://github.com/janosh/svelte-multiselect/pull/79)
185
+
186
+ ### [v5.0.0](https://github.com/janosh/svelte-multiselect/compare/v4.0.6...v5.0.0)
187
+
188
+ > 21 April 2022
189
+
190
+ - v5 release [`#76`](https://github.com/janosh/svelte-multiselect/pull/76)
191
+ - Work with string options as is, don't convert to objects internally [`#75`](https://github.com/janosh/svelte-multiselect/pull/75)
192
+ - v5 release (#76) [`#57`](https://github.com/janosh/svelte-multiselect/issues/57)
193
+
194
+ #### [v4.0.6](https://github.com/janosh/svelte-multiselect/compare/v4.0.5...v4.0.6)
195
+
196
+ > 7 April 2022
197
+
198
+ - Fix backspace deleting multiple selected options if identical labels [`#72`](https://github.com/janosh/svelte-multiselect/pull/72)
199
+ - Several fixes for `allowUserOptions` [`#69`](https://github.com/janosh/svelte-multiselect/pull/69)
200
+ - [pre-commit.ci] pre-commit autoupdate [`#70`](https://github.com/janosh/svelte-multiselect/pull/70)
201
+
202
+ #### [v4.0.5](https://github.com/janosh/svelte-multiselect/compare/v4.0.4...v4.0.5)
203
+
204
+ > 2 April 2022
205
+
206
+ - Fix MultiSelect `localStorage` binding [`#66`](https://github.com/janosh/svelte-multiselect/pull/66)
207
+
208
+ #### [v4.0.4](https://github.com/janosh/svelte-multiselect/compare/v4.0.3...v4.0.4)
209
+
210
+ > 30 March 2022
211
+
212
+ - Move examples to new `src/routes/demos` dir [`#63`](https://github.com/janosh/svelte-multiselect/pull/63)
213
+ - make ToC position fixed (closes #64) [`#64`](https://github.com/janosh/svelte-multiselect/issues/64)
214
+ - check for undefined (not falsy) value in rawOp processing (fixes #65) [`#65`](https://github.com/janosh/svelte-multiselect/issues/65)
215
+ - LanguageSlot change SVG icons src repo to vscode-icons for more coverage [`92390e9`](https://github.com/janosh/svelte-multiselect/commit/92390e937a063b2b0c88e0ac6f9a9d8f3cb1eadd)
216
+ - more preselected slots in Examples.svelte [`cd0a01a`](https://github.com/janosh/svelte-multiselect/commit/cd0a01a7a6b319299642b3c24c5caea8dc9dc24d)
217
+
218
+ #### [v4.0.3](https://github.com/janosh/svelte-multiselect/compare/v4.0.2...v4.0.3)
219
+
220
+ > 23 March 2022
221
+
222
+ - Add `aria-label` to hidden `.form-control` input [`#62`](https://github.com/janosh/svelte-multiselect/pull/62)
223
+ - Add `aria-label` to hidden `.form-control` input (#62) [`#58`](https://github.com/janosh/svelte-multiselect/issues/58) [`#35`](https://github.com/janosh/svelte-multiselect/issues/35)
224
+ - fix dropdown closing when clicking between list items (closes #61) [`#61`](https://github.com/janosh/svelte-multiselect/issues/61)
225
+ - svelte.config.js add kit.prerender.default: true, mv src/{global,app}.d.ts [`4a84913`](https://github.com/janosh/svelte-multiselect/commit/4a8491380e08bad137ca7bdda9ee4ddd38abe3d6)
226
+
227
+ #### [v4.0.2](https://github.com/janosh/svelte-multiselect/compare/v4.0.1...v4.0.2)
228
+
229
+ > 13 March 2022
230
+
231
+ - Improve a11y [`#60`](https://github.com/janosh/svelte-multiselect/pull/60)
232
+ - Convert tests to Playwright [`#59`](https://github.com/janosh/svelte-multiselect/pull/59)
233
+ - Convert tests to Playwright (#59) [`#58`](https://github.com/janosh/svelte-multiselect/issues/58)
234
+ - add and document prop invalid (closes #47) [`#47`](https://github.com/janosh/svelte-multiselect/issues/47)
235
+ - set width (not height) on svg icons and as px (not em) so they don't shrink with fluid typography on mobile screens [`ba77f93`](https://github.com/janosh/svelte-multiselect/commit/ba77f93b23b375bb650411b580406f1f7d55f365)
236
+
237
+ #### [v4.0.1](https://github.com/janosh/svelte-multiselect/compare/v4.0.0...v4.0.1)
238
+
239
+ > 5 March 2022
240
+
241
+ - Rename readonly to disabled [`#55`](https://github.com/janosh/svelte-multiselect/pull/55)
242
+ - CSS and UX tweaks [`#52`](https://github.com/janosh/svelte-multiselect/pull/52)
243
+ - Readme document test runner config to avoid transpiling errors in downstream testing [`#54`](https://github.com/janosh/svelte-multiselect/pull/54)
244
+ - More tests [`#51`](https://github.com/janosh/svelte-multiselect/pull/51)
245
+ - Add `vitest` [`#50`](https://github.com/janosh/svelte-multiselect/pull/50)
246
+ - Rename readonly to disabled (#55) [`#45`](https://github.com/janosh/svelte-multiselect/issues/45)
247
+ - close options dropdown list on input blur (fixes #53) [`#53`](https://github.com/janosh/svelte-multiselect/issues/53)
248
+ - CSS and UX tweaks (#52) [`#44`](https://github.com/janosh/svelte-multiselect/issues/44) [`#44`](https://github.com/janosh/svelte-multiselect/issues/44) [`#44`](https://github.com/janosh/svelte-multiselect/issues/44)
249
+ - Readme document test runner config to avoid transpiling errors in downstream testing (#54) [`#48`](https://github.com/janosh/svelte-multiselect/issues/48)
250
+
251
+ ### [v4.0.0](https://github.com/janosh/svelte-multiselect/compare/v3.3.0...v4.0.0)
252
+
253
+ > 21 February 2022
254
+
255
+ - Implement `allowUserOptions`, `autoScroll` and `loading` (closes #39) [`#41`](https://github.com/janosh/svelte-multiselect/pull/41)
256
+ - define DispatchEvents type used to annotate createEventDispatcher() [`#32`](https://github.com/janosh/svelte-multiselect/pull/32)
257
+ - add prop required to prevent form submission if no options selected (closes #42) [`#42`](https://github.com/janosh/svelte-multiselect/issues/42)
258
+ - Implement `allowUserOptions`, `autoScroll` and `loading` (closes #39) (#41) [`#39`](https://github.com/janosh/svelte-multiselect/issues/39) [`#39`](https://github.com/janosh/svelte-multiselect/issues/39)
259
+
260
+ #### [v3.3.0](https://github.com/janosh/svelte-multiselect/compare/v3.2.3...v3.3.0)
261
+
262
+ > 20 February 2022
263
+
264
+ - by default, only show maxSelectMsg if maxSelect != null and &gt; 1 (closes #37) [`#37`](https://github.com/janosh/svelte-multiselect/issues/37)
265
+ - add CSS var --sms-options-shadow defaults to subtle black shadow around dropdown list (0 0 14pt -8pt black) (closes #36) [`#36`](https://github.com/janosh/svelte-multiselect/issues/36)
266
+ - add prop liActiveOptionClass = '' (closes #35) [`#35`](https://github.com/janosh/svelte-multiselect/issues/35)
267
+ - turn searchText = and showOptions = false into bindable props (closes #33) [`#33`](https://github.com/janosh/svelte-multiselect/issues/33)
268
+ - document missing noOptionsMsg prop (closes #34) [`#34`](https://github.com/janosh/svelte-multiselect/issues/34)
269
+ - ensure custom class names (outerDivClass, ulOptionsClass) come last (closes #38) [`#38`](https://github.com/janosh/svelte-multiselect/issues/38)
270
+ - fix ToC scroll to heading (closes #31) [`#31`](https://github.com/janosh/svelte-multiselect/issues/31)
271
+ - only show remove all btn when maxSelect !== 1 (for #37) [`64cfd8a`](https://github.com/janosh/svelte-multiselect/commit/64cfd8a1108e19aae12e65c3ad17177f09a066d8)
272
+
273
+ #### [v3.2.3](https://github.com/janosh/svelte-multiselect/compare/v3.2.2...v3.2.3)
274
+
275
+ > 19 February 2022
276
+
277
+ - Fixes for focus on click and wiggle on hitting maxSelect [`#30`](https://github.com/janosh/svelte-multiselect/pull/30)
278
+
279
+ #### [v3.2.2](https://github.com/janosh/svelte-multiselect/compare/v3.2.1...v3.2.2)
280
+
281
+ > 16 February 2022
282
+
283
+ - Expose filter method [`#29`](https://github.com/janosh/svelte-multiselect/pull/29)
284
+ - readme improve docs on css variables and granular control through :global() selectors (closes #27) [`#27`](https://github.com/janosh/svelte-multiselect/issues/27)
285
+
286
+ #### [v3.2.1](https://github.com/janosh/svelte-multiselect/compare/v3.2.0...v3.2.1)
287
+
288
+ > 7 February 2022
289
+
290
+ - mv input outside ul.selected for better HTML semantics (closes #26) [`#26`](https://github.com/janosh/svelte-multiselect/issues/26)
291
+
292
+ #### [v3.2.0](https://github.com/janosh/svelte-multiselect/compare/v3.1.1...v3.2.0)
293
+
294
+ > 3 February 2022
295
+
296
+ - apply id prop to &lt;input&gt; instead of outer div (closes #25) [`#25`](https://github.com/janosh/svelte-multiselect/issues/25)
297
+ - add eslint commit hook + update deps [`6ad44b8`](https://github.com/janosh/svelte-multiselect/commit/6ad44b85057aef71eae19293de80f9d42f91f87b)
298
+ - v.3.2.0 [`71ff2d1`](https://github.com/janosh/svelte-multiselect/commit/71ff2d192caccacbe41f83949c14d7d4ca87d590)
299
+ - add readme badge to document minimum svelte version (for #24) [`7d9fe5a`](https://github.com/janosh/svelte-multiselect/commit/7d9fe5a977b56dab95069b64321f0718e0d61f08)
300
+
301
+ #### [v3.1.1](https://github.com/janosh/svelte-multiselect/compare/v3.1.0...v3.1.1)
302
+
303
+ > 25 January 2022
304
+
305
+ - wiggle the maxSelect msg on hitting selection limit (closes #19) [`#19`](https://github.com/janosh/svelte-multiselect/issues/19)
306
+ - readme better docs for CSS variables, rename slots {options,selected}Renderer -&gt; render{options,selected} [`c8ab724`](https://github.com/janosh/svelte-multiselect/commit/c8ab7241506cfe6b5930d098150a251e85c52afd)
307
+
308
+ #### [v3.1.0](https://github.com/janosh/svelte-multiselect/compare/v3.0.1...v3.1.0)
309
+
310
+ > 22 January 2022
311
+
312
+ - add selectedRenderer + optionRenderer named slots (closes #21) [`#21`](https://github.com/janosh/svelte-multiselect/issues/21)
313
+ - docs site use unmodified readme with slot to insert examples, yarn add svelte-github-corner [`1072691`](https://github.com/janosh/svelte-multiselect/commit/10726916ea2a72560cd8ee6f2806526bf932e771)
314
+ - readme add note on type exports for TS users, add error page that redirects to index [`dde76c8`](https://github.com/janosh/svelte-multiselect/commit/dde76c8b92408b7fddca0b555a63c2b1bfd0dbe8)
315
+
316
+ #### [v3.0.1](https://github.com/janosh/svelte-multiselect/compare/v3.0.0...v3.0.1)
317
+
318
+ > 7 January 2022
319
+
320
+ - favorite web framework show Confetti.svelte on:add Svelte [`8d109ee`](https://github.com/janosh/svelte-multiselect/commit/8d109ee5c7755e447fcb72419f3b7ecc19cac0b2)
321
+ - bump svelte@3.45.0 to silence warning: MultiSelect has unused export property 'defaultDisabledTitle' (sveltejs/svelte#6964) [`f80a7a6`](https://github.com/janosh/svelte-multiselect/commit/f80a7a622310005407585298f2611597c0941990)
322
+ - update readme + svelte-toc@0.2.0 [`40013ba`](https://github.com/janosh/svelte-multiselect/commit/40013badd61dd0fcade7ab295dabd26693e3cc51)
323
+ - [pre-commit.ci] pre-commit autoupdate [`0d05864`](https://github.com/janosh/svelte-multiselect/commit/0d05864d19987460dd30d667eb22deb91a520668)
324
+ - iOS Safari prevent zoom into page on focus MultiSelect input [`44f17be`](https://github.com/janosh/svelte-multiselect/commit/44f17be53378e38f4a8748b815737d25cdebc85f)
325
+
326
+ ### [v3.0.0](https://github.com/janosh/svelte-multiselect/compare/v2.0.0...v3.0.0)
327
+
328
+ > 29 December 2021
329
+
330
+ - ensure active option is scrolled into view if needed (closes #15), breaking change: renames tokens to options [`#15`](https://github.com/janosh/svelte-multiselect/issues/15)
331
+
332
+ ### [v2.0.0](https://github.com/janosh/svelte-multiselect/compare/v1.2.2...v2.0.0)
333
+
334
+ > 24 December 2021
335
+
336
+ - Convert options from simple strings to objects [`#16`](https://github.com/janosh/svelte-multiselect/pull/16)
337
+ - Add local to transition:fly [`#14`](https://github.com/janosh/svelte-multiselect/pull/14)
338
+ - add onClickOutside action, used to replace input.on:blur() for hiding options (closes #18) [`#18`](https://github.com/janosh/svelte-multiselect/issues/18)
339
+ - update deps [`fb90f93`](https://github.com/janosh/svelte-multiselect/commit/fb90f936fa0d49f81e6c9c60986dd04749ea6a67)
340
+ - more keyboard friendliness by showing remove button focus and triggering on space bar or enter key [`b87d22b`](https://github.com/janosh/svelte-multiselect/commit/b87d22bc5706acd18e1e79c40b3845f2ee3615b2)
341
+ - add plausible [`0557c0f`](https://github.com/janosh/svelte-multiselect/commit/0557c0f2bbef80820540302af29c79b7ac89023b)
342
+
343
+ #### [v1.2.2](https://github.com/janosh/svelte-multiselect/compare/v1.2.1...v1.2.2)
344
+
345
+ > 27 October 2021
346
+
347
+ - set &lt;input&gt; width back to 1pt as it's only needed to tab into, focus and blur &lt;MultiSelect&gt; (closes #12) [`#12`](https://github.com/janosh/svelte-multiselect/issues/12)
348
+ - update readme [`45c7993`](https://github.com/janosh/svelte-multiselect/commit/45c7993398c986499d4c0729177620cbec719cb7)
349
+
350
+ #### [v1.2.1](https://github.com/janosh/svelte-multiselect/compare/v1.2.0...v1.2.1)
351
+
352
+ > 21 October 2021
353
+
354
+ - make internal CSS easily overridable (sveltejs/svelte#6859) [`d15a445`](https://github.com/janosh/svelte-multiselect/commit/d15a44504707c178c67e22318b2cc6095b1b192f)
355
+
356
+ #### [v1.2.0](https://github.com/janosh/svelte-multiselect/compare/v1.1.13...v1.2.0)
357
+
358
+ > 12 October 2021
359
+
360
+ - add src/lib/index.ts for package path export '.' (closes #11) [`#11`](https://github.com/janosh/svelte-multiselect/issues/11)
361
+
362
+ #### [v1.1.13](https://github.com/janosh/svelte-multiselect/compare/v1.1.12...v1.1.13)
363
+
364
+ > 12 October 2021
365
+
366
+ - add src/lib/index.ts for package path export '.' (closes #11) [`#11`](https://github.com/janosh/svelte-multiselect/issues/11)
367
+
368
+ #### [v1.1.12](https://github.com/janosh/svelte-multiselect/compare/v1.1.11...v1.1.12)
369
+
370
+ > 11 October 2021
371
+
372
+ - Add new prop disabledOptions [`#9`](https://github.com/janosh/svelte-multiselect/pull/9)
373
+ - add pre-commit hooks [`dfb6399`](https://github.com/janosh/svelte-multiselect/commit/dfb6399a77b705f8e5979eb887d345a5f52ff929)
374
+ - [pre-commit.ci] pre-commit autoupdate [`b69425d`](https://github.com/janosh/svelte-multiselect/commit/b69425d18473122f1af889d2f48c60d02e43b99f)
375
+
376
+ #### [v1.1.11](https://github.com/janosh/svelte-multiselect/compare/v1.1.10...v1.1.11)
377
+
378
+ > 3 September 2021
379
+
380
+ - fix removeAll button not dispatching remove and change events (closes #7) [`#7`](https://github.com/janosh/svelte-multiselect/issues/7)
381
+ - remove @tsconfig/svelte, update deps [`9b2c231`](https://github.com/janosh/svelte-multiselect/commit/9b2c23181f4a96bd9d002f535dd669153e772b72)
382
+ - add type=(add|remove) detail to 'change' event dispatch [`8290458`](https://github.com/janosh/svelte-multiselect/commit/8290458b898292a28d65710d6941f193fb9964aa)
383
+
384
+ #### [v1.1.10](https://github.com/janosh/svelte-multiselect/compare/v1.1.9...v1.1.10)
385
+
386
+ > 12 August 2021
387
+
388
+ - add `on:change` event and document events in readme (closes #5) [`#5`](https://github.com/janosh/svelte-multiselect/issues/5)
389
+
390
+ #### [v1.1.9](https://github.com/janosh/svelte-multiselect/compare/v1.1.8...v1.1.9)
391
+
392
+ > 12 July 2021
393
+
394
+ - convert to typescript [`bd391c5`](https://github.com/janosh/svelte-multiselect/commit/bd391c5aba615ab41e2f561f81e057928a7064a8)
395
+ - update to @sveltejs/kit@1.0.0-next.124+ to use svelte field in `package.json` [`2367e38`](https://github.com/janosh/svelte-multiselect/commit/2367e38d699e503e6dc98808904278f96eb54ee7)
396
+
397
+ #### [v1.1.8](https://github.com/janosh/svelte-multiselect/compare/v1.1.7...v1.1.8)
398
+
399
+ > 7 July 2021
400
+
401
+ - turn hard-coded remove button titles into props [`c35162b`](https://github.com/janosh/svelte-multiselect/commit/c35162b0d0c1ed183bc23dbf15b0ff46638cbb3b)
402
+ - guard against selected being nullish, keep ul.options in the DOM even if showoptions is false to allow selecting in dev tools for styling [`b9bd576`](https://github.com/janosh/svelte-multiselect/commit/b9bd576f6f76ec86ebeff1d899d8947bef64f66f)
403
+
404
+ #### [v1.1.7](https://github.com/janosh/svelte-multiselect/compare/v1.1.6...v1.1.7)
405
+
406
+ > 5 July 2021
407
+
408
+ - add css classes as props for use with tailwind (closes #3) [`#3`](https://github.com/janosh/svelte-multiselect/issues/3)
409
+
410
+ #### [v1.1.6](https://github.com/janosh/svelte-multiselect/compare/v1.1.5...v1.1.6)
411
+
412
+ > 23 June 2021
413
+
414
+ - fix: don't remove tags if search string is non-empty, open options on clicking selected tags (#2) [`5ffed50`](https://github.com/janosh/svelte-multiselect/commit/5ffed50617f47dba6ffbafd6ce266fa6e064c7de)
415
+ - update svelte-toc to fix deploy [`d5279dd`](https://github.com/janosh/svelte-multiselect/commit/d5279dd11279509493030aeb26295873929b2253)
416
+
417
+ #### [v1.1.5](https://github.com/janosh/svelte-multiselect/compare/v1.1.4...v1.1.5)
418
+
419
+ > 22 June 2021
420
+
421
+ - convert to `svelte-kit package` [`9db3cfb`](https://github.com/janosh/svelte-multiselect/commit/9db3cfb5b6e2db844961be5bc59fc12e5d5b6b76)
422
+
423
+ #### [v1.1.4](https://github.com/janosh/svelte-multiselect/compare/v1.1.3...v1.1.4)
424
+
425
+ > 21 June 2021
426
+
427
+ - fix setting initial value for selected, fix setting class `'selected'` in single mode [`16d11de`](https://github.com/janosh/svelte-multiselect/commit/16d11de77567f9d30e37e815dfcb9a7d580d6500)
428
+
429
+ #### [v1.1.3](https://github.com/janosh/svelte-multiselect/compare/v1.1.2...v1.1.3)
430
+
431
+ > 20 June 2021
432
+
433
+ - replace prop single with maxSelect to specify any number of selectable options, add class single to div.multiselect if maxSelect===1 (#2) [`36e916f`](https://github.com/janosh/svelte-multiselect/commit/36e916f4a42d395c394ddff47364a17fd22a7ec1)
434
+ - add linked headings [`2eedf9a`](https://github.com/janosh/svelte-multiselect/commit/2eedf9aa24512ff96f8ccff564d3a1fa7615388a)
435
+
436
+ #### [v1.1.2](https://github.com/janosh/svelte-multiselect/compare/v1.1.1...v1.1.2)
437
+
438
+ > 28 May 2021
439
+
440
+ - add css var props [`f591814`](https://github.com/janosh/svelte-multiselect/commit/f5918141805cfc6acda28c836a57c3df81fa758f)
441
+
442
+ #### [v1.1.1](https://github.com/janosh/svelte-multiselect/compare/v1.1.0...v1.1.1)
443
+
444
+ > 25 May 2021
445
+
446
+ - add GitHubCorner.svelte for link to repo [`e80a402`](https://github.com/janosh/svelte-multiselect/commit/e80a402556783108bc5dc626f9816b647e2c937f)
447
+ - remove selected tokens with backspace [`c5d7495`](https://github.com/janosh/svelte-multiselect/commit/c5d7495a43b945dd56ad06fbe639de0db542d5f4)
448
+ - add readme badges [`992eaa4`](https://github.com/janosh/svelte-multiselect/commit/992eaa43ec19841b3035a5dcf9996eaf58316fa8)
449
+ - demo site fix stripping start of readme for docs [`107273d`](https://github.com/janosh/svelte-multiselect/commit/107273de356f176cb0fc94f28ae4f2e773b62d42)
450
+ - add `svelte-toc` table of contents to demo site [`36aa1c5`](https://github.com/janosh/svelte-multiselect/commit/36aa1c523c5bc3acb14e9613b61c04ffd54c6100)
451
+
452
+ #### [v1.1.0](https://github.com/janosh/svelte-multiselect/compare/v1.0.1...v1.1.0)
453
+
454
+ > 9 May 2021
455
+
456
+ - import readme on demo site (more DRY) [`c0e4924`](https://github.com/janosh/svelte-multiselect/commit/c0e49246e76a81600bb35931fd7d30f6f6aeb550)
457
+ - remove unused `example.svx` [`2138caa`](https://github.com/janosh/svelte-multiselect/commit/2138caa171f20a2f80c2e75d0dffd066caf17a83)
458
+ - rename package dir, improve readme [`0150378`](https://github.com/janosh/svelte-multiselect/commit/015037848f666a76b24b93603764084b41611740)
459
+
460
+ #### [v1.0.1](https://github.com/janosh/svelte-multiselect/compare/v1.0.0...v1.0.1)
461
+
462
+ > 8 May 2021
463
+
464
+ - remove hidden input for storing currently selected options as JSON [`802a219`](https://github.com/janosh/svelte-multiselect/commit/802a2195a28986c219298d7d9e7ca47f2aaf7db6)
465
+
466
+ #### v1.0.0
467
+
468
+ > 7 May 2021
469
+
470
+ - initial commit [`14dd38a`](https://github.com/janosh/svelte-multiselect/commit/14dd38adb06a8899e39efabdb114faab943cedf0)
package/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export { default } from './MultiSelect.svelte';
2
- export declare type Option = string | number | ObjectOption;
3
- export declare type ObjectOption = {
2
+ export type Option = string | number | ObjectOption;
3
+ export type ObjectOption = {
4
4
  label: string | number;
5
5
  value?: unknown;
6
6
  title?: string;
@@ -10,7 +10,7 @@ export declare type ObjectOption = {
10
10
  selectedTitle?: string;
11
11
  [key: string]: unknown;
12
12
  };
13
- export declare type DispatchEvents = {
13
+ export type DispatchEvents = {
14
14
  add: {
15
15
  option: Option;
16
16
  };
@@ -32,7 +32,7 @@ export declare type DispatchEvents = {
32
32
  event: Event;
33
33
  };
34
34
  };
35
- export declare type MultiSelectEvents = {
35
+ export type MultiSelectEvents = {
36
36
  [key in keyof DispatchEvents]: CustomEvent<DispatchEvents[key]>;
37
37
  } & {
38
38
  blur: FocusEvent;
package/package.json CHANGED
@@ -2,32 +2,33 @@
2
2
  "name": "svelte-multiselect",
3
3
  "description": "Svelte multi-select component",
4
4
  "author": "Janosh Riebesell <janosh.riebesell@gmail.com>",
5
- "homepage": "https://svelte-multiselect.netlify.app",
5
+ "homepage": "https://janosh.github.io/svelte-multiselect",
6
6
  "repository": "https://github.com/janosh/svelte-multiselect",
7
7
  "license": "MIT",
8
- "version": "8.0.4",
8
+ "version": "8.2.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
14
  "@iconify/svelte": "^3.0.0",
15
- "@playwright/test": "^1.27.1",
15
+ "@playwright/test": "^1.28.0",
16
16
  "@sveltejs/adapter-static": "1.0.0-next.48",
17
- "@sveltejs/kit": "1.0.0-next.544",
18
- "@sveltejs/package": "1.0.0-next.5",
19
- "@sveltejs/vite-plugin-svelte": "^1.1.1",
20
- "@typescript-eslint/eslint-plugin": "^5.42.1",
21
- "@typescript-eslint/parser": "^5.42.1",
22
- "@vitest/coverage-c8": "^0.25.1",
23
- "eslint": "^8.27.0",
17
+ "@sveltejs/kit": "1.0.0-next.553",
18
+ "@sveltejs/package": "1.0.0-next.6",
19
+ "@sveltejs/vite-plugin-svelte": "^1.2.0",
20
+ "@typescript-eslint/eslint-plugin": "^5.43.0",
21
+ "@typescript-eslint/parser": "^5.43.0",
22
+ "@vitest/coverage-c8": "^0.25.2",
23
+ "eslint": "^8.28.0",
24
24
  "eslint-plugin-svelte3": "^4.0.0",
25
25
  "hastscript": "^7.1.0",
26
26
  "highlight.js": "^11.6.0",
27
27
  "jsdom": "^20.0.2",
28
28
  "mdsvex": "^0.10.6",
29
+ "mdsvexamples": "^0.3.2",
29
30
  "prettier": "^2.7.1",
30
- "prettier-plugin-svelte": "^2.8.0",
31
+ "prettier-plugin-svelte": "^2.8.1",
31
32
  "rehype-autolink-headings": "^6.1.1",
32
33
  "rehype-slug": "^5.1.0",
33
34
  "svelte": "^3.53.1",
@@ -37,9 +38,9 @@
37
38
  "svelte-toc": "^0.4.1",
38
39
  "svelte2tsx": "^0.5.20",
39
40
  "tslib": "^2.4.1",
40
- "typescript": "^4.8.4",
41
- "vite": "^3.2.3",
42
- "vitest": "^0.25.1"
41
+ "typescript": "^4.9.3",
42
+ "vite": "^3.2.4",
43
+ "vitest": "^0.25.2"
43
44
  },
44
45
  "keywords": [
45
46
  "svelte",
package/readme.md CHANGED
@@ -6,7 +6,7 @@
6
6
  <h4 align="center">
7
7
 
8
8
  [![Tests](https://github.com/janosh/svelte-multiselect/actions/workflows/test.yml/badge.svg)](https://github.com/janosh/svelte-multiselect/actions/workflows/test.yml)
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)
9
+ [![Docs](https://github.com/janosh/svelte-multiselect/actions/workflows/docs.yml/badge.svg)](https://github.com/janosh/svelte-multiselect/actions/workflows/docs.yml)
10
10
  [![NPM version](https://img.shields.io/npm/v/svelte-multiselect?logo=NPM&color=purple)](https://npmjs.com/package/svelte-multiselect)
11
11
  [![Needs Svelte version](https://img.shields.io/npm/dependency-version/svelte-multiselect/dev/svelte?color=teal&logo=Svelte&label=Svelte)](https://github.com/sveltejs/svelte/blob/master/CHANGELOG.md)
12
12
  [![REPL](https://img.shields.io/badge/Svelte-REPL-blue?label=Try%20it!)](https://svelte.dev/repl/a5a14b8f15d64cb083b567292480db05)
@@ -16,7 +16,7 @@
16
16
 
17
17
  <p align="center"><strong>
18
18
  Keyboard-friendly, accessible and highly customizable multi-select component.
19
- <a class="hide-in-docs" href="https://svelte-multiselect.netlify.app">View the docs</a>
19
+ <a class="hide-in-docs" href="https://janosh.github.io/svelte-multiselect">View the docs</a>
20
20
  </strong></p>
21
21
 
22
22
  <slot name="examples" />
@@ -52,7 +52,7 @@ yarn add -D svelte-multiselect
52
52
 
53
53
  ## Usage
54
54
 
55
- ```svelte
55
+ ```html
56
56
  <script>
57
57
  import MultiSelect from 'svelte-multiselect'
58
58
 
@@ -61,7 +61,7 @@ yarn add -D svelte-multiselect
61
61
  let selected = []
62
62
  </script>
63
63
 
64
- Favorite Frontend Frameworks?
64
+ Favorite Frontend tools?
65
65
 
66
66
  <code>selected = {JSON.stringify(selected)}</code>
67
67
 
@@ -168,6 +168,12 @@ Full list of props/bindable variables for this component. The `Option` type you
168
168
 
169
169
  One of `true`, `false` or `'desktop'`. Whether to set the cursor back to the input element after selecting an element. 'desktop' means only do so if current window width is larger than the current value of `breakpoint` prop (default 800).
170
170
 
171
+ 1. ```ts
172
+ form_input: HTMLInputElement | null = null
173
+ ```
174
+
175
+ Handle to the `<input>` DOM node that's responsible for form validity checks and passing selected options to form submission handlers. Only available after component mounts (`null` before then).
176
+
171
177
  1. ```ts
172
178
  id: string | null = null
173
179
  ```
@@ -190,7 +196,7 @@ Full list of props/bindable variables for this component. The `Option` type you
190
196
  invalid: boolean = false
191
197
  ```
192
198
 
193
- 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.
199
+ 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.
194
200
 
195
201
  1. ```ts
196
202
  loading: boolean = false
@@ -223,11 +229,21 @@ Full list of props/bindable variables for this component. The `Option` type you
223
229
  maxSelectMsg = (current: number, max: number) => `${current}/${max}`
224
230
  ```
225
231
 
232
+ Use CSS selector `span.max-select-msg` (or prop `maxSelectMsgClass` if you're using a CSS framework like Tailwind) to customize appearance of the message container.
233
+
234
+ 1. ```ts
235
+ minSelect: number | null = null
236
+ ```
237
+
238
+ Conditionally render the `x` button which removes a selected option depending on the number of selected options. Meaning all remove buttons disappear if `selected.length <= minSelect`. E.g. if 2 options are selected and `minSelect={3}`, users will not be able to remove any selections until they selected more than 3 options.
239
+
240
+ Note: Prop `required={3}` should be used instead if you only care about the component state at form submission time. `minSelect={3}` should be used if you want to place constraints on component state at all times.
241
+
226
242
  1. ```ts
227
243
  name: string | null = null
228
244
  ```
229
245
 
230
- Applied to the `<input>` element. Sets the key of this field in a submitted form data object. See [form example](https://svelte-multiselect.netlify.app/form).
246
+ Applied to the `<input>` element. Sets the key of this field in a submitted form data object. See [form example](https://janosh.github.io/svelte-multiselect/form).
231
247
 
232
248
  1. ```ts
233
249
  noMatchingOptionsMsg: string = `No matching options`
@@ -284,10 +300,10 @@ Full list of props/bindable variables for this component. The `Option` type you
284
300
  Title text to display when user hovers over button to remove selected option (which defaults to a cross icon).
285
301
 
286
302
  1. ```ts
287
- required: boolean = false
303
+ required: boolean | number = false
288
304
  ```
289
305
 
290
- 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.
306
+ If `required = true, 1, 2, ...` forms can't be submitted without selecting given number of options. `true` means 1. `false` means even empty MultiSelect will pass form validity check. If user tries to submit a form containing MultiSelect with less than the required number of options, submission is aborted, MultiSelect scrolls into view and shows message "Please select at least `required` options".
291
307
 
292
308
  1. ```ts
293
309
  resetFilterOnAdd: boolean = true
@@ -310,11 +326,17 @@ Full list of props/bindable variables for this component. The `Option` type you
310
326
 
311
327
  Array of currently selected options. Supports 2-way binding `bind:selected={[1, 2, 3]}` to control component state externally. Can be passed as prop to set pre-selected options that will already be populated when component mounts before any user interaction.
312
328
 
329
+ 1. ```ts
330
+ selectedOptionsDraggable: boolean = true
331
+ ```
332
+
333
+ Whether selected options are draggable so users can change their order.
334
+
313
335
  1. ```ts
314
336
  sortSelected: boolean | ((op1: Option, op2: Option) => number) = false
315
337
  ```
316
338
 
317
- 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.
339
+ 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://janosh.github.io/svelte-multiselect/sort-selected) example.
318
340
 
319
341
  1. ```ts
320
342
  value: Option | Option[] | null = null
@@ -334,7 +356,7 @@ Full list of props/bindable variables for this component. The `Option` type you
334
356
 
335
357
  Example:
336
358
 
337
- ```svelte
359
+ ```html
338
360
  <MultiSelect options={[`Red`, `Green`, `Blue`, `Yellow`, `Purple`]}>
339
361
  <span let:idx let:option slot="option">
340
362
  {idx + 1}
@@ -395,7 +417,7 @@ Example:
395
417
 
396
418
  For example, here's how you might annoy your users with an alert every time one or more options are added or removed:
397
419
 
398
- ```svelte
420
+ ```html
399
421
  <MultiSelect
400
422
  on:change={(e) => {
401
423
  if (e.detail.type === 'add') alert(`You added ${e.detail.option}`)
@@ -409,7 +431,7 @@ For example, here's how you might annoy your users with an alert every time one
409
431
 
410
432
  The above list of events are [Svelte `dispatch` events](https://svelte.dev/tutorial/component-events). This component also forwards many DOM events from the `<input>` node: `blur`, `change`, `click`, `keydown`, `keyup`, `mousedown`, `mouseenter`, `mouseleave`, `touchcancel`, `touchend`, `touchmove`, `touchstart`. Registering listeners for these events works the same:
411
433
 
412
- ```svelte
434
+ ```html
413
435
  <MultiSelect
414
436
  options={[1, 2, 3]}
415
437
  on:keyup={(event) => console.log('key', event.target.value)}
@@ -420,7 +442,7 @@ The above list of events are [Svelte `dispatch` events](https://svelte.dev/tutor
420
442
 
421
443
  TypeScript users can import the types used for internal type safety:
422
444
 
423
- ```svelte
445
+ ```html
424
446
  <script lang="ts">
425
447
  import MultiSelect from 'svelte-multiselect'
426
448
  import type { Option, ObjectOption } from 'svelte-multiselect'
@@ -438,7 +460,7 @@ TypeScript users can import the types used for internal type safety:
438
460
 
439
461
  There are 3 ways to style this component. To understand which options do what, it helps to keep in mind this simplified DOM structure of the component:
440
462
 
441
- ```svelte
463
+ ```html
442
464
  <div class="multiselect">
443
465
  <ul class="selected">
444
466
  <li>Selected 1</li>
@@ -493,14 +515,14 @@ If you only want to make small adjustments, you can pass the following CSS varia
493
515
  - `background: var(--sms-li-selected-bg)`: Background of selected list items in options pane.
494
516
  - `color: var(--sms-li-selected-color)`: Text color of selected list items in options pane.
495
517
  - `div.multiselect > ul.options > li.active`
496
- - `background: var(--sms-li-active-bg, var(--sms-active-color, rgba(0, 0, 0, 0.15)))`: Background of active dropdown item. Items become active either by mouseover or by navigating to them with arrow keys.
518
+ - `background: var(--sms-li-active-bg, var(--sms-active-color, rgba(0, 0, 0, 0.15)))`: Background of active options. Options in the dropdown list become active either by mouseover or by navigating to them with arrow keys. Selected options become active when `selectedOptionsDraggable=true` and an option is being dragged to a new position. Note the active option in that case is not the dragged option but the option under it whose place it will take on drag end.
497
519
  - `div.multiselect > ul.options > li.disabled`
498
520
  - `background: var(--sms-li-disabled-bg, #f5f5f6)`: Background of disabled options in the dropdown list.
499
521
  - `color: var(--sms-li-disabled-text, #b8b8b8)`: Text color of disabled option in the dropdown list.
500
522
 
501
523
  For example, to change the background color of the options dropdown:
502
524
 
503
- ```svelte
525
+ ```html
504
526
  <MultiSelect --sms-options-bg="white" />
505
527
  ```
506
528
 
@@ -514,16 +536,18 @@ The second method allows you to pass in custom classes to the important DOM elem
514
536
  - `ulOptionsClass`: available options listed in the dropdown when component is in `open` state
515
537
  - `liOptionClass`: list items selectable from dropdown list
516
538
  - `liActiveOptionClass`: the currently active dropdown list item (i.e. hovered or navigated to with arrow keys)
539
+ - `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
517
540
 
518
541
  This simplified version of the DOM structure of the component shows where these classes are inserted:
519
542
 
520
- ```svelte
543
+ ```html
521
544
  <div class="multiselect {outerDivClass}">
522
545
  <input class={inputClass} />
523
546
  <ul class="selected {ulSelectedClass}">
524
547
  <li class={liSelectedClass}>Selected 1</li>
525
548
  <li class={liSelectedClass}>Selected 2</li>
526
549
  </ul>
550
+ <span class="maxSelectMsgClass">2/5 selected</span>
527
551
  <ul class="options {ulOptionsClass}">
528
552
  <li class={liOptionClass}>Option 1</li>
529
553
  <li class="{liOptionClass} {liActiveOptionClass}">
@@ -583,13 +607,6 @@ Odd as it may seem, you get the most fine-grained control over the styling of ev
583
607
  }
584
608
  ```
585
609
 
586
- ## Want to contribute?
587
-
588
- To submit a PR, clone the repo, install dependencies and start the dev server to try out your changes.
610
+ ## Want to contribute to this project?
589
611
 
590
- ```sh
591
- git clone https://github.com/janosh/svelte-multiselect
592
- cd svelte-multiselect
593
- pnpm install
594
- pnpm dev
595
- ```
612
+ [Here are some steps](https://github.com/janosh/svelte-multiselect/blob/main/contributing.md) to get you started!