@tldraw/commenting 5.3.0-next.2fa9c61a8de6 → 5.3.0-next.7654e7ac2a02
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 +63 -71
- 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 +252 -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 +0 -1
- 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 +77 -870
- 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 +134 -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 +323 -202
- 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 +12 -0
- package/dist-cjs/ui/format-time.js.map +2 -2
- package/dist-cjs/ui/icons.js +115 -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 +236 -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 +0 -1
- 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 +54 -878
- 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 +126 -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 +323 -202
- 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 +12 -0
- package/dist-esm/ui/format-time.mjs.map +2 -2
- package/dist-esm/ui/icons.mjs +95 -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 +5 -5
- 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.ts +378 -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.tsx +8 -12
- package/src/canvas/comments-filter-menu.tsx +9 -16
- package/src/canvas/comments-overflow-menu.tsx +8 -3
- package/src/canvas/comments-overlay.tsx +154 -1344
- 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 +157 -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 +418 -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 +58 -60
- package/src/ui/format-time.test.ts +69 -0
- package/src/ui/format-time.ts +20 -0
- package/src/ui/icons.tsx +116 -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,116 +1,43 @@
|
|
|
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);
|
|
@@ -128,121 +55,28 @@ function CanvasCommentsLayer(props) {
|
|
|
128
55
|
[allThreads, showResolved, openId]
|
|
129
56
|
);
|
|
130
57
|
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);
|
|
58
|
+
const {
|
|
59
|
+
model: clusterModel,
|
|
60
|
+
zoomBounds: clusterZoomBounds,
|
|
61
|
+
fadeNodes,
|
|
62
|
+
orphanThreads,
|
|
63
|
+
heldThreads
|
|
64
|
+
} = useClusterModel(editor, threads, openId);
|
|
238
65
|
const threadsById = useMemo(
|
|
239
66
|
() => new Map(threads.map((thread) => [thread.id, thread])),
|
|
240
67
|
[threads]
|
|
241
68
|
);
|
|
242
|
-
const
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
69
|
+
const pinStacksRef = useRef(/* @__PURE__ */ new Map());
|
|
70
|
+
const pinStacks = useValue(
|
|
71
|
+
"comment pin stacks",
|
|
72
|
+
() => {
|
|
73
|
+
const stacks = computePinStacks(editor, threads);
|
|
74
|
+
if (pinStacksEqual(pinStacksRef.current, stacks)) return pinStacksRef.current;
|
|
75
|
+
pinStacksRef.current = stacks;
|
|
76
|
+
return stacks;
|
|
77
|
+
},
|
|
78
|
+
[editor, threads]
|
|
79
|
+
);
|
|
246
80
|
const openThread = openId ? threadsById.get(openId) : null;
|
|
247
81
|
const hidden = useValue("comments hidden", () => commentsHidden.get(editor), [editor]);
|
|
248
82
|
useEffect(() => {
|
|
@@ -253,17 +87,18 @@ function CanvasCommentsLayer(props) {
|
|
|
253
87
|
revealThreadRequest.set(editor, null);
|
|
254
88
|
};
|
|
255
89
|
}, [editor]);
|
|
90
|
+
const openStackKeyIsStale = useValue(
|
|
91
|
+
"open stack key stale",
|
|
92
|
+
() => {
|
|
93
|
+
const key = openStackId.get(editor);
|
|
94
|
+
if (!key) return false;
|
|
95
|
+
return !isOpenStackKeyLive(editor, key, pinStacks, threadsById);
|
|
96
|
+
},
|
|
97
|
+
[editor, pinStacks, threadsById]
|
|
98
|
+
);
|
|
256
99
|
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]);
|
|
100
|
+
if (openStackKeyIsStale) openStackId.set(editor, null);
|
|
101
|
+
}, [editor, openStackKeyIsStale]);
|
|
267
102
|
const requestedRevealThread = useValue(
|
|
268
103
|
"requested reveal thread",
|
|
269
104
|
() => {
|
|
@@ -297,18 +132,11 @@ function CanvasCommentsLayer(props) {
|
|
|
297
132
|
},
|
|
298
133
|
[clusterModel.table, clusterZoomBounds, editor, options]
|
|
299
134
|
);
|
|
300
|
-
const
|
|
135
|
+
const expandCluster = useCallback(
|
|
301
136
|
(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);
|
|
137
|
+
zoomToClusterSplit(editor, clusterModel.table, clusterZoomBounds, node);
|
|
310
138
|
},
|
|
311
|
-
[clusterModel, clusterZoomBounds, editor]
|
|
139
|
+
[clusterModel.table, clusterZoomBounds, editor]
|
|
312
140
|
);
|
|
313
141
|
useEffect(() => {
|
|
314
142
|
const onKeyDown = (e) => {
|
|
@@ -362,9 +190,8 @@ function CanvasCommentsLayer(props) {
|
|
|
362
190
|
}
|
|
363
191
|
return /* @__PURE__ */ jsx(ThreadPin, { editor, thread, ...props });
|
|
364
192
|
};
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
/* @__PURE__ */ jsxs("div", { ref: layerRef, className: "tlui-cmt-canvas-layer", children: [
|
|
193
|
+
return (
|
|
194
|
+
/* @__PURE__ */ jsx(EditorPortal, { children: /* @__PURE__ */ jsxs("div", { className: "tlui-cmt-canvas-layer", children: [
|
|
368
195
|
options.enableClustering ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
369
196
|
fadeNodes.map(({ node, phase }) => {
|
|
370
197
|
let content;
|
|
@@ -382,7 +209,7 @@ function CanvasCommentsLayer(props) {
|
|
|
382
209
|
{
|
|
383
210
|
editor,
|
|
384
211
|
node,
|
|
385
|
-
onExpand:
|
|
212
|
+
onExpand: expandCluster,
|
|
386
213
|
onSelectThread: revealClusteredThread,
|
|
387
214
|
threadsById,
|
|
388
215
|
currentUserId: props.currentUserId,
|
|
@@ -395,10 +222,8 @@ function CanvasCommentsLayer(props) {
|
|
|
395
222
|
orphanThreads.map((thread) => /* @__PURE__ */ jsx(Fragment2, { children: renderThreadPin(thread) }, thread.id)),
|
|
396
223
|
heldThreads.map((thread) => /* @__PURE__ */ jsx(Fragment2, { children: renderThreadPin(thread) }, thread.id))
|
|
397
224
|
] }) : (
|
|
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.
|
|
225
|
+
// Clustering off: every thread renders its own pin. The open thread is excluded and
|
|
226
|
+
// rendered once below, or it would mount a second, stacked pin.
|
|
402
227
|
(threads.filter((thread) => thread.id !== openId).map(
|
|
403
228
|
(thread) => /* @__PURE__ */ jsx(Fragment2, { children: renderThreadPin(thread) }, thread.id)
|
|
404
229
|
))
|
|
@@ -407,656 +232,7 @@ function CanvasCommentsLayer(props) {
|
|
|
407
232
|
/* @__PURE__ */ jsx(RegionDraftBox, { editor }),
|
|
408
233
|
pending?.anchor.type === "region" && showPendingComposer && /* @__PURE__ */ jsx(RegionBox, { editor, box: pending.anchor }),
|
|
409
234
|
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
|
|
235
|
+
] }) })
|
|
1060
236
|
);
|
|
1061
237
|
}
|
|
1062
238
|
export {
|