docs(knowledge): capitalisation frontend — intégration du triage local (mai-juin 2026)

Triage et intégration des propositions frontend du buffer 95_a_capitaliser.md
(lot local RL799_V2/Vue3 + app-alexandrie/RN-Expo, mai-juin 2026).

~73 entrées intégrées sur knowledge/frontend/ + 1 nouveau fichier, dont :
- patterns/state.md : race-token partagé latest-wins (fusion 3 props), capture sync anti-race,
  event bus timestamp, clé cache composite, état dérivé = computed
- risques/state.md : 9 risques Zustand/store (fetchId reset, useRef remount, re-fetch infini
  sur [], flag optimiste écrasé, cache détail/liste stale, latch sans reset, :key index)
- patterns/navigation.md : Expo Router (tab bar, useFocusEffect, Href typé, routing pur fusionné)
- patterns/general.md : helpers temps purs, composants génériques + skeleton, fail-fast, touch target
- risques/general.md : 24 risques (sweep statique, filtre client liste paginée, hooks avant return,
  a11y VoiceOver/disabled, redirection allowlist, RangeError toISOString, section i18n...)
- design-tokens (cluster theming light/dark MD3), tests, performance, react-native, nextjs
- NOUVEAU risques/responsive.md (gating par capacité d'input + checklist régressions mobile)
- READMEs patterns/risques mis à jour

Doublons inter-fichiers évités (vérifié : aucune ancre dupliquée introduite).
Rejets (doublons 91/9/87), reciblages workflow (156/257) et bloc 32 (CLAUDE projet) non intégrés ici.
Source 95_a_capitaliser.md non purgée (purge en fin de capitalisation complète).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
MaksTinyWorkshop
2026-06-25 15:31:53 +02:00
parent f1b783407a
commit 5f5c87296e
15 changed files with 2439 additions and 12 deletions
@@ -184,3 +184,106 @@ it('variante primary utilise colors.primary', () => {
1. `.spec.ts` (node) : tokens, valeurs, logique pure
2. `.spec.tsx` (config séparée avec renderer) : rendu visuel, interactions
---
<a id="pattern-palette-light-dark-md3-usethemedcolors"></a>
## Pattern : Palette light/dark MD3 + hook `useThemedColors` + dual export
### Synthèse
- **Objectif** : poser un theming light/dark/system complet sur une codebase qui n'avait qu'une palette unique, sans casser les imports historiques.
- **Contexte** : React Native / Expo avec préférence utilisateur light/dark/system.
- **Quand l'utiliser** : introduction d'un 2ᵉ thème sur une base existante.
- **Quand l'éviter** : thème unique sans besoin de bascule (le hook serait du sucre sans bénéfice).
### Analyse
- **Avantages** :
- compat ascendante : `export const colors = dark` garde les imports `import { colors }` compilants
- le hook `useThemedColors` rend le reste mécanique (le composant ne code jamais le scheme en dur)
- dual export pour les styles legacy : `export const fooStyles = makeStyles(colors)` (snapshot dark) reste synchronisé avec la fonction dynamique
- **Limites / vigilance** :
- anti-pattern : palette plate sans typage par mode → force à coder le scheme en dur ou à dupliquer les styleSheets
- tokens "fixed" partagés light/dark (`primaryContainer`, `primaryFixedDim`) pour la continuité du branding ; `inverse-primary` d'un mode = `primary` de l'autre
- shadow : `#000000` OK en dark, mais en light un tinted neutre (ex. `outline` à 8 %), jamais noir pur
- validation WCAG : README documentant chaque token + ratio mesuré (texte ≥ 4.5:1, UI ≥ 3:1)
### Validation
- Validé le : 29-05-2026
- Contexte technique : React Native / Expo — app-alexandrie (ux-cleanup-8, ~95 fichiers migrés)
### Implémentation
```ts
// theme/colors.ts
const dark = { background: '#131316', primary: '#cdbdff' } as const;
const light = { background: '#fbf8fe', primary: '#4c00c9' } as const;
export const colors = dark; // compat ascendante (imports historiques)
export const colorsLight = light;
export const colorsDark = dark;
// theme/use-themed-colors.ts
export function useThemedColors() {
return useEffectiveColorScheme() === 'light' ? colorsLight : colorsDark;
}
// composant
const themed = useThemedColors();
const styles = useMemo(() => makeStyles(themed), [themed]);
function makeStyles(c: ReturnType<typeof useThemedColors>) {
return StyleSheet.create({ container: { backgroundColor: c.background } });
}
// styles exportés (compat tests) — source unique
export const fooStyles = makeStyles(colors); // snapshot dark
```
> Les pièges de migration associés (composants tiers, `<Text>` sans `color`, scheme effectif, ThemeProvider) sont documentés dans `risques/design-tokens.md#risque-theming-light-dark-pieges-caches`.
---
<a id="pattern-map-semantique-slug-token-icone"></a>
## Pattern : Map sémantique slug → token + icône
### Synthèse
- **Objectif** : différencier visuellement des entités d'un même type (forums, packs, badges) via une map slug → token résolue au runtime, sans hex en dur.
- **Contexte** : entités multiples d'un même type nécessitant un code couleur/icône cohérent light/dark.
- **Quand l'utiliser** : ≥ 2 entités à différencier visuellement.
- **Quand l'éviter** : entité unique ou différenciation purement textuelle.
### Analyse
- **Structure** : `getEntityBadgeTokens(slug) → { bgColorKey, fgColorKey, icon }`, le caller résout via `useThemedColors` (suit le thème).
- **Règles** : (1) toujours des `ColorKey` de `useThemedColors`, jamais de hex ; (2) toujours un fallback neutre (un slug futur ne casse pas l'UI) ; (3) icônes outline légères ; (4) tests env node sur map + fallback + distinctness.
- **Avantages** : vs if/else inline → 0 duplication ; vs hex map → suit le thème ; vs composant → reste un helper pur testable env node.
### Validation
- Validé le : 29-05-2026
- Contexte technique : React Native — app-alexandrie (`forum-badge.ts`, ux-cleanup-15)
---
<a id="pattern-migration-tokens-typo-formalises"></a>
## Pattern : Migration tokens typo formalisés
### Synthèse
- **Objectif** : formaliser et migrer les valeurs typographiques en dur (`fontSize`, `fontWeight`, `fontFamily`) vers des tokens, comme le sweep tokens couleur.
- **Contexte** : codebase avec ~100 occurrences de valeurs typo en dur sur des dizaines de fichiers.
- **Quand l'utiliser** : volumétrie significative de valeurs typo dispersées.
- **Quand l'éviter** : poignée d'usages localisés.
### Analyse
- **Méthodologie en 4 étapes** : (1) audit grep + rapport stats ; (2) étendre `typography.ts` SANS renommer les tokens existants (rétro-compat) — ajouter des aliases sémantiques ; (3) migration mécanique (perl/sed) + imports, typecheck après chaque batch ; (4) doc README (table sémantique + anti-patterns).
- **Cas dégénérés à laisser en dur** : `fontSize: 48/64` sur un emoji/hero = taille d'icône, pas de la typo → ne pas créer un token `iconLarge` (documenter l'exception).
- **Anti-patterns** : codemod auto sans review visuel (un `15 → 14` casse un layout) ; renommer un token existant (`fontSize.tab` utilisé partout → casse 50+ fichiers) ; créer `useThemedTypography()` si la typo ne varie pas light/dark (sucre sans bénéfice, garder l'import statique).
### Validation
- Validé le : 30-05-2026
- Contexte technique : React Native — app-alexandrie (ux-cleanup-12, 110 occurrences / 33 fichiers, 0 régression)