Un petit crochet de réact pour transformer les éléments en surfaces de contenu entièrement rendables et modifiables, comme les éditeurs de code, en utilisant un contenu (et une magie)
useEditable est un petit crochet qui permet aux éléments d'être contenteditable tout en étant entièrement rendables. Ceci est idéal pour créer de petits éditeurs de code ou en prose textareas en seulement 2kB !
Il vise à permettre à n'importe quel élément d'être modifiable tout en étant en mesure de lui rendre des éléments de réaction normaux - pas innerHTML et de devoir gérer ou rendre un HTML brut, ou de démarrer un projet d'éditeur complet à partir de zéro.
Consultez la démo complète sur la boîte de codes et avec prism-react-renderer !
Installer d'abord use-editable aux côtés de react :
yarn add use-editable
# or
npm install --save use-editable Vous pourrez alors importer useEditable et le transmettre une réflexion HTMLElement et un gestionnaire onChange .
import React , { useState , useRef } from 'react' ;
import { useEditable } from 'use-editable' ;
const RainbowCode = ( ) => {
const [ code , setCode ] = useState ( 'function test() {}nconsole.log("hello");' ) ;
const editorRef = useRef ( null ) ;
useEditable ( editorRef , setCode ) ;
return (
< div className = "App" >
< pre
style = { { whiteSpace : 'pre-wrap' , fontFamily : 'monospace' } }
ref = { editorRef }
>
{ code . split ( / r?n / ) . map ( ( content , i , arr ) => (
< React . Fragment key = { i } >
< span style = { { color : `hsl( ${ ( ( i % 20 ) * 17 ) | 0 } , 80%, 50%)` } } >
{ content }
</ span >
{ i < arr . length - 1 ? 'n' : null }
</ React . Fragment >
) ) }
</ pre >
</ div >
) ;
} ; Et tout comme cela, nous avons connecté useEditable à notre editorRef , qui pointe vers l'élément <pre> qui est rendu, et à setCode qui entraîne notre état contenant du code.
Cette bibliothèque a été testée et devrait fonctionner correctement en utilisant:
Il y a des problèmes connus dans IE 11 en raison de la méthode MutationObserver incapable de lire les nœuds de texte qui ont été supprimés via le contenteditable .
Traditionnellement, il y a eu trois options lors du choix des surfaces d'édition dans React. Soit on pourrait opter pour un grand projet comme Prochemirror / Codemirror ou similaire qui prennent le contrôle d'une grande partie des événements d'édition et de rendu et est donc plutôt opiniâtre, ou il est possible d'utiliser simplement contenteditable et de rendre à des HTML bruts qui sont remplacés dans le contenu de l'élément, ou enfin on pourrait combiner une textarea avec un div chevauchant ce contenu stylisé.
Les trois options ne permettent pas beaucoup de personnalisation en termes de ce qui est réellement rendu ou de mettre des restrictions déraisonnables sur la facilité avec laquelle il est de rendre et de gérer le contenu d'un modifiable.
Alors, qu'est-ce qui rend le rendu à un élément contenteditable si dur?
En règle générale, cela est difficile car ils modifient directement le DOM. Cela fait que la plupart des bibliothèques de rendu, comme React et Preact, sont confondues, car leurs DOM virtuels sous-jacents ne correspondent plus à la structure DOM réelle. Pour empêcher ce problème use-editable crée un MutationObserver , qui surveille toutes les modifications apportées à l'élément contenteditable . Avant qu'il ne rapporte ces modifications pour réagir, elle recule d'abord toutes les modifications du DOM afin que React voit ce qu'il attend.
En outre, il préserve également la position actuelle du caret, la sélection et la restaure une fois que React a mis à jour le Dom lui-même. Il s'agit d'une technique assez courante pour les éditeurs contenteditable , mais l'ajout MutationObserver est ce qui permet à use-editable de laisser une autre bibliothèque de vue mettre à jour le contenu de l'élément.
Actuellement, soit le contenu texte des éléments rendus doit éventuellement correspondre exactement à l'entrée de code, soit votre implémentation doit être en mesure de convertir le contenu texte rendu en ce que vous utilisez comme état. Il s'agit d'une limitation de la façon dont le travail de contenteditable , car ils ne captureront que le contenu DOM réel. Étant donné que use-editable ne vise pas à être un composant complet qui gère le cycle de rendu, il n'a pas à conserver un état supplémentaire, mais ne fera que transmettre le texte du Dom au rappel onChange .
En utilisant le rappel onChange , vous recevrez également un objet Position décrivant la position du curseur, le numéro de ligne actuel et le contenu de la ligne jusqu'à ce que le curseur, qui est utile pour les auto-légères, qui pourrait ensuite être appliqué avec la fonction update qui useEditable des retours pour mettre à jour la position du curseur.
Le premier argument est elementRef et accepte un objet REF de Type RefObject<HTMLElement> qui pointe vers l'élément qui devrait devenir modifiable. Cette référence est autorisée à être null ou à changer pendant l'exécution du crochet. Tant que les changements de la référence sont déclenchés par la réaction, tout doit se comporter comme prévu.
Le deuxième argument est onChange et accepte un rappel de type (text: string, pos: Position) => void qui s'appelle chaque fois que le contenu des changements contenteditable . Cela doit être configuré afin qu'il déclenche un rerender du contenu de l'élément.
Le text onChange reçoit n'est que la représentation textuelle du contenu de l'élément, tandis que la Position qu'elle reçoit contient la position actuelle du curseur, le numéro de ligne (zéro-indexé) et le contenu de la ligne actuelle jusqu'à ce que le curseur, qui est utile pour les autosugges.
Le troisième argument est un objet options facultatifs. Cela accepte actuellement deux options pour modifier le comportement d'édition du crochet:
disabled désactive l'édition sur le modifiable en retirant à nouveau l'attribut contentEditable .indentation peut être un certain nombre d'espaces affichés pour l'indentation. Cela permet également le comportement de la clé de Tab améliorée, qui liera la ligne actuelle ou dédent la ligne actuelle lorsque Shift sera maintenu (sachez que cela fera que l'éditeur agira comme un piège de mise au point!) Lorsque options.indentation est définie, alors useEditable empêchera l'insertion des caractères d'onglet et insérera plutôt la quantité spécifiée d'espaces blancs, ce qui facilite la gestion des colonnes.
De plus, le crochet useEditable renvoie une poignée Edit avec plusieurs méthodes, comme documenté ci-dessous.
Edit.update(content: string): void
Remplace l'intégralité du contenu de la modification lors de l'ajustement de la position des gueules. Cela déplacera le caret par la différence de longueur entre le contenu actuel et le contenu passé.
Edit.insert(append: string, offset?: number): void
Insère un nouveau texte à la position de la gare tout en supprimant du texte dans la plage du décalage (qui accepte les décalages négatifs). Par exemple, lorsque offset est défini sur -1 , un seul caractère est supprimé à gauche du caret avant d'insérer un nouveau texte. Lorsqu'il est réglé sur 2 , deux caractères à droite des Carets sont supprimés. Le texte append peut également être défini sur une chaîne vide pour appliquer les suppressions que sans insérer de texte. Lorsqu'un texte est sélectionné, il est simplement effacé en premier et offset est ignoré.
Edit.move(pos: number | { row: number; column: number }): void
Cela déplace le caret vers la position spécifiée. La position peut être un indice de caractères (un number ) ou des coordonnées spécifiant séparément une row et column .
Edit.getState(): { text: string; position: Position }
Cette méthode permet d'obtenir l'état actuel de l'état modifiable, ce qui est le même que ce que onChange reçoit généralement. Ceci est utile lors de l'ajout d'actions d'édition personnalisées dans un gestionnaire de clés ou lors de l'imitation programmatique onChange autrement, tandis que le modifiable est sélectionné.
react-live , sur lequel j'ai travaillé, avait l'un des premiers éditeurs contenteditable . (Mais avec des mises à jour HTML brutes)react-simple-code-editor a été la première (?) Bibliothèque à utiliser une TextArea divisée et à rendre l'implémentation de surface, qui a présenté à quoi devrait ressembler une belle API d'édition.codejar contient les meilleures astuces pour gérer les sélections, bien qu'il manque de solutions de contournement Firefox. Il utilise également la mise en évidence / mise à jour HTML brute.codemirror.next est une source inestimable pour voir différentes techniques lors de la gestion des astuces du texte et de la mise à jour DOM. Stable: Formidable ne prévoit pas de développer de nouvelles fonctionnalités pour ce projet. Nous répondons toujours aux rapports de bogues et aux problèmes de sécurité. Nous accueillons toujours PRS pour ce projet, mais les PR qui incluent de nouvelles fonctionnalités doivent être petits et faciles à intégrer et ne devraient pas inclure de changements de rupture.