import type { Meta, StoryObj } from '@storybook/vue3-vite' import { fn } from 'storybook/test' import { onMounted, ref } from 'vue' import FilePreview from './FilePreview.vue' import FileUpload from '../FileUpload/FileUpload.vue' import SyCheckbox from '../Customs/SyCheckbox/SyCheckbox.vue' const meta: Meta = { title: 'Composants/Données/FilePreview', component: FilePreview, argTypes: { locales: { description: 'Surcharge des chaînes affichées à l\'utilisateur (messages de prévisualisation et de chargement). Les valeurs par défaut sont définies dans le fichier `locales.ts` du composant. La prop accepte un objet partiel : seules les clés renseignées surchargent les valeurs par défaut, le reste est conservé.', control: 'object', table: { type: { summary: 'object', detail: `{ previewNotAvailable: string, previewTypeNotAvailable: string, loadingDocument: string, documentError: string, }` }, category: 'props', }, }, file: { control: false, table: { type: { summary: 'File | Blob', }, category: 'props', }, description: 'Fichier à afficher', }, options: { control: { type: 'object', }, table: { type: { summary: 'Object', detail: `{ pdf?: Record, image?: Record, }`, }, category: 'props', }, description: 'Configuration des attributs pour les balises `object` et `img`. Par défaut, l\'image a une description vide.', }, default: { control: { type: 'text', }, table: { category: 'slots', }, description: 'Remplace le contenu par défaut affiché quand le fichier n\'est pas une image ou un pdf', }, trackConsultation: { control: { type: 'boolean' }, table: { category: 'props', type: { summary: 'boolean' }, defaultValue: { summary: 'false' } }, description: 'Active le suivi de consultation d\'un PDF (rendu via pdf.js, chargé à la demande). Permet d\'utiliser `v-model:complete` et l\'évènement `loaded`. Désactivé par défaut (aperçu natif ``).', }, readonly: { control: { type: 'boolean' }, table: { category: 'props', type: { summary: 'boolean' }, defaultValue: { summary: 'false' } }, description: 'Aperçu en lecture seule : rendu via pdf.js sans barre d\'outils native (téléchargement, impression et annotation indisponibles). Désactivé par défaut (aperçu natif ``).', }, pdfWorkerSrc: { control: false, table: { category: 'props', type: { summary: 'string' } }, description: 'URL du worker pdf.js (optionnel). Par défaut, le worker bundlé est utilisé.', }, complete: { control: false, table: { category: 'props', type: { summary: 'boolean' }, defaultValue: { summary: 'false' } }, description: 'État de consultation complète du document (`v-model:complete`). Passe à `true` quand l\'utilisateur atteint la fin, et revient à `false` au chargement d\'un nouveau document.', }, }, } satisfies Meta export default meta type Story = StoryObj export const Default: Story = { render: args => ({ components: { FilePreview }, template: `
`, setup: () => { const file = ref() return { args, file } }, }), parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: `
`, }, { name: 'Script', code: ` import { ref } from 'vue' import { FilePreview } from '@cnamts/synapse' const file = ref()`, }, ], }, } export const UnsupportedFile: Story = { render: args => ({ components: { FilePreview }, template: ` `, setup: () => { const file = ref({ name: 'document.txt', size: 1000, type: 'text/plain', } as File) return { args, file } }, }), parameters: { sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` import { ref } from 'vue' import { FilePreview } from '@cnamts/synapse' const file = ref({ name: 'document.txt', size: 1000, type: 'text/plain', } as File)`, }, ], }, } export const FromApi: Story = { render: args => ({ components: { FilePreview }, template: ` `, setup: () => { const file = ref() onMounted(() => { fetch('https://picsum.photos/seed/picsum/750/350') .then(res => res.blob()) .then(blob => file.value = blob) }) return { args, file } }, }), parameters: { sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` import { onMounted, ref } from 'vue' import { FilePreview } from '@cnamts/synapse' const file = ref() onMounted(() => { fetch('https://picsum.photos/seed/picsum/750/350') .then(res => res.blob()) .then(blob => file.value = blob) })`, }, ], }, } export const WithFileUpload: Story = { render: args => ({ components: { FilePreview, FileUpload }, template: `
`, setup: () => { const files = ref([]) return { args, files } }, }), parameters: { sourceCode: [ { name: 'Template', code: `
`, }, { name: 'Script', code: ` import { ref } from 'vue' import { FilePreview, FileUpload } from '@cnamts/synapse' const files = ref([])`, }, ], }, } export const ReadOnly: Story = { args: { readonly: true, }, render: args => ({ components: { FilePreview, FileUpload }, template: `
`, setup: () => { const files = ref([]) return { args, files } }, }), parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: `
`, }, { name: 'Script', code: ` import { ref } from 'vue' import { FilePreview, FileUpload } from '@cnamts/synapse' const files = ref([])`, }, ], }, } export const MandatoryReading: Story = { args: { trackConsultation: true, }, render: args => ({ components: { FilePreview, FileUpload, SyCheckbox }, template: `

Faites défiler le document jusqu'à la fin pour activer la case à cocher.

`, setup: () => { const files = ref([]) const hasRead = ref(false) const acknowledged = ref(false) // Actions loggées dans le panneau « Actions » de Storybook const onLoaded = fn().mockName('loaded') const onAcknowledged = fn().mockName('acknowledged') const onComplete = fn().mockName('update:complete') return { args, files, hasRead, acknowledged, onLoaded, onAcknowledged, onComplete } }, }), parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: `
`, }, { name: 'Script', code: ` import { ref } from 'vue' import { FilePreview, FileUpload, SyCheckbox } from '@cnamts/synapse' const files = ref([]) const hasRead = ref(false) const acknowledged = ref(false)`, }, ], }, }