@mkljczk/lexical-remark
Version:
This package contains Markdown helpers and functionality for Lexical using remark-parse.
130 lines (111 loc) • 3.48 kB
text/typescript
/* eslint-disable @typescript-eslint/no-use-before-define */
import {
$createParagraphNode,
$isElementNode,
DOMConversionMap,
DOMConversionOutput,
DOMExportOutput,
EditorConfig,
ElementNode,
LexicalEditor,
LexicalNode,
RangeSelection,
SerializedElementNode,
} from 'lexical';
import { $isCollapsibleContainerNode } from '../container/node.js';
import { $isCollapsibleContentNode } from '../content/node.js';
type SerializedCollapsibleTitleNode = SerializedElementNode;
export function convertSummaryElement(domNode: HTMLElement): DOMConversionOutput | null {
const node = $createCollapsibleTitleNode();
return {
node,
};
}
/**
* A Lexical node to represent an HTML summary element
*/
export class CollapsibleTitleNode extends ElementNode {
static getType(): string {
return 'collapsible-title';
}
static clone(node: CollapsibleTitleNode): CollapsibleTitleNode {
return new CollapsibleTitleNode(node.__key);
}
createDOM(config: EditorConfig, editor: LexicalEditor): HTMLElement {
const dom = document.createElement('summary');
dom.classList.add('Collapsible__title');
return dom;
}
updateDOM(prevNode: CollapsibleTitleNode, dom: HTMLElement): boolean {
return false;
}
static importDOM(): DOMConversionMap | null {
return {
summary: (domNode: HTMLElement) => {
return {
conversion: convertSummaryElement,
priority: 1,
};
},
};
}
static importJSON(serializedNode: SerializedCollapsibleTitleNode): CollapsibleTitleNode {
return $createCollapsibleTitleNode();
}
exportDOM(): DOMExportOutput {
const element = document.createElement('summary');
return { element };
}
exportJSON(): SerializedCollapsibleTitleNode {
return {
...super.exportJSON(),
type: 'collapsible-title',
version: 1,
};
}
collapseAtStart(_selection: RangeSelection): boolean {
this.getParentOrThrow().insertBefore(this);
return true;
}
insertNewAfter(_: RangeSelection, restoreSelection = true): ElementNode {
const containerNode = this.getParentOrThrow();
if (!$isCollapsibleContainerNode(containerNode)) {
throw new Error('CollapsibleTitleNode expects to be child of CollapsibleContainerNode');
}
if (containerNode.getOpen()) {
const contentNode = this.getNextSibling();
if (!$isCollapsibleContentNode(contentNode)) {
throw new Error('CollapsibleTitleNode expects to have CollapsibleContentNode sibling');
}
const firstChild = contentNode.getFirstChild();
if ($isElementNode(firstChild)) {
return firstChild;
} else {
const paragraph = $createParagraphNode();
contentNode.append(paragraph);
return paragraph;
}
} else {
const paragraph = $createParagraphNode();
containerNode.insertAfter(paragraph, restoreSelection);
return paragraph;
}
}
}
/**
* Creates a Collapsible Title node
*
* @returns A Collapsible Title node
*/
export function $createCollapsibleTitleNode(): CollapsibleTitleNode {
return new CollapsibleTitleNode();
}
/**
* A typeguard function to assert on a Collapsible Title node
*
* @param node A Lexical node
* @returns true if the node is a Collapsible Title node, otherwise false
*/
export function $isCollapsibleTitleNode(node: LexicalNode | null | undefined): node is CollapsibleTitleNode {
return node instanceof CollapsibleTitleNode;
}