# @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 ``` --- ## 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 ``` --- ## 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 ``` --- ## 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 ``` --- ## 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 ``` ```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 ``` --- ## 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 ``` --- ## 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 ``` --- ## 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 ``` --- ## 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 ``` --- ## 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 ``` --- ## 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 ``` --- ## 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 ``` --- ## 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 ``` --- ## 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 ``` --- ## 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 ``` --- ## 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 ``` --- ## 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 ``` **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 ``` --- ## 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

Contenu du drawer

Fermeture uniquement via backdrop

Drawer plus large

``` --- ## 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[]` | **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 `` (twMerge) | | `emptyMessage` | `string` | `'Aucune donnée'` | Message si items vide | **Events :** `update:page(value: number)`, `update:per-page(value: number)`, `row-click(item: Record)` **Slots :** `#header-{key}` (filtre dans le `
`, placeholder = label), `#cell-{key}` (contenu du ``), `#empty` (état vide) ```vue ```