Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new prop disabledOptions #9

Merged
merged 7 commits into from
Oct 11, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.0.1
hooks:
- id: end-of-file-fixer
- id: check-case-conflict
- id: check-symlinks
- id: check-yaml
- id: destroyed-symlinks
- id: check-symlinks
- id: check-case-conflict
- id: trailing-whitespace
- id: mixed-line-ending
- id: double-quote-string-fixer
- id: end-of-file-fixer
- id: mixed-line-ending
- id: trailing-whitespace

- repo: https://github.com/pre-commit/mirrors-prettier
rev: v2.4.1
Expand Down
23 changes: 13 additions & 10 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,16 +75,17 @@ Full list of props/bindable variables for this component:

<div class="table">

| name | default | description |
| :------------ | :---------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `options` | [required] | Array of strings (or integers) that will be listed in the dropdown selection. |
| `maxSelect` | `null` | `null` or positive integer to allow users to select as many as they like or a maximum number of options, respectively. |
| `selected` | `[]` (or `''` if `maxSelect === 1`) | Array of currently/pre-selected options when binding/passing as props respectively. |
| `readonly` | `false` | Disables the input. User won't be able to interact with it. |
| `placeholder` | `''` | String shown when no option is selected. |
| `required` | `false` | Prevents submission in an HTML form when true. |
| `input` | `undefined` | Handle to the DOM node storing the currently selected options in JSON format as its `value` attribute. |
| `name` | `''` | Used as reference for associating HTML form labels with this component as well as for the `input` `id`. That is, the same DOM node `input` bindable through `<MultiSelect bind:input />` is also retrievable via `document.getElementByID(name)` e.g. for use in a JS file outside a Svelte component. |
| name | default | description |
| :---------------- | :---------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `options` | [required] | Array of strings (or numbers) that will be listed in the dropdown selection. |
| `maxSelect` | `null` | `null` or positive integer to allow users to select as many as they like or a maximum number of options, respectively. |
| `selected` | `[]` (or `''` if `maxSelect === 1`) | Array of currently/pre-selected options when binding/passing as props respectively. |
| `readonly` | `false` | Disables the input. User won't be able to interact with it. |
| `placeholder` | `''` | String shown when no option is selected. |
| `disabledOptions` | `[]` | Array of strings (or numbers) that will be disabled in the dropdown selection. |
| `required` | `false` | Prevents submission in an HTML form when true. |
| `input` | `undefined` | Handle to the DOM node storing the currently selected options in JSON format as its `value` attribute. |
| `name` | `''` | Used as `name` reference for associating HTML form `<label>`s with this component as well as for the `<input>`'s `id`. That is, the same DOM node bindable through `<MultiSelect bind:input />` is also retrievable via `document.getElementByID(name)` e.g. for use in a JS file outside a Svelte component. |

</div>
janosh marked this conversation as resolved.
Show resolved Hide resolved

Expand Down Expand Up @@ -141,6 +142,8 @@ The first, if you only want to make small adjustments, allows you to pass the fo
- `background: var(--sms-li-selected-bg, inherit)`: Background of selected list items in options pane.
- `color: var(--sms-li-selected-color, inherit)`: Text color of selected list items in options pane.
- `background: var(--sms-li-active-bg, var(--sms-active-color, cornflowerblue))`: Background of active (currently with arrow keys highlighted) list item.
- `background: var(--sms-li-disabled-bg, #f5f5f6)`: Background of disabled options in the dropdown list.
- `color: var(--sms-li-disabled-text, #b8b8b8)`: Text color of disabled option in the dropdown list.

For example, to change the background color of the options dropdown:

Expand Down
2 changes: 2 additions & 0 deletions src/components/Example.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
let selectedML = `PyTorch`

const placeholder = `Take your pick...`
const disabledOptions = [`Torch`, `CNTK`]
</script>

<section>
Expand Down Expand Up @@ -35,6 +36,7 @@
options={mlFrameworks}
bind:selected={selectedML}
{placeholder}
{disabledOptions}
--sms-active-color="var(--blue)"
--sms-options-bg="black" />
</div>
Expand Down
31 changes: 27 additions & 4 deletions src/lib/MultiSelect.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
export let maxSelect: number | null = null // null means any number of options are selectable
export let readonly = false
export let placeholder = ``
export let options: string[]
export let options: (string | number)[]
export let disabledOptions: (string | number)[] = []
export let input: HTMLInputElement | null = null
export let noOptionsMsg = `No matching options`

Expand All @@ -31,6 +32,12 @@

if (!(options?.length > 0)) console.error(`MultiSelect missing options`)

$: invalidDisabledOptions = disabledOptions.filter((opt) => !options.includes(opt))

$: if (invalidDisabledOptions.length > 0) {
console.error(`Some disabledOptions do not appear in the options list!`)
}

const dispatch = createEventDispatcher()
let activeOption: string, searchText: string
let showOptions = false
Expand Down Expand Up @@ -85,6 +92,8 @@
searchText = ``
} else if (event.key === `Enter`) {
if (activeOption) {
if (isDisabled(activeOption)) return

selected.includes(activeOption) ? remove(activeOption) : add(activeOption)
searchText = ``
} // no active option means the options are closed in which case enter means open
Expand Down Expand Up @@ -114,6 +123,8 @@
searchText = ``
}

const isDisabled = (option: string) => disabledOptions.includes(option)

$: isSelected = (option: string) => {
if (!(selected?.length > 0)) return false // nothing is selected if `selected` is the empty array or string
if (single) return selected === option
Expand Down Expand Up @@ -183,10 +194,14 @@
{#each filteredOptions as option}
<li
on:mouseup|preventDefault|stopPropagation
on:mousedown|preventDefault|stopPropagation={() =>
isSelected(option) ? remove(option) : add(option)}
on:mousedown|preventDefault|stopPropagation={() => {
if (isDisabled(option)) return

isSelected(option) ? remove(option) : add(option)
}}
class:selected={isSelected(option)}
class:active={activeOption === option}
class:disabled={isDisabled(option)}
class={liOptionClass}>
{option}
</li>
Expand Down Expand Up @@ -271,7 +286,6 @@
padding: 0;
top: 100%;
width: 100%;
cursor: pointer;
position: absolute;
border-radius: 1ex;
overflow: auto;
Expand All @@ -282,6 +296,7 @@
}
ul.options li {
padding: 3pt 2ex;
cursor: pointer;
}
ul.options li.selected {
border-left: var(
Expand All @@ -301,4 +316,12 @@
ul.options li.active {
background: var(--sms-li-active-bg, var(--sms-active-color, cornflowerblue));
}
ul.options li.disabled {
background: var(--sms-li-disabled-bg, #f5f5f6);
color: var(--sms-li-disabled-text, #b8b8b8);
cursor: not-allowed;
}
ul.options li.disabled:hover {
border-left: unset;
}
</style>