diff --git a/package.json b/package.json
index fa4448d..5752c7a 100644
--- a/package.json
+++ b/package.json
@@ -23,37 +23,37 @@
"update-coverage": "vitest tests/unit --run --coverage && npx istanbul-badges-readme"
},
"dependencies": {
- "svelte": "4.2.3"
+ "svelte": "4.2.8"
},
"devDependencies": {
- "@iconify/svelte": "^3.1.4",
- "@playwright/test": "^1.39.0",
- "@sveltejs/adapter-static": "^2.0.3",
- "@sveltejs/kit": "^1.27.6",
- "@sveltejs/package": "2.2.2",
- "@sveltejs/vite-plugin-svelte": "2.5.2",
- "@typescript-eslint/eslint-plugin": "^6.11.0",
- "@typescript-eslint/parser": "^6.11.0",
- "@vitest/coverage-v8": "^0.34.6",
- "eslint": "^8.53.0",
- "eslint-plugin-svelte": "^2.35.0",
+ "@iconify/svelte": "^3.1.6",
+ "@playwright/test": "^1.40.1",
+ "@sveltejs/adapter-static": "^3.0.1",
+ "@sveltejs/kit": "^2.3.2",
+ "@sveltejs/package": "2.2.5",
+ "@sveltejs/vite-plugin-svelte": "3.0.1",
+ "@typescript-eslint/eslint-plugin": "^6.18.1",
+ "@typescript-eslint/parser": "^6.18.1",
+ "@vitest/coverage-v8": "^1.2.0",
+ "eslint": "^8.56.0",
+ "eslint-plugin-svelte": "^2.35.1",
"hastscript": "^8.0.0",
"highlight.js": "^11.9.0",
- "jsdom": "^22.1.0",
+ "jsdom": "^23.2.0",
"mdsvex": "^0.11.0",
"mdsvexamples": "^0.4.1",
- "prettier": "^3.1.0",
- "prettier-plugin-svelte": "^3.1.0",
+ "prettier": "^3.2.1",
+ "prettier-plugin-svelte": "^3.1.2",
"rehype-autolink-headings": "^7.1.0",
"rehype-slug": "^6.0.0",
- "svelte-check": "^3.6.0",
- "svelte-preprocess": "^5.1.0",
+ "svelte-check": "^3.6.3",
+ "svelte-preprocess": "^5.1.3",
"svelte-toc": "^0.5.6",
"svelte-zoo": "^0.4.9",
- "svelte2tsx": "^0.6.25",
- "typescript": "5.2.2",
- "vite": "^4.5.0",
- "vitest": "^0.34.6"
+ "svelte2tsx": "^0.7.0",
+ "typescript": "5.3.3",
+ "vite": "^5.0.11",
+ "vitest": "^1.2.0"
},
"keywords": [
"svelte",
diff --git a/readme.md b/readme.md
index e3c9d98..7998196 100644
--- a/readme.md
+++ b/readme.md
@@ -229,12 +229,30 @@ Full list of props/bindable variables for this component. The `Option` type you
The `inputmode` attribute hints at the type of data the user may enter. Values like `'numeric' | 'tel' | 'email'` allow mobile browsers to display an appropriate virtual on-screen keyboard. See [MDN](https://developer.mozilla.org/docs/Web/HTML/Global_attributes/inputmode) for details. If you want to suppress the on-screen keyboard to leave full-screen real estate for the dropdown list of options, set `inputmode="none"`.
+1. ```ts
+ inputStyle: string | null = null
+ ```
+
+ One-off CSS rules applied to the `` element.
+
1. ```ts
invalid: boolean = false
```
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 `` and setting it to `true` based on outside events or custom validation.
+1. ```ts
+ liOptionStyle: string | null = null
+ ```
+
+ One-off CSS rules applied to the `
` elements that wrap the dropdown options.
+
+1. ```ts
+ liSelectedStyle: string | null = null
+ ```
+
+ One-off CSS rules applied to the `
` elements that wrap the selected options.
+
1. ```ts
loading: boolean = false
```
@@ -381,6 +399,24 @@ Full list of props/bindable variables for this component. The `Option` type you
Whether selected options are draggable so users can change their order.
+1. ```ts
+ style: string | null = null
+ ```
+
+ One-off CSS rules applied to the outer `
` that wraps the whole component for passing one-off CSS.
+
+1. ```ts
+ ulSelectedStyle: string | null = null
+ ```
+
+ One-off CSS rules applied to the `
` that wraps the list of selected options.
+
+1. ```ts
+ ulOptionsStyle: string | null = null
+ ```
+
+ One-off CSS rules applied to the `
` that wraps the list of selected options.
+
1. ```ts
value: Option | Option[] | null = null
```
diff --git a/src/lib/MultiSelect.svelte b/src/lib/MultiSelect.svelte
index 7e71175..424484b 100644
--- a/src/lib/MultiSelect.svelte
+++ b/src/lib/MultiSelect.svelte
@@ -35,12 +35,15 @@
export let id: string | null = null
export let input: HTMLInputElement | null = null
export let inputClass: string = ``
+ export let inputStyle: string | null = null
export let inputmode: string | null = null
export let invalid: boolean = false
export let liActiveOptionClass: string = ``
export let liActiveUserMsgClass: string = ``
export let liOptionClass: string = ``
+ export let liOptionStyle: string | null = null
export let liSelectedClass: string = ``
+ export let liSelectedStyle: string | null = null
export let liUserMsgClass: string = ``
export let loading: boolean = false
export let matchingOptions: Option[] = []
@@ -48,7 +51,7 @@
export let maxSelect: number | null = null // null means there is no upper limit for selected.length
export let maxSelectMsg: ((current: number, max: number) => string) | null = (
current: number,
- max: number
+ max: number,
) => (max > 1 ? `${current}/${max}` : ``)
export let maxSelectMsgClass: string = ``
export let name: string | null = null
@@ -72,8 +75,11 @@
.slice(0, maxSelect ?? undefined) ?? [] // don't allow more than maxSelect preselected options
export let sortSelected: boolean | ((op1: Option, op2: Option) => number) = false
export let selectedOptionsDraggable: boolean = !sortSelected
+ export let style: string | null = null
export let ulOptionsClass: string = ``
export let ulSelectedClass: string = ``
+ export let ulSelectedStyle: string | null = null
+ export let ulOptionsStyle: string | null = null
export let value: Option | Option[] | null = null
const selected_to_value = (selected: Option[]) => {
@@ -106,34 +112,34 @@
}
if (maxSelect !== null && maxSelect < 1) {
console.error(
- `MultiSelect's maxSelect must be null or positive integer, got ${maxSelect}`
+ `MultiSelect's maxSelect must be null or positive integer, got ${maxSelect}`,
)
}
if (!Array.isArray(selected)) {
console.error(
- `MultiSelect's selected prop should always be an array, got ${selected}`
+ `MultiSelect's selected prop should always be an array, got ${selected}`,
)
}
if (maxSelect && typeof required === `number` && required > maxSelect) {
console.error(
- `MultiSelect maxSelect=${maxSelect} < required=${required}, makes it impossible for users to submit a valid form`
+ `MultiSelect maxSelect=${maxSelect} < required=${required}, makes it impossible for users to submit a valid form`,
)
}
if (parseLabelsAsHtml && allowUserOptions) {
console.warn(
- `Don't combine parseLabelsAsHtml and allowUserOptions. It's susceptible to XSS attacks!`
+ `Don't combine parseLabelsAsHtml and allowUserOptions. It's susceptible to XSS attacks!`,
)
}
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.`
+ `user re-orderings of selected options will be undone by sortSelected on component re-renders.`,
)
}
if (allowUserOptions && !createOptionMsg && createOptionMsg !== null) {
console.error(
`MultiSelect has allowUserOptions=${allowUserOptions} but createOptionMsg=${createOptionMsg} is falsy. ` +
- `This prevents the "Add option" from showing up, resulting in a confusing user experience.`
+ `This prevents the "Add option" from showing up, resulting in a confusing user experience.`,
)
}
if (
@@ -141,7 +147,7 @@
(typeof maxOptions != `number` || maxOptions < 0 || maxOptions % 1 != 0)
) {
console.error(
- `MultiSelect's maxOptions must be undefined or a positive integer, got ${maxOptions}`
+ `MultiSelect's maxOptions must be undefined or a positive integer, got ${maxOptions}`,
)
}
@@ -154,7 +160,7 @@
(opt) =>
filterFunc(opt, searchText) &&
// remove already selected options from dropdown list unless duplicate selections are allowed
- (!selected.map(key).includes(key(opt)) || duplicates)
+ (!selected.map(key).includes(key(opt)) || duplicates),
)
// raise if matchingOptions[activeIndex] does not yield a value
@@ -261,8 +267,8 @@
if (option === undefined) {
return console.error(
`Multiselect can't remove selected option ${JSON.stringify(
- to_remove
- )}, not found in selected list`
+ to_remove,
+ )}, not found in selected list`,
)
}
@@ -474,6 +480,7 @@
data-id={id}
role="searchbox"
tabindex="-1"
+ {style}
>
@@ -502,7 +509,11 @@
-