@tldraw/commenting 0.0.0-bootstrap → 5.3.0-internal.1640468db8fd
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/commenting.css +284 -153
- package/dist-cjs/canvas/comment-body.js +1 -1
- package/dist-cjs/canvas/comment-body.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-render.js +2 -0
- package/dist-cjs/canvas/comment-render.js.map +2 -2
- package/dist-cjs/canvas/comment-tool.js +65 -12
- package/dist-cjs/canvas/comment-tool.js.map +2 -2
- package/dist-cjs/canvas/comments-filter-menu.js +54 -63
- package/dist-cjs/canvas/comments-filter-menu.js.map +2 -2
- package/dist-cjs/canvas/comments-overflow-menu.js +21 -27
- package/dist-cjs/canvas/comments-overflow-menu.js.map +2 -2
- package/dist-cjs/canvas/comments-overlay.js +304 -112
- package/dist-cjs/canvas/comments-overlay.js.map +2 -2
- package/dist-cjs/canvas/comments-sidebar.js +12 -18
- package/dist-cjs/canvas/comments-sidebar.js.map +2 -2
- package/dist-cjs/canvas/comments-visibility-toggle.js +66 -0
- package/dist-cjs/canvas/comments-visibility-toggle.js.map +7 -0
- package/dist-cjs/canvas/options.js +1 -0
- package/dist-cjs/canvas/options.js.map +2 -2
- 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 +11 -0
- package/dist-cjs/canvas/state.js.map +2 -2
- package/dist-cjs/canvas/thread-state.js +8 -1
- package/dist-cjs/canvas/thread-state.js.map +2 -2
- package/dist-cjs/clustering/runtime.js +119 -7
- package/dist-cjs/clustering/runtime.js.map +2 -2
- package/dist-cjs/index.d.ts +126 -41
- package/dist-cjs/index.js +7 -1
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/ui/avatar.js +14 -6
- package/dist-cjs/ui/avatar.js.map +2 -2
- package/dist-cjs/ui/byline.js +4 -4
- package/dist-cjs/ui/byline.js.map +2 -2
- package/dist-cjs/ui/comment-author.js +17 -0
- package/dist-cjs/ui/comment-author.js.map +7 -0
- package/dist-cjs/ui/comment-card.js +4 -4
- package/dist-cjs/ui/comment-card.js.map +2 -2
- package/dist-cjs/ui/comment-composer.js +92 -29
- package/dist-cjs/ui/comment-composer.js.map +2 -2
- package/dist-cjs/ui/comment-mention.js +1 -1
- package/dist-cjs/ui/comment-mention.js.map +2 -2
- package/dist-cjs/ui/comment-pin.js +23 -3
- package/dist-cjs/ui/comment-pin.js.map +2 -2
- package/dist-cjs/ui/comment-text.js +1 -1
- package/dist-cjs/ui/comment-text.js.map +2 -2
- package/dist-cjs/ui/comment-thread.js +6 -6
- package/dist-cjs/ui/comment-thread.js.map +2 -2
- package/dist-cjs/ui/comments-list.js +12 -12
- package/dist-cjs/ui/comments-list.js.map +2 -2
- package/dist-cjs/ui/count-badge.js +1 -1
- package/dist-cjs/ui/count-badge.js.map +2 -2
- package/dist-cjs/ui/empty-state.js +3 -3
- package/dist-cjs/ui/empty-state.js.map +2 -2
- package/dist-cjs/ui/format-time.js +3 -0
- package/dist-cjs/ui/format-time.js.map +2 -2
- package/dist-cjs/ui/mention-list.js +8 -8
- package/dist-cjs/ui/mention-list.js.map +2 -2
- package/dist-cjs/ui/mention-suggestion.js +3 -3
- package/dist-cjs/ui/mention-suggestion.js.map +2 -2
- package/dist-cjs/ui/mention.js +1 -1
- package/dist-cjs/ui/mention.js.map +2 -2
- package/dist-cjs/ui/reaction.js +11 -4
- package/dist-cjs/ui/reaction.js.map +2 -2
- package/dist-cjs/ui/reactions.js +10 -2
- package/dist-cjs/ui/reactions.js.map +2 -2
- package/dist-cjs/ui/send-button.js +1 -1
- package/dist-cjs/ui/send-button.js.map +2 -2
- package/dist-cjs/ui/tooltip-button.js +32 -0
- package/dist-cjs/ui/tooltip-button.js.map +7 -0
- package/dist-esm/canvas/comment-body.mjs +1 -1
- package/dist-esm/canvas/comment-body.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-render.mjs +2 -0
- package/dist-esm/canvas/comment-render.mjs.map +2 -2
- package/dist-esm/canvas/comment-tool.mjs +67 -14
- package/dist-esm/canvas/comment-tool.mjs.map +2 -2
- package/dist-esm/canvas/comments-filter-menu.mjs +54 -63
- package/dist-esm/canvas/comments-filter-menu.mjs.map +2 -2
- package/dist-esm/canvas/comments-overflow-menu.mjs +22 -27
- package/dist-esm/canvas/comments-overflow-menu.mjs.map +2 -2
- package/dist-esm/canvas/comments-overlay.mjs +322 -114
- package/dist-esm/canvas/comments-overlay.mjs.map +2 -2
- package/dist-esm/canvas/comments-sidebar.mjs +15 -21
- package/dist-esm/canvas/comments-sidebar.mjs.map +2 -2
- package/dist-esm/canvas/comments-visibility-toggle.mjs +46 -0
- package/dist-esm/canvas/comments-visibility-toggle.mjs.map +7 -0
- package/dist-esm/canvas/options.mjs +1 -0
- package/dist-esm/canvas/options.mjs.map +2 -2
- 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 +11 -0
- package/dist-esm/canvas/state.mjs.map +2 -2
- package/dist-esm/canvas/thread-state.mjs +8 -1
- package/dist-esm/canvas/thread-state.mjs.map +2 -2
- package/dist-esm/clustering/runtime.mjs +119 -7
- package/dist-esm/clustering/runtime.mjs.map +2 -2
- package/dist-esm/index.d.mts +126 -41
- package/dist-esm/index.mjs +11 -1
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/ui/avatar.mjs +14 -6
- package/dist-esm/ui/avatar.mjs.map +2 -2
- package/dist-esm/ui/byline.mjs +4 -4
- package/dist-esm/ui/byline.mjs.map +2 -2
- package/dist-esm/ui/comment-author.mjs +1 -0
- package/dist-esm/ui/comment-author.mjs.map +7 -0
- package/dist-esm/ui/comment-card.mjs +4 -4
- package/dist-esm/ui/comment-card.mjs.map +2 -2
- package/dist-esm/ui/comment-composer.mjs +93 -30
- package/dist-esm/ui/comment-composer.mjs.map +2 -2
- package/dist-esm/ui/comment-mention.mjs +1 -1
- package/dist-esm/ui/comment-mention.mjs.map +2 -2
- package/dist-esm/ui/comment-pin.mjs +23 -3
- package/dist-esm/ui/comment-pin.mjs.map +2 -2
- package/dist-esm/ui/comment-text.mjs +1 -1
- package/dist-esm/ui/comment-text.mjs.map +2 -2
- package/dist-esm/ui/comment-thread.mjs +6 -6
- package/dist-esm/ui/comment-thread.mjs.map +2 -2
- package/dist-esm/ui/comments-list.mjs +12 -12
- package/dist-esm/ui/comments-list.mjs.map +2 -2
- package/dist-esm/ui/count-badge.mjs +1 -1
- package/dist-esm/ui/count-badge.mjs.map +2 -2
- package/dist-esm/ui/empty-state.mjs +3 -3
- package/dist-esm/ui/empty-state.mjs.map +2 -2
- package/dist-esm/ui/format-time.mjs +3 -0
- package/dist-esm/ui/format-time.mjs.map +2 -2
- package/dist-esm/ui/mention-list.mjs +8 -8
- package/dist-esm/ui/mention-list.mjs.map +2 -2
- package/dist-esm/ui/mention-suggestion.mjs +3 -3
- package/dist-esm/ui/mention-suggestion.mjs.map +2 -2
- package/dist-esm/ui/mention.mjs +1 -1
- package/dist-esm/ui/mention.mjs.map +2 -2
- package/dist-esm/ui/reaction.mjs +11 -4
- package/dist-esm/ui/reaction.mjs.map +2 -2
- package/dist-esm/ui/reactions.mjs +10 -2
- package/dist-esm/ui/reactions.mjs.map +2 -2
- package/dist-esm/ui/send-button.mjs +1 -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 +3 -3
- package/src/canvas/canvas.css +79 -36
- package/src/canvas/comment-body.tsx +1 -1
- package/src/canvas/comment-drafts.test.ts +55 -0
- package/src/canvas/comment-drafts.ts +46 -0
- package/src/canvas/comment-render.test.ts +1 -1
- package/src/canvas/comment-render.ts +7 -2
- package/src/canvas/comment-tool.tsx +98 -17
- package/src/canvas/comments-filter-menu.tsx +27 -33
- package/src/canvas/comments-overflow-menu.tsx +13 -21
- package/src/canvas/comments-overlay.tsx +441 -145
- package/src/canvas/comments-sidebar.tsx +27 -28
- package/src/canvas/comments-visibility-toggle.tsx +50 -0
- package/src/canvas/options.ts +25 -0
- package/src/canvas/sidebar-filters.ts +4 -3
- package/src/canvas/state.ts +22 -0
- package/src/canvas/thread-state.ts +16 -3
- package/src/clustering/runtime.test.ts +183 -7
- package/src/clustering/runtime.ts +164 -15
- package/src/index.ts +7 -0
- package/src/ui/avatar.tsx +15 -11
- package/src/ui/byline.tsx +6 -5
- package/src/ui/comment-author.ts +15 -0
- package/src/ui/comment-card.tsx +6 -5
- package/src/ui/comment-composer.tsx +122 -33
- package/src/ui/comment-mention.ts +2 -2
- package/src/ui/comment-pin.tsx +35 -4
- package/src/ui/comment-text.tsx +1 -1
- package/src/ui/comment-thread.tsx +8 -6
- package/src/ui/comments-list.tsx +19 -14
- package/src/ui/comments.css +205 -117
- package/src/ui/count-badge.tsx +1 -1
- package/src/ui/empty-state.tsx +3 -3
- package/src/ui/format-time.ts +5 -0
- package/src/ui/mention-list.tsx +13 -16
- package/src/ui/mention-suggestion.tsx +3 -3
- package/src/ui/mention.tsx +1 -1
- package/src/ui/reaction.tsx +6 -3
- package/src/ui/reactions.tsx +6 -2
- package/src/ui/send-button.tsx +1 -1
- package/src/ui/tooltip-button.tsx +20 -0
|
@@ -34,8 +34,10 @@ var import_comment_pin = require("../ui/comment-pin");
|
|
|
34
34
|
var import_comment_thread = require("../ui/comment-thread");
|
|
35
35
|
var import_count_badge = require("../ui/count-badge");
|
|
36
36
|
var import_mention_suggestion = require("../ui/mention-suggestion");
|
|
37
|
+
var import_tooltip_button = require("../ui/tooltip-button");
|
|
37
38
|
var import_cluster_input = require("./cluster-input");
|
|
38
39
|
var import_comment_body = require("./comment-body");
|
|
40
|
+
var import_comment_drafts = require("./comment-drafts");
|
|
39
41
|
var import_comment_render = require("./comment-render");
|
|
40
42
|
var import_comment_store = require("./comment-store");
|
|
41
43
|
var import_hooks = require("./hooks");
|
|
@@ -45,10 +47,26 @@ var import_region_options = require("./region-options");
|
|
|
45
47
|
var import_state = require("./state");
|
|
46
48
|
var import_thread_state = require("./thread-state");
|
|
47
49
|
const stop = (e) => e.stopPropagation();
|
|
50
|
+
const IMPRECISE_PIN_INSET_PX = 20;
|
|
51
|
+
function impreciseShapePinInset(anchor, spot) {
|
|
52
|
+
if (anchor.type !== "shape" || anchor.isPrecise) return null;
|
|
53
|
+
return {
|
|
54
|
+
x: Math.sign(0.5 - spot.x) * IMPRECISE_PIN_INSET_PX,
|
|
55
|
+
y: Math.sign(0.5 - spot.y) * IMPRECISE_PIN_INSET_PX
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
const isCanvasPanGesture = (editor, e) => e.button !== 0 || editor.inputs.keys.has("Space");
|
|
59
|
+
function forwardPointerEventToCanvas(container, e) {
|
|
60
|
+
const cvs = container.querySelector(".tl-canvas");
|
|
61
|
+
if (!cvs) return;
|
|
62
|
+
const newEvent = new PointerEvent(e.type, e.nativeEvent);
|
|
63
|
+
newEvent.isSpecialRedispatchedEvent = true;
|
|
64
|
+
cvs.dispatchEvent(newEvent);
|
|
65
|
+
}
|
|
48
66
|
const initialOf = (name) => ((0, import_tldraw.getFirstCharacter)(name.trim()) || "?").toUpperCase();
|
|
49
67
|
const CLUSTER_FADE_MS = 150;
|
|
50
68
|
const CLUSTER_EXPAND_ZOOM_MS = 450;
|
|
51
|
-
const draftAvatar = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_comment_pin.CommentPin, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
69
|
+
const draftAvatar = (color) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_comment_pin.CommentPin, { color, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
52
70
|
"svg",
|
|
53
71
|
{
|
|
54
72
|
viewBox: "0 0 24 24",
|
|
@@ -66,11 +84,11 @@ const draftAvatar = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_comment_p
|
|
|
66
84
|
]
|
|
67
85
|
}
|
|
68
86
|
) });
|
|
69
|
-
function toCardProps(comment, props, components) {
|
|
87
|
+
function toCardProps(comment, props, components, resolveName) {
|
|
70
88
|
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
|
|
89
|
+
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 });
|
|
72
90
|
return {
|
|
73
|
-
author: props.
|
|
91
|
+
author: props.resolveAuthor(comment.authorId) ?? import_comment_render.UNKNOWN_COMMENT_AUTHOR,
|
|
74
92
|
body,
|
|
75
93
|
date: new Date(comment.createdAt).toISOString(),
|
|
76
94
|
you: comment.authorId === props.currentUserId,
|
|
@@ -92,24 +110,23 @@ function CanvasCommentsLayer(props) {
|
|
|
92
110
|
);
|
|
93
111
|
(0, import_react.useEffect)(() => (0, import_region_options.setRegionCommentOptions)(editor, regionOptions), [editor, regionOptions]);
|
|
94
112
|
const layerRef = (0, import_react.useRef)(null);
|
|
95
|
-
(0, import_tldraw.usePassThroughWheelEvents)(layerRef);
|
|
96
113
|
(0, import_tldraw.usePassThroughMouseOverEvents)(layerRef);
|
|
97
114
|
const deepLinkHandled = (0, import_react.useRef)(false);
|
|
98
115
|
const threads = (0, import_hooks.useCommentThreads)(editor);
|
|
99
116
|
const pending = (0, import_state.usePendingComment)();
|
|
100
117
|
const openId = (0, import_tldraw.useValue)("open thread id", () => import_state.openThreadId.get(editor), [editor]);
|
|
101
118
|
const impreciseShapeAnchor = props.impreciseShapeAnchor ?? options.impreciseShapeAnchor;
|
|
102
|
-
const [
|
|
119
|
+
const [heldThreadIds, setHeldThreadIds] = (0, import_react.useState)(EMPTY_SET);
|
|
103
120
|
const adoptOnRebuild = (0, import_react.useRef)(false);
|
|
104
121
|
const clusterLeaves = (0, import_tldraw.useValue)(
|
|
105
122
|
"comment cluster leaves",
|
|
106
123
|
() => (0, import_cluster_input.collectClusterLeaves)(
|
|
107
124
|
editor,
|
|
108
|
-
threads.filter((thread) => !
|
|
125
|
+
threads.filter((thread) => !heldThreadIds.has(thread.id)),
|
|
109
126
|
import_state.openThreadId.get(editor),
|
|
110
127
|
impreciseShapeAnchor
|
|
111
128
|
),
|
|
112
|
-
[editor, threads, impreciseShapeAnchor,
|
|
129
|
+
[editor, threads, impreciseShapeAnchor, heldThreadIds]
|
|
113
130
|
);
|
|
114
131
|
const clusterZoomBounds = (0, import_tldraw.useValue)(
|
|
115
132
|
"comment cluster zoom bounds",
|
|
@@ -124,21 +141,41 @@ function CanvasCommentsLayer(props) {
|
|
|
124
141
|
}, [clusterLeaves, clusterZoomBounds, editor]);
|
|
125
142
|
const [renderedModel, setRenderedModel] = (0, import_react.useState)(latestModel);
|
|
126
143
|
let clusterModel = renderedModel;
|
|
127
|
-
|
|
144
|
+
const pageId = (0, import_tldraw.useValue)("comment cluster page", () => editor.getCurrentPageId(), [editor]);
|
|
145
|
+
const pageRef = (0, import_react.useRef)(pageId);
|
|
146
|
+
if (pageRef.current !== pageId) {
|
|
147
|
+
pageRef.current = pageId;
|
|
148
|
+
adoptOnRebuild.current = false;
|
|
149
|
+
latestModel.runtime.seed(editor.getZoomLevel());
|
|
150
|
+
if (heldThreadIds.size > 0) setHeldThreadIds(EMPTY_SET);
|
|
151
|
+
setRenderedModel(latestModel);
|
|
152
|
+
clusterModel = latestModel;
|
|
153
|
+
}
|
|
154
|
+
const rejoinPending = heldThreadIds.size === 0 && adoptOnRebuild.current;
|
|
155
|
+
if (renderedModel !== latestModel && rejoinPending) {
|
|
128
156
|
adoptOnRebuild.current = false;
|
|
129
157
|
latestModel.runtime.seedFrom(editor.getZoomLevel(), renderedModel.runtime.getVisible());
|
|
130
158
|
setRenderedModel(latestModel);
|
|
131
159
|
clusterModel = latestModel;
|
|
160
|
+
} else if (heldThreadIds.size === 0 && renderedModel === latestModel) {
|
|
161
|
+
adoptOnRebuild.current = false;
|
|
132
162
|
}
|
|
133
163
|
const newlyMovedIds = findMovedClusteredLeafIds(clusterModel, latestModel);
|
|
134
164
|
if (newlyMovedIds.length > 0) {
|
|
135
|
-
|
|
136
|
-
const next = new Set(movedThreadIds);
|
|
165
|
+
const next = new Set(heldThreadIds);
|
|
137
166
|
for (const id of newlyMovedIds) next.add(id);
|
|
138
|
-
|
|
167
|
+
setHeldThreadIds(next);
|
|
168
|
+
}
|
|
169
|
+
{
|
|
170
|
+
const latestLeafIds = new Set(latestModel.table.leaves.map((leaf) => leaf.id));
|
|
171
|
+
for (const leaf of clusterModel.table.leaves) {
|
|
172
|
+
if (!latestLeafIds.has(leaf.id)) {
|
|
173
|
+
clusterModel.runtime.detachLeaf(leaf.id);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
139
176
|
}
|
|
140
177
|
(0, import_react.useEffect)(() => {
|
|
141
|
-
if (
|
|
178
|
+
if (heldThreadIds.size === 0) return;
|
|
142
179
|
let lastZoom = editor.getZoomLevel();
|
|
143
180
|
return (0, import_tldraw.react)("rejoin moved comment pins on zoom out", () => {
|
|
144
181
|
const zoom = editor.getZoomLevel();
|
|
@@ -146,9 +183,9 @@ function CanvasCommentsLayer(props) {
|
|
|
146
183
|
lastZoom = zoom;
|
|
147
184
|
if (zoom >= prevZoom) return;
|
|
148
185
|
adoptOnRebuild.current = true;
|
|
149
|
-
|
|
186
|
+
setHeldThreadIds(EMPTY_SET);
|
|
150
187
|
});
|
|
151
|
-
}, [
|
|
188
|
+
}, [heldThreadIds, editor]);
|
|
152
189
|
(0, import_react.useEffect)(() => {
|
|
153
190
|
if (clusterModel === latestModel) return;
|
|
154
191
|
let lastZoom = editor.getZoomLevel();
|
|
@@ -161,31 +198,31 @@ function CanvasCommentsLayer(props) {
|
|
|
161
198
|
setRenderedModel(latestModel);
|
|
162
199
|
});
|
|
163
200
|
}, [clusterModel, latestModel, editor]);
|
|
201
|
+
const partitionVersion = clusterModel.runtime.version;
|
|
164
202
|
const orphanThreads = (0, import_react.useMemo)(() => {
|
|
165
203
|
if (clusterModel === latestModel) return [];
|
|
166
|
-
const
|
|
204
|
+
const displayed = /* @__PURE__ */ new Set();
|
|
205
|
+
for (const node of clusterModel.runtime.getVisible().values()) {
|
|
206
|
+
for (const member of node.members) displayed.add(member);
|
|
207
|
+
}
|
|
167
208
|
const latestIds = new Set(latestModel.table.leaves.map((leaf) => leaf.id));
|
|
168
|
-
return threads.filter((thread) => latestIds.has(thread.id) && !
|
|
169
|
-
}, [clusterModel, latestModel, threads]);
|
|
170
|
-
const
|
|
171
|
-
() => threads.filter((thread) =>
|
|
172
|
-
[threads,
|
|
209
|
+
return threads.filter((thread) => latestIds.has(thread.id) && !displayed.has(thread.id));
|
|
210
|
+
}, [clusterModel, latestModel, threads, partitionVersion]);
|
|
211
|
+
const heldThreads = (0, import_react.useMemo)(
|
|
212
|
+
() => threads.filter((thread) => heldThreadIds.has(thread.id) && thread.id !== openId),
|
|
213
|
+
[threads, heldThreadIds, openId]
|
|
173
214
|
);
|
|
174
|
-
|
|
175
|
-
"comment cluster
|
|
215
|
+
(0, import_tldraw.useValue)(
|
|
216
|
+
"comment cluster version",
|
|
176
217
|
() => {
|
|
177
218
|
clusterModel.runtime.onCamera(editor.getZoomLevel());
|
|
178
|
-
return clusterModel.runtime.
|
|
219
|
+
return clusterModel.runtime.version;
|
|
179
220
|
},
|
|
180
221
|
[clusterModel, editor]
|
|
181
222
|
);
|
|
182
223
|
const visibleNodes = (0, import_react.useMemo)(() => {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
`[comments] cluster cursor k=${clusterCursor} \u2192 re-rendering ${nodes.length} visible nodes`
|
|
186
|
-
);
|
|
187
|
-
return nodes;
|
|
188
|
-
}, [clusterModel, clusterCursor]);
|
|
224
|
+
return Array.from(clusterModel.runtime.getVisible().values());
|
|
225
|
+
}, [clusterModel, partitionVersion]);
|
|
189
226
|
const fadeNodes = useFadeVisibleNodes(visibleNodes, clusterModel);
|
|
190
227
|
const threadsById = (0, import_react.useMemo)(
|
|
191
228
|
() => new Map(threads.map((thread) => [thread.id, thread])),
|
|
@@ -244,7 +281,7 @@ function CanvasCommentsLayer(props) {
|
|
|
244
281
|
if (e.key !== "Escape" || import_state.openThreadId.get(editor) === null) return;
|
|
245
282
|
if ((0, import_mention_suggestion.isMentionPickerOpen)()) return;
|
|
246
283
|
const target = e.target;
|
|
247
|
-
if (target && target.closest(".cmt-editing")) return;
|
|
284
|
+
if (target && target.closest(".tlui-cmt-editing")) return;
|
|
248
285
|
import_state.openThreadId.set(editor, null);
|
|
249
286
|
e.preventDefault();
|
|
250
287
|
e.stopPropagation();
|
|
@@ -265,7 +302,7 @@ function CanvasCommentsLayer(props) {
|
|
|
265
302
|
}, [editor]);
|
|
266
303
|
if (hidden) return null;
|
|
267
304
|
return (0, import_react_dom.createPortal)(
|
|
268
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { ref: layerRef, className: "cmt-canvas-layer", children: [
|
|
305
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { ref: layerRef, className: "tlui-cmt-canvas-layer", children: [
|
|
269
306
|
options.enableClustering ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
270
307
|
fadeNodes.map(({ node, phase }) => {
|
|
271
308
|
let content;
|
|
@@ -296,7 +333,7 @@ function CanvasCommentsLayer(props) {
|
|
|
296
333
|
},
|
|
297
334
|
thread.id
|
|
298
335
|
)),
|
|
299
|
-
|
|
336
|
+
heldThreads.map((thread) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
300
337
|
ThreadPin,
|
|
301
338
|
{
|
|
302
339
|
editor,
|
|
@@ -405,7 +442,7 @@ function cancelClusterFadeFrame(frame) {
|
|
|
405
442
|
else window.clearTimeout(frame);
|
|
406
443
|
}
|
|
407
444
|
function clusterFadeClassName(phase) {
|
|
408
|
-
return `cmt-cluster-fade cmt-cluster-fade--${phase}`;
|
|
445
|
+
return `tlui-cmt-cluster-fade tlui-cmt-cluster-fade--${phase}`;
|
|
409
446
|
}
|
|
410
447
|
function findMovedClusteredLeafIds(rendered, latest) {
|
|
411
448
|
if (rendered.table === latest.table) return [];
|
|
@@ -422,11 +459,6 @@ function findMovedClusteredLeafIds(rendered, latest) {
|
|
|
422
459
|
}
|
|
423
460
|
return moved;
|
|
424
461
|
}
|
|
425
|
-
function hasRemovedLeaves(rendered, latest) {
|
|
426
|
-
if (rendered.leaves.length === 0) return false;
|
|
427
|
-
const latestIds = new Set(latest.leaves.map((leaf) => leaf.id));
|
|
428
|
-
return rendered.leaves.some((leaf) => !latestIds.has(leaf.id));
|
|
429
|
-
}
|
|
430
462
|
function getClusterZoomBounds(editor) {
|
|
431
463
|
const cameraOptions = editor.getCameraOptions();
|
|
432
464
|
const baseZoom = cameraOptions.constraints ? editor.getBaseZoom() : 1;
|
|
@@ -478,6 +510,9 @@ const ClusterBadge = (0, import_react.memo)(function ClusterBadge2({
|
|
|
478
510
|
node,
|
|
479
511
|
onExpand
|
|
480
512
|
}) {
|
|
513
|
+
const container = (0, import_tldraw.useContainer)();
|
|
514
|
+
const badgeRef = (0, import_react.useRef)(null);
|
|
515
|
+
(0, import_tldraw.usePassThroughWheelEvents)(badgeRef);
|
|
481
516
|
const point = (0, import_tldraw.useValue)(
|
|
482
517
|
"cluster badge point",
|
|
483
518
|
() => {
|
|
@@ -491,9 +526,16 @@ const ClusterBadge = (0, import_react.memo)(function ClusterBadge2({
|
|
|
491
526
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
492
527
|
"div",
|
|
493
528
|
{
|
|
494
|
-
|
|
529
|
+
ref: badgeRef,
|
|
530
|
+
className: "tlui-cmt-canvas-cluster",
|
|
495
531
|
style: { left: point.x, top: point.y },
|
|
496
|
-
onPointerDown:
|
|
532
|
+
onPointerDown: (e) => {
|
|
533
|
+
if (isCanvasPanGesture(editor, e)) {
|
|
534
|
+
forwardPointerEventToCanvas(container, e);
|
|
535
|
+
return;
|
|
536
|
+
}
|
|
537
|
+
e.stopPropagation();
|
|
538
|
+
},
|
|
497
539
|
onClick: (e) => {
|
|
498
540
|
e.stopPropagation();
|
|
499
541
|
onExpand(node);
|
|
@@ -516,7 +558,19 @@ function ThreadPopover({
|
|
|
516
558
|
(0, import_tldraw.usePassThroughWheelEvents)(ref);
|
|
517
559
|
(0, import_tldraw.usePassThroughMouseOverEvents)(ref);
|
|
518
560
|
return (0, import_react_dom.createPortal)(
|
|
519
|
-
|
|
561
|
+
// contextmenu also stops here: portals bubble React events to the canvas's context-menu
|
|
562
|
+
// trigger (the layer mounts inside it), which would open the canvas menu over this panel.
|
|
563
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
564
|
+
"div",
|
|
565
|
+
{
|
|
566
|
+
ref,
|
|
567
|
+
className: "tlui-cmt-canvas-popover",
|
|
568
|
+
style,
|
|
569
|
+
onPointerDown: stop,
|
|
570
|
+
onContextMenu: stop,
|
|
571
|
+
children
|
|
572
|
+
}
|
|
573
|
+
),
|
|
520
574
|
container
|
|
521
575
|
);
|
|
522
576
|
}
|
|
@@ -537,12 +591,19 @@ function RegionBox({
|
|
|
537
591
|
[editor, box.x, box.y, box.w, box.h]
|
|
538
592
|
);
|
|
539
593
|
const grabRef = (0, import_react.useRef)(null);
|
|
594
|
+
const container = (0, import_tldraw.useContainer)();
|
|
595
|
+
const boxRef = (0, import_react.useRef)(null);
|
|
596
|
+
(0, import_tldraw.usePassThroughWheelEvents)(boxRef);
|
|
540
597
|
const translated = (e) => {
|
|
541
598
|
const g = grabRef.current;
|
|
542
599
|
const p = editor.screenToPage({ x: e.clientX, y: e.clientY });
|
|
543
600
|
return { ...g.box, x: g.box.x + (p.x - g.page.x), y: g.box.y + (p.y - g.page.y) };
|
|
544
601
|
};
|
|
545
602
|
const startMove = (e) => {
|
|
603
|
+
if (isCanvasPanGesture(editor, e)) {
|
|
604
|
+
forwardPointerEventToCanvas(container, e);
|
|
605
|
+
return;
|
|
606
|
+
}
|
|
546
607
|
e.stopPropagation();
|
|
547
608
|
grabRef.current = { page: editor.screenToPage({ x: e.clientX, y: e.clientY }), box };
|
|
548
609
|
e.currentTarget.setPointerCapture(e.pointerId);
|
|
@@ -561,7 +622,8 @@ function RegionBox({
|
|
|
561
622
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
562
623
|
"div",
|
|
563
624
|
{
|
|
564
|
-
|
|
625
|
+
ref: boxRef,
|
|
626
|
+
className: movable ? "tlui-cmt-canvas-region tlui-cmt-canvas-region--movable" : "tlui-cmt-canvas-region",
|
|
565
627
|
style: rect,
|
|
566
628
|
onPointerDown: movable ? startMove : void 0,
|
|
567
629
|
onPointerMove: movable ? onMove : void 0,
|
|
@@ -635,7 +697,7 @@ function RegionResizeHandles({
|
|
|
635
697
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: points.map((h) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
636
698
|
"div",
|
|
637
699
|
{
|
|
638
|
-
className: "cmt-canvas-region-handle",
|
|
700
|
+
className: "tlui-cmt-canvas-region-handle",
|
|
639
701
|
style: { left: h.left, top: h.top, cursor: h.cursor },
|
|
640
702
|
onPointerDown: startResize,
|
|
641
703
|
onPointerMove: onResize(h),
|
|
@@ -652,13 +714,15 @@ const ThreadPin = (0, import_react.memo)(function ThreadPin2({
|
|
|
652
714
|
}) {
|
|
653
715
|
const {
|
|
654
716
|
currentUserId,
|
|
655
|
-
|
|
717
|
+
resolveAuthor,
|
|
656
718
|
onPostComment,
|
|
657
719
|
isCommentUnread,
|
|
658
720
|
onCommentRead,
|
|
659
721
|
getMentionSuggestions,
|
|
660
722
|
renderMentionSuggestion
|
|
661
723
|
} = props;
|
|
724
|
+
const resolveName = (0, import_react.useCallback)((id) => resolveAuthor(id)?.name, [resolveAuthor]);
|
|
725
|
+
const me = currentUserId ? resolveAuthor(currentUserId) : void 0;
|
|
662
726
|
const options = (0, import_options.useCommentingOptions)();
|
|
663
727
|
const impreciseShapeAnchor = props.impreciseShapeAnchor ?? options.impreciseShapeAnchor;
|
|
664
728
|
const container = (0, import_tldraw.useContainer)();
|
|
@@ -668,7 +732,9 @@ const ThreadPin = (0, import_react.memo)(function ThreadPin2({
|
|
|
668
732
|
editor,
|
|
669
733
|
thread.id
|
|
670
734
|
]);
|
|
671
|
-
const [reply, setReply] = (0, import_react.useState)(
|
|
735
|
+
const [reply, setReply] = (0, import_react.useState)(
|
|
736
|
+
() => (0, import_comment_drafts.getCommentDraft)((0, import_comment_drafts.replyDraftSlot)(thread.id)) ?? import_comment_extensions.EMPTY_COMMENT
|
|
737
|
+
);
|
|
672
738
|
const [editingId, setEditingId] = (0, import_react.useState)(null);
|
|
673
739
|
const [editText, setEditText] = (0, import_react.useState)(import_comment_extensions.EMPTY_COMMENT);
|
|
674
740
|
const [dragPagePoint, setDragPagePoint] = (0, import_react.useState)(null);
|
|
@@ -687,24 +753,29 @@ const ThreadPin = (0, import_react.memo)(function ThreadPin2({
|
|
|
687
753
|
[editor, thread.anchor, thread.pageId]
|
|
688
754
|
);
|
|
689
755
|
const revealed = open || resizeBounds != null || regionOptions.reveal === "pointer" && pointerInRegion || regionOptions.reveal === "pin-hover" && pinHovered;
|
|
756
|
+
const pinCorner = thread.anchor.type === "region" ? (0, import_thread_state.regionAnchorPinCorner)(editor, thread.anchor) : regionOptions.pinCorner;
|
|
690
757
|
const resizeHandles = (0, import_react.useMemo)(
|
|
691
|
-
() => regionOptions.resize === "edges" ? REGION_EDGES : REGION_CORNERS.filter(
|
|
692
|
-
|
|
693
|
-
),
|
|
694
|
-
[regionOptions.resize, regionOptions.pinCorner]
|
|
758
|
+
() => regionOptions.resize === "edges" ? REGION_EDGES : REGION_CORNERS.filter((c) => c.x !== pinCorner.x || c.y !== pinCorner.y),
|
|
759
|
+
[regionOptions.resize, pinCorner]
|
|
695
760
|
);
|
|
696
761
|
const dragRef = (0, import_react.useRef)(null);
|
|
697
762
|
const markerRef = (0, import_react.useRef)(null);
|
|
763
|
+
(0, import_tldraw.usePassThroughWheelEvents)(markerRef);
|
|
764
|
+
(0, import_react.useEffect)(() => {
|
|
765
|
+
return () => {
|
|
766
|
+
if (dragRef.current) editor.setHintingShapes([]);
|
|
767
|
+
};
|
|
768
|
+
}, [editor]);
|
|
698
769
|
(0, import_react.useEffect)(() => {
|
|
699
770
|
if (!open) return;
|
|
700
771
|
const onPointerDown = (e) => {
|
|
701
772
|
const target = e.target;
|
|
702
773
|
if (!target) return;
|
|
703
|
-
if (target.closest(".cmt-canvas-popover")) return;
|
|
774
|
+
if (target.closest(".tlui-cmt-canvas-popover")) return;
|
|
704
775
|
const marker = markerRef.current;
|
|
705
776
|
if (marker && marker.contains(target)) return;
|
|
706
|
-
if (target.closest(".cmt-canvas-region-handle, .cmt-canvas-region--movable")) return;
|
|
707
|
-
if (target.closest(".tlui-menu, [data-radix-popper-content-wrapper], .cmt-mention-popup"))
|
|
777
|
+
if (target.closest(".tlui-cmt-canvas-region-handle, .tlui-cmt-canvas-region--movable")) return;
|
|
778
|
+
if (target.closest(".tlui-menu, [data-radix-popper-content-wrapper], .tlui-cmt-mention-popup"))
|
|
708
779
|
return;
|
|
709
780
|
import_state.openThreadId.set(editor, null);
|
|
710
781
|
};
|
|
@@ -716,7 +787,10 @@ const ThreadPin = (0, import_react.memo)(function ThreadPin2({
|
|
|
716
787
|
() => {
|
|
717
788
|
if (thread.pageId !== editor.getCurrentPageId()) return null;
|
|
718
789
|
const pagePoint = (0, import_thread_state.anchorPagePoint)(editor, thread.anchor, impreciseShapeAnchor);
|
|
719
|
-
|
|
790
|
+
if (!pagePoint) return null;
|
|
791
|
+
const viewportPoint = editor.pageToViewport(pagePoint);
|
|
792
|
+
const inset = impreciseShapePinInset(thread.anchor, impreciseShapeAnchor);
|
|
793
|
+
return inset ? { x: viewportPoint.x + inset.x, y: viewportPoint.y + inset.y } : viewportPoint;
|
|
720
794
|
},
|
|
721
795
|
[editor, thread.anchor, thread.pageId, impreciseShapeAnchor]
|
|
722
796
|
);
|
|
@@ -743,6 +817,7 @@ const ThreadPin = (0, import_react.memo)(function ThreadPin2({
|
|
|
743
817
|
if (onPostComment) onPostComment(comment);
|
|
744
818
|
});
|
|
745
819
|
setReply(import_comment_extensions.EMPTY_COMMENT);
|
|
820
|
+
(0, import_comment_drafts.clearCommentDraft)((0, import_comment_drafts.replyDraftSlot)(thread.id));
|
|
746
821
|
};
|
|
747
822
|
const toggleResolve = () => {
|
|
748
823
|
if (!currentUserId) return;
|
|
@@ -766,6 +841,16 @@ const ThreadPin = (0, import_react.memo)(function ThreadPin2({
|
|
|
766
841
|
setEditingId(comment.id);
|
|
767
842
|
setEditText(comment.body);
|
|
768
843
|
};
|
|
844
|
+
const deleteComment = (comment) => {
|
|
845
|
+
(0, import_state.commitCommentMutation)(editor, () => {
|
|
846
|
+
if (comments.length === 1) {
|
|
847
|
+
import_state.openThreadId.set(editor, null);
|
|
848
|
+
(0, import_comment_store.removeCommentRecords)(editor, [thread.id, comment.id]);
|
|
849
|
+
} else {
|
|
850
|
+
(0, import_comment_store.removeCommentRecords)(editor, [comment.id]);
|
|
851
|
+
}
|
|
852
|
+
});
|
|
853
|
+
};
|
|
769
854
|
const saveEdit = () => {
|
|
770
855
|
const comment = comments.find((c) => c.id === editingId);
|
|
771
856
|
if (!comment || (0, import_comment_extensions.isCommentEmpty)(editText)) return;
|
|
@@ -780,7 +865,7 @@ const ThreadPin = (0, import_react.memo)(function ThreadPin2({
|
|
|
780
865
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
781
866
|
"div",
|
|
782
867
|
{
|
|
783
|
-
className: "cmt-editing",
|
|
868
|
+
className: "tlui-cmt-editing",
|
|
784
869
|
onKeyDown: (e) => {
|
|
785
870
|
if (e.key === "Escape") {
|
|
786
871
|
setEditingId(null);
|
|
@@ -809,24 +894,54 @@ const ThreadPin = (0, import_react.memo)(function ThreadPin2({
|
|
|
809
894
|
import_comment_card.CommentCard,
|
|
810
895
|
{
|
|
811
896
|
...card,
|
|
812
|
-
actions: comment.authorId === currentUserId ? /* @__PURE__ */ (0, import_jsx_runtime.
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
897
|
+
actions: comment.authorId === currentUserId ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_tldraw.TldrawUiDropdownMenuRoot, { id: `comment-actions-${comment.id}`, children: [
|
|
898
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_tldraw.TldrawUiDropdownMenuTrigger, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
899
|
+
import_tooltip_button.TooltipButton,
|
|
900
|
+
{
|
|
901
|
+
tooltip: msg("comments.more-options"),
|
|
902
|
+
className: "tlui-cmt-thread__action",
|
|
903
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_tldraw.TldrawUiIcon, { icon: "dots-vertical", label: msg("comments.more-options"), small: true })
|
|
904
|
+
}
|
|
905
|
+
) }),
|
|
906
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
907
|
+
import_tldraw.TldrawUiDropdownMenuContent,
|
|
908
|
+
{
|
|
909
|
+
className: "tlui-cmt-menu",
|
|
910
|
+
side: "bottom",
|
|
911
|
+
align: "end",
|
|
912
|
+
alignOffset: 0,
|
|
913
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_tldraw.TldrawUiDropdownMenuGroup, { children: [
|
|
914
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_tldraw.TldrawUiDropdownMenuItem, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
915
|
+
"button",
|
|
916
|
+
{
|
|
917
|
+
type: "button",
|
|
918
|
+
className: "tlui-cmt-menu-item",
|
|
919
|
+
onClick: () => startEdit(comment),
|
|
920
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: msg("comments.edit-comment") })
|
|
921
|
+
}
|
|
922
|
+
) }),
|
|
923
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_tldraw.TldrawUiDropdownMenuItem, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
924
|
+
"button",
|
|
925
|
+
{
|
|
926
|
+
type: "button",
|
|
927
|
+
className: "tlui-cmt-menu-item tlui-cmt-menu-item--danger",
|
|
928
|
+
onClick: () => deleteComment(comment),
|
|
929
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: msg("comments.delete-comment") })
|
|
930
|
+
}
|
|
931
|
+
) })
|
|
932
|
+
] })
|
|
933
|
+
}
|
|
934
|
+
)
|
|
935
|
+
] }) : void 0
|
|
821
936
|
}
|
|
822
937
|
);
|
|
823
938
|
};
|
|
824
939
|
const headerActions = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
825
940
|
currentUserId && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
826
|
-
|
|
941
|
+
import_tooltip_button.TooltipButton,
|
|
827
942
|
{
|
|
828
|
-
|
|
829
|
-
|
|
943
|
+
tooltip: msg(thread.resolved ? "comments.reopen" : "comments.resolve"),
|
|
944
|
+
className: "tlui-cmt-thread__action",
|
|
830
945
|
onClick: toggleResolve,
|
|
831
946
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
832
947
|
import_tldraw.TldrawUiIcon,
|
|
@@ -838,33 +953,62 @@ const ThreadPin = (0, import_react.memo)(function ThreadPin2({
|
|
|
838
953
|
)
|
|
839
954
|
}
|
|
840
955
|
),
|
|
841
|
-
currentUserId && /* @__PURE__ */ (0, import_jsx_runtime.
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
956
|
+
currentUserId && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_tldraw.TldrawUiDropdownMenuRoot, { id: `comment-thread-actions-${thread.id}`, children: [
|
|
957
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_tldraw.TldrawUiDropdownMenuTrigger, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
958
|
+
import_tooltip_button.TooltipButton,
|
|
959
|
+
{
|
|
960
|
+
tooltip: msg("comments.more-options"),
|
|
961
|
+
className: "tlui-cmt-thread__action",
|
|
962
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_tldraw.TldrawUiIcon, { icon: "dots-vertical", label: msg("comments.more-options"), small: true })
|
|
963
|
+
}
|
|
964
|
+
) }),
|
|
965
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
966
|
+
import_tldraw.TldrawUiDropdownMenuContent,
|
|
967
|
+
{
|
|
968
|
+
className: "tlui-cmt-menu",
|
|
969
|
+
side: "bottom",
|
|
970
|
+
align: "end",
|
|
971
|
+
alignOffset: 0,
|
|
972
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_tldraw.TldrawUiDropdownMenuGroup, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_tldraw.TldrawUiDropdownMenuItem, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
973
|
+
"button",
|
|
974
|
+
{
|
|
975
|
+
type: "button",
|
|
976
|
+
className: "tlui-cmt-menu-item tlui-cmt-menu-item--danger",
|
|
977
|
+
onClick: deleteThread,
|
|
978
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: msg("comments.delete") })
|
|
979
|
+
}
|
|
980
|
+
) }) })
|
|
981
|
+
}
|
|
982
|
+
)
|
|
983
|
+
] })
|
|
859
984
|
] });
|
|
860
985
|
const PinContent = options.components.PinContent;
|
|
861
|
-
const
|
|
986
|
+
const threadAuthor = resolveAuthor(thread.createdBy);
|
|
987
|
+
const pinContent = PinContent ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PinContent, { thread, comments }) : initialOf(threadAuthor?.name ?? import_comment_render.UNKNOWN_AUTHOR);
|
|
862
988
|
const isRegion = thread.anchor.type === "region";
|
|
863
989
|
const pinMovable = regionOptions.move !== "body";
|
|
864
990
|
const bodyMovable = regionOptions.move !== "pin";
|
|
865
991
|
const startDrag = (e) => {
|
|
992
|
+
if (isCanvasPanGesture(editor, e)) {
|
|
993
|
+
forwardPointerEventToCanvas(container, e);
|
|
994
|
+
return;
|
|
995
|
+
}
|
|
866
996
|
e.stopPropagation();
|
|
867
|
-
|
|
997
|
+
const grabPage = editor.screenToPage({ x: e.clientX, y: e.clientY });
|
|
998
|
+
const anchorPage = (0, import_thread_state.anchorPagePoint)(editor, thread.anchor, impreciseShapeAnchor);
|
|
999
|
+
const inset = impreciseShapePinInset(thread.anchor, impreciseShapeAnchor);
|
|
1000
|
+
if (anchorPage && inset) {
|
|
1001
|
+
const zoom = editor.getZoomLevel();
|
|
1002
|
+
anchorPage.x += inset.x / zoom;
|
|
1003
|
+
anchorPage.y += inset.y / zoom;
|
|
1004
|
+
}
|
|
1005
|
+
dragRef.current = {
|
|
1006
|
+
startX: e.clientX,
|
|
1007
|
+
startY: e.clientY,
|
|
1008
|
+
moved: false,
|
|
1009
|
+
offsetX: anchorPage ? anchorPage.x - grabPage.x : 0,
|
|
1010
|
+
offsetY: anchorPage ? anchorPage.y - grabPage.y : 0
|
|
1011
|
+
};
|
|
868
1012
|
e.currentTarget.setPointerCapture(e.pointerId);
|
|
869
1013
|
};
|
|
870
1014
|
const onDrag = (e) => {
|
|
@@ -873,7 +1017,23 @@ const ThreadPin = (0, import_react.memo)(function ThreadPin2({
|
|
|
873
1017
|
if (isRegion && !pinMovable) return;
|
|
874
1018
|
if (!drag.moved && Math.hypot(e.clientX - drag.startX, e.clientY - drag.startY) < 4) return;
|
|
875
1019
|
drag.moved = true;
|
|
876
|
-
|
|
1020
|
+
const cursorPage = editor.screenToPage({ x: e.clientX, y: e.clientY });
|
|
1021
|
+
const pagePoint = { x: cursorPage.x + drag.offsetX, y: cursorPage.y + drag.offsetY };
|
|
1022
|
+
setDragPagePoint(pagePoint);
|
|
1023
|
+
if (!isRegion) {
|
|
1024
|
+
const hit = editor.getShapeAtPoint(pagePoint, { hitInside: true });
|
|
1025
|
+
editor.setHintingShapes(hit ? [hit.id] : []);
|
|
1026
|
+
}
|
|
1027
|
+
};
|
|
1028
|
+
const cancelDrag = (e) => {
|
|
1029
|
+
const drag = dragRef.current;
|
|
1030
|
+
dragRef.current = null;
|
|
1031
|
+
if (e.currentTarget.hasPointerCapture(e.pointerId)) {
|
|
1032
|
+
e.currentTarget.releasePointerCapture(e.pointerId);
|
|
1033
|
+
}
|
|
1034
|
+
if (!drag) return;
|
|
1035
|
+
setDragPagePoint(null);
|
|
1036
|
+
editor.setHintingShapes([]);
|
|
877
1037
|
};
|
|
878
1038
|
const endDrag = (e) => {
|
|
879
1039
|
const drag = dragRef.current;
|
|
@@ -882,38 +1042,51 @@ const ThreadPin = (0, import_react.memo)(function ThreadPin2({
|
|
|
882
1042
|
e.currentTarget.releasePointerCapture(e.pointerId);
|
|
883
1043
|
}
|
|
884
1044
|
if (!drag) return;
|
|
1045
|
+
editor.setHintingShapes([]);
|
|
885
1046
|
if (!drag.moved) {
|
|
886
1047
|
import_state.openThreadId.set(editor, import_state.openThreadId.get(editor) === thread.id ? null : thread.id);
|
|
887
1048
|
return;
|
|
888
1049
|
}
|
|
889
|
-
const
|
|
1050
|
+
const cursorPage = editor.screenToPage({ x: e.clientX, y: e.clientY });
|
|
1051
|
+
const pagePoint = { x: cursorPage.x + drag.offsetX, y: cursorPage.y + drag.offsetY };
|
|
890
1052
|
setDragPagePoint(null);
|
|
891
1053
|
let anchor;
|
|
892
1054
|
if (thread.anchor.type === "region") {
|
|
893
1055
|
anchor = {
|
|
894
1056
|
...thread.anchor,
|
|
895
|
-
x: pagePoint.x -
|
|
896
|
-
y: pagePoint.y -
|
|
1057
|
+
x: pagePoint.x - pinCorner.x * thread.anchor.w,
|
|
1058
|
+
y: pagePoint.y - pinCorner.y * thread.anchor.h
|
|
897
1059
|
};
|
|
898
1060
|
} else {
|
|
899
1061
|
const hit = editor.getShapeAtPoint(pagePoint, { hitInside: true });
|
|
900
|
-
anchor = hit ? (0, import_thread_state.shapeAnchorAt)(
|
|
1062
|
+
anchor = hit ? (0, import_thread_state.shapeAnchorAt)(
|
|
1063
|
+
editor,
|
|
1064
|
+
hit.id,
|
|
1065
|
+
pagePoint,
|
|
1066
|
+
(0, import_options.getCommentingOptions)(editor).shouldBePrecise(editor, {
|
|
1067
|
+
shapeId: hit.id,
|
|
1068
|
+
point: pagePoint,
|
|
1069
|
+
altKey: e.altKey
|
|
1070
|
+
})
|
|
1071
|
+
) : { type: "point", x: pagePoint.x, y: pagePoint.y };
|
|
901
1072
|
}
|
|
902
1073
|
(0, import_state.commitCommentMutation)(editor, () => (0, import_comment_store.putCommentRecords)(editor, [{ ...thread, anchor }]), "drag");
|
|
903
1074
|
};
|
|
904
|
-
const livePinPage = resizeBounds ? (0, import_thread_state.regionPinPoint)(resizeBounds,
|
|
905
|
-
const
|
|
1075
|
+
const livePinPage = resizeBounds ? (0, import_thread_state.regionPinPoint)(resizeBounds, pinCorner) : dragPagePoint;
|
|
1076
|
+
const renderPointBase = livePinPage ? editor.pageToViewport(livePinPage) : point;
|
|
1077
|
+
const renderPoint = isRegion ? { x: renderPointBase.x - 17, y: renderPointBase.y + 17 } : renderPointBase;
|
|
906
1078
|
const regionAnchor = thread.anchor.type === "region" ? thread.anchor : void 0;
|
|
907
1079
|
const movedRegion = regionAnchor && dragPagePoint ? {
|
|
908
1080
|
...regionAnchor,
|
|
909
|
-
x: dragPagePoint.x -
|
|
910
|
-
y: dragPagePoint.y -
|
|
1081
|
+
x: dragPagePoint.x - pinCorner.x * regionAnchor.w,
|
|
1082
|
+
y: dragPagePoint.y - pinCorner.y * regionAnchor.h
|
|
911
1083
|
} : regionAnchor;
|
|
912
1084
|
const regionBoxBounds = resizeBounds ?? movedRegion;
|
|
913
1085
|
const commitResize = (bounds) => {
|
|
914
1086
|
setResizeBounds(null);
|
|
915
1087
|
editor.run(
|
|
916
|
-
|
|
1088
|
+
// Spread the existing anchor first so the region's pin corner survives a resize.
|
|
1089
|
+
() => (0, import_comment_store.putCommentRecords)(editor, [{ ...thread, anchor: { ...regionAnchor, ...bounds } }]),
|
|
917
1090
|
{
|
|
918
1091
|
history: "ignore"
|
|
919
1092
|
}
|
|
@@ -943,44 +1116,52 @@ const ThreadPin = (0, import_react.memo)(function ThreadPin2({
|
|
|
943
1116
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
944
1117
|
"div",
|
|
945
1118
|
{
|
|
946
|
-
className:
|
|
1119
|
+
className: [
|
|
1120
|
+
"tlui-cmt-canvas-pin",
|
|
1121
|
+
open && "tlui-cmt-canvas-pin--open",
|
|
1122
|
+
dragPagePoint && "tlui-cmt-canvas-pin--dragging"
|
|
1123
|
+
].filter(Boolean).join(" "),
|
|
947
1124
|
style: { left: renderPoint.x, top: renderPoint.y },
|
|
948
1125
|
children: [
|
|
949
1126
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
950
1127
|
"div",
|
|
951
1128
|
{
|
|
952
1129
|
ref: markerRef,
|
|
953
|
-
className: "cmt-canvas-pin__marker",
|
|
1130
|
+
className: "tlui-cmt-canvas-pin__marker",
|
|
954
1131
|
onPointerDown: startDrag,
|
|
955
1132
|
onPointerMove: onDrag,
|
|
956
1133
|
onPointerUp: endDrag,
|
|
1134
|
+
onPointerCancel: cancelDrag,
|
|
957
1135
|
onPointerEnter: () => setPinHovered(true),
|
|
958
1136
|
onPointerLeave: () => setPinHovered(false),
|
|
959
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_comment_pin.CommentPin, { resolved: thread.resolved != null, open, children: pinContent })
|
|
1137
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_comment_pin.CommentPin, { resolved: thread.resolved != null, open, color: threadAuthor?.color, children: pinContent })
|
|
960
1138
|
}
|
|
961
1139
|
),
|
|
962
1140
|
open && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
963
1141
|
ThreadPopover,
|
|
964
1142
|
{
|
|
965
1143
|
container,
|
|
966
|
-
style: { left: renderPoint.x +
|
|
1144
|
+
style: { left: renderPoint.x + 48, top: renderPoint.y - 54 },
|
|
967
1145
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
968
1146
|
import_comment_thread.CommentThread,
|
|
969
1147
|
{
|
|
970
1148
|
header: msg("comments.thread-title"),
|
|
971
1149
|
headerActions,
|
|
972
1150
|
renderComment,
|
|
973
|
-
comments: comments.map((c) => toCardProps(c, props, options.components)),
|
|
1151
|
+
comments: comments.map((c) => toCardProps(c, props, options.components, resolveName)),
|
|
974
1152
|
resolvedBanner: thread.resolved ? msg("comments.resolved-by").replace(
|
|
975
1153
|
"{name}",
|
|
976
|
-
|
|
1154
|
+
resolveAuthor(thread.resolved.by)?.name ?? import_comment_render.UNKNOWN_AUTHOR
|
|
977
1155
|
) : void 0,
|
|
978
1156
|
composer: currentUserId && !thread.resolved ? {
|
|
979
|
-
author:
|
|
1157
|
+
author: me ?? import_comment_render.UNKNOWN_COMMENT_AUTHOR,
|
|
980
1158
|
placeholder: msg("comments.reply-placeholder"),
|
|
981
1159
|
sendLabel: msg("comments.send"),
|
|
982
1160
|
value: reply,
|
|
983
|
-
onChange:
|
|
1161
|
+
onChange: (value) => {
|
|
1162
|
+
setReply(value);
|
|
1163
|
+
(0, import_comment_drafts.saveCommentDraft)((0, import_comment_drafts.replyDraftSlot)(thread.id), value);
|
|
1164
|
+
},
|
|
984
1165
|
onSubmit: postReply,
|
|
985
1166
|
disabled: (0, import_comment_extensions.isCommentEmpty)(reply),
|
|
986
1167
|
getMentionSuggestions,
|
|
@@ -999,12 +1180,15 @@ function PendingComposer({
|
|
|
999
1180
|
editor,
|
|
1000
1181
|
pending,
|
|
1001
1182
|
currentUserId,
|
|
1002
|
-
|
|
1183
|
+
resolveAuthor,
|
|
1003
1184
|
onPostComment,
|
|
1004
1185
|
getMentionSuggestions,
|
|
1005
1186
|
renderMentionSuggestion
|
|
1006
1187
|
}) {
|
|
1007
|
-
const
|
|
1188
|
+
const me = currentUserId ? resolveAuthor(currentUserId) : void 0;
|
|
1189
|
+
const [text, setText] = (0, import_react.useState)(
|
|
1190
|
+
() => (0, import_comment_drafts.getCommentDraft)(import_comment_drafts.NEW_COMMENT_DRAFT) ?? import_comment_extensions.EMPTY_COMMENT
|
|
1191
|
+
);
|
|
1008
1192
|
const ref = (0, import_react.useRef)(null);
|
|
1009
1193
|
const msg = (0, import_tldraw.useTranslation)();
|
|
1010
1194
|
const container = (0, import_tldraw.useContainer)();
|
|
@@ -1019,7 +1203,7 @@ function PendingComposer({
|
|
|
1019
1203
|
const el = ref.current;
|
|
1020
1204
|
const target = e.target;
|
|
1021
1205
|
if (!el || !target) return;
|
|
1022
|
-
if (el.contains(target) || target.closest(".cmt-mention-popup")) return;
|
|
1206
|
+
if (el.contains(target) || target.closest(".tlui-cmt-mention-popup")) return;
|
|
1023
1207
|
import_state.pendingComment.set(editor, null);
|
|
1024
1208
|
};
|
|
1025
1209
|
document.addEventListener("pointerdown", onPointerDown, true);
|
|
@@ -1044,6 +1228,7 @@ function PendingComposer({
|
|
|
1044
1228
|
if (onPostComment) onPostComment(comment);
|
|
1045
1229
|
});
|
|
1046
1230
|
setText(import_comment_extensions.EMPTY_COMMENT);
|
|
1231
|
+
(0, import_comment_drafts.clearCommentDraft)(import_comment_drafts.NEW_COMMENT_DRAFT);
|
|
1047
1232
|
import_state.pendingComment.set(editor, null);
|
|
1048
1233
|
};
|
|
1049
1234
|
return (0, import_react_dom.createPortal)(
|
|
@@ -1051,26 +1236,33 @@ function PendingComposer({
|
|
|
1051
1236
|
"div",
|
|
1052
1237
|
{
|
|
1053
1238
|
ref,
|
|
1054
|
-
className:
|
|
1239
|
+
className: [
|
|
1240
|
+
"tlui-cmt-canvas-composer",
|
|
1241
|
+
pending.anchor.type === "region" && "tlui-cmt-canvas-composer--region"
|
|
1242
|
+
].filter(Boolean).join(" "),
|
|
1055
1243
|
style: { left: point.x, top: point.y },
|
|
1056
1244
|
onPointerDown: stop,
|
|
1245
|
+
onContextMenu: stop,
|
|
1057
1246
|
onKeyDown: (e) => {
|
|
1058
1247
|
if (e.key === "Escape" && !(0, import_mention_suggestion.isMentionPickerOpen)()) import_state.pendingComment.set(editor, null);
|
|
1059
1248
|
},
|
|
1060
1249
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1061
1250
|
import_comment_composer.CommentComposer,
|
|
1062
1251
|
{
|
|
1063
|
-
author:
|
|
1252
|
+
author: me ?? import_comment_render.UNKNOWN_COMMENT_AUTHOR,
|
|
1064
1253
|
placeholder: msg("comments.add-placeholder"),
|
|
1065
1254
|
sendLabel: msg("comments.send"),
|
|
1066
1255
|
value: text,
|
|
1067
|
-
onChange:
|
|
1256
|
+
onChange: (value) => {
|
|
1257
|
+
setText(value);
|
|
1258
|
+
(0, import_comment_drafts.saveCommentDraft)(import_comment_drafts.NEW_COMMENT_DRAFT, value);
|
|
1259
|
+
},
|
|
1068
1260
|
onSubmit: submit,
|
|
1069
1261
|
disabled: (0, import_comment_extensions.isCommentEmpty)(text),
|
|
1070
1262
|
getMentionSuggestions,
|
|
1071
1263
|
renderMentionSuggestion,
|
|
1072
1264
|
autoFocus: true,
|
|
1073
|
-
leading: draftAvatar
|
|
1265
|
+
leading: draftAvatar(me?.color)
|
|
1074
1266
|
}
|
|
1075
1267
|
)
|
|
1076
1268
|
}
|