feat: support item.disabled key for Dropdown, MultiSelect, ComboBox (#1328)

Closes #1326

* feat: support item.disabled key for `Dropdown`, `MultiSelect`, `ComboBox`

* Run "yarn build:docs"

* test: assert disabled property

* docs: add "Disabled items" examples
This commit is contained in:
metonym 2022-06-02 17:56:30 -07:00 committed by GitHub
commit f25a10c9c4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 150 additions and 19 deletions

View file

@ -646,6 +646,7 @@ export type ComboBoxItemId = any;
export interface ComboBoxItem {
id: ComboBoxItemId;
text: string;
disabled?: boolean;
}
```
@ -1140,6 +1141,7 @@ export type DropdownItemText = string;
export interface DropdownItem {
id: DropdownItemId;
text: DropdownItemText;
disabled?: boolean;
}
```
@ -2085,6 +2087,7 @@ None.
| :---------- | :------- | :--------------- | :------- | -------------------- | ------------------ | --------------------------------------------- |
| active | No | <code>let</code> | No | <code>boolean</code> | <code>false</code> | Set to `true` to enable the active state |
| highlighted | No | <code>let</code> | No | <code>boolean</code> | <code>false</code> | Set to `true` to enable the highlighted state |
| disabled | No | <code>let</code> | No | <code>boolean</code> | <code>false</code> | Set to `true` to disable the menu item |
### Slots
@ -2327,6 +2330,7 @@ export type MultiSelectItemText = string;
export interface MultiSelectItem {
id: MultiSelectItemId;
text: MultiSelectItemText;
disabled?: boolean;
}
```

View file

@ -1769,9 +1769,9 @@
"ts": "type ComboBoxItemId = any"
},
{
"type": "{ id: ComboBoxItemId; text: string; }",
"type": "{ id: ComboBoxItemId; text: string; disabled?: boolean; }",
"name": "ComboBoxItem",
"ts": "interface ComboBoxItem { id: ComboBoxItemId; text: string; }"
"ts": "interface ComboBoxItem { id: ComboBoxItemId; text: string; disabled?: boolean; }"
}
],
"rest_props": { "type": "Element", "name": "input" }
@ -3493,9 +3493,9 @@
"ts": "type DropdownItemText = string"
},
{
"type": "{ id: DropdownItemId; text: DropdownItemText; }",
"type": "{ id: DropdownItemId; text: DropdownItemText; disabled?: boolean; }",
"name": "DropdownItem",
"ts": "interface DropdownItem { id: DropdownItemId; text: DropdownItemText; }"
"ts": "interface DropdownItem { id: DropdownItemId; text: DropdownItemText; disabled?: boolean; }"
}
],
"rest_props": { "type": "Element", "name": "div" }
@ -6063,6 +6063,18 @@
"isRequired": false,
"constant": false,
"reactive": false
},
{
"name": "disabled",
"kind": "let",
"description": "Set to `true` to disable the menu item",
"type": "boolean",
"value": "false",
"isFunction": false,
"isFunctionDeclaration": false,
"isRequired": false,
"constant": false,
"reactive": false
}
],
"moduleExports": [],
@ -7296,9 +7308,9 @@
"ts": "type MultiSelectItemText = string"
},
{
"type": "{ id: MultiSelectItemId; text: MultiSelectItemText; }",
"type": "{ id: MultiSelectItemId; text: MultiSelectItemText; disabled?: boolean; }",
"name": "MultiSelectItem",
"ts": "interface MultiSelectItem { id: MultiSelectItemId; text: MultiSelectItemText; }"
"ts": "interface MultiSelectItem { id: MultiSelectItemId; text: MultiSelectItemText; disabled?: boolean; }"
}
],
"rest_props": { "type": "Element", "name": "input" }

View file

@ -112,11 +112,25 @@ items={[
{id: "2", text: "Fax"}
]} />
### Disabled
### Disabled state
<ComboBox disabled titleText="Contact" placeholder="Select contact method"
items={[
{id: "0", text: "Slack"},
{id: "1", text: "Email"},
{id: "2", text: "Fax"}
]} />
]} />
### Disabled items
Use the `disabled` property in the `items` prop to disable specific items.
<ComboBox
titleText="Contact"
placeholder="Select contact method"
items={[
{ id: "0", text: "Slack" },
{ id: "1", text: "Email", disabled: true },
{ id: "2", text: "Fax" },
]}
/>

View file

@ -95,6 +95,20 @@ Set `direction` to `"top"` for the dropdown menu to appear above the input.
{id: "1", text: "Email"},
{id: "2", text: "Fax"}]}" />
### Disabled items
Use the `disabled` property in the `items` prop to disable specific items.
<Dropdown
selectedId="0"
titleText="Contact"
items={[
{ id: "0", text: "Slack" },
{ id: "1", text: "Email", disabled: true },
{ id: "2", text: "Fax" },
]}
/>
### Skeleton
<DropdownSkeleton />

View file

@ -145,4 +145,18 @@ Set `direction` to `"top"` for the dropdown menu to appear above the input.
items="{[{id: "0", text: "Slack"},
{id: "1", text: "Email"},
{id: "2", text: "Fax"}]}"
/>
/>
### Disabled items
Use the `disabled` property in the `items` prop to disable specific items.
<MultiSelect
titleText="Contact"
label="Select contact methods..."
items={[
{ id: "0", text: "Slack" },
{ id: "1", text: "Email", disabled: true },
{ id: "2", text: "Fax" },
]}
/>

View file

@ -1,7 +1,7 @@
<script>
/**
* @typedef {any} ComboBoxItemId
* @typedef {{ id: ComboBoxItemId; text: string; }} ComboBoxItem
* @typedef {{ id: ComboBoxItemId; text: string; disabled?: boolean; }} ComboBoxItem
* @event {{ selectedId: ComboBoxItemId; selectedItem: ComboBoxItem }} select
* @slot {{ item: ComboBoxItem; index: number }}
*/
@ -133,6 +133,20 @@
} else if (index >= _items.length) {
index = 0;
}
let disabled = items[index].disabled;
while (disabled) {
index = index + dir;
if (index < 0) {
index = items.length - 1;
} else if (index >= items.length) {
index = 0;
}
disabled = items[index].disabled;
}
highlightedIndex = index;
}
@ -360,7 +374,12 @@
id="{item.id}"
active="{selectedId === item.id}"
highlighted="{highlightedIndex === i}"
on:click="{() => {
disabled="{item.disabled}"
on:click="{(e) => {
if (item.disabled) {
e.stopPropagation();
return;
}
selectedId = item.id;
open = false;
@ -369,6 +388,7 @@
}
}}"
on:mouseenter="{() => {
if (item.disabled) return;
highlightedIndex = i;
}}"
>

View file

@ -2,7 +2,7 @@
/**
* @typedef {any} DropdownItemId
* @typedef {string} DropdownItemText
* @typedef {{ id: DropdownItemId; text: DropdownItemText; }} DropdownItem
* @typedef {{ id: DropdownItemId; text: DropdownItemText; disabled?: boolean; }} DropdownItem
* @event {{ selectedId: DropdownItemId, selectedItem: DropdownItem }} select
* @slot {{ item: DropdownItem; index: number; }}
*/
@ -121,6 +121,20 @@
index = 0;
}
let disabled = items[index].disabled;
while (disabled) {
index = index + dir;
if (index < 0) {
index = items.length - 1;
} else if (index >= items.length) {
index = 0;
}
disabled = items[index].disabled;
}
highlightedIndex = index;
}
@ -248,11 +262,17 @@
id="{item.id}"
active="{selectedId === item.id}"
highlighted="{highlightedIndex === i || selectedId === item.id}"
on:click="{() => {
disabled="{item.disabled}"
on:click="{(e) => {
if (item.disabled) {
e.stopPropagation();
return;
}
selectedId = item.id;
ref.focus();
}}"
on:mouseenter="{() => {
if (item.disabled) return;
highlightedIndex = i;
}}"
>

View file

@ -5,6 +5,9 @@
/** Set to `true` to enable the highlighted state */
export let highlighted = false;
/** Set to `true` to disable the menu item */
export let disabled = false;
let ref = null;
$: isTruncated = ref?.offsetWidth < ref?.scrollWidth;
@ -17,6 +20,7 @@
class:bx--list-box__menu-item--active="{active}"
class:bx--list-box__menu-item--highlighted="{highlighted}"
aria-selected="{active}"
disabled="{disabled ? true : undefined}"
{...$$restProps}
on:click
on:mouseenter

View file

@ -2,7 +2,7 @@
/**
* @typedef {any} MultiSelectItemId
* @typedef {string} MultiSelectItemText
* @typedef {{ id: MultiSelectItemId; text: MultiSelectItemText; }} MultiSelectItem
* @typedef {{ id: MultiSelectItemId; text: MultiSelectItemText; disabled?: boolean; }} MultiSelectItem
* @event {{ selectedIds: MultiSelectItemId[]; selected: MultiSelectItem[]; unselected: MultiSelectItem[]; }} select
* @event {null} clear
* @event {FocusEvent | CustomEvent<FocusEvent>} blur
@ -210,6 +210,20 @@
index = 0;
}
let disabled = items[index].disabled;
while (disabled) {
index = index + direction;
if (index < 0) {
index = items.length - 1;
} else if (index >= items.length) {
index = 0;
}
disabled = items[index].disabled;
}
highlightedIndex = index;
}
@ -481,13 +495,19 @@
aria-selected="{item.checked}"
active="{item.checked}"
highlighted="{highlightedIndex === i}"
on:click="{() => {
disabled="{item.disabled}"
on:click="{(e) => {
if (item.disabled) {
e.stopPropagation();
return;
}
sortedItems = sortedItems.map((_) =>
_.id === item.id ? { ..._, checked: !_.checked } : _
);
fieldRef.focus();
}}"
on:mouseenter="{() => {
if (item.disabled) return;
highlightedIndex = i;
}}"
>
@ -499,7 +519,7 @@
tabindex="-1"
id="checkbox-{item.id}"
checked="{item.checked}"
disabled="{disabled}"
disabled="{item.disabled}"
on:blur="{() => {
if (i === filteredItems.length - 1) open = false;
}}"

View file

@ -5,7 +5,7 @@
const items: ComboBoxItem[] = [
{ id: 0, text: "Slack" },
{ id: "1", text: "Email" },
{ id: "2", text: "Fax" },
{ id: "2", text: "Fax", disabled: true },
];
let ref: ComboBox;

View file

@ -9,7 +9,7 @@
items="{[
{ id: 0, text: 'Slack' },
{ id: '1', text: 'Email' },
{ id: '2', text: 'Fax' },
{ id: '2', text: 'Fax', disabled: true },
]}"
on:select="{(e) => {
console.log(e.detail.selectedId);

View file

@ -10,7 +10,7 @@
items="{[
{ id: 0, text: 'Slack' },
{ id: '1', text: 'Email' },
{ id: '2', text: 'Fax' },
{ id: '2', text: 'Fax', disabled: true },
]}"
on:select="{(e) => {
console.log(e.detail.selectedIds);

View file

@ -6,6 +6,7 @@ export type ComboBoxItemId = any;
export interface ComboBoxItem {
id: ComboBoxItemId;
text: string;
disabled?: boolean;
}
export interface ComboBoxProps

View file

@ -8,6 +8,7 @@ export type DropdownItemText = string;
export interface DropdownItem {
id: DropdownItemId;
text: DropdownItemText;
disabled?: boolean;
}
export interface DropdownProps

View file

@ -14,6 +14,12 @@ export interface ListBoxMenuItemProps
* @default false
*/
highlighted?: boolean;
/**
* Set to `true` to disable the menu item
* @default false
*/
disabled?: boolean;
}
export default class ListBoxMenuItem extends SvelteComponentTyped<

View file

@ -8,6 +8,7 @@ export type MultiSelectItemText = string;
export interface MultiSelectItem {
id: MultiSelectItemId;
text: MultiSelectItemText;
disabled?: boolean;
}
export interface MultiSelectProps