feat(Dropdown): selectedIndex -> selectedId (#1004)

* feat(breaking): selectedIndex -> selectedId in Dropdown

* feat: omit `selectedIndex` from the `select` event
This commit is contained in:
Koichi Kiyokawa 2022-01-18 23:37:32 +09:00 committed by GitHub
commit e11a893bee
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 53 additions and 52 deletions

View file

@ -1166,7 +1166,7 @@ export interface DropdownItem {
| ref | <code>let</code> | Yes | <code>null &#124; HTMLButtonElement</code> | <code>null</code> | Obtain a reference to the button HTML element |
| inline | <code>let</code> | Yes | <code>boolean</code> | <code>false</code> | Set to `true` to use the inline variant |
| open | <code>let</code> | Yes | <code>boolean</code> | <code>false</code> | Set to `true` to open the dropdown |
| selectedIndex | <code>let</code> | Yes | <code>number</code> | <code>-1</code> | Specify the selected item index |
| selectedId | <code>let</code> | Yes | <code>DropdownItemId</code> | -- | Specify the selected item id |
| items | <code>let</code> | No | <code>DropdownItem[]</code> | <code>[]</code> | Set the dropdown items |
| itemToString | <code>let</code> | No | <code>(item: DropdownItem) => string</code> | <code>(item) => item.text &#124;&#124; item.id</code> | Override the display of a dropdown item |
| type | <code>let</code> | No | <code>"default" &#124; "inline"</code> | <code>"default"</code> | Specify the type of dropdown |
@ -1193,8 +1193,8 @@ None.
### Events
| Event name | Type | Detail |
| :--------- | :--------- | :--------------------------------------------------------------------------------------------- |
| select | dispatched | <code>{ selectedId: DropdownItemId, selectedIndex: number, selectedItem: DropdownItem }</code> |
| :--------- | :--------- | :---------------------------------------------------------------------- |
| select | dispatched | <code>{ selectedId: DropdownItemId, selectedItem: DropdownItem }</code> |
## `DropdownSkeleton`

View file

@ -3008,11 +3008,10 @@
"reactive": false
},
{
"name": "selectedIndex",
"name": "selectedId",
"kind": "let",
"description": "Specify the selected item index",
"type": "number",
"value": "-1",
"description": "Specify the selected item id",
"type": "DropdownItemId",
"isFunction": false,
"isFunctionDeclaration": false,
"constant": false,
@ -3229,7 +3228,7 @@
{
"type": "dispatched",
"name": "select",
"detail": "{ selectedId: DropdownItemId, selectedIndex: number, selectedItem: DropdownItem }"
"detail": "{ selectedId: DropdownItemId, selectedItem: DropdownItem }"
}
],
"typedefs": [

View file

@ -9,13 +9,13 @@ components: ["Dropdown", "DropdownSkeleton"]
### Default
<Dropdown titleText="Contact" selectedIndex={0} items="{[{id: "0", text: "Slack"},
<Dropdown titleText="Contact" selectedId="0" items="{[{id: "0", text: "Slack"},
{id: "1", text: "Email"},
{id: "2", text: "Fax"}]}" />
### Hidden label
<Dropdown hideLabel titleText="Contact" selectedIndex={0} items="{[{id: "0", text: "Slack"},
<Dropdown hideLabel titleText="Contact" selectedId="0" items="{[{id: "0", text: "Slack"},
{id: "1", text: "Email"},
{id: "2", text: "Fax"}]}" />
@ -25,7 +25,7 @@ Use the `itemToString` prop to format the display of individual items.
<Dropdown itemToString={item => {
return item.text + ' (' + item.id +')'
}} titleText="Contact" selectedIndex={0} items="{[{id: "0", text: "Slack"},
}} titleText="Contact" selectedId="0" items="{[{id: "0", text: "Slack"},
{id: "1", text: "Email"},
{id: "2", text: "Fax"}]}" />
@ -37,49 +37,49 @@ Use the `itemToString` prop to format the display of individual items.
Set `direction` to `"top"` for the dropdown menu to appear above the input.
<Dropdown direction="top" titleText="Contact" selectedIndex={0} items="{[{id: "0", text: "Slack"},
<Dropdown direction="top" titleText="Contact" selectedId="0" items="{[{id: "0", text: "Slack"},
{id: "1", text: "Email"},
{id: "2", text: "Fax"}]}" />
### Light variant
<Dropdown light titleText="Contact" selectedIndex={0} items="{[{id: "0", text: "Slack"},
<Dropdown light titleText="Contact" selectedId="0" items="{[{id: "0", text: "Slack"},
{id: "1", text: "Email"},
{id: "2", text: "Fax"}]}" />
### Inline variant
<Dropdown type="inline" titleText="Contact" selectedIndex={0} items="{[{id: "0", text: "Slack"},
<Dropdown type="inline" titleText="Contact" selectedId="0" items="{[{id: "0", text: "Slack"},
{id: "1", text: "Email"},
{id: "2", text: "Fax"}]}" />
### Extra-large size
<Dropdown size="xl" titleText="Contact" selectedIndex={0} items="{[{id: "0", text: "Slack"},
<Dropdown size="xl" titleText="Contact" selectedId="0" items="{[{id: "0", text: "Slack"},
{id: "1", text: "Email"},
{id: "2", text: "Fax"}]}" />
### Small size
<Dropdown size="sm" titleText="Contact" selectedIndex={0} items="{[{id: "0", text: "Slack"},
<Dropdown size="sm" titleText="Contact" selectedId="0" items="{[{id: "0", text: "Slack"},
{id: "1", text: "Email"},
{id: "2", text: "Fax"}]}" />
### Invalid state
<Dropdown invalid invalidText="Secondary contact method must be different from the primary contact" titleText="Contact" selectedIndex={0} items="{[{id: "0", text: "Slack"},
<Dropdown invalid invalidText="Secondary contact method must be different from the primary contact" titleText="Contact" selectedId="0" items="{[{id: "0", text: "Slack"},
{id: "1", text: "Email"},
{id: "2", text: "Fax"}]}" />
### Warning state
<Dropdown warn warnText="This contact method is not associated with your account" titleText="Contact" selectedIndex={0} items="{[{id: "0", text: "Slack"},
<Dropdown warn warnText="This contact method is not associated with your account" titleText="Contact" selectedId="0" items="{[{id: "0", text: "Slack"},
{id: "1", text: "Email"},
{id: "2", text: "Fax"}]}" />
### Disabled state
<Dropdown disabled titleText="Contact" selectedIndex={0} items="{[{id: "0", text: "Slack"},
<Dropdown disabled titleText="Contact" selectedId="0" items="{[{id: "0", text: "Slack"},
{id: "1", text: "Email"},
{id: "2", text: "Fax"}]}" />

View file

@ -7,28 +7,29 @@
{ id: "2", text: "Fax" },
];
let dropdown1_selectedIndex = 0;
let dropdown2_selectedIndex = 1;
let dropdown1_selectedId = "0";
let dropdown2_selectedId = "1";
const formatSelected = (i) => (items[i] ? items[i].text : "N/A");
const formatSelected = (id) =>
items.find((item) => item.id === id)?.text ?? "N/A";
$: primary = formatSelected(dropdown1_selectedIndex);
$: secondary = formatSelected(dropdown2_selectedIndex);
$: primary = formatSelected(dropdown1_selectedId);
$: secondary = formatSelected(dropdown2_selectedId);
</script>
<Dropdown
titleText="Primary contact"
bind:selectedIndex="{dropdown1_selectedIndex}"
bind:selectedId="{dropdown1_selectedId}"
items="{items}"
/>
<div>Primary: {primary}</div>
<Dropdown
invalid="{dropdown1_selectedIndex === dropdown2_selectedIndex}"
invalid="{dropdown1_selectedId === dropdown2_selectedId}"
invalidText="Secondary contact method must be different from the primary contact"
titleText="Secondary contact"
bind:selectedIndex="{dropdown2_selectedIndex}"
bind:selectedId="{dropdown2_selectedId}"
items="{items}"
/>

View file

@ -3,7 +3,7 @@
* @typedef {string} DropdownItemId
* @typedef {string} DropdownItemText
* @typedef {{ id: DropdownItemId; text: DropdownItemText; }} DropdownItem
* @event {{ selectedId: DropdownItemId, selectedIndex: number, selectedItem: DropdownItem }} select
* @event {{ selectedId: DropdownItemId, selectedItem: DropdownItem }} select
*/
/**
@ -18,8 +18,11 @@
*/
export let itemToString = (item) => item.text || item.id;
/** Specify the selected item index */
export let selectedIndex = -1;
/**
* Specify the selected item id
* @type {DropdownItemId}
*/
export let selectedId = undefined;
/**
* Specify the type of dropdown
@ -108,7 +111,6 @@
const dispatch = createEventDispatcher();
let selectedId = undefined;
let highlightedIndex = -1;
function change(dir) {
@ -123,12 +125,11 @@
highlightedIndex = index;
}
$: if (selectedIndex > -1) {
dispatch("select", { selectedId, selectedIndex, selectedItem });
$: if (selectedId !== undefined) {
dispatch("select", { selectedId, selectedItem });
}
$: inline = type === "inline";
$: selectedItem = items[selectedIndex];
$: selectedId = items[selectedIndex] ? items[selectedIndex].id : undefined;
$: selectedItem = items.find((item) => item.id === selectedId);
$: if (!open) {
highlightedIndex = -1;
}
@ -206,8 +207,11 @@
}
if (key === 'Enter') {
open = !open;
if (highlightedIndex > -1 && highlightedIndex !== selectedIndex) {
selectedIndex = highlightedIndex;
if (
highlightedIndex > -1 &&
items[highlightedIndex].id !== selectedId
) {
selectedId = items[highlightedIndex].id;
open = false;
}
} else if (key === 'Tab') {
@ -233,11 +237,10 @@
{#each items 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 || selectedId === item.id}"
on:click="{() => {
selectedId = item.id;
selectedIndex = i;
ref.focus();
}}"
on:mouseenter="{() => {

View file

@ -5,7 +5,7 @@
<Dropdown
direction="top"
titleText="Contact"
selectedIndex="{0}"
selectedId="0"
items="{[
{ id: '0', text: 'Slack' },
{ id: '1', text: 'Email' },
@ -18,7 +18,7 @@
return item.text + ' (' + item.id + ')';
}}"
titleText="Contact"
selectedIndex="{0}"
selectedId="0"
items="{[
{ id: '0', text: 'Slack' },
{ id: '1', text: 'Email' },
@ -29,7 +29,7 @@
<Dropdown
light
titleText="Contact"
selectedIndex="{0}"
selectedId="0"
items="{[
{ id: '0', text: 'Slack' },
{ id: '1', text: 'Email' },
@ -40,7 +40,7 @@
<Dropdown
type="inline"
titleText="Contact"
selectedIndex="{0}"
selectedId="0"
items="{[
{ id: '0', text: 'Slack' },
{ id: '1', text: 'Email' },
@ -51,7 +51,7 @@
<Dropdown
size="xl"
titleText="Contact"
selectedIndex="{0}"
selectedId="0"
items="{[
{ id: '0', text: 'Slack' },
{ id: '1', text: 'Email' },
@ -62,7 +62,7 @@
<Dropdown
size="sm"
titleText="Contact"
selectedIndex="{0}"
selectedId="0"
items="{[
{ id: '0', text: 'Slack' },
{ id: '1', text: 'Email' },
@ -73,7 +73,7 @@
<Dropdown
disabled
titleText="Contact"
selectedIndex="{0}"
selectedId="0"
items="{[
{ id: '0', text: 'Slack' },
{ id: '1', text: 'Email' },

View file

@ -25,10 +25,9 @@ export interface DropdownProps
itemToString?: (item: DropdownItem) => string;
/**
* Specify the selected item index
* @default -1
* Specify the selected item id
*/
selectedIndex?: number;
selectedId?: DropdownItemId;
/**
* Specify the type of dropdown
@ -146,7 +145,6 @@ export default class Dropdown extends SvelteComponentTyped<
{
select: CustomEvent<{
selectedId: DropdownItemId;
selectedIndex: number;
selectedItem: DropdownItem;
}>;
},