import type { Meta, StoryObj } from '@storybook/vue3-vite' import { computed, defineComponent, ref } from 'vue' import { mdiChevronDown, mdiChevronUp } from '@mdi/js' import type { VDataTable } from 'vuetify/components' import SyServerTable from './SyServerTable.vue' import { commonTableArgTypes, commonTableEventArgs } from '../common/storyArgTypes' import { StateEnum } from '../common/constants/StateEnum' import type { DataOptions } from '../common/types' import { serverUsers } from '../common/storyData' import { useServerTableDemo } from '../common/serverStoryHelpers' const meta = { title: 'Composants/Tableaux/SyServerTable/Lignes', component: SyServerTable, decorators: [ () => ({ template: '
', }), ], parameters: { layout: 'fullscreen', }, argTypes: { ...commonTableArgTypes, items: { description: 'Liste des éléments à afficher dans le tableau', control: { type: 'object' }, table: { category: 'props', defaultValue: { summary: 'undefined' }, }, }, serverItemsLength: { description: 'Nombre total d\'éléments à afficher', control: { type: 'number' }, }, }, } satisfies Meta export default meta type Story = StoryObj const serverHeaders = [ { title: 'Nom', key: 'lastname' }, { title: 'Prénom', key: 'firstname' }, { title: 'Email', key: 'email' }, ] const clickableUsers = [ { firstname: 'Virginie', lastname: 'Beauchesne', email: 'virginie.beauchesne@example.com' }, { firstname: 'Étienne', lastname: 'Salois', email: 'etienne.salois@example.com' }, { firstname: 'Alice', lastname: 'Dupont', email: 'alice.dupont@example.com' }, { firstname: 'Marc', lastname: 'Lefevre', email: 'marc.lefevre@example.com' }, ] /** * Lignes cliquables côté serveur (`clickable-row`) : chaque clic émet `@row-click` * avec l'élément de la ligne, indépendamment du chargement serveur. */ export const ClickableRow: Story = { parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { headers: serverHeaders, items: clickableUsers, serverItemsLength: 4, options: { itemsPerPage: 5, filters: [] }, clickableRow: true, suffix: 'clickable-row-server-table', density: 'default', striped: false, ...commonTableEventArgs(), }, render: args => ({ components: { ClickableRowServerTableCanvas: defineComponent({ components: { SyServerTable }, emits: ['row-click'], setup() { const options = ref({ itemsPerPage: 5, page: 1, sortBy: [], filters: [], ...(args.options ?? {}), }) const state = ref(StateEnum.IDLE) const totalUsers = ref(0) const users = ref[]>([]) const allUsers = clickableUsers const boundArgs = computed(() => { return Object.fromEntries( Object.entries(args).filter(([key]) => !['items', 'options', 'serverItemsLength', 'onRow-click'].includes(key)), ) }) const fetchData = async (nextOptions?: DataOptions) => { if (nextOptions) { options.value = { ...options.value, ...nextOptions } } state.value = StateEnum.PENDING await new Promise(resolve => setTimeout(resolve, 500)) const items = [...allUsers] const { page = 1, itemsPerPage = 5, sortBy = [] } = options.value if (sortBy.length > 0) { const [firstSort] = sortBy if (firstSort?.key && firstSort.order) { items.sort((a, b) => { const left = String(a[firstSort.key] ?? '') const right = String(b[firstSort.key] ?? '') return firstSort.order === 'asc' ? left.localeCompare(right) : right.localeCompare(left) }) } } totalUsers.value = items.length users.value = itemsPerPage > 0 ? items.slice((page - 1) * itemsPerPage, page * itemsPerPage) : items state.value = StateEnum.RESOLVED } fetchData() return { boundArgs, fetchData, options, state, totalUsers, users, StateEnum } }, template: ` `, }), }, setup() { const selectedRow = ref | null>(null) const handleRowClick = (item: Record) => { selectedRow.value = item args['onRow-click']?.(item) } return { selectedRow, handleRowClick } }, template: `

Ligne cliquée

Nom : {{ selectedRow.lastname }}
Prénom : {{ selectedRow.firstname }}
Email : {{ selectedRow.email }}
`, }), } /** * Lignes dépliables côté serveur (`show-expand`) : le slot * `#item.data-table-expand` personnalise le déclencheur, et `#expanded-row` le * contenu déplié. Le chargement serveur est mutualisé via `useServerTableDemo`. */ export const ExpandableRows: Story = { parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { options: { itemsPerPage: 5, sortBy: [{ key: 'lastname', order: 'asc' }], page: 1, }, headers: serverHeaders, caption: '', serverItemsLength: 15, showExpand: true, suffix: 'server-expandable', density: 'default', striped: false, ...commonTableEventArgs(), }, render: args => ({ components: { SyServerTable }, setup() { const { items, totalItems, state, options, fetchData, StateEnum } = useServerTableDemo(args, serverUsers) return { args, items, totalItems, state, options, fetchData, StateEnum, mdiChevronDown, mdiChevronUp } }, template: ` `, }), }