From 07f39ad4338fe87df9a97d74178d345cb386d1f4 Mon Sep 17 00:00:00 2001 From: MaksTinyWorkshop Date: Thu, 2 Apr 2026 10:17:12 +0200 Subject: [PATCH] docs(frontend): capitalise navigation et primitives UI --- knowledge/frontend/risques/general.md | 45 ++++++++++++ knowledge/frontend/risques/navigation.md | 94 +++++++++++++++++++++++- 2 files changed, 136 insertions(+), 3 deletions(-) diff --git a/knowledge/frontend/risques/general.md b/knowledge/frontend/risques/general.md index 2fa151e..8d060e5 100644 --- a/knowledge/frontend/risques/general.md +++ b/knowledge/frontend/risques/general.md @@ -84,3 +84,48 @@ function processLinks(content: string) { 3. Wrapper le `TextInput` dans `KeyboardAvoidingView` avec `behavior={Platform.OS === 'ios' ? 'padding' : 'height'}`. - Contexte technique : React Native / Expo cross-platform — app-alexandrie 31-03-2026 + +--- + + +## Primitive UI couplée au contexte parent (layout ou namespace métier) + +### Risques + +- Une primitive générique (`PageShell`, `ContentCard`, `SectionWrapper`) qui embarque des classes de surface, de largeur ou de namespace métier devient non réutilisable hors de son premier contexte +- Le couplage reste silencieux au lint et au typecheck, puis force l'ajout progressif de props `variant`, `layout`, `width` ou de classes externes contradictoires + +### Symptômes + +- La primitive applique directement des classes comme `.card`, `.card--dashboard`, `.dashboard__item`, `.profile__card` +- Le parent doit contourner le style natif de la primitive pour l'utiliser dans un autre écran +- Les classes `namespace__element` fuitent dans des composants supposés agnostiques du domaine + +### Bonnes pratiques / mitigations + +- Une primitive pose le squelette sémantique ; le parent pose la surface visuelle (card, width, background, espacement de contexte) +- Ne pas injecter de classes de namespace métier sur une primitive générique via `class` +- Si une variation réutilisable existe vraiment, l'exprimer via une API explicite et bornée (`tone`, `variant`) plutôt que par des classes métier ad hoc +- Contexte technique : Vue 3 / CSS modulaire — RL799_V2, 02-04-2026 + +--- + + +## Migration partielle vers un composant standard — classes legacy conservées + +### Risques + +- La coexistence de classes legacy (`.primary`, `.ghost`, `.danger`) et de classes du nouveau composant (`.app-btn--primary`, `.app-btn--ghost`) crée une ambiguïté durable de convention +- Les nouveaux développements continuent d'utiliser l'ancien système faute de règle claire, ce qui ralentit la standardisation + +### Symptômes + +- Deux façons de produire la même affordance coexistent dans le même repo +- Un composant dédié existe, mais des liens ou boutons continuent d'utiliser les anciennes classes globales + +### Bonnes pratiques / mitigations + +- Lorsqu'un composant standardise une affordance, supprimer en même temps les classes CSS globales équivalentes +- Si un reliquat legacy doit rester temporairement, documenter explicitement son périmètre et sa date de sortie attendue +- En review, traiter toute nouvelle utilisation d'une classe legacy équivalente comme une régression de standardisation +- Contexte technique : Vue 3 / design system léger — RL799_V2, 02-04-2026 diff --git a/knowledge/frontend/risques/navigation.md b/knowledge/frontend/risques/navigation.md index ebee22d..899b984 100644 --- a/knowledge/frontend/risques/navigation.md +++ b/knowledge/frontend/risques/navigation.md @@ -2,11 +2,11 @@ title: Frontend — Risques & vigilance : Navigation domain: frontend bucket: risques -tags: [navigation, expo-router, zustand, useeffect, deep-link] +tags: [navigation, expo-router, vue-router, vue, zustand, useeffect, deep-link, a11y] applies_to: [implementation, review, debug] severity: high -validated_on: 2026-03-25 -source_projects: [app-alexandrie] +validated_on: 2026-04-02 +source_projects: [app-alexandrie, RL799_V2] --- # Frontend — Risques & vigilance : Navigation @@ -144,3 +144,91 @@ router.push('/forgot-password' as never); - Règle : les groupes `(auth)`, `(tabs)`, etc. sont des conventions d'organisation de fichiers, pas des segments de route — ne jamais les inclure dans les appels de navigation programmatique - Contexte technique : Expo Router — app-alexandrie, 25-03-2026 + +--- + + +## Vue Router 4 — double route `/` avec `redirect` + layout parent + +### Risques + +- Déclarer à la fois `{ path: '/', redirect: ... }` et `{ path: '/', component: Layout, children: [...] }` dans le même tableau `routes` crée un conflit silencieux +- La première route `/` capturée empêche l'accès normal aux enfants du layout sur les accès directs à `/` + +### Symptômes + +- La redirection de `/` semble "fonctionner" en dev, mais uniquement parce qu'un guard global compense le problème +- Les enfants du layout parent ne sont jamais atteints directement depuis `/` + +### Bonnes pratiques / mitigations + +```typescript +// ❌ Anti-pattern — deux routes racine concurrentes +const routes = [ + { path: '/', redirect: '/home' }, + { path: '/', component: Layout, children: [...] }, +]; + +// ✅ Pattern correct — une seule route racine + redirect enfant +const routes = [ + { + path: '/', + component: Layout, + children: [ + { path: '', redirect: '/home' }, + ], + }, +]; +``` + +- Règle : ne jamais faire coexister deux entrées `path: '/'` concurrentes dans Vue Router +- Gérer la redirection de `/` soit via un enfant `path: ''`, soit via un guard global `beforeEach`, mais pas via une seconde route racine +- Contexte technique : Vue 3 / Vue Router 4 — RL799_V2, 02-04-2026 + +--- + + +## Navigation disabled via `router-link` + blocage au click + +### Risques + +- Un `router-link` rendu comme "disabled" continue de produire un `` valide dans le DOM +- Le lien reste accessible au clavier, aux lecteurs d'écran et aux tests a11y, même si `@click.prevent` bloque la navigation + +### Symptômes + +- Élément affiché avec `aria-disabled="true"` mais encore focusable et tabulable +- Faux positif visuel : l'UI semble désactivée, mais le DOM expose toujours un lien actif + +### Bonnes pratiques / mitigations + +```html + + + {{ item.label }} + + + + + {{ item.label }} + + + {{ item.label }} + +``` + +- Règle : un élément de navigation désactivé ne doit jamais être un lien +- Utiliser un élément non interactif (`span`) ou un vrai contrôle désactivable (`button disabled`) selon le besoin +- Contexte technique : Vue 3 / Vue Router 4 / accessibilité — RL799_V2, 02-04-2026