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