mirror of
https://github.com/BookStackApp/BookStack.git
synced 2024-10-01 01:36:00 -04:00
Lexical: Added horizontal rule node
This commit is contained in:
parent
72a0e081ca
commit
4e2820d6e3
@ -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 selection = $getSelection();
|
||||||
const blockElement = selection ? $getNearestBlockElementAncestorOrThrow(selection.getNodes()[0]) : null;
|
const blockElement = selection ? $getNearestBlockElementAncestorOrThrow(selection.getNodes()[0]) : null;
|
||||||
|
|
||||||
if (blockElement) {
|
if (blockElement) {
|
||||||
blockElement.insertAfter(node);
|
if (insertAfter) {
|
||||||
|
blockElement.insertAfter(node);
|
||||||
|
} else {
|
||||||
|
blockElement.insertBefore(node);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$getRoot().append(node);
|
$getRoot().append(node);
|
||||||
}
|
}
|
||||||
|
64
resources/js/wysiwyg/nodes/horizontal-rule.ts
Normal file
64
resources/js/wysiwyg/nodes/horizontal-rule.ts
Normal 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;
|
||||||
|
}
|
@ -8,6 +8,7 @@ import {DetailsNode, SummaryNode} from "./details";
|
|||||||
import {ListItemNode, ListNode} from "@lexical/list";
|
import {ListItemNode, ListNode} from "@lexical/list";
|
||||||
import {TableCellNode, TableNode, TableRowNode} from "@lexical/table";
|
import {TableCellNode, TableNode, TableRowNode} from "@lexical/table";
|
||||||
import {CustomTableNode} from "./custom-table";
|
import {CustomTableNode} from "./custom-table";
|
||||||
|
import {HorizontalRuleNode} from "./horizontal-rule";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load the nodes for lexical.
|
* Load the nodes for lexical.
|
||||||
@ -23,6 +24,7 @@ export function getNodesForPageEditor(): (KlassConstructor<typeof LexicalNode> |
|
|||||||
TableRowNode,
|
TableRowNode,
|
||||||
TableCellNode,
|
TableCellNode,
|
||||||
ImageNode,
|
ImageNode,
|
||||||
|
HorizontalRuleNode,
|
||||||
DetailsNode, SummaryNode,
|
DetailsNode, SummaryNode,
|
||||||
CustomParagraphNode,
|
CustomParagraphNode,
|
||||||
LinkNode,
|
LinkNode,
|
||||||
|
@ -9,7 +9,7 @@ import {
|
|||||||
UNDO_COMMAND
|
UNDO_COMMAND
|
||||||
} from "lexical";
|
} from "lexical";
|
||||||
import {
|
import {
|
||||||
getNodeFromSelection,
|
getNodeFromSelection, insertNewBlockNodeAtSelection,
|
||||||
selectionContainsNodeType,
|
selectionContainsNodeType,
|
||||||
selectionContainsTextFormat,
|
selectionContainsTextFormat,
|
||||||
toggleSelectionBlockNodeType
|
toggleSelectionBlockNodeType
|
||||||
@ -47,8 +47,10 @@ import listCheckIcon from "@icons/editor/list-check.svg"
|
|||||||
import linkIcon from "@icons/editor/link.svg"
|
import linkIcon from "@icons/editor/link.svg"
|
||||||
import tableIcon from "@icons/editor/table.svg"
|
import tableIcon from "@icons/editor/table.svg"
|
||||||
import imageIcon from "@icons/editor/image.svg"
|
import imageIcon from "@icons/editor/image.svg"
|
||||||
|
import horizontalRuleIcon from "@icons/editor/horizontal-rule.svg"
|
||||||
import detailsIcon from "@icons/editor/details.svg"
|
import detailsIcon from "@icons/editor/details.svg"
|
||||||
import sourceIcon from "@icons/editor/source-view.svg"
|
import sourceIcon from "@icons/editor/source-view.svg"
|
||||||
|
import {$createHorizontalRuleNode, $isHorizontalRuleNode, HorizontalRuleNode} from "../../nodes/horizontal-rule";
|
||||||
|
|
||||||
export const undo: EditorButtonDefinition = {
|
export const undo: EditorButtonDefinition = {
|
||||||
label: 'Undo',
|
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 = {
|
export const details: EditorButtonDefinition = {
|
||||||
label: 'Insert collapsible block',
|
label: 'Insert collapsible block',
|
||||||
icon: detailsIcon,
|
icon: detailsIcon,
|
||||||
|
@ -2,7 +2,7 @@ import {EditorButton} from "./framework/buttons";
|
|||||||
import {
|
import {
|
||||||
blockquote, bold, bulletList, clearFormating, code,
|
blockquote, bold, bulletList, clearFormating, code,
|
||||||
dangerCallout, details,
|
dangerCallout, details,
|
||||||
h2, h3, h4, h5, highlightColor, image,
|
h2, h3, h4, h5, highlightColor, horizontalRule, image,
|
||||||
infoCallout, italic, link, numberList, paragraph,
|
infoCallout, italic, link, numberList, paragraph,
|
||||||
redo, source, strikethrough, subscript,
|
redo, source, strikethrough, subscript,
|
||||||
successCallout, superscript, table, taskList, textColor, underline,
|
successCallout, superscript, table, taskList, textColor, underline,
|
||||||
@ -67,6 +67,7 @@ export function getMainEditorFullToolbar(): EditorContainerUiElement {
|
|||||||
new EditorTableCreator(),
|
new EditorTableCreator(),
|
||||||
]),
|
]),
|
||||||
new EditorButton(image),
|
new EditorButton(image),
|
||||||
|
new EditorButton(horizontalRule),
|
||||||
new EditorButton(details),
|
new EditorButton(details),
|
||||||
|
|
||||||
// Meta elements
|
// Meta elements
|
||||||
@ -74,21 +75,10 @@ export function getMainEditorFullToolbar(): EditorContainerUiElement {
|
|||||||
|
|
||||||
// Test
|
// Test
|
||||||
new EditorButton({
|
new EditorButton({
|
||||||
label: 'Expand table col 2',
|
label: 'Test button',
|
||||||
action(context: EditorUiContext) {
|
action(context: EditorUiContext) {
|
||||||
context.editor.update(() => {
|
context.editor.update(() => {
|
||||||
const root = $getRoot();
|
// Do stuff
|
||||||
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);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
isActive() {
|
isActive() {
|
||||||
|
Loading…
Reference in New Issue
Block a user