Un pequeño gancho React para convertir los elementos en superficies de contenido totalmente representables y editables, como editores de código, utilizando contento (y magia)
useEditable es un pequeño gancho que permite que los elementos se contenteditable sin dejar de ser totalmente renderizables. ¡Esto es ideal para crear pequeños editores de código o texturas en prosa en solo 2kB !
Su objetivo es permitir que cualquier elemento sea editable y al mismo tiempo que puede hacer que los elementos reactos normales no sean, sin innerHTML y tener que lidiar con operar o representar a HTML sin procesar, o comenzar un proyecto de editor completo desde cero.
¡Mira la demostración completa en Codesandbox con prism-react-renderer !
Primero instalar use-editable junto con react :
yarn add use-editable
# or
npm install --save use-editable Luego podrá importar useEditable y pasarlo un HTMLElement Ref y un controlador 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 >
) ;
} ; Y así, hemos conectado useEditable para nuestro editorRef , que apunta al elemento <pre> que se está procesando, y a setCode que impulsa nuestro estado que contiene algún código.
Esta biblioteca ha sido probada y debería funcionar correctamente usando:
Hay problemas conocidos en IE 11 debido a que el método MutationObserver no puede leer nodos de texto que se han eliminado a través de lo contenteditable .
Tradicionalmente, ha habido tres opciones al elegir la edición de superficies en React. Cualquiera de los cuales podría buscar un proyecto grande como Prosemirror / Codemirror o similar que tome el control sobre gran parte de los eventos de edición y representación y, por lo tanto, son bastante obstinados, o es posible usar simplemente contenteditable y renderizar a HTML que se reemplaza en el contenido del elemento, o, por último, uno podría combinar una textarea con un div sobrecargada que se aplica al contenido estilizado.
Las tres opciones no permiten mucha personalización en términos de lo que realmente se vuelve o pone restricciones irrazonables sobre lo fácil que es representar y administrar el contenido de un editable.
Entonces, ¿qué hace que la presentación de un elemento contenteditable sea tan difícil?
Por lo general, esto es difícil porque editan el DOM directamente. Esto hace que la mayoría de las bibliotecas de representación, como React y Preacat, se confundan, ya que sus DOM virtuales subyacentes ya no coinciden con la estructura DOM real. Para evitar este problema use-editable crea un MutationObserver , que observa todos los cambios que se realizan en el elemento contenteditable . Antes de informar estos cambios para reaccionar, primero reinicia todos los cambios al DOM para que React vea lo que espera.
Además, también conserva la posición actual del careto, la selección y la restaura una vez que React ha actualizado el DOM en sí. Esta es una técnica bastante común para los editores contenteditable , pero la adición de MutationObserver es lo que permite use-editable permitir que otra visión de la biblioteca actualice el contenido del elemento.
Actualmente, el contenido de texto de los elementos renderizados debe coincidir exactamente con la entrada del código, o su implementación debe poder convertir el contenido de texto renderizado nuevamente en lo que está utilizando como estado. Esta es una limitación de cómo el trabajo de contenteditable , ya que solo capturarán el contenido DOM real. Dado que use-editable no tiene como objetivo ser un componente completo que administre el ciclo de renderizado, no tiene que mantener ningún estado adicional, pero solo pasará el texto de DOM a la devolución de llamada onChange .
Usando la devolución de llamada onChange también recibirá un objeto Position que describe la posición del cursor, el número de línea actual y el contenido de la línea hasta el cursor, que es útil para las sugerencias automáticas, que luego podrían aplicarse con la función update que useEditable regresa para actualizar la posición del cursor.
El primer argumento es elementRef y acepta un objeto REF de Tipo RefObject<HTMLElement> que apunta al elemento que debería volverse editable. Esta árbitro puede ser null o cambiar durante el tiempo de ejecución del gancho. Mientras React se active los cambios de la REF, todo debería comportarse como se esperaba.
El segundo argumento es onChange y acepta una devolución de llamada del tipo (text: string, pos: Position) => void que se llama cada vez que cambia el contenido del contenteditable . Esto debe configurarse para que active un repostería del contenido del elemento.
El text que recibe onChange es solo la representación textual del contenido del elemento, mientras que la Position que recibe contiene la posición actual del cursor, el número de línea (indexado por cero) y el contenido de la alineación actual hasta el cursor, que es útil para autosugestiones.
El tercer argumento es un objeto options opcional. Esto acepta actualmente dos opciones para cambiar el comportamiento de edición del gancho:
disabled deshabilita la edición en el editable eliminando el atributo contentEditable de ella nuevamente.indentation puede ser una serie de espacios mostrados para la sangría. Esto también permite el comportamiento mejorado de la tecla Tab , que sangrará la línea actual o dedente la línea actual cuando se mantiene el cambio (¡tenga en cuenta que esto hará que el editor actúe como una trampa de enfoque!) Cuando options.indentation se establece, entonces useEditable evitará la inserción de los caracteres de TAB y, en su lugar, insertará la cantidad especificada de espacios en blanco, lo que facilita el manejo de columnas.
Además, el gancho useEditable devuelve un mango Edit con varios métodos, como se documenta a continuación.
Edit.update(content: string): void
Reemplaza todo el contenido de lo editable al ajustar la posición del careto. Esto cambiará el careto por la diferencia de longitud entre el contenido actual y el contenido aprobado.
Edit.insert(append: string, offset?: number): void
Inserta texto nuevo en la posición del careto mientras elimina el texto en el rango del desplazamiento (que acepta compensaciones negativas). Por ejemplo, cuando offset se establece en -1 entonces se elimina un solo carácter a la izquierda del careto antes de insertar cualquier texto nuevo. Cuando se establece en 2 , se eliminan dos caracteres a la derecha de los caretes. El texto append también se puede configurar en una cadena vacía para aplicar solo deleciones sin insertar ningún texto. Cuando se selecciona cualquier texto, simplemente se borra primero y se ignora offset .
Edit.move(pos: number | { row: number; column: number }): void
Esto mueve el careto a la posición especificada. La posición puede ser un índice de caracteres (un number ) o coordenadas que especifiquen una row y column por separado.
Edit.getState(): { text: string; position: Position }
Este método permite obtener el estado actual de lo editable, que es el mismo que generalmente recibe onChange . Esto es útil al agregar acciones de edición personalizadas en un controlador de llave o al imitar programáticamente onChange de lo contrario, mientras se selecciona el editable.
react-live , en el que he trabajado, tuvo uno de los primeros editores contenteditable . (Pero con actualizaciones de HTML en bruto)react-simple-code-editor fue la primera (?) Biblioteca en usar un textea dividido y una implementación de superficie de representación, que presentó cómo debería ser una buena API de edición.codejar contiene los mejores trucos para administrar las selecciones, aunque carece de algunas soluciones de Firefox. También utiliza resaltar / actualizar HTML en bruto.codemirror.next es una fuente invaluable para ver diferentes técnicas al manejar la entrada de texto y los trucos de actualización de DOM. Estable: Formidable no planea desarrollar ninguna característica nueva para este proyecto. Todavía estamos respondiendo a los informes de errores y las preocupaciones de seguridad. Todavía damos la bienvenida a los PRS para este proyecto, pero los PR que incluyen nuevas características deben ser pequeñas y fáciles de integrar y no deben incluir cambios en los cambios.