import type { Meta, StoryObj } from '@storybook/vue3' import { ref, watch } from 'vue' import AmeliproCustomSelector from './AmeliproCustomSelector.vue' import AmeliproTooltips from '../AmeliproTooltips/AmeliproTooltips.vue' const meta = { argTypes: { 'required': { description: 'Permet de rendre la selection obligatoire d’au moins une option' }, 'change:selected': { description: 'Événement émis au click sur une checkbox/bouton radio retourne le ou les éléments sélectionnés selon si la property unique est activé ou non et un identifiant pour le groupe' }, 'disabled': { description: 'Permet de désactiver le CustomSelector' }, 'groupLabel': { description: 'Label du groupe de checkbox/boutons radios' }, 'itemsPerLine': { description: 'Nombre de boutons par ligne' }, 'labelDescription': { description: 'Id de la tooltip associée au label si il y en a une' }, 'labelInfo': { description: 'Slot pour ajouter une tooltip après le label du groupe si besoin' }, 'labelMarginBottom': { description: 'Valeur du margin-bottom du label' }, 'modelValue': { description: 'Tableau d’objets qui permet de générer les checkbox/boutons radios', table: { type: { detail: `Array<{ disabled?: boolean; isChecked: boolean; label: string; value: string; }[]>`, summary: 'AmeliproCustomSelectorItem[]', }, }, }, 'multipleRequired': { description: 'Permet de rendre la selection multiple obligatoire' }, 'multipleRequiredErrorMessage': { description: 'Message d’erreur affiché lorsque la props multipleRequired est active' }, 'requiredErrorMessage': { description: 'Message d’erreur affiché lorsque la props required est active' }, 'unique': { description: 'Pour avoir seulement un item sélectionnable ' }, 'uniqueId': { description: 'Id unique du groupe de checkbox/boutons radios' }, 'update:model-value': { description: 'Événement émis au changement du v-model' }, }, component: AmeliproCustomSelector, title: 'Composants/Amelipro/Formulaires/AmeliproCustomSelector', } as Meta export default meta type Story = StoryObj const items = [ { id: 'item', isChecked: false, label: 'option 1', value: 'toto', }, { id: 'item2', isChecked: false, label: 'option 2', value: 'titi', }, { id: 'item3', isChecked: true, label: 'option 3', value: 'tutu', }, { id: 'item4', isChecked: false, label: 'option 4', value: 'tata', }, ] export const Default: Story = { args: { groupLabel: 'Mon label', modelValue: items, uniqueId: 'custom-selector-id', }, parameters: { args: {}, sourceCode: [ { name: 'Template', code: ``, }, { name: 'Scripts', code: ``, }, ], }, render: args => ({ components: { AmeliproCustomSelector }, setup() { const model = ref(args.modelValue) // Optional: Keeps v-model in sync with storybook args watch(() => args.modelValue, (newValue) => { model.value = newValue }) return { args, model } }, template: ` `, }), } export const Disabled: Story = { args: { groupLabel: 'Sélecteur désactivé', modelValue: items, uniqueId: 'custom-selector-disabled', disabled: true, }, parameters: { sourceCode: [ { name: 'Template', code: ``, }, { name: 'Script', code: ``, }, ], }, render: args => ({ components: { AmeliproCustomSelector }, setup() { const model = ref(args.modelValue) watch(() => args.modelValue, (newValue) => { model.value = newValue }) return { args, model } }, template: `

Le composant est entièrement désactivé grâce à la prop disabled.

`, }), } export const DisabledItem: Story = { args: { groupLabel: 'Un item désactivé', modelValue: items.map(i => i.id === 'item2' ? { ...i, disabled: true } : i), uniqueId: 'custom-selector-disableditem', }, parameters: { sourceCode: [ { name: 'Template', code: ``, }, { name: 'Script', code: ``, }, ], }, render: args => ({ components: { AmeliproCustomSelector }, setup() { const model = ref(args.modelValue) watch(() => args.modelValue, (newValue) => { model.value = newValue }) return { args, model } }, template: `

Un seul item est désactivé grâce à la prop disabled sur l’item.

`, }), } export const UniqueSelection: Story = { args: { groupLabel: 'Sélection unique (radio)', modelValue: items.map(i => ({ ...i, isChecked: i.id === 'item2' })), uniqueId: 'custom-selector-unique', unique: true, }, parameters: { sourceCode: [ { name: 'Template', code: ``, }, { name: 'Script', code: ``, }, ], }, render: args => ({ components: { AmeliproCustomSelector }, setup() { const model = ref(args.modelValue) watch(() => args.modelValue, (newValue) => { model.value = newValue }) return { args, model } }, template: `

Un seul choix possible grâce à la prop unique (mode radio).

`, }), } export const Required: Story = { args: { groupLabel: 'Sélection obligatoire', modelValue: items, uniqueId: 'custom-selector-required', required: true, requiredErrorMessage: 'Veuillez sélectionner au moins une option.', }, parameters: { sourceCode: [ { name: 'Template', code: ``, }, { name: 'Script', code: ``, }, ], }, render: args => ({ components: { AmeliproCustomSelector }, setup() { const model = ref(args.modelValue) watch(() => args.modelValue, (newValue) => { model.value = newValue }) return { args, model } }, template: `

La sélection d’au moins une option est obligatoire grâce à la prop required.

`, }), } export const MultipleRequired: Story = { args: { groupLabel: 'Sélection multiple obligatoire', modelValue: items, uniqueId: 'custom-selector-multireq', multipleRequired: true, multipleRequiredErrorMessage: 'Veuillez sélectionner au moins deux options.', }, parameters: { sourceCode: [ { name: 'Template', code: ``, }, { name: 'Script', code: ``, }, ], }, render: args => ({ components: { AmeliproCustomSelector }, setup() { const model = ref(args.modelValue) watch(() => args.modelValue, (newValue) => { model.value = newValue }) return { args, model } }, template: `

La sélection de plusieurs options est obligatoire grâce à la prop multipleRequired.

`, }), } export const ItemsPerLine: Story = { args: { groupLabel: '2 boutons par ligne', modelValue: items, uniqueId: 'custom-selector-itemsperline', itemsPerLine: 2, }, parameters: { sourceCode: [ { name: 'Template', code: ``, }, { name: 'Script', code: ``, }, ], }, render: args => ({ components: { AmeliproCustomSelector }, setup() { const model = ref(args.modelValue) watch(() => args.modelValue, (newValue) => { model.value = newValue }) return { args, model } }, template: `

Le nombre de boutons par ligne est défini via la prop itemsPerLine.

`, }), } export const LabelInfo: Story = { args: { groupLabel: 'Label avec info-bulle', modelValue: items, uniqueId: 'custom-selector-labelinfo', }, parameters: { sourceCode: [ { name: 'Template', code: ``, }, { name: 'Script', code: ``, }, ], }, render: args => ({ components: { AmeliproCustomSelector, AmeliproTooltips }, setup() { const model = ref(args.modelValue) watch(() => args.modelValue, (newValue) => { model.value = newValue }) return { args, model } }, template: `

Le slot labelInfo permet d’ajouter une info-bulle au label du groupe.

`, }), } export const LabelDescription: Story = { args: { groupLabel: 'Label avec description', modelValue: items, uniqueId: 'custom-selector-labeldesc', labelDescription: 'description-id', }, parameters: { sourceCode: [ { name: 'Template', code: ``, }, { name: 'Script', code: ``, }, ], }, render: args => ({ components: { AmeliproCustomSelector }, setup() { const model = ref(args.modelValue) watch(() => args.modelValue, (newValue) => { model.value = newValue }) return { args, model } }, template: `

La prop labelDescription permet d’associer une description au composant pour l’accessibilité.

Description associée au composant pour l’accessibilité.

`, }), } export const LabelMarginBottom: Story = { args: { groupLabel: 'Label avec marge personnalisée', modelValue: items, uniqueId: 'custom-selector-labelmb', labelMarginBottom: '32px', }, parameters: { sourceCode: [ { name: 'Template', code: ``, }, { name: 'Script', code: ``, }, ], }, render: args => ({ components: { AmeliproCustomSelector }, setup() { const model = ref(args.modelValue) watch(() => args.modelValue, (newValue) => { model.value = newValue }) return { args, model } }, template: `

La prop labelMarginBottom permet de personnaliser l’espacement sous le label.

`, }), }