import type { Meta, StoryObj } from '@storybook/vue3' import { computed, onMounted, ref } from 'vue' import SyCheckbox from '../SyCheckbox.vue' import SyForm from '../../SyForm/SyForm.vue' import { VBtn, VForm } from 'vuetify/components' import { getValidationDocumentation } from '@/composables/unifyValidation/documentationValidationProps' const meta: Meta = { title: 'Composants/Formulaires/SyCheckbox/Validation', component: SyCheckbox, decorators: [ () => ({ template: '
' }), ], parameters: { layout: 'fullscreen', docs: { description: { component: 'Stories démontrant les différents cas de validation de SyCheckbox (système unifié). Pour une case unique, « required » signifie que la case doit être cochée.', }, }, }, argTypes: { ...getValidationDocumentation(), label: { control: 'text', description: 'Label de la case' }, }, args: { label: 'J\'accepte les conditions générales', required: true, }, } export default meta type Story = StoryObj /** * Champ requis : la case doit être cochée, sinon une erreur s'affiche à la validation. */ export const WithError: Story = { parameters: { sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ``, }, ], }, render: args => ({ components: { SyCheckbox }, setup() { const accepted = ref(false) const checkboxRef = ref<{ validateOnSubmit: () => Promise } | null>(null) onMounted(() => checkboxRef.value?.validateOnSubmit()) return { args, accepted, checkboxRef } }, template: ``, }), } /** * Avertissement (customWarningRules) : non bloquant. */ export const WithWarning: Story = { args: { required: false, customWarningRules: [{ type: 'custom', options: { validate: (value: unknown) => value === true, warningMessage: 'Il est recommandé de cocher cette case.', }, }], }, parameters: { sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ``, }, ], }, render: args => ({ components: { SyCheckbox }, setup() { const accepted = ref(false) const checkboxRef = ref<{ validateOnSubmit: () => Promise } | null>(null) onMounted(() => checkboxRef.value?.validateOnSubmit()) return { args, accepted, checkboxRef } }, template: ``, }), } /** * Message de succès (customSuccessRules + showSuccessMessages). */ export const WithSuccess: Story = { args: { required: false, showSuccessMessages: true, customSuccessRules: [{ type: 'custom', options: { validate: (value: unknown) => value === true, successMessage: 'Merci d\'avoir accepté.', }, }], }, parameters: { sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ``, }, ], }, render: args => ({ components: { SyCheckbox }, setup() { const accepted = ref(true) const checkboxRef = ref<{ validateOnSubmit: () => Promise } | null>(null) onMounted(() => checkboxRef.value?.validateOnSubmit()) return { args, accepted, checkboxRef } }, template: ``, }), } /** * Règle personnalisée (customRules) avec validation **contextuelle** : ici la case ne peut être * cochée que si un prérequis est validé. C'est un vrai cas d'usage de `customRules`, distinct de * `required` (qui se contente d'exiger que la case soit cochée). */ export const WithCustomRules: Story = { parameters: { docs: { description: { story: 'La règle dépend d\'un état externe (le prérequis). Cocher la case sans valider le prérequis déclenche une erreur.', }, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ``, }, ], }, render: () => ({ components: { SyCheckbox }, setup() { const prerequisite = ref(false) const accepted = ref(false) const customRules = computed(() => [{ type: 'custom', options: { validate: (value: unknown) => value !== true || prerequisite.value, message: 'Vous devez d\'abord valider le prérequis avant de cocher cette case.', }, }]) return { prerequisite, accepted, customRules } }, template: `
`, }), } /** * Messages externes : l'état d'erreur est piloté par la prop errorMessages. */ export const ExternalMessages: Story = { args: { required: false, hasError: true, errorMessages: ['Cette case est invalide (message externe).'], }, parameters: { sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ``, }, ], }, render: args => ({ components: { SyCheckbox }, setup() { const accepted = ref(false) return { args, accepted } }, template: ``, }), } /** * Avec `disableErrorHandling: true`, les règles sont ignorées visuellement : aucune erreur ne * s'affiche même si la case requise reste décochée (utile quand la validation est pilotée ailleurs). */ export const DisableErrorHandling: Story = { args: { required: true, disableErrorHandling: true, }, parameters: { sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ``, }, ], }, render: args => ({ components: { SyCheckbox }, setup() { const accepted = ref(false) const checkboxRef = ref<{ validateOnSubmit: () => Promise } | null>(null) onMounted(() => checkboxRef.value?.validateOnSubmit()) return { args, accepted, checkboxRef } }, template: ``, }), } /** * Intégration avec SyForm : la case s'enregistre automatiquement (useValidatable) * et est validée à la soumission du formulaire. */ export const SyFormValidation: Story = { parameters: { docs: { description: { story: 'Il faut privilégier l\'utilisation de `SyForm`, qui valide automatiquement les composants enregistrés via `useValidatable`.', }, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ``, }, ], }, render: args => ({ components: { SyCheckbox, SyForm, VBtn }, setup() { const accepted = ref(false) function onSubmit(e: { isValid: boolean }) { alert(e.isValid ? 'Formulaire valide !' : 'Veuillez cocher la case.') } return { args, accepted, onSubmit } }, template: ` Valider `, }), } /** * Intégration avec un VForm Vuetify natif : la validation est déclenchée manuellement via la ref * du composant (`validateOnSubmit`). Il est toutefois recommandé d'utiliser `SyForm` pour * l'intégration automatique. */ export const VFormValidation: Story = { parameters: { docs: { description: { story: 'Avec un `VForm` natif, la case n\'est pas auto-enregistrée : on appelle `validateOnSubmit()` via une ref. Préférez `SyForm` (cf. story SyFormValidation).', }, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ``, }, ], }, render: args => ({ components: { SyCheckbox, VForm, VBtn }, setup() { const accepted = ref(false) const checkboxRef = ref<{ validateOnSubmit: () => Promise } | null>(null) async function handleSubmit() { const isValid = await checkboxRef.value?.validateOnSubmit() alert(isValid ? 'Formulaire valide !' : 'Veuillez cocher la case.') } return { args, accepted, checkboxRef, handleSubmit } }, template: ` Valider `, }), } /** * Mode de validation natif Vuetify (`useVuetifyValidation`) intégré à `SyForm`. * Les règles sont de simples fonctions `(value) => true | 'message'`, comme la prop `rules` de Vuetify. */ export const SyFormVuetifyValidation: Story = { parameters: { docs: { description: { story: 'Avec `use-vuetify-validation`, la case délègue sa validation à Vuetify via la prop `rules` (fonctions natives), tout en restant intégrée à `SyForm`.', }, }, sourceCode: [ { name: 'Template', code: ``, }, { name: 'Script', code: ``, }, ], }, render: args => ({ components: { SyCheckbox, SyForm, VBtn }, setup() { const accepted = ref(false) const vuetifyRules = [ (value: boolean | null) => value === true || 'Vous devez cocher cette case.', ] function handleSubmit(e: { isValid: boolean }) { alert(e.isValid ? 'Formulaire valide !' : 'Veuillez cocher la case.') } return { args, accepted, vuetifyRules, handleSubmit } }, template: ` Valider `, }), } /** * Mode de validation natif Vuetify (`useVuetifyValidation`) dans un `VForm` Vuetify. */ export const VFormVuetifyValidation: Story = { parameters: { docs: { description: { story: 'Validation déléguée à Vuetify (`use-vuetify-validation` + `rules`) dans un `VForm` natif.', }, }, sourceCode: [ { name: 'Template', code: ``, }, { name: 'Script', code: ``, }, ], }, render: args => ({ components: { SyCheckbox, VForm, VBtn }, setup() { const accepted = ref(false) const vuetifyRules = [ (value: boolean | null) => value === true || 'Vous devez cocher cette case.', ] async function handleSubmit(e: Promise<{ valid: boolean }>) { const { valid } = await e alert(valid ? 'Formulaire valide !' : 'Veuillez cocher la case.') } return { args, accepted, vuetifyRules, handleSubmit } }, template: ` Valider `, }), }