@liveblocks/react-lexical 2.16.0-toolbars3 → 2.16.0-toolbars5
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/anchored-threads.js +2 -2
- package/dist/comments/anchored-threads.js.map +1 -1
- package/dist/comments/anchored-threads.mjs +1 -1
- package/dist/comments/anchored-threads.mjs.map +1 -1
- package/dist/index.d.mts +185 -5
- package/dist/index.d.ts +185 -5
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/is-block-node-active.js +51 -0
- package/dist/is-block-node-active.js.map +1 -0
- package/dist/is-block-node-active.mjs +49 -0
- package/dist/is-block-node-active.mjs.map +1 -0
- package/dist/liveblocks-plugin-provider.js +2 -15
- package/dist/liveblocks-plugin-provider.js.map +1 -1
- package/dist/liveblocks-plugin-provider.mjs +2 -14
- package/dist/liveblocks-plugin-provider.mjs.map +1 -1
- package/dist/toolbar/floating-toolbar.js +16 -19
- package/dist/toolbar/floating-toolbar.js.map +1 -1
- package/dist/toolbar/floating-toolbar.mjs +16 -19
- package/dist/toolbar/floating-toolbar.mjs.map +1 -1
- package/dist/toolbar/toolbar.js +34 -30
- package/dist/toolbar/toolbar.js.map +1 -1
- package/dist/toolbar/toolbar.mjs +34 -30
- package/dist/toolbar/toolbar.mjs.map +1 -1
- package/dist/use-root-element.js +21 -0
- package/dist/use-root-element.js.map +1 -0
- package/dist/use-root-element.mjs +19 -0
- package/dist/use-root-element.mjs.map +1 -0
- package/dist/version.js +1 -1
- package/dist/version.mjs +1 -1
- package/package.json +6 -6
- package/dist/get-selected-block-element.js +0 -26
- package/dist/get-selected-block-element.js.map +0 -1
- package/dist/get-selected-block-element.mjs +0 -24
- package/dist/get-selected-block-element.mjs.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -77,7 +77,7 @@ interface FloatingThreadsProps<M extends BaseMetadata = DM> extends Omit<HTMLAtt
|
|
|
77
77
|
}
|
|
78
78
|
declare function FloatingThreads({ threads, components, ...props }: FloatingThreadsProps): react_jsx_runtime.JSX.Element | null;
|
|
79
79
|
|
|
80
|
-
declare function
|
|
80
|
+
declare function isBlockNodeActive(editor: LexicalEditor, isActive: (node: LexicalNode) => boolean): boolean;
|
|
81
81
|
|
|
82
82
|
declare function isTextFormatActive(editor: LexicalEditor, format: TextFormatType): boolean;
|
|
83
83
|
|
|
@@ -190,48 +190,228 @@ interface ToolbarSlotProps {
|
|
|
190
190
|
}
|
|
191
191
|
type ToolbarSlot = ReactNode | ComponentType<ToolbarSlotProps>;
|
|
192
192
|
interface ToolbarProps extends Omit<ComponentProps<"div">, "children"> {
|
|
193
|
+
/**
|
|
194
|
+
* The content of the toolbar, overriding the default content.
|
|
195
|
+
* Use the `before` and `after` props if you want to keep and extend the default content.
|
|
196
|
+
*/
|
|
193
197
|
children?: ToolbarSlot;
|
|
198
|
+
/**
|
|
199
|
+
* The content to display at the start of the toolbar.
|
|
200
|
+
*/
|
|
194
201
|
before?: ToolbarSlot;
|
|
202
|
+
/**
|
|
203
|
+
* The content to display at the end of the toolbar.
|
|
204
|
+
*/
|
|
195
205
|
after?: ToolbarSlot;
|
|
196
206
|
}
|
|
197
207
|
interface ToolbarButtonProps extends ComponentProps<"button"> {
|
|
198
|
-
|
|
208
|
+
/**
|
|
209
|
+
* The name of this button displayed in its tooltip.
|
|
210
|
+
*/
|
|
199
211
|
name: string;
|
|
212
|
+
/**
|
|
213
|
+
* An optional icon displayed in this button.
|
|
214
|
+
*/
|
|
215
|
+
icon?: ReactNode;
|
|
216
|
+
/**
|
|
217
|
+
* An optional keyboard shortcut displayed in this button's tooltip.
|
|
218
|
+
*
|
|
219
|
+
* @example
|
|
220
|
+
* "Mod-Alt-B" → "⌘⌥B" in Apple environments, "⌃⌥B" otherwise
|
|
221
|
+
* "Ctrl-Shift-Escape" → "⌃⇧⎋"
|
|
222
|
+
* "Space" → "␣"
|
|
223
|
+
*/
|
|
200
224
|
shortcut?: string;
|
|
201
225
|
}
|
|
202
226
|
interface ToolbarToggleProps extends ToolbarButtonProps {
|
|
227
|
+
/**
|
|
228
|
+
* Whether the button is toggled.
|
|
229
|
+
*/
|
|
203
230
|
active: boolean;
|
|
204
231
|
}
|
|
232
|
+
type ToolbarSeparatorProps = ComponentProps<"div">;
|
|
205
233
|
interface ToolbarBlockSelectorItem {
|
|
234
|
+
/**
|
|
235
|
+
* The name of this block element, displayed as the label of this item.
|
|
236
|
+
*/
|
|
206
237
|
name: string;
|
|
238
|
+
/**
|
|
239
|
+
* Optionally replace the name used as the label of this item by any content.
|
|
240
|
+
*/
|
|
241
|
+
label?: ReactNode;
|
|
242
|
+
/**
|
|
243
|
+
* An optional icon displayed in this item.
|
|
244
|
+
*/
|
|
207
245
|
icon?: ReactNode;
|
|
208
|
-
|
|
246
|
+
/**
|
|
247
|
+
* Whether this block element is currently active.
|
|
248
|
+
* Set to `"default"` to display this item when no other item is active.
|
|
249
|
+
*/
|
|
250
|
+
isActive: ((editor: LexicalEditor) => boolean) | "default";
|
|
251
|
+
/**
|
|
252
|
+
* A callback invoked when this item is selected.
|
|
253
|
+
*/
|
|
209
254
|
setActive: (editor: LexicalEditor) => void;
|
|
210
255
|
}
|
|
211
256
|
interface ToolbarBlockSelectorProps extends ComponentProps<"button"> {
|
|
257
|
+
/**
|
|
258
|
+
* The items displayed in this block selector.
|
|
259
|
+
* When provided as an array, the default items are overridden. To avoid this,
|
|
260
|
+
* a function can be provided instead and it will receive the default items.
|
|
261
|
+
*
|
|
262
|
+
* @example
|
|
263
|
+
* <Toolbar.BlockSelector
|
|
264
|
+
* items={[
|
|
265
|
+
* {
|
|
266
|
+
* name: "Text",
|
|
267
|
+
* isActive: "default",
|
|
268
|
+
* setActive: () => { ... },
|
|
269
|
+
* },
|
|
270
|
+
* {
|
|
271
|
+
* name: "Heading 1",
|
|
272
|
+
* isActive: () => { ... },
|
|
273
|
+
* setActive: () => { ... },
|
|
274
|
+
* },
|
|
275
|
+
* ]}
|
|
276
|
+
* />
|
|
277
|
+
*
|
|
278
|
+
* @example
|
|
279
|
+
* <Toolbar.BlockSelector
|
|
280
|
+
* items={(defaultItems) => [
|
|
281
|
+
* ...defaultItems,
|
|
282
|
+
* {
|
|
283
|
+
* name: "Custom block",
|
|
284
|
+
* isActive: () => { ... },
|
|
285
|
+
* setActive: () => { ... },
|
|
286
|
+
* },
|
|
287
|
+
* ]}
|
|
288
|
+
* />
|
|
289
|
+
*/
|
|
212
290
|
items?: ToolbarBlockSelectorItem[] | ((defaultItems: ToolbarBlockSelectorItem[]) => ToolbarBlockSelectorItem[]);
|
|
213
291
|
}
|
|
214
292
|
declare function ToolbarSectionHistory(): react_jsx_runtime.JSX.Element;
|
|
215
293
|
declare function ToolbarSectionInline(): react_jsx_runtime.JSX.Element | null;
|
|
216
294
|
declare function ToolbarSectionCollaboration(): react_jsx_runtime.JSX.Element;
|
|
295
|
+
/**
|
|
296
|
+
* A static toolbar containing actions and values related to the editor.
|
|
297
|
+
*
|
|
298
|
+
* @example
|
|
299
|
+
* <Toolbar />
|
|
300
|
+
*
|
|
301
|
+
* @example
|
|
302
|
+
* <Toolbar >
|
|
303
|
+
* <Toolbar.BlockSelector />
|
|
304
|
+
* <Toolbar.Separator />
|
|
305
|
+
* <Toolbar.SectionInline />
|
|
306
|
+
* <Toolbar.Separator />
|
|
307
|
+
* <Toolbar.Button name="Custom action" onClick={() => { ... }} icon={<Icon.QuestionMark />} />
|
|
308
|
+
* </Toolbar>
|
|
309
|
+
*/
|
|
217
310
|
declare const Toolbar: react.ForwardRefExoticComponent<Omit<ToolbarProps, "ref"> & react.RefAttributes<HTMLDivElement>> & {
|
|
311
|
+
/**
|
|
312
|
+
* A button for triggering actions.
|
|
313
|
+
*
|
|
314
|
+
* @example
|
|
315
|
+
* <Toolbar.Button name="Comment" shortcut="Mod-Shift-E" onClick={() => { ... }}>Comment</Toolbar.Button>
|
|
316
|
+
*
|
|
317
|
+
* @example
|
|
318
|
+
* <Toolbar.Button name="Mention someone" icon={<Icon.Mention />} onClick={() => { ... }} />
|
|
319
|
+
*/
|
|
218
320
|
Button: react.ForwardRefExoticComponent<Omit<ToolbarButtonProps, "ref"> & react.RefAttributes<HTMLButtonElement>>;
|
|
321
|
+
/**
|
|
322
|
+
* A toggle button for values that can be active or inactive.
|
|
323
|
+
*
|
|
324
|
+
* @example
|
|
325
|
+
* <Toolbar.Toggle name="Bold" active={isBold}>Bold</Toolbar.Toggle>
|
|
326
|
+
*
|
|
327
|
+
* @example
|
|
328
|
+
* <Toolbar.Toggle name="Italic" icon={<Icon.Italic />} shortcut="Mod-I" active={isItalic} onClick={() => { ... }} />
|
|
329
|
+
*/
|
|
219
330
|
Toggle: react.ForwardRefExoticComponent<Omit<ToolbarToggleProps, "ref"> & react.RefAttributes<HTMLButtonElement>>;
|
|
331
|
+
/**
|
|
332
|
+
* A dropdown selector to switch between different block types.
|
|
333
|
+
*
|
|
334
|
+
* @example
|
|
335
|
+
* <Toolbar.BlockSelector />
|
|
336
|
+
*/
|
|
337
|
+
BlockSelector: react.ForwardRefExoticComponent<Omit<ToolbarBlockSelectorProps, "ref"> & react.RefAttributes<HTMLButtonElement>>;
|
|
338
|
+
/**
|
|
339
|
+
* A visual (and accessible) separator to separate sections in a toolbar.
|
|
340
|
+
*/
|
|
220
341
|
Separator: react.ForwardRefExoticComponent<Omit<react.DetailedHTMLProps<react.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
|
|
342
|
+
/**
|
|
343
|
+
* A section containing history actions. (e.g. undo, redo)
|
|
344
|
+
*/
|
|
221
345
|
SectionHistory: typeof ToolbarSectionHistory;
|
|
346
|
+
/**
|
|
347
|
+
* A section containing inline formatting actions. (e.g. bold, italic, underline, ...)
|
|
348
|
+
*/
|
|
222
349
|
SectionInline: typeof ToolbarSectionInline;
|
|
350
|
+
/**
|
|
351
|
+
* A section containing collaborative actions. (e.g. adding a comment)
|
|
352
|
+
*/
|
|
223
353
|
SectionCollaboration: typeof ToolbarSectionCollaboration;
|
|
224
|
-
BlockSelector: react.ForwardRefExoticComponent<Omit<ToolbarBlockSelectorProps, "ref"> & react.RefAttributes<HTMLButtonElement>>;
|
|
225
354
|
};
|
|
226
355
|
|
|
227
356
|
interface FloatingToolbarProps extends Omit<ComponentProps<"div">, "children"> {
|
|
357
|
+
/**
|
|
358
|
+
* The vertical position of the floating toolbar.
|
|
359
|
+
*/
|
|
228
360
|
position?: FloatingPosition;
|
|
361
|
+
/**
|
|
362
|
+
* The vertical offset of the floating toolbar from the selection.
|
|
363
|
+
*/
|
|
229
364
|
offset?: number;
|
|
365
|
+
/**
|
|
366
|
+
* The content of the floating toolbar, overriding the default content.
|
|
367
|
+
* Use the `before` and `after` props if you want to keep and extend the default content.
|
|
368
|
+
*/
|
|
230
369
|
children?: ToolbarSlot;
|
|
370
|
+
/**
|
|
371
|
+
* The content to display at the start of the floating toolbar.
|
|
372
|
+
*/
|
|
231
373
|
before?: ToolbarSlot;
|
|
374
|
+
/**
|
|
375
|
+
* The content to display at the end of the floating toolbar.
|
|
376
|
+
*/
|
|
232
377
|
after?: ToolbarSlot;
|
|
233
378
|
}
|
|
379
|
+
/**
|
|
380
|
+
* A floating toolbar attached to the selection and containing actions and values related to the editor.
|
|
381
|
+
*
|
|
382
|
+
* @example
|
|
383
|
+
* <FloatingToolbar />
|
|
384
|
+
*
|
|
385
|
+
* @example
|
|
386
|
+
* <FloatingToolbar>
|
|
387
|
+
* <Toolbar.BlockSelector />
|
|
388
|
+
* <Toolbar.Separator />
|
|
389
|
+
* <Toolbar.SectionInline />
|
|
390
|
+
* <Toolbar.Separator />
|
|
391
|
+
* <Toolbar.Button name="Custom action" onClick={() => { ... }} icon={<Icon.QuestionMark />} />
|
|
392
|
+
* </FloatingToolbar>
|
|
393
|
+
*/
|
|
234
394
|
declare const FloatingToolbar: react.ForwardRefExoticComponent<Omit<FloatingToolbarProps, "ref"> & react.RefAttributes<HTMLDivElement>> & {
|
|
395
|
+
/**
|
|
396
|
+
* A component that can be wrapped around elements which are rendered outside of the floating
|
|
397
|
+
* toolbar (e.g. portals) to prevent the toolbar from closing when clicking/focusing within them.
|
|
398
|
+
*
|
|
399
|
+
* @example
|
|
400
|
+
* <FloatingToolbar>
|
|
401
|
+
* <Popover.Root>
|
|
402
|
+
* <Popover.Trigger asChild>
|
|
403
|
+
* <Toolbar.Button>Open popover</Toolbar.Button>
|
|
404
|
+
* </Popover.Trigger>
|
|
405
|
+
* <Popover.Portal>
|
|
406
|
+
* <FloatingToolbar.External>
|
|
407
|
+
* <Popover.Content>
|
|
408
|
+
* This popover is rendered outside of the floating toolbar, but the toolbar will not close when clicking/focusing within it.
|
|
409
|
+
* </Popover.Content>
|
|
410
|
+
* </FloatingToolbar.External>
|
|
411
|
+
* </Popover.Portal>
|
|
412
|
+
* </Popover.Root>
|
|
413
|
+
* </FloatingToolbar>
|
|
414
|
+
*/
|
|
235
415
|
External: react.ForwardRefExoticComponent<Omit<react.DetailedHTMLProps<react.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
|
|
236
416
|
};
|
|
237
417
|
|
|
@@ -247,4 +427,4 @@ interface HistoryVersionPreviewProps extends ComponentPropsWithoutRef<"div"> {
|
|
|
247
427
|
*/
|
|
248
428
|
declare const HistoryVersionPreview: react.ForwardRefExoticComponent<HistoryVersionPreviewProps & react.RefAttributes<HTMLDivElement>>;
|
|
249
429
|
|
|
250
|
-
export { AnchoredThreads, AnchoredThreadsProps, FloatingComposer, FloatingComposerProps, FloatingThreads, FloatingThreadsProps, FloatingToolbar, FloatingToolbarProps, HistoryVersionPreview, HistoryVersionPreviewProps, LiveblocksPlugin, OPEN_FLOATING_COMPOSER_COMMAND, Toolbar, ToolbarProps,
|
|
430
|
+
export { AnchoredThreads, AnchoredThreadsProps, FloatingComposer, FloatingComposerProps, FloatingThreads, FloatingThreadsProps, FloatingToolbar, FloatingToolbarProps, HistoryVersionPreview, HistoryVersionPreviewProps, LiveblocksPlugin, OPEN_FLOATING_COMPOSER_COMMAND, Toolbar, ToolbarBlockSelectorItem, ToolbarBlockSelectorProps, ToolbarButtonProps, ToolbarProps, ToolbarSeparatorProps, ToolbarToggleProps, isBlockNodeActive, isTextFormatActive, liveblocksConfig, useEditorStatus, useIsEditorReady, useIsThreadActive };
|
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ var anchoredThreads = require('./comments/anchored-threads.js');
|
|
|
6
6
|
var commentPluginProvider = require('./comments/comment-plugin-provider.js');
|
|
7
7
|
var floatingComposer = require('./comments/floating-composer.js');
|
|
8
8
|
var floatingThreads = require('./comments/floating-threads.js');
|
|
9
|
-
var
|
|
9
|
+
var isBlockNodeActive = require('./is-block-node-active.js');
|
|
10
10
|
var isTextFormatActive = require('./is-text-format-active.js');
|
|
11
11
|
var liveblocksConfig = require('./liveblocks-config.js');
|
|
12
12
|
var liveblocksPluginProvider = require('./liveblocks-plugin-provider.js');
|
|
@@ -21,7 +21,7 @@ exports.useIsThreadActive = commentPluginProvider.useIsThreadActive;
|
|
|
21
21
|
exports.FloatingComposer = floatingComposer.FloatingComposer;
|
|
22
22
|
exports.OPEN_FLOATING_COMPOSER_COMMAND = floatingComposer.OPEN_FLOATING_COMPOSER_COMMAND;
|
|
23
23
|
exports.FloatingThreads = floatingThreads.FloatingThreads;
|
|
24
|
-
exports.
|
|
24
|
+
exports.isBlockNodeActive = isBlockNodeActive.isBlockNodeActive;
|
|
25
25
|
exports.isTextFormatActive = isTextFormatActive.isTextFormatActive;
|
|
26
26
|
exports.liveblocksConfig = liveblocksConfig.liveblocksConfig;
|
|
27
27
|
exports.LiveblocksPlugin = liveblocksPluginProvider.LiveblocksPlugin;
|
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 type { AnchoredThreadsProps } from \"./comments/anchored-threads\";\nexport { AnchoredThreads } from \"./comments/anchored-threads\";\nexport { useIsThreadActive } from \"./comments/comment-plugin-provider\";\nexport type { FloatingComposerProps } from \"./comments/floating-composer\";\nexport {\n FloatingComposer,\n OPEN_FLOATING_COMPOSER_COMMAND,\n} from \"./comments/floating-composer\";\nexport type { FloatingThreadsProps } from \"./comments/floating-threads\";\nexport { FloatingThreads } from \"./comments/floating-threads\";\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 type { AnchoredThreadsProps } from \"./comments/anchored-threads\";\nexport { AnchoredThreads } from \"./comments/anchored-threads\";\nexport { useIsThreadActive } from \"./comments/comment-plugin-provider\";\nexport type { FloatingComposerProps } from \"./comments/floating-composer\";\nexport {\n FloatingComposer,\n OPEN_FLOATING_COMPOSER_COMMAND,\n} from \"./comments/floating-composer\";\nexport type { FloatingThreadsProps } from \"./comments/floating-threads\";\nexport { FloatingThreads } from \"./comments/floating-threads\";\nexport { isBlockNodeActive } from \"./is-block-node-active\";\nexport { isTextFormatActive } from \"./is-text-format-active\";\nexport { liveblocksConfig } from \"./liveblocks-config\";\nexport {\n LiveblocksPlugin,\n useEditorStatus,\n useIsEditorReady,\n} from \"./liveblocks-plugin-provider\";\nexport type { FloatingToolbarProps } from \"./toolbar/floating-toolbar\";\nexport { FloatingToolbar } from \"./toolbar/floating-toolbar\";\nexport type {\n ToolbarBlockSelectorItem,\n ToolbarBlockSelectorProps,\n ToolbarButtonProps,\n ToolbarProps,\n ToolbarSeparatorProps,\n ToolbarToggleProps,\n} from \"./toolbar/toolbar\";\nexport { Toolbar } from \"./toolbar/toolbar\";\nexport type { HistoryVersionPreviewProps } from \"./version-history/history-version-preview\";\nexport { HistoryVersionPreview } from \"./version-history/history-version-preview\";\n"],"names":["detectDupes","PKG_NAME","PKG_VERSION","PKG_FORMAT"],"mappings":";;;;;;;;;;;;;;;;AAIAA,gBAAY,CAAAC,gBAAA,EAAUC,qBAAaC,kBAAU,CAAA;;;;;;;;;;;;;;;;;"}
|
package/dist/index.mjs
CHANGED
|
@@ -4,7 +4,7 @@ export { AnchoredThreads } from './comments/anchored-threads.mjs';
|
|
|
4
4
|
export { useIsThreadActive } from './comments/comment-plugin-provider.mjs';
|
|
5
5
|
export { FloatingComposer, OPEN_FLOATING_COMPOSER_COMMAND } from './comments/floating-composer.mjs';
|
|
6
6
|
export { FloatingThreads } from './comments/floating-threads.mjs';
|
|
7
|
-
export {
|
|
7
|
+
export { isBlockNodeActive } from './is-block-node-active.mjs';
|
|
8
8
|
export { isTextFormatActive } from './is-text-format-active.mjs';
|
|
9
9
|
export { liveblocksConfig } from './liveblocks-config.mjs';
|
|
10
10
|
export { LiveblocksPlugin, useEditorStatus, useIsEditorReady } from './liveblocks-plugin-provider.mjs';
|
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 type { AnchoredThreadsProps } from \"./comments/anchored-threads\";\nexport { AnchoredThreads } from \"./comments/anchored-threads\";\nexport { useIsThreadActive } from \"./comments/comment-plugin-provider\";\nexport type { FloatingComposerProps } from \"./comments/floating-composer\";\nexport {\n FloatingComposer,\n OPEN_FLOATING_COMPOSER_COMMAND,\n} from \"./comments/floating-composer\";\nexport type { FloatingThreadsProps } from \"./comments/floating-threads\";\nexport { FloatingThreads } from \"./comments/floating-threads\";\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 type { AnchoredThreadsProps } from \"./comments/anchored-threads\";\nexport { AnchoredThreads } from \"./comments/anchored-threads\";\nexport { useIsThreadActive } from \"./comments/comment-plugin-provider\";\nexport type { FloatingComposerProps } from \"./comments/floating-composer\";\nexport {\n FloatingComposer,\n OPEN_FLOATING_COMPOSER_COMMAND,\n} from \"./comments/floating-composer\";\nexport type { FloatingThreadsProps } from \"./comments/floating-threads\";\nexport { FloatingThreads } from \"./comments/floating-threads\";\nexport { isBlockNodeActive } from \"./is-block-node-active\";\nexport { isTextFormatActive } from \"./is-text-format-active\";\nexport { liveblocksConfig } from \"./liveblocks-config\";\nexport {\n LiveblocksPlugin,\n useEditorStatus,\n useIsEditorReady,\n} from \"./liveblocks-plugin-provider\";\nexport type { FloatingToolbarProps } from \"./toolbar/floating-toolbar\";\nexport { FloatingToolbar } from \"./toolbar/floating-toolbar\";\nexport type {\n ToolbarBlockSelectorItem,\n ToolbarBlockSelectorProps,\n ToolbarButtonProps,\n ToolbarProps,\n ToolbarSeparatorProps,\n ToolbarToggleProps,\n} from \"./toolbar/toolbar\";\nexport { Toolbar } from \"./toolbar/toolbar\";\nexport type { HistoryVersionPreviewProps } from \"./version-history/history-version-preview\";\nexport { HistoryVersionPreview } from \"./version-history/history-version-preview\";\n"],"names":[],"mappings":";;;;;;;;;;;;;;AAIA,WAAY,CAAA,QAAA,EAAU,aAAa,UAAU,CAAA"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var utils = require('@lexical/utils');
|
|
4
|
+
var lexical = require('lexical');
|
|
5
|
+
|
|
6
|
+
function isParentRootOrShadowRoot(node) {
|
|
7
|
+
const parent = node.getParent();
|
|
8
|
+
return parent !== null && lexical.$isRootOrShadowRoot(parent);
|
|
9
|
+
}
|
|
10
|
+
const activeNodesByEditor = /* @__PURE__ */ new WeakMap();
|
|
11
|
+
function getActiveBlockNodes(editor) {
|
|
12
|
+
const currentState = editor.getEditorState();
|
|
13
|
+
return currentState.read(() => {
|
|
14
|
+
const selection = lexical.$getSelection();
|
|
15
|
+
if (!lexical.$isRangeSelection(selection)) {
|
|
16
|
+
activeNodesByEditor.delete(editor);
|
|
17
|
+
return [];
|
|
18
|
+
}
|
|
19
|
+
const cache = activeNodesByEditor.get(editor);
|
|
20
|
+
if (cache?.state === currentState) {
|
|
21
|
+
return cache.nodes;
|
|
22
|
+
}
|
|
23
|
+
const anchor = selection.anchor.getNode();
|
|
24
|
+
const focus = selection.focus.getNode();
|
|
25
|
+
const commonAncestor = anchor.getCommonAncestor(focus);
|
|
26
|
+
let activeNodes = [];
|
|
27
|
+
if (commonAncestor && !lexical.$isRootOrShadowRoot(commonAncestor)) {
|
|
28
|
+
const activeNode = isParentRootOrShadowRoot(commonAncestor) ? commonAncestor : utils.$findMatchingParent(commonAncestor, isParentRootOrShadowRoot);
|
|
29
|
+
if (activeNode) {
|
|
30
|
+
activeNodes = [activeNode];
|
|
31
|
+
}
|
|
32
|
+
} else {
|
|
33
|
+
activeNodes = selection.getNodes().filter((node) => lexical.$isRootOrShadowRoot(node.getParent()));
|
|
34
|
+
}
|
|
35
|
+
activeNodesByEditor.set(editor, {
|
|
36
|
+
state: currentState,
|
|
37
|
+
nodes: activeNodes
|
|
38
|
+
});
|
|
39
|
+
return activeNodes;
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
function isBlockNodeActive(editor, isActive) {
|
|
43
|
+
const activeNodes = getActiveBlockNodes(editor);
|
|
44
|
+
if (activeNodes.length === 0) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
return activeNodes.every(isActive);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
exports.isBlockNodeActive = isBlockNodeActive;
|
|
51
|
+
//# sourceMappingURL=is-block-node-active.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"is-block-node-active.js","sources":["../src/is-block-node-active.ts"],"sourcesContent":["import { $findMatchingParent } from \"@lexical/utils\";\nimport type { EditorState, LexicalEditor, LexicalNode } from \"lexical\";\nimport { $getSelection, $isRangeSelection, $isRootOrShadowRoot } from \"lexical\";\n\nfunction isParentRootOrShadowRoot(node: LexicalNode) {\n const parent = node.getParent();\n\n return parent !== null && $isRootOrShadowRoot(parent);\n}\n\nconst activeNodesByEditor = new WeakMap<\n LexicalEditor,\n {\n state: EditorState;\n nodes: LexicalNode[];\n }\n>();\n\nfunction getActiveBlockNodes(editor: LexicalEditor) {\n const currentState = editor.getEditorState();\n\n return currentState.read(() => {\n const selection = $getSelection();\n\n if (!$isRangeSelection(selection)) {\n activeNodesByEditor.delete(editor);\n\n return [];\n }\n\n const cache = activeNodesByEditor.get(editor);\n\n if (cache?.state === currentState) {\n return cache.nodes;\n }\n\n const anchor = selection.anchor.getNode();\n const focus = selection.focus.getNode();\n const commonAncestor = anchor.getCommonAncestor(focus);\n\n let activeNodes: LexicalNode[] = [];\n\n if (commonAncestor && !$isRootOrShadowRoot(commonAncestor)) {\n const activeNode = isParentRootOrShadowRoot(commonAncestor)\n ? commonAncestor\n : $findMatchingParent(commonAncestor, isParentRootOrShadowRoot);\n\n if (activeNode) {\n activeNodes = [activeNode];\n }\n } else {\n activeNodes = selection\n .getNodes()\n .filter((node) => $isRootOrShadowRoot(node.getParent()));\n }\n\n activeNodesByEditor.set(editor, {\n state: currentState,\n nodes: activeNodes,\n });\n\n return activeNodes;\n });\n}\n\nexport function isBlockNodeActive(\n editor: LexicalEditor,\n isActive: (node: LexicalNode) => boolean\n): boolean {\n const activeNodes = getActiveBlockNodes(editor);\n\n if (activeNodes.length === 0) {\n return false;\n }\n\n return activeNodes.every(isActive);\n}\n"],"names":["$isRootOrShadowRoot","$getSelection","$isRangeSelection","$findMatchingParent"],"mappings":";;;;;AAIA,SAAS,yBAAyB,IAAmB,EAAA;AACnD,EAAM,MAAA,MAAA,GAAS,KAAK,SAAU,EAAA,CAAA;AAE9B,EAAO,OAAA,MAAA,KAAW,IAAQ,IAAAA,2BAAA,CAAoB,MAAM,CAAA,CAAA;AACtD,CAAA;AAEA,MAAM,mBAAA,uBAA0B,OAM9B,EAAA,CAAA;AAEF,SAAS,oBAAoB,MAAuB,EAAA;AAClD,EAAM,MAAA,YAAA,GAAe,OAAO,cAAe,EAAA,CAAA;AAE3C,EAAO,OAAA,YAAA,CAAa,KAAK,MAAM;AAC7B,IAAA,MAAM,YAAYC,qBAAc,EAAA,CAAA;AAEhC,IAAI,IAAA,CAACC,yBAAkB,CAAA,SAAS,CAAG,EAAA;AACjC,MAAA,mBAAA,CAAoB,OAAO,MAAM,CAAA,CAAA;AAEjC,MAAA,OAAO,EAAC,CAAA;AAAA,KACV;AAEA,IAAM,MAAA,KAAA,GAAQ,mBAAoB,CAAA,GAAA,CAAI,MAAM,CAAA,CAAA;AAE5C,IAAI,IAAA,KAAA,EAAO,UAAU,YAAc,EAAA;AACjC,MAAA,OAAO,KAAM,CAAA,KAAA,CAAA;AAAA,KACf;AAEA,IAAM,MAAA,MAAA,GAAS,SAAU,CAAA,MAAA,CAAO,OAAQ,EAAA,CAAA;AACxC,IAAM,MAAA,KAAA,GAAQ,SAAU,CAAA,KAAA,CAAM,OAAQ,EAAA,CAAA;AACtC,IAAM,MAAA,cAAA,GAAiB,MAAO,CAAA,iBAAA,CAAkB,KAAK,CAAA,CAAA;AAErD,IAAA,IAAI,cAA6B,EAAC,CAAA;AAElC,IAAA,IAAI,cAAkB,IAAA,CAACF,2BAAoB,CAAA,cAAc,CAAG,EAAA;AAC1D,MAAA,MAAM,aAAa,wBAAyB,CAAA,cAAc,IACtD,cACA,GAAAG,yBAAA,CAAoB,gBAAgB,wBAAwB,CAAA,CAAA;AAEhE,MAAA,IAAI,UAAY,EAAA;AACd,QAAA,WAAA,GAAc,CAAC,UAAU,CAAA,CAAA;AAAA,OAC3B;AAAA,KACK,MAAA;AACL,MAAc,WAAA,GAAA,SAAA,CACX,QAAS,EAAA,CACT,MAAO,CAAA,CAAC,SAASH,2BAAoB,CAAA,IAAA,CAAK,SAAU,EAAC,CAAC,CAAA,CAAA;AAAA,KAC3D;AAEA,IAAA,mBAAA,CAAoB,IAAI,MAAQ,EAAA;AAAA,MAC9B,KAAO,EAAA,YAAA;AAAA,MACP,KAAO,EAAA,WAAA;AAAA,KACR,CAAA,CAAA;AAED,IAAO,OAAA,WAAA,CAAA;AAAA,GACR,CAAA,CAAA;AACH,CAAA;AAEgB,SAAA,iBAAA,CACd,QACA,QACS,EAAA;AACT,EAAM,MAAA,WAAA,GAAc,oBAAoB,MAAM,CAAA,CAAA;AAE9C,EAAI,IAAA,WAAA,CAAY,WAAW,CAAG,EAAA;AAC5B,IAAO,OAAA,KAAA,CAAA;AAAA,GACT;AAEA,EAAO,OAAA,WAAA,CAAY,MAAM,QAAQ,CAAA,CAAA;AACnC;;;;"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { $findMatchingParent } from '@lexical/utils';
|
|
2
|
+
import { $isRootOrShadowRoot, $getSelection, $isRangeSelection } from 'lexical';
|
|
3
|
+
|
|
4
|
+
function isParentRootOrShadowRoot(node) {
|
|
5
|
+
const parent = node.getParent();
|
|
6
|
+
return parent !== null && $isRootOrShadowRoot(parent);
|
|
7
|
+
}
|
|
8
|
+
const activeNodesByEditor = /* @__PURE__ */ new WeakMap();
|
|
9
|
+
function getActiveBlockNodes(editor) {
|
|
10
|
+
const currentState = editor.getEditorState();
|
|
11
|
+
return currentState.read(() => {
|
|
12
|
+
const selection = $getSelection();
|
|
13
|
+
if (!$isRangeSelection(selection)) {
|
|
14
|
+
activeNodesByEditor.delete(editor);
|
|
15
|
+
return [];
|
|
16
|
+
}
|
|
17
|
+
const cache = activeNodesByEditor.get(editor);
|
|
18
|
+
if (cache?.state === currentState) {
|
|
19
|
+
return cache.nodes;
|
|
20
|
+
}
|
|
21
|
+
const anchor = selection.anchor.getNode();
|
|
22
|
+
const focus = selection.focus.getNode();
|
|
23
|
+
const commonAncestor = anchor.getCommonAncestor(focus);
|
|
24
|
+
let activeNodes = [];
|
|
25
|
+
if (commonAncestor && !$isRootOrShadowRoot(commonAncestor)) {
|
|
26
|
+
const activeNode = isParentRootOrShadowRoot(commonAncestor) ? commonAncestor : $findMatchingParent(commonAncestor, isParentRootOrShadowRoot);
|
|
27
|
+
if (activeNode) {
|
|
28
|
+
activeNodes = [activeNode];
|
|
29
|
+
}
|
|
30
|
+
} else {
|
|
31
|
+
activeNodes = selection.getNodes().filter((node) => $isRootOrShadowRoot(node.getParent()));
|
|
32
|
+
}
|
|
33
|
+
activeNodesByEditor.set(editor, {
|
|
34
|
+
state: currentState,
|
|
35
|
+
nodes: activeNodes
|
|
36
|
+
});
|
|
37
|
+
return activeNodes;
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
function isBlockNodeActive(editor, isActive) {
|
|
41
|
+
const activeNodes = getActiveBlockNodes(editor);
|
|
42
|
+
if (activeNodes.length === 0) {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
return activeNodes.every(isActive);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export { isBlockNodeActive };
|
|
49
|
+
//# sourceMappingURL=is-block-node-active.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"is-block-node-active.mjs","sources":["../src/is-block-node-active.ts"],"sourcesContent":["import { $findMatchingParent } from \"@lexical/utils\";\nimport type { EditorState, LexicalEditor, LexicalNode } from \"lexical\";\nimport { $getSelection, $isRangeSelection, $isRootOrShadowRoot } from \"lexical\";\n\nfunction isParentRootOrShadowRoot(node: LexicalNode) {\n const parent = node.getParent();\n\n return parent !== null && $isRootOrShadowRoot(parent);\n}\n\nconst activeNodesByEditor = new WeakMap<\n LexicalEditor,\n {\n state: EditorState;\n nodes: LexicalNode[];\n }\n>();\n\nfunction getActiveBlockNodes(editor: LexicalEditor) {\n const currentState = editor.getEditorState();\n\n return currentState.read(() => {\n const selection = $getSelection();\n\n if (!$isRangeSelection(selection)) {\n activeNodesByEditor.delete(editor);\n\n return [];\n }\n\n const cache = activeNodesByEditor.get(editor);\n\n if (cache?.state === currentState) {\n return cache.nodes;\n }\n\n const anchor = selection.anchor.getNode();\n const focus = selection.focus.getNode();\n const commonAncestor = anchor.getCommonAncestor(focus);\n\n let activeNodes: LexicalNode[] = [];\n\n if (commonAncestor && !$isRootOrShadowRoot(commonAncestor)) {\n const activeNode = isParentRootOrShadowRoot(commonAncestor)\n ? commonAncestor\n : $findMatchingParent(commonAncestor, isParentRootOrShadowRoot);\n\n if (activeNode) {\n activeNodes = [activeNode];\n }\n } else {\n activeNodes = selection\n .getNodes()\n .filter((node) => $isRootOrShadowRoot(node.getParent()));\n }\n\n activeNodesByEditor.set(editor, {\n state: currentState,\n nodes: activeNodes,\n });\n\n return activeNodes;\n });\n}\n\nexport function isBlockNodeActive(\n editor: LexicalEditor,\n isActive: (node: LexicalNode) => boolean\n): boolean {\n const activeNodes = getActiveBlockNodes(editor);\n\n if (activeNodes.length === 0) {\n return false;\n }\n\n return activeNodes.every(isActive);\n}\n"],"names":[],"mappings":";;;AAIA,SAAS,yBAAyB,IAAmB,EAAA;AACnD,EAAM,MAAA,MAAA,GAAS,KAAK,SAAU,EAAA,CAAA;AAE9B,EAAO,OAAA,MAAA,KAAW,IAAQ,IAAA,mBAAA,CAAoB,MAAM,CAAA,CAAA;AACtD,CAAA;AAEA,MAAM,mBAAA,uBAA0B,OAM9B,EAAA,CAAA;AAEF,SAAS,oBAAoB,MAAuB,EAAA;AAClD,EAAM,MAAA,YAAA,GAAe,OAAO,cAAe,EAAA,CAAA;AAE3C,EAAO,OAAA,YAAA,CAAa,KAAK,MAAM;AAC7B,IAAA,MAAM,YAAY,aAAc,EAAA,CAAA;AAEhC,IAAI,IAAA,CAAC,iBAAkB,CAAA,SAAS,CAAG,EAAA;AACjC,MAAA,mBAAA,CAAoB,OAAO,MAAM,CAAA,CAAA;AAEjC,MAAA,OAAO,EAAC,CAAA;AAAA,KACV;AAEA,IAAM,MAAA,KAAA,GAAQ,mBAAoB,CAAA,GAAA,CAAI,MAAM,CAAA,CAAA;AAE5C,IAAI,IAAA,KAAA,EAAO,UAAU,YAAc,EAAA;AACjC,MAAA,OAAO,KAAM,CAAA,KAAA,CAAA;AAAA,KACf;AAEA,IAAM,MAAA,MAAA,GAAS,SAAU,CAAA,MAAA,CAAO,OAAQ,EAAA,CAAA;AACxC,IAAM,MAAA,KAAA,GAAQ,SAAU,CAAA,KAAA,CAAM,OAAQ,EAAA,CAAA;AACtC,IAAM,MAAA,cAAA,GAAiB,MAAO,CAAA,iBAAA,CAAkB,KAAK,CAAA,CAAA;AAErD,IAAA,IAAI,cAA6B,EAAC,CAAA;AAElC,IAAA,IAAI,cAAkB,IAAA,CAAC,mBAAoB,CAAA,cAAc,CAAG,EAAA;AAC1D,MAAA,MAAM,aAAa,wBAAyB,CAAA,cAAc,IACtD,cACA,GAAA,mBAAA,CAAoB,gBAAgB,wBAAwB,CAAA,CAAA;AAEhE,MAAA,IAAI,UAAY,EAAA;AACd,QAAA,WAAA,GAAc,CAAC,UAAU,CAAA,CAAA;AAAA,OAC3B;AAAA,KACK,MAAA;AACL,MAAc,WAAA,GAAA,SAAA,CACX,QAAS,EAAA,CACT,MAAO,CAAA,CAAC,SAAS,mBAAoB,CAAA,IAAA,CAAK,SAAU,EAAC,CAAC,CAAA,CAAA;AAAA,KAC3D;AAEA,IAAA,mBAAA,CAAoB,IAAI,MAAQ,EAAA;AAAA,MAC9B,KAAO,EAAA,YAAA;AAAA,MACP,KAAO,EAAA,WAAA;AAAA,KACR,CAAA,CAAA;AAED,IAAO,OAAA,WAAA,CAAA;AAAA,GACR,CAAA,CAAA;AACH,CAAA;AAEgB,SAAA,iBAAA,CACd,QACA,QACS,EAAA;AACT,EAAM,MAAA,WAAA,GAAc,oBAAoB,MAAM,CAAA,CAAA;AAE9C,EAAI,IAAA,WAAA,CAAY,WAAW,CAAG,EAAA;AAC5B,IAAO,OAAA,KAAA,CAAA;AAAA,GACT;AAEA,EAAO,OAAA,WAAA,CAAY,MAAM,QAAQ,CAAA,CAAA;AACnC;;;;"}
|
|
@@ -14,6 +14,7 @@ var commentPluginProvider = require('./comments/comment-plugin-provider.js');
|
|
|
14
14
|
var threadMarkNode = require('./comments/thread-mark-node.js');
|
|
15
15
|
var mentionNode = require('./mentions/mention-node.js');
|
|
16
16
|
var mentionPlugin = require('./mentions/mention-plugin.js');
|
|
17
|
+
var useRootElement = require('./use-root-element.js');
|
|
17
18
|
|
|
18
19
|
const providersMap = /* @__PURE__ */ new Map();
|
|
19
20
|
function useEditorStatus() {
|
|
@@ -118,7 +119,7 @@ const LiveblocksPlugin = ({
|
|
|
118
119
|
},
|
|
119
120
|
[room]
|
|
120
121
|
);
|
|
121
|
-
const root = useRootElement();
|
|
122
|
+
const root = useRootElement.useRootElement();
|
|
122
123
|
_private.useLayoutEffect(() => {
|
|
123
124
|
if (root === null)
|
|
124
125
|
return;
|
|
@@ -160,22 +161,8 @@ const LiveblocksPlugin = ({
|
|
|
160
161
|
]
|
|
161
162
|
});
|
|
162
163
|
};
|
|
163
|
-
function useRootElement() {
|
|
164
|
-
const [editor] = LexicalComposerContext.useLexicalComposerContext();
|
|
165
|
-
const subscribe = react.useCallback(
|
|
166
|
-
(onStoreChange) => {
|
|
167
|
-
return editor.registerRootListener(onStoreChange);
|
|
168
|
-
},
|
|
169
|
-
[editor]
|
|
170
|
-
);
|
|
171
|
-
const getSnapshot = react.useCallback(() => {
|
|
172
|
-
return editor.getRootElement();
|
|
173
|
-
}, [editor]);
|
|
174
|
-
return react.useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
175
|
-
}
|
|
176
164
|
|
|
177
165
|
exports.LiveblocksPlugin = LiveblocksPlugin;
|
|
178
166
|
exports.useEditorStatus = useEditorStatus;
|
|
179
167
|
exports.useIsEditorReady = useIsEditorReady;
|
|
180
|
-
exports.useRootElement = useRootElement;
|
|
181
168
|
//# sourceMappingURL=liveblocks-plugin-provider.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"liveblocks-plugin-provider.js","sources":["../src/liveblocks-plugin-provider.tsx"],"sourcesContent":["import { autoUpdate, useFloating } from \"@floating-ui/react-dom\";\nimport { CollaborationPlugin } from \"@lexical/react/LexicalCollaborationPlugin\";\nimport { useLexicalComposerContext } from \"@lexical/react/LexicalComposerContext\";\nimport type { Provider } from \"@lexical/yjs\";\nimport { nn, TextEditorType } from \"@liveblocks/core\";\nimport { useRoom, useSelf } from \"@liveblocks/react\";\nimport {\n useLayoutEffect,\n useReportTextEditor,\n useResolveMentionSuggestions,\n useYjsProvider,\n} from \"@liveblocks/react/_private\";\nimport { LiveblocksYjsProvider } from \"@liveblocks/yjs\";\nimport type { MutableRefObject, ReactNode } from \"react\";\nimport {\n useCallback,\n useEffect,\n useRef,\n useState,\n useSyncExternalStore,\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\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 *\n * @deprecated Prefer `useIsEditorReady` or `useSyncStatus` (from @liveblocks/react)\n */\nexport function useEditorStatus(): EditorStatus {\n const provider = useYjsProvider();\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => {\n if (provider === undefined) return () => {};\n provider.on(\"status\", onStoreChange);\n return () => {\n provider.off(\"status\", onStoreChange);\n };\n },\n [provider]\n );\n\n const getSnapshot = useCallback(() => {\n if (provider === undefined) {\n return \"not-loaded\";\n }\n return provider.getStatus();\n }, [provider]);\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n\n/**\n * Returns whether the editor has loaded the initial text contents from the\n * server and is ready to be used.\n */\nexport function useIsEditorReady(): boolean {\n const yjsProvider = useYjsProvider();\n\n const getSnapshot = useCallback(() => {\n const status = yjsProvider?.getStatus();\n return status === \"synchronizing\" || status === \"synchronized\";\n }, [yjsProvider]);\n\n const subscribe = useCallback(\n (callback: () => void) => {\n if (yjsProvider === undefined) return () => {};\n yjsProvider.on(\"status\", callback);\n return () => {\n yjsProvider.off(\"status\", callback);\n };\n },\n [yjsProvider]\n );\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n\nexport type LiveblocksPluginProps = {\n children?: 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 isResolveMentionSuggestionsDefined =\n useResolveMentionSuggestions() !== undefined;\n const [editor] = useLexicalComposerContext();\n const room = useRoom();\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 useReportTextEditor(TextEditorType.Lexical, \"root\");\n\n // Get user info or allow override from props\n const self = useSelf();\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 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 {self && (\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={self.info?.name ?? \"\"} // use empty string to prevent random name\n cursorColor={self.info?.color as string | undefined}\n cursorsContainerRef={containerRef}\n shouldBootstrap={true}\n />\n )}\n\n {isResolveMentionSuggestionsDefined && <MentionPlugin />}\n <CommentPluginProvider>{children}</CommentPluginProvider>\n </>\n );\n};\n\nexport function 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":["useYjsProvider","useCallback","useSyncExternalStore","useResolveMentionSuggestions","useLexicalComposerContext","useRoom","useRef","ThreadMarkNode","MentionNode","useState","useFloating","autoUpdate","useEffect","useReportTextEditor","TextEditorType","useSelf","Doc","LiveblocksYjsProvider","nn","useLayoutEffect","jsxs","Fragment","jsx","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 { CollaborationPlugin } from \"@lexical/react/LexicalCollaborationPlugin\";\nimport { useLexicalComposerContext } from \"@lexical/react/LexicalComposerContext\";\nimport type { Provider } from \"@lexical/yjs\";\nimport { nn, TextEditorType } from \"@liveblocks/core\";\nimport { useRoom, useSelf } from \"@liveblocks/react\";\nimport {\n useLayoutEffect,\n useReportTextEditor,\n useResolveMentionSuggestions,\n useYjsProvider,\n} from \"@liveblocks/react/_private\";\nimport { LiveblocksYjsProvider } from \"@liveblocks/yjs\";\nimport type { MutableRefObject, ReactNode } from \"react\";\nimport {\n useCallback,\n useEffect,\n useRef,\n useState,\n useSyncExternalStore,\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\";\nimport { useRootElement } from \"./use-root-element\";\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\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 *\n * @deprecated Prefer `useIsEditorReady` or `useSyncStatus` (from @liveblocks/react)\n */\nexport function useEditorStatus(): EditorStatus {\n const provider = useYjsProvider();\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => {\n if (provider === undefined) return () => {};\n provider.on(\"status\", onStoreChange);\n return () => {\n provider.off(\"status\", onStoreChange);\n };\n },\n [provider]\n );\n\n const getSnapshot = useCallback(() => {\n if (provider === undefined) {\n return \"not-loaded\";\n }\n return provider.getStatus();\n }, [provider]);\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n\n/**\n * Returns whether the editor has loaded the initial text contents from the\n * server and is ready to be used.\n */\nexport function useIsEditorReady(): boolean {\n const yjsProvider = useYjsProvider();\n\n const getSnapshot = useCallback(() => {\n const status = yjsProvider?.getStatus();\n return status === \"synchronizing\" || status === \"synchronized\";\n }, [yjsProvider]);\n\n const subscribe = useCallback(\n (callback: () => void) => {\n if (yjsProvider === undefined) return () => {};\n yjsProvider.on(\"status\", callback);\n return () => {\n yjsProvider.off(\"status\", callback);\n };\n },\n [yjsProvider]\n );\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n\nexport type LiveblocksPluginProps = {\n children?: 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 isResolveMentionSuggestionsDefined =\n useResolveMentionSuggestions() !== undefined;\n const [editor] = useLexicalComposerContext();\n const room = useRoom();\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 useReportTextEditor(TextEditorType.Lexical, \"root\");\n\n // Get user info or allow override from props\n const self = useSelf();\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 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 {self && (\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={self.info?.name ?? \"\"} // use empty string to prevent random name\n cursorColor={self.info?.color as string | undefined}\n cursorsContainerRef={containerRef}\n shouldBootstrap={true}\n />\n )}\n\n {isResolveMentionSuggestionsDefined && <MentionPlugin />}\n <CommentPluginProvider>{children}</CommentPluginProvider>\n </>\n );\n};\n"],"names":["useYjsProvider","useCallback","useSyncExternalStore","useResolveMentionSuggestions","useLexicalComposerContext","useRoom","useRef","ThreadMarkNode","MentionNode","useState","useFloating","autoUpdate","useEffect","useReportTextEditor","TextEditorType","useSelf","Doc","LiveblocksYjsProvider","nn","useRootElement","useLayoutEffect","jsxs","Fragment","jsx","CollaborationPlugin","MentionPlugin","CommentPluginProvider"],"mappings":"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"}
|
|
@@ -12,6 +12,7 @@ import { CommentPluginProvider } from './comments/comment-plugin-provider.mjs';
|
|
|
12
12
|
import { ThreadMarkNode } from './comments/thread-mark-node.mjs';
|
|
13
13
|
import { MentionNode } from './mentions/mention-node.mjs';
|
|
14
14
|
import { MentionPlugin } from './mentions/mention-plugin.mjs';
|
|
15
|
+
import { useRootElement } from './use-root-element.mjs';
|
|
15
16
|
|
|
16
17
|
const providersMap = /* @__PURE__ */ new Map();
|
|
17
18
|
function useEditorStatus() {
|
|
@@ -158,19 +159,6 @@ const LiveblocksPlugin = ({
|
|
|
158
159
|
]
|
|
159
160
|
});
|
|
160
161
|
};
|
|
161
|
-
function useRootElement() {
|
|
162
|
-
const [editor] = useLexicalComposerContext();
|
|
163
|
-
const subscribe = useCallback(
|
|
164
|
-
(onStoreChange) => {
|
|
165
|
-
return editor.registerRootListener(onStoreChange);
|
|
166
|
-
},
|
|
167
|
-
[editor]
|
|
168
|
-
);
|
|
169
|
-
const getSnapshot = useCallback(() => {
|
|
170
|
-
return editor.getRootElement();
|
|
171
|
-
}, [editor]);
|
|
172
|
-
return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
173
|
-
}
|
|
174
162
|
|
|
175
|
-
export { LiveblocksPlugin, useEditorStatus, useIsEditorReady
|
|
163
|
+
export { LiveblocksPlugin, useEditorStatus, useIsEditorReady };
|
|
176
164
|
//# sourceMappingURL=liveblocks-plugin-provider.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"liveblocks-plugin-provider.mjs","sources":["../src/liveblocks-plugin-provider.tsx"],"sourcesContent":["import { autoUpdate, useFloating } from \"@floating-ui/react-dom\";\nimport { CollaborationPlugin } from \"@lexical/react/LexicalCollaborationPlugin\";\nimport { useLexicalComposerContext } from \"@lexical/react/LexicalComposerContext\";\nimport type { Provider } from \"@lexical/yjs\";\nimport { nn, TextEditorType } from \"@liveblocks/core\";\nimport { useRoom, useSelf } from \"@liveblocks/react\";\nimport {\n useLayoutEffect,\n useReportTextEditor,\n useResolveMentionSuggestions,\n useYjsProvider,\n} from \"@liveblocks/react/_private\";\nimport { LiveblocksYjsProvider } from \"@liveblocks/yjs\";\nimport type { MutableRefObject, ReactNode } from \"react\";\nimport {\n useCallback,\n useEffect,\n useRef,\n useState,\n useSyncExternalStore,\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\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 *\n * @deprecated Prefer `useIsEditorReady` or `useSyncStatus` (from @liveblocks/react)\n */\nexport function useEditorStatus(): EditorStatus {\n const provider = useYjsProvider();\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => {\n if (provider === undefined) return () => {};\n provider.on(\"status\", onStoreChange);\n return () => {\n provider.off(\"status\", onStoreChange);\n };\n },\n [provider]\n );\n\n const getSnapshot = useCallback(() => {\n if (provider === undefined) {\n return \"not-loaded\";\n }\n return provider.getStatus();\n }, [provider]);\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n\n/**\n * Returns whether the editor has loaded the initial text contents from the\n * server and is ready to be used.\n */\nexport function useIsEditorReady(): boolean {\n const yjsProvider = useYjsProvider();\n\n const getSnapshot = useCallback(() => {\n const status = yjsProvider?.getStatus();\n return status === \"synchronizing\" || status === \"synchronized\";\n }, [yjsProvider]);\n\n const subscribe = useCallback(\n (callback: () => void) => {\n if (yjsProvider === undefined) return () => {};\n yjsProvider.on(\"status\", callback);\n return () => {\n yjsProvider.off(\"status\", callback);\n };\n },\n [yjsProvider]\n );\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n\nexport type LiveblocksPluginProps = {\n children?: 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 isResolveMentionSuggestionsDefined =\n useResolveMentionSuggestions() !== undefined;\n const [editor] = useLexicalComposerContext();\n const room = useRoom();\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 useReportTextEditor(TextEditorType.Lexical, \"root\");\n\n // Get user info or allow override from props\n const self = useSelf();\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 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 {self && (\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={self.info?.name ?? \"\"} // use empty string to prevent random name\n cursorColor={self.info?.color as string | undefined}\n cursorsContainerRef={containerRef}\n shouldBootstrap={true}\n />\n )}\n\n {isResolveMentionSuggestionsDefined && <MentionPlugin />}\n <CommentPluginProvider>{children}</CommentPluginProvider>\n </>\n );\n};\n\nexport function 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":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"liveblocks-plugin-provider.mjs","sources":["../src/liveblocks-plugin-provider.tsx"],"sourcesContent":["import { autoUpdate, useFloating } from \"@floating-ui/react-dom\";\nimport { CollaborationPlugin } from \"@lexical/react/LexicalCollaborationPlugin\";\nimport { useLexicalComposerContext } from \"@lexical/react/LexicalComposerContext\";\nimport type { Provider } from \"@lexical/yjs\";\nimport { nn, TextEditorType } from \"@liveblocks/core\";\nimport { useRoom, useSelf } from \"@liveblocks/react\";\nimport {\n useLayoutEffect,\n useReportTextEditor,\n useResolveMentionSuggestions,\n useYjsProvider,\n} from \"@liveblocks/react/_private\";\nimport { LiveblocksYjsProvider } from \"@liveblocks/yjs\";\nimport type { MutableRefObject, ReactNode } from \"react\";\nimport {\n useCallback,\n useEffect,\n useRef,\n useState,\n useSyncExternalStore,\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\";\nimport { useRootElement } from \"./use-root-element\";\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\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 *\n * @deprecated Prefer `useIsEditorReady` or `useSyncStatus` (from @liveblocks/react)\n */\nexport function useEditorStatus(): EditorStatus {\n const provider = useYjsProvider();\n\n const subscribe = useCallback(\n (onStoreChange: () => void) => {\n if (provider === undefined) return () => {};\n provider.on(\"status\", onStoreChange);\n return () => {\n provider.off(\"status\", onStoreChange);\n };\n },\n [provider]\n );\n\n const getSnapshot = useCallback(() => {\n if (provider === undefined) {\n return \"not-loaded\";\n }\n return provider.getStatus();\n }, [provider]);\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n\n/**\n * Returns whether the editor has loaded the initial text contents from the\n * server and is ready to be used.\n */\nexport function useIsEditorReady(): boolean {\n const yjsProvider = useYjsProvider();\n\n const getSnapshot = useCallback(() => {\n const status = yjsProvider?.getStatus();\n return status === \"synchronizing\" || status === \"synchronized\";\n }, [yjsProvider]);\n\n const subscribe = useCallback(\n (callback: () => void) => {\n if (yjsProvider === undefined) return () => {};\n yjsProvider.on(\"status\", callback);\n return () => {\n yjsProvider.off(\"status\", callback);\n };\n },\n [yjsProvider]\n );\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n\nexport type LiveblocksPluginProps = {\n children?: 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 isResolveMentionSuggestionsDefined =\n useResolveMentionSuggestions() !== undefined;\n const [editor] = useLexicalComposerContext();\n const room = useRoom();\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 useReportTextEditor(TextEditorType.Lexical, \"root\");\n\n // Get user info or allow override from props\n const self = useSelf();\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 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 {self && (\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={self.info?.name ?? \"\"} // use empty string to prevent random name\n cursorColor={self.info?.color as string | undefined}\n cursorsContainerRef={containerRef}\n shouldBootstrap={true}\n />\n )}\n\n {isResolveMentionSuggestionsDefined && <MentionPlugin />}\n <CommentPluginProvider>{children}</CommentPluginProvider>\n </>\n );\n};\n"],"names":[],"mappings":"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"}
|