@tldraw/commenting 0.0.0-bootstrap → 5.3.0-canary.04044ed9e96d
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 +1152 -350
- package/dist-cjs/canvas/anchor-lifecycle.js +148 -0
- package/dist-cjs/canvas/anchor-lifecycle.js.map +7 -0
- package/dist-cjs/{ui/avatar.js → canvas/canvas-events.js} +14 -22
- package/dist-cjs/canvas/canvas-events.js.map +7 -0
- package/dist-cjs/canvas/cluster-badge.js +121 -0
- package/dist-cjs/canvas/cluster-badge.js.map +7 -0
- package/dist-cjs/canvas/cluster-fade.js +85 -0
- package/dist-cjs/canvas/cluster-fade.js.map +7 -0
- package/dist-cjs/canvas/cluster-input.js +53 -3
- package/dist-cjs/canvas/cluster-input.js.map +2 -2
- package/dist-cjs/canvas/cluster-model.js +252 -0
- package/dist-cjs/canvas/cluster-model.js.map +7 -0
- package/dist-cjs/canvas/comment-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-mutations.js +152 -0
- package/dist-cjs/canvas/comment-mutations.js.map +7 -0
- package/dist-cjs/canvas/comment-reactions.js +160 -0
- package/dist-cjs/canvas/comment-reactions.js.map +7 -0
- package/dist-cjs/canvas/comment-render.js +9 -6
- 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 +63 -14
- package/dist-cjs/canvas/comment-tool.js.map +2 -2
- package/dist-cjs/canvas/comments-filter-menu.js +17 -37
- package/dist-cjs/canvas/comments-filter-menu.js.map +2 -2
- package/dist-cjs/canvas/comments-overflow-menu.js +25 -22
- package/dist-cjs/canvas/comments-overflow-menu.js.map +2 -2
- package/dist-cjs/canvas/comments-overlay.js +151 -989
- package/dist-cjs/canvas/comments-overlay.js.map +3 -3
- package/dist-cjs/canvas/comments-sidebar.js +49 -41
- package/dist-cjs/canvas/comments-sidebar.js.map +2 -2
- package/dist-cjs/canvas/comments-visibility-toggle.js +45 -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 +28 -3
- package/dist-cjs/canvas/hooks.js.map +2 -2
- package/dist-cjs/canvas/license.js.map +1 -1
- package/dist-cjs/canvas/mobile-placement.js +91 -0
- package/dist-cjs/canvas/mobile-placement.js.map +7 -0
- package/dist-cjs/canvas/options.js +57 -2
- package/dist-cjs/canvas/options.js.map +2 -2
- package/dist-cjs/canvas/pending-composer.js +134 -0
- package/dist-cjs/canvas/pending-composer.js.map +7 -0
- package/dist-cjs/canvas/pin-stacking.js +81 -0
- package/dist-cjs/canvas/pin-stacking.js.map +7 -0
- package/dist-cjs/canvas/region-box.js +113 -0
- package/dist-cjs/canvas/region-box.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-pin.js +304 -0
- package/dist-cjs/canvas/thread-pin.js.map +7 -0
- package/dist-cjs/canvas/thread-preview.js +177 -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 +82 -21
- package/dist-cjs/canvas/thread-state.js.map +2 -2
- package/dist-cjs/canvas/thread-view.js +450 -0
- package/dist-cjs/canvas/thread-view.js.map +7 -0
- package/dist-cjs/clustering/computeClusterTable.js +6 -6
- package/dist-cjs/clustering/computeClusterTable.js.map +2 -2
- package/dist-cjs/clustering/replay.js +89 -22
- package/dist-cjs/clustering/replay.js.map +3 -3
- package/dist-cjs/clustering/runtime.js +126 -7
- package/dist-cjs/clustering/runtime.js.map +2 -2
- package/dist-cjs/clustering/types.js.map +1 -1
- package/dist-cjs/index.d.ts +904 -353
- package/dist-cjs/index.js +52 -28
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/ui/byline.js +10 -6
- package/dist-cjs/ui/byline.js.map +2 -2
- package/dist-cjs/ui/comment-card.js +15 -8
- package/dist-cjs/ui/comment-card.js.map +2 -2
- package/dist-cjs/ui/comment-composer.js +124 -39
- package/dist-cjs/ui/comment-composer.js.map +2 -2
- package/dist-cjs/ui/comment-pin.js +11 -2
- package/dist-cjs/ui/comment-pin.js.map +2 -2
- package/dist-cjs/ui/comment-thread.js +9 -7
- package/dist-cjs/ui/comment-thread.js.map +2 -2
- package/dist-cjs/ui/comments-list.js +39 -40
- 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/empty-state.js +3 -3
- package/dist-cjs/ui/empty-state.js.map +2 -2
- package/dist-cjs/ui/format-time.js +16 -1
- package/dist-cjs/ui/format-time.js.map +2 -2
- package/dist-cjs/ui/icons.js +115 -0
- package/dist-cjs/ui/icons.js.map +7 -0
- package/dist-cjs/ui/reaction-picker.js +71 -0
- package/dist-cjs/ui/reaction-picker.js.map +7 -0
- package/dist-cjs/ui/reaction.js +58 -6
- package/dist-cjs/ui/reaction.js.map +2 -2
- package/dist-cjs/ui/reactions.js +20 -7
- 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 +13 -1
- package/dist-cjs/ui/send-button.js.map +2 -2
- package/dist-cjs/ui/{comment-text.js → visual-viewport.js} +12 -9
- package/dist-cjs/ui/visual-viewport.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/canvas-events.mjs +15 -0
- package/dist-esm/canvas/canvas-events.mjs.map +7 -0
- package/dist-esm/canvas/cluster-badge.mjs +106 -0
- package/dist-esm/canvas/cluster-badge.mjs.map +7 -0
- package/dist-esm/canvas/cluster-fade.mjs +65 -0
- package/dist-esm/canvas/cluster-fade.mjs.map +7 -0
- package/dist-esm/canvas/cluster-input.mjs +54 -4
- package/dist-esm/canvas/cluster-input.mjs.map +2 -2
- package/dist-esm/canvas/cluster-model.mjs +236 -0
- package/dist-esm/canvas/cluster-model.mjs.map +7 -0
- package/dist-esm/canvas/comment-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-mutations.mjs +132 -0
- package/dist-esm/canvas/comment-mutations.mjs.map +7 -0
- package/dist-esm/canvas/comment-reactions.mjs +145 -0
- package/dist-esm/canvas/comment-reactions.mjs.map +7 -0
- package/dist-esm/canvas/comment-render.mjs +10 -7
- 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 +66 -17
- package/dist-esm/canvas/comment-tool.mjs.map +2 -2
- package/dist-esm/canvas/comments-filter-menu.mjs +17 -36
- package/dist-esm/canvas/comments-filter-menu.mjs.map +2 -2
- package/dist-esm/canvas/comments-overflow-menu.mjs +27 -22
- package/dist-esm/canvas/comments-overflow-menu.mjs.map +2 -2
- package/dist-esm/canvas/comments-overlay.mjs +157 -1010
- package/dist-esm/canvas/comments-overlay.mjs.map +3 -3
- package/dist-esm/canvas/comments-sidebar.mjs +53 -46
- package/dist-esm/canvas/comments-sidebar.mjs.map +2 -2
- package/dist-esm/canvas/comments-visibility-toggle.mjs +25 -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 +35 -5
- package/dist-esm/canvas/hooks.mjs.map +2 -2
- package/dist-esm/canvas/license.mjs.map +1 -1
- package/dist-esm/canvas/mobile-placement.mjs +71 -0
- package/dist-esm/canvas/mobile-placement.mjs.map +7 -0
- package/dist-esm/canvas/options.mjs +59 -3
- package/dist-esm/canvas/options.mjs.map +2 -2
- package/dist-esm/canvas/pending-composer.mjs +126 -0
- package/dist-esm/canvas/pending-composer.mjs.map +7 -0
- package/dist-esm/canvas/pin-stacking.mjs +61 -0
- package/dist-esm/canvas/pin-stacking.mjs.map +7 -0
- package/dist-esm/canvas/region-box.mjs +93 -0
- package/dist-esm/canvas/region-box.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-pin.mjs +310 -0
- package/dist-esm/canvas/thread-pin.mjs.map +7 -0
- package/dist-esm/canvas/thread-preview.mjs +163 -0
- package/dist-esm/canvas/thread-preview.mjs.map +7 -0
- package/dist-esm/canvas/thread-stack.mjs +189 -0
- package/dist-esm/canvas/thread-stack.mjs.map +7 -0
- package/dist-esm/canvas/thread-state.mjs +86 -22
- package/dist-esm/canvas/thread-state.mjs.map +2 -2
- package/dist-esm/canvas/thread-view.mjs +461 -0
- package/dist-esm/canvas/thread-view.mjs.map +7 -0
- package/dist-esm/clustering/computeClusterTable.mjs +6 -6
- package/dist-esm/clustering/computeClusterTable.mjs.map +2 -2
- package/dist-esm/clustering/replay.mjs +89 -22
- package/dist-esm/clustering/replay.mjs.map +3 -3
- package/dist-esm/clustering/runtime.mjs +126 -7
- package/dist-esm/clustering/runtime.mjs.map +2 -2
- package/dist-esm/index.d.mts +904 -353
- package/dist-esm/index.mjs +102 -43
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/ui/byline.mjs +11 -7
- package/dist-esm/ui/byline.mjs.map +2 -2
- package/dist-esm/ui/comment-card.mjs +15 -8
- package/dist-esm/ui/comment-card.mjs.map +2 -2
- package/dist-esm/ui/comment-composer.mjs +135 -39
- package/dist-esm/ui/comment-composer.mjs.map +2 -2
- package/dist-esm/ui/comment-pin.mjs +11 -2
- package/dist-esm/ui/comment-pin.mjs.map +2 -2
- package/dist-esm/ui/comment-thread.mjs +9 -7
- package/dist-esm/ui/comment-thread.mjs.map +2 -2
- package/dist-esm/ui/comments-list.mjs +51 -50
- 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/empty-state.mjs +3 -3
- package/dist-esm/ui/empty-state.mjs.map +2 -2
- package/dist-esm/ui/format-time.mjs +16 -1
- package/dist-esm/ui/format-time.mjs.map +2 -2
- package/dist-esm/ui/icons.mjs +95 -0
- package/dist-esm/ui/icons.mjs.map +7 -0
- package/dist-esm/ui/reaction-picker.mjs +59 -0
- package/dist-esm/ui/reaction-picker.mjs.map +7 -0
- package/dist-esm/ui/reaction.mjs +59 -7
- package/dist-esm/ui/reaction.mjs.map +2 -2
- package/dist-esm/ui/reactions.mjs +21 -8
- 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 +13 -1
- package/dist-esm/ui/send-button.mjs.map +2 -2
- package/dist-esm/ui/visual-viewport.mjs +12 -0
- package/dist-esm/ui/visual-viewport.mjs.map +7 -0
- package/package.json +6 -6
- package/src/canvas/anchor-lifecycle.test.ts +290 -0
- package/src/canvas/anchor-lifecycle.ts +191 -0
- package/src/canvas/canvas-events.ts +18 -0
- package/src/canvas/canvas.css +464 -55
- package/src/canvas/cluster-badge.tsx +133 -0
- package/src/canvas/cluster-fade.ts +102 -0
- package/src/canvas/cluster-input.test.ts +178 -36
- package/src/canvas/cluster-input.ts +95 -9
- package/src/canvas/cluster-model.ts +378 -0
- 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-mutations.test.ts +452 -0
- package/src/canvas/comment-mutations.ts +299 -0
- package/src/canvas/comment-reactions.test.ts +154 -0
- package/src/canvas/comment-reactions.tsx +246 -0
- package/src/canvas/comment-render.test.ts +1 -1
- package/src/canvas/comment-render.ts +17 -13
- package/src/canvas/comment-store.ts +68 -33
- package/src/canvas/comment-tool.test.ts +162 -0
- package/src/canvas/comment-tool.tsx +103 -25
- package/src/canvas/comments-filter-menu.tsx +20 -36
- package/src/canvas/comments-overflow-menu.tsx +17 -19
- package/src/canvas/comments-overlay.tsx +252 -1369
- package/src/canvas/comments-sidebar.test.ts +45 -0
- package/src/canvas/comments-sidebar.tsx +112 -73
- package/src/canvas/comments-visibility-toggle.tsx +25 -0
- package/src/canvas/context.ts +48 -0
- package/src/canvas/hooks.test.ts +94 -0
- package/src/canvas/hooks.ts +66 -11
- package/src/canvas/license.ts +1 -1
- package/src/canvas/mobile-placement.ts +115 -0
- package/src/canvas/options.test.ts +176 -4
- package/src/canvas/options.ts +276 -18
- package/src/canvas/pending-composer.tsx +157 -0
- package/src/canvas/pin-stacking.test.ts +224 -0
- package/src/canvas/pin-stacking.ts +103 -0
- package/src/canvas/region-box.tsx +124 -0
- package/src/canvas/sidebar-filters.ts +4 -3
- package/src/canvas/state.ts +88 -39
- package/src/canvas/thread-pin.tsx +418 -0
- package/src/canvas/thread-preview.test.ts +91 -0
- package/src/canvas/thread-preview.tsx +294 -0
- package/src/canvas/thread-stack.tsx +242 -0
- package/src/canvas/thread-state.test.ts +260 -0
- package/src/canvas/thread-state.ts +171 -37
- package/src/canvas/thread-view.test.ts +72 -0
- package/src/canvas/thread-view.tsx +614 -0
- package/src/clustering/computeClusterTable.test.ts +24 -23
- package/src/clustering/computeClusterTable.ts +17 -8
- package/src/clustering/replay.test.ts +0 -7
- package/src/clustering/replay.ts +131 -32
- package/src/clustering/runtime.test.ts +267 -13
- package/src/clustering/runtime.ts +176 -19
- package/src/clustering/schedule.test.ts +0 -6
- package/src/clustering/screen-offsets.test.ts +171 -0
- package/src/clustering/types.ts +19 -9
- package/src/index.ts +91 -42
- package/src/ui/byline.tsx +21 -9
- package/src/ui/comment-card.tsx +20 -10
- package/src/ui/comment-composer.tsx +178 -56
- package/src/ui/comment-pin.tsx +13 -2
- package/src/ui/comment-thread.tsx +13 -6
- package/src/ui/comments-list.test.ts +31 -0
- package/src/ui/comments-list.tsx +82 -47
- package/src/ui/comments.css +577 -294
- 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/empty-state.tsx +3 -3
- package/src/ui/format-time.test.ts +69 -0
- package/src/ui/format-time.ts +27 -2
- package/src/ui/icons.tsx +116 -0
- package/src/ui/reaction-picker.tsx +102 -0
- package/src/ui/reaction.tsx +125 -6
- package/src/ui/reactions.tsx +69 -10
- package/src/ui/reply-count.ts +16 -0
- package/src/ui/send-button.tsx +13 -3
- package/src/ui/visual-viewport.test.ts +36 -0
- package/src/ui/visual-viewport.ts +27 -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.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 -23
- 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 -31
- 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
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var anchor_lifecycle_exports = {};
|
|
20
|
+
__export(anchor_lifecycle_exports, {
|
|
21
|
+
registerCommentAnchorLifecycle: () => registerCommentAnchorLifecycle
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(anchor_lifecycle_exports);
|
|
24
|
+
var import_utils = require("@tldraw/utils");
|
|
25
|
+
var import_comment_mutations = require("./comment-mutations");
|
|
26
|
+
var import_comment_store = require("./comment-store");
|
|
27
|
+
var import_thread_state = require("./thread-state");
|
|
28
|
+
const convertedByShapeCache = new import_utils.WeakCache();
|
|
29
|
+
function isAnchoredToShape(thread, shapeId) {
|
|
30
|
+
const anchor = thread.anchor;
|
|
31
|
+
return anchor.type === "shape" && anchor.shapeId === shapeId;
|
|
32
|
+
}
|
|
33
|
+
function registerCommentAnchorLifecycle(editor) {
|
|
34
|
+
const pendingByShape = /* @__PURE__ */ new Map();
|
|
35
|
+
const convertedByShape = convertedByShapeCache.get(editor, () => /* @__PURE__ */ new Map());
|
|
36
|
+
function rehomeThread(thread, pageId, updates) {
|
|
37
|
+
updates.push({ ...thread, pageId });
|
|
38
|
+
for (const comment of (0, import_comment_store.getComments)(editor)) {
|
|
39
|
+
if (comment.threadId === thread.id) updates.push({ ...comment, pageId });
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
const disposeBeforeDelete = editor.sideEffects.registerBeforeDeleteHandler(
|
|
43
|
+
"shape",
|
|
44
|
+
(shape, source) => {
|
|
45
|
+
if (source === "remote") return;
|
|
46
|
+
for (const thread of (0, import_comment_store.getCommentThreads)(editor)) {
|
|
47
|
+
if (!isAnchoredToShape(thread, shape.id)) continue;
|
|
48
|
+
let snapshot = pendingByShape.get(shape.id);
|
|
49
|
+
if (!snapshot) {
|
|
50
|
+
snapshot = /* @__PURE__ */ new Map();
|
|
51
|
+
pendingByShape.set(shape.id, snapshot);
|
|
52
|
+
}
|
|
53
|
+
let point = (0, import_thread_state.anchorPagePoint)(editor, thread.anchor);
|
|
54
|
+
const inset = (0, import_thread_state.impreciseShapePinInset)(editor, thread.anchor);
|
|
55
|
+
if (point && inset) {
|
|
56
|
+
const zoom = editor.getZoomLevel();
|
|
57
|
+
point = { x: point.x + inset.x / zoom, y: point.y + inset.y / zoom };
|
|
58
|
+
}
|
|
59
|
+
snapshot.set(thread.id, point);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
);
|
|
63
|
+
const returnedShapeIds = /* @__PURE__ */ new Set();
|
|
64
|
+
const disposeOperationComplete = editor.sideEffects.registerOperationCompleteHandler((source) => {
|
|
65
|
+
if (source === "remote") return;
|
|
66
|
+
if (pendingByShape.size === 0 && returnedShapeIds.size === 0) return;
|
|
67
|
+
const settled = [...pendingByShape.entries()];
|
|
68
|
+
pendingByShape.clear();
|
|
69
|
+
const returned = [...returnedShapeIds];
|
|
70
|
+
returnedShapeIds.clear();
|
|
71
|
+
const updates = [];
|
|
72
|
+
for (const [shapeId, threadPoints] of settled) {
|
|
73
|
+
if (editor.getShape(shapeId)) continue;
|
|
74
|
+
for (const [threadId, point] of threadPoints) {
|
|
75
|
+
if (!point) continue;
|
|
76
|
+
const thread = (0, import_comment_store.getCommentRecord)(editor, threadId);
|
|
77
|
+
if (!thread || thread.typeName !== "comment-thread") continue;
|
|
78
|
+
if (!isAnchoredToShape(thread, shapeId)) continue;
|
|
79
|
+
let converted = convertedByShape.get(shapeId);
|
|
80
|
+
if (!converted) {
|
|
81
|
+
converted = [];
|
|
82
|
+
convertedByShape.set(shapeId, converted);
|
|
83
|
+
}
|
|
84
|
+
converted.push({ threadId, anchor: thread.anchor, point });
|
|
85
|
+
updates.push({ ...thread, anchor: { type: "point", x: point.x, y: point.y } });
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
for (const shapeId of returned) {
|
|
89
|
+
const shape = editor.getShape(shapeId);
|
|
90
|
+
if (!shape) continue;
|
|
91
|
+
const converted = convertedByShape.get(shapeId);
|
|
92
|
+
if (!converted) continue;
|
|
93
|
+
convertedByShape.delete(shapeId);
|
|
94
|
+
const pageId = editor.getAncestorPageId(shape);
|
|
95
|
+
for (const { threadId, anchor, point } of converted) {
|
|
96
|
+
const thread = (0, import_comment_store.getCommentRecord)(editor, threadId);
|
|
97
|
+
if (!thread || thread.typeName !== "comment-thread") continue;
|
|
98
|
+
const current = thread.anchor;
|
|
99
|
+
if (current.type !== "point" || current.x !== point.x || current.y !== point.y) {
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
if (!pageId || thread.pageId === pageId) {
|
|
103
|
+
updates.push({ ...thread, anchor });
|
|
104
|
+
} else {
|
|
105
|
+
rehomeThread({ ...thread, anchor }, pageId, updates);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (updates.length > 0) {
|
|
110
|
+
(0, import_comment_mutations.commitCommentMutation)(editor, ({ put }) => put(updates));
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
const disposeAfterCreate = editor.sideEffects.registerAfterCreateHandler(
|
|
114
|
+
"shape",
|
|
115
|
+
(shape, source) => {
|
|
116
|
+
if (source === "remote") return;
|
|
117
|
+
if (convertedByShape.has(shape.id)) returnedShapeIds.add(shape.id);
|
|
118
|
+
}
|
|
119
|
+
);
|
|
120
|
+
const disposeAfterChange = editor.sideEffects.registerAfterChangeHandler(
|
|
121
|
+
"shape",
|
|
122
|
+
(prev, next, source) => {
|
|
123
|
+
if (source === "remote") return;
|
|
124
|
+
if (prev.parentId === next.parentId) return;
|
|
125
|
+
const pageId = editor.getAncestorPageId(next);
|
|
126
|
+
if (!pageId) return;
|
|
127
|
+
const movedIds = editor.getShapeAndDescendantIds([next.id]);
|
|
128
|
+
const updates = [];
|
|
129
|
+
for (const thread of (0, import_comment_store.getCommentThreads)(editor)) {
|
|
130
|
+
const anchor = thread.anchor;
|
|
131
|
+
if (anchor.type !== "shape") continue;
|
|
132
|
+
if (!movedIds.has(anchor.shapeId)) continue;
|
|
133
|
+
if (thread.pageId === pageId) continue;
|
|
134
|
+
rehomeThread(thread, pageId, updates);
|
|
135
|
+
}
|
|
136
|
+
if (updates.length > 0) {
|
|
137
|
+
(0, import_comment_mutations.commitCommentMutation)(editor, ({ put }) => put(updates));
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
);
|
|
141
|
+
return () => {
|
|
142
|
+
disposeBeforeDelete();
|
|
143
|
+
disposeOperationComplete();
|
|
144
|
+
disposeAfterCreate();
|
|
145
|
+
disposeAfterChange();
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=anchor-lifecycle.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/canvas/anchor-lifecycle.ts"],
|
|
4
|
+
"sourcesContent": ["import { WeakCache } from '@tldraw/utils'\nimport { Editor, TLCommentAnchor, TLCommentThread, TLPageId, TLShapeId, VecLike } from 'tldraw'\nimport { commitCommentMutation } from './comment-mutations'\nimport { getCommentRecord, getComments, getCommentThreads, TLCommentRecord } from './comment-store'\nimport { anchorPagePoint, impreciseShapePinInset } from './thread-state'\n\ntype ShapeAnchor = Extract<TLCommentAnchor, { type: 'shape' }>\n\n/**\n * Threads converted to point anchors because their shape was deleted, kept so the anchor can be\n * restored if the shape comes back. Owned by the editor, not the registration closure: the\n * registering effect can re-run, and an undo can arrive long after the delete.\n */\nconst convertedByShapeCache = new WeakCache<\n\tEditor,\n\tMap<TLShapeId, { threadId: string; anchor: ShapeAnchor; point: VecLike }[]>\n>()\n\nfunction isAnchoredToShape(\n\tthread: TLCommentThread,\n\tshapeId: TLShapeId\n): thread is TLCommentThread & { anchor: ShapeAnchor } {\n\tconst anchor = thread.anchor\n\treturn anchor.type === 'shape' && anchor.shapeId === shapeId\n}\n\n/**\n * Keep shape-anchored threads alive across their shape's lifecycle:\n *\n * - When the shape is deleted, the thread converts to a `point` anchor where its pin last sat, so\n * the conversation outlives the shape instead of becoming invisible.\n * - When the shape moves to another page, the thread follows: its `pageId` and each comment's\n * denormalized `pageId` update, and the anchor keeps riding the shape.\n * - When a deleted shape comes back, the thread re-attaches \u2014 unless its pin was manually moved in\n * the meantime, in which case the manual placement wins.\n *\n * A page move is `deleteShapes` + re-create with preserved ids inside one `editor.run`, but each\n * store write is its own operation, so \"this shape is being moved\" is never observable as a single\n * event. The handlers therefore cooperate across operations: `beforeDelete` snapshots where each\n * affected pin sits, the operation-complete pass converts threads whose shape is really gone, and\n * `afterCreate` plus that same pass restore the anchor once the store has settled. Undo/redo of a\n * move replays as a `parentId` update, so `afterChange` re-homes threads on cross-page reparents \u2014\n * including threads anchored to descendants, which move without change events of their own.\n *\n * Remote changes are ignored: the client that performed the operation runs this same maintenance\n * and syncs the result. Writes honour the {@link CommentingOptions.history} option.\n *\n * Registered by `CanvasComments` on mount; parts-built consumers can call this directly. Returns a\n * cleanup function that unregisters all handlers.\n *\n * @public\n */\nexport function registerCommentAnchorLifecycle(editor: Editor): () => void {\n\t// Pin positions snapshotted during the current operation: shape id -> (thread id -> pin page\n\t// point).\n\tconst pendingByShape = new Map<TLShapeId, Map<string, VecLike | null>>()\n\tconst convertedByShape = convertedByShapeCache.get(editor, () => new Map())\n\n\tfunction rehomeThread(thread: TLCommentThread, pageId: TLPageId, updates: TLCommentRecord[]) {\n\t\tupdates.push({ ...thread, pageId })\n\t\tfor (const comment of getComments(editor)) {\n\t\t\tif (comment.threadId === thread.id) updates.push({ ...comment, pageId })\n\t\t}\n\t}\n\n\tconst disposeBeforeDelete = editor.sideEffects.registerBeforeDeleteHandler(\n\t\t'shape',\n\t\t(shape, source) => {\n\t\t\tif (source === 'remote') return\n\t\t\tfor (const thread of getCommentThreads(editor)) {\n\t\t\t\tif (!isAnchoredToShape(thread, shape.id)) continue\n\t\t\t\tlet snapshot = pendingByShape.get(shape.id)\n\t\t\t\tif (!snapshot) {\n\t\t\t\t\tsnapshot = new Map()\n\t\t\t\t\tpendingByShape.set(shape.id, snapshot)\n\t\t\t\t}\n\t\t\t\t// Snapshot where the pin is drawn, not just the anchor point: imprecise shape pins render inset\n\t\t\t\t// toward the shape's centre, so without baking the inset in at the current zoom the pin would jump.\n\t\t\t\tlet point = anchorPagePoint(editor, thread.anchor)\n\t\t\t\tconst inset = impreciseShapePinInset(editor, thread.anchor)\n\t\t\t\tif (point && inset) {\n\t\t\t\t\tconst zoom = editor.getZoomLevel()\n\t\t\t\t\tpoint = { x: point.x + inset.x / zoom, y: point.y + inset.y / zoom }\n\t\t\t\t}\n\t\t\t\tsnapshot.set(thread.id, point)\n\t\t\t}\n\t\t}\n\t)\n\n\t// Shape ids from `convertedByShape` re-created during the current operation. Settled at operation\n\t// complete rather than in `afterCreate`: creation order within an operation is arbitrary, so a shape\n\t// can appear before its parent and not resolve an ancestor page yet.\n\tconst returnedShapeIds = new Set<TLShapeId>()\n\n\tconst disposeOperationComplete = editor.sideEffects.registerOperationCompleteHandler((source) => {\n\t\t// Only user-sourced handlers populate the maps and only local operations should settle\n\t\t// them; a remote operation completing leaves any (impossible-in-practice) leftovers for\n\t\t// the next local settle rather than judging them against remote state.\n\t\tif (source === 'remote') return\n\t\tif (pendingByShape.size === 0 && returnedShapeIds.size === 0) return\n\t\tconst settled = [...pendingByShape.entries()]\n\t\tpendingByShape.clear()\n\t\tconst returned = [...returnedShapeIds]\n\t\treturnedShapeIds.clear()\n\n\t\tconst updates: TLCommentRecord[] = []\n\t\tfor (const [shapeId, threadPoints] of settled) {\n\t\t\tif (editor.getShape(shapeId)) continue\n\t\t\tfor (const [threadId, point] of threadPoints) {\n\t\t\t\tif (!point) continue\n\t\t\t\tconst thread = getCommentRecord(editor, threadId)\n\t\t\t\tif (!thread || thread.typeName !== 'comment-thread') continue\n\t\t\t\tif (!isAnchoredToShape(thread, shapeId)) continue\n\t\t\t\tlet converted = convertedByShape.get(shapeId)\n\t\t\t\tif (!converted) {\n\t\t\t\t\tconverted = []\n\t\t\t\t\tconvertedByShape.set(shapeId, converted)\n\t\t\t\t}\n\t\t\t\tconverted.push({ threadId, anchor: thread.anchor, point })\n\t\t\t\tupdates.push({ ...thread, anchor: { type: 'point', x: point.x, y: point.y } })\n\t\t\t}\n\t\t}\n\n\t\tfor (const shapeId of returned) {\n\t\t\tconst shape = editor.getShape(shapeId)\n\t\t\tif (!shape) continue\n\t\t\tconst converted = convertedByShape.get(shapeId)\n\t\t\tif (!converted) continue\n\t\t\tconvertedByShape.delete(shapeId)\n\n\t\t\tconst pageId = editor.getAncestorPageId(shape)\n\t\t\tfor (const { threadId, anchor, point } of converted) {\n\t\t\t\tconst thread = getCommentRecord(editor, threadId)\n\t\t\t\tif (!thread || thread.typeName !== 'comment-thread') continue\n\t\t\t\t// Re-attach only threads still sitting exactly where the conversion left them \u2014 a\n\t\t\t\t// pin moved since then was placed deliberately, and that placement wins.\n\t\t\t\tconst current = thread.anchor\n\t\t\t\tif (current.type !== 'point' || current.x !== point.x || current.y !== point.y) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif (!pageId || thread.pageId === pageId) {\n\t\t\t\t\tupdates.push({ ...thread, anchor })\n\t\t\t\t} else {\n\t\t\t\t\trehomeThread({ ...thread, anchor }, pageId, updates)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (updates.length > 0) {\n\t\t\tcommitCommentMutation(editor, ({ put }) => put(updates))\n\t\t}\n\t})\n\n\tconst disposeAfterCreate = editor.sideEffects.registerAfterCreateHandler(\n\t\t'shape',\n\t\t(shape, source) => {\n\t\t\tif (source === 'remote') return\n\t\t\tif (convertedByShape.has(shape.id)) returnedShapeIds.add(shape.id)\n\t\t}\n\t)\n\n\tconst disposeAfterChange = editor.sideEffects.registerAfterChangeHandler(\n\t\t'shape',\n\t\t(prev, next, source) => {\n\t\t\tif (source === 'remote') return\n\t\t\tif (prev.parentId === next.parentId) return\n\t\t\tconst pageId = editor.getAncestorPageId(next)\n\t\t\tif (!pageId) return\n\t\t\t// Descendants move with their parent without change events of their own.\n\t\t\tconst movedIds = editor.getShapeAndDescendantIds([next.id])\n\t\t\tconst updates: TLCommentRecord[] = []\n\t\t\tfor (const thread of getCommentThreads(editor)) {\n\t\t\t\tconst anchor = thread.anchor\n\t\t\t\tif (anchor.type !== 'shape') continue\n\t\t\t\tif (!movedIds.has(anchor.shapeId)) continue\n\t\t\t\tif (thread.pageId === pageId) continue\n\t\t\t\trehomeThread(thread, pageId, updates)\n\t\t\t}\n\t\t\tif (updates.length > 0) {\n\t\t\t\tcommitCommentMutation(editor, ({ put }) => put(updates))\n\t\t\t}\n\t\t}\n\t)\n\n\treturn () => {\n\t\tdisposeBeforeDelete()\n\t\tdisposeOperationComplete()\n\t\tdisposeAfterCreate()\n\t\tdisposeAfterChange()\n\t}\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -16,28 +16,20 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
16
16
|
return to;
|
|
17
17
|
};
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
-
var
|
|
20
|
-
__export(
|
|
21
|
-
|
|
19
|
+
var canvas_events_exports = {};
|
|
20
|
+
__export(canvas_events_exports, {
|
|
21
|
+
forwardPointerEventToCanvas: () => forwardPointerEventToCanvas,
|
|
22
|
+
isCanvasPanGesture: () => isCanvasPanGesture
|
|
22
23
|
});
|
|
23
|
-
module.exports = __toCommonJS(
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
function initial(name) {
|
|
27
|
-
return ((0, import_tldraw.getFirstCharacter)(name.trim()) || "?").toUpperCase();
|
|
24
|
+
module.exports = __toCommonJS(canvas_events_exports);
|
|
25
|
+
function isCanvasPanGesture(editor, e) {
|
|
26
|
+
return e.button !== 0 || editor.inputs.keys.has("Space");
|
|
28
27
|
}
|
|
29
|
-
function
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
{
|
|
36
|
-
className: "cmt-avatar",
|
|
37
|
-
"aria-hidden": "true",
|
|
38
|
-
style: color ? { backgroundColor: color } : void 0,
|
|
39
|
-
children: initial(name)
|
|
40
|
-
}
|
|
41
|
-
);
|
|
28
|
+
function forwardPointerEventToCanvas(container, e) {
|
|
29
|
+
const cvs = container.querySelector(".tl-canvas");
|
|
30
|
+
if (!cvs) return;
|
|
31
|
+
const newEvent = new PointerEvent(e.type, e.nativeEvent);
|
|
32
|
+
newEvent.isSpecialRedispatchedEvent = true;
|
|
33
|
+
cvs.dispatchEvent(newEvent);
|
|
42
34
|
}
|
|
43
|
-
//# sourceMappingURL=
|
|
35
|
+
//# sourceMappingURL=canvas-events.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/canvas/canvas-events.ts"],
|
|
4
|
+
"sourcesContent": ["import { type PointerEvent as ReactPointerEvent } from 'react'\nimport { Editor } from 'tldraw'\n\n/** A pointer-down that belongs to the camera, not the comment UI: any non-primary button\n * (middle/right-button pans), or a primary press with the spacebar pan key held. */\nexport function isCanvasPanGesture(editor: Editor, e: ReactPointerEvent) {\n\treturn e.button !== 0 || editor.inputs.keys.has('Space')\n}\n\n/** Hand a pointer event to the canvas beneath the comments layer, marked the same way the\n * pass-through wheel/hover hooks mark their re-dispatched events. */\nexport function forwardPointerEventToCanvas(container: HTMLElement, e: ReactPointerEvent) {\n\tconst cvs = container.querySelector('.tl-canvas')\n\tif (!cvs) return\n\tconst newEvent = new PointerEvent(e.type, e.nativeEvent as any)\n\t;(newEvent as any).isSpecialRedispatchedEvent = true\n\tcvs.dispatchEvent(newEvent)\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAKO,SAAS,mBAAmB,QAAgB,GAAsB;AACxE,SAAO,EAAE,WAAW,KAAK,OAAO,OAAO,KAAK,IAAI,OAAO;AACxD;AAIO,SAAS,4BAA4B,WAAwB,GAAsB;AACzF,QAAM,MAAM,UAAU,cAAc,YAAY;AAChD,MAAI,CAAC,IAAK;AACV,QAAM,WAAW,IAAI,aAAa,EAAE,MAAM,EAAE,WAAkB;AAC7D,EAAC,SAAiB,6BAA6B;AAChD,MAAI,cAAc,QAAQ;AAC3B;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var cluster_badge_exports = {};
|
|
20
|
+
__export(cluster_badge_exports, {
|
|
21
|
+
ClusterBadge: () => ClusterBadge
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(cluster_badge_exports);
|
|
24
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
25
|
+
var import_react = require("react");
|
|
26
|
+
var import_tldraw = require("tldraw");
|
|
27
|
+
var import_count_badge = require("../ui/count-badge");
|
|
28
|
+
var import_canvas_events = require("./canvas-events");
|
|
29
|
+
var import_thread_preview = require("./thread-preview");
|
|
30
|
+
var import_thread_state = require("./thread-state");
|
|
31
|
+
const ClusterBadge = (0, import_react.memo)(function ClusterBadge2({
|
|
32
|
+
editor,
|
|
33
|
+
node,
|
|
34
|
+
onExpand,
|
|
35
|
+
onSelectThread,
|
|
36
|
+
threadsById,
|
|
37
|
+
...props
|
|
38
|
+
}) {
|
|
39
|
+
const container = (0, import_tldraw.useContainer)();
|
|
40
|
+
const msg = (0, import_tldraw.useTranslation)();
|
|
41
|
+
const badgeRef = (0, import_react.useRef)(null);
|
|
42
|
+
const { previewShown, previewHandlers } = (0, import_thread_preview.useMarkerPreview)(editor, `cluster:${node.id}`);
|
|
43
|
+
(0, import_tldraw.usePassThroughWheelEvents)(badgeRef);
|
|
44
|
+
const meanInset = (0, import_tldraw.useValue)(
|
|
45
|
+
"cluster badge inset",
|
|
46
|
+
() => {
|
|
47
|
+
let x = 0;
|
|
48
|
+
let y = 0;
|
|
49
|
+
for (const id of node.members) {
|
|
50
|
+
const thread = threadsById.get(id);
|
|
51
|
+
if (!thread) continue;
|
|
52
|
+
const inset = (0, import_thread_state.impreciseShapePinInset)(editor, thread.anchor);
|
|
53
|
+
if (inset) {
|
|
54
|
+
x += inset.x;
|
|
55
|
+
y += inset.y;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return { x: x / node.count, y: y / node.count };
|
|
59
|
+
},
|
|
60
|
+
[editor, node, threadsById]
|
|
61
|
+
);
|
|
62
|
+
const point = (0, import_tldraw.useValue)(
|
|
63
|
+
"cluster badge point",
|
|
64
|
+
() => {
|
|
65
|
+
const pagePoint = editor.pageToViewport(node.centroid);
|
|
66
|
+
if (!(0, import_thread_state.isInInflatedViewport)(editor, pagePoint)) return null;
|
|
67
|
+
return { x: pagePoint.x + meanInset.x, y: pagePoint.y + meanInset.y };
|
|
68
|
+
},
|
|
69
|
+
[editor, node, meanInset]
|
|
70
|
+
);
|
|
71
|
+
const previewThreads = (0, import_react.useMemo)(() => {
|
|
72
|
+
if (!previewShown) return [];
|
|
73
|
+
const threads = [];
|
|
74
|
+
for (const id of node.members) {
|
|
75
|
+
const thread = threadsById.get(id);
|
|
76
|
+
if (thread) threads.push(thread);
|
|
77
|
+
}
|
|
78
|
+
return (0, import_thread_preview.sortThreadsForPreview)(threads);
|
|
79
|
+
}, [previewShown, node.members, threadsById]);
|
|
80
|
+
if (!point) return null;
|
|
81
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
82
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
83
|
+
"button",
|
|
84
|
+
{
|
|
85
|
+
ref: badgeRef,
|
|
86
|
+
type: "button",
|
|
87
|
+
className: "tlui-cmt-button tlui-cmt-canvas-cluster",
|
|
88
|
+
style: { left: point.x, top: point.y },
|
|
89
|
+
"aria-label": msg("comments.cluster-label").replace("{count}", String(node.count)),
|
|
90
|
+
onPointerDown: (e) => {
|
|
91
|
+
if ((0, import_canvas_events.isCanvasPanGesture)(editor, e)) {
|
|
92
|
+
(0, import_canvas_events.forwardPointerEventToCanvas)(container, e);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
e.stopPropagation();
|
|
96
|
+
},
|
|
97
|
+
onClick: (e) => {
|
|
98
|
+
e.stopPropagation();
|
|
99
|
+
onExpand(node);
|
|
100
|
+
},
|
|
101
|
+
...previewHandlers,
|
|
102
|
+
onFocus: previewHandlers.onPointerEnter,
|
|
103
|
+
onBlur: previewHandlers.onPointerLeave,
|
|
104
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_count_badge.CountBadge, { count: node.count })
|
|
105
|
+
}
|
|
106
|
+
),
|
|
107
|
+
previewShown && previewThreads.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
108
|
+
import_thread_preview.ThreadPreview,
|
|
109
|
+
{
|
|
110
|
+
editor,
|
|
111
|
+
threads: previewThreads,
|
|
112
|
+
variant: "list",
|
|
113
|
+
point,
|
|
114
|
+
onSelectThread,
|
|
115
|
+
...previewHandlers,
|
|
116
|
+
...props
|
|
117
|
+
}
|
|
118
|
+
)
|
|
119
|
+
] });
|
|
120
|
+
});
|
|
121
|
+
//# sourceMappingURL=cluster-badge.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/canvas/cluster-badge.tsx"],
|
|
4
|
+
"sourcesContent": ["import { memo, useMemo, useRef } from 'react'\nimport {\n\tEditor,\n\tTLCommentThread,\n\tuseContainer,\n\tusePassThroughWheelEvents,\n\tuseTranslation,\n\tuseValue,\n} from 'tldraw'\nimport type { ClusterNode } from '../clustering/types'\nimport { CountBadge } from '../ui/count-badge'\nimport { forwardPointerEventToCanvas, isCanvasPanGesture } from './canvas-events'\nimport { type CommentingContext } from './context'\nimport { sortThreadsForPreview, ThreadPreview, useMarkerPreview } from './thread-preview'\nimport { impreciseShapePinInset, isInInflatedViewport } from './thread-state'\n\n/**\n * The count badge standing in for several threads folded together at the current zoom. Hovering it\n * previews its threads as a list; clicking zooms to the zoom level at which the cluster splits.\n *\n * Memoized: cluster nodes and thread records are identity-stable while unchanged, so pins and\n * badges skip re-rendering when the parent re-renders for reasons that don't concern them\n * (leaf recomputes during shape drags, partition changes elsewhere). Camera tracking still\n * works \u2014 each component subscribes to its own viewport position via signals, not via props.\n */\nexport const ClusterBadge = memo(function ClusterBadge({\n\teditor,\n\tnode,\n\tonExpand,\n\tonSelectThread,\n\tthreadsById,\n\t...props\n}: Pick<CommentingContext, 'currentUserId' | 'resolveAuthor'> & {\n\teditor: Editor\n\tnode: ClusterNode\n\tonExpand(node: ClusterNode): void\n\tonSelectThread(thread: TLCommentThread): void\n\tthreadsById: ReadonlyMap<string, TLCommentThread>\n}) {\n\tconst container = useContainer()\n\tconst msg = useTranslation()\n\tconst badgeRef = useRef<HTMLButtonElement>(null)\n\tconst { previewShown, previewHandlers } = useMarkerPreview(editor, `cluster:${node.id}`)\n\t// Wheel pass-through sits on the badge (never scrollable), not the layer root \u2014 see the\n\t// note on the layer.\n\tusePassThroughWheelEvents(badgeRef)\n\t// The mean of the members' render offsets, in screen px. Imprecise members' pins draw tucked\n\t// into their shape (see impreciseShapePinInset), and the merge thresholds are priced at those\n\t// visual positions \u2014 so the badge draws at the centroid of the pins as drawn, which (screen\n\t// mapping being affine) is the anchor centroid plus this mean. Camera-independent: its own\n\t// computed so the per-frame point below only adds two numbers, and a cluster of precise\n\t// members tracks nothing and adds zero.\n\tconst meanInset = useValue(\n\t\t'cluster badge inset',\n\t\t() => {\n\t\t\tlet x = 0\n\t\t\tlet y = 0\n\t\t\tfor (const id of node.members) {\n\t\t\t\tconst thread = threadsById.get(id)\n\t\t\t\tif (!thread) continue\n\t\t\t\tconst inset = impreciseShapePinInset(editor, thread.anchor)\n\t\t\t\tif (inset) {\n\t\t\t\t\tx += inset.x\n\t\t\t\t\ty += inset.y\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn { x: x / node.count, y: y / node.count }\n\t\t},\n\t\t[editor, node, threadsById]\n\t)\n\tconst point = useValue(\n\t\t'cluster badge point',\n\t\t() => {\n\t\t\tconst pagePoint = editor.pageToViewport(node.centroid)\n\t\t\tif (!isInInflatedViewport(editor, pagePoint)) return null\n\t\t\treturn { x: pagePoint.x + meanInset.x, y: pagePoint.y + meanInset.y }\n\t\t},\n\t\t[editor, node, meanInset]\n\t)\n\n\t// `node.members` is sorted by id (the clustering table's ordering); the preview wants them in\n\t// the order a reader would expect. Only computed while the preview is up.\n\tconst previewThreads = useMemo(() => {\n\t\tif (!previewShown) return []\n\t\tconst threads: TLCommentThread[] = []\n\t\tfor (const id of node.members) {\n\t\t\tconst thread = threadsById.get(id)\n\t\t\tif (thread) threads.push(thread)\n\t\t}\n\t\treturn sortThreadsForPreview(threads)\n\t}, [previewShown, node.members, threadsById])\n\n\tif (!point) return null\n\n\treturn (\n\t\t<>\n\t\t\t<button\n\t\t\t\tref={badgeRef}\n\t\t\t\ttype=\"button\"\n\t\t\t\tclassName=\"tlui-cmt-button tlui-cmt-canvas-cluster\"\n\t\t\t\tstyle={{ left: point.x, top: point.y }}\n\t\t\t\taria-label={msg('comments.cluster-label').replace('{count}', String(node.count))}\n\t\t\t\tonPointerDown={(e) => {\n\t\t\t\t\tif (isCanvasPanGesture(editor, e)) {\n\t\t\t\t\t\tforwardPointerEventToCanvas(container, e)\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\te.stopPropagation()\n\t\t\t\t}}\n\t\t\t\tonClick={(e) => {\n\t\t\t\t\te.stopPropagation()\n\t\t\t\t\tonExpand(node)\n\t\t\t\t}}\n\t\t\t\t{...previewHandlers}\n\t\t\t\tonFocus={previewHandlers.onPointerEnter}\n\t\t\t\tonBlur={previewHandlers.onPointerLeave}\n\t\t\t>\n\t\t\t\t<CountBadge count={node.count} />\n\t\t\t</button>\n\t\t\t{previewShown && previewThreads.length > 0 && (\n\t\t\t\t<ThreadPreview\n\t\t\t\t\teditor={editor}\n\t\t\t\t\tthreads={previewThreads}\n\t\t\t\t\tvariant=\"list\"\n\t\t\t\t\tpoint={point}\n\t\t\t\t\tonSelectThread={onSelectThread}\n\t\t\t\t\t{...previewHandlers}\n\t\t\t\t\t{...props}\n\t\t\t\t/>\n\t\t\t)}\n\t\t</>\n\t)\n})\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA+FE;AA/FF,mBAAsC;AACtC,oBAOO;AAEP,yBAA2B;AAC3B,2BAAgE;AAEhE,4BAAuE;AACvE,0BAA6D;AAWtD,MAAM,mBAAe,mBAAK,SAASA,cAAa;AAAA,EACtD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACJ,GAMG;AACF,QAAM,gBAAY,4BAAa;AAC/B,QAAM,UAAM,8BAAe;AAC3B,QAAM,eAAW,qBAA0B,IAAI;AAC/C,QAAM,EAAE,cAAc,gBAAgB,QAAI,wCAAiB,QAAQ,WAAW,KAAK,EAAE,EAAE;AAGvF,+CAA0B,QAAQ;AAOlC,QAAM,gBAAY;AAAA,IACjB;AAAA,IACA,MAAM;AACL,UAAI,IAAI;AACR,UAAI,IAAI;AACR,iBAAW,MAAM,KAAK,SAAS;AAC9B,cAAM,SAAS,YAAY,IAAI,EAAE;AACjC,YAAI,CAAC,OAAQ;AACb,cAAM,YAAQ,4CAAuB,QAAQ,OAAO,MAAM;AAC1D,YAAI,OAAO;AACV,eAAK,MAAM;AACX,eAAK,MAAM;AAAA,QACZ;AAAA,MACD;AACA,aAAO,EAAE,GAAG,IAAI,KAAK,OAAO,GAAG,IAAI,KAAK,MAAM;AAAA,IAC/C;AAAA,IACA,CAAC,QAAQ,MAAM,WAAW;AAAA,EAC3B;AACA,QAAM,YAAQ;AAAA,IACb;AAAA,IACA,MAAM;AACL,YAAM,YAAY,OAAO,eAAe,KAAK,QAAQ;AACrD,UAAI,KAAC,0CAAqB,QAAQ,SAAS,EAAG,QAAO;AACrD,aAAO,EAAE,GAAG,UAAU,IAAI,UAAU,GAAG,GAAG,UAAU,IAAI,UAAU,EAAE;AAAA,IACrE;AAAA,IACA,CAAC,QAAQ,MAAM,SAAS;AAAA,EACzB;AAIA,QAAM,qBAAiB,sBAAQ,MAAM;AACpC,QAAI,CAAC,aAAc,QAAO,CAAC;AAC3B,UAAM,UAA6B,CAAC;AACpC,eAAW,MAAM,KAAK,SAAS;AAC9B,YAAM,SAAS,YAAY,IAAI,EAAE;AACjC,UAAI,OAAQ,SAAQ,KAAK,MAAM;AAAA,IAChC;AACA,eAAO,6CAAsB,OAAO;AAAA,EACrC,GAAG,CAAC,cAAc,KAAK,SAAS,WAAW,CAAC;AAE5C,MAAI,CAAC,MAAO,QAAO;AAEnB,SACC,4EACC;AAAA;AAAA,MAAC;AAAA;AAAA,QACA,KAAK;AAAA,QACL,MAAK;AAAA,QACL,WAAU;AAAA,QACV,OAAO,EAAE,MAAM,MAAM,GAAG,KAAK,MAAM,EAAE;AAAA,QACrC,cAAY,IAAI,wBAAwB,EAAE,QAAQ,WAAW,OAAO,KAAK,KAAK,CAAC;AAAA,QAC/E,eAAe,CAAC,MAAM;AACrB,kBAAI,yCAAmB,QAAQ,CAAC,GAAG;AAClC,kEAA4B,WAAW,CAAC;AACxC;AAAA,UACD;AACA,YAAE,gBAAgB;AAAA,QACnB;AAAA,QACA,SAAS,CAAC,MAAM;AACf,YAAE,gBAAgB;AAClB,mBAAS,IAAI;AAAA,QACd;AAAA,QACC,GAAG;AAAA,QACJ,SAAS,gBAAgB;AAAA,QACzB,QAAQ,gBAAgB;AAAA,QAExB,sDAAC,iCAAW,OAAO,KAAK,OAAO;AAAA;AAAA,IAChC;AAAA,IACC,gBAAgB,eAAe,SAAS,KACxC;AAAA,MAAC;AAAA;AAAA,QACA;AAAA,QACA,SAAS;AAAA,QACT,SAAQ;AAAA,QACR;AAAA,QACA;AAAA,QACC,GAAG;AAAA,QACH,GAAG;AAAA;AAAA,IACL;AAAA,KAEF;AAEF,CAAC;",
|
|
6
|
+
"names": ["ClusterBadge"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var cluster_fade_exports = {};
|
|
20
|
+
__export(cluster_fade_exports, {
|
|
21
|
+
clusterFadeClassName: () => clusterFadeClassName,
|
|
22
|
+
useFadeVisibleNodes: () => useFadeVisibleNodes
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(cluster_fade_exports);
|
|
25
|
+
var import_react = require("react");
|
|
26
|
+
const CLUSTER_FADE_MS = 150;
|
|
27
|
+
function useFadeVisibleNodes(nodes, resetKey) {
|
|
28
|
+
const resetKeyRef = (0, import_react.useRef)(resetKey);
|
|
29
|
+
const didReset = resetKeyRef.current !== resetKey;
|
|
30
|
+
if (didReset) {
|
|
31
|
+
resetKeyRef.current = resetKey;
|
|
32
|
+
}
|
|
33
|
+
const [fadeNodes, setFadeNodes] = (0, import_react.useState)(() => toPresentFadeNodes(nodes));
|
|
34
|
+
const renderedNodes = didReset ? toPresentFadeNodes(nodes) : fadeNodes;
|
|
35
|
+
(0, import_react.useEffect)(() => {
|
|
36
|
+
setFadeNodes(toPresentFadeNodes(nodes));
|
|
37
|
+
}, [resetKey]);
|
|
38
|
+
(0, import_react.useEffect)(() => {
|
|
39
|
+
if (didReset) return;
|
|
40
|
+
setFadeNodes((previous) => reconcileFadeNodes(previous, nodes));
|
|
41
|
+
}, [didReset, nodes]);
|
|
42
|
+
const hasEntering = renderedNodes.some((item) => item.phase === "entering");
|
|
43
|
+
(0, import_react.useEffect)(() => {
|
|
44
|
+
if (!hasEntering) return;
|
|
45
|
+
const frame = requestAnimationFrame(() => {
|
|
46
|
+
setFadeNodes(
|
|
47
|
+
(previous) => previous.map((item) => item.phase === "entering" ? { ...item, phase: "present" } : item)
|
|
48
|
+
);
|
|
49
|
+
});
|
|
50
|
+
return () => cancelAnimationFrame(frame);
|
|
51
|
+
}, [hasEntering, renderedNodes]);
|
|
52
|
+
const hasExiting = renderedNodes.some((item) => item.phase === "exiting");
|
|
53
|
+
(0, import_react.useEffect)(() => {
|
|
54
|
+
if (!hasExiting) return;
|
|
55
|
+
const timeout = window.setTimeout(() => {
|
|
56
|
+
setFadeNodes((previous) => previous.filter((item) => item.phase !== "exiting"));
|
|
57
|
+
}, CLUSTER_FADE_MS);
|
|
58
|
+
return () => window.clearTimeout(timeout);
|
|
59
|
+
}, [hasExiting, renderedNodes]);
|
|
60
|
+
return renderedNodes;
|
|
61
|
+
}
|
|
62
|
+
function toPresentFadeNodes(nodes) {
|
|
63
|
+
return nodes.map((node) => ({ node, phase: "present" }));
|
|
64
|
+
}
|
|
65
|
+
function reconcileFadeNodes(previous, nextNodes) {
|
|
66
|
+
const previousById = new Map(previous.map((item) => [item.node.id, item]));
|
|
67
|
+
const nextIds = new Set(nextNodes.map((node) => node.id));
|
|
68
|
+
const next = [];
|
|
69
|
+
for (const node of nextNodes) {
|
|
70
|
+
const previousItem = previousById.get(node.id);
|
|
71
|
+
next.push({
|
|
72
|
+
node,
|
|
73
|
+
phase: previousItem && previousItem.phase !== "exiting" ? previousItem.phase : previousItem ? "present" : "entering"
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
for (const item of previous) {
|
|
77
|
+
if (nextIds.has(item.node.id)) continue;
|
|
78
|
+
next.push(item.phase === "exiting" ? item : { ...item, phase: "exiting" });
|
|
79
|
+
}
|
|
80
|
+
return next;
|
|
81
|
+
}
|
|
82
|
+
function clusterFadeClassName(phase) {
|
|
83
|
+
return `tlui-cmt-cluster-fade tlui-cmt-cluster-fade--${phase}`;
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=cluster-fade.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/canvas/cluster-fade.ts"],
|
|
4
|
+
"sourcesContent": ["import { useEffect, useRef, useState } from 'react'\nimport type { ClusterNode } from '../clustering/types'\n\nconst CLUSTER_FADE_MS = 150\n\nexport type ClusterFadePhase = 'entering' | 'present' | 'exiting'\n\nexport interface ClusterFadeNode {\n\tnode: ClusterNode\n\tphase: ClusterFadePhase\n}\n\n/**\n * Cross-fades the visible cluster nodes as the partition changes: a node that appears starts\n * `entering` and flips to `present` on the next frame, and one that leaves is kept as `exiting`\n * until the CSS transition has run. `resetKey` is compared by identity \u2014 a new cluster model\n * replaces the whole world, so its nodes snap to `present` instead of animating.\n */\nexport function useFadeVisibleNodes(\n\tnodes: readonly ClusterNode[],\n\tresetKey: object\n): ClusterFadeNode[] {\n\tconst resetKeyRef = useRef(resetKey)\n\tconst didReset = resetKeyRef.current !== resetKey\n\tif (didReset) {\n\t\tresetKeyRef.current = resetKey\n\t}\n\n\tconst [fadeNodes, setFadeNodes] = useState<ClusterFadeNode[]>(() => toPresentFadeNodes(nodes))\n\tconst renderedNodes = didReset ? toPresentFadeNodes(nodes) : fadeNodes\n\n\tuseEffect(() => {\n\t\tsetFadeNodes(toPresentFadeNodes(nodes))\n\t\t// Resets only on a new model (resetKey); node-list changes within the same model are\n\t\t// handled by the reconcile effect below, which fades entries in/out instead of snapping.\n\t\t// eslint-disable-next-line react-hooks/exhaustive-deps\n\t}, [resetKey])\n\n\tuseEffect(() => {\n\t\tif (didReset) return\n\t\tsetFadeNodes((previous) => reconcileFadeNodes(previous, nodes))\n\t}, [didReset, nodes])\n\n\tconst hasEntering = renderedNodes.some((item) => item.phase === 'entering')\n\tuseEffect(() => {\n\t\tif (!hasEntering) return\n\t\tconst frame = requestAnimationFrame(() => {\n\t\t\tsetFadeNodes((previous) =>\n\t\t\t\tprevious.map((item) => (item.phase === 'entering' ? { ...item, phase: 'present' } : item))\n\t\t\t)\n\t\t})\n\t\treturn () => cancelAnimationFrame(frame)\n\t}, [hasEntering, renderedNodes])\n\n\tconst hasExiting = renderedNodes.some((item) => item.phase === 'exiting')\n\tuseEffect(() => {\n\t\tif (!hasExiting) return\n\t\tconst timeout = window.setTimeout(() => {\n\t\t\tsetFadeNodes((previous) => previous.filter((item) => item.phase !== 'exiting'))\n\t\t}, CLUSTER_FADE_MS)\n\t\treturn () => window.clearTimeout(timeout)\n\t}, [hasExiting, renderedNodes])\n\n\treturn renderedNodes\n}\n\nfunction toPresentFadeNodes(nodes: readonly ClusterNode[]): ClusterFadeNode[] {\n\treturn nodes.map((node) => ({ node, phase: 'present' }))\n}\n\nfunction reconcileFadeNodes(\n\tprevious: readonly ClusterFadeNode[],\n\tnextNodes: readonly ClusterNode[]\n): ClusterFadeNode[] {\n\tconst previousById = new Map(previous.map((item) => [item.node.id, item]))\n\tconst nextIds = new Set(nextNodes.map((node) => node.id))\n\tconst next: ClusterFadeNode[] = []\n\n\tfor (const node of nextNodes) {\n\t\tconst previousItem = previousById.get(node.id)\n\t\tnext.push({\n\t\t\tnode,\n\t\t\tphase:\n\t\t\t\tpreviousItem && previousItem.phase !== 'exiting'\n\t\t\t\t\t? previousItem.phase\n\t\t\t\t\t: previousItem\n\t\t\t\t\t\t? 'present'\n\t\t\t\t\t\t: 'entering',\n\t\t})\n\t}\n\n\tfor (const item of previous) {\n\t\tif (nextIds.has(item.node.id)) continue\n\t\tnext.push(item.phase === 'exiting' ? item : { ...item, phase: 'exiting' })\n\t}\n\n\treturn next\n}\n\nexport function clusterFadeClassName(phase: ClusterFadePhase): string {\n\treturn `tlui-cmt-cluster-fade tlui-cmt-cluster-fade--${phase}`\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAA4C;AAG5C,MAAM,kBAAkB;AAejB,SAAS,oBACf,OACA,UACoB;AACpB,QAAM,kBAAc,qBAAO,QAAQ;AACnC,QAAM,WAAW,YAAY,YAAY;AACzC,MAAI,UAAU;AACb,gBAAY,UAAU;AAAA,EACvB;AAEA,QAAM,CAAC,WAAW,YAAY,QAAI,uBAA4B,MAAM,mBAAmB,KAAK,CAAC;AAC7F,QAAM,gBAAgB,WAAW,mBAAmB,KAAK,IAAI;AAE7D,8BAAU,MAAM;AACf,iBAAa,mBAAmB,KAAK,CAAC;AAAA,EAIvC,GAAG,CAAC,QAAQ,CAAC;AAEb,8BAAU,MAAM;AACf,QAAI,SAAU;AACd,iBAAa,CAAC,aAAa,mBAAmB,UAAU,KAAK,CAAC;AAAA,EAC/D,GAAG,CAAC,UAAU,KAAK,CAAC;AAEpB,QAAM,cAAc,cAAc,KAAK,CAAC,SAAS,KAAK,UAAU,UAAU;AAC1E,8BAAU,MAAM;AACf,QAAI,CAAC,YAAa;AAClB,UAAM,QAAQ,sBAAsB,MAAM;AACzC;AAAA,QAAa,CAAC,aACb,SAAS,IAAI,CAAC,SAAU,KAAK,UAAU,aAAa,EAAE,GAAG,MAAM,OAAO,UAAU,IAAI,IAAK;AAAA,MAC1F;AAAA,IACD,CAAC;AACD,WAAO,MAAM,qBAAqB,KAAK;AAAA,EACxC,GAAG,CAAC,aAAa,aAAa,CAAC;AAE/B,QAAM,aAAa,cAAc,KAAK,CAAC,SAAS,KAAK,UAAU,SAAS;AACxE,8BAAU,MAAM;AACf,QAAI,CAAC,WAAY;AACjB,UAAM,UAAU,OAAO,WAAW,MAAM;AACvC,mBAAa,CAAC,aAAa,SAAS,OAAO,CAAC,SAAS,KAAK,UAAU,SAAS,CAAC;AAAA,IAC/E,GAAG,eAAe;AAClB,WAAO,MAAM,OAAO,aAAa,OAAO;AAAA,EACzC,GAAG,CAAC,YAAY,aAAa,CAAC;AAE9B,SAAO;AACR;AAEA,SAAS,mBAAmB,OAAkD;AAC7E,SAAO,MAAM,IAAI,CAAC,UAAU,EAAE,MAAM,OAAO,UAAU,EAAE;AACxD;AAEA,SAAS,mBACR,UACA,WACoB;AACpB,QAAM,eAAe,IAAI,IAAI,SAAS,IAAI,CAAC,SAAS,CAAC,KAAK,KAAK,IAAI,IAAI,CAAC,CAAC;AACzE,QAAM,UAAU,IAAI,IAAI,UAAU,IAAI,CAAC,SAAS,KAAK,EAAE,CAAC;AACxD,QAAM,OAA0B,CAAC;AAEjC,aAAW,QAAQ,WAAW;AAC7B,UAAM,eAAe,aAAa,IAAI,KAAK,EAAE;AAC7C,SAAK,KAAK;AAAA,MACT;AAAA,MACA,OACC,gBAAgB,aAAa,UAAU,YACpC,aAAa,QACb,eACC,YACA;AAAA,IACN,CAAC;AAAA,EACF;AAEA,aAAW,QAAQ,UAAU;AAC5B,QAAI,QAAQ,IAAI,KAAK,KAAK,EAAE,EAAG;AAC/B,SAAK,KAAK,KAAK,UAAU,YAAY,OAAO,EAAE,GAAG,MAAM,OAAO,UAAU,CAAC;AAAA,EAC1E;AAEA,SAAO;AACR;AAEO,SAAS,qBAAqB,OAAiC;AACrE,SAAO,gDAAgD,KAAK;AAC7D;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -18,23 +18,73 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
19
|
var cluster_input_exports = {};
|
|
20
20
|
__export(cluster_input_exports, {
|
|
21
|
+
clusterInputEqual: () => clusterInputEqual,
|
|
22
|
+
clusterInputIdsEqual: () => clusterInputIdsEqual,
|
|
21
23
|
collectClusterLeaves: () => collectClusterLeaves
|
|
22
24
|
});
|
|
23
25
|
module.exports = __toCommonJS(cluster_input_exports);
|
|
24
26
|
var import_thread_state = require("./thread-state");
|
|
25
|
-
function collectClusterLeaves(editor, threads, openThreadId
|
|
27
|
+
function collectClusterLeaves(editor, threads, openThreadId) {
|
|
26
28
|
const pageId = editor.getCurrentPageId();
|
|
27
29
|
const leaves = [];
|
|
30
|
+
let screenOffsets;
|
|
28
31
|
for (const thread of threads) {
|
|
29
32
|
if (thread.id === openThreadId) continue;
|
|
30
33
|
if (thread.pageId !== pageId) continue;
|
|
31
|
-
const point = (0, import_thread_state.anchorPagePoint)(editor, thread.anchor
|
|
34
|
+
const point = (0, import_thread_state.anchorPagePoint)(editor, thread.anchor);
|
|
32
35
|
if (!point) continue;
|
|
33
36
|
leaves.push({
|
|
34
37
|
id: thread.id,
|
|
35
38
|
point: { x: point.x, y: point.y }
|
|
36
39
|
});
|
|
40
|
+
const inset = (0, import_thread_state.impreciseShapePinInset)(editor, thread.anchor);
|
|
41
|
+
if (inset) (screenOffsets ??= /* @__PURE__ */ new Map()).set(thread.id, inset);
|
|
37
42
|
}
|
|
38
|
-
return leaves;
|
|
43
|
+
return { leaves, screenOffsets };
|
|
44
|
+
}
|
|
45
|
+
function clusterInputEqual(a, b) {
|
|
46
|
+
if (a === b) return true;
|
|
47
|
+
return clusterLeavesEqual(a.leaves, b.leaves) && screenOffsetsEqual(a.screenOffsets, b.screenOffsets);
|
|
48
|
+
}
|
|
49
|
+
function clusterInputIdsEqual(a, b) {
|
|
50
|
+
if (a === b) return true;
|
|
51
|
+
return clusterLeafIdsEqual(a.leaves, b.leaves) && screenOffsetIdsEqual(a.screenOffsets, b.screenOffsets);
|
|
52
|
+
}
|
|
53
|
+
function screenOffsetsEqual(a, b) {
|
|
54
|
+
if (a === b) return true;
|
|
55
|
+
if (!a || !b) return false;
|
|
56
|
+
if (a.size !== b.size) return false;
|
|
57
|
+
for (const [id, offset] of b) {
|
|
58
|
+
const prev = a.get(id);
|
|
59
|
+
if (!prev || prev.x !== offset.x || prev.y !== offset.y) return false;
|
|
60
|
+
}
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
function screenOffsetIdsEqual(a, b) {
|
|
64
|
+
if (a === b) return true;
|
|
65
|
+
if (!a || !b) return false;
|
|
66
|
+
if (a.size !== b.size) return false;
|
|
67
|
+
for (const id of b.keys()) {
|
|
68
|
+
if (!a.has(id)) return false;
|
|
69
|
+
}
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
function clusterLeavesEqual(a, b) {
|
|
73
|
+
if (a === b) return true;
|
|
74
|
+
if (a.length !== b.length) return false;
|
|
75
|
+
for (let i = 0; i < a.length; i++) {
|
|
76
|
+
const la = a[i];
|
|
77
|
+
const lb = b[i];
|
|
78
|
+
if (la.id !== lb.id || la.point.x !== lb.point.x || la.point.y !== lb.point.y) return false;
|
|
79
|
+
}
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
function clusterLeafIdsEqual(a, b) {
|
|
83
|
+
if (a === b) return true;
|
|
84
|
+
if (a.length !== b.length) return false;
|
|
85
|
+
for (let i = 0; i < a.length; i++) {
|
|
86
|
+
if (a[i].id !== b[i].id) return false;
|
|
87
|
+
}
|
|
88
|
+
return true;
|
|
39
89
|
}
|
|
40
90
|
//# sourceMappingURL=cluster-input.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/canvas/cluster-input.ts"],
|
|
4
|
-
"sourcesContent": ["import type { Editor, TLCommentThread } from 'tldraw'\nimport type { LeafInput } from '../clustering/types'\nimport { anchorPagePoint } from './thread-state'\n\n/** @
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,
|
|
4
|
+
"sourcesContent": ["import type { Editor, TLCommentThread, VecLike } from 'tldraw'\nimport type { LeafInput, LeafScreenOffsets } from '../clustering/types'\nimport { anchorPagePoint, impreciseShapePinInset } from './thread-state'\n\n/** The clustering input for the current page's pinned threads. @internal */\nexport interface ClusterInput {\n\t/** One leaf per pinned thread, at its anchor page point. */\n\tleaves: LeafInput[]\n\t/**\n\t * The render offsets of the imprecise pins among the leaves \u2014 those draw tucked into their\n\t * shape by a constant screen-px inset rather than on their anchor, and the clustering prices\n\t * their merges at the visual positions. Undefined when every pin renders on its anchor,\n\t * which guarantees a byte-identical offset-unaware clustering run.\n\t */\n\tscreenOffsets: LeafScreenOffsets | undefined\n}\n\n/** The cluster leaves for the threads pinned on the current page. @internal */\nexport function collectClusterLeaves(\n\teditor: Editor,\n\tthreads: readonly TLCommentThread[],\n\topenThreadId: string | null\n): ClusterInput {\n\tconst pageId = editor.getCurrentPageId()\n\tconst leaves: LeafInput[] = []\n\tlet screenOffsets: Map<string, VecLike> | undefined\n\n\tfor (const thread of threads) {\n\t\tif (thread.id === openThreadId) continue\n\t\tif (thread.pageId !== pageId) continue\n\n\t\tconst point = anchorPagePoint(editor, thread.anchor)\n\t\tif (!point) continue\n\n\t\tleaves.push({\n\t\t\tid: thread.id,\n\t\t\tpoint: { x: point.x, y: point.y },\n\t\t})\n\n\t\tconst inset = impreciseShapePinInset(editor, thread.anchor)\n\t\tif (inset) (screenOffsets ??= new Map()).set(thread.id, inset)\n\t}\n\n\treturn { leaves, screenOffsets }\n}\n\n/**\n * Value equality over everything `computeClusterTable` reads. Keeps the input's identity stable\n * across recomputes that changed nothing, so the O(N\u00B2) rebuild only runs when it has to.\n * @internal\n */\nexport function clusterInputEqual(a: ClusterInput, b: ClusterInput): boolean {\n\tif (a === b) return true\n\treturn (\n\t\tclusterLeavesEqual(a.leaves, b.leaves) && screenOffsetsEqual(a.screenOffsets, b.screenOffsets)\n\t)\n}\n\n/**\n * The same, ignoring everything positional \u2014 anchor points and offset vectors alike. The mid-drag\n * gate: a move defers, but a thread added, removed, or changed precision still rebuilds.\n * @internal\n */\nexport function clusterInputIdsEqual(a: ClusterInput, b: ClusterInput): boolean {\n\tif (a === b) return true\n\treturn (\n\t\tclusterLeafIdsEqual(a.leaves, b.leaves) &&\n\t\tscreenOffsetIdsEqual(a.screenOffsets, b.screenOffsets)\n\t)\n}\n\nfunction screenOffsetsEqual(a: LeafScreenOffsets | undefined, b: LeafScreenOffsets | undefined) {\n\tif (a === b) return true\n\tif (!a || !b) return false\n\tif (a.size !== b.size) return false\n\tfor (const [id, offset] of b) {\n\t\tconst prev = a.get(id)\n\t\tif (!prev || prev.x !== offset.x || prev.y !== offset.y) return false\n\t}\n\treturn true\n}\n\n/** Which leaves carry an offset, ignoring the vectors: a leaf gains or loses one by changing\n * precision, which is a record change rather than a gesture. */\nfunction screenOffsetIdsEqual(a: LeafScreenOffsets | undefined, b: LeafScreenOffsets | undefined) {\n\tif (a === b) return true\n\tif (!a || !b) return false\n\tif (a.size !== b.size) return false\n\tfor (const id of b.keys()) {\n\t\tif (!a.has(id)) return false\n\t}\n\treturn true\n}\n\n/** Whether two leaf lists have the same threads at the same positions, in the same order. */\nfunction clusterLeavesEqual(a: readonly LeafInput[], b: readonly LeafInput[]): boolean {\n\tif (a === b) return true\n\tif (a.length !== b.length) return false\n\tfor (let i = 0; i < a.length; i++) {\n\t\tconst la = a[i]\n\t\tconst lb = b[i]\n\t\tif (la.id !== lb.id || la.point.x !== lb.point.x || la.point.y !== lb.point.y) return false\n\t}\n\treturn true\n}\n\n/** Whether two leaf lists contain the same thread ids in the same order, ignoring positions. */\nfunction clusterLeafIdsEqual(a: readonly LeafInput[], b: readonly LeafInput[]): boolean {\n\tif (a === b) return true\n\tif (a.length !== b.length) return false\n\tfor (let i = 0; i < a.length; i++) {\n\t\tif (a[i].id !== b[i].id) return false\n\t}\n\treturn true\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,0BAAwD;AAgBjD,SAAS,qBACf,QACA,SACA,cACe;AACf,QAAM,SAAS,OAAO,iBAAiB;AACvC,QAAM,SAAsB,CAAC;AAC7B,MAAI;AAEJ,aAAW,UAAU,SAAS;AAC7B,QAAI,OAAO,OAAO,aAAc;AAChC,QAAI,OAAO,WAAW,OAAQ;AAE9B,UAAM,YAAQ,qCAAgB,QAAQ,OAAO,MAAM;AACnD,QAAI,CAAC,MAAO;AAEZ,WAAO,KAAK;AAAA,MACX,IAAI,OAAO;AAAA,MACX,OAAO,EAAE,GAAG,MAAM,GAAG,GAAG,MAAM,EAAE;AAAA,IACjC,CAAC;AAED,UAAM,YAAQ,4CAAuB,QAAQ,OAAO,MAAM;AAC1D,QAAI,MAAO,EAAC,kBAAkB,oBAAI,IAAI,GAAG,IAAI,OAAO,IAAI,KAAK;AAAA,EAC9D;AAEA,SAAO,EAAE,QAAQ,cAAc;AAChC;AAOO,SAAS,kBAAkB,GAAiB,GAA0B;AAC5E,MAAI,MAAM,EAAG,QAAO;AACpB,SACC,mBAAmB,EAAE,QAAQ,EAAE,MAAM,KAAK,mBAAmB,EAAE,eAAe,EAAE,aAAa;AAE/F;AAOO,SAAS,qBAAqB,GAAiB,GAA0B;AAC/E,MAAI,MAAM,EAAG,QAAO;AACpB,SACC,oBAAoB,EAAE,QAAQ,EAAE,MAAM,KACtC,qBAAqB,EAAE,eAAe,EAAE,aAAa;AAEvD;AAEA,SAAS,mBAAmB,GAAkC,GAAkC;AAC/F,MAAI,MAAM,EAAG,QAAO;AACpB,MAAI,CAAC,KAAK,CAAC,EAAG,QAAO;AACrB,MAAI,EAAE,SAAS,EAAE,KAAM,QAAO;AAC9B,aAAW,CAAC,IAAI,MAAM,KAAK,GAAG;AAC7B,UAAM,OAAO,EAAE,IAAI,EAAE;AACrB,QAAI,CAAC,QAAQ,KAAK,MAAM,OAAO,KAAK,KAAK,MAAM,OAAO,EAAG,QAAO;AAAA,EACjE;AACA,SAAO;AACR;AAIA,SAAS,qBAAqB,GAAkC,GAAkC;AACjG,MAAI,MAAM,EAAG,QAAO;AACpB,MAAI,CAAC,KAAK,CAAC,EAAG,QAAO;AACrB,MAAI,EAAE,SAAS,EAAE,KAAM,QAAO;AAC9B,aAAW,MAAM,EAAE,KAAK,GAAG;AAC1B,QAAI,CAAC,EAAE,IAAI,EAAE,EAAG,QAAO;AAAA,EACxB;AACA,SAAO;AACR;AAGA,SAAS,mBAAmB,GAAyB,GAAkC;AACtF,MAAI,MAAM,EAAG,QAAO;AACpB,MAAI,EAAE,WAAW,EAAE,OAAQ,QAAO;AAClC,WAAS,IAAI,GAAG,IAAI,EAAE,QAAQ,KAAK;AAClC,UAAM,KAAK,EAAE,CAAC;AACd,UAAM,KAAK,EAAE,CAAC;AACd,QAAI,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,MAAM,GAAG,MAAM,KAAK,GAAG,MAAM,MAAM,GAAG,MAAM,EAAG,QAAO;AAAA,EACvF;AACA,SAAO;AACR;AAGA,SAAS,oBAAoB,GAAyB,GAAkC;AACvF,MAAI,MAAM,EAAG,QAAO;AACpB,MAAI,EAAE,WAAW,EAAE,OAAQ,QAAO;AAClC,WAAS,IAAI,GAAG,IAAI,EAAE,QAAQ,KAAK;AAClC,QAAI,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,GAAI,QAAO;AAAA,EACjC;AACA,SAAO;AACR;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|