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: `
Ligne cliquée
Nom : {{ selectedRow.lastname }}
Prénom : {{ selectedRow.firstname }}
Email : {{ selectedRow.email }}
`,
},
{
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: `
|
Informations complémentaires :
Plus de détails pour {{ item.firstname }} {{ item.lastname }}.
|
`,
},
{
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: `
|
Informations complémentaires :
Plus de détails pour {{ item.firstname }} {{ item.lastname }}.
|
`,
}),
}