@mozaic-ds/vue
Version:
Mozaic-Vue is the Vue.js implementation of ADEO Design system
192 lines (170 loc) • 4.5 kB
text/typescript
import type { Meta, StoryObj } from '@storybook/vue3-vite';
import MCombobox from './MCombobox.vue';
import { computed, ref } from 'vue';
import type { ListboxOption } from '../optionListbox/MOptionListbox.vue';
import MTag from '../tag/MTag.vue';
import MButton from '../button/MButton.vue';
const defaultOptions = Array.from({ length: 12 }).map((_el, index) => {
return {
label: `Option ${index + 1}`,
value: `option${index + 1}`,
};
});
let optionCount = 0;
const optionsWithSections: ListboxOption[] = Array.from({ length: 12 }).map(
(_el, index) => {
const isSection = index % 3 === 0;
if (!isSection) {
optionCount++;
}
return {
label: `${isSection ? 'Section' : 'Option'} ${isSection ? index / 3 + 1 : optionCount}`,
value: !isSection ? `option${optionCount}` : undefined,
type: isSection ? 'section' : 'option',
};
},
);
const meta: Meta<typeof MCombobox> = {
title: 'Form elements/Combobox',
component: MCombobox,
tags: ['v2'],
parameters: {
docs: {
description: {
component:
'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.',
},
story: {
height: '300px',
},
},
},
args: {
open: false,
modelValue: null,
checkableSections: true,
options: defaultOptions,
},
render: (args) => ({
components: { MCombobox },
setup() {
const counterLabel = computed(
() => `${(args.modelValue as Array<unknown>)?.length} selected`,
);
return { args, counterLabel };
},
template: `
<MCombobox v-bind="args" v-model="args.modelValue" v-model:open="args.open" :counter-label="counterLabel"></MCombobox>
`,
}),
};
export default meta;
type Story = StoryObj<typeof MCombobox>;
export const Default: Story = {};
export const Multiple: Story = {
args: {
multiple: true,
modelValue: [],
},
};
export const SearchInput: Story = {
args: {
search: true,
modelValue: [],
multiple: true,
},
};
export const ActionButtons: Story = {
args: {
modelValue: [],
multiple: true,
actions: true,
},
};
export const WithSections: Story = {
args: {
options: optionsWithSections,
},
};
export const SelectableSections: Story = {
args: {
modelValue: [],
multiple: true,
options: optionsWithSections,
checkableSections: true,
},
};
export const Clearable = {
args: {
clearable: true,
},
};
export const Disabled: Story = {
args: {
disabled: true,
},
};
export const Readonly: Story = {
args: {
readonly: true,
},
};
export const Invalid: Story = {
args: {
invalid: true,
},
};
export const AdditionalInformation: Story = {
args: {
options: defaultOptions.map((option) => ({
...option,
content: 'Additional information',
})),
},
};
export const RemovableTags: Story = {
args: {
modelValue: [],
options: defaultOptions,
multiple: true,
},
render: (args) => ({
components: { MCombobox, MTag, MButton },
setup() {
function findByValue(value: string | number) {
return args.options.find((option) => option.value === value);
}
const open = ref(false);
const maxResultsDisplayed = ref(9);
const counterLabel = computed(
() => `${(args.modelValue as Array<unknown>)?.length} selected`,
);
return { args, counterLabel, maxResultsDisplayed, findByValue, open };
},
template: `
<MCombobox v-bind="args" v-model="args.modelValue" :counter-label="counterLabel" @update:open="open = $event"></MCombobox>
<template
v-if="!open"
>
<div style="width: 300px; display: flex;align-items: center;gap: 10px;flex-wrap: wrap;margin: 16px 0;">
<MTag
v-for="(item, index) in args.modelValue?.slice(0, maxResultsDisplayed)"
:key="index"
id="tag"
:label="findByValue(item)?.label || ''"
type="removable"
size="s"
/>
</div>
<MButton
v-if="args.modelValue?.length > maxResultsDisplayed"
outlined
size="s"
@click="maxResultsDisplayed = args.modelValue?.length"
>
Show more
</MButton>
</template>
`,
}),
};