@tldraw/commenting 0.0.0-bootstrap
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 +11 -0
- package/commenting.css +832 -0
- package/dist-cjs/canvas/cluster-input.js +40 -0
- package/dist-cjs/canvas/cluster-input.js.map +7 -0
- package/dist-cjs/canvas/comment-body.js +31 -0
- package/dist-cjs/canvas/comment-body.js.map +7 -0
- package/dist-cjs/canvas/comment-render.js +72 -0
- package/dist-cjs/canvas/comment-render.js.map +7 -0
- package/dist-cjs/canvas/comment-store.js +48 -0
- package/dist-cjs/canvas/comment-store.js.map +7 -0
- package/dist-cjs/canvas/comment-tool.js +160 -0
- package/dist-cjs/canvas/comment-tool.js.map +7 -0
- package/dist-cjs/canvas/comments-filter-menu.js +109 -0
- package/dist-cjs/canvas/comments-filter-menu.js.map +7 -0
- package/dist-cjs/canvas/comments-menu-item.js +42 -0
- package/dist-cjs/canvas/comments-menu-item.js.map +7 -0
- package/dist-cjs/canvas/comments-overflow-menu.js +64 -0
- package/dist-cjs/canvas/comments-overflow-menu.js.map +7 -0
- package/dist-cjs/canvas/comments-overlay.js +1081 -0
- package/dist-cjs/canvas/comments-overlay.js.map +7 -0
- package/dist-cjs/canvas/comments-sidebar.js +134 -0
- package/dist-cjs/canvas/comments-sidebar.js.map +7 -0
- package/dist-cjs/canvas/hooks.js +45 -0
- package/dist-cjs/canvas/hooks.js.map +7 -0
- package/dist-cjs/canvas/license.js +28 -0
- package/dist-cjs/canvas/license.js.map +7 -0
- package/dist-cjs/canvas/options.js +45 -0
- package/dist-cjs/canvas/options.js.map +7 -0
- package/dist-cjs/canvas/region-options.js +49 -0
- package/dist-cjs/canvas/region-options.js.map +7 -0
- package/dist-cjs/canvas/rich-text.js +28 -0
- package/dist-cjs/canvas/rich-text.js.map +7 -0
- package/dist-cjs/canvas/sidebar-filters.js +30 -0
- package/dist-cjs/canvas/sidebar-filters.js.map +7 -0
- package/dist-cjs/canvas/state.js +76 -0
- package/dist-cjs/canvas/state.js.map +7 -0
- package/dist-cjs/canvas/thread-state.js +81 -0
- package/dist-cjs/canvas/thread-state.js.map +7 -0
- package/dist-cjs/clustering/computeClusterTable.js +83 -0
- package/dist-cjs/clustering/computeClusterTable.js.map +7 -0
- package/dist-cjs/clustering/mst.js +117 -0
- package/dist-cjs/clustering/mst.js.map +7 -0
- package/dist-cjs/clustering/replay.js +275 -0
- package/dist-cjs/clustering/replay.js.map +7 -0
- package/dist-cjs/clustering/runtime.js +134 -0
- package/dist-cjs/clustering/runtime.js.map +7 -0
- package/dist-cjs/clustering/schedule.js +170 -0
- package/dist-cjs/clustering/schedule.js.map +7 -0
- package/dist-cjs/clustering/types.js +17 -0
- package/dist-cjs/clustering/types.js.map +7 -0
- package/dist-cjs/index.d.ts +868 -0
- package/dist-cjs/index.js +126 -0
- package/dist-cjs/index.js.map +7 -0
- package/dist-cjs/ui/avatar.js +43 -0
- package/dist-cjs/ui/avatar.js.map +7 -0
- package/dist-cjs/ui/byline.js +35 -0
- package/dist-cjs/ui/byline.js.map +7 -0
- package/dist-cjs/ui/comment-card.js +37 -0
- package/dist-cjs/ui/comment-card.js.map +7 -0
- package/dist-cjs/ui/comment-composer.js +136 -0
- package/dist-cjs/ui/comment-composer.js.map +7 -0
- package/dist-cjs/ui/comment-extensions.js +37 -0
- package/dist-cjs/ui/comment-extensions.js.map +7 -0
- package/dist-cjs/ui/comment-mention.js +42 -0
- package/dist-cjs/ui/comment-mention.js.map +7 -0
- package/dist-cjs/ui/comment-pin.js +29 -0
- package/dist-cjs/ui/comment-pin.js.map +7 -0
- package/dist-cjs/ui/comment-text.js +29 -0
- package/dist-cjs/ui/comment-text.js.map +7 -0
- package/dist-cjs/ui/comment-thread.js +45 -0
- package/dist-cjs/ui/comment-thread.js.map +7 -0
- package/dist-cjs/ui/comments-list.js +106 -0
- package/dist-cjs/ui/comments-list.js.map +7 -0
- package/dist-cjs/ui/count-badge.js +28 -0
- package/dist-cjs/ui/count-badge.js.map +7 -0
- package/dist-cjs/ui/empty-state.js +31 -0
- package/dist-cjs/ui/empty-state.js.map +7 -0
- package/dist-cjs/ui/format-time.js +46 -0
- package/dist-cjs/ui/format-time.js.map +7 -0
- package/dist-cjs/ui/mention-list.js +70 -0
- package/dist-cjs/ui/mention-list.js.map +7 -0
- package/dist-cjs/ui/mention-suggestion.js +206 -0
- package/dist-cjs/ui/mention-suggestion.js.map +7 -0
- package/dist-cjs/ui/mention.js +31 -0
- package/dist-cjs/ui/mention.js.map +7 -0
- package/dist-cjs/ui/reaction.js +31 -0
- package/dist-cjs/ui/reaction.js.map +7 -0
- package/dist-cjs/ui/reactions.js +34 -0
- package/dist-cjs/ui/reactions.js.map +7 -0
- package/dist-cjs/ui/render-markdown.js +63 -0
- package/dist-cjs/ui/render-markdown.js.map +7 -0
- package/dist-cjs/ui/send-button.js +28 -0
- package/dist-cjs/ui/send-button.js.map +7 -0
- package/dist-esm/canvas/cluster-input.mjs +20 -0
- package/dist-esm/canvas/cluster-input.mjs.map +7 -0
- package/dist-esm/canvas/comment-body.mjs +11 -0
- package/dist-esm/canvas/comment-body.mjs.map +7 -0
- package/dist-esm/canvas/comment-render.mjs +52 -0
- package/dist-esm/canvas/comment-render.mjs.map +7 -0
- package/dist-esm/canvas/comment-store.mjs +28 -0
- package/dist-esm/canvas/comment-store.mjs.map +7 -0
- package/dist-esm/canvas/comment-tool.mjs +142 -0
- package/dist-esm/canvas/comment-tool.mjs.map +7 -0
- package/dist-esm/canvas/comments-filter-menu.mjs +99 -0
- package/dist-esm/canvas/comments-filter-menu.mjs.map +7 -0
- package/dist-esm/canvas/comments-menu-item.mjs +22 -0
- package/dist-esm/canvas/comments-menu-item.mjs.map +7 -0
- package/dist-esm/canvas/comments-overflow-menu.mjs +53 -0
- package/dist-esm/canvas/comments-overflow-menu.mjs.map +7 -0
- package/dist-esm/canvas/comments-overlay.mjs +1094 -0
- package/dist-esm/canvas/comments-overlay.mjs.map +7 -0
- package/dist-esm/canvas/comments-sidebar.mjs +120 -0
- package/dist-esm/canvas/comments-sidebar.mjs.map +7 -0
- package/dist-esm/canvas/hooks.mjs +25 -0
- package/dist-esm/canvas/hooks.mjs.map +7 -0
- package/dist-esm/canvas/license.mjs +8 -0
- package/dist-esm/canvas/license.mjs.map +7 -0
- package/dist-esm/canvas/options.mjs +27 -0
- package/dist-esm/canvas/options.mjs.map +7 -0
- package/dist-esm/canvas/region-options.mjs +29 -0
- package/dist-esm/canvas/region-options.mjs.map +7 -0
- package/dist-esm/canvas/rich-text.mjs +8 -0
- package/dist-esm/canvas/rich-text.mjs.map +7 -0
- package/dist-esm/canvas/sidebar-filters.mjs +10 -0
- package/dist-esm/canvas/sidebar-filters.mjs.map +7 -0
- package/dist-esm/canvas/state.mjs +60 -0
- package/dist-esm/canvas/state.mjs.map +7 -0
- package/dist-esm/canvas/thread-state.mjs +61 -0
- package/dist-esm/canvas/thread-state.mjs.map +7 -0
- package/dist-esm/clustering/computeClusterTable.mjs +63 -0
- package/dist-esm/clustering/computeClusterTable.mjs.map +7 -0
- package/dist-esm/clustering/mst.mjs +97 -0
- package/dist-esm/clustering/mst.mjs.map +7 -0
- package/dist-esm/clustering/replay.mjs +255 -0
- package/dist-esm/clustering/replay.mjs.map +7 -0
- package/dist-esm/clustering/runtime.mjs +114 -0
- package/dist-esm/clustering/runtime.mjs.map +7 -0
- package/dist-esm/clustering/schedule.mjs +150 -0
- package/dist-esm/clustering/schedule.mjs.map +7 -0
- package/dist-esm/clustering/types.mjs +1 -0
- package/dist-esm/clustering/types.mjs.map +7 -0
- package/dist-esm/index.d.mts +868 -0
- package/dist-esm/index.mjs +139 -0
- package/dist-esm/index.mjs.map +7 -0
- package/dist-esm/ui/avatar.mjs +23 -0
- package/dist-esm/ui/avatar.mjs.map +7 -0
- package/dist-esm/ui/byline.mjs +15 -0
- package/dist-esm/ui/byline.mjs.map +7 -0
- package/dist-esm/ui/comment-card.mjs +17 -0
- package/dist-esm/ui/comment-card.mjs.map +7 -0
- package/dist-esm/ui/comment-composer.mjs +116 -0
- package/dist-esm/ui/comment-composer.mjs.map +7 -0
- package/dist-esm/ui/comment-extensions.mjs +17 -0
- package/dist-esm/ui/comment-extensions.mjs.map +7 -0
- package/dist-esm/ui/comment-mention.mjs +22 -0
- package/dist-esm/ui/comment-mention.mjs.map +7 -0
- package/dist-esm/ui/comment-pin.mjs +9 -0
- package/dist-esm/ui/comment-pin.mjs.map +7 -0
- package/dist-esm/ui/comment-text.mjs +9 -0
- package/dist-esm/ui/comment-text.mjs.map +7 -0
- package/dist-esm/ui/comment-thread.mjs +25 -0
- package/dist-esm/ui/comment-thread.mjs.map +7 -0
- package/dist-esm/ui/comments-list.mjs +86 -0
- package/dist-esm/ui/comments-list.mjs.map +7 -0
- package/dist-esm/ui/count-badge.mjs +8 -0
- package/dist-esm/ui/count-badge.mjs.map +7 -0
- package/dist-esm/ui/empty-state.mjs +11 -0
- package/dist-esm/ui/empty-state.mjs.map +7 -0
- package/dist-esm/ui/format-time.mjs +26 -0
- package/dist-esm/ui/format-time.mjs.map +7 -0
- package/dist-esm/ui/mention-list.mjs +50 -0
- package/dist-esm/ui/mention-list.mjs.map +7 -0
- package/dist-esm/ui/mention-suggestion.mjs +186 -0
- package/dist-esm/ui/mention-suggestion.mjs.map +7 -0
- package/dist-esm/ui/mention.mjs +11 -0
- package/dist-esm/ui/mention.mjs.map +7 -0
- package/dist-esm/ui/reaction.mjs +11 -0
- package/dist-esm/ui/reaction.mjs.map +7 -0
- package/dist-esm/ui/reactions.mjs +14 -0
- package/dist-esm/ui/reactions.mjs.map +7 -0
- package/dist-esm/ui/render-markdown.mjs +45 -0
- package/dist-esm/ui/render-markdown.mjs.map +7 -0
- package/dist-esm/ui/send-button.mjs +8 -0
- package/dist-esm/ui/send-button.mjs.map +7 -0
- package/package.json +71 -0
- package/src/canvas/canvas.css +148 -0
- package/src/canvas/cluster-input.test.ts +223 -0
- package/src/canvas/cluster-input.ts +29 -0
- package/src/canvas/comment-body.tsx +21 -0
- package/src/canvas/comment-render.test.ts +90 -0
- package/src/canvas/comment-render.ts +92 -0
- package/src/canvas/comment-store.ts +55 -0
- package/src/canvas/comment-tool.tsx +200 -0
- package/src/canvas/comments-filter-menu.tsx +104 -0
- package/src/canvas/comments-menu-item.tsx +24 -0
- package/src/canvas/comments-overflow-menu.tsx +62 -0
- package/src/canvas/comments-overlay.tsx +1460 -0
- package/src/canvas/comments-sidebar.tsx +184 -0
- package/src/canvas/hooks.ts +28 -0
- package/src/canvas/license.ts +15 -0
- package/src/canvas/options.test.ts +127 -0
- package/src/canvas/options.ts +111 -0
- package/src/canvas/region-options.ts +57 -0
- package/src/canvas/rich-text.ts +15 -0
- package/src/canvas/sidebar-filters.ts +25 -0
- package/src/canvas/state.ts +102 -0
- package/src/canvas/thread-state.ts +91 -0
- package/src/clustering/computeClusterTable.test.ts +299 -0
- package/src/clustering/computeClusterTable.ts +82 -0
- package/src/clustering/locality.test.ts +189 -0
- package/src/clustering/mst.test.ts +383 -0
- package/src/clustering/mst.ts +134 -0
- package/src/clustering/replay.test.ts +547 -0
- package/src/clustering/replay.ts +326 -0
- package/src/clustering/runtime.test.ts +596 -0
- package/src/clustering/runtime.ts +153 -0
- package/src/clustering/schedule.test.ts +514 -0
- package/src/clustering/schedule.ts +184 -0
- package/src/clustering/types.ts +102 -0
- package/src/index.ts +96 -0
- package/src/ui/avatar.tsx +31 -0
- package/src/ui/byline.tsx +23 -0
- package/src/ui/comment-card.tsx +32 -0
- package/src/ui/comment-composer.tsx +179 -0
- package/src/ui/comment-extensions.ts +25 -0
- package/src/ui/comment-mention.ts +47 -0
- package/src/ui/comment-pin.tsx +21 -0
- package/src/ui/comment-text.tsx +12 -0
- package/src/ui/comment-thread.tsx +56 -0
- package/src/ui/comments-list.tsx +139 -0
- package/src/ui/comments.css +678 -0
- package/src/ui/count-badge.tsx +9 -0
- package/src/ui/empty-state.tsx +16 -0
- package/src/ui/format-time.ts +29 -0
- package/src/ui/mention-list.tsx +106 -0
- package/src/ui/mention-suggestion.test.ts +18 -0
- package/src/ui/mention-suggestion.tsx +285 -0
- package/src/ui/mention.tsx +9 -0
- package/src/ui/reaction.tsx +16 -0
- package/src/ui/reactions.tsx +15 -0
- package/src/ui/render-markdown.tsx +72 -0
- package/src/ui/send-button.tsx +15 -0
|
@@ -0,0 +1,868 @@
|
|
|
1
|
+
import { ComponentType } from 'react';
|
|
2
|
+
import { Editor } from 'tldraw';
|
|
3
|
+
import { EditorAtom } from 'tldraw';
|
|
4
|
+
import { JSX } from 'react/jsx-runtime';
|
|
5
|
+
import type { MentionNodeAttrs } from '@tiptap/extension-mention';
|
|
6
|
+
import { ReactNode } from 'react';
|
|
7
|
+
import { StateNode } from 'tldraw';
|
|
8
|
+
import type { SuggestionOptions } from '@tiptap/suggestion';
|
|
9
|
+
import { TLComment } from 'tldraw';
|
|
10
|
+
import { TLCommentAnchor } from 'tldraw';
|
|
11
|
+
import { TLCommentId } from 'tldraw';
|
|
12
|
+
import { TLCommentThread } from 'tldraw';
|
|
13
|
+
import { TLCommentThreadId } from 'tldraw';
|
|
14
|
+
import { TLHistoryBatchOptions } from 'tldraw';
|
|
15
|
+
import { TLRichText } from 'tldraw';
|
|
16
|
+
import { TLShapeId } from 'tldraw';
|
|
17
|
+
import { TLStateNodeConstructor } from 'tldraw';
|
|
18
|
+
import { TLUiOverrides } from 'tldraw';
|
|
19
|
+
import { VecLike } from 'tldraw';
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Where a thread's pin sits on the page, for each anchor kind. Null hides the pin. For imprecise
|
|
23
|
+
* shape anchors the pin uses `impreciseShapeAnchor` (a normalized 0–1 spot, top-right by default)
|
|
24
|
+
* rather than the stored `x`/`y`.
|
|
25
|
+
* @public
|
|
26
|
+
*/
|
|
27
|
+
export declare function anchorPagePoint(editor: Editor, anchor: TLCommentAnchor, impreciseShapeAnchor?: {
|
|
28
|
+
x: number;
|
|
29
|
+
y: number;
|
|
30
|
+
}): {
|
|
31
|
+
x: number;
|
|
32
|
+
y: number;
|
|
33
|
+
} | null;
|
|
34
|
+
|
|
35
|
+
/** A commenter's avatar — their image if provided, otherwise a single-initial coloured circle.
|
|
36
|
+
* @public @react */
|
|
37
|
+
export declare function Avatar({ name, color, image }: AvatarProps): JSX.Element;
|
|
38
|
+
|
|
39
|
+
/** @public */
|
|
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
|
+
}
|
|
47
|
+
|
|
48
|
+
/** A comment's metadata line: author name, relative time, and an edited marker. @public @react */
|
|
49
|
+
export declare function Byline({ author, date, edited }: BylineProps): JSX.Element;
|
|
50
|
+
|
|
51
|
+
/** @public */
|
|
52
|
+
export declare interface BylineProps {
|
|
53
|
+
author: string;
|
|
54
|
+
/** ISO datetime; formatted to relative time by the component. */
|
|
55
|
+
date: string;
|
|
56
|
+
/** Shows an "edited" marker when the comment has been edited. */
|
|
57
|
+
edited?: boolean;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** @public @react */
|
|
61
|
+
export declare function CanvasComments(props: CanvasCommentsProps): JSX.Element | null;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* A ready-to-use comments layer for a tldraw canvas: pins each thread at its anchor, opens a
|
|
65
|
+
* thread popover (with a reply composer) on click, and shows a composer where the comment tool
|
|
66
|
+
* placed a new thread. Reads/writes comment records straight from `editor.store`.
|
|
67
|
+
*
|
|
68
|
+
* It's meant as the batteries-included default — every visible piece is a lever (the `CommentBody`
|
|
69
|
+
* and `PinContent` slots on `CommentTool.configure({ components })`), and the pieces it composes
|
|
70
|
+
* (`CommentPin`, `CommentThread`, `CommentComposer`, the hooks, the tool) are all exported, so a
|
|
71
|
+
* consumer can rebuild this from parts instead.
|
|
72
|
+
* @public
|
|
73
|
+
*/
|
|
74
|
+
export declare interface CanvasCommentsProps {
|
|
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
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* A comments list panel for the current page, shown while the comment tool is active. Clicking a
|
|
104
|
+
* thread brings its pin into view and opens it. Batteries-included over the store (a sibling to
|
|
105
|
+
* `CanvasComments`); `CommentsList` is exported for a differently-placed or always-on list.
|
|
106
|
+
* @public @react
|
|
107
|
+
*/
|
|
108
|
+
export declare function CanvasCommentsSidebar(props: CanvasCommentsSidebarProps): JSX.Element | null;
|
|
109
|
+
|
|
110
|
+
/** @public */
|
|
111
|
+
export declare interface CanvasCommentsSidebarProps {
|
|
112
|
+
/** Map an author id to a display name, or `undefined` when the id can't be named. */
|
|
113
|
+
resolveName(id: string): string | undefined;
|
|
114
|
+
/** The signed-in user's id. Enables the "only your threads" filter when present. */
|
|
115
|
+
currentUserId?: string;
|
|
116
|
+
/**
|
|
117
|
+
* Whether a comment is unread for the current user (return true for unread). Enables the
|
|
118
|
+
* "only unread" filter when present.
|
|
119
|
+
*/
|
|
120
|
+
isCommentUnread?(commentId: TLCommentId): boolean;
|
|
121
|
+
/** Tool ids that show the sidebar. Defaults to the comment tool. */
|
|
122
|
+
tools?: string[];
|
|
123
|
+
/** Header above the list. */
|
|
124
|
+
header?: ReactNode;
|
|
125
|
+
/** Shown when the page has no threads. */
|
|
126
|
+
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
|
+
}
|
|
170
|
+
|
|
171
|
+
/** @public */
|
|
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[];
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Renders a comment's rich-text body read-only through the limited comment extension set (no
|
|
212
|
+
* headings), so formatting (bold, links, lists, highlight) is preserved rather than flattened, and
|
|
213
|
+
* headings can never render. Use this as the `body` of a `CommentCard` on a canvas.
|
|
214
|
+
* @public @react
|
|
215
|
+
*/
|
|
216
|
+
export declare function CommentBody({ richText, resolveName }: CommentBodyProps): JSX.Element;
|
|
217
|
+
|
|
218
|
+
/** @public */
|
|
219
|
+
export declare interface CommentBodyProps {
|
|
220
|
+
richText: TLRichText;
|
|
221
|
+
/** Maps a member id to its current display name, so \@mentions show the live name. */
|
|
222
|
+
resolveName?(id: string): string | undefined;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/** 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;
|
|
227
|
+
|
|
228
|
+
/** @public */
|
|
229
|
+
export declare interface CommentCardProps {
|
|
230
|
+
author: string;
|
|
231
|
+
/** The rendered comment body. The card doesn't dictate a format — pass a `<CommentText>`
|
|
232
|
+
* for markdown, a rich-text render, or any node. */
|
|
233
|
+
body: ReactNode;
|
|
234
|
+
/** ISO datetime; formatted to relative time by the component. */
|
|
235
|
+
date: string;
|
|
236
|
+
you: boolean;
|
|
237
|
+
/** Whether the comment has been edited (shows an "edited" marker). */
|
|
238
|
+
edited?: boolean;
|
|
239
|
+
/** Hover-revealed controls at the card's top-right (e.g. an edit affordance). */
|
|
240
|
+
actions?: ReactNode;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* The input for writing a comment: a TipTap rich-text editor restricted to the comment extension
|
|
245
|
+
* set (bold, italic, lists, links, code, highlight — no headings), with a Send button. Formatting
|
|
246
|
+
* is applied through markdown and keyboard shortcuts (e.g. `**bold**`, `- `, Cmd+B); there's no
|
|
247
|
+
* floating toolbar. Presentational by default; pass value/onChange/onSubmit to drive it as a form.
|
|
248
|
+
* @public @react
|
|
249
|
+
*/
|
|
250
|
+
export declare function CommentComposer({ author, placeholder, value, onChange, onSubmit, sendLabel, disabled, autoFocus, leading, getMentionSuggestions, renderMentionSuggestion }: CommentComposerProps): JSX.Element;
|
|
251
|
+
|
|
252
|
+
/** @public */
|
|
253
|
+
export declare interface CommentComposerProps {
|
|
254
|
+
author: string;
|
|
255
|
+
placeholder: string;
|
|
256
|
+
/** Controlled rich-text value. Omit for the presentational (display-only) composer. */
|
|
257
|
+
value?: TLRichText;
|
|
258
|
+
onChange?(value: TLRichText): void;
|
|
259
|
+
/** Called on Send click or Enter. When set, the composer is interactive. */
|
|
260
|
+
onSubmit?(): void;
|
|
261
|
+
sendLabel?: string;
|
|
262
|
+
disabled?: boolean;
|
|
263
|
+
autoFocus?: boolean;
|
|
264
|
+
/** The leading element before the field. Defaults to the author's avatar. */
|
|
265
|
+
leading?: ReactNode;
|
|
266
|
+
/** Resolve the members matching an `@`-query (sync or async). Provide to enable mentions. */
|
|
267
|
+
getMentionSuggestions?(query: string): MentionMember[] | Promise<MentionMember[]>;
|
|
268
|
+
/** Override a picker row's content. Defaults to avatar + name (+ secondary). */
|
|
269
|
+
renderMentionSuggestion?(member: MentionMember): ReactNode;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Component overrides for the batteries-included comments layer. Each slot replaces a built-in
|
|
274
|
+
* piece; leave a slot unset to keep its default.
|
|
275
|
+
*
|
|
276
|
+
* @public
|
|
277
|
+
*/
|
|
278
|
+
export declare interface CommentingComponents {
|
|
279
|
+
/** A comment's body. Replaces the default rich-text `<CommentBody>`. */
|
|
280
|
+
CommentBody?: ComponentType<{
|
|
281
|
+
comment: TLComment;
|
|
282
|
+
}>;
|
|
283
|
+
/** A pin's inner content. Replaces the author-initial default. */
|
|
284
|
+
PinContent?: ComponentType<{
|
|
285
|
+
comments: TLComment[];
|
|
286
|
+
thread: TLCommentThread;
|
|
287
|
+
}>;
|
|
288
|
+
/** A sidebar row's preview. Replaces the plaintext default. */
|
|
289
|
+
ThreadPreview?: ComponentType<{
|
|
290
|
+
comment: TLComment;
|
|
291
|
+
}>;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Configuration for the commenting layer. Static config only — pass it once via
|
|
296
|
+
* `CommentTool.configure({ ... })`, mirroring `ShapeUtil.configure`. Live, reactive values
|
|
297
|
+
* (`currentUserId`, `resolveName`, read-status callbacks) stay as props on `<CanvasComments>`.
|
|
298
|
+
*
|
|
299
|
+
* For defaults, see {@link defaultCommentingOptions}.
|
|
300
|
+
*
|
|
301
|
+
* @example
|
|
302
|
+
* ```tsx
|
|
303
|
+
* <Tldraw tools={[CommentTool.configure({ history: 'ignore', enableClustering: false })]} />
|
|
304
|
+
* ```
|
|
305
|
+
*
|
|
306
|
+
* @public
|
|
307
|
+
*/
|
|
308
|
+
export declare interface CommentingOptions {
|
|
309
|
+
/**
|
|
310
|
+
* How comment mutations (post, reply, edit, resolve, delete) interact with the editor undo
|
|
311
|
+
* stack. Defaults to `'ignore'` — comments are deliberately not undoable (see `TLComment`).
|
|
312
|
+
* `'record'` is a multiplayer footgun: undoing a delete resurrects a thread a collaborator
|
|
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.
|
|
315
|
+
*/
|
|
316
|
+
readonly history: TLHistoryBatchOptions['history'];
|
|
317
|
+
/**
|
|
318
|
+
* History mode for the pin drag-to-move re-anchor specifically. Unlike posts/edits this is a
|
|
319
|
+
* spatial edit that may reasonably be undoable alongside a shape move. Defaults to `history`.
|
|
320
|
+
*/
|
|
321
|
+
readonly dragHistory: TLHistoryBatchOptions['history'] | undefined;
|
|
322
|
+
/** Fold nearby pins into count badges as the camera zooms out. */
|
|
323
|
+
readonly enableClustering: boolean;
|
|
324
|
+
/** Normalized (0–1) spot within a shape where imprecise shape pins sit. Default top-right. */
|
|
325
|
+
readonly impreciseShapeAnchor: {
|
|
326
|
+
readonly x: number;
|
|
327
|
+
readonly y: number;
|
|
328
|
+
};
|
|
329
|
+
/** Screen-pixel margin by which the viewport is inflated when culling cluster badges. */
|
|
330
|
+
readonly clusterCullMargin: number;
|
|
331
|
+
/** How far past a cluster's split zoom to land when expanding it (1.05 = 5% overshoot). */
|
|
332
|
+
readonly clusterSplitZoomFactor: number;
|
|
333
|
+
/** Component overrides. See {@link CommentingComponents}. */
|
|
334
|
+
readonly components: CommentingComponents;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/** @public */
|
|
338
|
+
export declare interface CommentListItemProps {
|
|
339
|
+
id: string;
|
|
340
|
+
author: string;
|
|
341
|
+
/** A short preview of the thread — e.g. the first comment's body. */
|
|
342
|
+
preview: ReactNode;
|
|
343
|
+
/** ISO datetime of the thread's first comment. */
|
|
344
|
+
date: string;
|
|
345
|
+
resolved?: boolean;
|
|
346
|
+
/** Name of the page the thread lives on, shown as a small label. Omit to hide. */
|
|
347
|
+
page?: string;
|
|
348
|
+
/** Total comments in the thread. */
|
|
349
|
+
count?: number;
|
|
350
|
+
/** Whether this thread is the open one. */
|
|
351
|
+
selected?: boolean;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/** A canvas comment marker: shows its `children` (or a check when resolved). Purely
|
|
355
|
+
* presentational — it reflects open/resolved state via CSS; wrap it to make it clickable.
|
|
356
|
+
* @public @react */
|
|
357
|
+
export declare function CommentPin({ children, resolved, open }: CommentPinProps): JSX.Element;
|
|
358
|
+
|
|
359
|
+
/** @public */
|
|
360
|
+
export declare interface CommentPinProps {
|
|
361
|
+
/** What the pin shows when unresolved — a number, an author initial, an <Avatar>, etc.
|
|
362
|
+
* Left as a lever so consumers aren't locked into a count. */
|
|
363
|
+
children?: ReactNode;
|
|
364
|
+
resolved?: boolean;
|
|
365
|
+
/** The pin's thread is open — shows the active/selected indicator state. */
|
|
366
|
+
open?: boolean;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/** The funnel dropdown in the sidebar header: toggles for which threads the list shows.
|
|
370
|
+
* @public @react */
|
|
371
|
+
export declare function CommentsFilterMenu({ canFilterByAuthor, canFilterByUnread }: CommentsFilterMenuProps): JSX.Element;
|
|
372
|
+
|
|
373
|
+
/** @public */
|
|
374
|
+
export declare interface CommentsFilterMenuProps {
|
|
375
|
+
/** Whether to offer the "only your threads" toggle (needs a known current user). */
|
|
376
|
+
canFilterByAuthor?: boolean;
|
|
377
|
+
/** Whether to offer the "only unread" toggle (needs a read-status source). */
|
|
378
|
+
canFilterByUnread?: boolean;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Whether comment pins are hidden on the canvas. Governs the on-canvas layer (pins + open popover)
|
|
383
|
+
* only — the sidebar is unaffected.
|
|
384
|
+
* @public
|
|
385
|
+
*/
|
|
386
|
+
export declare const commentsHidden: EditorAtom<boolean>;
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* A scrollable list of comment threads — each an avatar, byline, and a one-line preview.
|
|
390
|
+
* Presentational: you supply the items (already summarised) and an `onSelect` handler; the canvas
|
|
391
|
+
* `CanvasCommentsSidebar` wires it to the store, but a consumer can build their own list from this.
|
|
392
|
+
* @public @react
|
|
393
|
+
*/
|
|
394
|
+
export declare function CommentsList({ items, onSelect, header, headerAction, empty, resolvedLabel, renderItem }: CommentsListProps): JSX.Element;
|
|
395
|
+
|
|
396
|
+
/** @public */
|
|
397
|
+
export declare interface CommentsListProps {
|
|
398
|
+
items: CommentListItemProps[];
|
|
399
|
+
/** Called with a thread id when an item is chosen. */
|
|
400
|
+
onSelect?(id: string): void;
|
|
401
|
+
/** Shown above the list (e.g. "Comments"). Omit for none. */
|
|
402
|
+
header?: ReactNode;
|
|
403
|
+
/** Rendered at the right of the header row — e.g. a filter menu. */
|
|
404
|
+
headerAction?: ReactNode;
|
|
405
|
+
/** Shown in place of the list when there are no threads. */
|
|
406
|
+
empty?: ReactNode;
|
|
407
|
+
/** Label for a resolved thread's marker on its row. Defaults to "Resolved". */
|
|
408
|
+
resolvedLabel?: string;
|
|
409
|
+
/** Override how each item renders. Defaults to `<CommentListItem>`. */
|
|
410
|
+
renderItem?(item: CommentListItemProps): ReactNode;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
* A checkbox menu item for a "View" menu that shows/hides comment pins on the canvas — checked
|
|
415
|
+
* when comments are visible, like tldraw's own grid/snap toggles. Reads and toggles the shared
|
|
416
|
+
* {@link commentsHidden} signal, so it stays in sync with the Shift+C shortcut and the sidebar
|
|
417
|
+
* control. Drop it into whichever menu your app owns.
|
|
418
|
+
* @public @react
|
|
419
|
+
*/
|
|
420
|
+
export declare function CommentsMenuItem(): JSX.Element;
|
|
421
|
+
|
|
422
|
+
/** The overflow (⋯) dropdown in the sidebar header. For now it holds the hide/show-comments
|
|
423
|
+
* toggle; it's the home for later comment-wide controls (notifications, mark all as read).
|
|
424
|
+
* @public @react */
|
|
425
|
+
export declare function CommentsOverflowMenu(): JSX.Element;
|
|
426
|
+
|
|
427
|
+
/** A comment's body, rendered as markdown (bold, italic, code, links, lists). @public @react */
|
|
428
|
+
export declare function CommentText({ text }: CommentTextProps): JSX.Element;
|
|
429
|
+
|
|
430
|
+
/** @public */
|
|
431
|
+
export declare interface CommentTextProps {
|
|
432
|
+
/** Rich text body, authored as markdown. */
|
|
433
|
+
text: string;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* A comment thread: an optional header, an optional resolved banner, the comments, and an
|
|
438
|
+
* optional reply composer. Presentational — you supply the comments (as card props) and the
|
|
439
|
+
* composer's handlers; how each comment renders is overridable via `renderComment`.
|
|
440
|
+
* @public @react
|
|
441
|
+
*/
|
|
442
|
+
export declare function CommentThread({ comments, header, headerActions, resolvedBanner, composer, renderComment }: CommentThreadProps): JSX.Element;
|
|
443
|
+
|
|
444
|
+
/** @public */
|
|
445
|
+
export declare interface CommentThreadProps {
|
|
446
|
+
/** The thread's comments, already adapted to card props (oldest first). */
|
|
447
|
+
comments: CommentCardProps[];
|
|
448
|
+
/** Optional header, e.g. "Thread". Omit for no header. */
|
|
449
|
+
header?: ReactNode;
|
|
450
|
+
/** Action controls shown at the right of the header (resolve, delete, dismiss…). */
|
|
451
|
+
headerActions?: ReactNode;
|
|
452
|
+
/** When set, shows a banner above the comments (e.g. "Resolved by Jess"). */
|
|
453
|
+
resolvedBanner?: ReactNode;
|
|
454
|
+
/** Reply composer props. Omit for a read-only thread (no composer). */
|
|
455
|
+
composer?: CommentComposerProps;
|
|
456
|
+
/** Override how each comment renders. Defaults to `<CommentCard>`. */
|
|
457
|
+
renderComment?(comment: CommentCardProps, index: number): ReactNode;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* The comment tool. A click starts a point/shape thread (the pin tracks the shape it lands on);
|
|
462
|
+
* dragging out a rectangle starts a region thread anchored to that area. Placement only opens a
|
|
463
|
+
* composer (via `pendingComment`); the records are created when the comment is posted.
|
|
464
|
+
* @public
|
|
465
|
+
*/
|
|
466
|
+
export declare class CommentTool extends StateNode {
|
|
467
|
+
static id: string;
|
|
468
|
+
static initial: string;
|
|
469
|
+
static children(): TLStateNodeConstructor[];
|
|
470
|
+
/**
|
|
471
|
+
* Configure this tool's {@link CommentTool.options | `options`}, returning a configured subclass
|
|
472
|
+
* to register via `tools`. Mirrors `ShapeUtil.configure`. Layers over any prior `configure`, so
|
|
473
|
+
* calls can be chained.
|
|
474
|
+
*
|
|
475
|
+
* @example
|
|
476
|
+
* ```tsx
|
|
477
|
+
* <Tldraw tools={[CommentTool.configure({ history: 'ignore', enableClustering: false })]} />
|
|
478
|
+
* ```
|
|
479
|
+
*/
|
|
480
|
+
static configure<T extends TLStateNodeConstructor>(this: T, options: T extends new (...args: any[]) => {
|
|
481
|
+
options: infer Options;
|
|
482
|
+
} ? Partial<Options> : never): T;
|
|
483
|
+
/**
|
|
484
|
+
* The merged commenting options for this editor. Read from anywhere via
|
|
485
|
+
* {@link getCommentingOptions}. Override with {@link CommentTool.configure}.
|
|
486
|
+
*/
|
|
487
|
+
options: CommentingOptions;
|
|
488
|
+
onEnter(): void;
|
|
489
|
+
onCancel(): void;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
/** Registers the comment tool in the UI (icon, label, shortcut). Compose into your overrides.
|
|
493
|
+
* Once registered, tldraw's `DefaultToolbarContent` shows the comment button next to the eraser.
|
|
494
|
+
* @public */
|
|
495
|
+
export declare const commentToolOverrides: TLUiOverrides;
|
|
496
|
+
|
|
497
|
+
/** @public */
|
|
498
|
+
export declare const commentTools: typeof CommentTool[];
|
|
499
|
+
|
|
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
|
+
/** @public @react */
|
|
512
|
+
export declare function CountBadge({ count }: CountBadgeProps): JSX.Element;
|
|
513
|
+
|
|
514
|
+
/** @public */
|
|
515
|
+
export declare interface CountBadgeProps {
|
|
516
|
+
count: number;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
/** @public */
|
|
520
|
+
export declare function createClusterRuntime(table: ClusterTable): ClusterRuntime;
|
|
521
|
+
|
|
522
|
+
/**
|
|
523
|
+
* Build the TipTap `suggestion` config for the comment \@-picker. `getSuggestions(query)` is the
|
|
524
|
+
* host's resolver — it returns the members matching the query (sync or async); the SDK owns neither
|
|
525
|
+
* the roster nor the filtering. The plugin runs outside React, so `render` mounts `MentionPopup` via
|
|
526
|
+
* a `ReactRenderer`, forwards navigation keys through the popup's imperative handle, and lets it call
|
|
527
|
+
* `command` to insert.
|
|
528
|
+
* @public
|
|
529
|
+
*/
|
|
530
|
+
export declare function createMentionSuggestion(getSuggestions: (query: string) => MentionMember[] | Promise<MentionMember[]>, options?: MentionSuggestionOptions): Omit<SuggestionOptions<MentionMember, MentionNodeAttrs>, 'editor'>;
|
|
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
|
+
};
|
|
537
|
+
|
|
538
|
+
/** The out-of-the-box region config: disabled, and — when a consumer enables it — the current
|
|
539
|
+
* bottom-right / pointer-reveal / pin-move / corner-resize behaviour.
|
|
540
|
+
* @public */
|
|
541
|
+
export declare const DEFAULT_REGION_COMMENT_OPTIONS: RegionCommentOptions;
|
|
542
|
+
|
|
543
|
+
/** @public */
|
|
544
|
+
export declare const DEFAULT_SIDEBAR_FILTERS: SidebarFilters;
|
|
545
|
+
|
|
546
|
+
/**
|
|
547
|
+
* The default {@link CommentingOptions}. Override via `CommentTool.configure({ ... })`.
|
|
548
|
+
*
|
|
549
|
+
* @public
|
|
550
|
+
*/
|
|
551
|
+
export declare const defaultCommentingOptions: {
|
|
552
|
+
readonly clusterCullMargin: 120;
|
|
553
|
+
readonly clusterSplitZoomFactor: 1.05;
|
|
554
|
+
readonly components: {};
|
|
555
|
+
readonly dragHistory: undefined;
|
|
556
|
+
readonly enableClustering: true;
|
|
557
|
+
readonly history: "ignore";
|
|
558
|
+
readonly impreciseShapeAnchor: {
|
|
559
|
+
readonly x: 1;
|
|
560
|
+
readonly y: 0;
|
|
561
|
+
};
|
|
562
|
+
};
|
|
563
|
+
|
|
564
|
+
/** The empty state shown when a thread has no comments yet. @public @react */
|
|
565
|
+
export declare function EmptyState({ message }: EmptyStateProps): JSX.Element;
|
|
566
|
+
|
|
567
|
+
/** @public */
|
|
568
|
+
export declare interface EmptyStateProps {
|
|
569
|
+
message: string;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
/** Members whose name contains the query (case-insensitive), capped to the popup's length.
|
|
573
|
+
* @public */
|
|
574
|
+
export declare function filterMentionMembers(members: MentionMember[], query: string): MentionMember[];
|
|
575
|
+
|
|
576
|
+
/** 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, impreciseShapeAnchor?: {
|
|
578
|
+
x: number;
|
|
579
|
+
y: number;
|
|
580
|
+
}): void;
|
|
581
|
+
|
|
582
|
+
/**
|
|
583
|
+
* Format an ISO datetime as relative time ("2 hours ago", "yesterday", "last week").
|
|
584
|
+
* Locale-aware via Intl.RelativeTimeFormat.
|
|
585
|
+
* @public
|
|
586
|
+
*/
|
|
587
|
+
export declare function formatRelativeTime(iso: string, locale?: string): string;
|
|
588
|
+
|
|
589
|
+
/**
|
|
590
|
+
* The merged {@link CommentingOptions} for an editor, read off the registered comment tool (which
|
|
591
|
+
* carries them via `CommentTool.configure`). Falls back to {@link defaultCommentingOptions} when
|
|
592
|
+
* the comment tool isn't registered. Usable from anywhere with an `Editor` — including the tool's
|
|
593
|
+
* own state, which has no React context.
|
|
594
|
+
*
|
|
595
|
+
* @public
|
|
596
|
+
*/
|
|
597
|
+
export declare function getCommentingOptions(editor: Editor): CommentingOptions;
|
|
598
|
+
|
|
599
|
+
/** Read one comment record by id, or `undefined` if the id isn't a present comment record. @public */
|
|
600
|
+
export declare function getCommentRecord(editor: Editor, id: string): TLCommentRecord | undefined;
|
|
601
|
+
|
|
602
|
+
/** All comments currently in the store (non-reactive; wrap in `useValue` to react). @public */
|
|
603
|
+
export declare function getComments(editor: Editor): TLComment[];
|
|
604
|
+
|
|
605
|
+
/** All comment threads currently in the store (non-reactive; wrap in `useValue` to react). @public */
|
|
606
|
+
export declare function getCommentThreads(editor: Editor): TLCommentThread[];
|
|
607
|
+
|
|
608
|
+
/**
|
|
609
|
+
* One comment thread's pin, already resolved to a page-space anchor point.
|
|
610
|
+
* @public
|
|
611
|
+
*/
|
|
612
|
+
export declare interface LeafInput {
|
|
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;
|
|
621
|
+
|
|
622
|
+
/**
|
|
623
|
+
* The \@-mention member picker: a popover list of people to mention, shown as the user types after
|
|
624
|
+
* `@`. Presentational — the composer's suggestion plugin owns resolution, keyboard navigation, and
|
|
625
|
+
* placement, and drives this with the host-resolved `members` and the highlighted `activeIndex`.
|
|
626
|
+
* @public @react
|
|
627
|
+
*/
|
|
628
|
+
export declare function MentionList({ members, activeIndex, onSelect, emptyLabel, renderMember }: MentionListProps): JSX.Element;
|
|
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
|
+
}
|
|
643
|
+
|
|
644
|
+
/** A person the composer's \@-mention picker can offer. @public */
|
|
645
|
+
export declare interface MentionMember {
|
|
646
|
+
id: string;
|
|
647
|
+
name: string;
|
|
648
|
+
/** Avatar image URL. Falls back to a coloured initial when omitted. */
|
|
649
|
+
avatar?: string;
|
|
650
|
+
/** Avatar background colour, used when there's no `avatar` image. */
|
|
651
|
+
color?: string;
|
|
652
|
+
/** A secondary line under the name — e.g. an email or handle. Omit for a single-line row. */
|
|
653
|
+
secondary?: string;
|
|
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
|
+
}
|
|
664
|
+
|
|
665
|
+
/** @public */
|
|
666
|
+
export declare interface MentionSuggestionOptions {
|
|
667
|
+
/** Override a member row's content in the picker. Defaults to avatar + name (+ secondary). */
|
|
668
|
+
renderMember?(member: MentionMember): ReactNode;
|
|
669
|
+
/**
|
|
670
|
+
* The tldraw editor the composer lives in. When provided, the popup re-anchors reactively as the
|
|
671
|
+
* canvas camera moves (the composer rides it) instead of polling every frame. Omit off-canvas.
|
|
672
|
+
*/
|
|
673
|
+
editor?: null | Editor;
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
/**
|
|
677
|
+
* A finalized merge event, ready for the runtime.
|
|
678
|
+
* @public
|
|
679
|
+
*/
|
|
680
|
+
export declare interface MergeEvent {
|
|
681
|
+
zMerge: number;
|
|
682
|
+
/** Reverses (splits) when zoom \>= zSplit. Always \> zMerge. May be +Infinity. */
|
|
683
|
+
zSplit: number;
|
|
684
|
+
children: ClusterNode[];
|
|
685
|
+
result: ClusterNode;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
/** The id of the one open thread (only one popover is open at a time), or null when all closed.
|
|
689
|
+
* @public */
|
|
690
|
+
export declare const openThreadId: EditorAtom<null | string>;
|
|
691
|
+
|
|
692
|
+
/** A comment being placed but not yet posted: where its composer sits and what it will anchor
|
|
693
|
+
* to. Shared between the tool (which sets it on click) and the overlay (which renders the
|
|
694
|
+
* composer). Null when nothing is being placed. The atom itself lives in `./state`
|
|
695
|
+
* ({@link pendingComment}), scoped per editor.
|
|
696
|
+
* @public */
|
|
697
|
+
export declare interface PendingComment {
|
|
698
|
+
anchor: TLCommentAnchor;
|
|
699
|
+
/** Page point where the composer opens (the click location, or a region's pin corner). */
|
|
700
|
+
point: VecLike;
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
/** The comment currently being placed (composer open, not yet posted), or null.
|
|
704
|
+
* @public */
|
|
705
|
+
export declare const pendingComment: EditorAtom<null | PendingComment>;
|
|
706
|
+
|
|
707
|
+
/** Write comment records to the store. @public */
|
|
708
|
+
export declare function putCommentRecords(editor: Editor, records: TLCommentRecord[]): void;
|
|
709
|
+
|
|
710
|
+
/** A single emoji reaction pill with a count, highlighted when the user reacted. @public @react */
|
|
711
|
+
export declare function Reaction({ emoji, count, active }: ReactionProps): JSX.Element;
|
|
712
|
+
|
|
713
|
+
/** @public */
|
|
714
|
+
export declare interface ReactionProps {
|
|
715
|
+
emoji: string;
|
|
716
|
+
count: number;
|
|
717
|
+
active: boolean;
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
/** The row of reactions under a comment, plus an add-reaction button. @public @react */
|
|
721
|
+
export declare function Reactions(): JSX.Element;
|
|
722
|
+
|
|
723
|
+
/**
|
|
724
|
+
* The configurable dimensions of region comments — a design surface for prototyping the interaction
|
|
725
|
+
* before settling it. Region is **off by default**, so a consumer that leaves it unset keeps plain
|
|
726
|
+
* click-only point/shape commenting. Set it per editor through `<CanvasComments regionOptions>`.
|
|
727
|
+
* @public
|
|
728
|
+
*/
|
|
729
|
+
export declare interface RegionCommentOptions {
|
|
730
|
+
/** Whether dragging the comment tool out creates a region anchor. Off → click-only. */
|
|
731
|
+
enabled: boolean;
|
|
732
|
+
/** Which corner the pin and composer sit on, as a normalized 0–1 offset. Default bottom-right. */
|
|
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';
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
/** Remove comment records from the store by id. @public */
|
|
744
|
+
export declare function removeCommentRecords(editor: Editor, ids: (TLCommentId | TLCommentThreadId)[]): void;
|
|
745
|
+
|
|
746
|
+
/**
|
|
747
|
+
* Minimal markdown for comment bodies: paragraphs, line breaks, bullet lists, and
|
|
748
|
+
* inline **bold**, *italic*, `code`, and [links](url). Not a full CommonMark parser —
|
|
749
|
+
* just the markdown people actually write in comments. Renders React elements only —
|
|
750
|
+
* never raw HTML — so there's no HTML-injection surface.
|
|
751
|
+
* @public
|
|
752
|
+
*/
|
|
753
|
+
export declare function renderMarkdown(text: string): ReactNode;
|
|
754
|
+
|
|
755
|
+
/**
|
|
756
|
+
* Flatten a rich-text comment body to plaintext through the limited comment extension set,
|
|
757
|
+
* separating paragraphs and list items with newlines. A convenience for consumers rendering bodies
|
|
758
|
+
* as plain text (e.g. the sidebar preview); richer rendering can read the `TLRichText` directly.
|
|
759
|
+
* @public
|
|
760
|
+
*/
|
|
761
|
+
export declare function richTextToPlaintext(body: TLRichText, resolveName?: (id: string) => string | undefined): string;
|
|
762
|
+
|
|
763
|
+
/** The button that posts a comment. @public @react */
|
|
764
|
+
export declare function SendButton({ label, disabled, onClick }: SendButtonProps): JSX.Element;
|
|
765
|
+
|
|
766
|
+
/** @public */
|
|
767
|
+
export declare interface SendButtonProps {
|
|
768
|
+
label: string;
|
|
769
|
+
disabled?: boolean;
|
|
770
|
+
onClick?(): void;
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
/**
|
|
774
|
+
* A shape anchor for a page point. `x`/`y` are the point's normalized (0–1) offset within the
|
|
775
|
+
* shape's page bounds, remembered either way. When `precise` (Alt held) the pin sits at exactly
|
|
776
|
+
* `x`/`y`; otherwise it sits at the consumer's imprecise default (top-right out of the box).
|
|
777
|
+
* @public
|
|
778
|
+
*/
|
|
779
|
+
export declare function shapeAnchorAt(editor: Editor, shapeId: TLShapeId, page: {
|
|
780
|
+
x: number;
|
|
781
|
+
y: number;
|
|
782
|
+
}, precise: boolean): TLCommentAnchor;
|
|
783
|
+
|
|
784
|
+
/**
|
|
785
|
+
* Which threads the comments sidebar shows. Held as an editor-scoped signal (the `sidebarFilters`
|
|
786
|
+
* `EditorAtom` in `./state`) rather than component state so it survives the sidebar
|
|
787
|
+
* unmounting when the comment tool deactivates — a user's "hide resolved" choice shouldn't reset
|
|
788
|
+
* every time they leave the tool.
|
|
789
|
+
* @public
|
|
790
|
+
*/
|
|
791
|
+
export declare interface SidebarFilters {
|
|
792
|
+
/** Include resolved threads. */
|
|
793
|
+
showResolved: boolean;
|
|
794
|
+
/** Only threads the current user started. Ignored when there's no current user. */
|
|
795
|
+
onlyMine: boolean;
|
|
796
|
+
/** Only threads with unread comments. Ignored when the host provides no read status. */
|
|
797
|
+
onlyUnread: boolean;
|
|
798
|
+
/** Only threads on the current page. Off = every page's threads, each labelled. */
|
|
799
|
+
onlyCurrentPage: boolean;
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
/** Which threads the comments sidebar shows.
|
|
803
|
+
* @public */
|
|
804
|
+
export declare const sidebarFilters: EditorAtom<SidebarFilters>;
|
|
805
|
+
|
|
806
|
+
/**
|
|
807
|
+
* Typed access to comment records on the editor store.
|
|
808
|
+
*
|
|
809
|
+
* Comment threads and comments live on the editor's local store so the canvas can render them
|
|
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.
|
|
815
|
+
*/
|
|
816
|
+
/** A record that lives in a comment thread: the thread itself or one of its messages. @public */
|
|
817
|
+
export declare type TLCommentRecord = TLComment | TLCommentThread;
|
|
818
|
+
|
|
819
|
+
/** Toggle comment-pin visibility for an editor.
|
|
820
|
+
* @public */
|
|
821
|
+
export declare function toggleCommentsHidden(editor: Editor): void;
|
|
822
|
+
|
|
823
|
+
/**
|
|
824
|
+
* Whether commenting is licensed for this editor. Enabled in development; in production it requires
|
|
825
|
+
* a tldraw license that includes the commenting feature (or the collaboration umbrella that grants
|
|
826
|
+
* it). Reactive: re-reads when license validation resolves, and returns `false` while validation is
|
|
827
|
+
* pending, so gated UI stays hidden until the license is confirmed.
|
|
828
|
+
*
|
|
829
|
+
* The built-in commenting components (`CanvasComments`, `CanvasCommentsSidebar`, and the comment
|
|
830
|
+
* tool's toolbar button) gate on this. Use it to gate any custom commenting UI the same way.
|
|
831
|
+
* @public
|
|
832
|
+
*/
|
|
833
|
+
export declare function useCommentingEnabled(): boolean;
|
|
834
|
+
|
|
835
|
+
/**
|
|
836
|
+
* React hook for {@link getCommentingOptions}. Options are fixed per editor (set at tool
|
|
837
|
+
* registration), so this doesn't need to be reactive.
|
|
838
|
+
*
|
|
839
|
+
* @public
|
|
840
|
+
*/
|
|
841
|
+
export declare function useCommentingOptions(): CommentingOptions;
|
|
842
|
+
|
|
843
|
+
/** Every comment in the store, oldest first, reactively. Group by `threadId` for per-thread lists. @public */
|
|
844
|
+
export declare function useComments(editor: Editor): TLComment[];
|
|
845
|
+
|
|
846
|
+
/** React hook for whether comment pins are hidden.
|
|
847
|
+
* @public */
|
|
848
|
+
export declare function useCommentsHidden(): boolean;
|
|
849
|
+
|
|
850
|
+
/** All comment threads in the store, reactively. @public */
|
|
851
|
+
export declare function useCommentThreads(editor: Editor): TLCommentThread[];
|
|
852
|
+
|
|
853
|
+
/** React hook for the open thread id.
|
|
854
|
+
* @public */
|
|
855
|
+
export declare function useOpenThreadId(): null | string;
|
|
856
|
+
|
|
857
|
+
/** React hook for the pending (being-placed) comment.
|
|
858
|
+
* @public */
|
|
859
|
+
export declare function usePendingComment(): null | PendingComment;
|
|
860
|
+
|
|
861
|
+
/** React hook for the current sidebar filters.
|
|
862
|
+
* @public */
|
|
863
|
+
export declare function useSidebarFilters(): SidebarFilters;
|
|
864
|
+
|
|
865
|
+
/** A thread's comments, oldest first, reactively. @public */
|
|
866
|
+
export declare function useThreadComments(editor: Editor, threadId: TLCommentThreadId): TLComment[];
|
|
867
|
+
|
|
868
|
+
export { }
|