Lexical: Merged custom paragraph node, removed old format/indent refs
Start of work to merge custom nodes into lexical, removing old unused format/indent core logic while extending common block elements where possible.
This commit is contained in:
		
							parent
							
								
									5164375b18
								
							
						
					
					
						commit
						f3fa63a5ae
					
				| 
						 | 
				
			
			@ -355,7 +355,6 @@ function onSelectionChange(
 | 
			
		|||
              lastNode instanceof ParagraphNode &&
 | 
			
		||||
              lastNode.getChildrenSize() === 0
 | 
			
		||||
            ) {
 | 
			
		||||
              selection.format = lastNode.getTextFormat();
 | 
			
		||||
              selection.style = lastNode.getTextStyle();
 | 
			
		||||
            } else {
 | 
			
		||||
              selection.format = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -578,7 +577,6 @@ function onBeforeInput(event: InputEvent, editor: LexicalEditor): void {
 | 
			
		|||
          if ($isRangeSelection(selection)) {
 | 
			
		||||
            const anchorNode = selection.anchor.getNode();
 | 
			
		||||
            anchorNode.markDirty();
 | 
			
		||||
            selection.format = anchorNode.getFormat();
 | 
			
		||||
            invariant(
 | 
			
		||||
              $isTextNode(anchorNode),
 | 
			
		||||
              'Anchor node must be a TextNode',
 | 
			
		||||
| 
						 | 
				
			
			@ -912,7 +910,6 @@ function onCompositionStart(
 | 
			
		|||
        // need to invoke the empty space heuristic below.
 | 
			
		||||
        anchor.type === 'element' ||
 | 
			
		||||
        !selection.isCollapsed() ||
 | 
			
		||||
        node.getFormat() !== selection.format ||
 | 
			
		||||
        ($isTextNode(node) && node.getStyle() !== selection.style)
 | 
			
		||||
      ) {
 | 
			
		||||
        // We insert a zero width character, ready for the composition
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -96,15 +96,6 @@ function shouldUpdateTextNodeFromMutation(
 | 
			
		|||
  targetDOM: Node,
 | 
			
		||||
  targetNode: TextNode,
 | 
			
		||||
): boolean {
 | 
			
		||||
  if ($isRangeSelection(selection)) {
 | 
			
		||||
    const anchorNode = selection.anchor.getNode();
 | 
			
		||||
    if (
 | 
			
		||||
      anchorNode.is(targetNode) &&
 | 
			
		||||
      selection.format !== anchorNode.getFormat()
 | 
			
		||||
    ) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return targetDOM.nodeType === DOM_TEXT_TYPE && targetNode.isAttached();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,7 +17,6 @@ import type {NodeKey, NodeMap} from './LexicalNode';
 | 
			
		|||
import type {ElementNode} from './nodes/LexicalElementNode';
 | 
			
		||||
 | 
			
		||||
import invariant from 'lexical/shared/invariant';
 | 
			
		||||
import normalizeClassNames from 'lexical/shared/normalizeClassNames';
 | 
			
		||||
 | 
			
		||||
import {
 | 
			
		||||
  $isDecoratorNode,
 | 
			
		||||
| 
						 | 
				
			
			@ -117,51 +116,6 @@ function setTextAlign(domStyle: CSSStyleDeclaration, value: string): void {
 | 
			
		|||
  domStyle.setProperty('text-align', value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const DEFAULT_INDENT_VALUE = '40px';
 | 
			
		||||
 | 
			
		||||
function setElementIndent(dom: HTMLElement, indent: number): void {
 | 
			
		||||
  const indentClassName = activeEditorConfig.theme.indent;
 | 
			
		||||
 | 
			
		||||
  if (typeof indentClassName === 'string') {
 | 
			
		||||
    const elementHasClassName = dom.classList.contains(indentClassName);
 | 
			
		||||
 | 
			
		||||
    if (indent > 0 && !elementHasClassName) {
 | 
			
		||||
      dom.classList.add(indentClassName);
 | 
			
		||||
    } else if (indent < 1 && elementHasClassName) {
 | 
			
		||||
      dom.classList.remove(indentClassName);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const indentationBaseValue =
 | 
			
		||||
    getComputedStyle(dom).getPropertyValue('--lexical-indent-base-value') ||
 | 
			
		||||
    DEFAULT_INDENT_VALUE;
 | 
			
		||||
 | 
			
		||||
  dom.style.setProperty(
 | 
			
		||||
    'padding-inline-start',
 | 
			
		||||
    indent === 0 ? '' : `calc(${indent} * ${indentationBaseValue})`,
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function setElementFormat(dom: HTMLElement, format: number): void {
 | 
			
		||||
  const domStyle = dom.style;
 | 
			
		||||
 | 
			
		||||
  if (format === 0) {
 | 
			
		||||
    setTextAlign(domStyle, '');
 | 
			
		||||
  } else if (format === IS_ALIGN_LEFT) {
 | 
			
		||||
    setTextAlign(domStyle, 'left');
 | 
			
		||||
  } else if (format === IS_ALIGN_CENTER) {
 | 
			
		||||
    setTextAlign(domStyle, 'center');
 | 
			
		||||
  } else if (format === IS_ALIGN_RIGHT) {
 | 
			
		||||
    setTextAlign(domStyle, 'right');
 | 
			
		||||
  } else if (format === IS_ALIGN_JUSTIFY) {
 | 
			
		||||
    setTextAlign(domStyle, 'justify');
 | 
			
		||||
  } else if (format === IS_ALIGN_START) {
 | 
			
		||||
    setTextAlign(domStyle, 'start');
 | 
			
		||||
  } else if (format === IS_ALIGN_END) {
 | 
			
		||||
    setTextAlign(domStyle, 'end');
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function $createNode(
 | 
			
		||||
  key: NodeKey,
 | 
			
		||||
  parentDOM: null | HTMLElement,
 | 
			
		||||
| 
						 | 
				
			
			@ -185,22 +139,14 @@ function $createNode(
 | 
			
		|||
  }
 | 
			
		||||
 | 
			
		||||
  if ($isElementNode(node)) {
 | 
			
		||||
    const indent = node.__indent;
 | 
			
		||||
    const childrenSize = node.__size;
 | 
			
		||||
 | 
			
		||||
    if (indent !== 0) {
 | 
			
		||||
      setElementIndent(dom, indent);
 | 
			
		||||
    }
 | 
			
		||||
    if (childrenSize !== 0) {
 | 
			
		||||
      const endIndex = childrenSize - 1;
 | 
			
		||||
      const children = createChildrenArray(node, activeNextNodeMap);
 | 
			
		||||
      $createChildren(children, node, 0, endIndex, dom, null);
 | 
			
		||||
    }
 | 
			
		||||
    const format = node.__format;
 | 
			
		||||
 | 
			
		||||
    if (format !== 0) {
 | 
			
		||||
      setElementFormat(dom, format);
 | 
			
		||||
    }
 | 
			
		||||
    if (!node.isInline()) {
 | 
			
		||||
      reconcileElementTerminatingLineBreak(null, node, dom);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -349,10 +295,8 @@ function reconcileParagraphFormat(element: ElementNode): void {
 | 
			
		|||
  if (
 | 
			
		||||
    $isParagraphNode(element) &&
 | 
			
		||||
    subTreeTextFormat != null &&
 | 
			
		||||
    subTreeTextFormat !== element.__textFormat &&
 | 
			
		||||
    !activeEditorStateReadOnly
 | 
			
		||||
  ) {
 | 
			
		||||
    element.setTextFormat(subTreeTextFormat);
 | 
			
		||||
    element.setTextStyle(subTreeTextStyle);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -563,17 +507,6 @@ function $reconcileNode(
 | 
			
		|||
 | 
			
		||||
  if ($isElementNode(prevNode) && $isElementNode(nextNode)) {
 | 
			
		||||
    // Reconcile element children
 | 
			
		||||
    const nextIndent = nextNode.__indent;
 | 
			
		||||
 | 
			
		||||
    if (nextIndent !== prevNode.__indent) {
 | 
			
		||||
      setElementIndent(dom, nextIndent);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const nextFormat = nextNode.__format;
 | 
			
		||||
 | 
			
		||||
    if (nextFormat !== prevNode.__format) {
 | 
			
		||||
      setElementFormat(dom, nextFormat);
 | 
			
		||||
    }
 | 
			
		||||
    if (isDirty) {
 | 
			
		||||
      $reconcileChildrenWithDirection(prevNode, nextNode, dom);
 | 
			
		||||
      if (!$isRootNode(nextNode) && !nextNode.isInline()) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -129,8 +129,6 @@ export class TestElementNode extends ElementNode {
 | 
			
		|||
    serializedNode: SerializedTestElementNode,
 | 
			
		||||
  ): TestInlineElementNode {
 | 
			
		||||
    const node = $createTestInlineElementNode();
 | 
			
		||||
    node.setFormat(serializedNode.format);
 | 
			
		||||
    node.setIndent(serializedNode.indent);
 | 
			
		||||
    node.setDirection(serializedNode.direction);
 | 
			
		||||
    return node;
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -195,8 +193,6 @@ export class TestInlineElementNode extends ElementNode {
 | 
			
		|||
    serializedNode: SerializedTestInlineElementNode,
 | 
			
		||||
  ): TestInlineElementNode {
 | 
			
		||||
    const node = $createTestInlineElementNode();
 | 
			
		||||
    node.setFormat(serializedNode.format);
 | 
			
		||||
    node.setIndent(serializedNode.indent);
 | 
			
		||||
    node.setDirection(serializedNode.direction);
 | 
			
		||||
    return node;
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -241,8 +237,6 @@ export class TestShadowRootNode extends ElementNode {
 | 
			
		|||
    serializedNode: SerializedTestShadowRootNode,
 | 
			
		||||
  ): TestShadowRootNode {
 | 
			
		||||
    const node = $createTestShadowRootNode();
 | 
			
		||||
    node.setFormat(serializedNode.format);
 | 
			
		||||
    node.setIndent(serializedNode.indent);
 | 
			
		||||
    node.setDirection(serializedNode.direction);
 | 
			
		||||
    return node;
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -322,8 +316,6 @@ export class TestExcludeFromCopyElementNode extends ElementNode {
 | 
			
		|||
    serializedNode: SerializedTestExcludeFromCopyElementNode,
 | 
			
		||||
  ): TestExcludeFromCopyElementNode {
 | 
			
		||||
    const node = $createTestExcludeFromCopyElementNode();
 | 
			
		||||
    node.setFormat(serializedNode.format);
 | 
			
		||||
    node.setIndent(serializedNode.indent);
 | 
			
		||||
    node.setDirection(serializedNode.direction);
 | 
			
		||||
    return node;
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,54 @@
 | 
			
		|||
import {ElementNode} from "./LexicalElementNode";
 | 
			
		||||
import {CommonBlockAlignment, SerializedCommonBlockNode} from "../../../nodes/_common";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
export class CommonBlockNode extends ElementNode {
 | 
			
		||||
    __id: string = '';
 | 
			
		||||
    __alignment: CommonBlockAlignment = '';
 | 
			
		||||
    __inset: number = 0;
 | 
			
		||||
 | 
			
		||||
    setId(id: string) {
 | 
			
		||||
        const self = this.getWritable();
 | 
			
		||||
        self.__id = id;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    getId(): string {
 | 
			
		||||
        const self = this.getLatest();
 | 
			
		||||
        return self.__id;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    setAlignment(alignment: CommonBlockAlignment) {
 | 
			
		||||
        const self = this.getWritable();
 | 
			
		||||
        self.__alignment = alignment;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    getAlignment(): CommonBlockAlignment {
 | 
			
		||||
        const self = this.getLatest();
 | 
			
		||||
        return self.__alignment;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    setInset(size: number) {
 | 
			
		||||
        const self = this.getWritable();
 | 
			
		||||
        self.__inset = size;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    getInset(): number {
 | 
			
		||||
        const self = this.getLatest();
 | 
			
		||||
        return self.__inset;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    exportJSON(): SerializedCommonBlockNode {
 | 
			
		||||
        return {
 | 
			
		||||
            ...super.exportJSON(),
 | 
			
		||||
            id: this.__id,
 | 
			
		||||
            alignment: this.__alignment,
 | 
			
		||||
            inset: this.__inset,
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function copyCommonBlockProperties(from: CommonBlockNode, to: CommonBlockNode): void {
 | 
			
		||||
    to.__id = from.__id;
 | 
			
		||||
    to.__alignment = from.__alignment;
 | 
			
		||||
    to.__inset = from.__inset;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -42,8 +42,6 @@ export type SerializedElementNode<
 | 
			
		|||
  {
 | 
			
		||||
    children: Array<T>;
 | 
			
		||||
    direction: 'ltr' | 'rtl' | null;
 | 
			
		||||
    format: ElementFormatType;
 | 
			
		||||
    indent: number;
 | 
			
		||||
  },
 | 
			
		||||
  SerializedLexicalNode
 | 
			
		||||
>;
 | 
			
		||||
| 
						 | 
				
			
			@ -74,12 +72,8 @@ export class ElementNode extends LexicalNode {
 | 
			
		|||
  /** @internal */
 | 
			
		||||
  __size: number;
 | 
			
		||||
  /** @internal */
 | 
			
		||||
  __format: number;
 | 
			
		||||
  /** @internal */
 | 
			
		||||
  __style: string;
 | 
			
		||||
  /** @internal */
 | 
			
		||||
  __indent: number;
 | 
			
		||||
  /** @internal */
 | 
			
		||||
  __dir: 'ltr' | 'rtl' | null;
 | 
			
		||||
 | 
			
		||||
  constructor(key?: NodeKey) {
 | 
			
		||||
| 
						 | 
				
			
			@ -87,9 +81,7 @@ export class ElementNode extends LexicalNode {
 | 
			
		|||
    this.__first = null;
 | 
			
		||||
    this.__last = null;
 | 
			
		||||
    this.__size = 0;
 | 
			
		||||
    this.__format = 0;
 | 
			
		||||
    this.__style = '';
 | 
			
		||||
    this.__indent = 0;
 | 
			
		||||
    this.__dir = null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -98,28 +90,14 @@ export class ElementNode extends LexicalNode {
 | 
			
		|||
    this.__first = prevNode.__first;
 | 
			
		||||
    this.__last = prevNode.__last;
 | 
			
		||||
    this.__size = prevNode.__size;
 | 
			
		||||
    this.__indent = prevNode.__indent;
 | 
			
		||||
    this.__format = prevNode.__format;
 | 
			
		||||
    this.__style = prevNode.__style;
 | 
			
		||||
    this.__dir = prevNode.__dir;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getFormat(): number {
 | 
			
		||||
    const self = this.getLatest();
 | 
			
		||||
    return self.__format;
 | 
			
		||||
  }
 | 
			
		||||
  getFormatType(): ElementFormatType {
 | 
			
		||||
    const format = this.getFormat();
 | 
			
		||||
    return ELEMENT_FORMAT_TO_TYPE[format] || '';
 | 
			
		||||
  }
 | 
			
		||||
  getStyle(): string {
 | 
			
		||||
    const self = this.getLatest();
 | 
			
		||||
    return self.__style;
 | 
			
		||||
  }
 | 
			
		||||
  getIndent(): number {
 | 
			
		||||
    const self = this.getLatest();
 | 
			
		||||
    return self.__indent;
 | 
			
		||||
  }
 | 
			
		||||
  getChildren<T extends LexicalNode>(): Array<T> {
 | 
			
		||||
    const children: Array<T> = [];
 | 
			
		||||
    let child: T | null = this.getFirstChild();
 | 
			
		||||
| 
						 | 
				
			
			@ -301,13 +279,6 @@ export class ElementNode extends LexicalNode {
 | 
			
		|||
    const self = this.getLatest();
 | 
			
		||||
    return self.__dir;
 | 
			
		||||
  }
 | 
			
		||||
  hasFormat(type: ElementFormatType): boolean {
 | 
			
		||||
    if (type !== '') {
 | 
			
		||||
      const formatFlag = ELEMENT_TYPE_TO_FORMAT[type];
 | 
			
		||||
      return (this.getFormat() & formatFlag) !== 0;
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Mutators
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -378,21 +349,11 @@ export class ElementNode extends LexicalNode {
 | 
			
		|||
    self.__dir = direction;
 | 
			
		||||
    return self;
 | 
			
		||||
  }
 | 
			
		||||
  setFormat(type: ElementFormatType): this {
 | 
			
		||||
    const self = this.getWritable();
 | 
			
		||||
    self.__format = type !== '' ? ELEMENT_TYPE_TO_FORMAT[type] : 0;
 | 
			
		||||
    return this;
 | 
			
		||||
  }
 | 
			
		||||
  setStyle(style: string): this {
 | 
			
		||||
    const self = this.getWritable();
 | 
			
		||||
    self.__style = style || '';
 | 
			
		||||
    return this;
 | 
			
		||||
  }
 | 
			
		||||
  setIndent(indentLevel: number): this {
 | 
			
		||||
    const self = this.getWritable();
 | 
			
		||||
    self.__indent = indentLevel;
 | 
			
		||||
    return this;
 | 
			
		||||
  }
 | 
			
		||||
  splice(
 | 
			
		||||
    start: number,
 | 
			
		||||
    deleteCount: number,
 | 
			
		||||
| 
						 | 
				
			
			@ -528,8 +489,6 @@ export class ElementNode extends LexicalNode {
 | 
			
		|||
    return {
 | 
			
		||||
      children: [],
 | 
			
		||||
      direction: this.getDirection(),
 | 
			
		||||
      format: this.getFormatType(),
 | 
			
		||||
      indent: this.getIndent(),
 | 
			
		||||
      type: 'element',
 | 
			
		||||
      version: 1,
 | 
			
		||||
    };
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,39 +19,36 @@ import type {
 | 
			
		|||
  LexicalNode,
 | 
			
		||||
  NodeKey,
 | 
			
		||||
} from '../LexicalNode';
 | 
			
		||||
import type {
 | 
			
		||||
  ElementFormatType,
 | 
			
		||||
  SerializedElementNode,
 | 
			
		||||
} from './LexicalElementNode';
 | 
			
		||||
import type {RangeSelection} from 'lexical';
 | 
			
		||||
 | 
			
		||||
import {TEXT_TYPE_TO_FORMAT} from '../LexicalConstants';
 | 
			
		||||
import {
 | 
			
		||||
  $applyNodeReplacement,
 | 
			
		||||
  getCachedClassNameArray,
 | 
			
		||||
  isHTMLElement,
 | 
			
		||||
} from '../LexicalUtils';
 | 
			
		||||
import {ElementNode} from './LexicalElementNode';
 | 
			
		||||
import {$isTextNode, TextFormatType} from './LexicalTextNode';
 | 
			
		||||
import {$isTextNode} from './LexicalTextNode';
 | 
			
		||||
import {
 | 
			
		||||
  commonPropertiesDifferent, deserializeCommonBlockNode,
 | 
			
		||||
  SerializedCommonBlockNode, setCommonBlockPropsFromElement,
 | 
			
		||||
  updateElementWithCommonBlockProps
 | 
			
		||||
} from "../../../nodes/_common";
 | 
			
		||||
import {CommonBlockNode, copyCommonBlockProperties} from "lexical/nodes/CommonBlockNode";
 | 
			
		||||
 | 
			
		||||
export type SerializedParagraphNode = Spread<
 | 
			
		||||
  {
 | 
			
		||||
    textFormat: number;
 | 
			
		||||
    textStyle: string;
 | 
			
		||||
  },
 | 
			
		||||
  SerializedElementNode
 | 
			
		||||
  SerializedCommonBlockNode
 | 
			
		||||
>;
 | 
			
		||||
 | 
			
		||||
/** @noInheritDoc */
 | 
			
		||||
export class ParagraphNode extends ElementNode {
 | 
			
		||||
export class ParagraphNode extends CommonBlockNode {
 | 
			
		||||
  ['constructor']!: KlassConstructor<typeof ParagraphNode>;
 | 
			
		||||
  /** @internal */
 | 
			
		||||
  __textFormat: number;
 | 
			
		||||
  __textStyle: string;
 | 
			
		||||
 | 
			
		||||
  constructor(key?: NodeKey) {
 | 
			
		||||
    super(key);
 | 
			
		||||
    this.__textFormat = 0;
 | 
			
		||||
    this.__textStyle = '';
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -59,22 +56,6 @@ export class ParagraphNode extends ElementNode {
 | 
			
		|||
    return 'paragraph';
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getTextFormat(): number {
 | 
			
		||||
    const self = this.getLatest();
 | 
			
		||||
    return self.__textFormat;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  setTextFormat(type: number): this {
 | 
			
		||||
    const self = this.getWritable();
 | 
			
		||||
    self.__textFormat = type;
 | 
			
		||||
    return self;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  hasTextFormat(type: TextFormatType): boolean {
 | 
			
		||||
    const formatFlag = TEXT_TYPE_TO_FORMAT[type];
 | 
			
		||||
    return (this.getTextFormat() & formatFlag) !== 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getTextStyle(): string {
 | 
			
		||||
    const self = this.getLatest();
 | 
			
		||||
    return self.__textStyle;
 | 
			
		||||
| 
						 | 
				
			
			@ -92,8 +73,8 @@ export class ParagraphNode extends ElementNode {
 | 
			
		|||
 | 
			
		||||
  afterCloneFrom(prevNode: this) {
 | 
			
		||||
    super.afterCloneFrom(prevNode);
 | 
			
		||||
    this.__textFormat = prevNode.__textFormat;
 | 
			
		||||
    this.__textStyle = prevNode.__textStyle;
 | 
			
		||||
    copyCommonBlockProperties(prevNode, this);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // View
 | 
			
		||||
| 
						 | 
				
			
			@ -105,6 +86,9 @@ export class ParagraphNode extends ElementNode {
 | 
			
		|||
      const domClassList = dom.classList;
 | 
			
		||||
      domClassList.add(...classNames);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    updateElementWithCommonBlockProps(dom, this);
 | 
			
		||||
 | 
			
		||||
    return dom;
 | 
			
		||||
  }
 | 
			
		||||
  updateDOM(
 | 
			
		||||
| 
						 | 
				
			
			@ -112,7 +96,7 @@ export class ParagraphNode extends ElementNode {
 | 
			
		|||
    dom: HTMLElement,
 | 
			
		||||
    config: EditorConfig,
 | 
			
		||||
  ): boolean {
 | 
			
		||||
    return false;
 | 
			
		||||
    return commonPropertiesDifferent(prevNode, this);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static importDOM(): DOMConversionMap | null {
 | 
			
		||||
| 
						 | 
				
			
			@ -131,16 +115,6 @@ export class ParagraphNode extends ElementNode {
 | 
			
		|||
      if (this.isEmpty()) {
 | 
			
		||||
        element.append(document.createElement('br'));
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      const formatType = this.getFormatType();
 | 
			
		||||
      element.style.textAlign = formatType;
 | 
			
		||||
 | 
			
		||||
      const indent = this.getIndent();
 | 
			
		||||
      if (indent > 0) {
 | 
			
		||||
        // padding-inline-start is not widely supported in email HTML, but
 | 
			
		||||
        // Lexical Reconciler uses padding-inline-start. Using text-indent instead.
 | 
			
		||||
        element.style.textIndent = `${indent * 20}px`;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
| 
						 | 
				
			
			@ -150,16 +124,13 @@ export class ParagraphNode extends ElementNode {
 | 
			
		|||
 | 
			
		||||
  static importJSON(serializedNode: SerializedParagraphNode): ParagraphNode {
 | 
			
		||||
    const node = $createParagraphNode();
 | 
			
		||||
    node.setFormat(serializedNode.format);
 | 
			
		||||
    node.setIndent(serializedNode.indent);
 | 
			
		||||
    node.setTextFormat(serializedNode.textFormat);
 | 
			
		||||
    deserializeCommonBlockNode(serializedNode, node);
 | 
			
		||||
    return node;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  exportJSON(): SerializedParagraphNode {
 | 
			
		||||
    return {
 | 
			
		||||
      ...super.exportJSON(),
 | 
			
		||||
      textFormat: this.getTextFormat(),
 | 
			
		||||
      textStyle: this.getTextStyle(),
 | 
			
		||||
      type: 'paragraph',
 | 
			
		||||
      version: 1,
 | 
			
		||||
| 
						 | 
				
			
			@ -173,11 +144,9 @@ export class ParagraphNode extends ElementNode {
 | 
			
		|||
    restoreSelection: boolean,
 | 
			
		||||
  ): ParagraphNode {
 | 
			
		||||
    const newElement = $createParagraphNode();
 | 
			
		||||
    newElement.setTextFormat(rangeSelection.format);
 | 
			
		||||
    newElement.setTextStyle(rangeSelection.style);
 | 
			
		||||
    const direction = this.getDirection();
 | 
			
		||||
    newElement.setDirection(direction);
 | 
			
		||||
    newElement.setFormat(this.getFormatType());
 | 
			
		||||
    newElement.setStyle(this.getTextStyle());
 | 
			
		||||
    this.insertAfter(newElement, restoreSelection);
 | 
			
		||||
    return newElement;
 | 
			
		||||
| 
						 | 
				
			
			@ -210,13 +179,7 @@ export class ParagraphNode extends ElementNode {
 | 
			
		|||
 | 
			
		||||
function $convertParagraphElement(element: HTMLElement): DOMConversionOutput {
 | 
			
		||||
  const node = $createParagraphNode();
 | 
			
		||||
  if (element.style) {
 | 
			
		||||
    node.setFormat(element.style.textAlign as ElementFormatType);
 | 
			
		||||
    const indent = parseInt(element.style.textIndent, 10) / 20;
 | 
			
		||||
    if (indent > 0) {
 | 
			
		||||
      node.setIndent(indent);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  setCommonBlockPropsFromElement(element, node);
 | 
			
		||||
  return {node};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -99,8 +99,6 @@ export class RootNode extends ElementNode {
 | 
			
		|||
  static importJSON(serializedNode: SerializedRootNode): RootNode {
 | 
			
		||||
    // We don't create a root, and instead use the existing root.
 | 
			
		||||
    const node = $getRoot();
 | 
			
		||||
    node.setFormat(serializedNode.format);
 | 
			
		||||
    node.setIndent(serializedNode.indent);
 | 
			
		||||
    node.setDirection(serializedNode.direction);
 | 
			
		||||
    return node;
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -109,8 +107,6 @@ export class RootNode extends ElementNode {
 | 
			
		|||
    return {
 | 
			
		||||
      children: [],
 | 
			
		||||
      direction: this.getDirection(),
 | 
			
		||||
      format: this.getFormatType(),
 | 
			
		||||
      indent: this.getIndent(),
 | 
			
		||||
      type: 'root',
 | 
			
		||||
      version: 1,
 | 
			
		||||
    };
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -327,9 +327,6 @@ function wrapContinuousInlines(
 | 
			
		|||
  for (let i = 0; i < nodes.length; i++) {
 | 
			
		||||
    const node = nodes[i];
 | 
			
		||||
    if ($isBlockElementNode(node)) {
 | 
			
		||||
      if (textAlign && !node.getFormat()) {
 | 
			
		||||
        node.setFormat(textAlign);
 | 
			
		||||
      }
 | 
			
		||||
      out.push(node);
 | 
			
		||||
    } else {
 | 
			
		||||
      continuousInlines.push(node);
 | 
			
		||||
| 
						 | 
				
			
			@ -338,7 +335,6 @@ function wrapContinuousInlines(
 | 
			
		|||
        (i < nodes.length - 1 && $isBlockElementNode(nodes[i + 1]))
 | 
			
		||||
      ) {
 | 
			
		||||
        const wrapper = createWrapperFn();
 | 
			
		||||
        wrapper.setFormat(textAlign);
 | 
			
		||||
        wrapper.append(...continuousInlines);
 | 
			
		||||
        out.push(wrapper);
 | 
			
		||||
        continuousInlines = [];
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -162,8 +162,6 @@ export class LinkNode extends ElementNode {
 | 
			
		|||
      target: serializedNode.target,
 | 
			
		||||
      title: serializedNode.title,
 | 
			
		||||
    });
 | 
			
		||||
    node.setFormat(serializedNode.format);
 | 
			
		||||
    node.setIndent(serializedNode.indent);
 | 
			
		||||
    node.setDirection(serializedNode.direction);
 | 
			
		||||
    return node;
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -402,8 +400,6 @@ export class AutoLinkNode extends LinkNode {
 | 
			
		|||
      target: serializedNode.target,
 | 
			
		||||
      title: serializedNode.title,
 | 
			
		||||
    });
 | 
			
		||||
    node.setFormat(serializedNode.format);
 | 
			
		||||
    node.setIndent(serializedNode.indent);
 | 
			
		||||
    node.setDirection(serializedNode.direction);
 | 
			
		||||
    return node;
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -126,14 +126,12 @@ export class ListItemNode extends ElementNode {
 | 
			
		|||
    const node = $createListItemNode();
 | 
			
		||||
    node.setChecked(serializedNode.checked);
 | 
			
		||||
    node.setValue(serializedNode.value);
 | 
			
		||||
    node.setFormat(serializedNode.format);
 | 
			
		||||
    node.setDirection(serializedNode.direction);
 | 
			
		||||
    return node;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  exportDOM(editor: LexicalEditor): DOMExportOutput {
 | 
			
		||||
    const element = this.createDOM(editor._config);
 | 
			
		||||
    element.style.textAlign = this.getFormatType();
 | 
			
		||||
    return {
 | 
			
		||||
      element,
 | 
			
		||||
    };
 | 
			
		||||
| 
						 | 
				
			
			@ -172,7 +170,6 @@ export class ListItemNode extends ElementNode {
 | 
			
		|||
    if ($isListItemNode(replaceWithNode)) {
 | 
			
		||||
      return super.replace(replaceWithNode);
 | 
			
		||||
    }
 | 
			
		||||
    this.setIndent(0);
 | 
			
		||||
    const list = this.getParentOrThrow();
 | 
			
		||||
    if (!$isListNode(list)) {
 | 
			
		||||
      return replaceWithNode;
 | 
			
		||||
| 
						 | 
				
			
			@ -351,41 +348,6 @@ export class ListItemNode extends ElementNode {
 | 
			
		|||
    this.setChecked(!this.__checked);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getIndent(): number {
 | 
			
		||||
    // If we don't have a parent, we are likely serializing
 | 
			
		||||
    const parent = this.getParent();
 | 
			
		||||
    if (parent === null) {
 | 
			
		||||
      return this.getLatest().__indent;
 | 
			
		||||
    }
 | 
			
		||||
    // ListItemNode should always have a ListNode for a parent.
 | 
			
		||||
    let listNodeParent = parent.getParentOrThrow();
 | 
			
		||||
    let indentLevel = 0;
 | 
			
		||||
    while ($isListItemNode(listNodeParent)) {
 | 
			
		||||
      listNodeParent = listNodeParent.getParentOrThrow().getParentOrThrow();
 | 
			
		||||
      indentLevel++;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return indentLevel;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  setIndent(indent: number): this {
 | 
			
		||||
    invariant(typeof indent === 'number', 'Invalid indent value.');
 | 
			
		||||
    indent = Math.floor(indent);
 | 
			
		||||
    invariant(indent >= 0, 'Indent value must be non-negative.');
 | 
			
		||||
    let currentIndent = this.getIndent();
 | 
			
		||||
    while (currentIndent !== indent) {
 | 
			
		||||
      if (currentIndent < indent) {
 | 
			
		||||
        $handleIndent(this);
 | 
			
		||||
        currentIndent++;
 | 
			
		||||
      } else {
 | 
			
		||||
        $handleOutdent(this);
 | 
			
		||||
        currentIndent--;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /** @deprecated @internal */
 | 
			
		||||
  canInsertAfter(node: LexicalNode): boolean {
 | 
			
		||||
    return $isListItemNode(node);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -84,10 +84,6 @@ export function insertList(editor: LexicalEditor, listType: ListType): void {
 | 
			
		|||
          if ($isRootOrShadowRoot(anchorNodeParent)) {
 | 
			
		||||
            anchorNode.replace(list);
 | 
			
		||||
            const listItem = $createListItemNode();
 | 
			
		||||
            if ($isElementNode(anchorNode)) {
 | 
			
		||||
              listItem.setFormat(anchorNode.getFormatType());
 | 
			
		||||
              listItem.setIndent(anchorNode.getIndent());
 | 
			
		||||
            }
 | 
			
		||||
            list.append(listItem);
 | 
			
		||||
          } else if ($isListItemNode(anchorNode)) {
 | 
			
		||||
            const parent = anchorNode.getParentOrThrow();
 | 
			
		||||
| 
						 | 
				
			
			@ -157,8 +153,6 @@ function $createListOrMerge(node: ElementNode, listType: ListType): ListNode {
 | 
			
		|||
  const previousSibling = node.getPreviousSibling();
 | 
			
		||||
  const nextSibling = node.getNextSibling();
 | 
			
		||||
  const listItem = $createListItemNode();
 | 
			
		||||
  listItem.setFormat(node.getFormatType());
 | 
			
		||||
  listItem.setIndent(node.getIndent());
 | 
			
		||||
  append(listItem, node.getChildren());
 | 
			
		||||
 | 
			
		||||
  if (
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -155,9 +155,6 @@ export class QuoteNode extends ElementNode {
 | 
			
		|||
      if (this.isEmpty()) {
 | 
			
		||||
        element.append(document.createElement('br'));
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      const formatType = this.getFormatType();
 | 
			
		||||
      element.style.textAlign = formatType;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
| 
						 | 
				
			
			@ -167,8 +164,6 @@ export class QuoteNode extends ElementNode {
 | 
			
		|||
 | 
			
		||||
  static importJSON(serializedNode: SerializedQuoteNode): QuoteNode {
 | 
			
		||||
    const node = $createQuoteNode();
 | 
			
		||||
    node.setFormat(serializedNode.format);
 | 
			
		||||
    node.setIndent(serializedNode.indent);
 | 
			
		||||
    return node;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -315,9 +310,6 @@ export class HeadingNode extends ElementNode {
 | 
			
		|||
      if (this.isEmpty()) {
 | 
			
		||||
        element.append(document.createElement('br'));
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      const formatType = this.getFormatType();
 | 
			
		||||
      element.style.textAlign = formatType;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
| 
						 | 
				
			
			@ -326,10 +318,7 @@ export class HeadingNode extends ElementNode {
 | 
			
		|||
  }
 | 
			
		||||
 | 
			
		||||
  static importJSON(serializedNode: SerializedHeadingNode): HeadingNode {
 | 
			
		||||
    const node = $createHeadingNode(serializedNode.tag);
 | 
			
		||||
    node.setFormat(serializedNode.format);
 | 
			
		||||
    node.setIndent(serializedNode.indent);
 | 
			
		||||
    return node;
 | 
			
		||||
    return $createHeadingNode(serializedNode.tag);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  exportJSON(): SerializedHeadingNode {
 | 
			
		||||
| 
						 | 
				
			
			@ -402,18 +391,12 @@ function $convertHeadingElement(element: HTMLElement): DOMConversionOutput {
 | 
			
		|||
    nodeName === 'h6'
 | 
			
		||||
  ) {
 | 
			
		||||
    node = $createHeadingNode(nodeName);
 | 
			
		||||
    if (element.style !== null) {
 | 
			
		||||
      node.setFormat(element.style.textAlign as ElementFormatType);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return {node};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function $convertBlockquoteElement(element: HTMLElement): DOMConversionOutput {
 | 
			
		||||
  const node = $createQuoteNode();
 | 
			
		||||
  if (element.style !== null) {
 | 
			
		||||
    node.setFormat(element.style.textAlign as ElementFormatType);
 | 
			
		||||
  }
 | 
			
		||||
  return {node};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -651,9 +634,6 @@ export function registerRichText(editor: LexicalEditor): () => void {
 | 
			
		|||
            (parentNode): parentNode is ElementNode =>
 | 
			
		||||
              $isElementNode(parentNode) && !parentNode.isInline(),
 | 
			
		||||
          );
 | 
			
		||||
          if (element !== null) {
 | 
			
		||||
            element.setFormat(format);
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
      },
 | 
			
		||||
| 
						 | 
				
			
			@ -691,28 +671,6 @@ export function registerRichText(editor: LexicalEditor): () => void {
 | 
			
		|||
      },
 | 
			
		||||
      COMMAND_PRIORITY_EDITOR,
 | 
			
		||||
    ),
 | 
			
		||||
    editor.registerCommand(
 | 
			
		||||
      INDENT_CONTENT_COMMAND,
 | 
			
		||||
      () => {
 | 
			
		||||
        return $handleIndentAndOutdent((block) => {
 | 
			
		||||
          const indent = block.getIndent();
 | 
			
		||||
          block.setIndent(indent + 1);
 | 
			
		||||
        });
 | 
			
		||||
      },
 | 
			
		||||
      COMMAND_PRIORITY_EDITOR,
 | 
			
		||||
    ),
 | 
			
		||||
    editor.registerCommand(
 | 
			
		||||
      OUTDENT_CONTENT_COMMAND,
 | 
			
		||||
      () => {
 | 
			
		||||
        return $handleIndentAndOutdent((block) => {
 | 
			
		||||
          const indent = block.getIndent();
 | 
			
		||||
          if (indent > 0) {
 | 
			
		||||
            block.setIndent(indent - 1);
 | 
			
		||||
          }
 | 
			
		||||
        });
 | 
			
		||||
      },
 | 
			
		||||
      COMMAND_PRIORITY_EDITOR,
 | 
			
		||||
    ),
 | 
			
		||||
    editor.registerCommand<KeyboardEvent>(
 | 
			
		||||
      KEY_ARROW_UP_COMMAND,
 | 
			
		||||
      (event) => {
 | 
			
		||||
| 
						 | 
				
			
			@ -846,19 +804,7 @@ export function registerRichText(editor: LexicalEditor): () => void {
 | 
			
		|||
          return false;
 | 
			
		||||
        }
 | 
			
		||||
        event.preventDefault();
 | 
			
		||||
        const {anchor} = selection;
 | 
			
		||||
        const anchorNode = anchor.getNode();
 | 
			
		||||
 | 
			
		||||
        if (
 | 
			
		||||
          selection.isCollapsed() &&
 | 
			
		||||
          anchor.offset === 0 &&
 | 
			
		||||
          !$isRootNode(anchorNode)
 | 
			
		||||
        ) {
 | 
			
		||||
          const element = $getNearestBlockElementAncestorOrThrow(anchorNode);
 | 
			
		||||
          if (element.getIndent() > 0) {
 | 
			
		||||
            return editor.dispatchCommand(OUTDENT_CONTENT_COMMAND, undefined);
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        return editor.dispatchCommand(DELETE_CHARACTER_COMMAND, true);
 | 
			
		||||
      },
 | 
			
		||||
      COMMAND_PRIORITY_EDITOR,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -81,8 +81,6 @@ export function $setBlocksType(
 | 
			
		|||
    invariant($isElementNode(node), 'Expected block node to be an ElementNode');
 | 
			
		||||
 | 
			
		||||
    const targetElement = createElement();
 | 
			
		||||
    targetElement.setFormat(node.getFormatType());
 | 
			
		||||
    targetElement.setIndent(node.getIndent());
 | 
			
		||||
    node.replace(targetElement, true);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -136,8 +134,6 @@ export function $wrapNodes(
 | 
			
		|||
        : anchor.getNode();
 | 
			
		||||
    const children = target.getChildren();
 | 
			
		||||
    let element = createElement();
 | 
			
		||||
    element.setFormat(target.getFormatType());
 | 
			
		||||
    element.setIndent(target.getIndent());
 | 
			
		||||
    children.forEach((child) => element.append(child));
 | 
			
		||||
 | 
			
		||||
    if (wrappingElement) {
 | 
			
		||||
| 
						 | 
				
			
			@ -277,8 +273,6 @@ export function $wrapNodesImpl(
 | 
			
		|||
 | 
			
		||||
      if (elementMapping.get(parentKey) === undefined) {
 | 
			
		||||
        const targetElement = createElement();
 | 
			
		||||
        targetElement.setFormat(parent.getFormatType());
 | 
			
		||||
        targetElement.setIndent(parent.getIndent());
 | 
			
		||||
        elements.push(targetElement);
 | 
			
		||||
        elementMapping.set(parentKey, targetElement);
 | 
			
		||||
        // Move node and its siblings to the new
 | 
			
		||||
| 
						 | 
				
			
			@ -299,8 +293,6 @@ export function $wrapNodesImpl(
 | 
			
		|||
        'Expected node in emptyElements to be an ElementNode',
 | 
			
		||||
      );
 | 
			
		||||
      const targetElement = createElement();
 | 
			
		||||
      targetElement.setFormat(node.getFormatType());
 | 
			
		||||
      targetElement.setIndent(node.getIndent());
 | 
			
		||||
      elements.push(targetElement);
 | 
			
		||||
      node.remove(true);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,123 +0,0 @@
 | 
			
		|||
import {
 | 
			
		||||
    DOMConversion,
 | 
			
		||||
    DOMConversionMap,
 | 
			
		||||
    DOMConversionOutput,
 | 
			
		||||
    LexicalNode,
 | 
			
		||||
    ParagraphNode, SerializedParagraphNode, Spread,
 | 
			
		||||
} from "lexical";
 | 
			
		||||
import {EditorConfig} from "lexical/LexicalEditor";
 | 
			
		||||
import {
 | 
			
		||||
    CommonBlockAlignment, commonPropertiesDifferent, deserializeCommonBlockNode,
 | 
			
		||||
    SerializedCommonBlockNode,
 | 
			
		||||
    setCommonBlockPropsFromElement,
 | 
			
		||||
    updateElementWithCommonBlockProps
 | 
			
		||||
} from "./_common";
 | 
			
		||||
 | 
			
		||||
export type SerializedCustomParagraphNode = Spread<SerializedCommonBlockNode, SerializedParagraphNode>
 | 
			
		||||
 | 
			
		||||
export class CustomParagraphNode extends ParagraphNode {
 | 
			
		||||
    __id: string = '';
 | 
			
		||||
    __alignment: CommonBlockAlignment = '';
 | 
			
		||||
    __inset: number = 0;
 | 
			
		||||
 | 
			
		||||
    static getType() {
 | 
			
		||||
        return 'custom-paragraph';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    setId(id: string) {
 | 
			
		||||
        const self = this.getWritable();
 | 
			
		||||
        self.__id = id;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    getId(): string {
 | 
			
		||||
        const self = this.getLatest();
 | 
			
		||||
        return self.__id;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    setAlignment(alignment: CommonBlockAlignment) {
 | 
			
		||||
        const self = this.getWritable();
 | 
			
		||||
        self.__alignment = alignment;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    getAlignment(): CommonBlockAlignment {
 | 
			
		||||
        const self = this.getLatest();
 | 
			
		||||
        return self.__alignment;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    setInset(size: number) {
 | 
			
		||||
        const self = this.getWritable();
 | 
			
		||||
        self.__inset = size;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    getInset(): number {
 | 
			
		||||
        const self = this.getLatest();
 | 
			
		||||
        return self.__inset;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static clone(node: CustomParagraphNode): CustomParagraphNode {
 | 
			
		||||
        const newNode = new CustomParagraphNode(node.__key);
 | 
			
		||||
        newNode.__id = node.__id;
 | 
			
		||||
        newNode.__alignment = node.__alignment;
 | 
			
		||||
        newNode.__inset = node.__inset;
 | 
			
		||||
        return newNode;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    createDOM(config: EditorConfig): HTMLElement {
 | 
			
		||||
        const dom = super.createDOM(config);
 | 
			
		||||
        updateElementWithCommonBlockProps(dom, this);
 | 
			
		||||
        return dom;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    updateDOM(prevNode: CustomParagraphNode, dom: HTMLElement, config: EditorConfig): boolean {
 | 
			
		||||
        return super.updateDOM(prevNode, dom, config)
 | 
			
		||||
            || commonPropertiesDifferent(prevNode, this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    exportJSON(): SerializedCustomParagraphNode {
 | 
			
		||||
        return {
 | 
			
		||||
            ...super.exportJSON(),
 | 
			
		||||
            type: 'custom-paragraph',
 | 
			
		||||
            version: 1,
 | 
			
		||||
            id: this.__id,
 | 
			
		||||
            alignment: this.__alignment,
 | 
			
		||||
            inset: this.__inset,
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static importJSON(serializedNode: SerializedCustomParagraphNode): CustomParagraphNode {
 | 
			
		||||
        const node = $createCustomParagraphNode();
 | 
			
		||||
        deserializeCommonBlockNode(serializedNode, node);
 | 
			
		||||
        return node;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static importDOM(): DOMConversionMap|null {
 | 
			
		||||
        return {
 | 
			
		||||
            p(node: HTMLElement): DOMConversion|null {
 | 
			
		||||
                return {
 | 
			
		||||
                    conversion: (element: HTMLElement): DOMConversionOutput|null => {
 | 
			
		||||
                        const node = $createCustomParagraphNode();
 | 
			
		||||
                        if (element.style.textIndent) {
 | 
			
		||||
                            const indent = parseInt(element.style.textIndent, 10) / 20;
 | 
			
		||||
                            if (indent > 0) {
 | 
			
		||||
                                node.setIndent(indent);
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        setCommonBlockPropsFromElement(element, node);
 | 
			
		||||
 | 
			
		||||
                        return {node};
 | 
			
		||||
                    },
 | 
			
		||||
                    priority: 1,
 | 
			
		||||
                };
 | 
			
		||||
            },
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function $createCustomParagraphNode(): CustomParagraphNode {
 | 
			
		||||
    return new CustomParagraphNode();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function $isCustomParagraphNode(node: LexicalNode | null | undefined): node is CustomParagraphNode {
 | 
			
		||||
    return node instanceof CustomParagraphNode;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -7,7 +7,6 @@ import {
 | 
			
		|||
    LexicalNodeReplacement, NodeMutation,
 | 
			
		||||
    ParagraphNode
 | 
			
		||||
} from "lexical";
 | 
			
		||||
import {CustomParagraphNode} from "./custom-paragraph";
 | 
			
		||||
import {LinkNode} from "@lexical/link";
 | 
			
		||||
import {ImageNode} from "./image";
 | 
			
		||||
import {DetailsNode, SummaryNode} from "./details";
 | 
			
		||||
| 
						 | 
				
			
			@ -45,14 +44,8 @@ export function getNodesForPageEditor(): (KlassConstructor<typeof LexicalNode> |
 | 
			
		|||
        CodeBlockNode,
 | 
			
		||||
        DiagramNode,
 | 
			
		||||
        MediaNode, // TODO - Alignment
 | 
			
		||||
        CustomParagraphNode,
 | 
			
		||||
        ParagraphNode,
 | 
			
		||||
        LinkNode,
 | 
			
		||||
        {
 | 
			
		||||
            replace: ParagraphNode,
 | 
			
		||||
            with: (node: ParagraphNode) => {
 | 
			
		||||
                return new CustomParagraphNode();
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            replace: HeadingNode,
 | 
			
		||||
            with: (node: HeadingNode) => {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,5 @@
 | 
			
		|||
import {
 | 
			
		||||
    $createParagraphNode,
 | 
			
		||||
    $insertNodes,
 | 
			
		||||
    $isDecoratorNode, COMMAND_PRIORITY_HIGH, DROP_COMMAND,
 | 
			
		||||
    LexicalEditor,
 | 
			
		||||
| 
						 | 
				
			
			@ -8,7 +9,6 @@ import {$insertNewBlockNodesAtSelection, $selectSingleNode} from "../utils/selec
 | 
			
		|||
import {$getNearestBlockNodeForCoords, $htmlToBlockNodes} from "../utils/nodes";
 | 
			
		||||
import {Clipboard} from "../../services/clipboard";
 | 
			
		||||
import {$createImageNode} from "../nodes/image";
 | 
			
		||||
import {$createCustomParagraphNode} from "../nodes/custom-paragraph";
 | 
			
		||||
import {$createLinkNode} from "@lexical/link";
 | 
			
		||||
import {EditorImageData, uploadImageFile} from "../utils/images";
 | 
			
		||||
import {EditorUiContext} from "../ui/framework/core";
 | 
			
		||||
| 
						 | 
				
			
			@ -67,7 +67,7 @@ function handleMediaInsert(data: DataTransfer, context: EditorUiContext): boolea
 | 
			
		|||
        for (const imageFile of images) {
 | 
			
		||||
            const loadingImage = window.baseUrl('/loading.gif');
 | 
			
		||||
            const loadingNode = $createImageNode(loadingImage);
 | 
			
		||||
            const imageWrap = $createCustomParagraphNode();
 | 
			
		||||
            const imageWrap = $createParagraphNode();
 | 
			
		||||
            imageWrap.append(loadingNode);
 | 
			
		||||
            $insertNodes([imageWrap]);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,6 @@
 | 
			
		|||
import {EditorUiContext} from "../ui/framework/core";
 | 
			
		||||
import {
 | 
			
		||||
    $createParagraphNode,
 | 
			
		||||
    $getSelection,
 | 
			
		||||
    $isDecoratorNode,
 | 
			
		||||
    COMMAND_PRIORITY_LOW,
 | 
			
		||||
| 
						 | 
				
			
			@ -13,7 +14,6 @@ import {$isImageNode} from "../nodes/image";
 | 
			
		|||
import {$isMediaNode} from "../nodes/media";
 | 
			
		||||
import {getLastSelection} from "../utils/selection";
 | 
			
		||||
import {$getNearestNodeBlockParent} from "../utils/nodes";
 | 
			
		||||
import {$createCustomParagraphNode} from "../nodes/custom-paragraph";
 | 
			
		||||
import {$isCustomListItemNode} from "../nodes/custom-list-item";
 | 
			
		||||
import {$setInsetForSelection} from "../utils/lists";
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -45,7 +45,7 @@ function insertAfterSingleSelectedNode(editor: LexicalEditor, event: KeyboardEve
 | 
			
		|||
        if (nearestBlock) {
 | 
			
		||||
            requestAnimationFrame(() => {
 | 
			
		||||
                editor.update(() => {
 | 
			
		||||
                    const newParagraph = $createCustomParagraphNode();
 | 
			
		||||
                    const newParagraph = $createParagraphNode();
 | 
			
		||||
                    nearestBlock.insertAfter(newParagraph);
 | 
			
		||||
                    newParagraph.select();
 | 
			
		||||
                });
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,11 @@
 | 
			
		|||
 | 
			
		||||
## In progress
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
Reorg
 | 
			
		||||
  - Merge custom nodes into original nodes
 | 
			
		||||
    - Reduce down to use CommonBlockNode where possible
 | 
			
		||||
    - Remove existing formatType/ElementFormatType references (replaced with alignment).
 | 
			
		||||
    - Remove existing indent references (replaced with inset).
 | 
			
		||||
 | 
			
		||||
## Main Todo
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,13 @@
 | 
			
		|||
import {$isQuoteNode, HeadingNode, HeadingTagType} from "@lexical/rich-text";
 | 
			
		||||
import {$createTextNode, $getSelection, $insertNodes, LexicalEditor, LexicalNode} from "lexical";
 | 
			
		||||
import {
 | 
			
		||||
    $createParagraphNode,
 | 
			
		||||
    $createTextNode,
 | 
			
		||||
    $getSelection,
 | 
			
		||||
    $insertNodes,
 | 
			
		||||
    $isParagraphNode,
 | 
			
		||||
    LexicalEditor,
 | 
			
		||||
    LexicalNode
 | 
			
		||||
} from "lexical";
 | 
			
		||||
import {
 | 
			
		||||
    $getBlockElementNodesInSelection,
 | 
			
		||||
    $getNodeFromSelection,
 | 
			
		||||
| 
						 | 
				
			
			@ -8,7 +16,6 @@ import {
 | 
			
		|||
    getLastSelection
 | 
			
		||||
} from "./selection";
 | 
			
		||||
import {$createCustomHeadingNode, $isCustomHeadingNode} from "../nodes/custom-heading";
 | 
			
		||||
import {$createCustomParagraphNode, $isCustomParagraphNode} from "../nodes/custom-paragraph";
 | 
			
		||||
import {$createCustomQuoteNode} from "../nodes/custom-quote";
 | 
			
		||||
import {$createCodeBlockNode, $isCodeBlockNode, $openCodeEditorForNode, CodeBlockNode} from "../nodes/code-block";
 | 
			
		||||
import {$createCalloutNode, $isCalloutNode, CalloutCategory} from "../nodes/callout";
 | 
			
		||||
| 
						 | 
				
			
			@ -31,7 +38,7 @@ export function toggleSelectionAsHeading(editor: LexicalEditor, tag: HeadingTagT
 | 
			
		|||
 | 
			
		||||
export function toggleSelectionAsParagraph(editor: LexicalEditor) {
 | 
			
		||||
    editor.update(() => {
 | 
			
		||||
        $toggleSelectionBlockNodeType($isCustomParagraphNode, $createCustomParagraphNode);
 | 
			
		||||
        $toggleSelectionBlockNodeType($isParagraphNode, $createParagraphNode);
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,5 @@
 | 
			
		|||
import {
 | 
			
		||||
    $createParagraphNode,
 | 
			
		||||
    $getRoot,
 | 
			
		||||
    $isDecoratorNode,
 | 
			
		||||
    $isElementNode, $isRootNode,
 | 
			
		||||
| 
						 | 
				
			
			@ -8,7 +9,6 @@ import {
 | 
			
		|||
    LexicalNode
 | 
			
		||||
} from "lexical";
 | 
			
		||||
import {LexicalNodeMatcher} from "../nodes";
 | 
			
		||||
import {$createCustomParagraphNode} from "../nodes/custom-paragraph";
 | 
			
		||||
import {$generateNodesFromDOM} from "@lexical/html";
 | 
			
		||||
import {htmlToDom} from "./dom";
 | 
			
		||||
import {NodeHasAlignment, NodeHasInset} from "../nodes/_common";
 | 
			
		||||
| 
						 | 
				
			
			@ -17,7 +17,7 @@ import {$findMatchingParent} from "@lexical/utils";
 | 
			
		|||
function wrapTextNodes(nodes: LexicalNode[]): LexicalNode[] {
 | 
			
		||||
    return nodes.map(node => {
 | 
			
		||||
        if ($isTextNode(node)) {
 | 
			
		||||
            const paragraph = $createCustomParagraphNode();
 | 
			
		||||
            const paragraph = $createParagraphNode();
 | 
			
		||||
            paragraph.append(node);
 | 
			
		||||
            return paragraph;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,17 +7,15 @@ import {
 | 
			
		|||
    $isTextNode,
 | 
			
		||||
    $setSelection,
 | 
			
		||||
    BaseSelection, DecoratorNode,
 | 
			
		||||
    ElementFormatType,
 | 
			
		||||
    ElementNode, LexicalEditor,
 | 
			
		||||
    LexicalNode,
 | 
			
		||||
    TextFormatType, TextNode
 | 
			
		||||
} from "lexical";
 | 
			
		||||
import {$findMatchingParent, $getNearestBlockElementAncestorOrThrow} from "@lexical/utils";
 | 
			
		||||
import {$getNearestBlockElementAncestorOrThrow} from "@lexical/utils";
 | 
			
		||||
import {LexicalElementNodeCreator, LexicalNodeMatcher} from "../nodes";
 | 
			
		||||
import {$setBlocksType} from "@lexical/selection";
 | 
			
		||||
 | 
			
		||||
import {$getNearestNodeBlockParent, $getParentOfType, nodeHasAlignment} from "./nodes";
 | 
			
		||||
import {$createCustomParagraphNode} from "../nodes/custom-paragraph";
 | 
			
		||||
import {CommonBlockAlignment} from "../nodes/_common";
 | 
			
		||||
 | 
			
		||||
const lastSelectionByEditor = new WeakMap<LexicalEditor, BaseSelection|null>;
 | 
			
		||||
| 
						 | 
				
			
			@ -71,7 +69,7 @@ export function $toggleSelectionBlockNodeType(matcher: LexicalNodeMatcher, creat
 | 
			
		|||
    const selection = $getSelection();
 | 
			
		||||
    const blockElement = selection ? $getNearestBlockElementAncestorOrThrow(selection.getNodes()[0]) : null;
 | 
			
		||||
    if (selection && matcher(blockElement)) {
 | 
			
		||||
        $setBlocksType(selection, $createCustomParagraphNode);
 | 
			
		||||
        $setBlocksType(selection, $createParagraphNode);
 | 
			
		||||
    } else {
 | 
			
		||||
        $setBlocksType(selection, creator);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue