@liveblocks/react-tiptap 0.0.1 → 2.8.3-tiptap2
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.js +206 -0
- package/dist/LiveblocksExtension.js.map +1 -0
- package/dist/LiveblocksExtension.mjs +204 -0
- package/dist/LiveblocksExtension.mjs.map +1 -0
- package/dist/classnames.js +8 -0
- package/dist/classnames.js.map +1 -0
- package/dist/classnames.mjs +6 -0
- package/dist/classnames.mjs.map +1 -0
- package/dist/comments/AnchoredThreads.js +178 -0
- package/dist/comments/AnchoredThreads.js.map +1 -0
- package/dist/comments/AnchoredThreads.mjs +176 -0
- package/dist/comments/AnchoredThreads.mjs.map +1 -0
- package/dist/comments/CommentsExtension.js +224 -0
- package/dist/comments/CommentsExtension.js.map +1 -0
- package/dist/comments/CommentsExtension.mjs +222 -0
- package/dist/comments/CommentsExtension.mjs.map +1 -0
- package/dist/comments/FloatingComposer.js +100 -0
- package/dist/comments/FloatingComposer.js.map +1 -0
- package/dist/comments/FloatingComposer.mjs +97 -0
- package/dist/comments/FloatingComposer.mjs.map +1 -0
- package/dist/comments/FloatingThreads.js +159 -0
- package/dist/comments/FloatingThreads.js.map +1 -0
- package/dist/comments/FloatingThreads.mjs +156 -0
- package/dist/comments/FloatingThreads.mjs.map +1 -0
- package/dist/index.d.mts +78 -0
- package/dist/index.d.ts +78 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +10 -0
- package/dist/index.mjs.map +1 -0
- package/dist/mentions/Avatar.js +53 -0
- package/dist/mentions/Avatar.js.map +1 -0
- package/dist/mentions/Avatar.mjs +51 -0
- package/dist/mentions/Avatar.mjs.map +1 -0
- package/dist/mentions/Mention.js +24 -0
- package/dist/mentions/Mention.js.map +1 -0
- package/dist/mentions/Mention.mjs +22 -0
- package/dist/mentions/Mention.mjs.map +1 -0
- package/dist/mentions/MentionExtension.js +222 -0
- package/dist/mentions/MentionExtension.js.map +1 -0
- package/dist/mentions/MentionExtension.mjs +220 -0
- package/dist/mentions/MentionExtension.mjs.map +1 -0
- package/dist/mentions/MentionsList.js +123 -0
- package/dist/mentions/MentionsList.js.map +1 -0
- package/dist/mentions/MentionsList.mjs +119 -0
- package/dist/mentions/MentionsList.mjs.map +1 -0
- package/dist/types.js +33 -0
- package/dist/types.js.map +1 -0
- package/dist/types.mjs +24 -0
- package/dist/types.mjs.map +1 -0
- package/dist/utils.js +47 -0
- package/dist/utils.js.map +1 -0
- package/dist/utils.mjs +43 -0
- package/dist/utils.mjs.map +1 -0
- package/dist/version-history/HistoryVersionPreview.js +79 -0
- package/dist/version-history/HistoryVersionPreview.js.map +1 -0
- package/dist/version-history/HistoryVersionPreview.mjs +77 -0
- package/dist/version-history/HistoryVersionPreview.mjs.map +1 -0
- package/dist/version.js +10 -0
- package/dist/version.js.map +1 -0
- package/dist/version.mjs +6 -0
- package/dist/version.mjs.map +1 -0
- package/package.json +77 -1
- package/src/styles/constants.css +9 -0
- package/src/styles/index.css +250 -0
- package/src/styles/utils.css +6 -0
- package/styles.css +1 -0
- package/styles.css.d.ts +1 -0
- package/styles.css.map +1 -0
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var reactDom = require('@floating-ui/react-dom');
|
|
4
|
+
var reactUi = require('@liveblocks/react-ui');
|
|
5
|
+
var React = require('react');
|
|
6
|
+
var reactDom$1 = require('react-dom');
|
|
7
|
+
var classnames = require('../classnames.js');
|
|
8
|
+
var types = require('../types.js');
|
|
9
|
+
|
|
10
|
+
function FloatingThreads({
|
|
11
|
+
threads,
|
|
12
|
+
components,
|
|
13
|
+
editor,
|
|
14
|
+
...props
|
|
15
|
+
}) {
|
|
16
|
+
const Thread = components?.Thread ?? reactUi.Thread;
|
|
17
|
+
const pluginState = editor ? types.THREADS_PLUGIN_KEY.getState(editor.state) : null;
|
|
18
|
+
const [activeThread, setActiveThread] = React.useState(null);
|
|
19
|
+
React.useEffect(() => {
|
|
20
|
+
if (!editor || !pluginState) {
|
|
21
|
+
setActiveThread(null);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const { selectedThreadId, selectedThreadPos } = pluginState;
|
|
25
|
+
if (selectedThreadId === null || selectedThreadPos === null) {
|
|
26
|
+
setActiveThread(null);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const active = (threads ?? []).find(
|
|
30
|
+
(thread) => selectedThreadId === thread.id
|
|
31
|
+
);
|
|
32
|
+
setActiveThread(active ?? null);
|
|
33
|
+
}, [editor, pluginState, threads]);
|
|
34
|
+
const handleEscapeKeydown = React.useCallback(() => {
|
|
35
|
+
if (!editor || activeThread === null)
|
|
36
|
+
return false;
|
|
37
|
+
editor.commands.selectThread(null);
|
|
38
|
+
return true;
|
|
39
|
+
}, [activeThread, editor]);
|
|
40
|
+
if (!activeThread || !editor || activeThread.resolved)
|
|
41
|
+
return null;
|
|
42
|
+
return /* @__PURE__ */ React.createElement(FloatingThreadPortal, {
|
|
43
|
+
thread: activeThread,
|
|
44
|
+
editor,
|
|
45
|
+
container: document.body,
|
|
46
|
+
...props
|
|
47
|
+
}, activeThread && /* @__PURE__ */ React.createElement(ThreadWrapper, {
|
|
48
|
+
key: activeThread.id,
|
|
49
|
+
thread: activeThread,
|
|
50
|
+
Thread,
|
|
51
|
+
onEscapeKeydown: handleEscapeKeydown,
|
|
52
|
+
className: "lb-tiptap-floating-threads-thread"
|
|
53
|
+
}));
|
|
54
|
+
}
|
|
55
|
+
const FLOATING_THREAD_COLLISION_PADDING = 10;
|
|
56
|
+
function FloatingThreadPortal({
|
|
57
|
+
container,
|
|
58
|
+
editor,
|
|
59
|
+
thread,
|
|
60
|
+
children,
|
|
61
|
+
className,
|
|
62
|
+
style,
|
|
63
|
+
...props
|
|
64
|
+
}) {
|
|
65
|
+
const {
|
|
66
|
+
refs: { setReference, setFloating },
|
|
67
|
+
strategy,
|
|
68
|
+
x,
|
|
69
|
+
y
|
|
70
|
+
} = reactDom.useFloating({
|
|
71
|
+
strategy: "absolute",
|
|
72
|
+
placement: "bottom",
|
|
73
|
+
middleware: [
|
|
74
|
+
reactDom.flip({ padding: FLOATING_THREAD_COLLISION_PADDING, crossAxis: false }),
|
|
75
|
+
reactDom.offset(10),
|
|
76
|
+
reactDom.hide({ padding: FLOATING_THREAD_COLLISION_PADDING }),
|
|
77
|
+
reactDom.shift({
|
|
78
|
+
padding: FLOATING_THREAD_COLLISION_PADDING,
|
|
79
|
+
limiter: reactDom.limitShift()
|
|
80
|
+
}),
|
|
81
|
+
reactDom.size({
|
|
82
|
+
padding: FLOATING_THREAD_COLLISION_PADDING,
|
|
83
|
+
apply({ availableWidth, availableHeight, elements }) {
|
|
84
|
+
elements.floating.style.setProperty(
|
|
85
|
+
"--lb-tiptap-floating-threads-available-width",
|
|
86
|
+
`${availableWidth}px`
|
|
87
|
+
);
|
|
88
|
+
elements.floating.style.setProperty(
|
|
89
|
+
"--lb-tiptap-floating-threads-available-height",
|
|
90
|
+
`${availableHeight}px`
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
})
|
|
94
|
+
],
|
|
95
|
+
whileElementsMounted: (...args) => {
|
|
96
|
+
return reactDom.autoUpdate(...args, {
|
|
97
|
+
animationFrame: true
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
const updateRef = React.useCallback(() => {
|
|
102
|
+
const el = editor.view.dom.querySelector(`[data-lb-thread-id="${thread.id}"]`);
|
|
103
|
+
if (el) {
|
|
104
|
+
setReference(el);
|
|
105
|
+
}
|
|
106
|
+
}, [setReference, editor, thread.id]);
|
|
107
|
+
React.useEffect(() => {
|
|
108
|
+
editor.on("transaction", updateRef);
|
|
109
|
+
return () => {
|
|
110
|
+
editor.off("transaction", updateRef);
|
|
111
|
+
};
|
|
112
|
+
}, [editor, updateRef]);
|
|
113
|
+
React.useLayoutEffect(updateRef, [updateRef]);
|
|
114
|
+
return reactDom$1.createPortal(
|
|
115
|
+
/* @__PURE__ */ React.createElement("div", {
|
|
116
|
+
ref: setFloating,
|
|
117
|
+
...props,
|
|
118
|
+
style: {
|
|
119
|
+
...style,
|
|
120
|
+
position: strategy,
|
|
121
|
+
top: 0,
|
|
122
|
+
left: 0,
|
|
123
|
+
transform: `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)`,
|
|
124
|
+
minWidth: "max-content"
|
|
125
|
+
},
|
|
126
|
+
className: classnames.classNames(
|
|
127
|
+
"lb-root lb-portal lb-elevation lb-tiptap-floating lb-tiptap-floating-threads",
|
|
128
|
+
className
|
|
129
|
+
)
|
|
130
|
+
}, children),
|
|
131
|
+
container
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
function ThreadWrapper({
|
|
135
|
+
thread,
|
|
136
|
+
Thread,
|
|
137
|
+
onEscapeKeydown,
|
|
138
|
+
onKeyDown,
|
|
139
|
+
...threadProps
|
|
140
|
+
}) {
|
|
141
|
+
const handleKeyDown = React.useCallback(
|
|
142
|
+
(event) => {
|
|
143
|
+
onKeyDown?.(event);
|
|
144
|
+
if (event.key === "Escape") {
|
|
145
|
+
onEscapeKeydown();
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
[onEscapeKeydown, onKeyDown]
|
|
149
|
+
);
|
|
150
|
+
return /* @__PURE__ */ React.createElement(Thread, {
|
|
151
|
+
thread,
|
|
152
|
+
onKeyDown: handleKeyDown,
|
|
153
|
+
...threadProps
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
exports.FLOATING_THREAD_COLLISION_PADDING = FLOATING_THREAD_COLLISION_PADDING;
|
|
158
|
+
exports.FloatingThreads = FloatingThreads;
|
|
159
|
+
//# sourceMappingURL=FloatingThreads.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FloatingThreads.js","sources":["../../src/comments/FloatingThreads.tsx"],"sourcesContent":["\nimport {\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, DM, ThreadData } from \"@liveblocks/core\";\nimport {\n Thread as DefaultThread,\n type ThreadProps,\n} from \"@liveblocks/react-ui\";\nimport type { Editor } from \"@tiptap/react\";\nimport React, {\n type ComponentType,\n type HTMLAttributes,\n type KeyboardEvent,\n type ReactNode,\n useCallback,\n useEffect,\n useLayoutEffect,\n useState,\n} from \"react\";\nimport { createPortal } from \"react-dom\";\n\nimport { classNames } from \"../classnames\";\nimport type { ThreadPluginState } from \"../types\";\nimport { THREADS_PLUGIN_KEY } from \"../types\";\n\ntype ThreadPanelComponents = {\n Thread: ComponentType<ThreadProps>;\n};\n\nexport interface FloatingThreadsProps<M extends BaseMetadata = DM>\n extends Omit<HTMLAttributes<HTMLDivElement>, \"children\"> {\n /**\n * The threads to display.\n */\n threads: ThreadData<M>[];\n\n /**\n * Override the component's components.\n */\n components?: Partial<ThreadPanelComponents>;\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\n const Thread = components?.Thread ?? DefaultThread;\n const pluginState = editor ? THREADS_PLUGIN_KEY.getState(editor.state) as ThreadPluginState : null;\n\n const [activeThread, setActiveThread] = useState<ThreadData | null>(null);\n\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((thread) =>\n 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\n thread={activeThread}\n editor={editor}\n container={document.body}\n {...props}\n >\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\n extends Omit<HTMLAttributes<HTMLDivElement>, \"children\"> {\n thread: ThreadData;\n editor: Editor;\n container: HTMLElement;\n children: ReactNode;\n}\n\nexport const FLOATING_THREAD_COLLISION_PADDING = 10;\n\nfunction FloatingThreadPortal({\n container,\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(`[data-lb-thread-id=\"${thread.id}\"]`);\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 createPortal(\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={classNames(\n \"lb-root lb-portal lb-elevation lb-tiptap-floating lb-tiptap-floating-threads\",\n className\n )}\n >\n {children}\n </div>,\n container\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\n"],"names":["DefaultThread","THREADS_PLUGIN_KEY","useState","useEffect","useCallback","useFloating","flip","offset","hide","shift","limitShift","size","autoUpdate","useLayoutEffect","createPortal","classNames"],"mappings":"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"}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { useFloating, flip, offset, hide, shift, limitShift, size, autoUpdate } from '@floating-ui/react-dom';
|
|
2
|
+
import { Thread } from '@liveblocks/react-ui';
|
|
3
|
+
import React, { useState, useEffect, useCallback, useLayoutEffect } from 'react';
|
|
4
|
+
import { createPortal } from 'react-dom';
|
|
5
|
+
import { classNames } from '../classnames.mjs';
|
|
6
|
+
import { THREADS_PLUGIN_KEY } from '../types.mjs';
|
|
7
|
+
|
|
8
|
+
function FloatingThreads({
|
|
9
|
+
threads,
|
|
10
|
+
components,
|
|
11
|
+
editor,
|
|
12
|
+
...props
|
|
13
|
+
}) {
|
|
14
|
+
const Thread$1 = components?.Thread ?? Thread;
|
|
15
|
+
const pluginState = editor ? THREADS_PLUGIN_KEY.getState(editor.state) : null;
|
|
16
|
+
const [activeThread, setActiveThread] = useState(null);
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
if (!editor || !pluginState) {
|
|
19
|
+
setActiveThread(null);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const { selectedThreadId, selectedThreadPos } = pluginState;
|
|
23
|
+
if (selectedThreadId === null || selectedThreadPos === null) {
|
|
24
|
+
setActiveThread(null);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const active = (threads ?? []).find(
|
|
28
|
+
(thread) => selectedThreadId === thread.id
|
|
29
|
+
);
|
|
30
|
+
setActiveThread(active ?? null);
|
|
31
|
+
}, [editor, pluginState, threads]);
|
|
32
|
+
const handleEscapeKeydown = useCallback(() => {
|
|
33
|
+
if (!editor || activeThread === null)
|
|
34
|
+
return false;
|
|
35
|
+
editor.commands.selectThread(null);
|
|
36
|
+
return true;
|
|
37
|
+
}, [activeThread, editor]);
|
|
38
|
+
if (!activeThread || !editor || activeThread.resolved)
|
|
39
|
+
return null;
|
|
40
|
+
return /* @__PURE__ */ React.createElement(FloatingThreadPortal, {
|
|
41
|
+
thread: activeThread,
|
|
42
|
+
editor,
|
|
43
|
+
container: document.body,
|
|
44
|
+
...props
|
|
45
|
+
}, activeThread && /* @__PURE__ */ React.createElement(ThreadWrapper, {
|
|
46
|
+
key: activeThread.id,
|
|
47
|
+
thread: activeThread,
|
|
48
|
+
Thread: Thread$1,
|
|
49
|
+
onEscapeKeydown: handleEscapeKeydown,
|
|
50
|
+
className: "lb-tiptap-floating-threads-thread"
|
|
51
|
+
}));
|
|
52
|
+
}
|
|
53
|
+
const FLOATING_THREAD_COLLISION_PADDING = 10;
|
|
54
|
+
function FloatingThreadPortal({
|
|
55
|
+
container,
|
|
56
|
+
editor,
|
|
57
|
+
thread,
|
|
58
|
+
children,
|
|
59
|
+
className,
|
|
60
|
+
style,
|
|
61
|
+
...props
|
|
62
|
+
}) {
|
|
63
|
+
const {
|
|
64
|
+
refs: { setReference, setFloating },
|
|
65
|
+
strategy,
|
|
66
|
+
x,
|
|
67
|
+
y
|
|
68
|
+
} = useFloating({
|
|
69
|
+
strategy: "absolute",
|
|
70
|
+
placement: "bottom",
|
|
71
|
+
middleware: [
|
|
72
|
+
flip({ padding: FLOATING_THREAD_COLLISION_PADDING, crossAxis: false }),
|
|
73
|
+
offset(10),
|
|
74
|
+
hide({ padding: FLOATING_THREAD_COLLISION_PADDING }),
|
|
75
|
+
shift({
|
|
76
|
+
padding: FLOATING_THREAD_COLLISION_PADDING,
|
|
77
|
+
limiter: limitShift()
|
|
78
|
+
}),
|
|
79
|
+
size({
|
|
80
|
+
padding: FLOATING_THREAD_COLLISION_PADDING,
|
|
81
|
+
apply({ availableWidth, availableHeight, elements }) {
|
|
82
|
+
elements.floating.style.setProperty(
|
|
83
|
+
"--lb-tiptap-floating-threads-available-width",
|
|
84
|
+
`${availableWidth}px`
|
|
85
|
+
);
|
|
86
|
+
elements.floating.style.setProperty(
|
|
87
|
+
"--lb-tiptap-floating-threads-available-height",
|
|
88
|
+
`${availableHeight}px`
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
})
|
|
92
|
+
],
|
|
93
|
+
whileElementsMounted: (...args) => {
|
|
94
|
+
return autoUpdate(...args, {
|
|
95
|
+
animationFrame: true
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
const updateRef = useCallback(() => {
|
|
100
|
+
const el = editor.view.dom.querySelector(`[data-lb-thread-id="${thread.id}"]`);
|
|
101
|
+
if (el) {
|
|
102
|
+
setReference(el);
|
|
103
|
+
}
|
|
104
|
+
}, [setReference, editor, thread.id]);
|
|
105
|
+
useEffect(() => {
|
|
106
|
+
editor.on("transaction", updateRef);
|
|
107
|
+
return () => {
|
|
108
|
+
editor.off("transaction", updateRef);
|
|
109
|
+
};
|
|
110
|
+
}, [editor, updateRef]);
|
|
111
|
+
useLayoutEffect(updateRef, [updateRef]);
|
|
112
|
+
return createPortal(
|
|
113
|
+
/* @__PURE__ */ React.createElement("div", {
|
|
114
|
+
ref: setFloating,
|
|
115
|
+
...props,
|
|
116
|
+
style: {
|
|
117
|
+
...style,
|
|
118
|
+
position: strategy,
|
|
119
|
+
top: 0,
|
|
120
|
+
left: 0,
|
|
121
|
+
transform: `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)`,
|
|
122
|
+
minWidth: "max-content"
|
|
123
|
+
},
|
|
124
|
+
className: classNames(
|
|
125
|
+
"lb-root lb-portal lb-elevation lb-tiptap-floating lb-tiptap-floating-threads",
|
|
126
|
+
className
|
|
127
|
+
)
|
|
128
|
+
}, children),
|
|
129
|
+
container
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
function ThreadWrapper({
|
|
133
|
+
thread,
|
|
134
|
+
Thread,
|
|
135
|
+
onEscapeKeydown,
|
|
136
|
+
onKeyDown,
|
|
137
|
+
...threadProps
|
|
138
|
+
}) {
|
|
139
|
+
const handleKeyDown = useCallback(
|
|
140
|
+
(event) => {
|
|
141
|
+
onKeyDown?.(event);
|
|
142
|
+
if (event.key === "Escape") {
|
|
143
|
+
onEscapeKeydown();
|
|
144
|
+
}
|
|
145
|
+
},
|
|
146
|
+
[onEscapeKeydown, onKeyDown]
|
|
147
|
+
);
|
|
148
|
+
return /* @__PURE__ */ React.createElement(Thread, {
|
|
149
|
+
thread,
|
|
150
|
+
onKeyDown: handleKeyDown,
|
|
151
|
+
...threadProps
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export { FLOATING_THREAD_COLLISION_PADDING, FloatingThreads };
|
|
156
|
+
//# sourceMappingURL=FloatingThreads.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FloatingThreads.mjs","sources":["../../src/comments/FloatingThreads.tsx"],"sourcesContent":["\nimport {\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, DM, ThreadData } from \"@liveblocks/core\";\nimport {\n Thread as DefaultThread,\n type ThreadProps,\n} from \"@liveblocks/react-ui\";\nimport type { Editor } from \"@tiptap/react\";\nimport React, {\n type ComponentType,\n type HTMLAttributes,\n type KeyboardEvent,\n type ReactNode,\n useCallback,\n useEffect,\n useLayoutEffect,\n useState,\n} from \"react\";\nimport { createPortal } from \"react-dom\";\n\nimport { classNames } from \"../classnames\";\nimport type { ThreadPluginState } from \"../types\";\nimport { THREADS_PLUGIN_KEY } from \"../types\";\n\ntype ThreadPanelComponents = {\n Thread: ComponentType<ThreadProps>;\n};\n\nexport interface FloatingThreadsProps<M extends BaseMetadata = DM>\n extends Omit<HTMLAttributes<HTMLDivElement>, \"children\"> {\n /**\n * The threads to display.\n */\n threads: ThreadData<M>[];\n\n /**\n * Override the component's components.\n */\n components?: Partial<ThreadPanelComponents>;\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\n const Thread = components?.Thread ?? DefaultThread;\n const pluginState = editor ? THREADS_PLUGIN_KEY.getState(editor.state) as ThreadPluginState : null;\n\n const [activeThread, setActiveThread] = useState<ThreadData | null>(null);\n\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((thread) =>\n 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\n thread={activeThread}\n editor={editor}\n container={document.body}\n {...props}\n >\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\n extends Omit<HTMLAttributes<HTMLDivElement>, \"children\"> {\n thread: ThreadData;\n editor: Editor;\n container: HTMLElement;\n children: ReactNode;\n}\n\nexport const FLOATING_THREAD_COLLISION_PADDING = 10;\n\nfunction FloatingThreadPortal({\n container,\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(`[data-lb-thread-id=\"${thread.id}\"]`);\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 createPortal(\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={classNames(\n \"lb-root lb-portal lb-elevation lb-tiptap-floating lb-tiptap-floating-threads\",\n className\n )}\n >\n {children}\n </div>,\n container\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\n"],"names":["Thread","DefaultThread"],"mappings":";;;;;;;AAuDO,SAAS,eAAgB,CAAA;AAAA,EAC9B,OAAA;AAAA,EACA,UAAA;AAAA,EACA,MAAA;AAAA,EACG,GAAA,KAAA;AACL,CAAyB,EAAA;AAEvB,EAAM,MAAAA,QAAA,GAAS,YAAY,MAAU,IAAAC,MAAA,CAAA;AACrC,EAAA,MAAM,cAAc,MAAS,GAAA,kBAAA,CAAmB,QAAS,CAAA,MAAA,CAAO,KAAK,CAAyB,GAAA,IAAA,CAAA;AAE9F,EAAA,MAAM,CAAC,YAAA,EAAc,eAAe,CAAA,GAAI,SAA4B,IAAI,CAAA,CAAA;AAGxE,EAAA,SAAA,CAAU,MAAM;AACd,IAAI,IAAA,CAAC,MAAU,IAAA,CAAC,WAAa,EAAA;AAC3B,MAAA,eAAA,CAAgB,IAAI,CAAA,CAAA;AACpB,MAAA,OAAA;AAAA,KACF;AACA,IAAM,MAAA,EAAE,gBAAkB,EAAA,iBAAA,EAAsB,GAAA,WAAA,CAAA;AAChD,IAAI,IAAA,gBAAA,KAAqB,IAAQ,IAAA,iBAAA,KAAsB,IAAM,EAAA;AAC3D,MAAA,eAAA,CAAgB,IAAI,CAAA,CAAA;AACpB,MAAA,OAAA;AAAA,KACF;AACA,IAAM,MAAA,MAAA,GAAA,CAAU,OAAW,IAAA,EAAI,EAAA,IAAA;AAAA,MAAK,CAAC,MACnC,KAAA,gBAAA,KAAqB,MAAO,CAAA,EAAA;AAAA,KAC9B,CAAA;AACA,IAAA,eAAA,CAAgB,UAAU,IAAI,CAAA,CAAA;AAAA,GAC7B,EAAA,CAAC,MAAQ,EAAA,WAAA,EAAa,OAAO,CAAC,CAAA,CAAA;AAEjC,EAAM,MAAA,mBAAA,GAAsB,YAAY,MAAe;AACrD,IAAI,IAAA,CAAC,UAAU,YAAiB,KAAA,IAAA;AAAM,MAAO,OAAA,KAAA,CAAA;AAC7C,IAAO,MAAA,CAAA,QAAA,CAAS,aAAa,IAAI,CAAA,CAAA;AACjC,IAAO,OAAA,IAAA,CAAA;AAAA,GACN,EAAA,CAAC,YAAc,EAAA,MAAM,CAAC,CAAA,CAAA;AAEzB,EAAA,IAAI,CAAC,YAAA,IAAgB,CAAC,MAAA,IAAU,YAAa,CAAA,QAAA;AAAU,IAAO,OAAA,IAAA,CAAA;AAE9D,EAAA,uBACG,KAAA,CAAA,aAAA,CAAA,oBAAA,EAAA;AAAA,IACC,MAAQ,EAAA,YAAA;AAAA,IACR,MAAA;AAAA,IACA,WAAW,QAAS,CAAA,IAAA;AAAA,IACnB,GAAG,KAAA;AAAA,GAAA,EAEH,gCACE,KAAA,CAAA,aAAA,CAAA,aAAA,EAAA;AAAA,IACC,KAAK,YAAa,CAAA,EAAA;AAAA,IAClB,MAAQ,EAAA,YAAA;AAAA,YACRD,QAAA;AAAA,IACA,eAAiB,EAAA,mBAAA;AAAA,IACjB,SAAU,EAAA,mCAAA;AAAA,GACZ,CAEJ,CAAA,CAAA;AAEJ,CAAA;AAUO,MAAM,iCAAoC,GAAA,GAAA;AAEjD,SAAS,oBAAqB,CAAA;AAAA,EAC5B,SAAA;AAAA,EACA,MAAA;AAAA,EACA,MAAA;AAAA,EACA,QAAA;AAAA,EACA,SAAA;AAAA,EACA,KAAA;AAAA,EACG,GAAA,KAAA;AACL,CAA8B,EAAA;AAC5B,EAAM,MAAA;AAAA,IACJ,IAAA,EAAM,EAAE,YAAA,EAAc,WAAY,EAAA;AAAA,IAClC,QAAA;AAAA,IACA,CAAA;AAAA,IACA,CAAA;AAAA,MACE,WAAY,CAAA;AAAA,IACd,QAAU,EAAA,UAAA;AAAA,IACV,SAAW,EAAA,QAAA;AAAA,IACX,UAAY,EAAA;AAAA,MACV,KAAK,EAAE,OAAA,EAAS,iCAAmC,EAAA,SAAA,EAAW,OAAO,CAAA;AAAA,MACrE,OAAO,EAAE,CAAA;AAAA,MACT,IAAK,CAAA,EAAE,OAAS,EAAA,iCAAA,EAAmC,CAAA;AAAA,MACnD,KAAM,CAAA;AAAA,QACJ,OAAS,EAAA,iCAAA;AAAA,QACT,SAAS,UAAW,EAAA;AAAA,OACrB,CAAA;AAAA,MACD,IAAK,CAAA;AAAA,QACH,OAAS,EAAA,iCAAA;AAAA,QACT,KAAM,CAAA,EAAE,cAAgB,EAAA,eAAA,EAAiB,UAAY,EAAA;AACnD,UAAA,QAAA,CAAS,SAAS,KAAM,CAAA,WAAA;AAAA,YACtB,8CAAA;AAAA,YACA,CAAG,EAAA,cAAA,CAAA,EAAA,CAAA;AAAA,WACL,CAAA;AACA,UAAA,QAAA,CAAS,SAAS,KAAM,CAAA,WAAA;AAAA,YACtB,+CAAA;AAAA,YACA,CAAG,EAAA,eAAA,CAAA,EAAA,CAAA;AAAA,WACL,CAAA;AAAA,SACF;AAAA,OACD,CAAA;AAAA,KACH;AAAA,IACA,oBAAA,EAAsB,IAAI,IAAS,KAAA;AACjC,MAAO,OAAA,UAAA,CAAW,GAAG,IAAM,EAAA;AAAA,QACzB,cAAgB,EAAA,IAAA;AAAA,OACjB,CAAA,CAAA;AAAA,KACH;AAAA,GACD,CAAA,CAAA;AAED,EAAM,MAAA,SAAA,GAAY,YAAY,MAAM;AAClC,IAAA,MAAM,KAAK,MAAO,CAAA,IAAA,CAAK,IAAI,aAAc,CAAA,CAAA,oBAAA,EAAuB,OAAO,EAAM,CAAA,EAAA,CAAA,CAAA,CAAA;AAC7E,IAAA,IAAI,EAAI,EAAA;AACN,MAAA,YAAA,CAAa,EAAE,CAAA,CAAA;AAAA,KACjB;AAAA,KACC,CAAC,YAAA,EAAc,MAAQ,EAAA,MAAA,CAAO,EAAE,CAAC,CAAA,CAAA;AAGpC,EAAA,SAAA,CAAU,MAAM;AACd,IAAO,MAAA,CAAA,EAAA,CAAG,eAAe,SAAS,CAAA,CAAA;AAClC,IAAA,OAAO,MAAM;AACX,MAAO,MAAA,CAAA,GAAA,CAAI,eAAe,SAAS,CAAA,CAAA;AAAA,KACrC,CAAA;AAAA,GACC,EAAA,CAAC,MAAQ,EAAA,SAAS,CAAC,CAAA,CAAA;AAEtB,EAAgB,eAAA,CAAA,SAAA,EAAW,CAAC,SAAS,CAAC,CAAA,CAAA;AAEtC,EAAO,OAAA,YAAA;AAAA,oBACJ,KAAA,CAAA,aAAA,CAAA,KAAA,EAAA;AAAA,MACC,GAAK,EAAA,WAAA;AAAA,MACJ,GAAG,KAAA;AAAA,MACJ,KAAO,EAAA;AAAA,QACL,GAAG,KAAA;AAAA,QACH,QAAU,EAAA,QAAA;AAAA,QACV,GAAK,EAAA,CAAA;AAAA,QACL,IAAM,EAAA,CAAA;AAAA,QACN,SAAA,EAAW,eAAe,IAAK,CAAA,KAAA,CAAM,CAAC,CAAQ,CAAA,IAAA,EAAA,IAAA,CAAK,MAAM,CAAC,CAAA,CAAA,MAAA,CAAA;AAAA,QAC1D,QAAU,EAAA,aAAA;AAAA,OACZ;AAAA,MACA,SAAW,EAAA,UAAA;AAAA,QACT,8EAAA;AAAA,QACA,SAAA;AAAA,OACF;AAAA,KAAA,EAEC,QACH,CAAA;AAAA,IACA,SAAA;AAAA,GACF,CAAA;AACF,CAAA;AAQA,SAAS,aAAc,CAAA;AAAA,EACrB,MAAA;AAAA,EACA,MAAA;AAAA,EACA,eAAA;AAAA,EACA,SAAA;AAAA,EACG,GAAA,WAAA;AACL,CAAuB,EAAA;AACrB,EAAA,MAAM,aAAgB,GAAA,WAAA;AAAA,IACpB,CAAC,KAAyC,KAAA;AACxC,MAAA,SAAA,GAAY,KAAK,CAAA,CAAA;AAGjB,MAAI,IAAA,KAAA,CAAM,QAAQ,QAAU,EAAA;AAC1B,QAAgB,eAAA,EAAA,CAAA;AAAA,OAClB;AAAA,KACF;AAAA,IACA,CAAC,iBAAiB,SAAS,CAAA;AAAA,GAC7B,CAAA;AAEA,EAAA,uBAAQ,KAAA,CAAA,aAAA,CAAA,MAAA,EAAA;AAAA,IAAO,MAAA;AAAA,IAAgB,SAAW,EAAA,aAAA;AAAA,IAAgB,GAAG,WAAA;AAAA,GAAa,CAAA,CAAA;AAC5E;;;;"}
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { BaseMetadata, DM, ThreadData, HistoryVersion } from '@liveblocks/core';
|
|
2
|
+
import { ThreadProps, ComposerProps } from '@liveblocks/react-ui';
|
|
3
|
+
import { Editor } from '@tiptap/react';
|
|
4
|
+
import React, { ComponentPropsWithoutRef, ComponentType, HTMLAttributes } from 'react';
|
|
5
|
+
import { BaseMetadata as BaseMetadata$1 } from '@liveblocks/client';
|
|
6
|
+
import { Extension } from '@tiptap/core';
|
|
7
|
+
|
|
8
|
+
declare type AnchoredThreadsComponents = {
|
|
9
|
+
Thread: ComponentType<ThreadProps>;
|
|
10
|
+
};
|
|
11
|
+
interface AnchoredThreadsProps<M extends BaseMetadata = DM> extends Omit<ComponentPropsWithoutRef<"div">, "children"> {
|
|
12
|
+
/**
|
|
13
|
+
* The threads to display.
|
|
14
|
+
*/
|
|
15
|
+
threads: ThreadData<M>[];
|
|
16
|
+
/**
|
|
17
|
+
* Override the component's components.
|
|
18
|
+
*/
|
|
19
|
+
components?: Partial<AnchoredThreadsComponents>;
|
|
20
|
+
/**
|
|
21
|
+
* The tiptap editor
|
|
22
|
+
*/
|
|
23
|
+
editor: Editor | null;
|
|
24
|
+
}
|
|
25
|
+
declare function AnchoredThreads({ threads, components, className, style, editor, ...props }: AnchoredThreadsProps): React.JSX.Element | null;
|
|
26
|
+
|
|
27
|
+
declare const FloatingComposer: React.ForwardRefExoticComponent<Omit<ComposerProps<BaseMetadata$1>, "threadId" | "commentId"> & {
|
|
28
|
+
editor: Editor | null;
|
|
29
|
+
} & React.RefAttributes<HTMLFormElement>>;
|
|
30
|
+
|
|
31
|
+
declare type ThreadPanelComponents = {
|
|
32
|
+
Thread: ComponentType<ThreadProps>;
|
|
33
|
+
};
|
|
34
|
+
interface FloatingThreadsProps<M extends BaseMetadata = DM> extends Omit<HTMLAttributes<HTMLDivElement>, "children"> {
|
|
35
|
+
/**
|
|
36
|
+
* The threads to display.
|
|
37
|
+
*/
|
|
38
|
+
threads: ThreadData<M>[];
|
|
39
|
+
/**
|
|
40
|
+
* Override the component's components.
|
|
41
|
+
*/
|
|
42
|
+
components?: Partial<ThreadPanelComponents>;
|
|
43
|
+
/**
|
|
44
|
+
* The tiptap editor
|
|
45
|
+
*/
|
|
46
|
+
editor: Editor | null;
|
|
47
|
+
}
|
|
48
|
+
declare function FloatingThreads({ threads, components, editor, ...props }: FloatingThreadsProps): React.JSX.Element | null;
|
|
49
|
+
|
|
50
|
+
declare const useLiveblocksExtension: () => Extension;
|
|
51
|
+
|
|
52
|
+
interface HistoryVersionPreviewProps extends ComponentPropsWithoutRef<"div"> {
|
|
53
|
+
version: HistoryVersion;
|
|
54
|
+
editor: Editor;
|
|
55
|
+
onVersionRestore?: (version: HistoryVersion) => void;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Displays a specific version of the current TipTap document.
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* <HistoryVersionPreview version={version} />
|
|
62
|
+
*/
|
|
63
|
+
declare const HistoryVersionPreview: React.ForwardRefExoticComponent<HistoryVersionPreviewProps & React.RefAttributes<HTMLDivElement>>;
|
|
64
|
+
|
|
65
|
+
declare module "@tiptap/core" {
|
|
66
|
+
interface Commands<ReturnType> {
|
|
67
|
+
comments: {
|
|
68
|
+
/**
|
|
69
|
+
* Add a comment
|
|
70
|
+
*/
|
|
71
|
+
addComment: (id: string) => ReturnType;
|
|
72
|
+
selectThread: (id: string | null) => ReturnType;
|
|
73
|
+
addPendingComment: () => ReturnType;
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export { AnchoredThreads, FloatingComposer, FloatingThreads, HistoryVersionPreview, useLiveblocksExtension };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { BaseMetadata, DM, ThreadData, HistoryVersion } from '@liveblocks/core';
|
|
2
|
+
import { ThreadProps, ComposerProps } from '@liveblocks/react-ui';
|
|
3
|
+
import { Editor } from '@tiptap/react';
|
|
4
|
+
import React, { ComponentPropsWithoutRef, ComponentType, HTMLAttributes } from 'react';
|
|
5
|
+
import { BaseMetadata as BaseMetadata$1 } from '@liveblocks/client';
|
|
6
|
+
import { Extension } from '@tiptap/core';
|
|
7
|
+
|
|
8
|
+
declare type AnchoredThreadsComponents = {
|
|
9
|
+
Thread: ComponentType<ThreadProps>;
|
|
10
|
+
};
|
|
11
|
+
interface AnchoredThreadsProps<M extends BaseMetadata = DM> extends Omit<ComponentPropsWithoutRef<"div">, "children"> {
|
|
12
|
+
/**
|
|
13
|
+
* The threads to display.
|
|
14
|
+
*/
|
|
15
|
+
threads: ThreadData<M>[];
|
|
16
|
+
/**
|
|
17
|
+
* Override the component's components.
|
|
18
|
+
*/
|
|
19
|
+
components?: Partial<AnchoredThreadsComponents>;
|
|
20
|
+
/**
|
|
21
|
+
* The tiptap editor
|
|
22
|
+
*/
|
|
23
|
+
editor: Editor | null;
|
|
24
|
+
}
|
|
25
|
+
declare function AnchoredThreads({ threads, components, className, style, editor, ...props }: AnchoredThreadsProps): React.JSX.Element | null;
|
|
26
|
+
|
|
27
|
+
declare const FloatingComposer: React.ForwardRefExoticComponent<Omit<ComposerProps<BaseMetadata$1>, "threadId" | "commentId"> & {
|
|
28
|
+
editor: Editor | null;
|
|
29
|
+
} & React.RefAttributes<HTMLFormElement>>;
|
|
30
|
+
|
|
31
|
+
declare type ThreadPanelComponents = {
|
|
32
|
+
Thread: ComponentType<ThreadProps>;
|
|
33
|
+
};
|
|
34
|
+
interface FloatingThreadsProps<M extends BaseMetadata = DM> extends Omit<HTMLAttributes<HTMLDivElement>, "children"> {
|
|
35
|
+
/**
|
|
36
|
+
* The threads to display.
|
|
37
|
+
*/
|
|
38
|
+
threads: ThreadData<M>[];
|
|
39
|
+
/**
|
|
40
|
+
* Override the component's components.
|
|
41
|
+
*/
|
|
42
|
+
components?: Partial<ThreadPanelComponents>;
|
|
43
|
+
/**
|
|
44
|
+
* The tiptap editor
|
|
45
|
+
*/
|
|
46
|
+
editor: Editor | null;
|
|
47
|
+
}
|
|
48
|
+
declare function FloatingThreads({ threads, components, editor, ...props }: FloatingThreadsProps): React.JSX.Element | null;
|
|
49
|
+
|
|
50
|
+
declare const useLiveblocksExtension: () => Extension;
|
|
51
|
+
|
|
52
|
+
interface HistoryVersionPreviewProps extends ComponentPropsWithoutRef<"div"> {
|
|
53
|
+
version: HistoryVersion;
|
|
54
|
+
editor: Editor;
|
|
55
|
+
onVersionRestore?: (version: HistoryVersion) => void;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Displays a specific version of the current TipTap document.
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* <HistoryVersionPreview version={version} />
|
|
62
|
+
*/
|
|
63
|
+
declare const HistoryVersionPreview: React.ForwardRefExoticComponent<HistoryVersionPreviewProps & React.RefAttributes<HTMLDivElement>>;
|
|
64
|
+
|
|
65
|
+
declare module "@tiptap/core" {
|
|
66
|
+
interface Commands<ReturnType> {
|
|
67
|
+
comments: {
|
|
68
|
+
/**
|
|
69
|
+
* Add a comment
|
|
70
|
+
*/
|
|
71
|
+
addComment: (id: string) => ReturnType;
|
|
72
|
+
selectThread: (id: string | null) => ReturnType;
|
|
73
|
+
addPendingComment: () => ReturnType;
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export { AnchoredThreads, FloatingComposer, FloatingThreads, HistoryVersionPreview, useLiveblocksExtension };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var core = require('@liveblocks/core');
|
|
4
|
+
var version = require('./version.js');
|
|
5
|
+
var AnchoredThreads = require('./comments/AnchoredThreads.js');
|
|
6
|
+
var FloatingComposer = require('./comments/FloatingComposer.js');
|
|
7
|
+
var FloatingThreads = require('./comments/FloatingThreads.js');
|
|
8
|
+
var LiveblocksExtension = require('./LiveblocksExtension.js');
|
|
9
|
+
var HistoryVersionPreview = require('./version-history/HistoryVersionPreview.js');
|
|
10
|
+
|
|
11
|
+
core.detectDupes(version.PKG_NAME, version.PKG_VERSION, version.PKG_FORMAT);
|
|
12
|
+
|
|
13
|
+
exports.AnchoredThreads = AnchoredThreads.AnchoredThreads;
|
|
14
|
+
exports.FloatingComposer = FloatingComposer.FloatingComposer;
|
|
15
|
+
exports.FloatingThreads = FloatingThreads.FloatingThreads;
|
|
16
|
+
exports.useLiveblocksExtension = LiveblocksExtension.useLiveblocksExtension;
|
|
17
|
+
exports.HistoryVersionPreview = HistoryVersionPreview.HistoryVersionPreview;
|
|
18
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":["import { detectDupes } from \"@liveblocks/core\";\n\nimport { PKG_FORMAT, PKG_NAME, PKG_VERSION } from \"./version\";\n\ndetectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);\n\nexport { AnchoredThreads } from \"./comments/AnchoredThreads\";\nexport { FloatingComposer } from \"./comments/FloatingComposer\";\nexport { FloatingThreads } from \"./comments/FloatingThreads\";\nexport { useLiveblocksExtension } from \"./LiveblocksExtension\";\nexport { HistoryVersionPreview } from \"./version-history/HistoryVersionPreview\";\n\ndeclare module \"@tiptap/core\" {\n interface Commands<ReturnType> {\n comments: {\n /**\n * Add a comment\n */\n addComment: (id: string) => ReturnType;\n selectThread: (id: string | null) => ReturnType;\n addPendingComment: () => ReturnType;\n };\n }\n}\n"],"names":["detectDupes","PKG_NAME","PKG_VERSION","PKG_FORMAT"],"mappings":";;;;;;;;;;AAIAA,gBAAY,CAAAC,gBAAA,EAAUC,qBAAaC,kBAAU,CAAA;;;;;;;;"}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { detectDupes } from '@liveblocks/core';
|
|
2
|
+
import { PKG_NAME, PKG_VERSION, PKG_FORMAT } from './version.mjs';
|
|
3
|
+
export { AnchoredThreads } from './comments/AnchoredThreads.mjs';
|
|
4
|
+
export { FloatingComposer } from './comments/FloatingComposer.mjs';
|
|
5
|
+
export { FloatingThreads } from './comments/FloatingThreads.mjs';
|
|
6
|
+
export { useLiveblocksExtension } from './LiveblocksExtension.mjs';
|
|
7
|
+
export { HistoryVersionPreview } from './version-history/HistoryVersionPreview.mjs';
|
|
8
|
+
|
|
9
|
+
detectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);
|
|
10
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":["../src/index.ts"],"sourcesContent":["import { detectDupes } from \"@liveblocks/core\";\n\nimport { PKG_FORMAT, PKG_NAME, PKG_VERSION } from \"./version\";\n\ndetectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);\n\nexport { AnchoredThreads } from \"./comments/AnchoredThreads\";\nexport { FloatingComposer } from \"./comments/FloatingComposer\";\nexport { FloatingThreads } from \"./comments/FloatingThreads\";\nexport { useLiveblocksExtension } from \"./LiveblocksExtension\";\nexport { HistoryVersionPreview } from \"./version-history/HistoryVersionPreview\";\n\ndeclare module \"@tiptap/core\" {\n interface Commands<ReturnType> {\n comments: {\n /**\n * Add a comment\n */\n addComment: (id: string) => ReturnType;\n selectThread: (id: string | null) => ReturnType;\n addPendingComment: () => ReturnType;\n };\n }\n}\n"],"names":[],"mappings":";;;;;;;;AAIA,WAAY,CAAA,QAAA,EAAU,aAAa,UAAU,CAAA"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var react = require('@liveblocks/react');
|
|
4
|
+
var React = require('react');
|
|
5
|
+
var classnames = require('../classnames.js');
|
|
6
|
+
|
|
7
|
+
const Avatar = React.forwardRef(
|
|
8
|
+
function Avatar2(props, forwardedRef) {
|
|
9
|
+
const { userId, className, ...spanProps } = props;
|
|
10
|
+
const { user, isLoading } = react.useUser(userId);
|
|
11
|
+
const avatar = user ? user.avatar : void 0;
|
|
12
|
+
const name = user ? user.name : void 0;
|
|
13
|
+
function Initials() {
|
|
14
|
+
const initials = name ? getInitials(name) : void 0;
|
|
15
|
+
if (initials) {
|
|
16
|
+
return /* @__PURE__ */ React.createElement("span", {
|
|
17
|
+
"aria-hidden": true,
|
|
18
|
+
className: "lb-avatar-fallback"
|
|
19
|
+
}, initials);
|
|
20
|
+
}
|
|
21
|
+
if (isLoading)
|
|
22
|
+
return null;
|
|
23
|
+
if (user === void 0)
|
|
24
|
+
return null;
|
|
25
|
+
return /* @__PURE__ */ React.createElement("span", {
|
|
26
|
+
"aria-label": userId,
|
|
27
|
+
title: userId,
|
|
28
|
+
className: "lb-avatar-fallback"
|
|
29
|
+
}, getInitials(userId));
|
|
30
|
+
}
|
|
31
|
+
return /* @__PURE__ */ React.createElement("span", {
|
|
32
|
+
"data-loading": isLoading ? "" : void 0,
|
|
33
|
+
...spanProps,
|
|
34
|
+
className: classnames.classNames("lb-avatar", className),
|
|
35
|
+
ref: forwardedRef
|
|
36
|
+
}, avatar && /* @__PURE__ */ React.createElement("img", {
|
|
37
|
+
src: avatar,
|
|
38
|
+
alt: name,
|
|
39
|
+
className: "lb-avatar-image"
|
|
40
|
+
}), /* @__PURE__ */ React.createElement(Initials, null));
|
|
41
|
+
}
|
|
42
|
+
);
|
|
43
|
+
function getInitials(name) {
|
|
44
|
+
return name.trim().split(" ").reduce((initials, name2, index, array) => {
|
|
45
|
+
if (index === 0 || index === array.length - 1) {
|
|
46
|
+
initials += name2.charAt(0).toLocaleUpperCase();
|
|
47
|
+
}
|
|
48
|
+
return initials;
|
|
49
|
+
}, "");
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
exports.Avatar = Avatar;
|
|
53
|
+
//# sourceMappingURL=Avatar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Avatar.js","sources":["../../src/mentions/Avatar.tsx"],"sourcesContent":["import { useUser } from \"@liveblocks/react\";\nimport type { HTMLAttributes } from \"react\";\nimport React, { forwardRef } from \"react\";\n\nimport { classNames } from \"../classnames\";\n\nexport interface AvatarProps\n extends Omit<HTMLAttributes<HTMLDivElement>, \"children\"> {\n userId: string;\n}\n\nexport const Avatar = forwardRef<HTMLSpanElement, AvatarProps>(\n function Avatar(props, forwardedRef) {\n const { userId, className, ...spanProps } = props;\n\n const { user, isLoading } = useUser(userId);\n\n const avatar = user ? user.avatar : undefined;\n\n const name = user ? user.name : undefined;\n\n function Initials() {\n const initials = name ? getInitials(name) : undefined;\n if (initials) {\n return (\n <span aria-hidden className=\"lb-avatar-fallback\">\n {initials}\n </span>\n );\n }\n\n if (isLoading) return null;\n\n if (user === undefined) return null;\n\n return (\n <span aria-label={userId} title={userId} className=\"lb-avatar-fallback\">\n {getInitials(userId)}\n </span>\n );\n }\n\n return (\n <span\n data-loading={isLoading ? \"\" : undefined}\n {...spanProps}\n className={classNames(\"lb-avatar\", className)}\n ref={forwardedRef}\n >\n {avatar && <img src={avatar} alt={name} className=\"lb-avatar-image\" />}\n\n <Initials />\n </span>\n );\n }\n);\n\nfunction getInitials(name: string) {\n return name\n .trim()\n .split(\" \")\n .reduce((initials, name, index, array) => {\n if (index === 0 || index === array.length - 1) {\n initials += name.charAt(0).toLocaleUpperCase();\n }\n\n return initials;\n }, \"\");\n}\n"],"names":["forwardRef","Avatar","useUser","classNames","name"],"mappings":";;;;;;AAWO,MAAM,MAAS,GAAAA,gBAAA;AAAA,EACpB,SAASC,OAAO,CAAA,KAAA,EAAO,YAAc,EAAA;AACnC,IAAA,MAAM,EAAE,MAAA,EAAQ,SAAc,EAAA,GAAA,SAAA,EAAc,GAAA,KAAA,CAAA;AAE5C,IAAA,MAAM,EAAE,IAAA,EAAM,SAAU,EAAA,GAAIC,cAAQ,MAAM,CAAA,CAAA;AAE1C,IAAM,MAAA,MAAA,GAAS,IAAO,GAAA,IAAA,CAAK,MAAS,GAAA,KAAA,CAAA,CAAA;AAEpC,IAAM,MAAA,IAAA,GAAO,IAAO,GAAA,IAAA,CAAK,IAAO,GAAA,KAAA,CAAA,CAAA;AAEhC,IAAA,SAAS,QAAW,GAAA;AAClB,MAAA,MAAM,QAAW,GAAA,IAAA,GAAO,WAAY,CAAA,IAAI,CAAI,GAAA,KAAA,CAAA,CAAA;AAC5C,MAAA,IAAI,QAAU,EAAA;AACZ,QAAA,uBACG,KAAA,CAAA,aAAA,CAAA,MAAA,EAAA;AAAA,UAAK,aAAW,EAAA,IAAA;AAAA,UAAC,SAAU,EAAA,oBAAA;AAAA,SAAA,EACzB,QACH,CAAA,CAAA;AAAA,OAEJ;AAEA,MAAI,IAAA,SAAA;AAAW,QAAO,OAAA,IAAA,CAAA;AAEtB,MAAA,IAAI,IAAS,KAAA,KAAA,CAAA;AAAW,QAAO,OAAA,IAAA,CAAA;AAE/B,MAAA,uBACG,KAAA,CAAA,aAAA,CAAA,MAAA,EAAA;AAAA,QAAK,YAAY,EAAA,MAAA;AAAA,QAAQ,KAAO,EAAA,MAAA;AAAA,QAAQ,SAAU,EAAA,oBAAA;AAAA,OAChD,EAAA,WAAA,CAAY,MAAM,CACrB,CAAA,CAAA;AAAA,KAEJ;AAEA,IAAA,uBACG,KAAA,CAAA,aAAA,CAAA,MAAA,EAAA;AAAA,MACC,cAAA,EAAc,YAAY,EAAK,GAAA,KAAA,CAAA;AAAA,MAC9B,GAAG,SAAA;AAAA,MACJ,SAAA,EAAWC,qBAAW,CAAA,WAAA,EAAa,SAAS,CAAA;AAAA,MAC5C,GAAK,EAAA,YAAA;AAAA,KAAA,EAEJ,0BAAW,KAAA,CAAA,aAAA,CAAA,KAAA,EAAA;AAAA,MAAI,GAAK,EAAA,MAAA;AAAA,MAAQ,GAAK,EAAA,IAAA;AAAA,MAAM,SAAU,EAAA,iBAAA;AAAA,KAAkB,CAAA,kBAEnE,KAAA,CAAA,aAAA,CAAA,QAAA,EAAA,IAAS,CACZ,CAAA,CAAA;AAAA,GAEJ;AACF,EAAA;AAEA,SAAS,YAAY,IAAc,EAAA;AACjC,EAAO,OAAA,IAAA,CACJ,IAAK,EAAA,CACL,KAAM,CAAA,GAAG,CACT,CAAA,MAAA,CAAO,CAAC,QAAA,EAAUC,KAAM,EAAA,KAAA,EAAO,KAAU,KAAA;AACxC,IAAA,IAAI,KAAU,KAAA,CAAA,IAAK,KAAU,KAAA,KAAA,CAAM,SAAS,CAAG,EAAA;AAC7C,MAAA,QAAA,IAAYA,KAAK,CAAA,MAAA,CAAO,CAAC,CAAA,CAAE,iBAAkB,EAAA,CAAA;AAAA,KAC/C;AAEA,IAAO,OAAA,QAAA,CAAA;AAAA,KACN,EAAE,CAAA,CAAA;AACT;;;;"}
|