| 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>
295 lines
9.2 KiB
Vue
295 lines
9.2 KiB
Vue
<template>
|
|
<Story title="Input/Autocomplete">
|
|
<div class="grid grid-cols-1 gap-6 md:grid-cols-2">
|
|
<div class="rounded-lg border p-4">
|
|
<h2 class="mb-4 text-xl font-bold">Simple (statique)</h2>
|
|
<MalioInputAutocomplete
|
|
v-model="simpleValue"
|
|
label="Pays"
|
|
:options="staticOptions"
|
|
/>
|
|
</div>
|
|
|
|
<div class="rounded-lg border p-4">
|
|
<h2 class="mb-4 text-xl font-bold">Avec icône à gauche</h2>
|
|
<MalioInputAutocomplete
|
|
v-model="leftIconValue"
|
|
label="Recherche"
|
|
icon-name="mdi:magnify"
|
|
icon-position="left"
|
|
:options="staticOptions"
|
|
/>
|
|
</div>
|
|
|
|
<div class="rounded-lg border p-4 md:col-span-2">
|
|
<h2 class="mb-4 text-xl font-bold">Branché sur une API (simulé)</h2>
|
|
<p class="mb-3 text-sm text-m-muted">
|
|
Tapez au moins 2 caractères. Le parent écoute <code>@search</code> et alimente <code>options</code> + <code>loading</code>.
|
|
</p>
|
|
<MalioInputAutocomplete
|
|
v-model="apiValue"
|
|
label="Client"
|
|
:options="apiOptions"
|
|
:loading="apiLoading"
|
|
:min-search-length="2"
|
|
icon-name="mdi:magnify"
|
|
icon-position="left"
|
|
@search="onSearchApi"
|
|
/>
|
|
</div>
|
|
|
|
<div class="rounded-lg border p-4">
|
|
<h2 class="mb-4 text-xl font-bold">Création libre (allowCreate)</h2>
|
|
<MalioInputAutocomplete
|
|
v-model="createValue"
|
|
label="Catégorie"
|
|
:options="staticOptions"
|
|
allow-create
|
|
hint="Taper Entrée pour créer une nouvelle valeur"
|
|
/>
|
|
</div>
|
|
|
|
<div class="rounded-lg border p-4">
|
|
<h2 class="mb-4 text-xl font-bold">Désactivé</h2>
|
|
<MalioInputAutocomplete
|
|
v-model="disabledValue"
|
|
label="Pays"
|
|
:options="staticOptions"
|
|
disabled
|
|
/>
|
|
</div>
|
|
|
|
<div class="rounded-lg border p-4">
|
|
<h2 class="mb-4 text-xl font-bold">Readonly</h2>
|
|
<MalioInputAutocomplete
|
|
v-model="readonlyValue"
|
|
label="Pays"
|
|
:options="staticOptions"
|
|
readonly
|
|
/>
|
|
</div>
|
|
|
|
<div class="rounded-lg border p-4">
|
|
<h2 class="mb-4 text-xl font-bold">Avec hint</h2>
|
|
<MalioInputAutocomplete
|
|
v-model="hintValue"
|
|
label="Pays"
|
|
:options="staticOptions"
|
|
hint="Sélectionne un pays dans la liste"
|
|
/>
|
|
</div>
|
|
|
|
<div class="rounded-lg border p-4">
|
|
<h2 class="mb-4 text-xl font-bold">Erreur</h2>
|
|
<MalioInputAutocomplete
|
|
v-model="errorValue"
|
|
label="Pays"
|
|
:options="staticOptions"
|
|
error="Sélection invalide"
|
|
/>
|
|
</div>
|
|
|
|
<div class="rounded-lg border p-4">
|
|
<h2 class="mb-4 text-xl font-bold">Succès</h2>
|
|
<MalioInputAutocomplete
|
|
v-model="successValue"
|
|
label="Pays"
|
|
:options="staticOptions"
|
|
success="Sélection valide"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</Story>
|
|
</template>
|
|
|
|
<docs lang="md">
|
|
# 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). Combine le pattern floating-label des autres inputs avec un dropdown inspiré de `MalioSelect`. Conçu pour les cas ERP où la liste vient d'un appel API (auth, transformation, cache gérés par le parent).
|
|
|
|
------------------------------------------------------------------------
|
|
|
|
## Props détaillées
|
|
|
|
### id
|
|
- Type: string
|
|
- Description: Identifiant HTML de l'input. Auto-généré si non fourni (préfixe `malio-input-autocomplete-`).
|
|
|
|
### label
|
|
- Type: string
|
|
- Description: Texte affiché comme label flottant.
|
|
|
|
### name
|
|
- Type: string
|
|
- Description: Attribut name de l'input (formulaires).
|
|
|
|
### modelValue
|
|
- Type: `string | number | null | undefined`
|
|
- Description: Valeur sélectionnée. Doit correspondre à un `option.value` (ou être un texte libre si `allowCreate`).
|
|
|
|
### options
|
|
- Type: `{ label: string; value: string | number }[]`
|
|
- Défaut: `[]`
|
|
- Description: Liste affichée dans le dropdown. Le parent alimente cette liste (statique ou via API en réponse à l'event `search`).
|
|
|
|
### loading
|
|
- Type: boolean
|
|
- Défaut: `false`
|
|
- Description: Affiche un spinner à la place du chevron et un message dans le dropdown.
|
|
|
|
### debounce
|
|
- Type: number
|
|
- Défaut: `300`
|
|
- Description: Délai (ms) avant émission de l'event `search` après une frappe. Évite de spammer l'API.
|
|
|
|
### minSearchLength
|
|
- Type: number
|
|
- Défaut: `0`
|
|
- Description: Nombre minimum de caractères avant d'émettre `search`. Pratique pour API : ne pas appeler avec query vide.
|
|
|
|
### allowCreate
|
|
- Type: boolean
|
|
- Défaut: `false`
|
|
- Description: Si vrai, l'utilisateur peut valider (Entrée ou clic ailleurs) une valeur libre non présente dans `options` ; émet l'event `create`.
|
|
|
|
------------------------------------------------------------------------
|
|
|
|
## Icône
|
|
|
|
### iconName
|
|
- Type: string
|
|
- Défaut: `''` (aucune)
|
|
- Description: Nom Iconify de l'icône décorative.
|
|
|
|
### iconPosition
|
|
- Type: `'left' | 'right'`
|
|
- Défaut: `left`
|
|
- Description: Côté d'affichage de l'icône. À droite, l'icône s'aligne avec le chevron.
|
|
|
|
### iconSize / iconColor
|
|
- Type: number / string
|
|
- Défaut: `24` / `text-m-muted`
|
|
|
|
------------------------------------------------------------------------
|
|
|
|
## Textes du dropdown
|
|
|
|
### noResultsText
|
|
- Type: string
|
|
- Défaut: `Aucun résultat`
|
|
- Description: Affiché quand `options` est vide.
|
|
|
|
### loadingText
|
|
- Type: string
|
|
- Défaut: `Chargement…`
|
|
- Description: Affiché pendant que `loading=true`.
|
|
|
|
### minSearchText
|
|
- Type: string
|
|
- Défaut: `Tapez pour rechercher`
|
|
- Description: Affiché quand l'utilisateur n'a pas atteint `minSearchLength`.
|
|
|
|
------------------------------------------------------------------------
|
|
|
|
## Apparence & Style
|
|
|
|
### inputClass / labelClass / groupClass
|
|
- Type: string
|
|
- Description: Classes CSS appliquées respectivement à l'input, au label et au conteneur (fusionnées via `twMerge`).
|
|
|
|
------------------------------------------------------------------------
|
|
|
|
## Validation & Contraintes
|
|
|
|
### required / disabled / readonly
|
|
- Type: boolean
|
|
- Description: Attributs HTML standards. `disabled` et `readonly` empêchent l'ouverture du dropdown.
|
|
|
|
------------------------------------------------------------------------
|
|
|
|
## États & Messages
|
|
|
|
### hint / error / success
|
|
- Type: string
|
|
- Description: Messages affichés sous le champ. `error` est prioritaire et active `aria-invalid`.
|
|
|
|
------------------------------------------------------------------------
|
|
|
|
## Clavier
|
|
|
|
- `↓` / `↑` : naviguer dans les options
|
|
- `Entrée` : sélectionner l'option active (ou créer si `allowCreate`)
|
|
- `Échap` : fermer le dropdown et revenir à la dernière sélection
|
|
|
|
------------------------------------------------------------------------
|
|
|
|
## Accessibilité
|
|
|
|
- `role="combobox"` sur l'input avec `aria-expanded`, `aria-controls`, `aria-activedescendant`.
|
|
- `role="listbox"` sur le dropdown, `role="option"` sur chaque entrée, `aria-selected` reflète `modelValue`.
|
|
- `aria-invalid` activé si `error` existe.
|
|
- `aria-describedby` référence dynamiquement le message affiché.
|
|
|
|
------------------------------------------------------------------------
|
|
|
|
## Events
|
|
|
|
### update:modelValue
|
|
- Émis quand l'utilisateur sélectionne une option. Permet l'utilisation avec v-model.
|
|
|
|
### search
|
|
- Émis (après debounce + minSearchLength) avec la query texte tapée. C'est ce que le parent écoute pour lancer l'appel API.
|
|
|
|
### select
|
|
- Émis avec l'objet `Option` complet (ou `null` à la réinitialisation). Utile pour récupérer le `label` côté parent en plus du `value`.
|
|
|
|
### create
|
|
- Émis avec la chaîne saisie quand `allowCreate` est vrai et que l'utilisateur valide une valeur libre.
|
|
</docs>
|
|
|
|
<script setup lang="ts">
|
|
import {ref} from 'vue'
|
|
import MalioInputAutocomplete from '../../components/malio/input/InputAutocomplete.vue'
|
|
|
|
type Option = {label: string; value: string | number}
|
|
|
|
const staticOptions: Option[] = [
|
|
{label: 'France', value: 'fr'},
|
|
{label: 'Belgique', value: 'be'},
|
|
{label: 'Canada', value: 'ca'},
|
|
{label: 'Suisse', value: 'ch'},
|
|
{label: 'Luxembourg', value: 'lu'},
|
|
{label: 'Allemagne', value: 'de'},
|
|
]
|
|
|
|
const simpleValue = ref<string | number | null>('fr')
|
|
const leftIconValue = ref<string | number | null>(null)
|
|
const createValue = ref<string | number | null>(null)
|
|
const disabledValue = ref<string | number | null>('fr')
|
|
const readonlyValue = ref<string | number | null>('be')
|
|
const hintValue = ref<string | number | null>(null)
|
|
const errorValue = ref<string | number | null>('fr')
|
|
const successValue = ref<string | number | null>('fr')
|
|
|
|
const apiValue = ref<string | number | null>(null)
|
|
const apiOptions = ref<Option[]>([])
|
|
const apiLoading = ref(false)
|
|
|
|
const fakeClients: Option[] = [
|
|
{label: 'Yuno Malio', value: 1},
|
|
{label: 'Yuna Corp', value: 2},
|
|
{label: 'Yum Foods', value: 3},
|
|
{label: 'Acme Inc.', value: 4},
|
|
{label: 'Globex Corp', value: 5},
|
|
]
|
|
|
|
const onSearchApi = async (query: string) => {
|
|
apiLoading.value = true
|
|
await new Promise(resolve => setTimeout(resolve, 400))
|
|
apiOptions.value = fakeClients.filter(c =>
|
|
c.label.toLowerCase().includes(query.toLowerCase()),
|
|
)
|
|
apiLoading.value = false
|
|
}
|
|
</script>
|