UNPKG

vueless

Version:

Vue Styleless UI Component Library, powered by Tailwind CSS.

449 lines (404 loc) • 12 kB
import { ref } from "vue"; import { getArgTypes, getSlotNames, getSlotsFragment, getDocsDescription, } from "../../utils/storybook.ts"; import USelect from "../../ui.form-select/USelect.vue"; import URow from "../../ui.container-row/URow.vue"; import UCol from "../../ui.container-col/UCol.vue"; import UBadge from "../../ui.text-badge/UBadge.vue"; import UIcon from "../../ui.image-icon/UIcon.vue"; import ULink from "../../ui.button-link/ULink.vue"; import UAvatar from "../../ui.image-avatar/UAvatar.vue"; import type { Meta, StoryFn } from "@storybook/vue3"; import type { Props } from "../types.ts"; interface USelectArgs extends Props { slotTemplate?: string; enum: "size" | "openDirection" | "labelAlign"; } interface SelectOption { id: string | number; label: string; badge?: string; } export default { id: "3080", title: "Form Inputs & Controls / Select", component: USelect, args: { label: "Choose a city", modelValue: null, options: [ { label: "New York", id: "1" }, { label: "Los Angeles", id: "2" }, { label: "Chicago", id: "3" }, { label: "Houston", id: "4" }, { label: "San Francisco", id: "5" }, ], }, argTypes: { ...getArgTypes(USelect.__name), }, parameters: { docs: { ...getDocsDescription(USelect.__name), story: { height: "300px", }, }, }, } as Meta; const DefaultTemplate: StoryFn<USelectArgs> = (args: USelectArgs) => ({ components: { USelect, UIcon, UBadge, ULink, UAvatar }, setup() { function getSelectedBadge(options: SelectOption[], currentValue: string | number) { return options?.find((option) => option.id === currentValue); } const slots = getSlotNames(USelect.__name); const showAlert = (message: string) => alert(message); return { args, slots, getSelectedBadge, showAlert }; }, template: ` <USelect v-bind="args" v-model="args.modelValue" class="max-w-96" @add="showAlert('You triggered the add action!')" > ${args.slotTemplate || getSlotsFragment("")} </USelect> `, }); const EnumVariantTemplate: StoryFn<USelectArgs> = (args: USelectArgs, { argTypes }) => ({ components: { USelect, UCol }, setup() { let filteredOptions = argTypes?.[args.enum]?.options; if (args.enum === "labelAlign") { filteredOptions = argTypes?.[args.enum]?.options?.filter( (item) => item !== "right" && item !== "topWithDesc", ); } return { args, filteredOptions }; }, template: ` <UCol> <USelect v-for="(option, index) in filteredOptions" :key="index" v-bind="args" v-model="args.modelValue" :[args.enum]="option" :description="option" class="max-w-96" /> </UCol> `, }); const GroupValuesTemplate: StoryFn<USelectArgs> = (args: USelectArgs) => ({ components: { USelect }, setup() { return { args, }; }, template: ` <USelect v-bind="args" v-model="args.modelValue" label="Single" /> <USelect class="mt-5" v-bind="args" v-model="args.modelValueMultiple" label="Multiple" multiple /> `, }); export const Default = DefaultTemplate.bind({}); Default.args = {}; export const Placeholder = DefaultTemplate.bind({}); Placeholder.args = { placeholder: "Start typing to search for a city..." }; export const Description = DefaultTemplate.bind({}); Description.args = { description: "You can only select a city from the list." }; export const Error = DefaultTemplate.bind({}); Error.args = { error: "Please select a city from the list" }; export const Disabled = DefaultTemplate.bind({}); Disabled.args = { disabled: true }; export const LabelPlacement = EnumVariantTemplate.bind({}); LabelPlacement.args = { enum: "labelAlign" }; export const Sizes = EnumVariantTemplate.bind({}); Sizes.args = { enum: "size", multiple: true, modelValue: [] }; export const LargeItemList = DefaultTemplate.bind({}); LargeItemList.args = { options: [...new Array(1000)].map((_, index) => { return { id: index + 1, label: `value ${index + 1}`, badge: "badge" }; }), }; export const Multiple = DefaultTemplate.bind({}); Multiple.args = { multiple: true, modelValue: [] }; export const ClearableAndSearchable = DefaultTemplate.bind({}); ClearableAndSearchable.args = { clearable: false, searchable: false }; ClearableAndSearchable.parameters = { docs: { description: { story: // eslint-disable-next-line vue/max-len "The `clearable` and `searchable` props control whether users can clear the selected value or search within the list. <br/> In this example, both are set to `false`, meaning the selection cannot be cleared, and searching is disabled.", }, }, }; export const OpenDirection = EnumVariantTemplate.bind({}); OpenDirection.args = { enum: "openDirection" }; export const GroupValue = GroupValuesTemplate.bind({}); GroupValue.args = { modelValue: "", groupValueKey: "libs", groupLabelKey: "language", labelKey: "name", valueKey: "name", // TODO: Implement recursion nesting and add ability to use group (nested) options with default options. options: [ { language: "Javascript", libs: [{ name: "Vue.js" }, { name: "Adonis" }], }, { language: "Ruby", libs: [ { name: "Frameworks", isSubGroup: true, level: 2 }, { name: "Rails", level: 3 }, { name: "Sinatra", level: 3 }, ], }, { language: "Other", libs: [{ name: "Laravel" }, { name: "Phoenix" }], }, ], }; export const OptionsLimit2 = DefaultTemplate.bind({}); OptionsLimit2.args = { optionsLimit: 2 }; OptionsLimit2.parameters = { docs: { description: { story: "`optionsLimit` prop controls the number of options displayed in the dropdown.", }, }, }; export const VisibleOptions = DefaultTemplate.bind({}); VisibleOptions.args = { visibleOptions: 3 }; VisibleOptions.parameters = { docs: { description: { story: "`visibleOptions` prop controls the number of options you can see without a scroll.", }, }, }; export const AddOption = DefaultTemplate.bind({}); AddOption.args = { addOption: true }; AddOption.parameters = { docs: { description: { story: // eslint-disable-next-line vue/max-len "The `addOption` prop displays an 'Add option' button, while the `add` event allows handling custom functionality when the button is clicked.", }, }, }; export const OptionSettings = DefaultTemplate.bind({}); OptionSettings.args = { options: [ { label: "1. New York", id: "1" }, { label: "2. Los Angeles", id: "2", isHidden: true }, { label: "3. Chicago", id: "3", onClick: (option) => alert("onClick function for the third option: " + JSON.stringify(option)), }, { label: "4. Houston", id: "4" }, { label: "5. San Francisco", id: "5" }, ], }; OptionSettings.parameters = { docs: { description: { story: // eslint-disable-next-line vue/max-len "The second option of the array is hidden (`isHidden` object property is set to `true`). <br/> The third option has `onClick` event handler: <br/> `onClick: (option: Option) => alert('onClick function for option 3: ' + JSON.stringify(option))`", }, }, }; export const IconProps: StoryFn<USelectArgs> = (args) => ({ components: { USelect, URow }, setup() { const levelOptions = [ { label: "Awesome", id: "1" }, { label: "Good", id: "2" }, { label: "Could be better", id: "3" }, { label: "Terrible", id: "4" }, ]; const roleOptions = [ { label: "Admin", id: "1" }, { label: "CEO", id: "2" }, { label: "Manager", id: "3" }, { label: "Guest", id: "4" }, ]; return { args, levelOptions, roleOptions }; }, template: ` <URow no-mobile> <USelect left-icon="feedback" label="Choose the level of our services" placeholder="Share your feedback with us" :options="levelOptions" /> <USelect right-icon="person" label="Select your role" placeholder="Choose a role from the list" :options="roleOptions" /> </URow> `, }); export const Slots: StoryFn<USelectArgs> = (args) => ({ components: { USelect, UCol, URow, ULink, UBadge, UAvatar }, setup() { const clearModel = ref(null); const clearMultipleModel = ref([]); const beforeToggleModel = ref(null); const afterToggleModel = ref(null); const leftModel = ref(null); const rightModel = ref(null); return { args, clearModel, clearMultipleModel, beforeToggleModel, afterToggleModel, leftModel, rightModel, }; }, template: ` <UCol no-mobile> <USelect v-bind="args" v-model="args.clearModel" label="Slot clear"> <template #clear> <ULink label="Close" /> </template> </USelect> <USelect v-bind="args" v-model="args.clearMultipleModel" multiple label="Slot clear-multiple" > <template #clear-multiple> <ULink label="Close" color="green" /> </template> </USelect> <URow no-mobile> <USelect v-bind="args" v-model="args.beforeToggleModel" label="Slot before-toggle"> <template #before-toggle> <UAvatar /> </template> </USelect> <USelect v-bind="args" v-model="args.afterToggleModel" :config="{ afterToggle: 'pt-0 items-center' }" label="Slot after-toggle" > <template #after-toggle> <UAvatar /> </template> </USelect> </URow> <URow no-mobile> <USelect v-bind="args" v-model="args.leftModel" label="Slot left"> <template #left> <UAvatar /> </template> </USelect> <USelect v-bind="args" v-model="args.rightModel" label="Slot right"> <template #right> <UAvatar /> </template> </USelect> </URow> </UCol> `, }); Slots.parameters = { docs: { story: { height: "500px", }, }, }; export const SlotToggle = DefaultTemplate.bind({}); SlotToggle.args = { slotTemplate: ` <template #toggle="{ opened }"> <UIcon name="expand_circle_down" :class="{ 'rotate-180': opened }" /> </template> `, }; export const SlotSelectedValueLabel = DefaultTemplate.bind({}); SlotSelectedValueLabel.args = { slotTemplate: ` <template #selected-label="{ selectedLabel }"> <UBadge :label="selectedLabel" color="green" /> </template> `, }; export const SlotSelectedValueLabelAfter = DefaultTemplate.bind({}); SlotSelectedValueLabelAfter.args = { options: [ { label: "Venice", id: "1", icon: "sailing", color: "green" }, { label: "Paris", id: "2", icon: "flight", color: "orange" }, ], slotTemplate: ` <template #selected-label-after="{ option }"> <UIcon :name="option.icon" :color="option.color" size="xs" class="ml-1" /> </template> `, }; export const SlotBeforeOption = DefaultTemplate.bind({}); SlotBeforeOption.args = { slotTemplate: ` <template #before-option="{ option, index }"> <UBadge v-if="index === 3" label="Special offer!" color="blue" class="mr-1" /> </template> `, }; export const SlotOption = DefaultTemplate.bind({}); SlotOption.args = { slotTemplate: ` <template #option="{ option, index }"> <UBadge v-if="index === 1" :label="option.label" /> </template> `, }; export const SlotAfterOption = DefaultTemplate.bind({}); SlotAfterOption.args = { slotTemplate: ` <template #after-option="{ option, index }"> <UBadge v-if="index === 2" label="Special offer!" color="blue" class="ml-1" /> </template> `, };