@mozaic-ds/web-components 1.6.0 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Condition20.js +1 -1
- package/dist/attributes.js +1 -1
- package/dist/branches.js +1 -1
- package/dist/branches.js.map +1 -1
- package/dist/bundle.d.ts +2 -0
- package/dist/bundle.d.ts.map +1 -1
- package/dist/bundle.js +2 -0
- package/dist/components/accordionlist/AccordionList.js +2 -2
- package/dist/components/accordionlistItem/AccordionListItem.js +2 -2
- package/dist/components/actionbottombar/ActionBottomBar.js +2 -2
- package/dist/components/actionlistbox/ActionListbox.js +2 -2
- package/dist/components/actionlistbox/ActionListbox.svelte +1 -1
- package/dist/components/actionlistboxitem/ActionListboxItem.js +1 -1
- package/dist/components/avatar/Avatar.js +1 -1
- package/dist/components/breadcrumb/Breadcrumb.js +2 -2
- package/dist/components/builtinmenu/BuiltInMenu.js +2 -2
- package/dist/components/builtinmenuitem/BuiltInMenuItem.js +2 -2
- package/dist/components/button/Button.js +1 -1
- package/dist/components/callout/Callout.js +2 -2
- package/dist/components/carousel/Carousel.js +2 -2
- package/dist/components/checkbox/Checkbox.js +1 -1
- package/dist/components/checkboxgroup/CheckboxGroup.js +1 -1
- package/dist/components/checklistmenu/CheckListMenu.js +1 -1
- package/dist/components/circularprogressbar/CircularProgressbar.js +2 -2
- package/dist/components/combobox/Combobox.js +4 -0
- package/dist/components/combobox/Combobox.js.map +1 -0
- package/dist/components/combobox/Combobox.spec.js +186 -0
- package/dist/components/combobox/Combobox.stories.d.ts +17 -0
- package/dist/components/combobox/Combobox.stories.d.ts.map +1 -0
- package/dist/components/combobox/Combobox.stories.js +126 -0
- package/dist/components/combobox/Combobox.svelte +415 -0
- package/dist/components/combobox/Combobox.svelte.d.ts +99 -0
- package/dist/components/combobox/Combobox.svelte.d.ts.map +1 -0
- package/dist/components/combobox/README.md +38 -0
- package/dist/components/container/Container.js +2 -2
- package/dist/components/datepicker/Datepicker.js +3 -3
- package/dist/components/datepicker/Datepicker.js.map +1 -1
- package/dist/components/datepicker/Datepicker.svelte +2 -1
- package/dist/components/divider/Divider.js +1 -1
- package/dist/components/drawer/Drawer.js +4 -4
- package/dist/components/drawer/Drawer.svelte +2 -1
- package/dist/components/field/Field.js +1 -1
- package/dist/components/fileuploader/FileUploader.js +2 -2
- package/dist/components/fileuploader/FileUploader.js.map +1 -1
- package/dist/components/fileuploader/FileUploader.svelte +1 -4
- package/dist/components/fileuploaderitem/FileUploaderItem.js +3 -3
- package/dist/components/fileuploaderitem/FileUploaderItem.svelte +1 -4
- package/dist/components/flag/Flag.js +2 -2
- package/dist/components/iconbutton/IconButton.js +2 -2
- package/dist/components/kpiitem/KpiItem.js +1 -1
- package/dist/components/linearprogressbarbuffer/LinearProgressbarBuffer.js +2 -2
- package/dist/components/linearprogressbarpercentage/LinearProgressbarPercentage.js +2 -2
- package/dist/components/link/Link.js +1 -1
- package/dist/components/loader/Loader.js +2 -2
- package/dist/components/loadingoverlay/LoadingOverlay.js +2 -2
- package/dist/components/loadingoverlay/LoadingOverlay.svelte +1 -1
- package/dist/components/modal/Modal.js +4 -4
- package/dist/components/modal/Modal.js.map +1 -1
- package/dist/components/modal/Modal.spec.js +3 -1
- package/dist/components/modal/Modal.svelte +9 -3
- package/dist/components/modal/Modal.svelte.d.ts +4 -0
- package/dist/components/modal/Modal.svelte.d.ts.map +1 -1
- package/dist/components/modal/README.md +1 -0
- package/dist/components/navigationindicator/NavigationIndicator.js +2 -2
- package/dist/components/numberbadge/NumberBadge.js +2 -2
- package/dist/components/optionlistbox/OptionListbox.js +23 -0
- package/dist/components/optionlistbox/OptionListbox.js.map +1 -0
- package/dist/components/optionlistbox/OptionListbox.spec.js +350 -0
- package/dist/components/optionlistbox/OptionListbox.svelte +566 -0
- package/dist/components/optionlistbox/OptionListbox.svelte.d.ts +92 -0
- package/dist/components/optionlistbox/OptionListbox.svelte.d.ts.map +1 -0
- package/dist/components/optionlistbox/README.md +38 -0
- package/dist/components/overlay/Overlay.js +2 -2
- package/dist/components/overlay/Overlay.svelte +2 -2
- package/dist/components/pageheader/PageHeader.js +1 -1
- package/dist/components/pagination/Pagination.js +4 -4
- package/dist/components/passwordinput/PasswordInput.js +3 -3
- package/dist/components/passwordinput/PasswordInput.js.map +1 -1
- package/dist/components/passwordinput/PasswordInput.svelte +2 -1
- package/dist/components/phonenumber/PhoneNumber.js +4 -4
- package/dist/components/phonenumber/PhoneNumber.js.map +1 -1
- package/dist/components/phonenumber/PhoneNumber.svelte +3 -2
- package/dist/components/pincode/Pincode.js +2 -2
- package/dist/components/popover/Popover.js +1 -1
- package/dist/components/quantityselector/QuantitySelector.js +2 -2
- package/dist/components/quantityselector/QuantitySelector.svelte +1 -1
- package/dist/components/radio/Radio.js +2 -2
- package/dist/components/radiogroup/RadioGroup.js +2 -2
- package/dist/components/segmentedcontrol/README.md +6 -3
- package/dist/components/segmentedcontrol/SegmentedControl.js +2 -2
- package/dist/components/segmentedcontrol/SegmentedControl.js.map +1 -1
- package/dist/components/segmentedcontrol/SegmentedControl.spec.js +60 -23
- package/dist/components/segmentedcontrol/SegmentedControl.stories.d.ts.map +1 -1
- package/dist/components/segmentedcontrol/SegmentedControl.stories.js +6 -1
- package/dist/components/segmentedcontrol/SegmentedControl.svelte +23 -10
- package/dist/components/segmentedcontrol/SegmentedControl.svelte.d.ts +10 -3
- package/dist/components/segmentedcontrol/SegmentedControl.svelte.d.ts.map +1 -1
- package/dist/components/select/Select.js +1 -1
- package/dist/components/sidebar/Sidebar.js +1 -1
- package/dist/components/sidebarexpandableitem/SidebarExpandableItem.js +2 -2
- package/dist/components/sidebarfooter/SidebarFooter.js +1 -1
- package/dist/components/sidebarfooter/_SidebarFooterMenu.js +2 -2
- package/dist/components/sidebarheader/SidebarHeader.js +1 -1
- package/dist/components/sidebarnavitem/SidebarNavItem.js +2 -2
- package/dist/components/sidebarshortcutitem/SidebarShortcutItem.js +1 -1
- package/dist/components/sidebarshortcuts/SidebarShortcuts.js +2 -2
- package/dist/components/starrating/StarRating.js +2 -2
- package/dist/components/statusbadge/StatusBadge.js +2 -2
- package/dist/components/statusdot/StatusDot.js +2 -2
- package/dist/components/statusmessage/StatusMessage.js +2 -2
- package/dist/components/statusmessage/StatusMessage.js.map +1 -1
- package/dist/components/statusmessage/StatusMessage.svelte +5 -0
- package/dist/components/statusnotification/StatusNotification.js +2 -2
- package/dist/components/statusnotification/StatusNotification.js.map +1 -1
- package/dist/components/statusnotification/StatusNotification.svelte +5 -0
- package/dist/components/stepperbottombar/StepperBottomBar.js +1 -1
- package/dist/components/steppercompact/StepperCompact.js +2 -2
- package/dist/components/stepperinline/README.md +6 -2
- package/dist/components/stepperinline/StepperInline.js +2 -2
- package/dist/components/stepperinline/StepperInline.js.map +1 -1
- package/dist/components/stepperinline/StepperInline.spec.js +57 -23
- package/dist/components/stepperinline/StepperInline.stories.d.ts.map +1 -1
- package/dist/components/stepperinline/StepperInline.stories.js +6 -11
- package/dist/components/stepperinline/StepperInline.svelte +23 -10
- package/dist/components/stepperinline/StepperInline.svelte.d.ts +10 -2
- package/dist/components/stepperinline/StepperInline.svelte.d.ts.map +1 -1
- package/dist/components/stepperstacked/README.md +15 -0
- package/dist/components/stepperstacked/StepperStacked.js +18 -0
- package/dist/components/stepperstacked/StepperStacked.js.map +1 -0
- package/dist/components/stepperstacked/StepperStacked.spec.js +138 -0
- package/dist/components/stepperstacked/StepperStacked.stories.d.ts +8 -0
- package/dist/components/stepperstacked/StepperStacked.stories.d.ts.map +1 -0
- package/dist/components/stepperstacked/StepperStacked.stories.js +33 -0
- package/dist/components/stepperstacked/StepperStacked.svelte +214 -0
- package/dist/components/stepperstacked/StepperStacked.svelte.d.ts +35 -0
- package/dist/components/stepperstacked/StepperStacked.svelte.d.ts.map +1 -0
- package/dist/components/tab/README.md +1 -0
- package/dist/components/tab/Tab.js +2 -2
- package/dist/components/tab/Tab.js.map +1 -1
- package/dist/components/tab/Tab.svelte +17 -1
- package/dist/components/tab/Tab.svelte.d.ts +4 -0
- package/dist/components/tab/Tab.svelte.d.ts.map +1 -1
- package/dist/components/tabs/Tabs.js +1 -1
- package/dist/components/tabs/Tabs.stories.d.ts +1 -0
- package/dist/components/tabs/Tabs.stories.d.ts.map +1 -1
- package/dist/components/tabs/Tabs.stories.js +10 -0
- package/dist/components/tag/README.md +1 -0
- package/dist/components/tag/Tag.js +2 -2
- package/dist/components/tag/Tag.js.map +1 -1
- package/dist/components/tag/Tag.svelte +7 -0
- package/dist/components/tag/Tag.svelte.d.ts +4 -0
- package/dist/components/tag/Tag.svelte.d.ts.map +1 -1
- package/dist/components/textarea/Textarea.js +2 -2
- package/dist/components/textarea/Textarea.js.map +1 -1
- package/dist/components/textarea/Textarea.svelte +1 -0
- package/dist/components/textinput/README.md +1 -0
- package/dist/components/textinput/Textinput.js +4 -4
- package/dist/components/textinput/Textinput.js.map +1 -1
- package/dist/components/textinput/Textinput.stories.d.ts.map +1 -1
- package/dist/components/textinput/Textinput.stories.js +1 -0
- package/dist/components/textinput/Textinput.svelte +5 -1
- package/dist/components/textinput/Textinput.svelte.d.ts +2 -1
- package/dist/components/textinput/Textinput.svelte.d.ts.map +1 -1
- package/dist/components/tile/Tile.js +1 -1
- package/dist/components/tileclickable/TileClickable.js +1 -1
- package/dist/components/tileexpandable/TileExpandable.js +1 -1
- package/dist/components/tileselectable/TileSelectable.js +2 -2
- package/dist/components/toaster/Toaster.js +3 -3
- package/dist/components/toaster/Toaster.js.map +1 -1
- package/dist/components/toaster/Toaster.svelte +6 -1
- package/dist/components/toggle/Toggle.js +1 -1
- package/dist/components/togglegroup/ToggleGroup.js +2 -2
- package/dist/components/tooltip/Tooltip.js +2 -2
- package/dist/custom-element.js +3 -3
- package/dist/custom-element.js.map +1 -1
- package/dist/documentation/DarkMode.mdx +115 -0
- package/dist/each.js +1 -1
- package/dist/each.js.map +1 -1
- package/dist/floating-item.svelte.js +1 -1
- package/dist/if.js +1 -1
- package/dist/if.js.map +1 -1
- package/dist/index-client.js +1 -1
- package/dist/input.js +1 -1
- package/dist/main.d.ts +3 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +3 -1
- package/dist/svelte-component.js +1 -1
- package/dist/svelte-component.js.map +1 -1
- package/dist/svelte-element.js +1 -1
- package/dist/this.js +1 -1
- package/package.json +3 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Combobox.js","sources":["../../../src/components/combobox/Combobox.svelte"],"sourcesContent":["<svelte:options\n customElement={{\n tag: 'm-combobox',\n props: {\n multiple: { reflect: true, type: 'Boolean', attribute: 'multiple' },\n compact: { reflect: true, type: 'Boolean', attribute: 'compact' },\n disabled: { reflect: true, type: 'Boolean', attribute: 'disabled' },\n readonly: { reflect: true, type: 'Boolean', attribute: 'readonly' },\n invalid: { reflect: true, type: 'Boolean', attribute: 'invalid' },\n clearable: { reflect: true, type: 'Boolean', attribute: 'clearable' },\n search: { reflect: true, type: 'Boolean', attribute: 'search' },\n actions: { reflect: true, type: 'Boolean', attribute: 'actions' },\n checkablesections: { reflect: true, type: 'Boolean', attribute: 'checkablesections' },\n },\n }}\n/>\n\n<script lang=\"ts\">\n import { onDestroy } from 'svelte';\n import OptionListbox, { type ListboxOption } from '../optionlistbox/OptionListbox.svelte';\n import { ChevronDown24, CrossCircleFilled24 } from '@mozaic-ds/icons-svelte';\n\n /**\n * A combobox is an input field that allows users to select an option from a dropdown list or enter a custom value. It combines the functionality of a text input and a dropdown menu, providing flexibility and ease of use in forms and user interfaces.\n * @slot optionPrefix - Use this slot to add a prefix to options.\n * @event update:open {CustomEvent<boolean>} - Emitted when the listbox is opened or closed.\n */\n interface Props {\n /**\n * The current selected value(s) of the combobox.\n */\n value: string | number | null | (string | number)[];\n /**\n * Enable multiple value mode.\n */\n multiple?: boolean;\n /**\n * Size of the combobox: small ('s') or medium ('m').\n */\n size?: 's' | 'm';\n /**\n * Disable the combobox input.\n */\n disabled?: boolean;\n /**\n * Make the combobox read-only.\n */\n readonly?: boolean;\n /**\n * Mark the combobox as invalid.\n */\n invalid?: boolean;\n /**\n * Show a clear value button.\n */\n clearable?: boolean;\n /**\n * Enable the search input inside the listbox.\n */\n search?: boolean;\n /**\n * Show select all / clear buttons when multiple.\n */\n actions?: boolean;\n /**\n * Enable checkable section headers in the listbox.\n */\n checkablesections?: boolean;\n /**\n * Placeholder text when no value is selected.\n */\n placeholder?: string;\n /**\n * Label for the selected items counter.\n */\n counterlabel?: string;\n /**\n * Placeholder text for the search input.\n */\n searchplaceholder?: string;\n /**\n * Label for the \"Select all\" button.\n */\n selectlabel?: string;\n /**\n * Label for the \"Clear value\" button.\n */\n clearlabel?: string;\n /**\n * Array of options to display in the listbox.\n */\n options: Array<ListboxOption>;\n /**\n * Callback to trigger when the listbox is opened or closed.\n */\n onopen?: (value: boolean) => void;\n }\n\n let {\n value = $bindable(),\n multiple,\n size = 'm',\n disabled,\n readonly,\n invalid,\n clearable,\n search,\n actions,\n checkablesections,\n placeholder = 'Select an option',\n counterlabel = '99 selected',\n searchplaceholder = 'Find an option...',\n selectlabel = 'Select all',\n clearlabel = 'Clear',\n options,\n onopen,\n }: Props = $props();\n\n const id = crypto.randomUUID();\n\n let combobox: HTMLElement;\n let listbox: InstanceType<typeof OptionListbox> | null = $state(null);\n let listboxEl: HTMLElement | null | undefined = $state(null);\n let comboboxControl: HTMLElement;\n\n let isOpen = $state(false);\n\n let activeIndex = $state(-1);\n\n const activeDescendantId = $derived.by(() => {\n return activeIndex >= 0 ? `option-${id}-${activeIndex}` : undefined;\n });\n\n const selectionLabel = $derived.by(() => {\n if (Array.isArray(value)) {\n if (!value.length) return placeholder;\n return (value as (string | number)[]).join(', ');\n }\n\n return options.find((option) => option.value === value)?.label || placeholder;\n });\n\n const hasValue = $derived.by(() =>\n multiple ? !!(value as (string | number)[]).length : !!value,\n );\n\n function handleClickOutside(event: MouseEvent) {\n const path = event.composedPath ? event.composedPath() : [];\n if (!path.includes(combobox) && !path.includes(listboxEl!)) {\n close();\n }\n }\n\n function open() {\n isOpen = true;\n handleOpen();\n document.addEventListener('click', handleClickOutside);\n }\n\n function close() {\n isOpen = false;\n handleOpen();\n document.removeEventListener('click', handleClickOutside);\n }\n\n function toggleListbox() {\n return isOpen ? close() : open();\n }\n\n function handleOpen() {\n onopen?.(isOpen);\n\n combobox.dispatchEvent(new CustomEvent('update:open', { bubbles: true, composed: true }));\n }\n\n onDestroy(() => {\n document.removeEventListener('click', handleClickOutside);\n });\n</script>\n\n<div\n bind:this={combobox}\n class={{\n 'mc-combobox': true,\n 'mc-combobox--open': isOpen,\n 'mc-combobox--multiple': multiple,\n 'mc-combobox--invalid': invalid,\n 'mc-combobox--s': size === 's',\n 'mc-combobox--disabled': disabled,\n 'mc-combobox--readonly': readonly,\n }}\n>\n <div class=\"mc-combobox__input\">\n <button\n bind:this={comboboxControl}\n aria-expanded={isOpen}\n aria-haspopup=\"listbox\"\n aria-controls={`listbox-${id}`}\n {disabled}\n class=\"mc-combobox__control\"\n aria-label=\"Combobox input\"\n onclick={toggleListbox}\n {...search\n ? {}\n : {\n role: 'combobox',\n 'aria-activedescendant': activeDescendantId,\n onkeydown: listbox?.handleKeydown,\n }}\n >\n {selectionLabel}\n </button>\n {#if multiple}\n <span class=\"mc-combobox__counter\">\n {counterlabel}\n </span>\n {/if}\n\n {#if clearable && hasValue}\n <button\n type=\"button\"\n class=\"mc-combobox__clear\"\n aria-label=\"Clear value\"\n onclick={() => listbox?.clearSelection()}\n >\n <CrossCircleFilled24 />\n </button>\n {/if}\n\n <button\n type=\"button\"\n tabindex={-1}\n class=\"mc-combobox__icon\"\n aria-label=\"Expand options list\"\n onclick={toggleListbox}\n >\n <ChevronDown24 />\n </button>\n </div>\n\n <div class=\"mc-combobox__listbox\">\n <OptionListbox\n bind:this={listbox}\n bind:element={listboxEl}\n bind:value\n {id}\n open={isOpen}\n {multiple}\n {search}\n {actions}\n {checkablesections}\n {searchplaceholder}\n {selectlabel}\n {clearlabel}\n {options}\n activeindex={activeIndex}\n onopen={open}\n onclose={() => {\n close();\n comboboxControl?.focus();\n }}\n >\n <slot name=\"optionPrefix\" slot=\"optionPrefix\" />\n </OptionListbox>\n </div>\n</div>\n\n<style lang=\"scss\">\n @use '@mozaic-ds/styles/components/combobox';\n</style>\n"],"names":["value","$.prop","$$props","multiple","size","disabled","readonly","invalid","clearable","search","actions","checkablesections","placeholder","counterlabel","searchplaceholder","selectlabel","clearlabel","options","onopen","id","combobox","listbox","$.state","listboxEl","comboboxControl","isOpen","activeIndex","activeDescendantId","$.derived","$.get","selectionLabel","option","hasValue","handleClickOutside","event","path","close","open","$.set","handleOpen","toggleListbox","onDestroy","div","root","div_1","$.child","button","text","$.reset","$$value","node","$.sibling","span","root_1","$$render","consequent","button_1","root_2","node_2","CrossCircleFilled24","$.append","$$anchor","consequent_1","button_2","node_1","$.set_attribute","node_3","ChevronDown24","div_2","OptionListbox","node_4","$.delegated"],"mappings":"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"}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { describe, it, expect, vi, afterEach } from 'vitest';
|
|
2
|
+
import { render, fireEvent, screen, cleanup } from '@testing-library/svelte';
|
|
3
|
+
import Combobox from './Combobox.svelte';
|
|
4
|
+
const mockOptions = [
|
|
5
|
+
{ value: 'apple', label: 'Apple' },
|
|
6
|
+
{ value: 'banana', label: 'Banana' },
|
|
7
|
+
{ value: 'cherry', label: 'Cherry' },
|
|
8
|
+
{ value: 'date', label: 'Date' },
|
|
9
|
+
];
|
|
10
|
+
const getControl = () => screen.getByRole('combobox', { name: /combobox input/i });
|
|
11
|
+
const getControlAsButton = () => screen.getByRole('button', { name: /combobox input/i });
|
|
12
|
+
describe('Combobox', () => {
|
|
13
|
+
afterEach(() => {
|
|
14
|
+
cleanup();
|
|
15
|
+
vi.restoreAllMocks();
|
|
16
|
+
});
|
|
17
|
+
describe('Rendering', () => {
|
|
18
|
+
it('renders the combobox control element', () => {
|
|
19
|
+
render(Combobox, { props: { value: null, options: mockOptions } });
|
|
20
|
+
expect(getControl()).toBeTruthy();
|
|
21
|
+
});
|
|
22
|
+
it('shows placeholder when no value', () => {
|
|
23
|
+
render(Combobox, {
|
|
24
|
+
props: { value: null, options: mockOptions, placeholder: 'Pick something' },
|
|
25
|
+
});
|
|
26
|
+
expect(screen.getByText('Pick something')).toBeTruthy();
|
|
27
|
+
});
|
|
28
|
+
it('shows counterlabel in multiple mode (non-compact)', () => {
|
|
29
|
+
render(Combobox, {
|
|
30
|
+
props: {
|
|
31
|
+
value: ['apple', 'banana'],
|
|
32
|
+
options: mockOptions,
|
|
33
|
+
multiple: true,
|
|
34
|
+
counterlabel: '2 selected',
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
expect(screen.getByText('2 selected')).toBeTruthy();
|
|
38
|
+
});
|
|
39
|
+
it('shows joined values as label in multiple+compact mode', () => {
|
|
40
|
+
render(Combobox, {
|
|
41
|
+
props: {
|
|
42
|
+
value: ['apple', 'banana'],
|
|
43
|
+
options: mockOptions,
|
|
44
|
+
multiple: true,
|
|
45
|
+
compact: true,
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
expect(screen.getByText('apple, banana')).toBeTruthy();
|
|
49
|
+
});
|
|
50
|
+
it('does not render removable tags in compact mode', () => {
|
|
51
|
+
render(Combobox, {
|
|
52
|
+
props: { value: ['apple'], options: mockOptions, multiple: true, compact: true },
|
|
53
|
+
});
|
|
54
|
+
expect(screen.queryByLabelText(/remove/i)).toBeNull();
|
|
55
|
+
});
|
|
56
|
+
it('renders as a native button (no role override) when search prop is true', () => {
|
|
57
|
+
render(Combobox, { props: { value: null, options: mockOptions, search: true } });
|
|
58
|
+
expect(getControlAsButton()).toBeTruthy();
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
describe('CSS modifier classes', () => {
|
|
62
|
+
it('applies mc-combobox--multiple when multiple', () => {
|
|
63
|
+
const { container } = render(Combobox, {
|
|
64
|
+
props: { value: [], options: mockOptions, multiple: true },
|
|
65
|
+
});
|
|
66
|
+
expect(container.querySelector('.mc-combobox--multiple')).toBeTruthy();
|
|
67
|
+
});
|
|
68
|
+
it('applies mc-combobox--invalid when invalid', () => {
|
|
69
|
+
const { container } = render(Combobox, {
|
|
70
|
+
props: { value: null, options: mockOptions, invalid: true },
|
|
71
|
+
});
|
|
72
|
+
expect(container.querySelector('.mc-combobox--invalid')).toBeTruthy();
|
|
73
|
+
});
|
|
74
|
+
it('applies mc-combobox--disabled when disabled', () => {
|
|
75
|
+
const { container } = render(Combobox, {
|
|
76
|
+
props: { value: null, options: mockOptions, disabled: true },
|
|
77
|
+
});
|
|
78
|
+
expect(container.querySelector('.mc-combobox--disabled')).toBeTruthy();
|
|
79
|
+
});
|
|
80
|
+
it('applies mc-combobox--readonly when readonly', () => {
|
|
81
|
+
const { container } = render(Combobox, {
|
|
82
|
+
props: { value: null, options: mockOptions, readonly: true },
|
|
83
|
+
});
|
|
84
|
+
expect(container.querySelector('.mc-combobox--readonly')).toBeTruthy();
|
|
85
|
+
});
|
|
86
|
+
it('applies mc-combobox--s for size s', () => {
|
|
87
|
+
const { container } = render(Combobox, {
|
|
88
|
+
props: { value: null, options: mockOptions, size: 's' },
|
|
89
|
+
});
|
|
90
|
+
expect(container.querySelector('.mc-combobox--s')).toBeTruthy();
|
|
91
|
+
});
|
|
92
|
+
it('does NOT apply mc-combobox--s for size m', () => {
|
|
93
|
+
const { container } = render(Combobox, {
|
|
94
|
+
props: { value: null, options: mockOptions, size: 'm' },
|
|
95
|
+
});
|
|
96
|
+
expect(container.querySelector('.mc-combobox--s')).toBeNull();
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
describe('Open / Close behaviour', () => {
|
|
100
|
+
it('opens the listbox when the control is clicked', async () => {
|
|
101
|
+
const { container } = render(Combobox, { props: { value: null, options: mockOptions } });
|
|
102
|
+
await fireEvent.click(getControl());
|
|
103
|
+
expect(container.querySelector('.mc-combobox--open')).toBeTruthy();
|
|
104
|
+
});
|
|
105
|
+
it('closes the listbox on second click (toggle)', async () => {
|
|
106
|
+
const { container } = render(Combobox, { props: { value: null, options: mockOptions } });
|
|
107
|
+
const control = getControl();
|
|
108
|
+
await fireEvent.click(control);
|
|
109
|
+
await fireEvent.click(control);
|
|
110
|
+
expect(container.querySelector('.mc-combobox--open')).toBeNull();
|
|
111
|
+
});
|
|
112
|
+
it('opens the listbox when the chevron icon button is clicked', async () => {
|
|
113
|
+
const { container } = render(Combobox, { props: { value: null, options: mockOptions } });
|
|
114
|
+
await fireEvent.click(screen.getByRole('button', { name: /expand options list/i }));
|
|
115
|
+
expect(container.querySelector('.mc-combobox--open')).toBeTruthy();
|
|
116
|
+
});
|
|
117
|
+
it('closes the listbox on outside click', async () => {
|
|
118
|
+
const { container } = render(Combobox, { props: { value: null, options: mockOptions } });
|
|
119
|
+
await fireEvent.click(getControl());
|
|
120
|
+
expect(container.querySelector('.mc-combobox--open')).toBeTruthy();
|
|
121
|
+
await fireEvent.click(document.body);
|
|
122
|
+
expect(container.querySelector('.mc-combobox--open')).toBeNull();
|
|
123
|
+
});
|
|
124
|
+
it('sets aria-expanded=true when open', async () => {
|
|
125
|
+
render(Combobox, { props: { value: null, options: mockOptions } });
|
|
126
|
+
const control = getControl();
|
|
127
|
+
await fireEvent.click(control);
|
|
128
|
+
expect(control.getAttribute('aria-expanded')).toBe('true');
|
|
129
|
+
});
|
|
130
|
+
it('sets aria-expanded=false when closed', () => {
|
|
131
|
+
render(Combobox, { props: { value: null, options: mockOptions } });
|
|
132
|
+
expect(getControl().getAttribute('aria-expanded')).toBe('false');
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
describe('Clear button', () => {
|
|
136
|
+
it('shows clear button when clearable and a single value is selected', () => {
|
|
137
|
+
render(Combobox, {
|
|
138
|
+
props: { value: 'apple', options: mockOptions, clearable: true },
|
|
139
|
+
});
|
|
140
|
+
expect(screen.getByRole('button', { name: /clear value/i })).toBeTruthy();
|
|
141
|
+
});
|
|
142
|
+
it('does not show clear button when no value is selected', () => {
|
|
143
|
+
render(Combobox, {
|
|
144
|
+
props: { value: null, options: mockOptions, clearable: true },
|
|
145
|
+
});
|
|
146
|
+
expect(screen.queryByRole('button', { name: /clear value/i })).toBeNull();
|
|
147
|
+
});
|
|
148
|
+
it('does not show clear button when clearable is false', () => {
|
|
149
|
+
render(Combobox, {
|
|
150
|
+
props: { value: 'apple', options: mockOptions, clearable: false },
|
|
151
|
+
});
|
|
152
|
+
expect(screen.queryByRole('button', { name: /clear value/i })).toBeNull();
|
|
153
|
+
});
|
|
154
|
+
it('resets single value to null when clear button is clicked', async () => {
|
|
155
|
+
render(Combobox, {
|
|
156
|
+
props: { value: 'apple', options: mockOptions, clearable: true },
|
|
157
|
+
});
|
|
158
|
+
await fireEvent.click(screen.getByRole('button', { name: /clear value/i }));
|
|
159
|
+
expect(screen.getByText('Select an option')).toBeTruthy();
|
|
160
|
+
});
|
|
161
|
+
it('resets multiple value to [] when clear button is clicked', async () => {
|
|
162
|
+
render(Combobox, {
|
|
163
|
+
props: {
|
|
164
|
+
value: ['apple', 'banana'],
|
|
165
|
+
options: mockOptions,
|
|
166
|
+
clearable: true,
|
|
167
|
+
multiple: true,
|
|
168
|
+
},
|
|
169
|
+
});
|
|
170
|
+
await fireEvent.click(screen.getByRole('button', { name: /clear value/i }));
|
|
171
|
+
expect(screen.getByText('Select an option')).toBeTruthy();
|
|
172
|
+
});
|
|
173
|
+
it('shows clear button in multiple mode when at least one item is selected', () => {
|
|
174
|
+
render(Combobox, {
|
|
175
|
+
props: { value: ['apple'], options: mockOptions, clearable: true, multiple: true },
|
|
176
|
+
});
|
|
177
|
+
expect(screen.getByRole('button', { name: /clear value/i })).toBeTruthy();
|
|
178
|
+
});
|
|
179
|
+
it('hides clear button in multiple mode when value is empty', () => {
|
|
180
|
+
render(Combobox, {
|
|
181
|
+
props: { value: [], options: mockOptions, clearable: true, multiple: true },
|
|
182
|
+
});
|
|
183
|
+
expect(screen.queryByRole('button', { name: /clear value/i })).toBeNull();
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/web-components-vite';
|
|
2
|
+
import './Combobox.svelte';
|
|
3
|
+
declare const meta: Meta;
|
|
4
|
+
export default meta;
|
|
5
|
+
type Story = StoryObj;
|
|
6
|
+
export declare const Standard: Story;
|
|
7
|
+
export declare const Multiple: Story;
|
|
8
|
+
export declare const SearchInput: Story;
|
|
9
|
+
export declare const ActionButtons: Story;
|
|
10
|
+
export declare const WithSections: Story;
|
|
11
|
+
export declare const SelectableSections: Story;
|
|
12
|
+
export declare const Clearable: Story;
|
|
13
|
+
export declare const Disabled: Story;
|
|
14
|
+
export declare const Readonly: Story;
|
|
15
|
+
export declare const Invalid: Story;
|
|
16
|
+
export declare const AdditionalInformation: Story;
|
|
17
|
+
//# sourceMappingURL=Combobox.stories.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Combobox.stories.d.ts","sourceRoot":"","sources":["../../../src/components/combobox/Combobox.stories.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAErE,OAAO,mBAAmB,CAAC;AA4B3B,QAAA,MAAM,IAAI,EAAE,IAwCX,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC;AAEtB,eAAO,MAAM,QAAQ,EAAE,KAAU,CAAC;AAElC,eAAO,MAAM,QAAQ,EAAE,KAKtB,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,KAMzB,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,KAM3B,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,KAI1B,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,KAOhC,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE,KAIvB,CAAC;AAEF,eAAO,MAAM,QAAQ,EAAE,KAItB,CAAC;AAEF,eAAO,MAAM,QAAQ,EAAE,KAItB,CAAC;AAEF,eAAO,MAAM,OAAO,EAAE,KAIrB,CAAC;AAEF,eAAO,MAAM,qBAAqB,EAAE,KAOnC,CAAC"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { html } from 'lit';
|
|
2
|
+
import './Combobox.svelte';
|
|
3
|
+
import { ifDefined } from 'lit-html/directives/if-defined.js';
|
|
4
|
+
const defaultOptions = Array.from({ length: 12 }).map((_el, index) => {
|
|
5
|
+
return {
|
|
6
|
+
id: (index + 1).toString(),
|
|
7
|
+
label: `Option ${index + 1}`,
|
|
8
|
+
value: `option${index + 1}`,
|
|
9
|
+
};
|
|
10
|
+
});
|
|
11
|
+
let optionCount = 0;
|
|
12
|
+
const optionsWithSections = Array.from({ length: 12 }).map((_el, index) => {
|
|
13
|
+
const isSection = index % 3 === 0;
|
|
14
|
+
if (!isSection) {
|
|
15
|
+
optionCount++;
|
|
16
|
+
}
|
|
17
|
+
return {
|
|
18
|
+
label: `${isSection ? 'Section' : 'Option'} ${isSection ? index / 3 + 1 : optionCount}`,
|
|
19
|
+
value: !isSection ? `option${optionCount}` : undefined,
|
|
20
|
+
type: isSection ? 'section' : 'option',
|
|
21
|
+
};
|
|
22
|
+
});
|
|
23
|
+
const meta = {
|
|
24
|
+
title: 'Form elements/Combobox',
|
|
25
|
+
component: 'm-combobox',
|
|
26
|
+
tags: ['v2'],
|
|
27
|
+
parameters: {
|
|
28
|
+
docs: {
|
|
29
|
+
story: {
|
|
30
|
+
height: '300px',
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
args: {
|
|
35
|
+
search: false,
|
|
36
|
+
actions: true,
|
|
37
|
+
value: null,
|
|
38
|
+
checkablesections: true,
|
|
39
|
+
options: defaultOptions,
|
|
40
|
+
},
|
|
41
|
+
render: (args) => html `
|
|
42
|
+
<m-combobox
|
|
43
|
+
.value="${args.value}"
|
|
44
|
+
?multiple="${args.multiple}"
|
|
45
|
+
?compact="${args.compact}"
|
|
46
|
+
size="${ifDefined(args.size)}"
|
|
47
|
+
?disabled="${args.disabled}"
|
|
48
|
+
?readonly="${args.readonly}"
|
|
49
|
+
?invalid="${args.invalid}"
|
|
50
|
+
?clearable="${args.clearable}"
|
|
51
|
+
?search="${args.search}"
|
|
52
|
+
?actions="${args.actions}"
|
|
53
|
+
?checkablesections="${args.checkablesections}"
|
|
54
|
+
placeholder="${ifDefined(args.placeholder)}"
|
|
55
|
+
counterlabel="${ifDefined(args.counterlabel)}"
|
|
56
|
+
searchplaceholder="${ifDefined(args.searchplaceholder)}"
|
|
57
|
+
selectlabel="${ifDefined(args.selectlabel)}"
|
|
58
|
+
clearlabel="${ifDefined(args.clearlabel)}"
|
|
59
|
+
showlabel="${ifDefined(args.showlabel)}"
|
|
60
|
+
.options="${args.options}"
|
|
61
|
+
></m-combobox>
|
|
62
|
+
`,
|
|
63
|
+
};
|
|
64
|
+
export default meta;
|
|
65
|
+
export const Standard = {};
|
|
66
|
+
export const Multiple = {
|
|
67
|
+
args: {
|
|
68
|
+
multiple: true,
|
|
69
|
+
value: [],
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
export const SearchInput = {
|
|
73
|
+
args: {
|
|
74
|
+
search: true,
|
|
75
|
+
value: [],
|
|
76
|
+
multiple: true,
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
export const ActionButtons = {
|
|
80
|
+
args: {
|
|
81
|
+
value: [],
|
|
82
|
+
multiple: true,
|
|
83
|
+
actions: true,
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
export const WithSections = {
|
|
87
|
+
args: {
|
|
88
|
+
options: optionsWithSections,
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
export const SelectableSections = {
|
|
92
|
+
args: {
|
|
93
|
+
value: [],
|
|
94
|
+
multiple: true,
|
|
95
|
+
options: optionsWithSections,
|
|
96
|
+
checkablesections: true,
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
export const Clearable = {
|
|
100
|
+
args: {
|
|
101
|
+
clearable: true,
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
export const Disabled = {
|
|
105
|
+
args: {
|
|
106
|
+
disabled: true,
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
export const Readonly = {
|
|
110
|
+
args: {
|
|
111
|
+
readonly: true,
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
export const Invalid = {
|
|
115
|
+
args: {
|
|
116
|
+
invalid: true,
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
export const AdditionalInformation = {
|
|
120
|
+
args: {
|
|
121
|
+
options: defaultOptions.map((option) => ({
|
|
122
|
+
...option,
|
|
123
|
+
content: 'Additional information',
|
|
124
|
+
})),
|
|
125
|
+
},
|
|
126
|
+
};
|