phx-react
Version:
PHX REACT
137 lines • 7.6 kB
JavaScript
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