Lexical: Added horizontal rule node

This commit is contained in:
Dan Brown 2024-06-27 15:48:06 +01:00
parent 72a0e081ca
commit 4e2820d6e3
No known key found for this signature in database
GPG Key ID: 46D9F943C24A2EF9
5 changed files with 92 additions and 17 deletions

View File

@ -80,12 +80,16 @@ export function toggleSelectionBlockNodeType(editor: LexicalEditor, matcher: Lex
});
}
export function insertNewBlockNodeAtSelection(node: LexicalNode) {
export function insertNewBlockNodeAtSelection(node: LexicalNode, insertAfter: boolean = true) {
const selection = $getSelection();
const blockElement = selection ? $getNearestBlockElementAncestorOrThrow(selection.getNodes()[0]) : null;
if (blockElement) {
blockElement.insertAfter(node);
if (insertAfter) {
blockElement.insertAfter(node);
} else {
blockElement.insertBefore(node);
}
} else {
$getRoot().append(node);
}

View File

@ -0,0 +1,64 @@
import {
DOMConversion,
DOMConversionMap, DOMConversionOutput,
ElementNode,
LexicalEditor,
LexicalNode,
SerializedElementNode,
} from 'lexical';
import type {EditorConfig} from "lexical/LexicalEditor";
export class HorizontalRuleNode extends ElementNode {
static getType() {
return 'horizontal-rule';
}
static clone(node: HorizontalRuleNode): HorizontalRuleNode {
return new HorizontalRuleNode(node.__key);
}
createDOM(_config: EditorConfig, _editor: LexicalEditor) {
return document.createElement('hr');
}
updateDOM(prevNode: unknown, dom: HTMLElement) {
return false;
}
static importDOM(): DOMConversionMap|null {
return {
hr(node: HTMLElement): DOMConversion|null {
return {
conversion: (element: HTMLElement): DOMConversionOutput|null => {
return {
node: new HorizontalRuleNode(),
};
},
priority: 3,
};
},
};
}
exportJSON(): SerializedElementNode {
return {
...super.exportJSON(),
type: 'horizontal-rule',
version: 1,
};
}
static importJSON(serializedNode: SerializedElementNode): HorizontalRuleNode {
return $createHorizontalRuleNode();
}
}
export function $createHorizontalRuleNode() {
return new HorizontalRuleNode();
}
export function $isHorizontalRuleNode(node: LexicalNode | null | undefined) {
return node instanceof HorizontalRuleNode;
}

View File

@ -8,6 +8,7 @@ import {DetailsNode, SummaryNode} from "./details";
import {ListItemNode, ListNode} from "@lexical/list";
import {TableCellNode, TableNode, TableRowNode} from "@lexical/table";
import {CustomTableNode} from "./custom-table";
import {HorizontalRuleNode} from "./horizontal-rule";
/**
* Load the nodes for lexical.
@ -23,6 +24,7 @@ export function getNodesForPageEditor(): (KlassConstructor<typeof LexicalNode> |
TableRowNode,
TableCellNode,
ImageNode,
HorizontalRuleNode,
DetailsNode, SummaryNode,
CustomParagraphNode,
LinkNode,

View File

@ -9,7 +9,7 @@ import {
UNDO_COMMAND
} from "lexical";
import {
getNodeFromSelection,
getNodeFromSelection, insertNewBlockNodeAtSelection,
selectionContainsNodeType,
selectionContainsTextFormat,
toggleSelectionBlockNodeType
@ -47,8 +47,10 @@ import listCheckIcon from "@icons/editor/list-check.svg"
import linkIcon from "@icons/editor/link.svg"
import tableIcon from "@icons/editor/table.svg"
import imageIcon from "@icons/editor/image.svg"
import horizontalRuleIcon from "@icons/editor/horizontal-rule.svg"
import detailsIcon from "@icons/editor/details.svg"
import sourceIcon from "@icons/editor/source-view.svg"
import {$createHorizontalRuleNode, $isHorizontalRuleNode, HorizontalRuleNode} from "../../nodes/horizontal-rule";
export const undo: EditorButtonDefinition = {
label: 'Undo',
@ -294,6 +296,19 @@ export const image: EditorButtonDefinition = {
}
};
export const horizontalRule: EditorButtonDefinition = {
label: 'Insert horizontal line',
icon: horizontalRuleIcon,
action(context: EditorUiContext) {
context.editor.update(() => {
insertNewBlockNodeAtSelection($createHorizontalRuleNode(), false);
});
},
isActive(selection: BaseSelection|null): boolean {
return selectionContainsNodeType(selection, $isHorizontalRuleNode);
}
};
export const details: EditorButtonDefinition = {
label: 'Insert collapsible block',
icon: detailsIcon,

View File

@ -2,7 +2,7 @@ import {EditorButton} from "./framework/buttons";
import {
blockquote, bold, bulletList, clearFormating, code,
dangerCallout, details,
h2, h3, h4, h5, highlightColor, image,
h2, h3, h4, h5, highlightColor, horizontalRule, image,
infoCallout, italic, link, numberList, paragraph,
redo, source, strikethrough, subscript,
successCallout, superscript, table, taskList, textColor, underline,
@ -67,6 +67,7 @@ export function getMainEditorFullToolbar(): EditorContainerUiElement {
new EditorTableCreator(),
]),
new EditorButton(image),
new EditorButton(horizontalRule),
new EditorButton(details),
// Meta elements
@ -74,21 +75,10 @@ export function getMainEditorFullToolbar(): EditorContainerUiElement {
// Test
new EditorButton({
label: 'Expand table col 2',
label: 'Test button',
action(context: EditorUiContext) {
context.editor.update(() => {
const root = $getRoot();
let table: CustomTableNode|null = null;
for (const child of root.getChildren()) {
if ($isCustomTableNode(child)) {
table = child as CustomTableNode;
break;
}
}
if (table) {
$setTableColumnWidth(table, 1, 500);
}
// Do stuff
});
},
isActive() {