import { fn } from '@storybook/test' import FileUpload from './FileUpload.vue' import type { Meta, StoryObj } from '@storybook/vue3' import NotificationBar from '@/components/NotificationBar/NotificationBar.vue' import { useNotificationService } from '@/services/NotificationService' import { mdiCloudUpload } from '@mdi/js' import { VIcon } from 'vuetify/components' import { computed, ref } from 'vue' import FileList from '../FileList/FileList.vue' const meta = { title: 'Composants/Formulaires/FileUpload', component: FileUpload, argTypes: { 'modelValue': { description: 'La/Les fichiers de l\'utilisateur', control: 'file', table: { type: { summary: 'File[]', }, disable: false, category: 'props', }, }, 'disabled': { description: 'Désactive le champ', control: 'boolean', table: { type: { summary: 'boolean', }, }, defaultValue: false, }, 'multiple': { description: 'Autorise l\'envoi de plusieurs fichiers', control: 'boolean', table: { type: { summary: 'boolean', }, }, defaultValue: false, }, 'fileSizeMax': { description: 'Taille maximale des fichiers en octets', control: 'number', table: { type: { summary: 'number', }, }, defaultValue: 10485760, }, 'fileSizeUnits': { description: 'Unité de taille des fichiers', control: 'object', table: { type: { summary: 'string[]', }, defaultValue: { summary: '[\'o\', \'Ko\', \'Mo\', \'Go\', \'To\']', }, }, }, 'allowedExtensions': { description: 'Extensions de fichiers autorisées, un tableau vide autorise toutes les extensions', control: 'object', table: { type: { summary: 'string[]', }, defaultValue: { summary: '[\'pdf\', \'jpg\', \'jpeg\', \'png\']', }, }, }, 'maxWidth': { description: 'Largeur maximale du composant', control: 'text', table: { type: { summary: 'number | string', }, category: 'props', }, }, 'minWidth': { description: 'Largeur minimale du composant', control: 'text', table: { type: { summary: 'number | string', }, category: 'props', }, }, 'width': { description: 'Largeur du composant', control: 'text', table: { type: { summary: 'number | string', }, category: 'props', }, }, 'onUpdate:modelValue': { description: 'Événement émis lorsqu\'un fichier est ajouté ou supprimé', table: { type: { summary: 'File[]', }, category: 'events', }, }, 'onError': { description: 'Événement émis lorsqu\'une erreur de validation survient', table: { type: { summary: 'string[]', }, category: 'events', }, }, 'default': { description: 'Intérieur de champ', control: 'text', table: { category: 'slots', type: { summary: undefined, }, }, }, 'icon': { description: 'Icône supérieur', control: 'text', table: { category: 'slots', type: { summary: undefined, }, }, }, 'action-text': { description: 'Texte de l\'appel à l\'action', control: 'text', table: { category: 'slots', type: { summary: undefined, }, }, }, 'or': { description: 'Texte de séparation entre le cta et le bouton', control: 'text', table: { category: 'slots', type: { summary: undefined, }, }, }, 'button-text': { description: 'Texte du bouton', control: 'text', table: { category: 'slots', type: { summary: undefined, }, }, }, 'locales': { description: 'Traductions', control: false, table: { category: 'props', type: { summary: undefined, }, defaultValue: { summary: `Locales`, detail: `{ or: 'Ou', chooseFile: (multiple: boolean) => multiple ? 'Choisir des fichiers' : 'Choisir un fichier', infoText: (max: string, ext: string[]): string => \`Taille max. : \${max}. \${ext.length === 1 ? 'Format accepté' : 'Formats acceptés'} : \${ext.join(', ')}\`, fileSizeUnits: ['o', 'Ko', 'Mo', 'Go', 'To'], dropFilesHere: (multiple: boolean): string => (!multiple ? 'Déposer votre fichier ici' : 'Déposer vos fichiers ici'), errorSize: (fileName: string, max: string): string => \`Le fichier \${fileName} est trop volumineux. Taille max. : \${max}\`, errorExtension: (fileName: string, ext: string[]): string => \`Le fichier \${fileName} a une extension invalide. Extensions acceptées : \${ext.join(', ')}\`, }`, }, }, }, }, parameters: { controls: { exclude: ['error', 'update:modelValue', 'slotName'], }, docs: { controls: { sort: 'requiredFirst', }, }, }, } satisfies Meta export default meta type Story = StoryObj export const Default: Story = { args: { 'modelValue': [], 'multiple': false, 'onUpdate:modelValue': fn(), 'onError': fn(), }, render: args => ({ components: { FileUpload }, setup() { return { args } }, template: `
  • {{ file.name }}
`, }), parameters: { sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, } export const MultipleFiles: Story = { args: { 'modelValue': [], 'multiple': true, 'onUpdate:modelValue': fn(), 'onError': fn(), }, render: args => ({ components: { FileUpload, NotificationBar }, setup() { const { addNotification } = useNotificationService() const sendError = (e: string[]) => { addNotification({ id: Date.now().toString(), message: e.join(', '), type: 'error', timeout: -1, }) } return { args, sendError } }, template: `
  • {{ file.name }}
`, }), parameters: { sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, } export const Customization: Story = { args: { 'modelValue': [], 'onUpdate:modelValue': fn(), 'onError': fn(), 'width': '50%', 'minWidth': '300px', 'maxWidth': '600px', }, render: args => ({ components: { FileUpload, VIcon }, setup() { return { args, uploadIcon: mdiCloudUpload } }, template: `
{{ uploadIcon }} Sélectionner un fichier
  • {{ file.name }}
`, }), parameters: { sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, } export const WithFileList: Story = { args: { 'modelValue': [], 'onUpdate:modelValue': fn(), 'onError': fn(), 'multiple': true, }, render: args => ({ components: { FileUpload, FileList }, setup() { const model = ref>([]) const uploadList = computed( () => model.value.map(item => ({ id: item.name, title: item.name, state: 'success', })), ) function removeFile(itemToRemove: { id: string }) { model.value = model.value.filter(item => item.name !== itemToRemove.id) } return { args, uploadList, removeFile, model } }, template: `
`, }), parameters: { sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, }