@a3s-lab/office 0.7.2 → 0.8.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 (28) hide show
  1. package/COLLABORATION_ROADMAP.md +81 -26
  2. package/README.md +48 -4
  3. package/dist/0~document-editor.js +414 -247
  4. package/dist/8928.js +689 -49
  5. package/dist/9787.js +14 -4
  6. package/dist/core.d.ts +2 -2
  7. package/dist/internal/collaboration/office-collaboration.d.ts +4 -2
  8. package/dist/internal/collaboration/office-document-collaboration-change-decisions.d.ts +7 -0
  9. package/dist/internal/collaboration/office-document-collaboration-claims.d.ts +2 -1
  10. package/dist/internal/collaboration/office-document-collaboration-comment-permissions.d.ts +3 -0
  11. package/dist/internal/collaboration/office-document-collaboration-sidecars.d.ts +3 -1
  12. package/dist/internal/collaboration/office-document-collaboration-suggestions.d.ts +6 -0
  13. package/dist/internal/collaboration/office-document-collaboration.d.ts +6 -2
  14. package/dist/internal/features/work/editors/document-changes-panel.d.ts +7 -1
  15. package/dist/internal/features/work/editors/document-comment-composer.d.ts +1 -0
  16. package/dist/internal/features/work/editors/document-comments-panel.d.ts +3 -1
  17. package/dist/internal/features/work/editors/document-selection-toolbar.d.ts +2 -1
  18. package/dist/internal/features/work/editors/document-toolbar.d.ts +5 -1
  19. package/dist/internal/features/work/editors/use-document-comments.d.ts +6 -1
  20. package/dist/internal/features/work/work-document-changes.d.ts +5 -2
  21. package/dist/internal/features/work/work-document-comments.d.ts +5 -1
  22. package/dist/internal/features/work/work-document-extensions.d.ts +1 -0
  23. package/dist/internal/features/work/work-document-paragraph-identity.d.ts +1 -0
  24. package/dist/internal/features/work/work-document-table-row-identity.d.ts +5 -1
  25. package/dist/internal/features/work/work-types.d.ts +22 -0
  26. package/dist/office-kernel.wasm +0 -0
  27. package/dist/styles.css +76 -0
  28. package/package.json +12 -3
@@ -6,7 +6,7 @@ import { Fragment as external_react_Fragment, forwardRef, useCallback, useEffect
6
6
  import { Extension, createNodeFromContent } from "@tiptap/core";
7
7
  import { NodeSelection, Plugin, PluginKey, TextSelection } from "@tiptap/pm/state";
8
8
  import { Decoration, DecorationSet } from "@tiptap/pm/view";
9
- import { AArrowDown, AArrowUp, AlignCenter, AlignJustify, AlignLeft, AlignRight, AlignVerticalJustifyCenter, AlignVerticalJustifyEnd, AlignVerticalJustifyStart, ArrowDown, ArrowUp, BetweenHorizontalEnd, BetweenHorizontalStart, BetweenVerticalEnd, BetweenVerticalStart, Bold, BookMarked, BookOpen, Bookmark, Check, CheckCheck, CheckCircle2, ChevronDown, ChevronRight, ChevronUp, ClipboardCopy, ClipboardPaste, Cloud, Columns3, Eraser, FileDiff, FilePlus2, FileText, Globe2, Grid2X2, Hash, Highlighter, Image, IndentDecrease, IndentIncrease, Italic, Link2, List, ListChecks, ListOrdered, MessageSquarePlus, MessageSquareReply, MessagesSquare, MoveVertical, Paintbrush, Palette, PanelBottom, PanelBottomOpen, PanelLeftOpen, PanelTop, PanelTopOpen, Pilcrow, PilcrowLeft, PilcrowRight, Plus, Quote, Redo2, RefreshCw, Replace, ReplaceAll, RotateCcw, Rows3, Ruler, Scan, Search, Settings2, StretchHorizontal, Strikethrough, Subscript, Superscript, Table2, TableCellsMerge, TableCellsSplit, TableProperties, TextWrap, Trash2, TriangleAlert, Underline, Undo2, Unlink, X, XCircle, ZoomIn, ZoomOut } from "lucide-react";
9
+ import { AArrowDown, AArrowUp, AlignCenter, AlignJustify, AlignLeft, AlignRight, AlignVerticalJustifyCenter, AlignVerticalJustifyEnd, AlignVerticalJustifyStart, ArrowDown, ArrowUp, BetweenHorizontalEnd, BetweenHorizontalStart, BetweenVerticalEnd, BetweenVerticalStart, Bold, BookMarked, BookOpen, Bookmark, Check, CheckCheck, CheckCircle2, ChevronDown, ChevronRight, ChevronUp, ClipboardCopy, ClipboardPaste, Cloud, Columns3, Eraser, FileDiff, FilePlus2, FileText, Globe2, Grid2X2, Hash, Highlighter, Image, IndentDecrease, IndentIncrease, Italic, Link2, List, ListChecks, ListOrdered, MessageSquarePlus, MessageSquareReply, MessagesSquare, MoveVertical, Paintbrush, Palette, PanelBottom, PanelBottomOpen, PanelLeftOpen, PanelTop, PanelTopOpen, Pilcrow, PilcrowLeft, PilcrowRight, Plus, Quote, Redo2, RefreshCw, Replace, ReplaceAll, RotateCcw, Rows3, Ruler, Scan, Search, Settings2, StretchHorizontal, Strikethrough, Subscript, Superscript, Table2, TableCellsMerge, TableCellsSplit, TableProperties, TextWrap, Trash2, TriangleAlert, Underline, Undo2, Unlink, Unlink2, X, XCircle, ZoomIn, ZoomOut } from "lucide-react";
10
10
  import { Node as model_Node } from "@tiptap/pm/model";
11
11
  import extension_color from "@tiptap/extension-color";
12
12
  import { TableKit } from "@tiptap/extension-table";
@@ -605,7 +605,7 @@ function DocumentTaskPane({ ariaLabel, title, description, closeLabel, className
605
605
  const DOCUMENT_CHANGE_ITEM_HEIGHT = 84;
606
606
  const DOCUMENT_CHANGE_ITEM_GAP = 7;
607
607
  const DOCUMENT_CHANGE_LIST_PADDING_TOP = 10;
608
- function DocumentChangesPanel({ editor, changes, trackChanges, onTrackChangesChange, onClose }) {
608
+ function DocumentChangesPanel({ editor, changes, decisions = [], trackChanges, suggestionOnly = false, onDecideChanges, onTrackChangesChange, onClose }) {
609
609
  const officeDialog = useOfficeDialog();
610
610
  const decisionButtonRefs = useRef(new Map());
611
611
  const pendingFocusRef = useRef(null);
@@ -654,7 +654,9 @@ function DocumentChangesPanel({ editor, changes, trackChanges, onTrackChangesCha
654
654
  decision
655
655
  };
656
656
  setRovingChangeKey(nextChangeKey);
657
- const handled = 'accept' === decision ? editor.commands.acceptDocumentChange(change.id) : editor.commands.rejectDocumentChange(change.id);
657
+ const handled = onDecideChanges ? onDecideChanges([
658
+ change
659
+ ], decision) : 'accept' === decision ? editor.commands.acceptDocumentChange(change.id) : editor.commands.rejectDocumentChange(change.id);
658
660
  if (!handled) {
659
661
  pendingFocusRef.current = null;
660
662
  setRovingChangeKey(currentChangeKey);
@@ -673,7 +675,8 @@ function DocumentChangesPanel({ editor, changes, trackChanges, onTrackChangesCha
673
675
  confirmLabel: '全部接受'
674
676
  });
675
677
  if (confirmed && !editor.isDestroyed) {
676
- editor.commands.acceptAllDocumentChanges();
678
+ if (onDecideChanges) onDecideChanges(changes, 'accept');
679
+ else editor.commands.acceptAllDocumentChanges();
677
680
  requestAnimationFrame(()=>{
678
681
  if (!editor.isDestroyed) editor.view.dom.focus();
679
682
  });
@@ -687,7 +690,8 @@ function DocumentChangesPanel({ editor, changes, trackChanges, onTrackChangesCha
687
690
  confirmTone: 'danger'
688
691
  });
689
692
  if (confirmed && !editor.isDestroyed) {
690
- editor.commands.rejectAllDocumentChanges();
693
+ if (onDecideChanges) onDecideChanges(changes, 'reject');
694
+ else editor.commands.rejectAllDocumentChanges();
691
695
  requestAnimationFrame(()=>{
692
696
  if (!editor.isDestroyed) editor.view.dom.focus();
693
697
  });
@@ -698,11 +702,11 @@ function DocumentChangesPanel({ editor, changes, trackChanges, onTrackChangesCha
698
702
  /*#__PURE__*/ jsxs(DocumentTaskPane, {
699
703
  className: "work-document-changes-panel",
700
704
  title: "修订审阅",
701
- description: changes.length ? `${changes.length} 项待处理` : '没有待处理的修订',
705
+ description: changes.length ? `${changes.length} 项待处理 · ${decisions.length} 项已决定` : decisions.length ? `没有待处理的修订 · ${decisions.length} 项已决定` : '没有待处理的修订',
702
706
  closeLabel: "关闭修订审阅",
703
707
  onClose: onClose,
704
708
  children: [
705
- changes.length > 0 && /*#__PURE__*/ jsxs("div", {
709
+ changes.length > 0 && !suggestionOnly && /*#__PURE__*/ jsxs("div", {
706
710
  className: "work-document-changes-bulk-actions",
707
711
  children: [
708
712
  /*#__PURE__*/ jsxs(button_Button, {
@@ -778,7 +782,7 @@ function DocumentChangesPanel({ editor, changes, trackChanges, onTrackChangesCha
778
782
  })
779
783
  ]
780
784
  }),
781
- /*#__PURE__*/ jsxs("div", {
785
+ !suggestionOnly && /*#__PURE__*/ jsxs("div", {
782
786
  children: [
783
787
  /*#__PURE__*/ jsxs(button_Button, {
784
788
  ref: (element)=>{
@@ -822,7 +826,7 @@ function DocumentChangesPanel({ editor, changes, trackChanges, onTrackChangesCha
822
826
  children: /*#__PURE__*/ jsx(CollectionState, {
823
827
  className: "work-document-changes-empty",
824
828
  icon: /*#__PURE__*/ jsx(FileDiff, {}),
825
- actions: /*#__PURE__*/ jsx(button_Button, {
829
+ actions: suggestionOnly ? void 0 : /*#__PURE__*/ jsx(button_Button, {
826
830
  size: "compact",
827
831
  tone: trackChanges ? 'quiet' : 'primary',
828
832
  onClick: ()=>onTrackChangesChange(!trackChanges),
@@ -830,8 +834,11 @@ function DocumentChangesPanel({ editor, changes, trackChanges, onTrackChangesCha
830
834
  }),
831
835
  tone: trackChanges ? 'info' : 'neutral',
832
836
  role: "status",
833
- children: trackChanges ? '正在记录新的改动。' : '当前没有记录新的改动。'
837
+ children: suggestionOnly ? '建议模式会自动记录带身份的新改动。' : trackChanges ? '正在记录新的改动。' : '当前没有记录新的改动。'
834
838
  })
839
+ }),
840
+ decisions.length > 0 && /*#__PURE__*/ jsx(DocumentChangeDecisionHistory, {
841
+ decisions: decisions
835
842
  })
836
843
  ]
837
844
  }),
@@ -839,6 +846,49 @@ function DocumentChangesPanel({ editor, changes, trackChanges, onTrackChangesCha
839
846
  ]
840
847
  });
841
848
  }
849
+ function DocumentChangeDecisionHistory({ decisions }) {
850
+ const visible = decisions.slice(-20).reverse();
851
+ return /*#__PURE__*/ jsxs("section", {
852
+ className: "work-document-change-decisions",
853
+ "aria-label": "修订决定记录",
854
+ children: [
855
+ /*#__PURE__*/ jsxs("header", {
856
+ children: [
857
+ /*#__PURE__*/ jsx("strong", {
858
+ children: "决定记录"
859
+ }),
860
+ /*#__PURE__*/ jsxs("span", {
861
+ children: [
862
+ decisions.length,
863
+ " 项"
864
+ ]
865
+ })
866
+ ]
867
+ }),
868
+ /*#__PURE__*/ jsx("ol", {
869
+ children: visible.map((decision)=>/*#__PURE__*/ jsxs("li", {
870
+ "data-document-change-decision": decision.decision,
871
+ children: [
872
+ /*#__PURE__*/ jsx("span", {
873
+ children: 'accept' === decision.decision ? '已接受' : '已拒绝'
874
+ }),
875
+ /*#__PURE__*/ jsx("strong", {
876
+ children: decision.text.trim() || '(空白字符)'
877
+ }),
878
+ /*#__PURE__*/ jsxs("small", {
879
+ children: [
880
+ decision.suggestedBy,
881
+ " → ",
882
+ decision.decidedBy,
883
+ decision.decidedAt ? ` · ${formatChangeDate(decision.decidedAt)}` : ''
884
+ ]
885
+ })
886
+ ]
887
+ }, decision.id))
888
+ })
889
+ ]
890
+ });
891
+ }
842
892
  function documentChangeDecisionKey(changeKey, decision) {
843
893
  return `${changeKey}:${decision}`;
844
894
  }
@@ -1608,7 +1658,7 @@ function optionalValue(value) {
1608
1658
  function sameSourceDraft(left, right) {
1609
1659
  return Object.keys(left).every((key)=>left[key] === right[key]);
1610
1660
  }
1611
- const document_comment_composer_DocumentCommentComposer = /*#__PURE__*/ forwardRef(function({ draft, top, onCancel, onDirtyChange, onSubmit }, forwardedRef) {
1661
+ const document_comment_composer_DocumentCommentComposer = /*#__PURE__*/ forwardRef(function({ author = '我', draft, top, onCancel, onDirtyChange, onSubmit }, forwardedRef) {
1612
1662
  const titleId = useId();
1613
1663
  const inputRef = useRef(null);
1614
1664
  const [text, setText] = useState('');
@@ -1660,7 +1710,8 @@ const document_comment_composer_DocumentCommentComposer = /*#__PURE__*/ forwardR
1660
1710
  children: [
1661
1711
  /*#__PURE__*/ jsx("span", {
1662
1712
  className: "work-document-comment-avatar",
1663
- children: "我"
1713
+ title: author,
1714
+ children: commentAuthorInitials(author)
1664
1715
  }),
1665
1716
  /*#__PURE__*/ jsxs("span", {
1666
1717
  className: "work-document-comment-composer-heading",
@@ -1669,9 +1720,13 @@ const document_comment_composer_DocumentCommentComposer = /*#__PURE__*/ forwardR
1669
1720
  id: titleId,
1670
1721
  children: "添加批注"
1671
1722
  }),
1672
- /*#__PURE__*/ jsx("span", {
1723
+ /*#__PURE__*/ jsxs("span", {
1673
1724
  title: draft.anchorText,
1674
- children: draft.anchorText
1725
+ children: [
1726
+ author,
1727
+ " \xb7 ",
1728
+ draft.anchorText
1729
+ ]
1675
1730
  })
1676
1731
  ]
1677
1732
  })
@@ -1716,6 +1771,12 @@ const document_comment_composer_DocumentCommentComposer = /*#__PURE__*/ forwardR
1716
1771
  ]
1717
1772
  });
1718
1773
  });
1774
+ function commentAuthorInitials(author) {
1775
+ const words = author.trim().split(/\s+/).filter(Boolean);
1776
+ if (!words.length) return '审';
1777
+ if (1 === words.length) return Array.from(words[0]).slice(0, 1).join('');
1778
+ return words.slice(0, 2).map((word)=>Array.from(word)[0]).join('').toLocaleUpperCase();
1779
+ }
1719
1780
  const DOCUMENT_COMMENT_WINDOW_THRESHOLD = 48;
1720
1781
  const DOCUMENT_COMMENT_WINDOW_LIMIT = 32;
1721
1782
  const DOCUMENT_COMMENT_WINDOW_OVERSCAN = 4;
@@ -1907,7 +1968,7 @@ const emptyLayout = {
1907
1968
  trackHeight: 1,
1908
1969
  items: []
1909
1970
  };
1910
- function DocumentCommentsPanel({ editor, comments, draft, surfaceRef, onReply, onToggleResolved, onDelete, onCancelDraft, onSubmitDraft, onClose, onDirtyChange }) {
1971
+ function DocumentCommentsPanel({ editor, comments, canDelete = canDeleteAnyComment, draft, draftAuthor = '我', surfaceRef, onReply, onToggleResolved, onDelete, onCancelDraft, onSubmitDraft, onClose, onDirtyChange }) {
1911
1972
  const [drafts, setDrafts] = useState({});
1912
1973
  const [activeCommentId, setActiveCommentId] = useState(()=>comments.find((comment)=>!comment.resolved)?.id ?? comments[0]?.id ?? null);
1913
1974
  const [draftDirty, setDraftDirty] = useState(false);
@@ -1974,7 +2035,7 @@ function DocumentCommentsPanel({ editor, comments, draft, surfaceRef, onReply, o
1974
2035
  ])), [
1975
2036
  layout.items
1976
2037
  ]);
1977
- const visibleConnectorItems = useMemo(()=>layout.items.filter((item)=>'draft' === item.kind || mountedCommentIds.has(item.id)), [
2038
+ const visibleConnectorItems = useMemo(()=>layout.items.filter((item)=>'draft' === item.kind || mountedCommentIds.has(item.id) && !item.detached), [
1978
2039
  layout.items,
1979
2040
  mountedCommentIds
1980
2041
  ]);
@@ -2025,6 +2086,7 @@ function DocumentCommentsPanel({ editor, comments, draft, surfaceRef, onReply, o
2025
2086
  onClose();
2026
2087
  };
2027
2088
  const deleteComment = async (commentId, index)=>{
2089
+ if (!canDelete(commentId)) return;
2028
2090
  const replyDirty = Boolean(drafts[commentId]?.trim());
2029
2091
  const confirmed = await officeDialog.confirm({
2030
2092
  title: '删除批注?',
@@ -2094,7 +2156,8 @@ function DocumentCommentsPanel({ editor, comments, draft, surfaceRef, onReply, o
2094
2156
  id: comment.id,
2095
2157
  kind: 'comment',
2096
2158
  commentId: comment.id,
2097
- from: comment.from,
2159
+ from: comment.from ?? Number.MAX_SAFE_INTEGER,
2160
+ detached: comment.detached,
2098
2161
  anchorRect: anchorRectsById.get(comment.id)
2099
2162
  }));
2100
2163
  if (draft) {
@@ -2139,7 +2202,8 @@ function DocumentCommentsPanel({ editor, comments, draft, surfaceRef, onReply, o
2139
2202
  startX,
2140
2203
  startY,
2141
2204
  endX,
2142
- endY
2205
+ endY,
2206
+ detached: entry.detached
2143
2207
  };
2144
2208
  });
2145
2209
  const nextLayout = {
@@ -2392,6 +2456,7 @@ function DocumentCommentsPanel({ editor, comments, draft, surfaceRef, onReply, o
2392
2456
  draft && /*#__PURE__*/ jsx("li", {
2393
2457
  className: "work-document-comment-draft-item",
2394
2458
  children: /*#__PURE__*/ jsx(document_comment_composer_DocumentCommentComposer, {
2459
+ author: draftAuthor,
2395
2460
  ref: (element)=>{
2396
2461
  const id = `draft:${draft.id}`;
2397
2462
  if (element) cardRefs.current.set(id, element);
@@ -2416,8 +2481,9 @@ function DocumentCommentsPanel({ editor, comments, draft, surfaceRef, onReply, o
2416
2481
  if (element) cardRefs.current.set(comment.id, element);
2417
2482
  else cardRefs.current.delete(comment.id);
2418
2483
  },
2419
- className: `work-document-comment-card${comment.resolved ? ' resolved' : ''}${active ? ' active' : ''}`,
2484
+ className: `work-document-comment-card${comment.resolved ? ' resolved' : ''}${comment.detached ? ' detached' : ''}${active ? ' active' : ''}`,
2420
2485
  "data-comment-id": comment.id,
2486
+ "data-document-comment-detached": comment.detached ? 'true' : 'false',
2421
2487
  "data-document-comment-card-top": Math.round(item?.cardTop ?? 8),
2422
2488
  "data-document-comment-item": index + 1,
2423
2489
  style: {
@@ -2433,18 +2499,19 @@ function DocumentCommentsPanel({ editor, comments, draft, surfaceRef, onReply, o
2433
2499
  },
2434
2500
  type: "button",
2435
2501
  className: "work-document-comment-anchor",
2436
- "aria-label": `定位批注 ${index + 1}`,
2502
+ "aria-label": `${comment.detached ? '查看已脱离正文的' : '定位'}批注 ${index + 1}`,
2437
2503
  "aria-current": active ? 'location' : void 0,
2438
2504
  tabIndex: commentWindow.rovingIndex === index ? 0 : -1,
2439
2505
  onKeyDown: (event)=>handleCommentAnchorKeyDown(event, index),
2440
2506
  onClick: ()=>{
2441
2507
  setActiveCommentId(comment.id);
2442
- editor.chain().focus().setTextSelection(documentCommentSelection(editor, comment)).run();
2508
+ const selection = documentCommentSelection(editor, comment);
2509
+ if (selection) editor.chain().focus().setTextSelection(selection).run();
2443
2510
  },
2444
2511
  children: [
2445
2512
  /*#__PURE__*/ jsx("span", {
2446
2513
  className: "work-document-comment-avatar",
2447
- children: commentAuthorInitials(comment.author)
2514
+ children: document_comments_panel_commentAuthorInitials(comment.author)
2448
2515
  }),
2449
2516
  /*#__PURE__*/ jsxs("span", {
2450
2517
  className: "work-document-comment-meta",
@@ -2460,7 +2527,15 @@ function DocumentCommentsPanel({ editor, comments, draft, surfaceRef, onReply, o
2460
2527
  }),
2461
2528
  /*#__PURE__*/ jsx("span", {
2462
2529
  className: "work-document-comment-quote",
2463
- children: comment.anchorText.trim() || '(空白字符)'
2530
+ children: comment.detached ? /*#__PURE__*/ jsxs(Fragment, {
2531
+ children: [
2532
+ /*#__PURE__*/ jsx(Unlink2, {
2533
+ size: 10,
2534
+ "aria-hidden": "true"
2535
+ }),
2536
+ "原文锚点已删除"
2537
+ ]
2538
+ }) : comment.anchorText.trim() || '(空白字符)'
2464
2539
  })
2465
2540
  ]
2466
2541
  }),
@@ -2543,6 +2618,8 @@ function DocumentCommentsPanel({ editor, comments, draft, surfaceRef, onReply, o
2543
2618
  size: "compact",
2544
2619
  tone: "danger",
2545
2620
  "aria-label": `删除批注 ${index + 1}`,
2621
+ disabled: !canDelete(comment.id),
2622
+ title: canDelete(comment.id) ? '删除批注' : '批注模式只能删除自己创建的批注',
2546
2623
  onClick: ()=>void deleteComment(comment.id, index),
2547
2624
  children: [
2548
2625
  /*#__PURE__*/ jsx(Trash2, {
@@ -2572,6 +2649,9 @@ function DocumentCommentsPanel({ editor, comments, draft, surfaceRef, onReply, o
2572
2649
  ]
2573
2650
  });
2574
2651
  }
2652
+ function canDeleteAnyComment() {
2653
+ return true;
2654
+ }
2575
2655
  function draftCommentAnchorRect(editor, range) {
2576
2656
  try {
2577
2657
  const position = Math.max(0, Math.min(editor.state.doc.content.size, range.to));
@@ -2589,7 +2669,7 @@ function sameCommentTrackLayout(current, next) {
2589
2669
  if (Math.abs(current.width - next.width) > 0.5 || Math.abs(current.height - next.height) > 0.5 || Math.abs(current.trackHeight - next.trackHeight) > 0.5 || current.items.length !== next.items.length) return false;
2590
2670
  return current.items.every((item, index)=>{
2591
2671
  const candidate = next.items[index];
2592
- return candidate?.id === item.id && candidate.kind === item.kind && candidate.commentId === item.commentId && Math.abs(candidate.cardTop - item.cardTop) <= 0.5 && Math.abs(candidate.startX - item.startX) <= 0.5 && Math.abs(candidate.startY - item.startY) <= 0.5 && Math.abs(candidate.endX - item.endX) <= 0.5 && Math.abs(candidate.endY - item.endY) <= 0.5;
2672
+ return candidate?.id === item.id && candidate.kind === item.kind && candidate.commentId === item.commentId && candidate.detached === item.detached && Math.abs(candidate.cardTop - item.cardTop) <= 0.5 && Math.abs(candidate.startX - item.startX) <= 0.5 && Math.abs(candidate.startY - item.startY) <= 0.5 && Math.abs(candidate.endX - item.endX) <= 0.5 && Math.abs(candidate.endY - item.endY) <= 0.5;
2593
2673
  });
2594
2674
  }
2595
2675
  function commentCardMeasurementKey(comment, active) {
@@ -2603,9 +2683,11 @@ function estimateCommentCardHeight(comment, active) {
2603
2683
  }
2604
2684
  function selectDocumentComment(editor, comment) {
2605
2685
  if (editor.isDestroyed) return;
2606
- editor.commands.setTextSelection(documentCommentSelection(editor, comment));
2686
+ const selection = documentCommentSelection(editor, comment);
2687
+ if (selection) editor.commands.setTextSelection(selection);
2607
2688
  }
2608
2689
  function documentCommentSelection(editor, comment) {
2690
+ if (comment.detached || null === comment.from || null === comment.to) return null;
2609
2691
  const maximum = Math.max(1, editor.state.doc.content.size - 1);
2610
2692
  return {
2611
2693
  from: Math.min(comment.from, maximum),
@@ -2615,7 +2697,7 @@ function documentCommentSelection(editor, comment) {
2615
2697
  function estimatedWrappedLines(value, charactersPerLine) {
2616
2698
  return Math.max(1, value.split('\n').reduce((lines, line)=>lines + Math.max(1, Math.ceil(line.length / charactersPerLine)), 0));
2617
2699
  }
2618
- function commentAuthorInitials(author) {
2700
+ function document_comments_panel_commentAuthorInitials(author) {
2619
2701
  const words = author.trim().split(/\s+/).filter(Boolean);
2620
2702
  if (!words.length) return '审';
2621
2703
  if (1 === words.length) return Array.from(words[0]).slice(0, 1).join('');
@@ -6226,7 +6308,7 @@ const bubbleMenuOptions = {
6226
6308
  inline: true
6227
6309
  };
6228
6310
  const selectionToolbarPluginKey = 'documentSelectionToolbar';
6229
- function DocumentSelectionToolbar({ editor, canInsertComment, layoutFonts = [], onInsertComment }) {
6311
+ function DocumentSelectionToolbar({ editor, canInsertComment, layoutFonts = [], onInsertComment, reviewOnly = false }) {
6230
6312
  const toolbarRef = useRef(null);
6231
6313
  const fontFamilyValue = documentFontFamilyValue(editor, layoutFonts);
6232
6314
  const fontSizeValue = documentFontSizeValue(editor);
@@ -6265,90 +6347,94 @@ function DocumentSelectionToolbar({ editor, canInsertComment, layoutFonts = [],
6265
6347
  if ('touch' !== event.nativeEvent.pointerType) event.preventDefault();
6266
6348
  },
6267
6349
  children: [
6268
- /*#__PURE__*/ jsx(OfficeSelect, {
6269
- ariaLabel: "快捷字体",
6270
- className: "work-document-selection-font-family",
6271
- value: fontFamilyValue,
6272
- options: documentFontFamilyOptionsForValue(fontFamilyValue, layoutFonts),
6273
- onValueChange: (value)=>{
6274
- if ('default' === value) editor.chain().focus().unsetFontFamily().run();
6275
- else editor.chain().focus().setFontFamily(value).run();
6276
- }
6277
- }),
6278
- /*#__PURE__*/ jsx(OfficeSelect, {
6279
- ariaLabel: "快捷字号",
6280
- className: "work-document-selection-font-size",
6281
- value: fontSizeValue,
6282
- options: documentFontSizeOptionsForValue(fontSizeValue),
6283
- onValueChange: (value)=>{
6284
- if ('default' === value) editor.chain().focus().unsetFontSize().run();
6285
- else editor.chain().focus().setFontSize(value).run();
6286
- }
6287
- }),
6288
- /*#__PURE__*/ jsx("span", {
6289
- className: "work-document-selection-divider",
6290
- "aria-hidden": "true"
6291
- }),
6292
- /*#__PURE__*/ jsx(SelectionToolbarButton, {
6293
- label: "加粗",
6294
- active: editor.isActive('bold'),
6295
- onClick: ()=>editor.chain().focus().toggleBold().run(),
6296
- children: /*#__PURE__*/ jsx(Bold, {
6297
- size: 15
6298
- })
6299
- }),
6300
- /*#__PURE__*/ jsx(SelectionToolbarButton, {
6301
- label: "斜体",
6302
- active: editor.isActive('italic'),
6303
- onClick: ()=>editor.chain().focus().toggleItalic().run(),
6304
- children: /*#__PURE__*/ jsx(Italic, {
6305
- size: 15
6306
- })
6307
- }),
6308
- /*#__PURE__*/ jsx(SelectionToolbarButton, {
6309
- label: "下划线",
6310
- active: editor.isActive('underline'),
6311
- onClick: ()=>editor.chain().focus().toggleUnderline().run(),
6312
- children: /*#__PURE__*/ jsx(Underline, {
6313
- size: 15
6314
- })
6315
- }),
6316
- /*#__PURE__*/ jsx(SelectionToolbarButton, {
6317
- label: "删除线",
6318
- active: editor.isActive('strike'),
6319
- onClick: ()=>editor.chain().focus().toggleStrike().run(),
6320
- children: /*#__PURE__*/ jsx(Strikethrough, {
6321
- size: 15
6322
- })
6323
- }),
6324
- /*#__PURE__*/ jsx(OfficeColorPicker, {
6325
- compact: true,
6326
- className: "work-document-selection-color",
6327
- value: editor.getAttributes('textStyle').color ?? '#172033',
6328
- ariaLabel: "快捷文字颜色",
6329
- onValueChange: (color)=>editor.chain().focus().setColor(color).run()
6330
- }),
6331
- /*#__PURE__*/ jsx(SelectionToolbarButton, {
6332
- label: "突出显示",
6333
- active: editor.isActive('highlight'),
6334
- onClick: ()=>editor.chain().focus().toggleHighlight({
6335
- color: '#fff0a6'
6336
- }).run(),
6337
- children: /*#__PURE__*/ jsx(Highlighter, {
6338
- size: 15
6339
- })
6340
- }),
6341
- /*#__PURE__*/ jsx(SelectionToolbarButton, {
6342
- className: "secondary",
6343
- label: "清除格式",
6344
- onClick: ()=>editor.commands.clearDocumentFormatting(),
6345
- children: /*#__PURE__*/ jsx(Eraser, {
6346
- size: 15
6347
- })
6348
- }),
6349
- /*#__PURE__*/ jsx("span", {
6350
- className: "work-document-selection-divider",
6351
- "aria-hidden": "true"
6350
+ !reviewOnly && /*#__PURE__*/ jsxs(Fragment, {
6351
+ children: [
6352
+ /*#__PURE__*/ jsx(OfficeSelect, {
6353
+ ariaLabel: "快捷字体",
6354
+ className: "work-document-selection-font-family",
6355
+ value: fontFamilyValue,
6356
+ options: documentFontFamilyOptionsForValue(fontFamilyValue, layoutFonts),
6357
+ onValueChange: (value)=>{
6358
+ if ('default' === value) editor.chain().focus().unsetFontFamily().run();
6359
+ else editor.chain().focus().setFontFamily(value).run();
6360
+ }
6361
+ }),
6362
+ /*#__PURE__*/ jsx(OfficeSelect, {
6363
+ ariaLabel: "快捷字号",
6364
+ className: "work-document-selection-font-size",
6365
+ value: fontSizeValue,
6366
+ options: documentFontSizeOptionsForValue(fontSizeValue),
6367
+ onValueChange: (value)=>{
6368
+ if ('default' === value) editor.chain().focus().unsetFontSize().run();
6369
+ else editor.chain().focus().setFontSize(value).run();
6370
+ }
6371
+ }),
6372
+ /*#__PURE__*/ jsx("span", {
6373
+ className: "work-document-selection-divider",
6374
+ "aria-hidden": "true"
6375
+ }),
6376
+ /*#__PURE__*/ jsx(SelectionToolbarButton, {
6377
+ label: "加粗",
6378
+ active: editor.isActive('bold'),
6379
+ onClick: ()=>editor.chain().focus().toggleBold().run(),
6380
+ children: /*#__PURE__*/ jsx(Bold, {
6381
+ size: 15
6382
+ })
6383
+ }),
6384
+ /*#__PURE__*/ jsx(SelectionToolbarButton, {
6385
+ label: "斜体",
6386
+ active: editor.isActive('italic'),
6387
+ onClick: ()=>editor.chain().focus().toggleItalic().run(),
6388
+ children: /*#__PURE__*/ jsx(Italic, {
6389
+ size: 15
6390
+ })
6391
+ }),
6392
+ /*#__PURE__*/ jsx(SelectionToolbarButton, {
6393
+ label: "下划线",
6394
+ active: editor.isActive('underline'),
6395
+ onClick: ()=>editor.chain().focus().toggleUnderline().run(),
6396
+ children: /*#__PURE__*/ jsx(Underline, {
6397
+ size: 15
6398
+ })
6399
+ }),
6400
+ /*#__PURE__*/ jsx(SelectionToolbarButton, {
6401
+ label: "删除线",
6402
+ active: editor.isActive('strike'),
6403
+ onClick: ()=>editor.chain().focus().toggleStrike().run(),
6404
+ children: /*#__PURE__*/ jsx(Strikethrough, {
6405
+ size: 15
6406
+ })
6407
+ }),
6408
+ /*#__PURE__*/ jsx(OfficeColorPicker, {
6409
+ compact: true,
6410
+ className: "work-document-selection-color",
6411
+ value: editor.getAttributes('textStyle').color ?? '#172033',
6412
+ ariaLabel: "快捷文字颜色",
6413
+ onValueChange: (color)=>editor.chain().focus().setColor(color).run()
6414
+ }),
6415
+ /*#__PURE__*/ jsx(SelectionToolbarButton, {
6416
+ label: "突出显示",
6417
+ active: editor.isActive('highlight'),
6418
+ onClick: ()=>editor.chain().focus().toggleHighlight({
6419
+ color: '#fff0a6'
6420
+ }).run(),
6421
+ children: /*#__PURE__*/ jsx(Highlighter, {
6422
+ size: 15
6423
+ })
6424
+ }),
6425
+ /*#__PURE__*/ jsx(SelectionToolbarButton, {
6426
+ className: "secondary",
6427
+ label: "清除格式",
6428
+ onClick: ()=>editor.commands.clearDocumentFormatting(),
6429
+ children: /*#__PURE__*/ jsx(Eraser, {
6430
+ size: 15
6431
+ })
6432
+ }),
6433
+ /*#__PURE__*/ jsx("span", {
6434
+ className: "work-document-selection-divider",
6435
+ "aria-hidden": "true"
6436
+ })
6437
+ ]
6352
6438
  }),
6353
6439
  /*#__PURE__*/ jsx(SelectionToolbarButton, {
6354
6440
  label: "添加批注",
@@ -11660,8 +11746,8 @@ function headingLevelForShortcut(code, key) {
11660
11746
  if ('3' === value) return 3;
11661
11747
  return null;
11662
11748
  }
11663
- function DocumentToolbar({ editor, defaultRibbonCollapsed = false, history, layoutOpen, layout, layoutFonts = [], navigationOpen, pageColor, showPageNumbers, showRulers, spellcheckEnabled, viewMode, zoom, pageChromeEditor, pageChromeEditingPart, pageChromeShowPageNumber, onRequestImage, onPageChromeEditingPartChange, onClosePageChrome, onTogglePageChromePageNumber, onToggleLayout, onLayoutChange, onOpenLayout, onToggleNavigation, onTogglePageNumbers, onToggleRulers, onPageColorChange, onToggleSpellcheck, onViewModeChange, onZoomChange, onZoomFit, onInsertSection, onInsertNote, onInsertCaption, onInsertCrossReference, citationsOpen, citationSourceCount, onToggleCitations, onInsertField, onRefreshFields, canInsertComment, onInsertComment, commentsOpen, commentCount, onToggleComments, trackChanges, changesOpen, changeCount, findReplaceMode, fileActions, onRibbonTabChange, onToggleTrackChanges, onToggleChanges, onOpenWordCount, onOpenFindReplace }) {
11664
- const [activeTab, setActiveTab] = useState('home');
11749
+ function DocumentToolbar({ editor, defaultRibbonCollapsed = false, reviewOnly = false, suggestionOnly = false, history, layoutOpen, layout, layoutFonts = [], navigationOpen, pageColor, showPageNumbers, showRulers, spellcheckEnabled, viewMode, zoom, pageChromeEditor, pageChromeEditingPart, pageChromeShowPageNumber, onRequestImage, onPageChromeEditingPartChange, onClosePageChrome, onTogglePageChromePageNumber, onToggleLayout, onLayoutChange, onOpenLayout, onToggleNavigation, onTogglePageNumbers, onToggleRulers, onPageColorChange, onToggleSpellcheck, onViewModeChange, onZoomChange, onZoomFit, onInsertSection, onInsertNote, onInsertCaption, onInsertCrossReference, citationsOpen, citationSourceCount, onToggleCitations, onInsertField, onRefreshFields, canInsertComment, onInsertComment, commentsOpen, commentCount, onToggleComments, trackChanges, changesOpen, changeCount, findReplaceMode, fileActions, onRibbonTabChange, onToggleTrackChanges, onToggleChanges, onDecideChange, onOpenWordCount, onOpenFindReplace }) {
11750
+ const [activeTab, setActiveTab] = useState(reviewOnly ? 'review' : 'home');
11665
11751
  const officeDialog = useOfficeDialog();
11666
11752
  const prompt = officeDialog.prompt;
11667
11753
  const imageSelected = editor.isActive('image');
@@ -11678,7 +11764,7 @@ function DocumentToolbar({ editor, defaultRibbonCollapsed = false, history, layo
11678
11764
  const spellingCommand = getDocumentCommandDefinition('spelling');
11679
11765
  const insertCommentCommand = getDocumentCommandDefinition('insertComment');
11680
11766
  const trackChangesCommand = getDocumentCommandDefinition('trackChanges');
11681
- const ribbonTabs = pageChromeEditor ? [
11767
+ const ribbonTabs = reviewOnly ? documentRibbonTabs.filter(({ id })=>'review' === id || 'view' === id) : pageChromeEditor ? [
11682
11768
  ...documentRibbonTabs,
11683
11769
  documentPageChromeRibbonTab
11684
11770
  ] : imageSelected ? [
@@ -11733,6 +11819,7 @@ function DocumentToolbar({ editor, defaultRibbonCollapsed = false, history, layo
11733
11819
  ]);
11734
11820
  useEffect(()=>{
11735
11821
  setActiveTab((current)=>{
11822
+ if (reviewOnly) return 'view' === current ? 'view' : 'review';
11736
11823
  if (pageChromeEditor) return 'pageChrome';
11737
11824
  if (imageSelected) return 'picture';
11738
11825
  if (tableSelected) return 'tableDesign' === current || 'tableLayout' === current ? current : 'tableDesign';
@@ -11741,6 +11828,7 @@ function DocumentToolbar({ editor, defaultRibbonCollapsed = false, history, layo
11741
11828
  }, [
11742
11829
  imageSelected,
11743
11830
  pageChromeEditor,
11831
+ reviewOnly,
11744
11832
  tableSelected
11745
11833
  ]);
11746
11834
  useEffect(()=>{
@@ -11750,6 +11838,13 @@ function DocumentToolbar({ editor, defaultRibbonCollapsed = false, history, layo
11750
11838
  if (event.defaultPrevented || event.repeat || isOfficeShortcutBlocked(event.target)) return;
11751
11839
  const key = event.key.toLowerCase();
11752
11840
  const insideEditor = event.target instanceof Node && Boolean(editorDom?.contains(event.target));
11841
+ if (reviewOnly) {
11842
+ if (insideEditor && (event.metaKey || event.ctrlKey) && event.altKey && !event.shiftKey && 'm' === key) {
11843
+ event.preventDefault();
11844
+ if (canInsertComment) onInsertComment();
11845
+ }
11846
+ return;
11847
+ }
11753
11848
  if (insideEditor && runDocumentWpsShortcut(editor, event, {
11754
11849
  canInsertComment,
11755
11850
  canRefreshFields: hasRefreshableFields,
@@ -11830,6 +11925,7 @@ function DocumentToolbar({ editor, defaultRibbonCollapsed = false, history, layo
11830
11925
  onOpenFindReplace,
11831
11926
  onOpenWordCount,
11832
11927
  onRefreshFields,
11928
+ reviewOnly,
11833
11929
  onToggleSpellcheck,
11834
11930
  onToggleTrackChanges,
11835
11931
  toggleLink
@@ -11855,7 +11951,7 @@ function DocumentToolbar({ editor, defaultRibbonCollapsed = false, history, layo
11855
11951
  changes[index + 1]?.id,
11856
11952
  changes[index - 1]?.id
11857
11953
  ].filter((id)=>Boolean(id));
11858
- const handled = 'accept' === decision ? editor.commands.acceptDocumentChange(change.id) : editor.commands.rejectDocumentChange(change.id);
11954
+ const handled = onDecideChange ? onDecideChange(change, decision) : 'accept' === decision ? editor.commands.acceptDocumentChange(change.id) : editor.commands.rejectDocumentChange(change.id);
11859
11955
  if (!handled) return;
11860
11956
  const remaining = collectDocumentChanges(editor.state.doc);
11861
11957
  const next = nextIds.map((id)=>remaining.find((candidate)=>candidate.id === id)).find((candidate)=>Boolean(candidate));
@@ -11867,7 +11963,7 @@ function DocumentToolbar({ editor, defaultRibbonCollapsed = false, history, layo
11867
11963
  /*#__PURE__*/ jsx(WorkOfficeRibbon, {
11868
11964
  ariaLabel: "文字功能区",
11869
11965
  tabs: ribbonTabs,
11870
- defaultTab: "home",
11966
+ defaultTab: reviewOnly ? 'review' : 'home',
11871
11967
  activeTab: activeTab,
11872
11968
  onTabChange: (tab)=>{
11873
11969
  const accepted = onRibbonTabChange?.(tab);
@@ -11879,7 +11975,7 @@ function DocumentToolbar({ editor, defaultRibbonCollapsed = false, history, layo
11879
11975
  adaptive: true,
11880
11976
  collapsible: true,
11881
11977
  fileActions: fileActions,
11882
- quickAccessActions: [
11978
+ quickAccessActions: reviewOnly && !suggestionOnly ? [] : [
11883
11979
  {
11884
11980
  id: undoCommand.id,
11885
11981
  label: undoCommand.label,
@@ -11913,13 +12009,13 @@ function DocumentToolbar({ editor, defaultRibbonCollapsed = false, history, layo
11913
12009
  className: "work-document-ribbon",
11914
12010
  toolbarClassName: "document-toolbar",
11915
12011
  panels: {
11916
- home: /*#__PURE__*/ jsx(DocumentHomeRibbon, {
12012
+ home: reviewOnly ? null : /*#__PURE__*/ jsx(DocumentHomeRibbon, {
11917
12013
  editor: editor,
11918
12014
  findReplaceMode: findReplaceMode,
11919
12015
  layoutFonts: layoutFonts,
11920
12016
  onFindText: (replace)=>onOpenFindReplace(replace ? 'replace' : 'find')
11921
12017
  }),
11922
- insert: /*#__PURE__*/ jsxs(Fragment, {
12018
+ insert: reviewOnly ? null : /*#__PURE__*/ jsxs(Fragment, {
11923
12019
  children: [
11924
12020
  /*#__PURE__*/ jsx(document_toolbar_RibbonGroup, {
11925
12021
  label: "页面",
@@ -12020,7 +12116,7 @@ function DocumentToolbar({ editor, defaultRibbonCollapsed = false, history, layo
12020
12116
  })
12021
12117
  ]
12022
12118
  }),
12023
- page: /*#__PURE__*/ jsx(DocumentPageLayoutRibbon, {
12119
+ page: reviewOnly ? null : /*#__PURE__*/ jsx(DocumentPageLayoutRibbon, {
12024
12120
  editor: editor,
12025
12121
  layout: layout,
12026
12122
  layoutOpen: layoutOpen,
@@ -12031,7 +12127,7 @@ function DocumentToolbar({ editor, defaultRibbonCollapsed = false, history, layo
12031
12127
  onPageColorChange: onPageColorChange,
12032
12128
  onInsertSection: onInsertSection
12033
12129
  }),
12034
- references: /*#__PURE__*/ jsxs(Fragment, {
12130
+ references: reviewOnly ? null : /*#__PURE__*/ jsxs(Fragment, {
12035
12131
  children: [
12036
12132
  /*#__PURE__*/ jsxs(document_toolbar_RibbonGroup, {
12037
12133
  label: "脚注",
@@ -12119,7 +12215,7 @@ function DocumentToolbar({ editor, defaultRibbonCollapsed = false, history, layo
12119
12215
  }),
12120
12216
  review: /*#__PURE__*/ jsxs(Fragment, {
12121
12217
  children: [
12122
- /*#__PURE__*/ jsx(document_toolbar_RibbonGroup, {
12218
+ !reviewOnly && /*#__PURE__*/ jsx(document_toolbar_RibbonGroup, {
12123
12219
  label: "校对",
12124
12220
  priority: "high",
12125
12221
  children: /*#__PURE__*/ jsx(document_toolbar_ToolbarButton, {
@@ -12134,7 +12230,7 @@ function DocumentToolbar({ editor, defaultRibbonCollapsed = false, history, layo
12134
12230
  })
12135
12231
  })
12136
12232
  }),
12137
- /*#__PURE__*/ jsxs(document_toolbar_RibbonGroup, {
12233
+ !suggestionOnly && /*#__PURE__*/ jsxs(document_toolbar_RibbonGroup, {
12138
12234
  label: "批注",
12139
12235
  priority: "high",
12140
12236
  children: [
@@ -12161,73 +12257,79 @@ function DocumentToolbar({ editor, defaultRibbonCollapsed = false, history, layo
12161
12257
  })
12162
12258
  ]
12163
12259
  }),
12164
- /*#__PURE__*/ jsxs(document_toolbar_RibbonGroup, {
12165
- label: "修订",
12166
- priority: "high",
12167
- children: [
12168
- /*#__PURE__*/ jsx(document_toolbar_ToolbarButton, {
12169
- label: "修订模式",
12170
- displayLabel: true,
12171
- shortcut: trackChangesCommand.shortcut?.label,
12172
- ariaKeyShortcuts: trackChangesCommand.shortcut?.aria,
12173
- active: trackChanges,
12174
- onClick: onToggleTrackChanges,
12175
- children: /*#__PURE__*/ jsx(FileDiff, {
12176
- size: 19
12177
- })
12178
- }),
12179
- /*#__PURE__*/ jsx(document_toolbar_ToolbarButton, {
12180
- label: `查看修订${changeCount ? `(${changeCount})` : ''}`,
12181
- displayLabel: true,
12182
- active: changesOpen,
12183
- onClick: onToggleChanges,
12184
- children: /*#__PURE__*/ jsx(ListChecks, {
12185
- size: 19
12186
- })
12187
- })
12188
- ]
12189
- }),
12190
- /*#__PURE__*/ jsxs(document_toolbar_RibbonGroup, {
12191
- label: "更改",
12192
- priority: "high",
12260
+ (!reviewOnly || suggestionOnly) && /*#__PURE__*/ jsxs(Fragment, {
12193
12261
  children: [
12194
- /*#__PURE__*/ jsx(document_toolbar_ToolbarButton, {
12195
- label: "接受修订",
12196
- displayLabel: true,
12197
- disabled: null === actionableChangeIndex,
12198
- title: "接受当前修订并转到下一处",
12199
- onClick: ()=>decideDocumentChange('accept'),
12200
- children: /*#__PURE__*/ jsx(Check, {
12201
- size: 19
12202
- })
12203
- }),
12204
- /*#__PURE__*/ jsx(document_toolbar_ToolbarButton, {
12205
- label: "拒绝修订",
12206
- displayLabel: true,
12207
- disabled: null === actionableChangeIndex,
12208
- title: "拒绝当前修订并转到下一处",
12209
- onClick: ()=>decideDocumentChange('reject'),
12210
- children: /*#__PURE__*/ jsx(XCircle, {
12211
- size: 19
12212
- })
12213
- }),
12214
- /*#__PURE__*/ jsx(document_toolbar_ToolbarButton, {
12215
- label: "上一处修订",
12216
- displayLabel: true,
12217
- disabled: null === previousChangeIndex,
12218
- onClick: ()=>navigateDocumentChange(-1),
12219
- children: /*#__PURE__*/ jsx(ChevronUp, {
12220
- size: 19
12221
- })
12262
+ /*#__PURE__*/ jsxs(document_toolbar_RibbonGroup, {
12263
+ label: "修订",
12264
+ priority: "high",
12265
+ children: [
12266
+ /*#__PURE__*/ jsx(document_toolbar_ToolbarButton, {
12267
+ label: suggestionOnly ? '建议模式' : '修订模式',
12268
+ displayLabel: true,
12269
+ shortcut: trackChangesCommand.shortcut?.label,
12270
+ ariaKeyShortcuts: trackChangesCommand.shortcut?.aria,
12271
+ active: suggestionOnly || trackChanges,
12272
+ disabled: suggestionOnly,
12273
+ title: suggestionOnly ? '建议模式始终记录带身份的文字修订' : void 0,
12274
+ onClick: onToggleTrackChanges,
12275
+ children: /*#__PURE__*/ jsx(FileDiff, {
12276
+ size: 19
12277
+ })
12278
+ }),
12279
+ /*#__PURE__*/ jsx(document_toolbar_ToolbarButton, {
12280
+ label: `查看修订${changeCount ? `(${changeCount})` : ''}`,
12281
+ displayLabel: true,
12282
+ active: changesOpen,
12283
+ onClick: onToggleChanges,
12284
+ children: /*#__PURE__*/ jsx(ListChecks, {
12285
+ size: 19
12286
+ })
12287
+ })
12288
+ ]
12222
12289
  }),
12223
- /*#__PURE__*/ jsx(document_toolbar_ToolbarButton, {
12224
- label: "下一处修订",
12225
- displayLabel: true,
12226
- disabled: null === nextChangeIndex,
12227
- onClick: ()=>navigateDocumentChange(1),
12228
- children: /*#__PURE__*/ jsx(ChevronDown, {
12229
- size: 19
12230
- })
12290
+ !suggestionOnly && /*#__PURE__*/ jsxs(document_toolbar_RibbonGroup, {
12291
+ label: "更改",
12292
+ priority: "high",
12293
+ children: [
12294
+ /*#__PURE__*/ jsx(document_toolbar_ToolbarButton, {
12295
+ label: "接受修订",
12296
+ displayLabel: true,
12297
+ disabled: null === actionableChangeIndex,
12298
+ title: "接受当前修订并转到下一处",
12299
+ onClick: ()=>decideDocumentChange('accept'),
12300
+ children: /*#__PURE__*/ jsx(Check, {
12301
+ size: 19
12302
+ })
12303
+ }),
12304
+ /*#__PURE__*/ jsx(document_toolbar_ToolbarButton, {
12305
+ label: "拒绝修订",
12306
+ displayLabel: true,
12307
+ disabled: null === actionableChangeIndex,
12308
+ title: "拒绝当前修订并转到下一处",
12309
+ onClick: ()=>decideDocumentChange('reject'),
12310
+ children: /*#__PURE__*/ jsx(XCircle, {
12311
+ size: 19
12312
+ })
12313
+ }),
12314
+ /*#__PURE__*/ jsx(document_toolbar_ToolbarButton, {
12315
+ label: "上一处修订",
12316
+ displayLabel: true,
12317
+ disabled: null === previousChangeIndex,
12318
+ onClick: ()=>navigateDocumentChange(-1),
12319
+ children: /*#__PURE__*/ jsx(ChevronUp, {
12320
+ size: 19
12321
+ })
12322
+ }),
12323
+ /*#__PURE__*/ jsx(document_toolbar_ToolbarButton, {
12324
+ label: "下一处修订",
12325
+ displayLabel: true,
12326
+ disabled: null === nextChangeIndex,
12327
+ onClick: ()=>navigateDocumentChange(1),
12328
+ children: /*#__PURE__*/ jsx(ChevronDown, {
12329
+ size: 19
12330
+ })
12331
+ })
12332
+ ]
12231
12333
  })
12232
12334
  ]
12233
12335
  })
@@ -12594,7 +12696,7 @@ function document_vertical_ruler_formatRulerValue(value) {
12594
12696
  return Number.isInteger(value) ? String(value) : value.toFixed(1);
12595
12697
  }
12596
12698
  const CURRENT_COMMENT_AUTHOR = '我';
12597
- function useDocumentComments({ contentRef, editor, onBeforeDraft }) {
12699
+ function useDocumentComments({ actor, contentRef, deleteOwnOnly = false, editor, enabled = true, onBeforeDraft }) {
12598
12700
  const [open, setOpen] = useState(false);
12599
12701
  const [draft, setDraft] = useState(null);
12600
12702
  useEffect(()=>()=>{
@@ -12603,23 +12705,40 @@ function useDocumentComments({ contentRef, editor, onBeforeDraft }) {
12603
12705
  editor
12604
12706
  ]);
12605
12707
  const reply = useCallback((id, text)=>{
12708
+ if (!enabled) return;
12606
12709
  editor?.commands.addDocumentCommentReply(id, {
12607
12710
  id: createWorkId('comment-reply'),
12608
- author: CURRENT_COMMENT_AUTHOR,
12711
+ ...commentActor(actor),
12609
12712
  date: new Date().toISOString(),
12610
12713
  text
12611
12714
  });
12612
12715
  }, [
12613
- editor
12716
+ actor,
12717
+ editor,
12718
+ enabled
12614
12719
  ]);
12615
12720
  const toggleResolved = useCallback((id)=>{
12721
+ if (!enabled) return;
12616
12722
  editor?.commands.toggleDocumentCommentResolved(id);
12617
12723
  }, [
12618
- editor
12724
+ editor,
12725
+ enabled
12726
+ ]);
12727
+ const canDeleteComment = useCallback((id)=>{
12728
+ if (!enabled) return false;
12729
+ if (!deleteOwnOnly) return true;
12730
+ return Boolean(actor && contentRef.current.comments?.some((comment)=>comment.id === id && comment.actorId === actor.id));
12731
+ }, [
12732
+ actor,
12733
+ contentRef,
12734
+ deleteOwnOnly,
12735
+ enabled
12619
12736
  ]);
12620
12737
  const deleteComment = useCallback((id)=>{
12738
+ if (!canDeleteComment(id)) return;
12621
12739
  editor?.commands.deleteDocumentComment(id);
12622
12740
  }, [
12741
+ canDeleteComment,
12623
12742
  editor
12624
12743
  ]);
12625
12744
  const closeDraft = useCallback((restoreEditorFocus = true)=>{
@@ -12638,7 +12757,7 @@ function useDocumentComments({ contentRef, editor, onBeforeDraft }) {
12638
12757
  closeDraft
12639
12758
  ]);
12640
12759
  const startDraft = useCallback(()=>{
12641
- if (!editor) return;
12760
+ if (!editor || !enabled) return;
12642
12761
  const { from, to } = editor.state.selection;
12643
12762
  const range = {
12644
12763
  from,
@@ -12657,17 +12776,18 @@ function useDocumentComments({ contentRef, editor, onBeforeDraft }) {
12657
12776
  setOpen(true);
12658
12777
  }, [
12659
12778
  editor,
12779
+ enabled,
12660
12780
  onBeforeDraft
12661
12781
  ]);
12662
12782
  const submitDraft = useCallback((text)=>{
12663
- if (!editor || !draft) return '批注草稿已经关闭,请重新选择文字。';
12783
+ if (!enabled || !editor || !draft) return '批注草稿已经关闭,请重新选择文字。';
12664
12784
  const range = documentCommentDraftRange(editor);
12665
12785
  if (!range) return '所选文字已变化,请重新选择。';
12666
12786
  const anchorText = editor.state.doc.textBetween(range.from, range.to, '\n');
12667
12787
  if (anchorText !== draft.anchorText) return '所选文字已变化,请重新选择。';
12668
12788
  const comment = {
12669
12789
  id: draft.id,
12670
- author: CURRENT_COMMENT_AUTHOR,
12790
+ ...commentActor(actor),
12671
12791
  date: new Date().toISOString(),
12672
12792
  text,
12673
12793
  resolved: false
@@ -12677,11 +12797,13 @@ function useDocumentComments({ contentRef, editor, onBeforeDraft }) {
12677
12797
  setOpen(true);
12678
12798
  return null;
12679
12799
  }, [
12800
+ actor,
12680
12801
  draft,
12681
- editor
12802
+ editor,
12803
+ enabled
12682
12804
  ]);
12683
12805
  const comments = editor ? documentCommentViews(contentRef.current.comments ?? [], collectDocumentCommentAnchors(editor.state.doc)) : [];
12684
- const canInsert = Boolean(editor && canInsertDocumentComment(editor));
12806
+ const canInsert = Boolean(enabled && editor && canInsertDocumentComment(editor));
12685
12807
  const toggleOpen = useCallback(()=>{
12686
12808
  if (open) close();
12687
12809
  else setOpen(true);
@@ -12690,6 +12812,7 @@ function useDocumentComments({ contentRef, editor, onBeforeDraft }) {
12690
12812
  open
12691
12813
  ]);
12692
12814
  return {
12815
+ canDeleteComment,
12693
12816
  canInsert,
12694
12817
  close,
12695
12818
  closeDraft,
@@ -12705,6 +12828,14 @@ function useDocumentComments({ contentRef, editor, onBeforeDraft }) {
12705
12828
  toggleResolved
12706
12829
  };
12707
12830
  }
12831
+ function commentActor(actor) {
12832
+ return actor ? {
12833
+ actorId: actor.id,
12834
+ author: actor.name
12835
+ } : {
12836
+ author: CURRENT_COMMENT_AUTHOR
12837
+ };
12838
+ }
12708
12839
  function useDocumentInsertCommands({ contentRef, editor, resolveFieldContext }) {
12709
12840
  const officeDialog = useOfficeDialog();
12710
12841
  const [insertDialog, setInsertDialog] = useState(null);
@@ -14107,10 +14238,13 @@ function DocumentReviewConflictNotice({ conflicts, onDismiss }) {
14107
14238
  }
14108
14239
  const EMPTY_DOCUMENT_LAYOUT_FONTS = [];
14109
14240
  const EMPTY_DOCUMENT_EXTENSIONS = [];
14110
- function createTrackedDocumentChange(_kind) {
14241
+ function createTrackedDocumentChange(_kind, actor) {
14111
14242
  return {
14112
14243
  id: createWorkId('change'),
14113
- author: 'A3S Work 用户',
14244
+ ...actor ? {
14245
+ actorId: actor.id
14246
+ } : {},
14247
+ author: actor?.name ?? 'A3S Work 用户',
14114
14248
  date: new Date().toISOString()
14115
14249
  };
14116
14250
  }
@@ -14133,7 +14267,7 @@ function CollaborativeDocumentEditor(props) {
14133
14267
  if (!initial.current) initial.current = readWorkOfficeDocumentCollaboration(collaboration);
14134
14268
  const bridge = useRef({
14135
14269
  getContent: ()=>initial.current,
14136
- isTracking: ()=>Boolean(initial.current?.trackChanges),
14270
+ isTracking: ()=>'suggest' === collaboration.mode || Boolean(initial.current?.trackChanges),
14137
14271
  onContentChange: ()=>void 0,
14138
14272
  onTrackingChange: ()=>void 0
14139
14273
  });
@@ -14147,7 +14281,7 @@ function CollaborativeDocumentEditor(props) {
14147
14281
  workExtensions: {
14148
14282
  getContent: ()=>bridge.current.getContent(),
14149
14283
  isTracking: ()=>bridge.current.isTracking(),
14150
- createChange: createTrackedDocumentChange,
14284
+ createChange: (kind)=>createTrackedDocumentChange(kind, collaboration.actor),
14151
14285
  onContentChange: (content)=>bridge.current.onContentChange(content),
14152
14286
  onTrackingChange: (enabled)=>bridge.current.onTrackingChange(enabled)
14153
14287
  }
@@ -14177,8 +14311,13 @@ function CollaborativeDocumentEditor(props) {
14177
14311
  });
14178
14312
  }
14179
14313
  function DocumentEditorSurface({ artifactId, autoFocus = true, collaboration, collaborationBinding, collaborationBridge, collaborationInitialContent, content, extensions = EMPTY_DOCUMENT_EXTENSIONS, preview: requestedPreview, defaultRibbonCollapsed = false, saveStatus = '已自动保存', kernelWasmUrl, layoutFonts = EMPTY_DOCUMENT_LAYOUT_FONTS, fileActions, getSelectionMenuItems, onChange, onAgentRequest, onReviewConflict }) {
14180
- const collaborationEditable = !collaboration || 'edit' === collaboration.mode;
14181
- const preview = requestedPreview || !collaborationEditable;
14314
+ const commentOnly = collaboration?.mode === 'comment' && !requestedPreview;
14315
+ const suggestionOnly = collaboration?.mode === 'suggest' && Boolean(collaboration.actor) && !requestedPreview;
14316
+ const collaborationInteractive = !collaboration || 'edit' === collaboration.mode || 'comment' === collaboration.mode || 'suggest' === collaboration.mode && Boolean(collaboration.actor);
14317
+ const preview = requestedPreview || !collaborationInteractive;
14318
+ const canEditDocument = !preview && (!collaboration || 'edit' === collaboration.mode);
14319
+ const canCommentDocument = !preview && (!collaboration || 'edit' === collaboration.mode || 'comment' === collaboration.mode && Boolean(collaboration.actor));
14320
+ const canReviewDocumentChanges = canEditDocument || suggestionOnly;
14182
14321
  const readOnly = preview;
14183
14322
  const initialContentRef = useRef(collaborationInitialContent ?? content);
14184
14323
  const effectiveContent = collaboration ? initialContentRef.current : content;
@@ -14195,7 +14334,7 @@ function DocumentEditorSurface({ artifactId, autoFocus = true, collaboration, co
14195
14334
  const statisticsInvokerRef = useRef(null);
14196
14335
  const contentRef = useRef(effectiveContent);
14197
14336
  const onChangeRef = useRef(onChange);
14198
- const trackChangesRef = useRef(Boolean(effectiveContent.trackChanges));
14337
+ const trackChangesRef = useRef(suggestionOnly || Boolean(effectiveContent.trackChanges));
14199
14338
  const collaborationBindingRef = useRef(collaborationBinding);
14200
14339
  const normalizedContent = useMemo(()=>normalizeDocumentHtml(effectiveContent), [
14201
14340
  effectiveContent
@@ -14230,7 +14369,7 @@ function DocumentEditorSurface({ artifactId, autoFocus = true, collaboration, co
14230
14369
  const loadedLayoutFontIds = useDocumentLayoutFonts(layoutFonts);
14231
14370
  if (!collaboration) contentRef.current = content;
14232
14371
  onChangeRef.current = onChange;
14233
- trackChangesRef.current = Boolean(contentRef.current.trackChanges);
14372
+ trackChangesRef.current = suggestionOnly || Boolean(contentRef.current.trackChanges);
14234
14373
  const commitContentChange = useCallback((next)=>{
14235
14374
  const previous = contentRef.current;
14236
14375
  const binding = collaborationBindingRef.current;
@@ -14241,9 +14380,10 @@ function DocumentEditorSurface({ artifactId, autoFocus = true, collaboration, co
14241
14380
  collaborationBindingRef.current = collaborationBinding;
14242
14381
  if (collaborationBridge) collaborationBridge.current = {
14243
14382
  getContent: ()=>contentRef.current,
14244
- isTracking: ()=>trackChangesRef.current,
14383
+ isTracking: ()=>suggestionOnly || trackChangesRef.current,
14245
14384
  onContentChange: (next)=>commitContentChange(next),
14246
14385
  onTrackingChange: (trackChanges)=>{
14386
+ if (suggestionOnly) return;
14247
14387
  trackChangesRef.current = trackChanges;
14248
14388
  commitContentChange({
14249
14389
  ...contentRef.current,
@@ -14255,11 +14395,12 @@ function DocumentEditorSurface({ artifactId, autoFocus = true, collaboration, co
14255
14395
  ...collaborationBinding?.extensions ?? createWorkDocumentExtensions({
14256
14396
  getContent: ()=>contentRef.current,
14257
14397
  isTracking: ()=>trackChangesRef.current,
14258
- createChange: createTrackedDocumentChange,
14398
+ createChange: (kind)=>createTrackedDocumentChange(kind, collaboration?.actor),
14259
14399
  onContentChange: (next)=>{
14260
14400
  commitContentChange(next);
14261
14401
  },
14262
14402
  onTrackingChange: (trackChanges)=>{
14403
+ if (suggestionOnly) return;
14263
14404
  trackChangesRef.current = trackChanges;
14264
14405
  const next = {
14265
14406
  ...contentRef.current,
@@ -14282,10 +14423,13 @@ function DocumentEditorSurface({ artifactId, autoFocus = true, collaboration, co
14282
14423
  attributes: {
14283
14424
  'aria-label': '文档正文',
14284
14425
  'aria-multiline': 'true',
14426
+ 'aria-readonly': commentOnly ? 'true' : 'false',
14285
14427
  role: 'textbox',
14286
14428
  spellcheck: 'true'
14287
14429
  }
14288
- }), []);
14430
+ }), [
14431
+ commentOnly
14432
+ ]);
14289
14433
  const editor = useEditor({
14290
14434
  extensions: editorExtensions,
14291
14435
  content: collaboration ? void 0 : initialEditorSourceRef.current,
@@ -14363,8 +14507,11 @@ function DocumentEditorSurface({ artifactId, autoFocus = true, collaboration, co
14363
14507
  reconcileControlledUpdates: !collaboration
14364
14508
  });
14365
14509
  const documentComments = useDocumentComments({
14510
+ actor: collaboration?.actor,
14366
14511
  contentRef,
14512
+ deleteOwnOnly: commentOnly,
14367
14513
  editor,
14514
+ enabled: canCommentDocument,
14368
14515
  onBeforeDraft: ()=>setTaskPane(null)
14369
14516
  });
14370
14517
  const [collaborationVersion, setCollaborationVersion] = useState(0);
@@ -14375,7 +14522,7 @@ function DocumentEditorSurface({ artifactId, autoFocus = true, collaboration, co
14375
14522
  const unsubscribeChange = collaborationBinding.subscribe((change)=>{
14376
14523
  pendingCollaborationContentRef.current = change.content;
14377
14524
  contentRef.current = change.content;
14378
- trackChangesRef.current = Boolean(change.content.trackChanges);
14525
+ trackChangesRef.current = suggestionOnly || Boolean(change.content.trackChanges);
14379
14526
  setCollaborationVersion((value)=>value + 1);
14380
14527
  });
14381
14528
  const unsubscribeError = collaborationBinding.subscribeError((error)=>{
@@ -14400,7 +14547,7 @@ function DocumentEditorSurface({ artifactId, autoFocus = true, collaboration, co
14400
14547
  const next = pendingCollaborationContentRef.current;
14401
14548
  pendingCollaborationContentRef.current = void 0;
14402
14549
  contentRef.current = next;
14403
- trackChangesRef.current = Boolean(next.trackChanges);
14550
+ trackChangesRef.current = suggestionOnly || Boolean(next.trackChanges);
14404
14551
  onChangeRef.current(next);
14405
14552
  }, [
14406
14553
  collaborationVersion
@@ -14601,6 +14748,7 @@ function DocumentEditorSurface({ artifactId, autoFocus = true, collaboration, co
14601
14748
  editor.setEditable(!readOnly);
14602
14749
  const editorDom = editor.view.dom;
14603
14750
  editorDom.setAttribute('role', preview ? 'document' : 'textbox');
14751
+ editorDom.setAttribute('aria-readonly', String(commentOnly || preview));
14604
14752
  if (preview) editorDom.removeAttribute('aria-multiline');
14605
14753
  else editorDom.setAttribute('aria-multiline', 'true');
14606
14754
  };
@@ -14610,6 +14758,7 @@ function DocumentEditorSurface({ artifactId, autoFocus = true, collaboration, co
14610
14758
  editor.off('mount', applyEditableState);
14611
14759
  };
14612
14760
  }, [
14761
+ commentOnly,
14613
14762
  editor,
14614
14763
  preview,
14615
14764
  readOnly
@@ -14700,7 +14849,7 @@ function DocumentEditorSurface({ artifactId, autoFocus = true, collaboration, co
14700
14849
  const lastPageMargins = resolveDocumentPageMargins(lastPageDescriptor.layout, lastPageDescriptor.physicalPage);
14701
14850
  const { chromeEditor: pageChromeEditor, close: closePageChrome, edit: editPageChrome, editing: pageChromeEditing, footerChrome, headerChrome, reset: resetPageChrome, setChromeEditor: setPageChromeEditor, togglePageNumber: toggleVisiblePageNumber, update: updateVisiblePageChrome, visibleChrome } = useDocumentPageChrome({
14702
14851
  editor,
14703
- enabled: !preview && 'page' === viewMode,
14852
+ enabled: canEditDocument && 'page' === viewMode,
14704
14853
  firstPage: firstPageDescriptor,
14705
14854
  footerRef: pageFooterRef,
14706
14855
  headerRef: pageHeaderRef,
@@ -14720,6 +14869,11 @@ function DocumentEditorSurface({ artifactId, autoFocus = true, collaboration, co
14720
14869
  });
14721
14870
  const finalPageNumber = pagination.pages.at(-1)?.pageNumber ?? Math.max(1, layout.pageNumberStart ?? 1) + pageCount - 1;
14722
14871
  const changes = collectDocumentChanges(editor.state.doc);
14872
+ const decideDocumentChanges = (selectedChanges, decision)=>{
14873
+ if (collaborationBinding) return collaborationBinding.decideChanges(editor, selectedChanges.map(({ id })=>id), decision);
14874
+ const ids = selectedChanges.map(({ id })=>id);
14875
+ return 'accept' === decision ? editor.commands.acceptDocumentChanges(ids) : editor.commands.rejectDocumentChanges(ids);
14876
+ };
14723
14877
  const citationCount = documentCitationCount(editor);
14724
14878
  const textStatistics = documentTextStatistics(editor);
14725
14879
  const paragraphIndent = documentParagraphIndent(editor);
@@ -14807,7 +14961,7 @@ function DocumentEditorSurface({ artifactId, autoFocus = true, collaboration, co
14807
14961
  restoreDocumentBodyFocus();
14808
14962
  };
14809
14963
  const openSelectionContextMenu = (event)=>{
14810
- if (preview || !getSelectionMenuItems && !onAgentRequest) return false;
14964
+ if (!canEditDocument || !getSelectionMenuItems && !onAgentRequest) return false;
14811
14965
  const snapshot = createWorkDocumentSelectionSnapshot(editor, contentRef.current);
14812
14966
  if (!snapshot) return false;
14813
14967
  event.preventDefault();
@@ -14834,10 +14988,11 @@ function DocumentEditorSurface({ artifactId, autoFocus = true, collaboration, co
14834
14988
  };
14835
14989
  return /*#__PURE__*/ jsxs("section", {
14836
14990
  className: `work-document-editor${preview ? ' preview' : ''}`,
14991
+ "data-collaboration-mode": collaboration?.mode,
14837
14992
  "data-work-pdf-artifact": artifactId,
14838
14993
  "data-work-pdf-surface": artifactId ? 'live' : void 0,
14839
14994
  children: [
14840
- !preview && /*#__PURE__*/ jsx(office_text_field_OfficeFileInput, {
14995
+ canEditDocument && /*#__PURE__*/ jsx(office_text_field_OfficeFileInput, {
14841
14996
  ref: imageInputRef,
14842
14997
  accept: "image/bmp,image/gif,image/jpeg,image/png,image/webp",
14843
14998
  "aria-label": "插入文档图片",
@@ -14852,7 +15007,9 @@ function DocumentEditorSurface({ artifactId, autoFocus = true, collaboration, co
14852
15007
  }) : /*#__PURE__*/ jsx(DocumentToolbar, {
14853
15008
  editor: editor,
14854
15009
  defaultRibbonCollapsed: defaultRibbonCollapsed,
14855
- history: collaborationBinding ? {
15010
+ reviewOnly: commentOnly || suggestionOnly,
15011
+ suggestionOnly: suggestionOnly,
15012
+ history: collaborationBinding && !commentOnly ? {
14856
15013
  canRedo: collaborationBinding.canRedo(),
14857
15014
  canUndo: collaborationBinding.canUndo(),
14858
15015
  redo: ()=>collaborationBinding.redo(),
@@ -14904,7 +15061,7 @@ function DocumentEditorSurface({ artifactId, autoFocus = true, collaboration, co
14904
15061
  commentsOpen: documentComments.open,
14905
15062
  commentCount: documentComments.comments.length,
14906
15063
  onToggleComments: ()=>void toggleCommentsPanel(),
14907
- trackChanges: Boolean(currentContent.trackChanges),
15064
+ trackChanges: suggestionOnly || Boolean(currentContent.trackChanges),
14908
15065
  changesOpen: changesOpen,
14909
15066
  changeCount: changes.length,
14910
15067
  findReplaceMode: findReplaceMode,
@@ -14913,10 +15070,14 @@ function DocumentEditorSurface({ artifactId, autoFocus = true, collaboration, co
14913
15070
  return requestEditorViewChange(keepCurrentPane ? taskPane : null, 'review' !== tab);
14914
15071
  },
14915
15072
  onToggleTrackChanges: ()=>{
15073
+ if (suggestionOnly) return;
14916
15074
  editor.commands.toggleDocumentTrackChanges();
14917
15075
  restoreDocumentBodyFocus();
14918
15076
  },
14919
15077
  onToggleChanges: ()=>void toggleTaskPane('changes'),
15078
+ onDecideChange: (change, decision)=>decideDocumentChanges([
15079
+ change
15080
+ ], decision),
14920
15081
  onOpenWordCount: openDocumentStatistics,
14921
15082
  onOpenFindReplace: openFindReplace
14922
15083
  }),
@@ -14988,7 +15149,7 @@ function DocumentEditorSurface({ artifactId, autoFocus = true, collaboration, co
14988
15149
  }),
14989
15150
  /*#__PURE__*/ jsxs("article", {
14990
15151
  ref: pageSurfaceRef,
14991
- className: `work-document-page${preview ? ' work-document-preview-page' : ''} ${layout.pageSize} ${layout.orientation}${pagination.pageCount ? ' paginated' : ''}${!preview && pageChromeEditing ? ' page-chrome-editing' : ''}`,
15152
+ className: `work-document-page${preview ? ' work-document-preview-page' : ''} ${layout.pageSize} ${layout.orientation}${pagination.pageCount ? ' paginated' : ''}${canEditDocument && pageChromeEditing ? ' page-chrome-editing' : ''}`,
14992
15153
  "data-work-pdf-live-document": artifactId && pagination.pageCount ? '' : void 0,
14993
15154
  "data-pdf-orientation": artifactId && pagination.pageCount ? layout.orientation : void 0,
14994
15155
  "data-pdf-page-count": artifactId ? pagination.pageCount : void 0,
@@ -15030,7 +15191,7 @@ function DocumentEditorSurface({ artifactId, autoFocus = true, collaboration, co
15030
15191
  }),
15031
15192
  'page' === viewMode && (!preview || Boolean(headerChrome.headerHtml)) && /*#__PURE__*/ jsx("header", {
15032
15193
  ref: pageHeaderRef,
15033
- className: `work-document-page-header${!preview && pageChromeEditing?.part === 'header' ? ' editing' : ''}`,
15194
+ className: `work-document-page-header${canEditDocument && pageChromeEditing?.part === 'header' ? ' editing' : ''}`,
15034
15195
  "data-document-page-chrome": firstPageDescriptor.pageChrome.variant,
15035
15196
  style: firstPageFrame && paginationGeometry ? {
15036
15197
  height: firstPageDescriptor.page.headerHeight,
@@ -15038,17 +15199,12 @@ function DocumentEditorSurface({ artifactId, autoFocus = true, collaboration, co
15038
15199
  right: paginationGeometry.width - firstPageFrame.left - firstPageFrame.width + firstPageDescriptor.page.marginRight,
15039
15200
  top: work_document_layout_millimetersToPixels(firstPageMargins.headerDistance)
15040
15201
  } : void 0,
15041
- onDoubleClick: preview ? void 0 : (event)=>{
15202
+ onDoubleClick: canEditDocument ? (event)=>{
15042
15203
  if (pageChromeEditing?.part === 'header') return;
15043
15204
  event.preventDefault();
15044
15205
  editPageChrome('header');
15045
- },
15046
- children: preview || pageChromeEditing?.part !== 'header' ? headerChrome.headerHtml ? /*#__PURE__*/ jsx("div", {
15047
- className: "work-document-page-chrome-html",
15048
- dangerouslySetInnerHTML: {
15049
- __html: headerChrome.headerHtml
15050
- }
15051
- }) : null : /*#__PURE__*/ jsx(DocumentPageChromeRichTextEditor, {
15206
+ } : void 0,
15207
+ children: canEditDocument && pageChromeEditing?.part === 'header' ? /*#__PURE__*/ jsx(DocumentPageChromeRichTextEditor, {
15052
15208
  autoFocus: true,
15053
15209
  className: "work-document-page-chrome-inline-editor",
15054
15210
  label: "页内页眉",
@@ -15059,14 +15215,19 @@ function DocumentEditorSurface({ artifactId, autoFocus = true, collaboration, co
15059
15215
  }),
15060
15216
  onEditorChange: setPageChromeEditor,
15061
15217
  onExit: closePageChrome
15062
- }, `${pageChromeEditing.sectionId}-${pageChromeEditing.variant}-header`)
15218
+ }, `${pageChromeEditing.sectionId}-${pageChromeEditing.variant}-header`) : headerChrome.headerHtml ? /*#__PURE__*/ jsx("div", {
15219
+ className: "work-document-page-chrome-html",
15220
+ dangerouslySetInnerHTML: {
15221
+ __html: headerChrome.headerHtml
15222
+ }
15223
+ }) : null
15063
15224
  }),
15064
15225
  /*#__PURE__*/ jsxs("section", {
15065
15226
  ref: editableSurfaceRef,
15066
15227
  className: `work-document-editable ${viewMode}`,
15067
15228
  "aria-label": "文档内容编辑区域",
15068
15229
  onDoubleClick: ()=>{
15069
- if (!preview && pageChromeEditing) closePageChrome();
15230
+ if (canEditDocument && pageChromeEditing) closePageChrome();
15070
15231
  },
15071
15232
  onContextMenu: openSelectionContextMenu,
15072
15233
  onKeyDownCapture: (event)=>{
@@ -15082,17 +15243,18 @@ function DocumentEditorSurface({ artifactId, autoFocus = true, collaboration, co
15082
15243
  editor: editor,
15083
15244
  kind: "document"
15084
15245
  }),
15085
- !preview && /*#__PURE__*/ jsx(DocumentSelectionToolbar, {
15246
+ !preview && (canEditDocument || canCommentDocument) && /*#__PURE__*/ jsx(DocumentSelectionToolbar, {
15086
15247
  editor: editor,
15087
15248
  canInsertComment: documentComments.canInsert,
15088
15249
  layoutFonts: layoutFonts,
15089
- onInsertComment: ()=>void startCommentDraft()
15250
+ onInsertComment: ()=>void startCommentDraft(),
15251
+ reviewOnly: commentOnly
15090
15252
  })
15091
15253
  ]
15092
15254
  }),
15093
15255
  'page' === viewMode && (!preview || Boolean(footerChrome.footerHtml) || footerChrome.showPageNumber) && /*#__PURE__*/ jsxs("footer", {
15094
15256
  ref: pageFooterRef,
15095
- className: `work-document-page-footer${!preview && pageChromeEditing?.part === 'footer' ? ' editing' : ''}`,
15257
+ className: `work-document-page-footer${canEditDocument && pageChromeEditing?.part === 'footer' ? ' editing' : ''}`,
15096
15258
  "data-document-page-chrome": lastPageDescriptor.pageChrome.variant,
15097
15259
  style: lastPageFrame && paginationGeometry ? {
15098
15260
  bottom: work_document_layout_millimetersToPixels(lastPageMargins.footerDistance),
@@ -15100,20 +15262,15 @@ function DocumentEditorSurface({ artifactId, autoFocus = true, collaboration, co
15100
15262
  left: lastPageFrame.left + lastPageDescriptor.page.marginLeft,
15101
15263
  right: paginationGeometry.width - lastPageFrame.left - lastPageFrame.width + lastPageDescriptor.page.marginRight
15102
15264
  } : void 0,
15103
- onDoubleClick: preview ? void 0 : (event)=>{
15265
+ onDoubleClick: canEditDocument ? (event)=>{
15104
15266
  if (pageChromeEditing?.part === 'footer') return;
15105
15267
  event.preventDefault();
15106
15268
  editPageChrome('footer');
15107
- },
15269
+ } : void 0,
15108
15270
  children: [
15109
15271
  /*#__PURE__*/ jsx("div", {
15110
15272
  className: "work-document-page-footer-content",
15111
- children: preview || pageChromeEditing?.part !== 'footer' ? footerChrome.footerHtml ? /*#__PURE__*/ jsx("div", {
15112
- className: "work-document-page-chrome-html",
15113
- dangerouslySetInnerHTML: {
15114
- __html: footerChrome.footerHtml
15115
- }
15116
- }) : null : /*#__PURE__*/ jsx(DocumentPageChromeRichTextEditor, {
15273
+ children: canEditDocument && pageChromeEditing?.part === 'footer' ? /*#__PURE__*/ jsx(DocumentPageChromeRichTextEditor, {
15117
15274
  autoFocus: true,
15118
15275
  className: "work-document-page-chrome-inline-editor",
15119
15276
  label: "页内页脚",
@@ -15124,7 +15281,12 @@ function DocumentEditorSurface({ artifactId, autoFocus = true, collaboration, co
15124
15281
  }),
15125
15282
  onEditorChange: setPageChromeEditor,
15126
15283
  onExit: closePageChrome
15127
- }, `${pageChromeEditing.sectionId}-${pageChromeEditing.variant}-footer`)
15284
+ }, `${pageChromeEditing.sectionId}-${pageChromeEditing.variant}-footer`) : footerChrome.footerHtml ? /*#__PURE__*/ jsx("div", {
15285
+ className: "work-document-page-chrome-html",
15286
+ dangerouslySetInnerHTML: {
15287
+ __html: footerChrome.footerHtml
15288
+ }
15289
+ }) : null
15128
15290
  }),
15129
15291
  footerChrome.showPageNumber && /*#__PURE__*/ jsxs("span", {
15130
15292
  className: "work-document-page-number",
@@ -15145,7 +15307,9 @@ function DocumentEditorSurface({ artifactId, autoFocus = true, collaboration, co
15145
15307
  !preview && documentComments.open && /*#__PURE__*/ jsx(DocumentCommentsPanel, {
15146
15308
  editor: editor,
15147
15309
  comments: documentComments.comments,
15310
+ canDelete: documentComments.canDeleteComment,
15148
15311
  draft: documentComments.draft,
15312
+ draftAuthor: collaboration?.actor?.name,
15149
15313
  surfaceRef: reviewSurfaceRef,
15150
15314
  onReply: documentComments.reply,
15151
15315
  onToggleResolved: documentComments.toggleResolved,
@@ -15158,20 +15322,23 @@ function DocumentEditorSurface({ artifactId, autoFocus = true, collaboration, co
15158
15322
  ]
15159
15323
  })
15160
15324
  }),
15161
- !preview && citationsOpen && /*#__PURE__*/ jsx(DocumentCitationsPanel, {
15325
+ canEditDocument && citationsOpen && /*#__PURE__*/ jsx(DocumentCitationsPanel, {
15162
15326
  editor: editor,
15163
15327
  content: currentContent,
15164
15328
  onClose: closeTaskPane,
15165
15329
  onDirtyChange: setCitationsDirty
15166
15330
  }),
15167
- !preview && changesOpen && /*#__PURE__*/ jsx(DocumentChangesPanel, {
15331
+ canReviewDocumentChanges && changesOpen && /*#__PURE__*/ jsx(DocumentChangesPanel, {
15168
15332
  editor: editor,
15169
15333
  changes: changes,
15170
- trackChanges: Boolean(currentContent.trackChanges),
15171
- onTrackChangesChange: (enabled)=>editor.commands.setDocumentTrackChanges(enabled),
15334
+ decisions: currentContent.changeDecisions,
15335
+ trackChanges: suggestionOnly || Boolean(currentContent.trackChanges),
15336
+ suggestionOnly: suggestionOnly,
15337
+ onDecideChanges: canEditDocument ? decideDocumentChanges : void 0,
15338
+ onTrackChangesChange: (enabled)=>suggestionOnly ? false : editor.commands.setDocumentTrackChanges(enabled),
15172
15339
  onClose: closeTaskPane
15173
15340
  }),
15174
- !preview && layoutOpen && section && /*#__PURE__*/ jsx(DocumentLayoutPanel, {
15341
+ canEditDocument && layoutOpen && section && /*#__PURE__*/ jsx(DocumentLayoutPanel, {
15175
15342
  layout: layout,
15176
15343
  activeTab: layoutPanelTab,
15177
15344
  sectionIndex: section.index,
@@ -15182,7 +15349,7 @@ function DocumentEditorSurface({ artifactId, autoFocus = true, collaboration, co
15182
15349
  onMergeSection: ()=>editor.commands.mergeDocumentSectionWithPrevious(),
15183
15350
  onClose: closeTaskPane
15184
15351
  }),
15185
- !preview && findReplaceMode && /*#__PURE__*/ jsx(DocumentFindReplacePanel, {
15352
+ canEditDocument && findReplaceMode && /*#__PURE__*/ jsx(DocumentFindReplacePanel, {
15186
15353
  editor: editor,
15187
15354
  mode: findReplaceMode,
15188
15355
  focusRequest: findReplaceFocusRequest,
@@ -15227,14 +15394,14 @@ function DocumentEditorSurface({ artifactId, autoFocus = true, collaboration, co
15227
15394
  onViewModeChange: changeViewMode,
15228
15395
  onZoomChange: setZoom
15229
15396
  }),
15230
- !preview && selectionMenu && /*#__PURE__*/ jsx(DocumentSelectionContextMenu, {
15397
+ canEditDocument && selectionMenu && /*#__PURE__*/ jsx(DocumentSelectionContextMenu, {
15231
15398
  editor: editor,
15232
15399
  menu: selectionMenu,
15233
15400
  getTrackChanges: ()=>trackChangesRef.current,
15234
15401
  onAgentRequest: onAgentRequest,
15235
15402
  onClose: ()=>setSelectionMenu(null)
15236
15403
  }),
15237
- !preview && documentInsert.dialog,
15404
+ canEditDocument && documentInsert.dialog,
15238
15405
  !preview && taskPaneDialog.dialog,
15239
15406
  !preview && statisticsOpen && /*#__PURE__*/ jsx(DocumentStatisticsDialog, {
15240
15407
  pageCount: pageCount,