v12.5
Schémas de domaine
Introduction
Focus intègre désormais Zod dans les domaines. On utilise désormais des schémas Zod au lieu des types de domaines ("string", "number", "number-array"...).
Les domaines se définissent maintenant à partir du schéma comme premier argument, par exemple :
export const DO_LIBELLE = domain(z.string().max(100));
export const DO_EMAIL = domain(z.email(), {inputProps: {icon: "email"}):Les schémas Zod incluent le type du champ, qui peut être une primitive simple comme string, ou bien un type plus complexe tel qu'un email (via z.email()) ou une date (via z.iso.date()), qui sont toujours des string mais avec un format plus précis. Ces schémas servent donc également à faire de la validation, et remplacent donc les validateurs tels qu'ils existaient dans Focus jusqu'à présent (comme le max(100) l'indique dans l'exemple précédent).
Pas de panique pour la migration de l'existant : les anciens validateurs existent toujours en l'état, et vous n'avez pas du tout besoin de migrer toute la logique de validation dans vos schémas Zod. La migration à minima de vos définitions existantes peuvent utiliser les correspondances suivantes :
"string"=>z.string(), de type TypescriptZodString"number"=>z.number(), de type TypescriptZodNumber"boolean"=>z.boolean(), de type TypescriptZodBoolean"xxx-array"=>z.array(z.xxx()), de type TypescriptZodArray<ZodXXX>"object"=>z.any(), de type TypescriptZodAny
Vous êtes cependant largement encouragés à mettre à jour progressivement vos domaines avec des schémas plus précis. Un jour, Focus supprimera les validateurs existants, donc vous pouvez d'ores et déjà vous préparer, en particulier pour le nouveau code.
Autres breaking changes
- Les propriétés
typedes composants de formulaires, qui prenaient avant un type de domaine, s'appellent désormaisschema, et prennent un schéma en paramètre. - Le domaine par défaut d'un nouveau champ est désormais
z.never(), alors que c'était un domaine"string"(sans composants) au préalable. Cela veut dire que vous devez renseigner un domaine dans unmakeFieldou unaddsi ce n'était pas déjà le cas, et que la définition doit être en premier. Vous le verrez bien assez vite avec les erreurs qui remonteront là-dessus 😉.
En revanche, un domaine sans schéma défini explicitement aura un schémaz.unknown()(vous pouvez appelerdomain()sans paramètres 😋).
Nouveaux comportements par défaut
Dans l'idée, le schéma devrait être suffisant en première approche pour définir entièrement un domaine. Par conséquent, la fonction de création de domaine va désormais déduire plus de choses qu'avant par défaut :
- Pour un booléen, le composant de saisie sera
BooleanRadio(au lieu d'Input), et aura un formatter de booléen standard qui affichera "Oui" ou "Non" (traduisible). - Pour un nombre, si le composant de saisie n'est pas modifié (on garde
Input), alorsmaxDecimalsetnoNegativeNumbersseront pré-renseignés avec ce qui est définit dans le schéma (valeur minimale, si le nombre est un entier). - Pour une chaîne de caractères, si le composant de saisie n'est pas modifié, alors
maxLengthsera pré-renseigné avec la valeur passée àmax(). - Pour une date (
z.iso.date()), le composant de saisie par défaut seraInputDate, et s'il n'est pas modifié, il sera pré-renseigné avecISOStringFormatà"date-only". De plus, le formateur par défaut affichera une date au format court dans la locale de l'utilisateur (dd/MM/yyyyen français). - Pour une date/heure (
z.iso.datetime()), le formateur par défaut affichera une date/heure au format court dans la locale de l'utilisateur (dd/MM/yyyy HH:mm:ssen français).
Si vous faites la migration minimale comme présentée dans le premier paragraphe, aucun de ces comportements ne devraient vous impacter (hormis celui sur les booléens, mais à priori le composant de saisie et le formateur sont déjà surchargés dans vos domaines existants).
Autres nouveautés
displayFormatteraccepte désormais une clé de traduction i18n, qui sera résolue avec la variable{{value}}, au lieu d'une fonction. Focus définit aussi trois transformations de base,boolean,dateetdatetime, qui peuvent être utilisées pour convertir l'affichage de la valeur en booléen, en date, ou en date/heure. C'est une fonctionnalité native d'i18next. C'est utilisé par les formateurs par défaut du paragraphe précédent : par exemple, la clé"focus.date"est la valeur par défaut dudisplayFormatterdes domaines de date et vaut"{{value, date}}".- La locale du
Calendar(utilisé dans leInputDate) est désormais définie à partir de la locale i18next, au lieu de celle de Luxon (qui est initialisée à partir de celle du navigateur). LeinputFormatde l'InputDateest lui aussi initialisé à partir de la locale i18next, au lieu d'avoir une valeur en dur par défaut (qui ne pouvait pas dépendre de la locale). - Dans les
makeFieldet autresadd/patchde champs, vous pouvez renseignerschemadans.metadata()pour modifier le schéma du champ. Il s'agit d'une fonction appelée avec le schéma original du domaine. Par exemple, vous pouvez faire.patch("myNumber", f => f.metadata({schema: s => s.nonnegative()})), pour ajouter une contrainte supplémentaire sur le schéma. Cela remplace l'ajout devalidatordans les métadonnées (qui reste toujours possible, mais déprécié comme dans le domaine). Vous ne pourrez en revanche pas changer le type du schéma.