Lexical: Added direction support to extra blocks

Also removed duplicated dir functionality that remained in core.
This commit is contained in:
Dan Brown 2024-09-22 12:07:24 +01:00
parent e6edd9340e
commit 2add15bd72
No known key found for this signature in database
GPG Key ID: 46D9F943C24A2EF9
6 changed files with 40 additions and 28 deletions

View File

@ -135,10 +135,6 @@ export class ParagraphNode extends ElementNode {
const formatType = this.getFormatType(); const formatType = this.getFormatType();
element.style.textAlign = formatType; element.style.textAlign = formatType;
const direction = this.getDirection();
if (direction) {
element.dir = direction;
}
const indent = this.getIndent(); const indent = this.getIndent();
if (indent > 0) { if (indent > 0) {
// padding-inline-start is not widely supported in email HTML, but // padding-inline-start is not widely supported in email HTML, but
@ -156,7 +152,6 @@ export class ParagraphNode extends ElementNode {
const node = $createParagraphNode(); const node = $createParagraphNode();
node.setFormat(serializedNode.format); node.setFormat(serializedNode.format);
node.setIndent(serializedNode.indent); node.setIndent(serializedNode.indent);
node.setDirection(serializedNode.direction);
node.setTextFormat(serializedNode.textFormat); node.setTextFormat(serializedNode.textFormat);
return node; return node;
} }

View File

@ -158,11 +158,6 @@ export class QuoteNode extends ElementNode {
const formatType = this.getFormatType(); const formatType = this.getFormatType();
element.style.textAlign = formatType; element.style.textAlign = formatType;
const direction = this.getDirection();
if (direction) {
element.dir = direction;
}
} }
return { return {
@ -174,7 +169,6 @@ export class QuoteNode extends ElementNode {
const node = $createQuoteNode(); const node = $createQuoteNode();
node.setFormat(serializedNode.format); node.setFormat(serializedNode.format);
node.setIndent(serializedNode.indent); node.setIndent(serializedNode.indent);
node.setDirection(serializedNode.direction);
return node; return node;
} }
@ -324,11 +318,6 @@ export class HeadingNode extends ElementNode {
const formatType = this.getFormatType(); const formatType = this.getFormatType();
element.style.textAlign = formatType; element.style.textAlign = formatType;
const direction = this.getDirection();
if (direction) {
element.dir = direction;
}
} }
return { return {
@ -340,7 +329,6 @@ export class HeadingNode extends ElementNode {
const node = $createHeadingNode(serializedNode.tag); const node = $createHeadingNode(serializedNode.tag);
node.setFormat(serializedNode.format); node.setFormat(serializedNode.format);
node.setIndent(serializedNode.indent); node.setIndent(serializedNode.indent);
node.setDirection(serializedNode.direction);
return node; return node;
} }

View File

@ -63,7 +63,7 @@ export function extractInsetFromElement(element: HTMLElement): number {
return sizeToPixels(elemPadding); return sizeToPixels(elemPadding);
} }
function extractDirectionFromElement(element: HTMLElement): EditorNodeDirection { export function extractDirectionFromElement(element: HTMLElement): EditorNodeDirection {
const elemDir = (element.dir || '').toLowerCase(); const elemDir = (element.dir || '').toLowerCase();
if (elemDir === 'rtl' || elemDir === 'ltr') { if (elemDir === 'rtl' || elemDir === 'ltr') {
return elemDir; return elemDir;

View File

@ -1,12 +1,12 @@
import { import {
DOMConversionFn, DOMConversionFn,
DOMConversionMap, DOMConversionMap, EditorConfig,
LexicalNode, LexicalNode,
Spread Spread
} from "lexical"; } from "lexical";
import {EditorConfig} from "lexical/LexicalEditor";
import {$isListItemNode, ListItemNode, ListNode, ListType, SerializedListNode} from "@lexical/list"; import {$isListItemNode, ListItemNode, ListNode, ListType, SerializedListNode} from "@lexical/list";
import {$createCustomListItemNode} from "./custom-list-item"; import {$createCustomListItemNode} from "./custom-list-item";
import {extractDirectionFromElement} from "./_common";
export type SerializedCustomListNode = Spread<{ export type SerializedCustomListNode = Spread<{
@ -33,6 +33,7 @@ export class CustomListNode extends ListNode {
static clone(node: CustomListNode) { static clone(node: CustomListNode) {
const newNode = new CustomListNode(node.__listType, node.__start, node.__key); const newNode = new CustomListNode(node.__listType, node.__start, node.__key);
newNode.__id = node.__id; newNode.__id = node.__id;
newNode.__dir = node.__dir;
return newNode; return newNode;
} }
@ -42,9 +43,18 @@ export class CustomListNode extends ListNode {
dom.setAttribute('id', this.__id); dom.setAttribute('id', this.__id);
} }
if (this.__dir) {
dom.setAttribute('dir', this.__dir);
}
return dom; return dom;
} }
updateDOM(prevNode: ListNode, dom: HTMLElement, config: EditorConfig): boolean {
return super.updateDOM(prevNode, dom, config) ||
prevNode.__dir !== this.__dir;
}
exportJSON(): SerializedCustomListNode { exportJSON(): SerializedCustomListNode {
return { return {
...super.exportJSON(), ...super.exportJSON(),
@ -57,6 +67,7 @@ export class CustomListNode extends ListNode {
static importJSON(serializedNode: SerializedCustomListNode): CustomListNode { static importJSON(serializedNode: SerializedCustomListNode): CustomListNode {
const node = $createCustomListNode(serializedNode.listType); const node = $createCustomListNode(serializedNode.listType);
node.setId(serializedNode.id); node.setId(serializedNode.id);
node.setDirection(serializedNode.direction);
return node; return node;
} }
@ -69,6 +80,10 @@ export class CustomListNode extends ListNode {
(baseResult.node as CustomListNode).setId(element.id); (baseResult.node as CustomListNode).setId(element.id);
} }
if (element.dir && baseResult?.node) {
(baseResult.node as CustomListNode).setDirection(extractDirectionFromElement(element));
}
if (baseResult) { if (baseResult) {
baseResult.after = $normalizeChildren; baseResult.after = $normalizeChildren;
} }

View File

@ -5,10 +5,11 @@ import {
LexicalEditor, LexicalEditor,
LexicalNode, LexicalNode,
SerializedElementNode, Spread, SerializedElementNode, Spread,
EditorConfig,
} from 'lexical'; } from 'lexical';
import type {EditorConfig} from "lexical/LexicalEditor";
import {el} from "../utils/dom"; import {el} from "../utils/dom";
import {extractDirectionFromElement} from "./_common";
export type SerializedDetailsNode = Spread<{ export type SerializedDetailsNode = Spread<{
id: string; id: string;
@ -34,6 +35,7 @@ export class DetailsNode extends ElementNode {
static clone(node: DetailsNode): DetailsNode { static clone(node: DetailsNode): DetailsNode {
const newNode = new DetailsNode(node.__key); const newNode = new DetailsNode(node.__key);
newNode.__id = node.__id; newNode.__id = node.__id;
newNode.__dir = node.__dir;
return newNode; return newNode;
} }
@ -43,11 +45,16 @@ export class DetailsNode extends ElementNode {
el.setAttribute('id', this.__id); el.setAttribute('id', this.__id);
} }
if (this.__dir) {
el.setAttribute('dir', this.__dir);
}
return el; return el;
} }
updateDOM(prevNode: DetailsNode, dom: HTMLElement) { updateDOM(prevNode: DetailsNode, dom: HTMLElement) {
return prevNode.__id !== this.__id; return prevNode.__id !== this.__id
|| prevNode.__dir !== this.__dir;
} }
static importDOM(): DOMConversionMap|null { static importDOM(): DOMConversionMap|null {
@ -60,6 +67,10 @@ export class DetailsNode extends ElementNode {
node.setId(element.id); node.setId(element.id);
} }
if (element.dir) {
node.setDirection(extractDirectionFromElement(element));
}
return {node}; return {node};
}, },
priority: 3, priority: 3,
@ -80,6 +91,7 @@ export class DetailsNode extends ElementNode {
static importJSON(serializedNode: SerializedDetailsNode): DetailsNode { static importJSON(serializedNode: SerializedDetailsNode): DetailsNode {
const node = $createDetailsNode(); const node = $createDetailsNode();
node.setId(serializedNode.id); node.setId(serializedNode.id);
node.setDirection(serializedNode.direction);
return node; return node;
} }

View File

@ -2,16 +2,14 @@
## In progress ## In progress
- RTL/LTR support //
- Basic implementation added
- Test across main range of content blocks
- Test that HTML is being set as expected
- Test editor defaults when between RTL/LTR modes
## Main Todo ## Main Todo
- Mac: Shortcut support via command. - Mac: Shortcut support via command.
- Translations - Translations
- Form closing on submit
- Update toolbar overflows to match existing editor, incl. direction dynamic controls
## Secondary Todo ## Secondary Todo
@ -19,7 +17,11 @@
- Color picker for color controls - Color picker for color controls
- Table caption text support - Table caption text support
- Support media src conversions (https://github.com/tinymce/tinymce/blob/release/6.6/modules/tinymce/src/plugins/media/main/ts/core/UrlPatterns.ts) - Support media src conversions (https://github.com/tinymce/tinymce/blob/release/6.6/modules/tinymce/src/plugins/media/main/ts/core/UrlPatterns.ts)
- Check translation coverage
## Bugs ## Bugs
- List selection can get lost on nesting/unnesting - List selection can get lost on nesting/unnesting
- Can't escape lists when bottom element
- Content not properly saving on new pages
- BookStack UI (non-editor) shortcuts can trigger in editor (`/` for example)