🚀 Big News:Socket Has Acquired Secure Annex.Learn More
Socket
Book a DemoSign in
Socket

svelte-multiselect

Package Overview
Dependencies
Maintainers
1
Versions
95
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

svelte-multiselect - npm Package Compare versions

Comparing version
8.6.0
to
8.6.1
+2
-2
dist/CmdPalette.svelte

@@ -13,4 +13,4 @@ <script>/* eslint-disable no-undef */ // TODO: remove when fixed

export let open = false;
export let dialog;
export let input;
export let dialog = null;
export let input = null;
export let placeholder = `Filter actions...`;

@@ -17,0 +17,0 @@ async function toggle(event) {

@@ -14,4 +14,4 @@ import { SvelteComponentTyped } from "svelte";

open?: boolean | undefined;
dialog: HTMLDialogElement;
input: HTMLInputElement;
dialog?: HTMLDialogElement | null | undefined;
input?: HTMLInputElement | null | undefined;
placeholder?: string | undefined;

@@ -18,0 +18,0 @@ };

export { default as CircleSpinner } from './CircleSpinner.svelte';
export { default as CmdPalette } from './CmdPalette.svelte';
export { default, default as MultiSelect } from './MultiSelect.svelte';
export { default as MultiSelect, default } from './MultiSelect.svelte';
export { default as Wiggle } from './Wiggle.svelte';

@@ -5,0 +5,0 @@ export type Option = string | number | ObjectOption;

export { default as CircleSpinner } from './CircleSpinner.svelte';
export { default as CmdPalette } from './CmdPalette.svelte';
export { default, default as MultiSelect } from './MultiSelect.svelte';
export { default as MultiSelect, default } from './MultiSelect.svelte';
export { default as Wiggle } from './Wiggle.svelte';
// Firefox lacks support for scrollIntoViewIfNeeded, see
// https://github.com/janosh/svelte-multiselect/issues/87
// this polyfill was copied from
// Firefox lacks support for scrollIntoViewIfNeeded (https://caniuse.com/scrollintoviewifneeded).
// See https://github.com/janosh/svelte-multiselect/issues/87
// Polyfill copied from
// https://github.com/nuxodin/lazyfill/blob/a8e63/polyfills/Element/prototype/scrollIntoViewIfNeeded.js
// exported for testing
export function scroll_into_view_if_needed_polyfill(centerIfNeeded = true) {
const el = this;
const elem = this;
const observer = new IntersectionObserver(function ([entry]) {

@@ -16,3 +16,3 @@ const ratio = entry.intersectionRatio;

const place = ratio <= 0 && centerIfNeeded ? `center` : `nearest`;
el.scrollIntoView({
elem.scrollIntoView({
block: place,

@@ -24,3 +24,3 @@ inline: place,

});
observer.observe(this);
observer.observe(elem);
return observer; // return for testing

@@ -27,0 +27,0 @@ }

@@ -103,9 +103,14 @@ <script>import { createEventDispatcher, tick } from 'svelte';

if (sortSelected && selectedOptionsDraggable) {
console.warn(`MultiSelect's sortSelected and selectedOptionsDraggable should not be combined as any user re-orderings of selected options will be undone by sortSelected on component re-renders.`);
console.warn(`MultiSelect's sortSelected and selectedOptionsDraggable should not be combined as any ` +
`user re-orderings of selected options will be undone by sortSelected on component re-renders.`);
}
if (allowUserOptions && !createOptionMsg) {
console.error(`MultiSelect's allowUserOptions=${allowUserOptions} but createOptionMsg=${createOptionMsg} is falsy. ` +
`This prevents the "Add option" <span> from showing up, resulting in a confusing user experience.`);
}
const dispatch = createEventDispatcher();
let add_option_msg_is_active = false; // controls active state of <li>{createOptionMsg}</li>
let option_msg_is_active = false; // controls active state of <li>{createOptionMsg}</li>
let window_width;
// options matching the current search text
$: matchingOptions = options.filter((op) => filterFunc(op, searchText) && !selected.map(get_label).includes(get_label(op)) // remove already selected options from dropdown list
$: matchingOptions = options.filter((op) => filterFunc(op, searchText) && !selected.includes(op) // remove already selected options from dropdown list
);

@@ -119,13 +124,13 @@ // raise if matchingOptions[activeIndex] does not yield a value

// add an option to selected list
function add(label, event) {
function add(option, event) {
if (maxSelect && maxSelect > 1 && selected.length >= maxSelect)
wiggle = true;
if (!isNaN(Number(label)) && typeof selected.map(get_label)[0] === `number`)
label = Number(label); // convert to number if possible
const is_duplicate = selected.some((option) => duplicateFunc(option, label));
if (!isNaN(Number(option)) && typeof selected.map(get_label)[0] === `number`) {
option = Number(option); // convert to number if possible
}
const is_duplicate = selected.some((op) => duplicateFunc(op, option));
if ((maxSelect === null || maxSelect === 1 || selected.length < maxSelect) &&
(duplicates || !is_duplicate)) {
// first check if we find option in the options list
let option = options.find((op) => get_label(op) === label);
if (!option && // this has the side-effect of not allowing to user to add the same
if (!options.includes(option) && // first check if we find option in the options list
// this has the side-effect of not allowing to user to add the same
// custom option twice in append mode

@@ -154,9 +159,6 @@ [true, `append`].includes(allowUserOptions) &&

}
if (option === undefined) {
throw `Run time error, option with label ${label} not found in options list`;
}
if (resetFilterOnAdd)
searchText = ``; // reset search string on selection
if ([``, undefined, null].includes(option)) {
console.error(`MultiSelect: encountered missing option with label ${label} (or option is poorly labeled)`);
console.error(`MultiSelect: encountered falsy option ${option}`);
return;

@@ -240,4 +242,3 @@ }

if (activeOption) {
const label = get_label(activeOption);
selected.map(get_label).includes(label) ? remove(label) : add(label, event);
selected.includes(activeOption) ? remove(activeOption) : add(activeOption, event);
searchText = ``;

@@ -264,3 +265,3 @@ }

// <li>{addUserMsg}</li> active on keydown (or toggle it if already active)
add_option_msg_is_active = !add_option_msg_is_active;
option_msg_is_active = !option_msg_is_active;
return;

@@ -290,3 +291,3 @@ }

else if (event.key === `Backspace` && selected.length > 0 && !searchText) {
remove(selected.map(get_label).at(-1));
remove(selected.at(-1));
}

@@ -353,3 +354,10 @@ // make first matching option active on any keypress (if none of the above special cases match)

return;
const tree_walker = document.createTreeWalker(ul_options, NodeFilter.SHOW_TEXT);
const tree_walker = document.createTreeWalker(ul_options, NodeFilter.SHOW_TEXT, {
acceptNode: (node) => {
// don't highlight text in the "no matching options" message
if (node?.textContent === noMatchingOptionsMsg)
return NodeFilter.FILTER_REJECT;
return NodeFilter.FILTER_ACCEPT;
},
});
const text_nodes = [];

@@ -363,6 +371,6 @@ let current_node = tree_walker.nextNode();

const ranges = text_nodes.map((el) => {
const text = el.textContent.toLowerCase();
const text = el.textContent?.toLowerCase();
const indices = [];
let start_pos = 0;
while (start_pos < text.length) {
while (text && start_pos < text.length) {
const index = text.indexOf(query, start_pos);

@@ -384,3 +392,3 @@ if (index === -1)

// eslint-disable-next-line no-undef
CSS.highlights.set(`search-results`, new Highlight(...ranges.flat()));
CSS.highlights.set(`sms-search-matches`, new Highlight(...ranges.flat()));
}

@@ -410,3 +418,3 @@ </script>

required={Boolean(required)}
value={selected.length >= required ? JSON.stringify(selected) : null}
value={selected.length >= Number(required) ? JSON.stringify(selected) : null}
tabindex="-1"

@@ -420,5 +428,5 @@ aria-hidden="true"

let msg
if (maxSelect && maxSelect > 1 && required > 1) {
if (maxSelect && maxSelect > 1 && Number(required) > 1) {
msg = `Please select between ${required} and ${maxSelect} options`
} else if (required > 1) {
} else if (Number(required) > 1) {
msg = `Please select at least ${required} options`

@@ -435,3 +443,3 @@ } else {

<ul class="selected {ulSelectedClass}" aria-label="selected options">
{#each selected as option, idx (get_label(option))}
{#each selected as option, idx (option)}
<li

@@ -456,4 +464,4 @@ class={liSelectedClass}

<button
on:mouseup|stopPropagation={() => remove(get_label(option))}
on:keydown={if_enter_or_space(() => remove(get_label(option)))}
on:mouseup|stopPropagation={() => remove(option)}
on:keydown={if_enter_or_space(() => remove(option))}
type="button"

@@ -549,3 +557,3 @@ title="{removeBtnTitle} {get_label(option)}"

on:mouseup|stopPropagation={(event) => {
if (!disabled) add(label, event)
if (!disabled) add(option, event)
}}

@@ -577,3 +585,8 @@ title={disabled

{:else}
{#if allowUserOptions && searchText}
{@const search_is_duplicate = selected.some((option) =>
duplicateFunc(option, searchText)
)}
{@const msg =
!duplicates && search_is_duplicate ? duplicateOptionMsg : createOptionMsg}
{#if allowUserOptions && searchText && msg}
<li

@@ -583,15 +596,16 @@ on:mousedown|stopPropagation

title={createOptionMsg}
class:active={add_option_msg_is_active}
on:mouseover={() => (add_option_msg_is_active = true)}
on:focus={() => (add_option_msg_is_active = true)}
on:mouseout={() => (add_option_msg_is_active = false)}
on:blur={() => (add_option_msg_is_active = false)}
class:active={option_msg_is_active}
on:mouseover={() => (option_msg_is_active = true)}
on:focus={() => (option_msg_is_active = true)}
on:mouseout={() => (option_msg_is_active = false)}
on:blur={() => (option_msg_is_active = false)}
class="user-msg"
>
{!duplicates && selected.some((option) => duplicateFunc(option, searchText))
? duplicateOptionMsg
: createOptionMsg}
{msg}
</li>
{:else}
<span>{noMatchingOptionsMsg}</span>
{:else if noMatchingOptionsMsg}
<!-- use span to not have cursor: pointer -->
<span class="user-msg">{noMatchingOptionsMsg}</span>
{/if}
<!-- Show nothing if all messages are empty -->
{/each}

@@ -740,4 +754,5 @@ </ul>

}
/* for noOptionsMsg */
:where(div.multiselect > ul.options span) {
:where(div.multiselect > ul.options .user-msg) {
/* block needed so vertical padding applies to span */
display: block;
padding: 3pt 2ex;

@@ -761,8 +776,5 @@ }

}
::highlight(search-results) {
color: var(--sms-highlight-color, orange);
background: var(--sms-highlight-bg);
text-decoration: var(--sms-highlight-text-decoration);
text-decoration-color: var(--sms-highlight-text-decoration-color);
::highlight(sms-search-matches) {
color: mediumaquamarine;
}
</style>
import { SvelteComponentTyped } from "svelte";
import type { MultiSelectEvents, Option as GenericOption } from './';
import type { Option as GenericOption, MultiSelectEvents } from './';
declare class __sveltets_Render<Option extends GenericOption> {

@@ -4,0 +4,0 @@ props(): {

@@ -8,3 +8,3 @@ {

"license": "MIT",
"version": "8.6.0",
"version": "8.6.1",
"type": "module",

@@ -27,33 +27,33 @@ "svelte": "./dist/index.js",

"dependencies": {
"svelte": "^3.57.0"
"svelte": "^3.58.0"
},
"devDependencies": {
"@iconify/svelte": "^3.1.0",
"@playwright/test": "^1.31.2",
"@sveltejs/adapter-static": "^2.0.1",
"@sveltejs/kit": "^1.12.0",
"@iconify/svelte": "^3.1.3",
"@playwright/test": "^1.33.0",
"@sveltejs/adapter-static": "^2.0.2",
"@sveltejs/kit": "^1.15.9",
"@sveltejs/package": "2.0.2",
"@sveltejs/vite-plugin-svelte": "^2.0.3",
"@typescript-eslint/eslint-plugin": "^5.55.0",
"@typescript-eslint/parser": "^5.55.0",
"@vitest/coverage-c8": "^0.29.3",
"eslint": "^8.36.0",
"@sveltejs/vite-plugin-svelte": "^2.1.1",
"@typescript-eslint/eslint-plugin": "^5.59.1",
"@typescript-eslint/parser": "^5.59.1",
"@vitest/coverage-c8": "^0.30.1",
"eslint": "^8.39.0",
"eslint-plugin-svelte3": "^4.0.0",
"hastscript": "^7.2.0",
"highlight.js": "^11.7.0",
"highlight.js": "^11.8.0",
"jsdom": "^21.1.1",
"mdsvex": "^0.10.6",
"mdsvexamples": "^0.3.3",
"prettier": "^2.8.4",
"prettier-plugin-svelte": "^2.9.0",
"prettier": "^2.8.8",
"prettier-plugin-svelte": "^2.10.0",
"rehype-autolink-headings": "^6.1.1",
"rehype-slug": "^5.1.0",
"svelte-check": "^3.1.4",
"svelte-check": "^3.2.0",
"svelte-preprocess": "^5.0.3",
"svelte-toc": "^0.5.4",
"svelte-zoo": "^0.4.3",
"svelte2tsx": "^0.6.10",
"typescript": "5.0.2",
"vite": "^4.2.0",
"vitest": "^0.29.3"
"svelte-toc": "^0.5.5",
"svelte-zoo": "^0.4.5",
"svelte2tsx": "^0.6.11",
"typescript": "5.0.4",
"vite": "^4.3.3",
"vitest": "^0.30.1"
},

@@ -60,0 +60,0 @@ "keywords": [

@@ -192,3 +192,3 @@ <h1 align="center">

Whether to highlight text in the dropdown options that matches the current user-entered search query. Uses the [CSS Custom Highlight API](https://developer.mozilla.org/docs/Web/API/CSS_Custom_Highlight_API) with limited browser support and [styling options](https://developer.mozilla.org/docs/Web/CSS/::highlight). See `::highlight(search-results)` below for available CSS variables.
Whether to highlight text in the dropdown options that matches the current user-entered search query. Uses the [CSS Custom Highlight API](https://developer.mozilla.org/docs/Web/API/CSS_Custom_Highlight_API) with limited browser support and [styling options](https://developer.mozilla.org/docs/Web/CSS/::highlight). See `::highlight(sms-search-matches)` below for available CSS variables.

@@ -530,3 +530,3 @@ 1. ```ts

- `div.multiselect:focus-within`
- `border: var(--sms-focus-border, 1pt solid var(--sms-active-color, cornflowerblue))`: Border when component has focus. Defaults to `--sms-active-color` if not set which defaults to `cornflowerblue`.
- `border: var(--sms-focus-border, 1pt solid var(--sms-active-color, cornflowerblue))`: Border when component has focus. Defaults to `--sms-active-color` which in turn defaults to `cornflowerblue`.
- `div.multiselect.disabled`

@@ -564,8 +564,12 @@ - `background: var(--sms-disabled-bg, lightgray)`: Background when in disabled state.

- `color: var(--sms-li-disabled-text, #b8b8b8)`: Text color of disabled option in the dropdown list.
- `::highlight(search-results)`: applies to search results in dropdown list that match the current search query if `highlightMatches=true`
- `color: var(--sms-highlight-color, orange)`
- `background: var(--sms-highlight-bg)`
- `text-decoration: var(--sms-highlight-text-decoration)`
- `text-decoration-color: var(--sms-highlight-text-decoration-color)`
- `::highlight(sms-search-matches)`: applies to search results in dropdown list that match the current search query if `highlightMatches=true`. These styles [cannot be set via CSS variables](https://stackoverflow.com/a/56799215). Instead, use a new rule set. For example:
```css
::highlight(sms-search-matches) {
color: orange;
background: rgba(0, 0, 0, 0.15);
text-decoration: underline;
}
```
### With CSS frameworks

@@ -572,0 +576,0 @@