@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
package/dist-esm/index.d.mts
CHANGED
|
@@ -1,14 +1,26 @@
|
|
|
1
|
+
import { Avatar } from '@tldraw/mentions';
|
|
2
|
+
import { AvatarProps } from '@tldraw/mentions';
|
|
3
|
+
import { CommentAuthor } from '@tldraw/mentions';
|
|
1
4
|
import { ComponentType } from 'react';
|
|
5
|
+
import { createMentionSuggestion } from '@tldraw/mentions';
|
|
2
6
|
import { Editor } from 'tldraw';
|
|
3
7
|
import { EditorAtom } from 'tldraw';
|
|
8
|
+
import { filterMentionMembers } from '@tldraw/mentions';
|
|
4
9
|
import { JSX } from 'react/jsx-runtime';
|
|
5
|
-
import
|
|
10
|
+
import { Mention } from '@tldraw/mentions';
|
|
11
|
+
import { MentionList } from '@tldraw/mentions';
|
|
12
|
+
import { MentionListProps } from '@tldraw/mentions';
|
|
13
|
+
import { MentionMember } from '@tldraw/mentions';
|
|
14
|
+
import { MentionProps } from '@tldraw/mentions';
|
|
15
|
+
import { MentionSuggestionOptions } from '@tldraw/mentions';
|
|
16
|
+
import { MouseEvent as MouseEvent_2 } from 'react';
|
|
6
17
|
import { ReactNode } from 'react';
|
|
7
18
|
import { StateNode } from 'tldraw';
|
|
8
|
-
import type { SuggestionOptions } from '@tiptap/suggestion';
|
|
9
19
|
import { TLComment } from 'tldraw';
|
|
10
20
|
import { TLCommentAnchor } from 'tldraw';
|
|
11
21
|
import { TLCommentId } from 'tldraw';
|
|
22
|
+
import { TLCommentReaction } from 'tldraw';
|
|
23
|
+
import { TLCommentReactionId } from 'tldraw';
|
|
12
24
|
import { TLCommentThread } from 'tldraw';
|
|
13
25
|
import { TLCommentThreadId } from 'tldraw';
|
|
14
26
|
import { TLHistoryBatchOptions } from 'tldraw';
|
|
@@ -19,193 +31,86 @@ import { TLUiOverrides } from 'tldraw';
|
|
|
19
31
|
import { VecLike } from 'tldraw';
|
|
20
32
|
|
|
21
33
|
/**
|
|
22
|
-
* Where a thread's pin sits on the page, for each anchor kind. Null hides the pin.
|
|
23
|
-
*
|
|
24
|
-
*
|
|
34
|
+
* Where a thread's pin sits on the page, for each anchor kind. Null hides the pin. Imprecise shape
|
|
35
|
+
* anchors use {@link CommentingOptions.impreciseShapeAnchor} rather than the stored `x`/`y`.
|
|
36
|
+
*
|
|
37
|
+
* A shape anchor's `x`/`y` are normalized within the shape's bounds and resolved through its page
|
|
38
|
+
* transform, so the pin rides rotation instead of being left behind in the bounding box.
|
|
25
39
|
* @public
|
|
26
40
|
*/
|
|
27
|
-
export declare function anchorPagePoint(editor: Editor, anchor: TLCommentAnchor
|
|
28
|
-
x: number;
|
|
29
|
-
y: number;
|
|
30
|
-
}): {
|
|
41
|
+
export declare function anchorPagePoint(editor: Editor, anchor: TLCommentAnchor): {
|
|
31
42
|
x: number;
|
|
32
43
|
y: number;
|
|
33
44
|
} | null;
|
|
34
45
|
|
|
35
|
-
|
|
36
|
-
* @public @react */
|
|
37
|
-
export declare function Avatar({ name, color, image }: AvatarProps): JSX.Element;
|
|
46
|
+
export { Avatar }
|
|
38
47
|
|
|
39
|
-
|
|
40
|
-
export declare interface AvatarProps {
|
|
41
|
-
name: string;
|
|
42
|
-
/** Background colour, used when there's no `image`. Falls back to the default avatar tint. */
|
|
43
|
-
color?: string;
|
|
44
|
-
/** Avatar image URL. When set, shows the image instead of the coloured initial. */
|
|
45
|
-
image?: string;
|
|
46
|
-
}
|
|
48
|
+
export { AvatarProps }
|
|
47
49
|
|
|
48
|
-
/**
|
|
50
|
+
/**
|
|
51
|
+
* A comment's metadata line: author name, relative time, and an edited marker. Hovering the time
|
|
52
|
+
* shows the full date and time in a tooltip.
|
|
53
|
+
* @public @react
|
|
54
|
+
*/
|
|
49
55
|
export declare function Byline({ author, date, edited }: BylineProps): JSX.Element;
|
|
50
56
|
|
|
51
57
|
/** @public */
|
|
52
58
|
export declare interface BylineProps {
|
|
53
|
-
author:
|
|
59
|
+
author: CommentAuthor;
|
|
54
60
|
/** ISO datetime; formatted to relative time by the component. */
|
|
55
61
|
date: string;
|
|
56
62
|
/** Shows an "edited" marker when the comment has been edited. */
|
|
57
63
|
edited?: boolean;
|
|
58
64
|
}
|
|
59
65
|
|
|
60
|
-
/** @public @react */
|
|
61
|
-
export declare function CanvasComments(props: CanvasCommentsProps): JSX.Element | null;
|
|
62
|
-
|
|
63
66
|
/**
|
|
64
67
|
* A ready-to-use comments layer for a tldraw canvas: pins each thread at its anchor, opens a
|
|
65
68
|
* thread popover (with a reply composer) on click, and shows a composer where the comment tool
|
|
66
69
|
* placed a new thread. Reads/writes comment records straight from `editor.store`.
|
|
67
70
|
*
|
|
68
|
-
* It's
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
71
|
+
* It's the batteries-included default: every visible piece is a slot on
|
|
72
|
+
* `CommentTool.configure({ components })`, and the pieces it composes (`CommentPin`,
|
|
73
|
+
* `CommentThread`, `CommentComposer`, the hooks, the tool) are all exported, so a consumer can
|
|
74
|
+
* rebuild it from parts instead. The host wiring is the {@link CommentingContext}, which
|
|
75
|
+
* `CanvasCommentsSidebar` takes too.
|
|
76
|
+
*
|
|
77
|
+
* @public @react
|
|
78
|
+
*/
|
|
79
|
+
export declare function CanvasComments(props: CanvasCommentsProps): JSX.Element | null;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* The host wiring for {@link CanvasComments} — see {@link CommentingContext}, which the sidebar
|
|
83
|
+
* takes the same fields from.
|
|
84
|
+
*
|
|
72
85
|
* @public
|
|
73
86
|
*/
|
|
74
|
-
export declare
|
|
75
|
-
/** The signed-in user's id, or null for a read-only viewer. Only a signed-in user composes. */
|
|
76
|
-
currentUserId: null | string;
|
|
77
|
-
/** Map an author id to a display name, or `undefined` when the id can't be named. */
|
|
78
|
-
resolveName(id: string): string | undefined;
|
|
79
|
-
/** Called after any comment (a new thread's first comment, or a reply) is posted. */
|
|
80
|
-
onPostComment?(comment: TLComment): void;
|
|
81
|
-
/** Whether a comment is unread for the current user (return true for unread). */
|
|
82
|
-
isCommentUnread?(commentId: TLCommentId): boolean;
|
|
83
|
-
/**
|
|
84
|
-
* Called for each unread comment shown to the user in an open thread popover, so hosts can
|
|
85
|
-
* record a read receipt. Needs `isCommentUnread` to know what's unread.
|
|
86
|
-
*/
|
|
87
|
-
onCommentRead?(commentId: TLCommentId): void;
|
|
88
|
-
/** Resolve the members matching an `@`-query in the composers (sync or async). */
|
|
89
|
-
getMentionSuggestions?(query: string): MentionMember[] | Promise<MentionMember[]>;
|
|
90
|
-
/** Override a mention-picker row's content. */
|
|
91
|
-
renderMentionSuggestion?(member: MentionMember): ReactNode;
|
|
92
|
-
/** Where imprecise shape pins sit — a normalized (0–1) spot within the shape. Default top-right. */
|
|
93
|
-
impreciseShapeAnchor?: {
|
|
94
|
-
x: number;
|
|
95
|
-
y: number;
|
|
96
|
-
};
|
|
97
|
-
/** Region comment behaviour. Region is off by default — omit this for click-only point/shape
|
|
98
|
-
* comments. Anything unset falls back to {@link DEFAULT_REGION_COMMENT_OPTIONS}. */
|
|
99
|
-
regionOptions?: Partial<RegionCommentOptions>;
|
|
100
|
-
}
|
|
87
|
+
export declare type CanvasCommentsProps = CommentingContext;
|
|
101
88
|
|
|
102
89
|
/**
|
|
103
|
-
* A comments list panel for the current page, shown while
|
|
104
|
-
* thread brings its pin into view and opens it. Batteries-included
|
|
105
|
-
* `CanvasComments`); `CommentsList` is exported for a differently-placed
|
|
90
|
+
* A comments list panel for the current page, shown while {@link commentsSidebarOpen} is set (e.g.
|
|
91
|
+
* toggled by a button). Clicking a thread brings its pin into view and opens it. Batteries-included
|
|
92
|
+
* over the store (a sibling to `CanvasComments`); `CommentsList` is exported for a differently-placed
|
|
93
|
+
* or always-on list.
|
|
106
94
|
* @public @react
|
|
107
95
|
*/
|
|
108
96
|
export declare function CanvasCommentsSidebar(props: CanvasCommentsSidebarProps): JSX.Element | null;
|
|
109
97
|
|
|
110
|
-
/**
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
*/
|
|
120
|
-
isCommentUnread?(commentId: TLCommentId): boolean;
|
|
121
|
-
/** Tool ids that show the sidebar. Defaults to the comment tool. */
|
|
122
|
-
tools?: string[];
|
|
98
|
+
/**
|
|
99
|
+
* The host wiring for {@link CanvasCommentsSidebar}: the {@link CommentingContext} fields it reads,
|
|
100
|
+
* plus the panel's own slots. A non-null `currentUserId` enables the "only your threads" filter, and
|
|
101
|
+
* an `isCommentUnread` the "only unread" one. `CanvasComments` takes the same fields, so a host
|
|
102
|
+
* mounting both can spread one object into each.
|
|
103
|
+
*
|
|
104
|
+
* @public
|
|
105
|
+
*/
|
|
106
|
+
export declare interface CanvasCommentsSidebarProps extends Pick<CommentingContext, 'currentUserId' | 'getThreadHref' | 'isCommentUnread' | 'resolveAuthor'> {
|
|
123
107
|
/** Header above the list. */
|
|
124
108
|
header?: ReactNode;
|
|
125
109
|
/** Shown when the page has no threads. */
|
|
126
110
|
empty?: ReactNode;
|
|
127
|
-
/** Where imprecise shape pins sit, so navigation centres on the same spot. Default top-right. */
|
|
128
|
-
impreciseShapeAnchor?: {
|
|
129
|
-
x: number;
|
|
130
|
-
y: number;
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* A cluster in the merge tree: a leaf (one thread) or a merged group.
|
|
136
|
-
* @public
|
|
137
|
-
*/
|
|
138
|
-
export declare interface ClusterNode {
|
|
139
|
-
/** Leaves: the thread id verbatim. Merged nodes: `cluster:${count}:${minMemberId}`. */
|
|
140
|
-
id: string;
|
|
141
|
-
/** Page space; count-weighted mean of all member leaf anchors. */
|
|
142
|
-
centroid: VecLike;
|
|
143
|
-
/** Number of member leaves. Leaves = 1. */
|
|
144
|
-
count: number;
|
|
145
|
-
/** All member thread ids, sorted lexicographically ascending. */
|
|
146
|
-
members: string[];
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
/** @public */
|
|
150
|
-
export declare interface ClusterOptions {
|
|
151
|
-
/** Cluster (merge) distance, screen px. Default 40. */
|
|
152
|
-
Tc?: number;
|
|
153
|
-
/** Uncluster (split) distance, screen px. Must be \> Tc. Default 1.5 · Tc. */
|
|
154
|
-
Tu?: number;
|
|
155
|
-
/** Contraction window ratio. Default 0.12. */
|
|
156
|
-
eps?: number;
|
|
157
|
-
/** Max cluster screen extent at birth, screen px. Must be \>= Tc. Default 3 · Tc. */
|
|
158
|
-
Dmax?: number;
|
|
159
|
-
/** Camera zoom bounds — pass the editor's camera constraints. Required. */
|
|
160
|
-
minZoom: number;
|
|
161
|
-
maxZoom: number;
|
|
162
|
-
/**
|
|
163
|
-
* Zoom by which every cluster has split, no matter how close its members are — including
|
|
164
|
-
* coincident anchors, which otherwise never split. Merge thresholds are capped at
|
|
165
|
-
* `maxSplitZoom / (Tu/Tc)` so the hysteresis band keeps its shape below the cap.
|
|
166
|
-
* Default 6 (600%).
|
|
167
|
-
*/
|
|
168
|
-
maxSplitZoom?: number;
|
|
169
111
|
}
|
|
170
112
|
|
|
171
|
-
|
|
172
|
-
export declare interface ClusterRuntime {
|
|
173
|
-
/** Events[0..k) are active. Exposed for tests and debugging. */
|
|
174
|
-
readonly k: number;
|
|
175
|
-
/** Reset state from scratch for the given zoom (cold start / after rebuild). */
|
|
176
|
-
seed(zoom: number): void;
|
|
177
|
-
/**
|
|
178
|
-
* Reset state for the given zoom, carrying hysteresis state over from a previous partition
|
|
179
|
-
* (the visible map of the model being replaced). Threshold-forced events ignore history:
|
|
180
|
-
* zoom \<= zMerge is always active, zoom \>= zSplit always inactive. An event inside its band
|
|
181
|
-
* is active iff its members were merged together in `previous`; a band event with no history
|
|
182
|
-
* (e.g. introduced by the rebuild) stays inactive until the next zoom-out crosses its zMerge.
|
|
183
|
-
* Active events must form a prefix of the table, so classification stops at the first
|
|
184
|
-
* inactive event; later band-active events conservatively resolve to split.
|
|
185
|
-
*/
|
|
186
|
-
seedFrom(zoom: number, previous: ReadonlyMap<string, ClusterNode>): void;
|
|
187
|
-
/** Advance/retreat the cursor for a camera change. No-op if zoom sits inside all bands. */
|
|
188
|
-
onCamera(zoom: number): void;
|
|
189
|
-
/** The current partition: cluster id → node. Do not mutate. */
|
|
190
|
-
getVisible(): ReadonlyMap<string, ClusterNode>;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
/**
|
|
194
|
-
* The precomputed clustering schedule for one page's comments.
|
|
195
|
-
* @public
|
|
196
|
-
*/
|
|
197
|
-
export declare interface ClusterTable {
|
|
198
|
-
/** Sorted non-increasing by zMerge; satisfies the invariants of CLUSTERING.md §7.6. */
|
|
199
|
-
events: readonly MergeEvent[];
|
|
200
|
-
/** One node per input leaf, in input order. */
|
|
201
|
-
leaves: readonly ClusterNode[];
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
/** @public */
|
|
205
|
-
export declare function collectClusterLeaves(editor: Editor, threads: readonly TLCommentThread[], openThreadId: null | string, impreciseShapeAnchor?: {
|
|
206
|
-
x: number;
|
|
207
|
-
y: number;
|
|
208
|
-
}): LeafInput[];
|
|
113
|
+
export { CommentAuthor }
|
|
209
114
|
|
|
210
115
|
/**
|
|
211
116
|
* Renders a comment's rich-text body read-only through the limited comment extension set (no
|
|
@@ -223,13 +128,13 @@ export declare interface CommentBodyProps {
|
|
|
223
128
|
}
|
|
224
129
|
|
|
225
130
|
/** A single comment: Avatar, Byline, and a body slot the consumer renders. @public @react */
|
|
226
|
-
export declare function CommentCard({ author, body, date, you, edited, actions }: CommentCardProps): JSX.Element;
|
|
131
|
+
export declare function CommentCard({ author, body, date, you, edited, actions, footer }: CommentCardProps): JSX.Element;
|
|
227
132
|
|
|
228
133
|
/** @public */
|
|
229
134
|
export declare interface CommentCardProps {
|
|
230
|
-
author:
|
|
231
|
-
/** The rendered comment body. The card doesn't dictate a format — pass a `<
|
|
232
|
-
* for
|
|
135
|
+
author: CommentAuthor;
|
|
136
|
+
/** The rendered comment body. The card doesn't dictate a format — pass a `<CommentBody>`
|
|
137
|
+
* for a comment's rich text, or any node of your own. */
|
|
233
138
|
body: ReactNode;
|
|
234
139
|
/** ISO datetime; formatted to relative time by the component. */
|
|
235
140
|
date: string;
|
|
@@ -238,6 +143,8 @@ export declare interface CommentCardProps {
|
|
|
238
143
|
edited?: boolean;
|
|
239
144
|
/** Hover-revealed controls at the card's top-right (e.g. an edit affordance). */
|
|
240
145
|
actions?: ReactNode;
|
|
146
|
+
/** Content under the body, aligned with it rather than the avatar (e.g. a `<Reactions>` row). */
|
|
147
|
+
footer?: ReactNode;
|
|
241
148
|
}
|
|
242
149
|
|
|
243
150
|
/**
|
|
@@ -247,11 +154,11 @@ export declare interface CommentCardProps {
|
|
|
247
154
|
* floating toolbar. Presentational by default; pass value/onChange/onSubmit to drive it as a form.
|
|
248
155
|
* @public @react
|
|
249
156
|
*/
|
|
250
|
-
export declare function CommentComposer({ author, placeholder, value, onChange, onSubmit, sendLabel, disabled, autoFocus, leading, getMentionSuggestions, renderMentionSuggestion }: CommentComposerProps): JSX.Element;
|
|
157
|
+
export declare function CommentComposer({ author, placeholder, value, onChange, onSubmit, sendLabel, onArrowUpWhenEmpty, disabled, autoFocus, leading, getMentionSuggestions, renderMentionSuggestion }: CommentComposerProps): JSX.Element;
|
|
251
158
|
|
|
252
159
|
/** @public */
|
|
253
160
|
export declare interface CommentComposerProps {
|
|
254
|
-
author:
|
|
161
|
+
author: CommentAuthor;
|
|
255
162
|
placeholder: string;
|
|
256
163
|
/** Controlled rich-text value. Omit for the presentational (display-only) composer. */
|
|
257
164
|
value?: TLRichText;
|
|
@@ -259,6 +166,9 @@ export declare interface CommentComposerProps {
|
|
|
259
166
|
/** Called on Send click or Enter. When set, the composer is interactive. */
|
|
260
167
|
onSubmit?(): void;
|
|
261
168
|
sendLabel?: string;
|
|
169
|
+
/** Called when Up is pressed in an empty composer — e.g. to start editing the comment above,
|
|
170
|
+
* the way chat apps edit your last message. With content in the field, Up moves the cursor. */
|
|
171
|
+
onArrowUpWhenEmpty?(): void;
|
|
262
172
|
disabled?: boolean;
|
|
263
173
|
autoFocus?: boolean;
|
|
264
174
|
/** The leading element before the field. Defaults to the author's avatar. */
|
|
@@ -289,12 +199,104 @@ export declare interface CommentingComponents {
|
|
|
289
199
|
ThreadPreview?: ComponentType<{
|
|
290
200
|
comment: TLComment;
|
|
291
201
|
}>;
|
|
202
|
+
/**
|
|
203
|
+
* A whole sidebar row. Replaces the default `<CommentListItem>`, which is exported — so a row
|
|
204
|
+
* that only adds an unread dot or a status chip can spread these props into it. Use
|
|
205
|
+
* `ThreadPreview` instead when only the preview text is changing.
|
|
206
|
+
*/
|
|
207
|
+
ThreadRow?: ComponentType<CommentListItemRenderProps & {
|
|
208
|
+
thread: TLCommentThread;
|
|
209
|
+
}>;
|
|
210
|
+
/**
|
|
211
|
+
* Extra controls in an open thread's header, added ahead of the built-in resolve and dismiss
|
|
212
|
+
* buttons rather than replacing them. "Copy link" is already built in whenever the host supplies
|
|
213
|
+
* `getThreadHref`.
|
|
214
|
+
*/
|
|
215
|
+
ThreadActions?: ComponentType<{
|
|
216
|
+
comments: TLComment[];
|
|
217
|
+
thread: TLCommentThread;
|
|
218
|
+
}>;
|
|
219
|
+
/**
|
|
220
|
+
* A reaction's visual, given its token. The default renders the token string for the OS emoji
|
|
221
|
+
* font. Override to draw a custom palette — an `<img>`, an SVG, anything. The token is what gets
|
|
222
|
+
* stored and synced; this only controls how it's drawn.
|
|
223
|
+
*/
|
|
224
|
+
ReactionContent?: ComponentType<{
|
|
225
|
+
token: string;
|
|
226
|
+
}>;
|
|
227
|
+
/**
|
|
228
|
+
* What the add-reaction button opens. Replaces the default `<EmojiPicker>` grid. Pairs with
|
|
229
|
+
* `ReactionContent` (which draws the tokens this emits) and `isAllowedReaction` (which must
|
|
230
|
+
* accept them).
|
|
231
|
+
*/
|
|
232
|
+
ReactionPalette?: ComponentType<EmojiPickerProps>;
|
|
233
|
+
/**
|
|
234
|
+
* The hover affordance naming who reacted with an emoji. Receives the reactors and the pill (as
|
|
235
|
+
* `children`) and owns the whole thing — box, size, shape, position. For a wording change,
|
|
236
|
+
* translate the `comments.reacted-*` strings instead.
|
|
237
|
+
*/
|
|
238
|
+
ReactionTooltip?: ComponentType<ReactionTooltipProps>;
|
|
239
|
+
/**
|
|
240
|
+
* Shown where a composer would sit when the viewer can't compose (see
|
|
241
|
+
* {@link CommentingOptions.canComment}). `context` is the surface rendering it: an open thread
|
|
242
|
+
* popover (`'thread'`) or the comment tool's placement popover (`'pending'`). Unset, those
|
|
243
|
+
* surfaces render nothing.
|
|
244
|
+
*/
|
|
245
|
+
ComposerFallback?: ComponentType<{
|
|
246
|
+
context: 'pending' | 'thread';
|
|
247
|
+
}>;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* The live, host-supplied half of commenting: who the viewer is, how author ids become names, read
|
|
252
|
+
* status, and the mention roster. (The static half is {@link CommentingOptions}, configured once on
|
|
253
|
+
* the tool.)
|
|
254
|
+
*
|
|
255
|
+
* Every commenting surface reads the same set, so a host mounting more than one — `CanvasComments`
|
|
256
|
+
* and `CanvasCommentsSidebar`, say — can build it once and spread it into each rather than
|
|
257
|
+
* repeating the props:
|
|
258
|
+
*
|
|
259
|
+
* ```tsx
|
|
260
|
+
* const commenting: CommentingContext = { currentUserId, resolveAuthor, isCommentUnread }
|
|
261
|
+
*
|
|
262
|
+
* <CanvasComments {...commenting} />
|
|
263
|
+
* <CanvasCommentsSidebar {...commenting} />
|
|
264
|
+
* ```
|
|
265
|
+
*
|
|
266
|
+
* @public
|
|
267
|
+
*/
|
|
268
|
+
export declare interface CommentingContext {
|
|
269
|
+
/** The signed-in user's id, or null for a read-only viewer. Only a signed-in user composes. */
|
|
270
|
+
currentUserId: null | string;
|
|
271
|
+
/** Map an author id to their display info, or `undefined` when the id can't be resolved. */
|
|
272
|
+
resolveAuthor(id: string): CommentAuthor | undefined;
|
|
273
|
+
/** Called after any comment (a new thread's first comment, or a reply) is posted. */
|
|
274
|
+
onPostComment?(comment: TLComment): void;
|
|
275
|
+
/** Whether a comment is unread for the current user (return true for unread). */
|
|
276
|
+
isCommentUnread?(commentId: TLCommentId): boolean;
|
|
277
|
+
/**
|
|
278
|
+
* Called with every unread comment shown to the user in an open thread popover, batched per
|
|
279
|
+
* report, so hosts can record read receipts without a write per comment. Needs
|
|
280
|
+
* `isCommentUnread` to know what's unread.
|
|
281
|
+
*/
|
|
282
|
+
onCommentsRead?(commentIds: TLCommentId[]): void;
|
|
283
|
+
/** Resolve the members matching an `@`-query in the composers (sync or async). */
|
|
284
|
+
getMentionSuggestions?(query: string): MentionMember[] | Promise<MentionMember[]>;
|
|
285
|
+
/** Override a mention-picker row's content. */
|
|
286
|
+
renderMentionSuggestion?(member: MentionMember): ReactNode;
|
|
287
|
+
/**
|
|
288
|
+
* The host's URL for a thread, so surfaces can link to it — e.g. the sidebar's rows render as
|
|
289
|
+
* anchors when this is present, letting ctrl/cmd-click and middle-click open the thread in a
|
|
290
|
+
* new tab (a plain click still selects the thread in place; the href isn't followed).
|
|
291
|
+
*/
|
|
292
|
+
getThreadHref?(threadId: TLCommentThreadId): string | undefined;
|
|
292
293
|
}
|
|
293
294
|
|
|
294
295
|
/**
|
|
295
296
|
* Configuration for the commenting layer. Static config only — pass it once via
|
|
296
297
|
* `CommentTool.configure({ ... })`, mirroring `ShapeUtil.configure`. Live, reactive values
|
|
297
|
-
* (`currentUserId`,
|
|
298
|
+
* (`currentUserId`, author resolution, read-status callbacks) are the `CommentingContext`, passed as
|
|
299
|
+
* props to each commenting surface.
|
|
298
300
|
*
|
|
299
301
|
* For defaults, see {@link defaultCommentingOptions}.
|
|
300
302
|
*
|
|
@@ -307,11 +309,9 @@ export declare interface CommentingComponents {
|
|
|
307
309
|
*/
|
|
308
310
|
export declare interface CommentingOptions {
|
|
309
311
|
/**
|
|
310
|
-
* How comment mutations
|
|
311
|
-
*
|
|
312
|
-
*
|
|
313
|
-
* already removed, and undoing a resolve/edit reverts their newer state. Safe only single-player
|
|
314
|
-
* or on a non-synced local comment store.
|
|
312
|
+
* How comment mutations interact with the editor undo stack. Defaults to `'ignore'` — comments
|
|
313
|
+
* are deliberately not undoable (see `TLComment`). `'record'` is a multiplayer footgun: undoing
|
|
314
|
+
* a delete resurrects a thread a collaborator already removed. Safe only single-player.
|
|
315
315
|
*/
|
|
316
316
|
readonly history: TLHistoryBatchOptions['history'];
|
|
317
317
|
/**
|
|
@@ -321,23 +321,89 @@ export declare interface CommentingOptions {
|
|
|
321
321
|
readonly dragHistory: TLHistoryBatchOptions['history'] | undefined;
|
|
322
322
|
/** Fold nearby pins into count badges as the camera zooms out. */
|
|
323
323
|
readonly enableClustering: boolean;
|
|
324
|
+
/**
|
|
325
|
+
* Whether a user may hold several emoji reactions on one comment. `true` (the default) is the
|
|
326
|
+
* Slack model: each emoji toggles independently. `false` is single-select: picking a new emoji
|
|
327
|
+
* replaces the user's existing reaction. Note this is enforced client-side; the server accepts
|
|
328
|
+
* per-emoji records either way.
|
|
329
|
+
*/
|
|
330
|
+
readonly allowMultipleReactions: boolean;
|
|
331
|
+
/**
|
|
332
|
+
* Whether a token may be added as a reaction. Defaults to {@link isAllowedReactionEmoji}, which
|
|
333
|
+
* keeps a scripted client from writing junk values the picker would never offer. Override
|
|
334
|
+
* alongside a custom `ReactionPalette`. Removals aren't checked — an off-palette reaction must
|
|
335
|
+
* still be clearable.
|
|
336
|
+
*/
|
|
337
|
+
isAllowedReaction(token: string): boolean;
|
|
338
|
+
/**
|
|
339
|
+
* Whether dragging the comment tool out creates a region anchor — a comment attached to a
|
|
340
|
+
* rectangular area, drawn as a dashed box with the pin on the corner the drag released on. Off
|
|
341
|
+
* by default, where comments attach to points and shapes only and a drag trails the composer.
|
|
342
|
+
*/
|
|
343
|
+
readonly enableRegions: boolean;
|
|
344
|
+
/**
|
|
345
|
+
* Whether the viewer may participate in commenting: composing, editing, deleting, resolving, and
|
|
346
|
+
* moving pins. When false, {@link CommentingComponents.ComposerFallback} renders in the
|
|
347
|
+
* composer's place and action affordances are hidden. Unset, participation is allowed exactly
|
|
348
|
+
* when `currentUserId` is set.
|
|
349
|
+
*
|
|
350
|
+
* Called during render via {@link useCanComment}, so signal reads are tracked. Posting still
|
|
351
|
+
* needs a `currentUserId`, so returning true for a signed-out viewer yields a composer whose
|
|
352
|
+
* send button stays disabled. A callback that throws is logged and read as false, rather than
|
|
353
|
+
* taking the comments layer down with it.
|
|
354
|
+
*/
|
|
355
|
+
readonly canComment: ((ctx: {
|
|
356
|
+
currentUserId: null | string;
|
|
357
|
+
editor: Editor;
|
|
358
|
+
}) => boolean) | undefined;
|
|
359
|
+
/**
|
|
360
|
+
* Whether the viewer may make a particular write against a particular record: editing or
|
|
361
|
+
* deleting a comment, or deleting a thread. Unset, each is its record's owner's to make
|
|
362
|
+
* ({@link defaultCanModifyComment}) — you edit and delete your own comments, and delete threads
|
|
363
|
+
* you started. Override it to widen that (a workspace admin or moderator who may remove
|
|
364
|
+
* anyone's comment) or to narrow it (no edits after an hour). Where it returns false the
|
|
365
|
+
* affordance isn't rendered.
|
|
366
|
+
*
|
|
367
|
+
* Checked after {@link CommentingOptions.canComment}, which gates commenting as a whole: a
|
|
368
|
+
* viewer who may not participate gets no action affordances at all, whatever this returns.
|
|
369
|
+
*
|
|
370
|
+
* Called during render via {@link useCanModifyComment}, so reactive reads (signals) are tracked.
|
|
371
|
+
* A callback that throws is logged and read as false: an affordance is withheld rather than the
|
|
372
|
+
* comments layer lost, and a denial is what a server enforcing the same rule would have said.
|
|
373
|
+
*
|
|
374
|
+
* @example
|
|
375
|
+
* ```tsx
|
|
376
|
+
* CommentTool.configure({
|
|
377
|
+
* canModifyComment: (ctx) =>
|
|
378
|
+
* // Moderators may delete anything; everything else stays the owner's to do.
|
|
379
|
+
* (ctx.action !== 'edit-comment' && isModerator(ctx.currentUserId)) ||
|
|
380
|
+
* defaultCanModifyComment(ctx),
|
|
381
|
+
* })
|
|
382
|
+
* ```
|
|
383
|
+
*/
|
|
384
|
+
readonly canModifyComment: ((ctx: CommentModificationContext) => boolean) | undefined;
|
|
324
385
|
/** Normalized (0–1) spot within a shape where imprecise shape pins sit. Default top-right. */
|
|
325
386
|
readonly impreciseShapeAnchor: {
|
|
326
387
|
readonly x: number;
|
|
327
388
|
readonly y: number;
|
|
328
389
|
};
|
|
329
|
-
/**
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
390
|
+
/**
|
|
391
|
+
* Whether a comment landing on a shape pins to the exact clicked spot, or to the shape as a
|
|
392
|
+
* whole (rendered at `impreciseShapeAnchor`). Always precise by default; return `false`, or
|
|
393
|
+
* decide from the context. Governs new placements only — existing anchors render as stored.
|
|
394
|
+
*/
|
|
395
|
+
shouldBePrecise(editor: Editor, context: ShapeCommentPrecisionContext): boolean;
|
|
333
396
|
/** Component overrides. See {@link CommentingComponents}. */
|
|
334
397
|
readonly components: CommentingComponents;
|
|
335
398
|
}
|
|
336
399
|
|
|
400
|
+
/** One thread's row in a {@link CommentsList}. @public @react */
|
|
401
|
+
export declare function CommentListItem({ id, author, preview, date, resolved, page, count, selected, reactions, href, resolvedLabel, onSelect }: CommentListItemRenderProps): JSX.Element;
|
|
402
|
+
|
|
337
403
|
/** @public */
|
|
338
404
|
export declare interface CommentListItemProps {
|
|
339
405
|
id: string;
|
|
340
|
-
author:
|
|
406
|
+
author: CommentAuthor;
|
|
341
407
|
/** A short preview of the thread — e.g. the first comment's body. */
|
|
342
408
|
preview: ReactNode;
|
|
343
409
|
/** ISO datetime of the thread's first comment. */
|
|
@@ -349,8 +415,61 @@ export declare interface CommentListItemProps {
|
|
|
349
415
|
count?: number;
|
|
350
416
|
/** Whether this thread is the open one. */
|
|
351
417
|
selected?: boolean;
|
|
418
|
+
/** Tallied reactions for the row (a thread's, or a single comment's when the row is one
|
|
419
|
+
* comment), shown as inert pills under the preview. Omit to hide. */
|
|
420
|
+
reactions?: ReactionSummary[];
|
|
421
|
+
/**
|
|
422
|
+
* Link target for the item. When set, the row renders as an anchor so browser affordances
|
|
423
|
+
* (ctrl/cmd-click, middle-click) open it in a new tab; a plain click still calls `onSelect`.
|
|
424
|
+
*/
|
|
425
|
+
href?: string;
|
|
352
426
|
}
|
|
353
427
|
|
|
428
|
+
/**
|
|
429
|
+
* What a row is rendered with: the item, plus the list-level wiring it needs to be interactive.
|
|
430
|
+
* A custom row gets the same props the default `<CommentListItem>` does, so it can wrap the
|
|
431
|
+
* default rather than reimplement it.
|
|
432
|
+
*
|
|
433
|
+
* @public
|
|
434
|
+
*/
|
|
435
|
+
export declare interface CommentListItemRenderProps extends CommentListItemProps {
|
|
436
|
+
/** Label for a resolved thread's marker on its row. */
|
|
437
|
+
resolvedLabel?: string;
|
|
438
|
+
/** Called with the thread id when the row is chosen. */
|
|
439
|
+
onSelect?(id: string): void;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* A commenting write that belongs to someone in particular, and the record it targets — the
|
|
444
|
+
* argument to {@link CommentingOptions.canModifyComment}.
|
|
445
|
+
*
|
|
446
|
+
* Resolving, reopening, reacting, and moving a pin aren't here: none of them is anyone's in
|
|
447
|
+
* particular, so {@link CommentingOptions.canComment} is the only gate on them.
|
|
448
|
+
*
|
|
449
|
+
* @public
|
|
450
|
+
*/
|
|
451
|
+
export declare type CommentModification = {
|
|
452
|
+
readonly action: 'delete-comment';
|
|
453
|
+
readonly comment: TLComment;
|
|
454
|
+
} | {
|
|
455
|
+
readonly action: 'delete-thread';
|
|
456
|
+
readonly thread: TLCommentThread;
|
|
457
|
+
} | {
|
|
458
|
+
readonly action: 'edit-comment';
|
|
459
|
+
readonly comment: TLComment;
|
|
460
|
+
};
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* The argument to {@link CommentingOptions.canModifyComment}: which write, against which record,
|
|
464
|
+
* and by whom.
|
|
465
|
+
*
|
|
466
|
+
* @public
|
|
467
|
+
*/
|
|
468
|
+
export declare type CommentModificationContext = {
|
|
469
|
+
readonly currentUserId: null | string;
|
|
470
|
+
readonly editor: Editor;
|
|
471
|
+
} & CommentModification;
|
|
472
|
+
|
|
354
473
|
/** A canvas comment marker: shows its `children` (or a check when resolved). Purely
|
|
355
474
|
* presentational — it reflects open/resolved state via CSS; wrap it to make it clickable.
|
|
356
475
|
* @public @react */
|
|
@@ -366,6 +485,39 @@ export declare interface CommentPinProps {
|
|
|
366
485
|
open?: boolean;
|
|
367
486
|
}
|
|
368
487
|
|
|
488
|
+
/**
|
|
489
|
+
* The add-reaction button for one comment. Belongs with the comment card's hover actions rather
|
|
490
|
+
* than in the reaction row, so opening it doesn't chase the row as reactions are added.
|
|
491
|
+
* @public @react
|
|
492
|
+
*/
|
|
493
|
+
export declare function CommentReactionPicker({ comment, currentUserId, emoji }: CommentReactionPickerProps): JSX.Element | null;
|
|
494
|
+
|
|
495
|
+
/** @public */
|
|
496
|
+
export declare interface CommentReactionPickerProps {
|
|
497
|
+
comment: TLComment;
|
|
498
|
+
/** The reacting user. Null/omitted renders nothing — there's nobody to react as. */
|
|
499
|
+
currentUserId?: null | string;
|
|
500
|
+
/** The emoji the picker offers. Defaults to `DEFAULT_REACTION_EMOJI`. */
|
|
501
|
+
emoji?: string[];
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* The tallied reaction row under one comment. Pair with `CommentReactionPicker`, which is what
|
|
506
|
+
* adds a reaction.
|
|
507
|
+
* @public @react
|
|
508
|
+
*/
|
|
509
|
+
export declare function CommentReactions({ comment, currentUserId, resolveName }: CommentReactionsProps): JSX.Element;
|
|
510
|
+
|
|
511
|
+
/** @public */
|
|
512
|
+
export declare interface CommentReactionsProps {
|
|
513
|
+
comment: TLComment;
|
|
514
|
+
/** The reacting user. Null/omitted gives a read-only row (signed out): counts show, but the
|
|
515
|
+
* pills don't toggle. */
|
|
516
|
+
currentUserId?: null | string;
|
|
517
|
+
/** Names a reactor id for the hover list. Ids it can't name fall back to a generic "Someone". */
|
|
518
|
+
resolveName?(userId: string): string | undefined;
|
|
519
|
+
}
|
|
520
|
+
|
|
369
521
|
/** The funnel dropdown in the sidebar header: toggles for which threads the list shows.
|
|
370
522
|
* @public @react */
|
|
371
523
|
export declare function CommentsFilterMenu({ canFilterByAuthor, canFilterByUnread }: CommentsFilterMenuProps): JSX.Element;
|
|
@@ -406,8 +558,12 @@ export declare interface CommentsListProps {
|
|
|
406
558
|
empty?: ReactNode;
|
|
407
559
|
/** Label for a resolved thread's marker on its row. Defaults to "Resolved". */
|
|
408
560
|
resolvedLabel?: string;
|
|
409
|
-
/**
|
|
410
|
-
|
|
561
|
+
/**
|
|
562
|
+
* Override how each item renders. Defaults to `<CommentListItem>`, which is exported — so a
|
|
563
|
+
* row that only adds something can spread these props into it rather than start over. The list
|
|
564
|
+
* supplies the key, so a custom row doesn't need one.
|
|
565
|
+
*/
|
|
566
|
+
renderItem?(props: CommentListItemRenderProps): ReactNode;
|
|
411
567
|
}
|
|
412
568
|
|
|
413
569
|
/**
|
|
@@ -424,14 +580,17 @@ export declare function CommentsMenuItem(): JSX.Element;
|
|
|
424
580
|
* @public @react */
|
|
425
581
|
export declare function CommentsOverflowMenu(): JSX.Element;
|
|
426
582
|
|
|
427
|
-
/**
|
|
428
|
-
|
|
583
|
+
/**
|
|
584
|
+
* Whether the comments sidebar (the thread list) is open. Driven by an explicit control rather than
|
|
585
|
+
* by which tool is active, so browsing threads is separate from placing them.
|
|
586
|
+
* @public
|
|
587
|
+
*/
|
|
588
|
+
export declare const commentsSidebarOpen: EditorAtom<boolean>;
|
|
429
589
|
|
|
430
|
-
/**
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
}
|
|
590
|
+
/** The sidebar header's show/hide toggle for comment pins — an eye that closes while comments
|
|
591
|
+
* are hidden. The same state as the Shift+C shortcut.
|
|
592
|
+
* @public @react */
|
|
593
|
+
export declare function CommentsVisibilityToggle(): JSX.Element;
|
|
435
594
|
|
|
436
595
|
/**
|
|
437
596
|
* A comment thread: an optional header, an optional resolved banner, the comments, and an
|
|
@@ -439,7 +598,7 @@ export declare interface CommentTextProps {
|
|
|
439
598
|
* composer's handlers; how each comment renders is overridable via `renderComment`.
|
|
440
599
|
* @public @react
|
|
441
600
|
*/
|
|
442
|
-
export declare function CommentThread({ comments, header, headerActions, resolvedBanner, composer, renderComment }: CommentThreadProps): JSX.Element;
|
|
601
|
+
export declare function CommentThread({ comments, header, headerActions, resolvedBanner, composer, footer, renderComment }: CommentThreadProps): JSX.Element;
|
|
443
602
|
|
|
444
603
|
/** @public */
|
|
445
604
|
export declare interface CommentThreadProps {
|
|
@@ -453,14 +612,18 @@ export declare interface CommentThreadProps {
|
|
|
453
612
|
resolvedBanner?: ReactNode;
|
|
454
613
|
/** Reply composer props. Omit for a read-only thread (no composer). */
|
|
455
614
|
composer?: CommentComposerProps;
|
|
615
|
+
/** Shown at the bottom of the thread (e.g. a sign-in prompt when there's no composer). When
|
|
616
|
+
* both are set, the footer renders after the composer. */
|
|
617
|
+
footer?: ReactNode;
|
|
456
618
|
/** Override how each comment renders. Defaults to `<CommentCard>`. */
|
|
457
619
|
renderComment?(comment: CommentCardProps, index: number): ReactNode;
|
|
458
620
|
}
|
|
459
621
|
|
|
460
622
|
/**
|
|
461
|
-
* The comment tool.
|
|
462
|
-
*
|
|
463
|
-
*
|
|
623
|
+
* The comment tool. Pressing down opens the comment composer at the pointer and it follows until
|
|
624
|
+
* release — like placing a sticky note — settling on a point, or on a shape when released over one.
|
|
625
|
+
* With region comments enabled, dragging past the threshold draws a region rectangle instead.
|
|
626
|
+
* Placement only opens a composer; the records are created when the comment is posted.
|
|
464
627
|
* @public
|
|
465
628
|
*/
|
|
466
629
|
export declare class CommentTool extends StateNode {
|
|
@@ -486,81 +649,172 @@ export declare class CommentTool extends StateNode {
|
|
|
486
649
|
*/
|
|
487
650
|
options: CommentingOptions;
|
|
488
651
|
onEnter(): void;
|
|
652
|
+
onExit(): void;
|
|
489
653
|
onCancel(): void;
|
|
490
654
|
}
|
|
491
655
|
|
|
492
656
|
/** Registers the comment tool in the UI (icon, label, shortcut). Compose into your overrides.
|
|
493
|
-
* Once registered, tldraw's `
|
|
657
|
+
* Once registered, tldraw's `DefaultQuickActionsContent` shows the comment button.
|
|
494
658
|
* @public */
|
|
495
659
|
export declare const commentToolOverrides: TLUiOverrides;
|
|
496
660
|
|
|
497
661
|
/** @public */
|
|
498
662
|
export declare const commentTools: typeof CommentTool[];
|
|
499
663
|
|
|
500
|
-
/**
|
|
501
|
-
* Commit a comment mutation with the configured undo/redo behavior. All comment writes go through
|
|
502
|
-
* here so the {@link CommentingOptions.history} option (and {@link CommentingOptions.dragHistory}
|
|
503
|
-
* for pin re-anchors) governs whether they land on the undo stack. Defaults to `'ignore'`.
|
|
504
|
-
* @public
|
|
505
|
-
*/
|
|
506
|
-
export declare function commitCommentMutation<T>(editor: Editor, fn: () => T, kind?: 'drag' | 'mutation'): T;
|
|
507
|
-
|
|
508
|
-
/** @public */
|
|
509
|
-
export declare function computeClusterTable(leaves: readonly LeafInput[], options: ClusterOptions): ClusterTable;
|
|
510
|
-
|
|
511
664
|
/** @public @react */
|
|
512
|
-
export declare function CountBadge({ count }: CountBadgeProps): JSX.Element;
|
|
665
|
+
export declare function CountBadge({ count, open }: CountBadgeProps): JSX.Element;
|
|
513
666
|
|
|
514
667
|
/** @public */
|
|
515
668
|
export declare interface CountBadgeProps {
|
|
516
669
|
count: number;
|
|
670
|
+
/** The badge's list is showing — shows the active/selected indicator state, as an open pin does. */
|
|
671
|
+
open?: boolean;
|
|
517
672
|
}
|
|
518
673
|
|
|
519
|
-
|
|
520
|
-
export declare function createClusterRuntime(table: ClusterTable): ClusterRuntime;
|
|
674
|
+
export { createMentionSuggestion }
|
|
521
675
|
|
|
522
676
|
/**
|
|
523
|
-
*
|
|
524
|
-
*
|
|
525
|
-
*
|
|
526
|
-
*
|
|
527
|
-
*
|
|
677
|
+
* The reaction emoji palette: the small, opinionated set the picker offers *and* the set a
|
|
678
|
+
* reaction is allowed to use. It's deliberately short — a quick affordance under a comment, not a
|
|
679
|
+
* full emoji keyboard — and it's the single source of truth for "which emoji may a reaction
|
|
680
|
+
* carry". A reaction's `emoji` field is a free-form `string`, so this palette is what keeps it to
|
|
681
|
+
* real, offered emoji; check membership with {@link isAllowedReactionEmoji}. Pass a custom `emoji`
|
|
682
|
+
* array to `ReactionPicker` to offer a different set — validate against that same set if you do.
|
|
683
|
+
*
|
|
528
684
|
* @public
|
|
529
685
|
*/
|
|
530
|
-
export declare
|
|
531
|
-
|
|
532
|
-
/** Where an imprecise shape comment sits by default: the shape's top-right corner. Overridable. @public */
|
|
533
|
-
export declare const DEFAULT_IMPRECISE_SHAPE_ANCHOR: {
|
|
534
|
-
x: number;
|
|
535
|
-
y: number;
|
|
536
|
-
};
|
|
686
|
+
export declare const DEFAULT_REACTION_EMOJI: string[];
|
|
537
687
|
|
|
538
|
-
/** The out-of-the-box
|
|
539
|
-
* bottom-right / pointer-reveal / pin-move / corner-resize behaviour.
|
|
688
|
+
/** The out-of-the-box view: every page's threads, resolved ones hidden until asked for.
|
|
540
689
|
* @public */
|
|
541
|
-
export declare const DEFAULT_REGION_COMMENT_OPTIONS: RegionCommentOptions;
|
|
542
|
-
|
|
543
|
-
/** @public */
|
|
544
690
|
export declare const DEFAULT_SIDEBAR_FILTERS: SidebarFilters;
|
|
545
691
|
|
|
692
|
+
/**
|
|
693
|
+
* The default {@link CommentingOptions.canModifyComment}: a write is its record's owner's to make —
|
|
694
|
+
* a comment's author edits and deletes it, a thread's creator deletes the thread — and a viewer
|
|
695
|
+
* with no identity may make none of them.
|
|
696
|
+
*
|
|
697
|
+
* Exported so a callback can widen the default rather than restate it:
|
|
698
|
+
* `(ctx) => isModerator(ctx.currentUserId) || defaultCanModifyComment(ctx)`.
|
|
699
|
+
*
|
|
700
|
+
* @public
|
|
701
|
+
*/
|
|
702
|
+
export declare function defaultCanModifyComment(ctx: CommentModificationContext): boolean;
|
|
703
|
+
|
|
546
704
|
/**
|
|
547
705
|
* The default {@link CommentingOptions}. Override via `CommentTool.configure({ ... })`.
|
|
548
706
|
*
|
|
549
707
|
* @public
|
|
550
708
|
*/
|
|
551
709
|
export declare const defaultCommentingOptions: {
|
|
552
|
-
readonly
|
|
553
|
-
readonly
|
|
710
|
+
readonly allowMultipleReactions: true;
|
|
711
|
+
readonly canComment: undefined;
|
|
712
|
+
readonly canModifyComment: undefined;
|
|
554
713
|
readonly components: {};
|
|
555
714
|
readonly dragHistory: undefined;
|
|
556
715
|
readonly enableClustering: true;
|
|
716
|
+
readonly enableRegions: false;
|
|
557
717
|
readonly history: "ignore";
|
|
558
718
|
readonly impreciseShapeAnchor: {
|
|
559
719
|
readonly x: 1;
|
|
560
720
|
readonly y: 0;
|
|
561
721
|
};
|
|
722
|
+
readonly isAllowedReaction: typeof isAllowedReactionEmoji;
|
|
723
|
+
readonly shouldBePrecise: () => true;
|
|
562
724
|
};
|
|
563
725
|
|
|
726
|
+
/**
|
|
727
|
+
* The default reactor tooltip: hangs the built-in inline sentence (`DefaultReactionTooltipContent`)
|
|
728
|
+
* in a standard tooltip below the pill — the same tooltip the toolbar uses. Replace it via
|
|
729
|
+
* `CommentingComponents.ReactionTooltip` to present the reactor list any other way (a different box,
|
|
730
|
+
* avatars, a banner, anywhere on screen); it receives the pill as `children`.
|
|
731
|
+
* @public @react
|
|
732
|
+
*/
|
|
733
|
+
export declare function DefaultReactionTooltip({ reactors, children }: ReactionTooltipProps): JSX.Element;
|
|
734
|
+
|
|
735
|
+
/**
|
|
736
|
+
* The default reactor sentence naming who reacted — up to three names spelled out, then "and N
|
|
737
|
+
* others" (e.g. "You reacted", "You and Bo reacted", "You, Bo and Ada reacted", "You, Bo, Ada and 2
|
|
738
|
+
* others reacted"). The wording lives in the `comments.reacted-*` translation strings so each locale
|
|
739
|
+
* controls the grammar. Exported so a custom `ReactionTooltip` can reuse it inside its own box.
|
|
740
|
+
* @public @react
|
|
741
|
+
*/
|
|
742
|
+
export declare function DefaultReactionTooltipContent({ reactors }: {
|
|
743
|
+
reactors: ReactionReactor[];
|
|
744
|
+
}): JSX.Element | null;
|
|
745
|
+
|
|
746
|
+
/** The default reaction renderer: emits the token string for the OS emoji font to draw. @public */
|
|
747
|
+
export declare function defaultRenderReaction(token: string): ReactNode;
|
|
748
|
+
|
|
749
|
+
/**
|
|
750
|
+
* Delete a comment.
|
|
751
|
+
*
|
|
752
|
+
* This is a soft delete: it sets `isDeleted` rather than removing the record, and the server prunes
|
|
753
|
+
* the comment and its reactions once the flag is persisted — so no client removes records it
|
|
754
|
+
* doesn't own, and a server enforcing per-record permissions has a write it can check.
|
|
755
|
+
*
|
|
756
|
+
* Deleting is the author's to do by default; {@link CommentingOptions.canModifyComment} widens
|
|
757
|
+
* that, as does its counterpart on the server.
|
|
758
|
+
*
|
|
759
|
+
* Never undoable, whatever {@link CommentingOptions.history} says: the flag is write-once
|
|
760
|
+
* server-side, so an undo clearing it would be vetoed rather than bring the comment back.
|
|
761
|
+
*
|
|
762
|
+
* Deleting a thread's last comment closes it and leaves the thread record for the server to prune,
|
|
763
|
+
* since the deleter may not be its creator. An already-deleted comment is a no-op.
|
|
764
|
+
*
|
|
765
|
+
* @public
|
|
766
|
+
*/
|
|
767
|
+
export declare function deleteComment(editor: Editor, comment: TLComment): void;
|
|
768
|
+
|
|
769
|
+
/**
|
|
770
|
+
* Delete a thread and, with it, the whole conversation.
|
|
771
|
+
*
|
|
772
|
+
* A soft delete on the same model as {@link deleteComment}: the server prunes the thread, its
|
|
773
|
+
* comments, and their reactions once the flag is persisted. Deleting a thread is its creator's to
|
|
774
|
+
* do by default ({@link CommentingOptions.canModifyComment}), and the write is never undoable.
|
|
775
|
+
* Closes the thread if it's the open one; a pruned thread is a no-op.
|
|
776
|
+
*
|
|
777
|
+
* @public
|
|
778
|
+
*/
|
|
779
|
+
export declare function deleteThread(editor: Editor, thread: TLCommentThread): void;
|
|
780
|
+
|
|
781
|
+
/**
|
|
782
|
+
* Replace a comment's body and stamp it as edited, which renders the "(edited)" marker on its
|
|
783
|
+
* byline. Editing is the author's to do by default ({@link CommentingOptions.canModifyComment}),
|
|
784
|
+
* and a server enforcing per-record permissions rejects anyone else's. Widening one end without the
|
|
785
|
+
* other leaves an edit that's offered and then rejected, so widen both.
|
|
786
|
+
*
|
|
787
|
+
* The body lands on the version the store currently holds, so a stale copy can't revert a later
|
|
788
|
+
* change or re-create a removed comment — editing one of those does nothing.
|
|
789
|
+
*
|
|
790
|
+
* @example
|
|
791
|
+
* ```ts
|
|
792
|
+
* editComment(editor, comment, toRichText('Actually, make it dashed'))
|
|
793
|
+
* ```
|
|
794
|
+
*
|
|
795
|
+
* @public
|
|
796
|
+
*/
|
|
797
|
+
export declare function editComment(editor: Editor, comment: TLComment, body: TLRichText): void;
|
|
798
|
+
|
|
799
|
+
/**
|
|
800
|
+
* A grid of emoji to react with. Presentational and unpositioned — the host owns placement and
|
|
801
|
+
* dismissal; `ReactionPicker` renders it in a dropdown under the add-reaction button.
|
|
802
|
+
* @public @react
|
|
803
|
+
*/
|
|
804
|
+
export declare function EmojiPicker({ emoji, selected, onSelect, renderReaction }: EmojiPickerProps): JSX.Element;
|
|
805
|
+
|
|
806
|
+
/** @public */
|
|
807
|
+
export declare interface EmojiPickerProps {
|
|
808
|
+
/** The emoji to offer. Defaults to `DEFAULT_REACTION_EMOJI`. */
|
|
809
|
+
emoji?: string[];
|
|
810
|
+
/** Emoji the current user has already reacted with; shown as pressed. */
|
|
811
|
+
selected?: string[];
|
|
812
|
+
/** Called when an emoji is chosen. */
|
|
813
|
+
onSelect?(emoji: string): void;
|
|
814
|
+
/** How to draw each emoji token. Defaults to the token string (OS emoji font). */
|
|
815
|
+
renderReaction?: RenderReaction;
|
|
816
|
+
}
|
|
817
|
+
|
|
564
818
|
/** The empty state shown when a thread has no comments yet. @public @react */
|
|
565
819
|
export declare function EmptyState({ message }: EmptyStateProps): JSX.Element;
|
|
566
820
|
|
|
@@ -569,23 +823,51 @@ export declare interface EmptyStateProps {
|
|
|
569
823
|
message: string;
|
|
570
824
|
}
|
|
571
825
|
|
|
572
|
-
|
|
573
|
-
* @public */
|
|
574
|
-
export declare function filterMentionMembers(members: MentionMember[], query: string): MentionMember[];
|
|
826
|
+
export { filterMentionMembers }
|
|
575
827
|
|
|
576
828
|
/** Open a thread and bring it into view — switch to its page if needed, then center its pin. @public */
|
|
577
|
-
export declare function focusThread(editor: Editor, thread: TLCommentThread
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
829
|
+
export declare function focusThread(editor: Editor, thread: TLCommentThread): void;
|
|
830
|
+
|
|
831
|
+
/**
|
|
832
|
+
* Format an ISO datetime as a full date and time ("Tuesday, July 22, 2025 at 4:44 PM").
|
|
833
|
+
* Locale-aware via Intl.DateTimeFormat.
|
|
834
|
+
* @public
|
|
835
|
+
*/
|
|
836
|
+
export declare function formatFullDateTime(iso: string, locale?: string): string;
|
|
581
837
|
|
|
582
838
|
/**
|
|
583
|
-
* Format an ISO datetime as relative time ("2
|
|
839
|
+
* Format an ISO datetime as short relative time ("2 hr. ago", "yesterday", "last wk.").
|
|
584
840
|
* Locale-aware via Intl.RelativeTimeFormat.
|
|
585
841
|
* @public
|
|
586
842
|
*/
|
|
587
843
|
export declare function formatRelativeTime(iso: string, locale?: string): string;
|
|
588
844
|
|
|
845
|
+
/**
|
|
846
|
+
* Whether the viewer may participate in commenting, per {@link CommentingOptions.canComment}
|
|
847
|
+
* (defaulting to `currentUserId != null` when unset). A callback that throws denies.
|
|
848
|
+
*
|
|
849
|
+
* This is a plain, untracked read — in React, use {@link useCanComment} instead.
|
|
850
|
+
*
|
|
851
|
+
* @public
|
|
852
|
+
*/
|
|
853
|
+
export declare function getCanComment(editor: Editor, currentUserId: null | string | undefined): boolean;
|
|
854
|
+
|
|
855
|
+
/**
|
|
856
|
+
* Whether the viewer may make a given write against a given record, per
|
|
857
|
+
* {@link CommentingOptions.canModifyComment} (defaulting to {@link defaultCanModifyComment} when
|
|
858
|
+
* unset). Where this is false the affordance isn't rendered.
|
|
859
|
+
*
|
|
860
|
+
* This is the per-record rule alone: the built-in UI additionally requires
|
|
861
|
+
* {@link CommentingOptions.canComment}, since a viewer who may not participate gets no action
|
|
862
|
+
* affordances at all.
|
|
863
|
+
*
|
|
864
|
+
* A plain, untracked read — a `canModifyComment` callback that reads signals is not observed. In
|
|
865
|
+
* React, use {@link useCanModifyComment} instead.
|
|
866
|
+
*
|
|
867
|
+
* @public
|
|
868
|
+
*/
|
|
869
|
+
export declare function getCanModifyComment(editor: Editor, currentUserId: null | string | undefined, modification: CommentModification): boolean;
|
|
870
|
+
|
|
589
871
|
/**
|
|
590
872
|
* The merged {@link CommentingOptions} for an editor, read off the registered comment tool (which
|
|
591
873
|
* carries them via `CommentTool.configure`). Falls back to {@link defaultCommentingOptions} when
|
|
@@ -596,161 +878,322 @@ export declare function formatRelativeTime(iso: string, locale?: string): string
|
|
|
596
878
|
*/
|
|
597
879
|
export declare function getCommentingOptions(editor: Editor): CommentingOptions;
|
|
598
880
|
|
|
881
|
+
/** All comment reactions currently in the store (non-reactive; wrap in `useValue` to react). @public */
|
|
882
|
+
export declare function getCommentReactions(editor: Editor): TLCommentReaction[];
|
|
883
|
+
|
|
599
884
|
/** Read one comment record by id, or `undefined` if the id isn't a present comment record. @public */
|
|
600
885
|
export declare function getCommentRecord(editor: Editor, id: string): TLCommentRecord | undefined;
|
|
601
886
|
|
|
602
|
-
/**
|
|
887
|
+
/**
|
|
888
|
+
* Every comment in the store, **including soft-deleted ones** awaiting the server's prune. For the
|
|
889
|
+
* set the UI shows, use {@link getLiveComments}.
|
|
890
|
+
*
|
|
891
|
+
* Non-reactive; wrap in `useValue`, or use `useComments`, to react.
|
|
892
|
+
* @public
|
|
893
|
+
*/
|
|
603
894
|
export declare function getComments(editor: Editor): TLComment[];
|
|
604
895
|
|
|
605
|
-
/**
|
|
896
|
+
/**
|
|
897
|
+
* Every comment thread in the store, **including soft-deleted and emptied ones** awaiting the
|
|
898
|
+
* server's prune, which nothing renders. For the set the UI shows, use {@link getLiveCommentThreads}.
|
|
899
|
+
*
|
|
900
|
+
* Non-reactive; wrap in `useValue`, or use `useCommentThreads`, to react.
|
|
901
|
+
* @public
|
|
902
|
+
*/
|
|
606
903
|
export declare function getCommentThreads(editor: Editor): TLCommentThread[];
|
|
607
904
|
|
|
608
905
|
/**
|
|
609
|
-
*
|
|
906
|
+
* The comments that should render: not soft-deleted. A deleted record lingers in the store until
|
|
907
|
+
* the server prunes it, so build counts and lists from this rather than {@link getComments}.
|
|
908
|
+
*
|
|
909
|
+
* Non-reactive; the reactive equivalent is `useComments` (which also sorts oldest first).
|
|
610
910
|
* @public
|
|
611
911
|
*/
|
|
612
|
-
export declare
|
|
613
|
-
/** Unique. Thread id. Uniqueness is a precondition — throw on duplicates. */
|
|
614
|
-
id: string;
|
|
615
|
-
/** Page-space coordinates. Must be finite — throw on NaN/Infinity. */
|
|
616
|
-
point: VecLike;
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
/** An \@-mention pill for referencing a person in a comment. @public @react */
|
|
620
|
-
export declare function Mention({ name }: MentionProps): JSX.Element;
|
|
912
|
+
export declare function getLiveComments(editor: Editor): TLComment[];
|
|
621
913
|
|
|
622
914
|
/**
|
|
623
|
-
* The
|
|
624
|
-
*
|
|
625
|
-
*
|
|
626
|
-
*
|
|
915
|
+
* The comment threads that should render (pins, sidebar): not soft-deleted, and still holding at
|
|
916
|
+
* least one live comment. A thread emptied by its last comment's delete lingers with no surface
|
|
917
|
+
* until the server's prune lands.
|
|
918
|
+
*
|
|
919
|
+
* Non-reactive; the reactive equivalent is `useCommentThreads`.
|
|
920
|
+
* @public
|
|
627
921
|
*/
|
|
628
|
-
export declare function
|
|
629
|
-
|
|
630
|
-
/** @public */
|
|
631
|
-
export declare interface MentionListProps {
|
|
632
|
-
/** Members to choose from — already resolved for the current query by the host. */
|
|
633
|
-
members: MentionMember[];
|
|
634
|
-
/** Index of the highlighted row, driven by the composer's keyboard navigation. */
|
|
635
|
-
activeIndex?: number;
|
|
636
|
-
/** Called when a member is chosen (click, or Enter on the active row). */
|
|
637
|
-
onSelect?(member: MentionMember): void;
|
|
638
|
-
/** Shown when no member matches the query. Defaults to a translated "No matches". */
|
|
639
|
-
emptyLabel?: string;
|
|
640
|
-
/** Override a row's content (inside the selectable button). Defaults to avatar + name (+ secondary). */
|
|
641
|
-
renderMember?(member: MentionMember): ReactNode;
|
|
642
|
-
}
|
|
922
|
+
export declare function getLiveCommentThreads(editor: Editor): TLCommentThread[];
|
|
643
923
|
|
|
644
|
-
/**
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
/** Marks the current user; shown as a "(You)" suffix after the name. */
|
|
655
|
-
you?: boolean;
|
|
656
|
-
/** Hosts may carry extra fields; a custom `renderMember` can read them. */
|
|
657
|
-
[key: string]: unknown;
|
|
658
|
-
}
|
|
659
|
-
|
|
660
|
-
/** @public */
|
|
661
|
-
export declare interface MentionProps {
|
|
662
|
-
name: string;
|
|
663
|
-
}
|
|
924
|
+
/**
|
|
925
|
+
* The id passed to the most recent {@link revealThread} call that `CanvasComments` hasn't served
|
|
926
|
+
* yet, or null. A request also clears when `CanvasComments` unmounts.
|
|
927
|
+
*
|
|
928
|
+
* This is a plain, untracked read — in React, use {@link useRevealThreadPending}, unless you need
|
|
929
|
+
* the value as of *now* rather than as of the render you closed over.
|
|
930
|
+
*
|
|
931
|
+
* @public
|
|
932
|
+
*/
|
|
933
|
+
export declare function getRevealThreadPending(editor: Editor): null | string;
|
|
664
934
|
|
|
665
|
-
/**
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
}
|
|
935
|
+
/**
|
|
936
|
+
* Whether `emoji` belongs to a reaction palette (defaults to {@link DEFAULT_REACTION_EMOJI}). Use
|
|
937
|
+
* it to reject arbitrary strings before writing a reaction, so a scripted client can't spam a
|
|
938
|
+
* comment with junk `emoji` values that the picker would never offer. Pass a custom `palette` to
|
|
939
|
+
* match a customized picker.
|
|
940
|
+
*
|
|
941
|
+
* @public
|
|
942
|
+
*/
|
|
943
|
+
export declare function isAllowedReactionEmoji(emoji: string, palette?: readonly string[]): boolean;
|
|
675
944
|
|
|
676
945
|
/**
|
|
677
|
-
*
|
|
946
|
+
* Whether a click should be left to the browser's link handling (new tab, new window, or download).
|
|
678
947
|
* @public
|
|
679
948
|
*/
|
|
680
|
-
export declare
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
}
|
|
949
|
+
export declare function isOpenInNewTabClick(e: MouseEvent_2): boolean;
|
|
950
|
+
|
|
951
|
+
export { Mention }
|
|
952
|
+
|
|
953
|
+
export { MentionList }
|
|
954
|
+
|
|
955
|
+
export { MentionListProps }
|
|
956
|
+
|
|
957
|
+
export { MentionMember }
|
|
958
|
+
|
|
959
|
+
export { MentionProps }
|
|
960
|
+
|
|
961
|
+
export { MentionSuggestionOptions }
|
|
687
962
|
|
|
688
963
|
/** The id of the one open thread (only one popover is open at a time), or null when all closed.
|
|
689
964
|
* @public */
|
|
690
965
|
export declare const openThreadId: EditorAtom<null | string>;
|
|
691
966
|
|
|
692
|
-
/**
|
|
693
|
-
*
|
|
694
|
-
*
|
|
695
|
-
*
|
|
696
|
-
* @
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
967
|
+
/**
|
|
968
|
+
* Write comment records to the store, under the configured {@link CommentingOptions.history}
|
|
969
|
+
* behavior. Defaults to `'ignore'`.
|
|
970
|
+
*
|
|
971
|
+
* Use it to seed or import threads, and to save an edit. To delete, prefer {@link deleteComment}
|
|
972
|
+
* and {@link deleteThread}: comments are soft-deleted, and a synced server rejects the hard delete.
|
|
973
|
+
*
|
|
974
|
+
* @public
|
|
975
|
+
*/
|
|
976
|
+
export declare function putCommentRecords(editor: Editor, records: TLCommentRecord[]): void;
|
|
702
977
|
|
|
703
|
-
/**
|
|
704
|
-
*
|
|
705
|
-
|
|
978
|
+
/**
|
|
979
|
+
* A single emoji reaction pill with a count, highlighted when the user reacted. Hovering it shows a
|
|
980
|
+
* tooltip naming who reacted (the current user included), when `enableHoverList` is set.
|
|
981
|
+
* @public @react
|
|
982
|
+
*/
|
|
983
|
+
export declare function Reaction({ emoji, count, active, reactors, enableHoverList, renderReaction, ReactionTooltip, onClick }: ReactionProps): JSX.Element;
|
|
706
984
|
|
|
707
|
-
/**
|
|
708
|
-
|
|
985
|
+
/**
|
|
986
|
+
* The add-reaction affordance: a smiley button that opens an emoji grid.
|
|
987
|
+
*
|
|
988
|
+
* Anchored to its own button rather than to the reactions row, so the menu keeps its position as
|
|
989
|
+
* reactions are added and the row reflows.
|
|
990
|
+
*
|
|
991
|
+
* Picking an emoji dismisses the grid — adding and removing alike, since either way the picker has
|
|
992
|
+
* done its job — and hands focus back to the trigger.
|
|
993
|
+
* @public @react
|
|
994
|
+
*/
|
|
995
|
+
export declare function ReactionPicker({ emoji, selected, onSelect, renderReaction, palette: Palette, menuId, className }: ReactionPickerProps): JSX.Element;
|
|
709
996
|
|
|
710
|
-
/**
|
|
711
|
-
export declare
|
|
997
|
+
/** @public */
|
|
998
|
+
export declare interface ReactionPickerProps {
|
|
999
|
+
/** The emoji to offer. Defaults to `DEFAULT_REACTION_EMOJI`. */
|
|
1000
|
+
emoji?: string[];
|
|
1001
|
+
/** Emoji the current user has already reacted with; shown as pressed in the grid. */
|
|
1002
|
+
selected?: string[];
|
|
1003
|
+
/** Called when an emoji is chosen. */
|
|
1004
|
+
onSelect?(emoji: string): void;
|
|
1005
|
+
/** How to draw each emoji token. Defaults to the token string (OS emoji font). */
|
|
1006
|
+
renderReaction?: RenderReaction;
|
|
1007
|
+
/**
|
|
1008
|
+
* What the button opens — the thing that produces a token. Defaults to `EmojiPicker`, the grid of
|
|
1009
|
+
* emoji. Swap it for any component taking the same props to offer something else entirely (the
|
|
1010
|
+
* drawn reactions example replaces it with a canvas you draw in); the props are passed straight
|
|
1011
|
+
* through either way.
|
|
1012
|
+
*/
|
|
1013
|
+
palette?: ComponentType<EmojiPickerProps>;
|
|
1014
|
+
/**
|
|
1015
|
+
* Identifies the menu in tldraw's global menu registry, which keys open/closed state by id.
|
|
1016
|
+
* A thread renders one picker per comment, so this must differ per comment — sharing an id
|
|
1017
|
+
* makes every picker in the thread open at once. Defaults to a per-instance generated id;
|
|
1018
|
+
* pass one only for a stabler, more debuggable value.
|
|
1019
|
+
*/
|
|
1020
|
+
menuId?: string;
|
|
1021
|
+
/** Class for the trigger button. Defaults to the card-action style, matching the ⋯ button. */
|
|
1022
|
+
className?: string;
|
|
1023
|
+
}
|
|
712
1024
|
|
|
713
1025
|
/** @public */
|
|
714
1026
|
export declare interface ReactionProps {
|
|
715
1027
|
emoji: string;
|
|
716
1028
|
count: number;
|
|
717
1029
|
active: boolean;
|
|
1030
|
+
/** How to draw the emoji token. Defaults to the token string (OS emoji font). */
|
|
1031
|
+
renderReaction?: RenderReaction;
|
|
1032
|
+
/** Who reacted with this emoji, in reaction order — shown when the pill is hovered. */
|
|
1033
|
+
reactors: ReactionReactor[];
|
|
1034
|
+
/** Whether hovering shows the reactor list. Pass false to suppress it — e.g. while another
|
|
1035
|
+
* popup menu on the comment is open. Defaults to true. */
|
|
1036
|
+
enableHoverList?: boolean;
|
|
1037
|
+
/** The hover affordance for the pill, naming who reacted. It receives the reactors and the pill
|
|
1038
|
+
* itself (as `children`) and returns the whole thing — so it owns the tooltip, its box, size,
|
|
1039
|
+
* shape, and position, not just the text inside. Defaults to `DefaultReactionTooltip`, which
|
|
1040
|
+
* hangs the built-in inline sentence below the pill. */
|
|
1041
|
+
ReactionTooltip?: ComponentType<ReactionTooltipProps>;
|
|
1042
|
+
/** Called when the pill is pressed — toggles the current user's reaction. */
|
|
1043
|
+
onClick?(): void;
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
/** One person who reacted with a given emoji, for the hover list. @public */
|
|
1047
|
+
export declare interface ReactionReactor {
|
|
1048
|
+
/** Display name of the person who reacted. */
|
|
1049
|
+
name: string;
|
|
1050
|
+
/** True for the current user. */
|
|
1051
|
+
you: boolean;
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
/**
|
|
1055
|
+
* The row of tallied reactions under a comment. Presentational — the host supplies the summaries
|
|
1056
|
+
* and owns what toggling does. Hovering a pill lists who reacted (see `Reaction`).
|
|
1057
|
+
*
|
|
1058
|
+
* The add-reaction affordance is a separate component (`ReactionPicker`) so it can live outside
|
|
1059
|
+
* this row — on a comment card it sits with the card's hover actions, which keeps its position
|
|
1060
|
+
* fixed as reactions are added here.
|
|
1061
|
+
* @public @react
|
|
1062
|
+
*/
|
|
1063
|
+
export declare function Reactions({ reactions, onToggle, canReact, enableHoverList, renderReaction, ReactionTooltip }: ReactionsProps): JSX.Element | null;
|
|
1064
|
+
|
|
1065
|
+
/** @public */
|
|
1066
|
+
export declare interface ReactionsProps {
|
|
1067
|
+
/** The comment's reactions, grouped by emoji. Empty renders nothing. */
|
|
1068
|
+
reactions: ReactionSummary[];
|
|
1069
|
+
/** Toggles the current user's reaction for an emoji. */
|
|
1070
|
+
onToggle?(emoji: string): void;
|
|
1071
|
+
/** Whether the current user may react. False makes the pills inert (e.g. a signed-out
|
|
1072
|
+
* viewer, or a read-only thread) while still showing counts. */
|
|
1073
|
+
canReact?: boolean;
|
|
1074
|
+
/** Whether hovering a pill shows its reactor list. Pass false to suppress it — e.g. while
|
|
1075
|
+
* another popup menu on the comment is open. Defaults to true. */
|
|
1076
|
+
enableHoverList?: boolean;
|
|
1077
|
+
/** How to draw each emoji token. Defaults to the token string (OS emoji font). */
|
|
1078
|
+
renderReaction?: RenderReaction;
|
|
1079
|
+
/** The tooltip naming who reacted, shown when a pill is hovered. Defaults to an inline sentence
|
|
1080
|
+
* (`DefaultReactionTooltip`). Swap it to render the reactor list however you like. */
|
|
1081
|
+
ReactionTooltip?: ComponentType<ReactionTooltipProps>;
|
|
718
1082
|
}
|
|
719
1083
|
|
|
720
|
-
/**
|
|
721
|
-
export declare
|
|
1084
|
+
/** One emoji's reactions on a comment, already tallied. @public */
|
|
1085
|
+
export declare interface ReactionSummary {
|
|
1086
|
+
emoji: string;
|
|
1087
|
+
/** How many people reacted with this emoji. */
|
|
1088
|
+
count: number;
|
|
1089
|
+
/** True when the current user is one of them — renders the pill highlighted. */
|
|
1090
|
+
active: boolean;
|
|
1091
|
+
/** Who reacted with this emoji, in reaction order — shown in the hover list. */
|
|
1092
|
+
reactors: ReactionReactor[];
|
|
1093
|
+
}
|
|
722
1094
|
|
|
723
1095
|
/**
|
|
724
|
-
* The
|
|
725
|
-
*
|
|
726
|
-
*
|
|
1096
|
+
* The reaction fields {@link summarizeReactions} needs — a structural subset of
|
|
1097
|
+
* {@link tldraw#TLCommentReaction}, so tallies can also be built from rows synced outside the
|
|
1098
|
+
* editor store.
|
|
1099
|
+
*
|
|
727
1100
|
* @public
|
|
728
1101
|
*/
|
|
729
|
-
export declare interface
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
pinCorner: VecLike;
|
|
734
|
-
/** When the dashed box and its handles reveal: while the pointer is within the region, while the
|
|
735
|
-
* pin is hovered, or only while the thread is open. */
|
|
736
|
-
reveal: 'open' | 'pin-hover' | 'pointer';
|
|
737
|
-
/** How a region is moved: dragging its pin, dragging its body, or either. */
|
|
738
|
-
move: 'body' | 'both' | 'pin';
|
|
739
|
-
/** The resize affordance: corner handles, edge handles, or none. */
|
|
740
|
-
resize: 'corners' | 'edges' | 'none';
|
|
1102
|
+
export declare interface ReactionSummaryInput {
|
|
1103
|
+
userId: string;
|
|
1104
|
+
emoji: string;
|
|
1105
|
+
createdAt: number;
|
|
741
1106
|
}
|
|
742
1107
|
|
|
743
|
-
/**
|
|
744
|
-
export declare
|
|
1108
|
+
/** @public */
|
|
1109
|
+
export declare interface ReactionTooltipProps {
|
|
1110
|
+
/** Who reacted with this emoji, in reaction order. */
|
|
1111
|
+
reactors: ReactionReactor[];
|
|
1112
|
+
/** The reaction pill to wrap. Anchor the hover affordance to this and render it. */
|
|
1113
|
+
children: ReactNode;
|
|
1114
|
+
}
|
|
745
1115
|
|
|
746
1116
|
/**
|
|
747
|
-
*
|
|
748
|
-
*
|
|
749
|
-
*
|
|
750
|
-
*
|
|
1117
|
+
* Keep shape-anchored threads alive across their shape's lifecycle:
|
|
1118
|
+
*
|
|
1119
|
+
* - When the shape is deleted, the thread converts to a `point` anchor where its pin last sat, so
|
|
1120
|
+
* the conversation outlives the shape instead of becoming invisible.
|
|
1121
|
+
* - When the shape moves to another page, the thread follows: its `pageId` and each comment's
|
|
1122
|
+
* denormalized `pageId` update, and the anchor keeps riding the shape.
|
|
1123
|
+
* - When a deleted shape comes back, the thread re-attaches — unless its pin was manually moved in
|
|
1124
|
+
* the meantime, in which case the manual placement wins.
|
|
1125
|
+
*
|
|
1126
|
+
* A page move is `deleteShapes` + re-create with preserved ids inside one `editor.run`, but each
|
|
1127
|
+
* store write is its own operation, so "this shape is being moved" is never observable as a single
|
|
1128
|
+
* event. The handlers therefore cooperate across operations: `beforeDelete` snapshots where each
|
|
1129
|
+
* affected pin sits, the operation-complete pass converts threads whose shape is really gone, and
|
|
1130
|
+
* `afterCreate` plus that same pass restore the anchor once the store has settled. Undo/redo of a
|
|
1131
|
+
* move replays as a `parentId` update, so `afterChange` re-homes threads on cross-page reparents —
|
|
1132
|
+
* including threads anchored to descendants, which move without change events of their own.
|
|
1133
|
+
*
|
|
1134
|
+
* Remote changes are ignored: the client that performed the operation runs this same maintenance
|
|
1135
|
+
* and syncs the result. Writes honour the {@link CommentingOptions.history} option.
|
|
1136
|
+
*
|
|
1137
|
+
* Registered by `CanvasComments` on mount; parts-built consumers can call this directly. Returns a
|
|
1138
|
+
* cleanup function that unregisters all handlers.
|
|
1139
|
+
*
|
|
751
1140
|
* @public
|
|
752
1141
|
*/
|
|
753
|
-
export declare function
|
|
1142
|
+
export declare function registerCommentAnchorLifecycle(editor: Editor): () => void;
|
|
1143
|
+
|
|
1144
|
+
/**
|
|
1145
|
+
* Remove comment records from the store by id, under the configured
|
|
1146
|
+
* {@link CommentingOptions.history} behavior.
|
|
1147
|
+
*
|
|
1148
|
+
* This is a hard delete, which is rarely what you want: the built-in UI soft-deletes
|
|
1149
|
+
* ({@link deleteComment}, {@link deleteThread}) so the server can prune the records, and a server
|
|
1150
|
+
* enforcing per-record permissions vetoes a hard delete outright. Reach for this on a local,
|
|
1151
|
+
* unsynced store, or to drop a reaction (see {@link toggleCommentReaction}).
|
|
1152
|
+
*
|
|
1153
|
+
* @public
|
|
1154
|
+
*/
|
|
1155
|
+
export declare function removeCommentRecords(editor: Editor, ids: (TLCommentId | TLCommentReactionId | TLCommentThreadId)[]): void;
|
|
1156
|
+
|
|
1157
|
+
/** Render a reaction token to its visual — the emoji glyph by default. @public */
|
|
1158
|
+
export declare type RenderReaction = (token: string) => ReactNode;
|
|
1159
|
+
|
|
1160
|
+
/**
|
|
1161
|
+
* Reopen a resolved thread, clearing the resolution. A no-op on a thread that isn't resolved, and
|
|
1162
|
+
* on one that's gone. Like {@link resolveThread}, it touches only the resolution.
|
|
1163
|
+
*
|
|
1164
|
+
* @public
|
|
1165
|
+
*/
|
|
1166
|
+
export declare function reopenThread(editor: Editor, thread: TLCommentThread): void;
|
|
1167
|
+
|
|
1168
|
+
/**
|
|
1169
|
+
* Mark a thread resolved, stamping who resolved it and when. Resolved threads keep their pin (a
|
|
1170
|
+
* checked one) and are hidden from the sidebar until its "show resolved" filter is on.
|
|
1171
|
+
*
|
|
1172
|
+
* Only the resolution is written — the rest of the thread is read fresh, so a stale copy can't drag
|
|
1173
|
+
* a pin back. A no-op on a thread that's gone.
|
|
1174
|
+
*
|
|
1175
|
+
* @public
|
|
1176
|
+
*/
|
|
1177
|
+
export declare function resolveThread(editor: Editor, thread: TLCommentThread, userId: string): void;
|
|
1178
|
+
|
|
1179
|
+
/**
|
|
1180
|
+
* Open a thread and bring it into view, given a thread id or the id of any comment in it. Use it to
|
|
1181
|
+
* jump to a thread from outside the canvas — a notification, a deep link, your own list.
|
|
1182
|
+
*
|
|
1183
|
+
* The request is served by `CanvasComments`, so it works before the records have arrived: the layer
|
|
1184
|
+
* waits for them, switches pages, unhides pins, and zooms far enough to split the thread out of any
|
|
1185
|
+
* cluster. That also means nothing happens if `CanvasComments` isn't mounted.
|
|
1186
|
+
*
|
|
1187
|
+
* To open a thread you already hold and skip the wait, see {@link focusThread}.
|
|
1188
|
+
*
|
|
1189
|
+
* @example
|
|
1190
|
+
* ```ts
|
|
1191
|
+
* revealThread(editor, new URLSearchParams(location.search).get('comment')!)
|
|
1192
|
+
* ```
|
|
1193
|
+
*
|
|
1194
|
+
* @public
|
|
1195
|
+
*/
|
|
1196
|
+
export declare function revealThread(editor: Editor, threadOrCommentId: string): void;
|
|
754
1197
|
|
|
755
1198
|
/**
|
|
756
1199
|
* Flatten a rich-text comment body to plaintext through the limited comment extension set,
|
|
@@ -760,11 +1203,12 @@ export declare function renderMarkdown(text: string): ReactNode;
|
|
|
760
1203
|
*/
|
|
761
1204
|
export declare function richTextToPlaintext(body: TLRichText, resolveName?: (id: string) => string | undefined): string;
|
|
762
1205
|
|
|
763
|
-
/** The button that posts a comment. @public @react */
|
|
1206
|
+
/** The button that posts a comment — an up arrow. @public @react */
|
|
764
1207
|
export declare function SendButton({ label, disabled, onClick }: SendButtonProps): JSX.Element;
|
|
765
1208
|
|
|
766
1209
|
/** @public */
|
|
767
1210
|
export declare interface SendButtonProps {
|
|
1211
|
+
/** The button's accessible name (e.g. "Send"). Shown as an up-arrow icon, so this is its label. */
|
|
768
1212
|
label: string;
|
|
769
1213
|
disabled?: boolean;
|
|
770
1214
|
onClick?(): void;
|
|
@@ -772,8 +1216,9 @@ export declare interface SendButtonProps {
|
|
|
772
1216
|
|
|
773
1217
|
/**
|
|
774
1218
|
* A shape anchor for a page point. `x`/`y` are the point's normalized (0–1) offset within the
|
|
775
|
-
* shape's
|
|
776
|
-
*
|
|
1219
|
+
* shape's own bounds, taken in the shape's own space, so a pin on a rotated shape records the spot
|
|
1220
|
+
* it was dropped on. Remembered either way: when `precise` the pin sits at exactly `x`/`y`,
|
|
1221
|
+
* otherwise at the consumer's imprecise default.
|
|
777
1222
|
* @public
|
|
778
1223
|
*/
|
|
779
1224
|
export declare function shapeAnchorAt(editor: Editor, shapeId: TLShapeId, page: {
|
|
@@ -781,6 +1226,19 @@ export declare function shapeAnchorAt(editor: Editor, shapeId: TLShapeId, page:
|
|
|
781
1226
|
y: number;
|
|
782
1227
|
}, precise: boolean): TLCommentAnchor;
|
|
783
1228
|
|
|
1229
|
+
/**
|
|
1230
|
+
* The gesture that's creating a shape anchor, passed to
|
|
1231
|
+
* {@link CommentingOptions.shouldBePrecise}: the target shape, the page point of the release, and
|
|
1232
|
+
* whether Alt was held.
|
|
1233
|
+
*
|
|
1234
|
+
* @public
|
|
1235
|
+
*/
|
|
1236
|
+
export declare interface ShapeCommentPrecisionContext {
|
|
1237
|
+
readonly shapeId: TLShapeId;
|
|
1238
|
+
readonly point: VecLike;
|
|
1239
|
+
readonly altKey: boolean;
|
|
1240
|
+
}
|
|
1241
|
+
|
|
784
1242
|
/**
|
|
785
1243
|
* Which threads the comments sidebar shows. Held as an editor-scoped signal (the `sidebarFilters`
|
|
786
1244
|
* `EditorAtom` in `./state`) rather than component state so it survives the sidebar
|
|
@@ -803,23 +1261,91 @@ export declare interface SidebarFilters {
|
|
|
803
1261
|
* @public */
|
|
804
1262
|
export declare const sidebarFilters: EditorAtom<SidebarFilters>;
|
|
805
1263
|
|
|
1264
|
+
/** A list row paired with the sort key that isn't part of what the row displays. @public */
|
|
1265
|
+
export declare interface SidebarRow {
|
|
1266
|
+
item: CommentListItemProps;
|
|
1267
|
+
/** When the thread's most recent comment was posted — what the list orders by. */
|
|
1268
|
+
lastActivity: number;
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
/**
|
|
1272
|
+
* Order the list: unresolved threads first, then by most recent activity, id as a stable tiebreak.
|
|
1273
|
+
* Recency is the thread's *latest* comment, not its first, so a thread someone just replied to rises
|
|
1274
|
+
* to the top instead of staying wherever it was started. (The row still shows the thread's opening
|
|
1275
|
+
* comment and its date — that's what identifies the thread; only the ordering follows the replies.)
|
|
1276
|
+
*
|
|
1277
|
+
* Exported so a hand-built list can match the sidebar's ordering instead of re-deriving it.
|
|
1278
|
+
*
|
|
1279
|
+
* @public
|
|
1280
|
+
*/
|
|
1281
|
+
export declare function sortSidebarRows(rows: readonly SidebarRow[]): readonly SidebarRow[];
|
|
1282
|
+
|
|
1283
|
+
/**
|
|
1284
|
+
* Tally a comment's reactions into an entry per emoji, ordered by when that emoji was first used so
|
|
1285
|
+
* the row stays stable as later reactions arrive. `active` marks the current user's emoji and
|
|
1286
|
+
* `reactors` lists who reacted, in reaction order. `resolveName` names each reactor; an id it can't
|
|
1287
|
+
* name falls back to a generic "Someone", never the raw user id.
|
|
1288
|
+
*
|
|
1289
|
+
* @public
|
|
1290
|
+
*/
|
|
1291
|
+
export declare function summarizeReactions(reactions: readonly ReactionSummaryInput[], currentUserId?: null | string, resolveName?: (userId: string) => string | undefined): ReactionSummary[];
|
|
1292
|
+
|
|
1293
|
+
/**
|
|
1294
|
+
* Typed reads of comment records on the editor store.
|
|
1295
|
+
*
|
|
1296
|
+
* Comment records live on the editor's local store so the canvas can render them reactively, but
|
|
1297
|
+
* they're opt-in and aren't part of the `TLRecord` union — so `editor.store` is statically typed
|
|
1298
|
+
* `Store<TLRecord>` and every access has to reinterpret the type. These helpers own that
|
|
1299
|
+
* reinterpretation behind one boundary and keep call sites typed.
|
|
1300
|
+
*
|
|
1301
|
+
* Writes do the same, but also answer to the undo/redo policy, so they live in
|
|
1302
|
+
* `comment-mutations.ts`.
|
|
1303
|
+
*/
|
|
1304
|
+
/**
|
|
1305
|
+
* A record that lives in a comment thread: the thread itself, one of its messages, or a reaction
|
|
1306
|
+
* to one of those messages.
|
|
1307
|
+
* @public
|
|
1308
|
+
*/
|
|
1309
|
+
export declare type TLCommentRecord = TLComment | TLCommentReaction | TLCommentThread;
|
|
1310
|
+
|
|
806
1311
|
/**
|
|
807
|
-
*
|
|
1312
|
+
* Toggle one user's reaction with a given emoji on a comment.
|
|
1313
|
+
*
|
|
1314
|
+
* Each reaction is its own record keyed by (comment, user, emoji), so this only touches that user's
|
|
1315
|
+
* own records and two people reacting at once never conflict. Behaviour depends on
|
|
1316
|
+
* `allowMultipleReactions`:
|
|
1317
|
+
*
|
|
1318
|
+
* - **multiple** (default): the emoji toggles independently, leaving other reactions alone.
|
|
1319
|
+
* - **single**: a new emoji replaces the user's existing reaction; the same one removes it.
|
|
808
1320
|
*
|
|
809
|
-
*
|
|
810
|
-
* reactively, but they are opt-in records that aren't part of the `TLRecord` union (they ride the
|
|
811
|
-
* sync server's object-store lane on the wire — see `TLCommentThread`). `editor.store` is therefore
|
|
812
|
-
* statically typed `Store<TLRecord>` and doesn't know about them, so every access has to reinterpret
|
|
813
|
-
* the type. These helpers own that reinterpretation — an `unknown` hop to exactly the type the store
|
|
814
|
-
* expects, so the rest of each call stays checked — behind one boundary, and keep call sites typed.
|
|
1321
|
+
* @public
|
|
815
1322
|
*/
|
|
816
|
-
|
|
817
|
-
export declare type TLCommentRecord = TLComment | TLCommentThread;
|
|
1323
|
+
export declare function toggleCommentReaction(editor: Editor, comment: TLComment, userId: string, emoji: string, now?: number): void;
|
|
818
1324
|
|
|
819
1325
|
/** Toggle comment-pin visibility for an editor.
|
|
820
1326
|
* @public */
|
|
821
1327
|
export declare function toggleCommentsHidden(editor: Editor): void;
|
|
822
1328
|
|
|
1329
|
+
/** Open or close the comments sidebar for an editor.
|
|
1330
|
+
* @public */
|
|
1331
|
+
export declare function toggleCommentsSidebar(editor: Editor): void;
|
|
1332
|
+
|
|
1333
|
+
/**
|
|
1334
|
+
* Reactive React hook for {@link getCanComment}: a `canComment` callback that reads signals
|
|
1335
|
+
* re-evaluates when they change.
|
|
1336
|
+
*
|
|
1337
|
+
* @public
|
|
1338
|
+
*/
|
|
1339
|
+
export declare function useCanComment(currentUserId: null | string | undefined): boolean;
|
|
1340
|
+
|
|
1341
|
+
/**
|
|
1342
|
+
* Reactive React hook for {@link getCanModifyComment}: a `canModifyComment` callback that reads
|
|
1343
|
+
* signals re-evaluates when they change.
|
|
1344
|
+
*
|
|
1345
|
+
* @public
|
|
1346
|
+
*/
|
|
1347
|
+
export declare function useCanModifyComment(currentUserId: null | string | undefined, modification: CommentModification): boolean;
|
|
1348
|
+
|
|
823
1349
|
/**
|
|
824
1350
|
* Whether commenting is licensed for this editor. Enabled in development; in production it requires
|
|
825
1351
|
* a tldraw license that includes the commenting feature (or the collaboration umbrella that grants
|
|
@@ -827,7 +1353,7 @@ export declare function toggleCommentsHidden(editor: Editor): void;
|
|
|
827
1353
|
* pending, so gated UI stays hidden until the license is confirmed.
|
|
828
1354
|
*
|
|
829
1355
|
* The built-in commenting components (`CanvasComments`, `CanvasCommentsSidebar`, and the comment
|
|
830
|
-
* tool's
|
|
1356
|
+
* tool's Quick Action) gate on this. Use it to gate any custom commenting UI the same way.
|
|
831
1357
|
* @public
|
|
832
1358
|
*/
|
|
833
1359
|
export declare function useCommentingEnabled(): boolean;
|
|
@@ -840,29 +1366,54 @@ export declare function useCommentingEnabled(): boolean;
|
|
|
840
1366
|
*/
|
|
841
1367
|
export declare function useCommentingOptions(): CommentingOptions;
|
|
842
1368
|
|
|
843
|
-
/**
|
|
1369
|
+
/**
|
|
1370
|
+
* One comment's reactions, oldest first, reactively.
|
|
1371
|
+
*
|
|
1372
|
+
* @public
|
|
1373
|
+
*/
|
|
1374
|
+
export declare function useCommentReactions(editor: Editor, commentId: TLComment['id']): TLCommentReaction[];
|
|
1375
|
+
|
|
1376
|
+
/** Every live comment in the store ({@link getLiveComments}), oldest first, reactively. Group by
|
|
1377
|
+
* `threadId` for per-thread lists. @public */
|
|
844
1378
|
export declare function useComments(editor: Editor): TLComment[];
|
|
845
1379
|
|
|
846
1380
|
/** React hook for whether comment pins are hidden.
|
|
847
1381
|
* @public */
|
|
848
1382
|
export declare function useCommentsHidden(): boolean;
|
|
849
1383
|
|
|
850
|
-
/**
|
|
1384
|
+
/** React hook for whether the comments sidebar is open.
|
|
1385
|
+
* @public */
|
|
1386
|
+
export declare function useCommentsSidebarOpen(): boolean;
|
|
1387
|
+
|
|
1388
|
+
/**
|
|
1389
|
+
* The comment threads that should render (pins, sidebar), reactively — the live set described by
|
|
1390
|
+
* {@link getLiveCommentThreads}. Use `getCommentThreads` for the unfiltered set, including
|
|
1391
|
+
* soft-deleted threads awaiting the server's prune.
|
|
1392
|
+
*
|
|
1393
|
+
* @public
|
|
1394
|
+
*/
|
|
851
1395
|
export declare function useCommentThreads(editor: Editor): TLCommentThread[];
|
|
852
1396
|
|
|
853
1397
|
/** React hook for the open thread id.
|
|
854
1398
|
* @public */
|
|
855
1399
|
export declare function useOpenThreadId(): null | string;
|
|
856
1400
|
|
|
857
|
-
/**
|
|
858
|
-
* @
|
|
859
|
-
|
|
1401
|
+
/**
|
|
1402
|
+
* Reactive React hook for {@link getRevealThreadPending}.
|
|
1403
|
+
*
|
|
1404
|
+
* Use it to notice a reveal that never lands — usually a deep link to a deleted comment. Give it a
|
|
1405
|
+
* grace period first, since a request also sits here while its records sync in, and re-check with
|
|
1406
|
+
* {@link getRevealThreadPending} when it elapses.
|
|
1407
|
+
*
|
|
1408
|
+
* @public
|
|
1409
|
+
*/
|
|
1410
|
+
export declare function useRevealThreadPending(): null | string;
|
|
860
1411
|
|
|
861
1412
|
/** React hook for the current sidebar filters.
|
|
862
1413
|
* @public */
|
|
863
1414
|
export declare function useSidebarFilters(): SidebarFilters;
|
|
864
1415
|
|
|
865
|
-
/** A thread's comments, oldest first, reactively. @public */
|
|
1416
|
+
/** A thread's live comments, oldest first, reactively. @public */
|
|
866
1417
|
export declare function useThreadComments(editor: Editor, threadId: TLCommentThreadId): TLComment[];
|
|
867
1418
|
|
|
868
1419
|
export { }
|