@univerjs/thread-comment-ui 1.0.0-insiders.20260809-70eefdd → 1.0.0-rc.0

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 (97) hide show
  1. package/LICENSE +176 -0
  2. package/README.md +0 -1
  3. package/lib/cjs/index.js +582 -132
  4. package/lib/cjs/locale/ar-SA.js +2 -3
  5. package/lib/cjs/locale/ca-ES.js +2 -3
  6. package/lib/cjs/locale/de-DE.js +2 -3
  7. package/lib/cjs/locale/en-US.js +2 -3
  8. package/lib/cjs/locale/es-ES.js +2 -3
  9. package/lib/cjs/locale/fa-IR.js +2 -3
  10. package/lib/cjs/locale/fr-FR.js +2 -3
  11. package/lib/cjs/locale/id-ID.js +2 -3
  12. package/lib/cjs/locale/it-IT.js +2 -3
  13. package/lib/cjs/locale/ja-JP.js +2 -3
  14. package/lib/cjs/locale/ko-KR.js +2 -3
  15. package/lib/cjs/locale/pl-PL.js +2 -3
  16. package/lib/cjs/locale/pt-BR.js +2 -3
  17. package/lib/cjs/locale/ru-RU.js +2 -3
  18. package/lib/cjs/locale/sk-SK.js +2 -3
  19. package/lib/cjs/locale/vi-VN.js +2 -3
  20. package/lib/cjs/locale/zh-CN.js +2 -3
  21. package/lib/cjs/locale/zh-HK.js +2 -3
  22. package/lib/cjs/locale/zh-TW.js +2 -3
  23. package/lib/es/index.js +573 -138
  24. package/lib/es/locale/ar-SA.js +2 -3
  25. package/lib/es/locale/ca-ES.js +2 -3
  26. package/lib/es/locale/de-DE.js +2 -3
  27. package/lib/es/locale/en-US.js +2 -3
  28. package/lib/es/locale/es-ES.js +2 -3
  29. package/lib/es/locale/fa-IR.js +2 -3
  30. package/lib/es/locale/fr-FR.js +2 -3
  31. package/lib/es/locale/id-ID.js +2 -3
  32. package/lib/es/locale/it-IT.js +2 -3
  33. package/lib/es/locale/ja-JP.js +2 -3
  34. package/lib/es/locale/ko-KR.js +2 -3
  35. package/lib/es/locale/pl-PL.js +2 -3
  36. package/lib/es/locale/pt-BR.js +2 -3
  37. package/lib/es/locale/ru-RU.js +2 -3
  38. package/lib/es/locale/sk-SK.js +2 -3
  39. package/lib/es/locale/vi-VN.js +2 -3
  40. package/lib/es/locale/zh-CN.js +2 -3
  41. package/lib/es/locale/zh-HK.js +2 -3
  42. package/lib/es/locale/zh-TW.js +2 -3
  43. package/lib/index.css +54 -18
  44. package/lib/index.js +573 -138
  45. package/lib/locale/ar-SA.js +2 -3
  46. package/lib/locale/ca-ES.js +2 -3
  47. package/lib/locale/de-DE.js +2 -3
  48. package/lib/locale/en-US.js +2 -3
  49. package/lib/locale/es-ES.js +2 -3
  50. package/lib/locale/fa-IR.js +2 -3
  51. package/lib/locale/fr-FR.js +2 -3
  52. package/lib/locale/id-ID.js +2 -3
  53. package/lib/locale/it-IT.js +2 -3
  54. package/lib/locale/ja-JP.js +2 -3
  55. package/lib/locale/ko-KR.js +2 -3
  56. package/lib/locale/pl-PL.js +2 -3
  57. package/lib/locale/pt-BR.js +2 -3
  58. package/lib/locale/ru-RU.js +2 -3
  59. package/lib/locale/sk-SK.js +2 -3
  60. package/lib/locale/vi-VN.js +2 -3
  61. package/lib/locale/zh-CN.js +2 -3
  62. package/lib/locale/zh-HK.js +2 -3
  63. package/lib/locale/zh-TW.js +2 -3
  64. package/lib/types/index.d.ts +7 -0
  65. package/lib/types/locale/en-US.d.ts +1 -2
  66. package/lib/types/mobile-plugin.d.ts +29 -0
  67. package/lib/types/render-objects/thread-comment-canvas-overlay.d.ts +66 -0
  68. package/lib/types/services/thread-comment-draft.service.d.ts +39 -0
  69. package/lib/types/services/thread-comment-panel.service.d.ts +7 -3
  70. package/lib/types/views/ThreadCommentEditor.d.ts +3 -1
  71. package/lib/types/views/ThreadCommentPanel.d.ts +9 -0
  72. package/lib/types/views/ThreadCommentTree.d.ts +10 -2
  73. package/lib/types/views/mobile/MobileThreadCommentEditor.d.ts +17 -0
  74. package/lib/types/views/mobile/MobileThreadCommentPanel.d.ts +17 -0
  75. package/lib/types/views/mobile/MobileThreadCommentTree.d.ts +17 -0
  76. package/lib/types/views/thread-comment-panel/util.d.ts +8 -0
  77. package/lib/umd/index.js +4 -4
  78. package/lib/umd/locale/ar-SA.js +1 -1
  79. package/lib/umd/locale/ca-ES.js +1 -1
  80. package/lib/umd/locale/de-DE.js +1 -1
  81. package/lib/umd/locale/en-US.js +1 -1
  82. package/lib/umd/locale/es-ES.js +1 -1
  83. package/lib/umd/locale/fa-IR.js +1 -1
  84. package/lib/umd/locale/fr-FR.js +1 -1
  85. package/lib/umd/locale/id-ID.js +1 -1
  86. package/lib/umd/locale/it-IT.js +1 -1
  87. package/lib/umd/locale/ja-JP.js +1 -1
  88. package/lib/umd/locale/ko-KR.js +1 -1
  89. package/lib/umd/locale/pl-PL.js +1 -1
  90. package/lib/umd/locale/pt-BR.js +1 -1
  91. package/lib/umd/locale/ru-RU.js +1 -1
  92. package/lib/umd/locale/sk-SK.js +1 -1
  93. package/lib/umd/locale/vi-VN.js +1 -1
  94. package/lib/umd/locale/zh-CN.js +1 -1
  95. package/lib/umd/locale/zh-HK.js +1 -1
  96. package/lib/umd/locale/zh-TW.js +1 -1
  97. package/package.json +11 -11
package/lib/es/index.js CHANGED
@@ -1,9 +1,10 @@
1
- import { BuildTextUtils, CommandType, CustomRangeType, DOCS_COMMENT_EDITOR_UNIT_ID_KEY, DOCS_NORMAL_EDITOR_UNIT_ID_KEY, DependentOn, Disposable, ICommandService, IConfigService, IUniverInstanceService, Inject, Injector, LOCALE_META, LocaleService, Plugin, RegionService, Tools, UniverInstanceType, UserManagerService, createParagraphId, createSectionId, dateKit, generateRandomId, getBodySlice, merge, mergeOverrideWithDependencies } from "@univerjs/core";
2
- import { ISidebarService, KeyCode, UI_PLUGIN_CONFIG_KEY, useConfigValue, useDependency, useObservable } from "@univerjs/ui";
3
- import { BehaviorSubject, debounceTime, filter, map, of, startWith } from "rxjs";
4
- import { BreakLineCommand, IEditorService, RichTextEditor, UniverDocsUIPlugin } from "@univerjs/docs-ui";
1
+ import { BuildTextUtils, CommandType, CustomRangeType, DOCS_COMMENT_EDITOR_UNIT_ID_KEY, DOCS_NORMAL_EDITOR_UNIT_ID_KEY, DependentOn, Disposable, ICommandService, IConfigService, IUniverInstanceService, Inject, Injector, LOCALE_META, LocaleService, Plugin, RegionService, Tools, UniverInstanceType, UserManagerService, createParagraphId, createSectionId, dateKit, generateRandomId, getBodySlice, merge, mergeOverrideWithDependencies, toDisposable } from "@univerjs/core";
2
+ import { ISidebarService, KeyCode, UI_PLUGIN_CONFIG_KEY, UniverMobileUIPlugin, useConfigValue, useDependency, useEvent, useObservable } from "@univerjs/ui";
3
+ import { BehaviorSubject, debounceTime, map, of, startWith } from "rxjs";
4
+ import { BreakLineCommand, DeleteLeftCommand, DeleteRightCommand, IEditorService, RichTextEditor, UniverDocsUIPlugin } from "@univerjs/docs-ui";
5
5
  import { AddCommentCommand, DeleteCommentCommand, DeleteCommentTreeCommand, ResolveCommentCommand, ThreadCommentModel, UniverThreadCommentPlugin, UpdateCommentCommand, getDT } from "@univerjs/thread-comment";
6
- import { Button, Dropdown, Select, Tooltip, borderClassName, clsx, scrollbarClassName } from "@univerjs/design";
6
+ import { BaseObject, DEFAULT_FONTFACE_PLANE } from "@univerjs/engine-render";
7
+ import { ActionRow, Button, Dropdown, MobileActionRowGroup, MobileDropdown, MobileSelect, Select, Tooltip, borderClassName, clsx, scrollbarClassName } from "@univerjs/design";
7
8
  import { DeleteIcon, IncreaseIcon, MoreHorizontalIcon, ReplyToCommentIcon, SuccessIcon, SuccessOutlineIcon } from "@univerjs/icons";
8
9
  import { forwardRef, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
9
10
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -69,19 +70,22 @@ function __decorate(decorators, target, key, desc) {
69
70
  //#endregion
70
71
  //#region src/services/thread-comment-panel.service.ts
71
72
  let ThreadCommentPanelService = class ThreadCommentPanelService extends Disposable {
72
- constructor(_sidebarService, _univerInstanceService) {
73
+ constructor(_sidebarService) {
73
74
  super();
74
75
  this._sidebarService = _sidebarService;
75
- this._univerInstanceService = _univerInstanceService;
76
76
  _defineProperty(this, "_panelVisible", false);
77
77
  _defineProperty(this, "_panelVisible$", new BehaviorSubject(false));
78
78
  _defineProperty(this, "_activeCommentId", void 0);
79
79
  _defineProperty(this, "_activeCommentId$", new BehaviorSubject(void 0));
80
+ _defineProperty(this, "_hoveredCommentId", void 0);
81
+ _defineProperty(this, "_hoveredCommentId$", new BehaviorSubject(void 0));
80
82
  _defineProperty(this, "panelVisible$", this._panelVisible$.asObservable());
81
83
  _defineProperty(this, "activeCommentId$", this._activeCommentId$.asObservable());
84
+ _defineProperty(this, "hoveredCommentId$", this._hoveredCommentId$.asObservable());
82
85
  this._init();
83
86
  this.disposeWithMe(() => {
84
87
  this._activeCommentId$.complete();
88
+ this._hoveredCommentId$.complete();
85
89
  this._panelVisible$.complete();
86
90
  });
87
91
  }
@@ -89,9 +93,6 @@ let ThreadCommentPanelService = class ThreadCommentPanelService extends Disposab
89
93
  this.disposeWithMe(this._sidebarService.sidebarOptions$.subscribe((opt) => {
90
94
  if (!opt.visible) this.setPanelVisible(false);
91
95
  }));
92
- this.disposeWithMe(this._univerInstanceService.getCurrentTypeOfUnit$(UniverInstanceType.UNIVER_SHEET).pipe(filter((sheet) => !sheet)).subscribe(() => {
93
- this._sidebarService.close();
94
- }));
95
96
  }
96
97
  get panelVisible() {
97
98
  return this._panelVisible;
@@ -99,16 +100,24 @@ let ThreadCommentPanelService = class ThreadCommentPanelService extends Disposab
99
100
  get activeCommentId() {
100
101
  return this._activeCommentId;
101
102
  }
103
+ get hoveredCommentId() {
104
+ return this._hoveredCommentId;
105
+ }
102
106
  setPanelVisible(visible) {
103
107
  this._panelVisible = visible;
104
108
  this._panelVisible$.next(visible);
109
+ if (!visible) this.setHoveredComment(void 0);
105
110
  }
106
111
  setActiveComment(commentInfo) {
107
112
  this._activeCommentId = commentInfo;
108
113
  this._activeCommentId$.next(commentInfo);
109
114
  }
115
+ setHoveredComment(commentInfo) {
116
+ this._hoveredCommentId = commentInfo;
117
+ this._hoveredCommentId$.next(commentInfo);
118
+ }
110
119
  };
111
- ThreadCommentPanelService = __decorate([__decorateParam(0, Inject(ISidebarService)), __decorateParam(1, IUniverInstanceService)], ThreadCommentPanelService);
120
+ ThreadCommentPanelService = __decorate([__decorateParam(0, Inject(ISidebarService))], ThreadCommentPanelService);
112
121
 
113
122
  //#endregion
114
123
  //#region src/commands/operations/comment.operations.ts
@@ -124,7 +133,7 @@ const SetActiveCommentOperation = {
124
133
  //#endregion
125
134
  //#region package.json
126
135
  var name = "@univerjs/thread-comment-ui";
127
- var version = "1.0.0-insiders.20260809-70eefdd";
136
+ var version = "1.0.0-rc.0";
128
137
 
129
138
  //#endregion
130
139
  //#region src/config/config.ts
@@ -132,6 +141,72 @@ const THREAD_COMMENT_UI_PLUGIN_CONFIG_KEY = "thread-comment-ui.config";
132
141
  const configSymbol = Symbol(THREAD_COMMENT_UI_PLUGIN_CONFIG_KEY);
133
142
  const defaultPluginConfig = {};
134
143
 
144
+ //#endregion
145
+ //#region src/services/thread-comment-draft.service.ts
146
+ let ThreadCommentDraftService = class ThreadCommentDraftService extends Disposable {
147
+ constructor(instanceService, _userManagerService) {
148
+ super();
149
+ this._userManagerService = _userManagerService;
150
+ _defineProperty(this, "_placementType$", new BehaviorSubject(null));
151
+ _defineProperty(this, "_draft$", new BehaviorSubject(null));
152
+ _defineProperty(this, "_placementUnitId", void 0);
153
+ _defineProperty(this, "_ownerUserId", void 0);
154
+ _defineProperty(this, "placementType$", this._placementType$.asObservable());
155
+ _defineProperty(this, "draft$", this._draft$.asObservable());
156
+ this.disposeWithMe(instanceService.unitDisposed$.subscribe((unit) => {
157
+ var _this$draft;
158
+ if (((_this$draft = this.draft) === null || _this$draft === void 0 ? void 0 : _this$draft.unitId) === unit.getUnitId() || this._placementUnitId === unit.getUnitId()) this.cancel();
159
+ }));
160
+ this.disposeWithMe(instanceService.focused$.subscribe((unitId) => {
161
+ if (unitId && this._placementUnitId && unitId !== this._placementUnitId) this.cancel();
162
+ }));
163
+ this.disposeWithMe(this._userManagerService.currentUser$.subscribe((user) => {
164
+ if (this._ownerUserId && (user === null || user === void 0 ? void 0 : user.userID) !== this._ownerUserId) this.cancel();
165
+ }));
166
+ if (typeof window !== "undefined") {
167
+ const cancelPlacement = (event) => {
168
+ if (event.key === "Escape" && (this.placementType || this.draft)) this.cancel();
169
+ };
170
+ window.addEventListener("keydown", cancelPlacement);
171
+ this.disposeWithMe(toDisposable(() => window.removeEventListener("keydown", cancelPlacement)));
172
+ }
173
+ }
174
+ get placementType() {
175
+ return this._placementType$.value;
176
+ }
177
+ get draft() {
178
+ return this._draft$.value;
179
+ }
180
+ startPlacement(type, unitId) {
181
+ if (this.placementType === type && this._placementUnitId === unitId) {
182
+ this.cancel();
183
+ return;
184
+ }
185
+ this._ownerUserId = this._userManagerService.getCurrentUser().userID;
186
+ this._placementUnitId = unitId;
187
+ this._draft$.next(null);
188
+ this._placementType$.next(type);
189
+ }
190
+ place(draft) {
191
+ this._ownerUserId = this._userManagerService.getCurrentUser().userID;
192
+ this._placementUnitId = void 0;
193
+ this._placementType$.next(null);
194
+ this._draft$.next(draft);
195
+ }
196
+ cancel() {
197
+ this._ownerUserId = void 0;
198
+ this._placementUnitId = void 0;
199
+ this._placementType$.next(null);
200
+ this._draft$.next(null);
201
+ }
202
+ dispose() {
203
+ this._placementType$.complete();
204
+ this._draft$.complete();
205
+ super.dispose();
206
+ }
207
+ };
208
+ ThreadCommentDraftService = __decorate([__decorateParam(0, IUniverInstanceService), __decorateParam(1, Inject(UserManagerService))], ThreadCommentDraftService);
209
+
135
210
  //#endregion
136
211
  //#region src/types/const.ts
137
212
  /**
@@ -151,6 +226,38 @@ const defaultPluginConfig = {};
151
226
  */
152
227
  const PLUGIN_NAME = "UNIVER_THREAD_COMMENT_UI_PLUGIN";
153
228
 
229
+ //#endregion
230
+ //#region src/mobile-plugin.ts
231
+ let UniverThreadCommentMobileUIPlugin = class UniverThreadCommentMobileUIPlugin extends Plugin {
232
+ constructor(_config = defaultPluginConfig, _injector, _commandService, _configService) {
233
+ super();
234
+ this._config = _config;
235
+ this._injector = _injector;
236
+ this._commandService = _commandService;
237
+ this._configService = _configService;
238
+ const { menu, ...rest } = merge({}, defaultPluginConfig, this._config);
239
+ if (menu) this._configService.setConfig("menu", menu, { merge: true });
240
+ this._configService.setConfig(THREAD_COMMENT_UI_PLUGIN_CONFIG_KEY, rest);
241
+ }
242
+ onStarting() {
243
+ var _this$_config;
244
+ mergeOverrideWithDependencies([[ThreadCommentDraftService], [ThreadCommentPanelService]], (_this$_config = this._config) === null || _this$_config === void 0 ? void 0 : _this$_config.overrides).forEach((dependency) => {
245
+ this._injector.add(dependency);
246
+ });
247
+ this._commandService.registerCommand(SetActiveCommentOperation);
248
+ }
249
+ };
250
+ _defineProperty(UniverThreadCommentMobileUIPlugin, "pluginName", PLUGIN_NAME);
251
+ _defineProperty(UniverThreadCommentMobileUIPlugin, "packageName", name);
252
+ _defineProperty(UniverThreadCommentMobileUIPlugin, "version", version);
253
+ _defineProperty(UniverThreadCommentMobileUIPlugin, "type", UniverInstanceType.UNIVER_UNKNOWN);
254
+ UniverThreadCommentMobileUIPlugin = __decorate([
255
+ DependentOn(UniverThreadCommentPlugin, UniverDocsUIPlugin, UniverMobileUIPlugin),
256
+ __decorateParam(1, Inject(Injector)),
257
+ __decorateParam(2, ICommandService),
258
+ __decorateParam(3, IConfigService)
259
+ ], UniverThreadCommentMobileUIPlugin);
260
+
154
261
  //#endregion
155
262
  //#region src/plugin.ts
156
263
  let UniverThreadCommentUIPlugin = class UniverThreadCommentUIPlugin extends Plugin {
@@ -166,7 +273,7 @@ let UniverThreadCommentUIPlugin = class UniverThreadCommentUIPlugin extends Plug
166
273
  }
167
274
  onStarting() {
168
275
  var _this$_config;
169
- mergeOverrideWithDependencies([[ThreadCommentPanelService]], (_this$_config = this._config) === null || _this$_config === void 0 ? void 0 : _this$_config.overrides).forEach((dep) => {
276
+ mergeOverrideWithDependencies([[ThreadCommentDraftService], [ThreadCommentPanelService]], (_this$_config = this._config) === null || _this$_config === void 0 ? void 0 : _this$_config.overrides).forEach((dep) => {
170
277
  this._injector.add(dep);
171
278
  });
172
279
  [SetActiveCommentOperation].forEach((command) => {
@@ -185,8 +292,175 @@ UniverThreadCommentUIPlugin = __decorate([
185
292
  __decorateParam(3, IConfigService)
186
293
  ], UniverThreadCommentUIPlugin);
187
294
 
295
+ //#endregion
296
+ //#region src/render-objects/thread-comment-canvas-overlay.ts
297
+ const MARKER_SIZE = 24;
298
+ const MARKER_IDLE_OPACITY = .58;
299
+ const MARKER_PREVIEW_OPACITY = .42;
300
+ const UNDERLINE_WIDTH = 2;
301
+ const UNDERLINE_HIT_PADDING = 4;
302
+ const OUTLINE_PADDING = 2;
303
+ var ThreadCommentCanvasOverlay = class extends BaseObject {
304
+ constructor(key, state) {
305
+ super(key);
306
+ _defineProperty(this, "_state", void 0);
307
+ _defineProperty(this, "_hoveredCommentId", null);
308
+ _defineProperty(this, "_hitCommentId", null);
309
+ this.evented = true;
310
+ this._state = state;
311
+ this.show();
312
+ }
313
+ get hitCommentId() {
314
+ return this._hitCommentId;
315
+ }
316
+ updateState(state) {
317
+ this._state = {
318
+ ...this._state,
319
+ ...state
320
+ };
321
+ if (this._hitCommentId && !this._containsComment(this._hitCommentId)) this._hitCommentId = null;
322
+ if (this._hoveredCommentId && !this._containsComment(this._hoveredCommentId)) this._hoveredCommentId = null;
323
+ if ("previewMarker" in state || "previewUnderline" in state) this.makeDirtyNoDebounce(true);
324
+ else this.makeDirty(true);
325
+ }
326
+ clearHover() {
327
+ if (this._hoveredCommentId) {
328
+ this._hoveredCommentId = null;
329
+ this.makeDirty(true);
330
+ }
331
+ this._hitCommentId = null;
332
+ }
333
+ isHit(coord) {
334
+ const zoomRatio = this._getZoomRatio();
335
+ const halfSize = MARKER_SIZE / zoomRatio / 2;
336
+ let marker;
337
+ for (let index = this._state.markers.length - 1; index >= 0; index -= 1) {
338
+ const item = this._state.markers[index];
339
+ if (!item) continue;
340
+ if (coord.x >= item.x - halfSize && coord.x <= item.x + halfSize && coord.y >= item.y - halfSize && coord.y <= item.y + halfSize) {
341
+ marker = item;
342
+ break;
343
+ }
344
+ }
345
+ let underline;
346
+ if (!marker) for (let index = this._state.underlines.length - 1; index >= 0; index -= 1) {
347
+ const item = this._state.underlines[index];
348
+ if (!item) continue;
349
+ if (coord.x >= item.left && coord.x <= item.left + item.width && Math.abs(coord.y - item.top) <= UNDERLINE_HIT_PADDING / zoomRatio) {
350
+ underline = item;
351
+ break;
352
+ }
353
+ }
354
+ const commentId = (marker === null || marker === void 0 ? void 0 : marker.commentId) ?? (underline === null || underline === void 0 ? void 0 : underline.commentId) ?? null;
355
+ this._hitCommentId = commentId;
356
+ if (commentId !== this._hoveredCommentId) {
357
+ this._hoveredCommentId = commentId;
358
+ this.makeDirty(true);
359
+ }
360
+ return commentId !== null;
361
+ }
362
+ render(ctx, _bounds) {
363
+ var _this$_state$focusOut;
364
+ const zoomRatio = this._getZoomRatio();
365
+ this._state.underlines.forEach((underline) => this._renderUnderline(ctx, underline, zoomRatio, 1));
366
+ (_this$_state$focusOut = this._state.focusOutlines) === null || _this$_state$focusOut === void 0 || _this$_state$focusOut.forEach((outline) => this._renderOutline(ctx, outline, zoomRatio));
367
+ if (this._state.previewUnderline) this._renderUnderline(ctx, this._state.previewUnderline, zoomRatio, MARKER_PREVIEW_OPACITY);
368
+ this._state.markers.forEach((marker) => {
369
+ var _this$_state$focusedC;
370
+ return this._renderMarker(ctx, marker, zoomRatio, this._markerContainsComment(marker, this._hoveredCommentId) || ((_this$_state$focusedC = this._state.focusedCommentIds) === null || _this$_state$focusedC === void 0 ? void 0 : _this$_state$focusedC.some((commentId) => this._markerContainsComment(marker, commentId))) ? 1 : MARKER_IDLE_OPACITY);
371
+ });
372
+ if (this._state.previewMarker) this._renderMarker(ctx, this._state.previewMarker, zoomRatio, MARKER_PREVIEW_OPACITY);
373
+ this.makeDirty(false);
374
+ return this;
375
+ }
376
+ _getZoomRatio() {
377
+ return Number.isFinite(this._state.zoomRatio) && this._state.zoomRatio > 0 ? this._state.zoomRatio : 1;
378
+ }
379
+ _containsComment(commentId) {
380
+ return this._state.markers.some((marker) => this._markerContainsComment(marker, commentId)) || this._state.underlines.some((underline) => underline.commentId === commentId);
381
+ }
382
+ _markerContainsComment(marker, commentId) {
383
+ var _marker$commentIds;
384
+ return commentId != null && (marker.commentId === commentId || ((_marker$commentIds = marker.commentIds) === null || _marker$commentIds === void 0 ? void 0 : _marker$commentIds.includes(commentId)) === true);
385
+ }
386
+ _renderUnderline(ctx, underline, zoomRatio, opacity) {
387
+ ctx.save();
388
+ ctx.globalAlpha = opacity;
389
+ ctx.strokeStyle = this._state.accentColor;
390
+ ctx.lineWidth = UNDERLINE_WIDTH / zoomRatio;
391
+ ctx.beginPath();
392
+ ctx.moveTo(underline.left, underline.top);
393
+ ctx.lineTo(underline.left + underline.width, underline.top);
394
+ ctx.stroke();
395
+ ctx.restore();
396
+ }
397
+ _renderOutline(ctx, outline, zoomRatio) {
398
+ const padding = OUTLINE_PADDING / zoomRatio;
399
+ ctx.save();
400
+ ctx.strokeStyle = this._state.accentColor;
401
+ ctx.lineWidth = UNDERLINE_WIDTH / zoomRatio;
402
+ ctx.strokeRect(outline.left - padding, outline.top - padding, outline.width + padding * 2, outline.height + padding * 2);
403
+ ctx.restore();
404
+ }
405
+ _renderMarker(ctx, marker, zoomRatio, opacity) {
406
+ const size = MARKER_SIZE / zoomRatio;
407
+ const left = marker.x - size / 2;
408
+ const top = marker.y - size / 2;
409
+ const radius = 4 / zoomRatio;
410
+ const tail = 4 / zoomRatio;
411
+ ctx.save();
412
+ ctx.globalAlpha = opacity;
413
+ ctx.fillStyle = this._state.accentColor;
414
+ ctx.strokeStyle = this._state.outlineColor;
415
+ ctx.lineWidth = 1.5 / zoomRatio;
416
+ ctx.beginPath();
417
+ ctx.moveTo(left + radius, top);
418
+ ctx.lineTo(left + size - radius, top);
419
+ ctx.quadraticCurveTo(left + size, top, left + size, top + radius);
420
+ ctx.lineTo(left + size, top + size - tail - radius);
421
+ ctx.quadraticCurveTo(left + size, top + size - tail, left + size - radius, top + size - tail);
422
+ ctx.lineTo(left + size / 2 + tail, top + size - tail);
423
+ ctx.lineTo(left + size / 2, top + size);
424
+ ctx.lineTo(left + size / 2 - tail, top + size - tail);
425
+ ctx.lineTo(left + radius, top + size - tail);
426
+ ctx.quadraticCurveTo(left, top + size - tail, left, top + size - tail - radius);
427
+ ctx.lineTo(left, top + radius);
428
+ ctx.quadraticCurveTo(left, top, left + radius, top);
429
+ ctx.closePath();
430
+ ctx.fill();
431
+ ctx.stroke();
432
+ ctx.fillStyle = this._state.foregroundColor;
433
+ if ((marker.count ?? 1) > 1) {
434
+ ctx.font = `600 ${11 / zoomRatio}px ${DEFAULT_FONTFACE_PLANE}`;
435
+ ctx.textAlign = "center";
436
+ ctx.textBaseline = "middle";
437
+ ctx.fillText(String(marker.count), marker.x, top + size * .42);
438
+ } else {
439
+ const dotRadius = 1.2 / zoomRatio;
440
+ const dotY = top + size * .43;
441
+ [
442
+ .32,
443
+ .5,
444
+ .68
445
+ ].forEach((ratio) => {
446
+ ctx.beginPath();
447
+ ctx.arc(left + size * ratio, dotY, dotRadius, 0, Math.PI * 2);
448
+ ctx.fill();
449
+ });
450
+ }
451
+ ctx.restore();
452
+ }
453
+ };
454
+
188
455
  //#endregion
189
456
  //#region src/views/thread-comment-panel/util.ts
457
+ function isSameThreadCommentTarget(active, comment) {
458
+ return (active === null || active === void 0 ? void 0 : active.unitId) === comment.unitId && active.subUnitId === comment.subUnitId && active.commentId === comment.id;
459
+ }
460
+ function shouldClearThreadCommentTarget(active, currentUnitId, commentExists) {
461
+ if (!active) return false;
462
+ return active.unitId !== currentUnitId || !commentExists;
463
+ }
190
464
  function getThreadCommentPanelItemKey(comment, index, section) {
191
465
  if (comment.id) return comment.id;
192
466
  return [
@@ -299,29 +573,60 @@ function getSnapshot(body) {
299
573
  };
300
574
  }
301
575
  const ThreadCommentEditor = forwardRef((props, ref) => {
302
- const { comment, onSave, id, onCancel, autoFocus, unitId, type, editorId } = props;
576
+ const { comment, onSave, id, onCancel, autoFocus, unitId, type, editorId, ActionRowComponent = ActionRow } = props;
303
577
  const commandService = useDependency(ICommandService);
304
578
  const localeService = useDependency(LocaleService);
305
579
  const [editing, setEditing] = useState(false);
580
+ const [submitting, setSubmitting] = useState(false);
581
+ const submittingRef = useRef(false);
582
+ const mountedRef = useRef(true);
306
583
  const editorService = useDependency(IEditorService);
307
- const editor = useRef(null);
584
+ const editorRef = useRef(null);
308
585
  const rootEditorId = type === UniverInstanceType.UNIVER_DOC ? DOCS_NORMAL_EDITOR_UNIT_ID_KEY : unitId;
309
586
  const [canSubmit, setCanSubmit] = useState(() => {
310
587
  var _comment$text;
311
588
  return BuildTextUtils.transform.getPlainText((comment === null || comment === void 0 || (_comment$text = comment.text) === null || _comment$text === void 0 ? void 0 : _comment$text.dataStream) ?? "");
312
589
  });
313
590
  const keyboardEventConfig = useMemo(() => ({
314
- keyCodes: [{ keyCode: KeyCode.ENTER }],
591
+ keyCodes: [
592
+ { keyCode: KeyCode.ENTER },
593
+ { keyCode: KeyCode.BACKSPACE },
594
+ { keyCode: KeyCode.DELETE }
595
+ ],
315
596
  handler: (keyCode) => {
316
- if (keyCode === KeyCode.ENTER) commandService.executeCommand(BreakLineCommand.id);
597
+ let commandId;
598
+ switch (keyCode) {
599
+ case KeyCode.ENTER:
600
+ commandId = BreakLineCommand.id;
601
+ break;
602
+ case KeyCode.BACKSPACE:
603
+ commandId = DeleteLeftCommand.id;
604
+ break;
605
+ case KeyCode.DELETE:
606
+ commandId = DeleteRightCommand.id;
607
+ break;
608
+ default: return;
609
+ }
610
+ focusThreadCommentEditor(editorService, editorId, editorRef.current);
611
+ commandService.executeCommand(commandId).then(() => {
612
+ if (keyCode !== KeyCode.ENTER && mountedRef.current) {
613
+ var _editorRef$current;
614
+ const dataStream = ((_editorRef$current = editorRef.current) === null || _editorRef$current === void 0 || (_editorRef$current = _editorRef$current.getDocumentData().body) === null || _editorRef$current === void 0 ? void 0 : _editorRef$current.dataStream) ?? "";
615
+ setCanSubmit(BuildTextUtils.transform.getPlainText(dataStream));
616
+ }
617
+ });
317
618
  }
318
- }), [commandService]);
619
+ }), [
620
+ commandService,
621
+ editorId,
622
+ editorService
623
+ ]);
319
624
  useImperativeHandle(ref, () => ({ reply(text) {
320
- var _editor$current;
321
- if (!editor.current) return;
322
- focusThreadCommentEditor(editorService, editorId, editor.current);
625
+ var _editorRef$current2;
626
+ if (!editorRef.current) return;
627
+ focusThreadCommentEditor(editorService, editorId, editorRef.current);
323
628
  const documentData = getSnapshot(text);
324
- (_editor$current = editor.current) === null || _editor$current === void 0 || _editor$current.setDocumentData(documentData, [{
629
+ (_editorRef$current2 = editorRef.current) === null || _editorRef$current2 === void 0 || _editorRef$current2.setDocumentData(documentData, [{
325
630
  startOffset: documentData.body.dataStream.length - 2,
326
631
  endOffset: documentData.body.dataStream.length - 2,
327
632
  collapsed: true
@@ -329,29 +634,44 @@ const ThreadCommentEditor = forwardRef((props, ref) => {
329
634
  setCanSubmit(BuildTextUtils.transform.getPlainText(documentData.body.dataStream));
330
635
  setEditing(true);
331
636
  } }));
332
- const handleSave = () => {
333
- const currentEditor = editor.current;
334
- if (currentEditor) {
335
- const newText = Tools.deepClone(currentEditor.getDocumentData().body);
637
+ const handleSave = async () => {
638
+ const currentEditor = editorRef.current;
639
+ if (!currentEditor || submittingRef.current) return;
640
+ const newText = Tools.deepClone(currentEditor.getDocumentData().body);
641
+ submittingRef.current = true;
642
+ setSubmitting(true);
643
+ try {
644
+ if (await (onSave === null || onSave === void 0 ? void 0 : onSave({
645
+ ...comment,
646
+ text: newText
647
+ })) === false) return;
648
+ if (!mountedRef.current) return;
336
649
  currentEditor.blur();
337
650
  currentEditor.replaceText("", false);
338
651
  currentEditor.setSelectionRanges([], false);
339
652
  setCanSubmit("");
340
653
  setEditing(false);
341
- onSave === null || onSave === void 0 || onSave({
342
- ...comment,
343
- text: newText
344
- });
654
+ } catch {
655
+ return;
656
+ } finally {
657
+ submittingRef.current = false;
658
+ if (mountedRef.current) setSubmitting(false);
345
659
  }
346
660
  };
347
661
  const handleEditorMouseDown = () => {
348
- focusThreadCommentEditor(editorService, editorId, editor.current);
662
+ focusThreadCommentEditor(editorService, editorId, editorRef.current);
349
663
  setEditing(true);
350
664
  };
665
+ useEffect(() => {
666
+ mountedRef.current = true;
667
+ return () => {
668
+ mountedRef.current = false;
669
+ };
670
+ }, []);
351
671
  useEffect(() => {
352
672
  if (!autoFocus) return;
353
673
  const timer = setTimeout(() => {
354
- focusThreadCommentEditor(editorService, editorId, editor.current);
674
+ focusThreadCommentEditor(editorService, editorId, editorRef.current);
355
675
  });
356
676
  return () => clearTimeout(timer);
357
677
  }, [
@@ -365,7 +685,7 @@ const ThreadCommentEditor = forwardRef((props, ref) => {
365
685
  onMouseDown: handleEditorMouseDown,
366
686
  children: /* @__PURE__ */ jsx(RichTextEditor, {
367
687
  className: "univer-w-full",
368
- editorRef: editor,
688
+ editorRef,
369
689
  editorId,
370
690
  preserveHostFocus: true,
371
691
  autoFocus,
@@ -385,12 +705,12 @@ const ThreadCommentEditor = forwardRef((props, ref) => {
385
705
  }, 30);
386
706
  }
387
707
  })
388
- }), editing ? /* @__PURE__ */ jsxs("div", {
708
+ }), editing ? /* @__PURE__ */ jsxs(ActionRowComponent, {
389
709
  className: "univer-mt-3 univer-flex univer-flex-row univer-justify-end univer-gap-2",
390
710
  children: [/* @__PURE__ */ jsx(Button, {
391
711
  type: "button",
392
712
  onClick: () => {
393
- const currentEditor = editor.current;
713
+ const currentEditor = editorRef.current;
394
714
  currentEditor === null || currentEditor === void 0 || currentEditor.blur();
395
715
  currentEditor === null || currentEditor === void 0 || currentEditor.replaceText("", false);
396
716
  currentEditor === null || currentEditor === void 0 || currentEditor.setSelectionRanges([], false);
@@ -403,7 +723,7 @@ const ThreadCommentEditor = forwardRef((props, ref) => {
403
723
  }), /* @__PURE__ */ jsx(Button, {
404
724
  type: "button",
405
725
  variant: "primary",
406
- disabled: !canSubmit,
726
+ disabled: !canSubmit || submitting,
407
727
  onClick: handleSave,
408
728
  children: localeService.t(id ? "thread-comment-ui.editor.save" : "thread-comment-ui.editor.reply")
409
729
  })]
@@ -433,7 +753,7 @@ function formatCommentDateTime(value, region) {
433
753
  });
434
754
  }
435
755
  const ThreadCommentItem = (props) => {
436
- const { item, unitId, subUnitId, editing, onEditingChange, onReply, resolved, isRoot, onClose, onDeleteComment, type, threadCommentEditorId } = props;
756
+ const { item, unitId, subUnitId, editing, onEditingChange, onReply, resolved, isRoot, onClose, onDeleteComment, onAfterDeleteComment, type, threadCommentEditorId, DropdownComponent, EditorComponent } = props;
437
757
  const commandService = useDependency(ICommandService);
438
758
  const localeService = useDependency(LocaleService);
439
759
  const regionService = useDependency(RegionService);
@@ -448,14 +768,20 @@ const ThreadCommentItem = (props) => {
448
768
  const currentRegion = useObservable(regionService.currentRegion$, regionService.getCurrentRegion());
449
769
  const direction = useObservable(localeService.direction$, localeService.getDirection());
450
770
  const dateText = isMock ? null : formatCommentDateTime(item.dT, currentRegion);
451
- const handleDeleteItem = () => {
771
+ const handleDeleteItem = async () => {
452
772
  if ((onDeleteComment === null || onDeleteComment === void 0 ? void 0 : onDeleteComment(item)) === false) return;
453
- commandService.executeCommand(isRoot ? DeleteCommentTreeCommand.id : DeleteCommentCommand.id, {
454
- unitId,
455
- subUnitId,
456
- commentId: item.id
457
- });
458
- if (isRoot) onClose === null || onClose === void 0 || onClose();
773
+ try {
774
+ if (await commandService.executeCommand(isRoot ? DeleteCommentTreeCommand.id : DeleteCommentCommand.id, {
775
+ unitId,
776
+ subUnitId,
777
+ commentId: item.id
778
+ })) {
779
+ try {
780
+ await (onAfterDeleteComment === null || onAfterDeleteComment === void 0 ? void 0 : onAfterDeleteComment(item));
781
+ } catch {}
782
+ if (isRoot) onClose === null || onClose === void 0 || onClose();
783
+ }
784
+ } catch {}
459
785
  };
460
786
  return /* @__PURE__ */ jsxs("div", {
461
787
  className: "univer-relative univer-mb-3 univer-pl-[30px] rtl:univer-pl-0 rtl:univer-pr-[30px]",
@@ -471,39 +797,47 @@ const ThreadCommentItem = (props) => {
471
797
  children: [/* @__PURE__ */ jsx("div", {
472
798
  className: "univer-text-sm univer-font-medium univer-leading-5",
473
799
  children: (user === null || user === void 0 ? void 0 : user.name) || " "
474
- }), /* @__PURE__ */ jsxs("div", { children: [isMock || resolved ? null : showReply && user ? /* @__PURE__ */ jsx("div", {
475
- className: "univer-ml-1 univer-inline-flex univer-size-6 univer-cursor-pointer univer-items-center univer-justify-center univer-rounded-sm univer-text-base hover:univer-bg-gray-50 rtl:univer-ml-0 rtl:univer-mr-1 dark:hover:!univer-bg-gray-800",
800
+ }), /* @__PURE__ */ jsxs("div", { children: [isMock || resolved ? null : showReply && user ? /* @__PURE__ */ jsx("button", {
801
+ type: "button",
802
+ "aria-label": localeService.t("thread-comment-ui.editor.reply"),
803
+ className: "univer-ml-1 univer-inline-flex univer-size-6 univer-cursor-pointer univer-items-center univer-justify-center univer-rounded-sm univer-border-0 univer-bg-transparent univer-p-0 univer-text-base hover:univer-bg-gray-50 rtl:univer-ml-0 rtl:univer-mr-1 dark:hover:!univer-bg-gray-800",
476
804
  onClick: () => onReply(user),
477
805
  children: /* @__PURE__ */ jsx(ReplyToCommentIcon, {})
478
- }) : null, isCommentBySelf && !isMock && !resolved ? /* @__PURE__ */ jsx(Dropdown, {
806
+ }) : null, isCommentBySelf && !isMock && !resolved ? /* @__PURE__ */ jsx(DropdownComponent, {
479
807
  overlay: /* @__PURE__ */ jsx("div", {
480
808
  dir: direction,
481
809
  className: "univer-rounded-lg",
482
810
  children: /* @__PURE__ */ jsxs("ul", {
483
- className: "univer-m-0 univer-box-border univer-grid univer-list-none univer-p-1.5 univer-text-sm rtl:univer-text-right [&_a]:univer-block [&_a]:univer-cursor-pointer [&_a]:univer-rounded [&_a]:univer-px-2 [&_a]:univer-py-1.5 [&_a]:univer-transition-colors",
484
- children: [/* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx("a", {
811
+ className: "univer-m-0 univer-box-border univer-grid univer-list-none univer-p-1.5 univer-text-sm rtl:univer-text-right [&_button]:univer-block [&_button]:univer-w-full [&_button]:univer-cursor-pointer [&_button]:univer-rounded [&_button]:univer-border-0 [&_button]:univer-bg-transparent [&_button]:univer-px-2 [&_button]:univer-py-1.5 [&_button]:univer-text-left [&_button]:univer-transition-colors rtl:[&_button]:univer-text-right",
812
+ children: [/* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx("button", {
813
+ type: "button",
485
814
  className: "hover:univer-bg-gray-200",
486
815
  onClick: () => onEditingChange === null || onEditingChange === void 0 ? void 0 : onEditingChange(true),
487
816
  children: localeService.t("thread-comment-ui.item.edit")
488
- }) }), /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx("a", {
817
+ }) }), /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx("button", {
818
+ type: "button",
489
819
  className: "hover:univer-bg-gray-200",
490
820
  onClick: handleDeleteItem,
491
821
  children: localeService.t("thread-comment-ui.item.delete")
492
822
  }) })]
493
823
  })
494
824
  }),
495
- children: /* @__PURE__ */ jsx("div", {
496
- className: "univer-ml-1 univer-inline-flex univer-size-6 univer-cursor-pointer univer-items-center univer-justify-center univer-rounded-sm univer-text-base hover:univer-bg-gray-50 rtl:univer-ml-0 rtl:univer-mr-1 dark:hover:!univer-bg-gray-800",
825
+ children: /* @__PURE__ */ jsx("button", {
826
+ type: "button",
827
+ "aria-label": localeService.t("thread-comment-ui.item.more"),
828
+ className: "univer-ml-1 univer-inline-flex univer-size-6 univer-cursor-pointer univer-items-center univer-justify-center univer-rounded-sm univer-border-0 univer-bg-transparent univer-p-0 univer-text-base hover:univer-bg-gray-50 rtl:univer-ml-0 rtl:univer-mr-1 dark:hover:!univer-bg-gray-800",
497
829
  children: /* @__PURE__ */ jsx(MoreHorizontalIcon, {})
498
830
  })
499
831
  }) : null] })]
500
832
  }) : null,
501
833
  dateText && /* @__PURE__ */ jsx("time", {
502
- dir: "ltr",
503
834
  className: "univer-mb-1 univer-block univer-text-xs/normal univer-text-gray-600 rtl:univer-text-right dark:!univer-text-gray-200",
504
- children: dateText
835
+ children: /* @__PURE__ */ jsx("bdo", {
836
+ dir: "ltr",
837
+ children: dateText
838
+ })
505
839
  }),
506
- editing ? /* @__PURE__ */ jsx(ThreadCommentEditor, {
840
+ editing ? /* @__PURE__ */ jsx(EditorComponent, {
507
841
  type,
508
842
  id: item.id,
509
843
  comment: item,
@@ -512,9 +846,8 @@ const ThreadCommentItem = (props) => {
512
846
  unitId,
513
847
  subUnitId,
514
848
  editorId: threadCommentEditorId,
515
- onSave: ({ text, attachments }) => {
516
- onEditingChange === null || onEditingChange === void 0 || onEditingChange(false);
517
- commandService.executeCommand(UpdateCommentCommand.id, {
849
+ onSave: async ({ text, attachments }) => {
850
+ const success = await commandService.executeCommand(UpdateCommentCommand.id, {
518
851
  unitId,
519
852
  subUnitId,
520
853
  payload: {
@@ -523,27 +856,35 @@ const ThreadCommentItem = (props) => {
523
856
  attachments
524
857
  }
525
858
  });
859
+ if (success) onEditingChange === null || onEditingChange === void 0 || onEditingChange(false);
860
+ return success;
526
861
  }
527
862
  }) : /* @__PURE__ */ jsx("div", {
528
- className: "univer-text-sm univer-text-gray-900 dark:!univer-text-white",
529
- children: transformDocument2TextNodes(item.text).map((paragraph, i) => /* @__PURE__ */ jsx("div", {
530
- className: "univer-break-words",
531
- children: paragraph.map((item, i) => {
532
- switch (item.type) {
533
- case "mention": return /* @__PURE__ */ jsxs("a", {
534
- className: "univer-text-primary-600",
535
- children: [item.content.label, " "]
536
- }, i);
537
- default: return item.content;
538
- }
539
- })
540
- }, i))
863
+ className: "univer-text-sm univer-text-gray-900 dark:!univer-text-gray-0",
864
+ children: transformDocument2TextNodes(item.text).map((paragraph, paragraphIndex) => {
865
+ var _item$text$paragraphs;
866
+ let offset = 0;
867
+ return /* @__PURE__ */ jsx("div", {
868
+ className: "univer-break-words",
869
+ children: paragraph.map((node) => {
870
+ const key = offset;
871
+ offset += node.type === "mention" ? node.content.label.length : node.content.length;
872
+ switch (node.type) {
873
+ case "mention": return /* @__PURE__ */ jsxs("a", {
874
+ className: "univer-text-primary-600",
875
+ children: [node.content.label, " "]
876
+ }, key);
877
+ default: return node.content;
878
+ }
879
+ })
880
+ }, (_item$text$paragraphs = item.text.paragraphs) === null || _item$text$paragraphs === void 0 || (_item$text$paragraphs = _item$text$paragraphs[paragraphIndex]) === null || _item$text$paragraphs === void 0 ? void 0 : _item$text$paragraphs.paragraphId);
881
+ })
541
882
  })
542
883
  ]
543
884
  });
544
885
  };
545
886
  const ThreadCommentTree = (props) => {
546
- const { id, unitId, subUnitId, refStr, showEdit = true, onClick, showHighlight, onClose, getSubUnitName, location, autoFocus, onMouseEnter, onMouseLeave, onAddComment, onDeleteComment, onResolve, type, style, full } = props;
887
+ const { id, unitId, subUnitId, refStr, displayRef, showEdit = true, onClick, showHighlight, onClose, getSubUnitName, location, autoFocus, onMouseEnter, onMouseLeave, onAddComment, onDeleteComment, onAfterDeleteComment, onResolve, type, style, full, DropdownComponent = Dropdown, EditorComponent = ThreadCommentEditor } = props;
547
888
  const threadCommentModel = useDependency(ThreadCommentModel);
548
889
  const [isHover, setIsHover] = useState(false);
549
890
  const [editingId, setEditingId] = useState("");
@@ -556,6 +897,7 @@ const ThreadCommentTree = (props) => {
556
897
  updte$
557
898
  ]);
558
899
  const commandService = useDependency(ICommandService);
900
+ const localeService = useDependency(LocaleService);
559
901
  const userManagerService = useDependency(UserManagerService);
560
902
  const resolved = comments === null || comments === void 0 ? void 0 : comments.root.resolved;
561
903
  const currentUser = useObservable(userManagerService.currentUser$);
@@ -571,40 +913,49 @@ const ThreadCommentTree = (props) => {
571
913
  subUnitId,
572
914
  threadId: ""
573
915
  }], ...(comments === null || comments === void 0 ? void 0 : comments.children) ?? []];
574
- const scroller = useRef(null);
575
- const handleResolve = (e) => {
916
+ const scrollerRef = useRef(null);
917
+ const handleMouseLeave = useEvent(onMouseLeave);
918
+ const handleResolve = async (e) => {
576
919
  e.stopPropagation();
577
- if (!resolved) commandService.executeCommand(SetActiveCommentOperation.id);
578
- else commandService.executeCommand(SetActiveCommentOperation.id, {
579
- unitId,
580
- subUnitId,
581
- commentId: id
582
- });
583
- commandService.executeCommand(ResolveCommentCommand.id, {
584
- unitId,
585
- subUnitId,
586
- commentId: id,
587
- resolved: !resolved
588
- });
589
- onResolve === null || onResolve === void 0 || onResolve(!resolved);
920
+ try {
921
+ if (!await commandService.executeCommand(ResolveCommentCommand.id, {
922
+ unitId,
923
+ subUnitId,
924
+ commentId: id,
925
+ resolved: !resolved
926
+ })) return;
927
+ await commandService.executeCommand(SetActiveCommentOperation.id, resolved ? {
928
+ unitId,
929
+ subUnitId,
930
+ commentId: id
931
+ } : void 0);
932
+ onResolve === null || onResolve === void 0 || onResolve(!resolved);
933
+ } catch {}
590
934
  };
591
- const handleDeleteRoot = (e) => {
935
+ const handleDeleteRoot = async (e) => {
592
936
  e.stopPropagation();
593
- commandService.executeCommand(SetActiveCommentOperation.id);
594
- if ((comments === null || comments === void 0 ? void 0 : comments.root) && (onDeleteComment === null || onDeleteComment === void 0 ? void 0 : onDeleteComment(comments.root)) === false) return;
595
- commandService.executeCommand(DeleteCommentTreeCommand.id, {
596
- unitId,
597
- subUnitId,
598
- commentId: id
599
- });
600
- onClose === null || onClose === void 0 || onClose();
937
+ const root = comments === null || comments === void 0 ? void 0 : comments.root;
938
+ if (!root || (onDeleteComment === null || onDeleteComment === void 0 ? void 0 : onDeleteComment(root)) === false) return;
939
+ try {
940
+ if (await commandService.executeCommand(DeleteCommentTreeCommand.id, {
941
+ unitId,
942
+ subUnitId,
943
+ commentId: id
944
+ })) {
945
+ try {
946
+ await (onAfterDeleteComment === null || onAfterDeleteComment === void 0 ? void 0 : onAfterDeleteComment(root));
947
+ } catch {}
948
+ await commandService.executeCommand(SetActiveCommentOperation.id);
949
+ onClose === null || onClose === void 0 || onClose();
950
+ }
951
+ } catch {}
601
952
  };
602
953
  useEffect(() => {
603
- return onMouseLeave === null || onMouseLeave === void 0 ? void 0 : onMouseLeave();
604
- }, []);
954
+ return handleMouseLeave;
955
+ }, [handleMouseLeave]);
605
956
  const subUnitName = getSubUnitName((comments === null || comments === void 0 ? void 0 : comments.root.subUnitId) ?? subUnitId);
606
957
  const editorVisible = showEdit && !editingId && !resolved;
607
- const title = `${refStr || (comments === null || comments === void 0 ? void 0 : comments.root.ref) || ""}${subUnitName ? " · " : ""}${subUnitName}`;
958
+ const title = `${displayRef ?? refStr ?? (comments === null || comments === void 0 ? void 0 : comments.root.ref) ?? ""}${subUnitName ? " · " : ""}${subUnitName}`;
608
959
  const threadCommentEditorId = getThreadCommentEditorId({
609
960
  location,
610
961
  unitId,
@@ -614,7 +965,7 @@ const ThreadCommentTree = (props) => {
614
965
  });
615
966
  return /* @__PURE__ */ jsxs("div", {
616
967
  id: `${location}-${unitId}-${subUnitId}-${id}`,
617
- className: clsx("univer-relative univer-box-border univer-rounded-md univer-bg-white univer-p-4 dark:!univer-bg-gray-900 dark:!univer-text-white", borderClassName, {
968
+ className: clsx("univer-relative univer-box-border univer-rounded-md univer-bg-gray-0 univer-p-4 univer-text-gray-900 dark:!univer-bg-gray-900 dark:!univer-text-gray-0", borderClassName, {
618
969
  "univer-w-[278px]": !full,
619
970
  "univer-w-full": full,
620
971
  "univer-shadow": !resolved && (showHighlight || isHover || location === "CELL")
@@ -645,19 +996,23 @@ const ThreadCommentTree = (props) => {
645
996
  })]
646
997
  }), !!comments && /* @__PURE__ */ jsxs("div", {
647
998
  className: "univer-flex univer-flex-shrink-0 univer-flex-grow-0 univer-flex-row",
648
- children: [/* @__PURE__ */ jsx("div", {
649
- className: clsx("univer-ml-1 univer-inline-flex univer-size-6 univer-cursor-pointer univer-items-center univer-justify-center univer-rounded-[3px] univer-text-base hover:univer-bg-gray-50 rtl:univer-ml-0 rtl:univer-mr-1 dark:hover:!univer-bg-gray-800", { "univer-text-green-500": resolved }),
999
+ children: [/* @__PURE__ */ jsx("button", {
1000
+ type: "button",
1001
+ "aria-label": localeService.t(resolved ? "thread-comment-ui.filter.status.unsolved" : "thread-comment-ui.filter.status.resolved"),
1002
+ className: clsx("univer-ml-1 univer-inline-flex univer-size-6 univer-cursor-pointer univer-items-center univer-justify-center univer-rounded-[3px] univer-border-0 univer-bg-transparent univer-p-0 univer-text-base hover:univer-bg-gray-50 rtl:univer-ml-0 rtl:univer-mr-1 dark:hover:!univer-bg-gray-800", { "univer-text-green-500": resolved }),
650
1003
  onClick: handleResolve,
651
1004
  children: resolved ? /* @__PURE__ */ jsx(SuccessIcon, {}) : /* @__PURE__ */ jsx(SuccessOutlineIcon, {})
652
- }), (currentUser === null || currentUser === void 0 ? void 0 : currentUser.userID) === comments.root.personId ? /* @__PURE__ */ jsx("div", {
653
- className: "univer-ml-1 univer-inline-flex univer-size-6 univer-cursor-pointer univer-items-center univer-justify-center univer-rounded-[3px] univer-text-base hover:univer-bg-gray-50 rtl:univer-ml-0 rtl:univer-mr-1 dark:hover:!univer-bg-gray-800",
1005
+ }), (currentUser === null || currentUser === void 0 ? void 0 : currentUser.userID) === comments.root.personId ? /* @__PURE__ */ jsx("button", {
1006
+ type: "button",
1007
+ "aria-label": localeService.t("thread-comment-ui.item.delete"),
1008
+ className: "univer-ml-1 univer-inline-flex univer-size-6 univer-cursor-pointer univer-items-center univer-justify-center univer-rounded-[3px] univer-border-0 univer-bg-transparent univer-p-0 univer-text-base hover:univer-bg-gray-50 rtl:univer-ml-0 rtl:univer-mr-1 dark:hover:!univer-bg-gray-800",
654
1009
  onClick: handleDeleteRoot,
655
1010
  children: /* @__PURE__ */ jsx(DeleteIcon, {})
656
1011
  }) : null]
657
1012
  })]
658
1013
  }),
659
1014
  /* @__PURE__ */ jsx("div", {
660
- ref: scroller,
1015
+ ref: scrollerRef,
661
1016
  className: clsx("univer-max-h-80 univer-overflow-y-auto univer-overflow-x-hidden", scrollbarClassName, location === "PANEL" && "-univer-mx-4 univer-px-4"),
662
1017
  children: renderComments.map((item) => /* @__PURE__ */ jsx(ThreadCommentItem, {
663
1018
  unitId,
@@ -668,6 +1023,8 @@ const ThreadCommentTree = (props) => {
668
1023
  resolved: comments === null || comments === void 0 ? void 0 : comments.root.resolved,
669
1024
  type,
670
1025
  threadCommentEditorId,
1026
+ DropdownComponent,
1027
+ EditorComponent,
671
1028
  onClose,
672
1029
  onEditingChange: (editing) => {
673
1030
  if (editing) setEditingId(item.id);
@@ -689,11 +1046,11 @@ const ThreadCommentTree = (props) => {
689
1046
  }]));
690
1047
  });
691
1048
  },
692
- onAddComment,
693
- onDeleteComment
1049
+ onDeleteComment,
1050
+ onAfterDeleteComment
694
1051
  }, item.id))
695
1052
  }),
696
- editorVisible && /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(ThreadCommentEditor, {
1053
+ editorVisible && /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(EditorComponent, {
697
1054
  ref: editorRef,
698
1055
  type,
699
1056
  unitId,
@@ -712,13 +1069,18 @@ const ThreadCommentTree = (props) => {
712
1069
  subUnitId,
713
1070
  threadId: (comments === null || comments === void 0 ? void 0 : comments.root.threadId) ?? ""
714
1071
  };
715
- if ((onAddComment === null || onAddComment === void 0 ? void 0 : onAddComment(comment)) === false) return;
716
- await commandService.executeCommand(AddCommentCommand.id, {
1072
+ if (await (onAddComment === null || onAddComment === void 0 ? void 0 : onAddComment(comment)) === false) {
1073
+ if (!comments) onClose === null || onClose === void 0 || onClose();
1074
+ return true;
1075
+ }
1076
+ const success = await commandService.executeCommand(AddCommentCommand.id, {
717
1077
  unitId,
718
1078
  subUnitId,
719
1079
  comment
720
1080
  });
721
- if (scroller.current) scroller.current.scrollTop = scroller.current.scrollHeight;
1081
+ if (success && scrollerRef.current) scrollerRef.current.scrollTop = scrollerRef.current.scrollHeight;
1082
+ if (success && !comments) onClose === null || onClose === void 0 || onClose();
1083
+ return success;
722
1084
  },
723
1085
  autoFocus: autoFocus || !comments,
724
1086
  onCancel: () => {
@@ -732,22 +1094,25 @@ const ThreadCommentTree = (props) => {
732
1094
  //#endregion
733
1095
  //#region src/views/ThreadCommentPanel.tsx
734
1096
  const ThreadCommentPanel = (props) => {
735
- const { unitId, subUnitId$, type, onAdd, getSubUnitName, onResolve, sortComments, onItemLeave, onItemEnter, disableAdd, tempComment, onAddComment, onDeleteComment, showComments } = props;
1097
+ const { unitId, subUnitId$, type, onAdd, getSubUnitName, onResolve, sortComments, onItemLeave, onItemEnter, disableAdd, tempComment, onAddComment, onDeleteComment, onAfterDeleteComment, showComments, formatRef, onTempCommentClose, autoFocusActiveComment = false, ActionRowComponent = ActionRow, SelectComponent = Select, ThreadCommentTreeComponent = ThreadCommentTree } = props;
736
1098
  const [unit, setUnit] = useState("all");
737
1099
  const [status, setStatus] = useState("all");
738
1100
  const localeService = useDependency(LocaleService);
739
1101
  const userService = useDependency(UserManagerService);
740
1102
  const threadCommentModel = useDependency(ThreadCommentModel);
741
- const [unitComments, setUnitComments] = useState(() => threadCommentModel.getUnit(unitId));
742
- const activeCommentId = useObservable(useDependency(ThreadCommentPanelService).activeCommentId$);
743
- const update = useObservable(threadCommentModel.commentUpdate$);
1103
+ const panelService = useDependency(ThreadCommentPanelService);
1104
+ const activeCommentId = useObservable(panelService.activeCommentId$);
1105
+ useObservable(threadCommentModel.commentUpdate$);
1106
+ const unitComments = threadCommentModel.getUnit(unitId);
1107
+ const scopedTempComment = (tempComment === null || tempComment === void 0 ? void 0 : tempComment.unitId) === unitId ? tempComment : null;
1108
+ const shouldClearActiveTarget = shouldClearThreadCommentTarget(activeCommentId, unitId, activeCommentId ? Boolean(threadCommentModel.getComment(activeCommentId.unitId, activeCommentId.subUnitId, activeCommentId.commentId) || scopedTempComment && isSameThreadCommentTarget(activeCommentId, scopedTempComment)) : false);
744
1109
  const commandService = useDependency(ICommandService);
745
1110
  const subUnitId = useObservable(subUnitId$);
746
- const shouldScroll = useRef(true);
1111
+ const shouldScrollRef = useRef(true);
747
1112
  const location = "PANEL";
748
1113
  const currentUser = useObservable(userService.currentUser$);
749
1114
  const comments = useMemo(() => {
750
- const allComments = unit === "all" ? unitComments : unitComments.filter((i) => i.subUnitId === subUnitId) ?? [];
1115
+ const allComments = unit === "all" && type !== UniverInstanceType.UNIVER_SLIDE ? unitComments : unitComments.filter((i) => i.subUnitId === subUnitId);
751
1116
  const sort = sortComments ?? ((a) => a);
752
1117
  const res = allComments.map((i) => ({
753
1118
  ...i.root,
@@ -766,7 +1131,8 @@ const ThreadCommentPanel = (props) => {
766
1131
  unit,
767
1132
  unitComments,
768
1133
  sortComments,
769
- subUnitId
1134
+ subUnitId,
1135
+ type
770
1136
  ]);
771
1137
  const commentsSorted = useMemo(() => [...comments.filter((comment) => !comment.resolved), ...comments.filter((comment) => comment.resolved)], [comments]);
772
1138
  const statuedComments = useMemo(() => {
@@ -782,7 +1148,7 @@ const ThreadCommentPanel = (props) => {
782
1148
  currentUser === null || currentUser === void 0 ? void 0 : currentUser.userID,
783
1149
  status
784
1150
  ]);
785
- const renderComments = tempComment ? [tempComment, ...statuedComments] : statuedComments;
1151
+ const renderComments = scopedTempComment ? [scopedTempComment, ...statuedComments] : statuedComments;
786
1152
  const unSolvedComments = renderComments.filter((comment) => !comment.resolved);
787
1153
  const solvedComments = renderComments.filter((comment) => comment.resolved);
788
1154
  const isFiltering = status !== "all" || unit !== "all";
@@ -791,24 +1157,49 @@ const ThreadCommentPanel = (props) => {
791
1157
  setUnit("all");
792
1158
  };
793
1159
  useEffect(() => {
794
- if (unitId) setUnitComments(threadCommentModel.getUnit(unitId));
1160
+ if (shouldClearActiveTarget) panelService.setActiveComment(void 0);
1161
+ }, [panelService, shouldClearActiveTarget]);
1162
+ useEffect(() => {
1163
+ if (tempComment && (tempComment.unitId !== unitId || subUnitId && tempComment.subUnitId !== subUnitId)) onTempCommentClose === null || onTempCommentClose === void 0 || onTempCommentClose();
795
1164
  }, [
796
- unitId,
797
- threadCommentModel,
798
- update
1165
+ onTempCommentClose,
1166
+ subUnitId,
1167
+ tempComment,
1168
+ unitId
1169
+ ]);
1170
+ useEffect(() => {
1171
+ if (!activeCommentId) return;
1172
+ const handlePointerDown = (event) => {
1173
+ const activeComment = panelService.activeCommentId;
1174
+ const target = event.target;
1175
+ if (event.button !== 0 || !activeComment || !(target instanceof Element)) return;
1176
+ const activeElement = document.getElementById(`${location}-${activeComment.unitId}-${activeComment.subUnitId}-${activeComment.commentId}`);
1177
+ if ((activeElement === null || activeElement === void 0 ? void 0 : activeElement.contains(target)) || target.closest("button, input, textarea, select, a, [contenteditable=\"true\"], [role=\"menu\"], [role=\"menuitem\"], [role=\"option\"], [role=\"listbox\"], [role=\"combobox\"], [role=\"separator\"]")) return;
1178
+ commandService.executeCommand(SetActiveCommentOperation.id);
1179
+ if (scopedTempComment && isSameThreadCommentTarget(activeComment, scopedTempComment)) onTempCommentClose === null || onTempCommentClose === void 0 || onTempCommentClose();
1180
+ };
1181
+ document.addEventListener("pointerdown", handlePointerDown, true);
1182
+ return () => document.removeEventListener("pointerdown", handlePointerDown, true);
1183
+ }, [
1184
+ activeCommentId,
1185
+ commandService,
1186
+ location,
1187
+ onTempCommentClose,
1188
+ panelService,
1189
+ scopedTempComment
799
1190
  ]);
800
1191
  useEffect(() => {
801
1192
  var _document$getElementB;
802
1193
  if (!activeCommentId) return;
803
- if (!shouldScroll.current) {
804
- shouldScroll.current = true;
1194
+ if (!shouldScrollRef.current) {
1195
+ shouldScrollRef.current = true;
805
1196
  return;
806
1197
  }
807
1198
  const { unitId, subUnitId, commentId } = activeCommentId;
808
1199
  const id = `${location}-${unitId}-${subUnitId}-${commentId}`;
809
1200
  (_document$getElementB = document.getElementById(id)) === null || _document$getElementB === void 0 || _document$getElementB.scrollIntoView({ block: "center" });
810
- }, [activeCommentId]);
811
- const renderComment = (section) => (comment, index) => /* @__PURE__ */ jsx(ThreadCommentTree, {
1201
+ }, [activeCommentId, location]);
1202
+ const renderComment = (section) => (comment, index) => /* @__PURE__ */ jsx(ThreadCommentTreeComponent, {
812
1203
  full: true,
813
1204
  location,
814
1205
  getSubUnitName,
@@ -816,11 +1207,13 @@ const ThreadCommentPanel = (props) => {
816
1207
  unitId: comment.unitId,
817
1208
  subUnitId: comment.subUnitId,
818
1209
  refStr: comment.ref,
1210
+ displayRef: formatRef === null || formatRef === void 0 ? void 0 : formatRef(comment),
819
1211
  type,
820
- showEdit: (activeCommentId === null || activeCommentId === void 0 ? void 0 : activeCommentId.commentId) === comment.id,
821
- showHighlight: (activeCommentId === null || activeCommentId === void 0 ? void 0 : activeCommentId.commentId) === comment.id,
1212
+ showEdit: !comment.id || isSameThreadCommentTarget(activeCommentId, comment),
1213
+ showHighlight: isSameThreadCommentTarget(activeCommentId, comment),
1214
+ autoFocus: autoFocusActiveComment && isSameThreadCommentTarget(activeCommentId, comment),
822
1215
  onClick: () => {
823
- shouldScroll.current = false;
1216
+ shouldScrollRef.current = false;
824
1217
  if (!comment.resolved) commandService.executeCommand(SetActiveCommentOperation.id, {
825
1218
  unitId: comment.unitId,
826
1219
  subUnitId: comment.subUnitId,
@@ -829,17 +1222,30 @@ const ThreadCommentPanel = (props) => {
829
1222
  });
830
1223
  else commandService.executeCommand(SetActiveCommentOperation.id);
831
1224
  },
832
- onMouseEnter: () => onItemEnter === null || onItemEnter === void 0 ? void 0 : onItemEnter(comment),
833
- onMouseLeave: () => onItemLeave === null || onItemLeave === void 0 ? void 0 : onItemLeave(comment),
1225
+ onMouseEnter: () => {
1226
+ panelService.setHoveredComment({
1227
+ unitId: comment.unitId,
1228
+ subUnitId: comment.subUnitId,
1229
+ commentId: comment.id,
1230
+ trigger: "panel-hover"
1231
+ });
1232
+ onItemEnter === null || onItemEnter === void 0 || onItemEnter(comment);
1233
+ },
1234
+ onMouseLeave: () => {
1235
+ if (isSameThreadCommentTarget(panelService.hoveredCommentId, comment)) panelService.setHoveredComment(void 0);
1236
+ onItemLeave === null || onItemLeave === void 0 || onItemLeave(comment);
1237
+ },
834
1238
  onAddComment,
835
1239
  onDeleteComment,
836
- onResolve: (resolved) => onResolve === null || onResolve === void 0 ? void 0 : onResolve(comment.id, resolved)
1240
+ onAfterDeleteComment,
1241
+ onResolve: (resolved) => onResolve === null || onResolve === void 0 ? void 0 : onResolve(comment.id, resolved),
1242
+ onClose: !comment.id ? onTempCommentClose : void 0
837
1243
  }, getThreadCommentPanelItemKey(comment, index, section));
838
1244
  return /* @__PURE__ */ jsxs("div", {
839
1245
  className: "univer-flex univer-min-h-full univer-flex-col univer-pb-3",
840
1246
  children: [/* @__PURE__ */ jsxs("div", {
841
1247
  className: "univer-mt-3 univer-flex univer-flex-row univer-justify-between",
842
- children: [type === UniverInstanceType.UNIVER_SHEET ? /* @__PURE__ */ jsx(Select, {
1248
+ children: [type === UniverInstanceType.UNIVER_SHEET ? /* @__PURE__ */ jsx(SelectComponent, {
843
1249
  borderless: true,
844
1250
  value: unit,
845
1251
  options: [{
@@ -850,7 +1256,7 @@ const ThreadCommentPanel = (props) => {
850
1256
  label: localeService.t("thread-comment-ui.filter.sheet.all")
851
1257
  }],
852
1258
  onChange: setUnit
853
- }) : null, /* @__PURE__ */ jsx(Select, {
1259
+ }) : null, /* @__PURE__ */ jsx(SelectComponent, {
854
1260
  borderless: true,
855
1261
  value: status,
856
1262
  options: [
@@ -875,13 +1281,13 @@ const ThreadCommentPanel = (props) => {
875
1281
  })]
876
1282
  }), renderComments.length === 0 ? /* @__PURE__ */ jsxs("div", {
877
1283
  className: "univer-flex univer-flex-1 univer-flex-col univer-items-center univer-justify-center univer-text-sm univer-text-gray-600 dark:!univer-text-gray-200",
878
- children: [localeService.t("thread-comment-ui.panel.empty"), isFiltering ? /* @__PURE__ */ jsx("div", {
1284
+ children: [localeService.t("thread-comment-ui.panel.empty"), isFiltering ? /* @__PURE__ */ jsx(ActionRowComponent, {
879
1285
  className: "univer-mt-2 univer-flex univer-flex-row",
880
1286
  children: /* @__PURE__ */ jsx(Button, {
881
1287
  onClick: onReset,
882
1288
  children: localeService.t("thread-comment-ui.panel.reset")
883
1289
  })
884
- }) : !disableAdd ? /* @__PURE__ */ jsx("div", {
1290
+ }) : !disableAdd ? /* @__PURE__ */ jsx(ActionRowComponent, {
885
1291
  className: "univer-mt-2 univer-flex univer-flex-row",
886
1292
  children: /* @__PURE__ */ jsxs(Button, {
887
1293
  onClick: onAdd,
@@ -903,4 +1309,33 @@ const ThreadCommentPanel = (props) => {
903
1309
  };
904
1310
 
905
1311
  //#endregion
906
- export { SetActiveCommentOperation, ThreadCommentPanel, ThreadCommentPanelService, ThreadCommentTree, ThreadCommentTreeLocation, UniverThreadCommentUIPlugin };
1312
+ //#region src/views/mobile/MobileThreadCommentEditor.tsx
1313
+ const MobileThreadCommentEditor = forwardRef((props, ref) => /* @__PURE__ */ jsx(ThreadCommentEditor, {
1314
+ ...props,
1315
+ ref,
1316
+ ActionRowComponent: MobileActionRowGroup
1317
+ }));
1318
+
1319
+ //#endregion
1320
+ //#region src/views/mobile/MobileThreadCommentTree.tsx
1321
+ function MobileThreadCommentTree(props) {
1322
+ return /* @__PURE__ */ jsx(ThreadCommentTree, {
1323
+ ...props,
1324
+ DropdownComponent: MobileDropdown,
1325
+ EditorComponent: MobileThreadCommentEditor
1326
+ });
1327
+ }
1328
+
1329
+ //#endregion
1330
+ //#region src/views/mobile/MobileThreadCommentPanel.tsx
1331
+ function MobileThreadCommentPanel(props) {
1332
+ return /* @__PURE__ */ jsx(ThreadCommentPanel, {
1333
+ ...props,
1334
+ ActionRowComponent: MobileActionRowGroup,
1335
+ SelectComponent: MobileSelect,
1336
+ ThreadCommentTreeComponent: MobileThreadCommentTree
1337
+ });
1338
+ }
1339
+
1340
+ //#endregion
1341
+ export { MobileThreadCommentPanel, MobileThreadCommentTree, SetActiveCommentOperation, ThreadCommentCanvasOverlay, ThreadCommentDraftService, ThreadCommentPanel, ThreadCommentPanelService, ThreadCommentTree, ThreadCommentTreeLocation, UniverThreadCommentMobileUIPlugin, UniverThreadCommentUIPlugin };