Aller au contenu principal

Formulaire

Composant composite formé de LhForm + LhFormItem, offrant la validation des données, l'affichage des erreurs et l'alignement des libellés.

Utilisation de base​

Formulaire avec validation
import { useRef, useState } from 'react'
import { LhButton, LhForm, LhFormItem, LhInput, LhSelect } from '@lh-ui/react'
import type { LhFormInstance, LhFormRule } from '@lh-ui/react'

interface FormData {
name: string
style: string
}

const rules: Record<string, LhFormRule[]> = {
name: [{ required: true, message: 'Veuillez saisir le nom de l’œuvre', trigger: 'blur' }],
style: [{ required: true, message: 'Veuillez choisir un style', trigger: 'change' }],
}

export default function Demo() {
const [formData, setFormData] = useState<FormData>({ name: '', style: '' })
const formRef = useRef<LhFormInstance>(null)

const handleSubmit = async () => {
const valid = await formRef.current?.validate()
if (valid) alert(`Envoi réussi : ${formData.name} / ${formData.style}`)
}

const handleReset = () => {
formRef.current?.resetFields()
setFormData({ name: '', style: '' })
}

return (
<LhForm ref={formRef} model={formData} rules={rules} labelWidth="80px">
<LhFormItem label="Nom de l'œuvre" prop="name">
<LhInput
value={formData.name}
onChange={(val) => setFormData((prev) => ({ ...prev, name: val }))}
/>
</LhFormItem>
<LhFormItem label="Style" prop="style">
<LhSelect
value={formData.style}
onChange={(val) => setFormData((prev) => ({ ...prev, style: val as string }))}
options={[{ label: 'Encre', value: 'ink' }]}
/>
</LhFormItem>
<LhFormItem>
<LhButton type="primary" onClick={handleSubmit}>Envoyer</LhButton>
<LhButton onClick={handleReset}>Réinitialiser</LhButton>
</LhFormItem>
</LhForm>
)
}

Form Props​

PropDescriptionTypeValeur par défaut
modelObjet de données du formulaire (requis)Record<string, unknown>—
rulesRègles de validation, indexées par nom de champRecord<string, LhFormRule[]>—
labelWidthLargeur des libellésstring | number—
labelPositionPosition des libellés'left' | 'right' | 'top''right'
inlineMise en page en lignebooleanfalse
disabledDésactive tous les enfantsbooleanfalse
sizeTaille des enfants'large' | 'middle' | 'small'Selon ConfigProvider
onSubmitÉvénement natif de soumission (preventDefault déjà appliqué)(event: FormEvent) => void—

FormItem Props​

PropDescriptionTypeValeur par défaut
labelTexte du libelléstring—
propNom du champ (chemins pointillés pris en charge, en correspondance avec une clé de model)string—
rulesRègles de niveau item (priment sur les règles de niveau form de même nom)LhFormRule[]—
requiredAstérisque requis (ne rend que le marqueur ; la sémantique de validation vient de rules)booleanfalse
labelWidthPrime sur la largeur des libellés de niveau formstring | number—
errorMessageMessage d'erreur personnaliséstring—
showMessageAfficher ou non le message d'erreurbooleantrue

LhFormRule​

PropDescriptionType
requiredChamp requis ou nonboolean
messageMessage en cas d'échec de la validationstring
triggerMode de déclenchement'blur' | 'change'
validatorFonction de validation personnalisée (peut renvoyer une Promise ; la validation asynchrone est correctement attendue)(value, model) => string | undefined | Promise<string | undefined>
min / maxValeur minimale / maximale (nombre ou longueur)number
patternValidation par expression régulièreRegExp

Méthodes exposées par le ref de Form​

LhFormInstance (exposé via forwardRef + useImperativeHandle) :

MéthodeDescriptionValeur de retour
validateValide tous les champsPromise<boolean>
validateFieldValide un seul champPromise<boolean>
resetFieldsRéinitialise tous les champs à leurs valeurs initialesvoid
resetFieldRéinitialise un seul champvoid
const formRef = useRef<LhFormInstance>(null)
const ok = await formRef.current?.validate()
Validation asynchrone

Cette bibliothèque corrige le défaut de validation asynchrone de plus : le validateField de plus utilise Promise.resolve(!message) sans attendre la Promise du validateur asynchrone, laquelle renvoie donc toujours true. La version React attend explicitement la thenable avant de conclure. Voir le guide de migration.

Enregistrement des champs

LhFormItem enregistre son validateur auprès du formulaire au sein de useEffect et se désenregistre automatiquement au démontage. Les champs n'ont pas besoin d'être déclarés à l'avance dans rules — un champ présent dans model mais absent de rules voit sa valeur initiale récupérée au moment de l'enregistrement.

Sémantique de trigger (amélioration React)

La fonction validateFormField de share n'interprète pas trigger ; le moment du déclenchement est câblé par cette couche : trigger: 'blur' (par défaut) valide lorsque le FormItem perd le focus, et trigger: 'change' valide lorsque la zone de contenu émet un change. Une règle sans trigger ne s'exécute qu'à la perte de focus et lors de validate(), afin d'éviter l'apparition répétée des erreurs pendant la saisie.

La validation sur change lit la nouvelle valeur de la cible de l'événement plutôt qu'un instantané de model — les mises à jour d'état de React et la distribution des événements ne tombent pas dans le même cycle, et lire le modèle en retour serait en retard d'un cycle. Les événements change des contrôles natifs (input / textarea / select natif) sont capturés à la remontée vers la zone de contenu ; les contrôles personnalisés n'ont pas d'événement change natif (un clic sur une option de LhSelect ne produit qu'un click), et déclenchent donc la validation au moyen de validateChange(value) du contexte du FormItem, en transmettant la nouvelle valeur.

La réinitialisation efface les erreurs (amélioration React)

Outre la restauration de model à l'instantané des valeurs initiales, resetFields() incrémente un resetVersion interne ; chaque FormItem observe ce changement de version et efface son propre état d'erreur. L'état contrôlé externe doit toujours être synchronisé manuellement (comme setFormData(initial) dans la démo) — React ne peut pas écrire le modèle à votre place, à la différence de la chaîne réactive de Vue.

Styles​

import '@lh-ui/react/style/form'