@docyrus/ui-pro-ai-assistant 0.0.2 → 0.0.3

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 (307) hide show
  1. package/package.json +2 -3
  2. package/src/components/assistant-animations.tsx +0 -29
  3. package/src/components/assistant-dialogs.tsx +0 -235
  4. package/src/components/code-view.tsx +0 -278
  5. package/src/components/create-agent-task.tsx +0 -104
  6. package/src/components/create-new-work-version.tsx +0 -30
  7. package/src/components/extract-web.tsx +0 -160
  8. package/src/components/forward-to-agent.tsx +0 -90
  9. package/src/components/generate-chart.tsx +0 -101
  10. package/src/components/generative-action-button.tsx +0 -122
  11. package/src/components/generative-tool.tsx +0 -685
  12. package/src/components/generative-ui-object.tsx +0 -210
  13. package/src/components/input-area.tsx +0 -1209
  14. package/src/components/json-schema-layout.tsx +0 -326
  15. package/src/components/list-item-card.tsx +0 -92
  16. package/src/components/mermaid-diagram.tsx +0 -192
  17. package/src/components/preview-image.tsx +0 -47
  18. package/src/components/request-approval.tsx +0 -48
  19. package/src/components/request-user-input.tsx +0 -270
  20. package/src/components/search-web.tsx +0 -319
  21. package/src/components/sheet-command.tsx +0 -88
  22. package/src/components/shell-canvas.tsx +0 -122
  23. package/src/components/show-advanced-data-table.tsx +0 -352
  24. package/src/components/show-generated-content-options.tsx +0 -93
  25. package/src/components/show-people-cards.tsx +0 -180
  26. package/src/components/subagent-tool.tsx +0 -180
  27. package/src/components/text-editor-tool.tsx +0 -328
  28. package/src/components/work-canvas.tsx +0 -88
  29. package/src/components/work-card.tsx +0 -42
  30. package/src/declarations.d.ts +0 -1
  31. package/src/docy-assistant.tsx +0 -1962
  32. package/src/hooks/index.ts +0 -7
  33. package/src/hooks/use-assistant-api.ts +0 -507
  34. package/src/hooks/use-deployment-data.ts +0 -162
  35. package/src/hooks/use-project-state.ts +0 -347
  36. package/src/hooks/use-session-state.ts +0 -207
  37. package/src/hooks/use-speech-recognition.ts +0 -137
  38. package/src/hooks/use-ui-state.ts +0 -185
  39. package/src/hooks/use-works-state.ts +0 -146
  40. package/src/i18n/context.tsx +0 -253
  41. package/src/i18n/index.ts +0 -19
  42. package/src/i18n/locales/de.json +0 -198
  43. package/src/i18n/locales/el.json +0 -198
  44. package/src/i18n/locales/en.json +0 -226
  45. package/src/i18n/locales/es.json +0 -198
  46. package/src/i18n/locales/fr.json +0 -198
  47. package/src/i18n/locales/it.json +0 -198
  48. package/src/i18n/locales/pt.json +0 -198
  49. package/src/i18n/locales/sl.json +0 -198
  50. package/src/i18n/locales/tr.json +0 -211
  51. package/src/i18n/types.ts +0 -23
  52. package/src/i18n/use-translation.ts +0 -17
  53. package/src/index.ts +0 -18
  54. package/src/internal/plate-editor/editor/auth-context.ts +0 -11
  55. package/src/internal/plate-editor/editor/editor-base-kit.tsx +0 -39
  56. package/src/internal/plate-editor/editor/editor-kit.tsx +0 -89
  57. package/src/internal/plate-editor/editor/plate-editor.tsx +0 -75
  58. package/src/internal/plate-editor/editor/plate-types.ts +0 -126
  59. package/src/internal/plate-editor/editor/plugins/ai-kit.tsx +0 -172
  60. package/src/internal/plate-editor/editor/plugins/autoformat-kit.tsx +0 -211
  61. package/src/internal/plate-editor/editor/plugins/basic-blocks-base-kit.tsx +0 -26
  62. package/src/internal/plate-editor/editor/plugins/basic-blocks-kit.tsx +0 -51
  63. package/src/internal/plate-editor/editor/plugins/basic-marks-base-kit.tsx +0 -24
  64. package/src/internal/plate-editor/editor/plugins/basic-marks-kit.tsx +0 -38
  65. package/src/internal/plate-editor/editor/plugins/basic-nodes-kit.tsx +0 -6
  66. package/src/internal/plate-editor/editor/plugins/block-menu-kit.tsx +0 -14
  67. package/src/internal/plate-editor/editor/plugins/block-placeholder-kit.tsx +0 -17
  68. package/src/internal/plate-editor/editor/plugins/block-selection-kit.tsx +0 -31
  69. package/src/internal/plate-editor/editor/plugins/callout-base-kit.tsx +0 -5
  70. package/src/internal/plate-editor/editor/plugins/callout-kit.tsx +0 -7
  71. package/src/internal/plate-editor/editor/plugins/code-block-base-kit.tsx +0 -23
  72. package/src/internal/plate-editor/editor/plugins/code-block-kit.tsx +0 -26
  73. package/src/internal/plate-editor/editor/plugins/column-base-kit.tsx +0 -8
  74. package/src/internal/plate-editor/editor/plugins/column-kit.tsx +0 -7
  75. package/src/internal/plate-editor/editor/plugins/comment-base-kit.tsx +0 -5
  76. package/src/internal/plate-editor/editor/plugins/comment-kit.tsx +0 -174
  77. package/src/internal/plate-editor/editor/plugins/copilot-kit.tsx +0 -68
  78. package/src/internal/plate-editor/editor/plugins/cursor-overlay-kit.tsx +0 -13
  79. package/src/internal/plate-editor/editor/plugins/date-base-kit.tsx +0 -5
  80. package/src/internal/plate-editor/editor/plugins/date-kit.tsx +0 -7
  81. package/src/internal/plate-editor/editor/plugins/discussion-kit.tsx +0 -36
  82. package/src/internal/plate-editor/editor/plugins/dnd-kit.tsx +0 -27
  83. package/src/internal/plate-editor/editor/plugins/docx-export-kit.tsx +0 -43
  84. package/src/internal/plate-editor/editor/plugins/docx-kit.tsx +0 -6
  85. package/src/internal/plate-editor/editor/plugins/emoji-kit.tsx +0 -15
  86. package/src/internal/plate-editor/editor/plugins/exit-break-kit.tsx +0 -12
  87. package/src/internal/plate-editor/editor/plugins/floating-toolbar-kit.tsx +0 -19
  88. package/src/internal/plate-editor/editor/plugins/font-base-kit.tsx +0 -36
  89. package/src/internal/plate-editor/editor/plugins/font-kit.tsx +0 -47
  90. package/src/internal/plate-editor/editor/plugins/indent-base-kit.tsx +0 -19
  91. package/src/internal/plate-editor/editor/plugins/indent-kit.tsx +0 -22
  92. package/src/internal/plate-editor/editor/plugins/link-base-kit.tsx +0 -5
  93. package/src/internal/plate-editor/editor/plugins/link-kit.tsx +0 -35
  94. package/src/internal/plate-editor/editor/plugins/list-base-kit.tsx +0 -24
  95. package/src/internal/plate-editor/editor/plugins/list-kit.tsx +0 -27
  96. package/src/internal/plate-editor/editor/plugins/markdown-kit.tsx +0 -18
  97. package/src/internal/plate-editor/editor/plugins/math-base-kit.tsx +0 -8
  98. package/src/internal/plate-editor/editor/plugins/math-kit.tsx +0 -10
  99. package/src/internal/plate-editor/editor/plugins/media-base-kit.tsx +0 -37
  100. package/src/internal/plate-editor/editor/plugins/media-kit.tsx +0 -53
  101. package/src/internal/plate-editor/editor/plugins/mention-base-kit.tsx +0 -5
  102. package/src/internal/plate-editor/editor/plugins/mention-kit.tsx +0 -36
  103. package/src/internal/plate-editor/editor/plugins/slash-kit.tsx +0 -17
  104. package/src/internal/plate-editor/editor/plugins/suggestion-base-kit.tsx +0 -5
  105. package/src/internal/plate-editor/editor/plugins/suggestion-kit.tsx +0 -95
  106. package/src/internal/plate-editor/editor/plugins/table-base-kit.tsx +0 -20
  107. package/src/internal/plate-editor/editor/plugins/table-kit.tsx +0 -22
  108. package/src/internal/plate-editor/editor/plugins/toc-base-kit.tsx +0 -5
  109. package/src/internal/plate-editor/editor/plugins/toc-kit.tsx +0 -14
  110. package/src/internal/plate-editor/editor/plugins/toggle-base-kit.tsx +0 -5
  111. package/src/internal/plate-editor/editor/plugins/toggle-kit.tsx +0 -9
  112. package/src/internal/plate-editor/editor/transforms.ts +0 -165
  113. package/src/internal/plate-editor/editor/use-chat.ts +0 -152
  114. package/src/internal/plate-editor/hooks/index.ts +0 -3
  115. package/src/internal/plate-editor/hooks/use-copy-to-clipboard.ts +0 -31
  116. package/src/internal/plate-editor/hooks/use-is-touch-device.ts +0 -26
  117. package/src/internal/plate-editor/hooks/use-lock-scroll.ts +0 -21
  118. package/src/internal/plate-editor/hooks/use-media-query.ts +0 -44
  119. package/src/internal/plate-editor/hooks/use-mounted.ts +0 -18
  120. package/src/internal/plate-editor/hooks/use-on-click-outside.ts +0 -114
  121. package/src/internal/plate-editor/hooks/use-upload-file.ts +0 -81
  122. package/src/internal/plate-editor/i18n/context.tsx +0 -58
  123. package/src/internal/plate-editor/i18n/index.ts +0 -3
  124. package/src/internal/plate-editor/i18n/locales/de.json +0 -57
  125. package/src/internal/plate-editor/i18n/locales/el.json +0 -57
  126. package/src/internal/plate-editor/i18n/locales/en.json +0 -57
  127. package/src/internal/plate-editor/i18n/locales/es.json +0 -57
  128. package/src/internal/plate-editor/i18n/locales/fr.json +0 -57
  129. package/src/internal/plate-editor/i18n/locales/it.json +0 -57
  130. package/src/internal/plate-editor/i18n/locales/pt.json +0 -57
  131. package/src/internal/plate-editor/i18n/locales/sl.json +0 -57
  132. package/src/internal/plate-editor/i18n/locales/tr.json +0 -57
  133. package/src/internal/plate-editor/i18n/types.ts +0 -59
  134. package/src/internal/plate-editor/i18n/use-translation.ts +0 -22
  135. package/src/internal/plate-editor/index.ts +0 -39
  136. package/src/internal/plate-editor/lib/ai-output-converter.ts +0 -153
  137. package/src/internal/plate-editor/lib/download-file.ts +0 -17
  138. package/src/internal/plate-editor/plate-ui/ai-chat-editor.tsx +0 -24
  139. package/src/internal/plate-editor/plate-ui/ai-menu.tsx +0 -828
  140. package/src/internal/plate-editor/plate-ui/ai-node.tsx +0 -41
  141. package/src/internal/plate-editor/plate-ui/ai-toolbar-button.tsx +0 -25
  142. package/src/internal/plate-editor/plate-ui/alert-dialog.tsx +0 -145
  143. package/src/internal/plate-editor/plate-ui/align-toolbar-button.tsx +0 -88
  144. package/src/internal/plate-editor/plate-ui/avatar.tsx +0 -3
  145. package/src/internal/plate-editor/plate-ui/block-context-menu.tsx +0 -104
  146. package/src/internal/plate-editor/plate-ui/block-discussion.tsx +0 -364
  147. package/src/internal/plate-editor/plate-ui/block-draggable.tsx +0 -557
  148. package/src/internal/plate-editor/plate-ui/block-list-static.tsx +0 -77
  149. package/src/internal/plate-editor/plate-ui/block-list.tsx +0 -85
  150. package/src/internal/plate-editor/plate-ui/block-menu.tsx +0 -555
  151. package/src/internal/plate-editor/plate-ui/block-selection.tsx +0 -47
  152. package/src/internal/plate-editor/plate-ui/block-suggestion.tsx +0 -469
  153. package/src/internal/plate-editor/plate-ui/blockquote-node-static.tsx +0 -10
  154. package/src/internal/plate-editor/plate-ui/blockquote-node.tsx +0 -11
  155. package/src/internal/plate-editor/plate-ui/button.tsx +0 -201
  156. package/src/internal/plate-editor/plate-ui/calendar.tsx +0 -3
  157. package/src/internal/plate-editor/plate-ui/callout-node-static.tsx +0 -76
  158. package/src/internal/plate-editor/plate-ui/callout-node.tsx +0 -54
  159. package/src/internal/plate-editor/plate-ui/caption.tsx +0 -47
  160. package/src/internal/plate-editor/plate-ui/checkbox.tsx +0 -3
  161. package/src/internal/plate-editor/plate-ui/code-block-node-static.tsx +0 -172
  162. package/src/internal/plate-editor/plate-ui/code-block-node.tsx +0 -226
  163. package/src/internal/plate-editor/plate-ui/code-node-static.tsx +0 -11
  164. package/src/internal/plate-editor/plate-ui/code-node.tsx +0 -12
  165. package/src/internal/plate-editor/plate-ui/column-node-static.tsx +0 -65
  166. package/src/internal/plate-editor/plate-ui/column-node.tsx +0 -24
  167. package/src/internal/plate-editor/plate-ui/command.tsx +0 -202
  168. package/src/internal/plate-editor/plate-ui/comment-node-static.tsx +0 -12
  169. package/src/internal/plate-editor/plate-ui/comment-node.tsx +0 -45
  170. package/src/internal/plate-editor/plate-ui/comment-toolbar-button.tsx +0 -24
  171. package/src/internal/plate-editor/plate-ui/comment.tsx +0 -619
  172. package/src/internal/plate-editor/plate-ui/cursor-overlay.tsx +0 -85
  173. package/src/internal/plate-editor/plate-ui/date-node-static.tsx +0 -43
  174. package/src/internal/plate-editor/plate-ui/date-node.tsx +0 -54
  175. package/src/internal/plate-editor/plate-ui/dialog.tsx +0 -445
  176. package/src/internal/plate-editor/plate-ui/dropdown-menu.tsx +0 -264
  177. package/src/internal/plate-editor/plate-ui/editor-static.tsx +0 -40
  178. package/src/internal/plate-editor/plate-ui/editor.tsx +0 -146
  179. package/src/internal/plate-editor/plate-ui/emoji-node.tsx +0 -48
  180. package/src/internal/plate-editor/plate-ui/emoji-toolbar-button.tsx +0 -626
  181. package/src/internal/plate-editor/plate-ui/equation-node-static.tsx +0 -155
  182. package/src/internal/plate-editor/plate-ui/equation-node.tsx +0 -226
  183. package/src/internal/plate-editor/plate-ui/equation-toolbar-button.tsx +0 -26
  184. package/src/internal/plate-editor/plate-ui/export-toolbar-button.tsx +0 -206
  185. package/src/internal/plate-editor/plate-ui/fixed-toolbar-buttons.tsx +0 -157
  186. package/src/internal/plate-editor/plate-ui/fixed-toolbar.tsx +0 -25
  187. package/src/internal/plate-editor/plate-ui/floating-discussion.tsx +0 -1129
  188. package/src/internal/plate-editor/plate-ui/floating-toolbar-buttons.tsx +0 -129
  189. package/src/internal/plate-editor/plate-ui/floating-toolbar.tsx +0 -97
  190. package/src/internal/plate-editor/plate-ui/font-color-toolbar-button.tsx +0 -209
  191. package/src/internal/plate-editor/plate-ui/font-size-toolbar-button.tsx +0 -152
  192. package/src/internal/plate-editor/plate-ui/ghost-text.tsx +0 -20
  193. package/src/internal/plate-editor/plate-ui/heading-node-static.tsx +0 -52
  194. package/src/internal/plate-editor/plate-ui/heading-node.tsx +0 -56
  195. package/src/internal/plate-editor/plate-ui/highlight-node-static.tsx +0 -9
  196. package/src/internal/plate-editor/plate-ui/highlight-node.tsx +0 -11
  197. package/src/internal/plate-editor/plate-ui/history-toolbar-button.tsx +0 -50
  198. package/src/internal/plate-editor/plate-ui/hover-card.tsx +0 -7
  199. package/src/internal/plate-editor/plate-ui/hr-node-static.tsx +0 -18
  200. package/src/internal/plate-editor/plate-ui/hr-node.tsx +0 -28
  201. package/src/internal/plate-editor/plate-ui/import-toolbar-button.tsx +0 -122
  202. package/src/internal/plate-editor/plate-ui/indent-toolbar-button.tsx +0 -32
  203. package/src/internal/plate-editor/plate-ui/inline-combobox.tsx +0 -409
  204. package/src/internal/plate-editor/plate-ui/input.tsx +0 -37
  205. package/src/internal/plate-editor/plate-ui/insert-toolbar-button.tsx +0 -258
  206. package/src/internal/plate-editor/plate-ui/label.tsx +0 -1
  207. package/src/internal/plate-editor/plate-ui/line-height-toolbar-button.tsx +0 -69
  208. package/src/internal/plate-editor/plate-ui/link-node-static.tsx +0 -15
  209. package/src/internal/plate-editor/plate-ui/link-node.tsx +0 -33
  210. package/src/internal/plate-editor/plate-ui/link-toolbar-button.tsx +0 -28
  211. package/src/internal/plate-editor/plate-ui/link-toolbar.tsx +0 -147
  212. package/src/internal/plate-editor/plate-ui/list-toolbar-button.tsx +0 -177
  213. package/src/internal/plate-editor/plate-ui/mark-toolbar-button.tsx +0 -34
  214. package/src/internal/plate-editor/plate-ui/media-audio-node-static.tsx +0 -21
  215. package/src/internal/plate-editor/plate-ui/media-audio-node.tsx +0 -32
  216. package/src/internal/plate-editor/plate-ui/media-embed-node.tsx +0 -103
  217. package/src/internal/plate-editor/plate-ui/media-file-node-static.tsx +0 -30
  218. package/src/internal/plate-editor/plate-ui/media-file-node.tsx +0 -52
  219. package/src/internal/plate-editor/plate-ui/media-image-node-static.tsx +0 -37
  220. package/src/internal/plate-editor/plate-ui/media-image-node.tsx +0 -183
  221. package/src/internal/plate-editor/plate-ui/media-placeholder-node.tsx +0 -441
  222. package/src/internal/plate-editor/plate-ui/media-preview-dialog.tsx +0 -127
  223. package/src/internal/plate-editor/plate-ui/media-toolbar-button.tsx +0 -227
  224. package/src/internal/plate-editor/plate-ui/media-toolbar.tsx +0 -214
  225. package/src/internal/plate-editor/plate-ui/media-upload-toast.tsx +0 -73
  226. package/src/internal/plate-editor/plate-ui/media-video-node-static.tsx +0 -35
  227. package/src/internal/plate-editor/plate-ui/media-video-node.tsx +0 -119
  228. package/src/internal/plate-editor/plate-ui/mention-node-static.tsx +0 -46
  229. package/src/internal/plate-editor/plate-ui/mention-node.tsx +0 -79
  230. package/src/internal/plate-editor/plate-ui/menu.tsx +0 -539
  231. package/src/internal/plate-editor/plate-ui/mode-toolbar-button.tsx +0 -124
  232. package/src/internal/plate-editor/plate-ui/more-toolbar-button.tsx +0 -34
  233. package/src/internal/plate-editor/plate-ui/paragraph-node-static.tsx +0 -15
  234. package/src/internal/plate-editor/plate-ui/paragraph-node.tsx +0 -16
  235. package/src/internal/plate-editor/plate-ui/popover.tsx +0 -75
  236. package/src/internal/plate-editor/plate-ui/progress.tsx +0 -1
  237. package/src/internal/plate-editor/plate-ui/remote-cursor-overlay.tsx +0 -79
  238. package/src/internal/plate-editor/plate-ui/resize-handle.tsx +0 -86
  239. package/src/internal/plate-editor/plate-ui/separator.tsx +0 -41
  240. package/src/internal/plate-editor/plate-ui/slash-node.tsx +0 -433
  241. package/src/internal/plate-editor/plate-ui/spinner.tsx +0 -1
  242. package/src/internal/plate-editor/plate-ui/suggestion-node-static.tsx +0 -35
  243. package/src/internal/plate-editor/plate-ui/suggestion-node.tsx +0 -166
  244. package/src/internal/plate-editor/plate-ui/suggestion-toolbar-button.tsx +0 -24
  245. package/src/internal/plate-editor/plate-ui/table-node-static.tsx +0 -84
  246. package/src/internal/plate-editor/plate-ui/table-node.tsx +0 -283
  247. package/src/internal/plate-editor/plate-ui/table-toolbar-button.tsx +0 -252
  248. package/src/internal/plate-editor/plate-ui/tabs.tsx +0 -3
  249. package/src/internal/plate-editor/plate-ui/textarea.tsx +0 -57
  250. package/src/internal/plate-editor/plate-ui/toc-node-static.tsx +0 -142
  251. package/src/internal/plate-editor/plate-ui/toc-node.tsx +0 -57
  252. package/src/internal/plate-editor/plate-ui/toc-sidebar.tsx +0 -48
  253. package/src/internal/plate-editor/plate-ui/toggle-node-static.tsx +0 -18
  254. package/src/internal/plate-editor/plate-ui/toggle-node.tsx +0 -33
  255. package/src/internal/plate-editor/plate-ui/toggle-toolbar-button.tsx +0 -24
  256. package/src/internal/plate-editor/plate-ui/toggle.tsx +0 -3
  257. package/src/internal/plate-editor/plate-ui/toolbar.tsx +0 -378
  258. package/src/internal/plate-editor/plate-ui/tooltip.tsx +0 -148
  259. package/src/internal/plate-editor/plate-ui/turn-into-toolbar-button.tsx +0 -175
  260. package/src/internal/plate-editor/types/index.ts +0 -22
  261. package/src/internal/plate-editor/vite.ts +0 -284
  262. package/src/internal/sheets/components/univer-sheets.tsx +0 -1104
  263. package/src/internal/sheets/i18n/context.tsx +0 -183
  264. package/src/internal/sheets/i18n/index.ts +0 -19
  265. package/src/internal/sheets/i18n/locales/de.json +0 -21
  266. package/src/internal/sheets/i18n/locales/el.json +0 -21
  267. package/src/internal/sheets/i18n/locales/en.json +0 -21
  268. package/src/internal/sheets/i18n/locales/es.json +0 -21
  269. package/src/internal/sheets/i18n/locales/fr.json +0 -21
  270. package/src/internal/sheets/i18n/locales/it.json +0 -21
  271. package/src/internal/sheets/i18n/locales/pt.json +0 -21
  272. package/src/internal/sheets/i18n/locales/sl.json +0 -21
  273. package/src/internal/sheets/i18n/locales/tr.json +0 -21
  274. package/src/internal/sheets/i18n/types.ts +0 -23
  275. package/src/internal/sheets/i18n/use-translation.ts +0 -17
  276. package/src/internal/sheets/index.ts +0 -14
  277. package/src/internal/sheets/types/css.d.ts +0 -11
  278. package/src/internal/sheets/types/index.ts +0 -260
  279. package/src/internal/sheets/xlsx.ts +0 -1169
  280. package/src/lib/api-client.ts +0 -77
  281. package/src/lib/assistant-api-actions.ts +0 -549
  282. package/src/lib/assistant-config.tsx +0 -75
  283. package/src/lib/class-utils.ts +0 -40
  284. package/src/lib/index.ts +0 -7
  285. package/src/lib/message-utils.ts +0 -131
  286. package/src/tools/tools-schema.json +0 -512
  287. package/src/types/index.ts +0 -235
  288. package/src/views/assistant-view.tsx +0 -1137
  289. package/src/views/canvas-app.tsx +0 -839
  290. package/src/views/canvas-code.tsx +0 -93
  291. package/src/views/canvas-deep-research.tsx +0 -44
  292. package/src/views/canvas-image.tsx +0 -25
  293. package/src/views/canvas-record-view.tsx +0 -285
  294. package/src/views/canvas-spreadsheet.tsx +0 -125
  295. package/src/views/canvas-text.tsx +0 -52
  296. package/src/views/canvas.tsx +0 -274
  297. package/src/views/chat-panel.tsx +0 -149
  298. package/src/views/index.ts +0 -20
  299. package/src/views/memories-panel.tsx +0 -365
  300. package/src/views/message-list.tsx +0 -370
  301. package/src/views/project-detail.tsx +0 -257
  302. package/src/views/projects-panel.tsx +0 -131
  303. package/src/views/sessions-list.tsx +0 -98
  304. package/src/views/sidebar-content.tsx +0 -256
  305. package/src/views/work-detail.tsx +0 -98
  306. package/src/vite.ts +0 -64
  307. package/src/worker.ts +0 -203
@@ -1,1129 +0,0 @@
1
- 'use client';
2
-
3
- import {
4
- Fragment, useCallback, useEffect, useReducer, useRef, useState, type ComponentProps, type RefObject
5
- } from 'react';
6
-
7
- import { getDraftCommentKey } from '@platejs/comment';
8
- import { BlockSelectionPlugin } from '@platejs/selection/react';
9
- import {
10
- acceptSuggestion,
11
- getSuggestionKey,
12
- getTransientSuggestionKey,
13
- keyId2SuggestionId,
14
- rejectSuggestion
15
- } from '@platejs/suggestion';
16
- import { CheckIcon, PencilLineIcon, XIcon } from 'lucide-react';
17
- import {
18
- ElementApi,
19
- KEYS,
20
- type Node,
21
- NodeApi,
22
- type NodeEntry,
23
- PathApi,
24
- type SlateEditor,
25
- type TCommentText,
26
- type TElement,
27
- TextApi,
28
- type TSuggestionText
29
- } from 'platejs';
30
- import {
31
- type PlateEditor,
32
- useEditorContainerRef,
33
- useEditorMounted,
34
- useEditorPlugin,
35
- useEditorRef,
36
- useEditorSelector,
37
- useEditorVersion,
38
- usePluginOption,
39
- usePluginOptions
40
- } from 'platejs/react';
41
-
42
- import { cn } from '@docyrus/ui-pro-shared/lib/utils';
43
-
44
- import { Avatar, AvatarFallback, AvatarImage } from '@docyrus/ui-pro-shared/avatar';
45
-
46
- import { Button } from './button';
47
-
48
- import {
49
- BLOCK_SUGGESTION,
50
- type ResolvedSuggestion,
51
- TYPE_TEXT_MAP
52
- } from './block-suggestion';
53
-
54
- import { Comment, CommentCreateForm, formatCommentDate } from './comment';
55
-
56
- import { commentPlugin } from '../editor/plugins/comment-kit';
57
- import {
58
- discussionPlugin,
59
- type TDiscussion
60
- } from '../editor/plugins/discussion-kit';
61
- import { suggestionPlugin } from '../editor/plugins/suggestion-kit';
62
-
63
- // Inline useDebouncedCallback - simplified version
64
- function useDebouncedCallback<T extends (...args: any[]) => any>(
65
- func: T,
66
- wait: number
67
- ) {
68
- const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
69
- const funcRef = useRef(func);
70
-
71
- funcRef.current = func;
72
-
73
- const debounced = useCallback(
74
- (...args: Parameters<T>) => {
75
- if (timeoutRef.current) {
76
- clearTimeout(timeoutRef.current);
77
- }
78
- timeoutRef.current = setTimeout(() => {
79
- funcRef.current(...args);
80
- }, wait);
81
- },
82
- [wait]
83
- );
84
-
85
- useEffect(() => {
86
- return () => {
87
- if (timeoutRef.current) {
88
- clearTimeout(timeoutRef.current);
89
- }
90
- };
91
- }, []);
92
-
93
- return debounced;
94
- }
95
-
96
- export function FloatingDiscussion() {
97
- const mounted = useEditorMounted();
98
- const isOverlapWithEditor = usePluginOption(
99
- commentPlugin,
100
- 'isOverlapWithEditor'
101
- );
102
-
103
- if (!mounted || isOverlapWithEditor) return null;
104
-
105
- return <FloatingDiscussionContent />;
106
- }
107
-
108
- const getCommentTop = (
109
- editor: SlateEditor,
110
- {
111
- node,
112
- relativeElement,
113
- topOffset = 30
114
- }: {
115
- node: TCommentText | TElement | TSuggestionText;
116
- relativeElement: HTMLDivElement;
117
- topOffset?: number;
118
- }
119
- ) => {
120
- const commentLeafDomNode = editor.api.toDOMNode(node);
121
-
122
- if (!commentLeafDomNode) return 0;
123
-
124
- const relativeElementRect = relativeElement.getBoundingClientRect();
125
- const { scrollTop } = relativeElement;
126
- const commentLeafRect = commentLeafDomNode.getBoundingClientRect();
127
-
128
- const top = commentLeafRect.top - relativeElementRect.top + scrollTop;
129
-
130
- return top > topOffset ? top - topOffset : 0;
131
- };
132
-
133
- const updateActiveBelow = (
134
- topMap: Record<string, number>,
135
- domMap: Record<string, HTMLDivElement | null>,
136
- activeId: string
137
- ) => {
138
- const discussionArray = Object.entries(topMap)
139
- .map(([id, top]) => ({ id, top }))
140
- .sort((a, b) => a.top - b.top);
141
-
142
- const activeIndex = discussionArray.findIndex(({ id }) => id === activeId);
143
-
144
- if (activeIndex === -1 || activeIndex === discussionArray.length - 1)
145
- return topMap;
146
-
147
- const activeElement = discussionArray[activeIndex];
148
- const start = activeElement.top;
149
- const end = start + (domMap[activeId]?.clientHeight ?? 100);
150
-
151
- const nextElement = discussionArray[activeIndex + 1];
152
- const nextStart = nextElement.top;
153
-
154
- // Check if next element overlaps with active element
155
- if (nextStart <= end) {
156
- // Move all following elements down
157
- const offset = end - nextStart + 10; // Add 10px gap
158
-
159
- for (let i = activeIndex + 1; i < discussionArray.length; i++) {
160
- discussionArray[i].top += offset;
161
- }
162
-
163
- return Object.fromEntries(discussionArray.map(d => [d.id, d.top]));
164
- }
165
-
166
- return topMap;
167
- };
168
-
169
- const updateActiveTop = (
170
- topMap: Record<string, number>,
171
- domMap: Record<string, HTMLDivElement | null>,
172
- activeId: string,
173
- targetTop: number
174
- ) => {
175
- const discussionArray = Object.entries(topMap)
176
- .map(([id, top]) => ({ id, top }))
177
- .sort((a, b) => a.top - b.top);
178
-
179
- const index = discussionArray.findIndex(({ id }) => id === activeId);
180
-
181
- if (index === -1) return topMap;
182
-
183
- const currentTop = discussionArray[index].top;
184
- const diff = targetTop - currentTop;
185
-
186
- // Set position of active element
187
- discussionArray[index].top = targetTop;
188
-
189
- if (diff < 0) {
190
- // Moving up - check for overlaps with previous elements
191
- for (let i = index - 1; i >= 0; i--) {
192
- const currentElement = discussionArray[i];
193
- const nextElement = discussionArray[i + 1];
194
- const elementHeight = domMap[currentElement.id]?.clientHeight ?? 100;
195
-
196
- // Check if current element overlaps with next element
197
- if (currentElement.top + elementHeight + 10 > nextElement.top) {
198
- // Move current element up to avoid overlap
199
- currentElement.top = nextElement.top - elementHeight - 10;
200
- } else {
201
- break; // No more overlaps
202
- }
203
- }
204
- } else {
205
- // Moving down - check for overlaps with next elements
206
- const activeHeight = domMap[activeId]?.clientHeight ?? 100;
207
- let activeBottom = targetTop + activeHeight + 10;
208
-
209
- // Only move elements that would overlap with active element
210
- for (let i = index + 1; i < discussionArray.length; i++) {
211
- if (discussionArray[i].top < activeBottom) {
212
- discussionArray[i].top = activeBottom;
213
- activeBottom
214
- = discussionArray[i].top
215
- + (domMap[discussionArray[i].id]?.clientHeight ?? 100)
216
- + 10;
217
- } else {
218
- break; // No more overlaps
219
- }
220
- }
221
- }
222
-
223
- return Object.fromEntries(discussionArray.map(d => [d.id, d.top]));
224
- };
225
-
226
- const updateTopCommenting = (
227
- topMap: Record<string, number>,
228
- domMap: Record<string, HTMLDivElement | null>
229
- ) => {
230
- const discussionArray = Object.entries(topMap)
231
- .map(([id, topDistance]) => ({ id, topDistance }))
232
- .sort((a, b) => a.topDistance - b.topDistance);
233
-
234
- const index = discussionArray.findIndex(
235
- ({ id }) => id === getDraftCommentKey()
236
- );
237
-
238
- if (index === -1) return topMap;
239
-
240
- const targetTopDistance = discussionArray[index].topDistance;
241
-
242
- // Find if any elements need to move up or down
243
- let moveDistance = 0;
244
-
245
- for (let i = 0; i < discussionArray.length; i++) {
246
- const current = discussionArray[i];
247
- const currentHeight = domMap[current.id]?.clientHeight ?? 100;
248
-
249
- if (i < index) {
250
- // Check if element needs to move up
251
- const minRequiredSpace = targetTopDistance - (currentHeight + 10);
252
-
253
- if (current.topDistance > minRequiredSpace) {
254
- const distance = current.topDistance - minRequiredSpace;
255
-
256
- moveDistance = Math.max(moveDistance, distance);
257
- }
258
- }
259
- }
260
-
261
- // Move elements up if needed
262
- if (moveDistance > 0) {
263
- for (let i = 0; i < index; i++) {
264
- discussionArray[i].topDistance -= moveDistance;
265
- }
266
- }
267
-
268
- // Check if next element overlaps with current element
269
- const currentHeight = domMap[discussionArray[index].id]?.clientHeight ?? 100;
270
- const currentBottom = targetTopDistance + currentHeight + 10;
271
-
272
- if (index + 1 < discussionArray.length) {
273
- const nextElement = discussionArray[index + 1];
274
-
275
- if (nextElement.topDistance < currentBottom) {
276
- // Only move elements that overlap
277
- let currentTop = currentBottom;
278
-
279
- for (let i = index + 1; i < discussionArray.length; i++) {
280
- const element = discussionArray[i];
281
-
282
- if (element.topDistance < currentTop) {
283
- element.topDistance = currentTop;
284
- const elementHeight = domMap[element.id]?.clientHeight ?? 100;
285
-
286
- currentTop += elementHeight + 10;
287
- } else {
288
- break; // No more overlaps
289
- }
290
- }
291
- }
292
- }
293
-
294
- return Object.fromEntries(discussionArray.map(d => [d.id, d.topDistance]));
295
- };
296
-
297
- const resolveOverlappingTop = (
298
- topMap: Record<string, number>,
299
- domMap: Record<string, HTMLDivElement | null>
300
- ) => {
301
- const discussionArray = Object.entries(topMap)
302
- .map(([id, topDistance]) => ({ id, topDistance }))
303
- .sort((a, b) => a.topDistance - b.topDistance);
304
-
305
- // Iterate through each discussion from top to bottom, checking for overlap with previous discussions
306
- for (let i = 1; i < discussionArray.length; i++) {
307
- const currentDiscussion = discussionArray[i];
308
- const currentElement = domMap[currentDiscussion.id];
309
-
310
- if (!currentElement) continue;
311
-
312
- // Calculate the range of current discussion
313
- const currentStart = currentDiscussion.topDistance;
314
- const currentEnd = currentStart + currentElement.clientHeight;
315
-
316
- // Check for overlap with all previous discussions
317
- for (let j = 0; j < i; j++) {
318
- const previousDiscussion = discussionArray[j];
319
- const previousElement = domMap[previousDiscussion.id];
320
-
321
- if (!previousElement) continue;
322
-
323
- const previousStart = previousDiscussion.topDistance;
324
- const previousEnd = previousStart + previousElement.clientHeight;
325
-
326
- // Check for overlap: condition for two intervals overlapping
327
- if (
328
- (currentStart <= previousEnd && currentEnd >= previousStart)
329
- || (previousStart <= currentEnd && previousEnd >= currentStart)
330
- ) {
331
- // If overlapping, move current discussion below the previous one
332
- currentDiscussion.topDistance = previousEnd + 10;
333
- // Update current discussion range and check for overlaps again
334
- i--;
335
-
336
- break;
337
- }
338
- }
339
- }
340
-
341
- return Object.fromEntries(discussionArray.map(d => [d.id, d.topDistance]));
342
- };
343
-
344
- const useCommentingNode = () => useEditorSelector((editor) => {
345
- if (!editor?.api || !editor.selection || editor.api.isExpanded()) return;
346
-
347
- return (editor.api.node({
348
- match: (n: TCommentText) => TextApi.isText(n) && n[KEYS.comment] && n[getDraftCommentKey()]
349
- }) as NodeEntry<TCommentText> | undefined)?.[0];
350
- }, []);
351
-
352
- function FloatingDiscussionContent() {
353
- const editorContainerRef = useEditorContainerRef() as RefObject<HTMLDivElement | null>;
354
- const editor = useEditorRef();
355
- const commentApi = editor.getApi(commentPlugin);
356
- const suggestionApi = editor.getApi(suggestionPlugin);
357
-
358
- const activeCommentId = usePluginOption(commentPlugin, 'activeId');
359
- const activeSuggestionId = usePluginOption(suggestionPlugin, 'activeId');
360
- const activeId = activeCommentId ?? activeSuggestionId;
361
- const isOverlapWithEditor = usePluginOption(
362
- commentPlugin,
363
- 'isOverlapWithEditor'
364
- );
365
- const updateTimestamp = usePluginOption(commentPlugin, 'updateTimestamp');
366
-
367
- const discussions = usePluginOption(discussionPlugin, 'discussions');
368
- const domRef = useRef<Record<string, HTMLDivElement | null>>({});
369
- const topRef = useRef<Record<string, number>>({});
370
-
371
- const [, forceUpdate] = useReducer(x => x + 1, 0);
372
-
373
- const commentingNode = useCommentingNode();
374
- const version = useEditorVersion();
375
-
376
- const suggestionEntriesMap = useRef<
377
- Record<string, NodeEntry<TElement | TSuggestionText>[]>
378
- >({});
379
-
380
- useEffect(() => {
381
- suggestionEntriesMap.current = {};
382
-
383
- const allSuggestionNodes = suggestionApi.suggestion
384
- .nodes({ at: [] })
385
- .filter(([node]: NodeEntry<TElement | TSuggestionText>) => !node[getTransientSuggestionKey()]);
386
-
387
- const suggestionIds = new Set<string>(
388
- allSuggestionNodes
389
- .flatMap(([node]: NodeEntry<TElement | TSuggestionText>) => {
390
- if (TextApi.isText(node)) {
391
- const dataList = suggestionApi.suggestion.dataList(node);
392
- const includeUpdate = dataList.some(
393
- (data: { type: string }) => data.type === 'update'
394
- );
395
-
396
- if (!includeUpdate) return suggestionApi.suggestion.nodeId(node);
397
-
398
- return dataList
399
- .filter((data: { type: string }) => data.type === 'update')
400
- .map((d: { id: string }) => d.id);
401
- }
402
- if (ElementApi.isElement(node)) {
403
- return suggestionApi.suggestion.nodeId(node);
404
- }
405
-
406
- return null;
407
- })
408
- .filter((id: string | null): id is string => typeof id === 'string' && id.length > 0)
409
- );
410
-
411
- suggestionIds.forEach((id) => {
412
- if (!id) return;
413
-
414
- const entries = [
415
- ...editor.api.nodes({
416
- at: [],
417
- mode: 'all',
418
- match: (n: TElement | TSuggestionText) => (n[KEYS.suggestion] && n[getSuggestionKey(id)])
419
- || suggestionApi.suggestion.nodeId(n as TElement) === id
420
- })
421
- ] as NodeEntry<TElement | TSuggestionText>[];
422
-
423
- suggestionEntriesMap.current[id] = entries;
424
- });
425
- }, [editor, suggestionApi.suggestion, version]);
426
-
427
- const suggestionList = Object.entries(suggestionEntriesMap.current).map(
428
- ([id, entries]) => ({
429
- id,
430
- entries
431
- })
432
- );
433
-
434
- const renderFloatingDiscussion = useCallback(() => {
435
- if (isOverlapWithEditor) return;
436
-
437
- topRef.current = {};
438
-
439
- discussions.forEach((discussion) => {
440
- if (
441
- discussion.isResolved
442
- || !commentApi.comment.has({ id: discussion.id })
443
- )
444
- return;
445
-
446
- const commentLeafEntry = commentApi.comment.node({
447
- id: discussion.id,
448
- at: []
449
- });
450
-
451
- if (!commentLeafEntry) return;
452
-
453
- const commentLeaf = commentLeafEntry[0];
454
-
455
- const topDistance = getCommentTop(editor, {
456
- node: commentLeaf,
457
- relativeElement: editorContainerRef.current as HTMLDivElement
458
- });
459
-
460
- topRef.current[discussion.id] = topDistance;
461
- });
462
-
463
- suggestionList.forEach(({ id, entries }) => {
464
- if (!id) return;
465
-
466
- const topDistance = getCommentTop(editor, {
467
- node: entries[0][0],
468
- relativeElement: editorContainerRef.current as HTMLDivElement
469
- });
470
-
471
- topRef.current[id] = topDistance;
472
- });
473
-
474
- topRef.current = resolveOverlappingTop(topRef.current, domRef.current);
475
- forceUpdate();
476
-
477
- // eslint-disable-next-line react-hooks/exhaustive-deps
478
- }, [
479
- discussions.length,
480
- suggestionList.length,
481
- editorContainerRef,
482
- isOverlapWithEditor
483
- ]);
484
-
485
- const renderFloatingCreateForm = useCallback(() => {
486
- if (!commentingNode || activeId !== getDraftCommentKey()) return;
487
-
488
- const topDistance = getCommentTop(editor, {
489
- node: commentingNode,
490
- relativeElement: editorContainerRef.current as HTMLDivElement
491
- });
492
-
493
- topRef.current[getDraftCommentKey()] = topDistance;
494
-
495
- topRef.current = updateTopCommenting(topRef.current, domRef.current);
496
-
497
- forceUpdate();
498
- }, [
499
- activeId,
500
- commentingNode,
501
- editor,
502
- editorContainerRef
503
- ]);
504
-
505
- const debouncedUpdateFloat = useDebouncedCallback(
506
- renderFloatingDiscussion,
507
- 500
508
- );
509
-
510
- useEffect(() => {
511
- if (updateTimestamp) {
512
- debouncedUpdateFloat();
513
- }
514
- }, [debouncedUpdateFloat, updateTimestamp]);
515
-
516
- useEffect(() => {
517
- if (!discussions) return;
518
-
519
- setTimeout(() => {
520
- renderFloatingDiscussion();
521
- }, 0);
522
- }, [discussions, renderFloatingDiscussion]);
523
-
524
- useEffect(() => {
525
- if (!activeId || !domRef.current[activeId]) return;
526
-
527
- const resizeObserver = new ResizeObserver(() => {
528
- topRef.current = updateActiveBelow(
529
- topRef.current,
530
- domRef.current,
531
- activeId
532
- );
533
-
534
- forceUpdate();
535
- });
536
-
537
- resizeObserver.observe(domRef.current[activeId]);
538
-
539
- return () => {
540
- resizeObserver.disconnect();
541
- };
542
- }, [activeId]);
543
-
544
- useEffect(() => {
545
- if (!activeId) {
546
- return renderFloatingDiscussion();
547
- }
548
-
549
- const activeNode = commentApi.comment.node({ id: activeId, at: [] });
550
- const activeSuggestionNode = suggestionApi.suggestion.node({
551
- id: activeId,
552
- at: [],
553
- isText: true
554
- });
555
-
556
- if (!activeNode && !activeSuggestionNode) return;
557
-
558
- topRef.current = updateActiveTop(
559
- topRef.current,
560
- domRef.current,
561
- activeId,
562
- getCommentTop(editor, {
563
- node: activeNode?.[0] || activeSuggestionNode![0],
564
- relativeElement: editorContainerRef.current as HTMLDivElement
565
- })
566
- );
567
-
568
- forceUpdate();
569
- }, [
570
- activeId,
571
- editor,
572
- commentingNode,
573
- editorContainerRef,
574
- renderFloatingDiscussion,
575
- commentApi.comment,
576
- suggestionApi.suggestion
577
- ]);
578
-
579
- useEffect(() => {
580
- if (!commentingNode || !domRef.current[getDraftCommentKey()]) {
581
- return;
582
- }
583
-
584
- const resizeObserver = new ResizeObserver(() => {
585
- renderFloatingCreateForm();
586
- });
587
-
588
- resizeObserver.observe(domRef.current[getDraftCommentKey()]!);
589
-
590
- return () => {
591
- resizeObserver.disconnect();
592
- };
593
- }, [
594
- commentingNode,
595
- editor,
596
- editorContainerRef,
597
- renderFloatingCreateForm,
598
- renderFloatingDiscussion
599
- ]);
600
-
601
- useEffect(() => {
602
- if (!isOverlapWithEditor) {
603
- renderFloatingDiscussion();
604
- }
605
- }, [isOverlapWithEditor, renderFloatingDiscussion]);
606
-
607
- // Only show if there are discussions/suggestions or active commenting
608
- const hasUnresolvedDiscussions = discussions.some((d: TDiscussion) => !d.isResolved);
609
- const hasSuggestions = suggestionList.length > 0;
610
-
611
- if (!commentingNode && !hasUnresolvedDiscussions && !hasSuggestions && !activeId) {
612
- return null;
613
- }
614
-
615
- return (
616
- <>
617
- {/* Unsubmit comment */}
618
- {commentingNode && (
619
- <div
620
- className="absolute right-[80px] w-[288px] cursor-pointer rounded-lg border bg-popover p-3 transition-transform duration-200"
621
- ref={(el) => {
622
- domRef.current[getDraftCommentKey()] = el;
623
- }}
624
- style={{
625
- top: topRef.current[getDraftCommentKey()] ?? -9999
626
- }}>
627
- <CommentCreateForm focusOnMount />
628
- </div>
629
- )}
630
-
631
- {discussions.map(
632
- discussion => !discussion.isResolved
633
- && commentApi.comment.has({ id: discussion.id }) && (
634
- <FloatingCommentsContent
635
- discussion={discussion}
636
- domRef={domRef}
637
- key={discussion.id}
638
- ref={(el) => {
639
- domRef.current[discussion.id] = el;
640
- }}
641
- top={topRef.current[discussion.id] ?? 0} />
642
- )
643
- )}
644
-
645
- {suggestionList.map(
646
- ({ id, entries }) => id && (
647
- <FloatingSuggestionContent
648
- entries={entries}
649
- id={id}
650
- key={id}
651
- ref={(el) => {
652
- domRef.current[id] = el;
653
- }}
654
- top={topRef.current[id] ?? 0} />
655
- )
656
- )}
657
- </>
658
- );
659
- }
660
-
661
- type FloatingCommentsContentProps = {
662
- discussion: TDiscussion;
663
- domRef: RefObject<Record<string, HTMLDivElement | null>>;
664
- top: number;
665
- };
666
-
667
- function FloatingCommentsContent({
668
- discussion,
669
- ref,
670
- top
671
- }: ComponentProps<'div'> & FloatingCommentsContentProps) {
672
- const editor = useEditorRef();
673
-
674
- const { activeId, hoverId } = usePluginOptions(
675
- commentPlugin,
676
- ({ activeId, hoverId }) => ({
677
- activeId,
678
- hoverId
679
- })
680
- );
681
-
682
- const [editingId, setEditingId] = useState<string | null>(null);
683
-
684
- const setHoverId = (id: string | null) => {
685
- /*
686
- * If dropdown menu open, do not unset the active state since it will make dropdown menu open in the wrong position
687
- * Notion has the same issue
688
- */
689
- if (document.activeElement?.closest('[data-radix-menu-content]')) return;
690
-
691
- editor.setOption(commentPlugin, 'hoverId', id);
692
- };
693
-
694
- const highlightDiscussion = (editor: PlateEditor, id: string) => {
695
- editor.setOption(commentPlugin, 'activeId', id);
696
- editor.setOption(suggestionPlugin, 'activeId', null);
697
- const leaf = editor.api.node({
698
- at: [],
699
- match: (n: TElement | TSuggestionText) => TextApi.isText(n)
700
- && n[KEYS.comment]
701
- && editor.getApi(commentPlugin).comment.nodeId(n) === id
702
- });
703
-
704
- if (!leaf) return;
705
-
706
- const parent = NodeApi.get<Node>(editor, leaf[1].slice(0, 1));
707
-
708
- editor
709
- .getApi(BlockSelectionPlugin)
710
- .blockSelection.addSelectedRow(parent!.id as string, {
711
- clear: false,
712
- delay: 1000
713
- });
714
- };
715
-
716
- return (
717
- <div
718
- className={cn(
719
- 'absolute right-20 z-10 w-72 animate-fade-in cursor-pointer rounded-lg border bg-popover p-3 transition-transform duration-200',
720
- '[&[data-hover=true][data-active=false]]:-translate-x-2 [&[data-hover=true][data-active=false]]:bg-muted',
721
- '[&[data-active=true]]:-translate-x-2'
722
- )}
723
- data-active={activeId === discussion.id}
724
- data-discussion-id={discussion.id}
725
- data-hover={hoverId === discussion.id}
726
- onClick={() => highlightDiscussion(editor, discussion.id)}
727
- onMouseEnter={() => setHoverId(discussion.id)}
728
- onMouseLeave={() => setHoverId(null)}
729
- ref={ref}
730
- style={{
731
- top
732
- }}>
733
- {discussion.comments.length >= 3 && activeId !== discussion.id ? (
734
- <>
735
- <Comment
736
- comment={discussion.comments[0]}
737
- discussionLength={discussion.comments.length}
738
- documentContent={discussion?.documentContent}
739
- editingId={editingId}
740
- index={0}
741
- key={discussion.comments[0].id}
742
- onEditorClick={() => highlightDiscussion(editor, discussion.id)}
743
- setEditingId={setEditingId} />
744
- <div className="relative mb-1 ml-[26px] flex h-7 items-center rounded-md pl-1.5 text-muted-foreground text-sm hover:bg-muted">
745
- <div className="absolute top-[-5px] left-[-14px] h-full w-0.5 shrink-0 bg-muted" />
746
- <div className="ml-2">
747
- Show {discussion.comments.length - 2} replies
748
- </div>
749
- </div>
750
- <Comment
751
- comment={discussion.comments.at(-1)!}
752
- discussionLength={discussion.comments.length}
753
- documentContent={discussion?.documentContent}
754
- editingId={editingId}
755
- index={discussion.comments.length - 1}
756
- key={discussion.comments.at(-1)!.id}
757
- onEditorClick={() => highlightDiscussion(editor, discussion.id)}
758
- setEditingId={setEditingId} />
759
- </>
760
- ) : (
761
- discussion.comments.map((comment, index) => (
762
- <Comment
763
- comment={comment}
764
- discussionLength={discussion.comments.length}
765
- documentContent={discussion?.documentContent}
766
- editingId={editingId}
767
- index={index}
768
- key={comment.id ?? index}
769
- onEditorClick={() => highlightDiscussion(editor, discussion.id)}
770
- setEditingId={setEditingId} />
771
- ))
772
- )}
773
-
774
- {activeId === discussion.id && (
775
- <CommentCreateForm discussionId={discussion.id} />
776
- )}
777
- </div>
778
- );
779
- }
780
-
781
- type FloatingSuggestionContentProps = {
782
- id: string;
783
- entries: NodeEntry<TElement | TSuggestionText>[];
784
- top: number;
785
- };
786
-
787
- const FloatingSuggestionContent = ({
788
- id,
789
- entries,
790
- ref,
791
- top
792
- }: ComponentProps<'div'> & FloatingSuggestionContentProps) => {
793
- const { api, editor, setOption } = useEditorPlugin(suggestionPlugin);
794
- const nodeData = api.suggestion.suggestionData(entries[0][0]);
795
-
796
- const { activeId, hoverId } = usePluginOptions(
797
- suggestionPlugin,
798
- ({ activeId, hoverId }) => ({
799
- activeId,
800
- hoverId
801
- })
802
- );
803
-
804
- const userId = usePluginOption(discussionPlugin, 'currentUserId');
805
- const userData = usePluginOption(discussionPlugin, 'user', userId);
806
- const discussions = usePluginOption(discussionPlugin, 'discussions');
807
-
808
- const [editingId, setEditingId] = useState<string | null>(null);
809
-
810
- if (entries.length === 0) return null;
811
-
812
- // move line break to the end
813
- entries.sort(([, path1], [, path2]) => PathApi.isChild(path1, path2) ? -1 : 1);
814
-
815
- let newText = '';
816
- let text = '';
817
- let properties: any = {};
818
- let newProperties: any = {};
819
-
820
- // overlapping suggestion
821
- entries.forEach(([node]) => {
822
- if (TextApi.isText(node)) {
823
- const dataList = api.suggestion.dataList(node);
824
-
825
- dataList.forEach((data) => {
826
- if (data.id !== id) return;
827
-
828
- switch (data.type) {
829
- case 'insert': {
830
- newText += node.text;
831
-
832
- break;
833
- }
834
-
835
- case 'remove': {
836
- text += node.text;
837
-
838
- break;
839
- }
840
-
841
- case 'update': {
842
- properties = {
843
- ...properties,
844
- ...data.properties
845
- };
846
- newProperties = {
847
- ...newProperties,
848
- ...data.newProperties
849
- };
850
- newText += node.text;
851
-
852
- break;
853
- }
854
- }
855
- });
856
- } else {
857
- const lineBreakData = api.suggestion.isBlockSuggestion(node) ? node.suggestion : undefined;
858
-
859
- if (lineBreakData?.id !== keyId2SuggestionId(id)) return;
860
- if (lineBreakData.type === 'insert') {
861
- newText += lineBreakData.isLineBreak ? BLOCK_SUGGESTION : BLOCK_SUGGESTION + TYPE_TEXT_MAP[node.type](node);
862
- } else if (lineBreakData.type === 'remove') {
863
- text += lineBreakData.isLineBreak ? BLOCK_SUGGESTION : BLOCK_SUGGESTION + TYPE_TEXT_MAP[node.type](node);
864
- }
865
- }
866
- });
867
-
868
- if (!nodeData) return null;
869
-
870
- const comments = discussions.find(d => d.id === id)?.comments || [];
871
- const createdAt = new Date(nodeData.createdAt);
872
- const keyId = getSuggestionKey(id);
873
-
874
- const suggestionText2Array = (text: string) => {
875
- if (text === BLOCK_SUGGESTION) return ['line breaks'];
876
-
877
- return text.split(BLOCK_SUGGESTION).filter(Boolean);
878
- };
879
-
880
- const accept = (suggestion: ResolvedSuggestion) => {
881
- api.suggestion.withoutSuggestions(() => {
882
- acceptSuggestion(editor, suggestion);
883
- });
884
- };
885
-
886
- const reject = (suggestion: ResolvedSuggestion) => {
887
- api.suggestion.withoutSuggestions(() => {
888
- rejectSuggestion(editor, suggestion);
889
- });
890
- };
891
-
892
- let suggestion: ResolvedSuggestion;
893
-
894
- if (nodeData.type === 'update') {
895
- suggestion = {
896
- comments,
897
- createdAt,
898
- keyId,
899
- newProperties,
900
- newText,
901
- properties,
902
- suggestionId: keyId2SuggestionId(id),
903
- type: 'update',
904
- userId: nodeData.userId
905
- };
906
- } else if (newText.length > 0 && text.length > 0) {
907
- suggestion = {
908
- comments,
909
- createdAt,
910
- keyId,
911
- newText,
912
- suggestionId: keyId2SuggestionId(id),
913
- text,
914
- type: 'replace',
915
- userId: nodeData.userId
916
- };
917
- } else if (newText.length > 0) {
918
- suggestion = {
919
- comments,
920
- createdAt,
921
- keyId,
922
- newText,
923
- suggestionId: keyId2SuggestionId(id),
924
- type: 'insert',
925
- userId: nodeData.userId
926
- };
927
- } else if (text.length > 0) {
928
- suggestion = {
929
- comments,
930
- createdAt,
931
- keyId,
932
- suggestionId: keyId2SuggestionId(id),
933
- text,
934
- type: 'remove',
935
- userId: nodeData.userId
936
- };
937
- } else {
938
- return null;
939
- }
940
-
941
- const highlightSuggestion = (editor: PlateEditor, id: string) => {
942
- editor.setOption(suggestionPlugin, 'activeId', id);
943
- editor.setOption(commentPlugin, 'activeId', null);
944
-
945
- const leaf = editor.api.node({
946
- at: [],
947
- match: (n: TElement | TSuggestionText) => n[KEYS.suggestion]
948
- && editor.getApi(suggestionPlugin).suggestion.nodeId(n as any) === id
949
- });
950
-
951
- if (!leaf) return;
952
-
953
- const parent = NodeApi.get<Node>(editor, leaf[1].slice(0, 1));
954
-
955
- editor
956
- .getApi(BlockSelectionPlugin)
957
- .blockSelection.addSelectedRow(parent!.id as string, {
958
- clear: false,
959
- delay: 1000
960
- });
961
- };
962
-
963
- // Only show if this suggestion is active or hovered
964
- if (activeId !== id && hoverId !== id) {
965
- return null;
966
- }
967
-
968
- return (
969
- <div
970
- className={cn(
971
- 'absolute right-20 z-10 w-72 animate-fade-in cursor-pointer rounded-lg border bg-popover p-3 transition-transform duration-200',
972
- '[&[data-hover=true][data-active=false]]:-translate-x-2 [&[data-hover=true][data-active=false]]:bg-muted',
973
- '[&[data-active=true]]:-translate-x-2'
974
- )}
975
- data-active={activeId === id}
976
- data-discussion-id={id}
977
- data-hover={hoverId === id}
978
- onClick={() => highlightSuggestion(editor, id)}
979
- onMouseEnter={() => setOption('hoverId', id)}
980
- onMouseLeave={() => setOption('hoverId', null)}
981
- ref={ref}
982
- style={{ top }}>
983
- <div className="flex flex-col">
984
- <div className="relative flex items-center">
985
- {userData && (
986
- <>
987
- <Avatar className="relative mr-2 size-6">
988
- <AvatarImage alt={userData.name} src={userData.avatarUrl} />
989
- <AvatarFallback>{userData.name?.[0]}</AvatarFallback>
990
- </Avatar>
991
- <PencilLineIcon className="-bottom-2 absolute left-4 size-4 rounded-[50%] bg-brand-foreground p-0.5 text-brand/80" />
992
- </>
993
- )}
994
- <h4 className="font-semibold text-sm leading-none">
995
- {userData?.name}
996
- </h4>
997
- <div className="ml-1.5 text-muted-foreground/80 text-xs leading-none">
998
- <span className="mr-1">
999
- {formatCommentDate(suggestion.createdAt)}
1000
- </span>
1001
- </div>
1002
- </div>
1003
-
1004
- <div className="relative mt-1 mb-4 pl-[32px]">
1005
- <div className="flex flex-col gap-2">
1006
- {suggestion.type === 'remove'
1007
- && suggestionText2Array(suggestion.text!).map((text, index) => (
1008
- <div className="flex items-center gap-2" key={index}>
1009
- <span className="text-muted-foreground text-sm">Delete:</span>
1010
- <span className="text-sm">{text}</span>
1011
- </div>
1012
- ))}
1013
-
1014
- {suggestion.type === 'insert'
1015
- && suggestionText2Array(suggestion.newText!).map((text, index) => (
1016
- <div className="flex items-center gap-2" key={index}>
1017
- <span className="text-muted-foreground text-sm">Add:</span>
1018
- <span className="text-sm">"{text || 'line breaks'}"</span>
1019
- </div>
1020
- ))}
1021
-
1022
- {suggestion.type === 'replace' && (
1023
- <div className="flex flex-col gap-2">
1024
- {suggestionText2Array(suggestion.newText!).map(
1025
- (text, index) => (
1026
- <Fragment key={index}>
1027
- <div className="flex items-center text-brand/80">
1028
- <span className="text-sm">With:</span>
1029
- <span className="text-sm">
1030
- "{text || 'line breaks'}"
1031
- </span>
1032
- </div>
1033
- </Fragment>
1034
- )
1035
- )}
1036
-
1037
- {suggestionText2Array(suggestion.text!).map((text, index) => (
1038
- <Fragment key={index}>
1039
- <div className="flex items-center">
1040
- <span className="text-muted-foreground text-sm">
1041
- {index === 0 ? 'Replace:' : 'Delete:'}
1042
- </span>
1043
- <span className="text-sm">"{text || 'line breaks'}"</span>
1044
- </div>
1045
- </Fragment>
1046
- ))}
1047
- </div>
1048
- )}
1049
-
1050
- {suggestion.type === 'update' && (
1051
- <div className="flex items-center gap-2">
1052
- <span className="text-muted-foreground text-sm">
1053
- {Object.keys(suggestion.properties).map(key => (
1054
- <span key={key}>Un{key}</span>
1055
- ))}
1056
- {Object.keys(suggestion.newProperties).map(key => (
1057
- <span key={key}>
1058
- {key.charAt(0).toUpperCase() + key.slice(1)}
1059
- </span>
1060
- ))}
1061
- </span>
1062
- <span className="text-sm">"{suggestion.newText}"</span>
1063
- </div>
1064
- )}
1065
- </div>
1066
- </div>
1067
-
1068
- {suggestion.comments.length >= 3 && activeId !== id ? (
1069
- <>
1070
- <Comment
1071
- comment={suggestion.comments[0]}
1072
- discussionLength={suggestion.comments.length}
1073
- documentContent="__suggestion__"
1074
- editingId={editingId}
1075
- index={0}
1076
- key={suggestion.comments[0].id}
1077
- setEditingId={setEditingId} />
1078
- <div className="relative mb-1 ml-[26px] flex h-7 items-center rounded-md pl-1.5 text-muted-foreground text-sm hover:bg-muted">
1079
- <div className="absolute top-[-5px] left-[-14px] h-full w-0.5 shrink-0 bg-muted" />
1080
- <div className="ml-2">
1081
- Show {suggestion.comments.length - 2} replies
1082
- </div>
1083
- </div>
1084
- <Comment
1085
- comment={suggestion.comments.at(-1)!}
1086
- discussionLength={suggestion.comments.length}
1087
- documentContent="__suggestion__"
1088
- editingId={editingId}
1089
- index={suggestion.comments.length - 1}
1090
- key={suggestion.comments.at(-1)!.id}
1091
- setEditingId={setEditingId} />
1092
- </>
1093
- ) : (
1094
- suggestion.comments.map((comment, index) => (
1095
- <Comment
1096
- comment={comment}
1097
- discussionLength={suggestion.comments.length}
1098
- documentContent="__suggestion__"
1099
- editingId={editingId}
1100
- index={index}
1101
- key={comment.id ?? index}
1102
- setEditingId={setEditingId} />
1103
- ))
1104
- )}
1105
-
1106
- {hoverId === id && (
1107
- <div className="absolute top-4 right-4 flex gap-2">
1108
- <Button
1109
- className="h-6 p-1 text-muted-foreground"
1110
- onClick={() => accept(suggestion)}
1111
- variant="ghost">
1112
- <CheckIcon className="size-4" />
1113
- </Button>
1114
- <Button
1115
- className="h-6 p-1 text-muted-foreground"
1116
- onClick={() => reject(suggestion)}
1117
- variant="ghost">
1118
- <XIcon className="size-4" />
1119
- </Button>
1120
- </div>
1121
- )}
1122
-
1123
- {activeId === id && (
1124
- <CommentCreateForm discussionId={suggestion.suggestionId} />
1125
- )}
1126
- </div>
1127
- </div>
1128
- );
1129
- };