import {$createLinkNode} from '@lexical/link';
import {$createListItemNode, $createListNode} from '@lexical/list';
-import {$createHeadingNode, $createQuoteNode} from '@lexical/rich-text';
import {$createTableNodeWithDimensions} from '@lexical/table';
import {$createParagraphNode, $createTextNode, $getRoot} from 'lexical';
import {initializeUnitTest} from '../utils';
+import {$createHeadingNode} from "@lexical/rich-text/LexicalHeadingNode";
+import {$createQuoteNode} from "@lexical/rich-text/LexicalQuoteNode";
function $createEditorContent() {
const root = $getRoot();
import {AutoLinkNode, LinkNode} from '@lexical/link';
import {ListItemNode, ListNode} from '@lexical/list';
-import {HeadingNode, QuoteNode} from '@lexical/rich-text';
import {TableCellNode, TableNode, TableRowNode} from '@lexical/table';
import {
LexicalNodeReplacement,
} from '../../LexicalEditor';
import {resetRandomKey} from '../../LexicalUtils';
+import {HeadingNode} from "@lexical/rich-text/LexicalHeadingNode";
+import {QuoteNode} from "@lexical/rich-text/LexicalQuoteNode";
type TestEnv = {
}
export function copyCommonBlockProperties(from: CommonBlockNode, to: CommonBlockNode): void {
- to.__id = from.__id;
+ // to.__id = from.__id;
to.__alignment = from.__alignment;
to.__inset = from.__inset;
}
\ No newline at end of file
$insertDataTransferForRichText,
} from '@lexical/clipboard';
import {$createListItemNode, $createListNode} from '@lexical/list';
-import {$createHeadingNode, registerRichText} from '@lexical/rich-text';
+import {registerRichText} from '@lexical/rich-text';
import {
$createParagraphNode,
$createRangeSelection,
initializeUnitTest,
invariant,
} from '../../../__tests__/utils';
+import {$createHeadingNode} from "@lexical/rich-text/LexicalHeadingNode";
describe('LexicalTabNode tests', () => {
initializeUnitTest((testEnv) => {
import {$generateHtmlFromNodes, $generateNodesFromDOM} from '@lexical/html';
import {LinkNode} from '@lexical/link';
import {ListItemNode, ListNode} from '@lexical/list';
-import {HeadingNode, QuoteNode} from '@lexical/rich-text';
import {
$createParagraphNode,
$createRangeSelection,
$createTextNode,
$getRoot,
} from 'lexical';
+import {HeadingNode} from "@lexical/rich-text/LexicalHeadingNode";
+import {QuoteNode} from "@lexical/rich-text/LexicalQuoteNode";
describe('HTML', () => {
type Input = Array<{
--- /dev/null
+import {
+ $applyNodeReplacement,
+ $createParagraphNode,
+ type DOMConversionMap,
+ DOMConversionOutput,
+ type DOMExportOutput,
+ type EditorConfig,
+ isHTMLElement,
+ type LexicalEditor,
+ type LexicalNode,
+ type NodeKey,
+ type ParagraphNode,
+ type RangeSelection,
+ type SerializedElementNode,
+ type Spread
+} from "lexical";
+import {addClassNamesToElement} from "@lexical/utils";
+import {CommonBlockNode, copyCommonBlockProperties} from "lexical/nodes/CommonBlockNode";
+import {
+ commonPropertiesDifferent, deserializeCommonBlockNode,
+ SerializedCommonBlockNode, setCommonBlockPropsFromElement,
+ updateElementWithCommonBlockProps
+} from "../../nodes/_common";
+
+export type HeadingTagType = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
+
+export type SerializedHeadingNode = Spread<
+ {
+ tag: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
+ },
+ SerializedCommonBlockNode
+>;
+
+/** @noInheritDoc */
+export class HeadingNode extends CommonBlockNode {
+ /** @internal */
+ __tag: HeadingTagType;
+
+ static getType(): string {
+ return 'heading';
+ }
+
+ static clone(node: HeadingNode): HeadingNode {
+ const clone = new HeadingNode(node.__tag, node.__key);
+ copyCommonBlockProperties(node, clone);
+ return clone;
+ }
+
+ constructor(tag: HeadingTagType, key?: NodeKey) {
+ super(key);
+ this.__tag = tag;
+ }
+
+ getTag(): HeadingTagType {
+ return this.__tag;
+ }
+
+ // View
+
+ createDOM(config: EditorConfig): HTMLElement {
+ const tag = this.__tag;
+ const element = document.createElement(tag);
+ const theme = config.theme;
+ const classNames = theme.heading;
+ if (classNames !== undefined) {
+ const className = classNames[tag];
+ addClassNamesToElement(element, className);
+ }
+ updateElementWithCommonBlockProps(element, this);
+ return element;
+ }
+
+ updateDOM(prevNode: HeadingNode, dom: HTMLElement): boolean {
+ return commonPropertiesDifferent(prevNode, this);
+ }
+
+ static importDOM(): DOMConversionMap | null {
+ return {
+ h1: (node: Node) => ({
+ conversion: $convertHeadingElement,
+ priority: 0,
+ }),
+ h2: (node: Node) => ({
+ conversion: $convertHeadingElement,
+ priority: 0,
+ }),
+ h3: (node: Node) => ({
+ conversion: $convertHeadingElement,
+ priority: 0,
+ }),
+ h4: (node: Node) => ({
+ conversion: $convertHeadingElement,
+ priority: 0,
+ }),
+ h5: (node: Node) => ({
+ conversion: $convertHeadingElement,
+ priority: 0,
+ }),
+ h6: (node: Node) => ({
+ conversion: $convertHeadingElement,
+ priority: 0,
+ }),
+ };
+ }
+
+ exportDOM(editor: LexicalEditor): DOMExportOutput {
+ const {element} = super.exportDOM(editor);
+
+ if (element && isHTMLElement(element)) {
+ if (this.isEmpty()) {
+ element.append(document.createElement('br'));
+ }
+ }
+
+ return {
+ element,
+ };
+ }
+
+ static importJSON(serializedNode: SerializedHeadingNode): HeadingNode {
+ const node = $createHeadingNode(serializedNode.tag);
+ deserializeCommonBlockNode(serializedNode, node);
+ return node;
+ }
+
+ exportJSON(): SerializedHeadingNode {
+ return {
+ ...super.exportJSON(),
+ tag: this.getTag(),
+ type: 'heading',
+ version: 1,
+ };
+ }
+
+ // Mutation
+ insertNewAfter(
+ selection?: RangeSelection,
+ restoreSelection = true,
+ ): ParagraphNode | HeadingNode {
+ const anchorOffet = selection ? selection.anchor.offset : 0;
+ const lastDesc = this.getLastDescendant();
+ const isAtEnd =
+ !lastDesc ||
+ (selection &&
+ selection.anchor.key === lastDesc.getKey() &&
+ anchorOffet === lastDesc.getTextContentSize());
+ const newElement =
+ isAtEnd || !selection
+ ? $createParagraphNode()
+ : $createHeadingNode(this.getTag());
+ const direction = this.getDirection();
+ newElement.setDirection(direction);
+ this.insertAfter(newElement, restoreSelection);
+ if (anchorOffet === 0 && !this.isEmpty() && selection) {
+ const paragraph = $createParagraphNode();
+ paragraph.select();
+ this.replace(paragraph, true);
+ }
+ return newElement;
+ }
+
+ collapseAtStart(): true {
+ const newElement = !this.isEmpty()
+ ? $createHeadingNode(this.getTag())
+ : $createParagraphNode();
+ const children = this.getChildren();
+ children.forEach((child) => newElement.append(child));
+ this.replace(newElement);
+ return true;
+ }
+
+ extractWithChild(): boolean {
+ return true;
+ }
+}
+
+function $convertHeadingElement(element: HTMLElement): DOMConversionOutput {
+ const nodeName = element.nodeName.toLowerCase();
+ let node = null;
+ if (
+ nodeName === 'h1' ||
+ nodeName === 'h2' ||
+ nodeName === 'h3' ||
+ nodeName === 'h4' ||
+ nodeName === 'h5' ||
+ nodeName === 'h6'
+ ) {
+ node = $createHeadingNode(nodeName);
+ setCommonBlockPropsFromElement(element, node);
+ }
+ return {node};
+}
+
+export function $createHeadingNode(headingTag: HeadingTagType): HeadingNode {
+ return $applyNodeReplacement(new HeadingNode(headingTag));
+}
+
+export function $isHeadingNode(
+ node: LexicalNode | null | undefined,
+): node is HeadingNode {
+ return node instanceof HeadingNode;
+}
\ No newline at end of file
--- /dev/null
+import {
+ $applyNodeReplacement,
+ $createParagraphNode,
+ type DOMConversionMap,
+ type DOMConversionOutput,
+ type DOMExportOutput,
+ type EditorConfig,
+ ElementNode,
+ isHTMLElement,
+ type LexicalEditor,
+ LexicalNode,
+ type NodeKey,
+ type ParagraphNode,
+ type RangeSelection,
+ SerializedElementNode
+} from "lexical";
+import {addClassNamesToElement} from "@lexical/utils";
+import {CommonBlockNode, copyCommonBlockProperties} from "lexical/nodes/CommonBlockNode";
+import {
+ commonPropertiesDifferent, deserializeCommonBlockNode,
+ SerializedCommonBlockNode, setCommonBlockPropsFromElement,
+ updateElementWithCommonBlockProps
+} from "../../nodes/_common";
+
+export type SerializedQuoteNode = SerializedCommonBlockNode;
+
+/** @noInheritDoc */
+export class QuoteNode extends CommonBlockNode {
+ static getType(): string {
+ return 'quote';
+ }
+
+ static clone(node: QuoteNode): QuoteNode {
+ const clone = new QuoteNode(node.__key);
+ copyCommonBlockProperties(node, clone);
+ return clone;
+ }
+
+ constructor(key?: NodeKey) {
+ super(key);
+ }
+
+ // View
+
+ createDOM(config: EditorConfig): HTMLElement {
+ const element = document.createElement('blockquote');
+ addClassNamesToElement(element, config.theme.quote);
+ updateElementWithCommonBlockProps(element, this);
+ return element;
+ }
+
+ updateDOM(prevNode: QuoteNode, dom: HTMLElement): boolean {
+ return commonPropertiesDifferent(prevNode, this);
+ }
+
+ static importDOM(): DOMConversionMap | null {
+ return {
+ blockquote: (node: Node) => ({
+ conversion: $convertBlockquoteElement,
+ priority: 0,
+ }),
+ };
+ }
+
+ exportDOM(editor: LexicalEditor): DOMExportOutput {
+ const {element} = super.exportDOM(editor);
+
+ if (element && isHTMLElement(element)) {
+ if (this.isEmpty()) {
+ element.append(document.createElement('br'));
+ }
+ }
+
+ return {
+ element,
+ };
+ }
+
+ static importJSON(serializedNode: SerializedQuoteNode): QuoteNode {
+ const node = $createQuoteNode();
+ deserializeCommonBlockNode(serializedNode, node);
+ return node;
+ }
+
+ exportJSON(): SerializedQuoteNode {
+ return {
+ ...super.exportJSON(),
+ type: 'quote',
+ };
+ }
+
+ // Mutation
+
+ insertNewAfter(_: RangeSelection, restoreSelection?: boolean): ParagraphNode {
+ const newBlock = $createParagraphNode();
+ const direction = this.getDirection();
+ newBlock.setDirection(direction);
+ this.insertAfter(newBlock, restoreSelection);
+ return newBlock;
+ }
+
+ collapseAtStart(): true {
+ const paragraph = $createParagraphNode();
+ const children = this.getChildren();
+ children.forEach((child) => paragraph.append(child));
+ this.replace(paragraph);
+ return true;
+ }
+
+ canMergeWhenEmpty(): true {
+ return true;
+ }
+}
+
+export function $createQuoteNode(): QuoteNode {
+ return $applyNodeReplacement(new QuoteNode());
+}
+
+export function $isQuoteNode(
+ node: LexicalNode | null | undefined,
+): node is QuoteNode {
+ return node instanceof QuoteNode;
+}
+
+function $convertBlockquoteElement(element: HTMLElement): DOMConversionOutput {
+ const node = $createQuoteNode();
+ setCommonBlockPropsFromElement(element, node);
+ return {node};
+}
\ No newline at end of file
*
*/
-import {
- $createHeadingNode,
- $isHeadingNode,
- HeadingNode,
-} from '@lexical/rich-text';
import {
$createTextNode,
$getRoot,
RangeSelection,
} from 'lexical';
import {initializeUnitTest} from 'lexical/__tests__/utils';
+import {$createHeadingNode, $isHeadingNode, HeadingNode} from "@lexical/rich-text/LexicalHeadingNode";
const editorConfig = Object.freeze({
namespace: '',
*
*/
-import {$createQuoteNode, QuoteNode} from '@lexical/rich-text';
import {$createRangeSelection, $getRoot, ParagraphNode} from 'lexical';
import {initializeUnitTest} from 'lexical/__tests__/utils';
+import {$createQuoteNode, QuoteNode} from "@lexical/rich-text/LexicalQuoteNode";
const editorConfig = Object.freeze({
namespace: '',
import type {
CommandPayloadType,
- DOMConversionMap,
- DOMConversionOutput,
- DOMExportOutput,
- EditorConfig,
ElementFormatType,
LexicalCommand,
LexicalEditor,
- LexicalNode,
- NodeKey,
- ParagraphNode,
PasteCommandType,
RangeSelection,
- SerializedElementNode,
- Spread,
TextFormatType,
} from 'lexical';
-
-import {
- $insertDataTransferForRichText,
- copyToClipboard,
-} from '@lexical/clipboard';
-import {
- $moveCharacter,
- $shouldOverrideDefaultCharacterSelection,
-} from '@lexical/selection';
import {
- $findMatchingParent,
- $getNearestBlockElementAncestorOrThrow,
- addClassNamesToElement,
- isHTMLElement,
- mergeRegister,
- objectKlassEquals,
-} from '@lexical/utils';
-import {
- $applyNodeReplacement,
- $createParagraphNode,
$createRangeSelection,
$createTabNode,
$getAdjacentNode,
$isElementNode,
$isNodeSelection,
$isRangeSelection,
- $isRootNode,
$isTextNode,
$normalizeSelection__EXPERIMENTAL,
$selectAll,
ElementNode,
FORMAT_ELEMENT_COMMAND,
FORMAT_TEXT_COMMAND,
- INDENT_CONTENT_COMMAND,
INSERT_LINE_BREAK_COMMAND,
INSERT_PARAGRAPH_COMMAND,
INSERT_TAB_COMMAND,
KEY_DELETE_COMMAND,
KEY_ENTER_COMMAND,
KEY_ESCAPE_COMMAND,
- OUTDENT_CONTENT_COMMAND,
PASTE_COMMAND,
REMOVE_TEXT_COMMAND,
SELECT_ALL_COMMAND,
} from 'lexical';
-import caretFromPoint from 'lexical/shared/caretFromPoint';
-import {
- CAN_USE_BEFORE_INPUT,
- IS_APPLE_WEBKIT,
- IS_IOS,
- IS_SAFARI,
-} from 'lexical/shared/environment';
-export type SerializedHeadingNode = Spread<
- {
- tag: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
- },
- SerializedElementNode
->;
+import {$insertDataTransferForRichText, copyToClipboard,} from '@lexical/clipboard';
+import {$moveCharacter, $shouldOverrideDefaultCharacterSelection,} from '@lexical/selection';
+import {$findMatchingParent, mergeRegister, objectKlassEquals,} from '@lexical/utils';
+import caretFromPoint from 'lexical/shared/caretFromPoint';
+import {CAN_USE_BEFORE_INPUT, IS_APPLE_WEBKIT, IS_IOS, IS_SAFARI,} from 'lexical/shared/environment';
export const DRAG_DROP_PASTE: LexicalCommand<Array<File>> = createCommand(
'DRAG_DROP_PASTE_FILE',
);
-export type SerializedQuoteNode = SerializedElementNode;
-
-/** @noInheritDoc */
-export class QuoteNode extends ElementNode {
- static getType(): string {
- return 'quote';
- }
-
- static clone(node: QuoteNode): QuoteNode {
- return new QuoteNode(node.__key);
- }
-
- constructor(key?: NodeKey) {
- super(key);
- }
-
- // View
-
- createDOM(config: EditorConfig): HTMLElement {
- const element = document.createElement('blockquote');
- addClassNamesToElement(element, config.theme.quote);
- return element;
- }
- updateDOM(prevNode: QuoteNode, dom: HTMLElement): boolean {
- return false;
- }
-
- static importDOM(): DOMConversionMap | null {
- return {
- blockquote: (node: Node) => ({
- conversion: $convertBlockquoteElement,
- priority: 0,
- }),
- };
- }
-
- exportDOM(editor: LexicalEditor): DOMExportOutput {
- const {element} = super.exportDOM(editor);
-
- if (element && isHTMLElement(element)) {
- if (this.isEmpty()) {
- element.append(document.createElement('br'));
- }
- }
-
- return {
- element,
- };
- }
-
- static importJSON(serializedNode: SerializedQuoteNode): QuoteNode {
- const node = $createQuoteNode();
- return node;
- }
-
- exportJSON(): SerializedElementNode {
- return {
- ...super.exportJSON(),
- type: 'quote',
- };
- }
-
- // Mutation
-
- insertNewAfter(_: RangeSelection, restoreSelection?: boolean): ParagraphNode {
- const newBlock = $createParagraphNode();
- const direction = this.getDirection();
- newBlock.setDirection(direction);
- this.insertAfter(newBlock, restoreSelection);
- return newBlock;
- }
-
- collapseAtStart(): true {
- const paragraph = $createParagraphNode();
- const children = this.getChildren();
- children.forEach((child) => paragraph.append(child));
- this.replace(paragraph);
- return true;
- }
-
- canMergeWhenEmpty(): true {
- return true;
- }
-}
-
-export function $createQuoteNode(): QuoteNode {
- return $applyNodeReplacement(new QuoteNode());
-}
-
-export function $isQuoteNode(
- node: LexicalNode | null | undefined,
-): node is QuoteNode {
- return node instanceof QuoteNode;
-}
-
-export type HeadingTagType = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
-
-/** @noInheritDoc */
-export class HeadingNode extends ElementNode {
- /** @internal */
- __tag: HeadingTagType;
-
- static getType(): string {
- return 'heading';
- }
-
- static clone(node: HeadingNode): HeadingNode {
- return new HeadingNode(node.__tag, node.__key);
- }
-
- constructor(tag: HeadingTagType, key?: NodeKey) {
- super(key);
- this.__tag = tag;
- }
-
- getTag(): HeadingTagType {
- return this.__tag;
- }
-
- // View
-
- createDOM(config: EditorConfig): HTMLElement {
- const tag = this.__tag;
- const element = document.createElement(tag);
- const theme = config.theme;
- const classNames = theme.heading;
- if (classNames !== undefined) {
- const className = classNames[tag];
- addClassNamesToElement(element, className);
- }
- return element;
- }
-
- updateDOM(prevNode: HeadingNode, dom: HTMLElement): boolean {
- return false;
- }
-
- static importDOM(): DOMConversionMap | null {
- return {
- h1: (node: Node) => ({
- conversion: $convertHeadingElement,
- priority: 0,
- }),
- h2: (node: Node) => ({
- conversion: $convertHeadingElement,
- priority: 0,
- }),
- h3: (node: Node) => ({
- conversion: $convertHeadingElement,
- priority: 0,
- }),
- h4: (node: Node) => ({
- conversion: $convertHeadingElement,
- priority: 0,
- }),
- h5: (node: Node) => ({
- conversion: $convertHeadingElement,
- priority: 0,
- }),
- h6: (node: Node) => ({
- conversion: $convertHeadingElement,
- priority: 0,
- }),
- p: (node: Node) => {
- // domNode is a <p> since we matched it by nodeName
- const paragraph = node as HTMLParagraphElement;
- const firstChild = paragraph.firstChild;
- if (firstChild !== null && isGoogleDocsTitle(firstChild)) {
- return {
- conversion: () => ({node: null}),
- priority: 3,
- };
- }
- return null;
- },
- span: (node: Node) => {
- if (isGoogleDocsTitle(node)) {
- return {
- conversion: (domNode: Node) => {
- return {
- node: $createHeadingNode('h1'),
- };
- },
- priority: 3,
- };
- }
- return null;
- },
- };
- }
-
- exportDOM(editor: LexicalEditor): DOMExportOutput {
- const {element} = super.exportDOM(editor);
-
- if (element && isHTMLElement(element)) {
- if (this.isEmpty()) {
- element.append(document.createElement('br'));
- }
- }
-
- return {
- element,
- };
- }
-
- static importJSON(serializedNode: SerializedHeadingNode): HeadingNode {
- return $createHeadingNode(serializedNode.tag);
- }
-
- exportJSON(): SerializedHeadingNode {
- return {
- ...super.exportJSON(),
- tag: this.getTag(),
- type: 'heading',
- version: 1,
- };
- }
-
- // Mutation
- insertNewAfter(
- selection?: RangeSelection,
- restoreSelection = true,
- ): ParagraphNode | HeadingNode {
- const anchorOffet = selection ? selection.anchor.offset : 0;
- const lastDesc = this.getLastDescendant();
- const isAtEnd =
- !lastDesc ||
- (selection &&
- selection.anchor.key === lastDesc.getKey() &&
- anchorOffet === lastDesc.getTextContentSize());
- const newElement =
- isAtEnd || !selection
- ? $createParagraphNode()
- : $createHeadingNode(this.getTag());
- const direction = this.getDirection();
- newElement.setDirection(direction);
- this.insertAfter(newElement, restoreSelection);
- if (anchorOffet === 0 && !this.isEmpty() && selection) {
- const paragraph = $createParagraphNode();
- paragraph.select();
- this.replace(paragraph, true);
- }
- return newElement;
- }
-
- collapseAtStart(): true {
- const newElement = !this.isEmpty()
- ? $createHeadingNode(this.getTag())
- : $createParagraphNode();
- const children = this.getChildren();
- children.forEach((child) => newElement.append(child));
- this.replace(newElement);
- return true;
- }
-
- extractWithChild(): boolean {
- return true;
- }
-}
-function isGoogleDocsTitle(domNode: Node): boolean {
- if (domNode.nodeName.toLowerCase() === 'span') {
- return (domNode as HTMLSpanElement).style.fontSize === '26pt';
- }
- return false;
-}
-
-function $convertHeadingElement(element: HTMLElement): DOMConversionOutput {
- const nodeName = element.nodeName.toLowerCase();
- let node = null;
- if (
- nodeName === 'h1' ||
- nodeName === 'h2' ||
- nodeName === 'h3' ||
- nodeName === 'h4' ||
- nodeName === 'h5' ||
- nodeName === 'h6'
- ) {
- node = $createHeadingNode(nodeName);
- }
- return {node};
-}
-
-function $convertBlockquoteElement(element: HTMLElement): DOMConversionOutput {
- const node = $createQuoteNode();
- return {node};
-}
-
-export function $createHeadingNode(headingTag: HeadingTagType): HeadingNode {
- return $applyNodeReplacement(new HeadingNode(headingTag));
-}
-
-export function $isHeadingNode(
- node: LexicalNode | null | undefined,
-): node is HeadingNode {
- return node instanceof HeadingNode;
-}
function onPasteForRichText(
event: CommandPayloadType<typeof PASTE_COMMAND>,
import {$createLinkNode} from '@lexical/link';
import {$createListItemNode, $createListNode} from '@lexical/list';
-import {$createHeadingNode, registerRichText} from '@lexical/rich-text';
+import {registerRichText} from '@lexical/rich-text';
import {
$addNodeStyle,
$getSelectionStyleValueForProperty,
} from '../utils';
import {createEmptyHistoryState, registerHistory} from "@lexical/history";
import {mergeRegister} from "@lexical/utils";
+import {$createHeadingNode} from "@lexical/rich-text/LexicalHeadingNode";
interface ExpectedSelection {
anchorPath: number[];
*/
import {$createLinkNode} from '@lexical/link';
-import {$createHeadingNode, $isHeadingNode} from '@lexical/rich-text';
import {
$getSelectionStyleValueForProperty,
$patchStyleText,
} from 'lexical/__tests__/utils';
import {$setAnchorPoint, $setFocusPoint} from '../utils';
+import {$createHeadingNode, $isHeadingNode} from "@lexical/rich-text/LexicalHeadingNode";
Range.prototype.getBoundingClientRect = function (): DOMRect {
const rect = {
*/
import {AutoLinkNode, LinkNode} from '@lexical/link';
import {ListItemNode, ListNode} from '@lexical/list';
-import {HeadingNode, QuoteNode, registerRichText} from '@lexical/rich-text';
+import {registerRichText} from '@lexical/rich-text';
import {
applySelectionInputs,
pasteHTML,
import {TableCellNode, TableNode, TableRowNode} from '@lexical/table';
import {$createParagraphNode, $insertNodes, LexicalEditor} from 'lexical';
import {createTestEditor, initializeClipboard} from 'lexical/__tests__/utils';
+import {HeadingNode} from "@lexical/rich-text/LexicalHeadingNode";
+import {QuoteNode} from "@lexical/rich-text/LexicalQuoteNode";
jest.mock('lexical/shared/environment', () => {
const originalModule = jest.requireActual('lexical/shared/environment');
+++ /dev/null
-import {
- DOMConversionMap,
- DOMConversionOutput,
- LexicalNode,
- Spread
-} from "lexical";
-import {EditorConfig} from "lexical/LexicalEditor";
-import {HeadingNode, HeadingTagType, SerializedHeadingNode} from "@lexical/rich-text";
-import {
- CommonBlockAlignment, commonPropertiesDifferent, deserializeCommonBlockNode,
- SerializedCommonBlockNode,
- setCommonBlockPropsFromElement,
- updateElementWithCommonBlockProps
-} from "./_common";
-
-
-export type SerializedCustomHeadingNode = Spread<SerializedCommonBlockNode, SerializedHeadingNode>
-
-export class CustomHeadingNode extends HeadingNode {
- __id: string = '';
- __alignment: CommonBlockAlignment = '';
- __inset: number = 0;
-
- static getType() {
- return 'custom-heading';
- }
-
- 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: CustomHeadingNode) {
- const newNode = new CustomHeadingNode(node.__tag, node.__key);
- 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: 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,
- inset: this.__inset,
- };
- }
-
- static importJSON(serializedNode: SerializedCustomHeadingNode): CustomHeadingNode {
- const node = $createCustomHeadingNode(serializedNode.tag);
- deserializeCommonBlockNode(serializedNode, node);
- return node;
- }
-
- static importDOM(): DOMConversionMap | null {
- return {
- h1: (node: Node) => ({
- conversion: $convertHeadingElement,
- priority: 0,
- }),
- h2: (node: Node) => ({
- conversion: $convertHeadingElement,
- priority: 0,
- }),
- h3: (node: Node) => ({
- conversion: $convertHeadingElement,
- priority: 0,
- }),
- h4: (node: Node) => ({
- conversion: $convertHeadingElement,
- priority: 0,
- }),
- h5: (node: Node) => ({
- conversion: $convertHeadingElement,
- priority: 0,
- }),
- h6: (node: Node) => ({
- conversion: $convertHeadingElement,
- priority: 0,
- }),
- };
- }
-}
-
-function $convertHeadingElement(element: HTMLElement): DOMConversionOutput {
- const nodeName = element.nodeName.toLowerCase();
- let node = null;
- if (
- nodeName === 'h1' ||
- nodeName === 'h2' ||
- nodeName === 'h3' ||
- nodeName === 'h4' ||
- nodeName === 'h5' ||
- nodeName === 'h6'
- ) {
- node = $createCustomHeadingNode(nodeName);
- setCommonBlockPropsFromElement(element, node);
- }
- return {node};
-}
-
-export function $createCustomHeadingNode(tag: HeadingTagType) {
- return new CustomHeadingNode(tag);
-}
-
-export function $isCustomHeadingNode(node: LexicalNode | null | undefined): node is CustomHeadingNode {
- return node instanceof CustomHeadingNode;
-}
\ No newline at end of file
+++ /dev/null
-import {
- DOMConversionMap,
- DOMConversionOutput,
- LexicalNode,
- Spread
-} from "lexical";
-import {EditorConfig} from "lexical/LexicalEditor";
-import {QuoteNode, SerializedQuoteNode} from "@lexical/rich-text";
-import {
- CommonBlockAlignment, commonPropertiesDifferent, deserializeCommonBlockNode,
- SerializedCommonBlockNode,
- setCommonBlockPropsFromElement,
- updateElementWithCommonBlockProps
-} from "./_common";
-
-
-export type SerializedCustomQuoteNode = Spread<SerializedCommonBlockNode, SerializedQuoteNode>
-
-export class CustomQuoteNode extends QuoteNode {
- __id: string = '';
- __alignment: CommonBlockAlignment = '';
- __inset: number = 0;
-
- static getType() {
- return 'custom-quote';
- }
-
- 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: CustomQuoteNode) {
- const newNode = new CustomQuoteNode(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: CustomQuoteNode): boolean {
- return commonPropertiesDifferent(prevNode, this);
- }
-
- exportJSON(): SerializedCustomQuoteNode {
- return {
- ...super.exportJSON(),
- type: 'custom-quote',
- version: 1,
- id: this.__id,
- alignment: this.__alignment,
- inset: this.__inset,
- };
- }
-
- static importJSON(serializedNode: SerializedCustomQuoteNode): CustomQuoteNode {
- const node = $createCustomQuoteNode();
- deserializeCommonBlockNode(serializedNode, node);
- return node;
- }
-
- static importDOM(): DOMConversionMap | null {
- return {
- blockquote: (node: Node) => ({
- conversion: $convertBlockquoteElement,
- priority: 0,
- }),
- };
- }
-}
-
-function $convertBlockquoteElement(element: HTMLElement): DOMConversionOutput {
- const node = $createCustomQuoteNode();
- setCommonBlockPropsFromElement(element, node);
- return {node};
-}
-
-export function $createCustomQuoteNode() {
- return new CustomQuoteNode();
-}
-
-export function $isCustomQuoteNode(node: LexicalNode | null | undefined): node is CustomQuoteNode {
- return node instanceof CustomQuoteNode;
-}
\ No newline at end of file
-import {HeadingNode, QuoteNode} from '@lexical/rich-text';
import {CalloutNode} from './callout';
import {
ElementNode,
import {CustomListItemNode} from "./custom-list-item";
import {CustomTableCellNode} from "./custom-table-cell";
import {CustomTableRowNode} from "./custom-table-row";
-import {CustomHeadingNode} from "./custom-heading";
-import {CustomQuoteNode} from "./custom-quote";
import {CustomListNode} from "./custom-list";
+import {HeadingNode} from "@lexical/rich-text/LexicalHeadingNode";
+import {QuoteNode} from "@lexical/rich-text/LexicalQuoteNode";
/**
* Load the nodes for lexical.
export function getNodesForPageEditor(): (KlassConstructor<typeof LexicalNode> | LexicalNodeReplacement)[] {
return [
CalloutNode,
- CustomHeadingNode,
- CustomQuoteNode,
+ HeadingNode,
+ QuoteNode,
CustomListNode,
CustomListItemNode, // TODO - Alignment?
CustomTableNode,
MediaNode, // TODO - Alignment
ParagraphNode,
LinkNode,
- {
- replace: HeadingNode,
- with: (node: HeadingNode) => {
- return new CustomHeadingNode(node.__tag);
- }
- },
- {
- replace: QuoteNode,
- with: (node: QuoteNode) => {
- return new CustomQuoteNode();
- }
- },
{
replace: ListNode,
with: (node: ListNode) => {
toggleSelectionAsHeading, toggleSelectionAsList,
toggleSelectionAsParagraph
} from "../utils/formats";
-import {HeadingTagType} from "@lexical/rich-text";
import {EditorUiContext} from "../ui/framework/core";
import {$getNodeFromSelection} from "../utils/selection";
import {$isLinkNode, LinkNode} from "@lexical/link";
import {$showLinkForm} from "../ui/defaults/forms/objects";
import {showLinkSelector} from "../utils/links";
+import {HeadingTagType} from "@lexical/rich-text/LexicalHeadingNode";
function headerHandler(editor: LexicalEditor, tag: HeadingTagType): boolean {
toggleSelectionAsHeading(editor, tag);
import {EditorButtonDefinition} from "../../framework/buttons";
import {EditorUiContext} from "../../framework/core";
import {$isParagraphNode, BaseSelection, LexicalNode} from "lexical";
-import {
- $isHeadingNode,
- $isQuoteNode,
- HeadingNode,
- HeadingTagType
-} from "@lexical/rich-text";
import {$selectionContainsNodeType, $toggleSelectionBlockNodeType} from "../../../utils/selection";
import {
toggleSelectionAsBlockquote,
toggleSelectionAsHeading,
toggleSelectionAsParagraph
} from "../../../utils/formats";
+import {$isHeadingNode, HeadingNode, HeadingTagType} from "@lexical/rich-text/LexicalHeadingNode";
+import {$isQuoteNode} from "@lexical/rich-text/LexicalQuoteNode";
function buildCalloutButton(category: CalloutCategory, name: string): EditorButtonDefinition {
return {
import {EditorContainerUiElement} from "../core";
import {el} from "../../../utils/dom";
import {EditorFormField} from "../forms";
-import {CustomHeadingNode} from "../../../nodes/custom-heading";
import {$getAllNodesOfType} from "../../../utils/nodes";
-import {$isHeadingNode} from "@lexical/rich-text";
import {uniqueIdSmall} from "../../../../services/util";
+import {$isHeadingNode, HeadingNode} from "@lexical/rich-text/LexicalHeadingNode";
export class LinkField extends EditorContainerUiElement {
protected input: EditorFormField;
- protected headerMap = new Map<string, CustomHeadingNode>();
+ protected headerMap = new Map<string, HeadingNode>();
constructor(input: EditorFormField) {
super([input]);
return container;
}
- updateFormFromHeader(header: CustomHeadingNode) {
+ updateFormFromHeader(header: HeadingNode) {
this.getHeaderIdAndText(header).then(({id, text}) => {
console.log('updating form', id, text);
const modal = this.getContext().manager.getActiveModal('link');
});
}
- getHeaderIdAndText(header: CustomHeadingNode): Promise<{id: string, text: string}> {
+ getHeaderIdAndText(header: HeadingNode): Promise<{id: string, text: string}> {
return new Promise((res) => {
this.getContext().editor.update(() => {
let id = header.getId();
updateDataList(listEl: HTMLElement) {
this.getContext().editor.getEditorState().read(() => {
- const headers = $getAllNodesOfType($isHeadingNode) as CustomHeadingNode[];
+ const headers = $getAllNodesOfType($isHeadingNode) as HeadingNode[];
this.headerMap.clear();
const listEls: HTMLElement[] = [];
-import {$isQuoteNode, HeadingNode, HeadingTagType} from "@lexical/rich-text";
import {
$createParagraphNode,
$createTextNode,
$toggleSelectionBlockNodeType,
getLastSelection
} from "./selection";
-import {$createCustomHeadingNode, $isCustomHeadingNode} from "../nodes/custom-heading";
-import {$createCustomQuoteNode} from "../nodes/custom-quote";
import {$createCodeBlockNode, $isCodeBlockNode, $openCodeEditorForNode, CodeBlockNode} from "../nodes/code-block";
import {$createCalloutNode, $isCalloutNode, CalloutCategory} from "../nodes/callout";
import {insertList, ListNode, ListType, removeList} from "@lexical/list";
import {$isCustomListNode} from "../nodes/custom-list";
import {$createLinkNode, $isLinkNode} from "@lexical/link";
+import {$createHeadingNode, $isHeadingNode, HeadingTagType} from "@lexical/rich-text/LexicalHeadingNode";
+import {$createQuoteNode, $isQuoteNode} from "@lexical/rich-text/LexicalQuoteNode";
const $isHeaderNodeOfTag = (node: LexicalNode | null | undefined, tag: HeadingTagType) => {
- return $isCustomHeadingNode(node) && (node as HeadingNode).getTag() === tag;
+ return $isHeadingNode(node) && node.getTag() === tag;
};
export function toggleSelectionAsHeading(editor: LexicalEditor, tag: HeadingTagType) {
editor.update(() => {
$toggleSelectionBlockNodeType(
(node) => $isHeaderNodeOfTag(node, tag),
- () => $createCustomHeadingNode(tag),
+ () => $createHeadingNode(tag),
)
});
}
export function toggleSelectionAsBlockquote(editor: LexicalEditor) {
editor.update(() => {
- $toggleSelectionBlockNodeType($isQuoteNode, $createCustomQuoteNode);
+ $toggleSelectionBlockNodeType($isQuoteNode, $createQuoteNode);
});
}