import type { Meta, StoryObj } from '@storybook/vue3' import { fn } from '@storybook/test' import { computed, defineComponent, ref } from 'vue' import SyTable from './SyTable.vue' import type { DataOptions, FilterType } from '../common/types' import type { VDataTable } from 'vuetify/components' import dayjs from 'dayjs' import { mdiChevronDown, mdiChevronUp } from '@mdi/js' const meta = { title: 'Composants/Tableaux/SyTable', component: SyTable, decorators: [ () => ({ template: '
', }), ], parameters: { layout: 'fullscreen', }, argTypes: { 'headers': { description: 'Liste des colonnes du tableau (voir : https://vuetifyjs.com/en/api/v-data-table/#props-headers)', control: { type: 'object' }, table: { category: 'props', }, }, 'items': { description: 'Liste des éléments à afficher dans le tableau', control: { type: 'object' }, table: { category: 'props', defaultValue: { summary: '[]', }, }, }, 'density': { description: 'Définit la densité du tableau', control: { type: 'select' }, options: ['default', 'comfortable', 'compact'], table: { category: 'props', type: { summary: 'string', detail: `'default' | 'comfortable' | 'compact'` }, }, }, 'striped': { description: 'Affiche les lignes du tableau avec un fond rayé', control: { type: 'boolean' }, table: { category: 'props', type: { summary: 'boolean' }, }, }, 'options': { description: 'Options de configuration du tableau', name: 'v-model:options', control: { type: 'object' }, table: { category: 'props', type: { summary: 'DataOptions', detail: '{ page: number, itemsPerPage: number, sortBy: SortOptions[], groupBy?: SortOptions[], multiSort?: boolean, mustSort?: boolean, filters?: FilterOption[] }' }, }, }, 'itemsPerPageOptions': { description: 'Limite les options disponibles dans le sélecteur "itemsPerPage"', control: { type: 'object' }, table: { category: 'props', type: { summary: 'number[]' }, defaultValue: { summary: 'undefined' }, }, }, 'saveState': { description: 'Permet d\'activer ou non la sauvegarde des options (pagination, tris, ordre des colonnes) du tableau dans le localStorage. Par défaut, cette fonctionnalité est activée.', control: { type: 'boolean' }, }, 'suffix': { description: 'Suffixe permettant de gérer individuellement le stockage des options d\'un tableau d\'une page à l\'autre. Ce prop est obligatoire pour garantir un stockage unique pour chaque tableau.', control: { type: 'text' }, table: { category: 'props', type: { summary: 'string' }, }, required: true, }, 'showExpand': { description: 'Affiche une colonne permettant d\'étendre les lignes pour afficher du contenu supplémentaire', control: { type: 'boolean' }, table: { category: 'props', }, }, 'resizableColumns': { description: 'Permet de redimensionner les colonnes du tableau', control: { type: 'boolean' }, table: { category: 'props', type: { summary: 'boolean' }, }, }, 'multiSort': { description: 'Permet de trier sur plusieurs colonnes simultanément. Lorsque activé, des indicateurs numériques apparaissent à côté des icônes de tri pour montrer l\'ordre de priorité.', control: { type: 'boolean' }, table: { category: 'props', type: { summary: 'boolean' }, defaultValue: { summary: 'false', }, }, }, 'mustSort': { description: 'Force au moins une colonne à être toujours triée. Si désactivé, toutes les colonnes peuvent être non triées.', control: { type: 'boolean' }, table: { category: 'props', type: { summary: 'boolean' }, defaultValue: { summary: 'false', }, }, }, 'caption': { description: 'Texte de la légende du tableau', control: { type: 'text' }, }, 'showFilters': { description: 'Affiche les filtres au-dessus du tableau', control: { type: 'boolean' }, }, 'enableColumnControls': { description: 'Allow the users to re-organize the columns', table: { defaultValue: { summary: 'false', }, type: { summary: 'boolean' }, category: 'props', }, control: { type: 'boolean' }, }, 'showSelect': { description: 'Affiche des cases à cocher pour sélectionner des lignes', control: { type: 'boolean' }, table: { category: 'props', type: { summary: 'boolean' }, }, }, 'showSelectSingle': { description: 'Affiche des cases à cocher pour sélectionner une seule ligne à la fois', control: { type: 'boolean' }, table: { category: 'props', type: { summary: 'boolean' }, }, }, 'stickySelect': { description: 'Rend la colonne de sélection (cases à cocher) sticky à gauche quand showSelect ou showSelectSingle est activé.', control: { type: 'boolean' }, table: { category: 'props', type: { summary: 'boolean' }, defaultValue: { summary: 'false', }, }, }, 'pinnedColumns': { description: 'Liste des colonnes à épingler (sticky). Chaque entrée peut être une clé de colonne (string) ou un objet `{ key: string, side?: \'left\' | \'right\' }`. Par défaut, les colonnes sont épinglées à gauche.', control: { type: 'object' }, table: { category: 'props', type: { summary: 'Array' }, defaultValue: { summary: 'undefined' }, }, }, 'pinnedColumnKey': { description: 'Raccourci pour épingler une seule colonne à gauche. Équivalent à `pinnedColumns: [key]`. Ignoré si `pinnedColumns` est défini.', control: { type: 'text' }, table: { category: 'props', type: { summary: 'string' }, defaultValue: { summary: 'undefined' }, }, }, 'selectionKey': { description: 'Clé utilisée pour identifier chaque ligne lors de la sélection. Par défaut, utilise "id" si présent, sinon l\'objet complet.', control: { type: 'text' }, table: { category: 'props', type: { summary: 'string' }, defaultValue: { summary: 'undefined (fallback: id | objet complet)' }, }, }, 'clickableRow': { description: 'Rend chaque ligne cliquable. Quand cette prop est activée, la ligne devient focusable au clavier et émet `row-click` sur clic, `Entrée` ou `Espace`, sans interférer avec les éléments interactifs imbriqués.', control: { type: 'boolean' }, table: { category: 'props', type: { summary: 'boolean' }, defaultValue: { summary: 'false' }, }, }, 'pageInput': { description: 'Affiche un champ de saisie numérique dans la pagination permettant de naviguer directement vers une page en la saisissant au clavier. La navigation est déclenchée à la validation (`Entrée`) ou à la perte de focus. La valeur est automatiquement clampée entre 1 et le nombre total de pages.', control: { type: 'boolean' }, table: { category: 'props', type: { summary: 'boolean' }, defaultValue: { summary: 'false' }, }, }, 'hideDefaultFooter': { description: 'Masque le footer par défaut du tableau (pagination et contrôles de page). Utile lorsque l\'on souhaite gérer la pagination manuellement ou ne pas en afficher.', control: { type: 'boolean' }, table: { category: 'props', type: { summary: 'boolean' }, defaultValue: { summary: 'false' }, }, }, // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore - 'cookie-description-${cookieName}' storybook can't infer dynamic slot name 'header.': { description: 'Slot permettant de personnaliser le rendu de l\'en-tête d\'une colonne spécifique. Remplacer `` par la clé de la colonne souhaitée.', control: undefined, table: { category: 'slots', type: { summary: 'slot', detail: `{ column: HeaderColumn, headers: HeaderColumn[][], columns: HeaderColumn[], locales: Record string)>, sortBy: DataOptions['sortBy'], someSelected: boolean, allSelected: boolean }`, }, }, }, 'onRow-click': { description: 'Émis lorsqu\'une ligne est activée alors que `clickableRow` est à `true`. Reçoit l\'objet de la ligne en paramètre. Les interactions avec des éléments déjà interactifs dans la ligne ne déclenchent pas cet événement.', table: { category: 'events', type: { summary: '(item: Record) => void' }, }, }, }, } satisfies Meta export default meta type Story = StoryObj export const Default: Story = { parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { 'headers': [ { title: 'Nom', key: 'lastname', }, { title: 'Prénom', key: 'firstname', }, { title: 'Email', value: 'email', }, ], 'items': [ { firstname: 'Virginie', lastname: 'Beauchesne', email: 'virginie.beauchesne@example.com', }, { firstname: 'Simone', lastname: 'Bellefeuille', email: 'simone.bellefeuille@example.com', }, { firstname: 'Étienne', lastname: 'Salois', email: 'etienne.salois@example.com', }, { firstname: 'Thierry', lastname: 'Bobu', email: 'thierry.bobu@example.com', }, { firstname: 'Bernadette', lastname: 'Langelier', email: 'bernadette.langelier@exemple.com', }, { firstname: 'Agate', lastname: 'Roy', email: 'agate.roy@exemple.com', }, ], 'options': { itemsPerPage: 4, }, 'caption': '', 'suffix': 'default-table', 'density': 'default', 'striped': false, 'onUpdate:options': fn(), }, render: (args) => { return { components: { SyTable }, setup() { return { args } }, template: ` `, } }, } export const SortBy: Story = { parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { 'headers': [ { title: 'Nom', key: 'lastname', }, { title: 'Prénom', key: 'firstname', }, { title: 'Email', value: 'email', }, ], 'items': [ { firstname: 'Virginie', lastname: 'Beauchesne', email: 'virginie.beauchesne@example.com', }, { firstname: 'Simone', lastname: 'Bellefeuille', email: 'simone.bellefeuille@example.com', }, { firstname: 'Étienne', lastname: 'Salois', email: 'etienne.salois@example.com', }, { firstname: 'Thierry', lastname: 'Bobu', email: 'thierry.bobu@example.com', }, { firstname: 'Bernadette', lastname: 'Langelier', email: 'bernadette.langelier@exemple.com', }, { firstname: 'Agate', lastname: 'Roy', email: 'agate.roy@exemple.com', }, ], 'caption': '', 'options': { itemsPerPage: 4, sortBy: [ { key: 'lastname', order: 'desc', }, ], }, 'suffix': 'sort-table', 'density': 'default', 'striped': false, 'onUpdate:options': fn(), }, render: (args) => { return { components: { SyTable }, setup() { return { args } }, template: ` `, } }, } export const MultiSort: Story = { parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { 'headers': [ { title: 'Nom', key: 'lastname', }, { title: 'Prénom', key: 'firstname', }, { title: 'Email', value: 'email', }, { title: 'Ville', key: 'city', }, ], 'items': [ { firstname: 'Virginie', lastname: 'Beauchesne', email: 'virginie.beauchesne@example.com', city: 'Paris', }, { firstname: 'Simone', lastname: 'Bellefeuille', email: 'simone.bellefeuille@example.com', city: 'Lyon', }, { firstname: 'Étienne', lastname: 'Salois', email: 'etienne.salois@example.com', city: 'Marseille', }, { firstname: 'Thierry', lastname: 'Bobu', email: 'thierry.bobu@example.com', city: 'Toulouse', }, { firstname: 'Bernadette', lastname: 'Langelier', email: 'bernadette.langelier@exemple.com', city: 'Nice', }, { firstname: 'Agate', lastname: 'Roy', email: 'agate.roy@exemple.com', city: 'Bordeaux', }, { firstname: 'Agate', lastname: 'Beauchesne', email: 'agate.beauchesne@exemple.com', city: 'Lille', }, ], 'caption': '', 'options': { itemsPerPage: 4, multiSort: true, sortBy: [ { key: 'lastname', order: 'desc', }, { key: 'firstname', order: 'asc', }, ], }, 'suffix': 'multi-sort-table', 'density': 'default', 'striped': false, 'multiSort': true, 'onUpdate:options': fn(), }, render: (args) => { return { components: { SyTable }, setup() { return { args } }, template: `

Cet exemple montre le tri multiple avec des indicateurs d'ordre de priorité. Les chiffres à côté des icônes de tri indiquent l'ordre de priorité du tri.

`, } }, } export const FilterByText: Story = { parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { 'headers': [ { title: 'Nom', key: 'lastname', filterable: true, filterType: 'text', }, { title: 'Prénom', key: 'firstname', filterable: true, filterType: 'text', }, { title: 'Email', value: 'email', filterable: true, filterType: 'text', }, ], 'items': [ { firstname: 'Virginie', lastname: 'Beauchesne', email: 'virginie.beauchesne@example.com', }, { firstname: 'Simone', lastname: 'Bellefeuille', email: 'simone.bellefeuille@example.com', }, { firstname: 'Étienne', lastname: 'Salois', email: 'etienne.salois@example.com', }, { firstname: 'Thierry', lastname: 'Bobu', email: 'thierry.bobu@example.com', }, { firstname: 'Bernadette', lastname: 'Langelier', email: 'bernadette.langelier@exemple.com', }, { firstname: 'Agate', lastname: 'Roy', email: 'agate.roy@exemple.com', }, ], 'caption': '', 'options': { itemsPerPage: 4, filters: [], }, 'showFilters': true, 'suffix': 'filter-text-table', 'density': 'default', 'striped': false, 'onUpdate:options': fn(), }, render: (args) => { return { components: { SyTable }, setup() { // Create reactive references const options = ref(args.options) const items = ref(args.items) return { args, options, items, } }, template: ` `, } }, } export const FilterByNumber: Story = { parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { 'headers': [ { title: 'Nom', key: 'name', filterable: true, filterType: 'text', }, { title: 'Âge', key: 'age', filterable: true, filterType: 'number', }, { title: 'Salaire', key: 'salary', filterable: true, filterType: 'number', }, ], 'items': [ { name: 'Jean Dupont', age: 32, salary: 45000, }, { name: 'Marie Martin', age: 28, salary: 52000, }, { name: 'Pierre Durand', age: 45, salary: 65000, }, { name: 'Sophie Petit', age: 36, salary: 48000, }, { name: 'Thomas Leroy', age: 41, salary: 58000, }, ], 'caption': '', 'options': { itemsPerPage: 5, filters: [], }, 'showFilters': true, 'suffix': 'filter-number-table', 'density': 'default', 'striped': false, 'onUpdate:options': fn(), }, render: (args) => { return { components: { SyTable }, setup() { // Create reactive references const options = ref(args.options) const items = ref(args.items) return { args, options, items, } }, template: ` `, } }, } export const FilterBySelect: Story = { parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { 'headers': [ { title: 'Nom', key: 'name', filterable: true, filterType: 'text', }, { title: 'Département', key: 'department', filterable: true, filterType: 'select', multiple: false, chips: false, hideMessages: true, filterOptions: [ { text: 'RH', value: 'RH' }, { text: 'IT', value: 'IT' }, { text: 'Finance', value: 'Finance' }, { text: 'Marketing', value: 'Marketing' }, ], }, { title: 'Statut', key: 'status', filterable: true, filterType: 'select', multiple: false, chips: false, hideMessages: true, filterOptions: [ { text: 'Actif', value: 'Actif' }, { text: 'En congé', value: 'En congé' }, { text: 'Inactif', value: 'Inactif' }, ], }, ], 'items': [ { name: 'Jean Dupont', department: 'RH', status: 'Actif', }, { name: 'Marie Martin', department: 'IT', status: 'En congé', }, { name: 'Pierre Durand', department: 'Finance', status: 'Actif', }, { name: 'Sophie Petit', department: 'Marketing', status: 'Actif', }, { name: 'Thomas Leroy', department: 'IT', status: 'Inactif', }, ], 'caption': '', 'options': { itemsPerPage: 5, filters: [], }, 'showFilters': true, 'suffix': 'filter-select-table', 'density': 'default', 'striped': false, 'onUpdate:options': fn(), }, render: (args) => { return { components: { SyTable }, setup() { // Create reactive references const options = ref(args.options) const items = ref(args.items) return { args, options, items, } }, template: ` `, } }, } export const FilterBySelectMultiple: Story = { parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { 'headers': [ { title: 'Nom', key: 'name', filterable: true, filterType: 'text', }, { title: 'Département', key: 'department', filterable: true, filterType: 'select', multiple: true, chips: true, hideMessages: true, filterOptions: [ { text: 'RH', value: 'RH' }, { text: 'IT', value: 'IT' }, { text: 'Finance', value: 'Finance' }, { text: 'Marketing', value: 'Marketing' }, ], }, { title: 'Statut', key: 'status', filterable: true, filterType: 'select', multiple: true, chips: true, hideMessages: true, filterOptions: [ { text: 'Actif', value: 'Actif' }, { text: 'En congé', value: 'En congé' }, { text: 'Inactif', value: 'Inactif' }, ], }, ], 'items': [ { name: 'Jean Dupont', department: 'RH', status: 'Actif', }, { name: 'Marie Martin', department: 'IT', status: 'En congé', }, { name: 'Pierre Durand', department: 'Finance', status: 'Actif', }, { name: 'Sophie Petit', department: 'Marketing', status: 'Actif', }, { name: 'Thomas Leroy', department: 'IT', status: 'Inactif', }, ], 'caption': '', 'options': { itemsPerPage: 5, filters: [], }, 'showFilters': true, 'suffix': 'filter-select-table', 'density': 'default', 'striped': false, 'onUpdate:options': fn(), }, render: (args) => { return { components: { SyTable }, setup() { // Create reactive references const options = ref(args.options) const items = ref(args.items) return { args, options, items, } }, template: ` `, } }, } export const FilterByAutocomplete: Story = { parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { 'headers': [ { title: 'Nom', key: 'name', filterable: true, filterType: 'text', }, { title: 'Département', key: 'department', filterable: true, filterType: 'autocomplete', filterOptions: [ { text: 'RH', value: 'RH' }, { text: 'IT', value: 'IT' }, { text: 'Finance', value: 'Finance' }, { text: 'Marketing', value: 'Marketing' }, ], }, { title: 'Statut', key: 'status', filterable: true, filterType: 'autocomplete', multiple: true, chips: true, filterOptions: [ { text: 'Actif', value: 'Actif' }, { text: 'En congé', value: 'En congé' }, { text: 'Inactif', value: 'Inactif' }, ], }, ], 'items': [ { name: 'Jean Dupont', department: 'RH', status: 'Actif' }, { name: 'Marie Martin', department: 'IT', status: 'En congé' }, { name: 'Pierre Durand', department: 'Finance', status: 'Actif' }, { name: 'Sophie Petit', department: 'Marketing', status: 'Actif' }, { name: 'Thomas Leroy', department: 'IT', status: 'Inactif' }, ], 'caption': '', 'options': { itemsPerPage: 5, filters: [], }, 'showFilters': true, 'suffix': 'filter-autocomplete-table', 'density': 'default', 'striped': false, 'onUpdate:options': fn(), }, render: (args) => { return { components: { SyTable }, setup() { const options = ref(args.options) const items = ref(args.items) return { args, options, items, } }, template: ` `, } }, } export const FilterByExactDate: Story = { parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { 'headers': [ { title: 'Nom', key: 'name', filterable: true, filterType: 'text', }, { title: 'Date d\'embauche', key: 'hireDate', filterable: true, filterType: 'date', dateFormat: 'DD/MM/YYYY', }, ], 'items': [ { name: 'Jean Dupont', hireDate: dayjs('2025-05-15').format('DD/MM/YYYY'), }, { name: 'Marie Martin', hireDate: dayjs('2025-03-10').format('DD/MM/YYYY'), }, { name: 'Pierre Durand', hireDate: dayjs('2025-11-22').format('DD/MM/YYYY'), }, { name: 'Sophie Petit', hireDate: dayjs('2025-01-08').format('DD/MM/YYYY'), }, { name: 'Thomas Leroy', hireDate: dayjs('2025-07-30').format('DD/MM/YYYY'), }, ], 'caption': '', 'options': { itemsPerPage: 5, filters: [], }, 'showFilters': true, 'suffix': 'filter-date-table', 'density': 'default', 'striped': false, 'onUpdate:options': fn(), }, render: (args) => { return { components: { SyTable }, setup() { // Create reactive references const options = ref(args.options) const items = ref(args.items) return { args, options, items, } }, template: ` `, } }, } export const FilterByPeriod: Story = { parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { 'headers': [ { title: 'Nom', key: 'name', filterable: true, filterType: 'text', }, { title: 'Date d\'embauche', key: 'hireDate', filterable: true, filterType: 'period', dateFormat: 'DD/MM/YYYY', }, ], 'items': [ { name: 'Jean Dupont', hireDate: dayjs('2025-05-15').format('DD/MM/YYYY'), }, { name: 'Marie Martin', hireDate: dayjs('2025-03-10').format('DD/MM/YYYY'), }, { name: 'Pierre Durand', hireDate: dayjs('2025-11-22').format('DD/MM/YYYY'), }, { name: 'Sophie Petit', hireDate: dayjs('2025-01-08').format('DD/MM/YYYY'), }, { name: 'Thomas Leroy', hireDate: dayjs('2025-07-30').format('DD/MM/YYYY'), }, ], 'caption': '', 'options': { itemsPerPage: 5, filters: [], }, 'showFilters': true, 'suffix': 'filter-date-table', 'density': 'default', 'striped': false, 'onUpdate:options': fn(), }, render: (args) => { return { components: { SyTable }, setup() { // Create reactive references const options = ref(args.options) const items = ref(args.items) return { args, options, items, } }, template: ` `, } }, } export const CustomFilterSlot: Story = { parameters: { a11y: { disable: true, }, docs: { description: { story: 'Cette story démontre comment utiliser un slot personnalisé pour le filtrage. Le filtre personnalisé utilise un v-select pour filtrer par statut.', }, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, { name: 'Style', code: ` `, }, ], }, args: { 'headers': [ { title: 'Nom', key: 'lastname', filterable: true, filterType: 'text', }, { title: 'Prénom', key: 'firstname', filterable: true, filterType: 'text', }, { title: 'Statut', key: 'status', filterable: true, filterType: 'custom', }, ], 'items': [ { firstname: 'Virginie', lastname: 'Beauchesne', status: 'Actif', }, { firstname: 'Simone', lastname: 'Bellefeuille', status: 'Inactif', }, { firstname: 'Étienne', lastname: 'Salois', status: 'En attente', }, { firstname: 'Thierry', lastname: 'Bobu', status: 'Actif', }, { firstname: 'Bernadette', lastname: 'Langelier', status: 'Inactif', }, { firstname: 'Agate', lastname: 'Roy', status: 'En attente', }, ], 'caption': '', 'options': { itemsPerPage: 4, filters: [], }, 'showFilters': true, 'suffix': 'custom-filter-slot-table', 'density': 'default', 'striped': false, 'onUpdate:options': fn(), }, render: (args) => { return { components: { SyTable }, setup() { // Create a fresh copy of the options to avoid reactivity issues const options = ref({ page: 1, itemsPerPage: 4, filters: [] as import('../common/types').FilterOption[], sortBy: [], }) // Create a reactive reference for the custom filter value const customFilterValue = ref('') const statusOptions = ['Actif', 'Inactif', 'En attente'] // Function to update the filter when the select value changes function handleFilterChange(val) { // Ensure options.value.filters is initialized if (!options.value.filters) { options.value.filters = [] } // Create a new filters array with proper typing const currentFilters = options.value.filters as import('../common/types').FilterOption[] const newFilters = [...currentFilters].filter(f => f.key !== 'status') // Add the new filter if a value is selected if (val) { newFilters.push({ key: 'status', value: val, type: 'select' as FilterType, // Use 'select' type for compatibility with filtering logic }) } // Update the options with the new filters options.value = { ...options.value, filters: newFilters, } } return { args, options, customFilterValue, statusOptions, handleFilterChange, } }, template: ` `, } }, } export const CustomFilterInputs: Story = { parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { 'headers': [ { title: 'Nom', key: 'lastname', filterable: true, filterType: 'text', }, { title: 'Prénom', key: 'firstname', filterable: true, filterType: 'text', }, { title: 'Email', value: 'email', filterable: true, filterType: 'text', }, ], 'items': [ { firstname: 'Virginie', lastname: 'Beauchesne', email: 'virginie.beauchesne@example.com', }, { firstname: 'Simone', lastname: 'Bellefeuille', email: 'simone.bellefeuille@example.com', }, { firstname: 'Étienne', lastname: 'Salois', email: 'etienne.salois@example.com', }, { firstname: 'Thierry', lastname: 'Bobu', email: 'thierry.bobu@example.com', }, { firstname: 'Bernadette', lastname: 'Langelier', email: 'bernadette.langelier@exemple.com', }, { firstname: 'Agate', lastname: 'Roy', email: 'agate.roy@exemple.com', }, ], 'caption': '', 'options': { itemsPerPage: 4, filters: [], }, 'filterInputConfig': { variant: 'outlined', density: 'comfortable', hideDetails: true, clearable: false, disableErrorHandling: true, }, 'showFilters': true, 'suffix': 'filter-text-table', 'density': 'default', 'striped': false, 'onUpdate:options': fn(), }, render: (args) => { return { components: { SyTable }, setup() { // Create reactive references const options = ref(args.options) const items = ref(args.items) return { args, options, items, } }, template: ` `, } }, } export const ManyTables: Story = { parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { 'headers': [ { title: 'Nom', key: 'lastname', }, { title: 'Prénom', key: 'firstname', }, { title: 'Email', value: 'email', }, ], 'items': [ { firstname: 'Virginie', lastname: 'Beauchesne', email: 'virginie.beauchesne@example.com', }, { firstname: 'Simone', lastname: 'Bellefeuille', email: 'simone.bellefeuille@example.com', }, { firstname: 'Étienne', lastname: 'Salois', email: 'etienne.salois@example.com', }, { firstname: 'Thierry', lastname: 'Bobu', email: 'thierry.bobu@example.com', }, { firstname: 'Bernadette', lastname: 'Langelier', email: 'bernadette.langelier@exemple.com', }, { firstname: 'Agate', lastname: 'Roy', email: 'agate.roy@exemple.com', }, ], 'caption': '', 'suffix': 'multi-server', 'density': 'default', 'striped': false, 'onUpdate:options': fn(), }, render: (args) => { return { components: { SyTable }, setup() { const options1 = ref>({ itemsPerPage: 4, }) const options2 = ref>({ itemsPerPage: 2, }) return { args, options1, options2 } }, template: `
`, } }, } export const DataAlignment: Story = { parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { 'headers': [ { title: 'ID', key: 'id', align: 'center', sortable: false, }, { title: 'Nom', key: 'lastname', align: 'start', sortable: false, }, { title: 'Date de naissance', key: 'birthdate', align: 'center', sortable: false, }, { title: 'NIR', key: 'nir', align: 'end', sortable: false, }, ], 'items': [ { id: '1', lastname: 'Lefebvre', birthdate: '18/02/1989', nir: '1 89 02 75 120 005 79', }, { id: '2', lastname: 'Richard', birthdate: '22/05/1991', nir: '2 91 05 75 120 005 76', }, { id: '3', lastname: 'Fournier', birthdate: '11/11/2000', nir: '2 00 11 42 120 008 87', }, ], 'options': { itemsPerPage: 4, }, 'suffix': 'alignment-table', 'onUpdate:options': fn(), }, render: (args) => { return { components: { SyTable }, setup() { return { args } }, template: ` `, } }, } export const ResizableColumns: Story = { parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { 'resizableColumns': true, 'headers': [ { title: 'Nom', key: 'lastname', }, { title: 'Prénom', key: 'firstname', }, { title: 'Email', value: 'email', }, ], 'items': [ { firstname: 'Virginie', lastname: 'Beauchesne', email: 'virginie.beauchesne@example.com', }, { firstname: 'Simone', lastname: 'Bellefeuille', email: 'simone.bellefeuille@example.com', }, { firstname: 'Étienne', lastname: 'Salois', email: 'etienne.salois@example.com', }, { firstname: 'Thierry', lastname: 'Bobu', email: 'thierry.bobu@example.com', }, { firstname: 'Bernadette', lastname: 'Langelier', email: 'bernadette.langelier@exemple.com', }, { firstname: 'Agate', lastname: 'Roy', email: 'agate.roy@exemple.com', }, ], 'options': { itemsPerPage: 4, }, 'suffix': 'resizable-columns', 'onUpdate:options': fn(), }, render: (args) => { return { components: { SyTable }, setup() { return { args } }, template: ` `, } }, } export const ClickableRow: Story = { parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { 'headers': [ { title: 'Nom', key: 'lastname' }, { title: 'Prénom', key: 'firstname' }, { title: 'Email', key: 'email' }, ], 'items': [ { 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' }, ], 'options': { itemsPerPage: 5, filters: [] }, 'clickableRow': true, 'suffix': 'clickable-row-table', 'density': 'default', 'striped': false, 'onUpdate:options': fn(), 'onRow-click': fn(), }, render: (args) => { return { components: { ClickableRowTableCanvas: defineComponent({ components: { SyTable }, emits: ['row-click'], setup() { const boundArgs = computed(() => { return Object.fromEntries(Object.entries(args).filter(([key]) => key !== 'onRow-click')) }) return { args, boundArgs } }, 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 }}
`, } }, } export const RowSelection: Story = { name: 'Row Selection', parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { headers: [ { title: 'Nom', key: 'lastname', }, { title: 'Prénom', key: 'firstname', }, { title: 'Email', value: 'email', }, ], items: [ { firstname: 'Virginie', lastname: 'Beauchesne', email: 'virginie.beauchesne@example.com', }, { firstname: 'Simone', lastname: 'Bellefeuille', email: 'simone.bellefeuille@example.com', }, { firstname: 'Étienne', lastname: 'Salois', email: 'etienne.salois@example.com', }, { firstname: 'Thierry', lastname: 'Bobu', email: 'thierry.bobu@example.com', }, { firstname: 'Bernadette', lastname: 'Langelier', email: 'bernadette.langelier@exemple.com', }, { firstname: 'Agate', lastname: 'Roy', email: 'agate.roy@exemple.com', }, ], options: { itemsPerPage: 4, }, caption: '', suffix: 'selection-table', density: 'default', striped: false, showSelect: true, showFilters: true, }, render(args) { return { components: { SyTable }, setup() { const items = ref(args.items) const selection = ref([]) return { args, selection, items } }, template: `

Item(s) sélectionné(s) ({{ selection.length }})

Nom: {{ typeof item === 'object' ? item.lastname : args.items.find(i => JSON.stringify(i) === item)?.lastname }}
Prénom: {{ typeof item === 'object' ? item.firstname : args.items.find(i => JSON.stringify(i) === item)?.firstname }}
Email: {{ typeof item === 'object' ? item.email : args.items.find(i => JSON.stringify(i) === item)?.email }}
`, } }, } export const SingleRowSelection: Story = { name: 'Single Row Selection', parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { headers: [ { title: 'Nom', key: 'lastname', }, { title: 'Prénom', key: 'firstname', }, { title: 'Email', value: 'email', }, ], items: [ { firstname: 'Virginie', lastname: 'Beauchesne', email: 'virginie.beauchesne@example.com', }, { firstname: 'Simone', lastname: 'Bellefeuille', email: 'simone.bellefeuille@example.com', }, { firstname: 'Étienne', lastname: 'Salois', email: 'etienne.salois@example.com', }, { firstname: 'Thierry', lastname: 'Bobu', email: 'thierry.bobu@example.com', }, { firstname: 'Bernadette', lastname: 'Langelier', email: 'bernadette.langelier@exemple.com', }, { firstname: 'Agate', lastname: 'Roy', email: 'agate.roy@exemple.com', }, ], options: { itemsPerPage: 4, }, caption: '', suffix: 'selection-table', density: 'default', striped: false, showSelectSingle: true, showFilters: true, }, render(args) { return { components: { SyTable }, setup() { const items = ref(args.items) const selection = ref([]) return { args, selection, items } }, template: `

Item(s) sélectionné(s) ({{ selection.length }})

Nom: {{ typeof item === 'object' ? item.lastname : args.items.find(i => JSON.stringify(i) === item)?.lastname }}
Prénom: {{ typeof item === 'object' ? item.firstname : args.items.find(i => JSON.stringify(i) === item)?.firstname }}
Email: {{ typeof item === 'object' ? item.email : args.items.find(i => JSON.stringify(i) === item)?.email }}
`, } }, } export const PinnedColumns: Story = { parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { 'headers': [ { title: 'ID', key: 'id', width: 80 }, { title: 'Nom', key: 'lastname', width: 160 }, { title: 'Prénom', key: 'firstname', width: 160 }, { title: 'Email', key: 'email', width: 240 }, { title: 'Ville', key: 'city', width: 160 }, { title: 'Pays', key: 'country', width: 160 }, { title: 'Téléphone', key: 'phone', width: 180 }, { title: 'Statut', key: 'status', width: 140 }, { title: 'Dernière connexion', key: 'lastLogin', width: 200 }, { title: 'Actions', key: 'actions', width: 140 }, ], 'items': Array.from({ length: 12 }).map((_, i) => ({ id: i + 1, lastname: 'Nom ' + (i + 1), firstname: 'Prénom ' + (i + 1), email: 'user' + (i + 1) + '@example.com', city: 'Paris', country: 'France', phone: '01 02 03 04 05', status: i % 2 === 0 ? 'Actif' : 'Inactif', lastLogin: dayjs().subtract(i, 'day').format('DD/MM/YYYY'), actions: '…', })), 'options': { itemsPerPage: 5, }, 'suffix': 'pinned-columns-table', 'showSelect': true, 'stickySelect': true, 'pinnedColumns': [ { key: 'actions', side: 'right' }, ], 'onUpdate:options': fn(), }, render: (args) => { return { components: { SyTable }, setup() { return { args } }, template: `
`, } }, } export const ColumnControls: Story = { parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: ` `, }, { name: 'Script', code: ` `, }, ], }, args: { 'headers': [ { title: 'Nom', key: 'lastname', }, { title: 'Prénom', key: 'firstname', }, { title: 'Email', value: 'email', }, ], 'items': [ { firstname: 'Virginie', lastname: 'Beauchesne', email: 'virginie.beauchesne@example.com', }, { firstname: 'Simone', lastname: 'Bellefeuille', email: 'simone.bellefeuille@example.com', }, { firstname: 'Étienne', lastname: 'Salois', email: 'etienne.salois@example.com', }, { firstname: 'Thierry', lastname: 'Bobu', email: 'thierry.bobu@example.com', }, { firstname: 'Bernadette', lastname: 'Langelier', email: 'bernadette.langelier@exemple.com', }, { firstname: 'Agate', lastname: 'Roy', email: 'agate.roy@exemple.com', }, ], 'options': { itemsPerPage: 4, }, 'caption': '', 'suffix': 'column-control-table', 'density': 'default', 'striped': false, 'enableColumnControls': true, 'onUpdate:options': fn(), }, render: (args) => { return { components: { SyTable }, setup() { return { args } }, template: ` `, } }, } export const ExpandableRows: Story = { parameters: { a11y: { disable: true, }, sourceCode: [ { name: 'Template', code: `