I created the following react component. It uses quill js and has a custom button to insert a line. The problem is I can't find a way to to insert an <hr>
tag through the insertLine
function. Is there a way to insert direct html?
import ReactQuill, { Quill } from 'react-quill'
import 'react-quill/dist/quill.snow.css'
function insertLine() {
}
const icons = Quill.import('ui/icons')
icons['code-block'] = '<svg strokeWidth="0" viewBox="0 0 16 16" height="15" width="15" xmlns="http://www.w3.org/2000/svg"><path d="M9.293 0H4a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V4.707A1 1 0 0 0 13.707 4L10 .293A1 1 0 0 0 9.293 0zM9.5 3.5v-2l3 3h-2a1 1 0 0 1-1-1zM6.646 7.646a.5.5 0 1 1 .708.708L5.707 10l1.647 1.646a.5.5 0 0 1-.708.708l-2-2a.5.5 0 0 1 0-.708l2-2zm2.708 0 2 2a.5.5 0 0 1 0 .708l-2 2a.5.5 0 0 1-.708-.708L10.293 10 8.646 8.354a.5.5 0 1 1 .708-.708z"></path></svg>'
const modules = {
toolbar: {
container: '#toolbar',
handlers: {
insertLine: insertLine
}
},
clipboard: {
matchVisual: false,
}
}
export default function TextEditor({ body, setBody }) {
return (
<div>
<div id='toolbar' style={{borderBottomWidth: '0'}}>
<span className='ql-formats'>
<select className='ql-header' defaultValue='7' onChange={e => e.persist()}>
<option value='1' />
<option value='2' />
<option value='7' />
</select>
</span>
<span className='ql-formats'>
<button className='ql-bold' />
<button className='ql-italic' />
<button className='ql-underline' />
<button className='ql-strike' />
</span>
<span className='ql-formats'>
<button className='ql-blockquote' />
<button className='ql-link' />
<button className='ql-image' />
<button className='ql-code' />
<button className='ql-code-block' />
</span>
<span className='ql-formats'>
<button className='ql-list' value='ordered' />
<button className='ql-list' value='bullet' />
<button className='ql-insertLine' style={{transform: 'rotate(90deg)'}}>
<svg stroke="currentColor" strokeWidth="0" viewBox="0 0 24 24" height="16" width="16" xmlns="http://www.w3.org/2000/svg"><path fill="none" d="M0 0h24v24H0z"></path><path d="M4 22H2V2h2v20zM22 2h-2v20h2V2zm-8.5 5h-3v10h3V7z"></path></svg>
</button>
</span>
</div>
<ReactQuill theme='snow' value={body} onChange={setBody} modules={modules} />
</div>
)
}
After some trial and error, this worked for me.
import React, { useRef, useEffect } from 'react'
import ReactQuill, { Quill } from 'react-quill'
import 'react-quill/dist/quill.snow.css'
const DividerBlot = Quill.import('blots/block')
class Divider extends DividerBlot {}
Divider.blotName = 'divider'
Divider.tagName = 'hr'
Quill.register(Divider)
const icons = Quill.import('ui/icons')
icons['code-block'] = '<svg strokeWidth="0" viewBox="0 0 16 16" height="15" width="15" xmlns="http://www.w3.org/2000/svg"><path d="M9.293 0H4a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V4.707A1 1 0 0 0 13.707 4L10 .293A1 1 0 0 0 9.293 0zM9.5 3.5v-2l3 3h-2a1 1 0 0 1-1-1zM6.646 7.646a.5.5 0 1 1 .708.708L5.707 10l1.647 1.646a.5.5 0 0 1-.708.708l-2-2a.5.5 0 0 1 0-.708l2-2zm2.708 0 2 2a.5.5 0 0 1 0 .708l-2 2a.5.5 0 0 1-.708-.708L10.293 10 8.646 8.354a.5.5 0 1 1 .708-.708z"></path></svg>'
const modules = {
toolbar: {
container: '#toolbar',
handlers: {
insertLine: insertLine
}
},
clipboard: {
matchVisual: false
}
}
function insertLine() {
const editor = this.quill
const range = editor.getSelection()
const cursorPosition = range ? range.index : 0
editor.insertEmbed(cursorPosition, 'divider', true, Quill.sources.USER)
editor.setSelection(cursorPosition + 1, Quill.sources.SILENT)
}
export default function TextEditor({ body, setBody }) {
const quillRef = useRef()
useEffect(() => {
if (quillRef.current) {
const editor = quillRef.current.getEditor()
editor.getModule('clipboard').addMatcher(Node.TEXT_NODE, function (node, delta) {
const text = node.data
if (text === '<hr>') {
const divider = new Divider()
const index = delta.ops.length - 1
delta.ops[index].insert = { divider }
}
return delta
})
editor.getModule('toolbar').addHandler('divider', insertLine)
}
}, [])
return (
<div>
<div id='toolbar' style={{borderBottomWidth: '0'}}>
<span className='ql-formats'>
<select className='ql-header' defaultValue='7' onChange={e => e.persist()}>
<option value='1' />
<option value='2' />
<option value='7' />
</select>
</span>
<span className='ql-formats'>
<button className='ql-bold' />
<button className='ql-italic' />
<button className='ql-underline' />
<button className='ql-strike' />
</span>
<span className='ql-formats'>
<button className='ql-blockquote' />
<button className='ql-link' />
<button className='ql-image' />
<button className='ql-code' />
<button className='ql-code-block' />
</span>
<span className='ql-formats'>
<button className='ql-list' value='ordered' />
<button className='ql-list' value='bullet' />
<button className='ql-insertLine' style={{transform: 'rotate(90deg)'}}>
<svg stroke="currentColor" strokeWidth="0" viewBox="0 0 24 24" height="16" width="16" xmlns="http://www.w3.org/2000/svg"><path fill="none" d="M0 0h24v24H0z"></path><path d="M4 22H2V2h2v20zM22 2h-2v20h2V2zm-8.5 5h-3v10h3V7z"></path></svg>
</button>
</span>
</div>
<ReactQuill ref={quillRef} theme='snow' value={body} onChange={setBody} modules={modules} />
</div>
)
}