-export type SerializedQuoteNode = SerializedElementNode;
-
-/** @noInheritDoc */
-export class QuoteNode extends ElementNode {
- static getType(): string {
- return 'quote';
- }
-
- static clone(node: QuoteNode): QuoteNode {
- return new QuoteNode(node.__key);
- }
-
- constructor(key?: NodeKey) {
- super(key);
- }
-
- // View
-
- createDOM(config: EditorConfig): HTMLElement {
- const element = document.createElement('blockquote');
- addClassNamesToElement(element, config.theme.quote);
- return element;
- }
- updateDOM(prevNode: QuoteNode, dom: HTMLElement): boolean {
- return false;
- }
-
- static importDOM(): DOMConversionMap | null {
- return {
- blockquote: (node: Node) => ({
- conversion: $convertBlockquoteElement,
- priority: 0,
- }),
- };
- }
-
- exportDOM(editor: LexicalEditor): DOMExportOutput {
- const {element} = super.exportDOM(editor);
-
- if (element && isHTMLElement(element)) {
- if (this.isEmpty()) {
- element.append(document.createElement('br'));
- }
- }
-
- return {
- element,
- };
- }
-
- static importJSON(serializedNode: SerializedQuoteNode): QuoteNode {
- const node = $createQuoteNode();
- return node;
- }
-
- exportJSON(): SerializedElementNode {
- return {
- ...super.exportJSON(),
- type: 'quote',
- };
- }
-
- // Mutation
-
- insertNewAfter(_: RangeSelection, restoreSelection?: boolean): ParagraphNode {
- const newBlock = $createParagraphNode();
- const direction = this.getDirection();
- newBlock.setDirection(direction);
- this.insertAfter(newBlock, restoreSelection);
- return newBlock;
- }
-
- collapseAtStart(): true {
- const paragraph = $createParagraphNode();
- const children = this.getChildren();
- children.forEach((child) => paragraph.append(child));
- this.replace(paragraph);
- return true;
- }
-
- canMergeWhenEmpty(): true {
- return true;
- }
-}
-
-export function $createQuoteNode(): QuoteNode {
- return $applyNodeReplacement(new QuoteNode());
-}
-
-export function $isQuoteNode(
- node: LexicalNode | null | undefined,
-): node is QuoteNode {
- return node instanceof QuoteNode;
-}
-
-export type HeadingTagType = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
-
-/** @noInheritDoc */
-export class HeadingNode extends ElementNode {
- /** @internal */
- __tag: HeadingTagType;
-
- static getType(): string {
- return 'heading';
- }
-
- static clone(node: HeadingNode): HeadingNode {
- return new HeadingNode(node.__tag, node.__key);
- }
-
- constructor(tag: HeadingTagType, key?: NodeKey) {
- super(key);
- this.__tag = tag;
- }
-
- getTag(): HeadingTagType {
- return this.__tag;
- }
-
- // View
-
- createDOM(config: EditorConfig): HTMLElement {
- const tag = this.__tag;
- const element = document.createElement(tag);
- const theme = config.theme;
- const classNames = theme.heading;
- if (classNames !== undefined) {
- const className = classNames[tag];
- addClassNamesToElement(element, className);
- }
- return element;
- }
-
- updateDOM(prevNode: HeadingNode, dom: HTMLElement): boolean {
- return false;
- }
-
- static importDOM(): DOMConversionMap | null {
- return {
- h1: (node: Node) => ({
- conversion: $convertHeadingElement,
- priority: 0,
- }),
- h2: (node: Node) => ({
- conversion: $convertHeadingElement,
- priority: 0,
- }),
- h3: (node: Node) => ({
- conversion: $convertHeadingElement,
- priority: 0,
- }),
- h4: (node: Node) => ({
- conversion: $convertHeadingElement,
- priority: 0,
- }),
- h5: (node: Node) => ({
- conversion: $convertHeadingElement,
- priority: 0,
- }),
- h6: (node: Node) => ({
- conversion: $convertHeadingElement,
- priority: 0,
- }),
- p: (node: Node) => {
- // domNode is a <p> since we matched it by nodeName
- const paragraph = node as HTMLParagraphElement;
- const firstChild = paragraph.firstChild;
- if (firstChild !== null && isGoogleDocsTitle(firstChild)) {
- return {
- conversion: () => ({node: null}),
- priority: 3,
- };
- }
- return null;
- },
- span: (node: Node) => {
- if (isGoogleDocsTitle(node)) {
- return {
- conversion: (domNode: Node) => {
- return {
- node: $createHeadingNode('h1'),
- };
- },
- priority: 3,
- };
- }
- return null;
- },
- };
- }
-
- exportDOM(editor: LexicalEditor): DOMExportOutput {
- const {element} = super.exportDOM(editor);
-
- if (element && isHTMLElement(element)) {
- if (this.isEmpty()) {
- element.append(document.createElement('br'));
- }
- }
-
- return {
- element,
- };
- }
-
- static importJSON(serializedNode: SerializedHeadingNode): HeadingNode {
- return $createHeadingNode(serializedNode.tag);
- }
-
- exportJSON(): SerializedHeadingNode {
- return {
- ...super.exportJSON(),
- tag: this.getTag(),
- type: 'heading',
- version: 1,
- };
- }
-
- // Mutation
- insertNewAfter(
- selection?: RangeSelection,
- restoreSelection = true,
- ): ParagraphNode | HeadingNode {
- const anchorOffet = selection ? selection.anchor.offset : 0;
- const lastDesc = this.getLastDescendant();
- const isAtEnd =
- !lastDesc ||
- (selection &&
- selection.anchor.key === lastDesc.getKey() &&
- anchorOffet === lastDesc.getTextContentSize());
- const newElement =
- isAtEnd || !selection
- ? $createParagraphNode()
- : $createHeadingNode(this.getTag());
- const direction = this.getDirection();
- newElement.setDirection(direction);
- this.insertAfter(newElement, restoreSelection);
- if (anchorOffet === 0 && !this.isEmpty() && selection) {
- const paragraph = $createParagraphNode();
- paragraph.select();
- this.replace(paragraph, true);
- }
- return newElement;
- }
-
- collapseAtStart(): true {
- const newElement = !this.isEmpty()
- ? $createHeadingNode(this.getTag())
- : $createParagraphNode();
- const children = this.getChildren();
- children.forEach((child) => newElement.append(child));
- this.replace(newElement);
- return true;
- }
-
- extractWithChild(): boolean {
- return true;
- }
-}