@selfcommunity/react-ui
Version:
React UI Components to integrate a Community created with SelfCommunity Platform.
195 lines (194 loc) • 7.86 kB
JavaScript
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;
;