Skip to content

Générer le thème NativeWind depuis tokens.json et migrer l'app #125

Closed

Description

@IlanAMG

Contexte

Epic : #13
Maquette : sans objet — socle technique ; les valeurs viennent de tokens.json, validé par D-015 et D-016
Direction-Artistique · Accessibilité, règles pour le code · Architecture-Technique · D-015, D-016

Décision d'Ilan du 2026-09-24 : le style de l'app passe à NativeWind, avec un thème généré depuis tokens.json ; StyleSheet reste permis occasionnellement, dans des cas particuliers. Le thème livré par #21 a été recopié à la main (19 couleurs en dur, tailles et graisses différentes de tokens.json) : ce ticket le remplace, et reprend les exigences de D-015 et D-016 restées dans #21, fermé.

Comportement attendu

  • Essai d'abord : vérifier que NativeWind fonctionne proprement avec Expo SDK 57 et React Native 0.86 (build de dev iOS et Android, rechargement à chaud, rendu d'un écran). En cas d'échec, commentaire ⛔ sur ce ticket et arrêt : pas de repli silencieux sur StyleSheet, la décision revient à Ilan.
  • Une seule source : une copie de tokens.json dans le dépôt, tenue identique à celle du wiki par un script de synchronisation. Un générateur en produit le preset Tailwind (couleurs, styles de texte, espacements, rayons, tailles, ombre) et un module TypeScript typé des mappings : placeCategories, filterIcons, badges, moodDots indexé par clé d'ambiance, uiIcons, darkSurfaces, seuils d'accessibilité. Les fichiers générés portent l'en-tête « généré depuis tokens.json, ne pas modifier ».
  • Rien que les tokens : le preset remplace la palette et les échelles par défaut de Tailwind, il ne les étend pas. Tokens mood-* compris ; le point Nature prend family-nature (D-016). Aucune valeur dark générée : le thème sombre n'est pas validé.
  • StyleSheet, occasionnellement : permis pour les cas que NativeWind couvre mal, comme les styles animés de Reanimated, les couches de la carte Mapbox ou une valeur calculée à l'exécution. Les valeurs y viennent toujours du thème généré, jamais en dur.
  • tokens.json version 4 (D-023, reprise de Initialiser l'app Expo avec expo-router, onglets, thème et client API #21 fermé) : icônes d'interface du profil et des réglages, pastilles new et certified.
  • tokens.json version 5 (D-025, reprise de Initialiser l'app Expo avec expo-router, onglets, thème et client API #21 fermé) : composant Toast (mappings.toast : succès, info, attention, erreur), noms des icônes d'interface dans mappings.uiIcons, couleurs *-on-strong.
  • tokens.json version 6 (D-028) : mappings.accessibility.denseComponents complété ; le plafond maxFontSizeMultiplier={1.3} se pose dans le composant de base de chaque élément de cette liste, jamais écran par écran.
  • tokens.json version 7 (D-029) : surface-strong-raised, radius-section et mappings.immersive pour la page immersive du parcours en cours et le mini-lecteur.
  • Mouvement (D-030, Direction-Artistique › Mouvement) : tokens.json version 8 ; constantes de mouvement (durées, courbes, ressort des gestes, vibrations) générées depuis mappings.motion ; « Réduire les animations » (ReduceMotion) géré dans les composants de base.
  • Police et icônes : Plus Jakarta Sans 400 à 800 (licence OFL) chargée au démarrage, avec les 20 styles de texte de tokens.json ; icônes Phosphor, appelées par leur nom dans les mappings (Extérieur = park).
  • Composants de base dans apps/mobile/src/ui : Text (variantes = styles de texte), Icon, Button (primaire, secondaire, Premium encre), Chip (36 px), Badge (Vérifié, Signature, Premium, Privé, depuis mappings.badges), MoodDot, pastille d'étape (famille et icône de catégorie, depuis mappings.placeCategories), Card (surface et rayon). Les règles d'accessibilité y sont intégrées : maxFontSizeMultiplier={1.3} sur les composants denses, zones tactiles de 44 px, aucune hauteur fixe sur un composant qui contient du texte. Les écrans assemblent ces composants au lieu de styler à partir de rien.
  • Migration : les six fichiers qui utilisent StyleSheet aujourd'hui passent à NativeWind et aux composants de base ; apps/mobile/src/theme/index.ts, recopié à la main, disparaît.
  • Garde-fous en CI, bloquants : un lint refuse les valeurs arbitraires (text-[15px], bg-[#fff]), les classes inconnues et toute couleur hexadécimale en dur dans apps/mobile/src hors fichiers générés ; un contrôle vérifie que la copie de tokens.json est identique à celle du wiki et que la régénération ne produit aucun diff.

Critères d'acceptation

  • Essai NativeWind concluant sur iOS et Android en build de dev, ou ⛔ commenté sur ce ticket
  • La CI échoue si la copie de tokens.json diffère du wiki ou si les fichiers générés ne sont pas à jour
  • Une classe hors tokens (bg-blue-500), une valeur arbitraire ou une couleur hexadécimale en dur font échouer le lint
  • Plus aucune couleur, taille ni police en dur dans apps/mobile/src hors fichiers générés ; apps/mobile/src/theme/index.ts supprimé
  • Chaque StyleSheet restant relève d'un cas particulier et lit ses valeurs dans le thème généré
  • Plus Jakarta Sans 400 à 800 chargée et les 20 styles de texte disponibles ; icônes Phosphor par nom de mapping
  • Composants de base livrés avec les plafonds 1,3, les zones tactiles de 44 px et sans hauteur fixe sur du texte ; captures à 100 % et 150 % de texte système dans la PR
  • Barre d'onglets et accueil existants conformes à Ecrans › E-01 avec les nouveaux composants
  • Aucune valeur dark livrée
  • Chaque élément de mappings.accessibility.denseComponents porte le plafond 1,3 dans son composant de base
  • Constantes de mouvement générées depuis mappings.motion, et « Réduire les animations » géré dans les composants de base

Notes techniques

  • Relevé du 2026-09-24 sur main : ni NativeWind ni Tailwind dans apps/mobile ; StyleSheet.create dans app/(tabs)/index.tsx, src/components/Button.tsx, ConsentBanner.tsx, Screen.tsx, StatusMessage.tsx et TabBar.tsx ; 19 couleurs en dur dans apps/mobile/src/theme/index.ts ; lint dans eslint.config.js.
  • Emplacement suggéré : un paquet packages/tokens qui garde la copie de tokens.json et son générateur. Le preset Tailwind servira aussi à l'admin web en v0.6.
  • Source à synchroniser : https://raw.githubusercontent.com/wiki/Inprogress-Agency/widoo-app/design/design-system/tokens.json, lisible sans jeton.
  • Une PR, plusieurs commits sous le plafond de diff : essai et installation, synchronisation et génération, lint et contrôles CI, composants de base, migration des écrans existants.
  • La décision NativeWind doit aussi s'inscrire dans la page wiki Architecture-Technique (DESIGN).

Activity

  1. added this to the v0.1 milestone on Sep 24, 2026
  2. PaulThiberville commented on Sep 25, 2026

    @PaulThiberville
    Collaborator

    🔨 Démarrage — plan :

    Branche issue/125-nativewind-tokens, une seule PR Fixes #125, un commit par étape, chacun sous 400 lignes utiles. Les fichiers générés sont rangés sous generated/ et ne comptent pas dans le plafond.

    1. Essai NativeWind : NativeWind 4.2.7 (dernière version stable ; la v5 n'existe qu'en RC) avec Tailwind 3.4, configuré dans Babel, Metro et global.css. Vérification en build de développement sur le simulateur iOS et l'émulateur Android : rendu d'un écran et rechargement à chaud. En cas d'échec : ⛔ ici et arrêt.
    2. packages/tokens : copie de tokens.json (version 8) et script sync qui la tient identique au wiki (URL raw, sans jeton), avec un mode --check.
    3. Générateur : il produit le preset Tailwind et remplace les valeurs par défaut au lieu de les étendre. Le preset porte les 59 couleurs en light seulement, les 20 styles de texte, les espacements, les rayons, les tailles et l'ombre. Il produit aussi un module TypeScript typé des mappings : placeCategories, filterIcons, badges, moodDots par clé d'ambiance de packages/shared, uiIcons, darkSurfaces, accessibility, toast, immersive, motion. En-tête « généré depuis tokens.json, ne pas modifier ». Tests Vitest : aucune valeur dark, et chaque clé de moods et de placeCategories a son entrée.
    4. Garde-fous CI bloquants :
      • une règle ESLint refuse les valeurs arbitraires (text-[15px]), les classes hors preset et les couleurs hexadécimales en dur dans apps/mobile/src ;
      • une étape CI vérifie que la copie est identique au wiki et que la régénération ne produit aucun diff.
    5. Police et icônes : Plus Jakarta Sans 400 à 800, icônes Phosphor (phosphor-react-native) appelées par nom de mapping, composants Text et Icon.
    6. Composants de base dans apps/mobile/src/ui : Button (primaire, secondaire, Premium encre), Chip, Badge, MoodDot, StepDot, Card. Ils portent le plafond 1,3 des composants denses, les zones de 44 px, aucune hauteur fixe sur du texte, les constantes de mouvement et la gestion de « Réduire les animations ».
    7. Migration : les six fichiers en StyleSheet passent aux composants de base, et src/theme/index.ts est supprimé. Le test des contrastes est repris sur les couleurs générées.

    Vérification finale : iOS et Android, captures à 100 % et à 150 % de texte système dans la PR.

  3. PaulThiberville commented on Sep 25, 2026

    @PaulThiberville
    Collaborator

    ✅ Essai NativeWind concluant, sur la branche issue/125-nativewind-tokens.

    Versions : NativeWind 4.2.7 (dernière stable), Tailwind CSS 3.4.19, Expo SDK 57.0.24, React Native 0.86.3, Reanimated 4.5.1.

    Vérifié en build de développement (expo run:ios, expo run:android) :

    • simulateur iPhone 17 Pro (iOS 26.4) et émulateur Android API 34 ;
    • rendu d'un écran stylé par className : fond, rayon, espacement, texte, ombre ;
    • rechargement à chaud d'un changement de classe sur les deux plateformes.

    Trois points à connaître, pris en compte dans la suite du ticket :

    1. pnpm : NativeWind injecte des imports de react-native-css-interop dans chaque fichier. react-native-css-interop (0.2.7, la version de NativeWind) doit donc être une dépendance directe de l'app, et babel-preset-expo une dépendance de développement directe, puisque babel.config.js le nomme.
    2. Pressable avec un style en fonction (({ pressed }) => …) : le style n'est plus appliqué. Le Button actuel perd son fond bleu. Il passe aux classes dans le même commit que l'installation, pour que l'app ne soit jamais cassée entre deux commits. Pour les autres états d'appui, on utilisera les variantes active: ou un état React.
    3. « Upgrade » de composant : une classe qui repose sur des variables CSS (l'ombre de Tailwind) ou sur une animation, ajoutée après le premier rendu, fait remonter le composant. En développement, le rechargement à chaud peut alors afficher une erreur de navigation, qu'un rechargement complet efface. En production, le même remontage survient si une classe de ce type s'active au cours de l'utilisation. D'où deux règles :
      • l'ombre unique shadow-tabbar est posée par le boxShadow natif, avec la valeur du thème généré (cas particulier StyleSheet prévu par le ticket) ;
      • les animations passent par Reanimated et les constantes générées de mappings.motion, jamais par les classes transition-* ou animate-*.
  4. 1 remaining item

  5. PaulThiberville commented on Sep 25, 2026

    @PaulThiberville
    Collaborator

    ✅ Fermé par #132, fusionnée en rebase and merge le 2026-09-25 (13 commits, tête 3b8ed72).

    Critères d'acceptation : tous tenus, sauf denseComponents, accepté en partiel par Paul par délégation d'Ilan. Le détail critère par critère est dans le tableau de la description de la PR ; les captures à 100 % et 150 %, sur iOS et Android, y sont jointes.

    Reste hors ticket, déposé dans l'Inbox :

    • icônes manquantes dans tokens.json (dont tag pour la chip « Gratuit ») et absence de tailles d'icônes ;
    • interligne sur Android ;
    • icônes des onglets inactifs, décrites autrement dans E-01 ;
    • clés et libellés de budget et de durée désalignés dans packages/shared ;
    • composants denses à construire par leurs tickets d'écran.
  6. PaulThiberville commented on Sep 25, 2026

    @PaulThiberville
    Collaborator

    Status du Project « Widoo — MVP » : À déployer → Terminés le 2026-09-25, pour ce ticket et pour l'epic #13.

    Décision de Paul du 2026-09-25, transmise à MANAGER par la session d'orchestration. L'app mobile n'a pas encore de build de recette (EAS non initialisé), donc aucune vérification en staging n'est possible. La décision repose sur les essais faits sur simulateur iOS et sur émulateur Android. Cette exception à la règle « Terminés après déploiement vérifié en staging » (CLAUDE.md) vaut pour la partie mobile.

  7. IlanAMG commented on Sep 25, 2026

    @IlanAMG
    MemberAuthor

    Livré avant le passage du wiki à tokens.json version 9 (D-033). La synchronisation de la version 9 est portée par #139.

  8. IlanAMG commented on Sep 25, 2026

    @IlanAMG
    MemberAuthor

    D-034 : tokens version 10 (voiles mappings.immersive : veil renforcé, textVeil, scrollDarken, photoText ; control-border pour les étoiles non choisies ; mappings.accessibility de E-07 et E-15 ; budget « ≈ »). Pas de nouveau ticket : la copie du dépôt et le thème sont mis à jour par la PR automatique #144 (action sync-tokens, #139). Utilisation dans l'app : #42 et #64.

  9. IlanAMG commented on Sep 25, 2026

    @IlanAMG
    MemberAuthor

    D-035 et D-036 (https://github.com/Inprogress-Agency/widoo-app/wiki/Design-Changelog) : tokens v12 (la synchro automatique doit suffire). Barre d'onglets : l'onglet s'appelle « Parcours » ; aligner le libellé lecteur d'écran qui porte encore « Sorties ».

  10. IlanAMG commented on Sep 25, 2026

    @IlanAMG
    MemberAuthor

    D-038 (https://github.com/Inprogress-Agency/widoo-app/wiki/Design-Changelog) : tokens v13 (error-ink #B42318, error-soft #FDECEA, mappings.planning). La synchro automatique doit suffire.

  11. IlanAMG commented on Sep 25, 2026

    @IlanAMG
    MemberAuthor

    D-039 : tokens v14 (notes d'icônes au format du générateur).

  12. IlanAMG commented on Sep 25, 2026

    @IlanAMG
    MemberAuthor
  13. IlanAMG commented on Sep 25, 2026

    @IlanAMG
    MemberAuthor

    Tokens v20 (D-051) : uniquement des clés d'accessibilité et mappings.toast.undo, pas de nouvelle couleur. Suivi dans les composants de base : #174.

  14. IlanAMG commented on Sep 29, 2026

    @IlanAMG
    MemberAuthor

    Tokens v34 (D-072) : mappings.premium (plans, passTag, routeCard, prix, états).

  15. IlanAMG commented on Sep 29, 2026

    @IlanAMG
    MemberAuthor

    Tokens v35 (D-073).

  16. IlanAMG commented on Sep 29, 2026

    @IlanAMG
    MemberAuthor

    Tokens v36 (D-074).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions