@tldraw/commenting 5.3.0-internal.c5c7f1d817d0 → 5.3.0-next.2fa9c61a8de6
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/README.md +0 -2
- package/commenting.css +1040 -230
- package/dist-cjs/canvas/anchor-lifecycle.js +148 -0
- package/dist-cjs/canvas/anchor-lifecycle.js.map +7 -0
- package/dist-cjs/canvas/cluster-input.js +2 -2
- package/dist-cjs/canvas/cluster-input.js.map +2 -2
- package/dist-cjs/canvas/comment-drafts.js +54 -0
- package/dist-cjs/canvas/comment-drafts.js.map +7 -0
- package/dist-cjs/canvas/comment-mutations.js +123 -0
- package/dist-cjs/canvas/comment-mutations.js.map +7 -0
- package/dist-cjs/canvas/comment-reactions.js +163 -0
- package/dist-cjs/canvas/comment-reactions.js.map +7 -0
- package/dist-cjs/canvas/comment-render.js +5 -3
- package/dist-cjs/canvas/comment-render.js.map +2 -2
- package/dist-cjs/canvas/comment-store.js +19 -9
- package/dist-cjs/canvas/comment-store.js.map +2 -2
- package/dist-cjs/canvas/comment-tool.js +64 -14
- package/dist-cjs/canvas/comment-tool.js.map +2 -2
- package/dist-cjs/canvas/comments-filter-menu.js +20 -38
- package/dist-cjs/canvas/comments-filter-menu.js.map +2 -2
- package/dist-cjs/canvas/comments-overflow-menu.js +22 -27
- package/dist-cjs/canvas/comments-overflow-menu.js.map +2 -2
- package/dist-cjs/canvas/comments-overlay.js +377 -437
- package/dist-cjs/canvas/comments-overlay.js.map +2 -2
- package/dist-cjs/canvas/comments-sidebar.js +34 -31
- package/dist-cjs/canvas/comments-sidebar.js.map +2 -2
- package/dist-cjs/canvas/comments-visibility-toggle.js +65 -0
- package/dist-cjs/canvas/comments-visibility-toggle.js.map +7 -0
- package/dist-cjs/canvas/context.js +17 -0
- package/dist-cjs/canvas/context.js.map +7 -0
- package/dist-cjs/canvas/hooks.js +22 -3
- package/dist-cjs/canvas/hooks.js.map +2 -2
- package/dist-cjs/canvas/options.js +19 -2
- package/dist-cjs/canvas/options.js.map +2 -2
- package/dist-cjs/canvas/pin-stacking.js +56 -0
- package/dist-cjs/canvas/pin-stacking.js.map +7 -0
- package/dist-cjs/canvas/sidebar-filters.js +2 -2
- package/dist-cjs/canvas/sidebar-filters.js.map +2 -2
- package/dist-cjs/canvas/state.js +28 -14
- package/dist-cjs/canvas/state.js.map +2 -2
- package/dist-cjs/canvas/thread-preview.js +185 -0
- package/dist-cjs/canvas/thread-preview.js.map +7 -0
- package/dist-cjs/canvas/thread-stack.js +199 -0
- package/dist-cjs/canvas/thread-stack.js.map +7 -0
- package/dist-cjs/canvas/thread-state.js +67 -21
- package/dist-cjs/canvas/thread-state.js.map +2 -2
- package/dist-cjs/canvas/thread-view.js +397 -0
- package/dist-cjs/canvas/thread-view.js.map +7 -0
- package/dist-cjs/clustering/computeClusterTable.js +4 -4
- package/dist-cjs/clustering/computeClusterTable.js.map +2 -2
- package/dist-cjs/clustering/runtime.js +9 -9
- package/dist-cjs/clustering/runtime.js.map +2 -2
- package/dist-cjs/clustering/types.js.map +1 -1
- package/dist-cjs/index.d.ts +763 -353
- package/dist-cjs/index.js +46 -28
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/ui/byline.js +3 -1
- package/dist-cjs/ui/byline.js.map +2 -2
- package/dist-cjs/ui/comment-card.js +12 -5
- package/dist-cjs/ui/comment-card.js.map +2 -2
- package/dist-cjs/ui/comment-composer.js +112 -17
- package/dist-cjs/ui/comment-composer.js.map +2 -2
- package/dist-cjs/ui/comment-pin.js +20 -2
- package/dist-cjs/ui/comment-pin.js.map +2 -2
- package/dist-cjs/ui/comment-thread.js +4 -2
- package/dist-cjs/ui/comment-thread.js.map +2 -2
- package/dist-cjs/ui/comments-list.js +22 -10
- package/dist-cjs/ui/comments-list.js.map +2 -2
- package/dist-cjs/ui/count-badge.js +3 -2
- package/dist-cjs/ui/count-badge.js.map +2 -2
- package/dist-cjs/ui/emoji-picker.js +54 -0
- package/dist-cjs/ui/emoji-picker.js.map +7 -0
- package/dist-cjs/ui/format-time.js +4 -1
- package/dist-cjs/ui/format-time.js.map +2 -2
- package/dist-cjs/ui/reaction-picker.js +73 -0
- package/dist-cjs/ui/reaction-picker.js.map +7 -0
- package/dist-cjs/ui/reaction.js +50 -4
- package/dist-cjs/ui/reaction.js.map +2 -2
- package/dist-cjs/ui/reactions.js +20 -15
- package/dist-cjs/ui/reactions.js.map +2 -2
- package/dist-cjs/ui/{mention.js → reply-count.js} +9 -11
- package/dist-cjs/ui/reply-count.js.map +7 -0
- package/dist-cjs/ui/send-button.js +20 -1
- package/dist-cjs/ui/send-button.js.map +2 -2
- package/dist-cjs/ui/{comment-text.js → tooltip-button.js} +12 -9
- package/dist-cjs/ui/tooltip-button.js.map +7 -0
- package/dist-esm/canvas/anchor-lifecycle.mjs +128 -0
- package/dist-esm/canvas/anchor-lifecycle.mjs.map +7 -0
- package/dist-esm/canvas/cluster-input.mjs +2 -2
- package/dist-esm/canvas/cluster-input.mjs.map +2 -2
- package/dist-esm/canvas/comment-drafts.mjs +34 -0
- package/dist-esm/canvas/comment-drafts.mjs.map +7 -0
- package/dist-esm/canvas/comment-mutations.mjs +103 -0
- package/dist-esm/canvas/comment-mutations.mjs.map +7 -0
- package/dist-esm/canvas/comment-reactions.mjs +152 -0
- package/dist-esm/canvas/comment-reactions.mjs.map +7 -0
- package/dist-esm/canvas/comment-render.mjs +5 -3
- package/dist-esm/canvas/comment-render.mjs.map +2 -2
- package/dist-esm/canvas/comment-store.mjs +19 -9
- package/dist-esm/canvas/comment-store.mjs.map +2 -2
- package/dist-esm/canvas/comment-tool.mjs +67 -17
- package/dist-esm/canvas/comment-tool.mjs.map +2 -2
- package/dist-esm/canvas/comments-filter-menu.mjs +20 -38
- package/dist-esm/canvas/comments-filter-menu.mjs.map +2 -2
- package/dist-esm/canvas/comments-overflow-menu.mjs +23 -27
- package/dist-esm/canvas/comments-overflow-menu.mjs.map +2 -2
- package/dist-esm/canvas/comments-overlay.mjs +398 -442
- package/dist-esm/canvas/comments-overlay.mjs.map +3 -3
- package/dist-esm/canvas/comments-sidebar.mjs +37 -34
- package/dist-esm/canvas/comments-sidebar.mjs.map +2 -2
- package/dist-esm/canvas/comments-visibility-toggle.mjs +45 -0
- package/dist-esm/canvas/comments-visibility-toggle.mjs.map +7 -0
- package/dist-esm/canvas/context.mjs +1 -0
- package/dist-esm/canvas/context.mjs.map +7 -0
- package/dist-esm/canvas/hooks.mjs +28 -5
- package/dist-esm/canvas/hooks.mjs.map +2 -2
- package/dist-esm/canvas/options.mjs +21 -3
- package/dist-esm/canvas/options.mjs.map +2 -2
- package/dist-esm/canvas/pin-stacking.mjs +36 -0
- package/dist-esm/canvas/pin-stacking.mjs.map +7 -0
- package/dist-esm/canvas/sidebar-filters.mjs +2 -2
- package/dist-esm/canvas/sidebar-filters.mjs.map +2 -2
- package/dist-esm/canvas/state.mjs +29 -19
- package/dist-esm/canvas/state.mjs.map +2 -2
- package/dist-esm/canvas/thread-preview.mjs +170 -0
- package/dist-esm/canvas/thread-preview.mjs.map +7 -0
- package/dist-esm/canvas/thread-stack.mjs +190 -0
- package/dist-esm/canvas/thread-stack.mjs.map +7 -0
- package/dist-esm/canvas/thread-state.mjs +71 -22
- package/dist-esm/canvas/thread-state.mjs.map +2 -2
- package/dist-esm/canvas/thread-view.mjs +402 -0
- package/dist-esm/canvas/thread-view.mjs.map +7 -0
- package/dist-esm/clustering/computeClusterTable.mjs +4 -4
- package/dist-esm/clustering/computeClusterTable.mjs.map +2 -2
- package/dist-esm/clustering/runtime.mjs +9 -9
- package/dist-esm/clustering/runtime.mjs.map +2 -2
- package/dist-esm/index.d.mts +763 -353
- package/dist-esm/index.mjs +87 -41
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/ui/byline.mjs +3 -1
- package/dist-esm/ui/byline.mjs.map +2 -2
- package/dist-esm/ui/comment-card.mjs +12 -5
- package/dist-esm/ui/comment-card.mjs.map +2 -2
- package/dist-esm/ui/comment-composer.mjs +122 -16
- package/dist-esm/ui/comment-composer.mjs.map +2 -2
- package/dist-esm/ui/comment-pin.mjs +20 -2
- package/dist-esm/ui/comment-pin.mjs.map +2 -2
- package/dist-esm/ui/comment-thread.mjs +4 -2
- package/dist-esm/ui/comment-thread.mjs.map +2 -2
- package/dist-esm/ui/comments-list.mjs +39 -25
- package/dist-esm/ui/comments-list.mjs.map +2 -2
- package/dist-esm/ui/count-badge.mjs +3 -2
- package/dist-esm/ui/count-badge.mjs.map +2 -2
- package/dist-esm/ui/emoji-picker.mjs +34 -0
- package/dist-esm/ui/emoji-picker.mjs.map +7 -0
- package/dist-esm/ui/format-time.mjs +4 -1
- package/dist-esm/ui/format-time.mjs.map +2 -2
- package/dist-esm/ui/reaction-picker.mjs +60 -0
- package/dist-esm/ui/reaction-picker.mjs.map +7 -0
- package/dist-esm/ui/reaction.mjs +51 -5
- package/dist-esm/ui/reaction.mjs.map +2 -2
- package/dist-esm/ui/reactions.mjs +21 -16
- package/dist-esm/ui/reactions.mjs.map +2 -2
- package/dist-esm/ui/reply-count.mjs +9 -0
- package/dist-esm/ui/reply-count.mjs.map +7 -0
- package/dist-esm/ui/send-button.mjs +20 -1
- package/dist-esm/ui/send-button.mjs.map +2 -2
- package/dist-esm/ui/tooltip-button.mjs +12 -0
- package/dist-esm/ui/tooltip-button.mjs.map +7 -0
- package/package.json +6 -6
- package/src/canvas/anchor-lifecycle.test.ts +290 -0
- package/src/canvas/anchor-lifecycle.ts +205 -0
- package/src/canvas/canvas.css +439 -24
- package/src/canvas/cluster-input.test.ts +31 -23
- package/src/canvas/cluster-input.ts +3 -4
- package/src/canvas/comment-drafts.test.ts +55 -0
- package/src/canvas/comment-drafts.ts +46 -0
- package/src/canvas/comment-mutations.test.ts +410 -0
- package/src/canvas/comment-mutations.ts +288 -0
- package/src/canvas/comment-reactions.test.ts +132 -0
- package/src/canvas/comment-reactions.tsx +245 -0
- package/src/canvas/comment-render.ts +9 -5
- package/src/canvas/comment-store.ts +67 -27
- package/src/canvas/comment-tool.test.ts +162 -0
- package/src/canvas/comment-tool.tsx +105 -23
- package/src/canvas/comments-filter-menu.tsx +23 -32
- package/src/canvas/comments-overflow-menu.tsx +12 -19
- package/src/canvas/comments-overlay.tsx +602 -562
- package/src/canvas/comments-sidebar.test.ts +45 -0
- package/src/canvas/comments-sidebar.tsx +75 -57
- package/src/canvas/comments-visibility-toggle.tsx +49 -0
- package/src/canvas/context.ts +47 -0
- package/src/canvas/hooks.ts +52 -11
- package/src/canvas/options.test.ts +52 -2
- package/src/canvas/options.ts +133 -9
- package/src/canvas/pin-stacking.test.ts +114 -0
- package/src/canvas/pin-stacking.ts +57 -0
- package/src/canvas/sidebar-filters.ts +4 -3
- package/src/canvas/state.ts +92 -35
- package/src/canvas/thread-preview.test.ts +91 -0
- package/src/canvas/thread-preview.tsx +304 -0
- package/src/canvas/thread-stack.tsx +252 -0
- package/src/canvas/thread-state.test.ts +209 -0
- package/src/canvas/thread-state.ts +137 -36
- package/src/canvas/thread-view.tsx +516 -0
- package/src/clustering/computeClusterTable.test.ts +24 -23
- package/src/clustering/computeClusterTable.ts +5 -5
- package/src/clustering/runtime.test.ts +34 -0
- package/src/clustering/runtime.ts +20 -15
- package/src/clustering/types.ts +9 -9
- package/src/index.ts +76 -40
- package/src/ui/byline.tsx +4 -2
- package/src/ui/comment-card.tsx +17 -7
- package/src/ui/comment-composer.tsx +160 -13
- package/src/ui/comment-pin.tsx +22 -2
- package/src/ui/comment-thread.tsx +6 -1
- package/src/ui/comments-list.test.ts +31 -0
- package/src/ui/comments-list.tsx +32 -12
- package/src/ui/comments.css +489 -204
- package/src/ui/count-badge.tsx +9 -2
- package/src/ui/emoji-picker.test.ts +25 -0
- package/src/ui/emoji-picker.tsx +76 -0
- package/src/ui/format-time.ts +7 -2
- package/src/ui/reaction-picker.tsx +109 -0
- package/src/ui/reaction.tsx +116 -4
- package/src/ui/reactions.tsx +68 -13
- package/src/ui/reply-count.ts +16 -0
- package/src/ui/send-button.tsx +18 -3
- package/src/ui/tooltip-button.tsx +20 -0
- package/dist-cjs/canvas/region-options.js +0 -49
- package/dist-cjs/canvas/region-options.js.map +0 -7
- package/dist-cjs/ui/avatar.js +0 -51
- package/dist-cjs/ui/avatar.js.map +0 -7
- package/dist-cjs/ui/comment-mention.js +0 -42
- package/dist-cjs/ui/comment-mention.js.map +0 -7
- package/dist-cjs/ui/comment-text.js.map +0 -7
- package/dist-cjs/ui/mention-list.js +0 -70
- package/dist-cjs/ui/mention-list.js.map +0 -7
- package/dist-cjs/ui/mention-suggestion.js +0 -206
- package/dist-cjs/ui/mention-suggestion.js.map +0 -7
- package/dist-cjs/ui/mention.js.map +0 -7
- package/dist-cjs/ui/render-markdown.js +0 -63
- package/dist-cjs/ui/render-markdown.js.map +0 -7
- package/dist-esm/canvas/region-options.mjs +0 -29
- package/dist-esm/canvas/region-options.mjs.map +0 -7
- package/dist-esm/ui/avatar.mjs +0 -31
- package/dist-esm/ui/avatar.mjs.map +0 -7
- package/dist-esm/ui/comment-mention.mjs +0 -22
- package/dist-esm/ui/comment-mention.mjs.map +0 -7
- package/dist-esm/ui/comment-text.mjs +0 -9
- package/dist-esm/ui/comment-text.mjs.map +0 -7
- package/dist-esm/ui/mention-list.mjs +0 -50
- package/dist-esm/ui/mention-list.mjs.map +0 -7
- package/dist-esm/ui/mention-suggestion.mjs +0 -186
- package/dist-esm/ui/mention-suggestion.mjs.map +0 -7
- package/dist-esm/ui/mention.mjs +0 -11
- package/dist-esm/ui/mention.mjs.map +0 -7
- package/dist-esm/ui/render-markdown.mjs +0 -45
- package/dist-esm/ui/render-markdown.mjs.map +0 -7
- package/src/canvas/region-options.ts +0 -57
- package/src/ui/avatar.tsx +0 -38
- package/src/ui/comment-mention.ts +0 -47
- package/src/ui/comment-text.tsx +0 -12
- package/src/ui/mention-list.tsx +0 -106
- package/src/ui/mention-suggestion.test.ts +0 -18
- package/src/ui/mention-suggestion.tsx +0 -285
- package/src/ui/mention.tsx +0 -9
- package/src/ui/render-markdown.tsx +0 -72
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Avatar, isMentionPickerOpen } from "@tldraw/mentions";
|
|
2
3
|
import {
|
|
4
|
+
Fragment as Fragment2,
|
|
3
5
|
memo,
|
|
4
6
|
useCallback,
|
|
5
7
|
useEffect,
|
|
8
|
+
useLayoutEffect,
|
|
6
9
|
useMemo,
|
|
7
10
|
useRef,
|
|
8
11
|
useState
|
|
@@ -11,9 +14,7 @@ import { createPortal } from "react-dom";
|
|
|
11
14
|
import {
|
|
12
15
|
createComment,
|
|
13
16
|
createCommentThread,
|
|
14
|
-
getFirstCharacter,
|
|
15
17
|
react,
|
|
16
|
-
TldrawUiIcon,
|
|
17
18
|
useContainer,
|
|
18
19
|
useEditor,
|
|
19
20
|
usePassThroughMouseOverEvents,
|
|
@@ -23,92 +24,110 @@ import {
|
|
|
23
24
|
} from "tldraw";
|
|
24
25
|
import { computeClusterTable } from "../clustering/computeClusterTable.mjs";
|
|
25
26
|
import { createClusterRuntime } from "../clustering/runtime.mjs";
|
|
26
|
-
import { CommentCard } from "../ui/comment-card.mjs";
|
|
27
27
|
import { CommentComposer } from "../ui/comment-composer.mjs";
|
|
28
28
|
import { EMPTY_COMMENT, isCommentEmpty } from "../ui/comment-extensions.mjs";
|
|
29
29
|
import { CommentPin } from "../ui/comment-pin.mjs";
|
|
30
|
-
import { CommentThread } from "../ui/comment-thread.mjs";
|
|
31
30
|
import { CountBadge } from "../ui/count-badge.mjs";
|
|
32
|
-
import {
|
|
31
|
+
import { registerCommentAnchorLifecycle } from "./anchor-lifecycle.mjs";
|
|
33
32
|
import { collectClusterLeaves } from "./cluster-input.mjs";
|
|
34
|
-
import {
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
import {
|
|
34
|
+
clearCommentDraft,
|
|
35
|
+
getCommentDraft,
|
|
36
|
+
NEW_COMMENT_DRAFT,
|
|
37
|
+
saveCommentDraft
|
|
38
|
+
} from "./comment-drafts.mjs";
|
|
39
|
+
import { commitCommentMutation, putRecordsInCommit } from "./comment-mutations.mjs";
|
|
40
|
+
import { UNKNOWN_AUTHOR, UNKNOWN_COMMENT_AUTHOR } from "./comment-render.mjs";
|
|
41
|
+
import { getCommentRecord } from "./comment-store.mjs";
|
|
37
42
|
import { useCommentThreads, useThreadComments } from "./hooks.mjs";
|
|
38
43
|
import { useCommentingEnabled } from "./license.mjs";
|
|
39
44
|
import {
|
|
40
45
|
getCommentingOptions,
|
|
46
|
+
useCanComment,
|
|
41
47
|
useCommentingOptions
|
|
42
48
|
} from "./options.mjs";
|
|
43
|
-
import {
|
|
44
|
-
DEFAULT_REGION_COMMENT_OPTIONS,
|
|
45
|
-
setRegionCommentOptions
|
|
46
|
-
} from "./region-options.mjs";
|
|
49
|
+
import { computePinStacks, pinStackKey } from "./pin-stacking.mjs";
|
|
47
50
|
import {
|
|
48
51
|
commentsHidden,
|
|
49
|
-
|
|
52
|
+
openStackId,
|
|
50
53
|
openThreadId,
|
|
51
54
|
pendingComment,
|
|
52
55
|
regionDraft,
|
|
56
|
+
revealThreadRequest,
|
|
57
|
+
sidebarFilters,
|
|
53
58
|
toggleCommentsHidden,
|
|
54
59
|
usePendingComment
|
|
55
60
|
} from "./state.mjs";
|
|
56
|
-
import {
|
|
61
|
+
import { ThreadPreview, sortThreadsForPreview, useMarkerPreview } from "./thread-preview.mjs";
|
|
62
|
+
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";
|
|
57
74
|
const stop = (e) => e.stopPropagation();
|
|
58
|
-
const
|
|
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
|
+
}
|
|
59
83
|
const CLUSTER_FADE_MS = 150;
|
|
60
84
|
const CLUSTER_EXPAND_ZOOM_MS = 450;
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
viewBox: "0 0 24 24",
|
|
65
|
-
width: "15",
|
|
66
|
-
height: "15",
|
|
67
|
-
fill: "none",
|
|
68
|
-
stroke: "currentColor",
|
|
69
|
-
strokeWidth: "2",
|
|
70
|
-
strokeLinecap: "round",
|
|
71
|
-
strokeLinejoin: "round",
|
|
72
|
-
"aria-hidden": "true",
|
|
73
|
-
children: [
|
|
74
|
-
/* @__PURE__ */ jsx("path", { d: "M12 20h9" }),
|
|
75
|
-
/* @__PURE__ */ jsx("path", { d: "M16.5 3.5a2.12 2.12 0 0 1 3 3L7 19l-4 1 1-4 12.5-12.5z" })
|
|
76
|
-
]
|
|
77
|
-
}
|
|
78
|
-
) });
|
|
79
|
-
function toCardProps(comment, props, components) {
|
|
80
|
-
const Body = components.CommentBody;
|
|
81
|
-
const body = Body ? /* @__PURE__ */ jsx(Body, { comment }) : /* @__PURE__ */ jsx(CommentBody, { richText: comment.body, resolveName: props.resolveName });
|
|
82
|
-
return {
|
|
83
|
-
author: props.resolveName(comment.authorId) ?? UNKNOWN_AUTHOR,
|
|
84
|
-
body,
|
|
85
|
-
date: new Date(comment.createdAt).toISOString(),
|
|
86
|
-
you: comment.authorId === props.currentUserId,
|
|
87
|
-
edited: comment.editedAt != null
|
|
88
|
-
};
|
|
89
|
-
}
|
|
85
|
+
const CLUSTER_SPLIT_ZOOM_FACTOR = 1.05;
|
|
86
|
+
const CLUSTER_CULL_MARGIN_PX = 120;
|
|
87
|
+
const THREAD_HEADER_BLOCK = 36;
|
|
90
88
|
function CanvasComments(props) {
|
|
91
89
|
const commentingEnabled = useCommentingEnabled();
|
|
92
90
|
if (!commentingEnabled) return null;
|
|
93
91
|
return /* @__PURE__ */ jsx(CanvasCommentsLayer, { ...props });
|
|
94
92
|
}
|
|
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
|
+
}
|
|
95
107
|
function CanvasCommentsLayer(props) {
|
|
96
108
|
const editor = useEditor();
|
|
97
109
|
const options = useCommentingOptions();
|
|
98
110
|
const container = useContainer();
|
|
99
|
-
const
|
|
100
|
-
() => ({ ...DEFAULT_REGION_COMMENT_OPTIONS, ...props.regionOptions }),
|
|
101
|
-
[props.regionOptions]
|
|
102
|
-
);
|
|
103
|
-
useEffect(() => setRegionCommentOptions(editor, regionOptions), [editor, regionOptions]);
|
|
111
|
+
const portalHost = useTrailingPortalHost(container);
|
|
104
112
|
const layerRef = useRef(null);
|
|
105
|
-
usePassThroughWheelEvents(layerRef);
|
|
106
113
|
usePassThroughMouseOverEvents(layerRef);
|
|
107
|
-
const
|
|
108
|
-
const threads = useCommentThreads(editor);
|
|
114
|
+
const allThreads = useCommentThreads(editor);
|
|
109
115
|
const pending = usePendingComment();
|
|
116
|
+
const canComment = useCanComment(props.currentUserId);
|
|
117
|
+
const canRenderComposer = canComment || options.components.ComposerFallback != null;
|
|
118
|
+
const showPendingComposer = pending != null && canRenderComposer;
|
|
119
|
+
useEffect(() => {
|
|
120
|
+
if (pending && !showPendingComposer) pendingComment.set(editor, null);
|
|
121
|
+
}, [editor, pending, showPendingComposer]);
|
|
110
122
|
const openId = useValue("open thread id", () => openThreadId.get(editor), [editor]);
|
|
111
|
-
const
|
|
123
|
+
const showResolved = useValue("show resolved", () => sidebarFilters.get(editor).showResolved, [
|
|
124
|
+
editor
|
|
125
|
+
]);
|
|
126
|
+
const threads = useMemo(
|
|
127
|
+
() => allThreads.filter((t) => showResolved || t.resolved == null || t.id === openId),
|
|
128
|
+
[allThreads, showResolved, openId]
|
|
129
|
+
);
|
|
130
|
+
useEffect(() => registerCommentAnchorLifecycle(editor), [editor]);
|
|
112
131
|
const [heldThreadIds, setHeldThreadIds] = useState(EMPTY_SET);
|
|
113
132
|
const adoptOnRebuild = useRef(false);
|
|
114
133
|
const clusterLeaves = useValue(
|
|
@@ -116,10 +135,9 @@ function CanvasCommentsLayer(props) {
|
|
|
116
135
|
() => collectClusterLeaves(
|
|
117
136
|
editor,
|
|
118
137
|
threads.filter((thread) => !heldThreadIds.has(thread.id)),
|
|
119
|
-
openThreadId.get(editor)
|
|
120
|
-
impreciseShapeAnchor
|
|
138
|
+
openThreadId.get(editor)
|
|
121
139
|
),
|
|
122
|
-
[editor, threads,
|
|
140
|
+
[editor, threads, heldThreadIds]
|
|
123
141
|
);
|
|
124
142
|
const clusterZoomBounds = useValue(
|
|
125
143
|
"comment cluster zoom bounds",
|
|
@@ -221,53 +239,76 @@ function CanvasCommentsLayer(props) {
|
|
|
221
239
|
() => new Map(threads.map((thread) => [thread.id, thread])),
|
|
222
240
|
[threads]
|
|
223
241
|
);
|
|
242
|
+
const pinStacks = useValue("comment pin stacks", () => computePinStacks(editor, threads), [
|
|
243
|
+
editor,
|
|
244
|
+
threads
|
|
245
|
+
]);
|
|
224
246
|
const openThread = openId ? threadsById.get(openId) : null;
|
|
225
247
|
const hidden = useValue("comments hidden", () => commentsHidden.get(editor), [editor]);
|
|
226
248
|
useEffect(() => {
|
|
227
249
|
return () => {
|
|
228
250
|
openThreadId.set(editor, null);
|
|
251
|
+
openStackId.set(editor, null);
|
|
229
252
|
pendingComment.set(editor, null);
|
|
253
|
+
revealThreadRequest.set(editor, null);
|
|
230
254
|
};
|
|
231
255
|
}, [editor]);
|
|
232
256
|
useEffect(() => {
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
if (!record) return;
|
|
241
|
-
let thread;
|
|
242
|
-
if (record.typeName === "comment") {
|
|
243
|
-
thread = threadsById.get(record.threadId);
|
|
244
|
-
} else {
|
|
245
|
-
thread = record;
|
|
257
|
+
const key = openStackId.get(editor);
|
|
258
|
+
if (!key) return;
|
|
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;
|
|
246
264
|
}
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
265
|
+
openStackId.set(editor, null);
|
|
266
|
+
}, [editor, pinStacks, threadsById]);
|
|
267
|
+
const requestedRevealThread = useValue(
|
|
268
|
+
"requested reveal thread",
|
|
269
|
+
() => {
|
|
270
|
+
const id = revealThreadRequest.get(editor);
|
|
271
|
+
if (!id) return null;
|
|
272
|
+
const record = getCommentRecord(editor, id);
|
|
273
|
+
if (!record) return null;
|
|
274
|
+
const thread = record.typeName === "comment" ? getCommentRecord(editor, record.threadId) : record;
|
|
275
|
+
return thread?.typeName === "comment-thread" ? thread : null;
|
|
276
|
+
},
|
|
277
|
+
[editor]
|
|
278
|
+
);
|
|
279
|
+
useEffect(() => {
|
|
280
|
+
if (!requestedRevealThread) return;
|
|
281
|
+
revealThreadRequest.set(editor, null);
|
|
282
|
+
commentsHidden.set(editor, false);
|
|
283
|
+
revealThreadPin(editor, requestedRevealThread, clusterModel.table, clusterZoomBounds, options);
|
|
284
|
+
openThreadId.set(editor, requestedRevealThread.id);
|
|
285
|
+
}, [requestedRevealThread, clusterModel.table, clusterZoomBounds, editor, options]);
|
|
286
|
+
const revealClusteredThread = useCallback(
|
|
287
|
+
(thread) => {
|
|
288
|
+
revealThreadPin(
|
|
289
|
+
editor,
|
|
290
|
+
thread,
|
|
291
|
+
clusterModel.table,
|
|
292
|
+
clusterZoomBounds,
|
|
293
|
+
options,
|
|
294
|
+
CLUSTER_EXPAND_ZOOM_MS
|
|
295
|
+
);
|
|
296
|
+
openThreadId.set(editor, thread.id);
|
|
297
|
+
},
|
|
298
|
+
[clusterModel.table, clusterZoomBounds, editor, options]
|
|
299
|
+
);
|
|
259
300
|
const zoomToClusterSplit = useCallback(
|
|
260
301
|
(node) => {
|
|
261
302
|
const event = clusterModel.table.events.find((e) => e.result.id === node.id);
|
|
262
303
|
if (!event || !Number.isFinite(event.zSplit)) return;
|
|
263
304
|
const zoom = clamp(
|
|
264
|
-
event.zSplit *
|
|
305
|
+
event.zSplit * CLUSTER_SPLIT_ZOOM_FACTOR,
|
|
265
306
|
clusterZoomBounds.minZoom,
|
|
266
307
|
clusterZoomBounds.maxZoom
|
|
267
308
|
);
|
|
268
309
|
centerOnPointAtZoom(editor, node.centroid, zoom, CLUSTER_EXPAND_ZOOM_MS);
|
|
269
310
|
},
|
|
270
|
-
[clusterModel, clusterZoomBounds, editor
|
|
311
|
+
[clusterModel, clusterZoomBounds, editor]
|
|
271
312
|
);
|
|
272
313
|
useEffect(() => {
|
|
273
314
|
const onKeyDown = (e) => {
|
|
@@ -294,79 +335,80 @@ function CanvasCommentsLayer(props) {
|
|
|
294
335
|
return () => document.removeEventListener("keydown", onKeyDown, true);
|
|
295
336
|
}, [editor]);
|
|
296
337
|
if (hidden) return null;
|
|
338
|
+
const stackGroupOf = (node) => {
|
|
339
|
+
const group = pinStacks.get(node.members[0]);
|
|
340
|
+
if (!group) return null;
|
|
341
|
+
return node.members.every((id) => group.includes(id)) ? group : null;
|
|
342
|
+
};
|
|
343
|
+
const renderedThreadIds = /* @__PURE__ */ new Set();
|
|
344
|
+
if (options.enableClustering) {
|
|
345
|
+
for (const { node } of fadeNodes) {
|
|
346
|
+
if (node.count === 1) renderedThreadIds.add(node.id);
|
|
347
|
+
else if (stackGroupOf(node)) for (const id of node.members) renderedThreadIds.add(id);
|
|
348
|
+
}
|
|
349
|
+
for (const thread of orphanThreads) renderedThreadIds.add(thread.id);
|
|
350
|
+
for (const thread of heldThreads) renderedThreadIds.add(thread.id);
|
|
351
|
+
} else {
|
|
352
|
+
for (const thread of threads) renderedThreadIds.add(thread.id);
|
|
353
|
+
}
|
|
354
|
+
if (openThread) renderedThreadIds.add(openThread.id);
|
|
355
|
+
const renderThreadPin = (thread) => {
|
|
356
|
+
const group = pinStacks.get(thread.id);
|
|
357
|
+
if (group) {
|
|
358
|
+
const owner = group.find((id) => renderedThreadIds.has(id));
|
|
359
|
+
if (owner !== thread.id) return null;
|
|
360
|
+
const stackThreads = group.map((id) => threadsById.get(id)).filter((t) => t !== void 0);
|
|
361
|
+
return /* @__PURE__ */ jsx(ThreadStackPin, { editor, threads: stackThreads, ...props });
|
|
362
|
+
}
|
|
363
|
+
return /* @__PURE__ */ jsx(ThreadPin, { editor, thread, ...props });
|
|
364
|
+
};
|
|
365
|
+
if (!portalHost) return null;
|
|
297
366
|
return createPortal(
|
|
298
367
|
/* @__PURE__ */ jsxs("div", { ref: layerRef, className: "tlui-cmt-canvas-layer", children: [
|
|
299
368
|
options.enableClustering ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
300
369
|
fadeNodes.map(({ node, phase }) => {
|
|
301
370
|
let content;
|
|
371
|
+
const stackGroup = node.count > 1 ? stackGroupOf(node) : null;
|
|
302
372
|
if (node.count === 1) {
|
|
303
373
|
const thread = threadsById.get(node.id);
|
|
304
374
|
if (!thread) return null;
|
|
375
|
+
content = renderThreadPin(thread);
|
|
376
|
+
} else if (stackGroup) {
|
|
377
|
+
const owner = stackGroup.find((id) => renderedThreadIds.has(id));
|
|
378
|
+
content = owner && node.members.includes(owner) ? renderThreadPin(threadsById.get(owner)) : null;
|
|
379
|
+
} else {
|
|
305
380
|
content = /* @__PURE__ */ jsx(
|
|
306
|
-
|
|
381
|
+
ClusterBadge,
|
|
307
382
|
{
|
|
308
383
|
editor,
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
384
|
+
node,
|
|
385
|
+
onExpand: zoomToClusterSplit,
|
|
386
|
+
onSelectThread: revealClusteredThread,
|
|
387
|
+
threadsById,
|
|
388
|
+
currentUserId: props.currentUserId,
|
|
389
|
+
resolveAuthor: props.resolveAuthor
|
|
312
390
|
}
|
|
313
391
|
);
|
|
314
|
-
} else {
|
|
315
|
-
content = /* @__PURE__ */ jsx(ClusterBadge, { editor, node, onExpand: zoomToClusterSplit });
|
|
316
392
|
}
|
|
317
393
|
return /* @__PURE__ */ jsx("div", { className: clusterFadeClassName(phase), children: content }, `cluster-fade:${node.id}`);
|
|
318
394
|
}),
|
|
319
|
-
orphanThreads.map((thread) => /* @__PURE__ */ jsx(
|
|
320
|
-
|
|
321
|
-
{
|
|
322
|
-
editor,
|
|
323
|
-
thread,
|
|
324
|
-
...props,
|
|
325
|
-
regionOptions
|
|
326
|
-
},
|
|
327
|
-
thread.id
|
|
328
|
-
)),
|
|
329
|
-
heldThreads.map((thread) => /* @__PURE__ */ jsx(
|
|
330
|
-
ThreadPin,
|
|
331
|
-
{
|
|
332
|
-
editor,
|
|
333
|
-
thread,
|
|
334
|
-
...props,
|
|
335
|
-
regionOptions
|
|
336
|
-
},
|
|
337
|
-
thread.id
|
|
338
|
-
))
|
|
395
|
+
orphanThreads.map((thread) => /* @__PURE__ */ jsx(Fragment2, { children: renderThreadPin(thread) }, thread.id)),
|
|
396
|
+
heldThreads.map((thread) => /* @__PURE__ */ jsx(Fragment2, { children: renderThreadPin(thread) }, thread.id))
|
|
339
397
|
] }) : (
|
|
340
398
|
// Clustering off: every thread renders as its own live pin (each returns null when it's
|
|
341
399
|
// not on the current page or its anchor is missing). The open thread is excluded here and
|
|
342
400
|
// rendered once below, mirroring how the clustering path keeps it out of the cluster leaves —
|
|
343
401
|
// otherwise it would mount a second, stacked pin.
|
|
344
|
-
(threads.filter((thread) => thread.id !== openId).map(
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
editor,
|
|
348
|
-
thread,
|
|
349
|
-
...props,
|
|
350
|
-
regionOptions
|
|
351
|
-
},
|
|
352
|
-
thread.id
|
|
353
|
-
)))
|
|
354
|
-
),
|
|
355
|
-
openThread && /* @__PURE__ */ jsx(
|
|
356
|
-
ThreadPin,
|
|
357
|
-
{
|
|
358
|
-
editor,
|
|
359
|
-
thread: openThread,
|
|
360
|
-
...props,
|
|
361
|
-
regionOptions
|
|
362
|
-
},
|
|
363
|
-
`open:${openThread.id}`
|
|
402
|
+
(threads.filter((thread) => thread.id !== openId).map(
|
|
403
|
+
(thread) => /* @__PURE__ */ jsx(Fragment2, { children: renderThreadPin(thread) }, thread.id)
|
|
404
|
+
))
|
|
364
405
|
),
|
|
406
|
+
openThread && /* @__PURE__ */ jsx(Fragment2, { children: renderThreadPin(openThread) }, `open:${openThread.id}`),
|
|
365
407
|
/* @__PURE__ */ jsx(RegionDraftBox, { editor }),
|
|
366
|
-
pending?.anchor.type === "region" && /* @__PURE__ */ jsx(RegionBox, { editor, box: pending.anchor }),
|
|
367
|
-
pending &&
|
|
408
|
+
pending?.anchor.type === "region" && showPendingComposer && /* @__PURE__ */ jsx(RegionBox, { editor, box: pending.anchor }),
|
|
409
|
+
pending && showPendingComposer && /* @__PURE__ */ jsx(PendingComposer, { editor, pending, ...props })
|
|
368
410
|
] }),
|
|
369
|
-
|
|
411
|
+
portalHost
|
|
370
412
|
);
|
|
371
413
|
}
|
|
372
414
|
const EMPTY_SET = /* @__PURE__ */ new Set();
|
|
@@ -461,34 +503,36 @@ function getClusterZoomBounds(editor) {
|
|
|
461
503
|
maxZoom: zoomSteps[zoomSteps.length - 1] * baseZoom
|
|
462
504
|
};
|
|
463
505
|
}
|
|
464
|
-
function
|
|
506
|
+
function revealThreadPin(editor, thread, table, zoomBounds, options, duration = 200) {
|
|
465
507
|
if (thread.pageId !== editor.getCurrentPageId()) {
|
|
466
508
|
editor.setCurrentPage(thread.pageId);
|
|
467
509
|
}
|
|
468
|
-
const point = anchorPagePoint(editor, thread.anchor
|
|
510
|
+
const point = anchorPagePoint(editor, thread.anchor);
|
|
469
511
|
if (!point) return;
|
|
470
512
|
if (options.enableClustering) {
|
|
471
513
|
const parentEvent = findDirectParentEvent(table, thread.id);
|
|
472
514
|
if (parentEvent && Number.isFinite(parentEvent.zSplit) && parentEvent.zSplit <= zoomBounds.maxZoom) {
|
|
473
515
|
const zoom = clamp(
|
|
474
|
-
parentEvent.zSplit *
|
|
516
|
+
parentEvent.zSplit * CLUSTER_SPLIT_ZOOM_FACTOR,
|
|
475
517
|
zoomBounds.minZoom,
|
|
476
518
|
zoomBounds.maxZoom
|
|
477
519
|
);
|
|
478
|
-
centerOnPointAtZoom(editor, point, zoom);
|
|
520
|
+
centerOnPointAtZoom(editor, point, zoom, duration);
|
|
479
521
|
return;
|
|
480
522
|
}
|
|
481
523
|
}
|
|
482
|
-
|
|
524
|
+
const offset = commentCenterScreenOffset(editor) / editor.getZoomLevel();
|
|
525
|
+
editor.centerOnPoint({ x: point.x + offset, y: point.y }, { animation: { duration } });
|
|
483
526
|
}
|
|
484
527
|
function findDirectParentEvent(table, threadId) {
|
|
485
528
|
return table.events.find((event) => event.children.some((child) => child.id === threadId));
|
|
486
529
|
}
|
|
487
530
|
function centerOnPointAtZoom(editor, point, zoom, duration = 200) {
|
|
488
531
|
const viewport = editor.getViewportScreenBounds();
|
|
532
|
+
const offset = commentCenterScreenOffset(editor);
|
|
489
533
|
editor.setCamera(
|
|
490
534
|
{
|
|
491
|
-
x: viewport.w /
|
|
535
|
+
x: (viewport.w / 2 - offset) / zoom - point.x,
|
|
492
536
|
y: viewport.h / (2 * zoom) - point.y,
|
|
493
537
|
z: zoom
|
|
494
538
|
},
|
|
@@ -501,8 +545,16 @@ function clamp(value, min, max) {
|
|
|
501
545
|
const ClusterBadge = memo(function ClusterBadge2({
|
|
502
546
|
editor,
|
|
503
547
|
node,
|
|
504
|
-
onExpand
|
|
548
|
+
onExpand,
|
|
549
|
+
onSelectThread,
|
|
550
|
+
threadsById,
|
|
551
|
+
...props
|
|
505
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);
|
|
506
558
|
const point = useValue(
|
|
507
559
|
"cluster badge point",
|
|
508
560
|
() => {
|
|
@@ -512,46 +564,63 @@ const ClusterBadge = memo(function ClusterBadge2({
|
|
|
512
564
|
},
|
|
513
565
|
[editor, node]
|
|
514
566
|
);
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
{
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
onPointerDown: stop,
|
|
522
|
-
onClick: (e) => {
|
|
523
|
-
e.stopPropagation();
|
|
524
|
-
onExpand(node);
|
|
525
|
-
},
|
|
526
|
-
children: /* @__PURE__ */ jsx(CountBadge, { count: node.count })
|
|
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);
|
|
527
573
|
}
|
|
528
|
-
|
|
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
|
+
] });
|
|
529
617
|
});
|
|
530
618
|
function isInInflatedViewport(editor, point) {
|
|
531
619
|
const viewport = editor.getViewportScreenBounds();
|
|
532
|
-
const margin =
|
|
620
|
+
const margin = CLUSTER_CULL_MARGIN_PX;
|
|
533
621
|
return point.x >= -margin && point.y >= -margin && point.x <= viewport.w + margin && point.y <= viewport.h + margin;
|
|
534
622
|
}
|
|
535
|
-
function
|
|
536
|
-
container,
|
|
537
|
-
style,
|
|
538
|
-
children
|
|
539
|
-
}) {
|
|
540
|
-
const ref = useRef(null);
|
|
541
|
-
usePassThroughWheelEvents(ref);
|
|
542
|
-
usePassThroughMouseOverEvents(ref);
|
|
543
|
-
return createPortal(
|
|
544
|
-
/* @__PURE__ */ jsx("div", { ref, className: "tlui-cmt-canvas-popover", style, onPointerDown: stop, children }),
|
|
545
|
-
container
|
|
546
|
-
);
|
|
547
|
-
}
|
|
548
|
-
function RegionBox({
|
|
549
|
-
editor,
|
|
550
|
-
box,
|
|
551
|
-
movable,
|
|
552
|
-
onPreview,
|
|
553
|
-
onCommit
|
|
554
|
-
}) {
|
|
623
|
+
function RegionBox({ editor, box }) {
|
|
555
624
|
const rect = useValue(
|
|
556
625
|
"region rect",
|
|
557
626
|
() => {
|
|
@@ -561,38 +630,7 @@ function RegionBox({
|
|
|
561
630
|
},
|
|
562
631
|
[editor, box.x, box.y, box.w, box.h]
|
|
563
632
|
);
|
|
564
|
-
|
|
565
|
-
const translated = (e) => {
|
|
566
|
-
const g = grabRef.current;
|
|
567
|
-
const p = editor.screenToPage({ x: e.clientX, y: e.clientY });
|
|
568
|
-
return { ...g.box, x: g.box.x + (p.x - g.page.x), y: g.box.y + (p.y - g.page.y) };
|
|
569
|
-
};
|
|
570
|
-
const startMove = (e) => {
|
|
571
|
-
e.stopPropagation();
|
|
572
|
-
grabRef.current = { page: editor.screenToPage({ x: e.clientX, y: e.clientY }), box };
|
|
573
|
-
e.currentTarget.setPointerCapture(e.pointerId);
|
|
574
|
-
};
|
|
575
|
-
const onMove = (e) => {
|
|
576
|
-
if (grabRef.current) onPreview?.(translated(e));
|
|
577
|
-
};
|
|
578
|
-
const endMove = (e) => {
|
|
579
|
-
if (!grabRef.current) return;
|
|
580
|
-
const bounds = translated(e);
|
|
581
|
-
grabRef.current = null;
|
|
582
|
-
if (e.currentTarget.hasPointerCapture(e.pointerId))
|
|
583
|
-
e.currentTarget.releasePointerCapture(e.pointerId);
|
|
584
|
-
onCommit?.(bounds);
|
|
585
|
-
};
|
|
586
|
-
return /* @__PURE__ */ jsx(
|
|
587
|
-
"div",
|
|
588
|
-
{
|
|
589
|
-
className: movable ? "tlui-cmt-canvas-region tlui-cmt-canvas-region--movable" : "tlui-cmt-canvas-region",
|
|
590
|
-
style: rect,
|
|
591
|
-
onPointerDown: movable ? startMove : void 0,
|
|
592
|
-
onPointerMove: movable ? onMove : void 0,
|
|
593
|
-
onPointerUp: movable ? endMove : void 0
|
|
594
|
-
}
|
|
595
|
-
);
|
|
633
|
+
return /* @__PURE__ */ jsx("div", { className: "tlui-cmt-canvas-region", style: rect });
|
|
596
634
|
}
|
|
597
635
|
function RegionDraftBox({ editor }) {
|
|
598
636
|
const box = useValue("region draft", () => regionDraft.get(editor), [editor]);
|
|
@@ -605,12 +643,6 @@ const REGION_CORNERS = [
|
|
|
605
643
|
{ x: 0, y: 1, cursor: "nesw-resize" },
|
|
606
644
|
{ x: 1, y: 1, cursor: "nwse-resize" }
|
|
607
645
|
];
|
|
608
|
-
const REGION_EDGES = [
|
|
609
|
-
{ x: 0.5, y: 0, cursor: "ns-resize" },
|
|
610
|
-
{ x: 1, y: 0.5, cursor: "ew-resize" },
|
|
611
|
-
{ x: 0.5, y: 1, cursor: "ns-resize" },
|
|
612
|
-
{ x: 0, y: 0.5, cursor: "ew-resize" }
|
|
613
|
-
];
|
|
614
646
|
const REGION_HANDLE_MARGIN_PX = 12;
|
|
615
647
|
function resizeRegion(box, handle, cursor) {
|
|
616
648
|
const controlsX = handle.x !== 0.5;
|
|
@@ -672,33 +704,22 @@ function RegionResizeHandles({
|
|
|
672
704
|
const ThreadPin = memo(function ThreadPin2({
|
|
673
705
|
editor,
|
|
674
706
|
thread,
|
|
675
|
-
regionOptions,
|
|
676
707
|
...props
|
|
677
708
|
}) {
|
|
678
|
-
const {
|
|
679
|
-
currentUserId,
|
|
680
|
-
resolveName,
|
|
681
|
-
onPostComment,
|
|
682
|
-
isCommentUnread,
|
|
683
|
-
onCommentRead,
|
|
684
|
-
getMentionSuggestions,
|
|
685
|
-
renderMentionSuggestion
|
|
686
|
-
} = props;
|
|
709
|
+
const { resolveAuthor } = props;
|
|
687
710
|
const options = useCommentingOptions();
|
|
688
|
-
const
|
|
711
|
+
const canComment = useCanComment(props.currentUserId);
|
|
689
712
|
const container = useContainer();
|
|
690
|
-
const comments = useThreadComments(editor, thread.id);
|
|
691
713
|
const msg = useTranslation();
|
|
714
|
+
const comments = useThreadComments(editor, thread.id);
|
|
692
715
|
const open = useValue("thread open", () => openThreadId.get(editor) === thread.id, [
|
|
693
716
|
editor,
|
|
694
717
|
thread.id
|
|
695
718
|
]);
|
|
696
|
-
const [reply, setReply] = useState(EMPTY_COMMENT);
|
|
697
|
-
const [editingId, setEditingId] = useState(null);
|
|
698
|
-
const [editText, setEditText] = useState(EMPTY_COMMENT);
|
|
699
719
|
const [dragPagePoint, setDragPagePoint] = useState(null);
|
|
700
720
|
const [resizeBounds, setResizeBounds] = useState(null);
|
|
701
|
-
const
|
|
721
|
+
const { previewShown, previewHandlers } = useMarkerPreview(editor, `pin:${thread.id}`);
|
|
722
|
+
const previewThreads = useMemo(() => [thread], [thread]);
|
|
702
723
|
const pointerInRegion = useValue(
|
|
703
724
|
"pointer in region",
|
|
704
725
|
() => {
|
|
@@ -711,15 +732,20 @@ const ThreadPin = memo(function ThreadPin2({
|
|
|
711
732
|
},
|
|
712
733
|
[editor, thread.anchor, thread.pageId]
|
|
713
734
|
);
|
|
714
|
-
const revealed = open || resizeBounds != null ||
|
|
735
|
+
const revealed = open || resizeBounds != null || pointerInRegion;
|
|
736
|
+
const pinCorner = thread.anchor.type === "region" ? regionAnchorPinCorner(thread.anchor) : REGION_PIN_CORNER;
|
|
715
737
|
const resizeHandles = useMemo(
|
|
716
|
-
() =>
|
|
717
|
-
|
|
718
|
-
),
|
|
719
|
-
[regionOptions.resize, regionOptions.pinCorner]
|
|
738
|
+
() => REGION_CORNERS.filter((c) => c.x !== pinCorner.x || c.y !== pinCorner.y),
|
|
739
|
+
[pinCorner]
|
|
720
740
|
);
|
|
721
741
|
const dragRef = useRef(null);
|
|
722
742
|
const markerRef = useRef(null);
|
|
743
|
+
usePassThroughWheelEvents(markerRef);
|
|
744
|
+
useEffect(() => {
|
|
745
|
+
return () => {
|
|
746
|
+
if (dragRef.current) editor.setHintingShapes([]);
|
|
747
|
+
};
|
|
748
|
+
}, [editor]);
|
|
723
749
|
useEffect(() => {
|
|
724
750
|
if (!open) return;
|
|
725
751
|
const onPointerDown = (e) => {
|
|
@@ -740,165 +766,68 @@ const ThreadPin = memo(function ThreadPin2({
|
|
|
740
766
|
"pin point",
|
|
741
767
|
() => {
|
|
742
768
|
if (thread.pageId !== editor.getCurrentPageId()) return null;
|
|
743
|
-
const pagePoint = anchorPagePoint(editor, thread.anchor
|
|
744
|
-
|
|
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;
|
|
745
774
|
},
|
|
746
|
-
[editor, thread.anchor, thread.pageId
|
|
775
|
+
[editor, thread.anchor, thread.pageId]
|
|
747
776
|
);
|
|
748
|
-
const visible = point !== null;
|
|
749
|
-
useEffect(() => {
|
|
750
|
-
if (!open || !visible || !isCommentUnread || !onCommentRead) return;
|
|
751
|
-
for (const comment of comments) {
|
|
752
|
-
if (isCommentUnread(comment.id)) {
|
|
753
|
-
onCommentRead(comment.id);
|
|
754
|
-
}
|
|
755
|
-
}
|
|
756
|
-
}, [open, visible, comments, isCommentUnread, onCommentRead]);
|
|
757
777
|
if (!point) return null;
|
|
758
|
-
const postReply = () => {
|
|
759
|
-
if (isCommentEmpty(reply) || !currentUserId) return;
|
|
760
|
-
commitCommentMutation(editor, () => {
|
|
761
|
-
const comment = createComment({
|
|
762
|
-
threadId: thread.id,
|
|
763
|
-
pageId: thread.pageId,
|
|
764
|
-
authorId: currentUserId,
|
|
765
|
-
body: reply
|
|
766
|
-
});
|
|
767
|
-
putCommentRecords(editor, [comment]);
|
|
768
|
-
if (onPostComment) onPostComment(comment);
|
|
769
|
-
});
|
|
770
|
-
setReply(EMPTY_COMMENT);
|
|
771
|
-
};
|
|
772
|
-
const toggleResolve = () => {
|
|
773
|
-
if (!currentUserId) return;
|
|
774
|
-
commitCommentMutation(editor, () => {
|
|
775
|
-
putCommentRecords(editor, [
|
|
776
|
-
{
|
|
777
|
-
...thread,
|
|
778
|
-
resolved: thread.resolved ? null : { at: Date.now(), by: currentUserId }
|
|
779
|
-
}
|
|
780
|
-
]);
|
|
781
|
-
});
|
|
782
|
-
};
|
|
783
|
-
const deleteThread = () => {
|
|
784
|
-
openThreadId.set(editor, null);
|
|
785
|
-
commitCommentMutation(
|
|
786
|
-
editor,
|
|
787
|
-
() => removeCommentRecords(editor, [thread.id, ...comments.map((c) => c.id)])
|
|
788
|
-
);
|
|
789
|
-
};
|
|
790
|
-
const startEdit = (comment) => {
|
|
791
|
-
setEditingId(comment.id);
|
|
792
|
-
setEditText(comment.body);
|
|
793
|
-
};
|
|
794
|
-
const saveEdit = () => {
|
|
795
|
-
const comment = comments.find((c) => c.id === editingId);
|
|
796
|
-
if (!comment || isCommentEmpty(editText)) return;
|
|
797
|
-
commitCommentMutation(editor, () => {
|
|
798
|
-
putCommentRecords(editor, [{ ...comment, body: editText, editedAt: Date.now() }]);
|
|
799
|
-
});
|
|
800
|
-
setEditingId(null);
|
|
801
|
-
};
|
|
802
|
-
const renderComment = (card, index) => {
|
|
803
|
-
const comment = comments[index];
|
|
804
|
-
if (editingId === comment.id) {
|
|
805
|
-
return /* @__PURE__ */ jsx(
|
|
806
|
-
"div",
|
|
807
|
-
{
|
|
808
|
-
className: "tlui-cmt-editing",
|
|
809
|
-
onKeyDown: (e) => {
|
|
810
|
-
if (e.key === "Escape") {
|
|
811
|
-
setEditingId(null);
|
|
812
|
-
e.stopPropagation();
|
|
813
|
-
}
|
|
814
|
-
},
|
|
815
|
-
children: /* @__PURE__ */ jsx(
|
|
816
|
-
CommentComposer,
|
|
817
|
-
{
|
|
818
|
-
author: card.author,
|
|
819
|
-
placeholder: msg("comments.edit-placeholder"),
|
|
820
|
-
value: editText,
|
|
821
|
-
onChange: setEditText,
|
|
822
|
-
onSubmit: saveEdit,
|
|
823
|
-
sendLabel: msg("comments.save"),
|
|
824
|
-
disabled: isCommentEmpty(editText),
|
|
825
|
-
getMentionSuggestions,
|
|
826
|
-
renderMentionSuggestion,
|
|
827
|
-
autoFocus: true
|
|
828
|
-
}
|
|
829
|
-
)
|
|
830
|
-
}
|
|
831
|
-
);
|
|
832
|
-
}
|
|
833
|
-
return /* @__PURE__ */ jsx(
|
|
834
|
-
CommentCard,
|
|
835
|
-
{
|
|
836
|
-
...card,
|
|
837
|
-
actions: comment.authorId === currentUserId ? /* @__PURE__ */ jsx(
|
|
838
|
-
"button",
|
|
839
|
-
{
|
|
840
|
-
className: "tlui-cmt-thread__action",
|
|
841
|
-
title: msg("comments.edit"),
|
|
842
|
-
onClick: () => startEdit(comment),
|
|
843
|
-
children: /* @__PURE__ */ jsx(TldrawUiIcon, { icon: "dots-horizontal", label: msg("comments.edit"), small: true })
|
|
844
|
-
}
|
|
845
|
-
) : void 0
|
|
846
|
-
}
|
|
847
|
-
);
|
|
848
|
-
};
|
|
849
|
-
const headerActions = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
850
|
-
currentUserId && /* @__PURE__ */ jsx(
|
|
851
|
-
"button",
|
|
852
|
-
{
|
|
853
|
-
className: "tlui-cmt-thread__action",
|
|
854
|
-
title: msg(thread.resolved ? "comments.reopen" : "comments.resolve"),
|
|
855
|
-
onClick: toggleResolve,
|
|
856
|
-
children: /* @__PURE__ */ jsx(
|
|
857
|
-
TldrawUiIcon,
|
|
858
|
-
{
|
|
859
|
-
icon: "check",
|
|
860
|
-
label: msg(thread.resolved ? "comments.reopen" : "comments.resolve"),
|
|
861
|
-
small: true
|
|
862
|
-
}
|
|
863
|
-
)
|
|
864
|
-
}
|
|
865
|
-
),
|
|
866
|
-
currentUserId && /* @__PURE__ */ jsx(
|
|
867
|
-
"button",
|
|
868
|
-
{
|
|
869
|
-
className: "tlui-cmt-thread__action",
|
|
870
|
-
title: msg("comments.delete"),
|
|
871
|
-
onClick: deleteThread,
|
|
872
|
-
children: /* @__PURE__ */ jsx(TldrawUiIcon, { icon: "trash", label: msg("comments.delete"), small: true })
|
|
873
|
-
}
|
|
874
|
-
),
|
|
875
|
-
/* @__PURE__ */ jsx(
|
|
876
|
-
"button",
|
|
877
|
-
{
|
|
878
|
-
className: "tlui-cmt-thread__action",
|
|
879
|
-
title: msg("comments.dismiss"),
|
|
880
|
-
onClick: () => openThreadId.set(editor, null),
|
|
881
|
-
children: /* @__PURE__ */ jsx(TldrawUiIcon, { icon: "cross-2", label: msg("comments.dismiss"), small: true })
|
|
882
|
-
}
|
|
883
|
-
)
|
|
884
|
-
] });
|
|
885
778
|
const PinContent = options.components.PinContent;
|
|
886
|
-
const
|
|
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);
|
|
887
784
|
const isRegion = thread.anchor.type === "region";
|
|
888
|
-
const pinMovable = regionOptions.move !== "body";
|
|
889
|
-
const bodyMovable = regionOptions.move !== "pin";
|
|
890
785
|
const startDrag = (e) => {
|
|
786
|
+
if (isCanvasPanGesture(editor, e)) {
|
|
787
|
+
forwardPointerEventToCanvas(container, e);
|
|
788
|
+
return;
|
|
789
|
+
}
|
|
891
790
|
e.stopPropagation();
|
|
892
|
-
|
|
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
|
+
};
|
|
893
806
|
e.currentTarget.setPointerCapture(e.pointerId);
|
|
894
807
|
};
|
|
895
808
|
const onDrag = (e) => {
|
|
896
809
|
const drag = dragRef.current;
|
|
897
810
|
if (!drag) return;
|
|
898
|
-
if (
|
|
811
|
+
if (!canComment) return;
|
|
899
812
|
if (!drag.moved && Math.hypot(e.clientX - drag.startX, e.clientY - drag.startY) < 4) return;
|
|
900
813
|
drag.moved = true;
|
|
901
|
-
|
|
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([]);
|
|
902
831
|
};
|
|
903
832
|
const endDrag = (e) => {
|
|
904
833
|
const drag = dragRef.current;
|
|
@@ -907,55 +836,59 @@ const ThreadPin = memo(function ThreadPin2({
|
|
|
907
836
|
e.currentTarget.releasePointerCapture(e.pointerId);
|
|
908
837
|
}
|
|
909
838
|
if (!drag) return;
|
|
839
|
+
editor.setHintingShapes([]);
|
|
910
840
|
if (!drag.moved) {
|
|
911
841
|
openThreadId.set(editor, openThreadId.get(editor) === thread.id ? null : thread.id);
|
|
912
842
|
return;
|
|
913
843
|
}
|
|
914
|
-
const
|
|
844
|
+
const cursorPage = editor.screenToPage({ x: e.clientX, y: e.clientY });
|
|
845
|
+
const pagePoint = { x: cursorPage.x + drag.offsetX, y: cursorPage.y + drag.offsetY };
|
|
915
846
|
setDragPagePoint(null);
|
|
916
847
|
let anchor;
|
|
917
848
|
if (thread.anchor.type === "region") {
|
|
918
849
|
anchor = {
|
|
919
850
|
...thread.anchor,
|
|
920
|
-
x: pagePoint.x -
|
|
921
|
-
y: pagePoint.y -
|
|
851
|
+
x: pagePoint.x - pinCorner.x * thread.anchor.w,
|
|
852
|
+
y: pagePoint.y - pinCorner.y * thread.anchor.h
|
|
922
853
|
};
|
|
923
854
|
} else {
|
|
924
|
-
const hit = editor
|
|
925
|
-
anchor = hit ? shapeAnchorAt(
|
|
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 };
|
|
926
866
|
}
|
|
927
|
-
commitCommentMutation(editor, () =>
|
|
867
|
+
commitCommentMutation(editor, () => putRecordsInCommit(editor, [{ ...thread, anchor }]), "drag");
|
|
928
868
|
};
|
|
929
|
-
const livePinPage = resizeBounds ? regionPinPoint(resizeBounds,
|
|
930
|
-
const
|
|
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;
|
|
931
872
|
const regionAnchor = thread.anchor.type === "region" ? thread.anchor : void 0;
|
|
932
873
|
const movedRegion = regionAnchor && dragPagePoint ? {
|
|
933
874
|
...regionAnchor,
|
|
934
|
-
x: dragPagePoint.x -
|
|
935
|
-
y: dragPagePoint.y -
|
|
875
|
+
x: dragPagePoint.x - pinCorner.x * regionAnchor.w,
|
|
876
|
+
y: dragPagePoint.y - pinCorner.y * regionAnchor.h
|
|
936
877
|
} : regionAnchor;
|
|
937
878
|
const regionBoxBounds = resizeBounds ?? movedRegion;
|
|
938
879
|
const commitResize = (bounds) => {
|
|
939
880
|
setResizeBounds(null);
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
}
|
|
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"
|
|
945
887
|
);
|
|
946
888
|
};
|
|
947
889
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
948
|
-
regionBoxBounds && (dragPagePoint || revealed) && /* @__PURE__ */ jsx(
|
|
949
|
-
|
|
950
|
-
{
|
|
951
|
-
editor,
|
|
952
|
-
box: regionBoxBounds,
|
|
953
|
-
movable: bodyMovable && !dragPagePoint,
|
|
954
|
-
onPreview: setResizeBounds,
|
|
955
|
-
onCommit: commitResize
|
|
956
|
-
}
|
|
957
|
-
),
|
|
958
|
-
regionBoxBounds && revealed && !dragPagePoint && regionOptions.resize !== "none" && /* @__PURE__ */ jsx(
|
|
890
|
+
regionBoxBounds && (dragPagePoint || revealed) && /* @__PURE__ */ jsx(RegionBox, { editor, box: regionBoxBounds }),
|
|
891
|
+
regionBoxBounds && revealed && !dragPagePoint && canComment && /* @__PURE__ */ jsx(
|
|
959
892
|
RegionResizeHandles,
|
|
960
893
|
{
|
|
961
894
|
editor,
|
|
@@ -968,19 +901,33 @@ const ThreadPin = memo(function ThreadPin2({
|
|
|
968
901
|
/* @__PURE__ */ jsxs(
|
|
969
902
|
"div",
|
|
970
903
|
{
|
|
971
|
-
className:
|
|
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(" "),
|
|
972
909
|
style: { left: renderPoint.x, top: renderPoint.y },
|
|
973
910
|
children: [
|
|
974
911
|
/* @__PURE__ */ jsx(
|
|
975
|
-
"
|
|
912
|
+
"button",
|
|
976
913
|
{
|
|
977
914
|
ref: markerRef,
|
|
978
|
-
|
|
915
|
+
type: "button",
|
|
916
|
+
className: "tlui-cmt-button tlui-cmt-canvas-pin__marker",
|
|
917
|
+
"aria-label": pinLabel,
|
|
918
|
+
"aria-expanded": open,
|
|
979
919
|
onPointerDown: startDrag,
|
|
980
920
|
onPointerMove: onDrag,
|
|
981
921
|
onPointerUp: endDrag,
|
|
982
|
-
|
|
983
|
-
|
|
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,
|
|
984
931
|
children: /* @__PURE__ */ jsx(CommentPin, { resolved: thread.resolved != null, open, children: pinContent })
|
|
985
932
|
}
|
|
986
933
|
),
|
|
@@ -988,31 +935,25 @@ const ThreadPin = memo(function ThreadPin2({
|
|
|
988
935
|
ThreadPopover,
|
|
989
936
|
{
|
|
990
937
|
container,
|
|
991
|
-
style: {
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
disabled: isCommentEmpty(reply),
|
|
1011
|
-
getMentionSuggestions,
|
|
1012
|
-
renderMentionSuggestion
|
|
1013
|
-
} : void 0
|
|
1014
|
-
}
|
|
1015
|
-
)
|
|
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
|
|
1016
957
|
}
|
|
1017
958
|
)
|
|
1018
959
|
]
|
|
@@ -1024,12 +965,18 @@ function PendingComposer({
|
|
|
1024
965
|
editor,
|
|
1025
966
|
pending,
|
|
1026
967
|
currentUserId,
|
|
1027
|
-
|
|
968
|
+
resolveAuthor,
|
|
1028
969
|
onPostComment,
|
|
1029
970
|
getMentionSuggestions,
|
|
1030
971
|
renderMentionSuggestion
|
|
1031
972
|
}) {
|
|
1032
|
-
const
|
|
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
|
+
);
|
|
1033
980
|
const ref = useRef(null);
|
|
1034
981
|
const msg = useTranslation();
|
|
1035
982
|
const container = useContainer();
|
|
@@ -1065,10 +1012,11 @@ function PendingComposer({
|
|
|
1065
1012
|
authorId: currentUserId,
|
|
1066
1013
|
body: text
|
|
1067
1014
|
});
|
|
1068
|
-
|
|
1015
|
+
putRecordsInCommit(editor, [thread, comment]);
|
|
1069
1016
|
if (onPostComment) onPostComment(comment);
|
|
1070
1017
|
});
|
|
1071
1018
|
setText(EMPTY_COMMENT);
|
|
1019
|
+
clearCommentDraft(NEW_COMMENT_DRAFT);
|
|
1072
1020
|
pendingComment.set(editor, null);
|
|
1073
1021
|
};
|
|
1074
1022
|
return createPortal(
|
|
@@ -1076,28 +1024,36 @@ function PendingComposer({
|
|
|
1076
1024
|
"div",
|
|
1077
1025
|
{
|
|
1078
1026
|
ref,
|
|
1079
|
-
className:
|
|
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(" "),
|
|
1080
1032
|
style: { left: point.x, top: point.y },
|
|
1081
1033
|
onPointerDown: stop,
|
|
1034
|
+
onContextMenu: stop,
|
|
1082
1035
|
onKeyDown: (e) => {
|
|
1083
1036
|
if (e.key === "Escape" && !isMentionPickerOpen()) pendingComment.set(editor, null);
|
|
1084
1037
|
},
|
|
1085
|
-
children: /* @__PURE__ */ jsx(
|
|
1038
|
+
children: canComment ? /* @__PURE__ */ jsx(
|
|
1086
1039
|
CommentComposer,
|
|
1087
1040
|
{
|
|
1088
|
-
author:
|
|
1041
|
+
author: me ?? UNKNOWN_COMMENT_AUTHOR,
|
|
1089
1042
|
placeholder: msg("comments.add-placeholder"),
|
|
1090
1043
|
sendLabel: msg("comments.send"),
|
|
1091
1044
|
value: text,
|
|
1092
|
-
onChange:
|
|
1045
|
+
onChange: (value) => {
|
|
1046
|
+
setText(value);
|
|
1047
|
+
saveCommentDraft(NEW_COMMENT_DRAFT, value);
|
|
1048
|
+
},
|
|
1093
1049
|
onSubmit: submit,
|
|
1094
|
-
disabled: isCommentEmpty(text),
|
|
1050
|
+
disabled: isCommentEmpty(text) || !currentUserId,
|
|
1095
1051
|
getMentionSuggestions,
|
|
1096
1052
|
renderMentionSuggestion,
|
|
1097
1053
|
autoFocus: true,
|
|
1098
1054
|
leading: draftAvatar
|
|
1099
1055
|
}
|
|
1100
|
-
)
|
|
1056
|
+
) : ComposerFallback && /* @__PURE__ */ jsx(ComposerFallback, { context: "pending" })
|
|
1101
1057
|
}
|
|
1102
1058
|
),
|
|
1103
1059
|
container
|