UNPKG

phx-react

Version:

PHX REACT

137 lines 7.6 kB
import { $generateNodesFromDOM, $generateHtmlFromNodes } from '@lexical/html'; import { LexicalComposer } from '@lexical/react/LexicalComposer'; import { $getRoot, TextNode, createEditor } from 'lexical'; import * as React from 'react'; import { useEffect, useState } from 'react'; import { SharedAutocompleteContext } from './context/SharedAutocompleteContext'; import { SharedHistoryContext, useSharedHistoryContext } from './context/SharedHistoryContext'; import { ExtendedTextNode } from './nodes/ExtendedTextNode'; import PlaygroundNodes from './nodes/PlaygroundNodes'; import { TableContext } from './plugins/TablePlugin'; import { CAN_USE_DOM } from './shared/canUseDOM'; import PlaygroundEditorTheme from './themes/PlaygroundEditorTheme'; import { CheckListPlugin } from '@lexical/react/LexicalCheckListPlugin'; import { ClearEditorPlugin } from '@lexical/react/LexicalClearEditorPlugin'; import { HistoryPlugin } from '@lexical/react/LexicalHistoryPlugin'; import { ListPlugin } from '@lexical/react/LexicalListPlugin'; import { OnChangePlugin } from '@lexical/react/LexicalOnChangePlugin'; import { RichTextPlugin } from '@lexical/react/LexicalRichTextPlugin'; import { TabIndentationPlugin } from '@lexical/react/LexicalTabIndentationPlugin'; import ImagesPlugin from './plugins/ImagesPlugin'; import InlineImagePlugin from './plugins/InlineImagePlugin'; import ListMaxIndentLevelPlugin from './plugins/ListMaxIndentLevelPlugin'; import { MaxLengthPlugin } from './plugins/MaxLengthPlugin'; import SanitizePastePlugin from './plugins/SanitizePastePlugin'; import PreserveFontSizeOnEnterPlugin from './plugins/PreserveFontSizeOnEnterPlugin'; import ResetEmptyListItemFormatPlugin from './plugins/ResetEmptyListItemFormatPlugin'; import ContentEditable from './ui/ContentEditable'; import ToolbarPlugin from './plugins/ToolbarPlugin'; import { useSettings } from './context/SettingsContext'; import { styleTag } from './constants'; import EditorStyle from './style'; import { ClickableLinkPlugin } from '@lexical/react/LexicalClickableLinkPlugin'; import { LinkPlugin } from '@lexical/react/LexicalLinkPlugin'; import { LexicalErrorBoundary } from './shared/LexicalErrorBoundary'; export default function PHXTextEditorV2({ defaultValue, label, onChange, placeholder, apiCdnUpload, disabled = false, }) { const [isSmallWidthViewport, setIsSmallWidthViewport] = useState(false); const { historyState } = useSharedHistoryContext(); const { settings: { isMaxLength }, } = useSettings(); const editorConfig = { theme: PlaygroundEditorTheme, editorState: prepopulatedRichText, onError(error) { throw error; }, nodes: [ ...PlaygroundNodes, ExtendedTextNode, { replace: TextNode, with: (node) => new ExtendedTextNode(node.__text), withKlass: ExtendedTextNode, }, ], }; function prepopulatedRichText() { const root = $getRoot(); try { if (defaultValue) { const editor = createEditor(); const parser = new DOMParser(); const dom = parser.parseFromString(defaultValue, 'text/html'); const nodes = $generateNodesFromDOM(editor, dom); if (root.getFirstChild() === null) { root.append(...nodes); } } } catch (e) { root.clear(); } } function ensureStyleTag(html, css) { const parser = new DOMParser(); const doc = parser.parseFromString(html, 'text/html'); const hasStyle = doc.querySelector('style'); if (hasStyle) { hasStyle.innerHTML = css; } else { const styleTag = doc.createElement('style'); styleTag.innerHTML = css; doc.head.appendChild(styleTag); } return doc.documentElement.outerHTML; } const handleChange = (editorState, editor) => { editorState.read(() => { const data = JSON.stringify(editorState); return data; }); editor.update(() => { const rawHTML = $generateHtmlFromNodes(editor, null); const htmlWithStyle = ensureStyleTag(rawHTML, styleTag); onChange === null || onChange === void 0 ? void 0 : onChange(htmlWithStyle); }); }; useEffect(() => { const updateViewPortWidth = () => { const isNextSmallWidthViewport = CAN_USE_DOM && window.matchMedia('(max-width: 1025px)').matches; if (isNextSmallWidthViewport !== isSmallWidthViewport) { setIsSmallWidthViewport(isNextSmallWidthViewport); } }; updateViewPortWidth(); window.addEventListener('resize', updateViewPortWidth); return () => { window.removeEventListener('resize', updateViewPortWidth); }; }, [isSmallWidthViewport]); return (React.createElement("div", null, React.createElement(EditorStyle, null), label && React.createElement("label", { className: 'block mb-1 text-xs font-normal text-gray-700' }, label), React.createElement(LexicalComposer, { initialConfig: editorConfig }, React.createElement(SharedHistoryContext, null, React.createElement(TableContext, null, React.createElement(SharedAutocompleteContext, null, React.createElement("div", { className: 'rounded-md border border-gray-300 shadow-sm overflow-hidden' }, React.createElement(ToolbarPlugin, { disabled: disabled, apiCdnUpload: apiCdnUpload }), React.createElement("div", { className: 'relative' }, isMaxLength && React.createElement(MaxLengthPlugin, { maxLength: 30 }), React.createElement(ClearEditorPlugin, null), React.createElement(OnChangePlugin, { onChange: handleChange }), React.createElement(HistoryPlugin, { externalHistoryState: historyState }), React.createElement(SanitizePastePlugin, null), React.createElement(PreserveFontSizeOnEnterPlugin, null), React.createElement(ResetEmptyListItemFormatPlugin, null), React.createElement(RichTextPlugin, { contentEditable: React.createElement(ContentEditable, { className: 'PHXTextEditorV2__contentEditable px-2 py-1.5 h-[20rem] overflow-y-auto outline-none' }), ErrorBoundary: LexicalErrorBoundary, placeholder: React.createElement("p", { className: 'absolute top-1.5 left-2 text-xs text-[#999] z-10 overflow-hidden text-ellipsis inline-block select-none pointer-events-none' }, placeholder) }), React.createElement(ListPlugin, null), React.createElement(CheckListPlugin, null), React.createElement(ListMaxIndentLevelPlugin, { maxDepth: 7 }), React.createElement(ImagesPlugin, null), React.createElement(InlineImagePlugin, null), React.createElement(LinkPlugin, null), React.createElement(ClickableLinkPlugin, { newTab: true }), React.createElement(TabIndentationPlugin, null))))))))); } //# sourceMappingURL=editor.js.map