import { type Meta, type StoryObj } from '@storybook/vue3' import { VBtn } from 'vuetify/components' import DialogBox from './DialogBox.vue' import { fn } from '@storybook/test' import { computed, ref } from 'vue' const meta: Meta = { title: 'Composants/Feedback/DialogBox', component: DialogBox, parameters: { layout: 'fullscreen', docs: { controls: { exclude: ['cancel', 'confirm', 'update:modelValue'], }, }, }, argTypes: { 'headingLevel': { control: { type: 'select' }, options: [1, 2, 3, 4, 5, 6], description: 'Niveau de titre pour le titre de la boîte de dialogue', }, 'modelValue': { control: 'boolean', description: 'Afficher la boîte de dialogue, a utiliser avec `v-model`', table: { category: 'props', }, }, 'title': { control: 'text', description: 'Titre de la boîte de dialogue, utilisable en prop ou slot', table: { type: { summary: 'string', }, }, }, 'default': { control: 'text', description: 'Contenu de la boîte de dialogue', table: { type: { summary: '{}', }, }, }, 'actions': { control: 'text', description: 'Contenu des actions de la boîte de dialogue', table: { type: { summary: '{}', }, }, }, 'width': { control: 'text', description: 'Largeur max de la boîte de dialogue', table: { type: { summary: 'string', }, }, }, 'cancelBtnText': { control: 'text', description: 'Texte du bouton d\'annulation', table: { type: { summary: 'string', }, defaultValue: { summary: `'Annuler'`, }, }, }, 'confirmBtnText': { control: 'text', description: 'Texte du bouton de confirmation', table: { type: { summary: 'string', }, defaultValue: { summary: `'Confirmer'`, }, }, }, 'hideActions': { control: 'boolean', description: 'Masquer les actions', table: { type: { summary: 'boolean', }, }, }, 'persistent': { control: 'boolean', description: 'Masquer le bouton de fermeture', table: { type: { summary: 'boolean', }, }, }, 'autofocusValidateBtn': { control: 'boolean', description: 'Focus automatique sur le bouton de validation à l\'ouverture', table: { type: { summary: 'boolean', }, defaultValue: { summary: 'false', }, }, }, 'draggable': { control: 'boolean', description: 'Rendre la boîte de dialogue déplaçable avec la souris ou les flèches du clavier', table: { type: { summary: 'boolean', }, defaultValue: { summary: 'false', }, }, }, 'vuetifyOptions': { control: 'object', description: 'Personnalisation des composants Vuetify internes', table: { category: 'props', defaultValue: { detail: ` { card: { class: 'pa-6', }, cardTitle: { class: 'd-flex align-start flex-nowrap pa-0 mb-6 mr-6', }, closeBtn: { icon: true, elevation: 0, width: '32px', height: '32px', class: 'mt-n2 mr-n2 ml-4', }, cardActions: { class: 'd-flex flex-wrap mt-6', }, cancelBtn: { color: 'primary', variant: 'text', }, confirmBtn: { color: 'primary', }, }`, }, type: { summary: 'Record', detail: ` { card?: Record, cardTitle?: Record, spacer?: Record, closeBtn?: Record, icon?: Record, actionsBtn?: Record, actionsSpacer?: Record, cancelBtn?: Record, confirmBtn?: Record, } `, }, }, }, 'onCancel': { description: 'Callback sur annulation', table: { category: 'events', }, }, 'onConfirm': { description: 'Callback sur confirmation', table: { category: 'events', }, }, 'onUpdate:modelValue': { description: 'Callback sur mise à jour de la valeur', table: { category: 'events', }, }, 'scrollable': { control: 'boolean', description: 'Rendre le contenu de la boîte de dialogue scrollable', table: { type: { summary: 'boolean', }, defaultValue: { summary: 'false', }, }, }, }, } satisfies Meta export default meta type Story = StoryObj export const Default: Story = { args: { 'headingLevel': 2, 'modelValue': false, 'title': 'DialogBox title', 'default': 'DialogBox content', 'onCancel': fn(), 'onConfirm': fn(), 'onUpdate:modelValue': fn(), }, render: (args) => { return { components: { DialogBox, VBtn }, setup() { const rest = computed(() => { // eslint-disable-next-line @typescript-eslint/no-unused-vars const { default: _, ...rest } = args return rest }) return { args, rest } }, template: `
Toggle DialogBox {{ args.default }}
`, } }, parameters: { sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, } export const ButtonTexts: Story = { args: { 'headingLevel': 2, 'modelValue': false, 'title': 'DialogBox title', 'default': 'DialogBox content', 'cancelBtnText': 'Retour', 'confirmBtnText': 'Valider', 'onCancel': fn(), 'onConfirm': fn(), 'onUpdate:modelValue': fn(), }, render: (args) => { return { components: { DialogBox, VBtn }, setup() { return { args } }, template: `
Toggle DialogBox {{ args.default }}
`, } }, parameters: { sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, } export const HideActions: Story = { args: { 'modelValue': false, 'title': 'DialogBox title', 'default': 'DialogBox content', 'hideActions': true, 'onCancel': fn(), 'onConfirm': fn(), 'onUpdate:modelValue': fn(), }, render: (args) => { return { components: { DialogBox, VBtn }, setup() { return { args } }, template: `
Toggle DialogBox {{ args.default }}
`, } }, parameters: { sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, } export const Persistent: Story = { args: { 'headingLevel': 2, 'modelValue': false, 'title': 'DialogBox title', 'default': 'DialogBox content', 'persistent': true, 'onCancel': fn(), 'onConfirm': fn(), 'onUpdate:modelValue': fn(), }, render: (args) => { return { components: { DialogBox, VBtn }, setup() { return { args } }, template: `
Toggle DialogBox {{ args.default }}
`, } }, parameters: { sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, } export const ActionsSlot: Story = { args: { 'modelValue': false, 'title': 'DialogBox title', 'default': 'DialogBox content', 'headingLevel': 2, 'onCancel': fn(), 'onConfirm': fn(), 'onUpdate:modelValue': fn(), }, render: (args) => { return { components: { DialogBox, VBtn }, setup() { return { args } }, template: `
Toggle DialogBox {{ args.default }}
`, } }, parameters: { sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, } export const TitleSlot: Story = { args: { 'headingLevel': 2, 'modelValue': false, 'default': 'DialogBox content', 'onCancel': fn(), 'onConfirm': fn(), 'onUpdate:modelValue': fn(), }, render: (args) => { return { components: { DialogBox, VBtn }, setup() { return { args } }, template: `
Toggle DialogBox {{ args.default }}
`, } }, parameters: { sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, } export const Width: Story = { args: { 'headingLevel': 2, 'modelValue': false, 'title': 'DialogBox title', 'default': 'DialogBox content', 'width': '500px', 'onCancel': fn(), 'onConfirm': fn(), 'onUpdate:modelValue': fn(), }, render: (args) => { return { components: { DialogBox, VBtn }, setup() { return { args } }, template: `
Toggle DialogBox {{ args.default }}
`, } }, parameters: { sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, } export const VuetifyOptions: Story = { args: { 'headingLevel': 2, 'modelValue': false, 'title': 'DialogBox title', 'default': 'DialogBox content', 'vuetifyOptions': { card: { rounded: 'xl', }, cardTitle: { class: 'pa-5 mb-4 secondary--text', }, closeBtn: { class: { 'd-none': true, }, }, icon: { color: 'secondary', }, cancelBtn: { color: 'secondary', text: false, }, confirmBtn: { color: 'secondary', text: true, }, }, 'onCancel': fn(), 'onConfirm': fn(), 'onUpdate:modelValue': fn(), }, render: (args) => { return { components: { DialogBox, VBtn }, setup() { return { args } }, template: `
Toggle DialogBox {{ args.default }}
`, } }, parameters: { sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, } export const Scrollable: Story = { parameters: { sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { 'headingLevel': 2, 'modelValue': false, 'title': 'DialogBox scrollable', 'scrollable': true, 'width': '600px', 'onCancel': fn(), 'onConfirm': fn(), 'onUpdate:modelValue': fn(), }, render: args => ({ components: { DialogBox, VBtn }, setup() { return { args } }, template: `
Ouvrir la DialogBox scrollable

Ligne de contenu numéro {{ index }}. Ce contenu permet de vérifier que seule la zone centrale de la boîte de dialogue est scrollable, tandis que les boutons d’action restent visibles en bas.

`, }), } export const Draggable: Story = { args: { 'headingLevel': 2, 'modelValue': false, 'title': 'DialogBox title', 'default': 'DialogBox content', 'draggable': true, 'onCancel': fn(), 'onConfirm': fn(), 'onUpdate:modelValue': fn(), }, render: (args) => { return { components: { DialogBox, VBtn }, setup() { return { args } }, template: `
Toggle DialogBox {{ args.default }}
`, } }, parameters: { sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, } export const Tutoriel: Story = { args: { 'headingLevel': 2, 'modelValue': false, 'title': 'Tutoriel', 'hideActions': true, 'width': '800px', 'onCancel': fn(), 'onConfirm': fn(), 'onUpdate:modelValue': fn(), }, render: (args) => { return { components: { DialogBox, VBtn }, setup() { const dialogOpen = ref(false) const currentStep = ref(0) const steps = [ { title: 'Étape 1 : Bienvenue', content: 'Dans cet espace, vous allez pouvoir découvrir les fonctionnalités principales de l\'application. Suivez ce tutoriel pour apprendre à utiliser tous les outils disponibles.', img: 'https://picsum.photos/400/300?random=1', }, { title: 'Étape 2 : Navigation', content: 'Utilisez le menu de navigation pour accéder aux différentes sections. Vous pouvez également utiliser les raccourcis clavier pour une navigation plus rapide.', img: 'https://picsum.photos/400/300?random=2', }, { title: 'Étape 3 : Terminé', content: 'Vous êtes maintenant prêt à utiliser l\'application ! N\'hésitez pas à consulter la documentation pour plus d\'informations.', img: 'https://picsum.photos/400/300?random=3', }, ] const handleNextOrFinish = () => { if (currentStep.value < steps.length - 1) { currentStep.value++ } else { args.onConfirm?.() closeDialog() } } const closeDialog = () => { dialogOpen.value = false setTimeout(() => { currentStep.value = 0 }, 300) } const skipTutorial = () => { args.onCancel?.() closeDialog() } const handleUpdateModelValue = (value: boolean) => { dialogOpen.value = value args['onUpdate:modelValue']?.(value) } const rest = computed(() => { // eslint-disable-next-line @typescript-eslint/no-unused-vars const { modelValue, 'onUpdate:modelValue': _, 'onCancel': __, 'onConfirm': ___, ...rest } = args return rest }) return { args, rest, dialogOpen, currentStep, steps, handleNextOrFinish, skipTutorial, handleUpdateModelValue } }, template: `
Ouvrir le tutoriel

{{ steps[currentStep].title }}

{{ steps[currentStep].content }}

Passer
{{ currentStep + 1 }}/{{ steps.length }}
{{ currentStep < steps.length - 1 ? 'Suivant' : 'Commencer' }}
`, } }, parameters: { sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, }