svelte-multiselect 10.1.0 → 10.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.
@@ -26,7 +26,7 @@ export let filterFunc = (opt, searchText) => {
26
26
  return true;
27
27
  return `${get_label(opt)}`.toLowerCase().includes(searchText.toLowerCase());
28
28
  };
29
- export let focusInputOnSelect = `desktop`;
29
+ export let closeDropdownOnSelect = `desktop`;
30
30
  export let form_input = null;
31
31
  export let highlightMatches = true;
32
32
  export let id = null;
@@ -186,10 +186,13 @@ function add(option, event) {
186
186
  selected = selected.sort(sortSelected);
187
187
  }
188
188
  }
189
- if (selected.length === maxSelect)
189
+ const reached_max_select = selected.length === maxSelect;
190
+ const dropdown_should_close = closeDropdownOnSelect === true ||
191
+ (closeDropdownOnSelect === `desktop` && window_width < breakpoint);
192
+ if (reached_max_select || dropdown_should_close) {
190
193
  close_dropdown(event);
191
- else if (focusInputOnSelect === true ||
192
- (focusInputOnSelect === `desktop` && window_width > breakpoint)) {
194
+ }
195
+ else if (!dropdown_should_close) {
193
196
  input?.focus();
194
197
  }
195
198
  dispatch(`add`, { option });
@@ -302,10 +305,10 @@ async function handle_keydown(event) {
302
305
  }
303
306
  }
304
307
  function remove_all() {
305
- selected = [];
306
- searchText = ``;
307
308
  dispatch(`removeAll`, { options: selected });
308
309
  dispatch(`change`, { options: selected, type: `removeAll` });
310
+ selected = [];
311
+ searchText = ``;
309
312
  }
310
313
  $: is_selected = (label) => selected.map(get_label).includes(label);
311
314
  const if_enter_or_space = (handler) => (event) => {
@@ -615,9 +618,9 @@ function highlight_matching_options(event) {
615
618
  {#if searchText}
616
619
  {@const text_input_is_duplicate = selected.map(get_label).includes(searchText)}
617
620
  {@const is_dupe = !duplicates && text_input_is_duplicate && `dupe`}
618
- {@const can_create = allowUserOptions && createOptionMsg && `create`}
621
+ {@const can_create = Boolean(allowUserOptions && createOptionMsg) && `create`}
619
622
  {@const no_match =
620
- matchingOptions?.length == 0 && noMatchingOptionsMsg && `no-match`}
623
+ Boolean(matchingOptions?.length == 0 && noMatchingOptionsMsg) && `no-match`}
621
624
  {@const msgType = is_dupe || can_create || no_match}
622
625
  {#if msgType}
623
626
  {@const msg = {
@@ -17,7 +17,7 @@ declare class __sveltets_Render<Option extends T> {
17
17
  duplicates?: boolean | undefined;
18
18
  key?: ((opt: T) => unknown) | undefined;
19
19
  filterFunc?: ((opt: Option, searchText: string) => boolean) | undefined;
20
- focusInputOnSelect?: boolean | "desktop" | undefined;
20
+ closeDropdownOnSelect?: boolean | "desktop" | undefined;
21
21
  form_input?: HTMLInputElement | null | undefined;
22
22
  highlightMatches?: boolean | undefined;
23
23
  id?: string | null | undefined;
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "homepage": "https://janosh.github.io/svelte-multiselect",
6
6
  "repository": "https://github.com/janosh/svelte-multiselect",
7
7
  "license": "MIT",
8
- "version": "10.1.0",
8
+ "version": "10.2.0",
9
9
  "type": "module",
10
10
  "svelte": "./dist/index.js",
11
11
  "bugs": "https://github.com/janosh/svelte-multiselect/issues",
@@ -23,37 +23,37 @@
23
23
  "update-coverage": "vitest tests/unit --run --coverage && npx istanbul-badges-readme"
24
24
  },
25
25
  "dependencies": {
26
- "svelte": "^4.0.5"
26
+ "svelte": "^4.2.0"
27
27
  },
28
28
  "devDependencies": {
29
29
  "@iconify/svelte": "^3.1.4",
30
- "@playwright/test": "^1.36.1",
31
- "@sveltejs/adapter-static": "^2.0.2",
32
- "@sveltejs/kit": "^1.22.3",
33
- "@sveltejs/package": "2.2.0",
34
- "@sveltejs/vite-plugin-svelte": "2.4.2",
35
- "@typescript-eslint/eslint-plugin": "^6.1.0",
36
- "@typescript-eslint/parser": "^6.1.0",
37
- "@vitest/coverage-v8": "^0.33.0",
38
- "eslint": "^8.45.0",
39
- "eslint-plugin-svelte": "^2.32.2",
40
- "hastscript": "^7.2.0",
30
+ "@playwright/test": "^1.37.1",
31
+ "@sveltejs/adapter-static": "^2.0.3",
32
+ "@sveltejs/kit": "^1.24.1",
33
+ "@sveltejs/package": "2.2.2",
34
+ "@sveltejs/vite-plugin-svelte": "2.4.5",
35
+ "@typescript-eslint/eslint-plugin": "^6.7.0",
36
+ "@typescript-eslint/parser": "^6.7.0",
37
+ "@vitest/coverage-v8": "^0.34.4",
38
+ "eslint": "^8.49.0",
39
+ "eslint-plugin-svelte": "^2.33.1",
40
+ "hastscript": "^8.0.0",
41
41
  "highlight.js": "^11.8.0",
42
42
  "jsdom": "^22.1.0",
43
43
  "mdsvex": "^0.11.0",
44
- "mdsvexamples": "^0.3.3",
45
- "prettier": "^2.8.8",
46
- "prettier-plugin-svelte": "^2.10.1",
47
- "rehype-autolink-headings": "^6.1.1",
48
- "rehype-slug": "^5.1.0",
49
- "svelte-check": "^3.4.6",
44
+ "mdsvexamples": "^0.4.1",
45
+ "prettier": "^3.0.3",
46
+ "prettier-plugin-svelte": "^3.0.3",
47
+ "rehype-autolink-headings": "^7.0.0",
48
+ "rehype-slug": "^6.0.0",
49
+ "svelte-check": "^3.5.1",
50
50
  "svelte-preprocess": "^5.0.4",
51
- "svelte-toc": "^0.5.5",
51
+ "svelte-toc": "^0.5.6",
52
52
  "svelte-zoo": "^0.4.9",
53
- "svelte2tsx": "^0.6.19",
54
- "typescript": "5.1.6",
55
- "vite": "^4.4.4",
56
- "vitest": "^0.33.0"
53
+ "svelte2tsx": "^0.6.21",
54
+ "typescript": "5.2.2",
55
+ "vite": "^4.4.9",
56
+ "vitest": "^0.34.4"
57
57
  },
58
58
  "keywords": [
59
59
  "svelte",
package/readme.md CHANGED
@@ -194,10 +194,10 @@ Full list of props/bindable variables for this component. The `Option` type you
194
194
  Customize how dropdown options are filtered when user enters search string into `<MultiSelect />`. Defaults to:
195
195
 
196
196
  1. ```ts
197
- focusInputOnSelect: boolean | 'desktop' = `desktop`
197
+ closeDropdownOnSelect: boolean | 'desktop' = `desktop`
198
198
  ```
199
199
 
200
- 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).
200
+ One of `true`, `false` or `'desktop'`. Whether to close the dropdown list after selecting a dropdown item. If `true`, component will loose focus and `dropdown` is closed. `'desktop'` means `false` if current window width is larger than the current value of `breakpoint` prop (default is 800, meaning screen width in pixels). This is to align with the default behavior of many mobile browsers like Safari which close dropdowns after selecting an option while desktop browsers facilitate multi-selection by leaving dropdowns open.
201
201
 
202
202
  1. ```ts
203
203
  form_input: HTMLInputElement | null = null
@@ -397,13 +397,11 @@ Full list of props/bindable variables for this component. The `Option` type you
397
397
  1. `slot="disabled-icon"`: Custom icon to display inside the input when in `disabled` state. Receives no props. Use an empty `<span slot="disabled-icon" />` or `div` to remove the default disabled icon.
398
398
  1. `slot="expand-icon"`: Allows setting a custom icon to indicate to users that the Multiselect text input field is expandable into a dropdown list. Receives prop `open: boolean` which is true if the Multiselect dropdown is visible and false if it's hidden.
399
399
  1. `slot="remove-icon"`: Custom icon to display as remove button. Will be used both by buttons to remove individual selected options and the 'remove all' button that clears all options at once. Receives no props.
400
- 1. `slot="user-msg"`: Displayed like a dropdown item when the list is empty and user is allowed to create custom options based on text input (or if the user's text input clashes with an existing option). `let:props`:
401
- - `duplicateOptionMsg: string`: See [props](#🔣-props).
402
- - `createOptionMsg: string`: See [props](#🔣-props).
403
- - `textInputIsDuplicate: boolean`: Whether user has typed text that matches an already existing option.
404
- - `searchText: string`: The text user typed into search input.
405
- - `msg: string`: `duplicateOptionMsg` if user input is a duplicate else `createOptionMsg`.
406
- 1. `slot='after-input'`: ForPlaced after the search input. For arbitrary content like icons or temporary messages. Receives props `selected`, `disabled`, `invalid`, `id`, `placeholder`, `open`, `required`.
400
+ 1. `slot="user-msg"`: Displayed like a dropdown item when the list is empty and user is allowed to create custom options based on text input (or if the user's text input clashes with an existing option). Receives props:
401
+ - `searchText`: The text user typed into search input.
402
+ - `msgType: false | 'create' | 'dupe' | 'no-match'`: `'dupe'` means user input is a duplicate of an existing option. `'create'` means user is allowed to convert their input into a new option not previously in the dropdown. `'no-match'` means user input doesn't match any dropdown items and users are not allowed to create new options. `false` means none of the above.
403
+ - `msg`: Will be `duplicateOptionMsg` or `createOptionMsg` (see [props](#🔣-props)) based on whether user input is a duplicate or can be created as new option. Note this slot replaces the default UI for displaying these messages so the slot needs to render them instead (unless purposely not showing a message).
404
+ 1. `slot='after-input'`: Placed after the search input. For arbitrary content like icons or temporary messages. Receives props `selected: Option[]`, `disabled: boolean`, `invalid: boolean`, `id: string | null`, `placeholder: string`, `open: boolean`, `required: boolean`. Can serve as a more dynamic, more customizable alternative to the `placeholder` prop.
407
405
 
408
406
  Example using several slots:
409
407