@liveblocks/react-lexical 2.0.0-alpha3 → 2.0.0-alpha4

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 (36) hide show
  1. package/dist/comments/comment-plugin-provider.js +19 -10
  2. package/dist/comments/comment-plugin-provider.js.map +1 -1
  3. package/dist/comments/comment-plugin-provider.mjs +20 -13
  4. package/dist/comments/comment-plugin-provider.mjs.map +1 -1
  5. package/dist/comments/floating-composer.js.map +1 -1
  6. package/dist/comments/floating-composer.mjs.map +1 -1
  7. package/dist/index.d.mts +119 -24
  8. package/dist/index.d.ts +119 -24
  9. package/dist/index.js +3 -4
  10. package/dist/index.js.map +1 -1
  11. package/dist/index.mjs +2 -3
  12. package/dist/index.mjs.map +1 -1
  13. package/dist/liveblocks-config.js.map +1 -1
  14. package/dist/liveblocks-config.mjs.map +1 -1
  15. package/dist/liveblocks-plugin-provider.js +72 -1
  16. package/dist/liveblocks-plugin-provider.js.map +1 -1
  17. package/dist/liveblocks-plugin-provider.mjs +74 -4
  18. package/dist/liveblocks-plugin-provider.mjs.map +1 -1
  19. package/dist/mentions/mention-component.js +1 -1
  20. package/dist/mentions/mention-component.js.map +1 -1
  21. package/dist/mentions/mention-component.mjs +1 -1
  22. package/dist/mentions/mention-component.mjs.map +1 -1
  23. package/dist/mentions/mention-plugin.js +0 -12
  24. package/dist/mentions/mention-plugin.js.map +1 -1
  25. package/dist/mentions/mention-plugin.mjs +1 -13
  26. package/dist/mentions/mention-plugin.mjs.map +1 -1
  27. package/dist/version.js +1 -1
  28. package/dist/version.mjs +1 -1
  29. package/package.json +6 -6
  30. package/src/styles/index.css +1 -24
  31. package/styles.css +1 -1
  32. package/styles.css.map +1 -1
  33. package/dist/comments/ThreadPanel.js +0 -51
  34. package/dist/comments/ThreadPanel.js.map +0 -1
  35. package/dist/comments/ThreadPanel.mjs +0 -49
  36. 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, GlobalOverrides, ThreadPanelOverrides, ThreadOverrides, CommentOverrides, ComposerOverrides, ThreadProps } from '@liveblocks/react-ui';
2
+ import { ComposerProps } from '@liveblocks/react-ui';
3
3
  import * as lexical from 'lexical';
4
- import { LexicalCommand, NodeKey } from 'lexical';
5
- import React, { ComponentProps, ComponentType, ReactNode } from '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
- declare type ThreadPanelComponents = {
16
- Thread: ComponentType<ThreadProps>;
17
- };
18
- interface ThreadPanelProps extends ComponentProps<"div"> {
19
- /**
20
- * Override the component's components.
21
- */
22
- components?: Partial<ThreadPanelComponents>;
23
- /**
24
- * Override the component's strings.
25
- */
26
- overrides?: Partial<GlobalOverrides & ThreadPanelOverrides & ThreadOverrides & CommentOverrides & ComposerOverrides>;
27
- }
28
- declare const ThreadPanel: React.ForwardRefExoticComponent<Omit<ThreadPanelProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
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
- declare function Mention({ nodeKey, children, }: {
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, GlobalOverrides, ThreadPanelOverrides, ThreadOverrides, CommentOverrides, ComposerOverrides, ThreadProps } from '@liveblocks/react-ui';
2
+ import { ComposerProps } from '@liveblocks/react-ui';
3
3
  import * as lexical from 'lexical';
4
- import { LexicalCommand, NodeKey } from 'lexical';
5
- import React, { ComponentProps, ComponentType, ReactNode } from '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
- declare type ThreadPanelComponents = {
16
- Thread: ComponentType<ThreadProps>;
17
- };
18
- interface ThreadPanelProps extends ComponentProps<"div"> {
19
- /**
20
- * Override the component's components.
21
- */
22
- components?: Partial<ThreadPanelComponents>;
23
- /**
24
- * Override the component's strings.
25
- */
26
- overrides?: Partial<GlobalOverrides & ThreadPanelOverrides & ThreadOverrides & CommentOverrides & ComposerOverrides>;
27
- }
28
- declare const ThreadPanel: React.ForwardRefExoticComponent<Omit<ThreadPanelProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
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
- declare function Mention({ nodeKey, children, }: {
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.Mention = mentionComponent.Mention;
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 {\n FloatingComposer,\n OPEN_FLOATING_COMPOSER_COMMAND,\n} from \"./comments/floating-composer\";\nexport type { ThreadPanelProps } from \"./comments/ThreadPanel\";\nexport { ThreadPanel } from \"./comments/ThreadPanel\";\nexport { liveblocksConfig } from \"./liveblocks-config\";\nexport { LiveblocksPlugin } from \"./liveblocks-plugin-provider\";\nexport { Mention } from \"./mentions/mention-component\";\n"],"names":["detectDupes","PKG_NAME","PKG_VERSION","PKG_FORMAT"],"mappings":";;;;;;;;;;AAIAA,gBAAY,CAAAC,gBAAA,EAAUC,qBAAaC,kBAAU,CAAA;;;;;;;;;"}
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
@@ -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 {\n FloatingComposer,\n OPEN_FLOATING_COMPOSER_COMMAND,\n} from \"./comments/floating-composer\";\nexport type { ThreadPanelProps } from \"./comments/ThreadPanel\";\nexport { ThreadPanel } from \"./comments/ThreadPanel\";\nexport { liveblocksConfig } from \"./liveblocks-config\";\nexport { LiveblocksPlugin } from \"./liveblocks-plugin-provider\";\nexport { Mention } from \"./mentions/mention-component\";\n"],"names":[],"mappings":";;;;;;;;AAIA,WAAY,CAAA,QAAA,EAAU,aAAa,UAAU,CAAA"}
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":";;;;;AAKO,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
+ {"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":";;;AAKO,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
+ {"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');
@@ -9,9 +10,33 @@ var yjs$1 = require('@liveblocks/yjs');
9
10
  var React = require('react');
10
11
  var yjs = require('yjs');
11
12
  var commentPluginProvider = require('./comments/comment-plugin-provider.js');
13
+ var threadMarkNode = require('./comments/thread-mark-node.js');
14
+ var mentionNode = require('./mentions/mention-node.js');
12
15
  var mentionPlugin = require('./mentions/mention-plugin.js');
13
16
 
14
17
  const providersMap = /* @__PURE__ */ new Map();
18
+ function getEditorStatus(provider) {
19
+ if (provider === void 0) {
20
+ return "not-loaded";
21
+ }
22
+ return provider.synced ? "synchronized" : "loading";
23
+ }
24
+ function useEditorStatus() {
25
+ const room = react.useRoom();
26
+ const provider = providersMap.get(room.id);
27
+ const [status, setStatus] = React.useState(getEditorStatus(provider));
28
+ React.useEffect(() => {
29
+ const provider2 = providersMap.get(room.id);
30
+ setStatus(getEditorStatus(provider2));
31
+ if (provider2 === void 0) {
32
+ return;
33
+ }
34
+ const cb = () => setStatus(getEditorStatus(provider2));
35
+ provider2.on("sync", cb);
36
+ return () => provider2.off("sync", cb);
37
+ }, [room]);
38
+ return status;
39
+ }
15
40
  const LiveblocksPlugin = ({
16
41
  children
17
42
  }) => {
@@ -21,6 +46,26 @@ const LiveblocksPlugin = ({
21
46
  const room = react.useRoom();
22
47
  const collabContext = React.useContext(LexicalCollaborationContext.CollaborationContext);
23
48
  const previousRoomIdRef = React.useRef(null);
49
+ if (!editor.hasNodes([threadMarkNode.ThreadMarkNode, mentionNode.MentionNode])) {
50
+ throw new Error(
51
+ "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"
52
+ );
53
+ }
54
+ const [containerRef, setContainerRef] = React.useState(void 0);
55
+ const {
56
+ refs: { setReference, setFloating },
57
+ strategy,
58
+ x,
59
+ y
60
+ } = reactDom.useFloating({
61
+ strategy: "fixed",
62
+ placement: "bottom",
63
+ whileElementsMounted: (...args) => {
64
+ return reactDom.autoUpdate(...args, {
65
+ animationFrame: true
66
+ });
67
+ }
68
+ });
24
69
  React.useEffect(() => {
25
70
  if (process.env.NODE_ENV !== "production") {
26
71
  if (!editor.getEditorState().isEmpty()) {
@@ -61,15 +106,41 @@ const LiveblocksPlugin = ({
61
106
  React.useEffect(() => {
62
107
  collabContext.name = username || "";
63
108
  }, [collabContext, username]);
64
- return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(LexicalCollaborationPlugin.CollaborationPlugin, {
109
+ React.useLayoutEffect(() => {
110
+ const editable = editor.getRootElement();
111
+ if (editable === null)
112
+ return;
113
+ setReference({
114
+ getBoundingClientRect: () => editable.getBoundingClientRect()
115
+ });
116
+ }, [setReference, editor]);
117
+ const handleFloatingRef = React.useCallback(
118
+ (node) => {
119
+ setFloating(node);
120
+ setContainerRef({ current: node });
121
+ },
122
+ [setFloating, setContainerRef]
123
+ );
124
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", {
125
+ ref: handleFloatingRef,
126
+ style: {
127
+ position: strategy,
128
+ top: 0,
129
+ left: 0,
130
+ transform: `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)`,
131
+ minWidth: "max-content"
132
+ }
133
+ }), /* @__PURE__ */ React.createElement(LexicalCollaborationPlugin.CollaborationPlugin, {
65
134
  key: room.id,
66
135
  id: room.id,
67
136
  providerFactory,
68
137
  username,
69
138
  cursorColor: cursorcolor,
139
+ cursorsContainerRef: containerRef,
70
140
  shouldBootstrap: true
71
141
  }), hasResolveMentionSuggestions && /* @__PURE__ */ React.createElement(mentionPlugin.MentionPlugin, null), /* @__PURE__ */ React.createElement(commentPluginProvider.CommentPluginProvider, null, children));
72
142
  };
73
143
 
74
144
  exports.LiveblocksPlugin = LiveblocksPlugin;
145
+ exports.useEditorStatus = useEditorStatus;
75
146
  //# 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":";;;;;;;;;;;;;AAcA,MAAM,YAAA,uBAAmB,GAGvB,EAAA,CAAA;AAMK,MAAM,mBAAmB,CAAC;AAAA,EAC/B,QAAA;AACF,CAA0C,KAAA;AACxC,EAAA,MAAM,SAASA,eAAU,EAAA,CAAA;AACzB,EAAM,MAAA,4BAAA,GACJ,MAAO,CAAAC,cAAA,CAAA,CAAW,yBAA8B,KAAA,KAAA,CAAA,CAAA;AAClD,EAAM,MAAA,CAAC,MAAM,CAAA,GAAIC,gDAA0B,EAAA,CAAA;AAC3C,EAAA,MAAM,OAAOC,aAAQ,EAAA,CAAA;AACrB,EAAM,MAAA,aAAA,GAAgBC,iBAAWC,gDAAoB,CAAA,CAAA;AACrD,EAAM,MAAA,iBAAA,GAAoBC,aAAsB,IAAI,CAAA,CAAA;AAGpD,EAAAC,eAAA,CAAU,MAAM;AAEd,IAAI,IAAA,OAAA,CAAQ,GAAI,CAAA,QAAA,KAAa,YAAc,EAAA;AAEzC,MAAA,IAAI,CAAC,MAAA,CAAO,cAAe,EAAA,CAAE,SAAW,EAAA;AACtC,QAAQ,OAAA,CAAA,IAAA;AAAA,UACN,qFAAA;AAAA,SACF,CAAA;AAAA,OACF;AAAA,KACF;AAAA,GAIF,EAAG,EAAE,CAAA,CAAA;AAEL,EAAAA,eAAA,CAAU,MAAM;AAEd,IAAK,IAAA,CAAAN,cAAA,CAAA,CAAW,gBAAiB,CAAA,SAAA,EAAW,MAAM,CAAA,CAAA;AAAA,GACpD,EAAG,CAAC,IAAI,CAAC,CAAA,CAAA;AAGT,EAAA,MAAM,IAAO,GAAAO,aAAA,CAAQ,CAAC,EAAA,KAAO,GAAG,IAAI,CAAA,CAAA;AACpC,EAAM,MAAA,QAAA,GAAW,MAAM,IAAQ,IAAA,EAAA,CAAA;AAC/B,EAAA,MAAM,cAAc,IAAM,EAAA,KAAA,CAAA;AAE1B,EAAA,MAAM,eAAkB,GAAAC,iBAAA;AAAA,IACtB,CAAC,IAAY,SAA0C,KAAA;AAGrD,MAAA,IACE,iBAAkB,CAAA,OAAA,KAAY,IAC9B,IAAA,iBAAA,CAAkB,YAAY,EAC9B,EAAA;AACA,QAAM,MAAA,gBAAA,GAAmB,YAAa,CAAA,GAAA,CAAI,EAAE,CAAA,CAAA;AAC5C,QAAA,IAAI,qBAAqB,KAAW,CAAA,EAAA;AAClC,UAAA,gBAAA,CAAiB,OAAQ,EAAA,CAAA;AAAA,SAC3B;AAAA,OACF;AAEA,MAAI,IAAA,GAAA,GAAM,SAAU,CAAA,GAAA,CAAI,EAAE,CAAA,CAAA;AAE1B,MAAA,IAAI,QAAQ,KAAW,CAAA,EAAA;AACrB,QAAA,GAAA,GAAM,IAAIC,OAAI,EAAA,CAAA;AACd,QAAA,MAAM,QAAW,GAAA,IAAIC,2BAAsB,CAAA,IAAA,EAAM,GAAG,CAAA,CAAA;AACpD,QAAU,SAAA,CAAA,GAAA,CAAI,IAAI,GAAG,CAAA,CAAA;AACrB,QAAa,YAAA,CAAA,GAAA,CAAI,IAAI,QAAQ,CAAA,CAAA;AAAA,OAC/B;AAEA,MAAO,OAAAC,OAAA;AAAA,QACL,YAAA,CAAa,IAAI,EAAE,CAAA;AAAA,QACnB,qCAAA;AAAA,OACF,CAAA;AAAA,KACF;AAAA,IACA,CAAC,IAAI,CAAA;AAAA,GACP,CAAA;AAEA,EAAAL,eAAA,CAAU,MAAM;AACd,IAAA,aAAA,CAAc,OAAO,QAAY,IAAA,EAAA,CAAA;AAAA,GAChC,EAAA,CAAC,aAAe,EAAA,QAAQ,CAAC,CAAA,CAAA;AAE5B,EAAA,iFAEK,KAAA,CAAA,aAAA,CAAAM,8CAAA,EAAA;AAAA,IAGC,KAAK,IAAK,CAAA,EAAA;AAAA,IACV,IAAI,IAAK,CAAA,EAAA;AAAA,IACT,eAAA;AAAA,IACA,QAAA;AAAA,IACA,WAAa,EAAA,WAAA;AAAA,IACb,eAAiB,EAAA,IAAA;AAAA,GACnB,CAAA,EAEC,gDAAiC,KAAA,CAAA,aAAA,CAAAC,2BAAA,EAAA,IAAc,mBAE/C,KAAA,CAAA,aAAA,CAAAC,2CAAA,EAAA,IAAA,EAAuB,QAAS,CACnC,CAAA,CAAA;AAEJ;;;;"}
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 { 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 useLayoutEffect(() => {\n const editable = editor.getRootElement();\n if (editable === null) return;\n\n setReference({\n getBoundingClientRect: () => editable.getBoundingClientRect(),\n });\n }, [setReference, editor]);\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"],"names":["useRoom","useState","useEffect","provider","useClient","kInternal","useLexicalComposerContext","useContext","CollaborationContext","useRef","ThreadMarkNode","MentionNode","useFloating","autoUpdate","useSelf","useCallback","Doc","LiveblocksYjsProvider","nn","useLayoutEffect","CollaborationPlugin","MentionPlugin","CommentPluginProvider"],"mappings":"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"}