8000 Releases · klee-contrib/focus4 · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Releases: klee-contrib/focus4

v12.2

16 May 14:25
Compare
Choose a tag to compare

CollectionStore : tri multiple

Le store de collection gère maintenant du tri par plusieurs colonnes, à la fois en mode local qu'en mode server.
Cela implique les breaking changes suivants :

  • CollectionStore :
    • sortBy?: string et sortAsc: boolean ont été remplacés par sort: {fieldName: string; sortDesc?: boolean}[] (L'inversion de sortAsc/sortDesc ne change pas la valeur du tri par défaut, qui était sortAsc: true avant et qui est sortDesc: false maintenant).
    • sort: {fieldName: string; sortDesc?: boolean}[] est aussi utilisé dans le QueryInput du service de recherche, à la place de sortFieldName et sortDesc.
  • ActionBar / Summary / AdvancedSearch
    • orderableColumnList : {label, key, order} a été remplacé par {label, sort: {fieldName, sortDesc}[]}.

Le tri est donc maintenant au moins toujours défini de la même manière 🙂

Impacts sur les composants

  • Via les évols sur orderableColumnList, vous pouvez définir des tri par plusieurs colonnes
  • Dans tableFor, vous pouvez activer le tri multiple via la prop maxSort, qui définit le nombre maximal de colonnes sur lesquelles il est possible de trier via les headers du tableau. Cette prop vaut 1 par défaut pour conserver le comportement actuel.

Ces deux évolutions sont utilisées dans le showcase des composants dans la documentation 🙂

v12.1

01 May 18:22
Compare
Choose a tag to compare

Evolutions de useLoad

  • Vous pouvez désormais utiliser useLoad sur un CollectionStore en mode local (sans service de chargement dédié côté serveur). Cela fonctionne de la même façon qu'avec un store d'entité classique, à la différence près qu'il faut appeler collectionStore.search() et non storeNode.load() pour appeler manuellement le service de chargement (puisque c'était déjà la méthode pour le store avec service de chargement dédié).
    Cela entraîne un petit breaking change, sur le fait qu'il n'est plus possible de renseigner store.isLoading manuellement sur un CollectionStore local. Vous devriez de toute façon utiliser useLoad à la place maintenant, et sinon vous avez accès au trackingId du store pour faire un requestStore.track à la main.
  • Les requêtes en cours lors d'un changement de paramètres ou si le composant contenant le useLoad est démonté sont maintenant correctement annulées, directement au niveau du navigateur. Cela veut dire que le résultat de cette requête ne sera même pas interprété par le navigateur, ce qui permet d'éviter tout une catégorie de problèmes si le serveur répond trop lentement.

Autres évolutions

  • Les traductions de messages d'erreurs sur les champs peuvent désormais utiliser la définition du champ dans leur template. Par exemple, vous pouvez désormais avoir Le champ '{{label}}' est obligatoire comme message.
  • Le composant InputFile peut désormais afficher des icônes différentes en fonction du type du fichier téléchargé.

v12

20 Mar 17:46
Compare
Choose a tag to compare
8000
v12

Montées de version

Cette version de Focus réalise les montées de versions suivantes :

  • react 19
  • mobx-react 9
  • eslint 9
  • lodash => es-toolkit
  • numeral => Intl.NumberFormat (qui est une API native du navigateur)

Les breaking changes associés sont :

  • Pour React, certaines APIs dépréciées depuis longtemps (mais pas toutes) ont enfin été retirées. A priori, si votre application à été commencée en React 16 vous ne devriez être concernés par aucune de ces dépréciations
  • Pour MobX React, les breaking changes concernent les composants classes, sur lesquels il n'y a plus de "hack" fait pour rendre les props (et le state) observable. C'est potentiellement très dérangeant pour les applications qui utilisent (encore) des classes
  • Pour ESLint, c'est juste le format de la configuration
  • Pour les autres libs, elles ont été retirées de Focus, mais cela ne vous force pas nécessairement à en faire de même (comme moment à l'époque)

Retrait du module legacy et support des composants classes

La montée de version de mobx-react a aussi l'occasion de passer aux décorateurs standards stage-3, qui ne sont pas compatibles avec les anciens. Toutes ces évolutions combinées vont rentre une éventuelle montée de version pour les projets qui utilisent encore des composants classes très difficile, sans compter le temps qu'il faudrait pour mettre à jour le module legacy lui même.

Le plus simple (pour l'instant en tout cas, il n'est pas exclus de revenir sur la décision plus tard, au moins partiellement) sera donc de supprimer le module legacy (AutoForm, @classAutorun et l'ancien routeur à base de ViewStore essentiellement), ainsi que les APIs makeFormNode/makeFormActions pour être cohérent. Si jamais un ancien projet souhaite faire la mise à jour vers la v12 dans le futur, son temps sera bien mieux utilisé à migrer vers des composants fonctions plutôt que de repasser sur tous ses composants classes pour essayer de continuer à les faire fonctionner...

Pour utiliser les nouveaux décorateurs, il faudra enlever l'option experimentalDecorators: true de la configuration Typescript.

Redécoupage des modules

  • Le module forms a été divisé en deux : forms et form-toolbox, pour séparer les composants pour créer les formulaires (fieldFor, useFormNode...) qui sont dans le premier, et les composants de formulaire, utilisés comme InputComponent/SelectComponent... (Input, Select...). Cela permet de retirer la dépendance au module toolbox de forms, pour permettre l'usage des formulaires Focus sans embarquer le module toolbox qui contient les composants de base, et ouvrir la porte à un interface "natif" avec d'autres librairies de composants. Il y aura donc des imports à modifier.
  • Le module focus4 a été supprimé. Vous devez maintenant explicitement référencer les modules dans votre package.json (un nouvel outil présenté plus loin vous aidera à le faire). Le module core expose désormais une fonction baseI18nextConfig qui permet de simplifier l'initialisation des traductions (le module focus4 réexportait toutes les traductions dans un seul objet avant).
  • L'objet de configuration (config) a été divisé entre le module core (coreConfig) et styling (uiConfig), afin de pouvoir avoir des séparations franches entre les modules de base de Focus. En particulier, styling et toolbox ne dépendent plus de core et pourraient être utilisés dans une application qui ne référence pas le reste de Focus (ni même MobX). En passant, uiConfig utilise désormais Material Symbols à la place de Material Icons par défaut.

Traductions

Focus comporte désormais des traductions en anglais, et utilise désormais react-i18next dans les composants pour s'interfacer avec i18next. Cela permet en particulier d'utiliser la fonction i18next.changeLanguage() et d'avoir l'intégralité des composants Focus qui se mettent à jour par défaut, sans avoir à recharger la page. Pour que cela fonctionne avec vos propres composants, il faudra utiliser le hook useTraduction() de react-i18next vous aussi.

De plus, une nouvelle option de configuration coreConfig.useI18nextAcceptHeader peut être renseignée à true pour renseigner le header Accept-Language par défaut sur tous vos appels serveur avec la langue sélectionnée dans i18next. Vous pouvez aussi laisser le header par défaut posé par le navigateur et utiliser le module d'i18next qui permet la détection automatique de la langue de l'utilisateur si vous préférez automatiser la chose.

Le starter-kit est donc désormais entièrement traduit et propose une dropdown dans son header pour changer entre français et anglais. La documentation dispose également d'une dropdown, mais elle ne concerne que les traductions Focus (vous pourrez encore attendre longtemps la doc Focus en anglais hein 😅).

Refonte de l'installation

Les modules de Focus déclarent désormais explicitement des peer dependencies vers react, react-dom, mobx et mobx-react, et toutes les autres dépendances (comme es-toolkit qui remplace lodash par exemple), ainsi que tous les modules Focus, doivent être définis explicitement dans les dépendances du projet, au lieu de dépendre d'un ajout implicite de tout ça via le méta package focus4. Cela permet d'arrêter de définir des "fausses" peerDependencies pour faire marcher les auto-imports.

Le module tooling expose désormais une nouvelle commande install ou update (qui sont rigoureusement identiques), pour gérer l'installation ou la mise à jour des modules Focus. Au lancement, elle va parcourir votre package.json et récupérer la dernière version de chaque module Focus défini dedans (ou ajouter tous les modules s'il n'y en a aucun), ainsi que celles de leurs peer dependencies. Vous pourrez donc utiliser cette commande pour gérer les mise à jour Focus automatiquement, au lieu de faire des mises à jour du package.json à la main et de bidouiller les peer dependencies pour que ça continue à marcher.

Exemple de montée de version

La mise à jour a été réalisée sur le starter kit ici, mais il y a aussi beaucoup d'évolutions liée aux traductions qui ne sont pas vraiment obligatoires à faire 🙂

v11.24

11 Feb 15:04
Compare
Choose a tag to compare

Une petite release contenant quelques évolutions et de fixes de stabilités.

disabled

Tous les composants de Select et d'Autocomplete supportent maintenant une liste de valeurs dans leur propriété disabled, au lieu d'un simple booléen, afin de pouvoir désactiver certaines options uniquement au lieu de tout le champ.

InputFile

Focus contient désormais (enfin !) un composant de upload de fichier, il est présenté dans la documentation.

v11.23

23 Jan 17:01
Compare
Choose a tag to compare

Evolutions sur les formulaires

Fix #193

  • useFormNode peut désormais être appelé avec une définition d'entité à la place d'un noeud existant. Vous n'êtes donc plus obligés d'utiliser un store externe global, ou de faire le buildNode vous même dans le composant

  • useFormActions :

    • Prend une nouvelle méthode init(init?: () => Promise<EntityToType<E0>>), qui sera appelée à la place de load au premier rendu s'il n'y pas de load à appeler. Elle effectue un set des données retournées par la méthode en paramètre sur le formNode (et non un replace sur le storeNode comme load), puis écrase les données du noeud source par les données du formulaire (avec un replace cette fois-ci).

      Elle permettra de faire des initialisations de données pour la création sans utiliser load (ou un effet externe) quand on a besoin d'un appel serveur et de s'assurer que le valeur de hasChanged du formulaire sera toujours calculée à partir des données initiales. Les données complèteront celles déjà définies dans useFormNode (d'où le set), et init pourra être appelé sans paramètre si on veut juste reset le noeud source.

      Idéalement, tout formulaire utilisé en création devrait appeler init, ce qui ne correspond malheureusement pas forcément à tous les formulaires sans load (il peut être défini dans un useLoad séparé par exemple, et ici on ne voudra pas du tout reset le noeud source).

    • Prend deux nouvelles méthodes create et update, mutuellement exclusives avec save, qui seront appelées par actions.save() selon si on a des params (pour update) ou non (pour create). update sera appelée avec les params puis avec le contenu du formulaire, pour correspondre aux API PUT classiques. Pour le reste, elles sont identiques à save.

    • On ajoute on("init"), .on("create") et on("update"), pour faire comme les autres méthodes

    • On autorise les fonctions de sauvegarde (donc create, update et save) à retourner une primitive, en plus de void ou le type du noeud.

    • Les différents on seront appelés avec la valeur retournée par la fonction correspondante (pour init, load, save, create et update). Cela permettra par exemple de faire on("create", id => router.to(x => x(id))) si votre service de création renvoie un ID.

    • On appelle aussi on("error") pour load, et il sera appelé avec le nom du service en erreur, ainsi que l'erreur elle-même.

    • On expose actions.params, pour pouvoir l'utiliser dans le rendu par exemple (pour distinguer le cas de création)

La documentation a évidemment été mise à jour, et le starter kit utilise également ces nouvelles fonctionnalités, si vous voulez un exemple 🙂

Les petits breaking changes à noter :

  • Les stores (source et de formulaire) sont désormais entièrement vidés en cas d'erreur pendant le chargement.
  • params() n'accepte plus de surcharge (qui n'était pas documentée d'ailleurs) qui prend plus d'un seul paramètre. Il faut explicitement passer un array dans ce cas.
  • Le type de FormActions a évolué pour inclure aussi les types de retours de create, update et save, ce qui peut poser quelques soucis si vous l'avez utilisé en props à certains endroits.

ProblemDetails

Focus accepte désormais nativement des réponses en erreur sous le format ProblemDetails, et utilisera les champs detail ou title en plus de errors pour y récupérer le ou les messages d'erreurs à afficher à l'utilisateur.

On supporte désormais des paires clés/valeurs dans errors (au lieu d'une simple liste plate). Chaque message sera préfixé par sa clé quand il sera ajouté au messageStore, ce qui s'interfacera à priori nativement avec les retours en erreurs de vos APIs de validation côté serveur.

Le seul breaking change la dessus concerne ce qui sera renvoyé à un catch d'un appel d'API :

  • avant, on renvoyait la réponse, avec $status et $parsedErrors avec les errors lues du retour serveur.
  • maintenant, on renvoie toujours la réponse, avec status s'il n'y était pas (status fait partie de la spec ProblemDetails), et $messages, qui contient la liste des messages ajoutés dans le messageStore.

C'est presque la même chose qu'avant donc 😁

v11.22

06 Jan 20:46
Compare
Choose a tag to compare

Remarque importante : attention lors de la mise à jour à vos peerDependencies, on n'est plus sur la dernière version de React ni d'i18next, il faudra bien avoir un 18 en face des deux packages react et react-dom et un 23 en face d'i18next. Une version (majeure !) ultérieure de Focus prendra en compte ces montées de versions.

hasChanged

Vous pouvez désormais utiliser node.form.hasChanged ou field.hasChanged dans un noeud de formulaire, pour savoir si une (ou plusieurs) valeur(s) a (ont) été modifiée(s) par rapport à leur(s) valeur(s) correspondantes dans le noeud source.

Remarque : un champ ajouté sera toujours identifié avec hasChanged = false puisqu'il n'existe pas dans le noeud source

router.confirmation

De nouvelles APIs ont été ajoutées sur le routeur afin de pouvoir entrer dans un mode de "confirmation", qui permet de bloquer toute navigation avant que l'utilisateur confirme son intention.

Si la méthode router.confirmation.toggle() permet d'activer/désactiver le mode manuellement, il peut se brancher directement à useFormActions via la méthode .withConfirmation(router) dans son configurateur. Cela aura pour effet d'activer le mode de confirmation si le formulaire est en édition et qu'au moins un champ a été modifié (via node.form.hasChanged), et de le désactiver sinon.

Vous pouvez interagir avec ce mode via :

  • router.confirmation.active => Pour savoir si le mode est actif ou non
  • router.confirmation.pending => Pour savoir si une confirmation est attendue de la part de l'utilisateur : vous pouvez l'utiliser pour afficher un Dialog par exemple
  • router.confirmation.commit(save?: boolean) => Pour confirmer la navigation en attente. Si vous l'appelez avec true, alors la sauvegarde du formulaire sera effectuée avec la confirmation (le service de sauvegarde est passé au routeur via withConfirmation(router)
  • router.confirmation.cancel() => Pour annuler la navigation en attente.

Vous pouvez utiliser ces APIs pour créer votre propre Dialog pour gérer la fonctionnalité. Le starter kit en implémente un exemple.

De plus, la documentation est évidemment à jour 🙂.

Remarques

  • Si vous déclenchez une navigation en dehors de l'application, alors vous aurez le popup natif du navigateur (au lieu de votre Dialog), qui n'est pas personnalisable. Il ne permettra en particulier pas de déclencher la sauvegarde.
  • Vous pouvez tout à fait avoir plusieurs formulaires sur la page qui sont branchés au mode de confirmation. Il sera actif dès lors qu'au moins un formulaire est en édition, et la confirmation avec sauvegarde appellera tous les services de sauvegarde des formulaires en édition.
  • Le routeur a été partiellement réimplémenté, en internalisant la dépendance à yester (une librairie développé par un mec dans son coin il y a 8 ans), qui n'était une légère surcouche à history, la librairie de référence pour gérer la navigation en JS.

v11.21

18 Oct 17:08
Compare
Choose a tag to compare

Refonte du Layout

Cette verrsion réimplémente le Layout/Scrollable (et les choses qui y sont liées comme le Header, le ScrollspyContainer et l'AdvancedSearch) pour implémenter tous les comportement "sticky" avec des position: sticky en CSS au lieu de calculer des positions à la main en Javascript pour tout faire.

En particulier :

  • Le Header n'est plus posé en double, c'est le même Header qui reste entre le header déplié (s'il y en a un) et le Header sticky. Si vous posez un HeaderContent, il scrollera maintenant avec le reste de la page et il passera sous le HeaderTopRow. Les HeaderActions seront posées sous le HeaderContent comme aujourd'hui et scrolleront pour rester "sticky" à leur place sur le header sticky. Il n'y a donc plus de notion de canDeploy/header plié ou déplié.

  • Le menu de gauche du Scrollspy (et de l'AdvancedSearch pour les facettes) est un composant dédié appelé LateralMenu qui se pose directement à côté (avec un display: flex à priori), au lieu d'avoir un portal qui remonte le poser dans le Scrollable (Layout), et il est entièrement géré en CSS. Cela vous laisse donc par exemple la possibilité de changer complètement la mise en page du Scrollspy (par exemple pour mettre le menu au dessus au lieu d'à gauche).

    Le MenuComponent du Scrollspy par défaut contient désormais le LateralMenu, donc si vous voulez le surcharger et garder son positionnement à gauche vous devrez aussi poser un LateralMenu
    Les facettes de l'AdvancedSearch sont maintenant toujours posées en sticky à gauche avec un LateralMenu (enfin sauf si avec facetBoxPosition à none ou action-bar. D'ailleurs, vous pouvez maintenant facilement le mettre à droite en inversant le sens du flex qui le contient.

  • Le "top row" (donc Summary + ActionBar) de la recherche avancée est désormais "sticky" par défaut, et un nouveau hook useStickyClip, utilisé par la recherche avancée du coup, permet de faire en sorte que les résultats soient bien "coupés" lorsqu'ils passent sous la "top row" (au lieu d'apparaitre derrière). tableFor peut aussi le faire avec les headers de colonnes, mais ce n'est pas le cas par défaut (à cause du box-shadow qui est posé par défaut en CSS qui fait que c'est moche 😄 )

  • Tous les calculs en Javascript n'ont pas été retirés, car on a toujours besoin de déterminer le top des divers position: sticky. Par défaut, pour les composants qui ont des comportements sticky, il sera calculé comme avant avec la hauteur du header + --content-padding-top, mais vous pouvez le surcharger avec le prop overrideOffsetTop dans le Scrollspy, AdvancedSearch et tableFor.

  • Ah, et le Panel est désormais dans le module layout au lieu du module forms, désolé ça va faire beaucoup d'imports à changer... 🥺

Cette version intègre également la documentation complète du module layout, maintenant qu'il a été refait tout beau ✨
Vous pourrez donc y voir ce que donnent les évolutions ainsi présentées dans cette release note 🙂

Résumé des breaking changes

  • Les imports de Panel viennent désormais de @focus4/layout au lieu de @focus4/forms
  • Le HeaderScrolling n'a plus de prop canDeploy (elle ne sert plus à rien)
  • Le HeaderContent est affiché différemment
  • Les menus latéraux du ScrollspyContainer et de l'AdvancedSearch ont un nouveau design (et AdvancedSearch n'a plus de facetBoxPosition: "sticky" car elle est toujours sticky maintenant)
  • Vous ne pouvez plus utiliser le ScrollableContext (qui est désormais exposé depuis @focus4/layout) pour poser un menu latéral, il faut le faire avec le composant LateralMenu. Si vous l'utilisiez pour faire une surcharge bizarre de la taille du header, vous pouvez maintenant la passer directement au ScrollspyContainer.

Fil d'Ariane

Pour répondre à la demande populaire, un composant de fil d'Ariane a été ajouté dans le module layout, qui s'intègre nativement avec le routeur et les traductions i18n.

Il est utilisé dans le starter kit et possède évidemment sa propre page de documentation 😉

v11.20

30 Sep 18:51
Compare
Choose a tag to compare

Cette release contient un grand nombre de petites évolutions suite à des demandes utilisateurs diverses :

Composants par défaut sur les domaines

Les composants par défaut (InputComponent, SelectComponent, DisplayComponent...) sont désormais portés par le domaine au lieu d'être définis dans le composant de champ (Field, posé par fieldFor/selectFor/autocompleteFor). Cette évolution est accompagnée d'un renforcement des types de composants que l'on peut passer aux domaines, afin de pouvoir être sûr que le composant passé corresponde bien au type de domaine (exemple : utiliser une Checkbox sur un domaine de type "boolean" uniquement).

Cela implique les changements (potentiellement breaking changes) suivants :

  • Si vous utilisez makeField ou .add() pour créer un champ sans domaine, alors vous n'aurez plus de composants d'affichage ou de saisie par défaut. Il est donc impératif de renseigner un domaine ou les composants d'affichage dont vous avez besoin.

  • Les composants génériques, ceux qui fonctionnent pour plusieurs types comme SelectAutocomplete par exemple, doivent spécifier le type dans la définition, car il ne peut pas être inféré automatiquement 🥺

    Cela veut dire qu'écrire domain({type: "number", SelectComponent: SelectAutocomplete}) est désormais une erreur et que vous devez écrire domain({type: "number", SelectComponent: SelectAutocomplete<"number">}) pour que ça fonctionne. En contrepartie, vous aurez bien le bon type partout dans selectProps, ce qui n'était pas forcément le cas avant.

  • Les domaines multiples ("boolean-array", "number-array" et "string-array") utilisent désormais SelectChips et AutocompleteChips comme composants par défaut (et aucun InputComponent), puisque les composants doivent désormais correspondre au type du domaine. Les domaines de type "object" n'ont plus aucun composant de saisie par défaut. Cela ne devrait casser personne puisqu'il fallait de toute façon impérativement renseigner d'autres composants pour utiliser ces domaines, vous pouvez en revanche maintenant vous en abstenir si les composants par défaut vous conviennent.

  • Vous devez désormais impérativement utiliser la fonction domain() pour créer un domaine. Si vous utilisiez simplement {type: "string"} à certains endroits par exemple, vous devrez le wrapper, ou bien spécifier manuellement les 5 composants de champs.

Autres évolutions

  • b4768c7 - showIfNoData sur les operationList de ActionBar/tableFor
    Vous pouvez renseigner cette propriété (à true) dans une définition d'action dans une ActionBar ou dans un tableFor pour qu'elle soit affichée en permanence, au lieu d'être conditionnée au fait d'avoir sélectionné au moins un élément. A noter que dans l'action est toujours appelée avec les éléments sélectionnés, donc ici ça serait une liste vide. Cette propriété doit être renseignée même s'il n'y a pas de sélection du tout (ce qui est un breaking change pour tableFor).

  • 6743d7a - noSuggestionsOnEmptyQuery sur Autocomplete
    Le composant d'Autocomplete (et donc SelectAutocomplete également) peuvent désormais ne pas afficher les suggestions tant que la query est vide, à la manière de AutocompleteSearch (dont le comportement inverse pouvait déjà être activé avec searchOnEmptyQuery)

  • 34827f3 - noBlurOnClick => noFocusOnClick
    Dans la définition d'un "trailing button" dans un dérivé de TextField, la propriété noBlurOnClick a été renommée en noFocusOnClick puisqu'elle n'effectue plus de "blur" (l'implémentation précédente le faisait à tort, ce qui pouvait entraîner des effets secondaires indésirables, comme dans l'InputDate par exemple)

  • 0775e83 - Conservation des modifications de criteriaBuilder dans le type de CollectionStore
    Le type d'un CollectionStore qui a patché son critère (comme avec useFormNode, via criteriaBuilder), prend désormais en compte le type résultant de ces modifications, au lieu de l'ignorer silencieusement.

  • c39d60e - Fix critères "vides" affichés quand même dans le Summary
    En particulier pour les listes vides.

  • d05d66c - Ajout mouseEvent sur onLineClick sur tableFor
    Il est passé en deuxième paramètre.

  • ab3eddd - Extraction de useInput de Input
    Le comportement du composant Input qui gère le masque de saisie et la saisie de nombres (décimaux) a été extrait dans un hook, si vous voulez l'utiliser dans un autre composant que le TextField.

v11.19

30 Aug 15:04
Compare
Choose a tag to compare

(Pour une fois, cette release n'apporte aucun breaking change 😄)

Compositions isRequired: false

Les compositions ("object", "list", et "recursive-list") peuvent désormais renseigner leur caractère obligatoire via isRequired, comme les champs. Si une composition est marquée comme étant non obligatoire, alors tous ses champs seront également non obligatoires si la composition est entièrement vide (tous les champs à undefined et toutes les listes vides). toFlatValues retirera la composition de son résultat (au lieu de mettre {}) dans ce cas.

isRequired reste facultatif dans les définitions d'entité et il sera true pour coller à l'existant sinon. Si vous utilisez TopModel, vous pouvez le générer avec l'option extendedCompositions du générateur JS.

required()

Vous pouvez désormais utiliser la fonction required() sur un builder de noeud de formulaire, qui fonctionne de la même manière que edit() :

  • required(false) rendra le noeud non obligatoire (comme décrit dans le paragraphe précédent)
  • required(() => /* truc calculé */, "champ1", "champ2") patchera les deux champs pour modifier leur isRequired (cela appelera metadata()).

Cette évolution a nécessité une petite refonte interne de la gestion des surcharges de metadata dans Focus, qui permet en plus de pouvoir spécifier plusieurs patch sur le même champ sans perdre leur caractère calculé (un second patch après un metadata calculé sortait d'ailleurs une erreur, ce qui n'est plus le cas).

Champs retirés sur Patch

Vous pouvez maintenant spécifier les champs retirés dans un formulaire avec Patch via son nouveau troisième paramètre optionnel : Patch<MyEntity, {}, "champRetiré1" | "champRetiré2">.

v11.18

10 Jul 19:31
Compare
Choose a tag to compare

Retrait des styles inline sur les champs

(fix partiel de #194)

Les champs ne posent plus de style inline à base de labelRatio/valueRatio (et disableInlineSizing pour le désactiver). A la place, deux variables CSS sont définies globalement, --field-label-width et --field-value-width, initialisées à 33% et 67% pour conserver l'existant par défaut, qui sont utilisées dans le CSS pour définir les largeurs dans les champs. Par conséquent, toute la mise en page des champs est désormais gérée en CSS, ce qui devrait largement faciliter sa personnalisation (à défaut de proposer d'autres mises en page par défaut, pour l'instant).

Il reste possible de spécifier de manière "inline" labelWidth et valueWidth sur Form et Field, à la place de labelRatio et valueRatio (ce sont donc plus des ratios mais simplement la valeur des deux variables CSS, donc vous pouvez y mettre ce que vous voulez). Ce n'est donc plus la manière recommandée de gérer la mise en page (puisqu'il est possible de tout faire en CSS maintenant), mais cela permet une mise à jour simple de l'existant. Pour émuler le comportement de disableInlineSizing, vous pouvez simplement affecter auto aux deux variables par exemple.
(Ces propriétés vont simplement poser les variables en style inline sur le <form> ou le <div> principal du Field)

TL:DR breaking changes :

  • labelRatio: x => labelWidth: "x%", et valueWidth: "(100 - x)%" si valueRatio n'était pas renseigné (valueRatio était calculé automatiquement avant, mais on ne peut plus le faire puisqu'on n'utilise plus nécessairement un pourcentage)
  • valueRatio: x => valueWidth: "x%"
  • disableInlineSizing: true => labelWidth: "auto", valueWidth: "auto"

react-transition-group => react-transition-state

Focus n'utilise plus react-transition-group qui n'est plus maintenu et ne sera jamais mis à jour pour React 19 (la lib est incompatible), mais une autre librairie plus flexible qui elle sera compatible. Cela ne change rien à l'utilisation (c'est utilisé pour les dialogs et les popins), mais cela devrait retirer un warning en console.

0