@lexical/react 0.13.1 → 0.14.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 (179) hide show
  1. package/LexicalAutoEmbedPlugin.dev.esm.js +131 -0
  2. package/LexicalAutoEmbedPlugin.esm.js +13 -0
  3. package/LexicalAutoEmbedPlugin.js +1 -1
  4. package/LexicalAutoEmbedPlugin.prod.esm.js +7 -0
  5. package/LexicalAutoFocusPlugin.dev.esm.js +42 -0
  6. package/LexicalAutoFocusPlugin.esm.js +10 -0
  7. package/LexicalAutoFocusPlugin.js +1 -1
  8. package/LexicalAutoFocusPlugin.prod.esm.js +7 -0
  9. package/LexicalAutoLinkPlugin.dev.esm.js +312 -0
  10. package/LexicalAutoLinkPlugin.dev.js +3 -1
  11. package/LexicalAutoLinkPlugin.esm.js +11 -0
  12. package/LexicalAutoLinkPlugin.js +1 -1
  13. package/LexicalAutoLinkPlugin.prod.esm.js +7 -0
  14. package/LexicalBlockWithAlignableContents.dev.esm.js +86 -0
  15. package/LexicalBlockWithAlignableContents.dev.js +1 -0
  16. package/LexicalBlockWithAlignableContents.esm.js +10 -0
  17. package/LexicalBlockWithAlignableContents.js +1 -1
  18. package/LexicalBlockWithAlignableContents.prod.esm.js +7 -0
  19. package/LexicalBlockWithAlignableContents.prod.js +1 -1
  20. package/LexicalCharacterLimitPlugin.d.ts +4 -1
  21. package/LexicalCharacterLimitPlugin.dev.esm.js +272 -0
  22. package/LexicalCharacterLimitPlugin.dev.js +12 -4
  23. package/LexicalCharacterLimitPlugin.esm.js +10 -0
  24. package/LexicalCharacterLimitPlugin.js +1 -1
  25. package/LexicalCharacterLimitPlugin.prod.esm.js +7 -0
  26. package/LexicalCharacterLimitPlugin.prod.js +9 -9
  27. package/LexicalCheckListPlugin.dev.esm.js +203 -0
  28. package/LexicalCheckListPlugin.esm.js +10 -0
  29. package/LexicalCheckListPlugin.js +1 -1
  30. package/LexicalCheckListPlugin.prod.esm.js +7 -0
  31. package/LexicalClearEditorPlugin.dev.esm.js +64 -0
  32. package/LexicalClearEditorPlugin.esm.js +10 -0
  33. package/LexicalClearEditorPlugin.js +1 -1
  34. package/LexicalClearEditorPlugin.prod.esm.js +7 -0
  35. package/LexicalClickableLinkPlugin.dev.esm.js +95 -0
  36. package/LexicalClickableLinkPlugin.esm.js +10 -0
  37. package/LexicalClickableLinkPlugin.js +1 -1
  38. package/LexicalClickableLinkPlugin.prod.esm.js +7 -0
  39. package/LexicalCollaborationContext.dev.esm.js +36 -0
  40. package/LexicalCollaborationContext.esm.js +11 -0
  41. package/LexicalCollaborationContext.js +1 -1
  42. package/LexicalCollaborationContext.prod.esm.js +7 -0
  43. package/LexicalCollaborationPlugin.dev.esm.js +308 -0
  44. package/LexicalCollaborationPlugin.esm.js +10 -0
  45. package/LexicalCollaborationPlugin.js +1 -1
  46. package/LexicalCollaborationPlugin.prod.esm.js +7 -0
  47. package/LexicalComposer.dev.esm.js +129 -0
  48. package/LexicalComposer.esm.js +10 -0
  49. package/LexicalComposer.js +1 -1
  50. package/LexicalComposer.prod.esm.js +7 -0
  51. package/LexicalComposerContext.dev.esm.js +42 -0
  52. package/LexicalComposerContext.esm.js +12 -0
  53. package/LexicalComposerContext.js +1 -1
  54. package/LexicalComposerContext.prod.esm.js +7 -0
  55. package/LexicalContentEditable.dev.esm.js +107 -0
  56. package/LexicalContentEditable.dev.js +5 -1
  57. package/LexicalContentEditable.esm.js +10 -0
  58. package/LexicalContentEditable.js +1 -1
  59. package/LexicalContentEditable.prod.esm.js +7 -0
  60. package/LexicalContentEditable.prod.js +3 -3
  61. package/LexicalContextMenuPlugin.dev.esm.js +455 -0
  62. package/LexicalContextMenuPlugin.dev.js +3 -1
  63. package/LexicalContextMenuPlugin.esm.js +11 -0
  64. package/LexicalContextMenuPlugin.js +1 -1
  65. package/LexicalContextMenuPlugin.prod.esm.js +7 -0
  66. package/LexicalDecoratorBlockNode.dev.esm.js +46 -0
  67. package/LexicalDecoratorBlockNode.esm.js +11 -0
  68. package/LexicalDecoratorBlockNode.js +1 -1
  69. package/LexicalDecoratorBlockNode.prod.esm.js +7 -0
  70. package/LexicalEditorRefPlugin.dev.esm.js +40 -0
  71. package/LexicalEditorRefPlugin.dev.js +10 -5
  72. package/LexicalEditorRefPlugin.esm.js +10 -0
  73. package/LexicalEditorRefPlugin.js +1 -1
  74. package/LexicalEditorRefPlugin.prod.esm.js +7 -0
  75. package/LexicalEditorRefPlugin.prod.js +1 -1
  76. package/LexicalErrorBoundary.dev.esm.js +157 -0
  77. package/LexicalErrorBoundary.esm.js +10 -0
  78. package/LexicalErrorBoundary.js +1 -1
  79. package/LexicalErrorBoundary.prod.esm.js +7 -0
  80. package/LexicalHashtagPlugin.dev.esm.js +163 -0
  81. package/LexicalHashtagPlugin.esm.js +10 -0
  82. package/LexicalHashtagPlugin.js +1 -1
  83. package/LexicalHashtagPlugin.prod.esm.js +7 -0
  84. package/LexicalHistoryPlugin.dev.esm.js +41 -0
  85. package/LexicalHistoryPlugin.esm.js +11 -0
  86. package/LexicalHistoryPlugin.js +1 -1
  87. package/LexicalHistoryPlugin.prod.esm.js +7 -0
  88. package/LexicalHorizontalRuleNode.dev.esm.js +118 -0
  89. package/LexicalHorizontalRuleNode.dev.js +1 -0
  90. package/LexicalHorizontalRuleNode.esm.js +13 -0
  91. package/LexicalHorizontalRuleNode.js +1 -1
  92. package/LexicalHorizontalRuleNode.prod.esm.js +7 -0
  93. package/LexicalHorizontalRuleNode.prod.js +1 -1
  94. package/LexicalHorizontalRulePlugin.dev.esm.js +39 -0
  95. package/LexicalHorizontalRulePlugin.esm.js +10 -0
  96. package/LexicalHorizontalRulePlugin.js +1 -1
  97. package/LexicalHorizontalRulePlugin.prod.esm.js +7 -0
  98. package/LexicalLinkPlugin.dev.esm.js +79 -0
  99. package/LexicalLinkPlugin.dev.js +6 -2
  100. package/LexicalLinkPlugin.esm.js +10 -0
  101. package/LexicalLinkPlugin.js +1 -1
  102. package/LexicalLinkPlugin.prod.esm.js +7 -0
  103. package/LexicalLinkPlugin.prod.js +1 -1
  104. package/LexicalListPlugin.dev.esm.js +59 -0
  105. package/LexicalListPlugin.esm.js +10 -0
  106. package/LexicalListPlugin.js +1 -1
  107. package/LexicalListPlugin.prod.esm.js +7 -0
  108. package/LexicalMarkdownShortcutPlugin.dev.esm.js +49 -0
  109. package/LexicalMarkdownShortcutPlugin.esm.js +11 -0
  110. package/LexicalMarkdownShortcutPlugin.js +1 -1
  111. package/LexicalMarkdownShortcutPlugin.prod.esm.js +7 -0
  112. package/LexicalNestedComposer.dev.esm.js +105 -0
  113. package/LexicalNestedComposer.esm.js +10 -0
  114. package/LexicalNestedComposer.js +1 -1
  115. package/LexicalNestedComposer.prod.esm.js +7 -0
  116. package/LexicalNodeEventPlugin.dev.esm.js +56 -0
  117. package/LexicalNodeEventPlugin.esm.js +10 -0
  118. package/LexicalNodeEventPlugin.js +1 -1
  119. package/LexicalNodeEventPlugin.prod.esm.js +7 -0
  120. package/LexicalNodeMenuPlugin.dev.esm.js +466 -0
  121. package/LexicalNodeMenuPlugin.dev.js +3 -1
  122. package/LexicalNodeMenuPlugin.esm.js +11 -0
  123. package/LexicalNodeMenuPlugin.js +1 -1
  124. package/LexicalNodeMenuPlugin.prod.esm.js +7 -0
  125. package/LexicalOnChangePlugin.dev.esm.js +62 -0
  126. package/LexicalOnChangePlugin.esm.js +10 -0
  127. package/LexicalOnChangePlugin.js +1 -1
  128. package/LexicalOnChangePlugin.prod.esm.js +7 -0
  129. package/LexicalPlainTextPlugin.dev.esm.js +161 -0
  130. package/LexicalPlainTextPlugin.esm.js +10 -0
  131. package/LexicalPlainTextPlugin.js +1 -1
  132. package/LexicalPlainTextPlugin.prod.esm.js +7 -0
  133. package/LexicalRichTextPlugin.dev.esm.js +161 -0
  134. package/LexicalRichTextPlugin.esm.js +10 -0
  135. package/LexicalRichTextPlugin.js +1 -1
  136. package/LexicalRichTextPlugin.prod.esm.js +7 -0
  137. package/LexicalTabIndentationPlugin.dev.esm.js +76 -0
  138. package/LexicalTabIndentationPlugin.esm.js +11 -0
  139. package/LexicalTabIndentationPlugin.js +1 -1
  140. package/LexicalTabIndentationPlugin.prod.esm.js +7 -0
  141. package/LexicalTableOfContents.dev.esm.js +157 -0
  142. package/LexicalTableOfContents.esm.js +10 -0
  143. package/LexicalTableOfContents.js +1 -1
  144. package/LexicalTableOfContents.prod.esm.js +7 -0
  145. package/LexicalTablePlugin.dev.esm.js +163 -0
  146. package/LexicalTablePlugin.esm.js +10 -0
  147. package/LexicalTablePlugin.js +1 -1
  148. package/LexicalTablePlugin.prod.esm.js +7 -0
  149. package/LexicalTreeView.dev.esm.js +483 -0
  150. package/LexicalTreeView.dev.js +3 -1
  151. package/LexicalTreeView.esm.js +10 -0
  152. package/LexicalTreeView.js +1 -1
  153. package/LexicalTreeView.prod.esm.js +7 -0
  154. package/LexicalTypeaheadMenuPlugin.dev.esm.js +569 -0
  155. package/LexicalTypeaheadMenuPlugin.dev.js +3 -1
  156. package/LexicalTypeaheadMenuPlugin.esm.js +16 -0
  157. package/LexicalTypeaheadMenuPlugin.js +1 -1
  158. package/LexicalTypeaheadMenuPlugin.prod.esm.js +7 -0
  159. package/package.json +583 -20
  160. package/useLexicalEditable.dev.esm.js +82 -0
  161. package/useLexicalEditable.esm.js +10 -0
  162. package/useLexicalEditable.js +1 -1
  163. package/useLexicalEditable.prod.esm.js +7 -0
  164. package/useLexicalIsTextContentEmpty.dev.esm.js +51 -0
  165. package/useLexicalIsTextContentEmpty.esm.js +10 -0
  166. package/useLexicalIsTextContentEmpty.js +1 -1
  167. package/useLexicalIsTextContentEmpty.prod.esm.js +7 -0
  168. package/useLexicalNodeSelection.dev.esm.js +69 -0
  169. package/useLexicalNodeSelection.esm.js +10 -0
  170. package/useLexicalNodeSelection.js +1 -1
  171. package/useLexicalNodeSelection.prod.esm.js +7 -0
  172. package/useLexicalSubscription.dev.esm.js +63 -0
  173. package/useLexicalSubscription.esm.js +10 -0
  174. package/useLexicalSubscription.js +1 -1
  175. package/useLexicalSubscription.prod.esm.js +7 -0
  176. package/useLexicalTextEntity.dev.esm.js +26 -0
  177. package/useLexicalTextEntity.esm.js +10 -0
  178. package/useLexicalTextEntity.js +1 -1
  179. package/useLexicalTextEntity.prod.esm.js +7 -0
@@ -0,0 +1,308 @@
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
+ import { useCollaborationContext } from '@lexical/react/LexicalCollaborationContext';
8
+ import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
9
+ import * as React from 'react';
10
+ import { useRef, useState, useMemo, useCallback, useEffect } from 'react';
11
+ import { mergeRegister } from '@lexical/utils';
12
+ import { createBinding, initLocalState, syncLexicalUpdateToYjs, TOGGLE_CONNECT_COMMAND, setLocalStateFocus, createUndoManager, CONNECTED_COMMAND, syncCursorPositions, syncYjsChangesToLexical } from '@lexical/yjs';
13
+ import { COMMAND_PRIORITY_EDITOR, FOCUS_COMMAND, BLUR_COMMAND, UNDO_COMMAND, REDO_COMMAND, CAN_UNDO_COMMAND, CAN_REDO_COMMAND, $getRoot, $createParagraphNode, $getSelection } from 'lexical';
14
+ import { createPortal } from 'react-dom';
15
+ import { UndoManager } from 'yjs';
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
+ function useYjsCollaboration(editor, id, provider, docMap, name, color, shouldBootstrap, cursorsContainerRef, initialEditorState, excludedProperties, awarenessData) {
25
+ const isReloadingDoc = useRef(false);
26
+ const [doc, setDoc] = useState(docMap.get(id));
27
+ const binding = useMemo(() => createBinding(editor, provider, id, doc, docMap, excludedProperties), [editor, provider, id, docMap, doc, excludedProperties]);
28
+ const connect = useCallback(() => {
29
+ provider.connect();
30
+ }, [provider]);
31
+ const disconnect = useCallback(() => {
32
+ try {
33
+ provider.disconnect();
34
+ } catch (e) {
35
+ // Do nothing
36
+ }
37
+ }, [provider]);
38
+ useEffect(() => {
39
+ const {
40
+ root
41
+ } = binding;
42
+ const {
43
+ awareness
44
+ } = provider;
45
+ const onStatus = ({
46
+ status
47
+ }) => {
48
+ editor.dispatchCommand(CONNECTED_COMMAND, status === 'connected');
49
+ };
50
+ const onSync = isSynced => {
51
+ if (shouldBootstrap && isSynced && root.isEmpty() && root._xmlText._length === 0 && isReloadingDoc.current === false) {
52
+ initializeEditor(editor, initialEditorState);
53
+ }
54
+ isReloadingDoc.current = false;
55
+ };
56
+ const onAwarenessUpdate = () => {
57
+ syncCursorPositions(binding, provider);
58
+ };
59
+ const onYjsTreeChanges = (events, transaction) => {
60
+ const origin = transaction.origin;
61
+ if (origin !== binding) {
62
+ const isFromUndoManger = origin instanceof UndoManager;
63
+ syncYjsChangesToLexical(binding, provider, events, isFromUndoManger);
64
+ }
65
+ };
66
+ initLocalState(provider, name, color, document.activeElement === editor.getRootElement(), awarenessData || {});
67
+ const onProviderDocReload = ydoc => {
68
+ clearEditorSkipCollab(editor, binding);
69
+ setDoc(ydoc);
70
+ docMap.set(id, ydoc);
71
+ isReloadingDoc.current = true;
72
+ };
73
+ provider.on('reload', onProviderDocReload);
74
+ provider.on('status', onStatus);
75
+ provider.on('sync', onSync);
76
+ awareness.on('update', onAwarenessUpdate);
77
+ // This updates the local editor state when we recieve updates from other clients
78
+ root.getSharedType().observeDeep(onYjsTreeChanges);
79
+ const removeListener = editor.registerUpdateListener(({
80
+ prevEditorState,
81
+ editorState,
82
+ dirtyLeaves,
83
+ dirtyElements,
84
+ normalizedNodes,
85
+ tags
86
+ }) => {
87
+ if (tags.has('skip-collab') === false) {
88
+ syncLexicalUpdateToYjs(binding, provider, prevEditorState, editorState, dirtyElements, dirtyLeaves, normalizedNodes, tags);
89
+ }
90
+ });
91
+ connect();
92
+ return () => {
93
+ if (isReloadingDoc.current === false) {
94
+ disconnect();
95
+ }
96
+ provider.off('sync', onSync);
97
+ provider.off('status', onStatus);
98
+ provider.off('reload', onProviderDocReload);
99
+ awareness.off('update', onAwarenessUpdate);
100
+ root.getSharedType().unobserveDeep(onYjsTreeChanges);
101
+ docMap.delete(id);
102
+ removeListener();
103
+ };
104
+ }, [binding, color, connect, disconnect, docMap, editor, id, initialEditorState, name, provider, shouldBootstrap, awarenessData]);
105
+ const cursorsContainer = useMemo(() => {
106
+ const ref = element => {
107
+ binding.cursorsContainer = element;
108
+ };
109
+ return /*#__PURE__*/createPortal( /*#__PURE__*/React.createElement("div", {
110
+ ref: ref
111
+ }), cursorsContainerRef && cursorsContainerRef.current || document.body);
112
+ }, [binding, cursorsContainerRef]);
113
+ useEffect(() => {
114
+ return editor.registerCommand(TOGGLE_CONNECT_COMMAND, payload => {
115
+ if (connect !== undefined && disconnect !== undefined) {
116
+ const shouldConnect = payload;
117
+ if (shouldConnect) {
118
+ // eslint-disable-next-line no-console
119
+ console.log('Collaboration connected!');
120
+ connect();
121
+ } else {
122
+ // eslint-disable-next-line no-console
123
+ console.log('Collaboration disconnected!');
124
+ disconnect();
125
+ }
126
+ }
127
+ return true;
128
+ }, COMMAND_PRIORITY_EDITOR);
129
+ }, [connect, disconnect, editor]);
130
+ return [cursorsContainer, binding];
131
+ }
132
+ function useYjsFocusTracking(editor, provider, name, color, awarenessData) {
133
+ useEffect(() => {
134
+ return mergeRegister(editor.registerCommand(FOCUS_COMMAND, () => {
135
+ setLocalStateFocus(provider, name, color, true, awarenessData || {});
136
+ return false;
137
+ }, COMMAND_PRIORITY_EDITOR), editor.registerCommand(BLUR_COMMAND, () => {
138
+ setLocalStateFocus(provider, name, color, false, awarenessData || {});
139
+ return false;
140
+ }, COMMAND_PRIORITY_EDITOR));
141
+ }, [color, editor, name, provider, awarenessData]);
142
+ }
143
+ function useYjsHistory(editor, binding) {
144
+ const undoManager = useMemo(() => createUndoManager(binding, binding.root.getSharedType()), [binding]);
145
+ useEffect(() => {
146
+ const undo = () => {
147
+ undoManager.undo();
148
+ };
149
+ const redo = () => {
150
+ undoManager.redo();
151
+ };
152
+ return mergeRegister(editor.registerCommand(UNDO_COMMAND, () => {
153
+ undo();
154
+ return true;
155
+ }, COMMAND_PRIORITY_EDITOR), editor.registerCommand(REDO_COMMAND, () => {
156
+ redo();
157
+ return true;
158
+ }, COMMAND_PRIORITY_EDITOR));
159
+ });
160
+ const clearHistory = useCallback(() => {
161
+ undoManager.clear();
162
+ }, [undoManager]);
163
+
164
+ // Exposing undo and redo states
165
+ React.useEffect(() => {
166
+ const updateUndoRedoStates = () => {
167
+ editor.dispatchCommand(CAN_UNDO_COMMAND, undoManager.undoStack.length > 0);
168
+ editor.dispatchCommand(CAN_REDO_COMMAND, undoManager.redoStack.length > 0);
169
+ };
170
+ undoManager.on('stack-item-added', updateUndoRedoStates);
171
+ undoManager.on('stack-item-popped', updateUndoRedoStates);
172
+ undoManager.on('stack-cleared', updateUndoRedoStates);
173
+ return () => {
174
+ undoManager.off('stack-item-added', updateUndoRedoStates);
175
+ undoManager.off('stack-item-popped', updateUndoRedoStates);
176
+ undoManager.off('stack-cleared', updateUndoRedoStates);
177
+ };
178
+ }, [editor, undoManager]);
179
+ return clearHistory;
180
+ }
181
+ function initializeEditor(editor, initialEditorState) {
182
+ editor.update(() => {
183
+ const root = $getRoot();
184
+ if (root.isEmpty()) {
185
+ if (initialEditorState) {
186
+ switch (typeof initialEditorState) {
187
+ case 'string':
188
+ {
189
+ const parsedEditorState = editor.parseEditorState(initialEditorState);
190
+ editor.setEditorState(parsedEditorState, {
191
+ tag: 'history-merge'
192
+ });
193
+ break;
194
+ }
195
+ case 'object':
196
+ {
197
+ editor.setEditorState(initialEditorState, {
198
+ tag: 'history-merge'
199
+ });
200
+ break;
201
+ }
202
+ case 'function':
203
+ {
204
+ editor.update(() => {
205
+ const root1 = $getRoot();
206
+ if (root1.isEmpty()) {
207
+ initialEditorState(editor);
208
+ }
209
+ }, {
210
+ tag: 'history-merge'
211
+ });
212
+ break;
213
+ }
214
+ }
215
+ } else {
216
+ const paragraph = $createParagraphNode();
217
+ root.append(paragraph);
218
+ const {
219
+ activeElement
220
+ } = document;
221
+ if ($getSelection() !== null || activeElement !== null && activeElement === editor.getRootElement()) {
222
+ paragraph.select();
223
+ }
224
+ }
225
+ }
226
+ }, {
227
+ tag: 'history-merge'
228
+ });
229
+ }
230
+ function clearEditorSkipCollab(editor, binding) {
231
+ // reset editor state
232
+ editor.update(() => {
233
+ const root = $getRoot();
234
+ root.clear();
235
+ root.select();
236
+ }, {
237
+ tag: 'skip-collab'
238
+ });
239
+ if (binding.cursors == null) {
240
+ return;
241
+ }
242
+ const cursors = binding.cursors;
243
+ if (cursors == null) {
244
+ return;
245
+ }
246
+ const cursorsContainer = binding.cursorsContainer;
247
+ if (cursorsContainer == null) {
248
+ return;
249
+ }
250
+
251
+ // reset cursors in dom
252
+ const cursorsArr = Array.from(cursors.values());
253
+ for (let i = 0; i < cursorsArr.length; i++) {
254
+ const cursor = cursorsArr[i];
255
+ const selection = cursor.selection;
256
+ if (selection && selection.selections != null) {
257
+ const selections = selection.selections;
258
+ for (let j = 0; j < selections.length; j++) {
259
+ cursorsContainer.removeChild(selections[i]);
260
+ }
261
+ }
262
+ }
263
+ }
264
+
265
+ /**
266
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
267
+ *
268
+ * This source code is licensed under the MIT license found in the
269
+ * LICENSE file in the root directory of this source tree.
270
+ *
271
+ */
272
+ function CollaborationPlugin({
273
+ id,
274
+ providerFactory,
275
+ shouldBootstrap,
276
+ username,
277
+ cursorColor,
278
+ cursorsContainerRef,
279
+ initialEditorState,
280
+ excludedProperties,
281
+ awarenessData
282
+ }) {
283
+ const collabContext = useCollaborationContext(username, cursorColor);
284
+ const {
285
+ yjsDocMap,
286
+ name,
287
+ color
288
+ } = collabContext;
289
+ const [editor] = useLexicalComposerContext();
290
+ useEffect(() => {
291
+ collabContext.isCollabActive = true;
292
+ return () => {
293
+ // Reseting flag only when unmount top level editor collab plugin. Nested
294
+ // editors (e.g. image caption) should unmount without affecting it
295
+ if (editor._parentEditor == null) {
296
+ collabContext.isCollabActive = false;
297
+ }
298
+ };
299
+ }, [collabContext, editor]);
300
+ const provider = useMemo(() => providerFactory(id, yjsDocMap), [id, providerFactory, yjsDocMap]);
301
+ const [cursors, binding] = useYjsCollaboration(editor, id, provider, yjsDocMap, name, color, shouldBootstrap, cursorsContainerRef, initialEditorState, excludedProperties, awarenessData);
302
+ collabContext.clientID = binding.clientID;
303
+ useYjsHistory(editor, binding);
304
+ useYjsFocusTracking(editor, provider, name, color, awarenessData);
305
+ return cursors;
306
+ }
307
+
308
+ export { CollaborationPlugin };
@@ -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
+ import * as modDev from './LexicalCollaborationPlugin.dev.esm.js';
8
+ import * as modProd from './LexicalCollaborationPlugin.prod.esm.js';
9
+ const mod = process.env.NODE_ENV === 'development' ? modDev : modProd;
10
+ export const CollaborationPlugin = mod.CollaborationPlugin;
@@ -5,5 +5,5 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  'use strict'
8
- const LexicalCollaborationPlugin = process.env.NODE_ENV === 'development' ? require('./LexicalCollaborationPlugin.dev.js') : require('./LexicalCollaborationPlugin.prod.js')
8
+ const LexicalCollaborationPlugin = process.env.NODE_ENV === 'development' ? require('./LexicalCollaborationPlugin.dev.js') : require('./LexicalCollaborationPlugin.prod.js');
9
9
  module.exports = LexicalCollaborationPlugin;
@@ -0,0 +1,7 @@
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
+ import{useCollaborationContext as e}from"@lexical/react/LexicalCollaborationContext";import{useLexicalComposerContext as t}from"@lexical/react/LexicalComposerContext";import*as o from"react";import{useRef as r,useState as n,useMemo as s,useCallback as c,useEffect as a}from"react";import{mergeRegister as i}from"@lexical/utils";import{createBinding as l,initLocalState as d,syncLexicalUpdateToYjs as m,TOGGLE_CONNECT_COMMAND as u,setLocalStateFocus as f,createUndoManager as p,CONNECTED_COMMAND as g,syncCursorPositions as y,syncYjsChangesToLexical as C}from"@lexical/yjs";import{COMMAND_PRIORITY_EDITOR as h,FOCUS_COMMAND as E,BLUR_COMMAND as v,UNDO_COMMAND as b,REDO_COMMAND as x,CAN_UNDO_COMMAND as k,CAN_REDO_COMMAND as S,$getRoot as D,$createParagraphNode as j,$getSelection as L}from"lexical";import{createPortal as T}from"react-dom";import{UndoManager as w}from"yjs";function A(e,t,i,f,p,E,v,b,x,k,S){const A=r(!1),[R,_]=n(f.get(t)),I=s((()=>l(e,i,t,R,f,k)),[e,i,t,f,R,k]),z=c((()=>{i.connect()}),[i]),B=c((()=>{try{i.disconnect()}catch(e){}}),[i]);a((()=>{const{root:o}=I,{awareness:r}=i,n=({status:t})=>{e.dispatchCommand(g,"connected"===t)},s=t=>{v&&t&&o.isEmpty()&&0===o._xmlText._length&&!1===A.current&&function(e,t){e.update((()=>{const o=D();if(o.isEmpty())if(t)switch(typeof t){case"string":{const o=e.parseEditorState(t);e.setEditorState(o,{tag:"history-merge"});break}case"object":e.setEditorState(t,{tag:"history-merge"});break;case"function":e.update((()=>{D().isEmpty()&&t(e)}),{tag:"history-merge"})}else{const t=j();o.append(t);const{activeElement:r}=document;(null!==L()||null!==r&&r===e.getRootElement())&&t.select()}}),{tag:"history-merge"})}(e,x),A.current=!1},c=()=>{y(I,i)},a=(e,t)=>{const o=t.origin;if(o!==I){C(I,i,e,o instanceof w)}};d(i,p,E,document.activeElement===e.getRootElement(),S||{});const l=o=>{!function(e,t){if(e.update((()=>{const e=D();e.clear(),e.select()}),{tag:"skip-collab"}),null==t.cursors)return;const o=t.cursors;if(null==o)return;const r=t.cursorsContainer;if(null==r)return;const n=Array.from(o.values());for(let e=0;e<n.length;e++){const t=n[e].selection;if(t&&null!=t.selections){const o=t.selections;for(let t=0;t<o.length;t++)r.removeChild(o[e])}}}(e,I),_(o),f.set(t,o),A.current=!0};i.on("reload",l),i.on("status",n),i.on("sync",s),r.on("update",c),o.getSharedType().observeDeep(a);const u=e.registerUpdateListener((({prevEditorState:e,editorState:t,dirtyLeaves:o,dirtyElements:r,normalizedNodes:n,tags:s})=>{!1===s.has("skip-collab")&&m(I,i,e,t,r,o,n,s)}));return z(),()=>{!1===A.current&&B(),i.off("sync",s),i.off("status",n),i.off("reload",l),r.off("update",c),o.getSharedType().unobserveDeep(a),f.delete(t),u()}}),[I,E,z,B,f,e,t,x,p,i,v,S]);const F=s((()=>T(o.createElement("div",{ref:e=>{I.cursorsContainer=e}}),b&&b.current||document.body)),[I,b]);return a((()=>e.registerCommand(u,(e=>{if(void 0!==z&&void 0!==B){e?(console.log("Collaboration connected!"),z()):(console.log("Collaboration disconnected!"),B())}return!0}),h)),[z,B,e]),[F,I]}function R(e,t){const r=s((()=>p(t,t.root.getSharedType())),[t]);a((()=>i(e.registerCommand(b,(()=>(r.undo(),!0)),h),e.registerCommand(x,(()=>(r.redo(),!0)),h))));const n=c((()=>{r.clear()}),[r]);return o.useEffect((()=>{const t=()=>{e.dispatchCommand(k,r.undoStack.length>0),e.dispatchCommand(S,r.redoStack.length>0)};return r.on("stack-item-added",t),r.on("stack-item-popped",t),r.on("stack-cleared",t),()=>{r.off("stack-item-added",t),r.off("stack-item-popped",t),r.off("stack-cleared",t)}}),[e,r]),n}function _({id:o,providerFactory:r,shouldBootstrap:n,username:c,cursorColor:l,cursorsContainerRef:d,initialEditorState:m,excludedProperties:u,awarenessData:p}){const g=e(c,l),{yjsDocMap:y,name:C,color:b}=g,[x]=t();a((()=>(g.isCollabActive=!0,()=>{null==x._parentEditor&&(g.isCollabActive=!1)})),[g,x]);const k=s((()=>r(o,y)),[o,r,y]),[S,D]=A(x,o,k,y,C,b,n,d,m,u,p);return g.clientID=D.clientID,R(x,D),function(e,t,o,r,n){a((()=>i(e.registerCommand(E,(()=>(f(t,o,r,!0,n||{}),!1)),h),e.registerCommand(v,(()=>(f(t,o,r,!1,n||{}),!1)),h))),[r,e,o,t,n])}(x,k,C,b,p),S}export{_ as CollaborationPlugin};
@@ -0,0 +1,129 @@
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
+ import { createLexicalComposerContext, LexicalComposerContext } from '@lexical/react/LexicalComposerContext';
8
+ import { createEditor, $getRoot, $createParagraphNode, $getSelection } from 'lexical';
9
+ import * as React from 'react';
10
+ import { useLayoutEffect as useLayoutEffect$1, useEffect, useMemo } from 'react';
11
+
12
+ /**
13
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
14
+ *
15
+ * This source code is licensed under the MIT license found in the
16
+ * LICENSE file in the root directory of this source tree.
17
+ *
18
+ */
19
+
20
+ const CAN_USE_DOM = typeof window !== 'undefined' && typeof window.document !== 'undefined' && typeof window.document.createElement !== 'undefined';
21
+
22
+ /**
23
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
24
+ *
25
+ * This source code is licensed under the MIT license found in the
26
+ * LICENSE file in the root directory of this source tree.
27
+ *
28
+ */
29
+ const useLayoutEffectImpl = CAN_USE_DOM ? useLayoutEffect$1 : useEffect;
30
+ var useLayoutEffect = useLayoutEffectImpl;
31
+
32
+ /**
33
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
34
+ *
35
+ * This source code is licensed under the MIT license found in the
36
+ * LICENSE file in the root directory of this source tree.
37
+ *
38
+ */
39
+ const HISTORY_MERGE_OPTIONS = {
40
+ tag: 'history-merge'
41
+ };
42
+ function LexicalComposer({
43
+ initialConfig,
44
+ children
45
+ }) {
46
+ const composerContext = useMemo(() => {
47
+ const {
48
+ theme,
49
+ namespace,
50
+ editor__DEPRECATED: initialEditor,
51
+ nodes,
52
+ onError,
53
+ editorState: initialEditorState,
54
+ html
55
+ } = initialConfig;
56
+ const context = createLexicalComposerContext(null, theme);
57
+ let editor = initialEditor || null;
58
+ if (editor === null) {
59
+ const newEditor = createEditor({
60
+ editable: initialConfig.editable,
61
+ html,
62
+ namespace,
63
+ nodes,
64
+ onError: error => onError(error, newEditor),
65
+ theme
66
+ });
67
+ initializeEditor(newEditor, initialEditorState);
68
+ editor = newEditor;
69
+ }
70
+ return [editor, context];
71
+ },
72
+ // We only do this for init
73
+ // eslint-disable-next-line react-hooks/exhaustive-deps
74
+ []);
75
+ useLayoutEffect(() => {
76
+ const isEditable = initialConfig.editable;
77
+ const [editor] = composerContext;
78
+ editor.setEditable(isEditable !== undefined ? isEditable : true);
79
+
80
+ // We only do this for init
81
+ // eslint-disable-next-line react-hooks/exhaustive-deps
82
+ }, []);
83
+ return /*#__PURE__*/React.createElement(LexicalComposerContext.Provider, {
84
+ value: composerContext
85
+ }, children);
86
+ }
87
+ function initializeEditor(editor, initialEditorState) {
88
+ if (initialEditorState === null) {
89
+ return;
90
+ } else if (initialEditorState === undefined) {
91
+ editor.update(() => {
92
+ const root = $getRoot();
93
+ if (root.isEmpty()) {
94
+ const paragraph = $createParagraphNode();
95
+ root.append(paragraph);
96
+ const activeElement = CAN_USE_DOM ? document.activeElement : null;
97
+ if ($getSelection() !== null || activeElement !== null && activeElement === editor.getRootElement()) {
98
+ paragraph.select();
99
+ }
100
+ }
101
+ }, HISTORY_MERGE_OPTIONS);
102
+ } else if (initialEditorState !== null) {
103
+ switch (typeof initialEditorState) {
104
+ case 'string':
105
+ {
106
+ const parsedEditorState = editor.parseEditorState(initialEditorState);
107
+ editor.setEditorState(parsedEditorState, HISTORY_MERGE_OPTIONS);
108
+ break;
109
+ }
110
+ case 'object':
111
+ {
112
+ editor.setEditorState(initialEditorState, HISTORY_MERGE_OPTIONS);
113
+ break;
114
+ }
115
+ case 'function':
116
+ {
117
+ editor.update(() => {
118
+ const root = $getRoot();
119
+ if (root.isEmpty()) {
120
+ initialEditorState(editor);
121
+ }
122
+ }, HISTORY_MERGE_OPTIONS);
123
+ break;
124
+ }
125
+ }
126
+ }
127
+ }
128
+
129
+ export { LexicalComposer };
@@ -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
+ import * as modDev from './LexicalComposer.dev.esm.js';
8
+ import * as modProd from './LexicalComposer.prod.esm.js';
9
+ const mod = process.env.NODE_ENV === 'development' ? modDev : modProd;
10
+ export const LexicalComposer = mod.LexicalComposer;
@@ -5,5 +5,5 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  'use strict'
8
- const LexicalComposer = process.env.NODE_ENV === 'development' ? require('./LexicalComposer.dev.js') : require('./LexicalComposer.prod.js')
8
+ const LexicalComposer = process.env.NODE_ENV === 'development' ? require('./LexicalComposer.dev.js') : require('./LexicalComposer.prod.js');
9
9
  module.exports = LexicalComposer;
@@ -0,0 +1,7 @@
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
+ import{createLexicalComposerContext as e,LexicalComposerContext as t}from"@lexical/react/LexicalComposerContext";import{createEditor as o,$getRoot as n,$createParagraphNode as i,$getSelection as r}from"lexical";import*as a from"react";import{useLayoutEffect as l,useEffect as c,useMemo as s}from"react";const d="undefined"!=typeof window&&void 0!==window.document&&void 0!==window.document.createElement;var m=d?l:c;const u={tag:"history-merge"};function f({initialConfig:l,children:c}){const f=s((()=>{const{theme:t,namespace:a,editor__DEPRECATED:c,nodes:s,onError:m,editorState:f,html:p}=l,E=e(null,t);let v=c||null;if(null===v){const e=o({editable:l.editable,html:p,namespace:a,nodes:s,onError:t=>m(t,e),theme:t});!function(e,t){if(null===t)return;if(void 0===t)e.update((()=>{const t=n();if(t.isEmpty()){const o=i();t.append(o);const n=d?document.activeElement:null;(null!==r()||null!==n&&n===e.getRootElement())&&o.select()}}),u);else if(null!==t)switch(typeof t){case"string":{const o=e.parseEditorState(t);e.setEditorState(o,u);break}case"object":e.setEditorState(t,u);break;case"function":e.update((()=>{n().isEmpty()&&t(e)}),u)}}(e,f),v=e}return[v,E]}),[]);return m((()=>{const e=l.editable,[t]=f;t.setEditable(void 0===e||e)}),[]),a.createElement(t.Provider,{value:f},c)}export{f as LexicalComposer};
@@ -0,0 +1,42 @@
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
+ import { createContext, useContext } from 'react';
8
+
9
+ /**
10
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
11
+ *
12
+ * This source code is licensed under the MIT license found in the
13
+ * LICENSE file in the root directory of this source tree.
14
+ *
15
+ */
16
+ const LexicalComposerContext = /*#__PURE__*/createContext(null);
17
+ function createLexicalComposerContext(parent, theme) {
18
+ let parentContext = null;
19
+ if (parent != null) {
20
+ parentContext = parent[1];
21
+ }
22
+ function getTheme() {
23
+ if (theme != null) {
24
+ return theme;
25
+ }
26
+ return parentContext != null ? parentContext.getTheme() : null;
27
+ }
28
+ return {
29
+ getTheme
30
+ };
31
+ }
32
+ function useLexicalComposerContext() {
33
+ const composerContext = useContext(LexicalComposerContext);
34
+ if (composerContext == null) {
35
+ {
36
+ throw Error(`LexicalComposerContext.useLexicalComposerContext: cannot find a LexicalComposerContext`);
37
+ }
38
+ }
39
+ return composerContext;
40
+ }
41
+
42
+ export { LexicalComposerContext, createLexicalComposerContext, useLexicalComposerContext };
@@ -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
+ import * as modDev from './LexicalComposerContext.dev.esm.js';
8
+ import * as modProd from './LexicalComposerContext.prod.esm.js';
9
+ const mod = process.env.NODE_ENV === 'development' ? modDev : modProd;
10
+ export const LexicalComposerContext = mod.LexicalComposerContext;
11
+ export const createLexicalComposerContext = mod.createLexicalComposerContext;
12
+ export const useLexicalComposerContext = mod.useLexicalComposerContext;
@@ -5,5 +5,5 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  'use strict'
8
- const LexicalComposerContext = process.env.NODE_ENV === 'development' ? require('./LexicalComposerContext.dev.js') : require('./LexicalComposerContext.prod.js')
8
+ const LexicalComposerContext = process.env.NODE_ENV === 'development' ? require('./LexicalComposerContext.dev.js') : require('./LexicalComposerContext.prod.js');
9
9
  module.exports = LexicalComposerContext;
@@ -0,0 +1,7 @@
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
+ import{createContext as e,useContext as n}from"react";var r=function(e){const n=new URLSearchParams;n.append("code",e);for(let e=1;e<arguments.length;e++)n.append("v",arguments[e]);throw Error(`Minified Lexical error #${e}; visit https://lexical.dev/docs/error?${n} for the full message or use the non-minified dev environment for full errors and additional helpful warnings.`)};const l=e(null);function t(e,n){let r=null;return null!=e&&(r=e[1]),{getTheme:function(){return null!=n?n:null!=r?r.getTheme():null}}}function o(){const e=n(l);return null==e&&r(8),e}export{l as LexicalComposerContext,t as createLexicalComposerContext,o as useLexicalComposerContext};
@@ -0,0 +1,107 @@
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
+ import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
8
+ import * as React from 'react';
9
+ import { useLayoutEffect as useLayoutEffect$1, useEffect, useState, useCallback } from 'react';
10
+
11
+ function _extends() {
12
+ _extends = Object.assign ? Object.assign.bind() : function (target) {
13
+ for (var i = 1; i < arguments.length; i++) {
14
+ var source = arguments[i];
15
+ for (var key in source) {
16
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
17
+ target[key] = source[key];
18
+ }
19
+ }
20
+ }
21
+ return target;
22
+ };
23
+ return _extends.apply(this, arguments);
24
+ }
25
+
26
+ /**
27
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
28
+ *
29
+ * This source code is licensed under the MIT license found in the
30
+ * LICENSE file in the root directory of this source tree.
31
+ *
32
+ */
33
+
34
+ const CAN_USE_DOM = typeof window !== 'undefined' && typeof window.document !== 'undefined' && typeof window.document.createElement !== 'undefined';
35
+
36
+ /**
37
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
38
+ *
39
+ * This source code is licensed under the MIT license found in the
40
+ * LICENSE file in the root directory of this source tree.
41
+ *
42
+ */
43
+ const useLayoutEffectImpl = CAN_USE_DOM ? useLayoutEffect$1 : useEffect;
44
+ var useLayoutEffect = useLayoutEffectImpl;
45
+
46
+ function ContentEditable({
47
+ ariaActiveDescendant,
48
+ ariaAutoComplete,
49
+ ariaControls,
50
+ ariaDescribedBy,
51
+ ariaExpanded,
52
+ ariaLabel,
53
+ ariaLabelledBy,
54
+ ariaMultiline,
55
+ ariaOwns,
56
+ ariaRequired,
57
+ autoCapitalize,
58
+ className,
59
+ id,
60
+ role = 'textbox',
61
+ spellCheck = true,
62
+ style,
63
+ tabIndex,
64
+ 'data-testid': testid,
65
+ ...rest
66
+ }) {
67
+ const [editor] = useLexicalComposerContext();
68
+ const [isEditable, setEditable] = useState(false);
69
+ const ref = useCallback(rootElement => {
70
+ // defaultView is required for a root element.
71
+ // In multi-window setups, the defaultView may not exist at certain points.
72
+ if (rootElement && rootElement.ownerDocument && rootElement.ownerDocument.defaultView) {
73
+ editor.setRootElement(rootElement);
74
+ }
75
+ }, [editor]);
76
+ useLayoutEffect(() => {
77
+ setEditable(editor.isEditable());
78
+ return editor.registerEditableListener(currentIsEditable => {
79
+ setEditable(currentIsEditable);
80
+ });
81
+ }, [editor]);
82
+ return /*#__PURE__*/React.createElement("div", _extends({}, rest, {
83
+ "aria-activedescendant": !isEditable ? undefined : ariaActiveDescendant,
84
+ "aria-autocomplete": !isEditable ? 'none' : ariaAutoComplete,
85
+ "aria-controls": !isEditable ? undefined : ariaControls,
86
+ "aria-describedby": ariaDescribedBy,
87
+ "aria-expanded": !isEditable ? undefined : role === 'combobox' ? !!ariaExpanded : undefined,
88
+ "aria-label": ariaLabel,
89
+ "aria-labelledby": ariaLabelledBy,
90
+ "aria-multiline": ariaMultiline,
91
+ "aria-owns": !isEditable ? undefined : ariaOwns,
92
+ "aria-readonly": !isEditable ? true : undefined,
93
+ "aria-required": ariaRequired,
94
+ autoCapitalize: autoCapitalize,
95
+ className: className,
96
+ contentEditable: isEditable,
97
+ "data-testid": testid,
98
+ id: id,
99
+ ref: ref,
100
+ role: role,
101
+ spellCheck: spellCheck,
102
+ style: style,
103
+ tabIndex: tabIndex
104
+ }));
105
+ }
106
+
107
+ export { ContentEditable };