@liveblocks/react-tiptap 2.15.2 → 2.16.0-toolbars2

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 (54) hide show
  1. package/dist/LiveblocksExtension.js.map +1 -1
  2. package/dist/LiveblocksExtension.mjs.map +1 -1
  3. package/dist/comments/CommentsExtension.js +6 -2
  4. package/dist/comments/CommentsExtension.js.map +1 -1
  5. package/dist/comments/CommentsExtension.mjs +7 -3
  6. package/dist/comments/CommentsExtension.mjs.map +1 -1
  7. package/dist/comments/FloatingComposer.js +27 -30
  8. package/dist/comments/FloatingComposer.js.map +1 -1
  9. package/dist/comments/FloatingComposer.mjs +29 -32
  10. package/dist/comments/FloatingComposer.mjs.map +1 -1
  11. package/dist/context.js +24 -0
  12. package/dist/context.js.map +1 -0
  13. package/dist/context.mjs +21 -0
  14. package/dist/context.mjs.map +1 -0
  15. package/dist/index.d.mts +67 -13
  16. package/dist/index.d.ts +67 -13
  17. package/dist/index.js +4 -0
  18. package/dist/index.js.map +1 -1
  19. package/dist/index.mjs +2 -0
  20. package/dist/index.mjs.map +1 -1
  21. package/dist/toolbar/FloatingToolbar.js +326 -0
  22. package/dist/toolbar/FloatingToolbar.js.map +1 -0
  23. package/dist/toolbar/FloatingToolbar.mjs +323 -0
  24. package/dist/toolbar/FloatingToolbar.mjs.map +1 -0
  25. package/dist/toolbar/Toolbar.js +354 -0
  26. package/dist/toolbar/Toolbar.js.map +1 -0
  27. package/dist/toolbar/Toolbar.mjs +329 -0
  28. package/dist/toolbar/Toolbar.mjs.map +1 -0
  29. package/dist/toolbar/shared.js +39 -0
  30. package/dist/toolbar/shared.js.map +1 -0
  31. package/dist/toolbar/shared.mjs +36 -0
  32. package/dist/toolbar/shared.mjs.map +1 -0
  33. package/dist/types.js +7 -3
  34. package/dist/types.js.map +1 -1
  35. package/dist/types.mjs +6 -3
  36. package/dist/types.mjs.map +1 -1
  37. package/dist/utils.js +17 -0
  38. package/dist/utils.js.map +1 -1
  39. package/dist/utils.mjs +16 -1
  40. package/dist/utils.mjs.map +1 -1
  41. package/dist/version-history/HistoryVersionPreview.js +79 -79
  42. package/dist/version-history/HistoryVersionPreview.js.map +1 -1
  43. package/dist/version-history/HistoryVersionPreview.mjs +79 -79
  44. package/dist/version-history/HistoryVersionPreview.mjs.map +1 -1
  45. package/dist/version.js +1 -1
  46. package/dist/version.js.map +1 -1
  47. package/dist/version.mjs +1 -1
  48. package/dist/version.mjs.map +1 -1
  49. package/package.json +11 -8
  50. package/src/styles/constants.css +2 -1
  51. package/src/styles/index.css +58 -6
  52. package/src/styles/utils.css +11 -0
  53. package/styles.css +1 -1
  54. package/styles.css.map +1 -1
@@ -1,27 +1,25 @@
1
1
  import { jsx } from 'react/jsx-runtime';
2
- import { useFloating, flip, offset, hide, shift, limitShift, size, autoUpdate } from '@floating-ui/react-dom';
2
+ import { useFloating, inline, flip, offset, hide, shift, limitShift, size, autoUpdate } from '@floating-ui/react-dom';
3
3
  import { useCreateThread } from '@liveblocks/react';
4
4
  import { useLayoutEffect } from '@liveblocks/react/_private';
5
5
  import { Composer } from '@liveblocks/react-ui';
6
6
  import { useEditorState } from '@tiptap/react';
7
- import { forwardRef, useCallback, useEffect } from 'react';
7
+ import { forwardRef, useCallback } from 'react';
8
8
  import { createPortal } from 'react-dom';
9
+ import { compareTextSelections, getDomRangeFromTextSelection } from '../utils.mjs';
9
10
 
10
11
  const FLOATING_COMPOSER_COLLISION_PADDING = 10;
11
12
  const FloatingComposer = forwardRef(function FloatingComposer2(props, forwardedRef) {
12
13
  const createThread = useCreateThread();
13
14
  const { editor, onComposerSubmit, onKeyDown } = props;
14
- const { showComposer } = useEditorState({
15
+ const pendingCommentSelection = useEditorState({
15
16
  editor,
16
- selector: (ctx) => ({
17
- showComposer: !!ctx.editor?.storage.liveblocksComments?.pendingCommentSelection
18
- }),
19
- equalityFn: (prev, next) => {
20
- if (!next)
21
- return false;
22
- return prev.showComposer === next.showComposer;
23
- }
24
- }) ?? { showComposer: false };
17
+ selector: (ctx) => {
18
+ return ctx.editor?.storage.liveblocksComments?.pendingCommentSelection;
19
+ },
20
+ equalityFn: compareTextSelections
21
+ }) ?? void 0;
22
+ const isOpen = pendingCommentSelection !== void 0;
25
23
  const {
26
24
  refs: { setReference, setFloating },
27
25
  strategy,
@@ -31,6 +29,7 @@ const FloatingComposer = forwardRef(function FloatingComposer2(props, forwardedR
31
29
  strategy: "fixed",
32
30
  placement: "bottom",
33
31
  middleware: [
32
+ inline({ padding: FLOATING_COMPOSER_COLLISION_PADDING }),
34
33
  flip({ padding: FLOATING_COMPOSER_COLLISION_PADDING, crossAxis: false }),
35
34
  offset(10),
36
35
  hide({ padding: FLOATING_COMPOSER_COLLISION_PADDING }),
@@ -46,25 +45,20 @@ const FloatingComposer = forwardRef(function FloatingComposer2(props, forwardedR
46
45
  });
47
46
  }
48
47
  });
49
- const updateRef = useCallback(() => {
50
- if (!editor || !showComposer) {
48
+ useLayoutEffect(() => {
49
+ if (!editor || !isOpen) {
51
50
  return;
52
51
  }
53
- const el = editor.view.dom.querySelector(".lb-tiptap-active-selection");
54
- if (el) {
55
- setReference(el);
56
- }
57
- }, [setReference, editor, showComposer]);
58
- useEffect(() => {
59
- if (!editor || !showComposer) {
60
- return;
52
+ if (!pendingCommentSelection) {
53
+ setReference(null);
54
+ } else {
55
+ const domRange = getDomRangeFromTextSelection(
56
+ pendingCommentSelection,
57
+ editor
58
+ );
59
+ setReference(domRange);
61
60
  }
62
- editor.on("transaction", updateRef);
63
- return () => {
64
- editor.off("transaction", updateRef);
65
- };
66
- }, [editor, updateRef, showComposer]);
67
- useLayoutEffect(updateRef, [updateRef]);
61
+ }, [pendingCommentSelection, editor, isOpen, setReference]);
68
62
  const handleComposerSubmit = useCallback(
69
63
  (comment, event) => {
70
64
  onComposerSubmit?.(comment, event);
@@ -85,14 +79,17 @@ const FloatingComposer = forwardRef(function FloatingComposer2(props, forwardedR
85
79
  );
86
80
  const handleKeyDown = useCallback(
87
81
  (event) => {
88
- if (event.key === "Escape" && editor) {
89
- editor.commands.focus();
90
- }
91
82
  onKeyDown?.(event);
83
+ if (event.isDefaultPrevented() || !editor) {
84
+ return;
85
+ }
86
+ if (event.key === "Escape") {
87
+ editor.chain().closePendingComment().run();
88
+ }
92
89
  },
93
90
  [editor, onKeyDown]
94
91
  );
95
- if (!showComposer || !editor) {
92
+ if (!isOpen || !editor) {
96
93
  return null;
97
94
  }
98
95
  return createPortal(
@@ -1 +1 @@
1
- {"version":3,"file":"FloatingComposer.mjs","sources":["../../src/comments/FloatingComposer.tsx"],"sourcesContent":["import {\n autoUpdate,\n flip,\n hide,\n limitShift,\n offset,\n shift,\n size,\n useFloating,\n} from \"@floating-ui/react-dom\";\nimport type { BaseMetadata } from \"@liveblocks/client\";\nimport type { DM } from \"@liveblocks/core\";\nimport { useCreateThread } from \"@liveblocks/react\";\nimport { useLayoutEffect } from \"@liveblocks/react/_private\";\nimport type {\n ComposerProps,\n ComposerSubmitComment,\n} from \"@liveblocks/react-ui\";\nimport { Composer } from \"@liveblocks/react-ui\";\nimport { type Editor, useEditorState } from \"@tiptap/react\";\nimport type { ComponentRef, FormEvent, KeyboardEvent } from \"react\";\nimport { forwardRef, useCallback, useEffect } from \"react\";\nimport { createPortal } from \"react-dom\";\n\nimport type { CommentsExtensionStorage } from \"../types\";\n\nexport type FloatingComposerProps<M extends BaseMetadata = DM> = Omit<\n ComposerProps<M>,\n \"threadId\" | \"commentId\"\n> & {\n editor: Editor | null;\n};\n\ntype ComposerElement = ComponentRef<typeof Composer>;\n\nexport const FLOATING_COMPOSER_COLLISION_PADDING = 10;\n\nexport const FloatingComposer = forwardRef<\n ComposerElement,\n FloatingComposerProps\n>(function FloatingComposer(props, forwardedRef) {\n const createThread = useCreateThread();\n const { editor, onComposerSubmit, onKeyDown } = props;\n const { showComposer } = useEditorState({\n editor,\n selector: (ctx) => ({\n showComposer: !!(\n ctx.editor?.storage.liveblocksComments as\n | CommentsExtensionStorage\n | undefined\n )?.pendingCommentSelection,\n }),\n equalityFn: (prev, next) => {\n if (!next) return false;\n return prev.showComposer === next.showComposer;\n },\n }) ?? { showComposer: false };\n\n const {\n refs: { setReference, setFloating },\n strategy,\n x,\n y,\n } = useFloating({\n strategy: \"fixed\",\n placement: \"bottom\",\n middleware: [\n flip({ padding: FLOATING_COMPOSER_COLLISION_PADDING, crossAxis: false }),\n offset(10),\n hide({ padding: FLOATING_COMPOSER_COLLISION_PADDING }),\n shift({\n padding: FLOATING_COMPOSER_COLLISION_PADDING,\n limiter: limitShift(),\n }),\n size({ padding: FLOATING_COMPOSER_COLLISION_PADDING }),\n ],\n whileElementsMounted: (...args) => {\n return autoUpdate(...args, {\n animationFrame: true,\n });\n },\n });\n\n const updateRef = useCallback(() => {\n if (!editor || !showComposer) {\n return;\n }\n const el = editor.view.dom.querySelector(\".lb-tiptap-active-selection\");\n if (el) {\n setReference(el);\n }\n }, [setReference, editor, showComposer]);\n\n // Remote cursor updates and other edits can cause the ref to break\n useEffect(() => {\n if (!editor || !showComposer) {\n return;\n }\n editor.on(\"transaction\", updateRef);\n return () => {\n editor.off(\"transaction\", updateRef);\n };\n }, [editor, updateRef, showComposer]);\n\n useLayoutEffect(updateRef, [updateRef]);\n\n // Submit a new thread and update the comment highlight to show a completed highlight\n const handleComposerSubmit = useCallback(\n (comment: ComposerSubmitComment, event: FormEvent<HTMLFormElement>) => {\n onComposerSubmit?.(comment, event);\n if (event.defaultPrevented) return;\n\n if (!editor) {\n return;\n }\n event.preventDefault();\n\n const thread = createThread({\n body: comment.body,\n attachments: comment.attachments,\n metadata: props.metadata ?? {},\n });\n editor.commands.addComment(thread.id);\n },\n [onComposerSubmit, editor, createThread, props.metadata]\n );\n\n const handleKeyDown = useCallback(\n (event: KeyboardEvent<HTMLFormElement>) => {\n if (event.key === \"Escape\" && editor) {\n editor.commands.focus();\n }\n onKeyDown?.(event);\n },\n [editor, onKeyDown]\n );\n\n if (!showComposer || !editor) {\n return null;\n }\n\n return createPortal(\n <div\n className=\"lb-root lb-portal lb-elevation lb-tiptap-floating lb-tiptap-floating-composer\"\n ref={setFloating}\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 <Composer\n ref={forwardedRef}\n {...props}\n onKeyDown={handleKeyDown}\n onComposerSubmit={handleComposerSubmit}\n onClick={(e) => {\n // Don't send up a click event from emoji popout and close the composer\n e.stopPropagation();\n }}\n autoFocus={true}\n />\n </div>,\n document.body\n );\n});\n"],"names":["FloatingComposer"],"mappings":"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"}
1
+ {"version":3,"file":"FloatingComposer.mjs","sources":["../../src/comments/FloatingComposer.tsx"],"sourcesContent":["import {\n autoUpdate,\n flip,\n hide,\n inline,\n limitShift,\n offset,\n shift,\n size,\n useFloating,\n} from \"@floating-ui/react-dom\";\nimport type { BaseMetadata } from \"@liveblocks/client\";\nimport type { DM } from \"@liveblocks/core\";\nimport { useCreateThread } from \"@liveblocks/react\";\nimport { useLayoutEffect } from \"@liveblocks/react/_private\";\nimport type {\n ComposerProps,\n ComposerSubmitComment,\n} from \"@liveblocks/react-ui\";\nimport { Composer } from \"@liveblocks/react-ui\";\nimport { type Editor, useEditorState } from \"@tiptap/react\";\nimport type { ComponentRef, FormEvent, KeyboardEvent } from \"react\";\nimport { forwardRef, useCallback } from \"react\";\nimport { createPortal } from \"react-dom\";\n\nimport type {\n CommentsExtensionStorage,\n ExtendedChainedCommands,\n} from \"../types\";\nimport { compareTextSelections, getDomRangeFromTextSelection } from \"../utils\";\n\nexport type FloatingComposerProps<M extends BaseMetadata = DM> = Omit<\n ComposerProps<M>,\n \"threadId\" | \"commentId\"\n> & {\n editor: Editor | null;\n};\n\ntype ComposerElement = ComponentRef<typeof Composer>;\n\nexport const FLOATING_COMPOSER_COLLISION_PADDING = 10;\n\nexport const FloatingComposer = forwardRef<\n ComposerElement,\n FloatingComposerProps\n>(function FloatingComposer(props, forwardedRef) {\n const createThread = useCreateThread();\n const { editor, onComposerSubmit, onKeyDown } = props;\n const pendingCommentSelection =\n useEditorState({\n editor,\n selector: (ctx) => {\n return (\n ctx.editor?.storage.liveblocksComments as\n | CommentsExtensionStorage\n | undefined\n )?.pendingCommentSelection;\n },\n equalityFn: compareTextSelections,\n }) ?? undefined;\n const isOpen = pendingCommentSelection !== undefined;\n const {\n refs: { setReference, setFloating },\n strategy,\n x,\n y,\n } = useFloating({\n strategy: \"fixed\",\n placement: \"bottom\",\n middleware: [\n inline({ padding: FLOATING_COMPOSER_COLLISION_PADDING }),\n flip({ padding: FLOATING_COMPOSER_COLLISION_PADDING, crossAxis: false }),\n offset(10),\n hide({ padding: FLOATING_COMPOSER_COLLISION_PADDING }),\n shift({\n padding: FLOATING_COMPOSER_COLLISION_PADDING,\n limiter: limitShift(),\n }),\n size({ padding: FLOATING_COMPOSER_COLLISION_PADDING }),\n ],\n whileElementsMounted: (...args) => {\n return autoUpdate(...args, {\n animationFrame: true,\n });\n },\n });\n\n useLayoutEffect(() => {\n if (!editor || !isOpen) {\n return;\n }\n\n if (!pendingCommentSelection) {\n setReference(null);\n } else {\n const domRange = getDomRangeFromTextSelection(\n pendingCommentSelection,\n editor\n );\n\n setReference(domRange);\n }\n }, [pendingCommentSelection, editor, isOpen, setReference]);\n\n // Submit a new thread and update the comment highlight to show a completed highlight\n const handleComposerSubmit = useCallback(\n (comment: ComposerSubmitComment, event: FormEvent<HTMLFormElement>) => {\n onComposerSubmit?.(comment, event);\n if (event.defaultPrevented) return;\n\n if (!editor) {\n return;\n }\n event.preventDefault();\n\n const thread = createThread({\n body: comment.body,\n attachments: comment.attachments,\n metadata: props.metadata ?? {},\n });\n editor.commands.addComment(thread.id);\n },\n [onComposerSubmit, editor, createThread, props.metadata]\n );\n\n const handleKeyDown = useCallback(\n (event: KeyboardEvent<HTMLFormElement>) => {\n onKeyDown?.(event);\n\n if (event.isDefaultPrevented() || !editor) {\n return;\n }\n\n if (event.key === \"Escape\") {\n (editor.chain() as ExtendedChainedCommands<\"closePendingComment\">)\n .closePendingComment()\n .run();\n }\n },\n [editor, onKeyDown]\n );\n\n if (!isOpen || !editor) {\n return null;\n }\n\n return createPortal(\n <div\n className=\"lb-root lb-portal lb-elevation lb-tiptap-floating lb-tiptap-floating-composer\"\n ref={setFloating}\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 <Composer\n ref={forwardedRef}\n {...props}\n onKeyDown={handleKeyDown}\n onComposerSubmit={handleComposerSubmit}\n onClick={(e) => {\n // Don't send up a click event from emoji popout and close the composer\n e.stopPropagation();\n }}\n autoFocus={true}\n />\n </div>,\n document.body\n );\n});\n"],"names":["FloatingComposer"],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+ var core = require('@liveblocks/core');
5
+ var react = require('react');
6
+
7
+ const EditorContext = react.createContext(null);
8
+ function EditorProvider({
9
+ editor,
10
+ children
11
+ }) {
12
+ return /* @__PURE__ */ jsxRuntime.jsx(EditorContext.Provider, {
13
+ value: editor,
14
+ children
15
+ });
16
+ }
17
+ function useCurrentEditor(source, parent) {
18
+ const currentEditor = react.useContext(EditorContext);
19
+ return core.nn(currentEditor, `${source} can\u2019t be used outside of ${parent}.`);
20
+ }
21
+
22
+ exports.EditorProvider = EditorProvider;
23
+ exports.useCurrentEditor = useCurrentEditor;
24
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sources":["../src/context.tsx"],"sourcesContent":["import { nn } from \"@liveblocks/core\";\nimport type { Editor } from \"@tiptap/react\";\nimport type { PropsWithChildren } from \"react\";\nimport { createContext, useContext } from \"react\";\n\nconst EditorContext = createContext<Editor | null>(null);\n\nexport function EditorProvider({\n editor,\n children,\n}: PropsWithChildren<{ editor: Editor }>) {\n return (\n <EditorContext.Provider value={editor}>{children}</EditorContext.Provider>\n );\n}\n\n/**\n * @tiptap/react already offers a `useCurrentEditor` hook but our components might\n * not live under `EditorProvider` or `EditorContent` so we create our own to reduce\n * repetition within our own nested components.\n *\n * @example\n * <Toolbar editor={editor}> // `editor` is required here\n * <ToolbarSectionInline /> // But it isn't there, because `Toolbar` uses our own `EditorProvider`\n * </Toolbar>\n */\nexport function useCurrentEditor(source: string, parent: string) {\n const currentEditor = useContext(EditorContext);\n\n return nn(currentEditor, `${source} can’t be used outside of ${parent}.`);\n}\n"],"names":["createContext","jsx","useContext","nn"],"mappings":";;;;;;AAKA,MAAM,aAAA,GAAgBA,oBAA6B,IAAI,CAAA,CAAA;AAEhD,SAAS,cAAe,CAAA;AAAA,EAC7B,MAAA;AAAA,EACA,QAAA;AACF,CAA0C,EAAA;AACxC,EACE,uBAAAC,cAAA,CAAC,cAAc,QAAd,EAAA;AAAA,IAAuB,KAAO,EAAA,MAAA;AAAA,IAAS,QAAA;AAAA,GAAS,CAAA,CAAA;AAErD,CAAA;AAYgB,SAAA,gBAAA,CAAiB,QAAgB,MAAgB,EAAA;AAC/D,EAAM,MAAA,aAAA,GAAgBC,iBAAW,aAAa,CAAA,CAAA;AAE9C,EAAA,OAAOC,OAAG,CAAA,aAAA,EAAe,CAAG,EAAA,MAAA,CAAA,+BAAA,EAAmC,MAAS,CAAA,CAAA,CAAA,CAAA,CAAA;AAC1E;;;;;"}
@@ -0,0 +1,21 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { nn } from '@liveblocks/core';
3
+ import { createContext, useContext } from 'react';
4
+
5
+ const EditorContext = createContext(null);
6
+ function EditorProvider({
7
+ editor,
8
+ children
9
+ }) {
10
+ return /* @__PURE__ */ jsx(EditorContext.Provider, {
11
+ value: editor,
12
+ children
13
+ });
14
+ }
15
+ function useCurrentEditor(source, parent) {
16
+ const currentEditor = useContext(EditorContext);
17
+ return nn(currentEditor, `${source} can\u2019t be used outside of ${parent}.`);
18
+ }
19
+
20
+ export { EditorProvider, useCurrentEditor };
21
+ //# sourceMappingURL=context.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.mjs","sources":["../src/context.tsx"],"sourcesContent":["import { nn } from \"@liveblocks/core\";\nimport type { Editor } from \"@tiptap/react\";\nimport type { PropsWithChildren } from \"react\";\nimport { createContext, useContext } from \"react\";\n\nconst EditorContext = createContext<Editor | null>(null);\n\nexport function EditorProvider({\n editor,\n children,\n}: PropsWithChildren<{ editor: Editor }>) {\n return (\n <EditorContext.Provider value={editor}>{children}</EditorContext.Provider>\n );\n}\n\n/**\n * @tiptap/react already offers a `useCurrentEditor` hook but our components might\n * not live under `EditorProvider` or `EditorContent` so we create our own to reduce\n * repetition within our own nested components.\n *\n * @example\n * <Toolbar editor={editor}> // `editor` is required here\n * <ToolbarSectionInline /> // But it isn't there, because `Toolbar` uses our own `EditorProvider`\n * </Toolbar>\n */\nexport function useCurrentEditor(source: string, parent: string) {\n const currentEditor = useContext(EditorContext);\n\n return nn(currentEditor, `${source} can’t be used outside of ${parent}.`);\n}\n"],"names":[],"mappings":";;;;AAKA,MAAM,aAAA,GAAgB,cAA6B,IAAI,CAAA,CAAA;AAEhD,SAAS,cAAe,CAAA;AAAA,EAC7B,MAAA;AAAA,EACA,QAAA;AACF,CAA0C,EAAA;AACxC,EACE,uBAAA,GAAA,CAAC,cAAc,QAAd,EAAA;AAAA,IAAuB,KAAO,EAAA,MAAA;AAAA,IAAS,QAAA;AAAA,GAAS,CAAA,CAAA;AAErD,CAAA;AAYgB,SAAA,gBAAA,CAAiB,QAAgB,MAAgB,EAAA;AAC/D,EAAM,MAAA,aAAA,GAAgB,WAAW,aAAa,CAAA,CAAA;AAE9C,EAAA,OAAO,EAAG,CAAA,aAAA,EAAe,CAAG,EAAA,MAAA,CAAA,+BAAA,EAAmC,MAAS,CAAA,CAAA,CAAA,CAAA,CAAA;AAC1E;;;;"}
package/dist/index.d.mts CHANGED
@@ -3,11 +3,21 @@ import { BaseMetadata, DM, ThreadData, HistoryVersion } from '@liveblocks/core';
3
3
  import { ThreadProps, ComposerProps } from '@liveblocks/react-ui';
4
4
  import { Editor } from '@tiptap/react';
5
5
  import * as react from 'react';
6
- import { ComponentPropsWithoutRef, ComponentType, HTMLAttributes } from 'react';
6
+ import { ComponentPropsWithoutRef, ComponentType, HTMLAttributes, ComponentProps, ReactNode } from 'react';
7
7
  import { BaseMetadata as BaseMetadata$1 } from '@liveblocks/client';
8
8
  import { Extension, Content } from '@tiptap/core';
9
9
 
10
- declare type AnchoredThreadsComponents = {
10
+ type FloatingPosition = "top" | "bottom";
11
+ type CommentsCommands<ReturnType> = {
12
+ /**
13
+ * Add a comment
14
+ */
15
+ addComment: (id: string) => ReturnType;
16
+ selectThread: (id: string | null) => ReturnType;
17
+ addPendingComment: () => ReturnType;
18
+ };
19
+
20
+ type AnchoredThreadsComponents = {
11
21
  Thread: ComponentType<ThreadProps>;
12
22
  };
13
23
  interface AnchoredThreadsProps<M extends BaseMetadata = DM> extends Omit<ComponentPropsWithoutRef<"div">, "children"> {
@@ -30,7 +40,7 @@ declare const FloatingComposer: react.ForwardRefExoticComponent<Omit<ComposerPro
30
40
  editor: Editor | null;
31
41
  } & react.RefAttributes<HTMLFormElement>>;
32
42
 
33
- declare type ThreadPanelComponents = {
43
+ type ThreadPanelComponents = {
34
44
  Thread: ComponentType<ThreadProps>;
35
45
  };
36
46
  interface FloatingThreadsProps<M extends BaseMetadata = DM> extends Omit<HTMLAttributes<HTMLDivElement>, "children"> {
@@ -49,7 +59,7 @@ interface FloatingThreadsProps<M extends BaseMetadata = DM> extends Omit<HTMLAtt
49
59
  }
50
60
  declare function FloatingThreads({ threads, components, editor, ...props }: FloatingThreadsProps): react_jsx_runtime.JSX.Element | null;
51
61
 
52
- declare type LiveblocksExtensionOptions = {
62
+ type LiveblocksExtensionOptions = {
53
63
  field?: string;
54
64
  comments?: boolean;
55
65
  mentions?: boolean;
@@ -64,6 +74,57 @@ declare type LiveblocksExtensionOptions = {
64
74
  declare function useIsEditorReady(): boolean;
65
75
  declare const useLiveblocksExtension: (opts?: LiveblocksExtensionOptions) => Extension;
66
76
 
77
+ interface ToolbarSlotProps {
78
+ editor: Editor;
79
+ }
80
+ type ToolbarSlot = ReactNode | ComponentType<ToolbarSlotProps>;
81
+ interface ToolbarProps extends Omit<ComponentProps<"div">, "children"> {
82
+ editor: Editor | null;
83
+ children?: ToolbarSlot;
84
+ before?: ToolbarSlot;
85
+ after?: ToolbarSlot;
86
+ }
87
+ interface ToolbarButtonProps extends ComponentProps<"button"> {
88
+ icon?: ReactNode;
89
+ name: string;
90
+ shortcut?: string;
91
+ }
92
+ interface ToolbarToggleProps extends ToolbarButtonProps {
93
+ active: boolean;
94
+ }
95
+ interface ToolbarBlockSelectorItem {
96
+ name: string;
97
+ isActive: (editor: Editor) => boolean;
98
+ setActive: (editor: Editor) => void;
99
+ }
100
+ interface ToolbarBlockSelectorProps extends ComponentProps<"button"> {
101
+ items?: ToolbarBlockSelectorItem[];
102
+ }
103
+ declare function ToolbarSectionHistory(): react_jsx_runtime.JSX.Element;
104
+ declare function ToolbarSectionInline(): react_jsx_runtime.JSX.Element;
105
+ declare function ToolbarSectionCollaboration(): react_jsx_runtime.JSX.Element;
106
+ declare const Toolbar: react.ForwardRefExoticComponent<Omit<ToolbarProps, "ref"> & react.RefAttributes<HTMLDivElement>> & {
107
+ Button: react.ForwardRefExoticComponent<Omit<ToolbarButtonProps, "ref"> & react.RefAttributes<HTMLButtonElement>>;
108
+ Toggle: react.ForwardRefExoticComponent<Omit<ToolbarToggleProps, "ref"> & react.RefAttributes<HTMLButtonElement>>;
109
+ Separator: react.ForwardRefExoticComponent<Omit<react.DetailedHTMLProps<react.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
110
+ SectionHistory: typeof ToolbarSectionHistory;
111
+ SectionInline: typeof ToolbarSectionInline;
112
+ SectionCollaboration: typeof ToolbarSectionCollaboration;
113
+ BlockSelector: react.ForwardRefExoticComponent<Omit<ToolbarBlockSelectorProps, "ref"> & react.RefAttributes<HTMLButtonElement>>;
114
+ };
115
+
116
+ interface FloatingToolbarProps extends Omit<ComponentProps<"div">, "children"> {
117
+ editor: Editor | null;
118
+ position?: FloatingPosition;
119
+ offset?: number;
120
+ children?: ToolbarSlot;
121
+ before?: ToolbarSlot;
122
+ after?: ToolbarSlot;
123
+ }
124
+ declare const FloatingToolbar: react.ForwardRefExoticComponent<Omit<FloatingToolbarProps, "ref"> & react.RefAttributes<HTMLDivElement>> & {
125
+ External: react.ForwardRefExoticComponent<Omit<react.DetailedHTMLProps<react.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
126
+ };
127
+
67
128
  interface HistoryVersionPreviewProps extends ComponentPropsWithoutRef<"div"> {
68
129
  version: HistoryVersion;
69
130
  editor: Editor;
@@ -79,15 +140,8 @@ declare const HistoryVersionPreview: react.ForwardRefExoticComponent<HistoryVers
79
140
 
80
141
  declare module "@tiptap/core" {
81
142
  interface Commands<ReturnType> {
82
- comments: {
83
- /**
84
- * Add a comment
85
- */
86
- addComment: (id: string) => ReturnType;
87
- selectThread: (id: string | null) => ReturnType;
88
- addPendingComment: () => ReturnType;
89
- };
143
+ comments: CommentsCommands<ReturnType>;
90
144
  }
91
145
  }
92
146
 
93
- export { AnchoredThreads, FloatingComposer, FloatingThreads, HistoryVersionPreview, useIsEditorReady, useLiveblocksExtension };
147
+ export { AnchoredThreads, FloatingComposer, FloatingThreads, FloatingToolbar, HistoryVersionPreview, Toolbar, useIsEditorReady, useLiveblocksExtension };
package/dist/index.d.ts CHANGED
@@ -3,11 +3,21 @@ import { BaseMetadata, DM, ThreadData, HistoryVersion } from '@liveblocks/core';
3
3
  import { ThreadProps, ComposerProps } from '@liveblocks/react-ui';
4
4
  import { Editor } from '@tiptap/react';
5
5
  import * as react from 'react';
6
- import { ComponentPropsWithoutRef, ComponentType, HTMLAttributes } from 'react';
6
+ import { ComponentPropsWithoutRef, ComponentType, HTMLAttributes, ComponentProps, ReactNode } from 'react';
7
7
  import { BaseMetadata as BaseMetadata$1 } from '@liveblocks/client';
8
8
  import { Extension, Content } from '@tiptap/core';
9
9
 
10
- declare type AnchoredThreadsComponents = {
10
+ type FloatingPosition = "top" | "bottom";
11
+ type CommentsCommands<ReturnType> = {
12
+ /**
13
+ * Add a comment
14
+ */
15
+ addComment: (id: string) => ReturnType;
16
+ selectThread: (id: string | null) => ReturnType;
17
+ addPendingComment: () => ReturnType;
18
+ };
19
+
20
+ type AnchoredThreadsComponents = {
11
21
  Thread: ComponentType<ThreadProps>;
12
22
  };
13
23
  interface AnchoredThreadsProps<M extends BaseMetadata = DM> extends Omit<ComponentPropsWithoutRef<"div">, "children"> {
@@ -30,7 +40,7 @@ declare const FloatingComposer: react.ForwardRefExoticComponent<Omit<ComposerPro
30
40
  editor: Editor | null;
31
41
  } & react.RefAttributes<HTMLFormElement>>;
32
42
 
33
- declare type ThreadPanelComponents = {
43
+ type ThreadPanelComponents = {
34
44
  Thread: ComponentType<ThreadProps>;
35
45
  };
36
46
  interface FloatingThreadsProps<M extends BaseMetadata = DM> extends Omit<HTMLAttributes<HTMLDivElement>, "children"> {
@@ -49,7 +59,7 @@ interface FloatingThreadsProps<M extends BaseMetadata = DM> extends Omit<HTMLAtt
49
59
  }
50
60
  declare function FloatingThreads({ threads, components, editor, ...props }: FloatingThreadsProps): react_jsx_runtime.JSX.Element | null;
51
61
 
52
- declare type LiveblocksExtensionOptions = {
62
+ type LiveblocksExtensionOptions = {
53
63
  field?: string;
54
64
  comments?: boolean;
55
65
  mentions?: boolean;
@@ -64,6 +74,57 @@ declare type LiveblocksExtensionOptions = {
64
74
  declare function useIsEditorReady(): boolean;
65
75
  declare const useLiveblocksExtension: (opts?: LiveblocksExtensionOptions) => Extension;
66
76
 
77
+ interface ToolbarSlotProps {
78
+ editor: Editor;
79
+ }
80
+ type ToolbarSlot = ReactNode | ComponentType<ToolbarSlotProps>;
81
+ interface ToolbarProps extends Omit<ComponentProps<"div">, "children"> {
82
+ editor: Editor | null;
83
+ children?: ToolbarSlot;
84
+ before?: ToolbarSlot;
85
+ after?: ToolbarSlot;
86
+ }
87
+ interface ToolbarButtonProps extends ComponentProps<"button"> {
88
+ icon?: ReactNode;
89
+ name: string;
90
+ shortcut?: string;
91
+ }
92
+ interface ToolbarToggleProps extends ToolbarButtonProps {
93
+ active: boolean;
94
+ }
95
+ interface ToolbarBlockSelectorItem {
96
+ name: string;
97
+ isActive: (editor: Editor) => boolean;
98
+ setActive: (editor: Editor) => void;
99
+ }
100
+ interface ToolbarBlockSelectorProps extends ComponentProps<"button"> {
101
+ items?: ToolbarBlockSelectorItem[];
102
+ }
103
+ declare function ToolbarSectionHistory(): react_jsx_runtime.JSX.Element;
104
+ declare function ToolbarSectionInline(): react_jsx_runtime.JSX.Element;
105
+ declare function ToolbarSectionCollaboration(): react_jsx_runtime.JSX.Element;
106
+ declare const Toolbar: react.ForwardRefExoticComponent<Omit<ToolbarProps, "ref"> & react.RefAttributes<HTMLDivElement>> & {
107
+ Button: react.ForwardRefExoticComponent<Omit<ToolbarButtonProps, "ref"> & react.RefAttributes<HTMLButtonElement>>;
108
+ Toggle: react.ForwardRefExoticComponent<Omit<ToolbarToggleProps, "ref"> & react.RefAttributes<HTMLButtonElement>>;
109
+ Separator: react.ForwardRefExoticComponent<Omit<react.DetailedHTMLProps<react.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
110
+ SectionHistory: typeof ToolbarSectionHistory;
111
+ SectionInline: typeof ToolbarSectionInline;
112
+ SectionCollaboration: typeof ToolbarSectionCollaboration;
113
+ BlockSelector: react.ForwardRefExoticComponent<Omit<ToolbarBlockSelectorProps, "ref"> & react.RefAttributes<HTMLButtonElement>>;
114
+ };
115
+
116
+ interface FloatingToolbarProps extends Omit<ComponentProps<"div">, "children"> {
117
+ editor: Editor | null;
118
+ position?: FloatingPosition;
119
+ offset?: number;
120
+ children?: ToolbarSlot;
121
+ before?: ToolbarSlot;
122
+ after?: ToolbarSlot;
123
+ }
124
+ declare const FloatingToolbar: react.ForwardRefExoticComponent<Omit<FloatingToolbarProps, "ref"> & react.RefAttributes<HTMLDivElement>> & {
125
+ External: react.ForwardRefExoticComponent<Omit<react.DetailedHTMLProps<react.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
126
+ };
127
+
67
128
  interface HistoryVersionPreviewProps extends ComponentPropsWithoutRef<"div"> {
68
129
  version: HistoryVersion;
69
130
  editor: Editor;
@@ -79,15 +140,8 @@ declare const HistoryVersionPreview: react.ForwardRefExoticComponent<HistoryVers
79
140
 
80
141
  declare module "@tiptap/core" {
81
142
  interface Commands<ReturnType> {
82
- comments: {
83
- /**
84
- * Add a comment
85
- */
86
- addComment: (id: string) => ReturnType;
87
- selectThread: (id: string | null) => ReturnType;
88
- addPendingComment: () => ReturnType;
89
- };
143
+ comments: CommentsCommands<ReturnType>;
90
144
  }
91
145
  }
92
146
 
93
- export { AnchoredThreads, FloatingComposer, FloatingThreads, HistoryVersionPreview, useIsEditorReady, useLiveblocksExtension };
147
+ export { AnchoredThreads, FloatingComposer, FloatingThreads, FloatingToolbar, HistoryVersionPreview, Toolbar, useIsEditorReady, useLiveblocksExtension };
package/dist/index.js CHANGED
@@ -6,6 +6,8 @@ var AnchoredThreads = require('./comments/AnchoredThreads.js');
6
6
  var FloatingComposer = require('./comments/FloatingComposer.js');
7
7
  var FloatingThreads = require('./comments/FloatingThreads.js');
8
8
  var LiveblocksExtension = require('./LiveblocksExtension.js');
9
+ var FloatingToolbar = require('./toolbar/FloatingToolbar.js');
10
+ var Toolbar = require('./toolbar/Toolbar.js');
9
11
  var HistoryVersionPreview = require('./version-history/HistoryVersionPreview.js');
10
12
 
11
13
  core.detectDupes(version.PKG_NAME, version.PKG_VERSION, version.PKG_FORMAT);
@@ -15,5 +17,7 @@ exports.FloatingComposer = FloatingComposer.FloatingComposer;
15
17
  exports.FloatingThreads = FloatingThreads.FloatingThreads;
16
18
  exports.useIsEditorReady = LiveblocksExtension.useIsEditorReady;
17
19
  exports.useLiveblocksExtension = LiveblocksExtension.useLiveblocksExtension;
20
+ exports.FloatingToolbar = FloatingToolbar.FloatingToolbar;
21
+ exports.Toolbar = Toolbar.Toolbar;
18
22
  exports.HistoryVersionPreview = HistoryVersionPreview.HistoryVersionPreview;
19
23
  //# 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 { AnchoredThreads } from \"./comments/AnchoredThreads\";\nexport { FloatingComposer } from \"./comments/FloatingComposer\";\nexport { FloatingThreads } from \"./comments/FloatingThreads\";\nexport { useLiveblocksExtension } from \"./LiveblocksExtension\";\nexport { useIsEditorReady } from \"./LiveblocksExtension\";\nexport { HistoryVersionPreview } from \"./version-history/HistoryVersionPreview\";\n\ndeclare module \"@tiptap/core\" {\n interface Commands<ReturnType> {\n comments: {\n /**\n * Add a comment\n */\n addComment: (id: string) => ReturnType;\n selectThread: (id: string | null) => ReturnType;\n addPendingComment: () => ReturnType;\n };\n }\n}\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 type { CommentsCommands } from \"./types\";\nimport { PKG_FORMAT, PKG_NAME, PKG_VERSION } from \"./version\";\n\ndetectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);\n\nexport { AnchoredThreads } from \"./comments/AnchoredThreads\";\nexport { FloatingComposer } from \"./comments/FloatingComposer\";\nexport { FloatingThreads } from \"./comments/FloatingThreads\";\nexport { useLiveblocksExtension } from \"./LiveblocksExtension\";\nexport { useIsEditorReady } from \"./LiveblocksExtension\";\nexport { FloatingToolbar } from \"./toolbar/FloatingToolbar\";\nexport { Toolbar } from \"./toolbar/Toolbar\";\nexport { HistoryVersionPreview } from \"./version-history/HistoryVersionPreview\";\n\ndeclare module \"@tiptap/core\" {\n interface Commands<ReturnType> {\n comments: CommentsCommands<ReturnType>;\n }\n}\n"],"names":["detectDupes","PKG_NAME","PKG_VERSION","PKG_FORMAT"],"mappings":";;;;;;;;;;;;AAKAA,gBAAY,CAAAC,gBAAA,EAAUC,qBAAaC,kBAAU,CAAA;;;;;;;;;;;"}
package/dist/index.mjs CHANGED
@@ -4,6 +4,8 @@ export { AnchoredThreads } from './comments/AnchoredThreads.mjs';
4
4
  export { FloatingComposer } from './comments/FloatingComposer.mjs';
5
5
  export { FloatingThreads } from './comments/FloatingThreads.mjs';
6
6
  export { useIsEditorReady, useLiveblocksExtension } from './LiveblocksExtension.mjs';
7
+ export { FloatingToolbar } from './toolbar/FloatingToolbar.mjs';
8
+ export { Toolbar } from './toolbar/Toolbar.mjs';
7
9
  export { HistoryVersionPreview } from './version-history/HistoryVersionPreview.mjs';
8
10
 
9
11
  detectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);
@@ -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 { AnchoredThreads } from \"./comments/AnchoredThreads\";\nexport { FloatingComposer } from \"./comments/FloatingComposer\";\nexport { FloatingThreads } from \"./comments/FloatingThreads\";\nexport { useLiveblocksExtension } from \"./LiveblocksExtension\";\nexport { useIsEditorReady } from \"./LiveblocksExtension\";\nexport { HistoryVersionPreview } from \"./version-history/HistoryVersionPreview\";\n\ndeclare module \"@tiptap/core\" {\n interface Commands<ReturnType> {\n comments: {\n /**\n * Add a comment\n */\n addComment: (id: string) => ReturnType;\n selectThread: (id: string | null) => ReturnType;\n addPendingComment: () => ReturnType;\n };\n }\n}\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 type { CommentsCommands } from \"./types\";\nimport { PKG_FORMAT, PKG_NAME, PKG_VERSION } from \"./version\";\n\ndetectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);\n\nexport { AnchoredThreads } from \"./comments/AnchoredThreads\";\nexport { FloatingComposer } from \"./comments/FloatingComposer\";\nexport { FloatingThreads } from \"./comments/FloatingThreads\";\nexport { useLiveblocksExtension } from \"./LiveblocksExtension\";\nexport { useIsEditorReady } from \"./LiveblocksExtension\";\nexport { FloatingToolbar } from \"./toolbar/FloatingToolbar\";\nexport { Toolbar } from \"./toolbar/Toolbar\";\nexport { HistoryVersionPreview } from \"./version-history/HistoryVersionPreview\";\n\ndeclare module \"@tiptap/core\" {\n interface Commands<ReturnType> {\n comments: CommentsCommands<ReturnType>;\n }\n}\n"],"names":[],"mappings":";;;;;;;;;;AAKA,WAAY,CAAA,QAAA,EAAU,aAAa,UAAU,CAAA"}