@tldraw/commenting 0.0.0-bootstrap → 5.3.0-internal.1640468db8fd

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 (184) hide show
  1. package/commenting.css +284 -153
  2. package/dist-cjs/canvas/comment-body.js +1 -1
  3. package/dist-cjs/canvas/comment-body.js.map +2 -2
  4. package/dist-cjs/canvas/comment-drafts.js +54 -0
  5. package/dist-cjs/canvas/comment-drafts.js.map +7 -0
  6. package/dist-cjs/canvas/comment-render.js +2 -0
  7. package/dist-cjs/canvas/comment-render.js.map +2 -2
  8. package/dist-cjs/canvas/comment-tool.js +65 -12
  9. package/dist-cjs/canvas/comment-tool.js.map +2 -2
  10. package/dist-cjs/canvas/comments-filter-menu.js +54 -63
  11. package/dist-cjs/canvas/comments-filter-menu.js.map +2 -2
  12. package/dist-cjs/canvas/comments-overflow-menu.js +21 -27
  13. package/dist-cjs/canvas/comments-overflow-menu.js.map +2 -2
  14. package/dist-cjs/canvas/comments-overlay.js +304 -112
  15. package/dist-cjs/canvas/comments-overlay.js.map +2 -2
  16. package/dist-cjs/canvas/comments-sidebar.js +12 -18
  17. package/dist-cjs/canvas/comments-sidebar.js.map +2 -2
  18. package/dist-cjs/canvas/comments-visibility-toggle.js +66 -0
  19. package/dist-cjs/canvas/comments-visibility-toggle.js.map +7 -0
  20. package/dist-cjs/canvas/options.js +1 -0
  21. package/dist-cjs/canvas/options.js.map +2 -2
  22. package/dist-cjs/canvas/sidebar-filters.js +2 -2
  23. package/dist-cjs/canvas/sidebar-filters.js.map +2 -2
  24. package/dist-cjs/canvas/state.js +11 -0
  25. package/dist-cjs/canvas/state.js.map +2 -2
  26. package/dist-cjs/canvas/thread-state.js +8 -1
  27. package/dist-cjs/canvas/thread-state.js.map +2 -2
  28. package/dist-cjs/clustering/runtime.js +119 -7
  29. package/dist-cjs/clustering/runtime.js.map +2 -2
  30. package/dist-cjs/index.d.ts +126 -41
  31. package/dist-cjs/index.js +7 -1
  32. package/dist-cjs/index.js.map +2 -2
  33. package/dist-cjs/ui/avatar.js +14 -6
  34. package/dist-cjs/ui/avatar.js.map +2 -2
  35. package/dist-cjs/ui/byline.js +4 -4
  36. package/dist-cjs/ui/byline.js.map +2 -2
  37. package/dist-cjs/ui/comment-author.js +17 -0
  38. package/dist-cjs/ui/comment-author.js.map +7 -0
  39. package/dist-cjs/ui/comment-card.js +4 -4
  40. package/dist-cjs/ui/comment-card.js.map +2 -2
  41. package/dist-cjs/ui/comment-composer.js +92 -29
  42. package/dist-cjs/ui/comment-composer.js.map +2 -2
  43. package/dist-cjs/ui/comment-mention.js +1 -1
  44. package/dist-cjs/ui/comment-mention.js.map +2 -2
  45. package/dist-cjs/ui/comment-pin.js +23 -3
  46. package/dist-cjs/ui/comment-pin.js.map +2 -2
  47. package/dist-cjs/ui/comment-text.js +1 -1
  48. package/dist-cjs/ui/comment-text.js.map +2 -2
  49. package/dist-cjs/ui/comment-thread.js +6 -6
  50. package/dist-cjs/ui/comment-thread.js.map +2 -2
  51. package/dist-cjs/ui/comments-list.js +12 -12
  52. package/dist-cjs/ui/comments-list.js.map +2 -2
  53. package/dist-cjs/ui/count-badge.js +1 -1
  54. package/dist-cjs/ui/count-badge.js.map +2 -2
  55. package/dist-cjs/ui/empty-state.js +3 -3
  56. package/dist-cjs/ui/empty-state.js.map +2 -2
  57. package/dist-cjs/ui/format-time.js +3 -0
  58. package/dist-cjs/ui/format-time.js.map +2 -2
  59. package/dist-cjs/ui/mention-list.js +8 -8
  60. package/dist-cjs/ui/mention-list.js.map +2 -2
  61. package/dist-cjs/ui/mention-suggestion.js +3 -3
  62. package/dist-cjs/ui/mention-suggestion.js.map +2 -2
  63. package/dist-cjs/ui/mention.js +1 -1
  64. package/dist-cjs/ui/mention.js.map +2 -2
  65. package/dist-cjs/ui/reaction.js +11 -4
  66. package/dist-cjs/ui/reaction.js.map +2 -2
  67. package/dist-cjs/ui/reactions.js +10 -2
  68. package/dist-cjs/ui/reactions.js.map +2 -2
  69. package/dist-cjs/ui/send-button.js +1 -1
  70. package/dist-cjs/ui/send-button.js.map +2 -2
  71. package/dist-cjs/ui/tooltip-button.js +32 -0
  72. package/dist-cjs/ui/tooltip-button.js.map +7 -0
  73. package/dist-esm/canvas/comment-body.mjs +1 -1
  74. package/dist-esm/canvas/comment-body.mjs.map +2 -2
  75. package/dist-esm/canvas/comment-drafts.mjs +34 -0
  76. package/dist-esm/canvas/comment-drafts.mjs.map +7 -0
  77. package/dist-esm/canvas/comment-render.mjs +2 -0
  78. package/dist-esm/canvas/comment-render.mjs.map +2 -2
  79. package/dist-esm/canvas/comment-tool.mjs +67 -14
  80. package/dist-esm/canvas/comment-tool.mjs.map +2 -2
  81. package/dist-esm/canvas/comments-filter-menu.mjs +54 -63
  82. package/dist-esm/canvas/comments-filter-menu.mjs.map +2 -2
  83. package/dist-esm/canvas/comments-overflow-menu.mjs +22 -27
  84. package/dist-esm/canvas/comments-overflow-menu.mjs.map +2 -2
  85. package/dist-esm/canvas/comments-overlay.mjs +322 -114
  86. package/dist-esm/canvas/comments-overlay.mjs.map +2 -2
  87. package/dist-esm/canvas/comments-sidebar.mjs +15 -21
  88. package/dist-esm/canvas/comments-sidebar.mjs.map +2 -2
  89. package/dist-esm/canvas/comments-visibility-toggle.mjs +46 -0
  90. package/dist-esm/canvas/comments-visibility-toggle.mjs.map +7 -0
  91. package/dist-esm/canvas/options.mjs +1 -0
  92. package/dist-esm/canvas/options.mjs.map +2 -2
  93. package/dist-esm/canvas/sidebar-filters.mjs +2 -2
  94. package/dist-esm/canvas/sidebar-filters.mjs.map +2 -2
  95. package/dist-esm/canvas/state.mjs +11 -0
  96. package/dist-esm/canvas/state.mjs.map +2 -2
  97. package/dist-esm/canvas/thread-state.mjs +8 -1
  98. package/dist-esm/canvas/thread-state.mjs.map +2 -2
  99. package/dist-esm/clustering/runtime.mjs +119 -7
  100. package/dist-esm/clustering/runtime.mjs.map +2 -2
  101. package/dist-esm/index.d.mts +126 -41
  102. package/dist-esm/index.mjs +11 -1
  103. package/dist-esm/index.mjs.map +2 -2
  104. package/dist-esm/ui/avatar.mjs +14 -6
  105. package/dist-esm/ui/avatar.mjs.map +2 -2
  106. package/dist-esm/ui/byline.mjs +4 -4
  107. package/dist-esm/ui/byline.mjs.map +2 -2
  108. package/dist-esm/ui/comment-author.mjs +1 -0
  109. package/dist-esm/ui/comment-author.mjs.map +7 -0
  110. package/dist-esm/ui/comment-card.mjs +4 -4
  111. package/dist-esm/ui/comment-card.mjs.map +2 -2
  112. package/dist-esm/ui/comment-composer.mjs +93 -30
  113. package/dist-esm/ui/comment-composer.mjs.map +2 -2
  114. package/dist-esm/ui/comment-mention.mjs +1 -1
  115. package/dist-esm/ui/comment-mention.mjs.map +2 -2
  116. package/dist-esm/ui/comment-pin.mjs +23 -3
  117. package/dist-esm/ui/comment-pin.mjs.map +2 -2
  118. package/dist-esm/ui/comment-text.mjs +1 -1
  119. package/dist-esm/ui/comment-text.mjs.map +2 -2
  120. package/dist-esm/ui/comment-thread.mjs +6 -6
  121. package/dist-esm/ui/comment-thread.mjs.map +2 -2
  122. package/dist-esm/ui/comments-list.mjs +12 -12
  123. package/dist-esm/ui/comments-list.mjs.map +2 -2
  124. package/dist-esm/ui/count-badge.mjs +1 -1
  125. package/dist-esm/ui/count-badge.mjs.map +2 -2
  126. package/dist-esm/ui/empty-state.mjs +3 -3
  127. package/dist-esm/ui/empty-state.mjs.map +2 -2
  128. package/dist-esm/ui/format-time.mjs +3 -0
  129. package/dist-esm/ui/format-time.mjs.map +2 -2
  130. package/dist-esm/ui/mention-list.mjs +8 -8
  131. package/dist-esm/ui/mention-list.mjs.map +2 -2
  132. package/dist-esm/ui/mention-suggestion.mjs +3 -3
  133. package/dist-esm/ui/mention-suggestion.mjs.map +2 -2
  134. package/dist-esm/ui/mention.mjs +1 -1
  135. package/dist-esm/ui/mention.mjs.map +2 -2
  136. package/dist-esm/ui/reaction.mjs +11 -4
  137. package/dist-esm/ui/reaction.mjs.map +2 -2
  138. package/dist-esm/ui/reactions.mjs +10 -2
  139. package/dist-esm/ui/reactions.mjs.map +2 -2
  140. package/dist-esm/ui/send-button.mjs +1 -1
  141. package/dist-esm/ui/send-button.mjs.map +2 -2
  142. package/dist-esm/ui/tooltip-button.mjs +12 -0
  143. package/dist-esm/ui/tooltip-button.mjs.map +7 -0
  144. package/package.json +3 -3
  145. package/src/canvas/canvas.css +79 -36
  146. package/src/canvas/comment-body.tsx +1 -1
  147. package/src/canvas/comment-drafts.test.ts +55 -0
  148. package/src/canvas/comment-drafts.ts +46 -0
  149. package/src/canvas/comment-render.test.ts +1 -1
  150. package/src/canvas/comment-render.ts +7 -2
  151. package/src/canvas/comment-tool.tsx +98 -17
  152. package/src/canvas/comments-filter-menu.tsx +27 -33
  153. package/src/canvas/comments-overflow-menu.tsx +13 -21
  154. package/src/canvas/comments-overlay.tsx +441 -145
  155. package/src/canvas/comments-sidebar.tsx +27 -28
  156. package/src/canvas/comments-visibility-toggle.tsx +50 -0
  157. package/src/canvas/options.ts +25 -0
  158. package/src/canvas/sidebar-filters.ts +4 -3
  159. package/src/canvas/state.ts +22 -0
  160. package/src/canvas/thread-state.ts +16 -3
  161. package/src/clustering/runtime.test.ts +183 -7
  162. package/src/clustering/runtime.ts +164 -15
  163. package/src/index.ts +7 -0
  164. package/src/ui/avatar.tsx +15 -11
  165. package/src/ui/byline.tsx +6 -5
  166. package/src/ui/comment-author.ts +15 -0
  167. package/src/ui/comment-card.tsx +6 -5
  168. package/src/ui/comment-composer.tsx +122 -33
  169. package/src/ui/comment-mention.ts +2 -2
  170. package/src/ui/comment-pin.tsx +35 -4
  171. package/src/ui/comment-text.tsx +1 -1
  172. package/src/ui/comment-thread.tsx +8 -6
  173. package/src/ui/comments-list.tsx +19 -14
  174. package/src/ui/comments.css +205 -117
  175. package/src/ui/count-badge.tsx +1 -1
  176. package/src/ui/empty-state.tsx +3 -3
  177. package/src/ui/format-time.ts +5 -0
  178. package/src/ui/mention-list.tsx +13 -16
  179. package/src/ui/mention-suggestion.tsx +3 -3
  180. package/src/ui/mention.tsx +1 -1
  181. package/src/ui/reaction.tsx +6 -3
  182. package/src/ui/reactions.tsx +6 -2
  183. package/src/ui/send-button.tsx +1 -1
  184. package/src/ui/tooltip-button.tsx +20 -0
@@ -5,5 +5,5 @@ export interface CountBadgeProps {
5
5
 
6
6
  /** @public @react */
7
7
  export function CountBadge({ count }: CountBadgeProps) {
8
- return <div className="cmt-count-badge">{count}</div>
8
+ return <div className="tlui-cmt-count-badge">{count}</div>
9
9
  }
@@ -6,11 +6,11 @@ export interface EmptyStateProps {
6
6
  /** The empty state shown when a thread has no comments yet. @public @react */
7
7
  export function EmptyState({ message }: EmptyStateProps) {
8
8
  return (
9
- <div className="cmt-empty">
10
- <div className="cmt-empty__icon" aria-hidden="true">
9
+ <div className="tlui-cmt-empty">
10
+ <div className="tlui-cmt-empty__icon" aria-hidden="true">
11
11
  💬
12
12
  </div>
13
- <p className="cmt-empty__message">{message}</p>
13
+ <p className="tlui-cmt-empty__message">{message}</p>
14
14
  </div>
15
15
  )
16
16
  }
@@ -19,6 +19,11 @@ export function formatRelativeTime(iso: string, locale = 'en'): string {
19
19
 
20
20
  const rtf = new Intl.RelativeTimeFormat(locale, { numeric: 'auto' })
21
21
  let duration = (then - Date.now()) / 1000
22
+ // Under a minute is just "now" — with second granularity the label visibly ticks while
23
+ // typing a reply (every keystroke re-renders the card).
24
+ if (Math.abs(duration) < 60) {
25
+ return rtf.format(0, 'second')
26
+ }
22
27
  for (const division of DIVISIONS) {
23
28
  if (Math.abs(duration) < division.amount) {
24
29
  return rtf.format(Math.round(duration), division.unit)
@@ -1,15 +1,12 @@
1
1
  import { ReactNode } from 'react'
2
2
  import { useTranslation } from 'tldraw'
3
3
  import { Avatar } from './avatar'
4
+ import { CommentAuthor } from './comment-author'
4
5
 
5
- /** A person the composer's \@-mention picker can offer. @public */
6
- export interface MentionMember {
6
+ /** A person the composer's \@-mention picker can offer: a {@link CommentAuthor} plus its id and
7
+ * picker-only display fields. @public */
8
+ export interface MentionMember extends CommentAuthor {
7
9
  id: string
8
- name: string
9
- /** Avatar image URL. Falls back to a coloured initial when omitted. */
10
- avatar?: string
11
- /** Avatar background colour, used when there's no `avatar` image. */
12
- color?: string
13
10
  /** A secondary line under the name — e.g. an email or handle. Omit for a single-line row. */
14
11
  secondary?: string
15
12
  /** Marks the current user; shown as a "(You)" suffix after the name. */
@@ -37,16 +34,16 @@ function DefaultMemberRow({ member }: { member: MentionMember }) {
37
34
  const msg = useTranslation()
38
35
  return (
39
36
  <>
40
- <Avatar name={member.name} color={member.color} image={member.avatar} />
41
- <span className="cmt-mention-list__text">
42
- <span className="cmt-mention-list__name">
37
+ <Avatar author={member} />
38
+ <span className="tlui-cmt-mention-list__text">
39
+ <span className="tlui-cmt-mention-list__name">
43
40
  {member.name}
44
41
  {member.you && (
45
- <span className="cmt-mention-list__you">{`(${msg('comments.mention-you')})`}</span>
42
+ <span className="tlui-cmt-mention-list__you">{`(${msg('comments.mention-you')})`}</span>
46
43
  )}
47
44
  </span>
48
45
  {member.secondary && (
49
- <span className="cmt-mention-list__secondary">{member.secondary}</span>
46
+ <span className="tlui-cmt-mention-list__secondary">{member.secondary}</span>
50
47
  )}
51
48
  </span>
52
49
  </>
@@ -69,13 +66,13 @@ export function MentionList({
69
66
  const msg = useTranslation()
70
67
  if (members.length === 0) {
71
68
  return (
72
- <div className="cmt-mention-list cmt-mention-list--empty">
69
+ <div className="tlui-cmt-mention-list tlui-cmt-mention-list--empty">
73
70
  {emptyLabel ?? msg('comments.mention-no-matches')}
74
71
  </div>
75
72
  )
76
73
  }
77
74
  return (
78
- <div className="cmt-mention-list" role="listbox">
75
+ <div className="tlui-cmt-mention-list" role="listbox">
79
76
  {members.map((member, i) => {
80
77
  const active = i === activeIndex
81
78
  return (
@@ -86,8 +83,8 @@ export function MentionList({
86
83
  aria-selected={active}
87
84
  className={
88
85
  active
89
- ? 'cmt-mention-list__item cmt-mention-list__item--active'
90
- : 'cmt-mention-list__item'
86
+ ? 'tlui-cmt-mention-list__item tlui-cmt-mention-list__item--active'
87
+ : 'tlui-cmt-mention-list__item'
91
88
  }
92
89
  // Keep the composer focused on a row press: it's portaled outside the editor, so a
93
90
  // bare mousedown would blur the composer — which now dismisses the picker — before
@@ -139,7 +139,7 @@ export function createMentionSuggestion(
139
139
  // the caret, matching its width), and remember the field's page-space anchor for reposition.
140
140
  const place = () => {
141
141
  if (!container || !editorEl || container.style.display === 'none') return
142
- const field = editorEl.closest('.cmt-composer__field') ?? editorEl
142
+ const field = editorEl.closest('.tlui-cmt-composer__field') ?? editorEl
143
143
  const rect = field.getBoundingClientRect()
144
144
  popupWidth = rect.width
145
145
  anchorPage = options.editor?.screenToPage({ x: rect.left, y: rect.bottom }) ?? null
@@ -193,7 +193,7 @@ export function createMentionSuggestion(
193
193
  // only redispatch when it can't). Done imperatively because the popup lives outside React.
194
194
  const onWheel = (e: WheelEvent) => {
195
195
  if ((e as any).isSpecialRedispatchedEvent || !canvasEl) return
196
- const list = container?.querySelector('.cmt-mention-list')
196
+ const list = container?.querySelector('.tlui-cmt-mention-list')
197
197
  if (list && list.scrollHeight > list.clientHeight) return
198
198
  e.preventDefault()
199
199
  const redispatched = new WheelEvent('wheel', e)
@@ -217,7 +217,7 @@ export function createMentionSuggestion(
217
217
  // composer — leaving Escape a no-op and the roster stuck on screen.
218
218
  editorEl.addEventListener('blur', hide)
219
219
  container = document.createElement('div')
220
- container.className = 'cmt-mention-popup'
220
+ container.className = 'tlui-cmt-mention-popup'
221
221
  container.appendChild(renderer.element)
222
222
  // Mount inside the tldraw container so the popup inherits the theme variables
223
223
  // (--tl-color-*); portaling to document.body would strip them and lose the panel.
@@ -5,5 +5,5 @@ export interface MentionProps {
5
5
 
6
6
  /** An \@-mention pill for referencing a person in a comment. @public @react */
7
7
  export function Mention({ name }: MentionProps) {
8
- return <span className="cmt-mention">@{name}</span>
8
+ return <span className="tlui-cmt-mention">@{name}</span>
9
9
  }
@@ -8,9 +8,12 @@ export interface ReactionProps {
8
8
  /** A single emoji reaction pill with a count, highlighted when the user reacted. @public @react */
9
9
  export function Reaction({ emoji, count, active }: ReactionProps) {
10
10
  return (
11
- <button className={active ? 'cmt-reaction cmt-reaction--active' : 'cmt-reaction'} type="button">
12
- <span className="cmt-reaction__emoji">{emoji}</span>
13
- <span className="cmt-reaction__count">{count}</span>
11
+ <button
12
+ className={active ? 'tlui-cmt-reaction tlui-cmt-reaction--active' : 'tlui-cmt-reaction'}
13
+ type="button"
14
+ >
15
+ <span className="tlui-cmt-reaction__emoji">{emoji}</span>
16
+ <span className="tlui-cmt-reaction__count">{count}</span>
14
17
  </button>
15
18
  )
16
19
  }
@@ -3,11 +3,15 @@ import { Reaction } from './reaction'
3
3
  /** The row of reactions under a comment, plus an add-reaction button. @public @react */
4
4
  export function Reactions() {
5
5
  return (
6
- <div className="cmt-reactions">
6
+ <div className="tlui-cmt-reactions">
7
7
  <Reaction emoji="👍" count={3} active={true} />
8
8
  <Reaction emoji="🎉" count={1} active={false} />
9
9
  <Reaction emoji="👀" count={2} active={false} />
10
- <button className="cmt-reaction cmt-reaction--add" type="button" aria-label="Add reaction">
10
+ <button
11
+ className="tlui-cmt-reaction tlui-cmt-reaction--add"
12
+ type="button"
13
+ aria-label="Add reaction"
14
+ >
11
15
 
12
16
  </button>
13
17
  </div>
@@ -8,7 +8,7 @@ export interface SendButtonProps {
8
8
  /** The button that posts a comment. @public @react */
9
9
  export function SendButton({ label, disabled, onClick }: SendButtonProps) {
10
10
  return (
11
- <button className="cmt-send" type="button" disabled={disabled} onClick={onClick}>
11
+ <button className="tlui-cmt-send" type="button" disabled={disabled} onClick={onClick}>
12
12
  {label}
13
13
  </button>
14
14
  )
@@ -0,0 +1,20 @@
1
+ import { type ButtonHTMLAttributes, forwardRef } from 'react'
2
+ import { TldrawUiTooltip } from 'tldraw'
3
+
4
+ interface TooltipButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
5
+ tooltip: string
6
+ }
7
+
8
+ /** An icon button labelled by a styled tooltip. Forwards ref and props to the underlying button
9
+ * so `asChild` triggers (dropdown, tooltip) both compose onto the real element. */
10
+ export const TooltipButton = forwardRef<HTMLButtonElement, TooltipButtonProps>(
11
+ function TooltipButton({ tooltip, children, ...props }, ref) {
12
+ return (
13
+ <TldrawUiTooltip content={tooltip}>
14
+ <button ref={ref} type="button" aria-label={tooltip} {...props}>
15
+ {children}
16
+ </button>
17
+ </TldrawUiTooltip>
18
+ )
19
+ }
20
+ )