feat: composant saisie assistée, composant téléphone et composant mail (#47)
All checks were successful
Release / release (push) Successful in 1m12s
All checks were successful
Release / release (push) Successful in 1m12s
| 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é Co-authored-by: matthieu <matthieu@yuno.malio.fr> Co-authored-by: THOLOT DECHENE Matthieu <matthieu@yuno.malio.fr> Reviewed-on: #47 Co-authored-by: tristan <tristan@yuno.malio.fr> Co-committed-by: tristan <tristan@yuno.malio.fr>
This commit was merged in pull request #47.
This commit is contained in:
294
app/story/input/inputAutocomplete.story.vue
Normal file
294
app/story/input/inputAutocomplete.story.vue
Normal file
@@ -0,0 +1,294 @@
|
||||
<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>
|
||||
261
app/story/input/inputEmail.story.vue
Normal file
261
app/story/input/inputEmail.story.vue
Normal file
@@ -0,0 +1,261 @@
|
||||
<template>
|
||||
<Story title="Input/Email">
|
||||
<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</h2>
|
||||
<MalioInputEmail
|
||||
v-model="simpleValue"
|
||||
label="Adresse email"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="rounded-lg border p-4">
|
||||
<h2 class="mb-4 text-xl font-bold">Icône à gauche</h2>
|
||||
<MalioInputEmail
|
||||
v-model="leftIconValue"
|
||||
label="Adresse email"
|
||||
icon-position="left"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="rounded-lg border p-4">
|
||||
<h2 class="mb-4 text-xl font-bold">Sans icône</h2>
|
||||
<MalioInputEmail
|
||||
v-model="noIconValue"
|
||||
label="Adresse email"
|
||||
:icon-name="''"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="rounded-lg border p-4">
|
||||
<h2 class="mb-4 text-xl font-bold">Avec hint</h2>
|
||||
<MalioInputEmail
|
||||
v-model="hintValue"
|
||||
label="Adresse email"
|
||||
hint="ex: prenom.nom@malio.fr"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="rounded-lg border p-4">
|
||||
<h2 class="mb-4 text-xl font-bold">Désactivé</h2>
|
||||
<MalioInputEmail
|
||||
v-model="disabledValue"
|
||||
label="Adresse email"
|
||||
disabled
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="rounded-lg border p-4">
|
||||
<h2 class="mb-4 text-xl font-bold">Readonly</h2>
|
||||
<MalioInputEmail
|
||||
v-model="readonlyValue"
|
||||
label="Adresse email"
|
||||
readonly
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="rounded-lg border p-4">
|
||||
<h2 class="mb-4 text-xl font-bold">Erreur</h2>
|
||||
<MalioInputEmail
|
||||
v-model="errorValue"
|
||||
label="Adresse email"
|
||||
error="Adresse email invalide"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="rounded-lg border p-4">
|
||||
<h2 class="mb-4 text-xl font-bold">Succès</h2>
|
||||
<MalioInputEmail
|
||||
v-model="successValue"
|
||||
label="Adresse email"
|
||||
success="Adresse email valide"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Story>
|
||||
</template>
|
||||
|
||||
<docs lang="md">
|
||||
# MalioInputEmail
|
||||
|
||||
Champ email avec label flottant, icône email par défaut, états visuels
|
||||
(erreur / succès) et accessibilité. Basé sur InputText mais ciblé sur la
|
||||
saisie d'une adresse email (`type="email"` + `inputmode="email"`).
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
## Props détaillées
|
||||
|
||||
### id
|
||||
|
||||
- Type: string
|
||||
- Description: Identifiant HTML de l'input.
|
||||
- Comportement: Si non fourni, un id unique est généré automatiquement
|
||||
(préfixe `malio-input-email-`).
|
||||
|
||||
### label
|
||||
|
||||
- Type: string
|
||||
- Description: Texte affiché comme label flottant.
|
||||
- Comportement: Si absent, aucun label n'est rendu.
|
||||
|
||||
### name
|
||||
|
||||
- Type: string
|
||||
- Description: Attribut name de l'input (utile pour les formulaires).
|
||||
|
||||
### autocomplete
|
||||
|
||||
- Type: string
|
||||
- Défaut: `off`
|
||||
- Description: Active ou configure l'autocomplétion navigateur. La
|
||||
valeur par défaut est `off` pour les formulaires de création d'ERP.
|
||||
Passer `email` pour permettre au navigateur de suggérer l'adresse
|
||||
de l'utilisateur (formulaires de connexion / inscription).
|
||||
|
||||
### modelValue
|
||||
|
||||
- Type: string | null | undefined
|
||||
- Description: Valeur contrôlée du composant.
|
||||
- Comportement:
|
||||
- Si défini → composant contrôlé (v-model).
|
||||
- Sinon → gestion interne de l'état.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
## Apparence & Style
|
||||
|
||||
### inputClass
|
||||
|
||||
- Type: string
|
||||
- Description: Classes CSS appliquées à l'input.
|
||||
|
||||
### labelClass
|
||||
|
||||
- Type: string
|
||||
- Description: Classes CSS appliquées au label.
|
||||
|
||||
### groupClass
|
||||
|
||||
- Type: string
|
||||
- Description: Classes CSS appliquées au conteneur.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
## Validation & Contraintes
|
||||
|
||||
### required
|
||||
|
||||
- Type: boolean
|
||||
- Description: Ajoute l'attribut HTML required.
|
||||
|
||||
### disabled
|
||||
|
||||
- Type: boolean
|
||||
- Description: Désactive complètement le champ.
|
||||
|
||||
### readonly
|
||||
|
||||
- Type: boolean
|
||||
- Description: Rend le champ non modifiable mais focusable.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
## États & Messages
|
||||
|
||||
### hint
|
||||
|
||||
- Type: string
|
||||
- Description: Message d'aide affiché sous le champ.
|
||||
|
||||
### error
|
||||
|
||||
- Type: string
|
||||
- Description: Message d'erreur.
|
||||
- Effet:
|
||||
- Active l'état visuel erreur.
|
||||
- aria-invalid=true
|
||||
- Prioritaire sur success et hint.
|
||||
|
||||
### success
|
||||
|
||||
- Type: string
|
||||
- Description: Message de succès.
|
||||
- Effet:
|
||||
- Actif uniquement si error est absent.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
## Icône
|
||||
|
||||
### iconName
|
||||
|
||||
- Type: string
|
||||
- Défaut: `mdi:email-outline`
|
||||
- Description: Nom Iconify de l'icône affichée. Passer une chaîne
|
||||
vide pour ne pas afficher d'icône.
|
||||
|
||||
### iconPosition
|
||||
|
||||
- Type: `'left' | 'right'`
|
||||
- Défaut: `right`
|
||||
|
||||
### iconSize
|
||||
|
||||
- Type: string | number
|
||||
- Défaut: `24`
|
||||
|
||||
### iconColor
|
||||
|
||||
- Type: string
|
||||
- Défaut: `text-m-muted`
|
||||
- Description: Classe Tailwind de couleur. Surchargée automatiquement
|
||||
par les états erreur / succès.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
## Comportement
|
||||
|
||||
- Aucune validation interne — le composant ne vérifie pas le format
|
||||
de l'email. Utiliser la validation HTML native (`type="email"`) ou
|
||||
piloter `error` / `success` depuis le parent.
|
||||
- `inputmode="email"` est appliqué pour adapter le clavier mobile.
|
||||
|
||||
## Priorité visuelle
|
||||
|
||||
1. error
|
||||
2. success
|
||||
3. neutre
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
## Accessibilité
|
||||
|
||||
- aria-invalid est activé si error existe.
|
||||
- aria-describedby référence dynamiquement le message affiché.
|
||||
- Fonctionne avec ou sans v-model.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
## Events
|
||||
|
||||
### update:modelValue
|
||||
|
||||
- Émis à chaque modification de l'input.
|
||||
- Permet l'utilisation avec v-model.
|
||||
|
||||
</docs>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {ref} from 'vue'
|
||||
import MalioInputEmail from '../../components/malio/input/InputEmail.vue'
|
||||
|
||||
const simpleValue = ref('')
|
||||
const leftIconValue = ref('')
|
||||
const noIconValue = ref('')
|
||||
const hintValue = ref('')
|
||||
const disabledValue = ref('contact@malio.fr')
|
||||
const readonlyValue = ref('readonly@malio.fr')
|
||||
const errorValue = ref('pas-un-email')
|
||||
const successValue = ref('contact@malio.fr')
|
||||
</script>
|
||||
285
app/story/input/inputPhone.story.vue
Normal file
285
app/story/input/inputPhone.story.vue
Normal file
@@ -0,0 +1,285 @@
|
||||
<template>
|
||||
<Story title="Input/Phone">
|
||||
<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</h2>
|
||||
<MalioInputPhone
|
||||
v-model="simpleValue"
|
||||
label="Téléphone"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="rounded-lg border p-4">
|
||||
<h2 class="mb-4 text-xl font-bold">Avec bouton « ajouter »</h2>
|
||||
<MalioInputPhone
|
||||
v-model="addableValue"
|
||||
label="Téléphone"
|
||||
addable
|
||||
@add="onAdd"
|
||||
/>
|
||||
<p v-if="addClicks > 0" class="mt-2 text-sm text-m-muted">
|
||||
Bouton cliqué {{ addClicks }} fois
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="rounded-lg border p-4">
|
||||
<h2 class="mb-4 text-xl font-bold">Icône à droite</h2>
|
||||
<MalioInputPhone
|
||||
v-model="rightIconValue"
|
||||
label="Téléphone"
|
||||
icon-position="right"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="rounded-lg border p-4">
|
||||
<h2 class="mb-4 text-xl font-bold">Sans icône</h2>
|
||||
<MalioInputPhone
|
||||
v-model="noIconValue"
|
||||
label="Téléphone"
|
||||
:icon-name="''"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="rounded-lg border p-4">
|
||||
<h2 class="mb-4 text-xl font-bold">Avec masque français</h2>
|
||||
<MalioInputPhone
|
||||
v-model="maskedValue"
|
||||
label="Téléphone (FR)"
|
||||
mask="+33 # ## ## ## ##"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="rounded-lg border p-4">
|
||||
<h2 class="mb-4 text-xl font-bold">Avec hint</h2>
|
||||
<MalioInputPhone
|
||||
v-model="hintValue"
|
||||
label="Téléphone"
|
||||
hint="Format international recommandé"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="rounded-lg border p-4">
|
||||
<h2 class="mb-4 text-xl font-bold">Désactivé (avec addable)</h2>
|
||||
<MalioInputPhone
|
||||
v-model="disabledValue"
|
||||
label="Téléphone"
|
||||
addable
|
||||
disabled
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="rounded-lg border p-4">
|
||||
<h2 class="mb-4 text-xl font-bold">Readonly</h2>
|
||||
<MalioInputPhone
|
||||
v-model="readonlyValue"
|
||||
label="Téléphone"
|
||||
addable
|
||||
readonly
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="rounded-lg border p-4">
|
||||
<h2 class="mb-4 text-xl font-bold">Erreur</h2>
|
||||
<MalioInputPhone
|
||||
v-model="errorValue"
|
||||
label="Téléphone"
|
||||
error="Numéro de téléphone invalide"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="rounded-lg border p-4">
|
||||
<h2 class="mb-4 text-xl font-bold">Succès</h2>
|
||||
<MalioInputPhone
|
||||
v-model="successValue"
|
||||
label="Téléphone"
|
||||
success="Numéro valide"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Story>
|
||||
</template>
|
||||
|
||||
<docs lang="md">
|
||||
# MalioInputPhone
|
||||
|
||||
Champ téléphone avec label flottant, icône phone par défaut (à gauche),
|
||||
états visuels (erreur / succès), accessibilité et bouton « + » optionnel
|
||||
pour gérer une liste de numéros côté parent (`type="tel"` +
|
||||
`inputmode="tel"`).
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
## Props détaillées
|
||||
|
||||
### id
|
||||
|
||||
- Type: string
|
||||
- Description: Identifiant HTML de l'input.
|
||||
- Comportement: Si non fourni, un id unique est généré automatiquement
|
||||
(préfixe `malio-input-phone-`).
|
||||
|
||||
### label
|
||||
|
||||
- Type: string
|
||||
- Description: Texte affiché comme label flottant.
|
||||
|
||||
### name
|
||||
|
||||
- Type: string
|
||||
- Description: Attribut name de l'input (utile pour les formulaires).
|
||||
|
||||
### autocomplete
|
||||
|
||||
- Type: string
|
||||
- Défaut: `off`
|
||||
- Description: Active ou configure l'autocomplétion navigateur. La
|
||||
valeur par défaut est `off` pour les formulaires de création d'ERP.
|
||||
Passer `tel` pour permettre au navigateur de suggérer un numéro
|
||||
enregistré.
|
||||
|
||||
### modelValue
|
||||
|
||||
- Type: string | null | undefined
|
||||
- Description: Valeur contrôlée du composant.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
## Apparence & Style
|
||||
|
||||
### inputClass / labelClass / groupClass
|
||||
|
||||
- Type: string
|
||||
- Description: Classes CSS appliquées respectivement à l'input, au
|
||||
label et au conteneur.
|
||||
|
||||
### mask
|
||||
|
||||
- Type: string | MaskInputOptions
|
||||
- Description: Masque maska à appliquer. Aucun masque par défaut —
|
||||
les formats téléphoniques varient trop selon les pays. À activer
|
||||
pour un usage mono-pays.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
## Validation & Contraintes
|
||||
|
||||
### required / disabled / readonly
|
||||
|
||||
- Type: boolean
|
||||
- Description: Attributs HTML standards.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
## États & Messages
|
||||
|
||||
### hint / error / success
|
||||
|
||||
- Type: string
|
||||
- Description: Messages affichés sous le champ.
|
||||
- `error` est prioritaire sur `success` et active `aria-invalid`.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
## Icône
|
||||
|
||||
### iconName
|
||||
|
||||
- Type: string
|
||||
- Défaut: `mdi:phone-outline`
|
||||
- Description: Nom Iconify de l'icône affichée. Passer une chaîne
|
||||
vide pour ne pas afficher d'icône.
|
||||
|
||||
### iconPosition
|
||||
|
||||
- Type: `'left' | 'right'`
|
||||
- Défaut: `left` (laisse la droite libre pour le bouton +).
|
||||
|
||||
### iconSize / iconColor
|
||||
|
||||
- Type: number / string
|
||||
- Défaut: `24` / `text-m-muted`
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
## Bouton « ajouter »
|
||||
|
||||
### addable
|
||||
|
||||
- Type: boolean
|
||||
- Défaut: `false`
|
||||
- Description: Affiche un bouton à droite du champ. Au clic, le
|
||||
composant émet l'event `add` — c'est au parent de gérer l'ajout
|
||||
d'un nouveau champ téléphone.
|
||||
|
||||
### addIconName
|
||||
|
||||
- Type: string
|
||||
- Défaut: `mdi:plus`
|
||||
- Description: Nom Iconify de l'icône du bouton d'ajout.
|
||||
|
||||
### addButtonLabel
|
||||
|
||||
- Type: string
|
||||
- Défaut: `Ajouter un numéro`
|
||||
- Description: Attribut `aria-label` du bouton (accessibilité).
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
## Comportement
|
||||
|
||||
- Aucune validation interne — le composant ne vérifie pas le format
|
||||
du numéro. Piloter `error` / `success` depuis le parent.
|
||||
- `inputmode="tel"` adapte le clavier mobile.
|
||||
- Le bouton `+` est désactivé quand `disabled` ou `readonly` est
|
||||
actif et n'émet pas l'event dans ce cas.
|
||||
|
||||
## Priorité visuelle
|
||||
|
||||
1. error
|
||||
2. success
|
||||
3. neutre
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
## Accessibilité
|
||||
|
||||
- `aria-invalid` activé si `error` existe.
|
||||
- `aria-describedby` référence dynamiquement le message affiché.
|
||||
- Le bouton `+` expose un `aria-label` configurable.
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
## Events
|
||||
|
||||
### update:modelValue
|
||||
|
||||
- Émis à chaque modification de l'input. Permet l'utilisation avec
|
||||
v-model.
|
||||
|
||||
### add
|
||||
|
||||
- Émis au clic du bouton `+` (uniquement si `addable` est vrai et
|
||||
que le champ n'est ni `disabled` ni `readonly`).
|
||||
|
||||
</docs>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {ref} from 'vue'
|
||||
import MalioInputPhone from '../../components/malio/input/InputPhone.vue'
|
||||
|
||||
const simpleValue = ref('')
|
||||
const addableValue = ref('')
|
||||
const rightIconValue = ref('')
|
||||
const noIconValue = ref('')
|
||||
const maskedValue = ref('')
|
||||
const hintValue = ref('')
|
||||
const disabledValue = ref('+33 6 12 34 56 78')
|
||||
const readonlyValue = ref('+33 6 12 34 56 78')
|
||||
const errorValue = ref('abc')
|
||||
const successValue = ref('+33 6 12 34 56 78')
|
||||
|
||||
const addClicks = ref(0)
|
||||
const onAdd = () => {
|
||||
addClicks.value++
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user