import type { Meta, StoryObj } from '@storybook/vue3' import SyCheckbox from '@/components/Customs/SyCheckbox/SyCheckbox.vue' import { ref, watch } from 'vue' import { fn } from '@storybook/test' // Interface pour typer correctement le composant SyCheckbox avec sa méthode validateOnSubmit interface SyCheckboxInstance { validateOnSubmit: () => Promise } const meta = { title: 'Composants/Formulaires/SyCheckbox', component: SyCheckbox, decorators: [ () => ({ template: '
', }), ], parameters: { layout: 'fullscreen', controls: { exclude: ['modelValue', 'errorMessages', 'warningMessages', 'successMessages'] }, docs: { description: { component: `SyCheckbox est un composant de case à cocher tri-état qui étend le composant VCheckbox de Vuetify avec des fonctionnalités supplémentaires comme la validation personnalisée et l'état indéterminé.`, }, }, }, argTypes: { modelValue: { control: 'boolean' }, label: { description: 'Texte affiché comme label de la case à cocher', control: 'text', }, color: { control: 'select', options: ['primary', 'success', 'error', 'warning'], description: 'Couleur de la case à cocher', }, indeterminate: { description: 'État indéterminé de la case à cocher', control: 'boolean', }, disabled: { description: 'Désactive la case à cocher', control: 'boolean', }, readonly: { description: 'Rend la case à cocher en lecture seule', control: 'boolean', }, required: { description: 'Rend la case à cocher obligatoire', control: 'boolean', }, hideDetails: { description: 'Masque les détails (messages d\'erreur, etc.)', control: 'boolean', }, density: { control: 'select', options: ['default', 'comfortable', 'compact'], description: 'Densité de la case à cocher', }, customRules: { description: 'Règles de validation personnalisées', control: 'object', }, customWarningRules: { description: 'Règles d\'avertissement personnalisées', control: 'object', }, customSuccessRules: { description: 'Règles de succès personnalisées', control: 'object', }, showSuccessMessages: { description: 'Afficher les messages de succès', control: 'boolean', }, isValidateOnBlur: { description: 'Vérifie la validité lors de la perte de focus', control: 'boolean', default: true, }, disableErrorHandling: { control: 'boolean', description: 'Désactive complètement la validation des règles et l\'affichage des erreurs', }, controlsIds: { description: 'IDs des éléments contrôlés par cette case à cocher (pour l\'état indéterminé)', control: 'object', }, displayAsterisk: { description: 'Afficher l\'astérisque (*) pour indiquer un champ obligatoire', control: 'boolean', }, }, } as Meta export default meta type Story = StoryObj export const Default: Story = { parameters: { sourceCode: [ { name: 'Template', code: ``, }, ], }, args: { 'onUpdate:modelValue': fn(), 'onUpdate:indeterminate': fn(), }, render: args => ({ components: { SyCheckbox }, setup() { const checked = ref(false) return { args, checked } }, template: ``, }), } export const Required: Story = { args: { ...Default.args, required: true, isValidateOnBlur: false, }, render: args => ({ components: { SyCheckbox }, setup() { const checked = ref(false) return { args, checked } }, template: ``, }), parameters: { sourceCode: [ { name: 'Template', code: ``, }, ], docs: { description: { story: ` ### Case à cocher obligatoire Cette case à cocher est marquée comme obligatoire, ce qui déclenchera une validation si elle n'est pas cochée. `, }, }, }, } export const Indeterminate: Story = { args: { ...Default.args, indeterminate: true, }, render: args => ({ components: { SyCheckbox }, setup() { const checked = ref(false) const indeterminate = ref(true) return { args, checked, indeterminate } }, template: ``, }), parameters: { sourceCode: [ { name: 'Template', code: ` `, }, ], docs: { description: { story: ` ### Case à cocher avec état indéterminé Cette case à cocher est dans un état indéterminé, généralement utilisé lorsque certains éléments d'un groupe sont sélectionnés mais pas tous. `, }, }, }, } export const WithControlsIds: Story = { parameters: { sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], docs: { description: { story: ` ### Case à cocher avec contrôle d'éléments enfants Cette case à cocher contrôle un groupe d'éléments enfants. Elle utilise la propriété \`controlsIds\` pour établir la relation entre le parent et les enfants. Lorsque certains enfants sont cochés mais pas tous, le parent passe automatiquement en état indéterminé. La propriété \`controlsIds\` permet de créer une relation sémantique entre une case à cocher parent et ses enfants, ce qui est important pour l'accessibilité. Cette relation est établie via les attributs \`aria-controls\` et les identifiants des cases à cocher enfants. `, }, }, }, render: args => ({ components: { SyCheckbox }, setup() { const parentChecked = ref(false) const parentIndeterminate = ref(false) const childChecked1 = ref(false) const childChecked2 = ref(false) const childChecked3 = ref(false) // Logique pour gérer l'état indéterminé du parent function updateParentState() { const checkedCount = [ childChecked1.value, childChecked2.value, childChecked3.value, ].filter(Boolean).length if (checkedCount === 0) { parentChecked.value = false parentIndeterminate.value = false } else if (checkedCount === 3) { parentChecked.value = true parentIndeterminate.value = false } else { parentChecked.value = false parentIndeterminate.value = true } } // Observer les changements des enfants const watchChild = () => { updateParentState() } // Mettre à jour les enfants lorsque le parent change const watchParent = () => { if (!parentIndeterminate.value) { childChecked1.value = parentChecked.value childChecked2.value = parentChecked.value childChecked3.value = parentChecked.value } } // Configurer les observateurs watch(childChecked1, watchChild) watch(childChecked2, watchChild) watch(childChecked3, watchChild) watch(parentChecked, watchParent) return { args, parentChecked, parentIndeterminate, childChecked1, childChecked2, childChecked3, } }, template: `
`, }), } export const ValidationRules: Story = { parameters: { sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` // Composition API export default { setup() { const checked = ref(false) const rules = [ { type: 'custom', options: { message: 'Cette case doit être cochée pour continuer.', validate: (value) => value === true, }, }, ] return { checked, rules, } } }`, }, ], docs: { description: { story: ` ### Case à cocher avec règles de validation personnalisées Cette case à cocher utilise des règles de validation personnalisées pour vérifier si elle est cochée. `, }, }, }, render: args => ({ components: { SyCheckbox }, setup() { const checked = ref(false) return { args, checked, rules: [ { type: 'custom', options: { message: 'Cette case doit être cochée pour continuer.', validate: (value: boolean) => value === true, }, }, ], isValidateOnBlur: false, } }, template: ` `, }), } export const DisabledState: Story = { args: { ...Default.args, disabled: true, }, render: args => ({ components: { SyCheckbox }, setup() { const checked = ref(true) return { args, checked } }, template: ``, }), parameters: { sourceCode: [ { name: 'Template', code: ``, }, ], docs: { description: { story: ` ### Case à cocher désactivée Cette case à cocher est désactivée et ne peut pas être modifiée par l'utilisateur. `, }, }, }, } export const ReadonlyState: Story = { args: { ...Default.args, readonly: true, }, render: args => ({ components: { SyCheckbox }, setup() { const checked = ref(true) return { args, checked } }, template: ``, }), parameters: { sourceCode: [ { name: 'Template', code: ``, }, ], docs: { description: { story: ` ### Case à cocher en lecture seule Cette case à cocher est en lecture seule et ne peut pas être modifiée par l'utilisateur, mais elle n'est pas visuellement désactivée comme la version disabled. `, }, }, }, } export const DifferentDensities: Story = { parameters: { sourceCode: [ { name: 'Template', code: `
`, }, ], docs: { description: { story: ` ### Différentes densités Le composant SyCheckbox prend en charge différentes densités pour s'adapter à différents contextes d'interface utilisateur. `, }, }, }, render: args => ({ components: { SyCheckbox }, setup() { const checked1 = ref(false) const checked2 = ref(false) const checked3 = ref(false) return { args, checked1, checked2, checked3 } }, template: `
`, }), } export const CustomColors: Story = { parameters: { sourceCode: [ { name: 'Template', code: `
`, }, ], docs: { description: { story: ` ### Couleurs personnalisées Le composant SyCheckbox peut être personnalisé avec différentes couleurs pour s'adapter à votre thème. `, }, }, }, render: args => ({ components: { SyCheckbox }, setup() { const checked1 = ref(true) const checked2 = ref(true) const checked3 = ref(true) const checked4 = ref(true) const checked5 = ref(true) return { args, checked1, checked2, checked3, checked4, checked5 } }, template: `
`, }), } export const FormValidation: Story = { parameters: { sourceCode: [ { name: 'Template', code: ` `, }, ], docs: { description: { story: ` ### Case à cocher avec validation au moment de la soumission Cette case à cocher utilise des règles de validation personnalisées et valide le formulaire lors de la soumission grâce à la propriété \`validateOnSubmit\`. Le bouton de soumission déclenche la validation et affiche un message de succès si la case est cochée. `, }, }, }, render: args => ({ components: { SyCheckbox }, setup() { const checkbox = ref(null) const checkbox2 = ref(null) const checked = ref(false) const checked2 = ref(false) const formSubmitted = ref(false) const hasError = ref(false) // Revalider quand les valeurs changent watch([checked, checked2], async () => { if (hasError.value && checkbox.value && checkbox2.value) { await checkbox.value.validateOnSubmit() await checkbox2.value.validateOnSubmit() } }) const validateForm = async (): Promise => { if (!checkbox.value || !checkbox2.value) return hasError.value = true const isValid = await checkbox.value.validateOnSubmit() const isValid2 = await checkbox2.value.validateOnSubmit() if (isValid && isValid2) { formSubmitted.value = true hasError.value = false } } return { args, checkbox, checked, checkbox2, checked2, formSubmitted, hasError, rules: [ { type: 'custom', options: { message: 'Cette case doit être cochée pour continuer.', validate: (value: boolean) => value === true, }, }, ], validateForm, } }, template: `

Validation avec règles personnalisées

Validation avec la prop required et display-asterisk

Soumettre

Formulaire soumis avec succès!

`, }), }