Approche initiale avec canvas
L’auteur a d’abord rendu tout le texte sur un élément <canvas>. Le rendu atteint entre 60 et 120 images par seconde, ce qui impose une charge CPU importante pour chaque rafraîchissement. Les fonctionnalités de base implémentées sont la mise en place du curseur, le déplacement avec les flèches, la mise en évidence de la ligne courante, la saisie de texte et une animation du curseur. Malgré ces succès, l’absence de sélection de texte, d’historique d’annulation, de collage multi‑ligne et de défilement natif rend l’outil peu utilisable. Pour pallier le dernier point, l’auteur a superposé un <div> caché, dimensionné comme le canvas, et a exploité le débordement natif du navigateur afin de calculer les offsets de rendu.
Transition vers contenteditable
Conscient de l’inaccessibilité du canvas, l’auteur a basculé vers un <div contenteditable="plaintext-only">. Cette configuration désactive automatiquement la mise en forme riche, ce qui convient aux éditeurs de code. Les attributs spellcheck="false", autocapitalize="off" et autocorrect="off" sont également désactivés pour éviter les pics de latence d’entrée. Le navigateur fournit alors nativement la sélection, l’historique d’annulation et la gestion du focus, éliminant ainsi la plupart des problèmes d’accessibilité. L’API Selection est utilisée pour récupérer les coordonnées du curseur et appliquer un style via ::selection. Le caret natif est rendu invisible avec caret-color: transparent, bien que cela puisse être considéré comme une mauvaise pratique.
<div
contenteditable="plaintext-only"
autocapitalize="off"
autocorrect="off"
spellcheck="false"
translate="no">
</div>
Adoption du textarea et optimisations
Lorsque le nombre de caractères dépasse un seuil non précisé, les performances se dégradent, surtout sous Chromium, alors que WebKit et Firefox restent plus stables. L’auteur a constaté que le <textarea> offre une meilleure réactivité pour de longs documents. Le composant ne supporte pas les pseudo‑classes ::highlight, ce qui a conduit à l’ajout d’une couche supplémentaire de <div> pour afficher les lignes visibles et appliquer la bibliothèque MicroLighter. Deux API récentes sont mentionnées : OpaqueRange, qui permet d’ajouter des surlignages personnalisés dans un <textarea>, et EditContext, qui améliore la saisie dans le canvas. L’auteur note que les nombreux ::highlight CSS constituent un goulot d’étranglement et propose d’utiliser Tree‑sitter pour générer un arbre syntaxique et ne mettre en évidence que les lignes affichées.
Limites et perspectives
Le prototype couvre environ 90 % des fonctions attendues avec seulement 1 % des caractéristiques complètes. Les problèmes restants incluent la gestion des tabulations (actuellement deux espaces insérés), les bugs liés aux unités UTF‑16 (exemple : "🍋🟩".length === 5 alors que le segment grapheme ne compte qu’un caractère) et la nécessité de gérer correctement les séquences Unicode. L’auteur propose d’utiliser Intl.Segmenter pour obtenir un comptage de graphemes fiable :
"🍋🟩".length; // 5
[..."🍋🟩"].length; // 3
const segmenter = new Intl.Segmenter("en", {granularity: "grapheme"});
[...segmenter.segment("🍋🟩")].length; // 1
En conclusion, le passage du canvas à contenteditable, puis à textarea, montre comment les API natives du navigateur peuvent réduire la complexité d’un éditeur texte tout en offrant de meilleures performances et accessibilité. Les améliorations futures porteront sur l’optimisation du rendu des surlignages et la prise en charge fiable des caractères Unicode.