Небольшой крючок React, чтобы превратить элементы в полностью отображаемые и редактируемые поверхности контента, такие как редакторы кода, используя довольные (и магии)
useEditable - это небольшой крючок, который позволяет contenteditable элементам, но при этом полностью выполняется. Это идеально подходит для создания небольших редакторов кода или прозы Textareas всего за 2kB !
Он направлен на то, чтобы позволить любому элементу быть редактируемым, в то же время имея возможность представлять в него нормальные элементы реагирования - без innerHTML и иметь дело с работой или рендерингом в необработанном HTML, или начинать полный редактор с нуля.
Проверьте полную демонстрацию на CodeSandbox с prism-react-renderer !
Сначала установите use-editable вместе с react :
yarn add use-editable
# or
npm install --save use-editable Затем вы сможете импортировать useEditable и передавать его HTMLElement Ref и обработчику 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 >
) ;
} ; И точно так же, как это мы useEditable к нашему editorRef , который указывает на элемент <pre> , который отображается, и на setCode , который управляет нашим состоянием, содержащим какой -то код.
Эта библиотека была проверена и должна работать должным образом, используя:
В IE 11 есть известные проблемы из -за метода MutationObserver , который не может читать текстовые узлы, которые были удалены с помощью contenteditable .
Традиционно было три варианта при выборе редактирования поверхностей в React. Либо можно было бы пойти на большой проект, такой как Prosemirror / Codemirror, либо аналогичный, который занимает контроль над большей частью событий редактирования и рендеринга и, следовательно, довольно самоуверенными, либо можно просто использовать contenteditable и представлять для необработанного HTML, который заменяется в контенте элемента, или, наконец, можно сочетать textarea с перекрывающимся div , который стилизовал контент.
Все три варианта не допускают особой настройки с точки зрения того, что на самом деле визуализируется или накладывает необоснованные ограничения на то, насколько легко отображать и управлять контентом редактируемого.
Так что же заставляет рендеринг в contenteditable элементе?
Как правило, это сложно, потому что они редактируют DOM напрямую. Это заставляет большинство библиотек рендеринга, например, реагировать и преучить, поскольку их основные виртуальные DOMS больше не совпадают с фактической структурой DOM. Чтобы предотвратить эту проблему use-editable создает MutationObserver , который следит за всеми изменениями, которые внесены в contenteditable элемент. Прежде чем сообщать об этих изменениях, чтобы отреагировать, сначала откатается назад все изменения в DOM, чтобы React видит то, что он ожидает.
Кроме того, он также сохраняет текущую позицию калики, выбор и восстанавливает его, как только React обновил сам DOM. Это довольно распространенный метод для contenteditable редакторов, но добавление MutationObserver -это то, что позволяет использовать use-editable чтобы позволить другому представлению библиотеки обновить контент элемента.
В настоящее время либо текстовый контент рендерированных элементов должен в конечном итоге точно соответствовать вводу кода, либо ваша реализация должна быть в состоянии преобразовать отображаемый текстовый содержимое обратно в то, что вы используете в качестве состояния. Это ограничение работы contenteditable , поскольку они будут отражать только фактический контент DOM. Поскольку use-editable не стремится стать полным компонентом, который управляет циклом рендеринга, он не должен сохранять какое-либо дополнительное состояние, но будет только передавать текст DOM обратно в обратный вызов onChange .
Используя обратный вызов onChange вы также получите объект Position описывающий позицию курсора, текущий номер строки и содержимое линии вверх до тех пор, пока курсор, который полезен для автоматических разгонов, которые затем можно применить с помощью функции update , которая useEditable для обновления позиции курсора.
Первый аргумент - elementRef и принимает объект REF типа RefObject<HTMLElement> , который указывает на элемент, который должен стать редактируемым. Этот рефери может быть null или изменять во время выполнения крючка. До тех пор, пока изменения рефери инициируются React, все должно вести себя так, как и ожидалось.
Второй аргумент - onChange и принимает обратный вызов типа (text: string, pos: Position) => void который называется всякий раз, когда содержание contenteditable изменений. Это должно быть настроено так, чтобы это вызвало запуск содержимого элемента.
text , который получает onChange является лишь текстовым представлением содержимого элемента, в то время как полученное Position содержит текущую позицию курсора, номер строки (нулевой индекс) и содержание текущей линейки вверх до курсора, которое полезно для автоматических разги.
Третий аргумент - это необязательный объект options . В настоящее время он принимает два варианта изменения поведения крючка:
disabled отключает редактирование в редактируемом, удалив из него атрибут contentEditable .indentation может быть несколькими отображаемыми пространствами для вдавления. Это также позволяет улучшить поведение ключа Tab , которое будет отступать в текущей линии или посвященной текущей линии при смене (имейте в виду, что это заставит редактор действовать как ловушка с фокусировкой!) Когда options.indentation установлена, тогда useEditable , предотвращая вставку символов вкладок и вместо этого вставит указанное количество пробелов, что значительно упрощает обработку столбцов.
Кроме того, useEditable крючок возвращает ручку Edit с помощью нескольких методов, как задокументировано ниже.
Edit.update(content: string): void
Заменяет все содержание редактируемого при настройке позиции карета. Это изменит калику на разницу в длине между текущим содержанием и пройденным контентом.
Edit.insert(append: string, offset?: number): void
Вставляет новый текст в положении карета при удалении текста в диапазоне смещения (который принимает отрицательные смещения). Например, когда offset установлено на -1 тогда один символ удаляется слева от калики, прежде чем вставить любой новый текст. Когда он установлен на 2 , то два символа справа от заболеваний удаляются. Текст append также может быть установлен на пустую строку для применения только удалений без вставки какого -либо текста. Когда любой текст выбран, он просто стерт сначала, а offset игнорируется.
Edit.move(pos: number | { row: number; column: number }): void
Это перемещает карету в указанную позицию. Положение может быть либо индексом символов ( number ), либо координатами, указывающими row и column отдельно.
Edit.getState(): { text: string; position: Position }
Этот метод позволяет получить текущее состояние редактируемого, которое такое же, как и то, onChange обычно получает. Это полезно при добавлении пользовательских действий по редактированию в обработчике с ключом вниз или при программном имитировании onChange иначе, в то время как редактируемый выбран.
react-live , над которым я работал, имел один из ранних крошечных contenteditable редакторов. (Но с необработанными обновлениями HTML)react-simple-code-editor была первой (?) Библиотекой, которая использовала разделенную Textarea и рендеринг поверхностной реализации, которая представила, как должен выглядеть хорошее API редактирования.codejar содержит лучшие хитрости для управления выбором, хотя в нем не хватает обходных путей Firefox. Он также использует необработанное HTML -выделение / обновление.codemirror.next является бесценным источником, чтобы увидеть различные методы при обработке текстового ввода и трюков обновления DOM. Стабильное: Грубоваемое не планирует разработать какие -либо новые функции для этого проекта. Мы все еще отвечаем на отчеты об ошибках и проблемы безопасности. Мы по -прежнему приветствуем PRS для этого проекта, но PR, которые включают новые функции, должны быть небольшими и простыми в интеграции и не должны включать нарушающие изменения.