import type { Meta, StoryObj } from '@storybook/vue3' import SySelect from '../SySelect.vue' import SyForm from '../../../SyForm/SyForm.vue' import { computed, ref, onMounted } from 'vue' import { fn } from '@storybook/test' import { VBtn, VForm } from 'vuetify/components' const meta: Meta = { title: 'Composants/Formulaires/Selects/SySelect/Validation', component: SySelect, parameters: { layout: 'fullscreen', }, args: { 'onUpdate:modelValue': fn(), }, } as Meta export default meta type Story = StoryObj const items = [ { text: 'Option 1', value: '1' }, { text: 'Option 2', value: '2' }, { text: 'Option 3', value: '3' }, ] export const WithError: Story = { parameters: { docs: { description: { story: '« Option 1 » est présélectionnée et déclenche une erreur bloquante au chargement.', }, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { 'items': items, 'label': 'Option', 'onUpdate:modelValue': fn(), }, render: args => ({ components: { SySelect }, setup() { const value = ref('1') const selectRef = ref<{ validateOnSubmit: () => Promise } | null>(null) onMounted(() => { selectRef.value?.validateOnSubmit() }) return { args, value, selectRef } }, template: `
`, }), } export const WithWarning: Story = { parameters: { docs: { description: { story: '« Option 1 » est présélectionnée et déclenche un avertissement (non bloquant) au chargement.', }, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { 'items': items, 'label': 'Option', 'onUpdate:modelValue': fn(), }, render: args => ({ components: { SySelect }, setup() { const value = ref('1') const selectRef = ref<{ validateOnSubmit: () => Promise } | null>(null) onMounted(() => { selectRef.value?.validateOnSubmit() }) return { args, value, selectRef } }, template: `
`, }), } export const WithSuccess: Story = { parameters: { docs: { description: { story: 'Une option est présélectionnée et déclenche la confirmation de succès au chargement.', }, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { 'items': items, 'label': 'Option', 'showSuccessMessages': true, 'onUpdate:modelValue': fn(), }, render: args => ({ components: { SySelect }, setup() { const value = ref('1') const selectRef = ref<{ validateOnSubmit: () => Promise } | null>(null) onMounted(() => { selectRef.value?.validateOnSubmit() }) return { args, value, selectRef } }, template: `
`, }), } export const NoSuccessMessage: Story = { parameters: { docs: { description: { story: 'Avec `showSuccessMessages: false`, l\'état visuel de succès reste actif (bordure verte, icône) mais le message texte n\'est pas affiché. Utile quand un retour positif silencieux est suffisant.', }, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { 'items': items, 'label': 'Option', 'showSuccessMessages': false, 'onUpdate:modelValue': fn(), }, render: args => ({ components: { SySelect }, setup() { const value = ref('1') const selectRef = ref<{ validateOnSubmit: () => Promise } | null>(null) onMounted(() => { selectRef.value?.validateOnSubmit() }) return { args, value, selectRef } }, template: `
`, }), } export const NoValidateOnBlur: Story = { parameters: { docs: { description: { story: 'Dans cette story, une sélection directe garde le composant dans un état neutre. Seuls les boutons activent un scénario de validation visible.', }, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { items, label: 'Option', isValidateOnBlur: false, showSuccessMessages: true, }, render: (args) => { return { components: { SySelect, VBtn }, setup() { const value = ref(null) const selectRef = ref<{ validateOnSubmit: () => Promise } | null>(null) const validationMode = ref<'neutral' | 'invalid' | 'valid'>('neutral') const customRules = computed(() => validationMode.value === 'invalid' ? [{ type: 'custom', options: { validate: (v: string | null) => v !== '1', message: 'Option 1 n\'est pas autorisée.', }, }] : []) const customSuccessRules = computed(() => { if (validationMode.value === 'neutral') { return [{ type: 'custom', options: { validate: () => false, }, }] } if (validationMode.value === 'valid') { return [{ type: 'custom', options: { validate: (v: string | null) => v !== null && v !== undefined, successMessage: 'Option sélectionnée avec succès.', }, }] } return [] }) const handleManualChange = (newValue: string | null) => { validationMode.value = 'neutral' value.value = newValue } const applyButtonValue = async (newValue: string | null) => { validationMode.value = newValue === '1' ? 'invalid' : newValue ? 'valid' : 'neutral' value.value = newValue await selectRef.value?.validateOnSubmit() } return { args, value, selectRef, customRules, customSuccessRules, handleManualChange, applyButtonValue } }, template: `
Définir une valeur invalide Définir une valeur valide Réinitialiser
`, } }, } export const DisableErrorHandling: Story = { parameters: { sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { items, }, render: (args) => { return { components: { SySelect }, setup() { const value1 = ref(null) const value2 = ref(null) return { args, value1, value2 } }, template: `
`, } }, } export const SyFormValidation: Story = { parameters: { docs: { description: { story: 'Exemple d\'utilisation du SySelect dans un formulaire.', }, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { 'items': items, 'label': 'Option', 'required': true, 'displayAsterisk': true, 'onUpdate:modelValue': fn(), }, render: (args) => { return { components: { SySelect, SyForm, VBtn }, setup() { const formData = ref({ option: '', }) const onSubmit = (event: { isValid: boolean }) => { if (event.isValid) { alert(`Formulaire valide : ${JSON.stringify(formData.value)}`) } else { alert('Formulaire invalide : veuillez choisir une option.') } } return { args, formData, onSubmit } }, template: `
Soumettre
`, } }, } export const VFormValidation: Story = { parameters: { docs: { description: { story: 'Intégration avec `VForm` natif Vuetify en conservant la validation Synapse. La soumission appelle `validateOnSubmit()` manuellement sur le champ pour déclencher la validation.', }, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { items, label: 'Option obligatoire', required: true, displayAsterisk: true, }, render: (args) => { return { components: { SySelect, VBtn, VForm }, setup() { const value = ref('') const selectRef = ref<{ validateOnSubmit: () => Promise } | null>(null) async function onSubmit() { const isValid = await selectRef.value?.validateOnSubmit() if (isValid) { alert(`Formulaire valide : ${JSON.stringify(value.value)}`) } else { alert('Formulaire invalide : veuillez choisir une option.') } } return { args, value, selectRef, onSubmit } }, template: `
Soumettre
`, } }, } export const SyFormVuetifyValidation: Story = { parameters: { docs: { description: { story: 'Exemple d\'utilisation de la validation native Vuetify via la prop `useVuetifyValidation`. Les règles sont définies au format Vuetify : des fonctions retournant `true` ou un message d\'erreur. Soumettez le formulaire pour déclencher la validation.', }, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { 'items': items, 'label': 'Option', 'useVuetifyValidation': true, 'showSuccessMessages': false, 'onUpdate:modelValue': fn(), }, render: args => ({ components: { SySelect, SyForm, VBtn }, setup() { const value = ref(null) function onSubmit(event: { isValid: boolean }) { if (event.isValid) { alert(`Formulaire valide : ${value.value}`) } else { alert('Formulaire invalide : veuillez choisir une option.') } } return { args, value, onSubmit } }, template: `
Soumettre
`, }), } export const VFormAndVuetifyValidation: Story = { parameters: { docs: { description: { story: 'Validation native Vuetify (`useVuetifyValidation`) intégrée dans un `VForm` natif (sans SyForm). La soumission du formulaire déclenche la validation via `form.validate()`.', }, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { 'items': items, 'label': 'Option', 'useVuetifyValidation': true, 'onUpdate:modelValue': fn(), }, render: args => ({ components: { SySelect, VBtn, VForm }, setup() { const value = ref(null) const formRef = ref | null>(null) async function onSubmit() { const result = await formRef.value?.validate() if (result?.valid) { alert(`Formulaire valide : ${value.value}`) } } return { args, value, formRef, onSubmit } }, template: `
Soumettre
`, }), }