mirror of
https://github.com/carbon-design-system/carbon-components-svelte.git
synced 2025-09-18 19:46:36 +00:00
feat(MultiSelect): add selectedOnly and combineValues props
The MultiSelect wasn't rendering form-submittable inputs. This fix adds two new props to help customize how the hidden inputs render. See #1742
This commit is contained in:
parent
cb40e8fb18
commit
276465aa9d
5 changed files with 167 additions and 44 deletions
|
@ -2355,43 +2355,46 @@ export interface MultiSelectItem {
|
||||||
|
|
||||||
### Props
|
### Props
|
||||||
|
|
||||||
| Prop name | Required | Kind | Reactive | Type | Default value | Description |
|
| Prop name | Required | Kind | Reactive | Type | Default value | Description |
|
||||||
| :----------------------- | :------- | :--------------- | :------- | ------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| :------------------------------ | :------------------------ | :---------------------------------------------------------------------------------------------------------------------------- | :------- | ------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| highlightedId | No | <code>let</code> | Yes | <code>null | MultiSelectItemId</code> | <code>null</code> | Id of the highlighted ListBoxMenuItem |
|
| highlightedId | No | <code>let</code> | Yes | <code>null | MultiSelectItemId</code> | <code>null</code> | Id of the highlighted ListBoxMenuItem |
|
||||||
| selectionRef | No | <code>let</code> | Yes | <code>null | HTMLDivElement</code> | <code>null</code> | Obtain a reference to the selection element |
|
| selectionRef | No | <code>let</code> | Yes | <code>null | HTMLDivElement</code> | <code>null</code> | Obtain a reference to the selection element |
|
||||||
| fieldRef | No | <code>let</code> | Yes | <code>null | HTMLDivElement</code> | <code>null</code> | Obtain a reference to the field box element |
|
| fieldRef | No | <code>let</code> | Yes | <code>null | HTMLDivElement</code> | <code>null</code> | Obtain a reference to the field box element |
|
||||||
| multiSelectRef | No | <code>let</code> | Yes | <code>null | HTMLDivElement</code> | <code>null</code> | Obtain a reference to the outer div element |
|
| multiSelectRef | No | <code>let</code> | Yes | <code>null | HTMLDivElement</code> | <code>null</code> | Obtain a reference to the outer div element |
|
||||||
| inputRef | No | <code>let</code> | Yes | <code>null | HTMLInputElement</code> | <code>null</code> | Obtain a reference to the input HTML element |
|
| inputRef | No | <code>let</code> | Yes | <code>null | HTMLInputElement</code> | <code>null</code> | Obtain a reference to the input HTML element |
|
||||||
| open | No | <code>let</code> | Yes | <code>boolean</code> | <code>false</code> | Set to `true` to open the dropdown |
|
| open | No | <code>let</code> | Yes | <code>boolean</code> | <code>false</code> | Set to `true` to open the dropdown |
|
||||||
| value | No | <code>let</code> | Yes | <code>string</code> | <code>""</code> | Specify the multiselect value |
|
| value | No | <code>let</code> | Yes | <code>string</code> | <code>""</code> | Specify the multiselect value |
|
||||||
| selectedIds | No | <code>let</code> | Yes | <code>ReadonlyArray<MultiSelectItemId></code> | <code>[]</code> | Set the selected ids |
|
| selectedIds | No | <code>let</code> | Yes | <code>ReadonlyArray<MultiSelectItemId></code> | <code>[]</code> | Set the selected ids |
|
||||||
| items | No | <code>let</code> | Yes | <code>ReadonlyArray<MultiSelectItem></code> | <code>[]</code> | Set the multiselect items |
|
| items | No | <code>let</code> | Yes | <code>ReadonlyArray<MultiSelectItem></code> | <code>[]</code> | Set the multiselect items |
|
||||||
| itemToString | No | <code>let</code> | No | <code>(item: MultiSelectItem) => any</code> | <code>(item) => item.text || item.id</code> | Override the display of a multiselect item |
|
| itemToString | No | <code>let</code> | No | <code>(item: MultiSelectItem) => any</code> | <code>(item) => item.text || item.id</code> | Override the display of a multiselect item |
|
||||||
| itemToInput | No | <code>let</code> | No | <code>(item: MultiSelectItem) => { name?: string; labelText?: any; title?: string; }</code> | <code>(item) => {}</code> | Override the item name, title, labelText passed to the checkbox input |
|
| itemToInput | No | <code>let</code> | No | <code>(item: MultiSelectItem) => { name?: string; labelText?: any; title?: |
|
||||||
| size | No | <code>let</code> | No | <code>"sm" | "lg" | "xl"</code> | <code>undefined</code> | Set the size of the combobox |
|
| string; value?: string }</code> | <code>(item) => {}</code> | Override the item name, title, labelText, or value passed to the user-selectable checkbox input as well as the hidden inputs. |
|
||||||
| type | No | <code>let</code> | No | <code>"default" | "inline"</code> | <code>"default"</code> | Specify the type of multiselect |
|
| selectedOnly | No | <code>let</code> | No | <code>boolean</code> | <code>false</code> | Set to `true` to only render selected options as hidden inputs for form submission. |
|
||||||
| direction | No | <code>let</code> | No | <code>"bottom" | "top"</code> | <code>"bottom"</code> | Specify the direction of the multiselect dropdown menu |
|
| combineValues | No | <code>let</code> | No | <code>false | true | string</code> | <code>false</code> | Combine selected items as comma-separated values when submitted in a form.<br />If set to `true`, the default separator is a comma `,`.<br />Pass in a string to override the separator. |
|
||||||
| selectionFeedback | No | <code>let</code> | No | <code>"top" | "fixed" | "top-after-reopen"</code> | <code>"top-after-reopen"</code> | Specify the selection feedback after selecting items |
|
| size | No | <code>let</code> | No | <code>"sm" | "lg" | "xl"</code> | <code>undefined</code> | Set the size of the combobox |
|
||||||
| disabled | No | <code>let</code> | No | <code>boolean</code> | <code>false</code> | Set to `true` to disable the dropdown |
|
| type | No | <code>let</code> | No | <code>"default" | "inline"</code> | <code>"default"</code> | Specify the type of multiselect |
|
||||||
| filterable | No | <code>let</code> | No | <code>boolean</code> | <code>false</code> | Set to `true` to filter items |
|
| direction | No | <code>let</code> | No | <code>"bottom" | "top"</code> | <code>"bottom"</code> | Specify the direction of the multiselect dropdown menu |
|
||||||
| filterItem | No | <code>let</code> | No | <code>(item: MultiSelectItem, value: string) => string</code> | <code>(item, value) => item.text.toLowerCase().includes(value.trim().toLowerCase())</code> | Override the filtering logic<br />The default filtering is an exact string comparison |
|
| selectionFeedback | No | <code>let</code> | No | <code>"top" | "fixed" | "top-after-reopen"</code> | <code>"top-after-reopen"</code> | Specify the selection feedback after selecting items |
|
||||||
| light | No | <code>let</code> | No | <code>boolean</code> | <code>false</code> | Set to `true` to enable the light variant |
|
| disabled | No | <code>let</code> | No | <code>boolean</code> | <code>false</code> | Set to `true` to disable the dropdown |
|
||||||
| locale | No | <code>let</code> | No | <code>string</code> | <code>"en"</code> | Specify the locale |
|
| filterable | No | <code>let</code> | No | <code>boolean</code> | <code>false</code> | Set to `true` to filter items |
|
||||||
| placeholder | No | <code>let</code> | No | <code>string</code> | <code>""</code> | Specify the placeholder text |
|
| filterItem | No | <code>let</code> | No | <code>(item: MultiSelectItem, value: string) => string</code> | <code>(item, value) => item.text.toLowerCase().includes(value.trim().toLowerCase())</code> | Override the filtering logic<br />The default filtering is an exact string comparison |
|
||||||
| sortItem | No | <code>let</code> | No | <code>((a: MultiSelectItem, b: MultiSelectItem) => MultiSelectItem) | (() => void)</code> | <code>(a, b) => a.text.localeCompare(b.text, locale, { numeric: true })</code> | Override the sorting logic<br />The default sorting compare the item text value |
|
| light | No | <code>let</code> | No | <code>boolean</code> | <code>false</code> | Set to `true` to enable the light variant |
|
||||||
| translateWithId | No | <code>let</code> | No | <code>(id: import("../ListBox/ListBoxMenuIcon.svelte").ListBoxMenuIconTranslationId) => string</code> | <code>undefined</code> | Override the chevron icon label based on the open state.<br />Defaults to "Open menu" when closed and "Close menu" when open |
|
| locale | No | <code>let</code> | No | <code>string</code> | <code>"en"</code> | Specify the locale |
|
||||||
| translateWithIdSelection | No | <code>let</code> | No | <code>(id: import("../ListBox/ListBoxSelection.svelte").ListBoxSelectionTranslationId) => string</code> | <code>undefined</code> | Override the label of the clear button when the input has a selection.<br />Defaults to "Clear selected item" and "Clear all items" if more than one item is selected |
|
| placeholder | No | <code>let</code> | No | <code>string</code> | <code>""</code> | Specify the placeholder text |
|
||||||
| titleText | No | <code>let</code> | No | <code>string</code> | <code>""</code> | Specify the title text |
|
| sortItem | No | <code>let</code> | No | <code>((a: MultiSelectItem, b: MultiSelectItem) => MultiSelectItem) | (() => void)</code> | <code>(a, b) => a.text.localeCompare(b.text, locale, { numeric: true })</code> | Override the sorting logic<br />The default sorting compare the item text value |
|
||||||
| useTitleInItem | No | <code>let</code> | No | <code>boolean</code> | <code>false</code> | Set to `true` to pass the item to `itemToString` in the checkbox |
|
| translateWithId | No | <code>let</code> | No | <code>(id: import("../ListBox/ListBoxMenuIcon.svelte").ListBoxMenuIconTranslationId) => string</code> | <code>undefined</code> | Override the chevron icon label based on the open state.<br />Defaults to "Open menu" when closed and "Close menu" when open |
|
||||||
| invalid | No | <code>let</code> | No | <code>boolean</code> | <code>false</code> | Set to `true` to indicate an invalid state |
|
| translateWithIdSelection | No | <code>let</code> | No | <code>(id: import("../ListBox/ListBoxSelection.svelte").ListBoxSelectionTranslationId) => string</code> | <code>undefined</code> | Override the label of the clear button when the input has a selection.<br />Defaults to "Clear selected item" and "Clear all items" if more than one item is selected |
|
||||||
| invalidText | No | <code>let</code> | No | <code>string</code> | <code>""</code> | Specify the invalid state text |
|
| titleText | No | <code>let</code> | No | <code>string</code> | <code>""</code> | Specify the title text |
|
||||||
| warn | No | <code>let</code> | No | <code>boolean</code> | <code>false</code> | Set to `true` to indicate an warning state |
|
| useTitleInItem | No | <code>let</code> | No | <code>boolean</code> | <code>false</code> | Set to `true` to pass the item to `itemToString` in the checkbox |
|
||||||
| warnText | No | <code>let</code> | No | <code>string</code> | <code>""</code> | Specify the warning state text |
|
| invalid | No | <code>let</code> | No | <code>boolean</code> | <code>false</code> | Set to `true` to indicate an invalid state |
|
||||||
| helperText | No | <code>let</code> | No | <code>string</code> | <code>""</code> | Specify the helper text |
|
| invalidText | No | <code>let</code> | No | <code>string</code> | <code>""</code> | Specify the invalid state text |
|
||||||
| label | No | <code>let</code> | No | <code>string</code> | <code>""</code> | Specify the list box label |
|
| warn | No | <code>let</code> | No | <code>boolean</code> | <code>false</code> | Set to `true` to indicate an warning state |
|
||||||
| hideLabel | No | <code>let</code> | No | <code>boolean</code> | <code>false</code> | Set to `true` to visually hide the label text |
|
| warnText | No | <code>let</code> | No | <code>string</code> | <code>""</code> | Specify the warning state text |
|
||||||
| id | No | <code>let</code> | No | <code>string</code> | <code>"ccs-" + Math.random().toString(36)</code> | Set an id for the list box component |
|
| helperText | No | <code>let</code> | No | <code>string</code> | <code>""</code> | Specify the helper text |
|
||||||
| name | No | <code>let</code> | No | <code>string</code> | <code>undefined</code> | Specify a name attribute for the select |
|
| label | No | <code>let</code> | No | <code>string</code> | <code>""</code> | Specify the list box label |
|
||||||
|
| hideLabel | No | <code>let</code> | No | <code>boolean</code> | <code>false</code> | Set to `true` to visually hide the label text |
|
||||||
|
| id | No | <code>let</code> | No | <code>string</code> | <code>"ccs-" + Math.random().toString(36)</code> | Set an id for the list box component |
|
||||||
|
| name | No | <code>let</code> | No | <code>string</code> | <code>undefined</code> | Specify a name attribute for the select |
|
||||||
|
|
||||||
### Slots
|
### Slots
|
||||||
|
|
||||||
|
|
|
@ -7006,8 +7006,8 @@
|
||||||
{
|
{
|
||||||
"name": "itemToInput",
|
"name": "itemToInput",
|
||||||
"kind": "let",
|
"kind": "let",
|
||||||
"description": "Override the item name, title, labelText passed to the checkbox input",
|
"description": "Override the item name, title, labelText, or value passed to the user-selectable checkbox input as well as the hidden inputs.",
|
||||||
"type": "(item: MultiSelectItem) => { name?: string; labelText?: any; title?: string; }",
|
"type": "(item: MultiSelectItem) => { name?: string; labelText?: any; title?:\nstring; value?: string }",
|
||||||
"value": "(item) => {}",
|
"value": "(item) => {}",
|
||||||
"isFunction": true,
|
"isFunction": true,
|
||||||
"isFunctionDeclaration": false,
|
"isFunctionDeclaration": false,
|
||||||
|
@ -7015,6 +7015,30 @@
|
||||||
"constant": false,
|
"constant": false,
|
||||||
"reactive": false
|
"reactive": false
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "selectedOnly",
|
||||||
|
"kind": "let",
|
||||||
|
"description": "Set to `true` to only render selected options as hidden inputs for form submission.",
|
||||||
|
"type": "boolean",
|
||||||
|
"value": "false",
|
||||||
|
"isFunction": false,
|
||||||
|
"isFunctionDeclaration": false,
|
||||||
|
"isRequired": false,
|
||||||
|
"constant": false,
|
||||||
|
"reactive": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "combineValues",
|
||||||
|
"kind": "let",
|
||||||
|
"description": "Combine selected items as comma-separated values when submitted in a form.\nIf set to `true`, the default separator is a comma `,`.\nPass in a string to override the separator.",
|
||||||
|
"type": "false | true | string",
|
||||||
|
"value": "false",
|
||||||
|
"isFunction": false,
|
||||||
|
"isFunctionDeclaration": false,
|
||||||
|
"isRequired": false,
|
||||||
|
"constant": false,
|
||||||
|
"reactive": false
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "selectedIds",
|
"name": "selectedIds",
|
||||||
"kind": "let",
|
"kind": "let",
|
||||||
|
|
|
@ -11,7 +11,13 @@
|
||||||
|
|
||||||
## Default
|
## Default
|
||||||
|
|
||||||
By default, items will be ordered alphabetically based on the `item.text` value. To prevent this, see [#no-alphabetical-ordering](#no-alphabetical-ordering).
|
By default, items will be ordered alphabetically based on the `item.text` value.
|
||||||
|
To prevent this, see [#no-alphabetical-ordering](#no-alphabetical-ordering).
|
||||||
|
|
||||||
|
Hidden inputs will be rendered based on user selection, such as `<input type="hidden"
|
||||||
|
name="0" value="true" />` to mirror checkbox values and to allow MultiSelect to
|
||||||
|
be submittable within forms. These hidden inputs can be customized with
|
||||||
|
the `combineValues` or `itemToInput` props.
|
||||||
|
|
||||||
<MultiSelect titleText="Contact" label="Select contact methods..."
|
<MultiSelect titleText="Contact" label="Select contact methods..."
|
||||||
items="{[{id: "0", text: "Slack"},
|
items="{[{id: "0", text: "Slack"},
|
||||||
|
@ -73,6 +79,56 @@ Use the `itemToString` prop to format the display of individual items.
|
||||||
sortItem="{() => {}}"
|
sortItem="{() => {}}"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
## Format checkbox values
|
||||||
|
|
||||||
|
Use the `itemToInput` prop to customize the user-selectable checkbox values.
|
||||||
|
This will also override the underlying hidden inputs used for form submission.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```js
|
||||||
|
(item) => ({name: `Contact_${item.id}`], value: item.id})
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
The above function sets the `name` attribute to
|
||||||
|
`Contact_0` (respective to each item's `id`) for every hidden input that
|
||||||
|
renders, along with each respective item's `id` set to the `value` attribute.
|
||||||
|
|
||||||
|
When using with the `selectedOnly` prop, you can override every hidden input to
|
||||||
|
use the same `name` attribute. This may be useful if you
|
||||||
|
wish to use `formData.getAll('contact')` in your server-side form handler.
|
||||||
|
|
||||||
|
<MultiSelect
|
||||||
|
itemToInput={(item) => ({name: 'contact', value: item.id})}
|
||||||
|
selectedOnly
|
||||||
|
titleText="Contact"
|
||||||
|
label="Select contact methods..."
|
||||||
|
items="{[
|
||||||
|
{id: "0", text: "Slack"},
|
||||||
|
{id: "1", text: "Email"},
|
||||||
|
{id: "2", text: "Fax"}
|
||||||
|
]}"
|
||||||
|
/>
|
||||||
|
|
||||||
|
## Combine values into a single input
|
||||||
|
|
||||||
|
With the `combineValues` prop, all selected items' values will render as a
|
||||||
|
comma-separated string within a single hidden input. A custom delimiter can
|
||||||
|
alternatively be passed in.
|
||||||
|
|
||||||
|
<MultiSelect
|
||||||
|
combineValues
|
||||||
|
titleText="Contact"
|
||||||
|
label="Select contact methods..."
|
||||||
|
items="{[
|
||||||
|
{id: "0", text: "Slack"},
|
||||||
|
{id: "1", text: "Email"},
|
||||||
|
{id: "2", text: "Fax"}
|
||||||
|
]}"
|
||||||
|
/>
|
||||||
|
|
||||||
## Top direction
|
## Top direction
|
||||||
|
|
||||||
Set `direction` to `"top"` for the dropdown menu to appear above the input.
|
Set `direction` to `"top"` for the dropdown menu to appear above the input.
|
||||||
|
@ -159,4 +215,4 @@ Use the `disabled` property in the `items` prop to disable specific items.
|
||||||
{ id: "1", text: "Email", disabled: true },
|
{ id: "1", text: "Email", disabled: true },
|
||||||
{ id: "2", text: "Fax" },
|
{ id: "2", text: "Fax" },
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -22,11 +22,26 @@
|
||||||
export let itemToString = (item) => item.text || item.id;
|
export let itemToString = (item) => item.text || item.id;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Override the item name, title, labelText passed to the checkbox input
|
* Override the item name, title, labelText, or value passed to the user-selectable checkbox input as well as the hidden inputs.
|
||||||
* @type {(item: MultiSelectItem) => { name?: string; labelText?: any; title?: string; }}
|
* @type {(item: MultiSelectItem) => { name?: string; labelText?: any; title?:
|
||||||
|
* string; value?: string }}
|
||||||
*/
|
*/
|
||||||
export let itemToInput = (item) => {};
|
export let itemToInput = (item) => {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set to `true` to only render selected options as hidden inputs for form submission.
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
export let selectedOnly = false
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Combine selected items as comma-separated values when submitted in a form.
|
||||||
|
* If set to `true`, the default separator is a comma `,`.
|
||||||
|
* Pass in a string to override the separator.
|
||||||
|
* @type {false | true | string}
|
||||||
|
*/
|
||||||
|
export let combineValues = false
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the selected ids
|
* Set the selected ids
|
||||||
* @type {ReadonlyArray<MultiSelectItemId>}
|
* @type {ReadonlyArray<MultiSelectItemId>}
|
||||||
|
@ -533,6 +548,16 @@
|
||||||
</ListBoxMenuItem>
|
</ListBoxMenuItem>
|
||||||
{/each}
|
{/each}
|
||||||
</ListBoxMenu>
|
</ListBoxMenu>
|
||||||
|
{:else}
|
||||||
|
{#if combineValues}
|
||||||
|
{@const items = checked.map(el => el.id).join(typeof combineValues ===
|
||||||
|
'string' ? combineValues : ',')}
|
||||||
|
<input type="hidden" name={titleText} value="{items}">
|
||||||
|
{:else}
|
||||||
|
{#each selectedOnly ? checked : sortedItems as item (item.id)}
|
||||||
|
<input type="hidden" name="{item.id}" value={item.checked} {...itemToInput(item)} />
|
||||||
|
{/each}
|
||||||
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
</ListBox>
|
</ListBox>
|
||||||
{#if !inline && !invalid && !warn && helperText}
|
{#if !inline && !invalid && !warn && helperText}
|
||||||
|
|
17
types/MultiSelect/MultiSelect.svelte.d.ts
vendored
17
types/MultiSelect/MultiSelect.svelte.d.ts
vendored
|
@ -27,15 +27,30 @@ export interface MultiSelectProps extends RestProps {
|
||||||
itemToString?: (item: MultiSelectItem) => any;
|
itemToString?: (item: MultiSelectItem) => any;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Override the item name, title, labelText passed to the checkbox input
|
* Override the item name, title, labelText, or value passed to the user-selectable checkbox input as well as the hidden inputs.
|
||||||
* @default (item) => {}
|
* @default (item) => {}
|
||||||
*/
|
*/
|
||||||
itemToInput?: (item: MultiSelectItem) => {
|
itemToInput?: (item: MultiSelectItem) => {
|
||||||
name?: string;
|
name?: string;
|
||||||
labelText?: any;
|
labelText?: any;
|
||||||
title?: string;
|
title?: string;
|
||||||
|
value?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set to `true` to only render selected options as hidden inputs for form submission.
|
||||||
|
* @default false
|
||||||
|
*/
|
||||||
|
selectedOnly?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Combine selected items as comma-separated values when submitted in a form.
|
||||||
|
* If set to `true`, the default separator is a comma `,`.
|
||||||
|
* Pass in a string to override the separator.
|
||||||
|
* @default false
|
||||||
|
*/
|
||||||
|
combineValues?: false | true | string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the selected ids
|
* Set the selected ids
|
||||||
* @default []
|
* @default []
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue