UNPKG

@wangeditor-next/editor-for-react

Version:
1 lines 10.2 kB
{"version":3,"file":"index.mjs","sources":["../src/components/Editor.tsx","../src/components/Toolbar.tsx"],"sourcesContent":["/**\n * @description editor react component\n * @author wangfupeng\n */\n\nimport type { IDomEditor, IEditorConfig } from '@wangeditor-next/editor'\nimport {\n createEditor, SlateDescendant,\n} from '@wangeditor-next/editor'\nimport React, {\n useCallback, useEffect, useRef, useState,\n} from 'react'\nimport ReactDOM from 'react-dom'\n\ninterface IProps {\n defaultContent?: SlateDescendant[]\n onCreated?: (editor: IDomEditor) => void\n defaultHtml?: string\n value?: string\n onChange: (editor: IDomEditor) => void\n defaultConfig: Partial<IEditorConfig>\n mode?: string\n style?: React.CSSProperties\n className?: string\n loading?: boolean\n loadingText?: React.ReactNode\n}\n\ninterface ICustomDomEditor extends IDomEditor {\n __react_on_change?: (editor: ICustomDomEditor) => void;\n}\n\nfunction EditorComponent(props: Partial<IProps>) {\n const {\n defaultContent = [], onCreated, defaultHtml = '', value = '', onChange, defaultConfig = {}, mode = 'default', style = {}, className,\n loading = false, loadingText = 'Loading...',\n } = props\n const ref = useRef<HTMLDivElement | null>(null)\n const [editorRoot, setEditorRoot] = useState<HTMLDivElement | null>(null)\n const latestHtmlRef = useRef('')\n const isSyncingFromPropsRef = useRef(false)\n const [editor, setEditor] = useState<ICustomDomEditor | null>(null)\n\n const setRootRef = useCallback((node: HTMLDivElement | null) => {\n ref.current = node\n setEditorRoot(node)\n }, [])\n\n const handleCreated = useCallback((createdEditor: IDomEditor) => {\n // 组件属性 onCreated\n if (onCreated) { onCreated(createdEditor) }\n\n // 编辑器 配置 onCreated\n const { onCreated: onCreatedFromConfig } = defaultConfig\n\n if (onCreatedFromConfig) { onCreatedFromConfig(createdEditor) }\n }, [defaultConfig, onCreated])\n\n const handleDestroyed = useCallback((destroyedEditor: IDomEditor) => {\n const { onDestroyed } = defaultConfig\n\n setEditor(null)\n if (onDestroyed) {\n onDestroyed(destroyedEditor)\n }\n }, [defaultConfig])\n\n useEffect(() => {\n if (editor == null) { return }\n\n editor.__react_on_change = (e: IDomEditor) => {\n const latestHtml = e.getHtml()\n const prevHtml = latestHtmlRef.current\n\n latestHtmlRef.current = latestHtml // 记录当前 html 值\n\n // 由 props 同步触发 setHtml 时,不向外触发 onChange,避免受控场景产生回环\n if (isSyncingFromPropsRef.current) { return }\n\n // 仅在内容发生变化时触发,对齐输入控件 onChange 语义(忽略选区/焦点变化)\n if (latestHtml === prevHtml) { return }\n\n // 组件属性 onChange\n if (onChange) { onChange(e) }\n\n // 编辑器 配置 onChange\n const { onChange: onChangeFromConfig } = defaultConfig\n\n if (onChangeFromConfig) { onChangeFromConfig(e) }\n }\n return () => {\n editor.__react_on_change = undefined\n }\n }, [editor, defaultConfig, onChange])\n\n // value 变化,重置 HTML\n useEffect(() => {\n if (editor == null) { return }\n\n if (value === latestHtmlRef.current) { return } // 如果和当前 html 值相等,则忽略\n\n // ------ 重新设置 HTML ------\n try {\n isSyncingFromPropsRef.current = true\n editor.setHtml(value)\n latestHtmlRef.current = editor.getHtml()\n } catch (error) {\n console.error(error)\n } finally {\n isSyncingFromPropsRef.current = false\n }\n }, [editor, value])\n\n useEffect(() => {\n if (ref.current == null) { return }\n if (editor != null) { return }\n // 防止重复渲染 当编辑器已经创建就不在创建了\n if (ref.current?.getAttribute('data-w-e-textarea')) { return }\n\n const newEditor = createEditor({\n selector: ref.current,\n config: {\n ...defaultConfig,\n onCreated: handleCreated,\n onChange: (e: IDomEditor) => newEditor?.__react_on_change?.(e),\n onDestroyed: handleDestroyed,\n },\n content: defaultContent,\n html: defaultHtml || value,\n mode,\n })as ICustomDomEditor\n\n latestHtmlRef.current = newEditor.getHtml()\n setEditor(newEditor)\n }, [\n editor,\n defaultConfig,\n defaultContent,\n defaultHtml,\n handleCreated,\n handleDestroyed,\n mode,\n value,\n ])\n\n return (\n <div\n ref={setRootRef}\n style={{ ...style, position: style.position || 'relative' }}\n className={className}\n data-w-e-react-editor-container=\"true\"\n >\n {loading && editorRoot && ReactDOM.createPortal((\n <div\n data-w-e-loading-overlay=\"true\"\n style={{\n position: 'absolute',\n top: 0,\n right: 0,\n bottom: 0,\n left: 0,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n background: 'rgba(255, 255, 255, 0.6)',\n zIndex: 10,\n }}\n >\n {loadingText}\n </div>\n ), editorRoot)}\n </div>\n )\n}\n\nexport default EditorComponent\n","/**\n * @description toolbar react component\n * @author wangfupeng\n */\n\nimport * as wangEditor from '@wangeditor-next/editor'\nimport React, { useEffect, useRef } from 'react'\n\ninterface IProps {\n editor: wangEditor.IDomEditor | null\n defaultConfig?: Partial<wangEditor.IToolbarConfig>\n mode?: string\n style?: object\n className?: string\n}\n\nfunction ToolbarComponent(props: IProps) {\n const {\n editor, defaultConfig = {}, mode = 'default', style = {}, className,\n } = props\n const ref = useRef<HTMLDivElement>(null)\n\n useEffect(() => {\n if (ref.current == null || editor == null) { return }\n if (ref.current?.getAttribute('data-w-e-toolbar')) { return }\n\n const toolbar = wangEditor.createToolbar({\n editor,\n selector: ref.current,\n config: defaultConfig,\n mode,\n })\n\n return () => {\n if (toolbar) {\n toolbar.destroy()\n ref.current?.removeAttribute('data-w-e-toolbar')\n }\n }\n }, [editor, defaultConfig, mode])\n\n return <div style={style} ref={ref} className={className}></div>\n}\n\nexport default ToolbarComponent\n"],"names":["EditorComponent","props","_a","defaultContent","onCreated","_b","defaultHtml","_c","value","onChange","_d","defaultConfig","_e","mode","_f","style","className","_g","loading","_h","loadingText","ref","useRef","_j","__read","useState","editorRoot","setEditorRoot","latestHtmlRef","isSyncingFromPropsRef","_k","editor","setEditor","setRootRef","useCallback","node","current","handleCreated","createdEditor","onCreatedFromConfig","handleDestroyed","destroyedEditor","onDestroyed","useEffect","__react_on_change","e","latestHtml","getHtml","prevHtml","onChangeFromConfig","undefined","setHtml","error","console","getAttribute","newEditor","createEditor","selector","config","__assign","call","content","html","React","createElement","position","ReactDOM","createPortal","top","right","bottom","left","display","alignItems","justifyContent","background","zIndex","ToolbarComponent","toolbar","wangEditor","createToolbar","destroy","removeAttribute"],"mappings":"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"}