/** * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * */ import { $applyNodeReplacement, DecoratorNode } from 'lexical'; import * as React from 'react'; import { Suspense } from 'react'; import type { DOMConversionMap, DOMConversionOutput, DOMExportOutput, EditorConfig, LexicalNode, NodeKey, SerializedLexicalNode, Spread, } from 'lexical'; const ImageComponent = React.lazy(() => import('./image-component')); interface ImagePayload { altText?: string key?: NodeKey src: string } const convertImageElement = (domNode: Node): null | DOMConversionOutput => { if (domNode instanceof HTMLImageElement) { const { alt: altText, src } = domNode; const node = $createImageNode({ altText, src }); return { node }; } return null; }; type SerializedImageNode = Spread< { altText: string src: string }, SerializedLexicalNode >; class ImageNode extends DecoratorNode { __src: string; __altText: string; static getType(): string { return 'image'; } static clone(node: ImageNode): ImageNode { return new ImageNode( node.__src, node.__altText, node.__key, ); } static importJSON(serializedNode: SerializedImageNode): ImageNode { const { altText, src } = serializedNode; const node = $createImageNode({ altText, src, }); return node; } exportDOM(): DOMExportOutput { const element = document.createElement('img'); element.setAttribute('src', this.__src); element.setAttribute('alt', this.__altText); return { element }; } static importDOM(): DOMConversionMap | null { return { img: (node: Node) => ({ conversion: convertImageElement, priority: 0, }), }; } constructor( src: string, altText: string, key?: NodeKey, ) { super(key); this.__src = src; this.__altText = altText; } exportJSON(): SerializedImageNode { return { altText: this.getAltText(), src: this.getSrc(), type: 'image', version: 1, }; } // View createDOM(config: EditorConfig): HTMLElement { const span = document.createElement('span'); const theme = config.theme; const className = theme.image; if (className !== undefined) { span.className = className; } return span; } updateDOM(): false { return false; } getSrc(): string { return this.__src; } getAltText(): string { return this.__altText; } decorate(): JSX.Element { return ( ); } } const $createImageNode = ({ altText = '', src, key, }: ImagePayload): ImageNode => { return $applyNodeReplacement( new ImageNode( src, altText, key, ), ); }; const $isImageNode = ( node: LexicalNode | null | undefined, ): node is ImageNode => node instanceof ImageNode; export { type ImagePayload, type SerializedImageNode, ImageNode, $createImageNode, $isImageNode, };