- Remplacement intégral index.css par palette Charcoal (DESIGN_SYSTEM.md v2.0)
- Dark = thème par défaut, .light = override via @custom-variant light
- Sidebar navy #0C1528 permanent (identique dark+light)
- Script anti-FOUC inline dans index.html
- Layout : radial-gradient sur <main>, sidebar 230px, max-w-[1100px]
- Renommage tokens Boréal→Charcoal sur ~45 composants
- Inversion dark: → baseline + light: sur primitives shadcn
- Fix logo blanc forcé dans sidebar
- ADR 006 mis à jour
Typecheck: OK · Tests: 122/122 ✅
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
75 lines
1.8 KiB
TypeScript
75 lines
1.8 KiB
TypeScript
/**
|
|
* Clavier de caractères spéciaux français pour la zone de saisie.
|
|
*
|
|
* Affiche une rangée horizontale scrollable de 30 caractères accentués
|
|
* (15 minuscules + 15 majuscules). Un clic insère le caractère à la
|
|
* position du curseur via le callback `onInsert`.
|
|
*
|
|
* Règle H : purement présentationnel, la logique d'insertion est dans le parent.
|
|
* Règle L : tokens Direction H exclusivement.
|
|
*
|
|
* `onMouseDown preventDefault` empêche le textarea de perdre le focus au clic,
|
|
* ce qui permet de conserver la position du curseur lors de l'insertion.
|
|
*/
|
|
|
|
const SPECIAL_CHARS = [
|
|
'à',
|
|
'â',
|
|
'é',
|
|
'è',
|
|
'ê',
|
|
'ë',
|
|
'î',
|
|
'ï',
|
|
'ô',
|
|
'ù',
|
|
'û',
|
|
'ü',
|
|
'ç',
|
|
'œ',
|
|
'æ',
|
|
'À',
|
|
'Â',
|
|
'É',
|
|
'È',
|
|
'Ê',
|
|
'Ë',
|
|
'Î',
|
|
'Ï',
|
|
'Ô',
|
|
'Ù',
|
|
'Û',
|
|
'Ü',
|
|
'Ç',
|
|
'Œ',
|
|
'Æ',
|
|
] as const
|
|
|
|
interface Props {
|
|
onInsert: (char: string) => void
|
|
disabled?: boolean
|
|
}
|
|
|
|
export function SpecialCharsKeyboard({ onInsert, disabled = false }: Props) {
|
|
return (
|
|
<div
|
|
role="toolbar"
|
|
aria-label="Caractères spéciaux"
|
|
className="flex flex-wrap gap-1.5 rounded-md border border-border bg-surface p-2"
|
|
>
|
|
{SPECIAL_CHARS.map((char) => (
|
|
<button
|
|
key={char}
|
|
type="button"
|
|
disabled={disabled}
|
|
onMouseDown={(e) => e.preventDefault()}
|
|
onClick={() => onInsert(char)}
|
|
aria-label={`Insérer le caractère ${char}`}
|
|
className="size-8 shrink-0 rounded-md border border-border bg-surface text-sm font-medium text-ink-primary transition-colors hover:border-brand hover:bg-brand-soft hover:text-brand-text focus:border-brand focus:outline-none focus:shadow-focus disabled:cursor-not-allowed disabled:opacity-50"
|
|
>
|
|
{char}
|
|
</button>
|
|
))}
|
|
</div>
|
|
)
|
|
}
|