@webiny/lexical-nodes 0.0.0-unstable.06b2ede40f

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/FontColorNode.d.ts +43 -0
  2. package/FontColorNode.js +122 -0
  3. package/FontColorNode.js.map +1 -0
  4. package/HeadingNode.d.ts +40 -0
  5. package/HeadingNode.js +195 -0
  6. package/HeadingNode.js.map +1 -0
  7. package/ImageNode.d.ts +56 -0
  8. package/ImageNode.js +164 -0
  9. package/ImageNode.js.map +1 -0
  10. package/LICENSE +21 -0
  11. package/LinkNode.d.ts +101 -0
  12. package/LinkNode.js +327 -0
  13. package/LinkNode.js.map +1 -0
  14. package/ListItemNode.d.ts +43 -0
  15. package/ListItemNode.js +363 -0
  16. package/ListItemNode.js.map +1 -0
  17. package/ListNode.d.ts +53 -0
  18. package/ListNode.js +248 -0
  19. package/ListNode.js.map +1 -0
  20. package/ParagraphNode.d.ts +39 -0
  21. package/ParagraphNode.js +157 -0
  22. package/ParagraphNode.js.map +1 -0
  23. package/QuoteNode.d.ts +38 -0
  24. package/QuoteNode.js +120 -0
  25. package/QuoteNode.js.map +1 -0
  26. package/README.md +6 -0
  27. package/components/ImageNode/ContentEditable.css +22 -0
  28. package/components/ImageNode/ContentEditable.d.ts +12 -0
  29. package/components/ImageNode/ContentEditable.js +19 -0
  30. package/components/ImageNode/ContentEditable.js.map +1 -0
  31. package/components/ImageNode/ImageComponent.css +43 -0
  32. package/components/ImageNode/ImageComponent.d.ts +18 -0
  33. package/components/ImageNode/ImageComponent.js +235 -0
  34. package/components/ImageNode/ImageComponent.js.map +1 -0
  35. package/components/ImageNode/ImageResizer.d.ts +24 -0
  36. package/components/ImageNode/ImageResizer.js +211 -0
  37. package/components/ImageNode/ImageResizer.js.map +1 -0
  38. package/components/ImageNode/Placeholder.css +20 -0
  39. package/components/ImageNode/Placeholder.d.ts +15 -0
  40. package/components/ImageNode/Placeholder.js +24 -0
  41. package/components/ImageNode/Placeholder.js.map +1 -0
  42. package/components/ImageNode/SharedHistoryContext.d.ts +10 -0
  43. package/components/ImageNode/SharedHistoryContext.js +19 -0
  44. package/components/ImageNode/SharedHistoryContext.js.map +1 -0
  45. package/generateInitialLexicalValue.d.ts +4 -0
  46. package/generateInitialLexicalValue.js +27 -0
  47. package/generateInitialLexicalValue.js.map +1 -0
  48. package/index.d.ts +19 -0
  49. package/index.js +51 -0
  50. package/index.js.map +1 -0
  51. package/package.json +39 -0
  52. package/prepareLexicalState.d.ts +2 -0
  53. package/prepareLexicalState.js +53 -0
  54. package/prepareLexicalState.js.map +1 -0
  55. package/types.d.ts +11 -0
  56. package/types.js +3 -0
  57. package/types.js.map +1 -0
  58. package/utils/clearNodeFormating.d.ts +2 -0
  59. package/utils/clearNodeFormating.js +23 -0
  60. package/utils/clearNodeFormating.js.map +1 -0
  61. package/utils/formatList.d.ts +19 -0
  62. package/utils/formatList.js +412 -0
  63. package/utils/formatList.js.map +1 -0
  64. package/utils/formatToHeading.d.ts +3 -0
  65. package/utils/formatToHeading.js +19 -0
  66. package/utils/formatToHeading.js.map +1 -0
  67. package/utils/formatToParagraph.d.ts +2 -0
  68. package/utils/formatToParagraph.js +13 -0
  69. package/utils/formatToParagraph.js.map +1 -0
  70. package/utils/formatToQuote.d.ts +2 -0
  71. package/utils/formatToQuote.js +19 -0
  72. package/utils/formatToQuote.js.map +1 -0
  73. package/utils/getStyleId.d.ts +11 -0
  74. package/utils/getStyleId.js +14 -0
  75. package/utils/getStyleId.js.map +1 -0
  76. package/utils/listNode.d.ts +21 -0
  77. package/utils/listNode.js +103 -0
  78. package/utils/listNode.js.map +1 -0
  79. package/utils/toggleLink.d.ts +8 -0
  80. package/utils/toggleLink.js +131 -0
  81. package/utils/toggleLink.js.map +1 -0
@@ -0,0 +1,43 @@
1
+ import type { EditorConfig, LexicalNode, SerializedTextNode, Spread } from "lexical";
2
+ import { TextNode } from "lexical";
3
+ import type { EditorTheme } from "@webiny/lexical-theme";
4
+ export declare class ThemeColorValue {
5
+ private readonly name;
6
+ private value;
7
+ constructor(value: string, name?: string);
8
+ getValue(): string;
9
+ getName(): string;
10
+ updateFromTheme(theme: EditorTheme): void;
11
+ }
12
+ export declare const ADD_FONT_COLOR_COMMAND: import("lexical").LexicalCommand<FontColorPayload>;
13
+ export interface FontColorPayload {
14
+ color: ThemeColorValue;
15
+ }
16
+ export type SerializedFontColorNode = Spread<{
17
+ themeColor: string;
18
+ color: string;
19
+ type: "wby-font-color";
20
+ }, SerializedTextNode>;
21
+ /**
22
+ * Main responsibility of this node is to apply custom or Webiny theme color to selected text.
23
+ * Extends the original TextNode node to add additional transformation and support for webiny theme font color.
24
+ */
25
+ export declare class FontColorNode extends TextNode {
26
+ private readonly __color;
27
+ constructor(text: string, color: ThemeColorValue, key?: string);
28
+ static getType(): string;
29
+ static clone(node: FontColorNode): FontColorNode;
30
+ static importJSON(serializedNode: SerializedFontColorNode): TextNode;
31
+ splitText(...splitOffsets: Array<number>): Array<FontColorNode>;
32
+ exportJSON(): SerializedFontColorNode;
33
+ private addColorValueToHTMLElement;
34
+ updateDOM(prevNode: this, dom: HTMLElement, config: EditorConfig): boolean;
35
+ getColorStyle(): {
36
+ color: string;
37
+ themeColor: string;
38
+ };
39
+ createDOM(config: EditorConfig): HTMLElement;
40
+ }
41
+ export declare const $createFontColorNode: (text: string, color: ThemeColorValue) => FontColorNode;
42
+ export declare const $isFontColorNode: (node: LexicalNode) => node is FontColorNode;
43
+ export declare function $applyStylesToNode(node: TextNode, source: TextNode): void;
@@ -0,0 +1,122 @@
1
+ import { $getSelection, $isRangeSelection, createCommand, TextNode } from "lexical";
2
+ export class ThemeColorValue {
3
+ // Webiny theme color variable, like color1, color2, etc.
4
+
5
+ // This can be a HEX value or a CSS variable.
6
+
7
+ constructor(value, name) {
8
+ this.value = value;
9
+ this.name = name ?? "custom";
10
+ }
11
+ getValue() {
12
+ return this.value;
13
+ }
14
+ getName() {
15
+ return this.name;
16
+ }
17
+ updateFromTheme(theme) {
18
+ if (theme?.styles?.colors && this.name !== "custom") {
19
+ this.value = theme.styles?.colors[this.name];
20
+ }
21
+ }
22
+ }
23
+ export const ADD_FONT_COLOR_COMMAND = createCommand("ADD_FONT_COLOR_COMMAND");
24
+ const FontColorNodeAttrName = "data-theme-font-color-name";
25
+ /**
26
+ * Main responsibility of this node is to apply custom or Webiny theme color to selected text.
27
+ * Extends the original TextNode node to add additional transformation and support for webiny theme font color.
28
+ */
29
+ export class FontColorNode extends TextNode {
30
+ constructor(text, color, key) {
31
+ super(text, key);
32
+ this.__color = color;
33
+ }
34
+ static getType() {
35
+ return "wby-font-color";
36
+ }
37
+ static clone(node) {
38
+ return new FontColorNode(node.__text, node.__color, node.__key);
39
+ }
40
+ static importJSON(serializedNode) {
41
+ const node = new FontColorNode(serializedNode.text, new ThemeColorValue(serializedNode.color, serializedNode.themeColor));
42
+ node.setTextContent(serializedNode.text);
43
+ node.setFormat(serializedNode.format);
44
+ node.setDetail(serializedNode.detail);
45
+ node.setMode(serializedNode.mode);
46
+ node.setStyle(serializedNode.style);
47
+ return node;
48
+ }
49
+ splitText(...splitOffsets) {
50
+ const newNodes = super.splitText(...splitOffsets);
51
+ const selection = $getSelection();
52
+
53
+ // After splitting, we need to re-apply styling to the new TextNodes.
54
+ const fontColorNodes = newNodes.map(node => {
55
+ if (node instanceof FontColorNode) {
56
+ return node;
57
+ }
58
+ const fontColorNode = $createFontColorNode(node.getTextContent(), this.__color);
59
+ $applyStylesToNode(fontColorNode, this);
60
+ const newNode = node.replace(fontColorNode);
61
+
62
+ // Since we're replacing the existing node, we need to update the selection keys.
63
+ // This is very important to not break the editor functionality!
64
+ if ($isRangeSelection(selection)) {
65
+ const anchor = selection.anchor;
66
+ const focus = selection.focus;
67
+ if (anchor.key === node.getKey()) {
68
+ anchor.key = newNode.getKey();
69
+ }
70
+ if (focus.key === node.getKey()) {
71
+ focus.key = newNode.getKey();
72
+ }
73
+ }
74
+ return newNode;
75
+ });
76
+ return fontColorNodes;
77
+ }
78
+ exportJSON() {
79
+ return {
80
+ ...super.exportJSON(),
81
+ themeColor: this.__color.getName(),
82
+ color: this.__color.getValue(),
83
+ type: "wby-font-color"
84
+ };
85
+ }
86
+ addColorValueToHTMLElement(element, theme) {
87
+ // Update color from webiny theme
88
+ this.__color.updateFromTheme(theme);
89
+ element.setAttribute(FontColorNodeAttrName, this.__color.getName());
90
+ element.style.color = this.__color.getValue();
91
+ return element;
92
+ }
93
+ updateDOM(prevNode, dom, config) {
94
+ const isUpdated = super.updateDOM(prevNode, dom, config);
95
+ this.__color.updateFromTheme(config.theme);
96
+ dom.setAttribute(FontColorNodeAttrName, this.__color.getName());
97
+ dom.style.color = this.__color.getValue();
98
+ return isUpdated;
99
+ }
100
+ getColorStyle() {
101
+ return {
102
+ color: this.__color.getValue(),
103
+ themeColor: this.__color.getName()
104
+ };
105
+ }
106
+ createDOM(config) {
107
+ const element = super.createDOM(config);
108
+ return this.addColorValueToHTMLElement(element, config.theme);
109
+ }
110
+ }
111
+ export const $createFontColorNode = (text, color) => {
112
+ return new FontColorNode(text, color);
113
+ };
114
+ export const $isFontColorNode = node => {
115
+ return node instanceof FontColorNode;
116
+ };
117
+ export function $applyStylesToNode(node, source) {
118
+ node.setFormat(source.getFormat());
119
+ node.setStyle(source.getStyle());
120
+ }
121
+
122
+ //# sourceMappingURL=FontColorNode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["$getSelection","$isRangeSelection","createCommand","TextNode","ThemeColorValue","constructor","value","name","getValue","getName","updateFromTheme","theme","styles","colors","ADD_FONT_COLOR_COMMAND","FontColorNodeAttrName","FontColorNode","text","color","key","__color","getType","clone","node","__text","__key","importJSON","serializedNode","themeColor","setTextContent","setFormat","format","setDetail","detail","setMode","mode","setStyle","style","splitText","splitOffsets","newNodes","selection","fontColorNodes","map","fontColorNode","$createFontColorNode","getTextContent","$applyStylesToNode","newNode","replace","anchor","focus","getKey","exportJSON","type","addColorValueToHTMLElement","element","setAttribute","updateDOM","prevNode","dom","config","isUpdated","getColorStyle","createDOM","$isFontColorNode","source","getFormat","getStyle"],"sources":["FontColorNode.ts"],"sourcesContent":["import type { EditorConfig, LexicalNode, SerializedTextNode, Spread } from \"lexical\";\nimport { $getSelection, $isRangeSelection, createCommand, TextNode } from \"lexical\";\nimport type { EditorTheme } from \"@webiny/lexical-theme\";\n\nexport class ThemeColorValue {\n // Webiny theme color variable, like color1, color2, etc.\n private readonly name: string;\n // This can be a HEX value or a CSS variable.\n private value: string;\n\n constructor(value: string, name?: string) {\n this.value = value;\n this.name = name ?? \"custom\";\n }\n\n getValue() {\n return this.value;\n }\n\n getName() {\n return this.name;\n }\n\n updateFromTheme(theme: EditorTheme) {\n if (theme?.styles?.colors && this.name !== \"custom\") {\n this.value = theme.styles?.colors[this.name];\n }\n }\n}\n\nexport const ADD_FONT_COLOR_COMMAND = createCommand<FontColorPayload>(\"ADD_FONT_COLOR_COMMAND\");\n\nconst FontColorNodeAttrName = \"data-theme-font-color-name\";\n\nexport interface FontColorPayload {\n color: ThemeColorValue;\n}\n\nexport type SerializedFontColorNode = Spread<\n {\n themeColor: string;\n color: string;\n type: \"wby-font-color\";\n },\n SerializedTextNode\n>;\n\n/**\n * Main responsibility of this node is to apply custom or Webiny theme color to selected text.\n * Extends the original TextNode node to add additional transformation and support for webiny theme font color.\n */\nexport class FontColorNode extends TextNode {\n private readonly __color: ThemeColorValue;\n\n constructor(text: string, color: ThemeColorValue, key?: string) {\n super(text, key);\n this.__color = color;\n }\n\n static override getType(): string {\n return \"wby-font-color\";\n }\n\n static override clone(node: FontColorNode): FontColorNode {\n return new FontColorNode(node.__text, node.__color, node.__key);\n }\n\n static override importJSON(serializedNode: SerializedFontColorNode): TextNode {\n const node = new FontColorNode(\n serializedNode.text,\n new ThemeColorValue(serializedNode.color, serializedNode.themeColor)\n );\n node.setTextContent(serializedNode.text);\n node.setFormat(serializedNode.format);\n node.setDetail(serializedNode.detail);\n node.setMode(serializedNode.mode);\n node.setStyle(serializedNode.style);\n return node;\n }\n\n override splitText(...splitOffsets: Array<number>): Array<FontColorNode> {\n const newNodes = super.splitText(...splitOffsets);\n\n const selection = $getSelection();\n\n // After splitting, we need to re-apply styling to the new TextNodes.\n const fontColorNodes = newNodes.map(node => {\n if (node instanceof FontColorNode) {\n return node;\n }\n\n const fontColorNode = $createFontColorNode(node.getTextContent(), this.__color);\n $applyStylesToNode(fontColorNode, this);\n\n const newNode = node.replace(fontColorNode);\n\n // Since we're replacing the existing node, we need to update the selection keys.\n // This is very important to not break the editor functionality!\n if ($isRangeSelection(selection)) {\n const anchor = selection.anchor;\n const focus = selection.focus;\n\n if (anchor.key === node.getKey()) {\n anchor.key = newNode.getKey();\n }\n\n if (focus.key === node.getKey()) {\n focus.key = newNode.getKey();\n }\n }\n\n return newNode;\n });\n\n return fontColorNodes as Array<FontColorNode>;\n }\n\n override exportJSON(): SerializedFontColorNode {\n return {\n ...super.exportJSON(),\n themeColor: this.__color.getName(),\n color: this.__color.getValue(),\n type: \"wby-font-color\"\n };\n }\n\n private addColorValueToHTMLElement(element: HTMLElement, theme: EditorTheme): HTMLElement {\n // Update color from webiny theme\n this.__color.updateFromTheme(theme);\n element.setAttribute(FontColorNodeAttrName, this.__color.getName());\n element.style.color = this.__color.getValue();\n return element;\n }\n\n override updateDOM(prevNode: this, dom: HTMLElement, config: EditorConfig): boolean {\n const isUpdated = super.updateDOM(prevNode, dom, config);\n this.__color.updateFromTheme(config.theme as EditorTheme);\n\n dom.setAttribute(FontColorNodeAttrName, this.__color.getName());\n dom.style.color = this.__color.getValue();\n return isUpdated;\n }\n\n getColorStyle() {\n return {\n color: this.__color.getValue(),\n themeColor: this.__color.getName()\n };\n }\n\n override createDOM(config: EditorConfig): HTMLElement {\n const element = super.createDOM(config);\n return this.addColorValueToHTMLElement(element, config.theme as EditorTheme);\n }\n}\n\nexport const $createFontColorNode = (text: string, color: ThemeColorValue): FontColorNode => {\n return new FontColorNode(text, color);\n};\n\nexport const $isFontColorNode = (node: LexicalNode): node is FontColorNode => {\n return node instanceof FontColorNode;\n};\n\nexport function $applyStylesToNode(node: TextNode, source: TextNode) {\n node.setFormat(source.getFormat());\n node.setStyle(source.getStyle());\n}\n"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,40 @@
1
+ import type { EditorConfig, LexicalNode, NodeKey, RangeSelection, Spread, LexicalEditor, DOMExportOutput, DOMConversionMap } from "lexical";
2
+ import type { HeadingTagType, SerializedHeadingNode as BaseSerializedHeadingNode } from "@lexical/rich-text";
3
+ import { HeadingNode as BaseHeadingNode } from "@lexical/rich-text";
4
+ import type { EditorTheme } from "@webiny/lexical-theme";
5
+ import type { ParagraphNode } from "./ParagraphNode";
6
+ import type { TypographyStylesNode, ThemeStyleValue } from "./types";
7
+ export type SerializeHeadingNode = Spread<{
8
+ styles?: ThemeStyleValue[];
9
+ styleId?: string;
10
+ className?: string;
11
+ type: "wby-heading";
12
+ }, BaseSerializedHeadingNode>;
13
+ interface HeadingNodeOptions {
14
+ className?: string;
15
+ styleId?: string;
16
+ key?: NodeKey;
17
+ }
18
+ export declare class HeadingNode extends BaseHeadingNode implements TypographyStylesNode {
19
+ private __styleId;
20
+ private __className;
21
+ constructor(tag: HeadingTagType, options?: HeadingNodeOptions);
22
+ getStyleId(): string | undefined;
23
+ setStyleId(styleId: string | undefined): void;
24
+ setClassName(className: string | undefined): void;
25
+ getClassName(): string | undefined;
26
+ static getType(): string;
27
+ static clone(node: HeadingNode): HeadingNode;
28
+ createDOM(config: EditorConfig): HTMLElement;
29
+ exportDOM(editor: LexicalEditor): DOMExportOutput;
30
+ static importDOM(): DOMConversionMap | null;
31
+ static importJSON(serializedNode: SerializeHeadingNode): BaseHeadingNode;
32
+ exportJSON(): SerializeHeadingNode;
33
+ insertNewAfter(selection?: RangeSelection, restoreSelection?: boolean): ParagraphNode | HeadingNode;
34
+ collapseAtStart(): true;
35
+ protected updateElementWithThemeClasses(element: HTMLElement, theme: EditorTheme): HTMLElement;
36
+ private setDefaultTypography;
37
+ }
38
+ export declare function $createHeadingNode(tag: HeadingTagType, styleId?: string): HeadingNode;
39
+ export declare function $isHeadingNode(node: LexicalNode | null | undefined): node is HeadingNode;
40
+ export {};
package/HeadingNode.js ADDED
@@ -0,0 +1,195 @@
1
+ import { $applyNodeReplacement, setNodeIndentFromDOM } from "lexical";
2
+ import { addClassNamesToElement } from "@lexical/utils";
3
+ import { HeadingNode as BaseHeadingNode } from "@lexical/rich-text";
4
+ import { findTypographyStyleByHtmlTag } from "@webiny/lexical-theme";
5
+ import { getStyleId } from "./utils/getStyleId";
6
+ function isGoogleDocsTitle(domNode) {
7
+ if (domNode.nodeName.toLowerCase() === "span") {
8
+ return domNode.style.fontSize === "26pt";
9
+ }
10
+ return false;
11
+ }
12
+ function $convertHeadingElement(element) {
13
+ const nodeName = element.nodeName.toLowerCase();
14
+ let node = null;
15
+ if (nodeName === "h1" || nodeName === "h2" || nodeName === "h3" || nodeName === "h4" || nodeName === "h5" || nodeName === "h6") {
16
+ node = $createHeadingNode(nodeName);
17
+ if (element.style !== null) {
18
+ setNodeIndentFromDOM(element, node);
19
+ node.setFormat(element.style.textAlign);
20
+ }
21
+ }
22
+ return {
23
+ node
24
+ };
25
+ }
26
+ export class HeadingNode extends BaseHeadingNode {
27
+ constructor(tag, options = {}) {
28
+ const {
29
+ styleId,
30
+ key,
31
+ className
32
+ } = options;
33
+ super(tag, key);
34
+ this.__styleId = styleId;
35
+ this.__className = className;
36
+ }
37
+ getStyleId() {
38
+ return this.__styleId;
39
+ }
40
+ setStyleId(styleId) {
41
+ this.__styleId = styleId;
42
+ }
43
+ setClassName(className) {
44
+ this.__className = className;
45
+ }
46
+ getClassName() {
47
+ return this.__className;
48
+ }
49
+ static getType() {
50
+ return "wby-heading";
51
+ }
52
+ static clone(node) {
53
+ return new HeadingNode(node.getTag(), {
54
+ key: node.getKey(),
55
+ styleId: node.getStyleId(),
56
+ className: node.getClassName()
57
+ });
58
+ }
59
+ createDOM(config) {
60
+ const element = super.createDOM(config);
61
+ return this.updateElementWithThemeClasses(element, config.theme);
62
+ }
63
+ exportDOM(editor) {
64
+ const base = super.exportDOM(editor);
65
+ const element = base.element;
66
+ if (element && this.__className) {
67
+ element.classList.add(this.__className);
68
+ }
69
+ return {
70
+ ...base,
71
+ element
72
+ };
73
+ }
74
+ static importDOM() {
75
+ return {
76
+ h1: () => ({
77
+ conversion: $convertHeadingElement,
78
+ priority: 0
79
+ }),
80
+ h2: () => ({
81
+ conversion: $convertHeadingElement,
82
+ priority: 0
83
+ }),
84
+ h3: () => ({
85
+ conversion: $convertHeadingElement,
86
+ priority: 0
87
+ }),
88
+ h4: () => ({
89
+ conversion: $convertHeadingElement,
90
+ priority: 0
91
+ }),
92
+ h5: () => ({
93
+ conversion: $convertHeadingElement,
94
+ priority: 0
95
+ }),
96
+ h6: () => ({
97
+ conversion: $convertHeadingElement,
98
+ priority: 0
99
+ }),
100
+ p: node => {
101
+ // domNode is a <p> since we matched it by nodeName
102
+ const firstChild = node.firstChild;
103
+ if (firstChild !== null && isGoogleDocsTitle(firstChild)) {
104
+ return {
105
+ conversion: () => ({
106
+ node: null
107
+ }),
108
+ priority: 3
109
+ };
110
+ }
111
+ return null;
112
+ },
113
+ span: node => {
114
+ if (isGoogleDocsTitle(node)) {
115
+ return {
116
+ conversion: () => {
117
+ return {
118
+ node: $createHeadingNode("h1")
119
+ };
120
+ },
121
+ priority: 3
122
+ };
123
+ }
124
+ return null;
125
+ }
126
+ };
127
+ }
128
+ static importJSON(serializedNode) {
129
+ const node = $createHeadingNode(serializedNode.tag);
130
+ node.setFormat(serializedNode.format);
131
+ node.setIndent(serializedNode.indent);
132
+ node.setDirection(serializedNode.direction);
133
+ const styleId = getStyleId({
134
+ styleId: serializedNode.styleId,
135
+ styles: serializedNode.styles
136
+ });
137
+ node.setStyleId(styleId);
138
+ node.setClassName(serializedNode.className);
139
+ return node;
140
+ }
141
+ exportJSON() {
142
+ return {
143
+ ...super.exportJSON(),
144
+ type: "wby-heading",
145
+ styleId: this.__styleId,
146
+ className: this.__className
147
+ };
148
+ }
149
+
150
+ // Mutation
151
+ insertNewAfter(selection, restoreSelection = true) {
152
+ // Next line for headings are always headings with the same tag
153
+ const newElement = $createHeadingNode(this.getTag());
154
+ const direction = this.getDirection();
155
+ newElement.setDirection(direction);
156
+ this.insertAfter(newElement, restoreSelection);
157
+ return newElement;
158
+ }
159
+ collapseAtStart() {
160
+ const newElement = $createHeadingNode(this.getTag());
161
+ const children = this.getChildren();
162
+ children.forEach(child => newElement.append(child));
163
+ this.replace(newElement);
164
+ return true;
165
+ }
166
+ updateElementWithThemeClasses(element, theme) {
167
+ if (!theme?.emotionMap) {
168
+ return element;
169
+ }
170
+ if (!this.__styleId || !this.__className) {
171
+ this.setDefaultTypography(theme.emotionMap);
172
+ }
173
+ if (this.__className) {
174
+ addClassNamesToElement(element, this.__className);
175
+ }
176
+ return element;
177
+ }
178
+ setDefaultTypography(themeEmotionMap) {
179
+ const typographyStyle = findTypographyStyleByHtmlTag(this.getTag(), themeEmotionMap);
180
+ if (typographyStyle) {
181
+ this.__styleId = typographyStyle.id;
182
+ this.__className = typographyStyle.className;
183
+ }
184
+ }
185
+ }
186
+ export function $createHeadingNode(tag, styleId) {
187
+ return $applyNodeReplacement(new HeadingNode(tag, {
188
+ styleId
189
+ }));
190
+ }
191
+ export function $isHeadingNode(node) {
192
+ return node instanceof HeadingNode;
193
+ }
194
+
195
+ //# sourceMappingURL=HeadingNode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["$applyNodeReplacement","setNodeIndentFromDOM","addClassNamesToElement","HeadingNode","BaseHeadingNode","findTypographyStyleByHtmlTag","getStyleId","isGoogleDocsTitle","domNode","nodeName","toLowerCase","style","fontSize","$convertHeadingElement","element","node","$createHeadingNode","setFormat","textAlign","constructor","tag","options","styleId","key","className","__styleId","__className","setStyleId","setClassName","getClassName","getType","clone","getTag","getKey","createDOM","config","updateElementWithThemeClasses","theme","exportDOM","editor","base","classList","add","importDOM","h1","conversion","priority","h2","h3","h4","h5","h6","p","firstChild","span","importJSON","serializedNode","format","setIndent","indent","setDirection","direction","styles","exportJSON","type","insertNewAfter","selection","restoreSelection","newElement","getDirection","insertAfter","collapseAtStart","children","getChildren","forEach","child","append","replace","emotionMap","setDefaultTypography","themeEmotionMap","typographyStyle","id","$isHeadingNode"],"sources":["HeadingNode.ts"],"sourcesContent":["import type {\n EditorConfig,\n LexicalNode,\n NodeKey,\n RangeSelection,\n Spread,\n LexicalEditor,\n DOMExportOutput,\n DOMConversionMap\n} from \"lexical\";\nimport { $applyNodeReplacement, setNodeIndentFromDOM } from \"lexical\";\nimport { addClassNamesToElement } from \"@lexical/utils\";\nimport type {\n HeadingTagType,\n SerializedHeadingNode as BaseSerializedHeadingNode\n} from \"@lexical/rich-text\";\nimport { HeadingNode as BaseHeadingNode } from \"@lexical/rich-text\";\nimport type { EditorTheme, ThemeEmotionMap } from \"@webiny/lexical-theme\";\nimport { findTypographyStyleByHtmlTag } from \"@webiny/lexical-theme\";\nimport type { ParagraphNode } from \"~/ParagraphNode\";\nimport type { TypographyStylesNode, ThemeStyleValue } from \"~/types\";\nimport { getStyleId } from \"~/utils/getStyleId\";\n\nexport type SerializeHeadingNode = Spread<\n {\n styles?: ThemeStyleValue[];\n styleId?: string;\n className?: string;\n type: \"wby-heading\";\n },\n BaseSerializedHeadingNode\n>;\n\ninterface HeadingNodeOptions {\n className?: string;\n styleId?: string;\n key?: NodeKey;\n}\n\nfunction isGoogleDocsTitle(domNode: HTMLElement) {\n if (domNode.nodeName.toLowerCase() === \"span\") {\n return domNode.style.fontSize === \"26pt\";\n }\n return false;\n}\nfunction $convertHeadingElement(element: HTMLElement) {\n const nodeName = element.nodeName.toLowerCase();\n let node = null;\n if (\n nodeName === \"h1\" ||\n nodeName === \"h2\" ||\n nodeName === \"h3\" ||\n nodeName === \"h4\" ||\n nodeName === \"h5\" ||\n nodeName === \"h6\"\n ) {\n node = $createHeadingNode(nodeName);\n if (element.style !== null) {\n setNodeIndentFromDOM(element, node);\n node.setFormat(element.style.textAlign as any);\n }\n }\n return {\n node\n };\n}\n\nexport class HeadingNode extends BaseHeadingNode implements TypographyStylesNode {\n private __styleId: string | undefined;\n private __className: string | undefined;\n\n constructor(tag: HeadingTagType, options: HeadingNodeOptions = {}) {\n const { styleId, key, className } = options;\n\n super(tag, key);\n\n this.__styleId = styleId;\n this.__className = className;\n }\n\n getStyleId(): string | undefined {\n return this.__styleId;\n }\n\n setStyleId(styleId: string | undefined) {\n this.__styleId = styleId;\n }\n\n setClassName(className: string | undefined) {\n this.__className = className;\n }\n\n getClassName(): string | undefined {\n return this.__className;\n }\n\n static override getType(): string {\n return \"wby-heading\";\n }\n\n static override clone(node: HeadingNode): HeadingNode {\n return new HeadingNode(node.getTag(), {\n key: node.getKey(),\n styleId: node.getStyleId(),\n className: node.getClassName()\n });\n }\n\n override createDOM(config: EditorConfig): HTMLElement {\n const element = super.createDOM(config);\n return this.updateElementWithThemeClasses(element, config.theme as EditorTheme);\n }\n\n override exportDOM(editor: LexicalEditor): DOMExportOutput {\n const base = super.exportDOM(editor);\n\n const element = base.element as HTMLElement;\n if (element && this.__className) {\n element.classList.add(this.__className);\n }\n\n return { ...base, element };\n }\n\n static override importDOM(): DOMConversionMap | null {\n return {\n h1: () => ({\n conversion: $convertHeadingElement,\n priority: 0\n }),\n h2: () => ({\n conversion: $convertHeadingElement,\n priority: 0\n }),\n h3: () => ({\n conversion: $convertHeadingElement,\n priority: 0\n }),\n h4: () => ({\n conversion: $convertHeadingElement,\n priority: 0\n }),\n h5: () => ({\n conversion: $convertHeadingElement,\n priority: 0\n }),\n h6: () => ({\n conversion: $convertHeadingElement,\n priority: 0\n }),\n p: node => {\n // domNode is a <p> since we matched it by nodeName\n const firstChild = node.firstChild as HTMLElement;\n if (firstChild !== null && isGoogleDocsTitle(firstChild)) {\n return {\n conversion: () => ({\n node: null\n }),\n priority: 3\n };\n }\n return null;\n },\n span: node => {\n if (isGoogleDocsTitle(node)) {\n return {\n conversion: () => {\n return {\n node: $createHeadingNode(\"h1\")\n };\n },\n priority: 3\n };\n }\n return null;\n }\n };\n }\n\n static override importJSON(serializedNode: SerializeHeadingNode): BaseHeadingNode {\n const node = $createHeadingNode(serializedNode.tag);\n node.setFormat(serializedNode.format);\n node.setIndent(serializedNode.indent);\n node.setDirection(serializedNode.direction);\n\n const styleId = getStyleId({\n styleId: serializedNode.styleId,\n styles: serializedNode.styles\n });\n\n node.setStyleId(styleId);\n node.setClassName(serializedNode.className);\n\n return node;\n }\n\n override exportJSON(): SerializeHeadingNode {\n return {\n ...super.exportJSON(),\n type: \"wby-heading\",\n styleId: this.__styleId,\n className: this.__className\n };\n }\n\n // Mutation\n override insertNewAfter(\n selection?: RangeSelection,\n restoreSelection = true\n ): ParagraphNode | HeadingNode {\n // Next line for headings are always headings with the same tag\n const newElement = $createHeadingNode(this.getTag());\n const direction = this.getDirection();\n newElement.setDirection(direction);\n this.insertAfter(newElement, restoreSelection);\n return newElement;\n }\n\n override collapseAtStart(): true {\n const newElement = $createHeadingNode(this.getTag());\n const children = this.getChildren();\n children.forEach(child => newElement.append(child));\n this.replace(newElement);\n return true;\n }\n\n protected updateElementWithThemeClasses(element: HTMLElement, theme: EditorTheme): HTMLElement {\n if (!theme?.emotionMap) {\n return element;\n }\n\n if (!this.__styleId || !this.__className) {\n this.setDefaultTypography(theme.emotionMap);\n }\n\n if (this.__className) {\n addClassNamesToElement(element, this.__className);\n }\n\n return element;\n }\n\n private setDefaultTypography(themeEmotionMap: ThemeEmotionMap) {\n const typographyStyle = findTypographyStyleByHtmlTag(this.getTag(), themeEmotionMap);\n if (typographyStyle) {\n this.__styleId = typographyStyle.id;\n this.__className = typographyStyle.className;\n }\n }\n}\n\nexport function $createHeadingNode(tag: HeadingTagType, styleId?: string): HeadingNode {\n return $applyNodeReplacement(new HeadingNode(tag, { styleId }));\n}\n\nexport function $isHeadingNode(node: LexicalNode | null | undefined): node is HeadingNode {\n return node instanceof HeadingNode;\n}\n"],"mappings":"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","ignoreList":[]}
package/ImageNode.d.ts ADDED
@@ -0,0 +1,56 @@
1
+ /// <reference types="react" />
2
+ import type { DOMConversionMap, DOMExportOutput, EditorConfig, LexicalEditor, LexicalNode, NodeKey, SerializedEditor, SerializedLexicalNode, Spread } from "lexical";
3
+ import { DecoratorNode } from "lexical";
4
+ export type SerializedImageNode = Spread<{
5
+ id: string;
6
+ altText: string;
7
+ caption: SerializedEditor;
8
+ height?: number;
9
+ maxWidth: number;
10
+ showCaption: boolean;
11
+ src: string;
12
+ width?: number;
13
+ }, SerializedLexicalNode>;
14
+ export interface ImageNodeProps {
15
+ id: string;
16
+ src: string;
17
+ altText: string;
18
+ maxWidth: number;
19
+ width?: "inherit" | number;
20
+ height?: "inherit" | number;
21
+ showCaption?: boolean;
22
+ caption?: LexicalEditor;
23
+ captionsEnabled?: boolean;
24
+ }
25
+ export declare class ImageNode extends DecoratorNode<JSX.Element> {
26
+ __id: string;
27
+ __src: string;
28
+ __altText: string;
29
+ __width: "inherit" | number;
30
+ __height: "inherit" | number;
31
+ __maxWidth: number;
32
+ __showCaption: boolean;
33
+ __caption: LexicalEditor;
34
+ __captionsEnabled: boolean;
35
+ static getType(): string;
36
+ static clone(node: ImageNode): ImageNode;
37
+ static importJSON(serializedNode: SerializedImageNode): ImageNode;
38
+ exportDOM(): DOMExportOutput;
39
+ /**
40
+ * Control how an HTMLElement is represented in Lexical.
41
+ * DOM data comes from clipboard or parsing HTML to nodes with the available lexical functions.
42
+ * (@see @lexical/html package: https://github.com/facebook/lexical/blob/main/packages/lexical-html/README.md).
43
+ */
44
+ static importDOM(): DOMConversionMap | null;
45
+ constructor(props: ImageNodeProps, key?: NodeKey);
46
+ exportJSON(): SerializedImageNode;
47
+ setWidthAndHeight(width: "inherit" | number, height: "inherit" | number): void;
48
+ setShowCaption(showCaption: boolean): void;
49
+ createDOM(config: EditorConfig): HTMLElement;
50
+ updateDOM(): false;
51
+ getSrc(): string;
52
+ getAltText(): string;
53
+ decorate(): JSX.Element;
54
+ }
55
+ export declare function $createImageNode(props: ImageNodeProps, key?: string): ImageNode;
56
+ export declare function $isImageNode(node: LexicalNode | null | undefined): node is ImageNode;
package/ImageNode.js ADDED
@@ -0,0 +1,164 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ */
8
+ import React, { Suspense } from "react";
9
+ import { $applyNodeReplacement, createEditor, DecoratorNode } from "lexical";
10
+ const ImageComponent = /*#__PURE__*/React.lazy(() => {
11
+ return import(/* webpackChunkName: "LexicalNodesComponentsImageNodeImageComponent" */"./components/ImageNode/ImageComponent");
12
+ });
13
+ export class ImageNode extends DecoratorNode {
14
+ // Captions cannot yet be used within editor cells
15
+
16
+ static getType() {
17
+ return "wby-image";
18
+ }
19
+ static clone(node) {
20
+ return new ImageNode({
21
+ id: node.__id,
22
+ src: node.__src,
23
+ altText: node.__altText,
24
+ maxWidth: node.__maxWidth,
25
+ width: node.__width,
26
+ height: node.__height,
27
+ showCaption: node.__showCaption,
28
+ caption: node.__caption,
29
+ captionsEnabled: node.__captionsEnabled
30
+ }, node.__key);
31
+ }
32
+ static importJSON(serializedNode) {
33
+ const {
34
+ id,
35
+ altText,
36
+ height,
37
+ width,
38
+ maxWidth,
39
+ caption,
40
+ src,
41
+ showCaption
42
+ } = serializedNode;
43
+ const node = $createImageNode({
44
+ id,
45
+ altText,
46
+ height,
47
+ maxWidth,
48
+ showCaption,
49
+ src,
50
+ width
51
+ });
52
+ const nestedEditor = node.__caption;
53
+ const editorState = nestedEditor.parseEditorState(caption.editorState);
54
+ if (!editorState.isEmpty()) {
55
+ nestedEditor.setEditorState(editorState);
56
+ }
57
+ return node;
58
+ }
59
+ exportDOM() {
60
+ const element = document.createElement("img");
61
+ element.setAttribute("id", this.__id);
62
+ element.setAttribute("src", this.__src);
63
+ element.setAttribute("alt", this.__altText);
64
+ element.setAttribute("width", this.__width.toString());
65
+ element.setAttribute("height", this.__height.toString());
66
+ return {
67
+ element
68
+ };
69
+ }
70
+
71
+ /**
72
+ * Control how an HTMLElement is represented in Lexical.
73
+ * DOM data comes from clipboard or parsing HTML to nodes with the available lexical functions.
74
+ * (@see @lexical/html package: https://github.com/facebook/lexical/blob/main/packages/lexical-html/README.md).
75
+ */
76
+ static importDOM() {
77
+ /**
78
+ * By returning 'null' value, we are preventing image node to be created.
79
+ * Example of how to implement and create the node:
80
+ * https://github.com/facebook/lexical/blob/main/packages/lexical-playground/src/nodes/ImageNode.tsx#L94
81
+ */
82
+ return null;
83
+ }
84
+ constructor(props, key) {
85
+ super(key);
86
+ this.__id = props.id;
87
+ this.__src = props.src;
88
+ this.__altText = props.altText;
89
+ this.__maxWidth = props.maxWidth;
90
+ this.__width = props.width || "inherit";
91
+ this.__height = props.height || "inherit";
92
+ this.__showCaption = props.showCaption || false;
93
+ this.__caption = props.caption || createEditor();
94
+ this.__captionsEnabled = props.captionsEnabled || props.captionsEnabled === undefined;
95
+ }
96
+ exportJSON() {
97
+ return {
98
+ id: this.__id,
99
+ altText: this.getAltText(),
100
+ caption: this.__caption.toJSON(),
101
+ height: this.__height === "inherit" ? 0 : this.__height,
102
+ maxWidth: this.__maxWidth,
103
+ showCaption: this.__showCaption,
104
+ src: this.getSrc(),
105
+ type: "wby-image",
106
+ width: this.__width === "inherit" ? 0 : this.__width,
107
+ version: 1
108
+ };
109
+ }
110
+ setWidthAndHeight(width, height) {
111
+ const writable = this.getWritable();
112
+ writable.__width = width;
113
+ writable.__height = height;
114
+ }
115
+ setShowCaption(showCaption) {
116
+ const writable = this.getWritable();
117
+ writable.__showCaption = showCaption;
118
+ }
119
+
120
+ // View
121
+ createDOM(config) {
122
+ const span = document.createElement("span");
123
+ const theme = config.theme;
124
+ const className = theme.image;
125
+ if (className !== undefined) {
126
+ span.className = className;
127
+ }
128
+ return span;
129
+ }
130
+ updateDOM() {
131
+ return false;
132
+ }
133
+ getSrc() {
134
+ return this.__src;
135
+ }
136
+ getAltText() {
137
+ return this.__altText;
138
+ }
139
+ decorate() {
140
+ return /*#__PURE__*/React.createElement(Suspense, {
141
+ fallback: null
142
+ }, /*#__PURE__*/React.createElement(ImageComponent, {
143
+ id: this.__id,
144
+ src: this.__src,
145
+ altText: this.__altText,
146
+ width: this.__width,
147
+ height: this.__height,
148
+ maxWidth: this.__maxWidth,
149
+ nodeKey: this.getKey(),
150
+ showCaption: this.__showCaption,
151
+ caption: this.__caption,
152
+ captionsEnabled: this.__captionsEnabled,
153
+ resizable: true
154
+ }));
155
+ }
156
+ }
157
+ export function $createImageNode(props, key) {
158
+ return $applyNodeReplacement(new ImageNode(props, key));
159
+ }
160
+ export function $isImageNode(node) {
161
+ return node instanceof ImageNode;
162
+ }
163
+
164
+ //# sourceMappingURL=ImageNode.js.map