[#MUI-32] Création d'un composant saisie assistée (autocomplete) (#46)
| 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>
This commit was merged in pull request #46.
This commit is contained in:
109
COMPONENTS.md
109
COMPONENTS.md
@@ -144,6 +144,82 @@ Champ téléphone (`type="tel"` + `inputmode="tel"`) avec icône `mdi:phone-outl
|
||||
|
||||
---
|
||||
|
||||
## 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).
|
||||
@@ -200,6 +276,7 @@ Zone de texte multiligne avec compteur et redimensionnement.
|
||||
| `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)`
|
||||
|
||||
@@ -285,6 +362,7 @@ Liste déroulante.
|
||||
| `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)
|
||||
@@ -310,6 +388,7 @@ Liste déroulante multi-sélection avec checkboxes.
|
||||
| `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)[])`
|
||||
|
||||
@@ -440,18 +519,42 @@ Navigation par onglets avec contenu dynamique.
|
||||
| Prop | Type | Défaut | Description |
|
||||
|------|------|--------|-------------|
|
||||
| `modelValue` | `string` | `undefined` | Onglet actif (v-model) |
|
||||
| `tabs` | `{ key: string, label: string, icon?: string }[]` | **requis** | Liste des onglets |
|
||||
| `tabs` | `Tab[]` | **requis** | Liste des onglets (voir type ci-dessous) |
|
||||
|
||||
**Events :** `update:modelValue(value: string)`
|
||||
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="[{ key: 'infos', label: 'Informations' }, { key: 'docs', label: 'Documents', icon: 'mdi:file' }]">
|
||||
<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
|
||||
|
||||
Reference in New Issue
Block a user