@tldraw/commenting 5.3.0-internal.c5c7f1d817d0 → 5.3.0-next.2fa9c61a8de6

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.
Files changed (268) hide show
  1. package/README.md +0 -2
  2. package/commenting.css +1040 -230
  3. package/dist-cjs/canvas/anchor-lifecycle.js +148 -0
  4. package/dist-cjs/canvas/anchor-lifecycle.js.map +7 -0
  5. package/dist-cjs/canvas/cluster-input.js +2 -2
  6. package/dist-cjs/canvas/cluster-input.js.map +2 -2
  7. package/dist-cjs/canvas/comment-drafts.js +54 -0
  8. package/dist-cjs/canvas/comment-drafts.js.map +7 -0
  9. package/dist-cjs/canvas/comment-mutations.js +123 -0
  10. package/dist-cjs/canvas/comment-mutations.js.map +7 -0
  11. package/dist-cjs/canvas/comment-reactions.js +163 -0
  12. package/dist-cjs/canvas/comment-reactions.js.map +7 -0
  13. package/dist-cjs/canvas/comment-render.js +5 -3
  14. package/dist-cjs/canvas/comment-render.js.map +2 -2
  15. package/dist-cjs/canvas/comment-store.js +19 -9
  16. package/dist-cjs/canvas/comment-store.js.map +2 -2
  17. package/dist-cjs/canvas/comment-tool.js +64 -14
  18. package/dist-cjs/canvas/comment-tool.js.map +2 -2
  19. package/dist-cjs/canvas/comments-filter-menu.js +20 -38
  20. package/dist-cjs/canvas/comments-filter-menu.js.map +2 -2
  21. package/dist-cjs/canvas/comments-overflow-menu.js +22 -27
  22. package/dist-cjs/canvas/comments-overflow-menu.js.map +2 -2
  23. package/dist-cjs/canvas/comments-overlay.js +377 -437
  24. package/dist-cjs/canvas/comments-overlay.js.map +2 -2
  25. package/dist-cjs/canvas/comments-sidebar.js +34 -31
  26. package/dist-cjs/canvas/comments-sidebar.js.map +2 -2
  27. package/dist-cjs/canvas/comments-visibility-toggle.js +65 -0
  28. package/dist-cjs/canvas/comments-visibility-toggle.js.map +7 -0
  29. package/dist-cjs/canvas/context.js +17 -0
  30. package/dist-cjs/canvas/context.js.map +7 -0
  31. package/dist-cjs/canvas/hooks.js +22 -3
  32. package/dist-cjs/canvas/hooks.js.map +2 -2
  33. package/dist-cjs/canvas/options.js +19 -2
  34. package/dist-cjs/canvas/options.js.map +2 -2
  35. package/dist-cjs/canvas/pin-stacking.js +56 -0
  36. package/dist-cjs/canvas/pin-stacking.js.map +7 -0
  37. package/dist-cjs/canvas/sidebar-filters.js +2 -2
  38. package/dist-cjs/canvas/sidebar-filters.js.map +2 -2
  39. package/dist-cjs/canvas/state.js +28 -14
  40. package/dist-cjs/canvas/state.js.map +2 -2
  41. package/dist-cjs/canvas/thread-preview.js +185 -0
  42. package/dist-cjs/canvas/thread-preview.js.map +7 -0
  43. package/dist-cjs/canvas/thread-stack.js +199 -0
  44. package/dist-cjs/canvas/thread-stack.js.map +7 -0
  45. package/dist-cjs/canvas/thread-state.js +67 -21
  46. package/dist-cjs/canvas/thread-state.js.map +2 -2
  47. package/dist-cjs/canvas/thread-view.js +397 -0
  48. package/dist-cjs/canvas/thread-view.js.map +7 -0
  49. package/dist-cjs/clustering/computeClusterTable.js +4 -4
  50. package/dist-cjs/clustering/computeClusterTable.js.map +2 -2
  51. package/dist-cjs/clustering/runtime.js +9 -9
  52. package/dist-cjs/clustering/runtime.js.map +2 -2
  53. package/dist-cjs/clustering/types.js.map +1 -1
  54. package/dist-cjs/index.d.ts +763 -353
  55. package/dist-cjs/index.js +46 -28
  56. package/dist-cjs/index.js.map +2 -2
  57. package/dist-cjs/ui/byline.js +3 -1
  58. package/dist-cjs/ui/byline.js.map +2 -2
  59. package/dist-cjs/ui/comment-card.js +12 -5
  60. package/dist-cjs/ui/comment-card.js.map +2 -2
  61. package/dist-cjs/ui/comment-composer.js +112 -17
  62. package/dist-cjs/ui/comment-composer.js.map +2 -2
  63. package/dist-cjs/ui/comment-pin.js +20 -2
  64. package/dist-cjs/ui/comment-pin.js.map +2 -2
  65. package/dist-cjs/ui/comment-thread.js +4 -2
  66. package/dist-cjs/ui/comment-thread.js.map +2 -2
  67. package/dist-cjs/ui/comments-list.js +22 -10
  68. package/dist-cjs/ui/comments-list.js.map +2 -2
  69. package/dist-cjs/ui/count-badge.js +3 -2
  70. package/dist-cjs/ui/count-badge.js.map +2 -2
  71. package/dist-cjs/ui/emoji-picker.js +54 -0
  72. package/dist-cjs/ui/emoji-picker.js.map +7 -0
  73. package/dist-cjs/ui/format-time.js +4 -1
  74. package/dist-cjs/ui/format-time.js.map +2 -2
  75. package/dist-cjs/ui/reaction-picker.js +73 -0
  76. package/dist-cjs/ui/reaction-picker.js.map +7 -0
  77. package/dist-cjs/ui/reaction.js +50 -4
  78. package/dist-cjs/ui/reaction.js.map +2 -2
  79. package/dist-cjs/ui/reactions.js +20 -15
  80. package/dist-cjs/ui/reactions.js.map +2 -2
  81. package/dist-cjs/ui/{mention.js → reply-count.js} +9 -11
  82. package/dist-cjs/ui/reply-count.js.map +7 -0
  83. package/dist-cjs/ui/send-button.js +20 -1
  84. package/dist-cjs/ui/send-button.js.map +2 -2
  85. package/dist-cjs/ui/{comment-text.js → tooltip-button.js} +12 -9
  86. package/dist-cjs/ui/tooltip-button.js.map +7 -0
  87. package/dist-esm/canvas/anchor-lifecycle.mjs +128 -0
  88. package/dist-esm/canvas/anchor-lifecycle.mjs.map +7 -0
  89. package/dist-esm/canvas/cluster-input.mjs +2 -2
  90. package/dist-esm/canvas/cluster-input.mjs.map +2 -2
  91. package/dist-esm/canvas/comment-drafts.mjs +34 -0
  92. package/dist-esm/canvas/comment-drafts.mjs.map +7 -0
  93. package/dist-esm/canvas/comment-mutations.mjs +103 -0
  94. package/dist-esm/canvas/comment-mutations.mjs.map +7 -0
  95. package/dist-esm/canvas/comment-reactions.mjs +152 -0
  96. package/dist-esm/canvas/comment-reactions.mjs.map +7 -0
  97. package/dist-esm/canvas/comment-render.mjs +5 -3
  98. package/dist-esm/canvas/comment-render.mjs.map +2 -2
  99. package/dist-esm/canvas/comment-store.mjs +19 -9
  100. package/dist-esm/canvas/comment-store.mjs.map +2 -2
  101. package/dist-esm/canvas/comment-tool.mjs +67 -17
  102. package/dist-esm/canvas/comment-tool.mjs.map +2 -2
  103. package/dist-esm/canvas/comments-filter-menu.mjs +20 -38
  104. package/dist-esm/canvas/comments-filter-menu.mjs.map +2 -2
  105. package/dist-esm/canvas/comments-overflow-menu.mjs +23 -27
  106. package/dist-esm/canvas/comments-overflow-menu.mjs.map +2 -2
  107. package/dist-esm/canvas/comments-overlay.mjs +398 -442
  108. package/dist-esm/canvas/comments-overlay.mjs.map +3 -3
  109. package/dist-esm/canvas/comments-sidebar.mjs +37 -34
  110. package/dist-esm/canvas/comments-sidebar.mjs.map +2 -2
  111. package/dist-esm/canvas/comments-visibility-toggle.mjs +45 -0
  112. package/dist-esm/canvas/comments-visibility-toggle.mjs.map +7 -0
  113. package/dist-esm/canvas/context.mjs +1 -0
  114. package/dist-esm/canvas/context.mjs.map +7 -0
  115. package/dist-esm/canvas/hooks.mjs +28 -5
  116. package/dist-esm/canvas/hooks.mjs.map +2 -2
  117. package/dist-esm/canvas/options.mjs +21 -3
  118. package/dist-esm/canvas/options.mjs.map +2 -2
  119. package/dist-esm/canvas/pin-stacking.mjs +36 -0
  120. package/dist-esm/canvas/pin-stacking.mjs.map +7 -0
  121. package/dist-esm/canvas/sidebar-filters.mjs +2 -2
  122. package/dist-esm/canvas/sidebar-filters.mjs.map +2 -2
  123. package/dist-esm/canvas/state.mjs +29 -19
  124. package/dist-esm/canvas/state.mjs.map +2 -2
  125. package/dist-esm/canvas/thread-preview.mjs +170 -0
  126. package/dist-esm/canvas/thread-preview.mjs.map +7 -0
  127. package/dist-esm/canvas/thread-stack.mjs +190 -0
  128. package/dist-esm/canvas/thread-stack.mjs.map +7 -0
  129. package/dist-esm/canvas/thread-state.mjs +71 -22
  130. package/dist-esm/canvas/thread-state.mjs.map +2 -2
  131. package/dist-esm/canvas/thread-view.mjs +402 -0
  132. package/dist-esm/canvas/thread-view.mjs.map +7 -0
  133. package/dist-esm/clustering/computeClusterTable.mjs +4 -4
  134. package/dist-esm/clustering/computeClusterTable.mjs.map +2 -2
  135. package/dist-esm/clustering/runtime.mjs +9 -9
  136. package/dist-esm/clustering/runtime.mjs.map +2 -2
  137. package/dist-esm/index.d.mts +763 -353
  138. package/dist-esm/index.mjs +87 -41
  139. package/dist-esm/index.mjs.map +2 -2
  140. package/dist-esm/ui/byline.mjs +3 -1
  141. package/dist-esm/ui/byline.mjs.map +2 -2
  142. package/dist-esm/ui/comment-card.mjs +12 -5
  143. package/dist-esm/ui/comment-card.mjs.map +2 -2
  144. package/dist-esm/ui/comment-composer.mjs +122 -16
  145. package/dist-esm/ui/comment-composer.mjs.map +2 -2
  146. package/dist-esm/ui/comment-pin.mjs +20 -2
  147. package/dist-esm/ui/comment-pin.mjs.map +2 -2
  148. package/dist-esm/ui/comment-thread.mjs +4 -2
  149. package/dist-esm/ui/comment-thread.mjs.map +2 -2
  150. package/dist-esm/ui/comments-list.mjs +39 -25
  151. package/dist-esm/ui/comments-list.mjs.map +2 -2
  152. package/dist-esm/ui/count-badge.mjs +3 -2
  153. package/dist-esm/ui/count-badge.mjs.map +2 -2
  154. package/dist-esm/ui/emoji-picker.mjs +34 -0
  155. package/dist-esm/ui/emoji-picker.mjs.map +7 -0
  156. package/dist-esm/ui/format-time.mjs +4 -1
  157. package/dist-esm/ui/format-time.mjs.map +2 -2
  158. package/dist-esm/ui/reaction-picker.mjs +60 -0
  159. package/dist-esm/ui/reaction-picker.mjs.map +7 -0
  160. package/dist-esm/ui/reaction.mjs +51 -5
  161. package/dist-esm/ui/reaction.mjs.map +2 -2
  162. package/dist-esm/ui/reactions.mjs +21 -16
  163. package/dist-esm/ui/reactions.mjs.map +2 -2
  164. package/dist-esm/ui/reply-count.mjs +9 -0
  165. package/dist-esm/ui/reply-count.mjs.map +7 -0
  166. package/dist-esm/ui/send-button.mjs +20 -1
  167. package/dist-esm/ui/send-button.mjs.map +2 -2
  168. package/dist-esm/ui/tooltip-button.mjs +12 -0
  169. package/dist-esm/ui/tooltip-button.mjs.map +7 -0
  170. package/package.json +6 -6
  171. package/src/canvas/anchor-lifecycle.test.ts +290 -0
  172. package/src/canvas/anchor-lifecycle.ts +205 -0
  173. package/src/canvas/canvas.css +439 -24
  174. package/src/canvas/cluster-input.test.ts +31 -23
  175. package/src/canvas/cluster-input.ts +3 -4
  176. package/src/canvas/comment-drafts.test.ts +55 -0
  177. package/src/canvas/comment-drafts.ts +46 -0
  178. package/src/canvas/comment-mutations.test.ts +410 -0
  179. package/src/canvas/comment-mutations.ts +288 -0
  180. package/src/canvas/comment-reactions.test.ts +132 -0
  181. package/src/canvas/comment-reactions.tsx +245 -0
  182. package/src/canvas/comment-render.ts +9 -5
  183. package/src/canvas/comment-store.ts +67 -27
  184. package/src/canvas/comment-tool.test.ts +162 -0
  185. package/src/canvas/comment-tool.tsx +105 -23
  186. package/src/canvas/comments-filter-menu.tsx +23 -32
  187. package/src/canvas/comments-overflow-menu.tsx +12 -19
  188. package/src/canvas/comments-overlay.tsx +602 -562
  189. package/src/canvas/comments-sidebar.test.ts +45 -0
  190. package/src/canvas/comments-sidebar.tsx +75 -57
  191. package/src/canvas/comments-visibility-toggle.tsx +49 -0
  192. package/src/canvas/context.ts +47 -0
  193. package/src/canvas/hooks.ts +52 -11
  194. package/src/canvas/options.test.ts +52 -2
  195. package/src/canvas/options.ts +133 -9
  196. package/src/canvas/pin-stacking.test.ts +114 -0
  197. package/src/canvas/pin-stacking.ts +57 -0
  198. package/src/canvas/sidebar-filters.ts +4 -3
  199. package/src/canvas/state.ts +92 -35
  200. package/src/canvas/thread-preview.test.ts +91 -0
  201. package/src/canvas/thread-preview.tsx +304 -0
  202. package/src/canvas/thread-stack.tsx +252 -0
  203. package/src/canvas/thread-state.test.ts +209 -0
  204. package/src/canvas/thread-state.ts +137 -36
  205. package/src/canvas/thread-view.tsx +516 -0
  206. package/src/clustering/computeClusterTable.test.ts +24 -23
  207. package/src/clustering/computeClusterTable.ts +5 -5
  208. package/src/clustering/runtime.test.ts +34 -0
  209. package/src/clustering/runtime.ts +20 -15
  210. package/src/clustering/types.ts +9 -9
  211. package/src/index.ts +76 -40
  212. package/src/ui/byline.tsx +4 -2
  213. package/src/ui/comment-card.tsx +17 -7
  214. package/src/ui/comment-composer.tsx +160 -13
  215. package/src/ui/comment-pin.tsx +22 -2
  216. package/src/ui/comment-thread.tsx +6 -1
  217. package/src/ui/comments-list.test.ts +31 -0
  218. package/src/ui/comments-list.tsx +32 -12
  219. package/src/ui/comments.css +489 -204
  220. package/src/ui/count-badge.tsx +9 -2
  221. package/src/ui/emoji-picker.test.ts +25 -0
  222. package/src/ui/emoji-picker.tsx +76 -0
  223. package/src/ui/format-time.ts +7 -2
  224. package/src/ui/reaction-picker.tsx +109 -0
  225. package/src/ui/reaction.tsx +116 -4
  226. package/src/ui/reactions.tsx +68 -13
  227. package/src/ui/reply-count.ts +16 -0
  228. package/src/ui/send-button.tsx +18 -3
  229. package/src/ui/tooltip-button.tsx +20 -0
  230. package/dist-cjs/canvas/region-options.js +0 -49
  231. package/dist-cjs/canvas/region-options.js.map +0 -7
  232. package/dist-cjs/ui/avatar.js +0 -51
  233. package/dist-cjs/ui/avatar.js.map +0 -7
  234. package/dist-cjs/ui/comment-mention.js +0 -42
  235. package/dist-cjs/ui/comment-mention.js.map +0 -7
  236. package/dist-cjs/ui/comment-text.js.map +0 -7
  237. package/dist-cjs/ui/mention-list.js +0 -70
  238. package/dist-cjs/ui/mention-list.js.map +0 -7
  239. package/dist-cjs/ui/mention-suggestion.js +0 -206
  240. package/dist-cjs/ui/mention-suggestion.js.map +0 -7
  241. package/dist-cjs/ui/mention.js.map +0 -7
  242. package/dist-cjs/ui/render-markdown.js +0 -63
  243. package/dist-cjs/ui/render-markdown.js.map +0 -7
  244. package/dist-esm/canvas/region-options.mjs +0 -29
  245. package/dist-esm/canvas/region-options.mjs.map +0 -7
  246. package/dist-esm/ui/avatar.mjs +0 -31
  247. package/dist-esm/ui/avatar.mjs.map +0 -7
  248. package/dist-esm/ui/comment-mention.mjs +0 -22
  249. package/dist-esm/ui/comment-mention.mjs.map +0 -7
  250. package/dist-esm/ui/comment-text.mjs +0 -9
  251. package/dist-esm/ui/comment-text.mjs.map +0 -7
  252. package/dist-esm/ui/mention-list.mjs +0 -50
  253. package/dist-esm/ui/mention-list.mjs.map +0 -7
  254. package/dist-esm/ui/mention-suggestion.mjs +0 -186
  255. package/dist-esm/ui/mention-suggestion.mjs.map +0 -7
  256. package/dist-esm/ui/mention.mjs +0 -11
  257. package/dist-esm/ui/mention.mjs.map +0 -7
  258. package/dist-esm/ui/render-markdown.mjs +0 -45
  259. package/dist-esm/ui/render-markdown.mjs.map +0 -7
  260. package/src/canvas/region-options.ts +0 -57
  261. package/src/ui/avatar.tsx +0 -38
  262. package/src/ui/comment-mention.ts +0 -47
  263. package/src/ui/comment-text.tsx +0 -12
  264. package/src/ui/mention-list.tsx +0 -106
  265. package/src/ui/mention-suggestion.test.ts +0 -18
  266. package/src/ui/mention-suggestion.tsx +0 -285
  267. package/src/ui/mention.tsx +0 -9
  268. package/src/ui/render-markdown.tsx +0 -72
package/dist-cjs/index.js CHANGED
@@ -18,7 +18,7 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
  var index_exports = {};
20
20
  __export(index_exports, {
21
- Avatar: () => import_avatar.Avatar,
21
+ Avatar: () => import_mentions.Avatar,
22
22
  Byline: () => import_byline.Byline,
23
23
  CanvasComments: () => import_comments_overlay.CanvasComments,
24
24
  CanvasCommentsSidebar: () => import_comments_sidebar.CanvasCommentsSidebar,
@@ -26,101 +26,119 @@ __export(index_exports, {
26
26
  CommentCard: () => import_comment_card.CommentCard,
27
27
  CommentComposer: () => import_comment_composer.CommentComposer,
28
28
  CommentPin: () => import_comment_pin.CommentPin,
29
- CommentText: () => import_comment_text.CommentText,
29
+ CommentReactionPicker: () => import_comment_reactions.CommentReactionPicker,
30
+ CommentReactions: () => import_comment_reactions.CommentReactions,
30
31
  CommentThread: () => import_comment_thread.CommentThread,
31
32
  CommentTool: () => import_comment_tool.CommentTool,
32
33
  CommentsFilterMenu: () => import_comments_filter_menu.CommentsFilterMenu,
33
34
  CommentsList: () => import_comments_list.CommentsList,
34
35
  CommentsMenuItem: () => import_comments_menu_item.CommentsMenuItem,
35
36
  CommentsOverflowMenu: () => import_comments_overflow_menu.CommentsOverflowMenu,
37
+ CommentsVisibilityToggle: () => import_comments_visibility_toggle.CommentsVisibilityToggle,
36
38
  CountBadge: () => import_count_badge.CountBadge,
37
- DEFAULT_IMPRECISE_SHAPE_ANCHOR: () => import_thread_state.DEFAULT_IMPRECISE_SHAPE_ANCHOR,
38
- DEFAULT_REGION_COMMENT_OPTIONS: () => import_region_options.DEFAULT_REGION_COMMENT_OPTIONS,
39
+ DEFAULT_REACTION_EMOJI: () => import_emoji_picker.DEFAULT_REACTION_EMOJI,
39
40
  DEFAULT_SIDEBAR_FILTERS: () => import_sidebar_filters.DEFAULT_SIDEBAR_FILTERS,
41
+ DefaultReactionTooltip: () => import_reaction.DefaultReactionTooltip,
42
+ DefaultReactionTooltipContent: () => import_reaction.DefaultReactionTooltipContent,
43
+ EmojiPicker: () => import_emoji_picker.EmojiPicker,
40
44
  EmptyState: () => import_empty_state.EmptyState,
41
- Mention: () => import_mention.Mention,
42
- MentionList: () => import_mention_list.MentionList,
45
+ Mention: () => import_mentions.Mention,
46
+ MentionList: () => import_mentions.MentionList,
43
47
  Reaction: () => import_reaction.Reaction,
48
+ ReactionPicker: () => import_reaction_picker.ReactionPicker,
44
49
  Reactions: () => import_reactions.Reactions,
45
50
  SendButton: () => import_send_button.SendButton,
46
51
  anchorPagePoint: () => import_thread_state.anchorPagePoint,
47
- collectClusterLeaves: () => import_cluster_input.collectClusterLeaves,
48
52
  commentToolOverrides: () => import_comment_tool.commentToolOverrides,
49
53
  commentTools: () => import_comment_tool.commentTools,
50
54
  commentsHidden: () => import_state.commentsHidden,
51
- commitCommentMutation: () => import_state.commitCommentMutation,
52
- computeClusterTable: () => import_computeClusterTable.computeClusterTable,
53
- createClusterRuntime: () => import_runtime.createClusterRuntime,
54
- createMentionSuggestion: () => import_mention_suggestion.createMentionSuggestion,
55
+ commentsSidebarOpen: () => import_state.commentsSidebarOpen,
56
+ createMentionSuggestion: () => import_mentions.createMentionSuggestion,
55
57
  defaultCommentingOptions: () => import_options.defaultCommentingOptions,
56
- filterMentionMembers: () => import_mention_suggestion.filterMentionMembers,
58
+ defaultRenderReaction: () => import_reaction.defaultRenderReaction,
59
+ deleteComment: () => import_comment_mutations.deleteComment,
60
+ deleteThread: () => import_comment_mutations.deleteThread,
61
+ editComment: () => import_comment_mutations.editComment,
62
+ filterMentionMembers: () => import_mentions.filterMentionMembers,
57
63
  focusThread: () => import_thread_state.focusThread,
58
64
  formatRelativeTime: () => import_format_time.formatRelativeTime,
65
+ getCanComment: () => import_options.getCanComment,
66
+ getCommentReactions: () => import_comment_store.getCommentReactions,
59
67
  getCommentRecord: () => import_comment_store.getCommentRecord,
60
68
  getCommentThreads: () => import_comment_store.getCommentThreads,
61
69
  getCommentingOptions: () => import_options.getCommentingOptions,
62
70
  getComments: () => import_comment_store.getComments,
71
+ getLiveCommentThreads: () => import_comment_store.getLiveCommentThreads,
72
+ getLiveComments: () => import_comment_store.getLiveComments,
73
+ getRevealThreadPending: () => import_state.getRevealThreadPending,
74
+ isAllowedReactionEmoji: () => import_emoji_picker.isAllowedReactionEmoji,
75
+ isOpenInNewTabClick: () => import_comments_list.isOpenInNewTabClick,
63
76
  openThreadId: () => import_state.openThreadId,
64
- pendingComment: () => import_state.pendingComment,
65
- putCommentRecords: () => import_comment_store.putCommentRecords,
66
- removeCommentRecords: () => import_comment_store.removeCommentRecords,
67
- renderMarkdown: () => import_render_markdown.renderMarkdown,
77
+ putCommentRecords: () => import_comment_mutations.putCommentRecords,
78
+ registerCommentAnchorLifecycle: () => import_anchor_lifecycle.registerCommentAnchorLifecycle,
79
+ removeCommentRecords: () => import_comment_mutations.removeCommentRecords,
80
+ reopenThread: () => import_comment_mutations.reopenThread,
81
+ resolveThread: () => import_comment_mutations.resolveThread,
82
+ revealThread: () => import_state.revealThread,
68
83
  richTextToPlaintext: () => import_rich_text.richTextToPlaintext,
69
84
  shapeAnchorAt: () => import_thread_state.shapeAnchorAt,
70
85
  sidebarFilters: () => import_state.sidebarFilters,
86
+ summarizeReactions: () => import_comment_reactions.summarizeReactions,
87
+ toggleCommentReaction: () => import_comment_reactions.toggleCommentReaction,
71
88
  toggleCommentsHidden: () => import_state.toggleCommentsHidden,
89
+ toggleCommentsSidebar: () => import_state.toggleCommentsSidebar,
90
+ useCanComment: () => import_options.useCanComment,
91
+ useCommentReactions: () => import_comment_reactions.useCommentReactions,
72
92
  useCommentThreads: () => import_hooks.useCommentThreads,
73
93
  useCommentingEnabled: () => import_license.useCommentingEnabled,
74
94
  useCommentingOptions: () => import_options.useCommentingOptions,
75
95
  useComments: () => import_hooks.useComments,
76
96
  useCommentsHidden: () => import_state.useCommentsHidden,
97
+ useCommentsSidebarOpen: () => import_state.useCommentsSidebarOpen,
77
98
  useOpenThreadId: () => import_state.useOpenThreadId,
78
- usePendingComment: () => import_state.usePendingComment,
99
+ useRevealThreadPending: () => import_state.useRevealThreadPending,
79
100
  useSidebarFilters: () => import_state.useSidebarFilters,
80
101
  useThreadComments: () => import_hooks.useThreadComments
81
102
  });
82
103
  module.exports = __toCommonJS(index_exports);
83
104
  var import_utils = require("@tldraw/utils");
84
- var import_avatar = require("./ui/avatar");
105
+ var import_mentions = require("@tldraw/mentions");
85
106
  var import_byline = require("./ui/byline");
86
107
  var import_comment_card = require("./ui/comment-card");
87
108
  var import_comment_composer = require("./ui/comment-composer");
88
109
  var import_count_badge = require("./ui/count-badge");
89
110
  var import_comment_pin = require("./ui/comment-pin");
90
- var import_comment_text = require("./ui/comment-text");
91
111
  var import_comment_thread = require("./ui/comment-thread");
92
112
  var import_comments_list = require("./ui/comments-list");
93
113
  var import_empty_state = require("./ui/empty-state");
94
114
  var import_format_time = require("./ui/format-time");
95
- var import_mention = require("./ui/mention");
96
- var import_mention_list = require("./ui/mention-list");
97
- var import_mention_suggestion = require("./ui/mention-suggestion");
115
+ var import_emoji_picker = require("./ui/emoji-picker");
98
116
  var import_reaction = require("./ui/reaction");
117
+ var import_reaction_picker = require("./ui/reaction-picker");
99
118
  var import_reactions = require("./ui/reactions");
100
- var import_render_markdown = require("./ui/render-markdown");
101
119
  var import_send_button = require("./ui/send-button");
120
+ var import_anchor_lifecycle = require("./canvas/anchor-lifecycle");
102
121
  var import_comment_body = require("./canvas/comment-body");
122
+ var import_comment_mutations = require("./canvas/comment-mutations");
123
+ var import_comment_reactions = require("./canvas/comment-reactions");
103
124
  var import_comment_tool = require("./canvas/comment-tool");
104
- var import_cluster_input = require("./canvas/cluster-input");
105
- var import_computeClusterTable = require("./clustering/computeClusterTable");
106
125
  var import_comment_store = require("./canvas/comment-store");
107
- var import_runtime = require("./clustering/runtime");
108
126
  var import_comments_filter_menu = require("./canvas/comments-filter-menu");
109
127
  var import_comments_menu_item = require("./canvas/comments-menu-item");
110
128
  var import_comments_overlay = require("./canvas/comments-overlay");
111
129
  var import_options = require("./canvas/options");
112
130
  var import_comments_overflow_menu = require("./canvas/comments-overflow-menu");
131
+ var import_comments_visibility_toggle = require("./canvas/comments-visibility-toggle");
113
132
  var import_comments_sidebar = require("./canvas/comments-sidebar");
114
133
  var import_hooks = require("./canvas/hooks");
115
134
  var import_license = require("./canvas/license");
116
- var import_region_options = require("./canvas/region-options");
117
135
  var import_rich_text = require("./canvas/rich-text");
118
136
  var import_sidebar_filters = require("./canvas/sidebar-filters");
119
137
  var import_state = require("./canvas/state");
120
138
  var import_thread_state = require("./canvas/thread-state");
121
139
  (0, import_utils.registerTldrawLibraryVersion)(
122
140
  "@tldraw/commenting",
123
- "5.3.0-internal.c5c7f1d817d0",
141
+ "5.3.0-next.2fa9c61a8de6",
124
142
  "cjs"
125
143
  );
126
144
  //# sourceMappingURL=index.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/index.ts"],
4
- "sourcesContent": ["import { registerTldrawLibraryVersion } from '@tldraw/utils'\n\n// Presentational commenting components. These are tldraw-independent and can be used to build\n// custom commenting UI.\nexport { Avatar, type AvatarProps } from './ui/avatar'\nexport { Byline, type BylineProps } from './ui/byline'\nexport { CommentCard, type CommentCardProps } from './ui/comment-card'\nexport { CommentComposer, type CommentComposerProps } from './ui/comment-composer'\nexport { CountBadge, type CountBadgeProps } from './ui/count-badge'\nexport { CommentPin, type CommentPinProps } from './ui/comment-pin'\nexport { CommentText, type CommentTextProps } from './ui/comment-text'\nexport { CommentThread, type CommentThreadProps } from './ui/comment-thread'\nexport { CommentsList, type CommentListItemProps, type CommentsListProps } from './ui/comments-list'\nexport { EmptyState, type EmptyStateProps } from './ui/empty-state'\nexport { formatRelativeTime } from './ui/format-time'\nexport { Mention, type MentionProps } from './ui/mention'\nexport { MentionList, type MentionListProps, type MentionMember } from './ui/mention-list'\nexport {\n\tcreateMentionSuggestion,\n\tfilterMentionMembers,\n\ttype MentionSuggestionOptions,\n} from './ui/mention-suggestion'\nexport { Reaction, type ReactionProps } from './ui/reaction'\nexport { Reactions } from './ui/reactions'\nexport { renderMarkdown } from './ui/render-markdown'\nexport { SendButton, type SendButtonProps } from './ui/send-button'\n\n// The tldraw-coupled commenting layer: the comment tool, reactive hooks over the comment\n// records, a rich-text body renderer, and a batteries-included <CanvasComments> overlay. Pairs\n// with the presentational components above.\nexport { CommentBody, type CommentBodyProps } from './canvas/comment-body'\nexport {\n\tCommentTool,\n\tcommentToolOverrides,\n\tcommentTools,\n\ttype PendingComment,\n} from './canvas/comment-tool'\nexport { collectClusterLeaves } from './canvas/cluster-input'\nexport { computeClusterTable } from './clustering/computeClusterTable'\nexport {\n\tgetCommentRecord,\n\tgetComments,\n\tgetCommentThreads,\n\tputCommentRecords,\n\tremoveCommentRecords,\n\ttype TLCommentRecord,\n} from './canvas/comment-store'\nexport { createClusterRuntime, type ClusterRuntime } from './clustering/runtime'\nexport type {\n\tClusterNode,\n\tClusterOptions,\n\tClusterTable,\n\tLeafInput,\n\tMergeEvent,\n} from './clustering/types'\nexport { CommentsFilterMenu, type CommentsFilterMenuProps } from './canvas/comments-filter-menu'\nexport { CommentsMenuItem } from './canvas/comments-menu-item'\nexport { CanvasComments, type CanvasCommentsProps } from './canvas/comments-overlay'\nexport {\n\ttype CommentingComponents,\n\ttype CommentingOptions,\n\tdefaultCommentingOptions,\n\tgetCommentingOptions,\n\tuseCommentingOptions,\n} from './canvas/options'\nexport { CommentsOverflowMenu } from './canvas/comments-overflow-menu'\nexport { CanvasCommentsSidebar, type CanvasCommentsSidebarProps } from './canvas/comments-sidebar'\nexport { useComments, useCommentThreads, useThreadComments } from './canvas/hooks'\nexport { useCommentingEnabled } from './canvas/license'\nexport { DEFAULT_REGION_COMMENT_OPTIONS, type RegionCommentOptions } from './canvas/region-options'\nexport { richTextToPlaintext } from './canvas/rich-text'\nexport { DEFAULT_SIDEBAR_FILTERS, type SidebarFilters } from './canvas/sidebar-filters'\nexport {\n\tcommentsHidden,\n\tcommitCommentMutation,\n\topenThreadId,\n\tpendingComment,\n\tsidebarFilters,\n\ttoggleCommentsHidden,\n\tuseCommentsHidden,\n\tuseOpenThreadId,\n\tusePendingComment,\n\tuseSidebarFilters,\n} from './canvas/state'\nexport {\n\tanchorPagePoint,\n\tDEFAULT_IMPRECISE_SHAPE_ANCHOR,\n\tfocusThread,\n\tshapeAnchorAt,\n} from './canvas/thread-state'\n\nregisterTldrawLibraryVersion(\n\t(globalThis as any).TLDRAW_LIBRARY_NAME,\n\t(globalThis as any).TLDRAW_LIBRARY_VERSION,\n\t(globalThis as any).TLDRAW_LIBRARY_MODULES\n)\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAA6C;AAI7C,oBAAyC;AACzC,oBAAyC;AACzC,0BAAmD;AACnD,8BAA2D;AAC3D,yBAAiD;AACjD,yBAAiD;AACjD,0BAAmD;AACnD,4BAAuD;AACvD,2BAAgF;AAChF,yBAAiD;AACjD,yBAAmC;AACnC,qBAA2C;AAC3C,0BAAuE;AACvE,gCAIO;AACP,sBAA6C;AAC7C,uBAA0B;AAC1B,6BAA+B;AAC/B,yBAAiD;AAKjD,0BAAmD;AACnD,0BAKO;AACP,2BAAqC;AACrC,iCAAoC;AACpC,2BAOO;AACP,qBAA0D;AAQ1D,kCAAiE;AACjE,gCAAiC;AACjC,8BAAyD;AACzD,qBAMO;AACP,oCAAqC;AACrC,8BAAuE;AACvE,mBAAkE;AAClE,qBAAqC;AACrC,4BAA0E;AAC1E,uBAAoC;AACpC,6BAA6D;AAC7D,mBAWO;AACP,0BAKO;AAAA,IAEP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AACF;",
4
+ "sourcesContent": ["import { registerTldrawLibraryVersion } from '@tldraw/utils'\n\n// Presentational commenting components. These are tldraw-independent and can be used to build\n// custom commenting UI. The mention picker, pill, and avatar are re-exported from @tldraw/mentions\n// so the commenting public API is unchanged.\nexport {\n\tAvatar,\n\ttype AvatarProps,\n\ttype CommentAuthor,\n\tcreateMentionSuggestion,\n\tfilterMentionMembers,\n\tMention,\n\tMentionList,\n\ttype MentionListProps,\n\ttype MentionMember,\n\ttype MentionProps,\n\ttype MentionSuggestionOptions,\n} from '@tldraw/mentions'\nexport { Byline, type BylineProps } from './ui/byline'\nexport { CommentCard, type CommentCardProps } from './ui/comment-card'\nexport { CommentComposer, type CommentComposerProps } from './ui/comment-composer'\nexport { CountBadge, type CountBadgeProps } from './ui/count-badge'\nexport { CommentPin, type CommentPinProps } from './ui/comment-pin'\nexport { CommentThread, type CommentThreadProps } from './ui/comment-thread'\nexport {\n\tCommentsList,\n\tisOpenInNewTabClick,\n\ttype CommentListItemProps,\n\ttype CommentsListProps,\n} from './ui/comments-list'\nexport { EmptyState, type EmptyStateProps } from './ui/empty-state'\nexport { formatRelativeTime } from './ui/format-time'\nexport {\n\tDEFAULT_REACTION_EMOJI,\n\tEmojiPicker,\n\ttype EmojiPickerProps,\n\tisAllowedReactionEmoji,\n} from './ui/emoji-picker'\nexport {\n\tReaction,\n\ttype ReactionProps,\n\ttype RenderReaction,\n\tdefaultRenderReaction,\n\tDefaultReactionTooltip,\n\tDefaultReactionTooltipContent,\n\ttype ReactionTooltipProps,\n} from './ui/reaction'\nexport { ReactionPicker, type ReactionPickerProps } from './ui/reaction-picker'\nexport {\n\tReactions,\n\ttype ReactionReactor,\n\ttype ReactionsProps,\n\ttype ReactionSummary,\n} from './ui/reactions'\nexport { SendButton, type SendButtonProps } from './ui/send-button'\n\n// The tldraw-coupled commenting layer: the comment tool, reactive hooks over the comment\n// records, a rich-text body renderer, and a batteries-included <CanvasComments> overlay. Pairs\n// with the presentational components above.\nexport { registerCommentAnchorLifecycle } from './canvas/anchor-lifecycle'\nexport { CommentBody, type CommentBodyProps } from './canvas/comment-body'\nexport {\n\tdeleteComment,\n\tdeleteThread,\n\teditComment,\n\tputCommentRecords,\n\tremoveCommentRecords,\n\treopenThread,\n\tresolveThread,\n} from './canvas/comment-mutations'\nexport {\n\tCommentReactionPicker,\n\ttype CommentReactionPickerProps,\n\tCommentReactions,\n\ttype CommentReactionsProps,\n\tsummarizeReactions,\n\ttoggleCommentReaction,\n\tuseCommentReactions,\n} from './canvas/comment-reactions'\nexport { CommentTool, commentToolOverrides, commentTools } from './canvas/comment-tool'\nexport {\n\tgetCommentReactions,\n\tgetCommentRecord,\n\tgetComments,\n\tgetCommentThreads,\n\tgetLiveComments,\n\tgetLiveCommentThreads,\n\ttype TLCommentRecord,\n} from './canvas/comment-store'\nexport { type CommentingContext } from './canvas/context'\nexport { CommentsFilterMenu, type CommentsFilterMenuProps } from './canvas/comments-filter-menu'\nexport { CommentsMenuItem } from './canvas/comments-menu-item'\nexport { CanvasComments, type CanvasCommentsProps } from './canvas/comments-overlay'\nexport {\n\ttype CommentingComponents,\n\ttype CommentingOptions,\n\tdefaultCommentingOptions,\n\tgetCanComment,\n\tgetCommentingOptions,\n\ttype ShapeCommentPrecisionContext,\n\tuseCanComment,\n\tuseCommentingOptions,\n} from './canvas/options'\nexport { CommentsOverflowMenu } from './canvas/comments-overflow-menu'\nexport { CommentsVisibilityToggle } from './canvas/comments-visibility-toggle'\nexport { CanvasCommentsSidebar, type CanvasCommentsSidebarProps } from './canvas/comments-sidebar'\nexport { useComments, useCommentThreads, useThreadComments } from './canvas/hooks'\nexport { useCommentingEnabled } from './canvas/license'\nexport { richTextToPlaintext } from './canvas/rich-text'\nexport { DEFAULT_SIDEBAR_FILTERS, type SidebarFilters } from './canvas/sidebar-filters'\nexport {\n\tcommentsHidden,\n\tcommentsSidebarOpen,\n\tgetRevealThreadPending,\n\topenThreadId,\n\trevealThread,\n\tsidebarFilters,\n\ttoggleCommentsHidden,\n\ttoggleCommentsSidebar,\n\tuseCommentsHidden,\n\tuseCommentsSidebarOpen,\n\tuseOpenThreadId,\n\tuseRevealThreadPending,\n\tuseSidebarFilters,\n} from './canvas/state'\nexport { anchorPagePoint, focusThread, shapeAnchorAt } from './canvas/thread-state'\n\nregisterTldrawLibraryVersion(\n\t(globalThis as any).TLDRAW_LIBRARY_NAME,\n\t(globalThis as any).TLDRAW_LIBRARY_VERSION,\n\t(globalThis as any).TLDRAW_LIBRARY_MODULES\n)\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAA6C;AAK7C,sBAYO;AACP,oBAAyC;AACzC,0BAAmD;AACnD,8BAA2D;AAC3D,yBAAiD;AACjD,yBAAiD;AACjD,4BAAuD;AACvD,2BAKO;AACP,yBAAiD;AACjD,yBAAmC;AACnC,0BAKO;AACP,sBAQO;AACP,6BAAyD;AACzD,uBAKO;AACP,yBAAiD;AAKjD,8BAA+C;AAC/C,0BAAmD;AACnD,+BAQO;AACP,+BAQO;AACP,0BAAgE;AAChE,2BAQO;AAEP,kCAAiE;AACjE,gCAAiC;AACjC,8BAAyD;AACzD,qBASO;AACP,oCAAqC;AACrC,wCAAyC;AACzC,8BAAuE;AACvE,mBAAkE;AAClE,qBAAqC;AACrC,uBAAoC;AACpC,6BAA6D;AAC7D,mBAcO;AACP,0BAA4D;AAAA,IAE5D;AAAA,EACE;AAAA,EACA;AAAA,EACA;AACF;",
6
6
  "names": []
7
7
  }
@@ -22,10 +22,12 @@ __export(byline_exports, {
22
22
  });
23
23
  module.exports = __toCommonJS(byline_exports);
24
24
  var import_jsx_runtime = require("react/jsx-runtime");
25
+ var import_mentions = require("@tldraw/mentions");
25
26
  var import_format_time = require("./format-time");
26
27
  function Byline({ author, date, edited }) {
27
28
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "tlui-cmt-head", children: [
28
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "tlui-cmt-author", children: author }),
29
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_mentions.Avatar, { author }),
30
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "tlui-cmt-author", children: author.name }),
29
31
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "tlui-cmt-time", children: [
30
32
  (0, import_format_time.formatRelativeTime)(date),
31
33
  edited && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "tlui-cmt-edited", children: " \xB7 edited" })
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/ui/byline.tsx"],
4
- "sourcesContent": ["import { formatRelativeTime } from './format-time'\n\n/** @public */\nexport interface BylineProps {\n\tauthor: string\n\t/** ISO datetime; formatted to relative time by the component. */\n\tdate: string\n\t/** Shows an \"edited\" marker when the comment has been edited. */\n\tedited?: boolean\n}\n\n/** A comment's metadata line: author name, relative time, and an edited marker. @public @react */\nexport function Byline({ author, date, edited }: BylineProps) {\n\treturn (\n\t\t<div className=\"tlui-cmt-head\">\n\t\t\t<span className=\"tlui-cmt-author\">{author}</span>\n\t\t\t<span className=\"tlui-cmt-time\">\n\t\t\t\t{formatRelativeTime(date)}\n\t\t\t\t{edited && <span className=\"tlui-cmt-edited\"> \u00B7 edited</span>}\n\t\t\t</span>\n\t\t</div>\n\t)\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAeG;AAfH,yBAAmC;AAY5B,SAAS,OAAO,EAAE,QAAQ,MAAM,OAAO,GAAgB;AAC7D,SACC,6CAAC,SAAI,WAAU,iBACd;AAAA,gDAAC,UAAK,WAAU,mBAAmB,kBAAO;AAAA,IAC1C,6CAAC,UAAK,WAAU,iBACd;AAAA,iDAAmB,IAAI;AAAA,MACvB,UAAU,4CAAC,UAAK,WAAU,mBAAkB,0BAAS;AAAA,OACvD;AAAA,KACD;AAEF;",
4
+ "sourcesContent": ["import { Avatar, type CommentAuthor } from '@tldraw/mentions'\nimport { formatRelativeTime } from './format-time'\n\n/** @public */\nexport interface BylineProps {\n\tauthor: CommentAuthor\n\t/** ISO datetime; formatted to relative time by the component. */\n\tdate: string\n\t/** Shows an \"edited\" marker when the comment has been edited. */\n\tedited?: boolean\n}\n\n/** A comment's metadata line: author name, relative time, and an edited marker. @public @react */\nexport function Byline({ author, date, edited }: BylineProps) {\n\treturn (\n\t\t<div className=\"tlui-cmt-head\">\n\t\t\t<Avatar author={author} />\n\t\t\t<span className=\"tlui-cmt-author\">{author.name}</span>\n\t\t\t<span className=\"tlui-cmt-time\">\n\t\t\t\t{formatRelativeTime(date)}\n\t\t\t\t{edited && <span className=\"tlui-cmt-edited\"> \u00B7 edited</span>}\n\t\t\t</span>\n\t\t</div>\n\t)\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAgBG;AAhBH,sBAA2C;AAC3C,yBAAmC;AAY5B,SAAS,OAAO,EAAE,QAAQ,MAAM,OAAO,GAAgB;AAC7D,SACC,6CAAC,SAAI,WAAU,iBACd;AAAA,gDAAC,0BAAO,QAAgB;AAAA,IACxB,4CAAC,UAAK,WAAU,mBAAmB,iBAAO,MAAK;AAAA,IAC/C,6CAAC,UAAK,WAAU,iBACd;AAAA,iDAAmB,IAAI;AAAA,MACvB,UAAU,4CAAC,UAAK,WAAU,mBAAkB,0BAAS;AAAA,OACvD;AAAA,KACD;AAEF;",
6
6
  "names": []
7
7
  }
@@ -22,14 +22,21 @@ __export(comment_card_exports, {
22
22
  });
23
23
  module.exports = __toCommonJS(comment_card_exports);
24
24
  var import_jsx_runtime = require("react/jsx-runtime");
25
- var import_avatar = require("./avatar");
26
25
  var import_byline = require("./byline");
27
- function CommentCard({ author, body, date, you, edited, actions }) {
26
+ function CommentCard({
27
+ author,
28
+ body,
29
+ date,
30
+ you,
31
+ edited,
32
+ actions,
33
+ footer
34
+ }) {
28
35
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: you ? "tlui-cmt-card tlui-cmt-card--you" : "tlui-cmt-card", children: [
29
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_avatar.Avatar, { name: author }),
36
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_byline.Byline, { author, date, edited }),
30
37
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "tlui-cmt-body", children: [
31
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_byline.Byline, { author, date, edited }),
32
- body
38
+ body,
39
+ footer
33
40
  ] }),
34
41
  actions !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "tlui-cmt-card__actions", children: actions })
35
42
  ] });
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/ui/comment-card.tsx"],
4
- "sourcesContent": ["import { ReactNode } from 'react'\nimport { Avatar } from './avatar'\nimport { Byline } from './byline'\n\n/** @public */\nexport interface CommentCardProps {\n\tauthor: string\n\t/** The rendered comment body. The card doesn't dictate a format \u2014 pass a `<CommentText>`\n\t * for markdown, a rich-text render, or any node. */\n\tbody: ReactNode\n\t/** ISO datetime; formatted to relative time by the component. */\n\tdate: string\n\tyou: boolean\n\t/** Whether the comment has been edited (shows an \"edited\" marker). */\n\tedited?: boolean\n\t/** Hover-revealed controls at the card's top-right (e.g. an edit affordance). */\n\tactions?: ReactNode\n}\n\n/** A single comment: Avatar, Byline, and a body slot the consumer renders. @public @react */\nexport function CommentCard({ author, body, date, you, edited, actions }: CommentCardProps) {\n\treturn (\n\t\t<div className={you ? 'tlui-cmt-card tlui-cmt-card--you' : 'tlui-cmt-card'}>\n\t\t\t<Avatar name={author} />\n\t\t\t<div className=\"tlui-cmt-body\">\n\t\t\t\t<Byline author={author} date={date} edited={edited} />\n\t\t\t\t{body}\n\t\t\t</div>\n\t\t\t{actions !== undefined && <div className=\"tlui-cmt-card__actions\">{actions}</div>}\n\t\t</div>\n\t)\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAuBG;AAtBH,oBAAuB;AACvB,oBAAuB;AAkBhB,SAAS,YAAY,EAAE,QAAQ,MAAM,MAAM,KAAK,QAAQ,QAAQ,GAAqB;AAC3F,SACC,6CAAC,SAAI,WAAW,MAAM,qCAAqC,iBAC1D;AAAA,gDAAC,wBAAO,MAAM,QAAQ;AAAA,IACtB,6CAAC,SAAI,WAAU,iBACd;AAAA,kDAAC,wBAAO,QAAgB,MAAY,QAAgB;AAAA,MACnD;AAAA,OACF;AAAA,IACC,YAAY,UAAa,4CAAC,SAAI,WAAU,0BAA0B,mBAAQ;AAAA,KAC5E;AAEF;",
4
+ "sourcesContent": ["import { type CommentAuthor } from '@tldraw/mentions'\nimport { ReactNode } from 'react'\nimport { Byline } from './byline'\n\n/** @public */\nexport interface CommentCardProps {\n\tauthor: CommentAuthor\n\t/** The rendered comment body. The card doesn't dictate a format \u2014 pass a `<CommentBody>`\n\t * for a comment's rich text, or any node of your own. */\n\tbody: ReactNode\n\t/** ISO datetime; formatted to relative time by the component. */\n\tdate: string\n\tyou: boolean\n\t/** Whether the comment has been edited (shows an \"edited\" marker). */\n\tedited?: boolean\n\t/** Hover-revealed controls at the card's top-right (e.g. an edit affordance). */\n\tactions?: ReactNode\n\t/** Content under the body, aligned with it rather than the avatar (e.g. a `<Reactions>` row). */\n\tfooter?: ReactNode\n}\n\n/** A single comment: Avatar, Byline, and a body slot the consumer renders. @public @react */\nexport function CommentCard({\n\tauthor,\n\tbody,\n\tdate,\n\tyou,\n\tedited,\n\tactions,\n\tfooter,\n}: CommentCardProps) {\n\treturn (\n\t\t<div className={you ? 'tlui-cmt-card tlui-cmt-card--you' : 'tlui-cmt-card'}>\n\t\t\t<Byline author={author} date={date} edited={edited} />\n\t\t\t<div className=\"tlui-cmt-body\">\n\t\t\t\t{body}\n\t\t\t\t{footer}\n\t\t\t</div>\n\t\t\t{actions !== undefined && <div className=\"tlui-cmt-card__actions\">{actions}</div>}\n\t\t</div>\n\t)\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAiCG;AA/BH,oBAAuB;AAoBhB,SAAS,YAAY;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,GAAqB;AACpB,SACC,6CAAC,SAAI,WAAW,MAAM,qCAAqC,iBAC1D;AAAA,gDAAC,wBAAO,QAAgB,MAAY,QAAgB;AAAA,IACpD,6CAAC,SAAI,WAAU,iBACb;AAAA;AAAA,MACA;AAAA,OACF;AAAA,IACC,YAAY,UAAa,4CAAC,SAAI,WAAU,0BAA0B,mBAAQ;AAAA,KAC5E;AAEF;",
6
6
  "names": []
7
7
  }
@@ -23,12 +23,10 @@ __export(comment_composer_exports, {
23
23
  module.exports = __toCommonJS(comment_composer_exports);
24
24
  var import_jsx_runtime = require("react/jsx-runtime");
25
25
  var import_react = require("@tiptap/react");
26
+ var import_mentions = require("@tldraw/mentions");
26
27
  var import_react2 = require("react");
27
28
  var import_tldraw = require("tldraw");
28
- var import_avatar = require("./avatar");
29
29
  var import_comment_extensions = require("./comment-extensions");
30
- var import_comment_mention = require("./comment-mention");
31
- var import_mention_suggestion = require("./mention-suggestion");
32
30
  var import_send_button = require("./send-button");
33
31
  function CommentComposer({
34
32
  author,
@@ -37,6 +35,7 @@ function CommentComposer({
37
35
  onChange,
38
36
  onSubmit,
39
37
  sendLabel = "Send",
38
+ onArrowUpWhenEmpty,
40
39
  disabled,
41
40
  autoFocus,
42
41
  leading,
@@ -49,6 +48,8 @@ function CommentComposer({
49
48
  onChangeRef.current = onChange;
50
49
  const onSubmitRef = (0, import_react2.useRef)(onSubmit);
51
50
  onSubmitRef.current = onSubmit;
51
+ const onArrowUpWhenEmptyRef = (0, import_react2.useRef)(onArrowUpWhenEmpty);
52
+ onArrowUpWhenEmptyRef.current = onArrowUpWhenEmpty;
52
53
  const disabledRef = (0, import_react2.useRef)(disabled);
53
54
  disabledRef.current = disabled;
54
55
  const getMentionSuggestionsRef = (0, import_react2.useRef)(getMentionSuggestions);
@@ -56,6 +57,44 @@ function CommentComposer({
56
57
  const renderMentionSuggestionRef = (0, import_react2.useRef)(renderMentionSuggestion);
57
58
  renderMentionSuggestionRef.current = renderMentionSuggestion;
58
59
  const [isEmpty, setIsEmpty] = (0, import_react2.useState)(() => !value || (0, import_comment_extensions.isCommentEmpty)(value));
60
+ const [expanded, setExpanded] = (0, import_react2.useState)(false);
61
+ const expandedRef = (0, import_react2.useRef)(expanded);
62
+ expandedRef.current = expanded;
63
+ const inputWrapRef = (0, import_react2.useRef)(null);
64
+ const mirrorRef = (0, import_react2.useRef)(null);
65
+ const remeasure = () => {
66
+ const wrap = inputWrapRef.current;
67
+ const mirror = mirrorRef.current;
68
+ const editor2 = editorRef.current;
69
+ if (!wrap || !mirror || !editor2) return;
70
+ if (editor2.isEmpty) {
71
+ if (expandedRef.current) setExpanded(false);
72
+ return;
73
+ }
74
+ if (wrap.clientWidth === 0) return;
75
+ const doc = editor2.state.doc;
76
+ const multiBlock = doc.childCount > 1 || doc.firstChild !== null && doc.firstChild.type.name !== "paragraph";
77
+ if (multiBlock) {
78
+ if (!expandedRef.current) setExpanded(true);
79
+ return;
80
+ }
81
+ const field = wrap.parentElement;
82
+ const send = field ? field.querySelector(".tlui-cmt-send") : null;
83
+ const input = wrap.querySelector(".tlui-cmt-input");
84
+ if (!send || !input) return;
85
+ mirror.innerHTML = input.innerHTML;
86
+ const textWidth = mirror.offsetWidth;
87
+ const wrapStyle = getComputedStyle(wrap);
88
+ const wrapPadX = parseFloat(wrapStyle.paddingLeft) + parseFloat(wrapStyle.paddingRight);
89
+ const collapsedAvailable = wrap.clientWidth - wrapPadX - (expandedRef.current ? send.offsetWidth + 6 : 0);
90
+ if (!expandedRef.current && textWidth > collapsedAvailable - 8) {
91
+ setExpanded(true);
92
+ } else if (expandedRef.current && textWidth < collapsedAvailable - 24) {
93
+ setExpanded(false);
94
+ }
95
+ };
96
+ const remeasureRef = (0, import_react2.useRef)(remeasure);
97
+ remeasureRef.current = remeasure;
59
98
  const editorRef = (0, import_react2.useRef)(null);
60
99
  const replayingEnter = (0, import_react2.useRef)(false);
61
100
  const mentionsEnabled = !!getMentionSuggestions;
@@ -66,15 +105,15 @@ function CommentComposer({
66
105
  const resolveSuggestions = (query) => getMentionSuggestionsRef.current?.(query) ?? [];
67
106
  const renderRow = hasCustomRow ? (member) => renderMentionSuggestionRef.current?.(member) : void 0;
68
107
  list.push(
69
- (0, import_comment_mention.commentMention)({
70
- suggestion: (0, import_mention_suggestion.createMentionSuggestion)(resolveSuggestions, {
108
+ (0, import_mentions.createMentionExtension)({
109
+ suggestion: (0, import_mentions.createMentionSuggestion)(resolveSuggestions, {
71
110
  renderMember: renderRow,
72
111
  editor: tlEditor
73
112
  })
74
113
  })
75
114
  );
76
115
  } else {
77
- list.push((0, import_comment_mention.commentMention)({ suggestion: { char: "@", allow: () => false } }));
116
+ list.push((0, import_mentions.createMentionExtension)({ suggestion: { char: "@", allow: () => false } }));
78
117
  }
79
118
  return list;
80
119
  }, [mentionsEnabled, hasCustomRow, tlEditor]);
@@ -89,14 +128,27 @@ function CommentComposer({
89
128
  enableCoreExtensions: { textDirection: false },
90
129
  textDirection: "auto",
91
130
  editorProps: {
92
- attributes: { class: "tlui-cmt-input" },
131
+ attributes: {
132
+ class: "tlui-cmt-input",
133
+ "aria-label": placeholder,
134
+ role: "textbox",
135
+ "aria-multiline": "true"
136
+ },
93
137
  // Runs before every keymap plugin, so it can distinguish Shift+Enter from Enter — an
94
138
  // `Enter` keymap binding also fires on Shift+Enter and would otherwise swallow it.
95
139
  handleKeyDown: (_view, event) => {
96
140
  if (replayingEnter.current) return false;
141
+ if (event.key === "ArrowUp" && !event.isComposing) {
142
+ if (onArrowUpWhenEmptyRef.current && editorRef.current?.isEmpty && !(0, import_mentions.isMentionPickerOpen)()) {
143
+ onArrowUpWhenEmptyRef.current();
144
+ return true;
145
+ }
146
+ return false;
147
+ }
97
148
  if (event.key !== "Enter" || event.isComposing) return false;
98
- if ((0, import_mention_suggestion.isMentionPickerOpen)()) return false;
149
+ if ((0, import_mentions.isMentionPickerOpen)()) return false;
99
150
  if (event.shiftKey && !event.metaKey && !event.ctrlKey && !event.altKey) {
151
+ if (editorRef.current?.isEmpty) return true;
100
152
  replayingEnter.current = true;
101
153
  try {
102
154
  editorRef.current?.commands.enter();
@@ -111,10 +163,11 @@ function CommentComposer({
111
163
  },
112
164
  onUpdate: ({ editor: editor2 }) => {
113
165
  setIsEmpty(editor2.isEmpty);
166
+ remeasureRef.current();
114
167
  onChangeRef.current?.(editor2.getJSON());
115
168
  }
116
169
  },
117
- [interactive]
170
+ [interactive, placeholder]
118
171
  );
119
172
  editorRef.current = editor;
120
173
  (0, import_react2.useEffect)(() => {
@@ -123,20 +176,62 @@ function CommentComposer({
123
176
  editor.commands.setContent(value);
124
177
  setIsEmpty(editor.isEmpty);
125
178
  }, [editor, value]);
179
+ (0, import_react2.useLayoutEffect)(() => {
180
+ remeasureRef.current();
181
+ }, [editor, value]);
126
182
  (0, import_react2.useEffect)(() => {
127
183
  if (!autoFocus || !editor) return;
128
184
  const raf = requestAnimationFrame(() => editor.commands.focus("end"));
129
185
  return () => cancelAnimationFrame(raf);
130
186
  }, [autoFocus, editor]);
187
+ (0, import_react2.useEffect)(() => {
188
+ const wrap = inputWrapRef.current;
189
+ if (!wrap) return;
190
+ const onWheel = (e) => {
191
+ const input = wrap.querySelector(".tlui-cmt-input");
192
+ if (!input || input.scrollHeight <= input.clientHeight) return;
193
+ const atTop = input.scrollTop <= 0;
194
+ const atBottom = input.scrollTop >= input.scrollHeight - input.clientHeight - 1;
195
+ if (e.deltaY < 0 && !atTop || e.deltaY > 0 && !atBottom) {
196
+ e.stopPropagation();
197
+ }
198
+ };
199
+ wrap.addEventListener("wheel", onWheel);
200
+ return () => wrap.removeEventListener("wheel", onWheel);
201
+ }, []);
202
+ const focusEditorFromField = (e) => {
203
+ const target = e.target;
204
+ if (target.closest(".tlui-cmt-input") || target.closest(".tlui-cmt-send")) return;
205
+ e.preventDefault();
206
+ editor?.commands.focus("end");
207
+ };
131
208
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "tlui-cmt-composer", children: [
132
- leading ?? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_avatar.Avatar, { name: author }),
133
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "tlui-cmt-composer__field", children: [
134
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "tlui-cmt-composer__input-wrap", children: [
135
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react.EditorContent, { editor }),
136
- isEmpty && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "tlui-cmt-input__placeholder", "aria-hidden": "true", children: placeholder })
137
- ] }),
138
- interactive && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_send_button.SendButton, { label: sendLabel, onClick: onSubmit, disabled })
139
- ] })
209
+ leading ?? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_mentions.Avatar, { author }),
210
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
211
+ "div",
212
+ {
213
+ className: [
214
+ "tlui-cmt-composer__field",
215
+ interactive && expanded && "tlui-cmt-composer__field--expanded"
216
+ ].filter(Boolean).join(" "),
217
+ onMouseDown: interactive ? focusEditorFromField : void 0,
218
+ children: [
219
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "tlui-cmt-composer__input-wrap", ref: inputWrapRef, children: [
220
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react.EditorContent, { editor }),
221
+ isEmpty && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "tlui-cmt-input__placeholder", "aria-hidden": "true", children: placeholder }),
222
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
223
+ "div",
224
+ {
225
+ className: "tlui-cmt-composer__mirror tlui-cmt-input",
226
+ ref: mirrorRef,
227
+ "aria-hidden": "true"
228
+ }
229
+ )
230
+ ] }),
231
+ interactive && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_send_button.SendButton, { label: sendLabel, onClick: onSubmit, disabled })
232
+ ]
233
+ }
234
+ )
140
235
  ] });
141
236
  }
142
237
  //# sourceMappingURL=comment-composer.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/ui/comment-composer.tsx"],
4
- "sourcesContent": ["import { JSONContent } from '@tiptap/core'\nimport { EditorContent, useEditor } from '@tiptap/react'\nimport { ReactNode, useEffect, useMemo, useRef, useState } from 'react'\nimport { isEqual, TLRichText, useMaybeEditor } from 'tldraw'\nimport { Avatar } from './avatar'\nimport { commentTipTapExtensions, EMPTY_COMMENT, isCommentEmpty } from './comment-extensions'\nimport { commentMention } from './comment-mention'\nimport { MentionMember } from './mention-list'\nimport { createMentionSuggestion, isMentionPickerOpen } from './mention-suggestion'\nimport { SendButton } from './send-button'\n\n/** @public */\nexport interface CommentComposerProps {\n\tauthor: string\n\tplaceholder: string\n\t/** Controlled rich-text value. Omit for the presentational (display-only) composer. */\n\tvalue?: TLRichText\n\tonChange?(value: TLRichText): void\n\t/** Called on Send click or Enter. When set, the composer is interactive. */\n\tonSubmit?(): void\n\tsendLabel?: string\n\tdisabled?: boolean\n\tautoFocus?: boolean\n\t/** The leading element before the field. Defaults to the author's avatar. */\n\tleading?: ReactNode\n\t/** Resolve the members matching an `@`-query (sync or async). Provide to enable mentions. */\n\tgetMentionSuggestions?(query: string): MentionMember[] | Promise<MentionMember[]>\n\t/** Override a picker row's content. Defaults to avatar + name (+ secondary). */\n\trenderMentionSuggestion?(member: MentionMember): ReactNode\n}\n\n/**\n * The input for writing a comment: a TipTap rich-text editor restricted to the comment extension\n * set (bold, italic, lists, links, code, highlight \u2014 no headings), with a Send button. Formatting\n * is applied through markdown and keyboard shortcuts (e.g. `**bold**`, `- `, Cmd+B); there's no\n * floating toolbar. Presentational by default; pass value/onChange/onSubmit to drive it as a form.\n * @public @react\n */\nexport function CommentComposer({\n\tauthor,\n\tplaceholder,\n\tvalue,\n\tonChange,\n\tonSubmit,\n\tsendLabel = 'Send',\n\tdisabled,\n\tautoFocus,\n\tleading,\n\tgetMentionSuggestions,\n\trenderMentionSuggestion,\n}: CommentComposerProps) {\n\tconst interactive = !!onChange || !!onSubmit\n\t// The canvas editor the composer lives in, if any \u2014 lets the mention popup track the camera. Null\n\t// when the composer is used outside a tldraw editor (e.g. an isolated demo).\n\tconst tlEditor = useMaybeEditor()\n\n\t// Callbacks are read through refs so the editor instance doesn't need to be recreated when they\n\t// change identity between renders.\n\tconst onChangeRef = useRef(onChange)\n\tonChangeRef.current = onChange\n\tconst onSubmitRef = useRef(onSubmit)\n\tonSubmitRef.current = onSubmit\n\tconst disabledRef = useRef(disabled)\n\tdisabledRef.current = disabled\n\tconst getMentionSuggestionsRef = useRef(getMentionSuggestions)\n\tgetMentionSuggestionsRef.current = getMentionSuggestions\n\tconst renderMentionSuggestionRef = useRef(renderMentionSuggestion)\n\trenderMentionSuggestionRef.current = renderMentionSuggestion\n\n\tconst [isEmpty, setIsEmpty] = useState(() => !value || isCommentEmpty(value))\n\n\t// The editor instance, reachable from `handleKeyDown` (which is created before `useEditor`\n\t// returns). Updated on every render so the ref never points at a stale editor.\n\tconst editorRef = useRef<ReturnType<typeof useEditor>>(null)\n\n\t// Set while we replay Enter through the keymaps for a Shift+Enter newline: `commands.enter()`\n\t// re-dispatches Enter through `handleKeyDown`, and without this guard our own handler would catch\n\t// that synthetic Enter and submit instead.\n\tconst replayingEnter = useRef(false)\n\n\t// Enter and Cmd/Ctrl+Enter submit the comment; Shift+Enter inserts a new line for the occasional\n\t// multi-line comment. This is handled through `editorProps.handleKeyDown` (below) rather than a\n\t// keyboard-shortcut extension: ProseMirror runs `handleKeyDown` before every keymap plugin, so it\n\t// can tell Shift+Enter apart from Enter \u2014 an `Enter` keymap binding also fires on Shift/Cmd+Enter\n\t// and would otherwise swallow the newline.\n\n\t// The suggestion plugin is built once (the editor is recreated only on `interactive`) and runs\n\t// outside React, so it must read the mention callbacks through refs \u2014 like onChange/onSubmit \u2014\n\t// or it queries the roster present at mount forever, never seeing a member who loads or joins\n\t// later. Whether mentions (and a custom picker row) are wired at all is fixed at mount; only the\n\t// callbacks themselves are live.\n\tconst mentionsEnabled = !!getMentionSuggestions\n\tconst hasCustomRow = !!renderMentionSuggestion\n\tconst extensions = useMemo(() => {\n\t\tconst list = [...commentTipTapExtensions]\n\t\t// Always register the mention node so an existing body that contains a mention keeps it on\n\t\t// edit (an unregistered node would be stripped by ProseMirror when the content loads). The `@`\n\t\t// picker itself only turns on when the host provides a resolver; otherwise the node is present\n\t\t// but its trigger is disabled.\n\t\tif (mentionsEnabled) {\n\t\t\tconst resolveSuggestions = (query: string) => getMentionSuggestionsRef.current?.(query) ?? []\n\t\t\tconst renderRow = hasCustomRow\n\t\t\t\t? (member: MentionMember) => renderMentionSuggestionRef.current?.(member)\n\t\t\t\t: undefined\n\t\t\tlist.push(\n\t\t\t\tcommentMention({\n\t\t\t\t\tsuggestion: createMentionSuggestion(resolveSuggestions, {\n\t\t\t\t\t\trenderMember: renderRow,\n\t\t\t\t\t\teditor: tlEditor,\n\t\t\t\t\t}),\n\t\t\t\t})\n\t\t\t)\n\t\t} else {\n\t\t\tlist.push(commentMention({ suggestion: { char: '@', allow: () => false } }))\n\t\t}\n\t\treturn list\n\t}, [mentionsEnabled, hasCustomRow, tlEditor])\n\n\tconst editor = useEditor(\n\t\t{\n\t\t\textensions,\n\t\t\tcontent: (value ?? EMPTY_COMMENT) as JSONContent,\n\t\t\teditable: interactive,\n\t\t\t// tldraw's default extensions add their own TextDirection extension (so it can be\n\t\t\t// overridden), so disable TipTap's core one to avoid a duplicate-extension warning \u2014\n\t\t\t// mirrors RichTextArea's setup.\n\t\t\tenableCoreExtensions: { textDirection: false },\n\t\t\ttextDirection: 'auto',\n\t\t\teditorProps: {\n\t\t\t\tattributes: { class: 'tlui-cmt-input' },\n\t\t\t\t// Runs before every keymap plugin, so it can distinguish Shift+Enter from Enter \u2014 an\n\t\t\t\t// `Enter` keymap binding also fires on Shift+Enter and would otherwise swallow it.\n\t\t\t\thandleKeyDown: (_view, event) => {\n\t\t\t\t\t// Let the keymaps handle the synthetic Enter we replay for a Shift+Enter newline.\n\t\t\t\t\tif (replayingEnter.current) return false\n\t\t\t\t\tif (event.key !== 'Enter' || event.isComposing) return false\n\t\t\t\t\t// While the @-mention picker is open, Enter selects the highlighted member \u2014 defer.\n\t\t\t\t\tif (isMentionPickerOpen()) return false\n\t\t\t\t\t// Shift+Enter inserts a new line. Replay a plain Enter through the keymaps (guarded so\n\t\t\t\t\t// we don't re-enter and submit) to reuse the editor's list-aware Enter handling \u2014 a new\n\t\t\t\t\t// list item in a list, a new paragraph otherwise. tldraw doesn't do soft breaks.\n\t\t\t\t\tif (event.shiftKey && !event.metaKey && !event.ctrlKey && !event.altKey) {\n\t\t\t\t\t\treplayingEnter.current = true\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\teditorRef.current?.commands.enter()\n\t\t\t\t\t\t} finally {\n\t\t\t\t\t\t\treplayingEnter.current = false\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn true\n\t\t\t\t\t}\n\t\t\t\t\t// Enter, Cmd+Enter, and Ctrl+Enter submit.\n\t\t\t\t\tif (!disabledRef.current) onSubmitRef.current?.()\n\t\t\t\t\treturn true\n\t\t\t\t},\n\t\t\t},\n\t\t\tonUpdate: ({ editor }) => {\n\t\t\t\tsetIsEmpty(editor.isEmpty)\n\t\t\t\tonChangeRef.current?.(editor.getJSON() as TLRichText)\n\t\t\t},\n\t\t},\n\t\t[interactive]\n\t)\n\teditorRef.current = editor\n\n\t// Sync controlled resets (e.g. the parent clearing to EMPTY_COMMENT after posting) into the\n\t// editor without echoing back the value the editor itself just emitted.\n\tuseEffect(() => {\n\t\tif (!editor || value === undefined) return\n\t\tif (isEqual(editor.getJSON(), value)) return\n\t\teditor.commands.setContent(value as JSONContent)\n\t\tsetIsEmpty(editor.isEmpty)\n\t}, [editor, value])\n\n\t// Focus on the next frame rather than via TipTap's autofocus: the composer often mounts from a\n\t// canvas pointer event whose default focus handling would otherwise steal it back.\n\tuseEffect(() => {\n\t\tif (!autoFocus || !editor) return\n\t\tconst raf = requestAnimationFrame(() => editor.commands.focus('end'))\n\t\treturn () => cancelAnimationFrame(raf)\n\t}, [autoFocus, editor])\n\n\treturn (\n\t\t<div className=\"tlui-cmt-composer\">\n\t\t\t{leading ?? <Avatar name={author} />}\n\t\t\t<div className=\"tlui-cmt-composer__field\">\n\t\t\t\t<div className=\"tlui-cmt-composer__input-wrap\">\n\t\t\t\t\t<EditorContent editor={editor} />\n\t\t\t\t\t{isEmpty && (\n\t\t\t\t\t\t<div className=\"tlui-cmt-input__placeholder\" aria-hidden=\"true\">\n\t\t\t\t\t\t\t{placeholder}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t\t{interactive && <SendButton label={sendLabel} onClick={onSubmit} disabled={disabled} />}\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { JSONContent } from '@tiptap/core'\nimport { EditorContent, useEditor } from '@tiptap/react'\nimport {\n\tAvatar,\n\ttype CommentAuthor,\n\tcreateMentionExtension,\n\tcreateMentionSuggestion,\n\tisMentionPickerOpen,\n\tMentionMember,\n} from '@tldraw/mentions'\nimport {\n\ttype MouseEvent as ReactMouseEvent,\n\tReactNode,\n\tuseEffect,\n\tuseLayoutEffect,\n\tuseMemo,\n\tuseRef,\n\tuseState,\n} from 'react'\nimport { isEqual, TLRichText, useMaybeEditor } from 'tldraw'\nimport { commentTipTapExtensions, EMPTY_COMMENT, isCommentEmpty } from './comment-extensions'\nimport { SendButton } from './send-button'\n\n/** @public */\nexport interface CommentComposerProps {\n\tauthor: CommentAuthor\n\tplaceholder: string\n\t/** Controlled rich-text value. Omit for the presentational (display-only) composer. */\n\tvalue?: TLRichText\n\tonChange?(value: TLRichText): void\n\t/** Called on Send click or Enter. When set, the composer is interactive. */\n\tonSubmit?(): void\n\tsendLabel?: string\n\t/** Called when Up is pressed in an empty composer \u2014 e.g. to start editing the comment above,\n\t * the way chat apps edit your last message. With content in the field, Up moves the cursor. */\n\tonArrowUpWhenEmpty?(): void\n\tdisabled?: boolean\n\tautoFocus?: boolean\n\t/** The leading element before the field. Defaults to the author's avatar. */\n\tleading?: ReactNode\n\t/** Resolve the members matching an `@`-query (sync or async). Provide to enable mentions. */\n\tgetMentionSuggestions?(query: string): MentionMember[] | Promise<MentionMember[]>\n\t/** Override a picker row's content. Defaults to avatar + name (+ secondary). */\n\trenderMentionSuggestion?(member: MentionMember): ReactNode\n}\n\n/**\n * The input for writing a comment: a TipTap rich-text editor restricted to the comment extension\n * set (bold, italic, lists, links, code, highlight \u2014 no headings), with a Send button. Formatting\n * is applied through markdown and keyboard shortcuts (e.g. `**bold**`, `- `, Cmd+B); there's no\n * floating toolbar. Presentational by default; pass value/onChange/onSubmit to drive it as a form.\n * @public @react\n */\nexport function CommentComposer({\n\tauthor,\n\tplaceholder,\n\tvalue,\n\tonChange,\n\tonSubmit,\n\tsendLabel = 'Send',\n\tonArrowUpWhenEmpty,\n\tdisabled,\n\tautoFocus,\n\tleading,\n\tgetMentionSuggestions,\n\trenderMentionSuggestion,\n}: CommentComposerProps) {\n\tconst interactive = !!onChange || !!onSubmit\n\t// The canvas editor the composer lives in, if any \u2014 lets the mention popup track the camera. Null\n\t// when the composer is used outside a tldraw editor (e.g. an isolated demo).\n\tconst tlEditor = useMaybeEditor()\n\n\t// Callbacks are read through refs so the editor instance doesn't need to be recreated when they\n\t// change identity between renders.\n\tconst onChangeRef = useRef(onChange)\n\tonChangeRef.current = onChange\n\tconst onSubmitRef = useRef(onSubmit)\n\tonSubmitRef.current = onSubmit\n\tconst onArrowUpWhenEmptyRef = useRef(onArrowUpWhenEmpty)\n\tonArrowUpWhenEmptyRef.current = onArrowUpWhenEmpty\n\tconst disabledRef = useRef(disabled)\n\tdisabledRef.current = disabled\n\tconst getMentionSuggestionsRef = useRef(getMentionSuggestions)\n\tgetMentionSuggestionsRef.current = getMentionSuggestions\n\tconst renderMentionSuggestionRef = useRef(renderMentionSuggestion)\n\trenderMentionSuggestionRef.current = renderMentionSuggestion\n\n\tconst [isEmpty, setIsEmpty] = useState(() => !value || isCommentEmpty(value))\n\t// Whether the field has grown to two rows: input across the full width, send button below.\n\t// Flips when the (single-line) content width reaches the space left beside the send button.\n\tconst [expanded, setExpanded] = useState(false)\n\tconst expandedRef = useRef(expanded)\n\texpandedRef.current = expanded\n\tconst inputWrapRef = useRef<HTMLDivElement>(null)\n\tconst mirrorRef = useRef<HTMLDivElement>(null)\n\n\t// Measure whether the content still fits on one line beside the send button. The mirror is a\n\t// hidden, nowrap clone of the editor's rendered content, so marks and mention chips measure at\n\t// their true width. A small dead zone between the expand and collapse thresholds keeps the\n\t// layout from flapping while typing at the boundary.\n\tconst remeasure = () => {\n\t\tconst wrap = inputWrapRef.current\n\t\tconst mirror = mirrorRef.current\n\t\tconst editor = editorRef.current\n\t\tif (!wrap || !mirror || !editor) return\n\t\t// Empty always fits \u2014 and measuring before TipTap's DOM has laid out reads zero widths,\n\t\t// which would flash the expanded layout for a frame on mount.\n\t\tif (editor.isEmpty) {\n\t\t\tif (expandedRef.current) setExpanded(false)\n\t\t\treturn\n\t\t}\n\t\tif (wrap.clientWidth === 0) return\n\t\tconst doc = editor.state.doc\n\t\tconst multiBlock =\n\t\t\tdoc.childCount > 1 || (doc.firstChild !== null && doc.firstChild.type.name !== 'paragraph')\n\t\tif (multiBlock) {\n\t\t\tif (!expandedRef.current) setExpanded(true)\n\t\t\treturn\n\t\t}\n\t\tconst field = wrap.parentElement\n\t\tconst send = field ? field.querySelector<HTMLElement>('.tlui-cmt-send') : null\n\t\tconst input = wrap.querySelector('.tlui-cmt-input')\n\t\tif (!send || !input) return\n\t\tmirror.innerHTML = input.innerHTML\n\t\tconst textWidth = mirror.offsetWidth\n\t\t// The single-line space the input has beside the send button: the wrap's *content* box\n\t\t// (clientWidth minus its own horizontal padding \u2014 the text wraps there, not at clientWidth),\n\t\t// less the button plus the field's 6px gap when already expanded (the wrap then spans the\n\t\t// full field). Without subtracting the padding, a padded wrap wraps to a second line ~padding\n\t\t// px before expansion fires, so the input grows a line and then snaps to the expanded layout.\n\t\tconst wrapStyle = getComputedStyle(wrap)\n\t\tconst wrapPadX = parseFloat(wrapStyle.paddingLeft) + parseFloat(wrapStyle.paddingRight)\n\t\tconst collapsedAvailable =\n\t\t\twrap.clientWidth - wrapPadX - (expandedRef.current ? send.offsetWidth + 6 : 0)\n\t\tif (!expandedRef.current && textWidth > collapsedAvailable - 8) {\n\t\t\tsetExpanded(true)\n\t\t} else if (expandedRef.current && textWidth < collapsedAvailable - 24) {\n\t\t\tsetExpanded(false)\n\t\t}\n\t}\n\tconst remeasureRef = useRef(remeasure)\n\tremeasureRef.current = remeasure\n\n\t// The editor instance, reachable from `handleKeyDown` (which is created before `useEditor`\n\t// returns). Updated on every render so the ref never points at a stale editor.\n\tconst editorRef = useRef<ReturnType<typeof useEditor>>(null)\n\n\t// Set while we replay Enter through the keymaps for a Shift+Enter newline: `commands.enter()`\n\t// re-dispatches Enter through `handleKeyDown`, and without this guard our own handler would catch\n\t// that synthetic Enter and submit instead.\n\tconst replayingEnter = useRef(false)\n\n\t// Enter and Cmd/Ctrl+Enter submit the comment; Shift+Enter inserts a new line for the occasional\n\t// multi-line comment. This is handled through `editorProps.handleKeyDown` (below) rather than a\n\t// keyboard-shortcut extension: ProseMirror runs `handleKeyDown` before every keymap plugin, so it\n\t// can tell Shift+Enter apart from Enter \u2014 an `Enter` keymap binding also fires on Shift/Cmd+Enter\n\t// and would otherwise swallow the newline.\n\n\t// The suggestion plugin is built once (the editor is recreated only on `interactive`) and runs\n\t// outside React, so it must read the mention callbacks through refs \u2014 like onChange/onSubmit \u2014\n\t// or it queries the roster present at mount forever, never seeing a member who loads or joins\n\t// later. Whether mentions (and a custom picker row) are wired at all is fixed at mount; only the\n\t// callbacks themselves are live.\n\tconst mentionsEnabled = !!getMentionSuggestions\n\tconst hasCustomRow = !!renderMentionSuggestion\n\tconst extensions = useMemo(() => {\n\t\tconst list = [...commentTipTapExtensions]\n\t\t// Always register the mention node so an existing body that contains a mention keeps it on\n\t\t// edit (an unregistered node would be stripped by ProseMirror when the content loads). The `@`\n\t\t// picker itself only turns on when the host provides a resolver; otherwise the node is present\n\t\t// but its trigger is disabled.\n\t\tif (mentionsEnabled) {\n\t\t\tconst resolveSuggestions = (query: string) => getMentionSuggestionsRef.current?.(query) ?? []\n\t\t\tconst renderRow = hasCustomRow\n\t\t\t\t? (member: MentionMember) => renderMentionSuggestionRef.current?.(member)\n\t\t\t\t: undefined\n\t\t\tlist.push(\n\t\t\t\tcreateMentionExtension({\n\t\t\t\t\tsuggestion: createMentionSuggestion(resolveSuggestions, {\n\t\t\t\t\t\trenderMember: renderRow,\n\t\t\t\t\t\teditor: tlEditor,\n\t\t\t\t\t}),\n\t\t\t\t})\n\t\t\t)\n\t\t} else {\n\t\t\tlist.push(createMentionExtension({ suggestion: { char: '@', allow: () => false } }))\n\t\t}\n\t\treturn list\n\t}, [mentionsEnabled, hasCustomRow, tlEditor])\n\n\tconst editor = useEditor(\n\t\t{\n\t\t\textensions,\n\t\t\tcontent: (value ?? EMPTY_COMMENT) as JSONContent,\n\t\t\teditable: interactive,\n\t\t\t// tldraw's default extensions add their own TextDirection extension (so it can be\n\t\t\t// overridden), so disable TipTap's core one to avoid a duplicate-extension warning \u2014\n\t\t\t// mirrors RichTextArea's setup.\n\t\t\tenableCoreExtensions: { textDirection: false },\n\t\t\ttextDirection: 'auto',\n\t\t\teditorProps: {\n\t\t\t\tattributes: {\n\t\t\t\t\tclass: 'tlui-cmt-input',\n\t\t\t\t\t'aria-label': placeholder,\n\t\t\t\t\trole: 'textbox',\n\t\t\t\t\t'aria-multiline': 'true',\n\t\t\t\t},\n\t\t\t\t// Runs before every keymap plugin, so it can distinguish Shift+Enter from Enter \u2014 an\n\t\t\t\t// `Enter` keymap binding also fires on Shift+Enter and would otherwise swallow it.\n\t\t\t\thandleKeyDown: (_view, event) => {\n\t\t\t\t\t// Let the keymaps handle the synthetic Enter we replay for a Shift+Enter newline.\n\t\t\t\t\tif (replayingEnter.current) return false\n\t\t\t\t\t// Up in an empty composer hands off to the host (edit the comment above). With\n\t\t\t\t\t// content, Up stays cursor movement; with the mention picker open, it navigates it.\n\t\t\t\t\tif (event.key === 'ArrowUp' && !event.isComposing) {\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tonArrowUpWhenEmptyRef.current &&\n\t\t\t\t\t\t\teditorRef.current?.isEmpty &&\n\t\t\t\t\t\t\t!isMentionPickerOpen()\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tonArrowUpWhenEmptyRef.current()\n\t\t\t\t\t\t\treturn true\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn false\n\t\t\t\t\t}\n\t\t\t\t\tif (event.key !== 'Enter' || event.isComposing) return false\n\t\t\t\t\t// While the @-mention picker is open, Enter selects the highlighted member \u2014 defer.\n\t\t\t\t\tif (isMentionPickerOpen()) return false\n\t\t\t\t\t// Shift+Enter inserts a new line. Replay a plain Enter through the keymaps (guarded so\n\t\t\t\t\t// we don't re-enter and submit) to reuse the editor's list-aware Enter handling \u2014 a new\n\t\t\t\t\t// list item in a list, a new paragraph otherwise. tldraw doesn't do soft breaks.\n\t\t\t\t\tif (event.shiftKey && !event.metaKey && !event.ctrlKey && !event.altKey) {\n\t\t\t\t\t\t// An empty field has nothing to break onto \u2014 swallow the keypress so it doesn't\n\t\t\t\t\t\t// open the comment with a stray leading blank line.\n\t\t\t\t\t\tif (editorRef.current?.isEmpty) return true\n\t\t\t\t\t\treplayingEnter.current = true\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\teditorRef.current?.commands.enter()\n\t\t\t\t\t\t} finally {\n\t\t\t\t\t\t\treplayingEnter.current = false\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn true\n\t\t\t\t\t}\n\t\t\t\t\t// Enter, Cmd+Enter, and Ctrl+Enter submit.\n\t\t\t\t\tif (!disabledRef.current) onSubmitRef.current?.()\n\t\t\t\t\treturn true\n\t\t\t\t},\n\t\t\t},\n\t\t\tonUpdate: ({ editor }) => {\n\t\t\t\tsetIsEmpty(editor.isEmpty)\n\t\t\t\t// Same-value state sets don't re-render, so measure here \u2014 the editor's DOM is\n\t\t\t\t// already updated when onUpdate fires.\n\t\t\t\tremeasureRef.current()\n\t\t\t\tonChangeRef.current?.(editor.getJSON() as TLRichText)\n\t\t\t},\n\t\t},\n\t\t[interactive, placeholder]\n\t)\n\teditorRef.current = editor\n\n\t// Sync controlled resets (e.g. the parent clearing to EMPTY_COMMENT after posting) into the\n\t// editor without echoing back the value the editor itself just emitted.\n\tuseEffect(() => {\n\t\tif (!editor || value === undefined) return\n\t\tif (isEqual(editor.getJSON(), value)) return\n\t\teditor.commands.setContent(value as JSONContent)\n\t\tsetIsEmpty(editor.isEmpty)\n\t}, [editor, value])\n\n\t// Measure once the editor's content is in the DOM, so a composer that mounts pre-filled (the\n\t// edit-in-place composer) starts in the right layout.\n\tuseLayoutEffect(() => {\n\t\tremeasureRef.current()\n\t}, [editor, value])\n\n\t// Focus on the next frame rather than via TipTap's autofocus: the composer often mounts from a\n\t// canvas pointer event whose default focus handling would otherwise steal it back.\n\tuseEffect(() => {\n\t\tif (!autoFocus || !editor) return\n\t\tconst raf = requestAnimationFrame(() => editor.commands.focus('end'))\n\t\treturn () => cancelAnimationFrame(raf)\n\t}, [autoFocus, editor])\n\n\t// tldraw's pass-through-wheel hook (on the floating composer's wrapper) forwards a wheel to the\n\t// canvas unless ITS element is scrollable \u2014 but the scrollable element is this input, not that\n\t// wrapper, so an overflowing input never scrolled: the wheel panned the canvas instead. Catch the\n\t// wheel on the wrap first (a native listener here fires before the wrapper's, deeper in the tree)\n\t// and stop it while the input can still scroll that way; at the scroll boundary let it through so\n\t// the canvas still zooms.\n\tuseEffect(() => {\n\t\tconst wrap = inputWrapRef.current\n\t\tif (!wrap) return\n\t\tconst onWheel = (e: WheelEvent) => {\n\t\t\tconst input = wrap.querySelector<HTMLElement>('.tlui-cmt-input')\n\t\t\tif (!input || input.scrollHeight <= input.clientHeight) return\n\t\t\tconst atTop = input.scrollTop <= 0\n\t\t\tconst atBottom = input.scrollTop >= input.scrollHeight - input.clientHeight - 1\n\t\t\tif ((e.deltaY < 0 && !atTop) || (e.deltaY > 0 && !atBottom)) {\n\t\t\t\te.stopPropagation()\n\t\t\t}\n\t\t}\n\t\twrap.addEventListener('wheel', onWheel)\n\t\treturn () => wrap.removeEventListener('wheel', onWheel)\n\t}, [])\n\n\t// The whole field behaves like the text input: clicking its empty area (the padding, or the\n\t// space beside/below a short line) focuses the editor rather than only the text glyphs being\n\t// clickable. The input (caret placement) and the send button keep their own click handling.\n\tconst focusEditorFromField = (e: ReactMouseEvent<HTMLDivElement>) => {\n\t\tconst target = e.target as HTMLElement\n\t\tif (target.closest('.tlui-cmt-input') || target.closest('.tlui-cmt-send')) return\n\t\te.preventDefault()\n\t\teditor?.commands.focus('end')\n\t}\n\n\treturn (\n\t\t<div className=\"tlui-cmt-composer\">\n\t\t\t{leading ?? <Avatar author={author} />}\n\t\t\t<div\n\t\t\t\tclassName={[\n\t\t\t\t\t'tlui-cmt-composer__field',\n\t\t\t\t\tinteractive && expanded && 'tlui-cmt-composer__field--expanded',\n\t\t\t\t]\n\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t.join(' ')}\n\t\t\t\tonMouseDown={interactive ? focusEditorFromField : undefined}\n\t\t\t>\n\t\t\t\t<div className=\"tlui-cmt-composer__input-wrap\" ref={inputWrapRef}>\n\t\t\t\t\t<EditorContent editor={editor} />\n\t\t\t\t\t{isEmpty && (\n\t\t\t\t\t\t<div className=\"tlui-cmt-input__placeholder\" aria-hidden=\"true\">\n\t\t\t\t\t\t\t{placeholder}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\t\t\t\t\t<div\n\t\t\t\t\t\tclassName=\"tlui-cmt-composer__mirror tlui-cmt-input\"\n\t\t\t\t\t\tref={mirrorRef}\n\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t/>\n\t\t\t\t</div>\n\t\t\t\t{interactive && <SendButton label={sendLabel} onClick={onSubmit} disabled={disabled} />}\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["import_react", "editor"]
7
7
  }
@@ -22,12 +22,30 @@ __export(comment_pin_exports, {
22
22
  });
23
23
  module.exports = __toCommonJS(comment_pin_exports);
24
24
  var import_jsx_runtime = require("react/jsx-runtime");
25
+ const resolvedCheck = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
26
+ "svg",
27
+ {
28
+ viewBox: "0 0 24 24",
29
+ width: "15",
30
+ height: "15",
31
+ fill: "none",
32
+ stroke: "currentColor",
33
+ strokeWidth: "2.5",
34
+ strokeLinecap: "round",
35
+ strokeLinejoin: "round",
36
+ "aria-hidden": "true",
37
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M4 12.5l5 5L20 6.5" })
38
+ }
39
+ );
25
40
  function CommentPin({ children, resolved, open }) {
26
41
  const className = [
42
+ // `tlui-cmt-marker` carries the resting shadow and the hover lift — the same treatment a
43
+ // count badge wears, so the two markers behave alike.
44
+ "tlui-cmt-marker",
27
45
  "tlui-cmt-pin",
28
46
  resolved && "tlui-cmt-pin--resolved",
29
- open && "tlui-cmt-pin--open"
47
+ open && "tlui-cmt-marker--open"
30
48
  ].filter(Boolean).join(" ");
31
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className, children: resolved ? "\u2713" : children });
49
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className, children: resolved ? resolvedCheck : children });
32
50
  }
33
51
  //# sourceMappingURL=comment-pin.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/ui/comment-pin.tsx"],
4
- "sourcesContent": ["import { ReactNode } from 'react'\n\n/** @public */\nexport interface CommentPinProps {\n\t/** What the pin shows when unresolved \u2014 a number, an author initial, an <Avatar>, etc.\n\t * Left as a lever so consumers aren't locked into a count. */\n\tchildren?: ReactNode\n\tresolved?: boolean\n\t/** The pin's thread is open \u2014 shows the active/selected indicator state. */\n\topen?: boolean\n}\n\n/** A canvas comment marker: shows its `children` (or a check when resolved). Purely\n * presentational \u2014 it reflects open/resolved state via CSS; wrap it to make it clickable.\n * @public @react */\nexport function CommentPin({ children, resolved, open }: CommentPinProps) {\n\tconst className = [\n\t\t'tlui-cmt-pin',\n\t\tresolved && 'tlui-cmt-pin--resolved',\n\t\topen && 'tlui-cmt-pin--open',\n\t]\n\t\t.filter(Boolean)\n\t\t.join(' ')\n\treturn <div className={className}>{resolved ? '\u2713' : children}</div>\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAuBQ;AARD,SAAS,WAAW,EAAE,UAAU,UAAU,KAAK,GAAoB;AACzE,QAAM,YAAY;AAAA,IACjB;AAAA,IACA,YAAY;AAAA,IACZ,QAAQ;AAAA,EACT,EACE,OAAO,OAAO,EACd,KAAK,GAAG;AACV,SAAO,4CAAC,SAAI,WAAuB,qBAAW,WAAM,UAAS;AAC9D;",
4
+ "sourcesContent": ["import { ReactNode } from 'react'\n\n/** @public */\nexport interface CommentPinProps {\n\t/** What the pin shows when unresolved \u2014 a number, an author initial, an <Avatar>, etc.\n\t * Left as a lever so consumers aren't locked into a count. */\n\tchildren?: ReactNode\n\tresolved?: boolean\n\t/** The pin's thread is open \u2014 shows the active/selected indicator state. */\n\topen?: boolean\n}\n\n/* An inline check, not a text glyph \u2014 the '\u2713' character sits off-baseline and varies by font. */\nconst resolvedCheck = (\n\t<svg\n\t\tviewBox=\"0 0 24 24\"\n\t\twidth=\"15\"\n\t\theight=\"15\"\n\t\tfill=\"none\"\n\t\tstroke=\"currentColor\"\n\t\tstrokeWidth=\"2.5\"\n\t\tstrokeLinecap=\"round\"\n\t\tstrokeLinejoin=\"round\"\n\t\taria-hidden=\"true\"\n\t>\n\t\t<path d=\"M4 12.5l5 5L20 6.5\" />\n\t</svg>\n)\n\n/** A canvas comment marker: shows its `children` (or a check when resolved). Purely\n * presentational \u2014 it reflects open/resolved state via CSS; wrap it to make it clickable.\n * @public @react */\nexport function CommentPin({ children, resolved, open }: CommentPinProps) {\n\tconst className = [\n\t\t// `tlui-cmt-marker` carries the resting shadow and the hover lift \u2014 the same treatment a\n\t\t// count badge wears, so the two markers behave alike.\n\t\t'tlui-cmt-marker',\n\t\t'tlui-cmt-pin',\n\t\tresolved && 'tlui-cmt-pin--resolved',\n\t\topen && 'tlui-cmt-marker--open',\n\t]\n\t\t.filter(Boolean)\n\t\t.join(' ')\n\treturn <div className={className}>{resolved ? resolvedCheck : children}</div>\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAyBE;AAZF,MAAM,gBACL;AAAA,EAAC;AAAA;AAAA,IACA,SAAQ;AAAA,IACR,OAAM;AAAA,IACN,QAAO;AAAA,IACP,MAAK;AAAA,IACL,QAAO;AAAA,IACP,aAAY;AAAA,IACZ,eAAc;AAAA,IACd,gBAAe;AAAA,IACf,eAAY;AAAA,IAEZ,sDAAC,UAAK,GAAE,sBAAqB;AAAA;AAC9B;AAMM,SAAS,WAAW,EAAE,UAAU,UAAU,KAAK,GAAoB;AACzE,QAAM,YAAY;AAAA;AAAA;AAAA,IAGjB;AAAA,IACA;AAAA,IACA,YAAY;AAAA,IACZ,QAAQ;AAAA,EACT,EACE,OAAO,OAAO,EACd,KAAK,GAAG;AACV,SAAO,4CAAC,SAAI,WAAuB,qBAAW,gBAAgB,UAAS;AACxE;",
6
6
  "names": []
7
7
  }