{"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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"}