UNPKG

@selfcommunity/react-ui

Version:

React UI Components to integrate a Community created with SelfCommunity Platform.

195 lines (194 loc) • 7.86 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.$isImageNode = exports.$createImageNode = exports.ImageNode = void 0; const jsx_runtime_1 = require("react/jsx-runtime"); const react_1 = require("react"); const lexical_1 = require("lexical"); const LexicalComposerContext_1 = require("@lexical/react/LexicalComposerContext"); const useLexicalNodeSelection_1 = require("@lexical/react/useLexicalNodeSelection"); const utils_1 = require("@lexical/utils"); const imageCache = new Set(); function useSuspenseImage(src) { if (!imageCache.has(src)) { throw new Promise((resolve) => { const img = new Image(); img.src = src; img.onload = () => { imageCache.add(src); resolve(); }; }); } } function LazyImage({ altText, className, imageRef, src, width, height, maxWidth }) { useSuspenseImage(src); return ((0, jsx_runtime_1.jsx)("img", { className: className, src: src, alt: altText, ref: imageRef, style: { height: `${height}${height === 'inherit' ? '' : 'px'}`, maxWidth, width: `${width}${width === 'inherit' ? '' : 'px'}` } })); } function ImageComponent({ src, altText, nodeKey, maxWidth }) { const imageRef = (0, react_1.useRef)(null); const buttonRef = (0, react_1.useRef)(null); const [isSelected, setSelected, clearSelection] = (0, useLexicalNodeSelection_1.useLexicalNodeSelection)(nodeKey); const [editor] = (0, LexicalComposerContext_1.useLexicalComposerContext)(); const activeEditorRef = (0, react_1.useRef)(null); const onDelete = (0, react_1.useCallback)((payload) => { if (isSelected && (0, lexical_1.$isNodeSelection)((0, lexical_1.$getSelection)())) { const event = payload; event.preventDefault(); const node = (0, lexical_1.$getNodeByKey)(nodeKey); if ($isImageNode(node)) { node.remove(); } setSelected(false); } return false; }, [isSelected, nodeKey, setSelected]); const onEnter = (0, react_1.useCallback)((event) => { const latestSelection = (0, lexical_1.$getSelection)(); const buttonElem = buttonRef.current; if (isSelected && (0, lexical_1.$isNodeSelection)(latestSelection) && latestSelection.getNodes().length === 1) { if (buttonElem !== null && buttonElem !== document.activeElement) { event.preventDefault(); buttonElem.focus(); return true; } } return false; }, [isSelected]); const onEscape = (0, react_1.useCallback)((event) => { if (buttonRef.current === event.target) { (0, lexical_1.$setSelection)(null); editor.update(() => { setSelected(true); const parentRootElement = editor.getRootElement(); if (parentRootElement !== null) { parentRootElement.focus(); } }); return true; } return false; }, [editor, setSelected]); (0, react_1.useEffect)(() => { const unregister = (0, utils_1.mergeRegister)(editor.registerCommand(lexical_1.SELECTION_CHANGE_COMMAND, (_, activeEditor) => { activeEditorRef.current = activeEditor; return false; }, lexical_1.COMMAND_PRIORITY_LOW), editor.registerCommand(lexical_1.CLICK_COMMAND, (payload) => { const event = payload; if (event.target === imageRef.current) { if (event.shiftKey) { setSelected(!isSelected); } else { clearSelection(); setSelected(true); } return true; } return false; }, lexical_1.COMMAND_PRIORITY_LOW), editor.registerCommand(lexical_1.KEY_DELETE_COMMAND, onDelete, lexical_1.COMMAND_PRIORITY_LOW), editor.registerCommand(lexical_1.KEY_BACKSPACE_COMMAND, onDelete, lexical_1.COMMAND_PRIORITY_LOW), editor.registerCommand(lexical_1.KEY_ENTER_COMMAND, onEnter, lexical_1.COMMAND_PRIORITY_LOW), editor.registerCommand(lexical_1.KEY_ESCAPE_COMMAND, onEscape, lexical_1.COMMAND_PRIORITY_LOW)); return () => { unregister(); }; }, [clearSelection, editor, isSelected, nodeKey, onDelete, onEnter, onEscape, setSelected]); return ((0, jsx_runtime_1.jsx)(react_1.Suspense, Object.assign({ fallback: null }, { children: (0, jsx_runtime_1.jsx)(LazyImage, { className: isSelected ? `selected` : null, src: src, altText: altText, imageRef: imageRef, maxWidth: maxWidth }) }))); } function convertImageElement(domNode) { if (domNode instanceof HTMLImageElement) { const { alt: altText, src } = domNode; const node = $createImageNode({ altText, src, maxWidth: '100%' }); return { node }; } return null; } // eslint-disable-next-line @typescript-eslint/ban-ts-ignore // @ts-ignore class ImageNode extends lexical_1.DecoratorNode { static getType() { return 'image'; } static clone(node) { return new ImageNode(node.__src, node.__altText, node.__maxWidth, node.__key); } constructor(src, altText, maxWidth, key) { super(key); this.__src = src; this.__altText = altText; this.__maxWidth = maxWidth; } setWidthAndHeight(width, height) { const writable = this.getWritable(); // eslint-disable-next-line @typescript-eslint/ban-ts-ignore // @ts-ignore writable.__width = width; // eslint-disable-next-line @typescript-eslint/ban-ts-ignore // @ts-ignore writable.__height = height; } // View createDOM(config) { const div = document.createElement('div'); const theme = config.theme; const className = theme.image; if (className !== undefined) { div.className = className; } return div; } updateDOM() { return false; } static importDOM() { // eslint-disable-next-line @typescript-eslint/ban-ts-ignore // @ts-ignore const dom = lexical_1.TextNode.importDOM(); return Object.assign({ img: (node) => ({ conversion: convertImageElement, priority: 0 }) }, dom); } exportDOM() { const element = document.createElement('img'); element.setAttribute('src', this.__src); element.setAttribute('alt', this.__altText); element.setAttribute('style', `max-width: ${this.__maxWidth}px;`); return { element }; } decorate() { return (0, jsx_runtime_1.jsx)(ImageComponent, { src: this.__src, altText: this.__altText, maxWidth: this.__maxWidth, nodeKey: this.getKey() }); } static importJSON(serializedNode) { const { altText, maxWidth, src } = serializedNode; const node = $createImageNode({ altText, src, maxWidth }); return node; } exportJSON() { return { // eslint-disable-next-line @typescript-eslint/ban-ts-ignore // @ts-ignore altText: this.getAltText(), maxWidth: this.__maxWidth, // eslint-disable-next-line @typescript-eslint/ban-ts-ignore // @ts-ignore src: this.getSrc(), type: 'image', version: 1 }; } } exports.ImageNode = ImageNode; function $createImageNode({ src, altText, maxWidth }) { return new ImageNode(src, altText, maxWidth); } exports.$createImageNode = $createImageNode; function $isImageNode(node) { return node.getType() === 'image'; } exports.$isImageNode = $isImageNode;