@tldraw/commenting 0.0.0-bootstrap → 5.3.0-canary.31036673d3f8
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 +1139 -329
- package/dist-cjs/canvas/anchor-lifecycle.js +148 -0
- package/dist-cjs/canvas/anchor-lifecycle.js.map +7 -0
- package/dist-cjs/canvas/cluster-input.js +2 -2
- package/dist-cjs/canvas/cluster-input.js.map +2 -2
- package/dist-cjs/canvas/comment-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 +123 -0
- package/dist-cjs/canvas/comment-mutations.js.map +7 -0
- package/dist-cjs/canvas/comment-reactions.js +163 -0
- package/dist-cjs/canvas/comment-reactions.js.map +7 -0
- package/dist-cjs/canvas/comment-render.js +5 -3
- package/dist-cjs/canvas/comment-render.js.map +2 -2
- package/dist-cjs/canvas/comment-store.js +19 -9
- package/dist-cjs/canvas/comment-store.js.map +2 -2
- package/dist-cjs/canvas/comment-tool.js +64 -14
- package/dist-cjs/canvas/comment-tool.js.map +2 -2
- package/dist-cjs/canvas/comments-filter-menu.js +20 -38
- package/dist-cjs/canvas/comments-filter-menu.js.map +2 -2
- package/dist-cjs/canvas/comments-overflow-menu.js +22 -27
- package/dist-cjs/canvas/comments-overflow-menu.js.map +2 -2
- package/dist-cjs/canvas/comments-overlay.js +429 -474
- package/dist-cjs/canvas/comments-overlay.js.map +2 -2
- package/dist-cjs/canvas/comments-sidebar.js +35 -32
- package/dist-cjs/canvas/comments-sidebar.js.map +2 -2
- package/dist-cjs/canvas/comments-visibility-toggle.js +65 -0
- package/dist-cjs/canvas/comments-visibility-toggle.js.map +7 -0
- package/dist-cjs/canvas/context.js +17 -0
- package/dist-cjs/canvas/context.js.map +7 -0
- package/dist-cjs/canvas/hooks.js +22 -3
- package/dist-cjs/canvas/hooks.js.map +2 -2
- package/dist-cjs/canvas/options.js +19 -2
- package/dist-cjs/canvas/options.js.map +2 -2
- package/dist-cjs/canvas/pin-stacking.js +56 -0
- package/dist-cjs/canvas/pin-stacking.js.map +7 -0
- package/dist-cjs/canvas/sidebar-filters.js +2 -2
- package/dist-cjs/canvas/sidebar-filters.js.map +2 -2
- package/dist-cjs/canvas/state.js +28 -14
- package/dist-cjs/canvas/state.js.map +2 -2
- package/dist-cjs/canvas/thread-preview.js +185 -0
- package/dist-cjs/canvas/thread-preview.js.map +7 -0
- package/dist-cjs/canvas/thread-stack.js +199 -0
- package/dist-cjs/canvas/thread-stack.js.map +7 -0
- package/dist-cjs/canvas/thread-state.js +67 -21
- package/dist-cjs/canvas/thread-state.js.map +2 -2
- package/dist-cjs/canvas/thread-view.js +397 -0
- package/dist-cjs/canvas/thread-view.js.map +7 -0
- package/dist-cjs/clustering/computeClusterTable.js +4 -4
- package/dist-cjs/clustering/computeClusterTable.js.map +2 -2
- package/dist-cjs/clustering/runtime.js +119 -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 +763 -333
- package/dist-cjs/index.js +46 -28
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/ui/byline.js +6 -4
- 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 +137 -36
- package/dist-cjs/ui/comment-composer.js.map +2 -2
- package/dist-cjs/ui/comment-pin.js +24 -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 +30 -18
- 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 +4 -1
- package/dist-cjs/ui/format-time.js.map +2 -2
- package/dist-cjs/ui/reaction-picker.js +73 -0
- package/dist-cjs/ui/reaction-picker.js.map +7 -0
- package/dist-cjs/ui/reaction.js +59 -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 +20 -1
- package/dist-cjs/ui/send-button.js.map +2 -2
- package/dist-cjs/ui/{comment-text.js → tooltip-button.js} +12 -9
- package/dist-cjs/ui/tooltip-button.js.map +7 -0
- package/dist-esm/canvas/anchor-lifecycle.mjs +128 -0
- package/dist-esm/canvas/anchor-lifecycle.mjs.map +7 -0
- package/dist-esm/canvas/cluster-input.mjs +2 -2
- package/dist-esm/canvas/cluster-input.mjs.map +2 -2
- package/dist-esm/canvas/comment-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 +103 -0
- package/dist-esm/canvas/comment-mutations.mjs.map +7 -0
- package/dist-esm/canvas/comment-reactions.mjs +152 -0
- package/dist-esm/canvas/comment-reactions.mjs.map +7 -0
- package/dist-esm/canvas/comment-render.mjs +5 -3
- package/dist-esm/canvas/comment-render.mjs.map +2 -2
- package/dist-esm/canvas/comment-store.mjs +19 -9
- package/dist-esm/canvas/comment-store.mjs.map +2 -2
- package/dist-esm/canvas/comment-tool.mjs +67 -17
- package/dist-esm/canvas/comment-tool.mjs.map +2 -2
- package/dist-esm/canvas/comments-filter-menu.mjs +20 -38
- package/dist-esm/canvas/comments-filter-menu.mjs.map +2 -2
- package/dist-esm/canvas/comments-overflow-menu.mjs +23 -27
- package/dist-esm/canvas/comments-overflow-menu.mjs.map +2 -2
- package/dist-esm/canvas/comments-overlay.mjs +450 -479
- package/dist-esm/canvas/comments-overlay.mjs.map +3 -3
- package/dist-esm/canvas/comments-sidebar.mjs +38 -35
- package/dist-esm/canvas/comments-sidebar.mjs.map +2 -2
- package/dist-esm/canvas/comments-visibility-toggle.mjs +45 -0
- package/dist-esm/canvas/comments-visibility-toggle.mjs.map +7 -0
- package/dist-esm/canvas/context.mjs +1 -0
- package/dist-esm/canvas/context.mjs.map +7 -0
- package/dist-esm/canvas/hooks.mjs +28 -5
- package/dist-esm/canvas/hooks.mjs.map +2 -2
- package/dist-esm/canvas/options.mjs +21 -3
- package/dist-esm/canvas/options.mjs.map +2 -2
- package/dist-esm/canvas/pin-stacking.mjs +36 -0
- package/dist-esm/canvas/pin-stacking.mjs.map +7 -0
- package/dist-esm/canvas/sidebar-filters.mjs +2 -2
- package/dist-esm/canvas/sidebar-filters.mjs.map +2 -2
- package/dist-esm/canvas/state.mjs +29 -19
- package/dist-esm/canvas/state.mjs.map +2 -2
- package/dist-esm/canvas/thread-preview.mjs +170 -0
- package/dist-esm/canvas/thread-preview.mjs.map +7 -0
- package/dist-esm/canvas/thread-stack.mjs +190 -0
- package/dist-esm/canvas/thread-stack.mjs.map +7 -0
- package/dist-esm/canvas/thread-state.mjs +71 -22
- package/dist-esm/canvas/thread-state.mjs.map +2 -2
- package/dist-esm/canvas/thread-view.mjs +402 -0
- package/dist-esm/canvas/thread-view.mjs.map +7 -0
- package/dist-esm/clustering/computeClusterTable.mjs +4 -4
- package/dist-esm/clustering/computeClusterTable.mjs.map +2 -2
- package/dist-esm/clustering/runtime.mjs +119 -7
- package/dist-esm/clustering/runtime.mjs.map +2 -2
- package/dist-esm/index.d.mts +763 -333
- package/dist-esm/index.mjs +87 -41
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/ui/byline.mjs +6 -4
- package/dist-esm/ui/byline.mjs.map +2 -2
- package/dist-esm/ui/comment-card.mjs +15 -8
- package/dist-esm/ui/comment-card.mjs.map +2 -2
- package/dist-esm/ui/comment-composer.mjs +148 -36
- package/dist-esm/ui/comment-composer.mjs.map +2 -2
- package/dist-esm/ui/comment-pin.mjs +24 -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 +43 -29
- 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 +4 -1
- package/dist-esm/ui/format-time.mjs.map +2 -2
- package/dist-esm/ui/reaction-picker.mjs +60 -0
- package/dist-esm/ui/reaction-picker.mjs.map +7 -0
- package/dist-esm/ui/reaction.mjs +60 -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 +20 -1
- package/dist-esm/ui/send-button.mjs.map +2 -2
- package/dist-esm/ui/tooltip-button.mjs +12 -0
- package/dist-esm/ui/tooltip-button.mjs.map +7 -0
- package/package.json +6 -6
- package/src/canvas/anchor-lifecycle.test.ts +290 -0
- package/src/canvas/anchor-lifecycle.ts +205 -0
- package/src/canvas/canvas.css +461 -46
- package/src/canvas/cluster-input.test.ts +31 -23
- package/src/canvas/cluster-input.ts +3 -4
- 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 +410 -0
- package/src/canvas/comment-mutations.ts +288 -0
- package/src/canvas/comment-reactions.test.ts +132 -0
- package/src/canvas/comment-reactions.tsx +245 -0
- package/src/canvas/comment-render.test.ts +1 -1
- package/src/canvas/comment-render.ts +9 -5
- package/src/canvas/comment-store.ts +67 -27
- package/src/canvas/comment-tool.test.ts +162 -0
- package/src/canvas/comment-tool.tsx +105 -23
- package/src/canvas/comments-filter-menu.tsx +23 -32
- package/src/canvas/comments-overflow-menu.tsx +14 -21
- package/src/canvas/comments-overlay.tsx +695 -622
- package/src/canvas/comments-sidebar.test.ts +45 -0
- package/src/canvas/comments-sidebar.tsx +76 -58
- package/src/canvas/comments-visibility-toggle.tsx +49 -0
- package/src/canvas/context.ts +47 -0
- package/src/canvas/hooks.ts +52 -11
- package/src/canvas/options.test.ts +52 -2
- package/src/canvas/options.ts +133 -9
- package/src/canvas/pin-stacking.test.ts +114 -0
- package/src/canvas/pin-stacking.ts +57 -0
- package/src/canvas/sidebar-filters.ts +4 -3
- package/src/canvas/state.ts +92 -35
- package/src/canvas/thread-preview.test.ts +91 -0
- package/src/canvas/thread-preview.tsx +304 -0
- package/src/canvas/thread-stack.tsx +252 -0
- package/src/canvas/thread-state.test.ts +209 -0
- package/src/canvas/thread-state.ts +137 -36
- package/src/canvas/thread-view.tsx +516 -0
- package/src/clustering/computeClusterTable.test.ts +24 -23
- package/src/clustering/computeClusterTable.ts +5 -5
- package/src/clustering/runtime.test.ts +217 -7
- package/src/clustering/runtime.ts +171 -17
- package/src/clustering/types.ts +9 -9
- package/src/index.ts +76 -40
- package/src/ui/byline.tsx +7 -5
- package/src/ui/comment-card.tsx +20 -10
- package/src/ui/comment-composer.tsx +206 -40
- package/src/ui/comment-pin.tsx +26 -2
- package/src/ui/comment-thread.tsx +13 -6
- package/src/ui/comments-list.test.ts +31 -0
- package/src/ui/comments-list.tsx +45 -21
- package/src/ui/comments.css +566 -281
- 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.ts +7 -2
- package/src/ui/reaction-picker.tsx +109 -0
- package/src/ui/reaction.tsx +121 -6
- package/src/ui/reactions.tsx +69 -10
- package/src/ui/reply-count.ts +16 -0
- package/src/ui/send-button.tsx +18 -3
- package/src/ui/tooltip-button.tsx +20 -0
- package/dist-cjs/canvas/region-options.js +0 -49
- package/dist-cjs/canvas/region-options.js.map +0 -7
- package/dist-cjs/ui/avatar.js +0 -43
- 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,205 @@
|
|
|
1
|
+
import { WeakCache } from '@tldraw/utils'
|
|
2
|
+
import { Editor, TLCommentAnchor, TLCommentThread, TLPageId, TLShapeId, VecLike } from 'tldraw'
|
|
3
|
+
import { commitCommentMutation, putRecordsInCommit } from './comment-mutations'
|
|
4
|
+
import { getCommentRecord, getComments, getCommentThreads, TLCommentRecord } from './comment-store'
|
|
5
|
+
import { anchorPagePoint, impreciseShapePinInset } from './thread-state'
|
|
6
|
+
|
|
7
|
+
type ShapeAnchor = Extract<TLCommentAnchor, { type: 'shape' }>
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Threads converted to point anchors because their shape was deleted, kept so the anchor can be
|
|
11
|
+
* restored if the shape comes back (page move re-create, undo of the delete). Owned by the
|
|
12
|
+
* editor, not the registration closure: the registering effect can re-run (a prop identity
|
|
13
|
+
* change, a remount), and an undo can arrive arbitrarily long after the delete — the memory has
|
|
14
|
+
* to outlive any one registration.
|
|
15
|
+
*/
|
|
16
|
+
const convertedByShapeCache = new WeakCache<
|
|
17
|
+
Editor,
|
|
18
|
+
Map<TLShapeId, { threadId: string; anchor: ShapeAnchor; point: VecLike }[]>
|
|
19
|
+
>()
|
|
20
|
+
|
|
21
|
+
function isAnchoredToShape(
|
|
22
|
+
thread: TLCommentThread,
|
|
23
|
+
shapeId: TLShapeId
|
|
24
|
+
): thread is TLCommentThread & { anchor: ShapeAnchor } {
|
|
25
|
+
const anchor = thread.anchor
|
|
26
|
+
return anchor.type === 'shape' && anchor.shapeId === shapeId
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Keep shape-anchored threads alive across their shape's lifecycle:
|
|
31
|
+
*
|
|
32
|
+
* - When the shape is deleted, the thread converts to a `point` anchor at the spot its pin last
|
|
33
|
+
* occupied, so the conversation outlives the shape instead of becoming invisible (a missing
|
|
34
|
+
* shape has no bounds, which hides the pin).
|
|
35
|
+
* - When the shape moves to another page, the thread follows: its `pageId` and each comment's
|
|
36
|
+
* denormalized `pageId` update to the shape's new page, and the anchor keeps riding the shape.
|
|
37
|
+
* - When a deleted shape comes back (a page move re-creates it with its id preserved; undoing a
|
|
38
|
+
* delete restores it), the thread re-attaches — unless its pin was manually moved in the
|
|
39
|
+
* meantime, in which case the manual placement wins.
|
|
40
|
+
*
|
|
41
|
+
* A page move is `deleteShapes` + re-create with preserved ids inside one `editor.run`, but each
|
|
42
|
+
* store write is its own operation — so at no single moment does "this shape is being moved"
|
|
43
|
+
* exist as an observable event. The handlers therefore cooperate across operations:
|
|
44
|
+
* `beforeDelete` snapshots where each affected pin sits (every record is still in the store at
|
|
45
|
+
* that point, so page bounds resolve even for children of a deleted frame); the
|
|
46
|
+
* operation-complete pass converts threads whose shape is really gone, remembering the original
|
|
47
|
+
* anchor; `afterCreate` notes a reappeared shape id, and the operation-complete pass restores
|
|
48
|
+
* the anchor once the store has settled (creation order within an operation is arbitrary, so a
|
|
49
|
+
* fresh shape may not resolve an ancestor page mid-operation). Undo/redo of a move
|
|
50
|
+
* replays as a `parentId` update (remove + add of one id squash to an update in the history
|
|
51
|
+
* diff), so an `afterChange` handler re-homes threads on cross-page reparents — including
|
|
52
|
+
* threads anchored to descendants, which move with their parent without change events of their
|
|
53
|
+
* own.
|
|
54
|
+
*
|
|
55
|
+
* Remote changes are ignored: the client that performed the operation runs this same
|
|
56
|
+
* maintenance and syncs the resulting thread updates. Writes honour the
|
|
57
|
+
* {@link CommentingOptions.history} option, so the consumer decides whether they're undoable.
|
|
58
|
+
*
|
|
59
|
+
* Registered by `CanvasComments` on mount; parts-built consumers can call this directly.
|
|
60
|
+
* Returns a cleanup function that unregisters all handlers.
|
|
61
|
+
*
|
|
62
|
+
* @public
|
|
63
|
+
*/
|
|
64
|
+
export function registerCommentAnchorLifecycle(editor: Editor): () => void {
|
|
65
|
+
// Pin positions snapshotted during the current operation: shape id -> (thread id -> pin page
|
|
66
|
+
// point).
|
|
67
|
+
const pendingByShape = new Map<TLShapeId, Map<string, VecLike | null>>()
|
|
68
|
+
const convertedByShape = convertedByShapeCache.get(editor, () => new Map())
|
|
69
|
+
|
|
70
|
+
function rehomeThread(thread: TLCommentThread, pageId: TLPageId, updates: TLCommentRecord[]) {
|
|
71
|
+
updates.push({ ...thread, pageId })
|
|
72
|
+
for (const comment of getComments(editor)) {
|
|
73
|
+
if (comment.threadId === thread.id) updates.push({ ...comment, pageId })
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const disposeBeforeDelete = editor.sideEffects.registerBeforeDeleteHandler(
|
|
78
|
+
'shape',
|
|
79
|
+
(shape, source) => {
|
|
80
|
+
if (source === 'remote') return
|
|
81
|
+
for (const thread of getCommentThreads(editor)) {
|
|
82
|
+
if (!isAnchoredToShape(thread, shape.id)) continue
|
|
83
|
+
let snapshot = pendingByShape.get(shape.id)
|
|
84
|
+
if (!snapshot) {
|
|
85
|
+
snapshot = new Map()
|
|
86
|
+
pendingByShape.set(shape.id, snapshot)
|
|
87
|
+
}
|
|
88
|
+
// Snapshot where the pin is drawn, not just the anchor point: imprecise shape pins
|
|
89
|
+
// render inset toward the shape's centre, and the converted point pin renders at
|
|
90
|
+
// its point exactly — without the inset the pin would jump on deletion. The inset
|
|
91
|
+
// is screen-fixed, so bake it in at the current zoom.
|
|
92
|
+
let point = anchorPagePoint(editor, thread.anchor)
|
|
93
|
+
const inset = impreciseShapePinInset(editor, thread.anchor)
|
|
94
|
+
if (point && inset) {
|
|
95
|
+
const zoom = editor.getZoomLevel()
|
|
96
|
+
point = { x: point.x + inset.x / zoom, y: point.y + inset.y / zoom }
|
|
97
|
+
}
|
|
98
|
+
snapshot.set(thread.id, point)
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
// Shape ids from `convertedByShape` re-created during the current operation. Restores are
|
|
104
|
+
// settled at operation complete rather than in `afterCreate` itself: creation order within an
|
|
105
|
+
// operation is arbitrary, so a shape can appear before its parent and not resolve an ancestor
|
|
106
|
+
// page yet — and the conversion memory must outlive any such partial state.
|
|
107
|
+
const returnedShapeIds = new Set<TLShapeId>()
|
|
108
|
+
|
|
109
|
+
const disposeOperationComplete = editor.sideEffects.registerOperationCompleteHandler((source) => {
|
|
110
|
+
// Only user-sourced handlers populate the maps and only local operations should settle
|
|
111
|
+
// them; a remote operation completing leaves any (impossible-in-practice) leftovers for
|
|
112
|
+
// the next local settle rather than judging them against remote state.
|
|
113
|
+
if (source === 'remote') return
|
|
114
|
+
if (pendingByShape.size === 0 && returnedShapeIds.size === 0) return
|
|
115
|
+
const settled = [...pendingByShape.entries()]
|
|
116
|
+
pendingByShape.clear()
|
|
117
|
+
const returned = [...returnedShapeIds]
|
|
118
|
+
returnedShapeIds.clear()
|
|
119
|
+
|
|
120
|
+
const updates: TLCommentRecord[] = []
|
|
121
|
+
for (const [shapeId, threadPoints] of settled) {
|
|
122
|
+
if (editor.getShape(shapeId)) continue
|
|
123
|
+
for (const [threadId, point] of threadPoints) {
|
|
124
|
+
if (!point) continue
|
|
125
|
+
const thread = getCommentRecord(editor, threadId)
|
|
126
|
+
if (!thread || thread.typeName !== 'comment-thread') continue
|
|
127
|
+
if (!isAnchoredToShape(thread, shapeId)) continue
|
|
128
|
+
let converted = convertedByShape.get(shapeId)
|
|
129
|
+
if (!converted) {
|
|
130
|
+
converted = []
|
|
131
|
+
convertedByShape.set(shapeId, converted)
|
|
132
|
+
}
|
|
133
|
+
converted.push({ threadId, anchor: thread.anchor, point })
|
|
134
|
+
updates.push({ ...thread, anchor: { type: 'point', x: point.x, y: point.y } })
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
for (const shapeId of returned) {
|
|
139
|
+
const shape = editor.getShape(shapeId)
|
|
140
|
+
if (!shape) continue
|
|
141
|
+
const converted = convertedByShape.get(shapeId)
|
|
142
|
+
if (!converted) continue
|
|
143
|
+
convertedByShape.delete(shapeId)
|
|
144
|
+
|
|
145
|
+
const pageId = editor.getAncestorPageId(shape)
|
|
146
|
+
for (const { threadId, anchor, point } of converted) {
|
|
147
|
+
const thread = getCommentRecord(editor, threadId)
|
|
148
|
+
if (!thread || thread.typeName !== 'comment-thread') continue
|
|
149
|
+
// Re-attach only threads still sitting exactly where the conversion left them — a
|
|
150
|
+
// pin moved since then was placed deliberately, and that placement wins.
|
|
151
|
+
const current = thread.anchor
|
|
152
|
+
if (current.type !== 'point' || current.x !== point.x || current.y !== point.y) {
|
|
153
|
+
continue
|
|
154
|
+
}
|
|
155
|
+
if (!pageId || thread.pageId === pageId) {
|
|
156
|
+
updates.push({ ...thread, anchor })
|
|
157
|
+
} else {
|
|
158
|
+
rehomeThread({ ...thread, anchor }, pageId, updates)
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (updates.length > 0) {
|
|
164
|
+
commitCommentMutation(editor, () => putRecordsInCommit(editor, updates))
|
|
165
|
+
}
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
const disposeAfterCreate = editor.sideEffects.registerAfterCreateHandler(
|
|
169
|
+
'shape',
|
|
170
|
+
(shape, source) => {
|
|
171
|
+
if (source === 'remote') return
|
|
172
|
+
if (convertedByShape.has(shape.id)) returnedShapeIds.add(shape.id)
|
|
173
|
+
}
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
const disposeAfterChange = editor.sideEffects.registerAfterChangeHandler(
|
|
177
|
+
'shape',
|
|
178
|
+
(prev, next, source) => {
|
|
179
|
+
if (source === 'remote') return
|
|
180
|
+
if (prev.parentId === next.parentId) return
|
|
181
|
+
const pageId = editor.getAncestorPageId(next)
|
|
182
|
+
if (!pageId) return
|
|
183
|
+
// Descendants move with their parent without change events of their own.
|
|
184
|
+
const movedIds = editor.getShapeAndDescendantIds([next.id])
|
|
185
|
+
const updates: TLCommentRecord[] = []
|
|
186
|
+
for (const thread of getCommentThreads(editor)) {
|
|
187
|
+
const anchor = thread.anchor
|
|
188
|
+
if (anchor.type !== 'shape') continue
|
|
189
|
+
if (!movedIds.has(anchor.shapeId)) continue
|
|
190
|
+
if (thread.pageId === pageId) continue
|
|
191
|
+
rehomeThread(thread, pageId, updates)
|
|
192
|
+
}
|
|
193
|
+
if (updates.length > 0) {
|
|
194
|
+
commitCommentMutation(editor, () => putRecordsInCommit(editor, updates))
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
return () => {
|
|
200
|
+
disposeBeforeDelete()
|
|
201
|
+
disposeOperationComplete()
|
|
202
|
+
disposeAfterCreate()
|
|
203
|
+
disposeAfterChange()
|
|
204
|
+
}
|
|
205
|
+
}
|