import React, { useCallback, useMemo, useState } from 'react' import isHotkey from 'is-hotkey' import { Editable, Slate, useSlate, withReact } from 'slate-react' import { createEditor, Descendant, Editor, Element as SlateElement, Transforms, } from 'slate' import { withHistory } from 'slate-history' import { Button, Icon, Toolbar } from '../components' const HOTKEYS = { 'mod+b': 'bold', 'mod+i': 'italic', 'mod+u': 'underline', 'mod+`': 'code', } const LIST_TYPES = ['numbered-list', 'bulleted-list'] const RichTextExample = () => { const [value, setValue] = useState(initialValue) const renderElement = useCallback(props => , []) const renderLeaf = useCallback(props => , []) const editor = useMemo(() => withHistory(withReact(createEditor())), []) return ( { for (const hotkey in HOTKEYS) { if (isHotkey(hotkey, event as any)) { event.preventDefault() const mark = HOTKEYS[hotkey] toggleMark(editor, mark) } } }} /> ) } const toggleBlock = (editor, format) => { const isActive = isBlockActive(editor, format) const isList = LIST_TYPES.includes(format) Transforms.unwrapNodes(editor, { match: n => LIST_TYPES.includes( !Editor.isEditor(n) && SlateElement.isElement(n) && n.type ), split: true, }) const newProperties: Partial = { type: isActive ? 'paragraph' : isList ? 'list-item' : format, } Transforms.setNodes(editor, newProperties) if (!isActive && isList) { const block = { type: format, children: [] } Transforms.wrapNodes(editor, block) } } const toggleMark = (editor, format) => { const isActive = isMarkActive(editor, format) if (isActive) { Editor.removeMark(editor, format) } else { Editor.addMark(editor, format, true) } } const isBlockActive = (editor, format) => { const [match] = Editor.nodes(editor, { match: n => !Editor.isEditor(n) && SlateElement.isElement(n) && n.type === format, }) return !!match } const isMarkActive = (editor, format) => { const marks = Editor.marks(editor) return marks ? marks[format] === true : false } const Element = ({ attributes, children, element }) => { switch (element.type) { case 'block-quote': return
{children}
case 'bulleted-list': return
    {children}
case 'heading-one': return

{children}

case 'heading-two': return

{children}

case 'list-item': return
  • {children}
  • case 'numbered-list': return
      {children}
    default: return

    {children}

    } } const Leaf = ({ attributes, children, leaf }) => { if (leaf.bold) { children = {children} } if (leaf.code) { children = {children} } if (leaf.italic) { children = {children} } if (leaf.underline) { children = {children} } return {children} } const BlockButton = ({ format, icon }) => { const editor = useSlate() return ( ) } const MarkButton = ({ format, icon }) => { const editor = useSlate() return ( ) } const initialValue: Descendant[] = [ { type: 'paragraph', children: [ { text: 'This is editable ' }, { text: 'rich', bold: true }, { text: ' text, ' }, { text: 'much', italic: true }, { text: ' better than a ' }, { text: '