| Numéro du ticket | Titre du ticket | |------------------|-----------------| | | | ## Description de la PR ## Modification du .env ## Check list - [ ] Pas de régression - [ ] TU/TI/TF rédigée - [ ] TU/TI/TF OK - [ ] CHANGELOG modifié Reviewed-on: #46 Co-authored-by: tristan <tristan@yuno.malio.fr> Co-committed-by: tristan <tristan@yuno.malio.fr>
667 lines
26 KiB
Markdown
667 lines
26 KiB
Markdown
# @malio/layer-ui — Composants
|
|
|
|
Tous les composants sont auto-importés avec le préfixe `Malio`. Utiliser `v-model` pour le binding bidirectionnel sur les composants de formulaire.
|
|
|
|
---
|
|
|
|
## MalioInputText
|
|
|
|
Champ texte avec label, icône optionnelle et support de masque de saisie.
|
|
|
|
| Prop | Type | Défaut | Description |
|
|
|------|------|--------|-------------|
|
|
| `id` | `string` | auto | Identifiant HTML |
|
|
| `label` | `string` | `''` | Label du champ |
|
|
| `modelValue` | `string \| null` | `undefined` | Valeur (v-model) |
|
|
| `disabled` | `boolean` | `false` | Désactive le champ |
|
|
| `readonly` | `boolean` | `false` | Lecture seule |
|
|
| `required` | `boolean` | `false` | Champ requis |
|
|
| `hint` | `string` | `''` | Message d'aide |
|
|
| `error` | `string` | `''` | Message d'erreur |
|
|
| `success` | `string` | `''` | Message de succès |
|
|
| `iconName` | `string` | `''` | Icône Iconify (ex: `mdi:magnify`) |
|
|
| `iconPosition` | `'left' \| 'right'` | `'right'` | Position de l'icône |
|
|
| `iconSize` | `string \| number` | `24` | Taille icône |
|
|
| `iconColor` | `string` | `'text-m-muted'` | Classe couleur icône |
|
|
| `mask` | `string \| MaskInputOptions` | — | Masque de saisie (maska) |
|
|
| `maxLength` | `number \| string` | — | Longueur max |
|
|
| `minLength` | `number \| string` | — | Longueur min |
|
|
| `inputClass` | `string` | `''` | Classes CSS input |
|
|
| `labelClass` | `string` | `''` | Classes CSS label |
|
|
| `groupClass` | `string` | `''` | Classes CSS conteneur |
|
|
|
|
**Events :** `update:modelValue(value: string)`
|
|
|
|
```vue
|
|
<MalioInputText v-model="nom" label="Nom" />
|
|
<MalioInputText v-model="search" label="Recherche" icon-name="mdi:magnify" />
|
|
<MalioInputText v-model="tel" label="Téléphone" mask="## ## ## ## ##" />
|
|
<MalioInputText v-model="email" label="Email" error="Email invalide" />
|
|
<MalioInputText v-model="info" label="Info" disabled hint="Champ désactivé" />
|
|
```
|
|
|
|
---
|
|
|
|
## MalioInputPassword
|
|
|
|
Champ mot de passe avec toggle visibilité.
|
|
|
|
| Prop | Type | Défaut | Description |
|
|
|------|------|--------|-------------|
|
|
| `modelValue` | `string \| null` | `undefined` | Valeur (v-model) |
|
|
| `label` | `string` | `''` | Label |
|
|
| `displayIcon` | `boolean` | `true` | Afficher l'icône toggle |
|
|
| `disabled` | `boolean` | `false` | Désactivé |
|
|
| `readonly` | `boolean` | `false` | Lecture seule |
|
|
| `hint` | `string` | `''` | Message d'aide |
|
|
| `error` | `string` | `''` | Message d'erreur |
|
|
| `success` | `string` | `''` | Message de succès |
|
|
|
|
**Events :** `update:modelValue(value: string)`
|
|
|
|
```vue
|
|
<MalioInputPassword v-model="password" label="Mot de passe" />
|
|
<MalioInputPassword v-model="password" label="Sans icône" :display-icon="false" />
|
|
```
|
|
|
|
---
|
|
|
|
## MalioInputEmail
|
|
|
|
Champ email (`type="email"` + `inputmode="email"`) avec icône `mdi:email-outline` à droite par défaut.
|
|
|
|
| Prop | Type | Défaut | Description |
|
|
|------|------|--------|-------------|
|
|
| `id` | `string` | auto | Identifiant HTML |
|
|
| `label` | `string` | `''` | Label du champ |
|
|
| `modelValue` | `string \| null` | `undefined` | Valeur (v-model) |
|
|
| `name` | `string` | `''` | Attribut name |
|
|
| `autocomplete` | `string` | `'off'` | Autocomplétion (passer `'email'` pour suggérer l'email utilisateur) |
|
|
| `disabled` | `boolean` | `false` | Désactive le champ |
|
|
| `readonly` | `boolean` | `false` | Lecture seule |
|
|
| `required` | `boolean` | `false` | Champ requis |
|
|
| `hint` | `string` | `''` | Message d'aide |
|
|
| `error` | `string` | `''` | Message d'erreur |
|
|
| `success` | `string` | `''` | Message de succès |
|
|
| `iconName` | `string` | `'mdi:email-outline'` | Icône Iconify (chaîne vide pour masquer) |
|
|
| `iconPosition` | `'left' \| 'right'` | `'right'` | Position de l'icône |
|
|
| `iconSize` | `string \| number` | `24` | Taille icône |
|
|
| `iconColor` | `string` | `'text-m-muted'` | Classe couleur icône |
|
|
| `inputClass` | `string` | `''` | Classes CSS input |
|
|
| `labelClass` | `string` | `''` | Classes CSS label |
|
|
| `groupClass` | `string` | `''` | Classes CSS conteneur |
|
|
|
|
**Events :** `update:modelValue(value: string)`
|
|
|
|
```vue
|
|
<MalioInputEmail v-model="email" label="Adresse email" />
|
|
<MalioInputEmail v-model="email" label="Email" autocomplete="email" />
|
|
<MalioInputEmail v-model="email" label="Email" :icon-name="''" />
|
|
<MalioInputEmail v-model="email" label="Email" error="Adresse email invalide" />
|
|
```
|
|
|
|
---
|
|
|
|
## MalioInputPhone
|
|
|
|
Champ téléphone (`type="tel"` + `inputmode="tel"`) avec icône `mdi:phone-outline` à gauche par défaut et bouton `+` optionnel à droite pour gérer une liste de numéros côté parent.
|
|
|
|
| Prop | Type | Défaut | Description |
|
|
|------|------|--------|-------------|
|
|
| `id` | `string` | auto | Identifiant HTML |
|
|
| `label` | `string` | `''` | Label du champ |
|
|
| `modelValue` | `string \| null` | `undefined` | Valeur (v-model) |
|
|
| `name` | `string` | `''` | Attribut name |
|
|
| `autocomplete` | `string` | `'off'` | Autocomplétion (passer `'tel'` pour suggérer un numéro enregistré) |
|
|
| `disabled` | `boolean` | `false` | Désactive le champ et le bouton + |
|
|
| `readonly` | `boolean` | `false` | Lecture seule (désactive aussi le bouton +) |
|
|
| `required` | `boolean` | `false` | Champ requis |
|
|
| `hint` | `string` | `''` | Message d'aide |
|
|
| `error` | `string` | `''` | Message d'erreur |
|
|
| `success` | `string` | `''` | Message de succès |
|
|
| `iconName` | `string` | `'mdi:phone-outline'` | Icône Iconify (chaîne vide pour masquer) |
|
|
| `iconPosition` | `'left' \| 'right'` | `'left'` | Position de l'icône |
|
|
| `iconSize` | `string \| number` | `24` | Taille icône |
|
|
| `iconColor` | `string` | `'text-m-muted'` | Classe couleur icône |
|
|
| `mask` | `string \| MaskInputOptions` | `undefined` | Masque maska (aucun par défaut, utile pour mono-pays) |
|
|
| `addable` | `boolean` | `false` | Affiche un bouton à droite qui émet l'event `add` |
|
|
| `addIconName` | `string` | `'mdi:plus'` | Icône Iconify du bouton d'ajout |
|
|
| `addButtonLabel` | `string` | `'Ajouter un numéro'` | aria-label du bouton d'ajout |
|
|
| `inputClass` | `string` | `''` | Classes CSS input |
|
|
| `labelClass` | `string` | `''` | Classes CSS label |
|
|
| `groupClass` | `string` | `''` | Classes CSS conteneur |
|
|
|
|
**Events :**
|
|
- `update:modelValue(value: string)`
|
|
- `add()` — émis au clic du bouton `+` (uniquement si `addable`, non `disabled`, non `readonly`)
|
|
|
|
```vue
|
|
<MalioInputPhone v-model="phone" label="Téléphone" />
|
|
<MalioInputPhone v-model="phone" label="Téléphone (FR)" mask="+33 # ## ## ## ##" />
|
|
<MalioInputPhone v-model="phone" label="Téléphone" addable @add="addPhoneField" />
|
|
<MalioInputPhone v-model="phone" label="Téléphone" error="Numéro invalide" />
|
|
```
|
|
|
|
---
|
|
|
|
## MalioInputAutocomplete
|
|
|
|
Champ de saisie assistée (typeahead / combobox) : l'utilisateur tape pour filtrer une liste d'options, ou pour déclencher une recherche côté parent (API). Le parent alimente `options` et `loading` en réponse à l'event `search` — c'est lui qui gère l'appel API, l'auth, la transformation et le cache.
|
|
|
|
| Prop | Type | Défaut | Description |
|
|
|------|------|--------|-------------|
|
|
| `id` | `string` | auto | Identifiant HTML |
|
|
| `label` | `string` | `''` | Label flottant |
|
|
| `modelValue` | `string \| number \| null` | `undefined` | Valeur sélectionnée (v-model) |
|
|
| `name` | `string` | `''` | Attribut name |
|
|
| `options` | `{label: string; value: string\|number}[]` | `[]` | Liste affichée dans le dropdown |
|
|
| `loading` | `boolean` | `false` | Affiche un spinner + un message de chargement |
|
|
| `debounce` | `number` | `300` | Délai (ms) avant émission de `search` |
|
|
| `minSearchLength` | `number` | `0` | Caractères mini avant d'émettre `search` |
|
|
| `allowCreate` | `boolean` | `false` | Autorise la saisie libre validée par Entrée (émet `create`) |
|
|
| `iconName` | `string` | `''` | Icône Iconify décorative |
|
|
| `iconPosition` | `'left' \| 'right'` | `'left'` | Position de l'icône décorative |
|
|
| `iconSize` | `string \| number` | `24` | Taille de l'icône |
|
|
| `iconColor` | `string` | `'text-m-muted'` | Classe couleur de l'icône |
|
|
| `noResultsText` | `string` | `'Aucun résultat'` | Texte affiché quand `options` est vide |
|
|
| `loadingText` | `string` | `'Chargement…'` | Texte affiché pendant le chargement |
|
|
| `minSearchText` | `string` | `'Tapez pour rechercher'` | Texte affiché tant que `minSearchLength` n'est pas atteint |
|
|
| `disabled` | `boolean` | `false` | Désactive le champ et empêche l'ouverture |
|
|
| `readonly` | `boolean` | `false` | Lecture seule (n'ouvre pas le dropdown) |
|
|
| `required` | `boolean` | `false` | Champ requis |
|
|
| `hint` | `string` | `''` | Message d'aide |
|
|
| `error` | `string` | `''` | Message d'erreur (prioritaire) |
|
|
| `success` | `string` | `''` | Message de succès |
|
|
| `inputClass` | `string` | `''` | Classes CSS input |
|
|
| `labelClass` | `string` | `''` | Classes CSS label |
|
|
| `groupClass` | `string` | `''` | Classes CSS conteneur |
|
|
|
|
**Events :**
|
|
- `update:modelValue(value: string \| number \| null)` — valeur sélectionnée (v-model)
|
|
- `search(query: string)` — émis (après debounce + minSearchLength) avec le texte tapé ; le parent l'écoute pour lancer son fetch API
|
|
- `select(option: Option \| null)` — émis avec l'objet `Option` complet (utile pour récupérer aussi le `label`)
|
|
- `create(value: string)` — émis quand `allowCreate=true` et que l'utilisateur valide une valeur libre
|
|
|
|
**Clavier :** `↓` / `↑` navigation, `Entrée` sélection (ou création), `Échap` ferme le dropdown.
|
|
|
|
```vue
|
|
<!-- Usage statique -->
|
|
<MalioInputAutocomplete v-model="country" label="Pays" :options="countries" />
|
|
|
|
<!-- Usage API (parent gère le fetch) -->
|
|
<MalioInputAutocomplete
|
|
v-model="clientId"
|
|
label="Client"
|
|
:options="clientOptions"
|
|
:loading="isFetching"
|
|
:min-search-length="2"
|
|
@search="onSearchClients"
|
|
@select="onSelectClient"
|
|
/>
|
|
|
|
<!-- Avec création libre -->
|
|
<MalioInputAutocomplete
|
|
v-model="category"
|
|
label="Catégorie"
|
|
:options="categories"
|
|
allow-create
|
|
@create="onCreateCategory"
|
|
/>
|
|
```
|
|
|
|
```ts
|
|
async function onSearchClients(query: string) {
|
|
isFetching.value = true
|
|
const res = await $fetch('/api/clients', {params: {q: query}})
|
|
clientOptions.value = res.map(c => ({label: c.name, value: c.id}))
|
|
isFetching.value = false
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## MalioInputAmount
|
|
|
|
Champ montant avec icône devise (euro par défaut).
|
|
|
|
| Prop | Type | Défaut | Description |
|
|
|------|------|--------|-------------|
|
|
| `modelValue` | `string \| null` | `undefined` | Valeur (v-model) |
|
|
| `label` | `string` | `''` | Label |
|
|
| `iconName` | `string` | `'mdi:currency-eur'` | Icône devise |
|
|
| `disabled` | `boolean` | `false` | Désactivé |
|
|
| `error` | `string` | `''` | Message d'erreur |
|
|
|
|
**Events :** `update:modelValue(value: string)`
|
|
|
|
```vue
|
|
<MalioInputAmount v-model="montant" label="Montant TTC" />
|
|
<MalioInputAmount v-model="prix" label="Prix" error="Montant invalide" />
|
|
```
|
|
|
|
---
|
|
|
|
## MalioInputNumber
|
|
|
|
Champ numérique avec boutons +/-.
|
|
|
|
| Prop | Type | Défaut | Description |
|
|
|------|------|--------|-------------|
|
|
| `modelValue` | `string \| null` | `undefined` | Valeur (v-model) |
|
|
| `label` | `string` | `''` | Label |
|
|
| `min` | `number \| string` | — | Valeur minimum |
|
|
| `max` | `number \| string` | — | Valeur maximum |
|
|
| `disabled` | `boolean` | `false` | Désactivé |
|
|
| `error` | `string` | `''` | Message d'erreur |
|
|
|
|
**Events :** `update:modelValue(value: string)`
|
|
|
|
```vue
|
|
<MalioInputNumber v-model="quantite" label="Quantité" min="0" max="100" />
|
|
```
|
|
|
|
---
|
|
|
|
## MalioInputTextArea
|
|
|
|
Zone de texte multiligne avec compteur et redimensionnement.
|
|
|
|
| Prop | Type | Défaut | Description |
|
|
|------|------|--------|-------------|
|
|
| `modelValue` | `string \| null` | `undefined` | Valeur (v-model) |
|
|
| `label` | `string` | `''` | Label |
|
|
| `size` | `number \| string` | `2` | Nombre de lignes |
|
|
| `resize` | `'none' \| 'both' \| 'horizontal' \| 'vertical'` | `'both'` | Mode redimensionnement |
|
|
| `maxLength` | `number` | `800` | Longueur max |
|
|
| `showCounter` | `boolean` | `false` | Afficher le compteur |
|
|
| `disabled` | `boolean` | `false` | Désactivé |
|
|
| `error` | `string` | `''` | Message d'erreur |
|
|
| `groupClass` | `string` | `''` | Classes CSS sur la div conteneur (utile pour `row-span-*`, `col-span-*`, etc.) |
|
|
|
|
**Events :** `update:modelValue(value: string)`
|
|
|
|
```vue
|
|
<MalioInputTextArea v-model="commentaire" label="Commentaire" :show-counter="true" />
|
|
<MalioInputTextArea v-model="note" label="Note" resize="vertical" :size="4" />
|
|
```
|
|
|
|
---
|
|
|
|
## MalioInputRichText
|
|
|
|
Éditeur de texte riche basé sur **TipTap v3** + **StarterKit** + **tiptap-markdown** + **TextStyle/Color/Highlight**. Toolbar avec gras, italique, barré, titres H2/H3, listes, citation, code, code-block, lien, **couleur du texte**, **surlignage**, undo/redo. Sortie en HTML (par défaut) ou markdown.
|
|
|
|
> Couleurs et surlignages ne sont **pas persistés en markdown**. Pour les conserver au save/reload, utiliser `output-format="html"`.
|
|
|
|
| Prop | Type | Défaut | Description |
|
|
|------|------|--------|-------------|
|
|
| `id` | `string` | auto | Identifiant HTML |
|
|
| `label` | `string` | `''` | Label affiché au-dessus de l'éditeur |
|
|
| `modelValue` | `string \| null` | `undefined` | Contenu (v-model) |
|
|
| `placeholder` | `string` | `''` | Texte affiché quand vide |
|
|
| `minHeight` | `string` | `'160px'` | Hauteur min de la zone d'édition |
|
|
| `editable` | `boolean` | `true` | `false` → mode affichage seul (toolbar masquée) |
|
|
| `disabled` | `boolean` | `false` | Désactive l'édition et la toolbar |
|
|
| `readonly` | `boolean` | `false` | Lecture seule (toolbar visible mais désactivée) |
|
|
| `hint` | `string` | `''` | Message d'aide |
|
|
| `error` | `string` | `''` | Message d'erreur |
|
|
| `success` | `string` | `''` | Message de succès |
|
|
| `outputFormat` | `'markdown' \| 'html'` | `'html'` | Format émis dans `update:modelValue` |
|
|
| `groupClass` | `string` | `''` | Classes CSS conteneur (twMerge) |
|
|
| `labelClass` | `string` | `''` | Classes CSS label (twMerge) |
|
|
| `editorClass` | `string` | `''` | Classes CSS wrapper éditeur (twMerge) |
|
|
|
|
**Events :** `update:modelValue(value: string)`
|
|
|
|
```vue
|
|
<MalioInputRichText v-model="note" label="Note" placeholder="Écrire ici…" />
|
|
<MalioInputRichText v-model="cr" label="Compte-rendu" error="Trop court" />
|
|
<MalioInputRichText v-model="article" label="Article" min-height="240px" />
|
|
<MalioInputRichText :model-value="content" :editable="false" />
|
|
```
|
|
|
|
---
|
|
|
|
## MalioInputUpload
|
|
|
|
Champ d'upload de fichier.
|
|
|
|
| Prop | Type | Défaut | Description |
|
|
|------|------|--------|-------------|
|
|
| `modelValue` | `string \| null` | `undefined` | Nom du fichier (v-model) |
|
|
| `label` | `string` | `''` | Label |
|
|
| `accept` | `string` | `''` | Types de fichiers acceptés |
|
|
| `displayIcon` | `boolean` | `true` | Afficher l'icône |
|
|
| `disabled` | `boolean` | `false` | Désactivé |
|
|
| `error` | `string` | `''` | Message d'erreur |
|
|
|
|
**Events :** `update:modelValue(value: string)`, `file-selected(file: File)`
|
|
|
|
```vue
|
|
<MalioInputUpload v-model="fileName" label="Document" accept=".pdf,.doc" @file-selected="onFile" />
|
|
```
|
|
|
|
---
|
|
|
|
## MalioSelect
|
|
|
|
Liste déroulante.
|
|
|
|
| Prop | Type | Défaut | Description |
|
|
|------|------|--------|-------------|
|
|
| `modelValue` | `string \| number \| null` | **requis** | Valeur sélectionnée (v-model) |
|
|
| `options` | `{ value: string \| number, text: string }[]` | `[]` | Options disponibles |
|
|
| `emptyOptionLabel` | `string` | `''` | Placeholder option vide |
|
|
| `label` | `string` | `''` | Label |
|
|
| `hint` | `string` | `''` | Message d'aide |
|
|
| `error` | `string` | `''` | Message d'erreur |
|
|
| `success` | `string` | `''` | Message de succès |
|
|
| `disabled` | `boolean` | `false` | Désactivé |
|
|
| `groupClass` | `string` | `''` | Classes CSS conteneur (twMerge) |
|
|
| `rounded` | `string` | `'rounded-md'` | Classe border-radius |
|
|
| `textField` | `string` | `'text-lg'` | Classe taille texte bouton |
|
|
| `textValue` | `string` | `'text-lg'` | Classe taille texte valeur |
|
|
| `textLabel` | `string` | `'text-sm'` | Classe taille texte label |
|
|
| `noOptionsText` | `string` | `'Aucune option disponible'` | Message affiché dans la dropdown quand `options` est vide |
|
|
|
|
**Events :** `update:modelValue(value: string | number | null)`
|
|
**Slots :** `icon` (icône dropdown custom)
|
|
|
|
```vue
|
|
<MalioSelect v-model="pays" label="Pays" :options="[{ value: 'FR', text: 'France' }, { value: 'BE', text: 'Belgique' }]" />
|
|
<MalioSelect v-model="ville" label="Ville" :options="villes" empty-option-label="Choisir..." />
|
|
<MalioSelect v-model="civilite" label="Civilité" :options="civilites" group-class="mt-0" />
|
|
```
|
|
|
|
---
|
|
|
|
## MalioSelectCheckbox
|
|
|
|
Liste déroulante multi-sélection avec checkboxes.
|
|
|
|
| Prop | Type | Défaut | Description |
|
|
|------|------|--------|-------------|
|
|
| `modelValue` | `(string \| number)[]` | **requis** | Valeurs sélectionnées (v-model) |
|
|
| `options` | `{ value: string \| number, text: string }[]` | `[]` | Options |
|
|
| `displayTag` | `boolean` | `false` | Afficher les tags sélectionnés |
|
|
| `displaySelectAll` | `boolean` | `false` | Afficher "Tout sélectionner" |
|
|
| `selectAllLabel` | `string` | `'Tout sélectionner'` | Texte du sélecteur global |
|
|
| `label` | `string` | `''` | Label |
|
|
| `disabled` | `boolean` | `false` | Désactivé |
|
|
| `noOptionsText` | `string` | `'Aucune option disponible'` | Message affiché dans la dropdown quand `options` est vide |
|
|
|
|
**Events :** `update:modelValue(value: (string | number)[])`
|
|
|
|
```vue
|
|
<MalioSelectCheckbox v-model="competences" label="Compétences" :options="skills" :display-tag="true" />
|
|
<MalioSelectCheckbox v-model="sites" label="Sites" :options="sitesList" :display-select-all="true" />
|
|
```
|
|
|
|
---
|
|
|
|
## MalioCheckbox
|
|
|
|
Case à cocher.
|
|
|
|
| Prop | Type | Défaut | Description |
|
|
|------|------|--------|-------------|
|
|
| `modelValue` | `boolean \| null` | `undefined` | Valeur (v-model) |
|
|
| `label` | `string` | `''` | Label |
|
|
| `disabled` | `boolean` | `false` | Désactivé |
|
|
| `readonly` | `boolean` | `false` | Lecture seule |
|
|
| `error` | `string` | `''` | Message d'erreur |
|
|
|
|
**Events :** `update:modelValue(value: boolean)`
|
|
|
|
```vue
|
|
<MalioCheckbox v-model="accepte" label="J'accepte les conditions" />
|
|
<MalioCheckbox v-model="newsletter" label="Newsletter" disabled />
|
|
```
|
|
|
|
---
|
|
|
|
## MalioRadioButton
|
|
|
|
Bouton radio (à utiliser en groupe avec le même `name`).
|
|
|
|
| Prop | Type | Défaut | Description |
|
|
|------|------|--------|-------------|
|
|
| `modelValue` | `string \| number \| boolean \| null` | `undefined` | Valeur du groupe (v-model) |
|
|
| `value` | `string \| number \| boolean \| null` | `undefined` | Valeur de cette option |
|
|
| `label` | `string` | `''` | Label |
|
|
| `name` | `string` | `''` | Nom du groupe radio |
|
|
| `disabled` | `boolean` | `false` | Désactivé |
|
|
| `readonly` | `boolean` | `false` | Lecture seule |
|
|
|
|
**Events :** `update:modelValue(value: string | number | boolean | null)`
|
|
|
|
```vue
|
|
<MalioRadioButton v-model="civilite" name="civilite" value="M" label="Monsieur" />
|
|
<MalioRadioButton v-model="civilite" name="civilite" value="Mme" label="Madame" />
|
|
```
|
|
|
|
---
|
|
|
|
## MalioTime
|
|
|
|
Sélecteur d'heure.
|
|
|
|
| Prop | Type | Défaut | Description |
|
|
|------|------|--------|-------------|
|
|
| `modelValue` | `string \| null` | `undefined` | Heure au format HH:mm (v-model) |
|
|
| `label` | `string` | `''` | Label |
|
|
| `disabled` | `boolean` | `false` | Désactivé |
|
|
| `readonly` | `boolean` | `false` | Lecture seule |
|
|
| `error` | `string` | `''` | Message d'erreur |
|
|
|
|
**Events :** `update:modelValue(value: string)`
|
|
|
|
```vue
|
|
<MalioTime v-model="heure" label="Heure de début" />
|
|
<MalioTime v-model="fin" label="Heure de fin" readonly />
|
|
```
|
|
|
|
---
|
|
|
|
## MalioButton
|
|
|
|
Bouton d'action avec 4 variantes visuelles et icône optionnelle.
|
|
|
|
| Prop | Type | Défaut | Description |
|
|
|------|------|--------|-------------|
|
|
| `label` | `string` | `''` | Texte du bouton (ou slot par défaut) |
|
|
| `variant` | `'primary' \| 'secondary' \| 'tertiary' \| 'danger'` | `'primary'` | Variante visuelle |
|
|
| `disabled` | `boolean` | `false` | Désactivé |
|
|
| `buttonClass` | `string` | `''` | Classes CSS additionnelles (twMerge) |
|
|
| `iconName` | `string` | `''` | Icône Iconify |
|
|
| `iconPosition` | `'left' \| 'right'` | `'right'` | Position icône |
|
|
| `iconSize` | `string \| number` | `16` | Taille icône |
|
|
|
|
**Events :** `click(e: MouseEvent)`
|
|
**Slots :** `default` (contenu du bouton, remplace `label`)
|
|
|
|
```vue
|
|
<MalioButton label="Valider" />
|
|
<MalioButton label="Modifier" variant="secondary" icon-name="mdi:pencil" icon-position="left" />
|
|
<MalioButton label="Voir plus" variant="tertiary" />
|
|
<MalioButton label="Supprimer" variant="danger" icon-name="mdi:trash" icon-position="left" />
|
|
<MalioButton label="Pleine largeur" button-class="w-full" />
|
|
```
|
|
|
|
---
|
|
|
|
## MalioButtonIcon
|
|
|
|
Bouton icône seul (sans texte).
|
|
|
|
| Prop | Type | Défaut | Description |
|
|
|------|------|--------|-------------|
|
|
| `icon` | `string` | **requis** | Icône Iconify |
|
|
| `ariaLabel` | `string` | **requis** | Label accessible |
|
|
| `variant` | `'filled' \| 'ghost'` | `'filled'` | Variante visuelle |
|
|
| `disabled` | `boolean` | `false` | Désactivé |
|
|
| `buttonClass` | `string` | `''` | Classes CSS additionnelles |
|
|
| `iconSize` | `string \| number` | `24` | Taille icône |
|
|
|
|
**Events :** `click(e: MouseEvent)`
|
|
|
|
```vue
|
|
<MalioButtonIcon icon="mdi:pencil" aria-label="Modifier" />
|
|
<MalioButtonIcon icon="mdi:trash" aria-label="Supprimer" variant="ghost" />
|
|
```
|
|
|
|
---
|
|
|
|
## MalioTabList
|
|
|
|
Navigation par onglets avec contenu dynamique.
|
|
|
|
| Prop | Type | Défaut | Description |
|
|
|------|------|--------|-------------|
|
|
| `modelValue` | `string` | `undefined` | Onglet actif (v-model) |
|
|
| `tabs` | `Tab[]` | **requis** | Liste des onglets (voir type ci-dessous) |
|
|
|
|
Type `Tab` :
|
|
|
|
| Propriété | Type | Défaut | Description |
|
|
|-----------|------|--------|-------------|
|
|
| `key` | `string` | — | Identifiant unique (utilisé pour le slot et le v-model) |
|
|
| `label` | `string` | — | Texte de l'onglet |
|
|
| `icon` | `string` | — | Nom Iconify (optionnel) |
|
|
| `iconSize` | `string` | `24` | Taille de l'icône |
|
|
| `disabled` | `boolean` | `false` | Onglet désactivé : grisé et non cliquable. Le parent calcule cet état selon sa logique de validation |
|
|
|
|
**Events :** `update:modelValue(value: string)` — émis uniquement quand l'onglet cible n'est pas `disabled`
|
|
**Slots :** Un slot nommé par `tab.key` pour le contenu de chaque onglet
|
|
|
|
```vue
|
|
<MalioTabList v-model="activeTab" :tabs="tabs">
|
|
<template #infos>Contenu infos</template>
|
|
<template #docs>Contenu docs</template>
|
|
</MalioTabList>
|
|
```
|
|
|
|
**Pattern de gating progressif** (déverrouille les onglets quand les précédents sont valides) :
|
|
|
|
```ts
|
|
const informationValid = computed(() => name.value && email.value)
|
|
const adressesValid = computed(() => /^\d{5}$/.test(codePostal.value))
|
|
|
|
const tabs = computed(() => [
|
|
{ key: 'information', label: 'Information' },
|
|
{ key: 'contacts', label: 'Contacts', disabled: !informationValid.value },
|
|
{ key: 'adresses', label: 'Adresses', disabled: !informationValid.value },
|
|
{ key: 'transport', label: 'Transport', disabled: !informationValid.value || !adressesValid.value },
|
|
])
|
|
```
|
|
|
|
---
|
|
|
|
## MalioSidebar
|
|
|
|
Barre latérale de navigation rétractable.
|
|
|
|
| Prop | Type | Défaut | Description |
|
|
|------|------|--------|-------------|
|
|
| `modelValue` | `boolean` | `undefined` | État ouvert/fermé (v-model) |
|
|
| `sections` | `SidebarSection[]` | **requis** | Sections de navigation |
|
|
| `sidebarClass` | `string` | `''` | Classes CSS sidebar |
|
|
| `toggleClass` | `string` | `''` | Classes CSS bouton toggle |
|
|
|
|
**Type SidebarSection :** `{ title?: string, items: { label: string, icon?: string, to?: string, href?: string, active?: boolean }[] }`
|
|
|
|
**Events :** `update:modelValue(value: boolean)`
|
|
**Slots :** `logo` (sidebar ouverte), `logo-collapsed` (sidebar fermée)
|
|
|
|
```vue
|
|
<MalioSidebar v-model="isOpen" :sections="menuSections">
|
|
<template #logo><img src="/logo.png" /></template>
|
|
<template #logo-collapsed><img src="/logo-small.png" /></template>
|
|
</MalioSidebar>
|
|
```
|
|
|
|
---
|
|
|
|
## MalioDrawer
|
|
|
|
Panneau latéral (drawer) qui s'ouvre depuis la droite avec backdrop semi-transparent.
|
|
|
|
| Prop | Type | Défaut | Description |
|
|
|------|------|--------|-------------|
|
|
| `id` | `string` | auto | Identifiant HTML |
|
|
| `modelValue` | `boolean` | `undefined` | État ouvert/fermé (v-model) |
|
|
| `title` | `string` | `''` | Titre affiché dans le header |
|
|
| `showClose` | `boolean` | `true` | Afficher le bouton de fermeture (croix) |
|
|
| `drawerClass` | `string` | `''` | Classes CSS panneau (twMerge) |
|
|
|
|
**Events :** `update:modelValue(value: boolean)`
|
|
**Slots :** `default` (contenu du drawer)
|
|
|
|
```vue
|
|
<MalioDrawer v-model="isOpen" title="Détails">
|
|
<p>Contenu du drawer</p>
|
|
</MalioDrawer>
|
|
<MalioDrawer v-model="isOpen" title="Sans croix" :show-close="false">
|
|
<p>Fermeture uniquement via backdrop</p>
|
|
</MalioDrawer>
|
|
<MalioDrawer v-model="isOpen" title="Large" drawer-class="max-w-2xl">
|
|
<p>Drawer plus large</p>
|
|
</MalioDrawer>
|
|
```
|
|
|
|
---
|
|
|
|
## MalioDataTable
|
|
|
|
Tableau de données presentational avec pagination, filtres par slots et lignes cliquables.
|
|
|
|
| Prop | Type | Défaut | Description |
|
|
|------|------|--------|-------------|
|
|
| `id` | `string` | auto | Identifiant HTML |
|
|
| `columns` | `{ key: string, label: string }[]` | **requis** | Définition des colonnes |
|
|
| `items` | `Record<string, unknown>[]` | **requis** | Données à afficher |
|
|
| `totalItems` | `number` | **requis** | Total pour la pagination |
|
|
| `page` | `number` | `1` | Page courante (v-model) |
|
|
| `perPage` | `number` | `10` | Lignes par page (v-model) |
|
|
| `perPageOptions` | `number[]` | `[10, 25, 50]` | Options du sélecteur de lignes |
|
|
| `rowClickable` | `boolean` | `true` | Lignes cliquables (cursor pointer + hover) |
|
|
| `tableClass` | `string` | `''` | Classes CSS sur `<table>` (twMerge) |
|
|
| `emptyMessage` | `string` | `'Aucune donnée'` | Message si items vide |
|
|
|
|
**Events :** `update:page(value: number)`, `update:per-page(value: number)`, `row-click(item: Record<string, unknown>)`
|
|
**Slots :** `#header-{key}` (filtre dans le `<th>`, placeholder = label), `#cell-{key}` (contenu du `<td>`), `#empty` (état vide)
|
|
|
|
```vue
|
|
<!-- Avec filtres et pagination -->
|
|
<MalioDataTable
|
|
:columns="[{ key: 'nom', label: 'Nom' }, { key: 'ville', label: 'Ville' }]"
|
|
:items="data"
|
|
:total-items="total"
|
|
v-model:page="page"
|
|
v-model:per-page="perPage"
|
|
@row-click="router.push(`/contact/${$event.id}`)"
|
|
>
|
|
<template #header-nom>
|
|
<input v-model="filtreNom" placeholder="Nom" class="w-full border-0 border-b border-black bg-transparent px-0 py-1 text-sm outline-none">
|
|
</template>
|
|
<template #header-ville>
|
|
<select v-model="filtreVille" class="w-full appearance-none border-0 border-b border-black bg-transparent px-0 py-1 text-sm outline-none">
|
|
<option value="">Ville</option>
|
|
<option v-for="v in villes" :key="v" :value="v">{{ v }}</option>
|
|
</select>
|
|
</template>
|
|
<template #cell-nom="{ item }">
|
|
<strong>{{ item.nom }}</strong>
|
|
</template>
|
|
</MalioDataTable>
|
|
|
|
<!-- Simple sans filtres -->
|
|
<MalioDataTable
|
|
:columns="columns"
|
|
:items="data"
|
|
:total-items="total"
|
|
v-model:page="page"
|
|
v-model:per-page="perPage"
|
|
/>
|
|
```
|