diff --git a/.gitignore b/.gitignore index e0d6829..5809a98 100644 --- a/.gitignore +++ b/.gitignore @@ -36,3 +36,7 @@ ghpages-output # Project ignore files packages/react/chromatic.config.json packages/tokens/src/lib/cunningham.ts + +# Claude Code +CLAUDE.md +.claude* diff --git a/openspec/changes/archive/2026-01-26-field-variant-classic/design.md b/openspec/changes/archive/2026-01-26-field-variant-classic/design.md new file mode 100644 index 0000000..9b11164 --- /dev/null +++ b/openspec/changes/archive/2026-01-26-field-variant-classic/design.md @@ -0,0 +1,167 @@ +## Context + +Le design system Cunningham utilise actuellement un pattern "floating label" pour tous les champs de formulaire. Ce pattern est implémenté via le composant `LabelledBox` qui est utilisé par Input, TextArea, Select et DatePicker. + +Architecture actuelle : +``` +Field (wrapper: state, text, fullWidth) + └── LabelledBox (gère le label flottant) + └── Composant natif (input, textarea, etc.) +``` + +Le `LabelledBox` gère : +- Le positionnement du label (absolu, avec transition) +- L'état `labelAsPlaceholder` (label en grand = placeholder, label petit = au-dessus) +- Le CSS des transitions + +## Goals / Non-Goals + +**Goals:** +- Ajouter une variante `classic` avec label externe et placeholder natif +- Maintenir la rétrocompatibilité (floating = défaut) +- Supporter la variante classic sur tous les composants concernés +- Avoir un champ plus compact en mode classic + +**Non-Goals:** +- Changer le comportement par défaut des composants existants +- Créer des composants séparés (ClassicInput, etc.) +- Modifier Checkbox, Radio, Switch (déjà label externe) + +## Decisions + +### 1. Type `FieldVariant` partagé + +Créer un type exporté dans `packages/react/src/components/Forms/types.ts` : + +```typescript +export type FieldVariant = "floating" | "classic"; +``` + +**Pourquoi** : Assure la cohérence du typage entre tous les composants. + +### 2. Architecture en mode Classic + +En mode classic, **le label est rendu EN DEHORS du wrapper bordé**, pas à l'intérieur : + +``` +Field (wrapper) + └── label.c__input__label (EN DEHORS - nouveau) + └── div.c__input__wrapper (wrapper bordé) + └── Composant natif (input) +``` + +Vs mode floating (existant) : +``` +Field (wrapper) + └── div.c__input__wrapper (wrapper bordé) + └── LabelledBox (gère le label flottant) + └── Composant natif (input) +``` + +**Pourquoi** : Le label doit être visuellement au-dessus de la bordure du champ, pas à l'intérieur. + +### 3. CSS pour la variante classic + +Chaque composant a sa propre classe label et un modifier `--classic` sur le wrapper : + +```scss +// Label externe +.c__input__label { + display: block; + font-size: var(--c--components--forms-labelledbox--classic-label-font-size); + color: var(--c--components--forms-labelledbox--label-color--small); + margin-bottom: var(--c--components--forms-labelledbox--classic-label-margin-bottom); +} + +// Wrapper en mode classic +.c__input__wrapper--classic { + align-items: center; // Centrage vertical du contenu + height: 2.75rem; // Hauteur réduite (vs 3.5rem en floating) +} +``` + +Classes par composant : +- Input : `.c__input__label`, `.c__input__wrapper--classic` +- TextArea : `.c__textarea__label`, `.c__textarea__wrapper--classic` +- Select : `.c__select__label`, `.c__select--classic` +- DatePicker : `.c__date-picker__label`, `.c__date-picker--classic` + +### 4. Gestion du placeholder par composant + +Chaque composant gère son placeholder selon la variante : + +**Input / TextArea** : +```typescript +// Si variant="classic", passer placeholder au /