@liveblocks/react-lexical 2.0.0-alpha3 → 2.0.0-alpha5
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.
- package/dist/comments/comment-plugin-provider.js +19 -10
- package/dist/comments/comment-plugin-provider.js.map +1 -1
- package/dist/comments/comment-plugin-provider.mjs +20 -13
- package/dist/comments/comment-plugin-provider.mjs.map +1 -1
- package/dist/comments/floating-composer.js.map +1 -1
- package/dist/comments/floating-composer.mjs.map +1 -1
- package/dist/comments/thread-mark-node.js.map +1 -1
- package/dist/comments/thread-mark-node.mjs.map +1 -1
- package/dist/index.d.mts +119 -24
- package/dist/index.d.ts +119 -24
- package/dist/index.js +3 -4
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -3
- package/dist/index.mjs.map +1 -1
- package/dist/liveblocks-config.js.map +1 -1
- package/dist/liveblocks-config.mjs.map +1 -1
- package/dist/liveblocks-plugin-provider.js +86 -1
- package/dist/liveblocks-plugin-provider.js.map +1 -1
- package/dist/liveblocks-plugin-provider.mjs +88 -4
- package/dist/liveblocks-plugin-provider.mjs.map +1 -1
- package/dist/mentions/mention-component.js +1 -1
- package/dist/mentions/mention-component.js.map +1 -1
- package/dist/mentions/mention-component.mjs +1 -1
- package/dist/mentions/mention-component.mjs.map +1 -1
- package/dist/mentions/mention-plugin.js +0 -12
- package/dist/mentions/mention-plugin.js.map +1 -1
- package/dist/mentions/mention-plugin.mjs +1 -13
- package/dist/mentions/mention-plugin.mjs.map +1 -1
- package/dist/version.js +1 -1
- package/dist/version.mjs +1 -1
- package/package.json +6 -6
- package/src/styles/index.css +1 -24
- package/styles.css +1 -1
- package/styles.css.map +1 -1
- package/dist/comments/ThreadPanel.js +0 -51
- package/dist/comments/ThreadPanel.js.map +0 -1
- package/dist/comments/ThreadPanel.mjs +0 -49
- package/dist/comments/ThreadPanel.mjs.map +0 -1
package/dist/index.d.mts
CHANGED
|
@@ -1,32 +1,84 @@
|
|
|
1
1
|
import { BaseMetadata } from '@liveblocks/core';
|
|
2
|
-
import { ComposerProps
|
|
2
|
+
import { ComposerProps } from '@liveblocks/react-ui';
|
|
3
3
|
import * as lexical from 'lexical';
|
|
4
|
-
import { LexicalCommand
|
|
5
|
-
import React
|
|
4
|
+
import { LexicalCommand } from 'lexical';
|
|
5
|
+
import React from 'react';
|
|
6
6
|
import { InitialConfigType } from '@lexical/react/LexicalComposer';
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* Returns whether the associated thread annotation for the given thread id is selected or not in the editor.
|
|
10
|
+
* @param threadId The id of the thread to check if the associated annotation is selected or not.
|
|
11
|
+
* @returns true if the associated annotation for the thread is selected, false otherwise.
|
|
12
|
+
*/
|
|
13
|
+
declare function useIsThreadActive(threadId: string): boolean;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Dispatching OPEN_FLOATING_COMPOSER_COMMAND will display the FloatingComposer
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
|
|
20
|
+
* import { OPEN_FLOATING_COMPOSER_COMMAND } from "@liveblocks/react-lexical";
|
|
21
|
+
*
|
|
22
|
+
* function Toolbar() {
|
|
23
|
+
* const [editor] = useLexicalComposerContext();
|
|
24
|
+
*
|
|
25
|
+
* return (
|
|
26
|
+
* <button
|
|
27
|
+
* onClick={() => {
|
|
28
|
+
* editor.dispatchCommand(OPEN_FLOATING_COMPOSER_COMMAND);
|
|
29
|
+
* }}
|
|
30
|
+
* >
|
|
31
|
+
* 💬 New comment
|
|
32
|
+
* </button>
|
|
33
|
+
* );
|
|
34
|
+
* }
|
|
35
|
+
*/
|
|
8
36
|
declare const OPEN_FLOATING_COMPOSER_COMMAND: LexicalCommand<void>;
|
|
9
37
|
declare type ThreadMetadata = {
|
|
10
38
|
resolved?: boolean;
|
|
11
39
|
};
|
|
12
40
|
declare type FloatingComposerProps<M extends BaseMetadata = ThreadMetadata> = Omit<ComposerProps<M>, "threadId" | "commentId">;
|
|
41
|
+
/**
|
|
42
|
+
* Displays a `Composer` near the current lexical selection.
|
|
43
|
+
*
|
|
44
|
+
* To open it, dispatch `OPEN_FLOATING_COMPOSER_COMMAND`.
|
|
45
|
+
*
|
|
46
|
+
* Submitting a comment will attach an annotation thread at the current selection.
|
|
47
|
+
* Should be nested inside `LiveblocksPlugin`.
|
|
48
|
+
*/
|
|
13
49
|
declare const FloatingComposer: React.ForwardRefExoticComponent<FloatingComposerProps<ThreadMetadata> & React.RefAttributes<HTMLFormElement>>;
|
|
14
50
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
51
|
+
/**
|
|
52
|
+
* Function that takes a Lexical editor config and modifies it to add the necessary
|
|
53
|
+
* `nodes` and `theme` to make `LiveblocksPlugin` works correctly.
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* import { LexicalComposer } from "@lexical/react/LexicalComposer";
|
|
57
|
+
* import { RichTextPlugin } from "@lexical/react/LexicalRichTextPlugin";
|
|
58
|
+
* import { ContentEditable } from "@lexical/react/LexicalContentEditable";
|
|
59
|
+
* import { LexicalErrorBoundary } from "@lexical/react/LexicalErrorBoundary";
|
|
60
|
+
* import { liveblocksConfig, LiveblocksPlugin } from "@liveblocks/react-lexical";
|
|
61
|
+
*
|
|
62
|
+
* const initialConfig = liveblocksConfig({
|
|
63
|
+
* namespace: "MyEditor",
|
|
64
|
+
* theme: {},
|
|
65
|
+
* nodes: [],
|
|
66
|
+
* onError: (err) => console.error(err),
|
|
67
|
+
* });
|
|
68
|
+
*
|
|
69
|
+
* function Editor() {
|
|
70
|
+
* return (
|
|
71
|
+
* <LexicalComposer initialConfig={initialConfig}>
|
|
72
|
+
* <LiveblocksPlugin />
|
|
73
|
+
* <RichTextPlugin
|
|
74
|
+
* contentEditable={<ContentEditable />}
|
|
75
|
+
* placeholder={<div>Enter some text...</div>}
|
|
76
|
+
* ErrorBoundary={LexicalErrorBoundary}
|
|
77
|
+
* />
|
|
78
|
+
* </LexicalComposer>
|
|
79
|
+
* );
|
|
80
|
+
* }
|
|
81
|
+
*/
|
|
30
82
|
declare function liveblocksConfig(editorConfig: Omit<InitialConfigType, "editorState">): {
|
|
31
83
|
nodes: (lexical.KlassConstructor<typeof lexical.LexicalNode> | lexical.LexicalNodeReplacement)[];
|
|
32
84
|
editorState: null;
|
|
@@ -38,14 +90,57 @@ declare function liveblocksConfig(editorConfig: Omit<InitialConfigType, "editorS
|
|
|
38
90
|
theme?: lexical.EditorThemeClasses | undefined;
|
|
39
91
|
};
|
|
40
92
|
|
|
93
|
+
declare type EditorStatus = "not-loaded" | "loading"
|
|
94
|
+
/**
|
|
95
|
+
* Not working yet! Will be available in a future release.
|
|
96
|
+
* Some editor state modifications has not been acknowledged yet by the server
|
|
97
|
+
*/
|
|
98
|
+
| "synchronizing" | "synchronized";
|
|
99
|
+
/**
|
|
100
|
+
* Get the storage status.
|
|
101
|
+
*
|
|
102
|
+
* - `not-loaded`: Initial state when entering the room.
|
|
103
|
+
* - `loading`: Once the editor state has been requested by LiveblocksPlugin.
|
|
104
|
+
* - `synchronizing`: Not working yet! Will be available in a future release.
|
|
105
|
+
* - `synchronized`: The editor state is sync with Liveblocks servers.
|
|
106
|
+
*/
|
|
107
|
+
declare function useEditorStatus(): EditorStatus;
|
|
41
108
|
declare type LiveblocksPluginProps = {
|
|
42
109
|
children?: React.ReactNode;
|
|
43
110
|
};
|
|
111
|
+
/**
|
|
112
|
+
* Liveblocks plugin for Lexical that adds collaboration to your editor.
|
|
113
|
+
*
|
|
114
|
+
* `LiveblocksPlugin` should always be nested inside `LexicalComposer`.
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
*
|
|
118
|
+
* import { LexicalComposer } from "@lexical/react/LexicalComposer";
|
|
119
|
+
* import { RichTextPlugin } from "@lexical/react/LexicalRichTextPlugin";
|
|
120
|
+
* import { ContentEditable } from "@lexical/react/LexicalContentEditable";
|
|
121
|
+
* import { LexicalErrorBoundary } from "@lexical/react/LexicalErrorBoundary";
|
|
122
|
+
* import { liveblocksConfig, LiveblocksPlugin } from "@liveblocks/react-lexical";
|
|
123
|
+
*
|
|
124
|
+
* const initialConfig = liveblocksConfig({
|
|
125
|
+
* namespace: "MyEditor",
|
|
126
|
+
* theme: {},
|
|
127
|
+
* nodes: [],
|
|
128
|
+
* onError: (err) => console.error(err),
|
|
129
|
+
* });
|
|
130
|
+
*
|
|
131
|
+
* function Editor() {
|
|
132
|
+
* return (
|
|
133
|
+
* <LexicalComposer initialConfig={initialConfig}>
|
|
134
|
+
* <LiveblocksPlugin />
|
|
135
|
+
* <RichTextPlugin
|
|
136
|
+
* contentEditable={<ContentEditable />}
|
|
137
|
+
* placeholder={<div>Enter some text...</div>}
|
|
138
|
+
* ErrorBoundary={LexicalErrorBoundary}
|
|
139
|
+
* />
|
|
140
|
+
* </LexicalComposer>
|
|
141
|
+
* );
|
|
142
|
+
* }
|
|
143
|
+
*/
|
|
44
144
|
declare const LiveblocksPlugin: ({ children, }: LiveblocksPluginProps) => JSX.Element;
|
|
45
145
|
|
|
46
|
-
|
|
47
|
-
nodeKey: NodeKey;
|
|
48
|
-
children: ReactNode;
|
|
49
|
-
}): React.JSX.Element;
|
|
50
|
-
|
|
51
|
-
export { FloatingComposer, LiveblocksPlugin, Mention, OPEN_FLOATING_COMPOSER_COMMAND, ThreadPanel, ThreadPanelProps, liveblocksConfig };
|
|
146
|
+
export { FloatingComposer, LiveblocksPlugin, OPEN_FLOATING_COMPOSER_COMMAND, liveblocksConfig, useEditorStatus, useIsThreadActive };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,32 +1,84 @@
|
|
|
1
1
|
import { BaseMetadata } from '@liveblocks/core';
|
|
2
|
-
import { ComposerProps
|
|
2
|
+
import { ComposerProps } from '@liveblocks/react-ui';
|
|
3
3
|
import * as lexical from 'lexical';
|
|
4
|
-
import { LexicalCommand
|
|
5
|
-
import React
|
|
4
|
+
import { LexicalCommand } from 'lexical';
|
|
5
|
+
import React from 'react';
|
|
6
6
|
import { InitialConfigType } from '@lexical/react/LexicalComposer';
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* Returns whether the associated thread annotation for the given thread id is selected or not in the editor.
|
|
10
|
+
* @param threadId The id of the thread to check if the associated annotation is selected or not.
|
|
11
|
+
* @returns true if the associated annotation for the thread is selected, false otherwise.
|
|
12
|
+
*/
|
|
13
|
+
declare function useIsThreadActive(threadId: string): boolean;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Dispatching OPEN_FLOATING_COMPOSER_COMMAND will display the FloatingComposer
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
|
|
20
|
+
* import { OPEN_FLOATING_COMPOSER_COMMAND } from "@liveblocks/react-lexical";
|
|
21
|
+
*
|
|
22
|
+
* function Toolbar() {
|
|
23
|
+
* const [editor] = useLexicalComposerContext();
|
|
24
|
+
*
|
|
25
|
+
* return (
|
|
26
|
+
* <button
|
|
27
|
+
* onClick={() => {
|
|
28
|
+
* editor.dispatchCommand(OPEN_FLOATING_COMPOSER_COMMAND);
|
|
29
|
+
* }}
|
|
30
|
+
* >
|
|
31
|
+
* 💬 New comment
|
|
32
|
+
* </button>
|
|
33
|
+
* );
|
|
34
|
+
* }
|
|
35
|
+
*/
|
|
8
36
|
declare const OPEN_FLOATING_COMPOSER_COMMAND: LexicalCommand<void>;
|
|
9
37
|
declare type ThreadMetadata = {
|
|
10
38
|
resolved?: boolean;
|
|
11
39
|
};
|
|
12
40
|
declare type FloatingComposerProps<M extends BaseMetadata = ThreadMetadata> = Omit<ComposerProps<M>, "threadId" | "commentId">;
|
|
41
|
+
/**
|
|
42
|
+
* Displays a `Composer` near the current lexical selection.
|
|
43
|
+
*
|
|
44
|
+
* To open it, dispatch `OPEN_FLOATING_COMPOSER_COMMAND`.
|
|
45
|
+
*
|
|
46
|
+
* Submitting a comment will attach an annotation thread at the current selection.
|
|
47
|
+
* Should be nested inside `LiveblocksPlugin`.
|
|
48
|
+
*/
|
|
13
49
|
declare const FloatingComposer: React.ForwardRefExoticComponent<FloatingComposerProps<ThreadMetadata> & React.RefAttributes<HTMLFormElement>>;
|
|
14
50
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
51
|
+
/**
|
|
52
|
+
* Function that takes a Lexical editor config and modifies it to add the necessary
|
|
53
|
+
* `nodes` and `theme` to make `LiveblocksPlugin` works correctly.
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* import { LexicalComposer } from "@lexical/react/LexicalComposer";
|
|
57
|
+
* import { RichTextPlugin } from "@lexical/react/LexicalRichTextPlugin";
|
|
58
|
+
* import { ContentEditable } from "@lexical/react/LexicalContentEditable";
|
|
59
|
+
* import { LexicalErrorBoundary } from "@lexical/react/LexicalErrorBoundary";
|
|
60
|
+
* import { liveblocksConfig, LiveblocksPlugin } from "@liveblocks/react-lexical";
|
|
61
|
+
*
|
|
62
|
+
* const initialConfig = liveblocksConfig({
|
|
63
|
+
* namespace: "MyEditor",
|
|
64
|
+
* theme: {},
|
|
65
|
+
* nodes: [],
|
|
66
|
+
* onError: (err) => console.error(err),
|
|
67
|
+
* });
|
|
68
|
+
*
|
|
69
|
+
* function Editor() {
|
|
70
|
+
* return (
|
|
71
|
+
* <LexicalComposer initialConfig={initialConfig}>
|
|
72
|
+
* <LiveblocksPlugin />
|
|
73
|
+
* <RichTextPlugin
|
|
74
|
+
* contentEditable={<ContentEditable />}
|
|
75
|
+
* placeholder={<div>Enter some text...</div>}
|
|
76
|
+
* ErrorBoundary={LexicalErrorBoundary}
|
|
77
|
+
* />
|
|
78
|
+
* </LexicalComposer>
|
|
79
|
+
* );
|
|
80
|
+
* }
|
|
81
|
+
*/
|
|
30
82
|
declare function liveblocksConfig(editorConfig: Omit<InitialConfigType, "editorState">): {
|
|
31
83
|
nodes: (lexical.KlassConstructor<typeof lexical.LexicalNode> | lexical.LexicalNodeReplacement)[];
|
|
32
84
|
editorState: null;
|
|
@@ -38,14 +90,57 @@ declare function liveblocksConfig(editorConfig: Omit<InitialConfigType, "editorS
|
|
|
38
90
|
theme?: lexical.EditorThemeClasses | undefined;
|
|
39
91
|
};
|
|
40
92
|
|
|
93
|
+
declare type EditorStatus = "not-loaded" | "loading"
|
|
94
|
+
/**
|
|
95
|
+
* Not working yet! Will be available in a future release.
|
|
96
|
+
* Some editor state modifications has not been acknowledged yet by the server
|
|
97
|
+
*/
|
|
98
|
+
| "synchronizing" | "synchronized";
|
|
99
|
+
/**
|
|
100
|
+
* Get the storage status.
|
|
101
|
+
*
|
|
102
|
+
* - `not-loaded`: Initial state when entering the room.
|
|
103
|
+
* - `loading`: Once the editor state has been requested by LiveblocksPlugin.
|
|
104
|
+
* - `synchronizing`: Not working yet! Will be available in a future release.
|
|
105
|
+
* - `synchronized`: The editor state is sync with Liveblocks servers.
|
|
106
|
+
*/
|
|
107
|
+
declare function useEditorStatus(): EditorStatus;
|
|
41
108
|
declare type LiveblocksPluginProps = {
|
|
42
109
|
children?: React.ReactNode;
|
|
43
110
|
};
|
|
111
|
+
/**
|
|
112
|
+
* Liveblocks plugin for Lexical that adds collaboration to your editor.
|
|
113
|
+
*
|
|
114
|
+
* `LiveblocksPlugin` should always be nested inside `LexicalComposer`.
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
*
|
|
118
|
+
* import { LexicalComposer } from "@lexical/react/LexicalComposer";
|
|
119
|
+
* import { RichTextPlugin } from "@lexical/react/LexicalRichTextPlugin";
|
|
120
|
+
* import { ContentEditable } from "@lexical/react/LexicalContentEditable";
|
|
121
|
+
* import { LexicalErrorBoundary } from "@lexical/react/LexicalErrorBoundary";
|
|
122
|
+
* import { liveblocksConfig, LiveblocksPlugin } from "@liveblocks/react-lexical";
|
|
123
|
+
*
|
|
124
|
+
* const initialConfig = liveblocksConfig({
|
|
125
|
+
* namespace: "MyEditor",
|
|
126
|
+
* theme: {},
|
|
127
|
+
* nodes: [],
|
|
128
|
+
* onError: (err) => console.error(err),
|
|
129
|
+
* });
|
|
130
|
+
*
|
|
131
|
+
* function Editor() {
|
|
132
|
+
* return (
|
|
133
|
+
* <LexicalComposer initialConfig={initialConfig}>
|
|
134
|
+
* <LiveblocksPlugin />
|
|
135
|
+
* <RichTextPlugin
|
|
136
|
+
* contentEditable={<ContentEditable />}
|
|
137
|
+
* placeholder={<div>Enter some text...</div>}
|
|
138
|
+
* ErrorBoundary={LexicalErrorBoundary}
|
|
139
|
+
* />
|
|
140
|
+
* </LexicalComposer>
|
|
141
|
+
* );
|
|
142
|
+
* }
|
|
143
|
+
*/
|
|
44
144
|
declare const LiveblocksPlugin: ({ children, }: LiveblocksPluginProps) => JSX.Element;
|
|
45
145
|
|
|
46
|
-
|
|
47
|
-
nodeKey: NodeKey;
|
|
48
|
-
children: ReactNode;
|
|
49
|
-
}): React.JSX.Element;
|
|
50
|
-
|
|
51
|
-
export { FloatingComposer, LiveblocksPlugin, Mention, OPEN_FLOATING_COMPOSER_COMMAND, ThreadPanel, ThreadPanelProps, liveblocksConfig };
|
|
146
|
+
export { FloatingComposer, LiveblocksPlugin, OPEN_FLOATING_COMPOSER_COMMAND, liveblocksConfig, useEditorStatus, useIsThreadActive };
|
package/dist/index.js
CHANGED
|
@@ -2,18 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
var core = require('@liveblocks/core');
|
|
4
4
|
var version = require('./version.js');
|
|
5
|
+
var commentPluginProvider = require('./comments/comment-plugin-provider.js');
|
|
5
6
|
var floatingComposer = require('./comments/floating-composer.js');
|
|
6
|
-
var ThreadPanel = require('./comments/ThreadPanel.js');
|
|
7
7
|
var liveblocksConfig = require('./liveblocks-config.js');
|
|
8
8
|
var liveblocksPluginProvider = require('./liveblocks-plugin-provider.js');
|
|
9
|
-
var mentionComponent = require('./mentions/mention-component.js');
|
|
10
9
|
|
|
11
10
|
core.detectDupes(version.PKG_NAME, version.PKG_VERSION, version.PKG_FORMAT);
|
|
12
11
|
|
|
12
|
+
exports.useIsThreadActive = commentPluginProvider.useIsThreadActive;
|
|
13
13
|
exports.FloatingComposer = floatingComposer.FloatingComposer;
|
|
14
14
|
exports.OPEN_FLOATING_COMPOSER_COMMAND = floatingComposer.OPEN_FLOATING_COMPOSER_COMMAND;
|
|
15
|
-
exports.ThreadPanel = ThreadPanel.ThreadPanel;
|
|
16
15
|
exports.liveblocksConfig = liveblocksConfig.liveblocksConfig;
|
|
17
16
|
exports.LiveblocksPlugin = liveblocksPluginProvider.LiveblocksPlugin;
|
|
18
|
-
exports.
|
|
17
|
+
exports.useEditorStatus = liveblocksPluginProvider.useEditorStatus;
|
|
19
18
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":["import { detectDupes } from \"@liveblocks/core\";\n\nimport { PKG_FORMAT, PKG_NAME, PKG_VERSION } from \"./version\";\n\ndetectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);\n\nexport {
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":["import { detectDupes } from \"@liveblocks/core\";\n\nimport { PKG_FORMAT, PKG_NAME, PKG_VERSION } from \"./version\";\n\ndetectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);\n\nexport { useIsThreadActive } from \"./comments/comment-plugin-provider\";\nexport {\n FloatingComposer,\n OPEN_FLOATING_COMPOSER_COMMAND,\n} from \"./comments/floating-composer\";\nexport { liveblocksConfig } from \"./liveblocks-config\";\nexport {\n LiveblocksPlugin,\n useEditorStatus,\n} from \"./liveblocks-plugin-provider\";\n"],"names":["detectDupes","PKG_NAME","PKG_VERSION","PKG_FORMAT"],"mappings":";;;;;;;;;AAIAA,gBAAY,CAAAC,gBAAA,EAAUC,qBAAaC,kBAAU,CAAA;;;;;;;;;"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { detectDupes } from '@liveblocks/core';
|
|
2
2
|
import { PKG_NAME, PKG_VERSION, PKG_FORMAT } from './version.mjs';
|
|
3
|
+
export { useIsThreadActive } from './comments/comment-plugin-provider.mjs';
|
|
3
4
|
export { FloatingComposer, OPEN_FLOATING_COMPOSER_COMMAND } from './comments/floating-composer.mjs';
|
|
4
|
-
export { ThreadPanel } from './comments/ThreadPanel.mjs';
|
|
5
5
|
export { liveblocksConfig } from './liveblocks-config.mjs';
|
|
6
|
-
export { LiveblocksPlugin } from './liveblocks-plugin-provider.mjs';
|
|
7
|
-
export { Mention } from './mentions/mention-component.mjs';
|
|
6
|
+
export { LiveblocksPlugin, useEditorStatus } from './liveblocks-plugin-provider.mjs';
|
|
8
7
|
|
|
9
8
|
detectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);
|
|
10
9
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","sources":["../src/index.ts"],"sourcesContent":["import { detectDupes } from \"@liveblocks/core\";\n\nimport { PKG_FORMAT, PKG_NAME, PKG_VERSION } from \"./version\";\n\ndetectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);\n\nexport {
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":["../src/index.ts"],"sourcesContent":["import { detectDupes } from \"@liveblocks/core\";\n\nimport { PKG_FORMAT, PKG_NAME, PKG_VERSION } from \"./version\";\n\ndetectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);\n\nexport { useIsThreadActive } from \"./comments/comment-plugin-provider\";\nexport {\n FloatingComposer,\n OPEN_FLOATING_COMPOSER_COMMAND,\n} from \"./comments/floating-composer\";\nexport { liveblocksConfig } from \"./liveblocks-config\";\nexport {\n LiveblocksPlugin,\n useEditorStatus,\n} from \"./liveblocks-plugin-provider\";\n"],"names":[],"mappings":";;;;;;;AAIA,WAAY,CAAA,QAAA,EAAU,aAAa,UAAU,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"liveblocks-config.js","sources":["../src/liveblocks-config.ts"],"sourcesContent":["import type { InitialConfigType } from \"@lexical/react/LexicalComposer\";\n\nimport { ThreadMarkNode } from \"./comments/thread-mark-node\";\nimport { MentionNode } from \"./mentions/mention-node\";\n\nexport function liveblocksConfig(\n editorConfig: Omit<InitialConfigType, \"editorState\">\n) {\n const nodes = [...(editorConfig.nodes ?? [])];\n\n nodes.push(ThreadMarkNode, MentionNode);\n\n return {\n ...editorConfig,\n nodes,\n editorState: null, // explicitly null because CollabProvider requires it\n };\n}\n"],"names":["ThreadMarkNode","MentionNode"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"liveblocks-config.js","sources":["../src/liveblocks-config.ts"],"sourcesContent":["import type { InitialConfigType } from \"@lexical/react/LexicalComposer\";\n\nimport { ThreadMarkNode } from \"./comments/thread-mark-node\";\nimport { MentionNode } from \"./mentions/mention-node\";\n\n/**\n * Function that takes a Lexical editor config and modifies it to add the necessary\n * `nodes` and `theme` to make `LiveblocksPlugin` works correctly.\n *\n * @example\n * import { LexicalComposer } from \"@lexical/react/LexicalComposer\";\n * import { RichTextPlugin } from \"@lexical/react/LexicalRichTextPlugin\";\n * import { ContentEditable } from \"@lexical/react/LexicalContentEditable\";\n * import { LexicalErrorBoundary } from \"@lexical/react/LexicalErrorBoundary\";\n * import { liveblocksConfig, LiveblocksPlugin } from \"@liveblocks/react-lexical\";\n *\n * const initialConfig = liveblocksConfig({\n * namespace: \"MyEditor\",\n * theme: {},\n * nodes: [],\n * onError: (err) => console.error(err),\n * });\n *\n * function Editor() {\n * return (\n * <LexicalComposer initialConfig={initialConfig}>\n * <LiveblocksPlugin />\n * <RichTextPlugin\n * contentEditable={<ContentEditable />}\n * placeholder={<div>Enter some text...</div>}\n * ErrorBoundary={LexicalErrorBoundary}\n * />\n * </LexicalComposer>\n * );\n * }\n */\nexport function liveblocksConfig(\n editorConfig: Omit<InitialConfigType, \"editorState\">\n) {\n const nodes = [...(editorConfig.nodes ?? [])];\n\n nodes.push(ThreadMarkNode, MentionNode);\n\n return {\n ...editorConfig,\n nodes,\n editorState: null, // explicitly null because CollabProvider requires it\n };\n}\n"],"names":["ThreadMarkNode","MentionNode"],"mappings":";;;;;AAoCO,SAAS,iBACd,YACA,EAAA;AACA,EAAA,MAAM,QAAQ,CAAC,GAAI,YAAa,CAAA,KAAA,IAAS,EAAG,CAAA,CAAA;AAE5C,EAAM,KAAA,CAAA,IAAA,CAAKA,+BAAgBC,uBAAW,CAAA,CAAA;AAEtC,EAAO,OAAA;AAAA,IACL,GAAG,YAAA;AAAA,IACH,KAAA;AAAA,IACA,WAAa,EAAA,IAAA;AAAA,GACf,CAAA;AACF;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"liveblocks-config.mjs","sources":["../src/liveblocks-config.ts"],"sourcesContent":["import type { InitialConfigType } from \"@lexical/react/LexicalComposer\";\n\nimport { ThreadMarkNode } from \"./comments/thread-mark-node\";\nimport { MentionNode } from \"./mentions/mention-node\";\n\nexport function liveblocksConfig(\n editorConfig: Omit<InitialConfigType, \"editorState\">\n) {\n const nodes = [...(editorConfig.nodes ?? [])];\n\n nodes.push(ThreadMarkNode, MentionNode);\n\n return {\n ...editorConfig,\n nodes,\n editorState: null, // explicitly null because CollabProvider requires it\n };\n}\n"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"liveblocks-config.mjs","sources":["../src/liveblocks-config.ts"],"sourcesContent":["import type { InitialConfigType } from \"@lexical/react/LexicalComposer\";\n\nimport { ThreadMarkNode } from \"./comments/thread-mark-node\";\nimport { MentionNode } from \"./mentions/mention-node\";\n\n/**\n * Function that takes a Lexical editor config and modifies it to add the necessary\n * `nodes` and `theme` to make `LiveblocksPlugin` works correctly.\n *\n * @example\n * import { LexicalComposer } from \"@lexical/react/LexicalComposer\";\n * import { RichTextPlugin } from \"@lexical/react/LexicalRichTextPlugin\";\n * import { ContentEditable } from \"@lexical/react/LexicalContentEditable\";\n * import { LexicalErrorBoundary } from \"@lexical/react/LexicalErrorBoundary\";\n * import { liveblocksConfig, LiveblocksPlugin } from \"@liveblocks/react-lexical\";\n *\n * const initialConfig = liveblocksConfig({\n * namespace: \"MyEditor\",\n * theme: {},\n * nodes: [],\n * onError: (err) => console.error(err),\n * });\n *\n * function Editor() {\n * return (\n * <LexicalComposer initialConfig={initialConfig}>\n * <LiveblocksPlugin />\n * <RichTextPlugin\n * contentEditable={<ContentEditable />}\n * placeholder={<div>Enter some text...</div>}\n * ErrorBoundary={LexicalErrorBoundary}\n * />\n * </LexicalComposer>\n * );\n * }\n */\nexport function liveblocksConfig(\n editorConfig: Omit<InitialConfigType, \"editorState\">\n) {\n const nodes = [...(editorConfig.nodes ?? [])];\n\n nodes.push(ThreadMarkNode, MentionNode);\n\n return {\n ...editorConfig,\n nodes,\n editorState: null, // explicitly null because CollabProvider requires it\n };\n}\n"],"names":[],"mappings":";;;AAoCO,SAAS,iBACd,YACA,EAAA;AACA,EAAA,MAAM,QAAQ,CAAC,GAAI,YAAa,CAAA,KAAA,IAAS,EAAG,CAAA,CAAA;AAE5C,EAAM,KAAA,CAAA,IAAA,CAAK,gBAAgB,WAAW,CAAA,CAAA;AAEtC,EAAO,OAAA;AAAA,IACL,GAAG,YAAA;AAAA,IACH,KAAA;AAAA,IACA,WAAa,EAAA,IAAA;AAAA,GACf,CAAA;AACF;;;;"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var reactDom = require('@floating-ui/react-dom');
|
|
3
4
|
var LexicalCollaborationContext = require('@lexical/react/LexicalCollaborationContext');
|
|
4
5
|
var LexicalCollaborationPlugin = require('@lexical/react/LexicalCollaborationPlugin');
|
|
5
6
|
var LexicalComposerContext = require('@lexical/react/LexicalComposerContext');
|
|
@@ -7,11 +8,36 @@ var core = require('@liveblocks/core');
|
|
|
7
8
|
var react = require('@liveblocks/react');
|
|
8
9
|
var yjs$1 = require('@liveblocks/yjs');
|
|
9
10
|
var React = require('react');
|
|
11
|
+
var index_js = require('use-sync-external-store/shim/index.js');
|
|
10
12
|
var yjs = require('yjs');
|
|
11
13
|
var commentPluginProvider = require('./comments/comment-plugin-provider.js');
|
|
14
|
+
var threadMarkNode = require('./comments/thread-mark-node.js');
|
|
15
|
+
var mentionNode = require('./mentions/mention-node.js');
|
|
12
16
|
var mentionPlugin = require('./mentions/mention-plugin.js');
|
|
13
17
|
|
|
14
18
|
const providersMap = /* @__PURE__ */ new Map();
|
|
19
|
+
function getEditorStatus(provider) {
|
|
20
|
+
if (provider === void 0) {
|
|
21
|
+
return "not-loaded";
|
|
22
|
+
}
|
|
23
|
+
return provider.synced ? "synchronized" : "loading";
|
|
24
|
+
}
|
|
25
|
+
function useEditorStatus() {
|
|
26
|
+
const room = react.useRoom();
|
|
27
|
+
const provider = providersMap.get(room.id);
|
|
28
|
+
const [status, setStatus] = React.useState(getEditorStatus(provider));
|
|
29
|
+
React.useEffect(() => {
|
|
30
|
+
const provider2 = providersMap.get(room.id);
|
|
31
|
+
setStatus(getEditorStatus(provider2));
|
|
32
|
+
if (provider2 === void 0) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const cb = () => setStatus(getEditorStatus(provider2));
|
|
36
|
+
provider2.on("sync", cb);
|
|
37
|
+
return () => provider2.off("sync", cb);
|
|
38
|
+
}, [room]);
|
|
39
|
+
return status;
|
|
40
|
+
}
|
|
15
41
|
const LiveblocksPlugin = ({
|
|
16
42
|
children
|
|
17
43
|
}) => {
|
|
@@ -21,6 +47,26 @@ const LiveblocksPlugin = ({
|
|
|
21
47
|
const room = react.useRoom();
|
|
22
48
|
const collabContext = React.useContext(LexicalCollaborationContext.CollaborationContext);
|
|
23
49
|
const previousRoomIdRef = React.useRef(null);
|
|
50
|
+
if (!editor.hasNodes([threadMarkNode.ThreadMarkNode, mentionNode.MentionNode])) {
|
|
51
|
+
throw new Error(
|
|
52
|
+
"LiveblocksPlugin requires Lexical configuration to be wrapped in the `liveblocksConfig(options)` function. For more information: https://liveblocks.io/docs/api-reference/liveblocks-react-lexical#liveblocksConfig"
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
const [containerRef, setContainerRef] = React.useState(void 0);
|
|
56
|
+
const {
|
|
57
|
+
refs: { setReference, setFloating },
|
|
58
|
+
strategy,
|
|
59
|
+
x,
|
|
60
|
+
y
|
|
61
|
+
} = reactDom.useFloating({
|
|
62
|
+
strategy: "fixed",
|
|
63
|
+
placement: "bottom",
|
|
64
|
+
whileElementsMounted: (...args) => {
|
|
65
|
+
return reactDom.autoUpdate(...args, {
|
|
66
|
+
animationFrame: true
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
});
|
|
24
70
|
React.useEffect(() => {
|
|
25
71
|
if (process.env.NODE_ENV !== "production") {
|
|
26
72
|
if (!editor.getEditorState().isEmpty()) {
|
|
@@ -61,15 +107,54 @@ const LiveblocksPlugin = ({
|
|
|
61
107
|
React.useEffect(() => {
|
|
62
108
|
collabContext.name = username || "";
|
|
63
109
|
}, [collabContext, username]);
|
|
64
|
-
|
|
110
|
+
const root = useRootElement();
|
|
111
|
+
React.useLayoutEffect(() => {
|
|
112
|
+
if (root === null)
|
|
113
|
+
return;
|
|
114
|
+
setReference({
|
|
115
|
+
getBoundingClientRect: () => root.getBoundingClientRect()
|
|
116
|
+
});
|
|
117
|
+
}, [setReference, root]);
|
|
118
|
+
const handleFloatingRef = React.useCallback(
|
|
119
|
+
(node) => {
|
|
120
|
+
setFloating(node);
|
|
121
|
+
setContainerRef({ current: node });
|
|
122
|
+
},
|
|
123
|
+
[setFloating, setContainerRef]
|
|
124
|
+
);
|
|
125
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", {
|
|
126
|
+
ref: handleFloatingRef,
|
|
127
|
+
style: {
|
|
128
|
+
position: strategy,
|
|
129
|
+
top: 0,
|
|
130
|
+
left: 0,
|
|
131
|
+
transform: `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)`,
|
|
132
|
+
minWidth: "max-content"
|
|
133
|
+
}
|
|
134
|
+
}), /* @__PURE__ */ React.createElement(LexicalCollaborationPlugin.CollaborationPlugin, {
|
|
65
135
|
key: room.id,
|
|
66
136
|
id: room.id,
|
|
67
137
|
providerFactory,
|
|
68
138
|
username,
|
|
69
139
|
cursorColor: cursorcolor,
|
|
140
|
+
cursorsContainerRef: containerRef,
|
|
70
141
|
shouldBootstrap: true
|
|
71
142
|
}), hasResolveMentionSuggestions && /* @__PURE__ */ React.createElement(mentionPlugin.MentionPlugin, null), /* @__PURE__ */ React.createElement(commentPluginProvider.CommentPluginProvider, null, children));
|
|
72
143
|
};
|
|
144
|
+
function useRootElement() {
|
|
145
|
+
const [editor] = LexicalComposerContext.useLexicalComposerContext();
|
|
146
|
+
const subscribe = React.useCallback(
|
|
147
|
+
(onStoreChange) => {
|
|
148
|
+
return editor.registerRootListener(onStoreChange);
|
|
149
|
+
},
|
|
150
|
+
[editor]
|
|
151
|
+
);
|
|
152
|
+
const getSnapshot = React.useCallback(() => {
|
|
153
|
+
return editor.getRootElement();
|
|
154
|
+
}, [editor]);
|
|
155
|
+
return index_js.useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
156
|
+
}
|
|
73
157
|
|
|
74
158
|
exports.LiveblocksPlugin = LiveblocksPlugin;
|
|
159
|
+
exports.useEditorStatus = useEditorStatus;
|
|
75
160
|
//# sourceMappingURL=liveblocks-plugin-provider.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"liveblocks-plugin-provider.js","sources":["../src/liveblocks-plugin-provider.tsx"],"sourcesContent":["import { CollaborationContext } from \"@lexical/react/LexicalCollaborationContext\";\nimport { CollaborationPlugin } from \"@lexical/react/LexicalCollaborationPlugin\";\nimport { useLexicalComposerContext } from \"@lexical/react/LexicalComposerContext\";\nimport type { Provider } from \"@lexical/yjs\";\nimport { kInternal, nn } from \"@liveblocks/core\";\nimport { useClient, useRoom, useSelf } from \"@liveblocks/react\";\nimport { LiveblocksYjsProvider } from \"@liveblocks/yjs\";\nimport React, { useCallback, useContext, useEffect, useRef } from \"react\";\nimport { Doc } from \"yjs\";\n\nimport { CommentPluginProvider } from \"./comments/comment-plugin-provider\";\nimport { MentionPlugin } from \"./mentions/mention-plugin\";\n\n// TODO: Replace by ref once I understand why useRef is not stable (?!)\nconst providersMap = new Map<\n string,\n LiveblocksYjsProvider<never, never, never, never, never>\n>();\n\nexport type LiveblocksPluginProps = {\n children?: React.ReactNode;\n};\n\nexport const LiveblocksPlugin = ({\n children,\n}: LiveblocksPluginProps): JSX.Element => {\n const client = useClient();\n const hasResolveMentionSuggestions =\n client[kInternal].resolveMentionSuggestions !== undefined;\n const [editor] = useLexicalComposerContext();\n const room = useRoom();\n const collabContext = useContext(CollaborationContext);\n const previousRoomIdRef = useRef<string | null>(null);\n\n // Warn users if initialConfig.editorState, set on the composer, is not null\n useEffect(() => {\n // only in dev mode\n if (process.env.NODE_ENV !== \"production\") {\n // A user should not even be set an emptyState, but when passing null, getEditorState still has initial empty state\n if (!editor.getEditorState().isEmpty()) {\n console.warn(\n \"Warning: LiveblocksPlugin: editorState in initialConfig detected, but must be null.\"\n );\n }\n }\n\n // we know editor is already defined as we're inside LexicalComposer, and we only want this running the first time\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n // Report that this is lexical and root is the rootKey\n room[kInternal].reportTextEditor(\"lexical\", \"root\");\n }, [room]);\n\n // Get user info or allow override from props\n const info = useSelf((me) => me.info);\n const username = info?.name || \"\"; // use empty string to prevent random name\n const cursorcolor = info?.color as string | undefined;\n\n const providerFactory = useCallback(\n (id: string, yjsDocMap: Map<string, Doc>): Provider => {\n // Destroy previously used provider to avoid memory leaks\n // TODO: Find a way to destroy the last used provider on unmount (while working with StrictMode)\n if (\n previousRoomIdRef.current !== null &&\n previousRoomIdRef.current !== id\n ) {\n const previousProvider = providersMap.get(id);\n if (previousProvider !== undefined) {\n previousProvider.destroy();\n }\n }\n\n let doc = yjsDocMap.get(id);\n\n if (doc === undefined) {\n doc = new Doc();\n const provider = new LiveblocksYjsProvider(room, doc);\n yjsDocMap.set(id, doc);\n providersMap.set(id, provider);\n }\n\n return nn(\n providersMap.get(id),\n \"Internal error. Should never happen\"\n ) as Provider;\n },\n [room]\n );\n\n useEffect(() => {\n collabContext.name = username || \"\";\n }, [collabContext, username]);\n\n return (\n <>\n <CollaborationPlugin\n // Setting the key allows us to reset the internal Y.doc used by useYjsCollaboration\n // without implementing `reload` event\n key={room.id}\n id={room.id}\n providerFactory={providerFactory}\n username={username}\n cursorColor={cursorcolor}\n shouldBootstrap={true}\n />\n\n {hasResolveMentionSuggestions && <MentionPlugin />}\n\n <CommentPluginProvider>{children}</CommentPluginProvider>\n </>\n );\n};\n"],"names":["useClient","kInternal","useLexicalComposerContext","useRoom","useContext","CollaborationContext","useRef","useEffect","useSelf","useCallback","Doc","LiveblocksYjsProvider","nn","CollaborationPlugin","MentionPlugin","CommentPluginProvider"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"liveblocks-plugin-provider.js","sources":["../src/liveblocks-plugin-provider.tsx"],"sourcesContent":["import { autoUpdate, useFloating } from \"@floating-ui/react-dom\";\nimport { CollaborationContext } from \"@lexical/react/LexicalCollaborationContext\";\nimport { CollaborationPlugin } from \"@lexical/react/LexicalCollaborationPlugin\";\nimport { useLexicalComposerContext } from \"@lexical/react/LexicalComposerContext\";\nimport type { Provider } from \"@lexical/yjs\";\nimport { kInternal, nn } from \"@liveblocks/core\";\nimport { useClient, useRoom, useSelf } from \"@liveblocks/react\";\nimport { LiveblocksYjsProvider } from \"@liveblocks/yjs\";\nimport type { MutableRefObject } from \"react\";\nimport React, {\n useCallback,\n useContext,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n} from \"react\";\nimport { useSyncExternalStore } from \"use-sync-external-store/shim/index.js\";\nimport { Doc } from \"yjs\";\n\nimport { CommentPluginProvider } from \"./comments/comment-plugin-provider\";\nimport { ThreadMarkNode } from \"./comments/thread-mark-node\";\nimport { MentionNode } from \"./mentions/mention-node\";\nimport { MentionPlugin } from \"./mentions/mention-plugin\";\n\n// TODO: Replace by ref once I understand why useRef is not stable (?!)\nconst providersMap = new Map<\n string,\n LiveblocksYjsProvider<never, never, never, never, never>\n>();\n\nexport type EditorStatus =\n /* The editor state is not loaded and has not been requested. */\n | \"not-loaded\"\n /* The editor state is loading from Liveblocks servers */\n | \"loading\"\n /**\n * Not working yet! Will be available in a future release.\n * Some editor state modifications has not been acknowledged yet by the server\n */\n | \"synchronizing\"\n /* The editor state is sync with Liveblocks servers */\n | \"synchronized\";\n\nfunction getEditorStatus(\n provider?: LiveblocksYjsProvider<never, never, never, never, never>\n) {\n if (provider === undefined) {\n return \"not-loaded\";\n }\n\n return provider.synced ? \"synchronized\" : \"loading\";\n}\n\n/**\n * Get the storage status.\n *\n * - `not-loaded`: Initial state when entering the room.\n * - `loading`: Once the editor state has been requested by LiveblocksPlugin.\n * - `synchronizing`: Not working yet! Will be available in a future release.\n * - `synchronized`: The editor state is sync with Liveblocks servers.\n */\nexport function useEditorStatus(): EditorStatus {\n const room = useRoom();\n const provider = providersMap.get(room.id);\n\n const [status, setStatus] = useState<EditorStatus>(getEditorStatus(provider));\n\n useEffect(() => {\n const provider = providersMap.get(room.id);\n\n setStatus(getEditorStatus(provider));\n\n if (provider === undefined) {\n return;\n }\n\n const cb = () => setStatus(getEditorStatus(provider));\n\n provider.on(\"sync\", cb);\n\n return () => provider.off(\"sync\", cb);\n }, [room]);\n\n return status;\n}\n\nexport type LiveblocksPluginProps = {\n children?: React.ReactNode;\n};\n\n/**\n * Liveblocks plugin for Lexical that adds collaboration to your editor.\n *\n * `LiveblocksPlugin` should always be nested inside `LexicalComposer`.\n *\n * @example\n *\n * import { LexicalComposer } from \"@lexical/react/LexicalComposer\";\n * import { RichTextPlugin } from \"@lexical/react/LexicalRichTextPlugin\";\n * import { ContentEditable } from \"@lexical/react/LexicalContentEditable\";\n * import { LexicalErrorBoundary } from \"@lexical/react/LexicalErrorBoundary\";\n * import { liveblocksConfig, LiveblocksPlugin } from \"@liveblocks/react-lexical\";\n *\n * const initialConfig = liveblocksConfig({\n * namespace: \"MyEditor\",\n * theme: {},\n * nodes: [],\n * onError: (err) => console.error(err),\n * });\n *\n * function Editor() {\n * return (\n * <LexicalComposer initialConfig={initialConfig}>\n * <LiveblocksPlugin />\n * <RichTextPlugin\n * contentEditable={<ContentEditable />}\n * placeholder={<div>Enter some text...</div>}\n * ErrorBoundary={LexicalErrorBoundary}\n * />\n * </LexicalComposer>\n * );\n * }\n */\nexport const LiveblocksPlugin = ({\n children,\n}: LiveblocksPluginProps): JSX.Element => {\n const client = useClient();\n const hasResolveMentionSuggestions =\n client[kInternal].resolveMentionSuggestions !== undefined;\n const [editor] = useLexicalComposerContext();\n const room = useRoom();\n const collabContext = useContext(CollaborationContext);\n const previousRoomIdRef = useRef<string | null>(null);\n\n if (!editor.hasNodes([ThreadMarkNode, MentionNode])) {\n throw new Error(\n \"LiveblocksPlugin requires Lexical configuration to be wrapped in the `liveblocksConfig(options)` function. For more information: https://liveblocks.io/docs/api-reference/liveblocks-react-lexical#liveblocksConfig\"\n );\n }\n\n const [containerRef, setContainerRef] = useState<\n MutableRefObject<HTMLDivElement | null> | undefined\n >(undefined);\n\n const {\n refs: { setReference, setFloating },\n strategy,\n x,\n y,\n } = useFloating({\n strategy: \"fixed\",\n placement: \"bottom\",\n whileElementsMounted: (...args) => {\n return autoUpdate(...args, {\n animationFrame: true,\n });\n },\n });\n\n // Warn users if initialConfig.editorState, set on the composer, is not null\n useEffect(() => {\n // only in dev mode\n if (process.env.NODE_ENV !== \"production\") {\n // A user should not even be set an emptyState, but when passing null, getEditorState still has initial empty state\n if (!editor.getEditorState().isEmpty()) {\n console.warn(\n \"Warning: LiveblocksPlugin: editorState in initialConfig detected, but must be null.\"\n );\n }\n }\n\n // we know editor is already defined as we're inside LexicalComposer, and we only want this running the first time\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n useEffect(() => {\n // Report that this is lexical and root is the rootKey\n room[kInternal].reportTextEditor(\"lexical\", \"root\");\n }, [room]);\n\n // Get user info or allow override from props\n const info = useSelf((me) => me.info);\n const username = info?.name || \"\"; // use empty string to prevent random name\n const cursorcolor = info?.color as string | undefined;\n\n const providerFactory = useCallback(\n (id: string, yjsDocMap: Map<string, Doc>): Provider => {\n // Destroy previously used provider to avoid memory leaks\n // TODO: Find a way to destroy the last used provider on unmount (while working with StrictMode)\n if (\n previousRoomIdRef.current !== null &&\n previousRoomIdRef.current !== id\n ) {\n const previousProvider = providersMap.get(id);\n if (previousProvider !== undefined) {\n previousProvider.destroy();\n }\n }\n\n let doc = yjsDocMap.get(id);\n\n if (doc === undefined) {\n doc = new Doc();\n const provider = new LiveblocksYjsProvider(room, doc);\n yjsDocMap.set(id, doc);\n providersMap.set(id, provider);\n }\n\n return nn(\n providersMap.get(id),\n \"Internal error. Should never happen\"\n ) as Provider;\n },\n [room]\n );\n\n useEffect(() => {\n collabContext.name = username || \"\";\n }, [collabContext, username]);\n\n const root = useRootElement();\n\n useLayoutEffect(() => {\n if (root === null) return;\n setReference({\n getBoundingClientRect: () => root.getBoundingClientRect(),\n });\n }, [setReference, root]);\n\n const handleFloatingRef = useCallback(\n (node: HTMLDivElement) => {\n setFloating(node);\n setContainerRef({ current: node });\n },\n [setFloating, setContainerRef]\n );\n\n return (\n <>\n <div\n ref={handleFloatingRef}\n style={{\n position: strategy,\n top: 0,\n left: 0,\n transform: `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)`,\n minWidth: \"max-content\",\n }}\n />\n\n <CollaborationPlugin\n // Setting the key allows us to reset the internal Y.doc used by useYjsCollaboration\n // without implementing `reload` event\n key={room.id}\n id={room.id}\n providerFactory={providerFactory}\n username={username}\n cursorColor={cursorcolor}\n cursorsContainerRef={containerRef}\n shouldBootstrap={true}\n />\n\n {hasResolveMentionSuggestions && <MentionPlugin />}\n\n <CommentPluginProvider>{children}</CommentPluginProvider>\n </>\n );\n};\n\nfunction useRootElement(): HTMLElement | null {\n const [editor] = useLexicalComposerContext();\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => {\n return editor.registerRootListener(onStoreChange);\n },\n [editor]\n );\n\n const getSnapshot = useCallback(() => {\n return editor.getRootElement();\n }, [editor]);\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n"],"names":["useRoom","useState","useEffect","provider","useClient","kInternal","useLexicalComposerContext","useContext","CollaborationContext","useRef","ThreadMarkNode","MentionNode","useFloating","autoUpdate","useSelf","useCallback","Doc","LiveblocksYjsProvider","nn","useLayoutEffect","CollaborationPlugin","MentionPlugin","CommentPluginProvider","useSyncExternalStore"],"mappings":"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"}
|