@tldraw/commenting 0.0.0-bootstrap → 5.3.0-internal.c5c7f1d817d0

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 (125) hide show
  1. package/commenting.css +131 -131
  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/comments-filter-menu.js +1 -1
  5. package/dist-cjs/canvas/comments-filter-menu.js.map +1 -1
  6. package/dist-cjs/canvas/comments-overflow-menu.js +3 -3
  7. package/dist-cjs/canvas/comments-overflow-menu.js.map +2 -2
  8. package/dist-cjs/canvas/comments-overlay.js +65 -50
  9. package/dist-cjs/canvas/comments-overlay.js.map +2 -2
  10. package/dist-cjs/canvas/comments-sidebar.js +2 -2
  11. package/dist-cjs/canvas/comments-sidebar.js.map +2 -2
  12. package/dist-cjs/clustering/runtime.js +119 -7
  13. package/dist-cjs/clustering/runtime.js.map +2 -2
  14. package/dist-cjs/index.d.ts +28 -8
  15. package/dist-cjs/index.js +1 -1
  16. package/dist-cjs/ui/avatar.js +10 -2
  17. package/dist-cjs/ui/avatar.js.map +2 -2
  18. package/dist-cjs/ui/byline.js +4 -4
  19. package/dist-cjs/ui/byline.js.map +2 -2
  20. package/dist-cjs/ui/comment-card.js +3 -3
  21. package/dist-cjs/ui/comment-card.js.map +2 -2
  22. package/dist-cjs/ui/comment-composer.js +30 -24
  23. package/dist-cjs/ui/comment-composer.js.map +2 -2
  24. package/dist-cjs/ui/comment-mention.js +1 -1
  25. package/dist-cjs/ui/comment-mention.js.map +2 -2
  26. package/dist-cjs/ui/comment-pin.js +5 -1
  27. package/dist-cjs/ui/comment-pin.js.map +2 -2
  28. package/dist-cjs/ui/comment-text.js +1 -1
  29. package/dist-cjs/ui/comment-text.js.map +2 -2
  30. package/dist-cjs/ui/comment-thread.js +6 -6
  31. package/dist-cjs/ui/comment-thread.js.map +2 -2
  32. package/dist-cjs/ui/comments-list.js +11 -11
  33. package/dist-cjs/ui/comments-list.js.map +2 -2
  34. package/dist-cjs/ui/count-badge.js +1 -1
  35. package/dist-cjs/ui/count-badge.js.map +2 -2
  36. package/dist-cjs/ui/empty-state.js +3 -3
  37. package/dist-cjs/ui/empty-state.js.map +2 -2
  38. package/dist-cjs/ui/mention-list.js +7 -7
  39. package/dist-cjs/ui/mention-list.js.map +2 -2
  40. package/dist-cjs/ui/mention-suggestion.js +3 -3
  41. package/dist-cjs/ui/mention-suggestion.js.map +2 -2
  42. package/dist-cjs/ui/mention.js +1 -1
  43. package/dist-cjs/ui/mention.js.map +2 -2
  44. package/dist-cjs/ui/reaction.js +11 -4
  45. package/dist-cjs/ui/reaction.js.map +2 -2
  46. package/dist-cjs/ui/reactions.js +10 -2
  47. package/dist-cjs/ui/reactions.js.map +2 -2
  48. package/dist-cjs/ui/send-button.js +1 -1
  49. package/dist-cjs/ui/send-button.js.map +2 -2
  50. package/dist-esm/canvas/comment-body.mjs +1 -1
  51. package/dist-esm/canvas/comment-body.mjs.map +2 -2
  52. package/dist-esm/canvas/comments-filter-menu.mjs +1 -1
  53. package/dist-esm/canvas/comments-filter-menu.mjs.map +1 -1
  54. package/dist-esm/canvas/comments-overflow-menu.mjs +3 -3
  55. package/dist-esm/canvas/comments-overflow-menu.mjs.map +2 -2
  56. package/dist-esm/canvas/comments-overlay.mjs +65 -50
  57. package/dist-esm/canvas/comments-overlay.mjs.map +2 -2
  58. package/dist-esm/canvas/comments-sidebar.mjs +2 -2
  59. package/dist-esm/canvas/comments-sidebar.mjs.map +2 -2
  60. package/dist-esm/clustering/runtime.mjs +119 -7
  61. package/dist-esm/clustering/runtime.mjs.map +2 -2
  62. package/dist-esm/index.d.mts +28 -8
  63. package/dist-esm/index.mjs +1 -1
  64. package/dist-esm/ui/avatar.mjs +10 -2
  65. package/dist-esm/ui/avatar.mjs.map +2 -2
  66. package/dist-esm/ui/byline.mjs +4 -4
  67. package/dist-esm/ui/byline.mjs.map +2 -2
  68. package/dist-esm/ui/comment-card.mjs +3 -3
  69. package/dist-esm/ui/comment-card.mjs.map +2 -2
  70. package/dist-esm/ui/comment-composer.mjs +30 -24
  71. package/dist-esm/ui/comment-composer.mjs.map +2 -2
  72. package/dist-esm/ui/comment-mention.mjs +1 -1
  73. package/dist-esm/ui/comment-mention.mjs.map +2 -2
  74. package/dist-esm/ui/comment-pin.mjs +5 -1
  75. package/dist-esm/ui/comment-pin.mjs.map +2 -2
  76. package/dist-esm/ui/comment-text.mjs +1 -1
  77. package/dist-esm/ui/comment-text.mjs.map +2 -2
  78. package/dist-esm/ui/comment-thread.mjs +6 -6
  79. package/dist-esm/ui/comment-thread.mjs.map +2 -2
  80. package/dist-esm/ui/comments-list.mjs +11 -11
  81. package/dist-esm/ui/comments-list.mjs.map +2 -2
  82. package/dist-esm/ui/count-badge.mjs +1 -1
  83. package/dist-esm/ui/count-badge.mjs.map +2 -2
  84. package/dist-esm/ui/empty-state.mjs +3 -3
  85. package/dist-esm/ui/empty-state.mjs.map +2 -2
  86. package/dist-esm/ui/mention-list.mjs +7 -7
  87. package/dist-esm/ui/mention-list.mjs.map +2 -2
  88. package/dist-esm/ui/mention-suggestion.mjs +3 -3
  89. package/dist-esm/ui/mention-suggestion.mjs.map +2 -2
  90. package/dist-esm/ui/mention.mjs +1 -1
  91. package/dist-esm/ui/mention.mjs.map +2 -2
  92. package/dist-esm/ui/reaction.mjs +11 -4
  93. package/dist-esm/ui/reaction.mjs.map +2 -2
  94. package/dist-esm/ui/reactions.mjs +10 -2
  95. package/dist-esm/ui/reactions.mjs.map +2 -2
  96. package/dist-esm/ui/send-button.mjs +1 -1
  97. package/dist-esm/ui/send-button.mjs.map +2 -2
  98. package/package.json +3 -3
  99. package/src/canvas/canvas.css +25 -25
  100. package/src/canvas/comment-body.tsx +1 -1
  101. package/src/canvas/comment-render.test.ts +1 -1
  102. package/src/canvas/comments-filter-menu.tsx +1 -1
  103. package/src/canvas/comments-overflow-menu.tsx +3 -3
  104. package/src/canvas/comments-overlay.tsx +109 -76
  105. package/src/canvas/comments-sidebar.tsx +2 -2
  106. package/src/clustering/runtime.test.ts +183 -7
  107. package/src/clustering/runtime.ts +164 -15
  108. package/src/ui/avatar.tsx +9 -2
  109. package/src/ui/byline.tsx +4 -4
  110. package/src/ui/comment-card.tsx +3 -3
  111. package/src/ui/comment-composer.tsx +49 -30
  112. package/src/ui/comment-mention.ts +2 -2
  113. package/src/ui/comment-pin.tsx +5 -1
  114. package/src/ui/comment-text.tsx +1 -1
  115. package/src/ui/comment-thread.tsx +8 -6
  116. package/src/ui/comments-list.tsx +16 -12
  117. package/src/ui/comments.css +106 -106
  118. package/src/ui/count-badge.tsx +1 -1
  119. package/src/ui/empty-state.tsx +3 -3
  120. package/src/ui/mention-list.tsx +8 -8
  121. package/src/ui/mention-suggestion.tsx +3 -3
  122. package/src/ui/mention.tsx +1 -1
  123. package/src/ui/reaction.tsx +6 -3
  124. package/src/ui/reactions.tsx +6 -2
  125. package/src/ui/send-button.tsx +1 -1
@@ -26,6 +26,6 @@ var import_react = require("react");
26
26
  var import_comment_render = require("./comment-render");
27
27
  function CommentBody({ richText, resolveName }) {
28
28
  const html = (0, import_react.useMemo)(() => (0, import_comment_render.renderCommentHtml)(richText, resolveName), [richText, resolveName]);
29
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "cmt-text", dangerouslySetInnerHTML: { __html: html } });
29
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "tlui-cmt-text", dangerouslySetInnerHTML: { __html: html } });
30
30
  }
31
31
  //# sourceMappingURL=comment-body.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/canvas/comment-body.tsx"],
4
- "sourcesContent": ["import { useMemo } from 'react'\nimport { TLRichText } from 'tldraw'\nimport { renderCommentHtml } from './comment-render'\n\n/** @public */\nexport interface CommentBodyProps {\n\trichText: TLRichText\n\t/** Maps a member id to its current display name, so \\@mentions show the live name. */\n\tresolveName?(id: string): string | undefined\n}\n\n/**\n * Renders a comment's rich-text body read-only through the limited comment extension set (no\n * headings), so formatting (bold, links, lists, highlight) is preserved rather than flattened, and\n * headings can never render. Use this as the `body` of a `CommentCard` on a canvas.\n * @public @react\n */\nexport function CommentBody({ richText, resolveName }: CommentBodyProps) {\n\tconst html = useMemo(() => renderCommentHtml(richText, resolveName), [richText, resolveName])\n\treturn <div className=\"cmt-text\" dangerouslySetInnerHTML={{ __html: html }} />\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAmBQ;AAnBR,mBAAwB;AAExB,4BAAkC;AAe3B,SAAS,YAAY,EAAE,UAAU,YAAY,GAAqB;AACxE,QAAM,WAAO,sBAAQ,UAAM,yCAAkB,UAAU,WAAW,GAAG,CAAC,UAAU,WAAW,CAAC;AAC5F,SAAO,4CAAC,SAAI,WAAU,YAAW,yBAAyB,EAAE,QAAQ,KAAK,GAAG;AAC7E;",
4
+ "sourcesContent": ["import { useMemo } from 'react'\nimport { TLRichText } from 'tldraw'\nimport { renderCommentHtml } from './comment-render'\n\n/** @public */\nexport interface CommentBodyProps {\n\trichText: TLRichText\n\t/** Maps a member id to its current display name, so \\@mentions show the live name. */\n\tresolveName?(id: string): string | undefined\n}\n\n/**\n * Renders a comment's rich-text body read-only through the limited comment extension set (no\n * headings), so formatting (bold, links, lists, highlight) is preserved rather than flattened, and\n * headings can never render. Use this as the `body` of a `CommentCard` on a canvas.\n * @public @react\n */\nexport function CommentBody({ richText, resolveName }: CommentBodyProps) {\n\tconst html = useMemo(() => renderCommentHtml(richText, resolveName), [richText, resolveName])\n\treturn <div className=\"tlui-cmt-text\" dangerouslySetInnerHTML={{ __html: html }} />\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAmBQ;AAnBR,mBAAwB;AAExB,4BAAkC;AAe3B,SAAS,YAAY,EAAE,UAAU,YAAY,GAAqB;AACxE,QAAM,WAAO,sBAAQ,UAAM,yCAAkB,UAAU,WAAW,GAAG,CAAC,UAAU,WAAW,CAAC;AAC5F,SAAO,4CAAC,SAAI,WAAU,iBAAgB,yBAAyB,EAAE,QAAQ,KAAK,GAAG;AAClF;",
6
6
  "names": []
7
7
  }
@@ -39,7 +39,7 @@ function CommentsFilterMenu({
39
39
  "button",
40
40
  {
41
41
  type: "button",
42
- className: "cmt-header-btn",
42
+ className: "tlui-cmt-header-btn",
43
43
  title: msg("comments.filter"),
44
44
  "aria-label": msg("comments.filter"),
45
45
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FilterIcon, {})
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/canvas/comments-filter-menu.tsx"],
4
- "sourcesContent": ["import {\n\tTldrawUiDropdownMenuContent,\n\tTldrawUiDropdownMenuRoot,\n\tTldrawUiDropdownMenuTrigger,\n\tTldrawUiMenuCheckboxItem,\n\tTldrawUiMenuContextProvider,\n\tTldrawUiMenuGroup,\n\tuseEditor,\n\tuseTranslation,\n\tuseValue,\n} from 'tldraw'\nimport { SidebarFilters } from './sidebar-filters'\nimport { sidebarFilters } from './state'\n\n/** @public */\nexport interface CommentsFilterMenuProps {\n\t/** Whether to offer the \"only your threads\" toggle (needs a known current user). */\n\tcanFilterByAuthor?: boolean\n\t/** Whether to offer the \"only unread\" toggle (needs a read-status source). */\n\tcanFilterByUnread?: boolean\n}\n\n/** The funnel dropdown in the sidebar header: toggles for which threads the list shows.\n * @public @react */\nexport function CommentsFilterMenu({\n\tcanFilterByAuthor,\n\tcanFilterByUnread,\n}: CommentsFilterMenuProps) {\n\tconst editor = useEditor()\n\tconst msg = useTranslation()\n\tconst filters = useValue('sidebar filters', () => sidebarFilters.get(editor), [editor])\n\tconst toggle = (key: keyof SidebarFilters) => {\n\t\tsidebarFilters.update(editor, (f) => ({ ...f, [key]: !f[key] }))\n\t}\n\n\treturn (\n\t\t<TldrawUiDropdownMenuRoot id=\"comments-filter\">\n\t\t\t<TldrawUiDropdownMenuTrigger>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclassName=\"cmt-header-btn\"\n\t\t\t\t\ttitle={msg('comments.filter')}\n\t\t\t\t\taria-label={msg('comments.filter')}\n\t\t\t\t>\n\t\t\t\t\t<FilterIcon />\n\t\t\t\t</button>\n\t\t\t</TldrawUiDropdownMenuTrigger>\n\t\t\t<TldrawUiDropdownMenuContent side=\"bottom\" align=\"start\">\n\t\t\t\t<TldrawUiMenuContextProvider type=\"menu\" sourceId=\"menu\">\n\t\t\t\t\t<TldrawUiMenuGroup id=\"comments-filter\">\n\t\t\t\t\t\t<TldrawUiMenuCheckboxItem\n\t\t\t\t\t\t\tid=\"show-resolved\"\n\t\t\t\t\t\t\tlabel=\"comments.show-resolved\"\n\t\t\t\t\t\t\tchecked={filters.showResolved}\n\t\t\t\t\t\t\tonSelect={() => toggle('showResolved')}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t{canFilterByAuthor && (\n\t\t\t\t\t\t\t<TldrawUiMenuCheckboxItem\n\t\t\t\t\t\t\t\tid=\"only-mine\"\n\t\t\t\t\t\t\t\tlabel=\"comments.only-mine\"\n\t\t\t\t\t\t\t\tchecked={filters.onlyMine}\n\t\t\t\t\t\t\t\tonSelect={() => toggle('onlyMine')}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t)}\n\t\t\t\t\t\t{canFilterByUnread && (\n\t\t\t\t\t\t\t<TldrawUiMenuCheckboxItem\n\t\t\t\t\t\t\t\tid=\"only-unread\"\n\t\t\t\t\t\t\t\tlabel=\"comments.only-unread\"\n\t\t\t\t\t\t\t\tchecked={filters.onlyUnread}\n\t\t\t\t\t\t\t\tonSelect={() => toggle('onlyUnread')}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t)}\n\t\t\t\t\t\t<TldrawUiMenuCheckboxItem\n\t\t\t\t\t\t\tid=\"only-current-page\"\n\t\t\t\t\t\t\tlabel=\"comments.only-current-page\"\n\t\t\t\t\t\t\tchecked={filters.onlyCurrentPage}\n\t\t\t\t\t\t\tonSelect={() => toggle('onlyCurrentPage')}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</TldrawUiMenuGroup>\n\t\t\t\t</TldrawUiMenuContextProvider>\n\t\t\t</TldrawUiDropdownMenuContent>\n\t\t</TldrawUiDropdownMenuRoot>\n\t)\n}\n\nfunction FilterIcon() {\n\treturn (\n\t\t<svg\n\t\t\twidth=\"16\"\n\t\t\theight=\"16\"\n\t\t\tviewBox=\"0 0 16 16\"\n\t\t\tfill=\"none\"\n\t\t\tstroke=\"currentColor\"\n\t\t\tstrokeWidth=\"1.5\"\n\t\t\tstrokeLinecap=\"round\"\n\t\t\taria-hidden=\"true\"\n\t\t>\n\t\t\t<line x1=\"2.5\" y1=\"5\" x2=\"13.5\" y2=\"5\" />\n\t\t\t<line x1=\"2.5\" y1=\"11\" x2=\"13.5\" y2=\"11\" />\n\t\t\t<circle cx=\"6\" cy=\"5\" r=\"1.9\" fill=\"currentColor\" stroke=\"none\" />\n\t\t\t<circle cx=\"10.5\" cy=\"11\" r=\"1.9\" fill=\"currentColor\" stroke=\"none\" />\n\t\t</svg>\n\t)\n}\n"],
4
+ "sourcesContent": ["import {\n\tTldrawUiDropdownMenuContent,\n\tTldrawUiDropdownMenuRoot,\n\tTldrawUiDropdownMenuTrigger,\n\tTldrawUiMenuCheckboxItem,\n\tTldrawUiMenuContextProvider,\n\tTldrawUiMenuGroup,\n\tuseEditor,\n\tuseTranslation,\n\tuseValue,\n} from 'tldraw'\nimport { SidebarFilters } from './sidebar-filters'\nimport { sidebarFilters } from './state'\n\n/** @public */\nexport interface CommentsFilterMenuProps {\n\t/** Whether to offer the \"only your threads\" toggle (needs a known current user). */\n\tcanFilterByAuthor?: boolean\n\t/** Whether to offer the \"only unread\" toggle (needs a read-status source). */\n\tcanFilterByUnread?: boolean\n}\n\n/** The funnel dropdown in the sidebar header: toggles for which threads the list shows.\n * @public @react */\nexport function CommentsFilterMenu({\n\tcanFilterByAuthor,\n\tcanFilterByUnread,\n}: CommentsFilterMenuProps) {\n\tconst editor = useEditor()\n\tconst msg = useTranslation()\n\tconst filters = useValue('sidebar filters', () => sidebarFilters.get(editor), [editor])\n\tconst toggle = (key: keyof SidebarFilters) => {\n\t\tsidebarFilters.update(editor, (f) => ({ ...f, [key]: !f[key] }))\n\t}\n\n\treturn (\n\t\t<TldrawUiDropdownMenuRoot id=\"comments-filter\">\n\t\t\t<TldrawUiDropdownMenuTrigger>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclassName=\"tlui-cmt-header-btn\"\n\t\t\t\t\ttitle={msg('comments.filter')}\n\t\t\t\t\taria-label={msg('comments.filter')}\n\t\t\t\t>\n\t\t\t\t\t<FilterIcon />\n\t\t\t\t</button>\n\t\t\t</TldrawUiDropdownMenuTrigger>\n\t\t\t<TldrawUiDropdownMenuContent side=\"bottom\" align=\"start\">\n\t\t\t\t<TldrawUiMenuContextProvider type=\"menu\" sourceId=\"menu\">\n\t\t\t\t\t<TldrawUiMenuGroup id=\"comments-filter\">\n\t\t\t\t\t\t<TldrawUiMenuCheckboxItem\n\t\t\t\t\t\t\tid=\"show-resolved\"\n\t\t\t\t\t\t\tlabel=\"comments.show-resolved\"\n\t\t\t\t\t\t\tchecked={filters.showResolved}\n\t\t\t\t\t\t\tonSelect={() => toggle('showResolved')}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t{canFilterByAuthor && (\n\t\t\t\t\t\t\t<TldrawUiMenuCheckboxItem\n\t\t\t\t\t\t\t\tid=\"only-mine\"\n\t\t\t\t\t\t\t\tlabel=\"comments.only-mine\"\n\t\t\t\t\t\t\t\tchecked={filters.onlyMine}\n\t\t\t\t\t\t\t\tonSelect={() => toggle('onlyMine')}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t)}\n\t\t\t\t\t\t{canFilterByUnread && (\n\t\t\t\t\t\t\t<TldrawUiMenuCheckboxItem\n\t\t\t\t\t\t\t\tid=\"only-unread\"\n\t\t\t\t\t\t\t\tlabel=\"comments.only-unread\"\n\t\t\t\t\t\t\t\tchecked={filters.onlyUnread}\n\t\t\t\t\t\t\t\tonSelect={() => toggle('onlyUnread')}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t)}\n\t\t\t\t\t\t<TldrawUiMenuCheckboxItem\n\t\t\t\t\t\t\tid=\"only-current-page\"\n\t\t\t\t\t\t\tlabel=\"comments.only-current-page\"\n\t\t\t\t\t\t\tchecked={filters.onlyCurrentPage}\n\t\t\t\t\t\t\tonSelect={() => toggle('onlyCurrentPage')}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</TldrawUiMenuGroup>\n\t\t\t\t</TldrawUiMenuContextProvider>\n\t\t\t</TldrawUiDropdownMenuContent>\n\t\t</TldrawUiDropdownMenuRoot>\n\t)\n}\n\nfunction FilterIcon() {\n\treturn (\n\t\t<svg\n\t\t\twidth=\"16\"\n\t\t\theight=\"16\"\n\t\t\tviewBox=\"0 0 16 16\"\n\t\t\tfill=\"none\"\n\t\t\tstroke=\"currentColor\"\n\t\t\tstrokeWidth=\"1.5\"\n\t\t\tstrokeLinecap=\"round\"\n\t\t\taria-hidden=\"true\"\n\t\t>\n\t\t\t<line x1=\"2.5\" y1=\"5\" x2=\"13.5\" y2=\"5\" />\n\t\t\t<line x1=\"2.5\" y1=\"11\" x2=\"13.5\" y2=\"11\" />\n\t\t\t<circle cx=\"6\" cy=\"5\" r=\"1.9\" fill=\"currentColor\" stroke=\"none\" />\n\t\t\t<circle cx=\"10.5\" cy=\"11\" r=\"1.9\" fill=\"currentColor\" stroke=\"none\" />\n\t\t</svg>\n\t)\n}\n"],
5
5
  "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA4CK;AA5CL,oBAUO;AAEP,mBAA+B;AAYxB,SAAS,mBAAmB;AAAA,EAClC;AAAA,EACA;AACD,GAA4B;AAC3B,QAAM,aAAS,yBAAU;AACzB,QAAM,UAAM,8BAAe;AAC3B,QAAM,cAAU,wBAAS,mBAAmB,MAAM,4BAAe,IAAI,MAAM,GAAG,CAAC,MAAM,CAAC;AACtF,QAAM,SAAS,CAAC,QAA8B;AAC7C,gCAAe,OAAO,QAAQ,CAAC,OAAO,EAAE,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,EAAE,GAAG,EAAE,EAAE;AAAA,EAChE;AAEA,SACC,6CAAC,0CAAyB,IAAG,mBAC5B;AAAA,gDAAC,6CACA;AAAA,MAAC;AAAA;AAAA,QACA,MAAK;AAAA,QACL,WAAU;AAAA,QACV,OAAO,IAAI,iBAAiB;AAAA,QAC5B,cAAY,IAAI,iBAAiB;AAAA,QAEjC,sDAAC,cAAW;AAAA;AAAA,IACb,GACD;AAAA,IACA,4CAAC,6CAA4B,MAAK,UAAS,OAAM,SAChD,sDAAC,6CAA4B,MAAK,QAAO,UAAS,QACjD,uDAAC,mCAAkB,IAAG,mBACrB;AAAA;AAAA,QAAC;AAAA;AAAA,UACA,IAAG;AAAA,UACH,OAAM;AAAA,UACN,SAAS,QAAQ;AAAA,UACjB,UAAU,MAAM,OAAO,cAAc;AAAA;AAAA,MACtC;AAAA,MACC,qBACA;AAAA,QAAC;AAAA;AAAA,UACA,IAAG;AAAA,UACH,OAAM;AAAA,UACN,SAAS,QAAQ;AAAA,UACjB,UAAU,MAAM,OAAO,UAAU;AAAA;AAAA,MAClC;AAAA,MAEA,qBACA;AAAA,QAAC;AAAA;AAAA,UACA,IAAG;AAAA,UACH,OAAM;AAAA,UACN,SAAS,QAAQ;AAAA,UACjB,UAAU,MAAM,OAAO,YAAY;AAAA;AAAA,MACpC;AAAA,MAED;AAAA,QAAC;AAAA;AAAA,UACA,IAAG;AAAA,UACH,OAAM;AAAA,UACN,SAAS,QAAQ;AAAA,UACjB,UAAU,MAAM,OAAO,iBAAiB;AAAA;AAAA,MACzC;AAAA,OACD,GACD,GACD;AAAA,KACD;AAEF;AAEA,SAAS,aAAa;AACrB,SACC;AAAA,IAAC;AAAA;AAAA,MACA,OAAM;AAAA,MACN,QAAO;AAAA,MACP,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,QAAO;AAAA,MACP,aAAY;AAAA,MACZ,eAAc;AAAA,MACd,eAAY;AAAA,MAEZ;AAAA,oDAAC,UAAK,IAAG,OAAM,IAAG,KAAI,IAAG,QAAO,IAAG,KAAI;AAAA,QACvC,4CAAC,UAAK,IAAG,OAAM,IAAG,MAAK,IAAG,QAAO,IAAG,MAAK;AAAA,QACzC,4CAAC,YAAO,IAAG,KAAI,IAAG,KAAI,GAAE,OAAM,MAAK,gBAAe,QAAO,QAAO;AAAA,QAChE,4CAAC,YAAO,IAAG,QAAO,IAAG,MAAK,GAAE,OAAM,MAAK,gBAAe,QAAO,QAAO;AAAA;AAAA;AAAA,EACrE;AAEF;",
6
6
  "names": []
7
7
  }
@@ -34,7 +34,7 @@ function CommentsOverflowMenu() {
34
34
  "button",
35
35
  {
36
36
  type: "button",
37
- className: "cmt-header-btn",
37
+ className: "tlui-cmt-header-btn",
38
38
  title: msg("comments.more-options"),
39
39
  "aria-label": msg("comments.more-options"),
40
40
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MoreIcon, {})
@@ -44,11 +44,11 @@ function CommentsOverflowMenu() {
44
44
  "button",
45
45
  {
46
46
  type: "button",
47
- className: "cmt-menu-item",
47
+ className: "tlui-cmt-menu-item",
48
48
  onClick: () => (0, import_state.toggleCommentsHidden)(editor),
49
49
  children: [
50
50
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: hidden ? msg("comments.show") : msg("comments.hide") }),
51
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "cmt-menu-item__shortcut", children: HIDE_SHORTCUT })
51
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "tlui-cmt-menu-item__shortcut", children: HIDE_SHORTCUT })
52
52
  ]
53
53
  }
54
54
  ) }) }) })
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/canvas/comments-overflow-menu.tsx"],
4
- "sourcesContent": ["import {\n\tTldrawUiDropdownMenuContent,\n\tTldrawUiDropdownMenuGroup,\n\tTldrawUiDropdownMenuItem,\n\tTldrawUiDropdownMenuRoot,\n\tTldrawUiDropdownMenuTrigger,\n\tuseEditor,\n\tuseTranslation,\n\tuseValue,\n} from 'tldraw'\nimport { commentsHidden, toggleCommentsHidden } from './state'\n\n// A keyboard-shortcut glyph, not translatable copy \u2014 kept out of JSX as a constant.\nconst HIDE_SHORTCUT = '\u21E7C'\n\n/** The overflow (\u22EF) dropdown in the sidebar header. For now it holds the hide/show-comments\n * toggle; it's the home for later comment-wide controls (notifications, mark all as read).\n * @public @react */\nexport function CommentsOverflowMenu() {\n\tconst editor = useEditor()\n\tconst msg = useTranslation()\n\tconst hidden = useValue('comments hidden', () => commentsHidden.get(editor), [editor])\n\n\treturn (\n\t\t<TldrawUiDropdownMenuRoot id=\"comments-overflow\">\n\t\t\t<TldrawUiDropdownMenuTrigger>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclassName=\"cmt-header-btn\"\n\t\t\t\t\ttitle={msg('comments.more-options')}\n\t\t\t\t\taria-label={msg('comments.more-options')}\n\t\t\t\t>\n\t\t\t\t\t<MoreIcon />\n\t\t\t\t</button>\n\t\t\t</TldrawUiDropdownMenuTrigger>\n\t\t\t<TldrawUiDropdownMenuContent side=\"bottom\" align=\"end\">\n\t\t\t\t<TldrawUiDropdownMenuGroup>\n\t\t\t\t\t<TldrawUiDropdownMenuItem>\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tclassName=\"cmt-menu-item\"\n\t\t\t\t\t\t\tonClick={() => toggleCommentsHidden(editor)}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<span>{hidden ? msg('comments.show') : msg('comments.hide')}</span>\n\t\t\t\t\t\t\t<span className=\"cmt-menu-item__shortcut\">{HIDE_SHORTCUT}</span>\n\t\t\t\t\t\t</button>\n\t\t\t\t\t</TldrawUiDropdownMenuItem>\n\t\t\t\t</TldrawUiDropdownMenuGroup>\n\t\t\t</TldrawUiDropdownMenuContent>\n\t\t</TldrawUiDropdownMenuRoot>\n\t)\n}\n\nfunction MoreIcon() {\n\treturn (\n\t\t<svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"currentColor\" aria-hidden=\"true\">\n\t\t\t<circle cx=\"3\" cy=\"8\" r=\"1.4\" />\n\t\t\t<circle cx=\"8\" cy=\"8\" r=\"1.4\" />\n\t\t\t<circle cx=\"13\" cy=\"8\" r=\"1.4\" />\n\t\t</svg>\n\t)\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAgCK;AAhCL,oBASO;AACP,mBAAqD;AAGrD,MAAM,gBAAgB;AAKf,SAAS,uBAAuB;AACtC,QAAM,aAAS,yBAAU;AACzB,QAAM,UAAM,8BAAe;AAC3B,QAAM,aAAS,wBAAS,mBAAmB,MAAM,4BAAe,IAAI,MAAM,GAAG,CAAC,MAAM,CAAC;AAErF,SACC,6CAAC,0CAAyB,IAAG,qBAC5B;AAAA,gDAAC,6CACA;AAAA,MAAC;AAAA;AAAA,QACA,MAAK;AAAA,QACL,WAAU;AAAA,QACV,OAAO,IAAI,uBAAuB;AAAA,QAClC,cAAY,IAAI,uBAAuB;AAAA,QAEvC,sDAAC,YAAS;AAAA;AAAA,IACX,GACD;AAAA,IACA,4CAAC,6CAA4B,MAAK,UAAS,OAAM,OAChD,sDAAC,2CACA,sDAAC,0CACA;AAAA,MAAC;AAAA;AAAA,QACA,MAAK;AAAA,QACL,WAAU;AAAA,QACV,SAAS,UAAM,mCAAqB,MAAM;AAAA,QAE1C;AAAA,sDAAC,UAAM,mBAAS,IAAI,eAAe,IAAI,IAAI,eAAe,GAAE;AAAA,UAC5D,4CAAC,UAAK,WAAU,2BAA2B,yBAAc;AAAA;AAAA;AAAA,IAC1D,GACD,GACD,GACD;AAAA,KACD;AAEF;AAEA,SAAS,WAAW;AACnB,SACC,6CAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,gBAAe,eAAY,QAC/E;AAAA,gDAAC,YAAO,IAAG,KAAI,IAAG,KAAI,GAAE,OAAM;AAAA,IAC9B,4CAAC,YAAO,IAAG,KAAI,IAAG,KAAI,GAAE,OAAM;AAAA,IAC9B,4CAAC,YAAO,IAAG,MAAK,IAAG,KAAI,GAAE,OAAM;AAAA,KAChC;AAEF;",
4
+ "sourcesContent": ["import {\n\tTldrawUiDropdownMenuContent,\n\tTldrawUiDropdownMenuGroup,\n\tTldrawUiDropdownMenuItem,\n\tTldrawUiDropdownMenuRoot,\n\tTldrawUiDropdownMenuTrigger,\n\tuseEditor,\n\tuseTranslation,\n\tuseValue,\n} from 'tldraw'\nimport { commentsHidden, toggleCommentsHidden } from './state'\n\n// A keyboard-shortcut glyph, not translatable copy \u2014 kept out of JSX as a constant.\nconst HIDE_SHORTCUT = '\u21E7C'\n\n/** The overflow (\u22EF) dropdown in the sidebar header. For now it holds the hide/show-comments\n * toggle; it's the home for later comment-wide controls (notifications, mark all as read).\n * @public @react */\nexport function CommentsOverflowMenu() {\n\tconst editor = useEditor()\n\tconst msg = useTranslation()\n\tconst hidden = useValue('comments hidden', () => commentsHidden.get(editor), [editor])\n\n\treturn (\n\t\t<TldrawUiDropdownMenuRoot id=\"comments-overflow\">\n\t\t\t<TldrawUiDropdownMenuTrigger>\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclassName=\"tlui-cmt-header-btn\"\n\t\t\t\t\ttitle={msg('comments.more-options')}\n\t\t\t\t\taria-label={msg('comments.more-options')}\n\t\t\t\t>\n\t\t\t\t\t<MoreIcon />\n\t\t\t\t</button>\n\t\t\t</TldrawUiDropdownMenuTrigger>\n\t\t\t<TldrawUiDropdownMenuContent side=\"bottom\" align=\"end\">\n\t\t\t\t<TldrawUiDropdownMenuGroup>\n\t\t\t\t\t<TldrawUiDropdownMenuItem>\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tclassName=\"tlui-cmt-menu-item\"\n\t\t\t\t\t\t\tonClick={() => toggleCommentsHidden(editor)}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<span>{hidden ? msg('comments.show') : msg('comments.hide')}</span>\n\t\t\t\t\t\t\t<span className=\"tlui-cmt-menu-item__shortcut\">{HIDE_SHORTCUT}</span>\n\t\t\t\t\t\t</button>\n\t\t\t\t\t</TldrawUiDropdownMenuItem>\n\t\t\t\t</TldrawUiDropdownMenuGroup>\n\t\t\t</TldrawUiDropdownMenuContent>\n\t\t</TldrawUiDropdownMenuRoot>\n\t)\n}\n\nfunction MoreIcon() {\n\treturn (\n\t\t<svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"currentColor\" aria-hidden=\"true\">\n\t\t\t<circle cx=\"3\" cy=\"8\" r=\"1.4\" />\n\t\t\t<circle cx=\"8\" cy=\"8\" r=\"1.4\" />\n\t\t\t<circle cx=\"13\" cy=\"8\" r=\"1.4\" />\n\t\t</svg>\n\t)\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAgCK;AAhCL,oBASO;AACP,mBAAqD;AAGrD,MAAM,gBAAgB;AAKf,SAAS,uBAAuB;AACtC,QAAM,aAAS,yBAAU;AACzB,QAAM,UAAM,8BAAe;AAC3B,QAAM,aAAS,wBAAS,mBAAmB,MAAM,4BAAe,IAAI,MAAM,GAAG,CAAC,MAAM,CAAC;AAErF,SACC,6CAAC,0CAAyB,IAAG,qBAC5B;AAAA,gDAAC,6CACA;AAAA,MAAC;AAAA;AAAA,QACA,MAAK;AAAA,QACL,WAAU;AAAA,QACV,OAAO,IAAI,uBAAuB;AAAA,QAClC,cAAY,IAAI,uBAAuB;AAAA,QAEvC,sDAAC,YAAS;AAAA;AAAA,IACX,GACD;AAAA,IACA,4CAAC,6CAA4B,MAAK,UAAS,OAAM,OAChD,sDAAC,2CACA,sDAAC,0CACA;AAAA,MAAC;AAAA;AAAA,QACA,MAAK;AAAA,QACL,WAAU;AAAA,QACV,SAAS,UAAM,mCAAqB,MAAM;AAAA,QAE1C;AAAA,sDAAC,UAAM,mBAAS,IAAI,eAAe,IAAI,IAAI,eAAe,GAAE;AAAA,UAC5D,4CAAC,UAAK,WAAU,gCAAgC,yBAAc;AAAA;AAAA;AAAA,IAC/D,GACD,GACD,GACD;AAAA,KACD;AAEF;AAEA,SAAS,WAAW;AACnB,SACC,6CAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,gBAAe,eAAY,QAC/E;AAAA,gDAAC,YAAO,IAAG,KAAI,IAAG,KAAI,GAAE,OAAM;AAAA,IAC9B,4CAAC,YAAO,IAAG,KAAI,IAAG,KAAI,GAAE,OAAM;AAAA,IAC9B,4CAAC,YAAO,IAAG,MAAK,IAAG,KAAI,GAAE,OAAM;AAAA,KAChC;AAEF;",
6
6
  "names": []
7
7
  }
@@ -99,17 +99,17 @@ function CanvasCommentsLayer(props) {
99
99
  const pending = (0, import_state.usePendingComment)();
100
100
  const openId = (0, import_tldraw.useValue)("open thread id", () => import_state.openThreadId.get(editor), [editor]);
101
101
  const impreciseShapeAnchor = props.impreciseShapeAnchor ?? options.impreciseShapeAnchor;
102
- const [movedThreadIds, setMovedThreadIds] = (0, import_react.useState)(EMPTY_SET);
102
+ const [heldThreadIds, setHeldThreadIds] = (0, import_react.useState)(EMPTY_SET);
103
103
  const adoptOnRebuild = (0, import_react.useRef)(false);
104
104
  const clusterLeaves = (0, import_tldraw.useValue)(
105
105
  "comment cluster leaves",
106
106
  () => (0, import_cluster_input.collectClusterLeaves)(
107
107
  editor,
108
- threads.filter((thread) => !movedThreadIds.has(thread.id)),
108
+ threads.filter((thread) => !heldThreadIds.has(thread.id)),
109
109
  import_state.openThreadId.get(editor),
110
110
  impreciseShapeAnchor
111
111
  ),
112
- [editor, threads, impreciseShapeAnchor, movedThreadIds]
112
+ [editor, threads, impreciseShapeAnchor, heldThreadIds]
113
113
  );
114
114
  const clusterZoomBounds = (0, import_tldraw.useValue)(
115
115
  "comment cluster zoom bounds",
@@ -124,21 +124,41 @@ function CanvasCommentsLayer(props) {
124
124
  }, [clusterLeaves, clusterZoomBounds, editor]);
125
125
  const [renderedModel, setRenderedModel] = (0, import_react.useState)(latestModel);
126
126
  let clusterModel = renderedModel;
127
- if (renderedModel !== latestModel && (adoptOnRebuild.current || hasRemovedLeaves(renderedModel.table, latestModel.table))) {
127
+ const pageId = (0, import_tldraw.useValue)("comment cluster page", () => editor.getCurrentPageId(), [editor]);
128
+ const pageRef = (0, import_react.useRef)(pageId);
129
+ if (pageRef.current !== pageId) {
130
+ pageRef.current = pageId;
131
+ adoptOnRebuild.current = false;
132
+ latestModel.runtime.seed(editor.getZoomLevel());
133
+ if (heldThreadIds.size > 0) setHeldThreadIds(EMPTY_SET);
134
+ setRenderedModel(latestModel);
135
+ clusterModel = latestModel;
136
+ }
137
+ const rejoinPending = heldThreadIds.size === 0 && adoptOnRebuild.current;
138
+ if (renderedModel !== latestModel && rejoinPending) {
128
139
  adoptOnRebuild.current = false;
129
140
  latestModel.runtime.seedFrom(editor.getZoomLevel(), renderedModel.runtime.getVisible());
130
141
  setRenderedModel(latestModel);
131
142
  clusterModel = latestModel;
143
+ } else if (heldThreadIds.size === 0 && renderedModel === latestModel) {
144
+ adoptOnRebuild.current = false;
132
145
  }
133
146
  const newlyMovedIds = findMovedClusteredLeafIds(clusterModel, latestModel);
134
147
  if (newlyMovedIds.length > 0) {
135
- console.debug(`[comments] pins popped out of clustering: ${newlyMovedIds.join(", ")}`);
136
- const next = new Set(movedThreadIds);
148
+ const next = new Set(heldThreadIds);
137
149
  for (const id of newlyMovedIds) next.add(id);
138
- setMovedThreadIds(next);
150
+ setHeldThreadIds(next);
151
+ }
152
+ {
153
+ const latestLeafIds = new Set(latestModel.table.leaves.map((leaf) => leaf.id));
154
+ for (const leaf of clusterModel.table.leaves) {
155
+ if (!latestLeafIds.has(leaf.id)) {
156
+ clusterModel.runtime.detachLeaf(leaf.id);
157
+ }
158
+ }
139
159
  }
140
160
  (0, import_react.useEffect)(() => {
141
- if (movedThreadIds.size === 0) return;
161
+ if (heldThreadIds.size === 0) return;
142
162
  let lastZoom = editor.getZoomLevel();
143
163
  return (0, import_tldraw.react)("rejoin moved comment pins on zoom out", () => {
144
164
  const zoom = editor.getZoomLevel();
@@ -146,9 +166,9 @@ function CanvasCommentsLayer(props) {
146
166
  lastZoom = zoom;
147
167
  if (zoom >= prevZoom) return;
148
168
  adoptOnRebuild.current = true;
149
- setMovedThreadIds(EMPTY_SET);
169
+ setHeldThreadIds(EMPTY_SET);
150
170
  });
151
- }, [movedThreadIds, editor]);
171
+ }, [heldThreadIds, editor]);
152
172
  (0, import_react.useEffect)(() => {
153
173
  if (clusterModel === latestModel) return;
154
174
  let lastZoom = editor.getZoomLevel();
@@ -161,31 +181,31 @@ function CanvasCommentsLayer(props) {
161
181
  setRenderedModel(latestModel);
162
182
  });
163
183
  }, [clusterModel, latestModel, editor]);
184
+ const partitionVersion = clusterModel.runtime.version;
164
185
  const orphanThreads = (0, import_react.useMemo)(() => {
165
186
  if (clusterModel === latestModel) return [];
166
- const renderedIds = new Set(clusterModel.table.leaves.map((leaf) => leaf.id));
187
+ const displayed = /* @__PURE__ */ new Set();
188
+ for (const node of clusterModel.runtime.getVisible().values()) {
189
+ for (const member of node.members) displayed.add(member);
190
+ }
167
191
  const latestIds = new Set(latestModel.table.leaves.map((leaf) => leaf.id));
168
- return threads.filter((thread) => latestIds.has(thread.id) && !renderedIds.has(thread.id));
169
- }, [clusterModel, latestModel, threads]);
170
- const movedThreads = (0, import_react.useMemo)(
171
- () => threads.filter((thread) => movedThreadIds.has(thread.id) && thread.id !== openId),
172
- [threads, movedThreadIds, openId]
192
+ return threads.filter((thread) => latestIds.has(thread.id) && !displayed.has(thread.id));
193
+ }, [clusterModel, latestModel, threads, partitionVersion]);
194
+ const heldThreads = (0, import_react.useMemo)(
195
+ () => threads.filter((thread) => heldThreadIds.has(thread.id) && thread.id !== openId),
196
+ [threads, heldThreadIds, openId]
173
197
  );
174
- const clusterCursor = (0, import_tldraw.useValue)(
175
- "comment cluster cursor",
198
+ (0, import_tldraw.useValue)(
199
+ "comment cluster version",
176
200
  () => {
177
201
  clusterModel.runtime.onCamera(editor.getZoomLevel());
178
- return clusterModel.runtime.k;
202
+ return clusterModel.runtime.version;
179
203
  },
180
204
  [clusterModel, editor]
181
205
  );
182
206
  const visibleNodes = (0, import_react.useMemo)(() => {
183
- const nodes = Array.from(clusterModel.runtime.getVisible().values());
184
- console.debug(
185
- `[comments] cluster cursor k=${clusterCursor} \u2192 re-rendering ${nodes.length} visible nodes`
186
- );
187
- return nodes;
188
- }, [clusterModel, clusterCursor]);
207
+ return Array.from(clusterModel.runtime.getVisible().values());
208
+ }, [clusterModel, partitionVersion]);
189
209
  const fadeNodes = useFadeVisibleNodes(visibleNodes, clusterModel);
190
210
  const threadsById = (0, import_react.useMemo)(
191
211
  () => new Map(threads.map((thread) => [thread.id, thread])),
@@ -244,7 +264,7 @@ function CanvasCommentsLayer(props) {
244
264
  if (e.key !== "Escape" || import_state.openThreadId.get(editor) === null) return;
245
265
  if ((0, import_mention_suggestion.isMentionPickerOpen)()) return;
246
266
  const target = e.target;
247
- if (target && target.closest(".cmt-editing")) return;
267
+ if (target && target.closest(".tlui-cmt-editing")) return;
248
268
  import_state.openThreadId.set(editor, null);
249
269
  e.preventDefault();
250
270
  e.stopPropagation();
@@ -265,7 +285,7 @@ function CanvasCommentsLayer(props) {
265
285
  }, [editor]);
266
286
  if (hidden) return null;
267
287
  return (0, import_react_dom.createPortal)(
268
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { ref: layerRef, className: "cmt-canvas-layer", children: [
288
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { ref: layerRef, className: "tlui-cmt-canvas-layer", children: [
269
289
  options.enableClustering ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
270
290
  fadeNodes.map(({ node, phase }) => {
271
291
  let content;
@@ -296,7 +316,7 @@ function CanvasCommentsLayer(props) {
296
316
  },
297
317
  thread.id
298
318
  )),
299
- movedThreads.map((thread) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
319
+ heldThreads.map((thread) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
300
320
  ThreadPin,
301
321
  {
302
322
  editor,
@@ -405,7 +425,7 @@ function cancelClusterFadeFrame(frame) {
405
425
  else window.clearTimeout(frame);
406
426
  }
407
427
  function clusterFadeClassName(phase) {
408
- return `cmt-cluster-fade cmt-cluster-fade--${phase}`;
428
+ return `tlui-cmt-cluster-fade tlui-cmt-cluster-fade--${phase}`;
409
429
  }
410
430
  function findMovedClusteredLeafIds(rendered, latest) {
411
431
  if (rendered.table === latest.table) return [];
@@ -422,11 +442,6 @@ function findMovedClusteredLeafIds(rendered, latest) {
422
442
  }
423
443
  return moved;
424
444
  }
425
- function hasRemovedLeaves(rendered, latest) {
426
- if (rendered.leaves.length === 0) return false;
427
- const latestIds = new Set(latest.leaves.map((leaf) => leaf.id));
428
- return rendered.leaves.some((leaf) => !latestIds.has(leaf.id));
429
- }
430
445
  function getClusterZoomBounds(editor) {
431
446
  const cameraOptions = editor.getCameraOptions();
432
447
  const baseZoom = cameraOptions.constraints ? editor.getBaseZoom() : 1;
@@ -491,7 +506,7 @@ const ClusterBadge = (0, import_react.memo)(function ClusterBadge2({
491
506
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
492
507
  "div",
493
508
  {
494
- className: "cmt-canvas-cluster",
509
+ className: "tlui-cmt-canvas-cluster",
495
510
  style: { left: point.x, top: point.y },
496
511
  onPointerDown: stop,
497
512
  onClick: (e) => {
@@ -516,7 +531,7 @@ function ThreadPopover({
516
531
  (0, import_tldraw.usePassThroughWheelEvents)(ref);
517
532
  (0, import_tldraw.usePassThroughMouseOverEvents)(ref);
518
533
  return (0, import_react_dom.createPortal)(
519
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ref, className: "cmt-canvas-popover", style, onPointerDown: stop, children }),
534
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ref, className: "tlui-cmt-canvas-popover", style, onPointerDown: stop, children }),
520
535
  container
521
536
  );
522
537
  }
@@ -561,7 +576,7 @@ function RegionBox({
561
576
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
562
577
  "div",
563
578
  {
564
- className: movable ? "cmt-canvas-region cmt-canvas-region--movable" : "cmt-canvas-region",
579
+ className: movable ? "tlui-cmt-canvas-region tlui-cmt-canvas-region--movable" : "tlui-cmt-canvas-region",
565
580
  style: rect,
566
581
  onPointerDown: movable ? startMove : void 0,
567
582
  onPointerMove: movable ? onMove : void 0,
@@ -635,7 +650,7 @@ function RegionResizeHandles({
635
650
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: points.map((h) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
636
651
  "div",
637
652
  {
638
- className: "cmt-canvas-region-handle",
653
+ className: "tlui-cmt-canvas-region-handle",
639
654
  style: { left: h.left, top: h.top, cursor: h.cursor },
640
655
  onPointerDown: startResize,
641
656
  onPointerMove: onResize(h),
@@ -700,11 +715,11 @@ const ThreadPin = (0, import_react.memo)(function ThreadPin2({
700
715
  const onPointerDown = (e) => {
701
716
  const target = e.target;
702
717
  if (!target) return;
703
- if (target.closest(".cmt-canvas-popover")) return;
718
+ if (target.closest(".tlui-cmt-canvas-popover")) return;
704
719
  const marker = markerRef.current;
705
720
  if (marker && marker.contains(target)) return;
706
- if (target.closest(".cmt-canvas-region-handle, .cmt-canvas-region--movable")) return;
707
- if (target.closest(".tlui-menu, [data-radix-popper-content-wrapper], .cmt-mention-popup"))
721
+ if (target.closest(".tlui-cmt-canvas-region-handle, .tlui-cmt-canvas-region--movable")) return;
722
+ if (target.closest(".tlui-menu, [data-radix-popper-content-wrapper], .tlui-cmt-mention-popup"))
708
723
  return;
709
724
  import_state.openThreadId.set(editor, null);
710
725
  };
@@ -780,7 +795,7 @@ const ThreadPin = (0, import_react.memo)(function ThreadPin2({
780
795
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
781
796
  "div",
782
797
  {
783
- className: "cmt-editing",
798
+ className: "tlui-cmt-editing",
784
799
  onKeyDown: (e) => {
785
800
  if (e.key === "Escape") {
786
801
  setEditingId(null);
@@ -812,7 +827,7 @@ const ThreadPin = (0, import_react.memo)(function ThreadPin2({
812
827
  actions: comment.authorId === currentUserId ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
813
828
  "button",
814
829
  {
815
- className: "cmt-thread__action",
830
+ className: "tlui-cmt-thread__action",
816
831
  title: msg("comments.edit"),
817
832
  onClick: () => startEdit(comment),
818
833
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_tldraw.TldrawUiIcon, { icon: "dots-horizontal", label: msg("comments.edit"), small: true })
@@ -825,7 +840,7 @@ const ThreadPin = (0, import_react.memo)(function ThreadPin2({
825
840
  currentUserId && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
826
841
  "button",
827
842
  {
828
- className: "cmt-thread__action",
843
+ className: "tlui-cmt-thread__action",
829
844
  title: msg(thread.resolved ? "comments.reopen" : "comments.resolve"),
830
845
  onClick: toggleResolve,
831
846
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
@@ -841,7 +856,7 @@ const ThreadPin = (0, import_react.memo)(function ThreadPin2({
841
856
  currentUserId && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
842
857
  "button",
843
858
  {
844
- className: "cmt-thread__action",
859
+ className: "tlui-cmt-thread__action",
845
860
  title: msg("comments.delete"),
846
861
  onClick: deleteThread,
847
862
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_tldraw.TldrawUiIcon, { icon: "trash", label: msg("comments.delete"), small: true })
@@ -850,7 +865,7 @@ const ThreadPin = (0, import_react.memo)(function ThreadPin2({
850
865
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
851
866
  "button",
852
867
  {
853
- className: "cmt-thread__action",
868
+ className: "tlui-cmt-thread__action",
854
869
  title: msg("comments.dismiss"),
855
870
  onClick: () => import_state.openThreadId.set(editor, null),
856
871
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_tldraw.TldrawUiIcon, { icon: "cross-2", label: msg("comments.dismiss"), small: true })
@@ -943,14 +958,14 @@ const ThreadPin = (0, import_react.memo)(function ThreadPin2({
943
958
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
944
959
  "div",
945
960
  {
946
- className: open ? "cmt-canvas-pin cmt-canvas-pin--open" : "cmt-canvas-pin",
961
+ className: open ? "tlui-cmt-canvas-pin tlui-cmt-canvas-pin--open" : "tlui-cmt-canvas-pin",
947
962
  style: { left: renderPoint.x, top: renderPoint.y },
948
963
  children: [
949
964
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
950
965
  "div",
951
966
  {
952
967
  ref: markerRef,
953
- className: "cmt-canvas-pin__marker",
968
+ className: "tlui-cmt-canvas-pin__marker",
954
969
  onPointerDown: startDrag,
955
970
  onPointerMove: onDrag,
956
971
  onPointerUp: endDrag,
@@ -1019,7 +1034,7 @@ function PendingComposer({
1019
1034
  const el = ref.current;
1020
1035
  const target = e.target;
1021
1036
  if (!el || !target) return;
1022
- if (el.contains(target) || target.closest(".cmt-mention-popup")) return;
1037
+ if (el.contains(target) || target.closest(".tlui-cmt-mention-popup")) return;
1023
1038
  import_state.pendingComment.set(editor, null);
1024
1039
  };
1025
1040
  document.addEventListener("pointerdown", onPointerDown, true);
@@ -1051,7 +1066,7 @@ function PendingComposer({
1051
1066
  "div",
1052
1067
  {
1053
1068
  ref,
1054
- className: "cmt-canvas-composer",
1069
+ className: "tlui-cmt-canvas-composer",
1055
1070
  style: { left: point.x, top: point.y },
1056
1071
  onPointerDown: stop,
1057
1072
  onKeyDown: (e) => {