# MalioDataTable — Design Spec Composant de tableau de données presentational avec pagination, filtres par slots et lignes cliquables. **Ticket :** MUI-22 **Branche :** `feature/MUI-22-developper-le-composant-datatable` ## Architecture Composant unique `MalioDataTable` dans `app/components/malio/datatable/DataTable.vue`. Pas de décomposition — la pagination est intégrée dans le composant. Le composant est **presentational** : il ne fait aucun fetch. Le parent fournit les données (`items`) et le total (`totalItems`), et réagit aux events de pagination/filtre pour relancer ses propres requêtes API. ## Props | Prop | Type | Défaut | Description | |------|------|--------|-------------| | `id` | `string` | auto-généré | Identifiant HTML du wrapper | | `columns` | `Column[]` | **requis** | Définition des colonnes | | `items` | `Record[]` | **requis** | Données à afficher | | `totalItems` | `number` | **requis** | Nombre total d'items (pour calculer le nb de pages) | | `page` | `number` | `1` | Page courante, 1-based (v-model) | | `perPage` | `number` | `10` | Nombre de lignes par page (v-model) | | `perPageOptions` | `number[]` | `[10, 25, 50]` | Options du sélecteur de lignes | | `rowClickable` | `boolean` | `true` | Rend les lignes cliquables (cursor pointer + hover) | | `tableClass` | `string` | `''` | Classes CSS additionnelles sur `` (twMerge) | | `emptyMessage` | `string` | `'Aucune donnée'` | Message affiché quand `items` est vide | ### Type Column ```ts type Column = { key: string // Clé correspondant à item[key] label: string // Texte affiché dans le
(fallback si pas de slot header) } ``` ## Events | Event | Payload | Description | |-------|---------|-------------| | `update:page` | `number` | Changement de page (pagination ou Prev/Next) | | `update:per-page` | `number` | Changement du nombre de lignes par page | | `row-click` | `Record` | Clic sur une ligne (l'item de la ligne) | ## Slots | Slot | Scope | Description | |------|-------|-------------| | `#header-{key}` | `{ column }` | Contenu du `` — filtre (input, select…). Si absent, affiche `column.label` en texte | | `#cell-{key}` | `{ item, column }` | Contenu du ``. Si absent, affiche `item[column.key]` en texte | | `#empty` | — | Contenu affiché quand `items` est vide. Si absent, affiche `emptyMessage` | ## Structure HTML ```
← wrapper ← état vide
← une seule ligne d'en-tête slot #header-{key} ← filtre (placeholder = nom colonne) OU label texte ← si pas de slot
slot #cell-{key} ← contenu custom OU item[col.key] ← texte brut
slot #empty OU emptyMessage
← barre de pagination (masquée si aucune donnée) ← sélecteur nb lignes (options mappées depuis perPageOptions)
``` ## Logique de pagination (troncature) ### Règles - **≤ 5 pages** : afficher toutes les pages, pas d'ellipsis - **> 5 pages** : toujours afficher page 1 et dernière page, **1 voisin** de chaque côté de la page active, ellipsis `…` quand écart > 1 - **Prev** : `MalioButton variant="tertiary"`, toujours visible, `disabled` sur page 1 - **Next** : `MalioButton variant="tertiary"`, toujours visible, `disabled` sur dernière page - **Changement de `perPage`** : émet automatiquement `update:page` avec `1` (reset à la première page) - **`totalItems = 0`** : la barre de pagination est masquée entièrement ### Exemples ``` ≤ 5 pages (toutes affichées) : Page 1/3 : Prev(disabled) [1] 2 3 Next Page 2/5 : Prev 1 [2] 3 4 5 Next Page 5/5 : Prev 1 2 3 4 [5] Next(disabled) > 5 pages (troncature 1 voisin) : Page 1/20 : Prev(disabled) [1] 2 … 20 Next Page 2/20 : Prev 1 [2] 3 … 20 Next Page 3/20 : Prev 1 2 [3] 4 … 20 Next Page 4/20 : Prev 1 … 3 [4] 5 … 20 Next Page 7/20 : Prev 1 … 6 [7] 8 … 20 Next Page 18/20 : Prev 1 … 17 [18] 19 20 Next Page 19/20 : Prev 1 … 18 [19] 20 Next Page 20/20 : Prev 1 … 19 [20] Next(disabled) ``` ## En-têtes — logique du `
` Chaque `` vérifie si le slot `#header-{key}` est fourni : - **Slot fourni** → rend le slot (le consommateur y met un `MalioInputText`, `MalioSelect`, etc. avec le placeholder qui sert de label de colonne) - **Slot absent** → rend `column.label` en texte (`font-semibold text-m-primary`) Pas de label séparé au-dessus du filtre. Le placeholder de l'input/select fait office de nom de colonne. ## Composants Malio utilisés en interne - `MalioSelect` — sélecteur du nombre de lignes par page. Les `perPageOptions` sont mappés au format `{ label: string, value: number }[]` attendu par MalioSelect (ex: `{ label: '10', value: 10 }`) - `MalioButton variant="tertiary"` — boutons Prev / Next ## Exemple d'utilisation consommateur ```vue ``` ## Accessibilité - `` élément natif (sémantique table implicite) - `` native) ## Styles - En-têtes : `bg-m-surface`, label en `text-m-primary font-semibold` - Bordures : `border-m-border` - Lignes hover : `hover:bg-m-bg` (si `rowClickable`) - Ligne cursor : `cursor-pointer` (si `rowClickable`) - Page active : `bg-m-btn-primary text-white rounded` - Boutons Prev/Next : `MalioButton variant="tertiary"` - Message vide : `text-m-muted text-center`, `
` sur chaque en-tête - Pagination dans un `
` avec `colspan` sur toute la largeur