svelte-multiselect 3.1.1 → 3.2.3
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.
- package/MultiSelect.svelte +63 -58
- package/MultiSelect.svelte.d.ts +2 -1
- package/package.json +13 -13
- package/readme.md +80 -47
package/MultiSelect.svelte
CHANGED
|
@@ -12,10 +12,15 @@ export let readonly = false;
|
|
|
12
12
|
export let options;
|
|
13
13
|
export let input = null;
|
|
14
14
|
export let placeholder = undefined;
|
|
15
|
-
export let name = undefined;
|
|
16
15
|
export let id = undefined;
|
|
16
|
+
export let name = id;
|
|
17
17
|
export let noOptionsMsg = `No matching options`;
|
|
18
18
|
export let activeOption = null;
|
|
19
|
+
export let filterFunc = (op, searchText) => {
|
|
20
|
+
if (!searchText)
|
|
21
|
+
return true;
|
|
22
|
+
return `${op.label}`.toLowerCase().includes(searchText.toLowerCase());
|
|
23
|
+
};
|
|
19
24
|
export let outerDivClass = ``;
|
|
20
25
|
export let ulSelectedClass = ``;
|
|
21
26
|
export let liSelectedClass = ``;
|
|
@@ -66,11 +71,7 @@ const dispatch = createEventDispatcher();
|
|
|
66
71
|
let searchText = ``;
|
|
67
72
|
let showOptions = false;
|
|
68
73
|
// options matching the current search text
|
|
69
|
-
$: matchingOptions = _options.filter((op) =>
|
|
70
|
-
if (!searchText)
|
|
71
|
-
return true;
|
|
72
|
-
return `${op.label}`.toLowerCase().includes(searchText.toLowerCase());
|
|
73
|
-
});
|
|
74
|
+
$: matchingOptions = _options.filter((op) => filterFunc(op, searchText));
|
|
74
75
|
$: matchingEnabledOptions = matchingOptions.filter((op) => !op.disabled);
|
|
75
76
|
$: if (
|
|
76
77
|
// if there was an active option but it's not in the filtered list of options
|
|
@@ -81,7 +82,7 @@ $: if (
|
|
|
81
82
|
// make the first filtered option active
|
|
82
83
|
activeOption = matchingEnabledOptions[0];
|
|
83
84
|
function add(label) {
|
|
84
|
-
if (
|
|
85
|
+
if (maxSelect && maxSelect > 1 && selected.length >= maxSelect)
|
|
85
86
|
wiggle = true;
|
|
86
87
|
if (!readonly &&
|
|
87
88
|
!selectedLabels.includes(label) &&
|
|
@@ -114,9 +115,6 @@ function remove(label) {
|
|
|
114
115
|
dispatch(`change`, { option, type: `remove` });
|
|
115
116
|
}
|
|
116
117
|
function setOptionsVisible(show) {
|
|
117
|
-
// nothing to do if visibility is already as intended
|
|
118
|
-
if (readonly || show === showOptions)
|
|
119
|
-
return;
|
|
120
118
|
showOptions = show;
|
|
121
119
|
if (show)
|
|
122
120
|
input?.focus();
|
|
@@ -200,16 +198,15 @@ const handleEnterAndSpaceKeys = (handler) => (event) => {
|
|
|
200
198
|
<!-- z-index: 2 when showOptions is true ensures the ul.selected of one <MultiSelect />
|
|
201
199
|
display above those of another following shortly after it -->
|
|
202
200
|
<div
|
|
203
|
-
{id}
|
|
204
201
|
class="multiselect {outerDivClass}"
|
|
205
202
|
class:readonly
|
|
206
203
|
class:single={maxSelect == 1}
|
|
207
|
-
|
|
204
|
+
class:open={showOptions}
|
|
208
205
|
on:mouseup|stopPropagation={() => setOptionsVisible(true)}
|
|
209
206
|
use:onClickOutside={() => setOptionsVisible(false)}
|
|
210
207
|
use:onClickOutside={() => dispatch(`blur`)}
|
|
211
208
|
>
|
|
212
|
-
<ExpandIcon
|
|
209
|
+
<ExpandIcon style="min-width: 1em; padding: 0 1pt;" />
|
|
213
210
|
<ul class="selected {ulSelectedClass}">
|
|
214
211
|
{#each selected as option, idx}
|
|
215
212
|
<li class={liSelectedClass}>
|
|
@@ -228,21 +225,24 @@ display above those of another following shortly after it -->
|
|
|
228
225
|
{/if}
|
|
229
226
|
</li>
|
|
230
227
|
{/each}
|
|
231
|
-
<
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
228
|
+
<li style="display: contents;">
|
|
229
|
+
<input
|
|
230
|
+
bind:this={input}
|
|
231
|
+
autocomplete="off"
|
|
232
|
+
bind:value={searchText}
|
|
233
|
+
on:mouseup|self|stopPropagation={() => setOptionsVisible(true)}
|
|
234
|
+
on:keydown={handleKeydown}
|
|
235
|
+
on:focus={() => setOptionsVisible(true)}
|
|
236
|
+
{id}
|
|
237
|
+
{name}
|
|
238
|
+
placeholder={selectedLabels.length ? `` : placeholder}
|
|
239
|
+
/>
|
|
240
|
+
</li>
|
|
241
241
|
</ul>
|
|
242
242
|
{#if readonly}
|
|
243
243
|
<ReadOnlyIcon height="14pt" />
|
|
244
244
|
{:else if selected.length > 0}
|
|
245
|
-
{#if maxSelect !== null &&
|
|
245
|
+
{#if maxSelect !== null && maxSelectMsg !== null}
|
|
246
246
|
<Wiggle bind:wiggle angle={20}>
|
|
247
247
|
<span style="padding: 0 3pt;">{maxSelectMsg(selected.length, maxSelect)}</span>
|
|
248
248
|
</Wiggle>
|
|
@@ -284,7 +284,7 @@ display above those of another following shortly after it -->
|
|
|
284
284
|
</slot>
|
|
285
285
|
</li>
|
|
286
286
|
{:else}
|
|
287
|
-
{noOptionsMsg}
|
|
287
|
+
<span>{noOptionsMsg}</span>
|
|
288
288
|
{/each}
|
|
289
289
|
</ul>
|
|
290
290
|
{/key}
|
|
@@ -294,15 +294,17 @@ display above those of another following shortly after it -->
|
|
|
294
294
|
:where(div.multiselect) {
|
|
295
295
|
position: relative;
|
|
296
296
|
margin: 1em 0;
|
|
297
|
-
border: var(--sms-border, 1pt solid lightgray);
|
|
298
|
-
border-radius: var(--sms-border-radius, 5pt);
|
|
299
|
-
background: var(--sms-input-bg);
|
|
300
|
-
height: var(--sms-input-height, 2em);
|
|
301
297
|
align-items: center;
|
|
302
|
-
min-height: 18pt;
|
|
303
298
|
display: flex;
|
|
304
299
|
cursor: text;
|
|
305
300
|
padding: 0 3pt;
|
|
301
|
+
border: var(--sms-border, 1pt solid lightgray);
|
|
302
|
+
border-radius: var(--sms-border-radius, 5pt);
|
|
303
|
+
background: var(--sms-input-bg);
|
|
304
|
+
min-height: var(--sms-input-min-height, 22pt);
|
|
305
|
+
}
|
|
306
|
+
:where(div.multiselect.open) {
|
|
307
|
+
z-index: var(--sms-open-z-index, 4);
|
|
306
308
|
}
|
|
307
309
|
:where(div.multiselect:focus-within) {
|
|
308
310
|
border: var(--sms-focus-border, 1pt solid var(--sms-active-color, cornflowerblue));
|
|
@@ -311,25 +313,33 @@ display above those of another following shortly after it -->
|
|
|
311
313
|
background: var(--sms-readonly-bg, lightgray);
|
|
312
314
|
}
|
|
313
315
|
|
|
314
|
-
:where(
|
|
315
|
-
|
|
316
|
+
:where(div.multiselect > ul.selected) {
|
|
317
|
+
display: flex;
|
|
318
|
+
flex: 1;
|
|
319
|
+
padding: 0;
|
|
320
|
+
margin: 0;
|
|
321
|
+
flex-wrap: wrap;
|
|
322
|
+
}
|
|
323
|
+
:where(div.multiselect > ul.selected > li) {
|
|
316
324
|
align-items: center;
|
|
317
325
|
border-radius: 4pt;
|
|
318
326
|
display: flex;
|
|
319
327
|
margin: 2pt;
|
|
320
|
-
|
|
328
|
+
line-height: normal;
|
|
329
|
+
padding: 1pt 2pt 1pt 5pt;
|
|
321
330
|
transition: 0.3s;
|
|
322
331
|
white-space: nowrap;
|
|
323
|
-
|
|
332
|
+
background: var(--sms-selected-bg, var(--sms-active-color, cornflowerblue));
|
|
333
|
+
height: var(--sms-selected-li-height);
|
|
324
334
|
}
|
|
325
|
-
:where(ul.selected > li button, button.remove-all) {
|
|
335
|
+
:where(div.multiselect > ul.selected > li button, button.remove-all) {
|
|
326
336
|
align-items: center;
|
|
327
337
|
border-radius: 50%;
|
|
328
338
|
display: flex;
|
|
329
339
|
cursor: pointer;
|
|
330
340
|
transition: 0.2s;
|
|
331
341
|
}
|
|
332
|
-
:where(button) {
|
|
342
|
+
:where(div.multiselect button) {
|
|
333
343
|
color: inherit;
|
|
334
344
|
background: transparent;
|
|
335
345
|
border: none;
|
|
@@ -340,32 +350,23 @@ display above those of another following shortly after it -->
|
|
|
340
350
|
:where(ul.selected > li button:hover, button.remove-all:hover, button:focus) {
|
|
341
351
|
color: var(--sms-remove-x-hover-focus-color, lightskyblue);
|
|
342
352
|
}
|
|
343
|
-
:where(button:focus) {
|
|
353
|
+
:where(div.multiselect > button:focus) {
|
|
344
354
|
transform: scale(1.04);
|
|
345
355
|
}
|
|
346
356
|
|
|
347
|
-
:where(div.multiselect input) {
|
|
357
|
+
:where(div.multiselect > ul.selected > li > input) {
|
|
348
358
|
border: none;
|
|
349
359
|
outline: none;
|
|
350
360
|
background: none;
|
|
351
|
-
color: var(--sms-text-color, inherit);
|
|
352
361
|
flex: 1; /* this + next line fix issue #12 https://git.io/JiDe3 */
|
|
353
362
|
min-width: 2em;
|
|
354
363
|
/* minimum font-size > 16px ensures iOS doesn't zoom in when focusing input */
|
|
355
364
|
/* https://stackoverflow.com/a/6394497 */
|
|
356
365
|
font-size: calc(16px + 0.1vw);
|
|
366
|
+
color: var(--sms-text-color, inherit);
|
|
357
367
|
}
|
|
358
368
|
|
|
359
|
-
:where(ul.
|
|
360
|
-
display: flex;
|
|
361
|
-
padding: 0;
|
|
362
|
-
margin: 0;
|
|
363
|
-
flex-wrap: wrap;
|
|
364
|
-
flex: 1;
|
|
365
|
-
overscroll-behavior: none;
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
:where(ul.options) {
|
|
369
|
+
:where(div.multiselect > ul.options) {
|
|
369
370
|
list-style: none;
|
|
370
371
|
max-height: 50vh;
|
|
371
372
|
padding: 0;
|
|
@@ -375,15 +376,20 @@ display above those of another following shortly after it -->
|
|
|
375
376
|
border-radius: 1ex;
|
|
376
377
|
overflow: auto;
|
|
377
378
|
background: var(--sms-options-bg, white);
|
|
379
|
+
overscroll-behavior: var(--sms-options-overscroll, none);
|
|
378
380
|
}
|
|
379
|
-
:where(ul.options.hidden) {
|
|
381
|
+
:where(div.multiselect > ul.options.hidden) {
|
|
380
382
|
visibility: hidden;
|
|
381
383
|
}
|
|
382
|
-
:where(ul.options li) {
|
|
384
|
+
:where(div.multiselect > ul.options > li) {
|
|
383
385
|
padding: 3pt 2ex;
|
|
384
386
|
cursor: pointer;
|
|
385
387
|
}
|
|
386
|
-
|
|
388
|
+
/* for noOptionsMsg */
|
|
389
|
+
:where(div.multiselect > ul.options span) {
|
|
390
|
+
padding: 3pt 2ex;
|
|
391
|
+
}
|
|
392
|
+
:where(div.multiselect > ul.options > li.selected) {
|
|
387
393
|
border-left: var(
|
|
388
394
|
--sms-li-selected-border-left,
|
|
389
395
|
3pt solid var(--sms-selected-color, green)
|
|
@@ -391,22 +397,21 @@ display above those of another following shortly after it -->
|
|
|
391
397
|
background: var(--sms-li-selected-bg, inherit);
|
|
392
398
|
color: var(--sms-li-selected-color, inherit);
|
|
393
399
|
}
|
|
394
|
-
:where(ul.options li:not(.selected):hover) {
|
|
400
|
+
:where(div.multiselect > ul.options > li:not(.selected):hover) {
|
|
395
401
|
border-left: var(
|
|
396
402
|
--sms-li-not-selected-hover-border-left,
|
|
397
403
|
3pt solid var(--sms-active-color, cornflowerblue)
|
|
398
404
|
);
|
|
399
|
-
border-left: 3pt solid var(--blue);
|
|
400
405
|
}
|
|
401
|
-
:where(ul.options li.active) {
|
|
406
|
+
:where(div.multiselect > ul.options > li.active) {
|
|
402
407
|
background: var(--sms-li-active-bg, var(--sms-active-color, cornflowerblue));
|
|
403
408
|
}
|
|
404
|
-
:where(ul.options li.disabled) {
|
|
409
|
+
:where(div.multiselect > ul.options > li.disabled) {
|
|
410
|
+
cursor: not-allowed;
|
|
405
411
|
background: var(--sms-li-disabled-bg, #f5f5f6);
|
|
406
412
|
color: var(--sms-li-disabled-text, #b8b8b8);
|
|
407
|
-
cursor: not-allowed;
|
|
408
413
|
}
|
|
409
|
-
:where(ul.options li.disabled:hover) {
|
|
414
|
+
:where(div.multiselect > ul.options > li.disabled:hover) {
|
|
410
415
|
border-left: unset;
|
|
411
416
|
}
|
|
412
417
|
</style>
|
package/MultiSelect.svelte.d.ts
CHANGED
|
@@ -11,10 +11,11 @@ declare const __propDef: {
|
|
|
11
11
|
options: ProtoOption[];
|
|
12
12
|
input?: HTMLInputElement | null | undefined;
|
|
13
13
|
placeholder?: string | undefined;
|
|
14
|
-
name?: string | undefined;
|
|
15
14
|
id?: string | undefined;
|
|
15
|
+
name?: string | undefined;
|
|
16
16
|
noOptionsMsg?: string | undefined;
|
|
17
17
|
activeOption?: Option | null | undefined;
|
|
18
|
+
filterFunc?: ((op: Option, searchText: string) => boolean) | undefined;
|
|
18
19
|
outerDivClass?: string | undefined;
|
|
19
20
|
ulSelectedClass?: string | undefined;
|
|
20
21
|
liSelectedClass?: string | undefined;
|
package/package.json
CHANGED
|
@@ -5,32 +5,32 @@
|
|
|
5
5
|
"homepage": "https://svelte-multiselect.netlify.app",
|
|
6
6
|
"repository": "https://github.com/janosh/svelte-multiselect",
|
|
7
7
|
"license": "MIT",
|
|
8
|
-
"version": "3.
|
|
8
|
+
"version": "3.2.3",
|
|
9
9
|
"type": "module",
|
|
10
10
|
"svelte": "index.js",
|
|
11
11
|
"bugs": "https://github.com/janosh/svelte-multiselect/issues",
|
|
12
12
|
"devDependencies": {
|
|
13
|
-
"@sveltejs/adapter-static": "^1.0.0-next.
|
|
14
|
-
"@sveltejs/kit": "^1.0.0-next.
|
|
15
|
-
"@typescript-eslint/eslint-plugin": "^5.
|
|
16
|
-
"@typescript-eslint/parser": "^5.
|
|
17
|
-
"eslint": "^8.
|
|
13
|
+
"@sveltejs/adapter-static": "^1.0.0-next.28",
|
|
14
|
+
"@sveltejs/kit": "^1.0.0-next.269",
|
|
15
|
+
"@typescript-eslint/eslint-plugin": "^5.12.0",
|
|
16
|
+
"@typescript-eslint/parser": "^5.12.0",
|
|
17
|
+
"eslint": "^8.9.0",
|
|
18
18
|
"eslint-plugin-svelte3": "^3.4.0",
|
|
19
19
|
"hastscript": "^7.0.2",
|
|
20
|
-
"mdsvex": "^0.
|
|
20
|
+
"mdsvex": "^0.10.5",
|
|
21
21
|
"prettier": "^2.5.1",
|
|
22
22
|
"prettier-plugin-svelte": "^2.6.0",
|
|
23
23
|
"rehype-autolink-headings": "^6.1.1",
|
|
24
24
|
"rehype-slug": "^5.0.1",
|
|
25
|
-
"svelte": "^3.46.
|
|
26
|
-
"svelte-check": "^2.3
|
|
25
|
+
"svelte": "^3.46.4",
|
|
26
|
+
"svelte-check": "^2.4.3",
|
|
27
27
|
"svelte-github-corner": "^0.1.0",
|
|
28
|
-
"svelte-preprocess": "^4.10.
|
|
29
|
-
"svelte-toc": "^0.2.
|
|
30
|
-
"svelte2tsx": "^0.
|
|
28
|
+
"svelte-preprocess": "^4.10.3",
|
|
29
|
+
"svelte-toc": "^0.2.5",
|
|
30
|
+
"svelte2tsx": "^0.5.3",
|
|
31
31
|
"tslib": "^2.3.1",
|
|
32
32
|
"typescript": "^4.5.5",
|
|
33
|
-
"vite": "^2.
|
|
33
|
+
"vite": "^2.8.2"
|
|
34
34
|
},
|
|
35
35
|
"keywords": [
|
|
36
36
|
"svelte",
|
package/readme.md
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
[](https://app.netlify.com/sites/svelte-multiselect/deploys)
|
|
9
9
|
[](https://npmjs.com/package/svelte-multiselect)
|
|
10
10
|
[](https://results.pre-commit.ci/latest/github/janosh/svelte-multiselect/main)
|
|
11
|
+

|
|
11
12
|
|
|
12
13
|
</h4>
|
|
13
14
|
|
|
@@ -21,7 +22,7 @@
|
|
|
21
22
|
|
|
22
23
|
<slot />
|
|
23
24
|
|
|
24
|
-
## Key
|
|
25
|
+
## Key features
|
|
25
26
|
|
|
26
27
|
- **Single / multiple select:** pass `maxSelect={1}` prop to only allow one selection
|
|
27
28
|
- **Dropdowns:** scrollable lists for large numbers of options
|
|
@@ -87,23 +88,39 @@ Full list of props/bindable variables for this component:
|
|
|
87
88
|
<div class="table">
|
|
88
89
|
|
|
89
90
|
<!-- prettier-ignore -->
|
|
90
|
-
| name | default
|
|
91
|
-
| :--------------- |
|
|
92
|
-
| `options` | required prop
|
|
93
|
-
| `activeOption` | `null`
|
|
94
|
-
| `maxSelect` | `null`
|
|
95
|
-
| `
|
|
96
|
-
| `
|
|
97
|
-
| `
|
|
98
|
-
| `
|
|
99
|
-
| `
|
|
100
|
-
| `
|
|
101
|
-
| `
|
|
102
|
-
| `name` | `
|
|
103
|
-
| `id` | `undefined` | Applied to the top-level `<div>` e.g. for `document.getElementById()`. |
|
|
91
|
+
| name | default | description |
|
|
92
|
+
| :--------------- | :------------ | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
93
|
+
| `options` | required prop | Array of strings/numbers or `Option` objects that will be listed in the dropdown. See `src/lib/index.ts` for admissible fields. The `label` is the only mandatory one. It must also be unique. |
|
|
94
|
+
| `activeOption` | `null` | Currently active option, i.e. the one the user currently hovers or navigated to with arrow keys. |
|
|
95
|
+
| `maxSelect` | `null` | Positive integer to limit the number of options users can pick. `null` means no limit. |
|
|
96
|
+
| `selected` | `[]` | Array of currently/pre-selected options when binding/passing as props respectively. |
|
|
97
|
+
| `selectedLabels` | `[]` | Labels of currently selected options. |
|
|
98
|
+
| `selectedValues` | `[]` | Values of currently selected options. |
|
|
99
|
+
| `readonly` | `false` | Disable the component. It will still be rendered but users won't be able to interact with it. |
|
|
100
|
+
| `placeholder` | `undefined` | String shown in the text input when no option is selected. |
|
|
101
|
+
| `input` | `undefined` | Handle to the `<input>` DOM node. |
|
|
102
|
+
| `id` | `undefined` | Applied to the `<input>` element for associating HTML form `<label>`s with this component for accessibility. Also, clicking a `<label>` with same `for` attribute as `id` will focus this component. |
|
|
103
|
+
| `name` | `id` | Applied to the `<input>` element. If not provided, will be set to the value of `id`. Sets the key of this field in a submitted form data object. Not useful at the moment since the value is stored in Svelte state, not on the `<input>`. |
|
|
104
104
|
|
|
105
105
|
</div>
|
|
106
106
|
|
|
107
|
+
## Exposed methods
|
|
108
|
+
|
|
109
|
+
1. `filterFunc = (op: Option, searchText: string) => boolean`: Determine what options are shown when user enters search string to filter dropdown list. Defaults to:
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
filterFunc = (op: Option, searchText: string) => {
|
|
113
|
+
if (!searchText) return true
|
|
114
|
+
return `${op.label}`.toLowerCase().includes(searchText.toLowerCase())
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
2. `maxSelectMsg = (current: number, max: number) => string`: Inform the user how many of the maximum allowed options they have currently selected. Return empty string to disable, i.e. `() => ''`. Is automatically disabled when `maxSelect === null`. Defaults to:
|
|
119
|
+
|
|
120
|
+
```ts
|
|
121
|
+
maxSelectMsg = (current: number, max: number) => `${current}/${max}`
|
|
122
|
+
```
|
|
123
|
+
|
|
107
124
|
## Slots
|
|
108
125
|
|
|
109
126
|
`MultiSelect.svelte` accepts two named slots
|
|
@@ -193,27 +210,36 @@ There are 3 ways to style this component. To understand which options do what, i
|
|
|
193
210
|
|
|
194
211
|
If you only want to make small adjustments, you can pass the following CSS variables directly to the component as props or define them in a `:global()` CSS context.
|
|
195
212
|
|
|
196
|
-
- `div.multiselect
|
|
213
|
+
- `div.multiselect`
|
|
197
214
|
- `border: var(--sms-border, 1pt solid lightgray)`: Change this to e.g. to `1px solid red` to indicate this form field is in an invalid state.
|
|
198
|
-
- `border-radius: var(--sms-border-radius, 5pt)
|
|
199
|
-
- `background: var(--sms-input-bg)
|
|
200
|
-
- `height: var(--sms-input-height, 2em)
|
|
201
|
-
|
|
215
|
+
- `border-radius: var(--sms-border-radius, 5pt)`
|
|
216
|
+
- `background: var(--sms-input-bg)`
|
|
217
|
+
- `height: var(--sms-input-height, 2em)`
|
|
218
|
+
- `div.multiselect.open`
|
|
219
|
+
- `z-index: var(--sms-open-z-index, 4)`: Increase this if needed to ensure the dropdown list is displayed atop all other page elements.
|
|
220
|
+
- `div.multiselect:focus-within`
|
|
221
|
+
- `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`.
|
|
222
|
+
- `div.multiselect.readonly`
|
|
202
223
|
- `background: var(--sms-readonly-bg, lightgray)`: Background when in readonly state.
|
|
203
|
-
- `div.multiselect input`
|
|
224
|
+
- `div.multiselect > ul.selected > li > input`
|
|
204
225
|
- `color: var(--sms-text-color, inherit)`: Input text color.
|
|
205
|
-
- `ul.selected > li
|
|
226
|
+
- `div.multiselect > ul.selected > li`
|
|
206
227
|
- `background: var(--sms-selected-bg, var(--sms-active-color, cornflowerblue))`: Background of selected options.
|
|
207
|
-
- `
|
|
228
|
+
- `height: var(--sms-selected-li-height)`: Height of selected options.
|
|
229
|
+
- `ul.selected > li button:hover, button.remove-all:hover, button:focus`
|
|
208
230
|
- `color: var(--sms-remove-x-hover-focus-color, lightskyblue)`: Color of the cross-icon buttons for removing all or individual selected options when in `:focus` or `:hover` state.
|
|
209
|
-
- `ul.options`
|
|
210
|
-
- `background: var(--sms-options-bg, white)`: Background of
|
|
211
|
-
- `
|
|
231
|
+
- `div.multiselect > ul.options`
|
|
232
|
+
- `background: var(--sms-options-bg, white)`: Background of dropdown list.
|
|
233
|
+
- `overscroll-behavior: var(--sms-options-overscroll, none)`: Whether scroll events bubble to parent elements when reaching the top/bottom of the options dropdown. See [MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/overscroll-behavior).
|
|
234
|
+
- `div.multiselect > ul.options > li.selected`
|
|
235
|
+
- `border-left: var(--sms-li-selected-border-left, 3pt solid var(--sms-selected-color, green))`
|
|
212
236
|
- `background: var(--sms-li-selected-bg, inherit)`: Background of selected list items in options pane.
|
|
213
237
|
- `color: var(--sms-li-selected-color, inherit)`: Text color of selected list items in options pane.
|
|
214
|
-
- `ul.options > li.
|
|
238
|
+
- `div.multiselect > ul.options > li:not(.selected):hover`
|
|
239
|
+
- `border-left: var(--sms-li-not-selected-hover-border-left, 3pt solid var(--sms-active-color, cornflowerblue))`
|
|
240
|
+
- `div.multiselect > ul.options > li.active`
|
|
215
241
|
- `background: var(--sms-li-active-bg, var(--sms-active-color, cornflowerblue))`: Background of active (currently with arrow keys highlighted) list item.
|
|
216
|
-
- `ul.options > li.disabled`
|
|
242
|
+
- `div.multiselect > ul.options > li.disabled`
|
|
217
243
|
- `background: var(--sms-li-disabled-bg, #f5f5f6)`: Background of disabled options in the dropdown list.
|
|
218
244
|
- `color: var(--sms-li-disabled-text, #b8b8b8)`: Text color of disabled option in the dropdown list.
|
|
219
245
|
|
|
@@ -253,40 +279,47 @@ This simplified version of the DOM structure of this component shows where these
|
|
|
253
279
|
You can alternatively style every part of this component with more fine-grained control by using the following `:global()` CSS selectors. `ul.selected` is the list of currently selected options rendered inside the component's input whereas `ul.options` is the list of available options that slides out when the component has focus.
|
|
254
280
|
|
|
255
281
|
```css
|
|
256
|
-
:global(.multiselect) {
|
|
282
|
+
:global(div.multiselect) {
|
|
257
283
|
/* top-level wrapper div */
|
|
258
284
|
}
|
|
259
|
-
:global(.multiselect
|
|
260
|
-
/*
|
|
285
|
+
:global(div.multiselect.open) {
|
|
286
|
+
/* top-level wrapper div when dropdown open */
|
|
287
|
+
}
|
|
288
|
+
:global(div.multiselect.readonly) {
|
|
289
|
+
/* top-level wrapper div when in readonly state */
|
|
261
290
|
}
|
|
262
|
-
:global(.multiselect ul.selected
|
|
263
|
-
|
|
291
|
+
:global(div.multiselect > ul.selected) {
|
|
292
|
+
/* selected list */
|
|
293
|
+
}
|
|
294
|
+
:global(div.multiselect > ul.selected > li) {
|
|
295
|
+
/* selected list items */
|
|
296
|
+
}
|
|
297
|
+
:global(div.multiselect button) {
|
|
298
|
+
/* target all buttons in this component */
|
|
299
|
+
}
|
|
300
|
+
:global(div.multiselect > ul.selected > li button, button.remove-all) {
|
|
264
301
|
/* buttons to remove a single or all selected options at once */
|
|
265
302
|
}
|
|
266
|
-
:global(.multiselect ul.
|
|
303
|
+
:global(div.multiselect > ul.selected > li > input) {
|
|
304
|
+
/* input inside the top-level wrapper div */
|
|
305
|
+
}
|
|
306
|
+
:global(div.multiselect > ul.options) {
|
|
267
307
|
/* dropdown options */
|
|
268
308
|
}
|
|
269
|
-
:global(.multiselect ul.options li) {
|
|
270
|
-
/* dropdown list
|
|
309
|
+
:global(div.multiselect > ul.options > li) {
|
|
310
|
+
/* dropdown list items */
|
|
271
311
|
}
|
|
272
|
-
:global(.multiselect ul.options li.selected) {
|
|
312
|
+
:global(div.multiselect > ul.options > li.selected) {
|
|
273
313
|
/* selected options in the dropdown list */
|
|
274
314
|
}
|
|
275
|
-
:global(.multiselect ul.options li:not(.selected):hover) {
|
|
315
|
+
:global(div.multiselect > ul.options > li:not(.selected):hover) {
|
|
276
316
|
/* unselected but hovered options in the dropdown list */
|
|
277
317
|
}
|
|
278
|
-
:global(.multiselect ul.options li.
|
|
279
|
-
/* selected and hovered options in the dropdown list */
|
|
280
|
-
/* probably not necessary to style this state in most cases */
|
|
281
|
-
}
|
|
282
|
-
:global(.multiselect ul.options li.active) {
|
|
318
|
+
:global(div.multiselect > ul.options > li.active) {
|
|
283
319
|
/* active means item was navigated to with up/down arrow keys */
|
|
284
320
|
/* ready to be selected by pressing enter */
|
|
285
321
|
}
|
|
286
|
-
:global(.multiselect ul.options li.
|
|
287
|
-
/* both active and already selected, pressing enter now will deselect the item */
|
|
288
|
-
}
|
|
289
|
-
:global(.multiselect ul.options li.disabled) {
|
|
322
|
+
:global(div.multiselect > ul.options > li.disabled) {
|
|
290
323
|
/* options with disabled key set to true (see props above) */
|
|
291
324
|
}
|
|
292
325
|
```
|