mirror of
https://github.com/carbon-design-system/carbon-components-svelte.git
synced 2025-09-14 18:01:06 +00:00
feat(ComboBox): selectedIndex -> selectedId (#1016)
* feat(breaking): selectedIndex -> selectedId in ComboBox * docs: update ComboBox
This commit is contained in:
parent
e11a893bee
commit
cde8a79fa8
9 changed files with 91 additions and 102 deletions
|
@ -656,31 +656,31 @@ export interface ComboBoxItem {
|
|||
|
||||
### Props
|
||||
|
||||
| Prop name | Kind | Reactive | Type | Default value | Description |
|
||||
| :--------------- | :-------------------- | :------- | :---------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
|
||||
| listRef | <code>let</code> | Yes | <code>null | HTMLDivElement</code> | <code>null</code> | Obtain a reference to the list HTML element |
|
||||
| ref | <code>let</code> | Yes | <code>null | HTMLInputElement</code> | <code>null</code> | Obtain a reference to the input HTML element |
|
||||
| open | <code>let</code> | Yes | <code>boolean</code> | <code>false</code> | Set to `true` to open the combobox menu dropdown |
|
||||
| value | <code>let</code> | Yes | <code>string</code> | <code>""</code> | Specify the selected combobox value |
|
||||
| selectedIndex | <code>let</code> | Yes | <code>number</code> | <code>-1</code> | Set the selected item by value index |
|
||||
| items | <code>let</code> | No | <code>ComboBoxItem[]</code> | <code>[]</code> | Set the combobox items |
|
||||
| itemToString | <code>let</code> | No | <code>(item: ComboBoxItem) => string</code> | <code>(item) => item.text || item.id</code> | Override the display of a combobox item |
|
||||
| direction | <code>let</code> | No | <code>"bottom" | "top"</code> | <code>"bottom"</code> | Specify the direction of the combobox dropdown menu |
|
||||
| size | <code>let</code> | No | <code>"sm" | "xl"</code> | -- | Set the size of the combobox |
|
||||
| disabled | <code>let</code> | No | <code>boolean</code> | <code>false</code> | Set to `true` to disable the combobox |
|
||||
| titleText | <code>let</code> | No | <code>string</code> | <code>""</code> | Specify the title text of the combobox |
|
||||
| placeholder | <code>let</code> | No | <code>string</code> | <code>""</code> | Specify the placeholder text |
|
||||
| helperText | <code>let</code> | No | <code>string</code> | <code>""</code> | Specify the helper text |
|
||||
| invalidText | <code>let</code> | No | <code>string</code> | <code>""</code> | Specify the invalid state text |
|
||||
| invalid | <code>let</code> | No | <code>boolean</code> | <code>false</code> | Set to `true` to indicate an invalid state |
|
||||
| warn | <code>let</code> | No | <code>boolean</code> | <code>false</code> | Set to `true` to indicate an warning state |
|
||||
| warnText | <code>let</code> | No | <code>string</code> | <code>""</code> | Specify the warning state text |
|
||||
| light | <code>let</code> | No | <code>boolean</code> | <code>false</code> | Set to `true` to enable the light variant |
|
||||
| shouldFilterItem | <code>let</code> | No | <code>(item: ComboBoxItem, value: string) => boolean</code> | <code>() => true</code> | Determine if an item should be filtered given the current combobox value |
|
||||
| translateWithId | <code>let</code> | No | <code>(id: any) => string</code> | -- | Override the default translation ids |
|
||||
| id | <code>let</code> | No | <code>string</code> | <code>"ccs-" + Math.random().toString(36)</code> | Set an id for the list box component |
|
||||
| name | <code>let</code> | No | <code>string</code> | -- | Specify a name attribute for the input |
|
||||
| clear | <code>function</code> | No | <code>(options?: { focus?: boolean; }) => void</code> | <code>() => { prevSelectedIndex = undefined; selectedIndex = -1; highlightedIndex = -1; highlightedId = undefined; selectedId = undefined; selectedItem = undefined; open = false; inputValue = ""; if (options?.focus !== false) ref?.focus(); }</code> | Clear the combo box programmatically |
|
||||
| Prop name | Kind | Reactive | Type | Default value | Description |
|
||||
| :--------------- | :-------------------- | :------- | :---------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
|
||||
| listRef | <code>let</code> | Yes | <code>null | HTMLDivElement</code> | <code>null</code> | Obtain a reference to the list HTML element |
|
||||
| ref | <code>let</code> | Yes | <code>null | HTMLInputElement</code> | <code>null</code> | Obtain a reference to the input HTML element |
|
||||
| open | <code>let</code> | Yes | <code>boolean</code> | <code>false</code> | Set to `true` to open the combobox menu dropdown |
|
||||
| value | <code>let</code> | Yes | <code>string</code> | <code>""</code> | Specify the selected combobox value |
|
||||
| selectedId | <code>let</code> | Yes | <code>string</code> | -- | Set the selected item by value id |
|
||||
| items | <code>let</code> | No | <code>ComboBoxItem[]</code> | <code>[]</code> | Set the combobox items |
|
||||
| itemToString | <code>let</code> | No | <code>(item: ComboBoxItem) => string</code> | <code>(item) => item.text || item.id</code> | Override the display of a combobox item |
|
||||
| direction | <code>let</code> | No | <code>"bottom" | "top"</code> | <code>"bottom"</code> | Specify the direction of the combobox dropdown menu |
|
||||
| size | <code>let</code> | No | <code>"sm" | "xl"</code> | -- | Set the size of the combobox |
|
||||
| disabled | <code>let</code> | No | <code>boolean</code> | <code>false</code> | Set to `true` to disable the combobox |
|
||||
| titleText | <code>let</code> | No | <code>string</code> | <code>""</code> | Specify the title text of the combobox |
|
||||
| placeholder | <code>let</code> | No | <code>string</code> | <code>""</code> | Specify the placeholder text |
|
||||
| helperText | <code>let</code> | No | <code>string</code> | <code>""</code> | Specify the helper text |
|
||||
| invalidText | <code>let</code> | No | <code>string</code> | <code>""</code> | Specify the invalid state text |
|
||||
| invalid | <code>let</code> | No | <code>boolean</code> | <code>false</code> | Set to `true` to indicate an invalid state |
|
||||
| warn | <code>let</code> | No | <code>boolean</code> | <code>false</code> | Set to `true` to indicate an warning state |
|
||||
| warnText | <code>let</code> | No | <code>string</code> | <code>""</code> | Specify the warning state text |
|
||||
| light | <code>let</code> | No | <code>boolean</code> | <code>false</code> | Set to `true` to enable the light variant |
|
||||
| shouldFilterItem | <code>let</code> | No | <code>(item: ComboBoxItem, value: string) => boolean</code> | <code>() => true</code> | Determine if an item should be filtered given the current combobox value |
|
||||
| translateWithId | <code>let</code> | No | <code>(id: any) => string</code> | -- | Override the default translation ids |
|
||||
| id | <code>let</code> | No | <code>string</code> | <code>"ccs-" + Math.random().toString(36)</code> | Set an id for the list box component |
|
||||
| name | <code>let</code> | No | <code>string</code> | -- | Specify a name attribute for the input |
|
||||
| clear | <code>function</code> | No | <code>(options?: { focus?: boolean; }) => void</code> | <code>() => { prevSelectedId = null; highlightedIndex = -1; highlightedId = undefined; selectedId = undefined; selectedItem = undefined; open = false; inputValue = ""; if (options?.focus !== false) ref?.focus(); }</code> | Clear the combo box programmatically |
|
||||
|
||||
### Slots
|
||||
|
||||
|
@ -688,15 +688,15 @@ None.
|
|||
|
||||
### Events
|
||||
|
||||
| Event name | Type | Detail |
|
||||
| :--------- | :--------- | :------------------------------------------------------------------------------------- |
|
||||
| select | dispatched | <code>{ selectedId: string; selectedIndex: number; selectedItem: ComboBoxItem }</code> |
|
||||
| keydown | forwarded | -- |
|
||||
| keyup | forwarded | -- |
|
||||
| focus | forwarded | -- |
|
||||
| blur | forwarded | -- |
|
||||
| clear | forwarded | -- |
|
||||
| scroll | forwarded | -- |
|
||||
| Event name | Type | Detail |
|
||||
| :--------- | :--------- | :-------------------------------------------------------------- |
|
||||
| select | dispatched | <code>{ selectedId: string; selectedItem: ComboBoxItem }</code> |
|
||||
| keydown | forwarded | -- |
|
||||
| keyup | forwarded | -- |
|
||||
| focus | forwarded | -- |
|
||||
| blur | forwarded | -- |
|
||||
| clear | forwarded | -- |
|
||||
| scroll | forwarded | -- |
|
||||
|
||||
## `ComposedModal`
|
||||
|
||||
|
|
|
@ -1395,11 +1395,10 @@
|
|||
"reactive": false
|
||||
},
|
||||
{
|
||||
"name": "selectedIndex",
|
||||
"name": "selectedId",
|
||||
"kind": "let",
|
||||
"description": "Set the selected item by value index",
|
||||
"type": "number",
|
||||
"value": "-1",
|
||||
"description": "Set the selected item by value id",
|
||||
"type": "string",
|
||||
"isFunction": false,
|
||||
"isFunctionDeclaration": false,
|
||||
"constant": false,
|
||||
|
@ -1616,7 +1615,7 @@
|
|||
"kind": "function",
|
||||
"description": "Clear the combo box programmatically",
|
||||
"type": "(options?: { focus?: boolean; }) => void",
|
||||
"value": "() => { prevSelectedIndex = undefined; selectedIndex = -1; highlightedIndex = -1; highlightedId = undefined; selectedId = undefined; selectedItem = undefined; open = false; inputValue = \"\"; if (options?.focus !== false) ref?.focus(); }",
|
||||
"value": "() => { prevSelectedId = null; highlightedIndex = -1; highlightedId = undefined; selectedId = undefined; selectedItem = undefined; open = false; inputValue = \"\"; if (options?.focus !== false) ref?.focus(); }",
|
||||
"isFunction": true,
|
||||
"isFunctionDeclaration": true,
|
||||
"constant": false,
|
||||
|
@ -1628,7 +1627,7 @@
|
|||
{
|
||||
"type": "dispatched",
|
||||
"name": "select",
|
||||
"detail": "{ selectedId: string; selectedIndex: number; selectedItem: ComboBoxItem }"
|
||||
"detail": "{ selectedId: string; selectedItem: ComboBoxItem }"
|
||||
},
|
||||
{ "type": "forwarded", "name": "keydown", "element": "input" },
|
||||
{ "type": "forwarded", "name": "keyup", "element": "input" },
|
||||
|
|
|
@ -12,10 +12,10 @@ items={[
|
|||
{id: "2", text: "Fax"}
|
||||
]} />
|
||||
|
||||
### Selected index
|
||||
### Selected id
|
||||
|
||||
<ComboBox titleText="Contact" placeholder="Select contact method"
|
||||
selectedIndex={1}
|
||||
selectedId="1"
|
||||
items={[
|
||||
{id: "0", text: "Slack"},
|
||||
{id: "1", text: "Email"},
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<ComboBox
|
||||
titleText="Contact"
|
||||
placeholder="Select contact method"
|
||||
selectedIndex="{1}"
|
||||
selectedId="1"
|
||||
bind:this="{ref}"
|
||||
items="{[
|
||||
{ id: '0', text: 'Slack' },
|
||||
|
|
|
@ -7,17 +7,18 @@
|
|||
{ id: "2", text: "Fax" },
|
||||
];
|
||||
|
||||
let comboBox1_selectedIndex = -1;
|
||||
let comboBox2_selectedIndex = -1;
|
||||
let comboBox1_selectedId = undefined;
|
||||
let comboBox2_selectedId = undefined;
|
||||
|
||||
const formatSelected = (i) => (items[i] ? items[i].text : "N/A");
|
||||
const formatSelected = (id) =>
|
||||
items.find((item) => item.id === id)?.text ?? "N/A";
|
||||
|
||||
$: primary = formatSelected(comboBox1_selectedIndex);
|
||||
$: secondary = formatSelected(comboBox2_selectedIndex);
|
||||
$: primary = formatSelected(comboBox1_selectedId);
|
||||
$: secondary = formatSelected(comboBox2_selectedId);
|
||||
</script>
|
||||
|
||||
<ComboBox
|
||||
bind:selectedIndex="{comboBox1_selectedIndex}"
|
||||
bind:selectedId="{comboBox1_selectedId}"
|
||||
titleText="Primary contact"
|
||||
placeholder="Select primary contact method"
|
||||
items="{items}"
|
||||
|
@ -26,7 +27,7 @@
|
|||
<div>Primary: {primary}</div>
|
||||
|
||||
<ComboBox
|
||||
bind:selectedIndex="{comboBox2_selectedIndex}"
|
||||
bind:selectedId="{comboBox2_selectedId}"
|
||||
titleText="Secondary contact"
|
||||
placeholder="Select secondary contact method"
|
||||
items="{items}"
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
<script>
|
||||
import { ComboBox, Button } from "carbon-components-svelte";
|
||||
let selectedIndex = 1;
|
||||
let selectedId = "1";
|
||||
</script>
|
||||
|
||||
<ComboBox
|
||||
titleText="Contact"
|
||||
placeholder="Select contact method"
|
||||
bind:selectedIndex
|
||||
bind:selectedId
|
||||
items="{[
|
||||
{ id: '0', text: 'Slack' },
|
||||
{ id: '1', text: 'Email' },
|
||||
|
@ -14,5 +14,7 @@
|
|||
]}"
|
||||
/>
|
||||
<br />
|
||||
<Button on:click="{() => (selectedIndex = -1)}">Set to -1 (unselected)</Button>
|
||||
<Button on:click="{() => (selectedIndex = 2)}">Set to 2 (Fax)</Button>
|
||||
<Button on:click="{() => (selectedId = undefined)}"
|
||||
>Set to undefined (unselected)</Button
|
||||
>
|
||||
<Button on:click="{() => (selectedId = '2')}">Set to 2 (Fax)</Button>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<script>
|
||||
/**
|
||||
* @typedef {{ id: string; text: string; }} ComboBoxItem
|
||||
* @event {{ selectedId: string; selectedIndex: number; selectedItem: ComboBoxItem }} select
|
||||
* @event {{ selectedId: string; selectedItem: ComboBoxItem }} select
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -16,8 +16,11 @@
|
|||
*/
|
||||
export let itemToString = (item) => item.text || item.id;
|
||||
|
||||
/** Set the selected item by value index */
|
||||
export let selectedIndex = -1;
|
||||
/**
|
||||
* Set the selected item by value id
|
||||
* @type {string}
|
||||
*/
|
||||
export let selectedId = undefined;
|
||||
|
||||
/** Specify the selected combobox value */
|
||||
export let value = "";
|
||||
|
@ -107,10 +110,9 @@
|
|||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
let selectedId = undefined;
|
||||
let selectedItem = undefined;
|
||||
let inputValue = value;
|
||||
let prevSelectedIndex = undefined;
|
||||
let prevSelectedId = null;
|
||||
let highlightedIndex = -1;
|
||||
|
||||
function change(dir) {
|
||||
|
@ -129,8 +131,7 @@
|
|||
* @type {(options?: { focus?: boolean; }) => void}
|
||||
*/
|
||||
export function clear(options = {}) {
|
||||
prevSelectedIndex = undefined;
|
||||
selectedIndex = -1;
|
||||
prevSelectedId = null;
|
||||
highlightedIndex = -1;
|
||||
highlightedId = undefined;
|
||||
selectedId = undefined;
|
||||
|
@ -149,34 +150,31 @@
|
|||
filteredItems = [];
|
||||
if (!selectedItem) {
|
||||
selectedId = undefined;
|
||||
selectedIndex = -1;
|
||||
inputValue = "";
|
||||
highlightedIndex = -1;
|
||||
highlightedId = undefined;
|
||||
prevSelectedIndex = undefined;
|
||||
} else {
|
||||
// programmatically set selectedIndex
|
||||
// programmatically set inputValue
|
||||
inputValue = selectedItem.text;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$: if (selectedIndex > -1) {
|
||||
if (prevSelectedIndex !== selectedIndex) {
|
||||
prevSelectedIndex = selectedIndex;
|
||||
$: if (selectedId !== undefined) {
|
||||
if (prevSelectedId !== selectedId) {
|
||||
prevSelectedId = selectedId;
|
||||
if (filteredItems?.length === 1 && open) {
|
||||
selectedId = filteredItems[0].id;
|
||||
selectedItem = filteredItems[0];
|
||||
highlightedIndex = -1;
|
||||
highlightedId = undefined;
|
||||
} else {
|
||||
selectedId = items[selectedIndex].id;
|
||||
selectedItem = items[selectedIndex];
|
||||
selectedItem = items.find((item) => item.id === selectedId);
|
||||
}
|
||||
dispatch("select", { selectedId, selectedIndex, selectedItem });
|
||||
dispatch("select", { selectedId, selectedItem });
|
||||
}
|
||||
} else {
|
||||
prevSelectedIndex = selectedIndex;
|
||||
prevSelectedId = selectedId;
|
||||
selectedItem = undefined;
|
||||
}
|
||||
|
||||
|
@ -269,29 +267,25 @@
|
|||
if (key === 'Enter') {
|
||||
open = !open;
|
||||
|
||||
if (highlightedIndex > -1 && highlightedIndex !== selectedIndex) {
|
||||
selectedIndex = highlightedIndex;
|
||||
if (
|
||||
highlightedIndex > -1 &&
|
||||
filteredItems[highlightedIndex]?.id !== selectedId
|
||||
) {
|
||||
open = false;
|
||||
highlightedIndex = -1;
|
||||
if (filteredItems[selectedIndex]) {
|
||||
inputValue = filteredItems[selectedIndex].text;
|
||||
selectedItem = filteredItems[selectedIndex];
|
||||
selectedId = filteredItems[selectedIndex].id;
|
||||
if (filteredItems[highlightedIndex]) {
|
||||
inputValue = filteredItems[highlightedIndex].text;
|
||||
selectedItem = filteredItems[highlightedIndex];
|
||||
selectedId = filteredItems[highlightedIndex].id;
|
||||
}
|
||||
selectedIndex = items.findIndex((item) => item.id === selectedId);
|
||||
} else {
|
||||
selectedIndex = 0;
|
||||
open = false;
|
||||
highlightedIndex = -1;
|
||||
if (filteredItems[selectedIndex]) {
|
||||
inputValue = filteredItems[selectedIndex].text;
|
||||
selectedItem = filteredItems[selectedIndex];
|
||||
selectedId = filteredItems[selectedIndex].id;
|
||||
selectedIndex = items.findIndex(
|
||||
(item) => item.id === selectedId
|
||||
);
|
||||
if (filteredItems[0]) {
|
||||
inputValue = filteredItems[0].text;
|
||||
selectedItem = filteredItems[0];
|
||||
selectedId = filteredItems[0].id;
|
||||
}
|
||||
}
|
||||
highlightedIndex = -1;
|
||||
} else if (key === 'Tab') {
|
||||
open = false;
|
||||
} else if (key === 'ArrowDown') {
|
||||
|
@ -354,12 +348,10 @@
|
|||
{#each filteredItems as item, i (item.id)}
|
||||
<ListBoxMenuItem
|
||||
id="{item.id}"
|
||||
active="{selectedIndex === i || selectedId === item.id}"
|
||||
highlighted="{highlightedIndex === i || selectedIndex === i}"
|
||||
active="{selectedId === item.id}"
|
||||
highlighted="{highlightedIndex === i}"
|
||||
on:click="{() => {
|
||||
selectedIndex = items
|
||||
.map(({ id }) => id)
|
||||
.indexOf(filteredItems[i].id);
|
||||
selectedId = item.id;
|
||||
open = false;
|
||||
|
||||
if (filteredItems[i]) {
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
<ComboBox
|
||||
titleText="Contact"
|
||||
placeholder="Select contact method"
|
||||
selectedIndex="{1}"
|
||||
selectedId="1"
|
||||
items="{items}"
|
||||
/>
|
||||
|
||||
|
|
11
types/ComboBox/ComboBox.svelte.d.ts
vendored
11
types/ComboBox/ComboBox.svelte.d.ts
vendored
|
@ -21,10 +21,9 @@ export interface ComboBoxProps
|
|||
itemToString?: (item: ComboBoxItem) => string;
|
||||
|
||||
/**
|
||||
* Set the selected item by value index
|
||||
* @default -1
|
||||
* Set the selected item by value id
|
||||
*/
|
||||
selectedIndex?: number;
|
||||
selectedId?: string;
|
||||
|
||||
/**
|
||||
* Specify the selected combobox value
|
||||
|
@ -141,11 +140,7 @@ export interface ComboBoxProps
|
|||
export default class ComboBox extends SvelteComponentTyped<
|
||||
ComboBoxProps,
|
||||
{
|
||||
select: CustomEvent<{
|
||||
selectedId: string;
|
||||
selectedIndex: number;
|
||||
selectedItem: ComboBoxItem;
|
||||
}>;
|
||||
select: CustomEvent<{ selectedId: string; selectedItem: ComboBoxItem }>;
|
||||
keydown: WindowEventMap["keydown"];
|
||||
keyup: WindowEventMap["keyup"];
|
||||
focus: WindowEventMap["focus"];
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue