@liveblocks/react-tiptap 3.18.4 → 3.18.5
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/LiveblocksExtension.cjs +2 -1
- package/dist/LiveblocksExtension.cjs.map +1 -1
- package/dist/LiveblocksExtension.js +2 -1
- package/dist/LiveblocksExtension.js.map +1 -1
- package/dist/ai/AiExtension.cjs.map +1 -1
- package/dist/ai/AiExtension.js.map +1 -1
- package/dist/comments/AnchoredThreads.cjs +12 -7
- package/dist/comments/AnchoredThreads.cjs.map +1 -1
- package/dist/comments/AnchoredThreads.js +12 -7
- package/dist/comments/AnchoredThreads.js.map +1 -1
- package/dist/comments/CommentsExtension.cjs +102 -120
- package/dist/comments/CommentsExtension.cjs.map +1 -1
- package/dist/comments/CommentsExtension.js +103 -120
- package/dist/comments/CommentsExtension.js.map +1 -1
- package/dist/comments/FloatingThreads.cjs +61 -42
- package/dist/comments/FloatingThreads.cjs.map +1 -1
- package/dist/comments/FloatingThreads.js +62 -43
- package/dist/comments/FloatingThreads.js.map +1 -1
- package/dist/types.cjs +1 -1
- package/dist/types.cjs.map +1 -1
- package/dist/types.js +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils.cjs +19 -0
- package/dist/utils.cjs.map +1 -1
- package/dist/utils.js +18 -1
- package/dist/utils.js.map +1 -1
- package/dist/version.cjs +1 -1
- package/dist/version.js +1 -1
- package/package.json +6 -6
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { jsx } from 'react/jsx-runtime';
|
|
2
2
|
import { useFloating, flip, offset, hide, shift, limitShift, size, autoUpdate } from '@floating-ui/react-dom';
|
|
3
|
+
import { shallow } from '@liveblocks/core';
|
|
3
4
|
import { useLayoutEffect } from '@liveblocks/react/_private';
|
|
4
5
|
import { Thread } from '@liveblocks/react-ui';
|
|
5
6
|
import { useStableComponent, Portal, cn } from '@liveblocks/react-ui/_private';
|
|
6
7
|
import { useEditorState } from '@tiptap/react';
|
|
7
|
-
import { useState,
|
|
8
|
+
import { useState, useCallback, useEffect } from 'react';
|
|
8
9
|
import { THREADS_PLUGIN_KEY } from '../types.js';
|
|
10
|
+
import { compareDocumentPosition } from '../utils.js';
|
|
9
11
|
|
|
10
12
|
function FloatingThreads({
|
|
11
13
|
threads,
|
|
@@ -14,57 +16,84 @@ function FloatingThreads({
|
|
|
14
16
|
...props
|
|
15
17
|
}) {
|
|
16
18
|
const Thread$1 = useStableComponent(components?.Thread, Thread);
|
|
17
|
-
const
|
|
19
|
+
const activeThreadIds = useEditorState({
|
|
18
20
|
editor,
|
|
19
21
|
selector: (ctx) => {
|
|
20
|
-
if (!ctx?.editor?.state)
|
|
22
|
+
if (!ctx?.editor?.state) {
|
|
23
|
+
return void 0;
|
|
24
|
+
}
|
|
21
25
|
const state = THREADS_PLUGIN_KEY.getState(ctx.editor.state);
|
|
22
|
-
return
|
|
23
|
-
pluginState: state
|
|
24
|
-
};
|
|
26
|
+
return state?.activeThreadIds;
|
|
25
27
|
},
|
|
26
28
|
equalityFn: (prev, next) => {
|
|
27
29
|
if (!prev || !next) return false;
|
|
28
|
-
return prev
|
|
30
|
+
return shallow(prev, next);
|
|
29
31
|
}
|
|
30
|
-
}) ??
|
|
31
|
-
const [
|
|
32
|
-
|
|
33
|
-
if (!editor || !
|
|
34
|
-
|
|
32
|
+
}) ?? void 0;
|
|
33
|
+
const [range, setRange] = useState(null);
|
|
34
|
+
const handleUpdateRange = useCallback(() => {
|
|
35
|
+
if (!editor || !editor.view || editor.view.isDestroyed || !activeThreadIds) {
|
|
36
|
+
setRange(null);
|
|
35
37
|
return;
|
|
36
38
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
setActiveThread(null);
|
|
39
|
+
if (activeThreadIds.length === 0) {
|
|
40
|
+
setRange(null);
|
|
40
41
|
return;
|
|
41
42
|
}
|
|
42
|
-
const
|
|
43
|
-
(thread) =>
|
|
43
|
+
const activeThreads = (threads ?? []).filter(
|
|
44
|
+
(thread) => activeThreadIds.includes(thread.id) && !thread.resolved
|
|
44
45
|
);
|
|
45
|
-
|
|
46
|
-
|
|
46
|
+
if (activeThreads.length === 0) {
|
|
47
|
+
setRange(null);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const elements = /* @__PURE__ */ new Set();
|
|
51
|
+
for (const id of activeThreadIds) {
|
|
52
|
+
const els = editor.view.dom.querySelectorAll(
|
|
53
|
+
`span.lb-tiptap-thread-mark[data-lb-thread-id="${id}"]`
|
|
54
|
+
);
|
|
55
|
+
els.forEach((el) => elements.add(el));
|
|
56
|
+
}
|
|
57
|
+
const sorted = Array.from(elements).sort(compareDocumentPosition);
|
|
58
|
+
if (sorted.length === 0) {
|
|
59
|
+
setRange(null);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const domRange = document.createRange();
|
|
63
|
+
domRange.setStartBefore(sorted[0]);
|
|
64
|
+
domRange.setEndAfter(sorted[sorted.length - 1]);
|
|
65
|
+
setRange({ range: domRange, threads: activeThreads });
|
|
66
|
+
}, [editor, activeThreadIds, threads]);
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
if (!editor) return;
|
|
69
|
+
editor.on("transaction", handleUpdateRange);
|
|
70
|
+
return () => {
|
|
71
|
+
editor.off("transaction", handleUpdateRange);
|
|
72
|
+
};
|
|
73
|
+
}, [editor, handleUpdateRange]);
|
|
74
|
+
useLayoutEffect(handleUpdateRange, [handleUpdateRange]);
|
|
47
75
|
const handleEscapeKeydown = useCallback(() => {
|
|
48
|
-
if (!editor ||
|
|
76
|
+
if (!editor || range === null) return false;
|
|
49
77
|
editor.commands.selectThread(null);
|
|
50
78
|
return true;
|
|
51
|
-
}, [
|
|
52
|
-
if (
|
|
53
|
-
|
|
79
|
+
}, [editor, range]);
|
|
80
|
+
if (range === null) {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
return /* @__PURE__ */ jsx(FloatingThreadPortal, { range: range.range, ...props, children: range.threads.map((thread) => /* @__PURE__ */ jsx(
|
|
54
84
|
ThreadWrapper,
|
|
55
85
|
{
|
|
56
|
-
thread
|
|
86
|
+
thread,
|
|
57
87
|
Thread: Thread$1,
|
|
58
88
|
onEscapeKeydown: handleEscapeKeydown,
|
|
59
89
|
className: "lb-tiptap-floating-threads-thread"
|
|
60
90
|
},
|
|
61
|
-
|
|
62
|
-
) });
|
|
91
|
+
thread.id
|
|
92
|
+
)) });
|
|
63
93
|
}
|
|
64
94
|
const FLOATING_THREAD_COLLISION_PADDING = 10;
|
|
65
95
|
function FloatingThreadPortal({
|
|
66
|
-
|
|
67
|
-
thread,
|
|
96
|
+
range,
|
|
68
97
|
children,
|
|
69
98
|
className,
|
|
70
99
|
style,
|
|
@@ -106,21 +135,11 @@ function FloatingThreadPortal({
|
|
|
106
135
|
});
|
|
107
136
|
}
|
|
108
137
|
});
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
);
|
|
113
|
-
|
|
114
|
-
setReference(el);
|
|
115
|
-
}
|
|
116
|
-
}, [setReference, editor, thread.id]);
|
|
117
|
-
useEffect(() => {
|
|
118
|
-
editor.on("transaction", updateRef);
|
|
119
|
-
return () => {
|
|
120
|
-
editor.off("transaction", updateRef);
|
|
121
|
-
};
|
|
122
|
-
}, [editor, updateRef]);
|
|
123
|
-
useLayoutEffect(updateRef, [updateRef]);
|
|
138
|
+
useLayoutEffect(() => {
|
|
139
|
+
setReference({
|
|
140
|
+
getBoundingClientRect: () => range.getBoundingClientRect()
|
|
141
|
+
});
|
|
142
|
+
}, [setReference, range]);
|
|
124
143
|
return /* @__PURE__ */ jsx(Portal, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
125
144
|
"div",
|
|
126
145
|
{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FloatingThreads.js","sources":["../../src/comments/FloatingThreads.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, DCM, DTM, ThreadData } from \"@liveblocks/core\";\nimport { useLayoutEffect } from \"@liveblocks/react/_private\";\nimport {\n Thread as DefaultThread,\n type ThreadProps,\n} from \"@liveblocks/react-ui\";\nimport { cn, Portal, useStableComponent } from \"@liveblocks/react-ui/_private\";\nimport { type Editor, useEditorState } from \"@tiptap/react\";\nimport {\n type ComponentType,\n type HTMLAttributes,\n type KeyboardEvent,\n type ReactNode,\n useCallback,\n useEffect,\n useState,\n} from \"react\";\n\nimport { THREADS_PLUGIN_KEY } from \"../types\";\n\ntype FloatingThreadsComponents = {\n Thread: ComponentType<ThreadProps>;\n};\n\nexport interface FloatingThreadsProps<\n TM extends BaseMetadata = DTM,\n CM extends BaseMetadata = DCM,\n> extends Omit<HTMLAttributes<HTMLDivElement>, \"children\"> {\n /**\n * The threads to display.\n */\n threads: ThreadData<TM, CM>[];\n\n /**\n * Override the component's components.\n */\n components?: Partial<FloatingThreadsComponents>;\n\n /**\n * The Tiptap editor.\n */\n editor: Editor | null;\n}\n\nexport function FloatingThreads({\n threads,\n components,\n editor,\n ...props\n}: FloatingThreadsProps) {\n const Thread = useStableComponent(components?.Thread, DefaultThread);\n\n const { pluginState } = useEditorState({\n editor,\n selector: (ctx) => {\n if (!ctx?.editor?.state) return { pluginState: undefined };\n const state = THREADS_PLUGIN_KEY.getState(ctx.editor.state);\n return {\n pluginState: state,\n };\n },\n equalityFn: (prev, next) => {\n if (!prev || !next) return false;\n return (\n prev.pluginState?.selectedThreadPos ===\n next.pluginState?.selectedThreadPos &&\n prev.pluginState?.selectedThreadId ===\n next.pluginState?.selectedThreadId\n );\n },\n }) ?? { pluginState: undefined };\n\n const [activeThread, setActiveThread] = useState<ThreadData | null>(null);\n\n useEffect(() => {\n if (!editor || !pluginState) {\n setActiveThread(null);\n return;\n }\n const { selectedThreadId, selectedThreadPos } = pluginState;\n if (selectedThreadId === null || selectedThreadPos === null) {\n setActiveThread(null);\n return;\n }\n const active = (threads ?? []).find(\n (thread) => selectedThreadId === thread.id\n );\n setActiveThread(active ?? null);\n }, [editor, pluginState, threads]);\n\n const handleEscapeKeydown = useCallback((): boolean => {\n if (!editor || activeThread === null) return false;\n editor.commands.selectThread(null);\n return true;\n }, [activeThread, editor]);\n\n if (!activeThread || !editor || activeThread.resolved) return null;\n\n return (\n <FloatingThreadPortal thread={activeThread} editor={editor} {...props}>\n {activeThread && (\n <ThreadWrapper\n key={activeThread.id}\n thread={activeThread}\n Thread={Thread}\n onEscapeKeydown={handleEscapeKeydown}\n className=\"lb-tiptap-floating-threads-thread\"\n />\n )}\n </FloatingThreadPortal>\n );\n}\n\ninterface FloatingThreadPortalProps extends Omit<\n HTMLAttributes<HTMLDivElement>,\n \"children\"\n> {\n thread: ThreadData;\n editor: Editor;\n children: ReactNode;\n}\n\nexport const FLOATING_THREAD_COLLISION_PADDING = 10;\n\nfunction FloatingThreadPortal({\n editor,\n thread,\n children,\n className,\n style,\n ...props\n}: FloatingThreadPortalProps) {\n const {\n refs: { setReference, setFloating },\n strategy,\n x,\n y,\n } = useFloating({\n strategy: \"absolute\",\n placement: \"bottom\",\n middleware: [\n flip({ padding: FLOATING_THREAD_COLLISION_PADDING, crossAxis: false }),\n offset(10),\n hide({ padding: FLOATING_THREAD_COLLISION_PADDING }),\n shift({\n padding: FLOATING_THREAD_COLLISION_PADDING,\n limiter: limitShift(),\n }),\n size({\n padding: FLOATING_THREAD_COLLISION_PADDING,\n apply({ availableWidth, availableHeight, elements }) {\n elements.floating.style.setProperty(\n \"--lb-tiptap-floating-threads-available-width\",\n `${availableWidth}px`\n );\n elements.floating.style.setProperty(\n \"--lb-tiptap-floating-threads-available-height\",\n `${availableHeight}px`\n );\n },\n }),\n ],\n whileElementsMounted: (...args) => {\n return autoUpdate(...args, {\n animationFrame: true,\n });\n },\n });\n\n const updateRef = useCallback(() => {\n const el = editor.view.dom.querySelector(\n `[data-lb-thread-id=\"${thread.id}\"]`\n );\n if (el) {\n setReference(el);\n }\n }, [setReference, editor, thread.id]);\n\n // Remote cursor updates and other edits can cause the ref to break\n useEffect(() => {\n editor.on(\"transaction\", updateRef);\n return () => {\n editor.off(\"transaction\", updateRef);\n };\n }, [editor, updateRef]);\n\n useLayoutEffect(updateRef, [updateRef]);\n\n return (\n <Portal asChild>\n <div\n ref={setFloating}\n {...props}\n style={{\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 className={cn(\n \"lb-root lb-portal lb-elevation lb-tiptap-floating lb-tiptap-floating-threads\",\n className\n )}\n >\n {children}\n </div>\n </Portal>\n );\n}\n\ninterface ThreadWrapperProps extends ThreadProps {\n thread: ThreadData;\n Thread: ComponentType<ThreadProps>;\n onEscapeKeydown: () => void;\n}\n\nfunction ThreadWrapper({\n thread,\n Thread,\n onEscapeKeydown,\n onKeyDown,\n ...threadProps\n}: ThreadWrapperProps) {\n const handleKeyDown = useCallback(\n (event: KeyboardEvent<HTMLDivElement>) => {\n onKeyDown?.(event);\n\n // TODO: Add ability to preventDefault on keydown to override the default behavior, e.g. to show an alert dialog\n if (event.key === \"Escape\") {\n onEscapeKeydown();\n }\n },\n [onEscapeKeydown, onKeyDown]\n );\n\n return <Thread thread={thread} onKeyDown={handleKeyDown} {...threadProps} />;\n}\n"],"names":["Thread","DefaultThread"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"FloatingThreads.js","sources":["../../src/comments/FloatingThreads.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 {\n type BaseMetadata,\n type DCM,\n type DTM,\n shallow,\n type ThreadData,\n} from \"@liveblocks/core\";\nimport { useLayoutEffect } from \"@liveblocks/react/_private\";\nimport {\n Thread as DefaultThread,\n type ThreadProps,\n} from \"@liveblocks/react-ui\";\nimport { cn, Portal, useStableComponent } from \"@liveblocks/react-ui/_private\";\nimport { type Editor, useEditorState } from \"@tiptap/react\";\nimport {\n type ComponentType,\n type HTMLAttributes,\n type KeyboardEvent,\n type ReactNode,\n useCallback,\n useEffect,\n useState,\n} from \"react\";\n\nimport { THREADS_PLUGIN_KEY } from \"../types\";\nimport { compareDocumentPosition } from \"../utils\";\n\ntype FloatingThreadsComponents = {\n Thread: ComponentType<ThreadProps>;\n};\n\nexport interface FloatingThreadsProps<\n TM extends BaseMetadata = DTM,\n CM extends BaseMetadata = DCM,\n> extends Omit<HTMLAttributes<HTMLDivElement>, \"children\"> {\n /**\n * The threads to display.\n */\n threads: ThreadData<TM, CM>[];\n\n /**\n * Override the component's components.\n */\n components?: Partial<FloatingThreadsComponents>;\n\n /**\n * The Tiptap editor.\n */\n editor: Editor | null;\n}\n\nexport function FloatingThreads({\n threads,\n components,\n editor,\n ...props\n}: FloatingThreadsProps) {\n const Thread = useStableComponent(components?.Thread, DefaultThread);\n\n const activeThreadIds =\n useEditorState({\n editor,\n selector: (ctx) => {\n if (!ctx?.editor?.state) {\n return undefined;\n }\n\n const state = THREADS_PLUGIN_KEY.getState(ctx.editor.state);\n\n return state?.activeThreadIds;\n },\n equalityFn: (prev, next) => {\n if (!prev || !next) return false;\n return shallow(prev, next);\n },\n }) ?? undefined;\n\n const [range, setRange] = useState<{\n range: Range;\n threads: ThreadData[];\n } | null>(null);\n\n const handleUpdateRange = useCallback(() => {\n if (\n !editor ||\n !editor.view ||\n editor.view.isDestroyed ||\n !activeThreadIds\n ) {\n setRange(null);\n return;\n }\n\n if (activeThreadIds.length === 0) {\n setRange(null);\n return;\n }\n\n const activeThreads = (threads ?? []).filter(\n (thread) => activeThreadIds.includes(thread.id) && !thread.resolved\n );\n if (activeThreads.length === 0) {\n setRange(null);\n return;\n }\n\n // A thread mark can be split across multiple DOM elements (e.g. when\n // overlapping with another mark), so we collect every matching element and\n // build a DOM range spanning from the first to the last one.\n const elements = new Set<HTMLElement>();\n for (const id of activeThreadIds) {\n const els = editor.view.dom.querySelectorAll<HTMLElement>(\n `span.lb-tiptap-thread-mark[data-lb-thread-id=\"${id}\"]`\n );\n els.forEach((el) => elements.add(el));\n }\n\n const sorted = Array.from(elements).sort(compareDocumentPosition);\n if (sorted.length === 0) {\n setRange(null);\n return;\n }\n\n const domRange = document.createRange();\n domRange.setStartBefore(sorted[0]);\n domRange.setEndAfter(sorted[sorted.length - 1]);\n setRange({ range: domRange, threads: activeThreads });\n }, [editor, activeThreadIds, threads]);\n\n // Remote cursor updates and other edits can shift the underlying DOM\n // elements, so we recompute the range on every change.\n useEffect(() => {\n if (!editor) return;\n editor.on(\"transaction\", handleUpdateRange);\n return () => {\n editor.off(\"transaction\", handleUpdateRange);\n };\n }, [editor, handleUpdateRange]);\n\n useLayoutEffect(handleUpdateRange, [handleUpdateRange]);\n\n const handleEscapeKeydown = useCallback((): boolean => {\n if (!editor || range === null) return false;\n editor.commands.selectThread(null);\n return true;\n }, [editor, range]);\n\n if (range === null) {\n return null;\n }\n\n return (\n <FloatingThreadPortal range={range.range} {...props}>\n {range.threads.map((thread) => (\n <ThreadWrapper\n key={thread.id}\n thread={thread}\n Thread={Thread}\n onEscapeKeydown={handleEscapeKeydown}\n className=\"lb-tiptap-floating-threads-thread\"\n />\n ))}\n </FloatingThreadPortal>\n );\n}\n\ninterface FloatingThreadPortalProps extends Omit<\n HTMLAttributes<HTMLDivElement>,\n \"children\"\n> {\n range: Range;\n children: ReactNode;\n}\n\nexport const FLOATING_THREAD_COLLISION_PADDING = 10;\n\nfunction FloatingThreadPortal({\n range,\n children,\n className,\n style,\n ...props\n}: FloatingThreadPortalProps) {\n const {\n refs: { setReference, setFloating },\n strategy,\n x,\n y,\n } = useFloating({\n strategy: \"absolute\",\n placement: \"bottom\",\n middleware: [\n flip({ padding: FLOATING_THREAD_COLLISION_PADDING, crossAxis: false }),\n offset(10),\n hide({ padding: FLOATING_THREAD_COLLISION_PADDING }),\n shift({\n padding: FLOATING_THREAD_COLLISION_PADDING,\n limiter: limitShift(),\n }),\n size({\n padding: FLOATING_THREAD_COLLISION_PADDING,\n apply({ availableWidth, availableHeight, elements }) {\n elements.floating.style.setProperty(\n \"--lb-tiptap-floating-threads-available-width\",\n `${availableWidth}px`\n );\n elements.floating.style.setProperty(\n \"--lb-tiptap-floating-threads-available-height\",\n `${availableHeight}px`\n );\n },\n }),\n ],\n whileElementsMounted: (...args) => {\n return autoUpdate(...args, {\n animationFrame: true,\n });\n },\n });\n\n useLayoutEffect(() => {\n setReference({\n getBoundingClientRect: () => range.getBoundingClientRect(),\n });\n }, [setReference, range]);\n\n return (\n <Portal asChild>\n <div\n ref={setFloating}\n {...props}\n style={{\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 className={cn(\n \"lb-root lb-portal lb-elevation lb-tiptap-floating lb-tiptap-floating-threads\",\n className\n )}\n >\n {children}\n </div>\n </Portal>\n );\n}\n\ninterface ThreadWrapperProps extends ThreadProps {\n thread: ThreadData;\n Thread: ComponentType<ThreadProps>;\n onEscapeKeydown: () => void;\n}\n\nfunction ThreadWrapper({\n thread,\n Thread,\n onEscapeKeydown,\n onKeyDown,\n ...threadProps\n}: ThreadWrapperProps) {\n const handleKeyDown = useCallback(\n (event: KeyboardEvent<HTMLDivElement>) => {\n onKeyDown?.(event);\n\n // TODO: Add ability to preventDefault on keydown to override the default behavior, e.g. to show an alert dialog\n if (event.key === \"Escape\") {\n onEscapeKeydown();\n }\n },\n [onEscapeKeydown, onKeyDown]\n );\n\n return <Thread thread={thread} onKeyDown={handleKeyDown} {...threadProps} />;\n}\n"],"names":["Thread","DefaultThread"],"mappings":"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"}
|
package/dist/types.cjs
CHANGED
|
@@ -23,7 +23,7 @@ const AI_TOOLBAR_SELECTION_PLUGIN = new state.PluginKey(
|
|
|
23
23
|
);
|
|
24
24
|
const LIVEBLOCKS_COMMENT_MARK_TYPE = "liveblocksCommentMark";
|
|
25
25
|
var ThreadPluginActions = /* @__PURE__ */ ((ThreadPluginActions2) => {
|
|
26
|
-
ThreadPluginActions2["
|
|
26
|
+
ThreadPluginActions2["SET_ACTIVE_THREAD_IDS"] = "SET_ACTIVE_THREAD_IDS";
|
|
27
27
|
return ThreadPluginActions2;
|
|
28
28
|
})(ThreadPluginActions || {});
|
|
29
29
|
|
package/dist/types.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.cjs","sources":["../src/types.ts"],"sourcesContent":["import type {\n ContextualPromptContext,\n ContextualPromptResponse,\n MentionData,\n Relax,\n TextEditorType,\n ThreadData,\n} from \"@liveblocks/core\";\nimport type { LiveblocksYjsProvider } from \"@liveblocks/yjs\";\nimport type { Content, Range } from \"@tiptap/core\";\nimport { PluginKey } from \"@tiptap/pm/state\";\nimport type { DecorationSet } from \"@tiptap/pm/view\";\nimport type { ChainedCommands, SingleCommands } from \"@tiptap/react\";\nimport type { ProsemirrorBinding } from \"y-prosemirror\";\nimport type { Doc, PermanentUserData, Snapshot } from \"yjs\";\n\nexport const LIVEBLOCKS_MENTION_KEY = new PluginKey(\"lb-plugin-mention\");\nexport const LIVEBLOCKS_MENTION_PASTE_KEY = new PluginKey(\n \"lb-plugin-mention-paste\"\n);\nexport const LIVEBLOCKS_MENTION_NOTIFIER_KEY = new PluginKey(\n \"lb-plugin-mention-notify\"\n);\n\nexport const LIVEBLOCKS_MENTION_EXTENSION = \"liveblocksMentionExt\";\nexport const LIVEBLOCKS_MENTION_TYPE = \"liveblocksMention\";\nexport const LIVEBLOCKS_GROUP_MENTION_TYPE = \"liveblocksGroupMention\";\n\nexport const THREADS_ACTIVE_SELECTION_PLUGIN = new PluginKey(\n \"lb-threads-active-selection-plugin\"\n);\nexport const THREADS_PLUGIN_KEY = new PluginKey<ThreadPluginState>(\n \"lb-threads-plugin\"\n);\nexport const AI_TOOLBAR_SELECTION_PLUGIN = new PluginKey(\n \"lb-ai-toolbar-selection-plugin\"\n);\n\nexport const LIVEBLOCKS_COMMENT_MARK_TYPE = \"liveblocksCommentMark\";\n\n/**\n * @beta\n */\nexport type ResolveContextualPromptArgs = {\n /**\n * The prompt being requested by the user.\n */\n prompt: string;\n\n /**\n * The context of the document and its current selection.\n */\n context: ContextualPromptContext;\n\n /**\n * The previous request and its response, if this is a follow-up request.\n */\n previous?: {\n prompt: string;\n response: ContextualPromptResponse;\n };\n\n /**\n * An abort signal that can be used to cancel requests.\n */\n signal: AbortSignal;\n};\n\n/**\n * @beta\n */\nexport type ResolveContextualPromptResponse = ContextualPromptResponse;\n\nexport interface AiConfiguration {\n /**\n * The AI's name. (\"Ask {name} anything…\", \"{name} is thinking…\", etc)\n */\n name?: string;\n\n /**\n * A function that returns an a response to a contextual prompt.\n */\n resolveContextualPrompt?: (\n args: ResolveContextualPromptArgs\n ) => Promise<ContextualPromptResponse>;\n}\n\nexport type LiveblocksExtensionOptions = {\n field?: string;\n comments?: boolean; // | CommentsConfiguration\n mentions?: boolean; // | MentionsConfiguration\n ai?: boolean | AiConfiguration;\n offlineSupport_experimental?: boolean;\n threads_experimental?: ThreadData[];\n initialContent?: Content;\n enablePermanentUserData?: boolean;\n /**\n * @internal\n * For reporting another text editor type from a\n * text editor extended from `TipTap` such as our `BlockNote` integration.\n *\n * Only useful for Liveblocks developers, not for end users.\n */\n textEditorType?: TextEditorType;\n};\n\nexport type LiveblocksExtensionStorage = {\n unsubs: (() => void)[];\n doc: Doc;\n provider: LiveblocksYjsProvider;\n permanentUserData?: PermanentUserData;\n};\n\nexport type CommentsExtensionStorage = {\n pendingComment: boolean;\n};\n\nexport const enum ThreadPluginActions {\n SET_SELECTED_THREAD_ID = \"SET_SELECTED_THREAD_ID\",\n}\n\nexport type AiExtensionOptions = Required<\n Pick<AiConfiguration, \"name\" | \"resolveContextualPrompt\">\n> & {\n doc: Doc | undefined;\n pud: PermanentUserData | undefined;\n};\n\n/**\n * The state of the AI toolbar.\n *\n * ┌────────────────────────────────────────────────────────────────────────────────┐\n * │ │\n * │ ┌──────────────────────────────────────────────┐ │\n * ▼ ▼ │ │\n * ┌───────$closeAiToolbar()───────┐ │ │\n * ▼ ◇ ◇ ◇\n * ┌───────────────────────┐ ┌───────────────────────┐ ┌───────────────────────┐ ┌───────────────────────┐\n * │ CLOSED │ │ ASKING │ │ THINKING │ │ REVIEWING │\n * └───────────────────────┘ └───────────────────────┘ └───────────────────────┘ └───────────────────────┘\n * ▲ ◇ ◇ ▲ ▲ ◇ ▲ ▲ ◇ ▲ ◇ ◇\n * │ │ └───$openAiToolbarAsking()──┘ │ │ └ ─ ─ ─ ─ ─ ─⚠─ ─ ─ ─ ─ ─ ─│─├── ─ ─ ─ ─ ─ ─✓─ ─ ─ ─ ─ ─ ─ ┘ │ │\n * │ │ │ ▼ │ │ │ │\n * │ └─────────────────$startAiToolbarThinking(prompt)──────────────┘ │ │ │\n * │ │ ▲ │ │ │\n * │ │ └──────────────────────────────┼───────────────────────────────┘ │\n * │ │ │ │\n * │ └───$cancelAiToolbarThinking()───┘ │\n * │ │\n * └─────────────────────────────────────$acceptAiToolbarResponse()─────────────────────────────────────┘\n *\n */\nexport type AiToolbarState = Relax<\n | {\n phase: \"closed\";\n }\n | {\n phase: \"asking\";\n\n /**\n * The selection stored when opening the AI toolbar.\n */\n initialSelection: Range;\n\n /**\n * The custom prompt being written in the toolbar.\n */\n customPrompt: string;\n\n /**\n * A potential error that occurred during the last AI request.\n */\n error?: Error;\n }\n | {\n phase: \"thinking\";\n\n /**\n * The selection stored when opening the AI toolbar.\n */\n initialSelection: Range;\n\n /**\n * The custom prompt being written in the toolbar.\n */\n customPrompt: string;\n\n /**\n * An abort controller to cancel the AI request.\n */\n abortController: AbortController;\n\n /**\n * The prompt sent to the AI.\n */\n prompt: string;\n\n /**\n * The previous response if this \"thinking\" phase is a refinement.\n */\n previousResponse?: ContextualPromptResponse;\n }\n | {\n phase: \"reviewing\";\n\n /**\n * The selection stored when opening the AI toolbar.\n */\n initialSelection: Range;\n\n /**\n * The custom prompt being written in the toolbar.\n */\n customPrompt: string;\n\n /**\n * The prompt sent to the AI.\n */\n prompt: string;\n\n /**\n * The response of the AI request.\n */\n response: ContextualPromptResponse;\n }\n>;\n\nexport type AiExtensionStorage = {\n name: string;\n state: AiToolbarState;\n snapshot?: Snapshot;\n};\n\ndeclare module \"@tiptap/core\" {\n interface Storage {\n liveblocksAi: AiExtensionStorage;\n liveblocksExtension: LiveblocksExtensionStorage;\n liveblocksComments: CommentsExtensionStorage;\n }\n // TODO: this is already defined in collaboration-caret, we shouldn't need it, but something isn't working\n // maybe because we use configure?\n interface Commands<ReturnType> {\n collaborationCaret: {\n /**\n * Update details of the current user\n * @example editor.commands.updateUser({ name: 'John Doe', color: '#305500' })\n */\n updateUser: (attributes: Record<string, any>) => ReturnType;\n /**\n * Update details of the current user\n *\n * @deprecated The \"user\" command is deprecated. Please use \"updateUser\" instead. Read more: https://tiptap.dev/api/extensions/collaboration-caret\n */\n user: (attributes: Record<string, any>) => ReturnType;\n };\n\n collaboration: {\n /**\n * Undo recent changes\n * @example editor.commands.undo()\n */\n undo: () => ReturnType;\n /**\n * Reapply reverted changes\n * @example editor.commands.redo()\n */\n redo: () => ReturnType;\n };\n }\n}\nexport type ThreadPluginState = {\n threadPositions: Map<string, { from: number; to: number }>;\n selectedThreadId: string | null;\n selectedThreadPos: number | null;\n decorations: DecorationSet;\n};\n\nexport type FloatingPosition = \"top\" | \"bottom\";\n\nexport type ExtendedCommands<\n T extends string,\n A extends any[] = [],\n> = SingleCommands & Record<T, (...args: A) => boolean>;\n\nexport type ExtendedChainedCommands<\n T extends string,\n A extends any[] = [],\n> = ChainedCommands & Record<T, (...args: A) => ChainedCommands>;\n\nexport type ChainedAiCommands = ChainedCommands & {\n [K in keyof AiCommands]: (\n ...args: Parameters<AiCommands[K]>\n ) => ChainedCommands;\n};\n\nexport type CommentsCommands<ReturnType = boolean> = {\n /**\n * Add a comment\n */\n addComment: (id: string) => ReturnType;\n selectThread: (id: string | null) => ReturnType;\n addPendingComment: () => ReturnType;\n\n /** @internal */\n closePendingComment: () => ReturnType;\n};\n\nexport type AiCommands<ReturnType = boolean> = {\n /**\n * Open the AI toolbar, with an optional prompt.\n */\n askAi: (prompt?: string) => ReturnType;\n\n /**\n * Close the AI toolbar.\n */\n closeAi: () => ReturnType;\n\n // Transitions (see AiToolbarState)\n\n /**\n * @internal\n * @transition\n *\n * Close the AI toolbar.\n */\n $closeAiToolbar: () => ReturnType;\n\n /**\n * @internal\n * @transition\n *\n * Accept the current AI response and close the AI toolbar.\n */\n $acceptAiToolbarResponse: () => ReturnType;\n\n /**\n * @internal\n * @transition\n *\n * Open the AI toolbar in the \"asking\" phase.\n */\n $openAiToolbarAsking: () => ReturnType;\n\n /**\n * @internal\n * @transition\n *\n * Set (and open if not already open) the AI toolbar in the \"thinking\" phase with the given prompt.\n */\n $startAiToolbarThinking: (\n prompt: string,\n withPreviousResponse?: boolean\n ) => ReturnType;\n\n /**\n * @internal\n * @transition\n *\n * Cancel the current \"thinking\" phase, going back to the \"asking\" phase.\n */\n $cancelAiToolbarThinking: () => ReturnType;\n\n // Other\n\n /**\n * @internal\n *\n * Show the diff of the current \"reviewing\" phase.\n */\n _showAiToolbarReviewingDiff: () => ReturnType;\n\n /**\n * @internal\n *\n * Handle the success of the current \"thinking\" phase.\n */\n _handleAiToolbarThinkingSuccess: (\n response: ContextualPromptResponse\n ) => ReturnType;\n\n /**\n * @internal\n *\n * Handle an error of the current \"thinking\" phase.\n */\n _handleAiToolbarThinkingError: (error: unknown) => ReturnType;\n\n /**\n * @internal\n *\n * Update the current custom AI prompt.\n */\n _updateAiToolbarCustomPrompt: (\n customPrompt: string | ((currentCustomPrompt: string) => string)\n ) => ReturnType;\n};\n\nexport type YSyncPluginState = {\n binding: ProsemirrorBinding;\n};\n\nexport type TiptapMentionData = MentionData & {\n notificationId: string;\n};\n\nexport type SerializedTiptapMentionData = TiptapMentionData extends infer T\n ? T extends { kind: \"group\" }\n ? Omit<T, \"userIds\"> & { userIds?: string }\n : T\n : never;\n"],"names":["PluginKey","ThreadPluginActions"],"mappings":";;;;AAgBa,MAAA,sBAAA,GAAyB,IAAIA,eAAA,CAAU,mBAAmB,EAAA;AAChE,MAAM,+BAA+B,IAAIA,eAAA;AAAA,EAC9C,yBAAA;AACF,EAAA;AACO,MAAM,kCAAkC,IAAIA,eAAA;AAAA,EACjD,0BAAA;AACF,EAAA;AAEO,MAAM,4BAA+B,GAAA,uBAAA;AACrC,MAAM,uBAA0B,GAAA,oBAAA;AAChC,MAAM,6BAAgC,GAAA,yBAAA;AAEtC,MAAM,kCAAkC,IAAIA,eAAA;AAAA,EACjD,oCAAA;AACF,EAAA;AACO,MAAM,qBAAqB,IAAIA,eAAA;AAAA,EACpC,mBAAA;AACF,EAAA;AACO,MAAM,8BAA8B,IAAIA,eAAA;AAAA,EAC7C,gCAAA;AACF,EAAA;AAEO,MAAM,4BAA+B,GAAA,wBAAA;AA+E1B,IAAA,mBAAA,qBAAAC,oBAAX,KAAA;AACL,EAAAA,qBAAA,wBAAyB,CAAA,GAAA,wBAAA,CAAA;AADT,EAAAA,OAAAA,oBAAAA,CAAAA;AAAA,CAAA,EAAA,mBAAA,IAAA,EAAA;;;;;;;;;;;;;;"}
|
|
1
|
+
{"version":3,"file":"types.cjs","sources":["../src/types.ts"],"sourcesContent":["import type {\n ContextualPromptContext,\n ContextualPromptResponse,\n MentionData,\n Relax,\n TextEditorType,\n ThreadData,\n} from \"@liveblocks/core\";\nimport type { LiveblocksYjsProvider } from \"@liveblocks/yjs\";\nimport type { Content, Range } from \"@tiptap/core\";\nimport { PluginKey } from \"@tiptap/pm/state\";\nimport type { DecorationSet } from \"@tiptap/pm/view\";\nimport type { ChainedCommands, SingleCommands } from \"@tiptap/react\";\nimport type { ProsemirrorBinding } from \"y-prosemirror\";\nimport type { Doc, PermanentUserData, Snapshot } from \"yjs\";\n\nexport const LIVEBLOCKS_MENTION_KEY = new PluginKey(\"lb-plugin-mention\");\nexport const LIVEBLOCKS_MENTION_PASTE_KEY = new PluginKey(\n \"lb-plugin-mention-paste\"\n);\nexport const LIVEBLOCKS_MENTION_NOTIFIER_KEY = new PluginKey(\n \"lb-plugin-mention-notify\"\n);\n\nexport const LIVEBLOCKS_MENTION_EXTENSION = \"liveblocksMentionExt\";\nexport const LIVEBLOCKS_MENTION_TYPE = \"liveblocksMention\";\nexport const LIVEBLOCKS_GROUP_MENTION_TYPE = \"liveblocksGroupMention\";\n\nexport const THREADS_ACTIVE_SELECTION_PLUGIN = new PluginKey(\n \"lb-threads-active-selection-plugin\"\n);\nexport const THREADS_PLUGIN_KEY = new PluginKey<ThreadPluginState>(\n \"lb-threads-plugin\"\n);\nexport const AI_TOOLBAR_SELECTION_PLUGIN = new PluginKey(\n \"lb-ai-toolbar-selection-plugin\"\n);\n\nexport const LIVEBLOCKS_COMMENT_MARK_TYPE = \"liveblocksCommentMark\";\n\n/**\n * @beta\n */\nexport type ResolveContextualPromptArgs = {\n /**\n * The prompt being requested by the user.\n */\n prompt: string;\n\n /**\n * The context of the document and its current selection.\n */\n context: ContextualPromptContext;\n\n /**\n * The previous request and its response, if this is a follow-up request.\n */\n previous?: {\n prompt: string;\n response: ContextualPromptResponse;\n };\n\n /**\n * An abort signal that can be used to cancel requests.\n */\n signal: AbortSignal;\n};\n\n/**\n * @beta\n */\nexport type ResolveContextualPromptResponse = ContextualPromptResponse;\n\nexport interface AiConfiguration {\n /**\n * The AI's name. (\"Ask {name} anything…\", \"{name} is thinking…\", etc)\n */\n name?: string;\n\n /**\n * A function that returns an a response to a contextual prompt.\n */\n resolveContextualPrompt?: (\n args: ResolveContextualPromptArgs\n ) => Promise<ContextualPromptResponse>;\n}\n\nexport type LiveblocksExtensionOptions = {\n field?: string;\n comments?: boolean; // | CommentsConfiguration\n mentions?: boolean; // | MentionsConfiguration\n ai?: boolean | AiConfiguration;\n offlineSupport_experimental?: boolean;\n threads_experimental?: ThreadData[];\n initialContent?: Content;\n enablePermanentUserData?: boolean;\n /**\n * @internal\n * For reporting another text editor type from a\n * text editor extended from `TipTap` such as our `BlockNote` integration.\n *\n * Only useful for Liveblocks developers, not for end users.\n */\n textEditorType?: TextEditorType;\n};\n\nexport type LiveblocksExtensionStorage = {\n unsubs: (() => void)[];\n doc: Doc;\n provider: LiveblocksYjsProvider;\n permanentUserData?: PermanentUserData;\n};\n\nexport type CommentsExtensionStorage = {\n pendingComment: boolean;\n};\n\nexport const enum ThreadPluginActions {\n SET_ACTIVE_THREAD_IDS = \"SET_ACTIVE_THREAD_IDS\",\n}\n\nexport type AiExtensionOptions = Required<\n Pick<AiConfiguration, \"name\" | \"resolveContextualPrompt\">\n> & {\n doc: Doc | undefined;\n pud: PermanentUserData | undefined;\n};\n\n/**\n * The state of the AI toolbar.\n *\n * ┌────────────────────────────────────────────────────────────────────────────────┐\n * │ │\n * │ ┌──────────────────────────────────────────────┐ │\n * ▼ ▼ │ │\n * ┌───────$closeAiToolbar()───────┐ │ │\n * ▼ ◇ ◇ ◇\n * ┌───────────────────────┐ ┌───────────────────────┐ ┌───────────────────────┐ ┌───────────────────────┐\n * │ CLOSED │ │ ASKING │ │ THINKING │ │ REVIEWING │\n * └───────────────────────┘ └───────────────────────┘ └───────────────────────┘ └───────────────────────┘\n * ▲ ◇ ◇ ▲ ▲ ◇ ▲ ▲ ◇ ▲ ◇ ◇\n * │ │ └───$openAiToolbarAsking()──┘ │ │ └ ─ ─ ─ ─ ─ ─⚠─ ─ ─ ─ ─ ─ ─│─├── ─ ─ ─ ─ ─ ─✓─ ─ ─ ─ ─ ─ ─ ┘ │ │\n * │ │ │ ▼ │ │ │ │\n * │ └─────────────────$startAiToolbarThinking(prompt)──────────────┘ │ │ │\n * │ │ ▲ │ │ │\n * │ │ └──────────────────────────────┼───────────────────────────────┘ │\n * │ │ │ │\n * │ └───$cancelAiToolbarThinking()───┘ │\n * │ │\n * └─────────────────────────────────────$acceptAiToolbarResponse()─────────────────────────────────────┘\n *\n */\nexport type AiToolbarState = Relax<\n | {\n phase: \"closed\";\n }\n | {\n phase: \"asking\";\n\n /**\n * The selection stored when opening the AI toolbar.\n */\n initialSelection: Range;\n\n /**\n * The custom prompt being written in the toolbar.\n */\n customPrompt: string;\n\n /**\n * A potential error that occurred during the last AI request.\n */\n error?: Error;\n }\n | {\n phase: \"thinking\";\n\n /**\n * The selection stored when opening the AI toolbar.\n */\n initialSelection: Range;\n\n /**\n * The custom prompt being written in the toolbar.\n */\n customPrompt: string;\n\n /**\n * An abort controller to cancel the AI request.\n */\n abortController: AbortController;\n\n /**\n * The prompt sent to the AI.\n */\n prompt: string;\n\n /**\n * The previous response if this \"thinking\" phase is a refinement.\n */\n previousResponse?: ContextualPromptResponse;\n }\n | {\n phase: \"reviewing\";\n\n /**\n * The selection stored when opening the AI toolbar.\n */\n initialSelection: Range;\n\n /**\n * The custom prompt being written in the toolbar.\n */\n customPrompt: string;\n\n /**\n * The prompt sent to the AI.\n */\n prompt: string;\n\n /**\n * The response of the AI request.\n */\n response: ContextualPromptResponse;\n }\n>;\n\nexport type AiExtensionStorage = {\n name: string;\n state: AiToolbarState;\n snapshot?: Snapshot;\n};\n\ndeclare module \"@tiptap/core\" {\n interface Storage {\n liveblocksAi: AiExtensionStorage;\n liveblocksExtension: LiveblocksExtensionStorage;\n liveblocksComments: CommentsExtensionStorage;\n }\n // TODO: this is already defined in collaboration-caret, we shouldn't need it, but something isn't working\n // maybe because we use configure?\n interface Commands<ReturnType> {\n collaborationCaret: {\n /**\n * Update details of the current user\n * @example editor.commands.updateUser({ name: 'John Doe', color: '#305500' })\n */\n updateUser: (attributes: Record<string, any>) => ReturnType;\n /**\n * Update details of the current user\n *\n * @deprecated The \"user\" command is deprecated. Please use \"updateUser\" instead. Read more: https://tiptap.dev/api/extensions/collaboration-caret\n */\n user: (attributes: Record<string, any>) => ReturnType;\n };\n\n collaboration: {\n /**\n * Undo recent changes\n * @example editor.commands.undo()\n */\n undo: () => ReturnType;\n /**\n * Reapply reverted changes\n * @example editor.commands.redo()\n */\n redo: () => ReturnType;\n };\n }\n}\nexport type ThreadPluginState = {\n threadPositions: Map<string, { from: number; to: number }>;\n activeThreadIds: string[];\n decorations: DecorationSet;\n};\n\nexport type FloatingPosition = \"top\" | \"bottom\";\n\nexport type ExtendedCommands<\n T extends string,\n A extends any[] = [],\n> = SingleCommands & Record<T, (...args: A) => boolean>;\n\nexport type ExtendedChainedCommands<\n T extends string,\n A extends any[] = [],\n> = ChainedCommands & Record<T, (...args: A) => ChainedCommands>;\n\nexport type ChainedAiCommands = ChainedCommands & {\n [K in keyof AiCommands]: (\n ...args: Parameters<AiCommands[K]>\n ) => ChainedCommands;\n};\n\nexport type CommentsCommands<ReturnType = boolean> = {\n /**\n * Add a comment\n */\n addComment: (id: string) => ReturnType;\n selectThread: (id: string | null) => ReturnType;\n addPendingComment: () => ReturnType;\n\n /** @internal */\n closePendingComment: () => ReturnType;\n};\n\nexport type AiCommands<ReturnType = boolean> = {\n /**\n * Open the AI toolbar, with an optional prompt.\n */\n askAi: (prompt?: string) => ReturnType;\n\n /**\n * Close the AI toolbar.\n */\n closeAi: () => ReturnType;\n\n // Transitions (see AiToolbarState)\n\n /**\n * @internal\n * @transition\n *\n * Close the AI toolbar.\n */\n $closeAiToolbar: () => ReturnType;\n\n /**\n * @internal\n * @transition\n *\n * Accept the current AI response and close the AI toolbar.\n */\n $acceptAiToolbarResponse: () => ReturnType;\n\n /**\n * @internal\n * @transition\n *\n * Open the AI toolbar in the \"asking\" phase.\n */\n $openAiToolbarAsking: () => ReturnType;\n\n /**\n * @internal\n * @transition\n *\n * Set (and open if not already open) the AI toolbar in the \"thinking\" phase with the given prompt.\n */\n $startAiToolbarThinking: (\n prompt: string,\n withPreviousResponse?: boolean\n ) => ReturnType;\n\n /**\n * @internal\n * @transition\n *\n * Cancel the current \"thinking\" phase, going back to the \"asking\" phase.\n */\n $cancelAiToolbarThinking: () => ReturnType;\n\n // Other\n\n /**\n * @internal\n *\n * Show the diff of the current \"reviewing\" phase.\n */\n _showAiToolbarReviewingDiff: () => ReturnType;\n\n /**\n * @internal\n *\n * Handle the success of the current \"thinking\" phase.\n */\n _handleAiToolbarThinkingSuccess: (\n response: ContextualPromptResponse\n ) => ReturnType;\n\n /**\n * @internal\n *\n * Handle an error of the current \"thinking\" phase.\n */\n _handleAiToolbarThinkingError: (error: unknown) => ReturnType;\n\n /**\n * @internal\n *\n * Update the current custom AI prompt.\n */\n _updateAiToolbarCustomPrompt: (\n customPrompt: string | ((currentCustomPrompt: string) => string)\n ) => ReturnType;\n};\n\nexport type YSyncPluginState = {\n binding: ProsemirrorBinding;\n};\n\nexport type TiptapMentionData = MentionData & {\n notificationId: string;\n};\n\nexport type SerializedTiptapMentionData = TiptapMentionData extends infer T\n ? T extends { kind: \"group\" }\n ? Omit<T, \"userIds\"> & { userIds?: string }\n : T\n : never;\n"],"names":["PluginKey","ThreadPluginActions"],"mappings":";;;;AAgBa,MAAA,sBAAA,GAAyB,IAAIA,eAAA,CAAU,mBAAmB,EAAA;AAChE,MAAM,+BAA+B,IAAIA,eAAA;AAAA,EAC9C,yBAAA;AACF,EAAA;AACO,MAAM,kCAAkC,IAAIA,eAAA;AAAA,EACjD,0BAAA;AACF,EAAA;AAEO,MAAM,4BAA+B,GAAA,uBAAA;AACrC,MAAM,uBAA0B,GAAA,oBAAA;AAChC,MAAM,6BAAgC,GAAA,yBAAA;AAEtC,MAAM,kCAAkC,IAAIA,eAAA;AAAA,EACjD,oCAAA;AACF,EAAA;AACO,MAAM,qBAAqB,IAAIA,eAAA;AAAA,EACpC,mBAAA;AACF,EAAA;AACO,MAAM,8BAA8B,IAAIA,eAAA;AAAA,EAC7C,gCAAA;AACF,EAAA;AAEO,MAAM,4BAA+B,GAAA,wBAAA;AA+E1B,IAAA,mBAAA,qBAAAC,oBAAX,KAAA;AACL,EAAAA,qBAAA,uBAAwB,CAAA,GAAA,uBAAA,CAAA;AADR,EAAAA,OAAAA,oBAAAA,CAAAA;AAAA,CAAA,EAAA,mBAAA,IAAA,EAAA;;;;;;;;;;;;;;"}
|
package/dist/types.js
CHANGED
|
@@ -21,7 +21,7 @@ const AI_TOOLBAR_SELECTION_PLUGIN = new PluginKey(
|
|
|
21
21
|
);
|
|
22
22
|
const LIVEBLOCKS_COMMENT_MARK_TYPE = "liveblocksCommentMark";
|
|
23
23
|
var ThreadPluginActions = /* @__PURE__ */ ((ThreadPluginActions2) => {
|
|
24
|
-
ThreadPluginActions2["
|
|
24
|
+
ThreadPluginActions2["SET_ACTIVE_THREAD_IDS"] = "SET_ACTIVE_THREAD_IDS";
|
|
25
25
|
return ThreadPluginActions2;
|
|
26
26
|
})(ThreadPluginActions || {});
|
|
27
27
|
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sources":["../src/types.ts"],"sourcesContent":["import type {\n ContextualPromptContext,\n ContextualPromptResponse,\n MentionData,\n Relax,\n TextEditorType,\n ThreadData,\n} from \"@liveblocks/core\";\nimport type { LiveblocksYjsProvider } from \"@liveblocks/yjs\";\nimport type { Content, Range } from \"@tiptap/core\";\nimport { PluginKey } from \"@tiptap/pm/state\";\nimport type { DecorationSet } from \"@tiptap/pm/view\";\nimport type { ChainedCommands, SingleCommands } from \"@tiptap/react\";\nimport type { ProsemirrorBinding } from \"y-prosemirror\";\nimport type { Doc, PermanentUserData, Snapshot } from \"yjs\";\n\nexport const LIVEBLOCKS_MENTION_KEY = new PluginKey(\"lb-plugin-mention\");\nexport const LIVEBLOCKS_MENTION_PASTE_KEY = new PluginKey(\n \"lb-plugin-mention-paste\"\n);\nexport const LIVEBLOCKS_MENTION_NOTIFIER_KEY = new PluginKey(\n \"lb-plugin-mention-notify\"\n);\n\nexport const LIVEBLOCKS_MENTION_EXTENSION = \"liveblocksMentionExt\";\nexport const LIVEBLOCKS_MENTION_TYPE = \"liveblocksMention\";\nexport const LIVEBLOCKS_GROUP_MENTION_TYPE = \"liveblocksGroupMention\";\n\nexport const THREADS_ACTIVE_SELECTION_PLUGIN = new PluginKey(\n \"lb-threads-active-selection-plugin\"\n);\nexport const THREADS_PLUGIN_KEY = new PluginKey<ThreadPluginState>(\n \"lb-threads-plugin\"\n);\nexport const AI_TOOLBAR_SELECTION_PLUGIN = new PluginKey(\n \"lb-ai-toolbar-selection-plugin\"\n);\n\nexport const LIVEBLOCKS_COMMENT_MARK_TYPE = \"liveblocksCommentMark\";\n\n/**\n * @beta\n */\nexport type ResolveContextualPromptArgs = {\n /**\n * The prompt being requested by the user.\n */\n prompt: string;\n\n /**\n * The context of the document and its current selection.\n */\n context: ContextualPromptContext;\n\n /**\n * The previous request and its response, if this is a follow-up request.\n */\n previous?: {\n prompt: string;\n response: ContextualPromptResponse;\n };\n\n /**\n * An abort signal that can be used to cancel requests.\n */\n signal: AbortSignal;\n};\n\n/**\n * @beta\n */\nexport type ResolveContextualPromptResponse = ContextualPromptResponse;\n\nexport interface AiConfiguration {\n /**\n * The AI's name. (\"Ask {name} anything…\", \"{name} is thinking…\", etc)\n */\n name?: string;\n\n /**\n * A function that returns an a response to a contextual prompt.\n */\n resolveContextualPrompt?: (\n args: ResolveContextualPromptArgs\n ) => Promise<ContextualPromptResponse>;\n}\n\nexport type LiveblocksExtensionOptions = {\n field?: string;\n comments?: boolean; // | CommentsConfiguration\n mentions?: boolean; // | MentionsConfiguration\n ai?: boolean | AiConfiguration;\n offlineSupport_experimental?: boolean;\n threads_experimental?: ThreadData[];\n initialContent?: Content;\n enablePermanentUserData?: boolean;\n /**\n * @internal\n * For reporting another text editor type from a\n * text editor extended from `TipTap` such as our `BlockNote` integration.\n *\n * Only useful for Liveblocks developers, not for end users.\n */\n textEditorType?: TextEditorType;\n};\n\nexport type LiveblocksExtensionStorage = {\n unsubs: (() => void)[];\n doc: Doc;\n provider: LiveblocksYjsProvider;\n permanentUserData?: PermanentUserData;\n};\n\nexport type CommentsExtensionStorage = {\n pendingComment: boolean;\n};\n\nexport const enum ThreadPluginActions {\n SET_SELECTED_THREAD_ID = \"SET_SELECTED_THREAD_ID\",\n}\n\nexport type AiExtensionOptions = Required<\n Pick<AiConfiguration, \"name\" | \"resolveContextualPrompt\">\n> & {\n doc: Doc | undefined;\n pud: PermanentUserData | undefined;\n};\n\n/**\n * The state of the AI toolbar.\n *\n * ┌────────────────────────────────────────────────────────────────────────────────┐\n * │ │\n * │ ┌──────────────────────────────────────────────┐ │\n * ▼ ▼ │ │\n * ┌───────$closeAiToolbar()───────┐ │ │\n * ▼ ◇ ◇ ◇\n * ┌───────────────────────┐ ┌───────────────────────┐ ┌───────────────────────┐ ┌───────────────────────┐\n * │ CLOSED │ │ ASKING │ │ THINKING │ │ REVIEWING │\n * └───────────────────────┘ └───────────────────────┘ └───────────────────────┘ └───────────────────────┘\n * ▲ ◇ ◇ ▲ ▲ ◇ ▲ ▲ ◇ ▲ ◇ ◇\n * │ │ └───$openAiToolbarAsking()──┘ │ │ └ ─ ─ ─ ─ ─ ─⚠─ ─ ─ ─ ─ ─ ─│─├── ─ ─ ─ ─ ─ ─✓─ ─ ─ ─ ─ ─ ─ ┘ │ │\n * │ │ │ ▼ │ │ │ │\n * │ └─────────────────$startAiToolbarThinking(prompt)──────────────┘ │ │ │\n * │ │ ▲ │ │ │\n * │ │ └──────────────────────────────┼───────────────────────────────┘ │\n * │ │ │ │\n * │ └───$cancelAiToolbarThinking()───┘ │\n * │ │\n * └─────────────────────────────────────$acceptAiToolbarResponse()─────────────────────────────────────┘\n *\n */\nexport type AiToolbarState = Relax<\n | {\n phase: \"closed\";\n }\n | {\n phase: \"asking\";\n\n /**\n * The selection stored when opening the AI toolbar.\n */\n initialSelection: Range;\n\n /**\n * The custom prompt being written in the toolbar.\n */\n customPrompt: string;\n\n /**\n * A potential error that occurred during the last AI request.\n */\n error?: Error;\n }\n | {\n phase: \"thinking\";\n\n /**\n * The selection stored when opening the AI toolbar.\n */\n initialSelection: Range;\n\n /**\n * The custom prompt being written in the toolbar.\n */\n customPrompt: string;\n\n /**\n * An abort controller to cancel the AI request.\n */\n abortController: AbortController;\n\n /**\n * The prompt sent to the AI.\n */\n prompt: string;\n\n /**\n * The previous response if this \"thinking\" phase is a refinement.\n */\n previousResponse?: ContextualPromptResponse;\n }\n | {\n phase: \"reviewing\";\n\n /**\n * The selection stored when opening the AI toolbar.\n */\n initialSelection: Range;\n\n /**\n * The custom prompt being written in the toolbar.\n */\n customPrompt: string;\n\n /**\n * The prompt sent to the AI.\n */\n prompt: string;\n\n /**\n * The response of the AI request.\n */\n response: ContextualPromptResponse;\n }\n>;\n\nexport type AiExtensionStorage = {\n name: string;\n state: AiToolbarState;\n snapshot?: Snapshot;\n};\n\ndeclare module \"@tiptap/core\" {\n interface Storage {\n liveblocksAi: AiExtensionStorage;\n liveblocksExtension: LiveblocksExtensionStorage;\n liveblocksComments: CommentsExtensionStorage;\n }\n // TODO: this is already defined in collaboration-caret, we shouldn't need it, but something isn't working\n // maybe because we use configure?\n interface Commands<ReturnType> {\n collaborationCaret: {\n /**\n * Update details of the current user\n * @example editor.commands.updateUser({ name: 'John Doe', color: '#305500' })\n */\n updateUser: (attributes: Record<string, any>) => ReturnType;\n /**\n * Update details of the current user\n *\n * @deprecated The \"user\" command is deprecated. Please use \"updateUser\" instead. Read more: https://tiptap.dev/api/extensions/collaboration-caret\n */\n user: (attributes: Record<string, any>) => ReturnType;\n };\n\n collaboration: {\n /**\n * Undo recent changes\n * @example editor.commands.undo()\n */\n undo: () => ReturnType;\n /**\n * Reapply reverted changes\n * @example editor.commands.redo()\n */\n redo: () => ReturnType;\n };\n }\n}\nexport type ThreadPluginState = {\n threadPositions: Map<string, { from: number; to: number }>;\n selectedThreadId: string | null;\n selectedThreadPos: number | null;\n decorations: DecorationSet;\n};\n\nexport type FloatingPosition = \"top\" | \"bottom\";\n\nexport type ExtendedCommands<\n T extends string,\n A extends any[] = [],\n> = SingleCommands & Record<T, (...args: A) => boolean>;\n\nexport type ExtendedChainedCommands<\n T extends string,\n A extends any[] = [],\n> = ChainedCommands & Record<T, (...args: A) => ChainedCommands>;\n\nexport type ChainedAiCommands = ChainedCommands & {\n [K in keyof AiCommands]: (\n ...args: Parameters<AiCommands[K]>\n ) => ChainedCommands;\n};\n\nexport type CommentsCommands<ReturnType = boolean> = {\n /**\n * Add a comment\n */\n addComment: (id: string) => ReturnType;\n selectThread: (id: string | null) => ReturnType;\n addPendingComment: () => ReturnType;\n\n /** @internal */\n closePendingComment: () => ReturnType;\n};\n\nexport type AiCommands<ReturnType = boolean> = {\n /**\n * Open the AI toolbar, with an optional prompt.\n */\n askAi: (prompt?: string) => ReturnType;\n\n /**\n * Close the AI toolbar.\n */\n closeAi: () => ReturnType;\n\n // Transitions (see AiToolbarState)\n\n /**\n * @internal\n * @transition\n *\n * Close the AI toolbar.\n */\n $closeAiToolbar: () => ReturnType;\n\n /**\n * @internal\n * @transition\n *\n * Accept the current AI response and close the AI toolbar.\n */\n $acceptAiToolbarResponse: () => ReturnType;\n\n /**\n * @internal\n * @transition\n *\n * Open the AI toolbar in the \"asking\" phase.\n */\n $openAiToolbarAsking: () => ReturnType;\n\n /**\n * @internal\n * @transition\n *\n * Set (and open if not already open) the AI toolbar in the \"thinking\" phase with the given prompt.\n */\n $startAiToolbarThinking: (\n prompt: string,\n withPreviousResponse?: boolean\n ) => ReturnType;\n\n /**\n * @internal\n * @transition\n *\n * Cancel the current \"thinking\" phase, going back to the \"asking\" phase.\n */\n $cancelAiToolbarThinking: () => ReturnType;\n\n // Other\n\n /**\n * @internal\n *\n * Show the diff of the current \"reviewing\" phase.\n */\n _showAiToolbarReviewingDiff: () => ReturnType;\n\n /**\n * @internal\n *\n * Handle the success of the current \"thinking\" phase.\n */\n _handleAiToolbarThinkingSuccess: (\n response: ContextualPromptResponse\n ) => ReturnType;\n\n /**\n * @internal\n *\n * Handle an error of the current \"thinking\" phase.\n */\n _handleAiToolbarThinkingError: (error: unknown) => ReturnType;\n\n /**\n * @internal\n *\n * Update the current custom AI prompt.\n */\n _updateAiToolbarCustomPrompt: (\n customPrompt: string | ((currentCustomPrompt: string) => string)\n ) => ReturnType;\n};\n\nexport type YSyncPluginState = {\n binding: ProsemirrorBinding;\n};\n\nexport type TiptapMentionData = MentionData & {\n notificationId: string;\n};\n\nexport type SerializedTiptapMentionData = TiptapMentionData extends infer T\n ? T extends { kind: \"group\" }\n ? Omit<T, \"userIds\"> & { userIds?: string }\n : T\n : never;\n"],"names":["ThreadPluginActions"],"mappings":";;AAgBa,MAAA,sBAAA,GAAyB,IAAI,SAAA,CAAU,mBAAmB,EAAA;AAChE,MAAM,+BAA+B,IAAI,SAAA;AAAA,EAC9C,yBAAA;AACF,EAAA;AACO,MAAM,kCAAkC,IAAI,SAAA;AAAA,EACjD,0BAAA;AACF,EAAA;AAEO,MAAM,4BAA+B,GAAA,uBAAA;AACrC,MAAM,uBAA0B,GAAA,oBAAA;AAChC,MAAM,6BAAgC,GAAA,yBAAA;AAEtC,MAAM,kCAAkC,IAAI,SAAA;AAAA,EACjD,oCAAA;AACF,EAAA;AACO,MAAM,qBAAqB,IAAI,SAAA;AAAA,EACpC,mBAAA;AACF,EAAA;AACO,MAAM,8BAA8B,IAAI,SAAA;AAAA,EAC7C,gCAAA;AACF,EAAA;AAEO,MAAM,4BAA+B,GAAA,wBAAA;AA+E1B,IAAA,mBAAA,qBAAAA,oBAAX,KAAA;AACL,EAAAA,qBAAA,wBAAyB,CAAA,GAAA,wBAAA,CAAA;AADT,EAAAA,OAAAA,oBAAAA,CAAAA;AAAA,CAAA,EAAA,mBAAA,IAAA,EAAA;;;;"}
|
|
1
|
+
{"version":3,"file":"types.js","sources":["../src/types.ts"],"sourcesContent":["import type {\n ContextualPromptContext,\n ContextualPromptResponse,\n MentionData,\n Relax,\n TextEditorType,\n ThreadData,\n} from \"@liveblocks/core\";\nimport type { LiveblocksYjsProvider } from \"@liveblocks/yjs\";\nimport type { Content, Range } from \"@tiptap/core\";\nimport { PluginKey } from \"@tiptap/pm/state\";\nimport type { DecorationSet } from \"@tiptap/pm/view\";\nimport type { ChainedCommands, SingleCommands } from \"@tiptap/react\";\nimport type { ProsemirrorBinding } from \"y-prosemirror\";\nimport type { Doc, PermanentUserData, Snapshot } from \"yjs\";\n\nexport const LIVEBLOCKS_MENTION_KEY = new PluginKey(\"lb-plugin-mention\");\nexport const LIVEBLOCKS_MENTION_PASTE_KEY = new PluginKey(\n \"lb-plugin-mention-paste\"\n);\nexport const LIVEBLOCKS_MENTION_NOTIFIER_KEY = new PluginKey(\n \"lb-plugin-mention-notify\"\n);\n\nexport const LIVEBLOCKS_MENTION_EXTENSION = \"liveblocksMentionExt\";\nexport const LIVEBLOCKS_MENTION_TYPE = \"liveblocksMention\";\nexport const LIVEBLOCKS_GROUP_MENTION_TYPE = \"liveblocksGroupMention\";\n\nexport const THREADS_ACTIVE_SELECTION_PLUGIN = new PluginKey(\n \"lb-threads-active-selection-plugin\"\n);\nexport const THREADS_PLUGIN_KEY = new PluginKey<ThreadPluginState>(\n \"lb-threads-plugin\"\n);\nexport const AI_TOOLBAR_SELECTION_PLUGIN = new PluginKey(\n \"lb-ai-toolbar-selection-plugin\"\n);\n\nexport const LIVEBLOCKS_COMMENT_MARK_TYPE = \"liveblocksCommentMark\";\n\n/**\n * @beta\n */\nexport type ResolveContextualPromptArgs = {\n /**\n * The prompt being requested by the user.\n */\n prompt: string;\n\n /**\n * The context of the document and its current selection.\n */\n context: ContextualPromptContext;\n\n /**\n * The previous request and its response, if this is a follow-up request.\n */\n previous?: {\n prompt: string;\n response: ContextualPromptResponse;\n };\n\n /**\n * An abort signal that can be used to cancel requests.\n */\n signal: AbortSignal;\n};\n\n/**\n * @beta\n */\nexport type ResolveContextualPromptResponse = ContextualPromptResponse;\n\nexport interface AiConfiguration {\n /**\n * The AI's name. (\"Ask {name} anything…\", \"{name} is thinking…\", etc)\n */\n name?: string;\n\n /**\n * A function that returns an a response to a contextual prompt.\n */\n resolveContextualPrompt?: (\n args: ResolveContextualPromptArgs\n ) => Promise<ContextualPromptResponse>;\n}\n\nexport type LiveblocksExtensionOptions = {\n field?: string;\n comments?: boolean; // | CommentsConfiguration\n mentions?: boolean; // | MentionsConfiguration\n ai?: boolean | AiConfiguration;\n offlineSupport_experimental?: boolean;\n threads_experimental?: ThreadData[];\n initialContent?: Content;\n enablePermanentUserData?: boolean;\n /**\n * @internal\n * For reporting another text editor type from a\n * text editor extended from `TipTap` such as our `BlockNote` integration.\n *\n * Only useful for Liveblocks developers, not for end users.\n */\n textEditorType?: TextEditorType;\n};\n\nexport type LiveblocksExtensionStorage = {\n unsubs: (() => void)[];\n doc: Doc;\n provider: LiveblocksYjsProvider;\n permanentUserData?: PermanentUserData;\n};\n\nexport type CommentsExtensionStorage = {\n pendingComment: boolean;\n};\n\nexport const enum ThreadPluginActions {\n SET_ACTIVE_THREAD_IDS = \"SET_ACTIVE_THREAD_IDS\",\n}\n\nexport type AiExtensionOptions = Required<\n Pick<AiConfiguration, \"name\" | \"resolveContextualPrompt\">\n> & {\n doc: Doc | undefined;\n pud: PermanentUserData | undefined;\n};\n\n/**\n * The state of the AI toolbar.\n *\n * ┌────────────────────────────────────────────────────────────────────────────────┐\n * │ │\n * │ ┌──────────────────────────────────────────────┐ │\n * ▼ ▼ │ │\n * ┌───────$closeAiToolbar()───────┐ │ │\n * ▼ ◇ ◇ ◇\n * ┌───────────────────────┐ ┌───────────────────────┐ ┌───────────────────────┐ ┌───────────────────────┐\n * │ CLOSED │ │ ASKING │ │ THINKING │ │ REVIEWING │\n * └───────────────────────┘ └───────────────────────┘ └───────────────────────┘ └───────────────────────┘\n * ▲ ◇ ◇ ▲ ▲ ◇ ▲ ▲ ◇ ▲ ◇ ◇\n * │ │ └───$openAiToolbarAsking()──┘ │ │ └ ─ ─ ─ ─ ─ ─⚠─ ─ ─ ─ ─ ─ ─│─├── ─ ─ ─ ─ ─ ─✓─ ─ ─ ─ ─ ─ ─ ┘ │ │\n * │ │ │ ▼ │ │ │ │\n * │ └─────────────────$startAiToolbarThinking(prompt)──────────────┘ │ │ │\n * │ │ ▲ │ │ │\n * │ │ └──────────────────────────────┼───────────────────────────────┘ │\n * │ │ │ │\n * │ └───$cancelAiToolbarThinking()───┘ │\n * │ │\n * └─────────────────────────────────────$acceptAiToolbarResponse()─────────────────────────────────────┘\n *\n */\nexport type AiToolbarState = Relax<\n | {\n phase: \"closed\";\n }\n | {\n phase: \"asking\";\n\n /**\n * The selection stored when opening the AI toolbar.\n */\n initialSelection: Range;\n\n /**\n * The custom prompt being written in the toolbar.\n */\n customPrompt: string;\n\n /**\n * A potential error that occurred during the last AI request.\n */\n error?: Error;\n }\n | {\n phase: \"thinking\";\n\n /**\n * The selection stored when opening the AI toolbar.\n */\n initialSelection: Range;\n\n /**\n * The custom prompt being written in the toolbar.\n */\n customPrompt: string;\n\n /**\n * An abort controller to cancel the AI request.\n */\n abortController: AbortController;\n\n /**\n * The prompt sent to the AI.\n */\n prompt: string;\n\n /**\n * The previous response if this \"thinking\" phase is a refinement.\n */\n previousResponse?: ContextualPromptResponse;\n }\n | {\n phase: \"reviewing\";\n\n /**\n * The selection stored when opening the AI toolbar.\n */\n initialSelection: Range;\n\n /**\n * The custom prompt being written in the toolbar.\n */\n customPrompt: string;\n\n /**\n * The prompt sent to the AI.\n */\n prompt: string;\n\n /**\n * The response of the AI request.\n */\n response: ContextualPromptResponse;\n }\n>;\n\nexport type AiExtensionStorage = {\n name: string;\n state: AiToolbarState;\n snapshot?: Snapshot;\n};\n\ndeclare module \"@tiptap/core\" {\n interface Storage {\n liveblocksAi: AiExtensionStorage;\n liveblocksExtension: LiveblocksExtensionStorage;\n liveblocksComments: CommentsExtensionStorage;\n }\n // TODO: this is already defined in collaboration-caret, we shouldn't need it, but something isn't working\n // maybe because we use configure?\n interface Commands<ReturnType> {\n collaborationCaret: {\n /**\n * Update details of the current user\n * @example editor.commands.updateUser({ name: 'John Doe', color: '#305500' })\n */\n updateUser: (attributes: Record<string, any>) => ReturnType;\n /**\n * Update details of the current user\n *\n * @deprecated The \"user\" command is deprecated. Please use \"updateUser\" instead. Read more: https://tiptap.dev/api/extensions/collaboration-caret\n */\n user: (attributes: Record<string, any>) => ReturnType;\n };\n\n collaboration: {\n /**\n * Undo recent changes\n * @example editor.commands.undo()\n */\n undo: () => ReturnType;\n /**\n * Reapply reverted changes\n * @example editor.commands.redo()\n */\n redo: () => ReturnType;\n };\n }\n}\nexport type ThreadPluginState = {\n threadPositions: Map<string, { from: number; to: number }>;\n activeThreadIds: string[];\n decorations: DecorationSet;\n};\n\nexport type FloatingPosition = \"top\" | \"bottom\";\n\nexport type ExtendedCommands<\n T extends string,\n A extends any[] = [],\n> = SingleCommands & Record<T, (...args: A) => boolean>;\n\nexport type ExtendedChainedCommands<\n T extends string,\n A extends any[] = [],\n> = ChainedCommands & Record<T, (...args: A) => ChainedCommands>;\n\nexport type ChainedAiCommands = ChainedCommands & {\n [K in keyof AiCommands]: (\n ...args: Parameters<AiCommands[K]>\n ) => ChainedCommands;\n};\n\nexport type CommentsCommands<ReturnType = boolean> = {\n /**\n * Add a comment\n */\n addComment: (id: string) => ReturnType;\n selectThread: (id: string | null) => ReturnType;\n addPendingComment: () => ReturnType;\n\n /** @internal */\n closePendingComment: () => ReturnType;\n};\n\nexport type AiCommands<ReturnType = boolean> = {\n /**\n * Open the AI toolbar, with an optional prompt.\n */\n askAi: (prompt?: string) => ReturnType;\n\n /**\n * Close the AI toolbar.\n */\n closeAi: () => ReturnType;\n\n // Transitions (see AiToolbarState)\n\n /**\n * @internal\n * @transition\n *\n * Close the AI toolbar.\n */\n $closeAiToolbar: () => ReturnType;\n\n /**\n * @internal\n * @transition\n *\n * Accept the current AI response and close the AI toolbar.\n */\n $acceptAiToolbarResponse: () => ReturnType;\n\n /**\n * @internal\n * @transition\n *\n * Open the AI toolbar in the \"asking\" phase.\n */\n $openAiToolbarAsking: () => ReturnType;\n\n /**\n * @internal\n * @transition\n *\n * Set (and open if not already open) the AI toolbar in the \"thinking\" phase with the given prompt.\n */\n $startAiToolbarThinking: (\n prompt: string,\n withPreviousResponse?: boolean\n ) => ReturnType;\n\n /**\n * @internal\n * @transition\n *\n * Cancel the current \"thinking\" phase, going back to the \"asking\" phase.\n */\n $cancelAiToolbarThinking: () => ReturnType;\n\n // Other\n\n /**\n * @internal\n *\n * Show the diff of the current \"reviewing\" phase.\n */\n _showAiToolbarReviewingDiff: () => ReturnType;\n\n /**\n * @internal\n *\n * Handle the success of the current \"thinking\" phase.\n */\n _handleAiToolbarThinkingSuccess: (\n response: ContextualPromptResponse\n ) => ReturnType;\n\n /**\n * @internal\n *\n * Handle an error of the current \"thinking\" phase.\n */\n _handleAiToolbarThinkingError: (error: unknown) => ReturnType;\n\n /**\n * @internal\n *\n * Update the current custom AI prompt.\n */\n _updateAiToolbarCustomPrompt: (\n customPrompt: string | ((currentCustomPrompt: string) => string)\n ) => ReturnType;\n};\n\nexport type YSyncPluginState = {\n binding: ProsemirrorBinding;\n};\n\nexport type TiptapMentionData = MentionData & {\n notificationId: string;\n};\n\nexport type SerializedTiptapMentionData = TiptapMentionData extends infer T\n ? T extends { kind: \"group\" }\n ? Omit<T, \"userIds\"> & { userIds?: string }\n : T\n : never;\n"],"names":["ThreadPluginActions"],"mappings":";;AAgBa,MAAA,sBAAA,GAAyB,IAAI,SAAA,CAAU,mBAAmB,EAAA;AAChE,MAAM,+BAA+B,IAAI,SAAA;AAAA,EAC9C,yBAAA;AACF,EAAA;AACO,MAAM,kCAAkC,IAAI,SAAA;AAAA,EACjD,0BAAA;AACF,EAAA;AAEO,MAAM,4BAA+B,GAAA,uBAAA;AACrC,MAAM,uBAA0B,GAAA,oBAAA;AAChC,MAAM,6BAAgC,GAAA,yBAAA;AAEtC,MAAM,kCAAkC,IAAI,SAAA;AAAA,EACjD,oCAAA;AACF,EAAA;AACO,MAAM,qBAAqB,IAAI,SAAA;AAAA,EACpC,mBAAA;AACF,EAAA;AACO,MAAM,8BAA8B,IAAI,SAAA;AAAA,EAC7C,gCAAA;AACF,EAAA;AAEO,MAAM,4BAA+B,GAAA,wBAAA;AA+E1B,IAAA,mBAAA,qBAAAA,oBAAX,KAAA;AACL,EAAAA,qBAAA,uBAAwB,CAAA,GAAA,uBAAA,CAAA;AADR,EAAAA,OAAAA,oBAAAA,CAAAA;AAAA,CAAA,EAAA,mBAAA,IAAA,EAAA;;;;"}
|
package/dist/utils.cjs
CHANGED
|
@@ -32,6 +32,23 @@ const getRectFromCoords = (coords) => {
|
|
|
32
32
|
height: coords.bottom - coords.top
|
|
33
33
|
};
|
|
34
34
|
};
|
|
35
|
+
const compareDocumentPosition = (a, b) => {
|
|
36
|
+
const position = a.compareDocumentPosition(b);
|
|
37
|
+
if (position & Node.DOCUMENT_POSITION_FOLLOWING) {
|
|
38
|
+
return -1;
|
|
39
|
+
}
|
|
40
|
+
if (position & Node.DOCUMENT_POSITION_PRECEDING) {
|
|
41
|
+
return 1;
|
|
42
|
+
}
|
|
43
|
+
return 0;
|
|
44
|
+
};
|
|
45
|
+
const areSetsEqual = (a, b) => {
|
|
46
|
+
if (a === b) return true;
|
|
47
|
+
if (!a || !b) return false;
|
|
48
|
+
if (a.size !== b.size) return false;
|
|
49
|
+
for (const v of a) if (!b.has(v)) return false;
|
|
50
|
+
return true;
|
|
51
|
+
};
|
|
35
52
|
const getMentionsFromNode = (node, range) => {
|
|
36
53
|
const mentions = /* @__PURE__ */ new Map();
|
|
37
54
|
node.nodesBetween(range.from, range.to, (child) => {
|
|
@@ -187,6 +204,8 @@ function getContextualPromptContext(editor, maxLength = 1e4) {
|
|
|
187
204
|
}
|
|
188
205
|
}
|
|
189
206
|
|
|
207
|
+
exports.areSetsEqual = areSetsEqual;
|
|
208
|
+
exports.compareDocumentPosition = compareDocumentPosition;
|
|
190
209
|
exports.compareSelections = compareSelections;
|
|
191
210
|
exports.getContextualPromptContext = getContextualPromptContext;
|
|
192
211
|
exports.getDomRangeFromSelection = getDomRangeFromSelection;
|
package/dist/utils.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.cjs","sources":["../src/utils.ts"],"sourcesContent":["import type { ClientRectObject } from \"@floating-ui/react-dom\";\nimport { assertNever, type ContextualPromptContext } from \"@liveblocks/core\";\nimport type { Editor, Range } from \"@tiptap/core\";\nimport type { Node as ProseMirrorNode } from \"@tiptap/pm/model\";\nimport { Fragment } from \"@tiptap/pm/model\";\nimport {\n type EditorState,\n type Selection,\n TextSelection,\n} from \"@tiptap/pm/state\";\nimport {\n getRelativeSelection,\n relativePositionToAbsolutePosition,\n ySyncPluginKey,\n} from \"y-prosemirror\";\nimport type { RelativePosition } from \"yjs\";\n\nimport type {\n SerializedTiptapMentionData,\n TiptapMentionData,\n YSyncPluginState,\n} from \"./types\";\nimport {\n LIVEBLOCKS_GROUP_MENTION_TYPE,\n LIVEBLOCKS_MENTION_TYPE,\n} from \"./types\";\n\nconst CONTEXT_TRUNCATION = \"[…]\";\nconst CONTEXT_BLOCK_SEPARATOR = \"\\n\";\n\nexport const getRelativeSelectionFromState = (state: EditorState) => {\n const pluginState = ySyncPluginKey.getState(state) as YSyncPluginState;\n if (!pluginState) return null;\n return getRelativeSelection(pluginState.binding, state);\n};\n\nexport const getRangeFromRelativeSelections = (\n pos: { anchor: RelativePosition; head: RelativePosition },\n state: EditorState\n) => {\n const pluginState = ySyncPluginKey.getState(state) as YSyncPluginState;\n if (!pluginState || !pluginState.binding) return { from: 0, to: 0 };\n const { doc, type, mapping } = pluginState.binding;\n const anchor =\n relativePositionToAbsolutePosition(doc, type, pos.anchor, mapping) ?? 0;\n const head =\n relativePositionToAbsolutePosition(doc, type, pos.head, mapping) ?? 0;\n\n const from = anchor > head ? head : anchor;\n const to = anchor > head ? anchor : head;\n return { from, to };\n};\n\nexport const getRectFromCoords = (coords: {\n top: number;\n left: number;\n right: number;\n bottom: number;\n}): ClientRectObject => {\n return {\n ...coords,\n x: coords.left,\n y: coords.top,\n width: coords.right - coords.left,\n height: coords.bottom - coords.top,\n };\n};\n\nexport const getMentionsFromNode = (\n node: ProseMirrorNode,\n range: Range\n): Map<string, TiptapMentionData> => {\n const mentions = new Map<string, TiptapMentionData>();\n\n node.nodesBetween(range.from, range.to, (child) => {\n if (\n child.type.name === LIVEBLOCKS_MENTION_TYPE ||\n child.type.name === LIVEBLOCKS_GROUP_MENTION_TYPE\n ) {\n const mention = child.attrs as Omit<SerializedTiptapMentionData, \"kind\">;\n\n if (mention.id && mention.notificationId) {\n if (child.type.name === LIVEBLOCKS_MENTION_TYPE) {\n mentions.set(mention.notificationId, {\n kind: \"user\",\n id: mention.id,\n notificationId: mention.notificationId,\n });\n } else if (child.type.name === LIVEBLOCKS_GROUP_MENTION_TYPE) {\n let userIds: string[] | undefined;\n\n if (mention.userIds) {\n try {\n const parsedUserIds = JSON.parse(mention.userIds) as string[];\n\n if (Array.isArray(parsedUserIds)) {\n userIds = parsedUserIds;\n }\n } catch {\n userIds = undefined;\n }\n }\n\n mentions.set(mention.notificationId, {\n kind: \"group\",\n id: mention.id,\n userIds,\n notificationId: mention.notificationId,\n });\n } else {\n assertNever(child.type.name, \"Unexpected mention kind\");\n }\n }\n }\n });\n\n return mentions;\n};\n\n// How to modify data in transformPasted, inspired by: https://discuss.prosemirror.net/t/modify-specific-node-on-copy-and-paste-in-clipboard/4901/4\nexport const mapFragment = (\n fragment: Fragment,\n callback: (\n node: ProseMirrorNode\n ) => ProseMirrorNode | ProseMirrorNode[] | Fragment | null\n): Fragment => {\n const content: ProseMirrorNode[] = [];\n fragment.forEach((node) => {\n if (node.content.childCount > 0) {\n content.push(\n node.type.create(node.attrs, mapFragment(node.content, callback))\n );\n return;\n }\n content.push(callback(node) as ProseMirrorNode);\n });\n\n return Fragment.from(content);\n};\n\nexport function getDomRangeFromSelection(editor: Editor, selection: Selection) {\n if (selection.from === selection.to) {\n const { parent, parentOffset } = selection.$from;\n\n // If the selection is collapsed and in an empty block node or at the end\n // of a text node, extend it to the entire node\n if (\n (parent.isBlock && parent.content.size === 0) ||\n (parent.isTextblock && parentOffset === parent.content.size)\n ) {\n selection = TextSelection.create(\n editor.state.doc,\n selection.$from.before(),\n selection.$from.after()\n );\n }\n }\n\n const from = editor.view.domAtPos(selection.from);\n const to = editor.view.domAtPos(selection.to);\n\n const domRange = document.createRange();\n domRange.setStart(from.node, from.offset);\n domRange.setEnd(to.node, to.offset);\n\n return domRange;\n}\n\nexport function compareSelections(\n a: Selection | null | undefined,\n b: Selection | null | undefined\n) {\n if (!a || !b) {\n return false;\n }\n\n return a.eq(b);\n}\n\nexport function getContextualPromptContext(\n editor: Editor,\n maxLength = 10_000\n): ContextualPromptContext {\n const { selection, doc } = editor.state;\n\n const selectionLength = selection.to - selection.from;\n\n if (maxLength >= doc.content.size) {\n // If the document is smaller than the maximum length, return the entire document\n return {\n beforeSelection: doc.textBetween(\n 0,\n selection.from,\n CONTEXT_BLOCK_SEPARATOR\n ),\n selection: doc.textBetween(\n selection.from,\n selection.to,\n CONTEXT_BLOCK_SEPARATOR\n ),\n afterSelection: doc.textBetween(\n selection.to,\n doc.content.size,\n CONTEXT_BLOCK_SEPARATOR\n ),\n };\n } else if (selectionLength > maxLength) {\n // If the selection is too large, truncate its middle to still allow continuations\n const selectionStart = doc.textBetween(\n selection.from,\n selection.from + Math.floor(maxLength / 2) - CONTEXT_TRUNCATION.length,\n CONTEXT_BLOCK_SEPARATOR\n );\n const selectionEnd = doc.textBetween(\n selection.to - Math.floor(maxLength / 2) + CONTEXT_TRUNCATION.length,\n selection.to,\n CONTEXT_BLOCK_SEPARATOR\n );\n\n return {\n beforeSelection: \"\",\n selection: `${selectionStart}${CONTEXT_TRUNCATION}${selectionEnd}`,\n afterSelection: \"\",\n };\n } else {\n // If the selection is smaller than (or equal to) the maximum length, extract as much as possible from the document around the selection\n\n // Start by taking as much as possible after the selection\n let beforeLength = Math.min(\n selection.from,\n Math.floor((maxLength - selectionLength) / 2)\n );\n const afterLength = Math.min(\n doc.content.size - selection.to,\n maxLength - selectionLength - beforeLength\n );\n\n // If needed (e.g. the selection is near the end), compensate before the selection\n if (beforeLength + afterLength + selectionLength < maxLength) {\n beforeLength = Math.min(\n selection.from,\n maxLength - selectionLength - afterLength\n );\n }\n\n let beforeSelection = doc.textBetween(\n Math.max(0, selection.from - beforeLength),\n selection.from,\n CONTEXT_BLOCK_SEPARATOR\n );\n let afterSelection = doc.textBetween(\n selection.to,\n Math.min(doc.content.size, selection.to + afterLength),\n CONTEXT_BLOCK_SEPARATOR\n );\n\n // Add leading truncation if `beforeSelection` doesn't contain the document's start\n if (selection.from - beforeLength > 0) {\n beforeSelection = `${CONTEXT_TRUNCATION}${beforeSelection}`;\n }\n\n // Add trailing truncation if `afterSelection` doesn't contain the document's end\n if (selection.to + afterLength < doc.content.size) {\n afterSelection = `${afterSelection}${CONTEXT_TRUNCATION}`;\n }\n\n return {\n beforeSelection,\n selection: doc.textBetween(\n selection.from,\n selection.to,\n CONTEXT_BLOCK_SEPARATOR\n ),\n afterSelection,\n };\n }\n}\n"],"names":["ySyncPluginKey","getRelativeSelection","relativePositionToAbsolutePosition","LIVEBLOCKS_MENTION_TYPE","LIVEBLOCKS_GROUP_MENTION_TYPE","assertNever","Fragment","TextSelection"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"utils.cjs","sources":["../src/utils.ts"],"sourcesContent":["import type { ClientRectObject } from \"@floating-ui/react-dom\";\nimport { assertNever, type ContextualPromptContext } from \"@liveblocks/core\";\nimport type { Editor, Range } from \"@tiptap/core\";\nimport type { Node as ProseMirrorNode } from \"@tiptap/pm/model\";\nimport { Fragment } from \"@tiptap/pm/model\";\nimport {\n type EditorState,\n type Selection,\n TextSelection,\n} from \"@tiptap/pm/state\";\nimport {\n getRelativeSelection,\n relativePositionToAbsolutePosition,\n ySyncPluginKey,\n} from \"y-prosemirror\";\nimport type { RelativePosition } from \"yjs\";\n\nimport type {\n SerializedTiptapMentionData,\n TiptapMentionData,\n YSyncPluginState,\n} from \"./types\";\nimport {\n LIVEBLOCKS_GROUP_MENTION_TYPE,\n LIVEBLOCKS_MENTION_TYPE,\n} from \"./types\";\n\nconst CONTEXT_TRUNCATION = \"[…]\";\nconst CONTEXT_BLOCK_SEPARATOR = \"\\n\";\n\nexport const getRelativeSelectionFromState = (state: EditorState) => {\n const pluginState = ySyncPluginKey.getState(state) as YSyncPluginState;\n if (!pluginState) return null;\n return getRelativeSelection(pluginState.binding, state);\n};\n\nexport const getRangeFromRelativeSelections = (\n pos: { anchor: RelativePosition; head: RelativePosition },\n state: EditorState\n) => {\n const pluginState = ySyncPluginKey.getState(state) as YSyncPluginState;\n if (!pluginState || !pluginState.binding) return { from: 0, to: 0 };\n const { doc, type, mapping } = pluginState.binding;\n const anchor =\n relativePositionToAbsolutePosition(doc, type, pos.anchor, mapping) ?? 0;\n const head =\n relativePositionToAbsolutePosition(doc, type, pos.head, mapping) ?? 0;\n\n const from = anchor > head ? head : anchor;\n const to = anchor > head ? anchor : head;\n return { from, to };\n};\n\nexport const getRectFromCoords = (coords: {\n top: number;\n left: number;\n right: number;\n bottom: number;\n}): ClientRectObject => {\n return {\n ...coords,\n x: coords.left,\n y: coords.top,\n width: coords.right - coords.left,\n height: coords.bottom - coords.top,\n };\n};\n\nexport const compareDocumentPosition = (a: Node, b: Node) => {\n const position = a.compareDocumentPosition(b);\n if (position & Node.DOCUMENT_POSITION_FOLLOWING) {\n return -1;\n }\n if (position & Node.DOCUMENT_POSITION_PRECEDING) {\n return 1;\n }\n return 0;\n};\n\nexport const areSetsEqual = (a?: Set<string>, b?: Set<string>): boolean => {\n if (a === b) return true;\n if (!a || !b) return false;\n if (a.size !== b.size) return false;\n for (const v of a) if (!b.has(v)) return false;\n return true;\n};\n\nexport const getMentionsFromNode = (\n node: ProseMirrorNode,\n range: Range\n): Map<string, TiptapMentionData> => {\n const mentions = new Map<string, TiptapMentionData>();\n\n node.nodesBetween(range.from, range.to, (child) => {\n if (\n child.type.name === LIVEBLOCKS_MENTION_TYPE ||\n child.type.name === LIVEBLOCKS_GROUP_MENTION_TYPE\n ) {\n const mention = child.attrs as Omit<SerializedTiptapMentionData, \"kind\">;\n\n if (mention.id && mention.notificationId) {\n if (child.type.name === LIVEBLOCKS_MENTION_TYPE) {\n mentions.set(mention.notificationId, {\n kind: \"user\",\n id: mention.id,\n notificationId: mention.notificationId,\n });\n } else if (child.type.name === LIVEBLOCKS_GROUP_MENTION_TYPE) {\n let userIds: string[] | undefined;\n\n if (mention.userIds) {\n try {\n const parsedUserIds = JSON.parse(mention.userIds) as string[];\n\n if (Array.isArray(parsedUserIds)) {\n userIds = parsedUserIds;\n }\n } catch {\n userIds = undefined;\n }\n }\n\n mentions.set(mention.notificationId, {\n kind: \"group\",\n id: mention.id,\n userIds,\n notificationId: mention.notificationId,\n });\n } else {\n assertNever(child.type.name, \"Unexpected mention kind\");\n }\n }\n }\n });\n\n return mentions;\n};\n\n// How to modify data in transformPasted, inspired by: https://discuss.prosemirror.net/t/modify-specific-node-on-copy-and-paste-in-clipboard/4901/4\nexport const mapFragment = (\n fragment: Fragment,\n callback: (\n node: ProseMirrorNode\n ) => ProseMirrorNode | ProseMirrorNode[] | Fragment | null\n): Fragment => {\n const content: ProseMirrorNode[] = [];\n fragment.forEach((node) => {\n if (node.content.childCount > 0) {\n content.push(\n node.type.create(node.attrs, mapFragment(node.content, callback))\n );\n return;\n }\n content.push(callback(node) as ProseMirrorNode);\n });\n\n return Fragment.from(content);\n};\n\nexport function getDomRangeFromSelection(editor: Editor, selection: Selection) {\n if (selection.from === selection.to) {\n const { parent, parentOffset } = selection.$from;\n\n // If the selection is collapsed and in an empty block node or at the end\n // of a text node, extend it to the entire node\n if (\n (parent.isBlock && parent.content.size === 0) ||\n (parent.isTextblock && parentOffset === parent.content.size)\n ) {\n selection = TextSelection.create(\n editor.state.doc,\n selection.$from.before(),\n selection.$from.after()\n );\n }\n }\n\n const from = editor.view.domAtPos(selection.from);\n const to = editor.view.domAtPos(selection.to);\n\n const domRange = document.createRange();\n domRange.setStart(from.node, from.offset);\n domRange.setEnd(to.node, to.offset);\n\n return domRange;\n}\n\nexport function compareSelections(\n a: Selection | null | undefined,\n b: Selection | null | undefined\n) {\n if (!a || !b) {\n return false;\n }\n\n return a.eq(b);\n}\n\nexport function getContextualPromptContext(\n editor: Editor,\n maxLength = 10_000\n): ContextualPromptContext {\n const { selection, doc } = editor.state;\n\n const selectionLength = selection.to - selection.from;\n\n if (maxLength >= doc.content.size) {\n // If the document is smaller than the maximum length, return the entire document\n return {\n beforeSelection: doc.textBetween(\n 0,\n selection.from,\n CONTEXT_BLOCK_SEPARATOR\n ),\n selection: doc.textBetween(\n selection.from,\n selection.to,\n CONTEXT_BLOCK_SEPARATOR\n ),\n afterSelection: doc.textBetween(\n selection.to,\n doc.content.size,\n CONTEXT_BLOCK_SEPARATOR\n ),\n };\n } else if (selectionLength > maxLength) {\n // If the selection is too large, truncate its middle to still allow continuations\n const selectionStart = doc.textBetween(\n selection.from,\n selection.from + Math.floor(maxLength / 2) - CONTEXT_TRUNCATION.length,\n CONTEXT_BLOCK_SEPARATOR\n );\n const selectionEnd = doc.textBetween(\n selection.to - Math.floor(maxLength / 2) + CONTEXT_TRUNCATION.length,\n selection.to,\n CONTEXT_BLOCK_SEPARATOR\n );\n\n return {\n beforeSelection: \"\",\n selection: `${selectionStart}${CONTEXT_TRUNCATION}${selectionEnd}`,\n afterSelection: \"\",\n };\n } else {\n // If the selection is smaller than (or equal to) the maximum length, extract as much as possible from the document around the selection\n\n // Start by taking as much as possible after the selection\n let beforeLength = Math.min(\n selection.from,\n Math.floor((maxLength - selectionLength) / 2)\n );\n const afterLength = Math.min(\n doc.content.size - selection.to,\n maxLength - selectionLength - beforeLength\n );\n\n // If needed (e.g. the selection is near the end), compensate before the selection\n if (beforeLength + afterLength + selectionLength < maxLength) {\n beforeLength = Math.min(\n selection.from,\n maxLength - selectionLength - afterLength\n );\n }\n\n let beforeSelection = doc.textBetween(\n Math.max(0, selection.from - beforeLength),\n selection.from,\n CONTEXT_BLOCK_SEPARATOR\n );\n let afterSelection = doc.textBetween(\n selection.to,\n Math.min(doc.content.size, selection.to + afterLength),\n CONTEXT_BLOCK_SEPARATOR\n );\n\n // Add leading truncation if `beforeSelection` doesn't contain the document's start\n if (selection.from - beforeLength > 0) {\n beforeSelection = `${CONTEXT_TRUNCATION}${beforeSelection}`;\n }\n\n // Add trailing truncation if `afterSelection` doesn't contain the document's end\n if (selection.to + afterLength < doc.content.size) {\n afterSelection = `${afterSelection}${CONTEXT_TRUNCATION}`;\n }\n\n return {\n beforeSelection,\n selection: doc.textBetween(\n selection.from,\n selection.to,\n CONTEXT_BLOCK_SEPARATOR\n ),\n afterSelection,\n };\n }\n}\n"],"names":["ySyncPluginKey","getRelativeSelection","relativePositionToAbsolutePosition","LIVEBLOCKS_MENTION_TYPE","LIVEBLOCKS_GROUP_MENTION_TYPE","assertNever","Fragment","TextSelection"],"mappings":"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"}
|
package/dist/utils.js
CHANGED
|
@@ -30,6 +30,23 @@ const getRectFromCoords = (coords) => {
|
|
|
30
30
|
height: coords.bottom - coords.top
|
|
31
31
|
};
|
|
32
32
|
};
|
|
33
|
+
const compareDocumentPosition = (a, b) => {
|
|
34
|
+
const position = a.compareDocumentPosition(b);
|
|
35
|
+
if (position & Node.DOCUMENT_POSITION_FOLLOWING) {
|
|
36
|
+
return -1;
|
|
37
|
+
}
|
|
38
|
+
if (position & Node.DOCUMENT_POSITION_PRECEDING) {
|
|
39
|
+
return 1;
|
|
40
|
+
}
|
|
41
|
+
return 0;
|
|
42
|
+
};
|
|
43
|
+
const areSetsEqual = (a, b) => {
|
|
44
|
+
if (a === b) return true;
|
|
45
|
+
if (!a || !b) return false;
|
|
46
|
+
if (a.size !== b.size) return false;
|
|
47
|
+
for (const v of a) if (!b.has(v)) return false;
|
|
48
|
+
return true;
|
|
49
|
+
};
|
|
33
50
|
const getMentionsFromNode = (node, range) => {
|
|
34
51
|
const mentions = /* @__PURE__ */ new Map();
|
|
35
52
|
node.nodesBetween(range.from, range.to, (child) => {
|
|
@@ -185,5 +202,5 @@ function getContextualPromptContext(editor, maxLength = 1e4) {
|
|
|
185
202
|
}
|
|
186
203
|
}
|
|
187
204
|
|
|
188
|
-
export { compareSelections, getContextualPromptContext, getDomRangeFromSelection, getMentionsFromNode, getRangeFromRelativeSelections, getRectFromCoords, getRelativeSelectionFromState, mapFragment };
|
|
205
|
+
export { areSetsEqual, compareDocumentPosition, compareSelections, getContextualPromptContext, getDomRangeFromSelection, getMentionsFromNode, getRangeFromRelativeSelections, getRectFromCoords, getRelativeSelectionFromState, mapFragment };
|
|
189
206
|
//# sourceMappingURL=utils.js.map
|
package/dist/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sources":["../src/utils.ts"],"sourcesContent":["import type { ClientRectObject } from \"@floating-ui/react-dom\";\nimport { assertNever, type ContextualPromptContext } from \"@liveblocks/core\";\nimport type { Editor, Range } from \"@tiptap/core\";\nimport type { Node as ProseMirrorNode } from \"@tiptap/pm/model\";\nimport { Fragment } from \"@tiptap/pm/model\";\nimport {\n type EditorState,\n type Selection,\n TextSelection,\n} from \"@tiptap/pm/state\";\nimport {\n getRelativeSelection,\n relativePositionToAbsolutePosition,\n ySyncPluginKey,\n} from \"y-prosemirror\";\nimport type { RelativePosition } from \"yjs\";\n\nimport type {\n SerializedTiptapMentionData,\n TiptapMentionData,\n YSyncPluginState,\n} from \"./types\";\nimport {\n LIVEBLOCKS_GROUP_MENTION_TYPE,\n LIVEBLOCKS_MENTION_TYPE,\n} from \"./types\";\n\nconst CONTEXT_TRUNCATION = \"[…]\";\nconst CONTEXT_BLOCK_SEPARATOR = \"\\n\";\n\nexport const getRelativeSelectionFromState = (state: EditorState) => {\n const pluginState = ySyncPluginKey.getState(state) as YSyncPluginState;\n if (!pluginState) return null;\n return getRelativeSelection(pluginState.binding, state);\n};\n\nexport const getRangeFromRelativeSelections = (\n pos: { anchor: RelativePosition; head: RelativePosition },\n state: EditorState\n) => {\n const pluginState = ySyncPluginKey.getState(state) as YSyncPluginState;\n if (!pluginState || !pluginState.binding) return { from: 0, to: 0 };\n const { doc, type, mapping } = pluginState.binding;\n const anchor =\n relativePositionToAbsolutePosition(doc, type, pos.anchor, mapping) ?? 0;\n const head =\n relativePositionToAbsolutePosition(doc, type, pos.head, mapping) ?? 0;\n\n const from = anchor > head ? head : anchor;\n const to = anchor > head ? anchor : head;\n return { from, to };\n};\n\nexport const getRectFromCoords = (coords: {\n top: number;\n left: number;\n right: number;\n bottom: number;\n}): ClientRectObject => {\n return {\n ...coords,\n x: coords.left,\n y: coords.top,\n width: coords.right - coords.left,\n height: coords.bottom - coords.top,\n };\n};\n\nexport const getMentionsFromNode = (\n node: ProseMirrorNode,\n range: Range\n): Map<string, TiptapMentionData> => {\n const mentions = new Map<string, TiptapMentionData>();\n\n node.nodesBetween(range.from, range.to, (child) => {\n if (\n child.type.name === LIVEBLOCKS_MENTION_TYPE ||\n child.type.name === LIVEBLOCKS_GROUP_MENTION_TYPE\n ) {\n const mention = child.attrs as Omit<SerializedTiptapMentionData, \"kind\">;\n\n if (mention.id && mention.notificationId) {\n if (child.type.name === LIVEBLOCKS_MENTION_TYPE) {\n mentions.set(mention.notificationId, {\n kind: \"user\",\n id: mention.id,\n notificationId: mention.notificationId,\n });\n } else if (child.type.name === LIVEBLOCKS_GROUP_MENTION_TYPE) {\n let userIds: string[] | undefined;\n\n if (mention.userIds) {\n try {\n const parsedUserIds = JSON.parse(mention.userIds) as string[];\n\n if (Array.isArray(parsedUserIds)) {\n userIds = parsedUserIds;\n }\n } catch {\n userIds = undefined;\n }\n }\n\n mentions.set(mention.notificationId, {\n kind: \"group\",\n id: mention.id,\n userIds,\n notificationId: mention.notificationId,\n });\n } else {\n assertNever(child.type.name, \"Unexpected mention kind\");\n }\n }\n }\n });\n\n return mentions;\n};\n\n// How to modify data in transformPasted, inspired by: https://discuss.prosemirror.net/t/modify-specific-node-on-copy-and-paste-in-clipboard/4901/4\nexport const mapFragment = (\n fragment: Fragment,\n callback: (\n node: ProseMirrorNode\n ) => ProseMirrorNode | ProseMirrorNode[] | Fragment | null\n): Fragment => {\n const content: ProseMirrorNode[] = [];\n fragment.forEach((node) => {\n if (node.content.childCount > 0) {\n content.push(\n node.type.create(node.attrs, mapFragment(node.content, callback))\n );\n return;\n }\n content.push(callback(node) as ProseMirrorNode);\n });\n\n return Fragment.from(content);\n};\n\nexport function getDomRangeFromSelection(editor: Editor, selection: Selection) {\n if (selection.from === selection.to) {\n const { parent, parentOffset } = selection.$from;\n\n // If the selection is collapsed and in an empty block node or at the end\n // of a text node, extend it to the entire node\n if (\n (parent.isBlock && parent.content.size === 0) ||\n (parent.isTextblock && parentOffset === parent.content.size)\n ) {\n selection = TextSelection.create(\n editor.state.doc,\n selection.$from.before(),\n selection.$from.after()\n );\n }\n }\n\n const from = editor.view.domAtPos(selection.from);\n const to = editor.view.domAtPos(selection.to);\n\n const domRange = document.createRange();\n domRange.setStart(from.node, from.offset);\n domRange.setEnd(to.node, to.offset);\n\n return domRange;\n}\n\nexport function compareSelections(\n a: Selection | null | undefined,\n b: Selection | null | undefined\n) {\n if (!a || !b) {\n return false;\n }\n\n return a.eq(b);\n}\n\nexport function getContextualPromptContext(\n editor: Editor,\n maxLength = 10_000\n): ContextualPromptContext {\n const { selection, doc } = editor.state;\n\n const selectionLength = selection.to - selection.from;\n\n if (maxLength >= doc.content.size) {\n // If the document is smaller than the maximum length, return the entire document\n return {\n beforeSelection: doc.textBetween(\n 0,\n selection.from,\n CONTEXT_BLOCK_SEPARATOR\n ),\n selection: doc.textBetween(\n selection.from,\n selection.to,\n CONTEXT_BLOCK_SEPARATOR\n ),\n afterSelection: doc.textBetween(\n selection.to,\n doc.content.size,\n CONTEXT_BLOCK_SEPARATOR\n ),\n };\n } else if (selectionLength > maxLength) {\n // If the selection is too large, truncate its middle to still allow continuations\n const selectionStart = doc.textBetween(\n selection.from,\n selection.from + Math.floor(maxLength / 2) - CONTEXT_TRUNCATION.length,\n CONTEXT_BLOCK_SEPARATOR\n );\n const selectionEnd = doc.textBetween(\n selection.to - Math.floor(maxLength / 2) + CONTEXT_TRUNCATION.length,\n selection.to,\n CONTEXT_BLOCK_SEPARATOR\n );\n\n return {\n beforeSelection: \"\",\n selection: `${selectionStart}${CONTEXT_TRUNCATION}${selectionEnd}`,\n afterSelection: \"\",\n };\n } else {\n // If the selection is smaller than (or equal to) the maximum length, extract as much as possible from the document around the selection\n\n // Start by taking as much as possible after the selection\n let beforeLength = Math.min(\n selection.from,\n Math.floor((maxLength - selectionLength) / 2)\n );\n const afterLength = Math.min(\n doc.content.size - selection.to,\n maxLength - selectionLength - beforeLength\n );\n\n // If needed (e.g. the selection is near the end), compensate before the selection\n if (beforeLength + afterLength + selectionLength < maxLength) {\n beforeLength = Math.min(\n selection.from,\n maxLength - selectionLength - afterLength\n );\n }\n\n let beforeSelection = doc.textBetween(\n Math.max(0, selection.from - beforeLength),\n selection.from,\n CONTEXT_BLOCK_SEPARATOR\n );\n let afterSelection = doc.textBetween(\n selection.to,\n Math.min(doc.content.size, selection.to + afterLength),\n CONTEXT_BLOCK_SEPARATOR\n );\n\n // Add leading truncation if `beforeSelection` doesn't contain the document's start\n if (selection.from - beforeLength > 0) {\n beforeSelection = `${CONTEXT_TRUNCATION}${beforeSelection}`;\n }\n\n // Add trailing truncation if `afterSelection` doesn't contain the document's end\n if (selection.to + afterLength < doc.content.size) {\n afterSelection = `${afterSelection}${CONTEXT_TRUNCATION}`;\n }\n\n return {\n beforeSelection,\n selection: doc.textBetween(\n selection.from,\n selection.to,\n CONTEXT_BLOCK_SEPARATOR\n ),\n afterSelection,\n };\n }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"utils.js","sources":["../src/utils.ts"],"sourcesContent":["import type { ClientRectObject } from \"@floating-ui/react-dom\";\nimport { assertNever, type ContextualPromptContext } from \"@liveblocks/core\";\nimport type { Editor, Range } from \"@tiptap/core\";\nimport type { Node as ProseMirrorNode } from \"@tiptap/pm/model\";\nimport { Fragment } from \"@tiptap/pm/model\";\nimport {\n type EditorState,\n type Selection,\n TextSelection,\n} from \"@tiptap/pm/state\";\nimport {\n getRelativeSelection,\n relativePositionToAbsolutePosition,\n ySyncPluginKey,\n} from \"y-prosemirror\";\nimport type { RelativePosition } from \"yjs\";\n\nimport type {\n SerializedTiptapMentionData,\n TiptapMentionData,\n YSyncPluginState,\n} from \"./types\";\nimport {\n LIVEBLOCKS_GROUP_MENTION_TYPE,\n LIVEBLOCKS_MENTION_TYPE,\n} from \"./types\";\n\nconst CONTEXT_TRUNCATION = \"[…]\";\nconst CONTEXT_BLOCK_SEPARATOR = \"\\n\";\n\nexport const getRelativeSelectionFromState = (state: EditorState) => {\n const pluginState = ySyncPluginKey.getState(state) as YSyncPluginState;\n if (!pluginState) return null;\n return getRelativeSelection(pluginState.binding, state);\n};\n\nexport const getRangeFromRelativeSelections = (\n pos: { anchor: RelativePosition; head: RelativePosition },\n state: EditorState\n) => {\n const pluginState = ySyncPluginKey.getState(state) as YSyncPluginState;\n if (!pluginState || !pluginState.binding) return { from: 0, to: 0 };\n const { doc, type, mapping } = pluginState.binding;\n const anchor =\n relativePositionToAbsolutePosition(doc, type, pos.anchor, mapping) ?? 0;\n const head =\n relativePositionToAbsolutePosition(doc, type, pos.head, mapping) ?? 0;\n\n const from = anchor > head ? head : anchor;\n const to = anchor > head ? anchor : head;\n return { from, to };\n};\n\nexport const getRectFromCoords = (coords: {\n top: number;\n left: number;\n right: number;\n bottom: number;\n}): ClientRectObject => {\n return {\n ...coords,\n x: coords.left,\n y: coords.top,\n width: coords.right - coords.left,\n height: coords.bottom - coords.top,\n };\n};\n\nexport const compareDocumentPosition = (a: Node, b: Node) => {\n const position = a.compareDocumentPosition(b);\n if (position & Node.DOCUMENT_POSITION_FOLLOWING) {\n return -1;\n }\n if (position & Node.DOCUMENT_POSITION_PRECEDING) {\n return 1;\n }\n return 0;\n};\n\nexport const areSetsEqual = (a?: Set<string>, b?: Set<string>): boolean => {\n if (a === b) return true;\n if (!a || !b) return false;\n if (a.size !== b.size) return false;\n for (const v of a) if (!b.has(v)) return false;\n return true;\n};\n\nexport const getMentionsFromNode = (\n node: ProseMirrorNode,\n range: Range\n): Map<string, TiptapMentionData> => {\n const mentions = new Map<string, TiptapMentionData>();\n\n node.nodesBetween(range.from, range.to, (child) => {\n if (\n child.type.name === LIVEBLOCKS_MENTION_TYPE ||\n child.type.name === LIVEBLOCKS_GROUP_MENTION_TYPE\n ) {\n const mention = child.attrs as Omit<SerializedTiptapMentionData, \"kind\">;\n\n if (mention.id && mention.notificationId) {\n if (child.type.name === LIVEBLOCKS_MENTION_TYPE) {\n mentions.set(mention.notificationId, {\n kind: \"user\",\n id: mention.id,\n notificationId: mention.notificationId,\n });\n } else if (child.type.name === LIVEBLOCKS_GROUP_MENTION_TYPE) {\n let userIds: string[] | undefined;\n\n if (mention.userIds) {\n try {\n const parsedUserIds = JSON.parse(mention.userIds) as string[];\n\n if (Array.isArray(parsedUserIds)) {\n userIds = parsedUserIds;\n }\n } catch {\n userIds = undefined;\n }\n }\n\n mentions.set(mention.notificationId, {\n kind: \"group\",\n id: mention.id,\n userIds,\n notificationId: mention.notificationId,\n });\n } else {\n assertNever(child.type.name, \"Unexpected mention kind\");\n }\n }\n }\n });\n\n return mentions;\n};\n\n// How to modify data in transformPasted, inspired by: https://discuss.prosemirror.net/t/modify-specific-node-on-copy-and-paste-in-clipboard/4901/4\nexport const mapFragment = (\n fragment: Fragment,\n callback: (\n node: ProseMirrorNode\n ) => ProseMirrorNode | ProseMirrorNode[] | Fragment | null\n): Fragment => {\n const content: ProseMirrorNode[] = [];\n fragment.forEach((node) => {\n if (node.content.childCount > 0) {\n content.push(\n node.type.create(node.attrs, mapFragment(node.content, callback))\n );\n return;\n }\n content.push(callback(node) as ProseMirrorNode);\n });\n\n return Fragment.from(content);\n};\n\nexport function getDomRangeFromSelection(editor: Editor, selection: Selection) {\n if (selection.from === selection.to) {\n const { parent, parentOffset } = selection.$from;\n\n // If the selection is collapsed and in an empty block node or at the end\n // of a text node, extend it to the entire node\n if (\n (parent.isBlock && parent.content.size === 0) ||\n (parent.isTextblock && parentOffset === parent.content.size)\n ) {\n selection = TextSelection.create(\n editor.state.doc,\n selection.$from.before(),\n selection.$from.after()\n );\n }\n }\n\n const from = editor.view.domAtPos(selection.from);\n const to = editor.view.domAtPos(selection.to);\n\n const domRange = document.createRange();\n domRange.setStart(from.node, from.offset);\n domRange.setEnd(to.node, to.offset);\n\n return domRange;\n}\n\nexport function compareSelections(\n a: Selection | null | undefined,\n b: Selection | null | undefined\n) {\n if (!a || !b) {\n return false;\n }\n\n return a.eq(b);\n}\n\nexport function getContextualPromptContext(\n editor: Editor,\n maxLength = 10_000\n): ContextualPromptContext {\n const { selection, doc } = editor.state;\n\n const selectionLength = selection.to - selection.from;\n\n if (maxLength >= doc.content.size) {\n // If the document is smaller than the maximum length, return the entire document\n return {\n beforeSelection: doc.textBetween(\n 0,\n selection.from,\n CONTEXT_BLOCK_SEPARATOR\n ),\n selection: doc.textBetween(\n selection.from,\n selection.to,\n CONTEXT_BLOCK_SEPARATOR\n ),\n afterSelection: doc.textBetween(\n selection.to,\n doc.content.size,\n CONTEXT_BLOCK_SEPARATOR\n ),\n };\n } else if (selectionLength > maxLength) {\n // If the selection is too large, truncate its middle to still allow continuations\n const selectionStart = doc.textBetween(\n selection.from,\n selection.from + Math.floor(maxLength / 2) - CONTEXT_TRUNCATION.length,\n CONTEXT_BLOCK_SEPARATOR\n );\n const selectionEnd = doc.textBetween(\n selection.to - Math.floor(maxLength / 2) + CONTEXT_TRUNCATION.length,\n selection.to,\n CONTEXT_BLOCK_SEPARATOR\n );\n\n return {\n beforeSelection: \"\",\n selection: `${selectionStart}${CONTEXT_TRUNCATION}${selectionEnd}`,\n afterSelection: \"\",\n };\n } else {\n // If the selection is smaller than (or equal to) the maximum length, extract as much as possible from the document around the selection\n\n // Start by taking as much as possible after the selection\n let beforeLength = Math.min(\n selection.from,\n Math.floor((maxLength - selectionLength) / 2)\n );\n const afterLength = Math.min(\n doc.content.size - selection.to,\n maxLength - selectionLength - beforeLength\n );\n\n // If needed (e.g. the selection is near the end), compensate before the selection\n if (beforeLength + afterLength + selectionLength < maxLength) {\n beforeLength = Math.min(\n selection.from,\n maxLength - selectionLength - afterLength\n );\n }\n\n let beforeSelection = doc.textBetween(\n Math.max(0, selection.from - beforeLength),\n selection.from,\n CONTEXT_BLOCK_SEPARATOR\n );\n let afterSelection = doc.textBetween(\n selection.to,\n Math.min(doc.content.size, selection.to + afterLength),\n CONTEXT_BLOCK_SEPARATOR\n );\n\n // Add leading truncation if `beforeSelection` doesn't contain the document's start\n if (selection.from - beforeLength > 0) {\n beforeSelection = `${CONTEXT_TRUNCATION}${beforeSelection}`;\n }\n\n // Add trailing truncation if `afterSelection` doesn't contain the document's end\n if (selection.to + afterLength < doc.content.size) {\n afterSelection = `${afterSelection}${CONTEXT_TRUNCATION}`;\n }\n\n return {\n beforeSelection,\n selection: doc.textBetween(\n selection.from,\n selection.to,\n CONTEXT_BLOCK_SEPARATOR\n ),\n afterSelection,\n };\n }\n}\n"],"names":[],"mappings":"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"}
|
package/dist/version.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const PKG_NAME = "@liveblocks/react-tiptap";
|
|
4
|
-
const PKG_VERSION = typeof "3.18.
|
|
4
|
+
const PKG_VERSION = typeof "3.18.5" === "string" && "3.18.5";
|
|
5
5
|
const PKG_FORMAT = typeof "cjs" === "string" && "cjs";
|
|
6
6
|
|
|
7
7
|
exports.PKG_FORMAT = PKG_FORMAT;
|
package/dist/version.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const PKG_NAME = "@liveblocks/react-tiptap";
|
|
2
|
-
const PKG_VERSION = typeof "3.18.
|
|
2
|
+
const PKG_VERSION = typeof "3.18.5" === "string" && "3.18.5";
|
|
3
3
|
const PKG_FORMAT = typeof "esm" === "string" && "esm";
|
|
4
4
|
|
|
5
5
|
export { PKG_FORMAT, PKG_NAME, PKG_VERSION };
|