@docyrus/ui-pro-ai-assistant 0.0.1

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 (308) hide show
  1. package/dist/index.js +26161 -0
  2. package/dist/index.js.map +1 -0
  3. package/package.json +155 -0
  4. package/src/components/assistant-animations.tsx +29 -0
  5. package/src/components/assistant-dialogs.tsx +235 -0
  6. package/src/components/code-view.tsx +278 -0
  7. package/src/components/create-agent-task.tsx +104 -0
  8. package/src/components/create-new-work-version.tsx +30 -0
  9. package/src/components/extract-web.tsx +160 -0
  10. package/src/components/forward-to-agent.tsx +90 -0
  11. package/src/components/generate-chart.tsx +101 -0
  12. package/src/components/generative-action-button.tsx +122 -0
  13. package/src/components/generative-tool.tsx +685 -0
  14. package/src/components/generative-ui-object.tsx +210 -0
  15. package/src/components/input-area.tsx +1209 -0
  16. package/src/components/json-schema-layout.tsx +326 -0
  17. package/src/components/list-item-card.tsx +92 -0
  18. package/src/components/mermaid-diagram.tsx +192 -0
  19. package/src/components/preview-image.tsx +47 -0
  20. package/src/components/request-approval.tsx +48 -0
  21. package/src/components/request-user-input.tsx +270 -0
  22. package/src/components/search-web.tsx +319 -0
  23. package/src/components/sheet-command.tsx +88 -0
  24. package/src/components/shell-canvas.tsx +122 -0
  25. package/src/components/show-advanced-data-table.tsx +352 -0
  26. package/src/components/show-generated-content-options.tsx +93 -0
  27. package/src/components/show-people-cards.tsx +180 -0
  28. package/src/components/subagent-tool.tsx +180 -0
  29. package/src/components/text-editor-tool.tsx +328 -0
  30. package/src/components/work-canvas.tsx +88 -0
  31. package/src/components/work-card.tsx +42 -0
  32. package/src/declarations.d.ts +1 -0
  33. package/src/docy-assistant.tsx +1962 -0
  34. package/src/hooks/index.ts +7 -0
  35. package/src/hooks/use-assistant-api.ts +507 -0
  36. package/src/hooks/use-deployment-data.ts +162 -0
  37. package/src/hooks/use-project-state.ts +347 -0
  38. package/src/hooks/use-session-state.ts +207 -0
  39. package/src/hooks/use-speech-recognition.ts +137 -0
  40. package/src/hooks/use-ui-state.ts +185 -0
  41. package/src/hooks/use-works-state.ts +146 -0
  42. package/src/i18n/context.tsx +253 -0
  43. package/src/i18n/index.ts +19 -0
  44. package/src/i18n/locales/de.json +198 -0
  45. package/src/i18n/locales/el.json +198 -0
  46. package/src/i18n/locales/en.json +226 -0
  47. package/src/i18n/locales/es.json +198 -0
  48. package/src/i18n/locales/fr.json +198 -0
  49. package/src/i18n/locales/it.json +198 -0
  50. package/src/i18n/locales/pt.json +198 -0
  51. package/src/i18n/locales/sl.json +198 -0
  52. package/src/i18n/locales/tr.json +211 -0
  53. package/src/i18n/types.ts +23 -0
  54. package/src/i18n/use-translation.ts +17 -0
  55. package/src/index.ts +18 -0
  56. package/src/internal/plate-editor/editor/auth-context.ts +11 -0
  57. package/src/internal/plate-editor/editor/editor-base-kit.tsx +39 -0
  58. package/src/internal/plate-editor/editor/editor-kit.tsx +89 -0
  59. package/src/internal/plate-editor/editor/plate-editor.tsx +75 -0
  60. package/src/internal/plate-editor/editor/plate-types.ts +126 -0
  61. package/src/internal/plate-editor/editor/plugins/ai-kit.tsx +172 -0
  62. package/src/internal/plate-editor/editor/plugins/autoformat-kit.tsx +211 -0
  63. package/src/internal/plate-editor/editor/plugins/basic-blocks-base-kit.tsx +26 -0
  64. package/src/internal/plate-editor/editor/plugins/basic-blocks-kit.tsx +51 -0
  65. package/src/internal/plate-editor/editor/plugins/basic-marks-base-kit.tsx +24 -0
  66. package/src/internal/plate-editor/editor/plugins/basic-marks-kit.tsx +38 -0
  67. package/src/internal/plate-editor/editor/plugins/basic-nodes-kit.tsx +6 -0
  68. package/src/internal/plate-editor/editor/plugins/block-menu-kit.tsx +14 -0
  69. package/src/internal/plate-editor/editor/plugins/block-placeholder-kit.tsx +17 -0
  70. package/src/internal/plate-editor/editor/plugins/block-selection-kit.tsx +31 -0
  71. package/src/internal/plate-editor/editor/plugins/callout-base-kit.tsx +5 -0
  72. package/src/internal/plate-editor/editor/plugins/callout-kit.tsx +7 -0
  73. package/src/internal/plate-editor/editor/plugins/code-block-base-kit.tsx +23 -0
  74. package/src/internal/plate-editor/editor/plugins/code-block-kit.tsx +26 -0
  75. package/src/internal/plate-editor/editor/plugins/column-base-kit.tsx +8 -0
  76. package/src/internal/plate-editor/editor/plugins/column-kit.tsx +7 -0
  77. package/src/internal/plate-editor/editor/plugins/comment-base-kit.tsx +5 -0
  78. package/src/internal/plate-editor/editor/plugins/comment-kit.tsx +174 -0
  79. package/src/internal/plate-editor/editor/plugins/copilot-kit.tsx +68 -0
  80. package/src/internal/plate-editor/editor/plugins/cursor-overlay-kit.tsx +13 -0
  81. package/src/internal/plate-editor/editor/plugins/date-base-kit.tsx +5 -0
  82. package/src/internal/plate-editor/editor/plugins/date-kit.tsx +7 -0
  83. package/src/internal/plate-editor/editor/plugins/discussion-kit.tsx +36 -0
  84. package/src/internal/plate-editor/editor/plugins/dnd-kit.tsx +27 -0
  85. package/src/internal/plate-editor/editor/plugins/docx-export-kit.tsx +43 -0
  86. package/src/internal/plate-editor/editor/plugins/docx-kit.tsx +6 -0
  87. package/src/internal/plate-editor/editor/plugins/emoji-kit.tsx +15 -0
  88. package/src/internal/plate-editor/editor/plugins/exit-break-kit.tsx +12 -0
  89. package/src/internal/plate-editor/editor/plugins/floating-toolbar-kit.tsx +19 -0
  90. package/src/internal/plate-editor/editor/plugins/font-base-kit.tsx +36 -0
  91. package/src/internal/plate-editor/editor/plugins/font-kit.tsx +47 -0
  92. package/src/internal/plate-editor/editor/plugins/indent-base-kit.tsx +19 -0
  93. package/src/internal/plate-editor/editor/plugins/indent-kit.tsx +22 -0
  94. package/src/internal/plate-editor/editor/plugins/link-base-kit.tsx +5 -0
  95. package/src/internal/plate-editor/editor/plugins/link-kit.tsx +35 -0
  96. package/src/internal/plate-editor/editor/plugins/list-base-kit.tsx +24 -0
  97. package/src/internal/plate-editor/editor/plugins/list-kit.tsx +27 -0
  98. package/src/internal/plate-editor/editor/plugins/markdown-kit.tsx +18 -0
  99. package/src/internal/plate-editor/editor/plugins/math-base-kit.tsx +8 -0
  100. package/src/internal/plate-editor/editor/plugins/math-kit.tsx +10 -0
  101. package/src/internal/plate-editor/editor/plugins/media-base-kit.tsx +37 -0
  102. package/src/internal/plate-editor/editor/plugins/media-kit.tsx +53 -0
  103. package/src/internal/plate-editor/editor/plugins/mention-base-kit.tsx +5 -0
  104. package/src/internal/plate-editor/editor/plugins/mention-kit.tsx +36 -0
  105. package/src/internal/plate-editor/editor/plugins/slash-kit.tsx +17 -0
  106. package/src/internal/plate-editor/editor/plugins/suggestion-base-kit.tsx +5 -0
  107. package/src/internal/plate-editor/editor/plugins/suggestion-kit.tsx +95 -0
  108. package/src/internal/plate-editor/editor/plugins/table-base-kit.tsx +20 -0
  109. package/src/internal/plate-editor/editor/plugins/table-kit.tsx +22 -0
  110. package/src/internal/plate-editor/editor/plugins/toc-base-kit.tsx +5 -0
  111. package/src/internal/plate-editor/editor/plugins/toc-kit.tsx +14 -0
  112. package/src/internal/plate-editor/editor/plugins/toggle-base-kit.tsx +5 -0
  113. package/src/internal/plate-editor/editor/plugins/toggle-kit.tsx +9 -0
  114. package/src/internal/plate-editor/editor/transforms.ts +165 -0
  115. package/src/internal/plate-editor/editor/use-chat.ts +152 -0
  116. package/src/internal/plate-editor/hooks/index.ts +3 -0
  117. package/src/internal/plate-editor/hooks/use-copy-to-clipboard.ts +31 -0
  118. package/src/internal/plate-editor/hooks/use-is-touch-device.ts +26 -0
  119. package/src/internal/plate-editor/hooks/use-lock-scroll.ts +21 -0
  120. package/src/internal/plate-editor/hooks/use-media-query.ts +44 -0
  121. package/src/internal/plate-editor/hooks/use-mounted.ts +18 -0
  122. package/src/internal/plate-editor/hooks/use-on-click-outside.ts +114 -0
  123. package/src/internal/plate-editor/hooks/use-upload-file.ts +81 -0
  124. package/src/internal/plate-editor/i18n/context.tsx +58 -0
  125. package/src/internal/plate-editor/i18n/index.ts +3 -0
  126. package/src/internal/plate-editor/i18n/locales/de.json +57 -0
  127. package/src/internal/plate-editor/i18n/locales/el.json +57 -0
  128. package/src/internal/plate-editor/i18n/locales/en.json +57 -0
  129. package/src/internal/plate-editor/i18n/locales/es.json +57 -0
  130. package/src/internal/plate-editor/i18n/locales/fr.json +57 -0
  131. package/src/internal/plate-editor/i18n/locales/it.json +57 -0
  132. package/src/internal/plate-editor/i18n/locales/pt.json +57 -0
  133. package/src/internal/plate-editor/i18n/locales/sl.json +57 -0
  134. package/src/internal/plate-editor/i18n/locales/tr.json +57 -0
  135. package/src/internal/plate-editor/i18n/types.ts +59 -0
  136. package/src/internal/plate-editor/i18n/use-translation.ts +22 -0
  137. package/src/internal/plate-editor/index.ts +39 -0
  138. package/src/internal/plate-editor/lib/ai-output-converter.ts +153 -0
  139. package/src/internal/plate-editor/lib/download-file.ts +17 -0
  140. package/src/internal/plate-editor/plate-ui/ai-chat-editor.tsx +26 -0
  141. package/src/internal/plate-editor/plate-ui/ai-menu.tsx +828 -0
  142. package/src/internal/plate-editor/plate-ui/ai-node.tsx +41 -0
  143. package/src/internal/plate-editor/plate-ui/ai-toolbar-button.tsx +27 -0
  144. package/src/internal/plate-editor/plate-ui/alert-dialog.tsx +147 -0
  145. package/src/internal/plate-editor/plate-ui/align-toolbar-button.tsx +90 -0
  146. package/src/internal/plate-editor/plate-ui/avatar.tsx +3 -0
  147. package/src/internal/plate-editor/plate-ui/block-context-menu.tsx +106 -0
  148. package/src/internal/plate-editor/plate-ui/block-discussion.tsx +364 -0
  149. package/src/internal/plate-editor/plate-ui/block-draggable.tsx +556 -0
  150. package/src/internal/plate-editor/plate-ui/block-list-static.tsx +78 -0
  151. package/src/internal/plate-editor/plate-ui/block-list.tsx +85 -0
  152. package/src/internal/plate-editor/plate-ui/block-menu.tsx +557 -0
  153. package/src/internal/plate-editor/plate-ui/block-selection.tsx +47 -0
  154. package/src/internal/plate-editor/plate-ui/block-suggestion.tsx +469 -0
  155. package/src/internal/plate-editor/plate-ui/blockquote-node-static.tsx +10 -0
  156. package/src/internal/plate-editor/plate-ui/blockquote-node.tsx +11 -0
  157. package/src/internal/plate-editor/plate-ui/button.tsx +190 -0
  158. package/src/internal/plate-editor/plate-ui/calendar.tsx +3 -0
  159. package/src/internal/plate-editor/plate-ui/callout-node-static.tsx +76 -0
  160. package/src/internal/plate-editor/plate-ui/callout-node.tsx +54 -0
  161. package/src/internal/plate-editor/plate-ui/caption.tsx +48 -0
  162. package/src/internal/plate-editor/plate-ui/checkbox.tsx +3 -0
  163. package/src/internal/plate-editor/plate-ui/code-block-node-static.tsx +172 -0
  164. package/src/internal/plate-editor/plate-ui/code-block-node.tsx +228 -0
  165. package/src/internal/plate-editor/plate-ui/code-node-static.tsx +11 -0
  166. package/src/internal/plate-editor/plate-ui/code-node.tsx +12 -0
  167. package/src/internal/plate-editor/plate-ui/column-node-static.tsx +65 -0
  168. package/src/internal/plate-editor/plate-ui/column-node.tsx +24 -0
  169. package/src/internal/plate-editor/plate-ui/command.tsx +204 -0
  170. package/src/internal/plate-editor/plate-ui/comment-node-static.tsx +12 -0
  171. package/src/internal/plate-editor/plate-ui/comment-node.tsx +45 -0
  172. package/src/internal/plate-editor/plate-ui/comment-toolbar-button.tsx +24 -0
  173. package/src/internal/plate-editor/plate-ui/comment.tsx +619 -0
  174. package/src/internal/plate-editor/plate-ui/cursor-overlay.tsx +85 -0
  175. package/src/internal/plate-editor/plate-ui/date-node-static.tsx +43 -0
  176. package/src/internal/plate-editor/plate-ui/date-node.tsx +56 -0
  177. package/src/internal/plate-editor/plate-ui/dialog.tsx +426 -0
  178. package/src/internal/plate-editor/plate-ui/dropdown-menu.tsx +266 -0
  179. package/src/internal/plate-editor/plate-ui/editor-static.tsx +40 -0
  180. package/src/internal/plate-editor/plate-ui/editor.tsx +148 -0
  181. package/src/internal/plate-editor/plate-ui/emoji-node.tsx +48 -0
  182. package/src/internal/plate-editor/plate-ui/emoji-toolbar-button.tsx +626 -0
  183. package/src/internal/plate-editor/plate-ui/equation-node-static.tsx +155 -0
  184. package/src/internal/plate-editor/plate-ui/equation-node.tsx +226 -0
  185. package/src/internal/plate-editor/plate-ui/equation-toolbar-button.tsx +26 -0
  186. package/src/internal/plate-editor/plate-ui/export-toolbar-button.tsx +208 -0
  187. package/src/internal/plate-editor/plate-ui/fixed-toolbar-buttons.tsx +157 -0
  188. package/src/internal/plate-editor/plate-ui/fixed-toolbar.tsx +27 -0
  189. package/src/internal/plate-editor/plate-ui/floating-discussion.tsx +1129 -0
  190. package/src/internal/plate-editor/plate-ui/floating-toolbar-buttons.tsx +129 -0
  191. package/src/internal/plate-editor/plate-ui/floating-toolbar.tsx +99 -0
  192. package/src/internal/plate-editor/plate-ui/font-color-toolbar-button.tsx +211 -0
  193. package/src/internal/plate-editor/plate-ui/font-size-toolbar-button.tsx +154 -0
  194. package/src/internal/plate-editor/plate-ui/ghost-text.tsx +20 -0
  195. package/src/internal/plate-editor/plate-ui/heading-node-static.tsx +52 -0
  196. package/src/internal/plate-editor/plate-ui/heading-node.tsx +56 -0
  197. package/src/internal/plate-editor/plate-ui/highlight-node-static.tsx +9 -0
  198. package/src/internal/plate-editor/plate-ui/highlight-node.tsx +11 -0
  199. package/src/internal/plate-editor/plate-ui/history-toolbar-button.tsx +52 -0
  200. package/src/internal/plate-editor/plate-ui/hover-card.tsx +7 -0
  201. package/src/internal/plate-editor/plate-ui/hr-node-static.tsx +18 -0
  202. package/src/internal/plate-editor/plate-ui/hr-node.tsx +28 -0
  203. package/src/internal/plate-editor/plate-ui/import-toolbar-button.tsx +124 -0
  204. package/src/internal/plate-editor/plate-ui/indent-toolbar-button.tsx +34 -0
  205. package/src/internal/plate-editor/plate-ui/inline-combobox.tsx +409 -0
  206. package/src/internal/plate-editor/plate-ui/input.tsx +39 -0
  207. package/src/internal/plate-editor/plate-ui/insert-toolbar-button.tsx +260 -0
  208. package/src/internal/plate-editor/plate-ui/label.tsx +1 -0
  209. package/src/internal/plate-editor/plate-ui/line-height-toolbar-button.tsx +71 -0
  210. package/src/internal/plate-editor/plate-ui/link-node-static.tsx +15 -0
  211. package/src/internal/plate-editor/plate-ui/link-node.tsx +33 -0
  212. package/src/internal/plate-editor/plate-ui/link-toolbar-button.tsx +30 -0
  213. package/src/internal/plate-editor/plate-ui/link-toolbar.tsx +149 -0
  214. package/src/internal/plate-editor/plate-ui/list-toolbar-button.tsx +179 -0
  215. package/src/internal/plate-editor/plate-ui/mark-toolbar-button.tsx +36 -0
  216. package/src/internal/plate-editor/plate-ui/media-audio-node-static.tsx +21 -0
  217. package/src/internal/plate-editor/plate-ui/media-audio-node.tsx +32 -0
  218. package/src/internal/plate-editor/plate-ui/media-embed-node.tsx +103 -0
  219. package/src/internal/plate-editor/plate-ui/media-file-node-static.tsx +30 -0
  220. package/src/internal/plate-editor/plate-ui/media-file-node.tsx +52 -0
  221. package/src/internal/plate-editor/plate-ui/media-image-node-static.tsx +37 -0
  222. package/src/internal/plate-editor/plate-ui/media-image-node.tsx +183 -0
  223. package/src/internal/plate-editor/plate-ui/media-placeholder-node.tsx +441 -0
  224. package/src/internal/plate-editor/plate-ui/media-preview-dialog.tsx +127 -0
  225. package/src/internal/plate-editor/plate-ui/media-toolbar-button.tsx +229 -0
  226. package/src/internal/plate-editor/plate-ui/media-toolbar.tsx +216 -0
  227. package/src/internal/plate-editor/plate-ui/media-upload-toast.tsx +73 -0
  228. package/src/internal/plate-editor/plate-ui/media-video-node-static.tsx +35 -0
  229. package/src/internal/plate-editor/plate-ui/media-video-node.tsx +119 -0
  230. package/src/internal/plate-editor/plate-ui/mention-node-static.tsx +46 -0
  231. package/src/internal/plate-editor/plate-ui/mention-node.tsx +79 -0
  232. package/src/internal/plate-editor/plate-ui/menu.tsx +532 -0
  233. package/src/internal/plate-editor/plate-ui/mode-toolbar-button.tsx +126 -0
  234. package/src/internal/plate-editor/plate-ui/more-toolbar-button.tsx +34 -0
  235. package/src/internal/plate-editor/plate-ui/paragraph-node-static.tsx +15 -0
  236. package/src/internal/plate-editor/plate-ui/paragraph-node.tsx +16 -0
  237. package/src/internal/plate-editor/plate-ui/popover.tsx +77 -0
  238. package/src/internal/plate-editor/plate-ui/progress.tsx +1 -0
  239. package/src/internal/plate-editor/plate-ui/remote-cursor-overlay.tsx +81 -0
  240. package/src/internal/plate-editor/plate-ui/resize-handle.tsx +88 -0
  241. package/src/internal/plate-editor/plate-ui/separator.tsx +43 -0
  242. package/src/internal/plate-editor/plate-ui/slash-node.tsx +435 -0
  243. package/src/internal/plate-editor/plate-ui/spinner.tsx +1 -0
  244. package/src/internal/plate-editor/plate-ui/suggestion-node-static.tsx +35 -0
  245. package/src/internal/plate-editor/plate-ui/suggestion-node.tsx +168 -0
  246. package/src/internal/plate-editor/plate-ui/suggestion-toolbar-button.tsx +24 -0
  247. package/src/internal/plate-editor/plate-ui/table-node-static.tsx +85 -0
  248. package/src/internal/plate-editor/plate-ui/table-node.tsx +285 -0
  249. package/src/internal/plate-editor/plate-ui/table-toolbar-button.tsx +254 -0
  250. package/src/internal/plate-editor/plate-ui/tabs.tsx +3 -0
  251. package/src/internal/plate-editor/plate-ui/textarea.tsx +58 -0
  252. package/src/internal/plate-editor/plate-ui/toc-node-static.tsx +142 -0
  253. package/src/internal/plate-editor/plate-ui/toc-node.tsx +57 -0
  254. package/src/internal/plate-editor/plate-ui/toc-sidebar.tsx +50 -0
  255. package/src/internal/plate-editor/plate-ui/toggle-node-static.tsx +18 -0
  256. package/src/internal/plate-editor/plate-ui/toggle-node.tsx +33 -0
  257. package/src/internal/plate-editor/plate-ui/toggle-toolbar-button.tsx +26 -0
  258. package/src/internal/plate-editor/plate-ui/toggle.tsx +3 -0
  259. package/src/internal/plate-editor/plate-ui/toolbar.tsx +380 -0
  260. package/src/internal/plate-editor/plate-ui/tooltip.tsx +149 -0
  261. package/src/internal/plate-editor/plate-ui/turn-into-toolbar-button.tsx +177 -0
  262. package/src/internal/plate-editor/types/index.ts +22 -0
  263. package/src/internal/plate-editor/vite.ts +284 -0
  264. package/src/internal/sheets/components/univer-sheets.tsx +1104 -0
  265. package/src/internal/sheets/i18n/context.tsx +183 -0
  266. package/src/internal/sheets/i18n/index.ts +19 -0
  267. package/src/internal/sheets/i18n/locales/de.json +21 -0
  268. package/src/internal/sheets/i18n/locales/el.json +21 -0
  269. package/src/internal/sheets/i18n/locales/en.json +21 -0
  270. package/src/internal/sheets/i18n/locales/es.json +21 -0
  271. package/src/internal/sheets/i18n/locales/fr.json +21 -0
  272. package/src/internal/sheets/i18n/locales/it.json +21 -0
  273. package/src/internal/sheets/i18n/locales/pt.json +21 -0
  274. package/src/internal/sheets/i18n/locales/sl.json +21 -0
  275. package/src/internal/sheets/i18n/locales/tr.json +21 -0
  276. package/src/internal/sheets/i18n/types.ts +23 -0
  277. package/src/internal/sheets/i18n/use-translation.ts +17 -0
  278. package/src/internal/sheets/index.ts +14 -0
  279. package/src/internal/sheets/types/css.d.ts +11 -0
  280. package/src/internal/sheets/types/index.ts +260 -0
  281. package/src/internal/sheets/xlsx.ts +1169 -0
  282. package/src/lib/api-client.ts +77 -0
  283. package/src/lib/assistant-api-actions.ts +549 -0
  284. package/src/lib/assistant-config.tsx +71 -0
  285. package/src/lib/class-utils.ts +40 -0
  286. package/src/lib/index.ts +7 -0
  287. package/src/lib/message-utils.ts +131 -0
  288. package/src/tools/tools-schema.json +512 -0
  289. package/src/types/index.ts +235 -0
  290. package/src/views/assistant-view.tsx +1137 -0
  291. package/src/views/canvas-app.tsx +839 -0
  292. package/src/views/canvas-code.tsx +93 -0
  293. package/src/views/canvas-deep-research.tsx +44 -0
  294. package/src/views/canvas-image.tsx +25 -0
  295. package/src/views/canvas-record-view.tsx +285 -0
  296. package/src/views/canvas-spreadsheet.tsx +125 -0
  297. package/src/views/canvas-text.tsx +52 -0
  298. package/src/views/canvas.tsx +274 -0
  299. package/src/views/chat-panel.tsx +149 -0
  300. package/src/views/index.ts +20 -0
  301. package/src/views/memories-panel.tsx +365 -0
  302. package/src/views/message-list.tsx +370 -0
  303. package/src/views/project-detail.tsx +257 -0
  304. package/src/views/projects-panel.tsx +131 -0
  305. package/src/views/sessions-list.tsx +98 -0
  306. package/src/views/sidebar-content.tsx +256 -0
  307. package/src/views/work-detail.tsx +98 -0
  308. package/src/vite.ts +284 -0
@@ -0,0 +1,1104 @@
1
+ // Univer Plugin Mode imports - Core
2
+ import {
3
+ useCallback, useEffect, useRef, useState, type ChangeEvent
4
+ } from 'react';
5
+
6
+ import {
7
+ CommandType,
8
+ ICommandService,
9
+ LocaleType,
10
+ Univer,
11
+ UniverInstanceType,
12
+ type ICommand
13
+ } from '@univerjs/core';
14
+ import { defaultTheme } from '@univerjs/design';
15
+ // ==== LOCALE IMPORTS - English (en-US) ====
16
+ import DesignEnUS from '@univerjs/design/locale/en-US';
17
+ // ==== LOCALE IMPORTS - Spanish (es-ES) ====
18
+ import DesignEsES from '@univerjs/design/locale/es-ES';
19
+ // ==== LOCALE IMPORTS - French (fr-FR) ====
20
+ import DesignFrFR from '@univerjs/design/locale/fr-FR';
21
+ import { UniverDocsPlugin } from '@univerjs/docs';
22
+ import { UniverDocsUIPlugin } from '@univerjs/docs-ui';
23
+ import DocsUIEnUS from '@univerjs/docs-ui/locale/en-US';
24
+ import DocsUIEsES from '@univerjs/docs-ui/locale/es-ES';
25
+ import DocsUIFrFR from '@univerjs/docs-ui/locale/fr-FR';
26
+ // Drawing plugins (required for images)
27
+ import { UniverDrawingPlugin } from '@univerjs/drawing';
28
+ import { UniverDrawingUIPlugin } from '@univerjs/drawing-ui';
29
+ import DrawingUIEnUS from '@univerjs/drawing-ui/locale/en-US';
30
+ import DrawingUIEsES from '@univerjs/drawing-ui/locale/es-ES';
31
+ import DrawingUIFrFR from '@univerjs/drawing-ui/locale/fr-FR';
32
+ import { UniverFormulaEnginePlugin } from '@univerjs/engine-formula';
33
+ import { UniverRenderEnginePlugin } from '@univerjs/engine-render';
34
+ // Find & Replace plugin
35
+ import FindReplaceEnUS from '@univerjs/find-replace/locale/en-US';
36
+ import FindReplaceEsES from '@univerjs/find-replace/locale/es-ES';
37
+ import FindReplaceFrFR from '@univerjs/find-replace/locale/fr-FR';
38
+ import { UniverSheetsPlugin } from '@univerjs/sheets';
39
+ import SheetsEnUS from '@univerjs/sheets/locale/en-US';
40
+ import SheetsEsES from '@univerjs/sheets/locale/es-ES';
41
+ import SheetsFrFR from '@univerjs/sheets/locale/fr-FR';
42
+ // Conditional Formatting plugins
43
+ import { UniverSheetsConditionalFormattingPlugin } from '@univerjs/sheets-conditional-formatting';
44
+ import { UniverSheetsConditionalFormattingUIPlugin } from '@univerjs/sheets-conditional-formatting-ui';
45
+ import SheetsConditionalFormattingUIEnUS from '@univerjs/sheets-conditional-formatting-ui/locale/en-US';
46
+ import SheetsConditionalFormattingUIEsES from '@univerjs/sheets-conditional-formatting-ui/locale/es-ES';
47
+ import SheetsConditionalFormattingUIFrFR from '@univerjs/sheets-conditional-formatting-ui/locale/fr-FR';
48
+ // Crosshair Highlight plugin
49
+ import { UniverSheetsCrosshairHighlightPlugin } from '@univerjs/sheets-crosshair-highlight';
50
+ import SheetsCrosshairHighlightEnUS from '@univerjs/sheets-crosshair-highlight/locale/en-US';
51
+ import SheetsCrosshairHighlightEsES from '@univerjs/sheets-crosshair-highlight/locale/es-ES';
52
+ import SheetsCrosshairHighlightFrFR from '@univerjs/sheets-crosshair-highlight/locale/fr-FR';
53
+ // Data Validation plugins
54
+ import { UniverSheetsDataValidationPlugin } from '@univerjs/sheets-data-validation';
55
+ import { UniverSheetsDataValidationUIPlugin } from '@univerjs/sheets-data-validation-ui';
56
+ import SheetsDataValidationUIEnUS from '@univerjs/sheets-data-validation-ui/locale/en-US';
57
+ import SheetsDataValidationUIEsES from '@univerjs/sheets-data-validation-ui/locale/es-ES';
58
+ import SheetsDataValidationUIFrFR from '@univerjs/sheets-data-validation-ui/locale/fr-FR';
59
+ import { UniverSheetsDrawingPlugin } from '@univerjs/sheets-drawing';
60
+ import { UniverSheetsDrawingUIPlugin } from '@univerjs/sheets-drawing-ui';
61
+ import SheetsDrawingUIEnUS from '@univerjs/sheets-drawing-ui/locale/en-US';
62
+ import SheetsDrawingUIEsES from '@univerjs/sheets-drawing-ui/locale/es-ES';
63
+ import SheetsDrawingUIFrFR from '@univerjs/sheets-drawing-ui/locale/fr-FR';
64
+ // Filter plugins
65
+ import { UniverSheetsFilterPlugin } from '@univerjs/sheets-filter';
66
+ import { UniverSheetsFilterUIPlugin } from '@univerjs/sheets-filter-ui';
67
+ import SheetsFilterUIEnUS from '@univerjs/sheets-filter-ui/locale/en-US';
68
+ import SheetsFilterUIEsES from '@univerjs/sheets-filter-ui/locale/es-ES';
69
+ import SheetsFilterUIFrFR from '@univerjs/sheets-filter-ui/locale/fr-FR';
70
+ import { UniverSheetsFindReplacePlugin } from '@univerjs/sheets-find-replace';
71
+ import SheetsFindReplaceEnUS from '@univerjs/sheets-find-replace/locale/en-US';
72
+ import SheetsFindReplaceEsES from '@univerjs/sheets-find-replace/locale/es-ES';
73
+ import SheetsFindReplaceFrFR from '@univerjs/sheets-find-replace/locale/fr-FR';
74
+ import { UniverSheetsFormulaPlugin } from '@univerjs/sheets-formula';
75
+ import { UniverSheetsFormulaUIPlugin } from '@univerjs/sheets-formula-ui';
76
+ import SheetsFormulaUIEnUS from '@univerjs/sheets-formula-ui/locale/en-US';
77
+ import SheetsFormulaUIEsES from '@univerjs/sheets-formula-ui/locale/es-ES';
78
+ import SheetsFormulaUIFrFR from '@univerjs/sheets-formula-ui/locale/fr-FR';
79
+ // Hyperlink plugins
80
+ import { UniverSheetsHyperLinkPlugin } from '@univerjs/sheets-hyper-link';
81
+ import { UniverSheetsHyperLinkUIPlugin } from '@univerjs/sheets-hyper-link-ui';
82
+ import SheetsHyperLinkUIEnUS from '@univerjs/sheets-hyper-link-ui/locale/en-US';
83
+ import SheetsHyperLinkUIEsES from '@univerjs/sheets-hyper-link-ui/locale/es-ES';
84
+ import SheetsHyperLinkUIFrFR from '@univerjs/sheets-hyper-link-ui/locale/fr-FR';
85
+ import { UniverSheetsNumfmtPlugin } from '@univerjs/sheets-numfmt';
86
+ import { UniverSheetsNumfmtUIPlugin } from '@univerjs/sheets-numfmt-ui';
87
+ import SheetsNumfmtUIEnUS from '@univerjs/sheets-numfmt-ui/locale/en-US';
88
+ import SheetsNumfmtUIEsES from '@univerjs/sheets-numfmt-ui/locale/es-ES';
89
+ import SheetsNumfmtUIFrFR from '@univerjs/sheets-numfmt-ui/locale/fr-FR';
90
+ // Sort plugins
91
+ import { UniverSheetsSortPlugin } from '@univerjs/sheets-sort';
92
+ import { UniverSheetsSortUIPlugin } from '@univerjs/sheets-sort-ui';
93
+ import SheetsSortUIEnUS from '@univerjs/sheets-sort-ui/locale/en-US';
94
+ import SheetsSortUIEsES from '@univerjs/sheets-sort-ui/locale/es-ES';
95
+ import SheetsSortUIFrFR from '@univerjs/sheets-sort-ui/locale/fr-FR';
96
+ // Thread Comment plugins
97
+ import { UniverSheetsThreadCommentPlugin } from '@univerjs/sheets-thread-comment';
98
+ import { UniverSheetsThreadCommentUIPlugin } from '@univerjs/sheets-thread-comment-ui';
99
+ import SheetsThreadCommentUIEnUS from '@univerjs/sheets-thread-comment-ui/locale/en-US';
100
+ import SheetsThreadCommentUIEsES from '@univerjs/sheets-thread-comment-ui/locale/es-ES';
101
+ import SheetsThreadCommentUIFrFR from '@univerjs/sheets-thread-comment-ui/locale/fr-FR';
102
+ import { UniverSheetsUIPlugin } from '@univerjs/sheets-ui';
103
+ import SheetsUIEnUS from '@univerjs/sheets-ui/locale/en-US';
104
+ import SheetsUIEsES from '@univerjs/sheets-ui/locale/es-ES';
105
+ import SheetsUIFrFR from '@univerjs/sheets-ui/locale/fr-FR';
106
+ import ThreadCommentUIEnUS from '@univerjs/thread-comment-ui/locale/en-US';
107
+ import ThreadCommentUIEsES from '@univerjs/thread-comment-ui/locale/es-ES';
108
+ import ThreadCommentUIFrFR from '@univerjs/thread-comment-ui/locale/fr-FR';
109
+ import {
110
+ ComponentManager,
111
+ IMenuManagerService,
112
+ MenuItemType,
113
+ RibbonStartGroup,
114
+ UniverUIPlugin,
115
+ type IFontConfig
116
+ } from '@univerjs/ui';
117
+ import UIEnUS from '@univerjs/ui/locale/en-US';
118
+ import UIEsES from '@univerjs/ui/locale/es-ES';
119
+ import UIFrFR from '@univerjs/ui/locale/fr-FR';
120
+ // Watermark plugin
121
+ import { UniverWatermarkPlugin } from '@univerjs/watermark';
122
+ import { FUniver } from '@univerjs/core/facade';
123
+
124
+ // Facade API imports - Core
125
+ import '@univerjs/sheets/facade';
126
+ import '@univerjs/sheets-ui/facade';
127
+ import '@univerjs/sheets-numfmt/facade';
128
+
129
+ // Facade API imports - Feature plugins
130
+ import '@univerjs/sheets-data-validation/facade';
131
+ import '@univerjs/sheets-conditional-formatting/facade';
132
+ import '@univerjs/sheets-filter/facade';
133
+ import '@univerjs/sheets-sort/facade';
134
+ import '@univerjs/sheets-hyper-link/facade';
135
+ import '@univerjs/sheets-find-replace/facade';
136
+ import '@univerjs/sheets-thread-comment/facade';
137
+ import '@univerjs/sheets-drawing-ui/facade';
138
+ import '@univerjs/watermark/facade';
139
+ import '@univerjs/sheets-crosshair-highlight/facade';
140
+ // CSS imports - order matters!
141
+ import '@univerjs/design/lib/index.css';
142
+ import '@univerjs/ui/lib/index.css';
143
+ import '@univerjs/docs-ui/lib/index.css';
144
+ import '@univerjs/sheets-ui/lib/index.css';
145
+ import '@univerjs/sheets-formula-ui/lib/index.css';
146
+ import '@univerjs/sheets-numfmt-ui/lib/index.css';
147
+
148
+ // CSS imports - Feature plugins
149
+ import '@univerjs/drawing-ui/lib/index.css';
150
+ import '@univerjs/sheets-drawing-ui/lib/index.css';
151
+ import '@univerjs/sheets-data-validation-ui/lib/index.css';
152
+ import '@univerjs/sheets-conditional-formatting-ui/lib/index.css';
153
+ import '@univerjs/sheets-filter-ui/lib/index.css';
154
+ import '@univerjs/sheets-sort-ui/lib/index.css';
155
+ import '@univerjs/sheets-hyper-link-ui/lib/index.css';
156
+ import '@univerjs/sheets-thread-comment-ui/lib/index.css';
157
+ import '@univerjs/sheets-crosshair-highlight/lib/index.css';
158
+
159
+ import { type Locale } from '../i18n/types';
160
+
161
+ import { type IWorkbookData as XlsxWorkbookData } from '../types';
162
+
163
+ import { csvToUniver, downloadWorkbook, xlsxToUniver } from '../xlsx';
164
+
165
+ // Custom font list - only common fonts, excluding Chinese-specific fonts
166
+ const CUSTOM_FONT_LIST: IFontConfig[] = [
167
+ { value: 'Arial', label: 'fontFamily.arial', category: 'sans-serif' },
168
+ { value: 'Times New Roman', label: 'fontFamily.times-new-roman', category: 'serif' },
169
+ { value: 'Tahoma', label: 'fontFamily.tahoma', category: 'sans-serif' },
170
+ { value: 'Verdana', label: 'fontFamily.verdana', category: 'sans-serif' },
171
+ { value: 'Georgia', label: 'fontFamily.georgia', category: 'serif' },
172
+ { value: 'Courier New', label: 'fontFamily.courier-new', category: 'monospace' },
173
+ { value: 'Trebuchet MS', label: 'fontFamily.trebuchet-ms', category: 'sans-serif' },
174
+ { value: 'Comic Sans MS', label: 'fontFamily.comic-sans-ms', category: 'handwriting' }
175
+ ];
176
+
177
+ // Deep merge utility for locale objects
178
+ function deepMerge(...objects: unknown[]): Record<string, unknown> {
179
+ const result: Record<string, unknown> = {};
180
+
181
+ for (const obj of objects) {
182
+ if (obj && typeof obj === 'object') {
183
+ for (const key of Object.keys(obj)) {
184
+ const value = (obj as Record<string, unknown>)[key];
185
+
186
+ if (
187
+ typeof value === 'object'
188
+ && value !== null
189
+ && !Array.isArray(value)
190
+ && typeof result[key] === 'object'
191
+ && result[key] !== null
192
+ && !Array.isArray(result[key])
193
+ ) {
194
+ result[key] = deepMerge(result[key] as Record<string, unknown>, value as Record<string, unknown>);
195
+ } else {
196
+ result[key] = value;
197
+ }
198
+ }
199
+ }
200
+ }
201
+
202
+ return result;
203
+ }
204
+
205
+ // Additional font family translations for custom fonts not in Univer defaults
206
+ const CUSTOM_FONT_TRANSLATIONS = {
207
+ fontFamily: {
208
+ georgia: 'Georgia',
209
+ 'courier-new': 'Courier New',
210
+ 'trebuchet-ms': 'Trebuchet MS',
211
+ 'comic-sans-ms': 'Comic Sans MS'
212
+ }
213
+ };
214
+
215
+ // Pre-merged locale data for each supported Univer locale
216
+ const UNIVER_LOCALES = {
217
+ 'en-US': deepMerge(
218
+ DesignEnUS,
219
+ UIEnUS,
220
+ DocsUIEnUS,
221
+ SheetsEnUS,
222
+ SheetsUIEnUS,
223
+ SheetsFormulaUIEnUS,
224
+ SheetsNumfmtUIEnUS,
225
+ DrawingUIEnUS,
226
+ SheetsDrawingUIEnUS,
227
+ SheetsDataValidationUIEnUS,
228
+ SheetsConditionalFormattingUIEnUS,
229
+ SheetsFilterUIEnUS,
230
+ SheetsSortUIEnUS,
231
+ SheetsHyperLinkUIEnUS,
232
+ FindReplaceEnUS,
233
+ SheetsFindReplaceEnUS,
234
+ ThreadCommentUIEnUS,
235
+ SheetsThreadCommentUIEnUS,
236
+ SheetsCrosshairHighlightEnUS,
237
+ CUSTOM_FONT_TRANSLATIONS
238
+ ),
239
+ 'es-ES': deepMerge(
240
+ DesignEsES,
241
+ UIEsES,
242
+ DocsUIEsES,
243
+ SheetsEsES,
244
+ SheetsUIEsES,
245
+ SheetsFormulaUIEsES,
246
+ SheetsNumfmtUIEsES,
247
+ DrawingUIEsES,
248
+ SheetsDrawingUIEsES,
249
+ SheetsDataValidationUIEsES,
250
+ SheetsConditionalFormattingUIEsES,
251
+ SheetsFilterUIEsES,
252
+ SheetsSortUIEsES,
253
+ SheetsHyperLinkUIEsES,
254
+ FindReplaceEsES,
255
+ SheetsFindReplaceEsES,
256
+ ThreadCommentUIEsES,
257
+ SheetsThreadCommentUIEsES,
258
+ SheetsCrosshairHighlightEsES,
259
+ CUSTOM_FONT_TRANSLATIONS
260
+ ),
261
+ 'fr-FR': deepMerge(
262
+ DesignFrFR,
263
+ UIFrFR,
264
+ DocsUIFrFR,
265
+ SheetsFrFR,
266
+ SheetsUIFrFR,
267
+ SheetsFormulaUIFrFR,
268
+ SheetsNumfmtUIFrFR,
269
+ DrawingUIFrFR,
270
+ SheetsDrawingUIFrFR,
271
+ SheetsDataValidationUIFrFR,
272
+ SheetsConditionalFormattingUIFrFR,
273
+ SheetsFilterUIFrFR,
274
+ SheetsSortUIFrFR,
275
+ SheetsHyperLinkUIFrFR,
276
+ FindReplaceFrFR,
277
+ SheetsFindReplaceFrFR,
278
+ ThreadCommentUIFrFR,
279
+ SheetsThreadCommentUIFrFR,
280
+ SheetsCrosshairHighlightFrFR,
281
+ CUSTOM_FONT_TRANSLATIONS
282
+ )
283
+ } as const;
284
+
285
+ type UniverLocaleCode = keyof typeof UNIVER_LOCALES;
286
+
287
+ // Map app locale to Univer locale
288
+ function getUniverLocale(appLocale: Locale): {
289
+ code: UniverLocaleCode;
290
+ type: LocaleType;
291
+ data: Record<string, unknown>;
292
+ } {
293
+ const mapping: Record<Locale, { code: UniverLocaleCode; type: LocaleType }> = {
294
+ en: { code: 'en-US', type: LocaleType.EN_US },
295
+ es: { code: 'es-ES', type: LocaleType.ES_ES },
296
+ fr: { code: 'fr-FR', type: LocaleType.FR_FR },
297
+ de: { code: 'en-US', type: LocaleType.EN_US }, // Fallback - German not supported by Univer
298
+ el: { code: 'en-US', type: LocaleType.EN_US }, // Fallback - Greek not supported by Univer
299
+ it: { code: 'en-US', type: LocaleType.EN_US }, // Fallback - Italian not supported by Univer
300
+ pt: { code: 'en-US', type: LocaleType.EN_US }, // Fallback - Portuguese not supported by Univer
301
+ sl: { code: 'en-US', type: LocaleType.EN_US }, // Fallback - Slovenian not supported by Univer
302
+ tr: { code: 'en-US', type: LocaleType.EN_US } // Fallback - Turkish not supported by Univer
303
+ };
304
+ const localeInfo = mapping[appLocale] || mapping.en;
305
+
306
+ return {
307
+ ...localeInfo,
308
+ data: UNIVER_LOCALES[localeInfo.code]
309
+ };
310
+ }
311
+
312
+ /**
313
+ * Map app locale to numfmt locale for decimal/thousands separator
314
+ * This affects how numbers are displayed (e.g., 1,234.56 vs 1.234,56)
315
+ */
316
+ function getNumfmtLocale(appLocale: Locale): string {
317
+ const mapping: Record<Locale, string> = {
318
+ en: 'en_US',
319
+ es: 'es_ES',
320
+ fr: 'fr_FR',
321
+ de: 'de_DE',
322
+ el: 'el_GR',
323
+ it: 'it_IT',
324
+ pt: 'pt_PT',
325
+ sl: 'sl_SI',
326
+ tr: 'tr_TR'
327
+ };
328
+
329
+ return mapping[appLocale] || 'en_US';
330
+ }
331
+
332
+ /*
333
+ * ============================================================================
334
+ * Import/Export Toolbar Setup
335
+ * ============================================================================
336
+ */
337
+
338
+ // Command IDs
339
+ const IMPORT_XLSX_COMMAND_ID = 'docyrus.sheets.import-xlsx';
340
+ const EXPORT_XLSX_COMMAND_ID = 'docyrus.sheets.export-xlsx';
341
+ const EXPORT_CSV_COMMAND_ID = 'docyrus.sheets.export-csv';
342
+
343
+ // Import/Export command handlers - will be set by the component
344
+ const importExportHandlers = {
345
+ import: null as (() => void) | null,
346
+ exportXlsx: null as (() => void) | null,
347
+ exportCsv: null as (() => void) | null
348
+ };
349
+
350
+ // Setup import/export toolbar buttons after Univer is initialized
351
+ function setupImportExportToolbar(univer: Univer): void {
352
+ const injector = (univer as any).__injector || (univer as any)._injector;
353
+
354
+ if (!injector) {
355
+ console.warn('[UniverSheets] Could not access injector for toolbar setup');
356
+
357
+ return;
358
+ }
359
+
360
+ try {
361
+ const commandService = injector.get(ICommandService);
362
+ const menuManagerService = injector.get(IMenuManagerService);
363
+ const componentManager = injector.get(ComponentManager);
364
+
365
+ // Register icons
366
+ componentManager.register('ImportIcon', () => (
367
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
368
+ <polyline points="17 8 12 3 7 8" />
369
+ <line x1="12" y1="3" x2="12" y2="15" />
370
+ <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" />
371
+ </svg>
372
+ ));
373
+
374
+ componentManager.register('ExportXlsxIcon', () => (
375
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#217346" strokeWidth="2">
376
+ <polyline points="7 10 12 15 17 10" />
377
+ <line x1="12" y1="15" x2="12" y2="3" />
378
+ <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" />
379
+ </svg>
380
+ ));
381
+
382
+ componentManager.register('ExportCsvIcon', () => (
383
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#666" strokeWidth="2">
384
+ <polyline points="7 10 12 15 17 10" />
385
+ <line x1="12" y1="15" x2="12" y2="3" />
386
+ <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" />
387
+ </svg>
388
+ ));
389
+
390
+ // Register commands
391
+ const importCommand: ICommand = {
392
+ id: IMPORT_XLSX_COMMAND_ID,
393
+ type: CommandType.COMMAND,
394
+ handler: async () => {
395
+ importExportHandlers.import?.();
396
+
397
+ return true;
398
+ }
399
+ };
400
+
401
+ const exportXlsxCommand: ICommand = {
402
+ id: EXPORT_XLSX_COMMAND_ID,
403
+ type: CommandType.COMMAND,
404
+ handler: async () => {
405
+ importExportHandlers.exportXlsx?.();
406
+
407
+ return true;
408
+ }
409
+ };
410
+
411
+ const exportCsvCommand: ICommand = {
412
+ id: EXPORT_CSV_COMMAND_ID,
413
+ type: CommandType.COMMAND,
414
+ handler: async () => {
415
+ importExportHandlers.exportCsv?.();
416
+
417
+ return true;
418
+ }
419
+ };
420
+
421
+ commandService.registerCommand(importCommand);
422
+ commandService.registerCommand(exportXlsxCommand);
423
+ commandService.registerCommand(exportCsvCommand);
424
+
425
+ // Add menu items to toolbar ribbon
426
+ menuManagerService.mergeMenu({
427
+ [RibbonStartGroup.OTHERS]: {
428
+ [IMPORT_XLSX_COMMAND_ID]: {
429
+ order: 0,
430
+ menuItemFactory: () => ({
431
+ id: IMPORT_XLSX_COMMAND_ID,
432
+ title: 'Import',
433
+ tooltip: 'Import XLSX/CSV',
434
+ icon: 'ImportIcon',
435
+ type: MenuItemType.BUTTON
436
+ })
437
+ },
438
+ [EXPORT_XLSX_COMMAND_ID]: {
439
+ order: 1,
440
+ menuItemFactory: () => ({
441
+ id: EXPORT_XLSX_COMMAND_ID,
442
+ title: 'XLSX',
443
+ tooltip: 'Export as XLSX',
444
+ icon: 'ExportXlsxIcon',
445
+ type: MenuItemType.BUTTON
446
+ })
447
+ },
448
+ [EXPORT_CSV_COMMAND_ID]: {
449
+ order: 2,
450
+ menuItemFactory: () => ({
451
+ id: EXPORT_CSV_COMMAND_ID,
452
+ title: 'CSV',
453
+ tooltip: 'Export as CSV',
454
+ icon: 'ExportCsvIcon',
455
+ type: MenuItemType.BUTTON
456
+ })
457
+ }
458
+ }
459
+ });
460
+
461
+ console.info('[UniverSheets] Import/Export toolbar buttons registered');
462
+ } catch (err) {
463
+ console.warn('[UniverSheets] Failed to setup import/export toolbar:', err);
464
+ }
465
+ }
466
+
467
+ // Type definitions
468
+ export interface SheetsPayload {
469
+ workbookData?: Record<string, unknown>;
470
+ user?: {
471
+ tenantId?: string;
472
+ name?: string;
473
+ };
474
+ recordId?: string;
475
+ versionId?: string;
476
+ }
477
+
478
+ export interface IApiCallPayload {
479
+ id?: string;
480
+ method: string;
481
+ args?: unknown[];
482
+ }
483
+
484
+ export interface UniverSheetsProps {
485
+ /** Initial workbook data to load */
486
+ initialData?: unknown;
487
+ /** Locale for UI translations (default: "en") */
488
+ locale?: Locale;
489
+ /** Commands to execute after the workbook loads */
490
+ commands?: IApiCallPayload[];
491
+ onReady?: () => void;
492
+ onData?: (data: { workbook: unknown; workbookJson: string }) => void;
493
+ onLoaded?: (data: { workbookId: string }) => void;
494
+ onError?: (error: string) => void;
495
+ }
496
+
497
+ const SAMPLE_WORKBOOK_DATA = {};
498
+
499
+ type RangeObj = any;
500
+ type SheetObj = any;
501
+
502
+ const RANGE_ACTIONS: Record<string, (r: RangeObj, a: unknown[]) => void> = {
503
+ setValue: (r, a) => r.setValue(a[0]),
504
+ setValues: (r, a) => r.setValues(a[0]),
505
+ getValue: r => r.getValue(),
506
+ getValues: r => r.getValues(),
507
+ setBackgroundColor: (r, a) => r.setBackgroundColor(a[0]),
508
+ setFontColor: (r, a) => r.setFontColor(a[0]),
509
+ setFontWeight: (r, a) => r.setFontWeight(a[0]),
510
+ setFontStyle: (r, a) => r.setFontStyle(a[0]),
511
+ setFontSize: (r, a) => r.setFontSize(a[0]),
512
+ setFontFamily: (r, a) => r.setFontFamily(a[0]),
513
+ setHorizontalAlignment: (r, a) => r.setHorizontalAlignment(a[0]),
514
+ setVerticalAlignment: (r, a) => r.setVerticalAlignment(a[0]),
515
+ setNumberFormat: (r, a) => r.setNumberFormat(a[0]),
516
+ setWrap: (r, a) => r.setWrap(a[0]),
517
+ setBorder: (r, a) => r.setBorder(a[0], a[1], a[2], a[3], a[4], a[5]),
518
+ setNote: (r, a) => r.setNote(a[0]),
519
+ getNote: r => r.getNote(),
520
+ clearNote: r => r.clearNote(),
521
+ merge: r => r.merge(),
522
+ unmerge: r => r.breakApart(),
523
+ clearFormat: r => r.clearFormat(),
524
+ clearContent: r => r.clearContent(),
525
+ clear: r => r.clear(),
526
+ activate: r => r.activate(),
527
+ isMerged: r => r.isMerged(),
528
+ copyTo: (r, a) => r.copyTo(a[0]),
529
+ sort: (r, a) => r.sort(a[0])
530
+ };
531
+
532
+ const SHEET_ACTIONS: Record<string, (s: SheetObj, a: unknown[]) => void> = {
533
+ insertRowsAfter: (s, a) => s.insertRowsAfter(a[0], a[1]),
534
+ insertRowsBefore: (s, a) => s.insertRowsBefore(a[0], a[1]),
535
+ deleteRows: (s, a) => s.deleteRows(a[0], a[1]),
536
+ insertColumnsAfter: (s, a) => s.insertColumnsAfter(a[0], a[1]),
537
+ insertColumnsBefore: (s, a) => s.insertColumnsBefore(a[0], a[1]),
538
+ deleteColumns: (s, a) => s.deleteColumns(a[0], a[1]),
539
+ setRowHeight: (s, a) => s.setRowHeight(a[0], a[1]),
540
+ setColumnWidth: (s, a) => s.setColumnWidth(a[0], a[1]),
541
+ setFrozenRows: (s, a) => s.setFrozenRows(a[0]),
542
+ setFrozenColumns: (s, a) => s.setFrozenColumns(a[0]),
543
+ setName: (s, a) => s.setName(a[0]),
544
+ activate: s => s.activate(),
545
+ hideRows: (s, a) => s.hideRows(a[0], a[1]),
546
+ showRows: (s, a) => s.showRows(a[0], a[1]),
547
+ hideColumns: (s, a) => s.hideColumns(a[0], a[1]),
548
+ showColumns: (s, a) => s.showColumns(a[0], a[1]),
549
+ zoom: (s, a) => s.zoom(a[0]),
550
+ getMaxRows: s => s.getMaxRows(),
551
+ getMaxColumns: s => s.getMaxColumns()
552
+ };
553
+
554
+ // Instance generation counter to handle React Strict Mode cleanup timing
555
+ let instanceGeneration = 0;
556
+
557
+ export function UniverSheets({
558
+ initialData,
559
+ locale = 'en',
560
+ commands,
561
+ onReady,
562
+ onData,
563
+ onLoaded,
564
+ onError: _onError
565
+ }: UniverSheetsProps) {
566
+ const containerRef = useRef<HTMLDivElement>(null);
567
+ const univerRef = useRef<Univer | null>(null);
568
+ const univerAPIRef = useRef<FUniver | null>(null);
569
+ const instanceGenerationRef = useRef<number>(0);
570
+ const pendingDataRef = useRef<unknown>(null);
571
+ const fileInputRef = useRef<HTMLInputElement>(null);
572
+ const workbookNameRef = useRef<string>('');
573
+ const [isClient, setIsClient] = useState(false);
574
+
575
+ // Store callbacks in refs to avoid effect re-runs when they change
576
+ const onReadyRef = useRef(onReady);
577
+ const onDataRef = useRef(onData);
578
+ const onLoadedRef = useRef(onLoaded);
579
+ // Store initial data in ref - only used on first load
580
+ const initialDataRef = useRef(initialData);
581
+ // Store commands in ref so they're accessible inside the initialization effect
582
+ const commandsRef = useRef(commands);
583
+ // True while the initial createUnit is pending its async doc.command-replace-snapshot
584
+ const isInitializingRef = useRef(false);
585
+ // Skip first-mount run of the commands effect (init effect already handles it)
586
+ const isCommandsInitialMountRef = useRef(true);
587
+
588
+ // Update refs when callbacks change
589
+ useEffect(() => {
590
+ onReadyRef.current = onReady;
591
+ onDataRef.current = onData;
592
+ onLoadedRef.current = onLoaded;
593
+ }, [onReady, onData, onLoaded]);
594
+
595
+ /*
596
+ * Execute an api:call payload directly against the Univer API.
597
+ * Method format: 'range:A1:setValue' | 'sheet:methodName' | 'undo' | 'redo'
598
+ */
599
+ const executeApiCommand = useCallback(async (payload: IApiCallPayload) => {
600
+ if (!univerAPIRef.current) {
601
+ console.warn('[Sheets] executeApiCommand called but Univer not ready:', payload.method);
602
+
603
+ return;
604
+ }
605
+
606
+ const { method, args = [] } = payload;
607
+ const parts = method.split(':');
608
+ const target = parts[0];
609
+ const action = parts[parts.length - 1];
610
+
611
+ try {
612
+ const workbook = univerAPIRef.current.getActiveWorkbook();
613
+ const sheet = workbook?.getActiveSheet();
614
+
615
+ if (target === 'undo') {
616
+ await univerAPIRef.current.executeCommand('univer.command.undo');
617
+ } else if (target === 'redo') {
618
+ await univerAPIRef.current.executeCommand('univer.command.redo');
619
+ } else if (target === 'range') {
620
+ if (!sheet) throw new Error('No active sheet');
621
+
622
+ const selector = parts.slice(1, -1).join(':');
623
+ const range = sheet.getRange(selector);
624
+ const fn = RANGE_ACTIONS[action];
625
+
626
+ if (fn) {
627
+ fn(range, args);
628
+ } else {
629
+ console.warn('[Sheets] Unknown range action:', action);
630
+ }
631
+ } else if (target === 'sheet') {
632
+ if (!sheet) throw new Error('No active sheet');
633
+
634
+ const fn = SHEET_ACTIONS[action];
635
+
636
+ if (fn) {
637
+ fn(sheet, args);
638
+ } else {
639
+ console.warn('[Sheets] Unknown sheet action:', action);
640
+ }
641
+ } else {
642
+ console.warn('[Sheets] Unknown api:call target:', target);
643
+ }
644
+ } catch (err) {
645
+ console.error('[Sheets] api:call failed:', method, err);
646
+ }
647
+ }, []);
648
+
649
+ /*
650
+ * Handle api:call postMessages from parent
651
+ * Format: { type: 'event', eventName: 'api:call', payload: { id, method, args } }
652
+ */
653
+ useEffect(() => {
654
+ const handleApiCall = (event: MessageEvent) => {
655
+ if (!event.data || typeof event.data !== 'object') return;
656
+
657
+ const { type, eventName, payload } = event.data;
658
+
659
+ if (type !== 'event' || eventName !== 'api:call' || !payload?.method) return;
660
+
661
+ void executeApiCommand(payload as IApiCallPayload);
662
+ };
663
+
664
+ window.addEventListener('message', handleApiCall);
665
+
666
+ return () => window.removeEventListener('message', handleApiCall);
667
+ }, [executeApiCommand]);
668
+
669
+ // Execute new commands whenever the commands prop changes after initial mount
670
+ useEffect(() => {
671
+ commandsRef.current = commands;
672
+
673
+ if (isCommandsInitialMountRef.current) {
674
+ isCommandsInitialMountRef.current = false;
675
+
676
+ return;
677
+ }
678
+
679
+ if (!commands?.length || !univerAPIRef.current) return;
680
+
681
+ for (const cmd of commands) {
682
+ void executeApiCommand(cmd);
683
+ }
684
+ }, [commands, executeApiCommand]);
685
+
686
+ // Handle file import
687
+ const handleImport = () => {
688
+ fileInputRef.current?.click();
689
+ };
690
+
691
+ const handleFileChange = async (e: ChangeEvent<HTMLInputElement>) => {
692
+ const file = e.target.files?.[0];
693
+
694
+ if (!file) return;
695
+
696
+ try {
697
+ const arrayBuffer = await file.arrayBuffer();
698
+ const bytes = new Uint8Array(arrayBuffer);
699
+ const filename = file.name.toLowerCase();
700
+ const isCSV = filename.endsWith('.csv');
701
+
702
+ let workbookData: XlsxWorkbookData;
703
+
704
+ const workbookName = file.name.replace(/\.[^.]+$/, '');
705
+
706
+ if (isCSV) {
707
+ const text = new TextDecoder().decode(bytes);
708
+
709
+ workbookData = csvToUniver(text, {
710
+ workbookName,
711
+ firstRowIsHeader: true
712
+ });
713
+ } else {
714
+ workbookData = xlsxToUniver(arrayBuffer, {
715
+ workbookName
716
+ });
717
+ }
718
+
719
+ // Track the workbook name for export
720
+ workbookNameRef.current = workbookName;
721
+
722
+ if (univerRef.current) {
723
+ univerRef.current.createUnit(UniverInstanceType.UNIVER_SHEET, workbookData as any);
724
+ }
725
+ } catch (err) {
726
+ console.error('Import error:', err);
727
+ }
728
+
729
+ e.target.value = '';
730
+ };
731
+
732
+ // Get workbook name for export (fallback to ref, sheet name, ID, or timestamp)
733
+ const getExportFileName = useCallback((workbookData: XlsxWorkbookData): string => {
734
+ // Use workbook name from data if available and not empty
735
+ if (workbookData.name && workbookData.name.trim()) {
736
+ return workbookData.name.trim();
737
+ }
738
+
739
+ // Fallback to tracked workbook name (from import or initial load)
740
+ if (workbookNameRef.current && workbookNameRef.current.trim()) {
741
+ return workbookNameRef.current.trim();
742
+ }
743
+
744
+ // Fallback to first sheet name
745
+ if (workbookData.sheets) {
746
+ const sheetOrder = workbookData.sheetOrder || Object.keys(workbookData.sheets);
747
+ const firstSheetId = sheetOrder[0];
748
+
749
+ if (firstSheetId && workbookData.sheets[firstSheetId]?.name) {
750
+ const sheetName = workbookData.sheets[firstSheetId].name.trim();
751
+
752
+ if (sheetName) {
753
+ return sheetName;
754
+ }
755
+ }
756
+ }
757
+
758
+ // Fallback to workbook ID
759
+ if (workbookData.id) {
760
+ return `Spreadsheet_${workbookData.id}`;
761
+ }
762
+
763
+ // Last resort: timestamp
764
+ return `Spreadsheet_${new Date().toISOString().slice(0, 10)}`;
765
+ }, []);
766
+
767
+ // Handle file export using SheetJS
768
+ const handleExportXlsx = useCallback(() => {
769
+ try {
770
+ const workbook = univerAPIRef.current?.getActiveWorkbook();
771
+
772
+ if (!workbook) return;
773
+
774
+ const workbookData = workbook.save() as unknown as XlsxWorkbookData;
775
+ const name = getExportFileName(workbookData);
776
+
777
+ downloadWorkbook(workbookData, name, 'xlsx');
778
+ } catch (err) {
779
+ console.error('XLSX Export error:', err);
780
+ }
781
+ }, [getExportFileName]);
782
+
783
+ // Handle CSV export (uses SheetJS - simpler format)
784
+ const handleExportCsv = useCallback(() => {
785
+ try {
786
+ const workbook = univerAPIRef.current?.getActiveWorkbook();
787
+
788
+ if (!workbook) return;
789
+
790
+ const workbookData = workbook.save() as unknown as XlsxWorkbookData;
791
+ const name = getExportFileName(workbookData);
792
+
793
+ downloadWorkbook(workbookData, name, 'csv');
794
+ } catch (err) {
795
+ console.error('CSV Export error:', err);
796
+ }
797
+ }, [getExportFileName]);
798
+
799
+ // Client-side only check
800
+ useEffect(() => {
801
+ setIsClient(true);
802
+ }, []);
803
+
804
+ // Initialize Univer
805
+ useEffect(() => {
806
+ if (!isClient || !containerRef.current) return;
807
+
808
+ // Get locale data synchronously
809
+ const univerLocale = getUniverLocale(locale);
810
+
811
+ // Increment generation and capture for this effect instance
812
+ instanceGeneration++;
813
+ const currentGeneration = instanceGeneration;
814
+
815
+ instanceGenerationRef.current = currentGeneration;
816
+
817
+ // Always dispose existing instance first (handles React Strict Mode)
818
+ if (univerRef.current) {
819
+ univerRef.current.dispose();
820
+ univerRef.current = null;
821
+ univerAPIRef.current = null;
822
+ }
823
+
824
+ const container = containerRef.current;
825
+ const rect = container.getBoundingClientRect();
826
+
827
+ // If container has no dimensions, wait for next frame
828
+ if (rect.width === 0 || rect.height === 0) {
829
+ const timerId = setTimeout(() => {
830
+ // Force re-render by updating isClient (already true, but React will re-run effect)
831
+ setIsClient(true);
832
+ }, 50);
833
+
834
+ return () => clearTimeout(timerId);
835
+ }
836
+
837
+ const univer = new Univer({
838
+ theme: defaultTheme,
839
+ locale: univerLocale.type,
840
+ locales: {
841
+ [univerLocale.type]: univerLocale.data
842
+ } as any
843
+ });
844
+
845
+ // Register core plugins in order
846
+ univer.registerPlugin(UniverRenderEnginePlugin as any);
847
+ univer.registerPlugin(UniverFormulaEnginePlugin as any);
848
+ univer.registerPlugin(UniverUIPlugin as any, {
849
+ container: containerRef.current,
850
+ customFontFamily: {
851
+ override: true,
852
+ list: CUSTOM_FONT_LIST
853
+ }
854
+ });
855
+
856
+ univer.registerPlugin(UniverDocsPlugin as any);
857
+ univer.registerPlugin(UniverDocsUIPlugin as any);
858
+
859
+ univer.registerPlugin(UniverSheetsPlugin as any);
860
+ univer.registerPlugin(UniverSheetsUIPlugin as any);
861
+ univer.registerPlugin(UniverSheetsFormulaPlugin as any);
862
+ univer.registerPlugin(UniverSheetsFormulaUIPlugin as any);
863
+ univer.registerPlugin(UniverSheetsNumfmtPlugin as any);
864
+ univer.registerPlugin(UniverSheetsNumfmtUIPlugin as any);
865
+
866
+ // Register Drawing plugins
867
+ univer.registerPlugin(UniverDrawingPlugin as any);
868
+ univer.registerPlugin(UniverDrawingUIPlugin as any);
869
+ univer.registerPlugin(UniverSheetsDrawingPlugin as any);
870
+ univer.registerPlugin(UniverSheetsDrawingUIPlugin as any);
871
+
872
+ // Register feature plugins
873
+ univer.registerPlugin(UniverSheetsDataValidationPlugin as any);
874
+ univer.registerPlugin(UniverSheetsDataValidationUIPlugin as any);
875
+ univer.registerPlugin(UniverSheetsConditionalFormattingPlugin as any);
876
+ univer.registerPlugin(UniverSheetsConditionalFormattingUIPlugin as any);
877
+ univer.registerPlugin(UniverSheetsFilterPlugin as any);
878
+ univer.registerPlugin(UniverSheetsFilterUIPlugin as any);
879
+ univer.registerPlugin(UniverSheetsSortPlugin as any);
880
+ univer.registerPlugin(UniverSheetsSortUIPlugin as any);
881
+ univer.registerPlugin(UniverSheetsHyperLinkPlugin as any);
882
+ univer.registerPlugin(UniverSheetsHyperLinkUIPlugin as any);
883
+ univer.registerPlugin(UniverSheetsFindReplacePlugin as any);
884
+ univer.registerPlugin(UniverSheetsThreadCommentPlugin as any);
885
+ univer.registerPlugin(UniverSheetsThreadCommentUIPlugin as any);
886
+ univer.registerPlugin(UniverWatermarkPlugin as any);
887
+ univer.registerPlugin(UniverSheetsCrosshairHighlightPlugin as any);
888
+
889
+ univerRef.current = univer;
890
+ univerAPIRef.current = FUniver.newAPI(univer);
891
+
892
+ // Listen for workbook changes
893
+ let debounceTimer: ReturnType<typeof setTimeout> | null = null;
894
+ const univerAPI = univerAPIRef.current;
895
+
896
+ univerAPI.addEvent(univerAPI.Event.CommandExecuted, (event) => {
897
+ /*
898
+ * Only react to user-level commands (CommandType.COMMAND = 0).
899
+ * System plugins such as SHEET_FILTER_PLUGIN fire CommandType.MUTATION (2)
900
+ * directly without a command wrapper, which must not trigger a save.
901
+ * All user actions (typing, paste, API calls via FUniver) go through
902
+ * CommandType.COMMAND first, so this is the correct layer to listen on.
903
+ */
904
+ if (event.type !== CommandType.COMMAND) return;
905
+
906
+ const cmd = event.id || '';
907
+
908
+ /*
909
+ * Skip the async snapshot-replace fired by createUnit during initialization.
910
+ * Once it fires, clear the flag so subsequent calls (e.g. file import) are saved.
911
+ */
912
+ if (cmd === 'doc.command-replace-snapshot') {
913
+ isInitializingRef.current = false;
914
+
915
+ return;
916
+ }
917
+
918
+ // Skip UI-only commands that don't change workbook data
919
+ const isUICommand
920
+ = cmd.includes('select')
921
+ || cmd.includes('scroll')
922
+ || cmd.includes('focus')
923
+ || cmd.includes('hover')
924
+ || cmd.includes('click')
925
+ || cmd.includes('cursor')
926
+ || cmd.includes('highlight')
927
+ || cmd.includes('zoom')
928
+ || cmd.includes('view')
929
+ || cmd.includes('activate')
930
+ || cmd.includes('editor')
931
+ || cmd.includes('operation');
932
+
933
+ if (isUICommand) return;
934
+
935
+ const isMutation
936
+ = cmd.includes('set-range-values')
937
+ || cmd.includes('set-cell')
938
+ || cmd.includes('insert-row')
939
+ || cmd.includes('insert-col')
940
+ || cmd.includes('delete-row')
941
+ || cmd.includes('delete-col')
942
+ || cmd.includes('remove-row')
943
+ || cmd.includes('remove-col')
944
+ || cmd.includes('move-row')
945
+ || cmd.includes('move-col')
946
+ || cmd.includes('add-merge')
947
+ || cmd.includes('remove-merge')
948
+ || cmd.includes('clear-selection')
949
+ || cmd.includes('set-worksheet-name')
950
+ || cmd.includes('paste')
951
+ || cmd.includes('cut')
952
+ || cmd.includes('set-style')
953
+ || cmd.includes('set-format')
954
+ || cmd.includes('undo')
955
+ || cmd.includes('redo');
956
+
957
+ if (!isMutation) return;
958
+
959
+ if (debounceTimer) clearTimeout(debounceTimer);
960
+ debounceTimer = setTimeout(() => {
961
+ const workbook = univerAPIRef.current?.getActiveWorkbook();
962
+
963
+ if (!workbook) return;
964
+
965
+ const snapshot = workbook.save();
966
+
967
+ onDataRef.current?.({
968
+ workbook: snapshot,
969
+ workbookJson: JSON.stringify(snapshot)
970
+ });
971
+ }, 300);
972
+ });
973
+
974
+ onReadyRef.current?.();
975
+
976
+ // Set up toolbar command handlers
977
+ importExportHandlers.import = handleImport;
978
+ importExportHandlers.exportXlsx = handleExportXlsx;
979
+ importExportHandlers.exportCsv = handleExportCsv;
980
+
981
+ // Setup import/export toolbar buttons
982
+ setupImportExportToolbar(univer);
983
+
984
+ // Use initialData prop or pendingDataRef or empty workbook
985
+ const workbookData = initialDataRef.current || pendingDataRef.current;
986
+
987
+ if (workbookData) {
988
+ console.info('[UniverSheets] Loading workbook data:', workbookData);
989
+
990
+ // Track workbook name from loaded data
991
+ const loadedName = (workbookData as any).name;
992
+
993
+ if (loadedName && loadedName.trim()) {
994
+ workbookNameRef.current = loadedName.trim();
995
+ }
996
+
997
+ isInitializingRef.current = true;
998
+ univer.createUnit(UniverInstanceType.UNIVER_SHEET, workbookData as any);
999
+ onLoadedRef.current?.({ workbookId: (workbookData as any).id });
1000
+ pendingDataRef.current = null;
1001
+ } else {
1002
+ console.info('[UniverSheets] Creating empty workbook');
1003
+ univer.createUnit(UniverInstanceType.UNIVER_SHEET, SAMPLE_WORKBOOK_DATA);
1004
+ }
1005
+
1006
+ // Execute initial commands after the workbook is fully initialized
1007
+ const pendingCommands = commandsRef.current;
1008
+
1009
+ if (pendingCommands && pendingCommands.length > 0) {
1010
+ for (const cmd of pendingCommands) {
1011
+ void executeApiCommand(cmd);
1012
+ }
1013
+ }
1014
+
1015
+ // Set numfmt locale for decimal/thousands separator based on app locale
1016
+ const numfmtLocale = getNumfmtLocale(locale);
1017
+ const activeWorkbook = univerAPIRef.current?.getActiveWorkbook();
1018
+
1019
+ if (activeWorkbook) {
1020
+ try {
1021
+ (activeWorkbook as any).setNumfmtLocal(numfmtLocale);
1022
+ console.info('[UniverSheets] Set numfmt locale to:', numfmtLocale);
1023
+ } catch (e) {
1024
+ console.warn('[UniverSheets] Failed to set numfmt locale:', e);
1025
+ }
1026
+ }
1027
+
1028
+ return () => {
1029
+ /*
1030
+ * Only dispose if this cleanup is for the current generation
1031
+ * This prevents React Strict Mode's first cleanup from disposing
1032
+ * the instance created by the second render
1033
+ */
1034
+ if (instanceGenerationRef.current === currentGeneration) {
1035
+ console.info('[UniverSheets] Cleanup - disposing generation:', currentGeneration);
1036
+
1037
+ // Defer dispose to next tick to avoid React concurrent rendering conflicts
1038
+ queueMicrotask(() => {
1039
+ try {
1040
+ univer.dispose();
1041
+ } catch (e) {
1042
+ /*
1043
+ * Ignore errors during dispose - can happen when navigating away
1044
+ * while Univer's internal callbacks are still running
1045
+ */
1046
+ console.warn('[UniverSheets] Error during dispose (safe to ignore):', e);
1047
+ }
1048
+ });
1049
+
1050
+ univerRef.current = null;
1051
+ univerAPIRef.current = null;
1052
+ } else {
1053
+ console.info(
1054
+ '[UniverSheets] Cleanup - skipping stale generation:',
1055
+ currentGeneration,
1056
+ 'current:',
1057
+ instanceGenerationRef.current
1058
+ );
1059
+ }
1060
+ };
1061
+ }, [
1062
+ isClient,
1063
+ locale,
1064
+ handleExportXlsx,
1065
+ handleExportCsv,
1066
+ executeApiCommand
1067
+ ]);
1068
+
1069
+ if (!isClient) {
1070
+ return (
1071
+ <div
1072
+ style={{
1073
+ width: '100%',
1074
+ height: '100%',
1075
+ display: 'flex',
1076
+ alignItems: 'center',
1077
+ justifyContent: 'center',
1078
+ background: '#f5f5f5'
1079
+ }}>
1080
+ <span>Loading...</span>
1081
+ </div>
1082
+ );
1083
+ }
1084
+
1085
+ return (
1086
+ <div style={{ position: 'absolute', inset: 0 }}>
1087
+ {/* Hidden file input for import - triggered by toolbar button */}
1088
+ <input
1089
+ ref={fileInputRef}
1090
+ type="file"
1091
+ accept=".xlsx,.xls,.csv"
1092
+ onChange={handleFileChange}
1093
+ style={{ display: 'none' }} />
1094
+
1095
+ <div
1096
+ ref={containerRef}
1097
+ style={{
1098
+ position: 'absolute',
1099
+ inset: 0,
1100
+ overflow: 'hidden'
1101
+ }} />
1102
+ </div>
1103
+ );
1104
+ }