]> BookStack Code Mirror - bookstack/commitdiff
Lexical: Added custom alignment handling for blocks
authorDan Brown <redacted>
Sun, 18 Aug 2024 15:51:08 +0000 (16:51 +0100)
committerDan Brown <redacted>
Sun, 18 Aug 2024 15:51:08 +0000 (16:51 +0100)
To align with pre-existing use of alignment classes.

12 files changed:
resources/js/wysiwyg/nodes/_common.ts [new file with mode: 0644]
resources/js/wysiwyg/nodes/callout.ts
resources/js/wysiwyg/nodes/custom-heading.ts
resources/js/wysiwyg/nodes/custom-paragraph.ts
resources/js/wysiwyg/nodes/custom-quote.ts
resources/js/wysiwyg/nodes/custom-table-cell.ts
resources/js/wysiwyg/nodes/custom-table.ts
resources/js/wysiwyg/nodes/index.ts
resources/js/wysiwyg/todo.md
resources/js/wysiwyg/ui/defaults/buttons/alignments.ts
resources/js/wysiwyg/utils/nodes.ts
resources/sass/_content.scss

diff --git a/resources/js/wysiwyg/nodes/_common.ts b/resources/js/wysiwyg/nodes/_common.ts
new file mode 100644 (file)
index 0000000..cc45dc9
--- /dev/null
@@ -0,0 +1,66 @@
+import {LexicalNode, Spread} from "lexical";
+import type {SerializedElementNode} from "lexical/nodes/LexicalElementNode";
+
+export type CommonBlockAlignment = 'left' | 'right' | 'center' | 'justify' | '';
+const validAlignments: CommonBlockAlignment[] = ['left', 'right', 'center', 'justify'];
+
+export type SerializedCommonBlockNode = Spread<{
+    id: string;
+    alignment: CommonBlockAlignment;
+}, SerializedElementNode>
+
+export interface NodeHasAlignment {
+    readonly __alignment: CommonBlockAlignment;
+    setAlignment(alignment: CommonBlockAlignment): void;
+    getAlignment(): CommonBlockAlignment;
+}
+
+export interface NodeHasId {
+    readonly __id: string;
+    setId(id: string): void;
+    getId(): string;
+}
+
+interface CommonBlockInterface extends NodeHasId, NodeHasAlignment {}
+
+export function extractAlignmentFromElement(element: HTMLElement): CommonBlockAlignment {
+    const textAlignStyle: string = element.style.textAlign || '';
+    if (validAlignments.includes(textAlignStyle as CommonBlockAlignment)) {
+        return textAlignStyle as CommonBlockAlignment;
+    }
+
+    if (element.classList.contains('align-left')) {
+        return 'left';
+    } else if (element.classList.contains('align-right')) {
+        return 'right'
+    } else if (element.classList.contains('align-center')) {
+        return 'center'
+    } else if (element.classList.contains('align-justify')) {
+        return 'justify'
+    }
+
+    return '';
+}
+
+export function setCommonBlockPropsFromElement(element: HTMLElement, node: CommonBlockInterface): void {
+    if (element.id) {
+        node.setId(element.id);
+    }
+
+    node.setAlignment(extractAlignmentFromElement(element));
+}
+
+export function commonPropertiesDifferent(nodeA: CommonBlockInterface, nodeB: CommonBlockInterface): boolean {
+    return nodeA.__id !== nodeB.__id ||
+        nodeA.__alignment !== nodeB.__alignment;
+}
+
+export function updateElementWithCommonBlockProps(element: HTMLElement, node: CommonBlockInterface): void {
+    if (node.__id) {
+        element.setAttribute('id', node.__id);
+    }
+
+    if (node.__alignment) {
+        element.classList.add('align-' + node.__alignment);
+    }
+}
\ No newline at end of file
index b720b5c43ce91c123da63c5ca7f89937eb1e5296..8018190c8a78a00e6223d07a570c2c4f8bb8192b 100644 (file)
@@ -5,22 +5,27 @@ import {
     ElementNode,
     LexicalEditor,
     LexicalNode,
-    ParagraphNode, SerializedElementNode, Spread
+    ParagraphNode, Spread
 } from 'lexical';
 import type {EditorConfig} from "lexical/LexicalEditor";
 import type {RangeSelection} from "lexical/LexicalSelection";
-import {el} from "../utils/dom";
+import {
+    CommonBlockAlignment, commonPropertiesDifferent,
+    SerializedCommonBlockNode,
+    setCommonBlockPropsFromElement,
+    updateElementWithCommonBlockProps
+} from "./_common";
 
 export type CalloutCategory = 'info' | 'danger' | 'warning' | 'success';
 
 export type SerializedCalloutNode = Spread<{
     category: CalloutCategory;
-    id: string;
-}, SerializedElementNode>
+}, SerializedCommonBlockNode>
 
 export class CalloutNode extends ElementNode {
     __id: string = '';
     __category: CalloutCategory = 'info';
+    __alignment: CommonBlockAlignment = '';
 
     static getType() {
         return 'callout';
@@ -57,19 +62,26 @@ export class CalloutNode extends ElementNode {
         return self.__id;
     }
 
+    setAlignment(alignment: CommonBlockAlignment) {
+        const self = this.getWritable();
+        self.__alignment = alignment;
+    }
+
+    getAlignment(): CommonBlockAlignment {
+        const self = this.getLatest();
+        return self.__alignment;
+    }
+
     createDOM(_config: EditorConfig, _editor: LexicalEditor) {
         const element = document.createElement('p');
         element.classList.add('callout', this.__category || '');
-        if (this.__id) {
-            element.setAttribute('id', this.__id);
-        }
+        updateElementWithCommonBlockProps(element, this);
         return element;
     }
 
-    updateDOM(prevNode: unknown, dom: HTMLElement) {
-        // Returning false tells Lexical that this node does not need its
-        // DOM element replacing with a new copy from createDOM.
-        return false;
+    updateDOM(prevNode: CalloutNode): boolean {
+        return prevNode.__category !== this.__category ||
+            commonPropertiesDifferent(prevNode, this);
     }
 
     insertNewAfter(selection: RangeSelection, restoreSelection?: boolean): CalloutNode|ParagraphNode {
@@ -106,9 +118,7 @@ export class CalloutNode extends ElementNode {
                             }
 
                             const node = new CalloutNode(category);
-                            if (element.id) {
-                                node.setId(element.id);
-                            }
+                            setCommonBlockPropsFromElement(element, node);
 
                             return {
                                 node,
@@ -129,12 +139,14 @@ export class CalloutNode extends ElementNode {
             version: 1,
             category: this.__category,
             id: this.__id,
+            alignment: this.__alignment,
         };
     }
 
     static importJSON(serializedNode: SerializedCalloutNode): CalloutNode {
         const node = $createCalloutNode(serializedNode.category);
         node.setId(serializedNode.id);
+        node.setAlignment(serializedNode.alignment);
         return node;
     }
 
index f069ff16048bd84ff08cf4e0ca74b57593848aba..885622ad338b2a71fe092865533a6b2fbee27a60 100644 (file)
@@ -1,19 +1,24 @@
 import {
     DOMConversionMap,
-    DOMConversionOutput, ElementFormatType,
+    DOMConversionOutput,
     LexicalNode,
     Spread
 } from "lexical";
 import {EditorConfig} from "lexical/LexicalEditor";
 import {HeadingNode, HeadingTagType, SerializedHeadingNode} from "@lexical/rich-text";
+import {
+    CommonBlockAlignment, commonPropertiesDifferent,
+    SerializedCommonBlockNode,
+    setCommonBlockPropsFromElement,
+    updateElementWithCommonBlockProps
+} from "./_common";
 
 
-export type SerializedCustomHeadingNode = Spread<{
-    id: string;
-}, SerializedHeadingNode>
+export type SerializedCustomHeadingNode = Spread<SerializedCommonBlockNode, SerializedHeadingNode>
 
 export class CustomHeadingNode extends HeadingNode {
     __id: string = '';
+    __alignment: CommonBlockAlignment = '';
 
     static getType() {
         return 'custom-heading';
@@ -29,31 +34,47 @@ export class CustomHeadingNode extends HeadingNode {
         return self.__id;
     }
 
+    setAlignment(alignment: CommonBlockAlignment) {
+        const self = this.getWritable();
+        self.__alignment = alignment;
+    }
+
+    getAlignment(): CommonBlockAlignment {
+        const self = this.getLatest();
+        return self.__alignment;
+    }
+
     static clone(node: CustomHeadingNode) {
-        return new CustomHeadingNode(node.__tag, node.__key);
+        const newNode = new CustomHeadingNode(node.__tag, node.__key);
+        newNode.__alignment = node.__alignment;
+        return newNode;
     }
 
     createDOM(config: EditorConfig): HTMLElement {
         const dom = super.createDOM(config);
-        if (this.__id) {
-            dom.setAttribute('id', this.__id);
-        }
-
+        updateElementWithCommonBlockProps(dom, this);
         return dom;
     }
 
+    updateDOM(prevNode: CustomHeadingNode, dom: HTMLElement): boolean {
+        return super.updateDOM(prevNode, dom)
+            || commonPropertiesDifferent(prevNode, this);
+    }
+
     exportJSON(): SerializedCustomHeadingNode {
         return {
             ...super.exportJSON(),
             type: 'custom-heading',
             version: 1,
             id: this.__id,
+            alignment: this.__alignment,
         };
     }
 
     static importJSON(serializedNode: SerializedCustomHeadingNode): CustomHeadingNode {
         const node = $createCustomHeadingNode(serializedNode.tag);
         node.setId(serializedNode.id);
+        node.setAlignment(serializedNode.alignment);
         return node;
     }
 
@@ -99,12 +120,7 @@ function $convertHeadingElement(element: HTMLElement): DOMConversionOutput {
         nodeName === 'h6'
     ) {
         node = $createCustomHeadingNode(nodeName);
-        if (element.style !== null) {
-            node.setFormat(element.style.textAlign as ElementFormatType);
-        }
-        if (element.id) {
-            node.setId(element.id);
-        }
+        setCommonBlockPropsFromElement(element, node);
     }
     return {node};
 }
index cb936a5599b3dfe11c86b5cbdf72d9853d392ef2..663f32dfc687234537d7140019e9bd7dc537cc22 100644 (file)
@@ -1,21 +1,23 @@
 import {
     DOMConversion,
     DOMConversionMap,
-    DOMConversionOutput, ElementFormatType,
+    DOMConversionOutput,
     LexicalNode,
-    ParagraphNode,
-    SerializedParagraphNode,
-    Spread
+    ParagraphNode, SerializedParagraphNode, Spread,
 } from "lexical";
 import {EditorConfig} from "lexical/LexicalEditor";
+import {
+    CommonBlockAlignment, commonPropertiesDifferent,
+    SerializedCommonBlockNode,
+    setCommonBlockPropsFromElement,
+    updateElementWithCommonBlockProps
+} from "./_common";
 
-
-export type SerializedCustomParagraphNode = Spread<{
-    id: string;
-}, SerializedParagraphNode>
+export type SerializedCustomParagraphNode = Spread<SerializedCommonBlockNode, SerializedParagraphNode>
 
 export class CustomParagraphNode extends ParagraphNode {
     __id: string = '';
+    __alignment: CommonBlockAlignment = '';
 
     static getType() {
         return 'custom-paragraph';
@@ -31,33 +33,48 @@ export class CustomParagraphNode extends ParagraphNode {
         return self.__id;
     }
 
+    setAlignment(alignment: CommonBlockAlignment) {
+        const self = this.getWritable();
+        self.__alignment = alignment;
+    }
+
+    getAlignment(): CommonBlockAlignment {
+        const self = this.getLatest();
+        return self.__alignment;
+    }
+
     static clone(node: CustomParagraphNode): CustomParagraphNode {
         const newNode = new CustomParagraphNode(node.__key);
         newNode.__id = node.__id;
+        newNode.__alignment = node.__alignment;
         return newNode;
     }
 
     createDOM(config: EditorConfig): HTMLElement {
         const dom = super.createDOM(config);
-        if (this.__id) {
-            dom.setAttribute('id', this.__id);
-        }
-
+        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,
         };
     }
 
     static importJSON(serializedNode: SerializedCustomParagraphNode): CustomParagraphNode {
         const node = $createCustomParagraphNode();
         node.setId(serializedNode.id);
+        node.setAlignment(serializedNode.alignment);
         return node;
     }
 
@@ -67,17 +84,14 @@ export class CustomParagraphNode extends ParagraphNode {
                 return {
                     conversion: (element: HTMLElement): DOMConversionOutput|null => {
                         const node = $createCustomParagraphNode();
-                        if (element.style) {
-                            node.setFormat(element.style.textAlign as ElementFormatType);
+                        if (element.style.textIndent) {
                             const indent = parseInt(element.style.textIndent, 10) / 20;
                             if (indent > 0) {
                                 node.setIndent(indent);
                             }
                         }
 
-                        if (element.id) {
-                            node.setId(element.id);
-                        }
+                        setCommonBlockPropsFromElement(element, node);
 
                         return {node};
                     },
index 58c62f76919ee87b82f2d9a7a311099f61cd7885..cee289dbe72e806c73778c4ab44ceb200b60cf3d 100644 (file)
@@ -1,19 +1,24 @@
 import {
     DOMConversionMap,
-    DOMConversionOutput, ElementFormatType,
+    DOMConversionOutput,
     LexicalNode,
     Spread
 } from "lexical";
 import {EditorConfig} from "lexical/LexicalEditor";
 import {QuoteNode, SerializedQuoteNode} from "@lexical/rich-text";
+import {
+    CommonBlockAlignment, commonPropertiesDifferent,
+    SerializedCommonBlockNode,
+    setCommonBlockPropsFromElement,
+    updateElementWithCommonBlockProps
+} from "./_common";
 
 
-export type SerializedCustomQuoteNode = Spread<{
-    id: string;
-}, SerializedQuoteNode>
+export type SerializedCustomQuoteNode = Spread<SerializedCommonBlockNode, SerializedQuoteNode>
 
 export class CustomQuoteNode extends QuoteNode {
     __id: string = '';
+    __alignment: CommonBlockAlignment = '';
 
     static getType() {
         return 'custom-quote';
@@ -29,33 +34,47 @@ export class CustomQuoteNode extends QuoteNode {
         return self.__id;
     }
 
+    setAlignment(alignment: CommonBlockAlignment) {
+        const self = this.getWritable();
+        self.__alignment = alignment;
+    }
+
+    getAlignment(): CommonBlockAlignment {
+        const self = this.getLatest();
+        return self.__alignment;
+    }
+
     static clone(node: CustomQuoteNode) {
         const newNode = new CustomQuoteNode(node.__key);
         newNode.__id = node.__id;
+        newNode.__alignment = node.__alignment;
         return newNode;
     }
 
     createDOM(config: EditorConfig): HTMLElement {
         const dom = super.createDOM(config);
-        if (this.__id) {
-            dom.setAttribute('id', this.__id);
-        }
-
+        updateElementWithCommonBlockProps(dom, this);
         return dom;
     }
 
+    updateDOM(prevNode: CustomQuoteNode): boolean {
+        return commonPropertiesDifferent(prevNode, this);
+    }
+
     exportJSON(): SerializedCustomQuoteNode {
         return {
             ...super.exportJSON(),
             type: 'custom-quote',
             version: 1,
             id: this.__id,
+            alignment: this.__alignment,
         };
     }
 
     static importJSON(serializedNode: SerializedCustomQuoteNode): CustomQuoteNode {
         const node = $createCustomQuoteNode();
         node.setId(serializedNode.id);
+        node.setAlignment(serializedNode.alignment);
         return node;
     }
 
@@ -71,12 +90,7 @@ export class CustomQuoteNode extends QuoteNode {
 
 function $convertBlockquoteElement(element: HTMLElement): DOMConversionOutput {
     const node = $createCustomQuoteNode();
-    if (element.style !== null) {
-        node.setFormat(element.style.textAlign as ElementFormatType);
-    }
-    if (element.id) {
-        node.setId(element.id);
-    }
+    setCommonBlockPropsFromElement(element, node);
     return {node};
 }
 
index c8fe58c772d4d76975f96625ea852a653ee3948e..15c305dcb0fd6f35078d1ff181d216b5044444e3 100644 (file)
@@ -21,13 +21,16 @@ import {
 } from "@lexical/table";
 import {TableCellHeaderState} from "@lexical/table/LexicalTableCellNode";
 import {extractStyleMapFromElement, StyleMap} from "../utils/dom";
+import {CommonBlockAlignment, extractAlignmentFromElement} from "./_common";
 
 export type SerializedCustomTableCellNode = Spread<{
-    styles: Record<string, string>,
+    styles: Record<string, string>;
+    alignment: CommonBlockAlignment;
 }, SerializedTableCellNode>
 
 export class CustomTableCellNode extends TableCellNode {
     __styles: StyleMap = new Map;
+    __alignment: CommonBlockAlignment = '';
 
     static getType(): string {
         return 'custom-table-cell';
@@ -42,6 +45,7 @@ export class CustomTableCellNode extends TableCellNode {
         );
         cellNode.__rowSpan = node.__rowSpan;
         cellNode.__styles = new Map(node.__styles);
+        cellNode.__alignment = node.__alignment;
         return cellNode;
     }
 
@@ -60,6 +64,16 @@ export class CustomTableCellNode extends TableCellNode {
         self.__styles = new Map(styles);
     }
 
+    setAlignment(alignment: CommonBlockAlignment) {
+        const self = this.getWritable();
+        self.__alignment = alignment;
+    }
+
+    getAlignment(): CommonBlockAlignment {
+        const self = this.getLatest();
+        return self.__alignment;
+    }
+
     updateTag(tag: string): void {
         const isHeader = tag.toLowerCase() === 'th';
         const state = isHeader ? TableCellHeaderStates.ROW : TableCellHeaderStates.NO_STATUS;
@@ -74,12 +88,17 @@ export class CustomTableCellNode extends TableCellNode {
             element.style.setProperty(name, value);
         }
 
+        if (this.__alignment) {
+            element.classList.add('align-' + this.__alignment);
+        }
+
         return element;
     }
 
     updateDOM(prevNode: CustomTableCellNode): boolean {
         return super.updateDOM(prevNode)
-            || this.__styles !== prevNode.__styles;
+            || this.__styles !== prevNode.__styles
+            || this.__alignment !== prevNode.__alignment;
     }
 
     static importDOM(): DOMConversionMap | null {
@@ -110,6 +129,7 @@ export class CustomTableCellNode extends TableCellNode {
         );
 
         node.setStyles(new Map(Object.entries(serializedNode.styles)));
+        node.setAlignment(serializedNode.alignment);
 
         return node;
     }
@@ -119,6 +139,7 @@ export class CustomTableCellNode extends TableCellNode {
             ...super.exportJSON(),
             type: 'custom-table-cell',
             styles: Object.fromEntries(this.__styles),
+            alignment: this.__alignment,
         };
     }
 }
@@ -128,6 +149,7 @@ function $convertCustomTableCellNodeElement(domNode: Node): DOMConversionOutput
 
     if (domNode instanceof HTMLElement && output.node instanceof CustomTableCellNode) {
         output.node.setStyles(extractStyleMapFromElement(domNode));
+        output.node.setAlignment(extractAlignmentFromElement(domNode));
     }
 
     return output;
index 1d95b789625e1b0ab48204cae062959fd7b8001a..b699763d97689351a463cdceef39ccf007ef9a83 100644 (file)
@@ -4,17 +4,23 @@ import {EditorConfig} from "lexical/LexicalEditor";
 
 import {el, extractStyleMapFromElement, StyleMap} from "../utils/dom";
 import {getTableColumnWidths} from "../utils/tables";
-
-export type SerializedCustomTableNode = Spread<{
-    id: string;
+import {
+    CommonBlockAlignment,
+    SerializedCommonBlockNode,
+    setCommonBlockPropsFromElement,
+    updateElementWithCommonBlockProps
+} from "./_common";
+
+export type SerializedCustomTableNode = Spread<Spread<{
     colWidths: string[];
     styles: Record<string, string>,
-}, SerializedTableNode>
+}, SerializedTableNode>, SerializedCommonBlockNode>
 
 export class CustomTableNode extends TableNode {
     __id: string = '';
     __colWidths: string[] = [];
     __styles: StyleMap = new Map;
+    __alignment: CommonBlockAlignment = '';
 
     static getType() {
         return 'custom-table';
@@ -30,6 +36,16 @@ export class CustomTableNode extends TableNode {
         return self.__id;
     }
 
+    setAlignment(alignment: CommonBlockAlignment) {
+        const self = this.getWritable();
+        self.__alignment = alignment;
+    }
+
+    getAlignment(): CommonBlockAlignment {
+        const self = this.getLatest();
+        return self.__alignment;
+    }
+
     setColWidths(widths: string[]) {
         const self = this.getWritable();
         self.__colWidths = widths;
@@ -55,15 +71,13 @@ export class CustomTableNode extends TableNode {
         newNode.__id = node.__id;
         newNode.__colWidths = node.__colWidths;
         newNode.__styles = new Map(node.__styles);
+        newNode.__alignment = node.__alignment;
         return newNode;
     }
 
     createDOM(config: EditorConfig): HTMLElement {
         const dom = super.createDOM(config);
-        const id = this.getId();
-        if (id) {
-            dom.setAttribute('id', id);
-        }
+        updateElementWithCommonBlockProps(dom, this);
 
         const colWidths = this.getColWidths();
         if (colWidths.length > 0) {
@@ -97,6 +111,7 @@ export class CustomTableNode extends TableNode {
             id: this.__id,
             colWidths: this.__colWidths,
             styles: Object.fromEntries(this.__styles),
+            alignment: this.__alignment,
         };
     }
 
@@ -105,6 +120,7 @@ export class CustomTableNode extends TableNode {
         node.setId(serializedNode.id);
         node.setColWidths(serializedNode.colWidths);
         node.setStyles(new Map(Object.entries(serializedNode.styles)));
+        node.setAlignment(serializedNode.alignment);
         return node;
     }
 
@@ -114,10 +130,7 @@ export class CustomTableNode extends TableNode {
                 return {
                     conversion: (element: HTMLElement): DOMConversionOutput|null => {
                         const node = $createCustomTableNode();
-
-                        if (element.id) {
-                            node.setId(element.id);
-                        }
+                        setCommonBlockPropsFromElement(element, node);
 
                         const colWidths = getTableColumnWidths(element as HTMLTableElement);
                         node.setColWidths(colWidths);
index 8cbec20dad21f58460fc638ee72b78c311c32068..b5483c5009cc613ca4bbc0113e20cbf700695f31 100644 (file)
@@ -35,17 +35,17 @@ export function getNodesForPageEditor(): (KlassConstructor<typeof LexicalNode> |
         CustomHeadingNode,
         CustomQuoteNode,
         CustomListNode,
-        CustomListItemNode,
+        CustomListItemNode, // TODO - Alignment?
         CustomTableNode,
         CustomTableRowNode,
         CustomTableCellNode,
-        ImageNode,
+        ImageNode, // TODO - Alignment
         HorizontalRuleNode,
         DetailsNode, SummaryNode,
         CodeBlockNode,
         DiagramNode,
-        MediaNode,
-        CustomParagraphNode, // TODO - ID
+        MediaNode, // TODO - Alignment
+        CustomParagraphNode,
         LinkNode,
         {
             replace: ParagraphNode,
index f3a8da404e695e59aea717dc3f841f9643640099..fec38271a06a971825fb87f689412bdaf2cc85ed 100644 (file)
@@ -6,7 +6,7 @@
 
 ## Main Todo
 
-- Alignments: Use existing classes for blocks (including table cells)
+
 - Alignments: Handle inline block content (image, video)
 - Image paste upload
 - Keyboard shortcuts support
index 40d9c89dce8c95cbdd3ba5b8c2e92201ddf473aa..78de3c9a243590de8d83ddf4f483003731b2df5d 100644 (file)
@@ -1,4 +1,4 @@
-import {$getSelection, BaseSelection, ElementFormatType} from "lexical";
+import {$getSelection, BaseSelection} from "lexical";
 import {EditorButtonDefinition} from "../../framework/buttons";
 import alignLeftIcon from "@icons/editor/align-left.svg";
 import {EditorUiContext} from "../../framework/core";
@@ -6,13 +6,17 @@ import alignCenterIcon from "@icons/editor/align-center.svg";
 import alignRightIcon from "@icons/editor/align-right.svg";
 import alignJustifyIcon from "@icons/editor/align-justify.svg";
 import {$getBlockElementNodesInSelection, $selectionContainsElementFormat} from "../../../utils/selection";
+import {CommonBlockAlignment} from "../../../nodes/_common";
+import {nodeHasAlignment} from "../../../utils/nodes";
 
 
-function setAlignmentForSection(alignment: ElementFormatType): void {
+function setAlignmentForSection(alignment: CommonBlockAlignment): void {
     const selection = $getSelection();
     const elements = $getBlockElementNodesInSelection(selection);
     for (const node of elements) {
-        node.setFormat(alignment);
+        if (nodeHasAlignment(node)) {
+            node.setAlignment(alignment)
+        }
     }
 }
 
index 6278186ca12614fcec9c5a8f2abb91ebf6204e01..e33cfda7ce6c1eb146ffdd4b92911114469dd920 100644 (file)
@@ -3,6 +3,7 @@ import {LexicalNodeMatcher} from "../nodes";
 import {$createCustomParagraphNode} from "../nodes/custom-paragraph";
 import {$generateNodesFromDOM} from "@lexical/html";
 import {htmlToDom} from "./dom";
+import {NodeHasAlignment} from "../nodes/_common";
 
 function wrapTextNodes(nodes: LexicalNode[]): LexicalNode[] {
     return nodes.map(node => {
@@ -70,4 +71,8 @@ export function $getNearestBlockNodeForCoords(editor: LexicalEditor, x: number,
     }
 
     return null;
+}
+
+export function nodeHasAlignment(node: object): node is NodeHasAlignment {
+    return '__alignment' in node;
 }
\ No newline at end of file
index 3aa4ac653d92da1db9eb5be4be90dd7e7a7ceeb1..b187d6408cc70b4c29f886af249160771a78e1c6 100644 (file)
@@ -32,6 +32,9 @@
     margin-left: auto;
     margin-right: auto;
   }
+  .align-justify {
+    text-align: justify;
+  }
   h1, h2, h3, h4, h5, h6, pre {
     clear: left;
   }