import React, { useCallback, useMemo } from 'react'; import isHotkey from 'is-hotkey'; import { Editable, withReact, useSlate, Slate, ReactEditor } from 'slate-react'; import { Editor, createEditor, BaseEditor, Descendant } from 'slate'; import { withHistory } from 'slate-history'; import { Button, Icon, Toolbar } from './components'; import { injectGlobal } from '@emotion/css'; const HOTKEYS = { 'mod+b': 'bold', 'mod+i': 'italic', 'mod+u': 'underline', 'mod+`': 'code', }; //注入全局样式 injectGlobal` @font-face { font-family: 'Material Icons'; font-style: normal; font-weight: 400; src: url(https://fonts.gstatic.com/s/materialicons/v140/flUhRq6tzZclQEJ-Vdg-IuiaDsNcIhQ8tQ.woff2) format('woff2'); } .material-icons { font-family: 'Material Icons'; font-weight: normal; font-style: normal; font-size: 24px; line-height: 1; letter-spacing: normal; text-transform: none; display: inline-block; white-space: nowrap; word-wrap: normal; direction: ltr; -webkit-font-feature-settings: 'liga'; -webkit-font-smoothing: antialiased; } `; // 实现一个递归函数,有children就继续往下递归查找并把text拼接起来 function extractText(node: Descendant[] | any) { let text = ''; if (node.text) { // 处理加粗 text = node.bold ? `${node.text}` : node.text; } // 如果自己是数组 if (Array.isArray(node)) { node.forEach(item => (text += extractText(item))); } else { if (node.children && node.children.length > 0) { for (const curNode of node.children) { text += extractText(curNode); } } } return text; } // const LIST_TYPES = ['numbered-list', 'bulleted-list']; // const TEXT_ALIGN_TYPES = ['left', 'center', 'right', 'justify']; const initialValue: Descendant[] = [ { // @ts-ignore type: 'paragraph', children: [{ text: '' }], }, ]; const RichText = (props: { editor?: ReactEditor; value: Descendant[]; maxLength?: number; children?: React.ReactNode; onChange?: ((value: Descendant[], content: string) => void) | undefined; }) => { const { onChange, value, children, ...rest } = props; const renderElement = useCallback((props: any) => , []); const renderLeaf = useCallback((props: any) => , []); const editor = useMemo(() => withHistory(withReact(createEditor())), []); return ( { if (onChange) { return onChange(value, extractText(value)); } // onChange && onChange(value, extractText(value)); }} > {/* */} { if (event.key === 'Enter') { return event.preventDefault(); } for (const hotkey in HOTKEYS) { if (isHotkey(hotkey, event as any)) { event.preventDefault(); // @ts-ignore const mark = HOTKEYS[hotkey]; toggleMark(editor, mark); } } }} {...rest} /> ); }; // const toggleBlock = (editor: BaseEditor, format: string) => { // const isActive = isBlockActive( // editor, // format, // TEXT_ALIGN_TYPES.includes(format) ? 'align' : 'type' // ); // const isList = LIST_TYPES.includes(format); // Transforms.unwrapNodes(editor, { // match: n => // !Editor.isEditor(n) && // SlateElement.isElement(n) && // LIST_TYPES.includes(n.type) && // !TEXT_ALIGN_TYPES.includes(format), // split: true, // }); // let newProperties: Partial; // if (TEXT_ALIGN_TYPES.includes(format)) { // newProperties = { // align: isActive ? undefined : format, // }; // } else { // newProperties = { // 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: BaseEditor, format: string) => { const isActive = isMarkActive(editor, format); if (isActive) { Editor.removeMark(editor, format); } else { Editor.addMark(editor, format, true); } }; // const isBlockActive = (editor: BaseEditor, format: any, blockType = 'type') => { // const { selection } = editor; // if (!selection) return false; // const [match] = Array.from( // Editor.nodes(editor, { // at: Editor.unhangRange(editor, selection), // match: n => // !Editor.isEditor(n) && // SlateElement.isElement(n) && // n[blockType] === format, // }) // ); // return !!match; // }; const isMarkActive = (editor: BaseEditor, format: string | number) => { const marks: Record | null = Editor.marks(editor); return marks ? marks[format] === true : false; }; const Element = ({ attributes, children, element }: any) => { const style = { textAlign: element.align }; 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 }: any) => { 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 }: any) => { const editor = useSlate(); return ( ); }; export default RichText;