@lexical/react 0.15.0 → 0.16.0

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 (118) hide show
  1. package/LexicalAutoEmbedPlugin.dev.js +12 -24
  2. package/LexicalAutoEmbedPlugin.dev.mjs +2 -2
  3. package/LexicalAutoEmbedPlugin.prod.js +4 -5
  4. package/LexicalAutoEmbedPlugin.prod.mjs +1 -1
  5. package/LexicalBlockWithAlignableContents.dev.js +9 -20
  6. package/LexicalBlockWithAlignableContents.dev.mjs +5 -4
  7. package/LexicalBlockWithAlignableContents.prod.js +4 -4
  8. package/LexicalBlockWithAlignableContents.prod.mjs +1 -1
  9. package/LexicalCharacterLimitPlugin.dev.js +10 -22
  10. package/LexicalCharacterLimitPlugin.dev.mjs +5 -5
  11. package/LexicalCharacterLimitPlugin.prod.js +9 -9
  12. package/LexicalCharacterLimitPlugin.prod.mjs +1 -1
  13. package/LexicalCheckListPlugin.dev.js +2 -0
  14. package/LexicalCheckListPlugin.dev.mjs +2 -0
  15. package/LexicalCheckListPlugin.prod.js +2 -2
  16. package/LexicalCheckListPlugin.prod.mjs +1 -1
  17. package/LexicalClearEditorPlugin.dev.js +4 -0
  18. package/LexicalClearEditorPlugin.dev.mjs +4 -0
  19. package/LexicalClickableLinkPlugin.d.ts +3 -1
  20. package/LexicalClickableLinkPlugin.dev.js +3 -2
  21. package/LexicalClickableLinkPlugin.dev.mjs +2 -2
  22. package/LexicalClickableLinkPlugin.js.flow +3 -1
  23. package/LexicalClickableLinkPlugin.mjs +1 -0
  24. package/LexicalClickableLinkPlugin.node.mjs +1 -0
  25. package/LexicalClickableLinkPlugin.prod.js +4 -3
  26. package/LexicalClickableLinkPlugin.prod.mjs +1 -1
  27. package/LexicalCollaborationPlugin.dev.js +2 -1
  28. package/LexicalCollaborationPlugin.dev.mjs +2 -1
  29. package/LexicalCollaborationPlugin.prod.js +9 -9
  30. package/LexicalCollaborationPlugin.prod.mjs +1 -1
  31. package/LexicalComposer.dev.js +12 -19
  32. package/LexicalComposer.dev.mjs +9 -4
  33. package/LexicalComposer.prod.js +3 -4
  34. package/LexicalComposer.prod.mjs +1 -1
  35. package/LexicalContentEditable.dev.js +20 -34
  36. package/LexicalContentEditable.dev.mjs +16 -18
  37. package/LexicalContentEditable.prod.js +3 -4
  38. package/LexicalContentEditable.prod.mjs +1 -1
  39. package/LexicalContextMenuPlugin.dev.js +6 -1
  40. package/LexicalContextMenuPlugin.dev.mjs +6 -1
  41. package/LexicalContextMenuPlugin.prod.js +15 -15
  42. package/LexicalContextMenuPlugin.prod.mjs +1 -1
  43. package/LexicalErrorBoundary.d.ts +3 -1
  44. package/LexicalErrorBoundary.dev.js +11 -7
  45. package/LexicalErrorBoundary.dev.mjs +10 -7
  46. package/LexicalErrorBoundary.js.flow +4 -1
  47. package/LexicalErrorBoundary.mjs +1 -0
  48. package/LexicalErrorBoundary.node.mjs +1 -0
  49. package/LexicalErrorBoundary.prod.js +4 -4
  50. package/LexicalErrorBoundary.prod.mjs +1 -1
  51. package/LexicalHorizontalRuleNode.d.ts +2 -2
  52. package/LexicalHorizontalRuleNode.dev.js +16 -21
  53. package/LexicalHorizontalRuleNode.dev.mjs +13 -6
  54. package/LexicalHorizontalRuleNode.prod.js +5 -5
  55. package/LexicalHorizontalRuleNode.prod.mjs +1 -1
  56. package/LexicalNestedComposer.dev.js +11 -22
  57. package/LexicalNestedComposer.dev.mjs +5 -4
  58. package/LexicalNestedComposer.prod.js +5 -5
  59. package/LexicalNestedComposer.prod.mjs +1 -1
  60. package/LexicalNodeMenuPlugin.dev.js +6 -1
  61. package/LexicalNodeMenuPlugin.dev.mjs +6 -1
  62. package/LexicalNodeMenuPlugin.prod.js +13 -13
  63. package/LexicalNodeMenuPlugin.prod.mjs +1 -1
  64. package/LexicalOnChangePlugin.dev.js +4 -0
  65. package/LexicalOnChangePlugin.dev.mjs +4 -0
  66. package/LexicalPlainTextPlugin.dev.js +24 -28
  67. package/LexicalPlainTextPlugin.dev.mjs +19 -11
  68. package/LexicalPlainTextPlugin.js.flow +1 -1
  69. package/LexicalPlainTextPlugin.prod.js +4 -4
  70. package/LexicalPlainTextPlugin.prod.mjs +1 -1
  71. package/LexicalRichTextPlugin.dev.js +24 -28
  72. package/LexicalRichTextPlugin.dev.mjs +19 -11
  73. package/LexicalRichTextPlugin.js.flow +1 -1
  74. package/LexicalRichTextPlugin.prod.js +4 -4
  75. package/LexicalRichTextPlugin.prod.mjs +1 -1
  76. package/LexicalTableOfContents.d.ts +6 -13
  77. package/LexicalTableOfContents.dev.js +10 -2
  78. package/LexicalTableOfContents.dev.mjs +10 -2
  79. package/LexicalTableOfContents.js.flow +3 -7
  80. package/LexicalTableOfContents.prod.js +1 -1
  81. package/LexicalTableOfContentsPlugin.d.ts +20 -0
  82. package/LexicalTableOfContentsPlugin.dev.js +198 -0
  83. package/LexicalTableOfContentsPlugin.dev.mjs +196 -0
  84. package/LexicalTableOfContentsPlugin.js +11 -0
  85. package/LexicalTableOfContentsPlugin.js.flow +18 -0
  86. package/LexicalTableOfContentsPlugin.mjs +12 -0
  87. package/LexicalTableOfContentsPlugin.node.mjs +10 -0
  88. package/LexicalTableOfContentsPlugin.prod.js +12 -0
  89. package/LexicalTableOfContentsPlugin.prod.mjs +9 -0
  90. package/LexicalTreeView.d.ts +3 -1
  91. package/LexicalTreeView.dev.js +5 -3
  92. package/LexicalTreeView.dev.mjs +5 -3
  93. package/LexicalTreeView.js.flow +2 -0
  94. package/LexicalTreeView.prod.js +3 -3
  95. package/LexicalTreeView.prod.mjs +1 -1
  96. package/LexicalTypeaheadMenuPlugin.dev.js +6 -1
  97. package/LexicalTypeaheadMenuPlugin.dev.mjs +6 -1
  98. package/LexicalTypeaheadMenuPlugin.prod.js +17 -17
  99. package/LexicalTypeaheadMenuPlugin.prod.mjs +1 -1
  100. package/package.json +50 -20
  101. package/useLexicalEditable.d.ts +11 -1
  102. package/useLexicalEditable.dev.js +16 -1
  103. package/useLexicalEditable.dev.mjs +15 -1
  104. package/useLexicalEditable.js.flow +4 -1
  105. package/useLexicalEditable.mjs +2 -1
  106. package/useLexicalEditable.node.mjs +2 -1
  107. package/useLexicalEditable.prod.js +1 -1
  108. package/useLexicalEditable.prod.mjs +1 -1
  109. package/useLexicalIsTextContentEmpty.dev.js +4 -0
  110. package/useLexicalIsTextContentEmpty.dev.mjs +4 -0
  111. package/useLexicalSubscription.d.ts +4 -1
  112. package/useLexicalSubscription.dev.js +7 -1
  113. package/useLexicalSubscription.dev.mjs +6 -1
  114. package/useLexicalSubscription.js.flow +4 -1
  115. package/useLexicalSubscription.mjs +2 -1
  116. package/useLexicalSubscription.node.mjs +2 -1
  117. package/useLexicalSubscription.prod.js +2 -2
  118. package/useLexicalSubscription.prod.mjs +1 -1
@@ -0,0 +1,198 @@
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
+
9
+ 'use strict';
10
+
11
+ var LexicalComposerContext = require('@lexical/react/LexicalComposerContext');
12
+ var richText = require('@lexical/rich-text');
13
+ var utils = require('@lexical/utils');
14
+ var lexical = require('lexical');
15
+ var react = require('react');
16
+
17
+ /**
18
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
19
+ *
20
+ * This source code is licensed under the MIT license found in the
21
+ * LICENSE file in the root directory of this source tree.
22
+ *
23
+ */
24
+
25
+ function toEntry(heading) {
26
+ return [heading.getKey(), heading.getTextContent(), heading.getTag()];
27
+ }
28
+ function $insertHeadingIntoTableOfContents(prevHeading, newHeading, currentTableOfContents) {
29
+ if (newHeading === null) {
30
+ return currentTableOfContents;
31
+ }
32
+ const newEntry = toEntry(newHeading);
33
+ let newTableOfContents = [];
34
+ if (prevHeading === null) {
35
+ // check if key already exists
36
+ if (currentTableOfContents.length > 0 && currentTableOfContents[0][0] === newHeading.__key) {
37
+ return currentTableOfContents;
38
+ }
39
+ newTableOfContents = [newEntry, ...currentTableOfContents];
40
+ } else {
41
+ for (let i = 0; i < currentTableOfContents.length; i++) {
42
+ const key = currentTableOfContents[i][0];
43
+ newTableOfContents.push(currentTableOfContents[i]);
44
+ if (key === prevHeading.getKey() && key !== newHeading.getKey()) {
45
+ // check if key already exists
46
+ if (i + 1 < currentTableOfContents.length && currentTableOfContents[i + 1][0] === newHeading.__key) {
47
+ return currentTableOfContents;
48
+ }
49
+ newTableOfContents.push(newEntry);
50
+ }
51
+ }
52
+ }
53
+ return newTableOfContents;
54
+ }
55
+ function $deleteHeadingFromTableOfContents(key, currentTableOfContents) {
56
+ const newTableOfContents = [];
57
+ for (const heading of currentTableOfContents) {
58
+ if (heading[0] !== key) {
59
+ newTableOfContents.push(heading);
60
+ }
61
+ }
62
+ return newTableOfContents;
63
+ }
64
+ function $updateHeadingInTableOfContents(heading, currentTableOfContents) {
65
+ const newTableOfContents = [];
66
+ for (const oldHeading of currentTableOfContents) {
67
+ if (oldHeading[0] === heading.getKey()) {
68
+ newTableOfContents.push(toEntry(heading));
69
+ } else {
70
+ newTableOfContents.push(oldHeading);
71
+ }
72
+ }
73
+ return newTableOfContents;
74
+ }
75
+
76
+ /**
77
+ * Returns the updated table of contents, placing the given `heading` before the given `prevHeading`. If `prevHeading`
78
+ * is undefined, `heading` is placed at the start of table of contents
79
+ */
80
+ function $updateHeadingPosition(prevHeading, heading, currentTableOfContents) {
81
+ const newTableOfContents = [];
82
+ const newEntry = toEntry(heading);
83
+ if (!prevHeading) {
84
+ newTableOfContents.push(newEntry);
85
+ }
86
+ for (const oldHeading of currentTableOfContents) {
87
+ if (oldHeading[0] === heading.getKey()) {
88
+ continue;
89
+ }
90
+ newTableOfContents.push(oldHeading);
91
+ if (prevHeading && oldHeading[0] === prevHeading.getKey()) {
92
+ newTableOfContents.push(newEntry);
93
+ }
94
+ }
95
+ return newTableOfContents;
96
+ }
97
+ function $getPreviousHeading(node) {
98
+ let prevHeading = utils.$getNextRightPreorderNode(node);
99
+ while (prevHeading !== null && !richText.$isHeadingNode(prevHeading)) {
100
+ prevHeading = utils.$getNextRightPreorderNode(prevHeading);
101
+ }
102
+ return prevHeading;
103
+ }
104
+ function TableOfContentsPlugin({
105
+ children
106
+ }) {
107
+ const [tableOfContents, setTableOfContents] = react.useState([]);
108
+ const [editor] = LexicalComposerContext.useLexicalComposerContext();
109
+ react.useEffect(() => {
110
+ // Set table of contents initial state
111
+ let currentTableOfContents = [];
112
+ editor.getEditorState().read(() => {
113
+ const root = lexical.$getRoot();
114
+ const rootChildren = root.getChildren();
115
+ for (const child of rootChildren) {
116
+ if (richText.$isHeadingNode(child)) {
117
+ currentTableOfContents.push([child.getKey(), child.getTextContent(), child.getTag()]);
118
+ }
119
+ }
120
+ setTableOfContents(currentTableOfContents);
121
+ });
122
+ const removeRootUpdateListener = editor.registerUpdateListener(({
123
+ editorState,
124
+ dirtyElements
125
+ }) => {
126
+ editorState.read(() => {
127
+ const updateChildHeadings = node => {
128
+ for (const child of node.getChildren()) {
129
+ if (richText.$isHeadingNode(child)) {
130
+ const prevHeading = $getPreviousHeading(child);
131
+ currentTableOfContents = $updateHeadingPosition(prevHeading, child, currentTableOfContents);
132
+ setTableOfContents(currentTableOfContents);
133
+ } else if (lexical.$isElementNode(child)) {
134
+ updateChildHeadings(child);
135
+ }
136
+ }
137
+ };
138
+
139
+ // If a node is changes, all child heading positions need to be updated
140
+ lexical.$getRoot().getChildren().forEach(node => {
141
+ if (lexical.$isElementNode(node) && dirtyElements.get(node.__key)) {
142
+ updateChildHeadings(node);
143
+ }
144
+ });
145
+ });
146
+ });
147
+
148
+ // Listen to updates to heading mutations and update state
149
+ const removeHeaderMutationListener = editor.registerMutationListener(richText.HeadingNode, mutatedNodes => {
150
+ editor.getEditorState().read(() => {
151
+ for (const [nodeKey, mutation] of mutatedNodes) {
152
+ if (mutation === 'created') {
153
+ const newHeading = lexical.$getNodeByKey(nodeKey);
154
+ if (newHeading !== null) {
155
+ const prevHeading = $getPreviousHeading(newHeading);
156
+ currentTableOfContents = $insertHeadingIntoTableOfContents(prevHeading, newHeading, currentTableOfContents);
157
+ }
158
+ } else if (mutation === 'destroyed') {
159
+ currentTableOfContents = $deleteHeadingFromTableOfContents(nodeKey, currentTableOfContents);
160
+ } else if (mutation === 'updated') {
161
+ const newHeading = lexical.$getNodeByKey(nodeKey);
162
+ if (newHeading !== null) {
163
+ const prevHeading = $getPreviousHeading(newHeading);
164
+ currentTableOfContents = $updateHeadingPosition(prevHeading, newHeading, currentTableOfContents);
165
+ }
166
+ }
167
+ }
168
+ setTableOfContents(currentTableOfContents);
169
+ });
170
+ });
171
+
172
+ // Listen to text node mutation updates
173
+ const removeTextNodeMutationListener = editor.registerMutationListener(lexical.TextNode, mutatedNodes => {
174
+ editor.getEditorState().read(() => {
175
+ for (const [nodeKey, mutation] of mutatedNodes) {
176
+ if (mutation === 'updated') {
177
+ const currNode = lexical.$getNodeByKey(nodeKey);
178
+ if (currNode !== null) {
179
+ const parentNode = currNode.getParentOrThrow();
180
+ if (richText.$isHeadingNode(parentNode)) {
181
+ currentTableOfContents = $updateHeadingInTableOfContents(parentNode, currentTableOfContents);
182
+ setTableOfContents(currentTableOfContents);
183
+ }
184
+ }
185
+ }
186
+ }
187
+ });
188
+ });
189
+ return () => {
190
+ removeHeaderMutationListener();
191
+ removeTextNodeMutationListener();
192
+ removeRootUpdateListener();
193
+ };
194
+ }, [editor]);
195
+ return children(tableOfContents, editor);
196
+ }
197
+
198
+ exports.TableOfContentsPlugin = TableOfContentsPlugin;
@@ -0,0 +1,196 @@
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
+
9
+ import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
10
+ import { $isHeadingNode, HeadingNode } from '@lexical/rich-text';
11
+ import { $getNextRightPreorderNode } from '@lexical/utils';
12
+ import { $getRoot, $isElementNode, $getNodeByKey, TextNode } from 'lexical';
13
+ import { useState, useEffect } from 'react';
14
+
15
+ /**
16
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
17
+ *
18
+ * This source code is licensed under the MIT license found in the
19
+ * LICENSE file in the root directory of this source tree.
20
+ *
21
+ */
22
+
23
+ function toEntry(heading) {
24
+ return [heading.getKey(), heading.getTextContent(), heading.getTag()];
25
+ }
26
+ function $insertHeadingIntoTableOfContents(prevHeading, newHeading, currentTableOfContents) {
27
+ if (newHeading === null) {
28
+ return currentTableOfContents;
29
+ }
30
+ const newEntry = toEntry(newHeading);
31
+ let newTableOfContents = [];
32
+ if (prevHeading === null) {
33
+ // check if key already exists
34
+ if (currentTableOfContents.length > 0 && currentTableOfContents[0][0] === newHeading.__key) {
35
+ return currentTableOfContents;
36
+ }
37
+ newTableOfContents = [newEntry, ...currentTableOfContents];
38
+ } else {
39
+ for (let i = 0; i < currentTableOfContents.length; i++) {
40
+ const key = currentTableOfContents[i][0];
41
+ newTableOfContents.push(currentTableOfContents[i]);
42
+ if (key === prevHeading.getKey() && key !== newHeading.getKey()) {
43
+ // check if key already exists
44
+ if (i + 1 < currentTableOfContents.length && currentTableOfContents[i + 1][0] === newHeading.__key) {
45
+ return currentTableOfContents;
46
+ }
47
+ newTableOfContents.push(newEntry);
48
+ }
49
+ }
50
+ }
51
+ return newTableOfContents;
52
+ }
53
+ function $deleteHeadingFromTableOfContents(key, currentTableOfContents) {
54
+ const newTableOfContents = [];
55
+ for (const heading of currentTableOfContents) {
56
+ if (heading[0] !== key) {
57
+ newTableOfContents.push(heading);
58
+ }
59
+ }
60
+ return newTableOfContents;
61
+ }
62
+ function $updateHeadingInTableOfContents(heading, currentTableOfContents) {
63
+ const newTableOfContents = [];
64
+ for (const oldHeading of currentTableOfContents) {
65
+ if (oldHeading[0] === heading.getKey()) {
66
+ newTableOfContents.push(toEntry(heading));
67
+ } else {
68
+ newTableOfContents.push(oldHeading);
69
+ }
70
+ }
71
+ return newTableOfContents;
72
+ }
73
+
74
+ /**
75
+ * Returns the updated table of contents, placing the given `heading` before the given `prevHeading`. If `prevHeading`
76
+ * is undefined, `heading` is placed at the start of table of contents
77
+ */
78
+ function $updateHeadingPosition(prevHeading, heading, currentTableOfContents) {
79
+ const newTableOfContents = [];
80
+ const newEntry = toEntry(heading);
81
+ if (!prevHeading) {
82
+ newTableOfContents.push(newEntry);
83
+ }
84
+ for (const oldHeading of currentTableOfContents) {
85
+ if (oldHeading[0] === heading.getKey()) {
86
+ continue;
87
+ }
88
+ newTableOfContents.push(oldHeading);
89
+ if (prevHeading && oldHeading[0] === prevHeading.getKey()) {
90
+ newTableOfContents.push(newEntry);
91
+ }
92
+ }
93
+ return newTableOfContents;
94
+ }
95
+ function $getPreviousHeading(node) {
96
+ let prevHeading = $getNextRightPreorderNode(node);
97
+ while (prevHeading !== null && !$isHeadingNode(prevHeading)) {
98
+ prevHeading = $getNextRightPreorderNode(prevHeading);
99
+ }
100
+ return prevHeading;
101
+ }
102
+ function TableOfContentsPlugin({
103
+ children
104
+ }) {
105
+ const [tableOfContents, setTableOfContents] = useState([]);
106
+ const [editor] = useLexicalComposerContext();
107
+ useEffect(() => {
108
+ // Set table of contents initial state
109
+ let currentTableOfContents = [];
110
+ editor.getEditorState().read(() => {
111
+ const root = $getRoot();
112
+ const rootChildren = root.getChildren();
113
+ for (const child of rootChildren) {
114
+ if ($isHeadingNode(child)) {
115
+ currentTableOfContents.push([child.getKey(), child.getTextContent(), child.getTag()]);
116
+ }
117
+ }
118
+ setTableOfContents(currentTableOfContents);
119
+ });
120
+ const removeRootUpdateListener = editor.registerUpdateListener(({
121
+ editorState,
122
+ dirtyElements
123
+ }) => {
124
+ editorState.read(() => {
125
+ const updateChildHeadings = node => {
126
+ for (const child of node.getChildren()) {
127
+ if ($isHeadingNode(child)) {
128
+ const prevHeading = $getPreviousHeading(child);
129
+ currentTableOfContents = $updateHeadingPosition(prevHeading, child, currentTableOfContents);
130
+ setTableOfContents(currentTableOfContents);
131
+ } else if ($isElementNode(child)) {
132
+ updateChildHeadings(child);
133
+ }
134
+ }
135
+ };
136
+
137
+ // If a node is changes, all child heading positions need to be updated
138
+ $getRoot().getChildren().forEach(node => {
139
+ if ($isElementNode(node) && dirtyElements.get(node.__key)) {
140
+ updateChildHeadings(node);
141
+ }
142
+ });
143
+ });
144
+ });
145
+
146
+ // Listen to updates to heading mutations and update state
147
+ const removeHeaderMutationListener = editor.registerMutationListener(HeadingNode, mutatedNodes => {
148
+ editor.getEditorState().read(() => {
149
+ for (const [nodeKey, mutation] of mutatedNodes) {
150
+ if (mutation === 'created') {
151
+ const newHeading = $getNodeByKey(nodeKey);
152
+ if (newHeading !== null) {
153
+ const prevHeading = $getPreviousHeading(newHeading);
154
+ currentTableOfContents = $insertHeadingIntoTableOfContents(prevHeading, newHeading, currentTableOfContents);
155
+ }
156
+ } else if (mutation === 'destroyed') {
157
+ currentTableOfContents = $deleteHeadingFromTableOfContents(nodeKey, currentTableOfContents);
158
+ } else if (mutation === 'updated') {
159
+ const newHeading = $getNodeByKey(nodeKey);
160
+ if (newHeading !== null) {
161
+ const prevHeading = $getPreviousHeading(newHeading);
162
+ currentTableOfContents = $updateHeadingPosition(prevHeading, newHeading, currentTableOfContents);
163
+ }
164
+ }
165
+ }
166
+ setTableOfContents(currentTableOfContents);
167
+ });
168
+ });
169
+
170
+ // Listen to text node mutation updates
171
+ const removeTextNodeMutationListener = editor.registerMutationListener(TextNode, mutatedNodes => {
172
+ editor.getEditorState().read(() => {
173
+ for (const [nodeKey, mutation] of mutatedNodes) {
174
+ if (mutation === 'updated') {
175
+ const currNode = $getNodeByKey(nodeKey);
176
+ if (currNode !== null) {
177
+ const parentNode = currNode.getParentOrThrow();
178
+ if ($isHeadingNode(parentNode)) {
179
+ currentTableOfContents = $updateHeadingInTableOfContents(parentNode, currentTableOfContents);
180
+ setTableOfContents(currentTableOfContents);
181
+ }
182
+ }
183
+ }
184
+ }
185
+ });
186
+ });
187
+ return () => {
188
+ removeHeaderMutationListener();
189
+ removeTextNodeMutationListener();
190
+ removeRootUpdateListener();
191
+ };
192
+ }, [editor]);
193
+ return children(tableOfContents, editor);
194
+ }
195
+
196
+ export { TableOfContentsPlugin };
@@ -0,0 +1,11 @@
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
+
9
+ 'use strict'
10
+ const LexicalTableOfContentsPlugin = process.env.NODE_ENV === 'development' ? require('./LexicalTableOfContentsPlugin.dev.js') : require('./LexicalTableOfContentsPlugin.prod.js');
11
+ module.exports = LexicalTableOfContentsPlugin;
@@ -0,0 +1,18 @@
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
+ * @flow strict
8
+ */
9
+
10
+ import type {HeadingTagType} from '@lexical/rich-text';
11
+ import type {LexicalEditor, NodeKey} from 'lexical';
12
+
13
+ declare export function TableOfContentsPlugin({
14
+ children: (
15
+ tableOfContents: Array<[NodeKey, string, HeadingTagType]>,
16
+ editor: LexicalEditor,
17
+ ) => React$Node,
18
+ }): React$Node;
@@ -0,0 +1,12 @@
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
+
9
+ import * as modDev from './LexicalTableOfContentsPlugin.dev.mjs';
10
+ import * as modProd from './LexicalTableOfContentsPlugin.prod.mjs';
11
+ const mod = process.env.NODE_ENV === 'development' ? modDev : modProd;
12
+ export const TableOfContentsPlugin = mod.TableOfContentsPlugin;
@@ -0,0 +1,10 @@
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
+
9
+ const mod = await (process.env.NODE_ENV === 'development' ? import('./LexicalTableOfContentsPlugin.dev.mjs') : import('./LexicalTableOfContentsPlugin.prod.mjs'));
10
+ export const TableOfContentsPlugin = mod.TableOfContentsPlugin;
@@ -0,0 +1,12 @@
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
+
9
+ 'use strict';var h=require("@lexical/react/LexicalComposerContext"),q=require("@lexical/rich-text"),v=require("@lexical/utils"),w=require("lexical"),x=require("react");function y(d){return[d.getKey(),d.getTextContent(),d.getTag()]}function z(d,t,n){let e=[],c=y(t);d||e.push(c);for(let r of n)r[0]!==t.getKey()&&(e.push(r),d&&r[0]===d.getKey()&&e.push(c));return e}function B(d){for(d=v.$getNextRightPreorderNode(d);null!==d&&!q.$isHeadingNode(d);)d=v.$getNextRightPreorderNode(d);return d}
10
+ exports.TableOfContentsPlugin=function({children:d}){let [t,n]=x.useState([]),[e]=h.useLexicalComposerContext();x.useEffect(()=>{let c=[];e.getEditorState().read(()=>{let l=w.$getRoot().getChildren();for(let a of l)q.$isHeadingNode(a)&&c.push([a.getKey(),a.getTextContent(),a.getTag()]);n(c)});let r=e.registerUpdateListener(({editorState:l,dirtyElements:a})=>{l.read(()=>{const f=b=>{for(const g of b.getChildren())q.$isHeadingNode(g)?(b=B(g),c=z(b,g,c),n(c)):w.$isElementNode(g)&&f(g)};w.$getRoot().getChildren().forEach(b=>
11
+ {w.$isElementNode(b)&&a.get(b.__key)&&f(b)})})}),C=e.registerMutationListener(q.HeadingNode,l=>{e.getEditorState().read(()=>{for(const [g,m]of l)if("created"===m){var a=w.$getNodeByKey(g);if(null!==a)a:{var f=B(a),b=c;if(null===a){c=b;break a}let k=y(a),u=[];if(null===f){if(0<b.length&&b[0][0]===a.__key){c=b;break a}u=[k,...b]}else for(let p=0;p<b.length;p++){let A=b[p][0];u.push(b[p]);if(A===f.getKey()&&A!==a.getKey()){if(p+1<b.length&&b[p+1][0]===a.__key){c=b;break a}u.push(k)}}c=u}}else if("destroyed"===
12
+ m){f=g;a=c;b=[];for(let k of a)k[0]!==f&&b.push(k);c=b}else"updated"===m&&(f=w.$getNodeByKey(g),null!==f&&(a=B(f),c=z(a,f,c)));n(c)})}),D=e.registerMutationListener(w.TextNode,l=>{e.getEditorState().read(()=>{for(const [b,g]of l)if("updated"===g){var a=w.$getNodeByKey(b);if(null!==a&&(a=a.getParentOrThrow(),q.$isHeadingNode(a))){var f=c;let m=[];for(let k of f)k[0]===a.getKey()?m.push(y(a)):m.push(k);c=m;n(c)}}})});return()=>{C();D();r()}},[e]);return d(t,e)}
@@ -0,0 +1,9 @@
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
+
9
+ import{useLexicalComposerContext as t}from"@lexical/react/LexicalComposerContext";import{$isHeadingNode as e,HeadingNode as r}from"@lexical/rich-text";import{$getNextRightPreorderNode as n}from"@lexical/utils";import{$getRoot as o,$isElementNode as i,$getNodeByKey as s,TextNode as f}from"lexical";import{useState as c,useEffect as l}from"react";function u(t){return[t.getKey(),t.getTextContent(),t.getTag()]}function g(t,e,r){if(null===e)return r;const n=u(e);let o=[];if(null===t){if(r.length>0&&r[0][0]===e.__key)return r;o=[n,...r]}else for(let i=0;i<r.length;i++){const s=r[i][0];if(o.push(r[i]),s===t.getKey()&&s!==e.getKey()){if(i+1<r.length&&r[i+1][0]===e.__key)return r;o.push(n)}}return o}function a(t,e){const r=[];for(const n of e)n[0]!==t&&r.push(n);return r}function d(t,e){const r=[];for(const n of e)n[0]===t.getKey()?r.push(u(t)):r.push(n);return r}function h(t,e,r){const n=[],o=u(e);t||n.push(o);for(const i of r)i[0]!==e.getKey()&&(n.push(i),t&&i[0]===t.getKey()&&n.push(o));return n}function p(t){let r=n(t);for(;null!==r&&!e(r);)r=n(r);return r}function m({children:n}){const[u,m]=c([]),[y]=t();return l((()=>{let t=[];y.getEditorState().read((()=>{const r=o().getChildren();for(const n of r)e(n)&&t.push([n.getKey(),n.getTextContent(),n.getTag()]);m(t)}));const n=y.registerUpdateListener((({editorState:r,dirtyElements:n})=>{r.read((()=>{const r=n=>{for(const o of n.getChildren())if(e(o)){const e=p(o);t=h(e,o,t),m(t)}else i(o)&&r(o)};o().getChildren().forEach((t=>{i(t)&&n.get(t.__key)&&r(t)}))}))})),c=y.registerMutationListener(r,(e=>{y.getEditorState().read((()=>{for(const[r,n]of e)if("created"===n){const e=s(r);if(null!==e){const r=p(e);t=g(r,e,t)}}else if("destroyed"===n)t=a(r,t);else if("updated"===n){const e=s(r);if(null!==e){const r=p(e);t=h(r,e,t)}}m(t)}))})),l=y.registerMutationListener(f,(r=>{y.getEditorState().read((()=>{for(const[n,o]of r)if("updated"===o){const r=s(n);if(null!==r){const n=r.getParentOrThrow();e(n)&&(t=d(n,t),m(t))}}}))}));return()=>{c(),l(),n()}}),[y]),n(u,y)}export{m as TableOfContentsPlugin};
@@ -7,7 +7,8 @@
7
7
  */
8
8
  /// <reference types="react" />
9
9
  import type { LexicalEditor } from 'lexical';
10
- export declare function TreeView({ treeTypeButtonClassName, timeTravelButtonClassName, timeTravelPanelSliderClassName, timeTravelPanelButtonClassName, viewClassName, timeTravelPanelClassName, editor, }: {
10
+ import { CustomPrintNodeFn } from '@lexical/devtools-core';
11
+ export declare function TreeView({ treeTypeButtonClassName, timeTravelButtonClassName, timeTravelPanelSliderClassName, timeTravelPanelButtonClassName, viewClassName, timeTravelPanelClassName, editor, customPrintNode, }: {
11
12
  editor: LexicalEditor;
12
13
  treeTypeButtonClassName: string;
13
14
  timeTravelButtonClassName: string;
@@ -15,4 +16,5 @@ export declare function TreeView({ treeTypeButtonClassName, timeTravelButtonClas
15
16
  timeTravelPanelClassName: string;
16
17
  timeTravelPanelSliderClassName: string;
17
18
  viewClassName: string;
19
+ customPrintNode?: CustomPrintNodeFn;
18
20
  }): JSX.Element;
@@ -11,6 +11,7 @@
11
11
  var devtoolsCore = require('@lexical/devtools-core');
12
12
  var utils = require('@lexical/utils');
13
13
  var React = require('react');
14
+ var jsxRuntime = require('react/jsx-runtime');
14
15
 
15
16
  function _interopNamespaceDefault(e) {
16
17
  var n = Object.create(null);
@@ -40,7 +41,8 @@ function TreeView({
40
41
  timeTravelPanelButtonClassName,
41
42
  viewClassName,
42
43
  timeTravelPanelClassName,
43
- editor
44
+ editor,
45
+ customPrintNode
44
46
  }) {
45
47
  const treeElementRef = /*#__PURE__*/React__namespace.createRef();
46
48
  const [editorCurrentState, setEditorCurrentState] = React.useState(editor.getEditorState());
@@ -72,7 +74,7 @@ function TreeView({
72
74
  }
73
75
  rootElement.contentEditable = isReadonly ? 'false' : 'true';
74
76
  };
75
- return /*#__PURE__*/React__namespace.createElement(devtoolsCore.TreeView, {
77
+ return /*#__PURE__*/jsxRuntime.jsx(devtoolsCore.TreeView, {
76
78
  treeTypeButtonClassName: treeTypeButtonClassName,
77
79
  timeTravelButtonClassName: timeTravelButtonClassName,
78
80
  timeTravelPanelSliderClassName: timeTravelPanelSliderClassName,
@@ -83,7 +85,7 @@ function TreeView({
83
85
  editorState: editorCurrentState,
84
86
  setEditorState: state => editor.setEditorState(state),
85
87
  generateContent: async function (exportDOM) {
86
- return devtoolsCore.generateContent(editor, commandsLog, exportDOM);
88
+ return devtoolsCore.generateContent(editor, commandsLog, exportDOM, customPrintNode);
87
89
  },
88
90
  ref: treeElementRef
89
91
  });
@@ -10,6 +10,7 @@ import { useLexicalCommandsLog, TreeView as TreeView$1, generateContent } from '
10
10
  import { mergeRegister } from '@lexical/utils';
11
11
  import * as React from 'react';
12
12
  import { useState, useEffect } from 'react';
13
+ import { jsx } from 'react/jsx-runtime';
13
14
 
14
15
  /**
15
16
  * Copyright (c) Meta Platforms, Inc. and affiliates.
@@ -26,7 +27,8 @@ function TreeView({
26
27
  timeTravelPanelButtonClassName,
27
28
  viewClassName,
28
29
  timeTravelPanelClassName,
29
- editor
30
+ editor,
31
+ customPrintNode
30
32
  }) {
31
33
  const treeElementRef = /*#__PURE__*/React.createRef();
32
34
  const [editorCurrentState, setEditorCurrentState] = useState(editor.getEditorState());
@@ -58,7 +60,7 @@ function TreeView({
58
60
  }
59
61
  rootElement.contentEditable = isReadonly ? 'false' : 'true';
60
62
  };
61
- return /*#__PURE__*/React.createElement(TreeView$1, {
63
+ return /*#__PURE__*/jsx(TreeView$1, {
62
64
  treeTypeButtonClassName: treeTypeButtonClassName,
63
65
  timeTravelButtonClassName: timeTravelButtonClassName,
64
66
  timeTravelPanelSliderClassName: timeTravelPanelSliderClassName,
@@ -69,7 +71,7 @@ function TreeView({
69
71
  editorState: editorCurrentState,
70
72
  setEditorState: state => editor.setEditorState(state),
71
73
  generateContent: async function (exportDOM) {
72
- return generateContent(editor, commandsLog, exportDOM);
74
+ return generateContent(editor, commandsLog, exportDOM, customPrintNode);
73
75
  },
74
76
  ref: treeElementRef
75
77
  });
@@ -7,6 +7,7 @@
7
7
  * @flow strict
8
8
  */
9
9
 
10
+ import type {CustomPrintNodeFn} from '@lexical/devtools-core';
10
11
  import type {LexicalEditor} from 'lexical';
11
12
 
12
13
  declare export function TreeView(props: {
@@ -16,4 +17,5 @@ declare export function TreeView(props: {
16
17
  timeTravelButtonClassName: string,
17
18
  viewClassName: string,
18
19
  editor: LexicalEditor,
20
+ customPrintNode?: CustomPrintNodeFn,
19
21
  }): React$Node;
@@ -6,6 +6,6 @@
6
6
  *
7
7
  */
8
8
 
9
- 'use strict';var c=require("@lexical/devtools-core"),d=require("@lexical/utils"),e=require("react"),g=Object.create(null);if(e)for(var l in e)g[l]=e[l];g.default=e;
10
- exports.TreeView=function({treeTypeButtonClassName:m,timeTravelButtonClassName:n,timeTravelPanelSliderClassName:p,timeTravelPanelButtonClassName:q,viewClassName:r,timeTravelPanelClassName:t,editor:a}){let f=g.createRef(),[u,h]=e.useState(a.getEditorState()),v=c.useLexicalCommandsLog(a);e.useEffect(()=>d.mergeRegister(a.registerUpdateListener(({editorState:b})=>{h(b)}),a.registerEditableListener(()=>{h(a.getEditorState())})),[a]);e.useEffect(()=>{let b=f.current;if(null!==b)return b.__lexicalEditor=
11
- a,()=>{b.__lexicalEditor=null}},[a,f]);return g.createElement(c.TreeView,{treeTypeButtonClassName:m,timeTravelButtonClassName:n,timeTravelPanelSliderClassName:p,timeTravelPanelButtonClassName:q,viewClassName:r,timeTravelPanelClassName:t,setEditorReadOnly:b=>{const k=a.getRootElement();null!=k&&(k.contentEditable=b?"false":"true")},editorState:u,setEditorState:b=>a.setEditorState(b),generateContent:async function(b){return c.generateContent(a,v,b)},ref:f})}
9
+ 'use strict';var c=require("@lexical/devtools-core"),d=require("@lexical/utils"),e=require("react"),g=require("react/jsx-runtime"),l=Object.create(null);if(e)for(var m in e)l[m]=e[m];l.default=e;
10
+ exports.TreeView=function({treeTypeButtonClassName:n,timeTravelButtonClassName:p,timeTravelPanelSliderClassName:q,timeTravelPanelButtonClassName:r,viewClassName:t,timeTravelPanelClassName:u,editor:a,customPrintNode:v}){let f=l.createRef(),[w,h]=e.useState(a.getEditorState()),x=c.useLexicalCommandsLog(a);e.useEffect(()=>d.mergeRegister(a.registerUpdateListener(({editorState:b})=>{h(b)}),a.registerEditableListener(()=>{h(a.getEditorState())})),[a]);e.useEffect(()=>{let b=f.current;if(null!==b)return b.__lexicalEditor=
11
+ a,()=>{b.__lexicalEditor=null}},[a,f]);return g.jsx(c.TreeView,{treeTypeButtonClassName:n,timeTravelButtonClassName:p,timeTravelPanelSliderClassName:q,timeTravelPanelButtonClassName:r,viewClassName:t,timeTravelPanelClassName:u,setEditorReadOnly:b=>{const k=a.getRootElement();null!=k&&(k.contentEditable=b?"false":"true")},editorState:w,setEditorState:b=>a.setEditorState(b),generateContent:async function(b){return c.generateContent(a,x,b,v)},ref:f})}
@@ -6,4 +6,4 @@
6
6
  *
7
7
  */
8
8
 
9
- import{useLexicalCommandsLog as e,TreeView as t,generateContent as a}from"@lexical/devtools-core";import{mergeRegister as r}from"@lexical/utils";import*as l from"react";import{useState as i,useEffect as s}from"react";function n({treeTypeButtonClassName:n,timeTravelButtonClassName:o,timeTravelPanelSliderClassName:m,timeTravelPanelButtonClassName:c,viewClassName:d,timeTravelPanelClassName:u,editor:C}){const N=l.createRef(),[v,E]=i(C.getEditorState()),T=e(C);s((()=>r(C.registerUpdateListener((({editorState:e})=>{E(e)})),C.registerEditableListener((()=>{E(C.getEditorState())})))),[C]),s((()=>{const e=N.current;if(null!==e)return e.__lexicalEditor=C,()=>{e.__lexicalEditor=null}}),[C,N]);return l.createElement(t,{treeTypeButtonClassName:n,timeTravelButtonClassName:o,timeTravelPanelSliderClassName:m,timeTravelPanelButtonClassName:c,viewClassName:d,timeTravelPanelClassName:u,setEditorReadOnly:e=>{const t=C.getRootElement();null!=t&&(t.contentEditable=e?"false":"true")},editorState:v,setEditorState:e=>C.setEditorState(e),generateContent:async function(e){return a(C,T,e)},ref:N})}export{n as TreeView};
9
+ import{useLexicalCommandsLog as e,TreeView as t,generateContent as a}from"@lexical/devtools-core";import{mergeRegister as r}from"@lexical/utils";import*as l from"react";import{useState as i,useEffect as s}from"react";import{jsx as o}from"react/jsx-runtime";function n({treeTypeButtonClassName:n,timeTravelButtonClassName:m,timeTravelPanelSliderClassName:u,timeTravelPanelButtonClassName:c,viewClassName:d,timeTravelPanelClassName:C,editor:N,customPrintNode:f}){const v=l.createRef(),[T,E]=i(N.getEditorState()),p=e(N);s((()=>r(N.registerUpdateListener((({editorState:e})=>{E(e)})),N.registerEditableListener((()=>{E(N.getEditorState())})))),[N]),s((()=>{const e=v.current;if(null!==e)return e.__lexicalEditor=N,()=>{e.__lexicalEditor=null}}),[N,v]);return o(t,{treeTypeButtonClassName:n,timeTravelButtonClassName:m,timeTravelPanelSliderClassName:u,timeTravelPanelButtonClassName:c,viewClassName:d,timeTravelPanelClassName:C,setEditorReadOnly:e=>{const t=N.getRootElement();null!=t&&(t.contentEditable=e?"false":"true")},editorState:T,setEditorState:e=>N.setEditorState(e),generateContent:async function(e){return a(N,p,e,f)},ref:v})}export{n as TreeView};
@@ -12,6 +12,7 @@ var LexicalComposerContext = require('@lexical/react/LexicalComposerContext');
12
12
  var lexical = require('lexical');
13
13
  var React = require('react');
14
14
  var utils = require('@lexical/utils');
15
+ var jsxRuntime = require('react/jsx-runtime');
15
16
 
16
17
  function _interopNamespaceDefault(e) {
17
18
  var n = Object.create(null);
@@ -44,6 +45,10 @@ const CAN_USE_DOM = typeof window !== 'undefined' && typeof window.document !==
44
45
  *
45
46
  */
46
47
 
48
+
49
+ // This workaround is no longer necessary in React 19,
50
+ // but we currently support React >=17.x
51
+ // https://github.com/facebook/react/pull/26395
47
52
  const useLayoutEffectImpl = CAN_USE_DOM ? React.useLayoutEffect : React.useEffect;
48
53
 
49
54
  /**
@@ -571,7 +576,7 @@ function LexicalTypeaheadMenuPlugin({
571
576
  removeUpdateListener();
572
577
  };
573
578
  }, [editor, triggerFn, onQueryChange, resolution, closeTypeahead, openTypeahead]);
574
- return resolution === null || editor === null ? null : /*#__PURE__*/React__namespace.createElement(LexicalMenu, {
579
+ return resolution === null || editor === null ? null : /*#__PURE__*/jsxRuntime.jsx(LexicalMenu, {
575
580
  close: closeTypeahead,
576
581
  resolution: resolution,
577
582
  editor: editor,
@@ -11,6 +11,7 @@ import { createCommand, KEY_ARROW_DOWN_COMMAND, KEY_ARROW_UP_COMMAND, KEY_ESCAPE
11
11
  import * as React from 'react';
12
12
  import { useLayoutEffect, useEffect, useState, useCallback, useMemo, useRef } from 'react';
13
13
  import { mergeRegister } from '@lexical/utils';
14
+ import { jsx } from 'react/jsx-runtime';
14
15
 
15
16
  /**
16
17
  * Copyright (c) Meta Platforms, Inc. and affiliates.
@@ -30,6 +31,10 @@ const CAN_USE_DOM = typeof window !== 'undefined' && typeof window.document !==
30
31
  *
31
32
  */
32
33
 
34
+
35
+ // This workaround is no longer necessary in React 19,
36
+ // but we currently support React >=17.x
37
+ // https://github.com/facebook/react/pull/26395
33
38
  const useLayoutEffectImpl = CAN_USE_DOM ? useLayoutEffect : useEffect;
34
39
 
35
40
  /**
@@ -557,7 +562,7 @@ function LexicalTypeaheadMenuPlugin({
557
562
  removeUpdateListener();
558
563
  };
559
564
  }, [editor, triggerFn, onQueryChange, resolution, closeTypeahead, openTypeahead]);
560
- return resolution === null || editor === null ? null : /*#__PURE__*/React.createElement(LexicalMenu, {
565
+ return resolution === null || editor === null ? null : /*#__PURE__*/jsx(LexicalMenu, {
561
566
  close: closeTypeahead,
562
567
  resolution: resolution,
563
568
  editor: editor,