4 DOMConversionMap, DOMConversionOutput,
8 ParagraphNode, SerializedElementNode, Spread
10 import type {EditorConfig} from "lexical/LexicalEditor";
11 import type {RangeSelection} from "lexical/LexicalSelection";
13 export type CalloutCategory = 'info' | 'danger' | 'warning' | 'success';
15 export type SerializedCalloutNode = Spread<{
16 category: CalloutCategory;
17 }, SerializedElementNode>
19 export class Callout extends ElementNode {
21 __category: CalloutCategory = 'info';
27 static clone(node: Callout) {
28 return new Callout(node.__category, node.__key);
31 constructor(category: CalloutCategory, key?: string) {
33 this.__category = category;
36 createDOM(_config: EditorConfig, _editor: LexicalEditor) {
37 const element = document.createElement('p');
38 element.classList.add('callout', this.__category || '');
42 updateDOM(prevNode: unknown, dom: HTMLElement) {
43 // Returning false tells Lexical that this node does not need its
44 // DOM element replacing with a new copy from createDOM.
48 insertNewAfter(selection: RangeSelection, restoreSelection?: boolean): Callout|ParagraphNode {
49 const anchorOffset = selection ? selection.anchor.offset : 0;
50 const newElement = anchorOffset === this.getTextContentSize() || !selection
51 ? $createParagraphNode() : $createCalloutNode(this.__category);
53 newElement.setDirection(this.getDirection());
54 this.insertAfter(newElement, restoreSelection);
56 if (anchorOffset === 0 && !this.isEmpty() && selection) {
57 const paragraph = $createParagraphNode();
59 this.replace(paragraph, true);
65 static importDOM(): DOMConversionMap|null {
67 p(node: HTMLElement): DOMConversion|null {
68 if (node.classList.contains('callout')) {
70 conversion: (element: HTMLElement): DOMConversionOutput|null => {
71 let category: CalloutCategory = 'info';
72 const categories: CalloutCategory[] = ['info', 'success', 'warning', 'danger'];
74 for (const c of categories) {
75 if (element.classList.contains(c)) {
82 node: new Callout(category),
93 exportJSON(): SerializedCalloutNode {
95 ...super.exportJSON(),
98 category: this.__category,
102 static importJSON(serializedNode: SerializedCalloutNode): Callout {
103 return $createCalloutNode(serializedNode.category);
108 export function $createCalloutNode(category: CalloutCategory = 'info') {
109 return new Callout(category);
112 export function $isCalloutNode(node: LexicalNode | null | undefined) {
113 return node instanceof Callout;