@tldraw/commenting 5.3.0-next.2fa9c61a8de6 → 5.3.0-next.4b4b4837d10b
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/commenting.css +85 -87
- package/dist-cjs/canvas/anchor-lifecycle.js +2 -2
- package/dist-cjs/canvas/anchor-lifecycle.js.map +2 -2
- package/dist-cjs/{ui/tooltip-button.js → canvas/canvas-events.js} +16 -13
- package/dist-cjs/canvas/canvas-events.js.map +7 -0
- package/dist-cjs/canvas/cluster-badge.js +121 -0
- package/dist-cjs/canvas/cluster-badge.js.map +7 -0
- package/dist-cjs/canvas/cluster-fade.js +85 -0
- package/dist-cjs/canvas/cluster-fade.js.map +7 -0
- package/dist-cjs/canvas/cluster-input.js +51 -1
- package/dist-cjs/canvas/cluster-input.js.map +2 -2
- package/dist-cjs/canvas/cluster-model.js +276 -0
- package/dist-cjs/canvas/cluster-model.js.map +7 -0
- package/dist-cjs/canvas/comment-mutations.js +57 -28
- package/dist-cjs/canvas/comment-mutations.js.map +2 -2
- package/dist-cjs/canvas/comment-reactions.js +4 -7
- package/dist-cjs/canvas/comment-reactions.js.map +2 -2
- package/dist-cjs/canvas/comment-render.js +4 -3
- package/dist-cjs/canvas/comment-render.js.map +2 -2
- package/dist-cjs/canvas/comment-store.js.map +2 -2
- package/dist-cjs/canvas/comment-tool.js +12 -7
- package/dist-cjs/canvas/comment-tool.js.map +2 -2
- package/dist-cjs/canvas/comments-filter-menu.js +11 -13
- package/dist-cjs/canvas/comments-filter-menu.js.map +2 -2
- package/dist-cjs/canvas/comments-overflow-menu.js +10 -2
- package/dist-cjs/canvas/comments-overflow-menu.js.map +2 -2
- package/dist-cjs/canvas/comments-overlay.js +81 -871
- package/dist-cjs/canvas/comments-overlay.js.map +3 -3
- package/dist-cjs/canvas/comments-sidebar.js +16 -11
- package/dist-cjs/canvas/comments-sidebar.js.map +2 -2
- package/dist-cjs/canvas/comments-visibility-toggle.js +5 -25
- package/dist-cjs/canvas/comments-visibility-toggle.js.map +2 -2
- package/dist-cjs/canvas/context.js.map +1 -1
- package/dist-cjs/canvas/hooks.js +8 -2
- package/dist-cjs/canvas/hooks.js.map +2 -2
- package/dist-cjs/canvas/license.js.map +1 -1
- package/dist-cjs/canvas/mobile-placement.js +91 -0
- package/dist-cjs/canvas/mobile-placement.js.map +7 -0
- package/dist-cjs/canvas/options.js +39 -1
- package/dist-cjs/canvas/options.js.map +2 -2
- package/dist-cjs/canvas/pending-composer.js +135 -0
- package/dist-cjs/canvas/pending-composer.js.map +7 -0
- package/dist-cjs/canvas/pin-stacking.js +26 -1
- package/dist-cjs/canvas/pin-stacking.js.map +2 -2
- package/dist-cjs/canvas/region-box.js +113 -0
- package/dist-cjs/canvas/region-box.js.map +7 -0
- package/dist-cjs/canvas/state.js.map +2 -2
- package/dist-cjs/canvas/thread-pin.js +304 -0
- package/dist-cjs/canvas/thread-pin.js.map +7 -0
- package/dist-cjs/canvas/thread-preview.js +41 -49
- package/dist-cjs/canvas/thread-preview.js.map +2 -2
- package/dist-cjs/canvas/thread-stack.js +7 -7
- package/dist-cjs/canvas/thread-stack.js.map +2 -2
- package/dist-cjs/canvas/thread-state.js +15 -0
- package/dist-cjs/canvas/thread-state.js.map +2 -2
- package/dist-cjs/canvas/thread-view.js +120 -67
- package/dist-cjs/canvas/thread-view.js.map +3 -3
- package/dist-cjs/clustering/computeClusterTable.js +2 -2
- package/dist-cjs/clustering/computeClusterTable.js.map +2 -2
- package/dist-cjs/clustering/replay.js +89 -22
- package/dist-cjs/clustering/replay.js.map +3 -3
- package/dist-cjs/clustering/runtime.js +19 -12
- package/dist-cjs/clustering/runtime.js.map +2 -2
- package/dist-cjs/clustering/types.js.map +1 -1
- package/dist-cjs/index.d.ts +326 -203
- package/dist-cjs/index.js +7 -1
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/ui/byline.js +5 -3
- package/dist-cjs/ui/byline.js.map +2 -2
- package/dist-cjs/ui/comment-composer.js +2 -18
- package/dist-cjs/ui/comment-composer.js.map +2 -2
- package/dist-cjs/ui/comment-pin.js +2 -15
- package/dist-cjs/ui/comment-pin.js.map +2 -2
- package/dist-cjs/ui/comments-list.js +11 -24
- package/dist-cjs/ui/comments-list.js.map +2 -2
- package/dist-cjs/ui/format-time.js +13 -1
- package/dist-cjs/ui/format-time.js.map +2 -2
- package/dist-cjs/ui/icons.js +138 -0
- package/dist-cjs/ui/icons.js.map +7 -0
- package/dist-cjs/ui/reaction-picker.js +11 -13
- package/dist-cjs/ui/reaction-picker.js.map +2 -2
- package/dist-cjs/ui/reaction.js +3 -4
- package/dist-cjs/ui/reaction.js.map +2 -2
- package/dist-cjs/ui/send-button.js +2 -9
- package/dist-cjs/ui/send-button.js.map +2 -2
- package/dist-cjs/ui/visual-viewport.js +32 -0
- package/dist-cjs/ui/visual-viewport.js.map +7 -0
- package/dist-esm/canvas/anchor-lifecycle.mjs +3 -3
- package/dist-esm/canvas/anchor-lifecycle.mjs.map +2 -2
- package/dist-esm/canvas/canvas-events.mjs +15 -0
- package/dist-esm/canvas/canvas-events.mjs.map +7 -0
- package/dist-esm/canvas/cluster-badge.mjs +106 -0
- package/dist-esm/canvas/cluster-badge.mjs.map +7 -0
- package/dist-esm/canvas/cluster-fade.mjs +65 -0
- package/dist-esm/canvas/cluster-fade.mjs.map +7 -0
- package/dist-esm/canvas/cluster-input.mjs +52 -2
- package/dist-esm/canvas/cluster-input.mjs.map +2 -2
- package/dist-esm/canvas/cluster-model.mjs +260 -0
- package/dist-esm/canvas/cluster-model.mjs.map +7 -0
- package/dist-esm/canvas/comment-mutations.mjs +57 -28
- package/dist-esm/canvas/comment-mutations.mjs.map +2 -2
- package/dist-esm/canvas/comment-reactions.mjs +5 -12
- package/dist-esm/canvas/comment-reactions.mjs.map +2 -2
- package/dist-esm/canvas/comment-render.mjs +5 -4
- package/dist-esm/canvas/comment-render.mjs.map +2 -2
- package/dist-esm/canvas/comment-store.mjs.map +2 -2
- package/dist-esm/canvas/comment-tool.mjs +12 -7
- package/dist-esm/canvas/comment-tool.mjs.map +2 -2
- package/dist-esm/canvas/comments-filter-menu.mjs +12 -13
- package/dist-esm/canvas/comments-filter-menu.mjs.map +2 -2
- package/dist-esm/canvas/comments-overflow-menu.mjs +11 -2
- package/dist-esm/canvas/comments-overflow-menu.mjs.map +2 -2
- package/dist-esm/canvas/comments-overlay.mjs +58 -879
- package/dist-esm/canvas/comments-overlay.mjs.map +3 -3
- package/dist-esm/canvas/comments-sidebar.mjs +18 -14
- package/dist-esm/canvas/comments-sidebar.mjs.map +2 -2
- package/dist-esm/canvas/comments-visibility-toggle.mjs +5 -25
- package/dist-esm/canvas/comments-visibility-toggle.mjs.map +2 -2
- package/dist-esm/canvas/hooks.mjs +9 -2
- package/dist-esm/canvas/hooks.mjs.map +2 -2
- package/dist-esm/canvas/license.mjs.map +1 -1
- package/dist-esm/canvas/mobile-placement.mjs +71 -0
- package/dist-esm/canvas/mobile-placement.mjs.map +7 -0
- package/dist-esm/canvas/options.mjs +39 -1
- package/dist-esm/canvas/options.mjs.map +2 -2
- package/dist-esm/canvas/pending-composer.mjs +127 -0
- package/dist-esm/canvas/pending-composer.mjs.map +7 -0
- package/dist-esm/canvas/pin-stacking.mjs +26 -1
- package/dist-esm/canvas/pin-stacking.mjs.map +2 -2
- package/dist-esm/canvas/region-box.mjs +93 -0
- package/dist-esm/canvas/region-box.mjs.map +7 -0
- package/dist-esm/canvas/state.mjs.map +2 -2
- package/dist-esm/canvas/thread-pin.mjs +310 -0
- package/dist-esm/canvas/thread-pin.mjs.map +7 -0
- package/dist-esm/canvas/thread-preview.mjs +42 -49
- package/dist-esm/canvas/thread-preview.mjs.map +2 -2
- package/dist-esm/canvas/thread-stack.mjs +8 -9
- package/dist-esm/canvas/thread-stack.mjs.map +2 -2
- package/dist-esm/canvas/thread-state.mjs +15 -0
- package/dist-esm/canvas/thread-state.mjs.map +2 -2
- package/dist-esm/canvas/thread-view.mjs +131 -72
- package/dist-esm/canvas/thread-view.mjs.map +3 -3
- package/dist-esm/clustering/computeClusterTable.mjs +2 -2
- package/dist-esm/clustering/computeClusterTable.mjs.map +2 -2
- package/dist-esm/clustering/replay.mjs +89 -22
- package/dist-esm/clustering/replay.mjs.map +3 -3
- package/dist-esm/clustering/runtime.mjs +19 -12
- package/dist-esm/clustering/runtime.mjs.map +2 -2
- package/dist-esm/index.d.mts +326 -203
- package/dist-esm/index.mjs +16 -3
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/ui/byline.mjs +6 -4
- package/dist-esm/ui/byline.mjs.map +2 -2
- package/dist-esm/ui/comment-composer.mjs +2 -18
- package/dist-esm/ui/comment-composer.mjs.map +2 -2
- package/dist-esm/ui/comment-pin.mjs +2 -15
- package/dist-esm/ui/comment-pin.mjs.map +2 -2
- package/dist-esm/ui/comments-list.mjs +10 -23
- package/dist-esm/ui/comments-list.mjs.map +2 -2
- package/dist-esm/ui/format-time.mjs +13 -1
- package/dist-esm/ui/format-time.mjs.map +2 -2
- package/dist-esm/ui/icons.mjs +118 -0
- package/dist-esm/ui/icons.mjs.map +7 -0
- package/dist-esm/ui/reaction-picker.mjs +12 -13
- package/dist-esm/ui/reaction-picker.mjs.map +2 -2
- package/dist-esm/ui/reaction.mjs +3 -4
- package/dist-esm/ui/reaction.mjs.map +2 -2
- package/dist-esm/ui/send-button.mjs +2 -9
- package/dist-esm/ui/send-button.mjs.map +2 -2
- package/dist-esm/ui/visual-viewport.mjs +12 -0
- package/dist-esm/ui/visual-viewport.mjs.map +7 -0
- package/package.json +7 -6
- package/src/canvas/anchor-lifecycle.test.ts +2 -2
- package/src/canvas/anchor-lifecycle.ts +25 -39
- package/src/canvas/canvas-events.ts +18 -0
- package/src/canvas/canvas.css +5 -11
- package/src/canvas/cluster-badge.tsx +133 -0
- package/src/canvas/cluster-fade.ts +102 -0
- package/src/canvas/cluster-input.test.ts +148 -14
- package/src/canvas/cluster-input.ts +92 -5
- package/src/canvas/cluster-model.test.ts +88 -0
- package/src/canvas/cluster-model.ts +421 -0
- package/src/canvas/comment-mutations.test.ts +46 -4
- package/src/canvas/comment-mutations.ts +115 -104
- package/src/canvas/comment-reactions.test.ts +22 -0
- package/src/canvas/comment-reactions.tsx +33 -32
- package/src/canvas/comment-render.ts +8 -8
- package/src/canvas/comment-store.ts +12 -17
- package/src/canvas/comment-tool.test.ts +109 -4
- package/src/canvas/comment-tool.tsx +31 -19
- package/src/canvas/comments-filter-menu.tsx +10 -17
- package/src/canvas/comments-overflow-menu.tsx +8 -3
- package/src/canvas/comments-overlay.tsx +160 -1345
- package/src/canvas/comments-sidebar.tsx +40 -19
- package/src/canvas/comments-visibility-toggle.tsx +6 -30
- package/src/canvas/context.ts +4 -3
- package/src/canvas/hooks.test.ts +94 -0
- package/src/canvas/hooks.ts +17 -3
- package/src/canvas/license.ts +1 -1
- package/src/canvas/mobile-placement.ts +115 -0
- package/src/canvas/options.test.ts +124 -2
- package/src/canvas/options.ts +192 -58
- package/src/canvas/pending-composer.tsx +161 -0
- package/src/canvas/pin-stacking.test.ts +111 -1
- package/src/canvas/pin-stacking.ts +46 -0
- package/src/canvas/region-box.tsx +124 -0
- package/src/canvas/state.ts +20 -28
- package/src/canvas/thread-pin.tsx +419 -0
- package/src/canvas/thread-preview.tsx +77 -87
- package/src/canvas/thread-stack.tsx +19 -29
- package/src/canvas/thread-state.test.ts +51 -0
- package/src/canvas/thread-state.ts +56 -23
- package/src/canvas/thread-view.test.ts +72 -0
- package/src/canvas/thread-view.tsx +231 -133
- package/src/clustering/computeClusterTable.ts +12 -3
- package/src/clustering/replay.test.ts +0 -7
- package/src/clustering/replay.ts +131 -32
- package/src/clustering/runtime.test.ts +50 -6
- package/src/clustering/runtime.ts +42 -39
- package/src/clustering/schedule.test.ts +0 -6
- package/src/clustering/screen-offsets.test.ts +171 -0
- package/src/clustering/types.ts +10 -0
- package/src/index.ts +15 -2
- package/src/ui/byline.tsx +16 -6
- package/src/ui/comment-composer.tsx +25 -69
- package/src/ui/comment-pin.tsx +3 -16
- package/src/ui/comments-list.tsx +40 -29
- package/src/ui/comments.css +80 -76
- package/src/ui/format-time.test.ts +69 -0
- package/src/ui/format-time.ts +22 -2
- package/src/ui/icons.tsx +138 -0
- package/src/ui/reaction-picker.tsx +9 -16
- package/src/ui/reaction.tsx +10 -6
- package/src/ui/send-button.tsx +3 -8
- package/src/ui/visual-viewport.test.ts +36 -0
- package/src/ui/visual-viewport.ts +27 -0
- package/dist-cjs/ui/tooltip-button.js.map +0 -7
- package/dist-esm/ui/tooltip-button.mjs +0 -12
- package/dist-esm/ui/tooltip-button.mjs.map +0 -7
- package/src/ui/tooltip-button.tsx +0 -20
|
@@ -1,123 +1,53 @@
|
|
|
1
1
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
memo,
|
|
6
|
-
useCallback,
|
|
7
|
-
useEffect,
|
|
8
|
-
useLayoutEffect,
|
|
9
|
-
useMemo,
|
|
10
|
-
useRef,
|
|
11
|
-
useState
|
|
12
|
-
} from "react";
|
|
13
|
-
import { createPortal } from "react-dom";
|
|
14
|
-
import {
|
|
15
|
-
createComment,
|
|
16
|
-
createCommentThread,
|
|
17
|
-
react,
|
|
18
|
-
useContainer,
|
|
19
|
-
useEditor,
|
|
20
|
-
usePassThroughMouseOverEvents,
|
|
21
|
-
usePassThroughWheelEvents,
|
|
22
|
-
useTranslation,
|
|
23
|
-
useValue
|
|
24
|
-
} from "tldraw";
|
|
25
|
-
import { computeClusterTable } from "../clustering/computeClusterTable.mjs";
|
|
26
|
-
import { createClusterRuntime } from "../clustering/runtime.mjs";
|
|
27
|
-
import { CommentComposer } from "../ui/comment-composer.mjs";
|
|
28
|
-
import { EMPTY_COMMENT, isCommentEmpty } from "../ui/comment-extensions.mjs";
|
|
29
|
-
import { CommentPin } from "../ui/comment-pin.mjs";
|
|
30
|
-
import { CountBadge } from "../ui/count-badge.mjs";
|
|
2
|
+
import { isMentionPickerOpen } from "@tldraw/mentions";
|
|
3
|
+
import { Fragment as Fragment2, useCallback, useEffect, useMemo, useRef } from "react";
|
|
4
|
+
import { EditorPortal, useEditor, useValue } from "tldraw";
|
|
31
5
|
import { registerCommentAnchorLifecycle } from "./anchor-lifecycle.mjs";
|
|
32
|
-
import {
|
|
6
|
+
import { ClusterBadge } from "./cluster-badge.mjs";
|
|
7
|
+
import { clusterFadeClassName } from "./cluster-fade.mjs";
|
|
33
8
|
import {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
} from "./
|
|
39
|
-
import { commitCommentMutation, putRecordsInCommit } from "./comment-mutations.mjs";
|
|
40
|
-
import { UNKNOWN_AUTHOR, UNKNOWN_COMMENT_AUTHOR } from "./comment-render.mjs";
|
|
9
|
+
CLUSTER_EXPAND_ZOOM_MS,
|
|
10
|
+
revealThreadPin,
|
|
11
|
+
useClusterModel,
|
|
12
|
+
zoomToClusterSplit
|
|
13
|
+
} from "./cluster-model.mjs";
|
|
41
14
|
import { getCommentRecord } from "./comment-store.mjs";
|
|
42
|
-
import { useCommentThreads
|
|
15
|
+
import { useCommentThreads } from "./hooks.mjs";
|
|
43
16
|
import { useCommentingEnabled } from "./license.mjs";
|
|
44
|
-
import {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
} from "./options.mjs";
|
|
49
|
-
import { computePinStacks, pinStackKey } from "./pin-stacking.mjs";
|
|
17
|
+
import { useCanComment, useCommentingOptions } from "./options.mjs";
|
|
18
|
+
import { PendingComposer } from "./pending-composer.mjs";
|
|
19
|
+
import { computePinStacks, isOpenStackKeyLive, pinStacksEqual } from "./pin-stacking.mjs";
|
|
20
|
+
import { RegionBox, RegionDraftBox } from "./region-box.mjs";
|
|
50
21
|
import {
|
|
51
22
|
commentsHidden,
|
|
52
23
|
openStackId,
|
|
53
24
|
openThreadId,
|
|
54
25
|
pendingComment,
|
|
55
|
-
regionDraft,
|
|
56
26
|
revealThreadRequest,
|
|
57
27
|
sidebarFilters,
|
|
58
28
|
toggleCommentsHidden,
|
|
59
29
|
usePendingComment
|
|
60
30
|
} from "./state.mjs";
|
|
61
|
-
import {
|
|
31
|
+
import { ThreadPin } from "./thread-pin.mjs";
|
|
62
32
|
import { ThreadStackPin } from "./thread-stack.mjs";
|
|
63
|
-
import {
|
|
64
|
-
anchorPagePoint,
|
|
65
|
-
commentCenterScreenOffset,
|
|
66
|
-
commentTargetShapeAt,
|
|
67
|
-
impreciseShapePinInset,
|
|
68
|
-
REGION_PIN_CORNER,
|
|
69
|
-
regionAnchorPinCorner,
|
|
70
|
-
regionPinPoint,
|
|
71
|
-
shapeAnchorAt
|
|
72
|
-
} from "./thread-state.mjs";
|
|
73
|
-
import { POPOVER_OFFSET, ThreadPopover, ThreadView } from "./thread-view.mjs";
|
|
74
|
-
const stop = (e) => e.stopPropagation();
|
|
75
|
-
const isCanvasPanGesture = (editor, e) => e.button !== 0 || editor.inputs.keys.has("Space");
|
|
76
|
-
function forwardPointerEventToCanvas(container, e) {
|
|
77
|
-
const cvs = container.querySelector(".tl-canvas");
|
|
78
|
-
if (!cvs) return;
|
|
79
|
-
const newEvent = new PointerEvent(e.type, e.nativeEvent);
|
|
80
|
-
newEvent.isSpecialRedispatchedEvent = true;
|
|
81
|
-
cvs.dispatchEvent(newEvent);
|
|
82
|
-
}
|
|
83
|
-
const CLUSTER_FADE_MS = 150;
|
|
84
|
-
const CLUSTER_EXPAND_ZOOM_MS = 450;
|
|
85
|
-
const CLUSTER_SPLIT_ZOOM_FACTOR = 1.05;
|
|
86
|
-
const CLUSTER_CULL_MARGIN_PX = 120;
|
|
87
|
-
const THREAD_HEADER_BLOCK = 36;
|
|
88
33
|
function CanvasComments(props) {
|
|
89
34
|
const commentingEnabled = useCommentingEnabled();
|
|
90
35
|
if (!commentingEnabled) return null;
|
|
91
36
|
return /* @__PURE__ */ jsx(CanvasCommentsLayer, { ...props });
|
|
92
37
|
}
|
|
93
|
-
function useTrailingPortalHost(container) {
|
|
94
|
-
const [host, setHost] = useState(null);
|
|
95
|
-
useLayoutEffect(() => {
|
|
96
|
-
const elm = container.ownerDocument.createElement("div");
|
|
97
|
-
elm.style.display = "contents";
|
|
98
|
-
container.appendChild(elm);
|
|
99
|
-
setHost(elm);
|
|
100
|
-
return () => {
|
|
101
|
-
elm.remove();
|
|
102
|
-
setHost(null);
|
|
103
|
-
};
|
|
104
|
-
}, [container]);
|
|
105
|
-
return host;
|
|
106
|
-
}
|
|
107
38
|
function CanvasCommentsLayer(props) {
|
|
108
39
|
const editor = useEditor();
|
|
109
40
|
const options = useCommentingOptions();
|
|
110
|
-
const container = useContainer();
|
|
111
|
-
const portalHost = useTrailingPortalHost(container);
|
|
112
|
-
const layerRef = useRef(null);
|
|
113
|
-
usePassThroughMouseOverEvents(layerRef);
|
|
114
41
|
const allThreads = useCommentThreads(editor);
|
|
115
42
|
const pending = usePendingComment();
|
|
116
43
|
const canComment = useCanComment(props.currentUserId);
|
|
117
44
|
const canRenderComposer = canComment || options.components.ComposerFallback != null;
|
|
118
45
|
const showPendingComposer = pending != null && canRenderComposer;
|
|
119
46
|
useEffect(() => {
|
|
120
|
-
if (pending && !showPendingComposer)
|
|
47
|
+
if (pending && !showPendingComposer) {
|
|
48
|
+
pendingComment.set(editor, null);
|
|
49
|
+
if (editor.isIn("comment")) editor.setCurrentTool("select");
|
|
50
|
+
}
|
|
121
51
|
}, [editor, pending, showPendingComposer]);
|
|
122
52
|
const openId = useValue("open thread id", () => openThreadId.get(editor), [editor]);
|
|
123
53
|
const showResolved = useValue("show resolved", () => sidebarFilters.get(editor).showResolved, [
|
|
@@ -128,121 +58,28 @@ function CanvasCommentsLayer(props) {
|
|
|
128
58
|
[allThreads, showResolved, openId]
|
|
129
59
|
);
|
|
130
60
|
useEffect(() => registerCommentAnchorLifecycle(editor), [editor]);
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
openThreadId.get(editor)
|
|
139
|
-
),
|
|
140
|
-
[editor, threads, heldThreadIds]
|
|
141
|
-
);
|
|
142
|
-
const clusterZoomBounds = useValue(
|
|
143
|
-
"comment cluster zoom bounds",
|
|
144
|
-
() => getClusterZoomBounds(editor),
|
|
145
|
-
[editor]
|
|
146
|
-
);
|
|
147
|
-
const latestModel = useMemo(() => {
|
|
148
|
-
const table = computeClusterTable(clusterLeaves, clusterZoomBounds);
|
|
149
|
-
const runtime = createClusterRuntime(table);
|
|
150
|
-
runtime.seed(editor.getZoomLevel());
|
|
151
|
-
return { runtime, table };
|
|
152
|
-
}, [clusterLeaves, clusterZoomBounds, editor]);
|
|
153
|
-
const [renderedModel, setRenderedModel] = useState(latestModel);
|
|
154
|
-
let clusterModel = renderedModel;
|
|
155
|
-
const pageId = useValue("comment cluster page", () => editor.getCurrentPageId(), [editor]);
|
|
156
|
-
const pageRef = useRef(pageId);
|
|
157
|
-
if (pageRef.current !== pageId) {
|
|
158
|
-
pageRef.current = pageId;
|
|
159
|
-
adoptOnRebuild.current = false;
|
|
160
|
-
latestModel.runtime.seed(editor.getZoomLevel());
|
|
161
|
-
if (heldThreadIds.size > 0) setHeldThreadIds(EMPTY_SET);
|
|
162
|
-
setRenderedModel(latestModel);
|
|
163
|
-
clusterModel = latestModel;
|
|
164
|
-
}
|
|
165
|
-
const rejoinPending = heldThreadIds.size === 0 && adoptOnRebuild.current;
|
|
166
|
-
if (renderedModel !== latestModel && rejoinPending) {
|
|
167
|
-
adoptOnRebuild.current = false;
|
|
168
|
-
latestModel.runtime.seedFrom(editor.getZoomLevel(), renderedModel.runtime.getVisible());
|
|
169
|
-
setRenderedModel(latestModel);
|
|
170
|
-
clusterModel = latestModel;
|
|
171
|
-
} else if (heldThreadIds.size === 0 && renderedModel === latestModel) {
|
|
172
|
-
adoptOnRebuild.current = false;
|
|
173
|
-
}
|
|
174
|
-
const newlyMovedIds = findMovedClusteredLeafIds(clusterModel, latestModel);
|
|
175
|
-
if (newlyMovedIds.length > 0) {
|
|
176
|
-
const next = new Set(heldThreadIds);
|
|
177
|
-
for (const id of newlyMovedIds) next.add(id);
|
|
178
|
-
setHeldThreadIds(next);
|
|
179
|
-
}
|
|
180
|
-
{
|
|
181
|
-
const latestLeafIds = new Set(latestModel.table.leaves.map((leaf) => leaf.id));
|
|
182
|
-
for (const leaf of clusterModel.table.leaves) {
|
|
183
|
-
if (!latestLeafIds.has(leaf.id)) {
|
|
184
|
-
clusterModel.runtime.detachLeaf(leaf.id);
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
useEffect(() => {
|
|
189
|
-
if (heldThreadIds.size === 0) return;
|
|
190
|
-
let lastZoom = editor.getZoomLevel();
|
|
191
|
-
return react("rejoin moved comment pins on zoom out", () => {
|
|
192
|
-
const zoom = editor.getZoomLevel();
|
|
193
|
-
const prevZoom = lastZoom;
|
|
194
|
-
lastZoom = zoom;
|
|
195
|
-
if (zoom >= prevZoom) return;
|
|
196
|
-
adoptOnRebuild.current = true;
|
|
197
|
-
setHeldThreadIds(EMPTY_SET);
|
|
198
|
-
});
|
|
199
|
-
}, [heldThreadIds, editor]);
|
|
200
|
-
useEffect(() => {
|
|
201
|
-
if (clusterModel === latestModel) return;
|
|
202
|
-
let lastZoom = editor.getZoomLevel();
|
|
203
|
-
return react("adopt pending cluster model on zoom out", () => {
|
|
204
|
-
const zoom = editor.getZoomLevel();
|
|
205
|
-
const prevZoom = lastZoom;
|
|
206
|
-
lastZoom = zoom;
|
|
207
|
-
if (zoom >= prevZoom) return;
|
|
208
|
-
latestModel.runtime.seedFrom(zoom, clusterModel.runtime.getVisible());
|
|
209
|
-
setRenderedModel(latestModel);
|
|
210
|
-
});
|
|
211
|
-
}, [clusterModel, latestModel, editor]);
|
|
212
|
-
const partitionVersion = clusterModel.runtime.version;
|
|
213
|
-
const orphanThreads = useMemo(() => {
|
|
214
|
-
if (clusterModel === latestModel) return [];
|
|
215
|
-
const displayed = /* @__PURE__ */ new Set();
|
|
216
|
-
for (const node of clusterModel.runtime.getVisible().values()) {
|
|
217
|
-
for (const member of node.members) displayed.add(member);
|
|
218
|
-
}
|
|
219
|
-
const latestIds = new Set(latestModel.table.leaves.map((leaf) => leaf.id));
|
|
220
|
-
return threads.filter((thread) => latestIds.has(thread.id) && !displayed.has(thread.id));
|
|
221
|
-
}, [clusterModel, latestModel, threads, partitionVersion]);
|
|
222
|
-
const heldThreads = useMemo(
|
|
223
|
-
() => threads.filter((thread) => heldThreadIds.has(thread.id) && thread.id !== openId),
|
|
224
|
-
[threads, heldThreadIds, openId]
|
|
225
|
-
);
|
|
226
|
-
useValue(
|
|
227
|
-
"comment cluster version",
|
|
228
|
-
() => {
|
|
229
|
-
clusterModel.runtime.onCamera(editor.getZoomLevel());
|
|
230
|
-
return clusterModel.runtime.version;
|
|
231
|
-
},
|
|
232
|
-
[clusterModel, editor]
|
|
233
|
-
);
|
|
234
|
-
const visibleNodes = useMemo(() => {
|
|
235
|
-
return Array.from(clusterModel.runtime.getVisible().values());
|
|
236
|
-
}, [clusterModel, partitionVersion]);
|
|
237
|
-
const fadeNodes = useFadeVisibleNodes(visibleNodes, clusterModel);
|
|
61
|
+
const {
|
|
62
|
+
model: clusterModel,
|
|
63
|
+
zoomBounds: clusterZoomBounds,
|
|
64
|
+
fadeNodes,
|
|
65
|
+
orphanThreads,
|
|
66
|
+
heldThreads
|
|
67
|
+
} = useClusterModel(editor, threads, openId);
|
|
238
68
|
const threadsById = useMemo(
|
|
239
69
|
() => new Map(threads.map((thread) => [thread.id, thread])),
|
|
240
70
|
[threads]
|
|
241
71
|
);
|
|
242
|
-
const
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
72
|
+
const pinStacksRef = useRef(/* @__PURE__ */ new Map());
|
|
73
|
+
const pinStacks = useValue(
|
|
74
|
+
"comment pin stacks",
|
|
75
|
+
() => {
|
|
76
|
+
const stacks = computePinStacks(editor, threads);
|
|
77
|
+
if (pinStacksEqual(pinStacksRef.current, stacks)) return pinStacksRef.current;
|
|
78
|
+
pinStacksRef.current = stacks;
|
|
79
|
+
return stacks;
|
|
80
|
+
},
|
|
81
|
+
[editor, threads]
|
|
82
|
+
);
|
|
246
83
|
const openThread = openId ? threadsById.get(openId) : null;
|
|
247
84
|
const hidden = useValue("comments hidden", () => commentsHidden.get(editor), [editor]);
|
|
248
85
|
useEffect(() => {
|
|
@@ -253,17 +90,18 @@ function CanvasCommentsLayer(props) {
|
|
|
253
90
|
revealThreadRequest.set(editor, null);
|
|
254
91
|
};
|
|
255
92
|
}, [editor]);
|
|
93
|
+
const openStackKeyIsStale = useValue(
|
|
94
|
+
"open stack key stale",
|
|
95
|
+
() => {
|
|
96
|
+
const key = openStackId.get(editor);
|
|
97
|
+
if (!key) return false;
|
|
98
|
+
return !isOpenStackKeyLive(editor, key, pinStacks, threadsById);
|
|
99
|
+
},
|
|
100
|
+
[editor, pinStacks, threadsById]
|
|
101
|
+
);
|
|
256
102
|
useEffect(() => {
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
for (const id of pinStacks.keys()) {
|
|
260
|
-
const thread = threadsById.get(id);
|
|
261
|
-
if (!thread) continue;
|
|
262
|
-
const point = anchorPagePoint(editor, thread.anchor);
|
|
263
|
-
if (point && pinStackKey(point) === key) return;
|
|
264
|
-
}
|
|
265
|
-
openStackId.set(editor, null);
|
|
266
|
-
}, [editor, pinStacks, threadsById]);
|
|
103
|
+
if (openStackKeyIsStale) openStackId.set(editor, null);
|
|
104
|
+
}, [editor, openStackKeyIsStale]);
|
|
267
105
|
const requestedRevealThread = useValue(
|
|
268
106
|
"requested reveal thread",
|
|
269
107
|
() => {
|
|
@@ -297,18 +135,11 @@ function CanvasCommentsLayer(props) {
|
|
|
297
135
|
},
|
|
298
136
|
[clusterModel.table, clusterZoomBounds, editor, options]
|
|
299
137
|
);
|
|
300
|
-
const
|
|
138
|
+
const expandCluster = useCallback(
|
|
301
139
|
(node) => {
|
|
302
|
-
|
|
303
|
-
if (!event || !Number.isFinite(event.zSplit)) return;
|
|
304
|
-
const zoom = clamp(
|
|
305
|
-
event.zSplit * CLUSTER_SPLIT_ZOOM_FACTOR,
|
|
306
|
-
clusterZoomBounds.minZoom,
|
|
307
|
-
clusterZoomBounds.maxZoom
|
|
308
|
-
);
|
|
309
|
-
centerOnPointAtZoom(editor, node.centroid, zoom, CLUSTER_EXPAND_ZOOM_MS);
|
|
140
|
+
zoomToClusterSplit(editor, clusterModel.table, clusterZoomBounds, node);
|
|
310
141
|
},
|
|
311
|
-
[clusterModel, clusterZoomBounds, editor]
|
|
142
|
+
[clusterModel.table, clusterZoomBounds, editor]
|
|
312
143
|
);
|
|
313
144
|
useEffect(() => {
|
|
314
145
|
const onKeyDown = (e) => {
|
|
@@ -362,9 +193,8 @@ function CanvasCommentsLayer(props) {
|
|
|
362
193
|
}
|
|
363
194
|
return /* @__PURE__ */ jsx(ThreadPin, { editor, thread, ...props });
|
|
364
195
|
};
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
/* @__PURE__ */ jsxs("div", { ref: layerRef, className: "tlui-cmt-canvas-layer", children: [
|
|
196
|
+
return (
|
|
197
|
+
/* @__PURE__ */ jsx(EditorPortal, { children: /* @__PURE__ */ jsxs("div", { className: "tlui-cmt-canvas-layer", children: [
|
|
368
198
|
options.enableClustering ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
369
199
|
fadeNodes.map(({ node, phase }) => {
|
|
370
200
|
let content;
|
|
@@ -382,7 +212,7 @@ function CanvasCommentsLayer(props) {
|
|
|
382
212
|
{
|
|
383
213
|
editor,
|
|
384
214
|
node,
|
|
385
|
-
onExpand:
|
|
215
|
+
onExpand: expandCluster,
|
|
386
216
|
onSelectThread: revealClusteredThread,
|
|
387
217
|
threadsById,
|
|
388
218
|
currentUserId: props.currentUserId,
|
|
@@ -395,10 +225,8 @@ function CanvasCommentsLayer(props) {
|
|
|
395
225
|
orphanThreads.map((thread) => /* @__PURE__ */ jsx(Fragment2, { children: renderThreadPin(thread) }, thread.id)),
|
|
396
226
|
heldThreads.map((thread) => /* @__PURE__ */ jsx(Fragment2, { children: renderThreadPin(thread) }, thread.id))
|
|
397
227
|
] }) : (
|
|
398
|
-
// Clustering off: every thread renders
|
|
399
|
-
//
|
|
400
|
-
// rendered once below, mirroring how the clustering path keeps it out of the cluster leaves —
|
|
401
|
-
// otherwise it would mount a second, stacked pin.
|
|
228
|
+
// Clustering off: every thread renders its own pin. The open thread is excluded and
|
|
229
|
+
// rendered once below, or it would mount a second, stacked pin.
|
|
402
230
|
(threads.filter((thread) => thread.id !== openId).map(
|
|
403
231
|
(thread) => /* @__PURE__ */ jsx(Fragment2, { children: renderThreadPin(thread) }, thread.id)
|
|
404
232
|
))
|
|
@@ -407,656 +235,7 @@ function CanvasCommentsLayer(props) {
|
|
|
407
235
|
/* @__PURE__ */ jsx(RegionDraftBox, { editor }),
|
|
408
236
|
pending?.anchor.type === "region" && showPendingComposer && /* @__PURE__ */ jsx(RegionBox, { editor, box: pending.anchor }),
|
|
409
237
|
pending && showPendingComposer && /* @__PURE__ */ jsx(PendingComposer, { editor, pending, ...props })
|
|
410
|
-
] })
|
|
411
|
-
portalHost
|
|
412
|
-
);
|
|
413
|
-
}
|
|
414
|
-
const EMPTY_SET = /* @__PURE__ */ new Set();
|
|
415
|
-
const MOVED_LEAF_EPSILON = 1e-6;
|
|
416
|
-
function useFadeVisibleNodes(nodes, resetKey) {
|
|
417
|
-
const resetKeyRef = useRef(resetKey);
|
|
418
|
-
const didReset = resetKeyRef.current !== resetKey;
|
|
419
|
-
if (didReset) {
|
|
420
|
-
resetKeyRef.current = resetKey;
|
|
421
|
-
}
|
|
422
|
-
const [fadeNodes, setFadeNodes] = useState(() => toPresentFadeNodes(nodes));
|
|
423
|
-
const renderedNodes = didReset ? toPresentFadeNodes(nodes) : fadeNodes;
|
|
424
|
-
useEffect(() => {
|
|
425
|
-
setFadeNodes(toPresentFadeNodes(nodes));
|
|
426
|
-
}, [resetKey]);
|
|
427
|
-
useEffect(() => {
|
|
428
|
-
if (didReset) return;
|
|
429
|
-
setFadeNodes((previous) => reconcileFadeNodes(previous, nodes));
|
|
430
|
-
}, [didReset, nodes]);
|
|
431
|
-
const hasEntering = renderedNodes.some((item) => item.phase === "entering");
|
|
432
|
-
useEffect(() => {
|
|
433
|
-
if (!hasEntering) return;
|
|
434
|
-
const frame = requestClusterFadeFrame(() => {
|
|
435
|
-
setFadeNodes(
|
|
436
|
-
(previous) => previous.map((item) => item.phase === "entering" ? { ...item, phase: "present" } : item)
|
|
437
|
-
);
|
|
438
|
-
});
|
|
439
|
-
return () => cancelClusterFadeFrame(frame);
|
|
440
|
-
}, [hasEntering, renderedNodes]);
|
|
441
|
-
const hasExiting = renderedNodes.some((item) => item.phase === "exiting");
|
|
442
|
-
useEffect(() => {
|
|
443
|
-
if (!hasExiting) return;
|
|
444
|
-
const timeout = window.setTimeout(() => {
|
|
445
|
-
setFadeNodes((previous) => previous.filter((item) => item.phase !== "exiting"));
|
|
446
|
-
}, CLUSTER_FADE_MS);
|
|
447
|
-
return () => window.clearTimeout(timeout);
|
|
448
|
-
}, [hasExiting, renderedNodes]);
|
|
449
|
-
return renderedNodes;
|
|
450
|
-
}
|
|
451
|
-
function toPresentFadeNodes(nodes) {
|
|
452
|
-
return nodes.map((node) => ({ node, phase: "present" }));
|
|
453
|
-
}
|
|
454
|
-
function reconcileFadeNodes(previous, nextNodes) {
|
|
455
|
-
const previousById = new Map(previous.map((item) => [item.node.id, item]));
|
|
456
|
-
const nextIds = new Set(nextNodes.map((node) => node.id));
|
|
457
|
-
const next = [];
|
|
458
|
-
for (const node of nextNodes) {
|
|
459
|
-
const previousItem = previousById.get(node.id);
|
|
460
|
-
next.push({
|
|
461
|
-
node,
|
|
462
|
-
phase: previousItem && previousItem.phase !== "exiting" ? previousItem.phase : previousItem ? "present" : "entering"
|
|
463
|
-
});
|
|
464
|
-
}
|
|
465
|
-
for (const item of previous) {
|
|
466
|
-
if (nextIds.has(item.node.id)) continue;
|
|
467
|
-
next.push(item.phase === "exiting" ? item : { ...item, phase: "exiting" });
|
|
468
|
-
}
|
|
469
|
-
return next;
|
|
470
|
-
}
|
|
471
|
-
function requestClusterFadeFrame(callback) {
|
|
472
|
-
if (typeof requestAnimationFrame === "function") return requestAnimationFrame(callback);
|
|
473
|
-
return window.setTimeout(() => callback(0), 16);
|
|
474
|
-
}
|
|
475
|
-
function cancelClusterFadeFrame(frame) {
|
|
476
|
-
if (typeof cancelAnimationFrame === "function") cancelAnimationFrame(frame);
|
|
477
|
-
else window.clearTimeout(frame);
|
|
478
|
-
}
|
|
479
|
-
function clusterFadeClassName(phase) {
|
|
480
|
-
return `tlui-cmt-cluster-fade tlui-cmt-cluster-fade--${phase}`;
|
|
481
|
-
}
|
|
482
|
-
function findMovedClusteredLeafIds(rendered, latest) {
|
|
483
|
-
if (rendered.table === latest.table) return [];
|
|
484
|
-
const visible = rendered.runtime.getVisible();
|
|
485
|
-
const latestById = new Map(latest.table.leaves.map((leaf) => [leaf.id, leaf]));
|
|
486
|
-
const moved = [];
|
|
487
|
-
for (const leaf of rendered.table.leaves) {
|
|
488
|
-
if (visible.has(leaf.id)) continue;
|
|
489
|
-
const current = latestById.get(leaf.id);
|
|
490
|
-
if (!current) continue;
|
|
491
|
-
if (Math.abs(current.centroid.x - leaf.centroid.x) > MOVED_LEAF_EPSILON || Math.abs(current.centroid.y - leaf.centroid.y) > MOVED_LEAF_EPSILON) {
|
|
492
|
-
moved.push(leaf.id);
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
return moved;
|
|
496
|
-
}
|
|
497
|
-
function getClusterZoomBounds(editor) {
|
|
498
|
-
const cameraOptions = editor.getCameraOptions();
|
|
499
|
-
const baseZoom = cameraOptions.constraints ? editor.getBaseZoom() : 1;
|
|
500
|
-
const zoomSteps = cameraOptions.zoomSteps;
|
|
501
|
-
return {
|
|
502
|
-
minZoom: zoomSteps[0] * baseZoom,
|
|
503
|
-
maxZoom: zoomSteps[zoomSteps.length - 1] * baseZoom
|
|
504
|
-
};
|
|
505
|
-
}
|
|
506
|
-
function revealThreadPin(editor, thread, table, zoomBounds, options, duration = 200) {
|
|
507
|
-
if (thread.pageId !== editor.getCurrentPageId()) {
|
|
508
|
-
editor.setCurrentPage(thread.pageId);
|
|
509
|
-
}
|
|
510
|
-
const point = anchorPagePoint(editor, thread.anchor);
|
|
511
|
-
if (!point) return;
|
|
512
|
-
if (options.enableClustering) {
|
|
513
|
-
const parentEvent = findDirectParentEvent(table, thread.id);
|
|
514
|
-
if (parentEvent && Number.isFinite(parentEvent.zSplit) && parentEvent.zSplit <= zoomBounds.maxZoom) {
|
|
515
|
-
const zoom = clamp(
|
|
516
|
-
parentEvent.zSplit * CLUSTER_SPLIT_ZOOM_FACTOR,
|
|
517
|
-
zoomBounds.minZoom,
|
|
518
|
-
zoomBounds.maxZoom
|
|
519
|
-
);
|
|
520
|
-
centerOnPointAtZoom(editor, point, zoom, duration);
|
|
521
|
-
return;
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
const offset = commentCenterScreenOffset(editor) / editor.getZoomLevel();
|
|
525
|
-
editor.centerOnPoint({ x: point.x + offset, y: point.y }, { animation: { duration } });
|
|
526
|
-
}
|
|
527
|
-
function findDirectParentEvent(table, threadId) {
|
|
528
|
-
return table.events.find((event) => event.children.some((child) => child.id === threadId));
|
|
529
|
-
}
|
|
530
|
-
function centerOnPointAtZoom(editor, point, zoom, duration = 200) {
|
|
531
|
-
const viewport = editor.getViewportScreenBounds();
|
|
532
|
-
const offset = commentCenterScreenOffset(editor);
|
|
533
|
-
editor.setCamera(
|
|
534
|
-
{
|
|
535
|
-
x: (viewport.w / 2 - offset) / zoom - point.x,
|
|
536
|
-
y: viewport.h / (2 * zoom) - point.y,
|
|
537
|
-
z: zoom
|
|
538
|
-
},
|
|
539
|
-
{ animation: { duration } }
|
|
540
|
-
);
|
|
541
|
-
}
|
|
542
|
-
function clamp(value, min, max) {
|
|
543
|
-
return Math.max(min, Math.min(max, value));
|
|
544
|
-
}
|
|
545
|
-
const ClusterBadge = memo(function ClusterBadge2({
|
|
546
|
-
editor,
|
|
547
|
-
node,
|
|
548
|
-
onExpand,
|
|
549
|
-
onSelectThread,
|
|
550
|
-
threadsById,
|
|
551
|
-
...props
|
|
552
|
-
}) {
|
|
553
|
-
const container = useContainer();
|
|
554
|
-
const msg = useTranslation();
|
|
555
|
-
const badgeRef = useRef(null);
|
|
556
|
-
const { previewShown, previewHandlers } = useMarkerPreview(editor, `cluster:${node.id}`);
|
|
557
|
-
usePassThroughWheelEvents(badgeRef);
|
|
558
|
-
const point = useValue(
|
|
559
|
-
"cluster badge point",
|
|
560
|
-
() => {
|
|
561
|
-
const pagePoint = editor.pageToViewport(node.centroid);
|
|
562
|
-
if (!isInInflatedViewport(editor, pagePoint)) return null;
|
|
563
|
-
return pagePoint;
|
|
564
|
-
},
|
|
565
|
-
[editor, node]
|
|
566
|
-
);
|
|
567
|
-
const previewThreads = useMemo(() => {
|
|
568
|
-
if (!previewShown) return [];
|
|
569
|
-
const threads = [];
|
|
570
|
-
for (const id of node.members) {
|
|
571
|
-
const thread = threadsById.get(id);
|
|
572
|
-
if (thread) threads.push(thread);
|
|
573
|
-
}
|
|
574
|
-
return sortThreadsForPreview(threads);
|
|
575
|
-
}, [previewShown, node.members, threadsById]);
|
|
576
|
-
if (!point) return null;
|
|
577
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
578
|
-
/* @__PURE__ */ jsx(
|
|
579
|
-
"button",
|
|
580
|
-
{
|
|
581
|
-
ref: badgeRef,
|
|
582
|
-
type: "button",
|
|
583
|
-
className: "tlui-cmt-button tlui-cmt-canvas-cluster",
|
|
584
|
-
style: { left: point.x, top: point.y },
|
|
585
|
-
"aria-label": msg("comments.cluster-label").replace("{count}", String(node.count)),
|
|
586
|
-
onPointerDown: (e) => {
|
|
587
|
-
if (isCanvasPanGesture(editor, e)) {
|
|
588
|
-
forwardPointerEventToCanvas(container, e);
|
|
589
|
-
return;
|
|
590
|
-
}
|
|
591
|
-
e.stopPropagation();
|
|
592
|
-
},
|
|
593
|
-
onClick: (e) => {
|
|
594
|
-
e.stopPropagation();
|
|
595
|
-
onExpand(node);
|
|
596
|
-
},
|
|
597
|
-
...previewHandlers,
|
|
598
|
-
onFocus: previewHandlers.onPointerEnter,
|
|
599
|
-
onBlur: previewHandlers.onPointerLeave,
|
|
600
|
-
children: /* @__PURE__ */ jsx(CountBadge, { count: node.count })
|
|
601
|
-
}
|
|
602
|
-
),
|
|
603
|
-
previewShown && previewThreads.length > 0 && /* @__PURE__ */ jsx(
|
|
604
|
-
ThreadPreview,
|
|
605
|
-
{
|
|
606
|
-
editor,
|
|
607
|
-
threads: previewThreads,
|
|
608
|
-
container,
|
|
609
|
-
variant: "list",
|
|
610
|
-
point,
|
|
611
|
-
onSelectThread,
|
|
612
|
-
...previewHandlers,
|
|
613
|
-
...props
|
|
614
|
-
}
|
|
615
|
-
)
|
|
616
|
-
] });
|
|
617
|
-
});
|
|
618
|
-
function isInInflatedViewport(editor, point) {
|
|
619
|
-
const viewport = editor.getViewportScreenBounds();
|
|
620
|
-
const margin = CLUSTER_CULL_MARGIN_PX;
|
|
621
|
-
return point.x >= -margin && point.y >= -margin && point.x <= viewport.w + margin && point.y <= viewport.h + margin;
|
|
622
|
-
}
|
|
623
|
-
function RegionBox({ editor, box }) {
|
|
624
|
-
const rect = useValue(
|
|
625
|
-
"region rect",
|
|
626
|
-
() => {
|
|
627
|
-
const topLeft = editor.pageToViewport({ x: box.x, y: box.y });
|
|
628
|
-
const zoom = editor.getZoomLevel();
|
|
629
|
-
return { left: topLeft.x, top: topLeft.y, width: box.w * zoom, height: box.h * zoom };
|
|
630
|
-
},
|
|
631
|
-
[editor, box.x, box.y, box.w, box.h]
|
|
632
|
-
);
|
|
633
|
-
return /* @__PURE__ */ jsx("div", { className: "tlui-cmt-canvas-region", style: rect });
|
|
634
|
-
}
|
|
635
|
-
function RegionDraftBox({ editor }) {
|
|
636
|
-
const box = useValue("region draft", () => regionDraft.get(editor), [editor]);
|
|
637
|
-
if (!box) return null;
|
|
638
|
-
return /* @__PURE__ */ jsx(RegionBox, { editor, box });
|
|
639
|
-
}
|
|
640
|
-
const REGION_CORNERS = [
|
|
641
|
-
{ x: 0, y: 0, cursor: "nwse-resize" },
|
|
642
|
-
{ x: 1, y: 0, cursor: "nesw-resize" },
|
|
643
|
-
{ x: 0, y: 1, cursor: "nesw-resize" },
|
|
644
|
-
{ x: 1, y: 1, cursor: "nwse-resize" }
|
|
645
|
-
];
|
|
646
|
-
const REGION_HANDLE_MARGIN_PX = 12;
|
|
647
|
-
function resizeRegion(box, handle, cursor) {
|
|
648
|
-
const controlsX = handle.x !== 0.5;
|
|
649
|
-
const controlsY = handle.y !== 0.5;
|
|
650
|
-
const fixedX = box.x + (1 - handle.x) * box.w;
|
|
651
|
-
const fixedY = box.y + (1 - handle.y) * box.h;
|
|
652
|
-
return {
|
|
653
|
-
x: controlsX ? Math.min(fixedX, cursor.x) : box.x,
|
|
654
|
-
y: controlsY ? Math.min(fixedY, cursor.y) : box.y,
|
|
655
|
-
w: controlsX ? Math.abs(cursor.x - fixedX) : box.w,
|
|
656
|
-
h: controlsY ? Math.abs(cursor.y - fixedY) : box.h
|
|
657
|
-
};
|
|
658
|
-
}
|
|
659
|
-
function RegionResizeHandles({
|
|
660
|
-
editor,
|
|
661
|
-
box,
|
|
662
|
-
handles,
|
|
663
|
-
onPreview,
|
|
664
|
-
onCommit
|
|
665
|
-
}) {
|
|
666
|
-
const boxRef = useRef(null);
|
|
667
|
-
const points = useValue(
|
|
668
|
-
"region handle points",
|
|
669
|
-
() => handles.map((h) => {
|
|
670
|
-
const p = editor.pageToViewport({ x: box.x + h.x * box.w, y: box.y + h.y * box.h });
|
|
671
|
-
return { ...h, key: `${h.x}-${h.y}`, left: p.x, top: p.y };
|
|
672
|
-
}),
|
|
673
|
-
[editor, box.x, box.y, box.w, box.h, handles]
|
|
674
|
-
);
|
|
675
|
-
const startResize = (e) => {
|
|
676
|
-
e.stopPropagation();
|
|
677
|
-
boxRef.current = box;
|
|
678
|
-
e.currentTarget.setPointerCapture(e.pointerId);
|
|
679
|
-
};
|
|
680
|
-
const resizedTo = (h, e) => resizeRegion(boxRef.current, h, editor.screenToPage({ x: e.clientX, y: e.clientY }));
|
|
681
|
-
const onResize = (h) => (e) => {
|
|
682
|
-
if (boxRef.current) onPreview(resizedTo(h, e));
|
|
683
|
-
};
|
|
684
|
-
const endResize = (h) => (e) => {
|
|
685
|
-
if (!boxRef.current) return;
|
|
686
|
-
const bounds = resizedTo(h, e);
|
|
687
|
-
boxRef.current = null;
|
|
688
|
-
if (e.currentTarget.hasPointerCapture(e.pointerId))
|
|
689
|
-
e.currentTarget.releasePointerCapture(e.pointerId);
|
|
690
|
-
onCommit(bounds);
|
|
691
|
-
};
|
|
692
|
-
return /* @__PURE__ */ jsx(Fragment, { children: points.map((h) => /* @__PURE__ */ jsx(
|
|
693
|
-
"div",
|
|
694
|
-
{
|
|
695
|
-
className: "tlui-cmt-canvas-region-handle",
|
|
696
|
-
style: { left: h.left, top: h.top, cursor: h.cursor },
|
|
697
|
-
onPointerDown: startResize,
|
|
698
|
-
onPointerMove: onResize(h),
|
|
699
|
-
onPointerUp: endResize(h)
|
|
700
|
-
},
|
|
701
|
-
h.key
|
|
702
|
-
)) });
|
|
703
|
-
}
|
|
704
|
-
const ThreadPin = memo(function ThreadPin2({
|
|
705
|
-
editor,
|
|
706
|
-
thread,
|
|
707
|
-
...props
|
|
708
|
-
}) {
|
|
709
|
-
const { resolveAuthor } = props;
|
|
710
|
-
const options = useCommentingOptions();
|
|
711
|
-
const canComment = useCanComment(props.currentUserId);
|
|
712
|
-
const container = useContainer();
|
|
713
|
-
const msg = useTranslation();
|
|
714
|
-
const comments = useThreadComments(editor, thread.id);
|
|
715
|
-
const open = useValue("thread open", () => openThreadId.get(editor) === thread.id, [
|
|
716
|
-
editor,
|
|
717
|
-
thread.id
|
|
718
|
-
]);
|
|
719
|
-
const [dragPagePoint, setDragPagePoint] = useState(null);
|
|
720
|
-
const [resizeBounds, setResizeBounds] = useState(null);
|
|
721
|
-
const { previewShown, previewHandlers } = useMarkerPreview(editor, `pin:${thread.id}`);
|
|
722
|
-
const previewThreads = useMemo(() => [thread], [thread]);
|
|
723
|
-
const pointerInRegion = useValue(
|
|
724
|
-
"pointer in region",
|
|
725
|
-
() => {
|
|
726
|
-
if (thread.anchor.type !== "region" || thread.pageId !== editor.getCurrentPageId())
|
|
727
|
-
return false;
|
|
728
|
-
const m = REGION_HANDLE_MARGIN_PX / editor.getZoomLevel();
|
|
729
|
-
const p = editor.inputs.getCurrentPagePoint();
|
|
730
|
-
const a = thread.anchor;
|
|
731
|
-
return p.x >= a.x - m && p.x <= a.x + a.w + m && p.y >= a.y - m && p.y <= a.y + a.h + m;
|
|
732
|
-
},
|
|
733
|
-
[editor, thread.anchor, thread.pageId]
|
|
734
|
-
);
|
|
735
|
-
const revealed = open || resizeBounds != null || pointerInRegion;
|
|
736
|
-
const pinCorner = thread.anchor.type === "region" ? regionAnchorPinCorner(thread.anchor) : REGION_PIN_CORNER;
|
|
737
|
-
const resizeHandles = useMemo(
|
|
738
|
-
() => REGION_CORNERS.filter((c) => c.x !== pinCorner.x || c.y !== pinCorner.y),
|
|
739
|
-
[pinCorner]
|
|
740
|
-
);
|
|
741
|
-
const dragRef = useRef(null);
|
|
742
|
-
const markerRef = useRef(null);
|
|
743
|
-
usePassThroughWheelEvents(markerRef);
|
|
744
|
-
useEffect(() => {
|
|
745
|
-
return () => {
|
|
746
|
-
if (dragRef.current) editor.setHintingShapes([]);
|
|
747
|
-
};
|
|
748
|
-
}, [editor]);
|
|
749
|
-
useEffect(() => {
|
|
750
|
-
if (!open) return;
|
|
751
|
-
const onPointerDown = (e) => {
|
|
752
|
-
const target = e.target;
|
|
753
|
-
if (!target) return;
|
|
754
|
-
if (target.closest(".tlui-cmt-canvas-popover")) return;
|
|
755
|
-
const marker = markerRef.current;
|
|
756
|
-
if (marker && marker.contains(target)) return;
|
|
757
|
-
if (target.closest(".tlui-cmt-canvas-region-handle, .tlui-cmt-canvas-region--movable")) return;
|
|
758
|
-
if (target.closest(".tlui-menu, [data-radix-popper-content-wrapper], .tlui-cmt-mention-popup"))
|
|
759
|
-
return;
|
|
760
|
-
openThreadId.set(editor, null);
|
|
761
|
-
};
|
|
762
|
-
document.addEventListener("pointerdown", onPointerDown, true);
|
|
763
|
-
return () => document.removeEventListener("pointerdown", onPointerDown, true);
|
|
764
|
-
}, [open, editor]);
|
|
765
|
-
const point = useValue(
|
|
766
|
-
"pin point",
|
|
767
|
-
() => {
|
|
768
|
-
if (thread.pageId !== editor.getCurrentPageId()) return null;
|
|
769
|
-
const pagePoint = anchorPagePoint(editor, thread.anchor);
|
|
770
|
-
if (!pagePoint) return null;
|
|
771
|
-
const viewportPoint = editor.pageToViewport(pagePoint);
|
|
772
|
-
const inset = impreciseShapePinInset(editor, thread.anchor);
|
|
773
|
-
return inset ? { x: viewportPoint.x + inset.x, y: viewportPoint.y + inset.y } : viewportPoint;
|
|
774
|
-
},
|
|
775
|
-
[editor, thread.anchor, thread.pageId]
|
|
776
|
-
);
|
|
777
|
-
if (!point) return null;
|
|
778
|
-
const PinContent = options.components.PinContent;
|
|
779
|
-
const threadAuthor = resolveAuthor(thread.createdBy);
|
|
780
|
-
const pinContent = PinContent ? /* @__PURE__ */ jsx(PinContent, { thread, comments }) : /* @__PURE__ */ jsx(Avatar, { author: threadAuthor ?? UNKNOWN_COMMENT_AUTHOR });
|
|
781
|
-
const pinLabel = msg(
|
|
782
|
-
thread.resolved ? "comments.pin-label-resolved" : "comments.pin-label"
|
|
783
|
-
).replace("{name}", threadAuthor?.name ?? UNKNOWN_AUTHOR);
|
|
784
|
-
const isRegion = thread.anchor.type === "region";
|
|
785
|
-
const startDrag = (e) => {
|
|
786
|
-
if (isCanvasPanGesture(editor, e)) {
|
|
787
|
-
forwardPointerEventToCanvas(container, e);
|
|
788
|
-
return;
|
|
789
|
-
}
|
|
790
|
-
e.stopPropagation();
|
|
791
|
-
const grabPage = editor.screenToPage({ x: e.clientX, y: e.clientY });
|
|
792
|
-
const anchorPage = anchorPagePoint(editor, thread.anchor);
|
|
793
|
-
const inset = impreciseShapePinInset(editor, thread.anchor);
|
|
794
|
-
if (anchorPage && inset) {
|
|
795
|
-
const zoom = editor.getZoomLevel();
|
|
796
|
-
anchorPage.x += inset.x / zoom;
|
|
797
|
-
anchorPage.y += inset.y / zoom;
|
|
798
|
-
}
|
|
799
|
-
dragRef.current = {
|
|
800
|
-
startX: e.clientX,
|
|
801
|
-
startY: e.clientY,
|
|
802
|
-
moved: false,
|
|
803
|
-
offsetX: anchorPage ? anchorPage.x - grabPage.x : 0,
|
|
804
|
-
offsetY: anchorPage ? anchorPage.y - grabPage.y : 0
|
|
805
|
-
};
|
|
806
|
-
e.currentTarget.setPointerCapture(e.pointerId);
|
|
807
|
-
};
|
|
808
|
-
const onDrag = (e) => {
|
|
809
|
-
const drag = dragRef.current;
|
|
810
|
-
if (!drag) return;
|
|
811
|
-
if (!canComment) return;
|
|
812
|
-
if (!drag.moved && Math.hypot(e.clientX - drag.startX, e.clientY - drag.startY) < 4) return;
|
|
813
|
-
drag.moved = true;
|
|
814
|
-
const cursorPage = editor.screenToPage({ x: e.clientX, y: e.clientY });
|
|
815
|
-
const pagePoint = { x: cursorPage.x + drag.offsetX, y: cursorPage.y + drag.offsetY };
|
|
816
|
-
setDragPagePoint(pagePoint);
|
|
817
|
-
if (!isRegion) {
|
|
818
|
-
const hit = commentTargetShapeAt(editor, pagePoint);
|
|
819
|
-
editor.setHintingShapes(hit ? [hit.id] : []);
|
|
820
|
-
}
|
|
821
|
-
};
|
|
822
|
-
const cancelDrag = (e) => {
|
|
823
|
-
const drag = dragRef.current;
|
|
824
|
-
dragRef.current = null;
|
|
825
|
-
if (e.currentTarget.hasPointerCapture(e.pointerId)) {
|
|
826
|
-
e.currentTarget.releasePointerCapture(e.pointerId);
|
|
827
|
-
}
|
|
828
|
-
if (!drag) return;
|
|
829
|
-
setDragPagePoint(null);
|
|
830
|
-
editor.setHintingShapes([]);
|
|
831
|
-
};
|
|
832
|
-
const endDrag = (e) => {
|
|
833
|
-
const drag = dragRef.current;
|
|
834
|
-
dragRef.current = null;
|
|
835
|
-
if (e.currentTarget.hasPointerCapture(e.pointerId)) {
|
|
836
|
-
e.currentTarget.releasePointerCapture(e.pointerId);
|
|
837
|
-
}
|
|
838
|
-
if (!drag) return;
|
|
839
|
-
editor.setHintingShapes([]);
|
|
840
|
-
if (!drag.moved) {
|
|
841
|
-
openThreadId.set(editor, openThreadId.get(editor) === thread.id ? null : thread.id);
|
|
842
|
-
return;
|
|
843
|
-
}
|
|
844
|
-
const cursorPage = editor.screenToPage({ x: e.clientX, y: e.clientY });
|
|
845
|
-
const pagePoint = { x: cursorPage.x + drag.offsetX, y: cursorPage.y + drag.offsetY };
|
|
846
|
-
setDragPagePoint(null);
|
|
847
|
-
let anchor;
|
|
848
|
-
if (thread.anchor.type === "region") {
|
|
849
|
-
anchor = {
|
|
850
|
-
...thread.anchor,
|
|
851
|
-
x: pagePoint.x - pinCorner.x * thread.anchor.w,
|
|
852
|
-
y: pagePoint.y - pinCorner.y * thread.anchor.h
|
|
853
|
-
};
|
|
854
|
-
} else {
|
|
855
|
-
const hit = commentTargetShapeAt(editor, pagePoint);
|
|
856
|
-
anchor = hit ? shapeAnchorAt(
|
|
857
|
-
editor,
|
|
858
|
-
hit.id,
|
|
859
|
-
pagePoint,
|
|
860
|
-
getCommentingOptions(editor).shouldBePrecise(editor, {
|
|
861
|
-
shapeId: hit.id,
|
|
862
|
-
point: pagePoint,
|
|
863
|
-
altKey: e.altKey
|
|
864
|
-
})
|
|
865
|
-
) : { type: "point", x: pagePoint.x, y: pagePoint.y };
|
|
866
|
-
}
|
|
867
|
-
commitCommentMutation(editor, () => putRecordsInCommit(editor, [{ ...thread, anchor }]), "drag");
|
|
868
|
-
};
|
|
869
|
-
const livePinPage = resizeBounds ? regionPinPoint(resizeBounds, pinCorner) : dragPagePoint;
|
|
870
|
-
const renderPointBase = livePinPage ? editor.pageToViewport(livePinPage) : point;
|
|
871
|
-
const renderPoint = isRegion ? { x: renderPointBase.x - 17, y: renderPointBase.y + 17 } : renderPointBase;
|
|
872
|
-
const regionAnchor = thread.anchor.type === "region" ? thread.anchor : void 0;
|
|
873
|
-
const movedRegion = regionAnchor && dragPagePoint ? {
|
|
874
|
-
...regionAnchor,
|
|
875
|
-
x: dragPagePoint.x - pinCorner.x * regionAnchor.w,
|
|
876
|
-
y: dragPagePoint.y - pinCorner.y * regionAnchor.h
|
|
877
|
-
} : regionAnchor;
|
|
878
|
-
const regionBoxBounds = resizeBounds ?? movedRegion;
|
|
879
|
-
const commitResize = (bounds) => {
|
|
880
|
-
setResizeBounds(null);
|
|
881
|
-
if (!canComment) return;
|
|
882
|
-
commitCommentMutation(
|
|
883
|
-
editor,
|
|
884
|
-
// Spread the existing anchor first so the region's pin corner survives a resize.
|
|
885
|
-
() => putRecordsInCommit(editor, [{ ...thread, anchor: { ...regionAnchor, ...bounds } }]),
|
|
886
|
-
"drag"
|
|
887
|
-
);
|
|
888
|
-
};
|
|
889
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
890
|
-
regionBoxBounds && (dragPagePoint || revealed) && /* @__PURE__ */ jsx(RegionBox, { editor, box: regionBoxBounds }),
|
|
891
|
-
regionBoxBounds && revealed && !dragPagePoint && canComment && /* @__PURE__ */ jsx(
|
|
892
|
-
RegionResizeHandles,
|
|
893
|
-
{
|
|
894
|
-
editor,
|
|
895
|
-
box: regionBoxBounds,
|
|
896
|
-
handles: resizeHandles,
|
|
897
|
-
onPreview: setResizeBounds,
|
|
898
|
-
onCommit: commitResize
|
|
899
|
-
}
|
|
900
|
-
),
|
|
901
|
-
/* @__PURE__ */ jsxs(
|
|
902
|
-
"div",
|
|
903
|
-
{
|
|
904
|
-
className: [
|
|
905
|
-
"tlui-cmt-canvas-pin",
|
|
906
|
-
open && "tlui-cmt-canvas-pin--open",
|
|
907
|
-
dragPagePoint && "tlui-cmt-canvas-pin--dragging"
|
|
908
|
-
].filter(Boolean).join(" "),
|
|
909
|
-
style: { left: renderPoint.x, top: renderPoint.y },
|
|
910
|
-
children: [
|
|
911
|
-
/* @__PURE__ */ jsx(
|
|
912
|
-
"button",
|
|
913
|
-
{
|
|
914
|
-
ref: markerRef,
|
|
915
|
-
type: "button",
|
|
916
|
-
className: "tlui-cmt-button tlui-cmt-canvas-pin__marker",
|
|
917
|
-
"aria-label": pinLabel,
|
|
918
|
-
"aria-expanded": open,
|
|
919
|
-
onPointerDown: startDrag,
|
|
920
|
-
onPointerMove: onDrag,
|
|
921
|
-
onPointerUp: endDrag,
|
|
922
|
-
onPointerCancel: cancelDrag,
|
|
923
|
-
onClick: (e) => {
|
|
924
|
-
if (e.detail !== 0) return;
|
|
925
|
-
openThreadId.set(editor, openThreadId.get(editor) === thread.id ? null : thread.id);
|
|
926
|
-
},
|
|
927
|
-
onPointerEnter: previewHandlers.onPointerEnter,
|
|
928
|
-
onPointerLeave: previewHandlers.onPointerLeave,
|
|
929
|
-
onFocus: previewHandlers.onPointerEnter,
|
|
930
|
-
onBlur: previewHandlers.onPointerLeave,
|
|
931
|
-
children: /* @__PURE__ */ jsx(CommentPin, { resolved: thread.resolved != null, open, children: pinContent })
|
|
932
|
-
}
|
|
933
|
-
),
|
|
934
|
-
open && /* @__PURE__ */ jsx(
|
|
935
|
-
ThreadPopover,
|
|
936
|
-
{
|
|
937
|
-
container,
|
|
938
|
-
style: {
|
|
939
|
-
left: renderPoint.x + POPOVER_OFFSET.thread.x,
|
|
940
|
-
top: renderPoint.y + POPOVER_OFFSET.thread.y - THREAD_HEADER_BLOCK
|
|
941
|
-
},
|
|
942
|
-
children: /* @__PURE__ */ jsx(ThreadView, { editor, thread, ...props })
|
|
943
|
-
}
|
|
944
|
-
),
|
|
945
|
-
previewShown && !dragPagePoint && /* @__PURE__ */ jsx(
|
|
946
|
-
ThreadPreview,
|
|
947
|
-
{
|
|
948
|
-
editor,
|
|
949
|
-
threads: previewThreads,
|
|
950
|
-
container,
|
|
951
|
-
variant: "thread",
|
|
952
|
-
point: renderPoint,
|
|
953
|
-
onSelectThread: () => openThreadId.set(editor, thread.id),
|
|
954
|
-
...previewHandlers,
|
|
955
|
-
currentUserId: props.currentUserId,
|
|
956
|
-
resolveAuthor
|
|
957
|
-
}
|
|
958
|
-
)
|
|
959
|
-
]
|
|
960
|
-
}
|
|
961
|
-
)
|
|
962
|
-
] });
|
|
963
|
-
});
|
|
964
|
-
function PendingComposer({
|
|
965
|
-
editor,
|
|
966
|
-
pending,
|
|
967
|
-
currentUserId,
|
|
968
|
-
resolveAuthor,
|
|
969
|
-
onPostComment,
|
|
970
|
-
getMentionSuggestions,
|
|
971
|
-
renderMentionSuggestion
|
|
972
|
-
}) {
|
|
973
|
-
const ComposerFallback = useCommentingOptions().components.ComposerFallback;
|
|
974
|
-
const canComment = useCanComment(currentUserId);
|
|
975
|
-
const me = currentUserId ? resolveAuthor(currentUserId) : void 0;
|
|
976
|
-
const draftAvatar = /* @__PURE__ */ jsx(CommentPin, { children: /* @__PURE__ */ jsx(Avatar, { author: me ?? UNKNOWN_COMMENT_AUTHOR }) });
|
|
977
|
-
const [text, setText] = useState(
|
|
978
|
-
() => getCommentDraft(NEW_COMMENT_DRAFT) ?? EMPTY_COMMENT
|
|
979
|
-
);
|
|
980
|
-
const ref = useRef(null);
|
|
981
|
-
const msg = useTranslation();
|
|
982
|
-
const container = useContainer();
|
|
983
|
-
usePassThroughWheelEvents(ref);
|
|
984
|
-
usePassThroughMouseOverEvents(ref);
|
|
985
|
-
const point = useValue("composer point", () => editor.pageToViewport(pending.point), [
|
|
986
|
-
editor,
|
|
987
|
-
pending.point
|
|
988
|
-
]);
|
|
989
|
-
useEffect(() => {
|
|
990
|
-
const onPointerDown = (e) => {
|
|
991
|
-
const el = ref.current;
|
|
992
|
-
const target = e.target;
|
|
993
|
-
if (!el || !target) return;
|
|
994
|
-
if (el.contains(target) || target.closest(".tlui-cmt-mention-popup")) return;
|
|
995
|
-
pendingComment.set(editor, null);
|
|
996
|
-
};
|
|
997
|
-
document.addEventListener("pointerdown", onPointerDown, true);
|
|
998
|
-
return () => document.removeEventListener("pointerdown", onPointerDown, true);
|
|
999
|
-
}, [editor]);
|
|
1000
|
-
const submit = () => {
|
|
1001
|
-
if (isCommentEmpty(text) || !currentUserId) return;
|
|
1002
|
-
commitCommentMutation(editor, () => {
|
|
1003
|
-
const pageId = editor.getCurrentPageId();
|
|
1004
|
-
const thread = createCommentThread({
|
|
1005
|
-
pageId,
|
|
1006
|
-
anchor: pending.anchor,
|
|
1007
|
-
createdBy: currentUserId
|
|
1008
|
-
});
|
|
1009
|
-
const comment = createComment({
|
|
1010
|
-
threadId: thread.id,
|
|
1011
|
-
pageId,
|
|
1012
|
-
authorId: currentUserId,
|
|
1013
|
-
body: text
|
|
1014
|
-
});
|
|
1015
|
-
putRecordsInCommit(editor, [thread, comment]);
|
|
1016
|
-
if (onPostComment) onPostComment(comment);
|
|
1017
|
-
});
|
|
1018
|
-
setText(EMPTY_COMMENT);
|
|
1019
|
-
clearCommentDraft(NEW_COMMENT_DRAFT);
|
|
1020
|
-
pendingComment.set(editor, null);
|
|
1021
|
-
};
|
|
1022
|
-
return createPortal(
|
|
1023
|
-
/* @__PURE__ */ jsx(
|
|
1024
|
-
"div",
|
|
1025
|
-
{
|
|
1026
|
-
ref,
|
|
1027
|
-
className: [
|
|
1028
|
-
"tlui-cmt-canvas-composer",
|
|
1029
|
-
pending.anchor.type === "region" && "tlui-cmt-canvas-composer--region",
|
|
1030
|
-
!canComment && "tlui-cmt-canvas-composer--fallback"
|
|
1031
|
-
].filter(Boolean).join(" "),
|
|
1032
|
-
style: { left: point.x, top: point.y },
|
|
1033
|
-
onPointerDown: stop,
|
|
1034
|
-
onContextMenu: stop,
|
|
1035
|
-
onKeyDown: (e) => {
|
|
1036
|
-
if (e.key === "Escape" && !isMentionPickerOpen()) pendingComment.set(editor, null);
|
|
1037
|
-
},
|
|
1038
|
-
children: canComment ? /* @__PURE__ */ jsx(
|
|
1039
|
-
CommentComposer,
|
|
1040
|
-
{
|
|
1041
|
-
author: me ?? UNKNOWN_COMMENT_AUTHOR,
|
|
1042
|
-
placeholder: msg("comments.add-placeholder"),
|
|
1043
|
-
sendLabel: msg("comments.send"),
|
|
1044
|
-
value: text,
|
|
1045
|
-
onChange: (value) => {
|
|
1046
|
-
setText(value);
|
|
1047
|
-
saveCommentDraft(NEW_COMMENT_DRAFT, value);
|
|
1048
|
-
},
|
|
1049
|
-
onSubmit: submit,
|
|
1050
|
-
disabled: isCommentEmpty(text) || !currentUserId,
|
|
1051
|
-
getMentionSuggestions,
|
|
1052
|
-
renderMentionSuggestion,
|
|
1053
|
-
autoFocus: true,
|
|
1054
|
-
leading: draftAvatar
|
|
1055
|
-
}
|
|
1056
|
-
) : ComposerFallback && /* @__PURE__ */ jsx(ComposerFallback, { context: "pending" })
|
|
1057
|
-
}
|
|
1058
|
-
),
|
|
1059
|
-
container
|
|
238
|
+
] }) })
|
|
1060
239
|
);
|
|
1061
240
|
}
|
|
1062
241
|
export {
|