import { CheckIcon } from '@modrinth/assets'
import type { Meta, StoryObj } from '@storybook/vue3-vite'
import { computed, ref } from 'vue'
import MultiSelect from '../../components/base/MultiSelect.vue'
const meta = {
title: 'Base/MultiSelect',
// @ts-ignore - error comes from generically typed component
component: MultiSelect,
render: (args) => ({
components: { MultiSelect },
setup() {
const selected = ref(args.modelValue)
return { args, selected }
},
template: /*html*/ `
`,
}),
} satisfies Meta
export default meta
type Story = StoryObj
export const Default: Story = {
args: {
options: [
{ value: 'en', label: 'English' },
{ value: 'es', label: 'Spanish' },
{ value: 'fr', label: 'French' },
{ value: 'de', label: 'German' },
{ value: 'zh-CN', label: 'Chinese (Simplified)' },
{ value: 'ko', label: 'Korean' },
{ value: 'ja', label: 'Japanese' },
{ value: 'pt', label: 'Portuguese' },
{ value: 'ru', label: 'Russian' },
{ value: 'it', label: 'Italian' },
{ value: 'ar', label: 'Arabic' },
],
modelValue: ['en', 'es', 'fr', 'zh-CN'],
placeholder: 'Select languages',
},
}
export const WithSearch: Story = {
args: {
...Default.args,
searchable: true,
searchPlaceholder: 'Search versions',
},
}
export const WithSelectAll: Story = {
args: {
...Default.args,
searchable: true,
includeSelectAllOption: true,
searchPlaceholder: 'Search versions',
},
}
export const WithSelectionActions: Story = {
args: {
...Default.args,
searchable: true,
showSelectionActions: true,
searchPlaceholder: 'Search versions',
},
}
export const WithTopSlot: Story = {
args: {
...Default.args,
modelValue: [],
searchable: true,
showSelectionActions: true,
searchPlaceholder: 'Search languages',
placeholder: 'All languages',
},
render: (args) => ({
components: { CheckIcon, MultiSelect },
setup() {
const selected = ref(args.modelValue)
const isAllLanguagesSelected = computed(() => selected.value.length === 0)
const selectAllLanguages = () => {
selected.value = []
}
return { args, isAllLanguagesSelected, selectAllLanguages, selected }
},
template: /*html*/ `
`,
}),
}
export const DropdownMinWidth: Story = {
args: {
...Default.args,
modelValue: ['en'],
dropdownMinWidth: 320,
placeholder: 'Languages',
},
render: (args) => ({
components: { MultiSelect },
setup() {
const selected = ref(args.modelValue)
return { args, selected }
},
template: /*html*/ `
`,
}),
}
export const ManySelected: Story = {
args: {
...Default.args,
modelValue: ['en', 'es', 'fr', 'zh-CN', 'ko', 'ja', 'pt', 'ru', 'it', 'ar', 'de'],
searchable: true,
includeSelectAllOption: true,
},
}
export const TwoTagRows: Story = {
args: {
...ManySelected.args,
maxTagRows: 2,
},
}
export const CustomInputContent: Story = {
args: {
...Default.args,
modelValue: ['en', 'es'],
fitContent: true,
showChevron: false,
clearable: false,
triggerClass:
'h-10 max-w-[16rem] border border-solid border-surface-5 bg-surface-4 px-3 py-1.5 hover:bg-surface-5 hover:brightness-100 active:brightness-100',
},
render: (args) => ({
components: { MultiSelect },
setup() {
const selected = ref(args.modelValue)
const selectedLabel = () => {
if (selected.value.length === 0) return 'All languages'
if (selected.value.length === 1) {
const option = args.options.find((item) => item.value === selected.value[0])
return option?.label ?? '1 selected'
}
return `${selected.value.length} selected`
}
return { args, selected, selectedLabel }
},
template: /*html*/ `
Languages:
{{ selectedLabel() }}
⌄
`,
}),
}
export const WithBottomSlot: Story = {
args: {
...Default.args,
modelValue: ['en', 'es'],
searchable: true,
includeSelectAllOption: true,
},
render: (args) => ({
components: { MultiSelect },
setup() {
const selected = ref(args.modelValue)
const minimum = ref('')
return { args, selected, minimum }
},
template: /*html*/ `
`,
}),
}
export const NoOptions: Story = {
args: {
...Default.args,
options: [],
modelValue: [],
searchable: true,
noOptionsMessage: 'No options available',
},
}
export const Empty: Story = {
args: {
...Default.args,
modelValue: [],
},
}