@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.
Files changed (69) hide show
  1. package/dist/LiveblocksExtension.js +206 -0
  2. package/dist/LiveblocksExtension.js.map +1 -0
  3. package/dist/LiveblocksExtension.mjs +204 -0
  4. package/dist/LiveblocksExtension.mjs.map +1 -0
  5. package/dist/classnames.js +8 -0
  6. package/dist/classnames.js.map +1 -0
  7. package/dist/classnames.mjs +6 -0
  8. package/dist/classnames.mjs.map +1 -0
  9. package/dist/comments/AnchoredThreads.js +178 -0
  10. package/dist/comments/AnchoredThreads.js.map +1 -0
  11. package/dist/comments/AnchoredThreads.mjs +176 -0
  12. package/dist/comments/AnchoredThreads.mjs.map +1 -0
  13. package/dist/comments/CommentsExtension.js +224 -0
  14. package/dist/comments/CommentsExtension.js.map +1 -0
  15. package/dist/comments/CommentsExtension.mjs +222 -0
  16. package/dist/comments/CommentsExtension.mjs.map +1 -0
  17. package/dist/comments/FloatingComposer.js +100 -0
  18. package/dist/comments/FloatingComposer.js.map +1 -0
  19. package/dist/comments/FloatingComposer.mjs +97 -0
  20. package/dist/comments/FloatingComposer.mjs.map +1 -0
  21. package/dist/comments/FloatingThreads.js +159 -0
  22. package/dist/comments/FloatingThreads.js.map +1 -0
  23. package/dist/comments/FloatingThreads.mjs +156 -0
  24. package/dist/comments/FloatingThreads.mjs.map +1 -0
  25. package/dist/index.d.mts +78 -0
  26. package/dist/index.d.ts +78 -0
  27. package/dist/index.js +18 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/index.mjs +10 -0
  30. package/dist/index.mjs.map +1 -0
  31. package/dist/mentions/Avatar.js +53 -0
  32. package/dist/mentions/Avatar.js.map +1 -0
  33. package/dist/mentions/Avatar.mjs +51 -0
  34. package/dist/mentions/Avatar.mjs.map +1 -0
  35. package/dist/mentions/Mention.js +24 -0
  36. package/dist/mentions/Mention.js.map +1 -0
  37. package/dist/mentions/Mention.mjs +22 -0
  38. package/dist/mentions/Mention.mjs.map +1 -0
  39. package/dist/mentions/MentionExtension.js +222 -0
  40. package/dist/mentions/MentionExtension.js.map +1 -0
  41. package/dist/mentions/MentionExtension.mjs +220 -0
  42. package/dist/mentions/MentionExtension.mjs.map +1 -0
  43. package/dist/mentions/MentionsList.js +123 -0
  44. package/dist/mentions/MentionsList.js.map +1 -0
  45. package/dist/mentions/MentionsList.mjs +119 -0
  46. package/dist/mentions/MentionsList.mjs.map +1 -0
  47. package/dist/types.js +33 -0
  48. package/dist/types.js.map +1 -0
  49. package/dist/types.mjs +24 -0
  50. package/dist/types.mjs.map +1 -0
  51. package/dist/utils.js +47 -0
  52. package/dist/utils.js.map +1 -0
  53. package/dist/utils.mjs +43 -0
  54. package/dist/utils.mjs.map +1 -0
  55. package/dist/version-history/HistoryVersionPreview.js +79 -0
  56. package/dist/version-history/HistoryVersionPreview.js.map +1 -0
  57. package/dist/version-history/HistoryVersionPreview.mjs +77 -0
  58. package/dist/version-history/HistoryVersionPreview.mjs.map +1 -0
  59. package/dist/version.js +10 -0
  60. package/dist/version.js.map +1 -0
  61. package/dist/version.mjs +6 -0
  62. package/dist/version.mjs.map +1 -0
  63. package/package.json +77 -1
  64. package/src/styles/constants.css +9 -0
  65. package/src/styles/index.css +250 -0
  66. package/src/styles/utils.css +6 -0
  67. package/styles.css +1 -0
  68. package/styles.css.d.ts +1 -0
  69. package/styles.css.map +1 -0
@@ -0,0 +1,178 @@
1
+ 'use strict';
2
+
3
+ var reactUi = require('@liveblocks/react-ui');
4
+ var React = require('react');
5
+ var classnames = require('../classnames.js');
6
+ var types = require('../types.js');
7
+ var utils = require('../utils.js');
8
+
9
+ const DEFAULT_GAP = 20;
10
+ const DEFAULT_ACTIVE_THREAD_OFFSET = -12;
11
+ const GAP = `var(--lb-tiptap-anchored-threads-gap, ${DEFAULT_GAP}px)`;
12
+ const ACTIVE_THREAD_OFFSET = `var(--lb-tiptap-anchored-threads-active-thread-offset, ${DEFAULT_ACTIVE_THREAD_OFFSET}px)`;
13
+ function AnchoredThreads({
14
+ threads,
15
+ components,
16
+ className,
17
+ style,
18
+ editor,
19
+ ...props
20
+ }) {
21
+ const Thread = components?.Thread ?? reactUi.Thread;
22
+ const containerRef = React.useRef(null);
23
+ const [orderedThreads, setOrderedThreads] = React.useState([]);
24
+ const [elements, setElements] = React.useState(/* @__PURE__ */ new Map());
25
+ const [positions, setPositions] = React.useState(/* @__PURE__ */ new Map());
26
+ const pluginState = editor ? types.THREADS_PLUGIN_KEY.getState(editor.state) : null;
27
+ const handlePositionThreads = React.useCallback(() => {
28
+ const container = containerRef.current;
29
+ if (container === null || !editor)
30
+ return;
31
+ const activeIndex = orderedThreads.findIndex(
32
+ ({ thread }) => thread.id === pluginState?.selectedThreadId
33
+ );
34
+ const ascending = activeIndex !== -1 ? orderedThreads.slice(activeIndex) : orderedThreads;
35
+ const descending = activeIndex !== -1 ? orderedThreads.slice(0, activeIndex) : [];
36
+ const newPositions = /* @__PURE__ */ new Map();
37
+ for (const { thread, position } of ascending) {
38
+ const coords = editor.view.coordsAtPos(Math.min(position.from, editor.view.state.doc.content.size - 1));
39
+ const rect = utils.getRectFromCoords(coords);
40
+ let top = rect.top - container.getBoundingClientRect().top;
41
+ for (const [id, position2] of newPositions) {
42
+ const el = elements.get(id);
43
+ if (el === void 0)
44
+ continue;
45
+ if (top >= position2 && top <= position2 + el.getBoundingClientRect().height) {
46
+ top = position2 + el.getBoundingClientRect().height;
47
+ }
48
+ }
49
+ newPositions.set(thread.id, top);
50
+ }
51
+ for (const { thread, position } of descending.reverse()) {
52
+ const coords = editor.view.coordsAtPos(position.from);
53
+ const rect = utils.getRectFromCoords(coords);
54
+ const el = elements.get(thread.id);
55
+ if (el === void 0)
56
+ continue;
57
+ let top = rect.top - container.getBoundingClientRect().top;
58
+ for (const [, position2] of newPositions) {
59
+ if (top >= position2 - el.getBoundingClientRect().height) {
60
+ top = position2 - el.getBoundingClientRect().height;
61
+ }
62
+ }
63
+ newPositions.set(thread.id, top);
64
+ }
65
+ setPositions(newPositions);
66
+ }, [editor, orderedThreads, pluginState?.selectedThreadId, elements]);
67
+ React.useEffect(() => {
68
+ if (!pluginState)
69
+ return;
70
+ setOrderedThreads(Array.from(pluginState.threadPositions, ([threadId, position]) => ({ threadId, position })).reduce((acc, { threadId, position }) => {
71
+ const thread = threads.find((thread2) => thread2.id === threadId && !thread2.resolved);
72
+ if (!thread)
73
+ return acc;
74
+ acc.push({ thread, position });
75
+ return acc;
76
+ }, []));
77
+ handlePositionThreads();
78
+ }, [pluginState, threads]);
79
+ React.useLayoutEffect(() => {
80
+ handlePositionThreads();
81
+ }, [handlePositionThreads]);
82
+ React.useEffect(() => {
83
+ const observer = new ResizeObserver(handlePositionThreads);
84
+ for (const element of elements.values()) {
85
+ observer.observe(element);
86
+ }
87
+ return () => observer.disconnect();
88
+ }, [elements, handlePositionThreads]);
89
+ const onItemAdd = React.useCallback((id, el) => {
90
+ setElements((prev) => new Map(prev).set(id, el));
91
+ }, []);
92
+ const onItemRemove = React.useCallback((id) => {
93
+ setElements((prev) => {
94
+ const items = new Map(prev);
95
+ items.delete(id);
96
+ return items;
97
+ });
98
+ }, []);
99
+ const onThreadSelect = React.useCallback((id) => {
100
+ if (!editor)
101
+ return;
102
+ editor.commands.selectThread(id);
103
+ }, [editor]);
104
+ if (!editor)
105
+ return null;
106
+ return /* @__PURE__ */ React.createElement("div", {
107
+ ...props,
108
+ className: classnames.classNames(className, "lb-root lb-tiptap-anchored-threads"),
109
+ ref: containerRef,
110
+ style: {
111
+ position: "relative",
112
+ ...style
113
+ }
114
+ }, orderedThreads.map(({ thread, position }) => {
115
+ const coords = editor.view.coordsAtPos(Math.min(position.from, editor.state.doc.content.size - 1));
116
+ const rect = utils.getRectFromCoords(coords);
117
+ const offset = editor.options.element.getBoundingClientRect().top;
118
+ let top = rect.top - offset;
119
+ if (positions.has(thread.id)) {
120
+ top = positions.get(thread.id);
121
+ }
122
+ const isActive = thread.id === pluginState?.selectedThreadId;
123
+ return /* @__PURE__ */ React.createElement(ThreadWrapper, {
124
+ key: thread.id,
125
+ onThreadClick: onThreadSelect,
126
+ onItemAdd,
127
+ onItemRemove,
128
+ Thread,
129
+ thread,
130
+ isActive,
131
+ style: {
132
+ position: "absolute",
133
+ transform: `translate3d(${isActive ? ACTIVE_THREAD_OFFSET : 0}, ${top}px, 0)`,
134
+ insetInlineStart: 0,
135
+ inlineSize: "100%",
136
+ paddingBlockEnd: GAP
137
+ }
138
+ });
139
+ }));
140
+ }
141
+ function ThreadWrapper({
142
+ onThreadClick,
143
+ onItemAdd,
144
+ onItemRemove,
145
+ thread,
146
+ Thread,
147
+ className,
148
+ isActive,
149
+ ...props
150
+ }) {
151
+ const handleRef = React.useCallback(
152
+ (el) => {
153
+ onItemAdd(thread.id, el);
154
+ return () => onItemRemove(thread.id);
155
+ },
156
+ [thread.id, onItemAdd, onItemRemove]
157
+ );
158
+ function handleThreadClick() {
159
+ onThreadClick(thread.id);
160
+ }
161
+ return /* @__PURE__ */ React.createElement("div", {
162
+ ref: handleRef,
163
+ className: classnames.classNames(
164
+ "lb-tiptap-anchored-threads-thread-container",
165
+ className
166
+ ),
167
+ ...props
168
+ }, /* @__PURE__ */ React.createElement(Thread, {
169
+ thread,
170
+ "data-state": isActive ? "active" : "inactive",
171
+ onClick: handleThreadClick,
172
+ className: "lb-tiptap-anchored-threads-thread",
173
+ showComposer: isActive ? true : false
174
+ }));
175
+ }
176
+
177
+ exports.AnchoredThreads = AnchoredThreads;
178
+ //# sourceMappingURL=AnchoredThreads.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AnchoredThreads.js","sources":["../../src/comments/AnchoredThreads.tsx"],"sourcesContent":["import 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 type { ComponentPropsWithoutRef, ComponentType } from \"react\";\nimport React, {\n useCallback,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n} from \"react\";\n\nimport { classNames } from \"../classnames\";\nimport type { ThreadPluginState } from \"../types\";\nimport { THREADS_PLUGIN_KEY } from \"../types\";\nimport { getRectFromCoords } from \"../utils\";\n\nconst DEFAULT_GAP = 20;\nconst DEFAULT_ACTIVE_THREAD_OFFSET = -12;\n\n// TODO: move that back to a variable\nconst GAP = `var(--lb-tiptap-anchored-threads-gap, ${DEFAULT_GAP}px)`;\nconst ACTIVE_THREAD_OFFSET = `var(--lb-tiptap-anchored-threads-active-thread-offset, ${DEFAULT_ACTIVE_THREAD_OFFSET}px)`;\n\ntype AnchoredThreadsComponents = {\n Thread: ComponentType<ThreadProps>;\n};\n\nexport interface AnchoredThreadsProps<M extends BaseMetadata = DM>\n extends Omit<ComponentPropsWithoutRef<\"div\">, \"children\"> {\n /**\n * The threads to display.\n */\n threads: ThreadData<M>[];\n\n /**\n * Override the component's components.\n */\n components?: Partial<AnchoredThreadsComponents>;\n /**\n * The tiptap editor\n */\n editor: Editor | null;\n}\n\nexport function AnchoredThreads({\n threads,\n components,\n className,\n style,\n editor,\n ...props\n}: AnchoredThreadsProps) {\n const Thread = components?.Thread ?? DefaultThread;\n const containerRef = useRef<HTMLDivElement>(null);\n const [orderedThreads, setOrderedThreads] = useState<{ position: { from: number, to: number }, thread: ThreadData }[]>([]);\n const [elements, setElements] = useState<Map<string, HTMLElement>>(new Map());\n const [positions, setPositions] = useState<Map<string, number>>(new Map()); // A map of thread ids to their 'top' position in the document\n\n const pluginState = editor ? THREADS_PLUGIN_KEY.getState(editor.state) as ThreadPluginState : null;\n\n // TODO: lexical supoprts multiple threads being active, should probably do that here as well\n const handlePositionThreads = useCallback(() => {\n const container = containerRef.current;\n if (container === null || !editor) return;\n\n const activeIndex = orderedThreads.findIndex(({ thread }) =>\n thread.id === pluginState?.selectedThreadId\n );\n const ascending = activeIndex !== -1 ? orderedThreads.slice(activeIndex) : orderedThreads;\n const descending = activeIndex !== -1 ? orderedThreads.slice(0, activeIndex) : [];\n\n const newPositions = new Map<string, number>();\n\n // Iterate over each thread and calculate its new position by taking into account the position of the previously positioned threads\n for (const { thread, position } of ascending) {\n const coords = editor.view.coordsAtPos(Math.min(position.from, editor.view.state.doc.content.size - 1));\n const rect = getRectFromCoords(coords);\n let top = rect.top - container.getBoundingClientRect().top;\n\n for (const [id, position] of newPositions) {\n // Retrieve the element associated with the thread\n const el = elements.get(id);\n if (el === undefined) continue;\n\n if (\n top >= position &&\n top <= position + el.getBoundingClientRect().height\n ) {\n top = position + el.getBoundingClientRect().height;\n }\n }\n\n newPositions.set(thread.id, top);\n }\n\n for (const { thread, position } of descending.reverse()) {\n const coords = editor.view.coordsAtPos(position.from);\n const rect = getRectFromCoords(coords);\n // Retrieve the element associated with the current thread\n const el = elements.get(thread.id);\n if (el === undefined) continue;\n\n let top = rect.top - container.getBoundingClientRect().top;\n for (const [, position] of newPositions) {\n if (top >= position - el.getBoundingClientRect().height) {\n top = position - el.getBoundingClientRect().height;\n }\n }\n\n newPositions.set(thread.id, top);\n }\n\n setPositions(newPositions);\n }, [editor, orderedThreads, pluginState?.selectedThreadId, elements]);\n\n useEffect(() => {\n if (!pluginState) return;\n setOrderedThreads(Array.from(pluginState.threadPositions, ([threadId, position]) => ({ threadId, position })).reduce((acc, { threadId, position }) => {\n const thread = threads.find((thread) => thread.id === threadId && !thread.resolved);\n if (!thread) return acc;\n acc.push({ thread, position });\n return acc;\n }, [] as { thread: ThreadData, position: { from: number, to: number } }[]));\n handlePositionThreads();\n // disable exhaustive deps because we don't want an infinite loop\n // eslint-disable-next-line react-hooks/exhaustive-deps \n }, [pluginState, threads]);\n\n\n useLayoutEffect(() => {\n handlePositionThreads();\n }, [handlePositionThreads]);\n\n useEffect(() => {\n const observer = new ResizeObserver(handlePositionThreads);\n for (const element of elements.values()) {\n observer.observe(element);\n }\n\n return () => observer.disconnect();\n }, [elements, handlePositionThreads]);\n\n const onItemAdd = useCallback((id: string, el: HTMLElement) => {\n setElements((prev) => new Map(prev).set(id, el));\n }, []);\n\n const onItemRemove = useCallback((id: string) => {\n setElements((prev) => {\n const items = new Map(prev);\n items.delete(id);\n return items;\n });\n }, []);\n\n const onThreadSelect = useCallback((id: string) => {\n if (!editor) return;\n editor.commands.selectThread(id);\n }, [editor]);\n\n\n if (!editor) return null;\n\n return (\n <div\n {...props}\n className={classNames(className, \"lb-root lb-tiptap-anchored-threads\")}\n ref={containerRef}\n style={{\n position: \"relative\",\n ...style,\n }}\n >\n {orderedThreads.map(({ thread, position }) => {\n const coords = editor.view.coordsAtPos(Math.min(position.from, editor.state.doc.content.size - 1));\n const rect = getRectFromCoords(coords);\n const offset = editor.options.element.getBoundingClientRect().top;\n\n let top = rect.top - offset;\n\n if (positions.has(thread.id)) {\n top = positions.get(thread.id)!;\n }\n\n const isActive = thread.id === pluginState?.selectedThreadId;\n\n return (\n <ThreadWrapper\n key={thread.id}\n onThreadClick={onThreadSelect}\n onItemAdd={onItemAdd}\n onItemRemove={onItemRemove}\n Thread={Thread}\n thread={thread}\n isActive={isActive}\n style={{\n position: \"absolute\",\n transform: `translate3d(${isActive ? ACTIVE_THREAD_OFFSET : 0}, ${top}px, 0)`,\n insetInlineStart: 0,\n inlineSize: \"100%\",\n paddingBlockEnd: GAP,\n }}\n />\n );\n })}\n </div>\n );\n}\n\ninterface ThreadWrapperProps extends ThreadProps {\n Thread: ComponentType<ThreadProps>;\n onThreadClick: (id: string) => void;\n onItemAdd: (id: string, el: HTMLElement) => void;\n onItemRemove: (id: string) => void;\n isActive: boolean;\n}\n\nfunction ThreadWrapper({\n onThreadClick,\n onItemAdd,\n onItemRemove,\n thread,\n Thread,\n className,\n isActive,\n ...props\n}: ThreadWrapperProps) {\n\n const handleRef = useCallback(\n (el: HTMLDivElement) => {\n onItemAdd(thread.id, el);\n return () => onItemRemove(thread.id);\n },\n [thread.id, onItemAdd, onItemRemove]\n );\n\n\n function handleThreadClick() {\n onThreadClick(thread.id);\n }\n\n return (\n <div\n ref={handleRef}\n className={classNames(\n \"lb-tiptap-anchored-threads-thread-container\",\n className\n )}\n {...props}\n >\n <Thread\n thread={thread}\n data-state={isActive ? \"active\" : \"inactive\"}\n onClick={handleThreadClick}\n className=\"lb-tiptap-anchored-threads-thread\"\n showComposer={isActive ? true : false}\n />\n </div>\n );\n}\n"],"names":["DefaultThread","useRef","useState","THREADS_PLUGIN_KEY","useCallback","getRectFromCoords","position","useEffect","thread","useLayoutEffect","classNames"],"mappings":"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"}
@@ -0,0 +1,176 @@
1
+ import { Thread } from '@liveblocks/react-ui';
2
+ import React, { useRef, useState, useCallback, useEffect, useLayoutEffect } from 'react';
3
+ import { classNames } from '../classnames.mjs';
4
+ import { THREADS_PLUGIN_KEY } from '../types.mjs';
5
+ import { getRectFromCoords } from '../utils.mjs';
6
+
7
+ const DEFAULT_GAP = 20;
8
+ const DEFAULT_ACTIVE_THREAD_OFFSET = -12;
9
+ const GAP = `var(--lb-tiptap-anchored-threads-gap, ${DEFAULT_GAP}px)`;
10
+ const ACTIVE_THREAD_OFFSET = `var(--lb-tiptap-anchored-threads-active-thread-offset, ${DEFAULT_ACTIVE_THREAD_OFFSET}px)`;
11
+ function AnchoredThreads({
12
+ threads,
13
+ components,
14
+ className,
15
+ style,
16
+ editor,
17
+ ...props
18
+ }) {
19
+ const Thread$1 = components?.Thread ?? Thread;
20
+ const containerRef = useRef(null);
21
+ const [orderedThreads, setOrderedThreads] = useState([]);
22
+ const [elements, setElements] = useState(/* @__PURE__ */ new Map());
23
+ const [positions, setPositions] = useState(/* @__PURE__ */ new Map());
24
+ const pluginState = editor ? THREADS_PLUGIN_KEY.getState(editor.state) : null;
25
+ const handlePositionThreads = useCallback(() => {
26
+ const container = containerRef.current;
27
+ if (container === null || !editor)
28
+ return;
29
+ const activeIndex = orderedThreads.findIndex(
30
+ ({ thread }) => thread.id === pluginState?.selectedThreadId
31
+ );
32
+ const ascending = activeIndex !== -1 ? orderedThreads.slice(activeIndex) : orderedThreads;
33
+ const descending = activeIndex !== -1 ? orderedThreads.slice(0, activeIndex) : [];
34
+ const newPositions = /* @__PURE__ */ new Map();
35
+ for (const { thread, position } of ascending) {
36
+ const coords = editor.view.coordsAtPos(Math.min(position.from, editor.view.state.doc.content.size - 1));
37
+ const rect = getRectFromCoords(coords);
38
+ let top = rect.top - container.getBoundingClientRect().top;
39
+ for (const [id, position2] of newPositions) {
40
+ const el = elements.get(id);
41
+ if (el === void 0)
42
+ continue;
43
+ if (top >= position2 && top <= position2 + el.getBoundingClientRect().height) {
44
+ top = position2 + el.getBoundingClientRect().height;
45
+ }
46
+ }
47
+ newPositions.set(thread.id, top);
48
+ }
49
+ for (const { thread, position } of descending.reverse()) {
50
+ const coords = editor.view.coordsAtPos(position.from);
51
+ const rect = getRectFromCoords(coords);
52
+ const el = elements.get(thread.id);
53
+ if (el === void 0)
54
+ continue;
55
+ let top = rect.top - container.getBoundingClientRect().top;
56
+ for (const [, position2] of newPositions) {
57
+ if (top >= position2 - el.getBoundingClientRect().height) {
58
+ top = position2 - el.getBoundingClientRect().height;
59
+ }
60
+ }
61
+ newPositions.set(thread.id, top);
62
+ }
63
+ setPositions(newPositions);
64
+ }, [editor, orderedThreads, pluginState?.selectedThreadId, elements]);
65
+ useEffect(() => {
66
+ if (!pluginState)
67
+ return;
68
+ setOrderedThreads(Array.from(pluginState.threadPositions, ([threadId, position]) => ({ threadId, position })).reduce((acc, { threadId, position }) => {
69
+ const thread = threads.find((thread2) => thread2.id === threadId && !thread2.resolved);
70
+ if (!thread)
71
+ return acc;
72
+ acc.push({ thread, position });
73
+ return acc;
74
+ }, []));
75
+ handlePositionThreads();
76
+ }, [pluginState, threads]);
77
+ useLayoutEffect(() => {
78
+ handlePositionThreads();
79
+ }, [handlePositionThreads]);
80
+ useEffect(() => {
81
+ const observer = new ResizeObserver(handlePositionThreads);
82
+ for (const element of elements.values()) {
83
+ observer.observe(element);
84
+ }
85
+ return () => observer.disconnect();
86
+ }, [elements, handlePositionThreads]);
87
+ const onItemAdd = useCallback((id, el) => {
88
+ setElements((prev) => new Map(prev).set(id, el));
89
+ }, []);
90
+ const onItemRemove = useCallback((id) => {
91
+ setElements((prev) => {
92
+ const items = new Map(prev);
93
+ items.delete(id);
94
+ return items;
95
+ });
96
+ }, []);
97
+ const onThreadSelect = useCallback((id) => {
98
+ if (!editor)
99
+ return;
100
+ editor.commands.selectThread(id);
101
+ }, [editor]);
102
+ if (!editor)
103
+ return null;
104
+ return /* @__PURE__ */ React.createElement("div", {
105
+ ...props,
106
+ className: classNames(className, "lb-root lb-tiptap-anchored-threads"),
107
+ ref: containerRef,
108
+ style: {
109
+ position: "relative",
110
+ ...style
111
+ }
112
+ }, orderedThreads.map(({ thread, position }) => {
113
+ const coords = editor.view.coordsAtPos(Math.min(position.from, editor.state.doc.content.size - 1));
114
+ const rect = getRectFromCoords(coords);
115
+ const offset = editor.options.element.getBoundingClientRect().top;
116
+ let top = rect.top - offset;
117
+ if (positions.has(thread.id)) {
118
+ top = positions.get(thread.id);
119
+ }
120
+ const isActive = thread.id === pluginState?.selectedThreadId;
121
+ return /* @__PURE__ */ React.createElement(ThreadWrapper, {
122
+ key: thread.id,
123
+ onThreadClick: onThreadSelect,
124
+ onItemAdd,
125
+ onItemRemove,
126
+ Thread: Thread$1,
127
+ thread,
128
+ isActive,
129
+ style: {
130
+ position: "absolute",
131
+ transform: `translate3d(${isActive ? ACTIVE_THREAD_OFFSET : 0}, ${top}px, 0)`,
132
+ insetInlineStart: 0,
133
+ inlineSize: "100%",
134
+ paddingBlockEnd: GAP
135
+ }
136
+ });
137
+ }));
138
+ }
139
+ function ThreadWrapper({
140
+ onThreadClick,
141
+ onItemAdd,
142
+ onItemRemove,
143
+ thread,
144
+ Thread,
145
+ className,
146
+ isActive,
147
+ ...props
148
+ }) {
149
+ const handleRef = useCallback(
150
+ (el) => {
151
+ onItemAdd(thread.id, el);
152
+ return () => onItemRemove(thread.id);
153
+ },
154
+ [thread.id, onItemAdd, onItemRemove]
155
+ );
156
+ function handleThreadClick() {
157
+ onThreadClick(thread.id);
158
+ }
159
+ return /* @__PURE__ */ React.createElement("div", {
160
+ ref: handleRef,
161
+ className: classNames(
162
+ "lb-tiptap-anchored-threads-thread-container",
163
+ className
164
+ ),
165
+ ...props
166
+ }, /* @__PURE__ */ React.createElement(Thread, {
167
+ thread,
168
+ "data-state": isActive ? "active" : "inactive",
169
+ onClick: handleThreadClick,
170
+ className: "lb-tiptap-anchored-threads-thread",
171
+ showComposer: isActive ? true : false
172
+ }));
173
+ }
174
+
175
+ export { AnchoredThreads };
176
+ //# sourceMappingURL=AnchoredThreads.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AnchoredThreads.mjs","sources":["../../src/comments/AnchoredThreads.tsx"],"sourcesContent":["import 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 type { ComponentPropsWithoutRef, ComponentType } from \"react\";\nimport React, {\n useCallback,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n} from \"react\";\n\nimport { classNames } from \"../classnames\";\nimport type { ThreadPluginState } from \"../types\";\nimport { THREADS_PLUGIN_KEY } from \"../types\";\nimport { getRectFromCoords } from \"../utils\";\n\nconst DEFAULT_GAP = 20;\nconst DEFAULT_ACTIVE_THREAD_OFFSET = -12;\n\n// TODO: move that back to a variable\nconst GAP = `var(--lb-tiptap-anchored-threads-gap, ${DEFAULT_GAP}px)`;\nconst ACTIVE_THREAD_OFFSET = `var(--lb-tiptap-anchored-threads-active-thread-offset, ${DEFAULT_ACTIVE_THREAD_OFFSET}px)`;\n\ntype AnchoredThreadsComponents = {\n Thread: ComponentType<ThreadProps>;\n};\n\nexport interface AnchoredThreadsProps<M extends BaseMetadata = DM>\n extends Omit<ComponentPropsWithoutRef<\"div\">, \"children\"> {\n /**\n * The threads to display.\n */\n threads: ThreadData<M>[];\n\n /**\n * Override the component's components.\n */\n components?: Partial<AnchoredThreadsComponents>;\n /**\n * The tiptap editor\n */\n editor: Editor | null;\n}\n\nexport function AnchoredThreads({\n threads,\n components,\n className,\n style,\n editor,\n ...props\n}: AnchoredThreadsProps) {\n const Thread = components?.Thread ?? DefaultThread;\n const containerRef = useRef<HTMLDivElement>(null);\n const [orderedThreads, setOrderedThreads] = useState<{ position: { from: number, to: number }, thread: ThreadData }[]>([]);\n const [elements, setElements] = useState<Map<string, HTMLElement>>(new Map());\n const [positions, setPositions] = useState<Map<string, number>>(new Map()); // A map of thread ids to their 'top' position in the document\n\n const pluginState = editor ? THREADS_PLUGIN_KEY.getState(editor.state) as ThreadPluginState : null;\n\n // TODO: lexical supoprts multiple threads being active, should probably do that here as well\n const handlePositionThreads = useCallback(() => {\n const container = containerRef.current;\n if (container === null || !editor) return;\n\n const activeIndex = orderedThreads.findIndex(({ thread }) =>\n thread.id === pluginState?.selectedThreadId\n );\n const ascending = activeIndex !== -1 ? orderedThreads.slice(activeIndex) : orderedThreads;\n const descending = activeIndex !== -1 ? orderedThreads.slice(0, activeIndex) : [];\n\n const newPositions = new Map<string, number>();\n\n // Iterate over each thread and calculate its new position by taking into account the position of the previously positioned threads\n for (const { thread, position } of ascending) {\n const coords = editor.view.coordsAtPos(Math.min(position.from, editor.view.state.doc.content.size - 1));\n const rect = getRectFromCoords(coords);\n let top = rect.top - container.getBoundingClientRect().top;\n\n for (const [id, position] of newPositions) {\n // Retrieve the element associated with the thread\n const el = elements.get(id);\n if (el === undefined) continue;\n\n if (\n top >= position &&\n top <= position + el.getBoundingClientRect().height\n ) {\n top = position + el.getBoundingClientRect().height;\n }\n }\n\n newPositions.set(thread.id, top);\n }\n\n for (const { thread, position } of descending.reverse()) {\n const coords = editor.view.coordsAtPos(position.from);\n const rect = getRectFromCoords(coords);\n // Retrieve the element associated with the current thread\n const el = elements.get(thread.id);\n if (el === undefined) continue;\n\n let top = rect.top - container.getBoundingClientRect().top;\n for (const [, position] of newPositions) {\n if (top >= position - el.getBoundingClientRect().height) {\n top = position - el.getBoundingClientRect().height;\n }\n }\n\n newPositions.set(thread.id, top);\n }\n\n setPositions(newPositions);\n }, [editor, orderedThreads, pluginState?.selectedThreadId, elements]);\n\n useEffect(() => {\n if (!pluginState) return;\n setOrderedThreads(Array.from(pluginState.threadPositions, ([threadId, position]) => ({ threadId, position })).reduce((acc, { threadId, position }) => {\n const thread = threads.find((thread) => thread.id === threadId && !thread.resolved);\n if (!thread) return acc;\n acc.push({ thread, position });\n return acc;\n }, [] as { thread: ThreadData, position: { from: number, to: number } }[]));\n handlePositionThreads();\n // disable exhaustive deps because we don't want an infinite loop\n // eslint-disable-next-line react-hooks/exhaustive-deps \n }, [pluginState, threads]);\n\n\n useLayoutEffect(() => {\n handlePositionThreads();\n }, [handlePositionThreads]);\n\n useEffect(() => {\n const observer = new ResizeObserver(handlePositionThreads);\n for (const element of elements.values()) {\n observer.observe(element);\n }\n\n return () => observer.disconnect();\n }, [elements, handlePositionThreads]);\n\n const onItemAdd = useCallback((id: string, el: HTMLElement) => {\n setElements((prev) => new Map(prev).set(id, el));\n }, []);\n\n const onItemRemove = useCallback((id: string) => {\n setElements((prev) => {\n const items = new Map(prev);\n items.delete(id);\n return items;\n });\n }, []);\n\n const onThreadSelect = useCallback((id: string) => {\n if (!editor) return;\n editor.commands.selectThread(id);\n }, [editor]);\n\n\n if (!editor) return null;\n\n return (\n <div\n {...props}\n className={classNames(className, \"lb-root lb-tiptap-anchored-threads\")}\n ref={containerRef}\n style={{\n position: \"relative\",\n ...style,\n }}\n >\n {orderedThreads.map(({ thread, position }) => {\n const coords = editor.view.coordsAtPos(Math.min(position.from, editor.state.doc.content.size - 1));\n const rect = getRectFromCoords(coords);\n const offset = editor.options.element.getBoundingClientRect().top;\n\n let top = rect.top - offset;\n\n if (positions.has(thread.id)) {\n top = positions.get(thread.id)!;\n }\n\n const isActive = thread.id === pluginState?.selectedThreadId;\n\n return (\n <ThreadWrapper\n key={thread.id}\n onThreadClick={onThreadSelect}\n onItemAdd={onItemAdd}\n onItemRemove={onItemRemove}\n Thread={Thread}\n thread={thread}\n isActive={isActive}\n style={{\n position: \"absolute\",\n transform: `translate3d(${isActive ? ACTIVE_THREAD_OFFSET : 0}, ${top}px, 0)`,\n insetInlineStart: 0,\n inlineSize: \"100%\",\n paddingBlockEnd: GAP,\n }}\n />\n );\n })}\n </div>\n );\n}\n\ninterface ThreadWrapperProps extends ThreadProps {\n Thread: ComponentType<ThreadProps>;\n onThreadClick: (id: string) => void;\n onItemAdd: (id: string, el: HTMLElement) => void;\n onItemRemove: (id: string) => void;\n isActive: boolean;\n}\n\nfunction ThreadWrapper({\n onThreadClick,\n onItemAdd,\n onItemRemove,\n thread,\n Thread,\n className,\n isActive,\n ...props\n}: ThreadWrapperProps) {\n\n const handleRef = useCallback(\n (el: HTMLDivElement) => {\n onItemAdd(thread.id, el);\n return () => onItemRemove(thread.id);\n },\n [thread.id, onItemAdd, onItemRemove]\n );\n\n\n function handleThreadClick() {\n onThreadClick(thread.id);\n }\n\n return (\n <div\n ref={handleRef}\n className={classNames(\n \"lb-tiptap-anchored-threads-thread-container\",\n className\n )}\n {...props}\n >\n <Thread\n thread={thread}\n data-state={isActive ? \"active\" : \"inactive\"}\n onClick={handleThreadClick}\n className=\"lb-tiptap-anchored-threads-thread\"\n showComposer={isActive ? true : false}\n />\n </div>\n );\n}\n"],"names":["Thread","DefaultThread","position","thread"],"mappings":"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"}
@@ -0,0 +1,224 @@
1
+ 'use strict';
2
+
3
+ var core = require('@tiptap/core');
4
+ var state = require('@tiptap/pm/state');
5
+ var view = require('@tiptap/pm/view');
6
+ var yProsemirror = require('y-prosemirror');
7
+ var types = require('../types.js');
8
+
9
+ const Comment = core.Mark.create({
10
+ name: types.LIVEBLOCKS_COMMENT_MARK_TYPE,
11
+ excludes: "",
12
+ inclusive: false,
13
+ keepOnSplit: true,
14
+ addAttributes() {
15
+ return {
16
+ orphan: {
17
+ parseHTML: (element) => !!element.getAttribute("data-orphan"),
18
+ renderHTML: (attributes) => {
19
+ return attributes.orphan ? {
20
+ "data-orphan": "true"
21
+ } : {};
22
+ },
23
+ default: false
24
+ },
25
+ threadId: {
26
+ parseHTML: (element) => element.getAttribute("data-lb-thread-id"),
27
+ renderHTML: (attributes) => {
28
+ return {
29
+ "data-lb-thread-id": attributes.threadId
30
+ };
31
+ },
32
+ default: ""
33
+ }
34
+ };
35
+ },
36
+ renderHTML({ HTMLAttributes }) {
37
+ return [
38
+ "span",
39
+ core.mergeAttributes(HTMLAttributes, {
40
+ class: "lb-root lb-tiptap-thread-mark"
41
+ })
42
+ ];
43
+ },
44
+ addProseMirrorPlugins() {
45
+ const updateState = (doc, selectedThreadId) => {
46
+ const threadPositions = /* @__PURE__ */ new Map();
47
+ const decorations = [];
48
+ doc.descendants((node, pos) => {
49
+ node.marks.forEach((mark) => {
50
+ if (mark.type === this.type) {
51
+ const thisThreadId = mark.attrs.threadId;
52
+ if (!thisThreadId) {
53
+ return;
54
+ }
55
+ const from = pos;
56
+ const to = from + node.nodeSize;
57
+ const currentPosition = threadPositions.get(thisThreadId) ?? {
58
+ from: Infinity,
59
+ to: 0
60
+ };
61
+ threadPositions.set(thisThreadId, {
62
+ from: Math.min(from, currentPosition.from),
63
+ to: Math.max(to, currentPosition.to)
64
+ });
65
+ if (selectedThreadId === thisThreadId) {
66
+ decorations.push(
67
+ view.Decoration.inline(from, to, {
68
+ class: "lb-root lb-tiptap-thread-mark-selected"
69
+ })
70
+ );
71
+ }
72
+ }
73
+ });
74
+ });
75
+ return {
76
+ decorations: view.DecorationSet.create(doc, decorations),
77
+ selectedThreadId,
78
+ threadPositions,
79
+ selectedThreadPos: selectedThreadId !== null ? threadPositions.get(selectedThreadId)?.to ?? null : null
80
+ };
81
+ };
82
+ return [
83
+ new state.Plugin({
84
+ key: types.THREADS_PLUGIN_KEY,
85
+ state: {
86
+ init() {
87
+ return {
88
+ threadPositions: /* @__PURE__ */ new Map(),
89
+ selectedThreadId: null,
90
+ selectedThreadPos: null,
91
+ decorations: view.DecorationSet.empty
92
+ };
93
+ },
94
+ apply(tr, state) {
95
+ const action = tr.getMeta(types.THREADS_PLUGIN_KEY);
96
+ if (!tr.docChanged && !action) {
97
+ return state;
98
+ }
99
+ if (!action) {
100
+ return updateState(tr.doc, state.selectedThreadId);
101
+ }
102
+ if (action.name === types.ThreadPluginActions.SET_SELECTED_THREAD_ID && state.selectedThreadId !== action.data) {
103
+ return updateState(tr.doc, action.data);
104
+ }
105
+ return state;
106
+ }
107
+ },
108
+ props: {
109
+ decorations: (state) => {
110
+ return types.THREADS_PLUGIN_KEY.getState(state)?.decorations ?? view.DecorationSet.empty;
111
+ },
112
+ handleClick: (view, pos, event) => {
113
+ if (event.button !== 0) {
114
+ return;
115
+ }
116
+ const selectThread = (threadId2) => {
117
+ view.dispatch(
118
+ view.state.tr.setMeta(types.THREADS_PLUGIN_KEY, {
119
+ name: types.ThreadPluginActions.SET_SELECTED_THREAD_ID,
120
+ data: threadId2
121
+ })
122
+ );
123
+ };
124
+ const node = view.state.doc.nodeAt(pos);
125
+ if (!node) {
126
+ selectThread(null);
127
+ return;
128
+ }
129
+ const commentMark = node.marks.find(
130
+ (mark) => mark.type === this.type
131
+ );
132
+ if (commentMark?.attrs.orphan) {
133
+ selectThread(null);
134
+ return;
135
+ }
136
+ const threadId = commentMark?.attrs.threadId;
137
+ selectThread(threadId ?? null);
138
+ }
139
+ }
140
+ })
141
+ ];
142
+ }
143
+ });
144
+ const CommentsExtension = core.Extension.create({
145
+ name: "liveblocksComments",
146
+ priority: 95,
147
+ addExtensions() {
148
+ return [Comment];
149
+ },
150
+ addStorage() {
151
+ return {
152
+ pendingCommentSelection: null
153
+ };
154
+ },
155
+ addCommands() {
156
+ return {
157
+ addPendingComment: () => () => {
158
+ if (this.editor.state.selection.empty) {
159
+ return false;
160
+ }
161
+ this.editor.view.dispatch(
162
+ this.editor.state.tr.setMeta(types.THREADS_PLUGIN_KEY, {
163
+ name: types.ThreadPluginActions.SET_SELECTED_THREAD_ID,
164
+ data: null
165
+ })
166
+ );
167
+ this.storage.pendingCommentSelection = new state.TextSelection(
168
+ this.editor.state.selection.$anchor,
169
+ this.editor.state.selection.$head
170
+ );
171
+ return true;
172
+ },
173
+ selectThread: (id) => () => {
174
+ this.editor.view.dispatch(
175
+ this.editor.state.tr.setMeta(types.THREADS_PLUGIN_KEY, {
176
+ name: types.ThreadPluginActions.SET_SELECTED_THREAD_ID,
177
+ data: id
178
+ })
179
+ );
180
+ return true;
181
+ },
182
+ addComment: (id) => ({ commands }) => {
183
+ if (!this.storage.pendingCommentSelection) {
184
+ return false;
185
+ }
186
+ this.editor.state.selection = this.storage.pendingCommentSelection;
187
+ commands.setMark(types.LIVEBLOCKS_COMMENT_MARK_TYPE, { threadId: id });
188
+ this.storage.pendingCommentSelection = null;
189
+ return true;
190
+ }
191
+ };
192
+ },
193
+ onSelectionUpdate({ transaction }) {
194
+ if (!this.storage.pendingCommentSelection || transaction.getMeta(yProsemirror.ySyncPluginKey)) {
195
+ return;
196
+ }
197
+ this.storage.pendingCommentSelection = null;
198
+ },
199
+ addProseMirrorPlugins() {
200
+ return [
201
+ new state.Plugin({
202
+ key: types.ACTIVE_SELECTION_PLUGIN,
203
+ props: {
204
+ decorations: ({ doc }) => {
205
+ const active = this.storage.pendingCommentSelection !== null;
206
+ if (!active) {
207
+ return view.DecorationSet.create(doc, []);
208
+ }
209
+ const { from, to } = this.storage.pendingCommentSelection;
210
+ const decorations = [
211
+ view.Decoration.inline(from, to, {
212
+ class: "lb-root lb-tiptap-active-selection"
213
+ })
214
+ ];
215
+ return view.DecorationSet.create(doc, decorations);
216
+ }
217
+ }
218
+ })
219
+ ];
220
+ }
221
+ });
222
+
223
+ exports.CommentsExtension = CommentsExtension;
224
+ //# sourceMappingURL=CommentsExtension.js.map