@a3s-lab/office 0.25.0 → 0.27.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 (93) hide show
  1. package/README.md +76 -2
  2. package/dist/0~4595.js +16 -2
  3. package/dist/0~5093.js +463 -201
  4. package/dist/0~6090.js +77 -77
  5. package/dist/{0~2805.js → 0~7043.js} +305 -2
  6. package/dist/0~document-editor.js +2451 -985
  7. package/dist/0~spreadsheet-editor.js +22113 -20117
  8. package/dist/0~work-docx-export.js +492 -10
  9. package/dist/0~work-docx-import.js +171 -98
  10. package/dist/0~work-office-diagnostics.js +198 -4
  11. package/dist/{164.js → 1544.js} +1412 -1055
  12. package/dist/4104.js +145 -29
  13. package/dist/6282.js +1920 -544
  14. package/dist/9424.js +16 -0
  15. package/dist/core.js +1 -1
  16. package/dist/index.js +1 -1
  17. package/dist/internal/features/work/editors/document-command-catalog.d.ts +102 -0
  18. package/dist/internal/features/work/editors/document-font-dialog-model.d.ts +83 -0
  19. package/dist/internal/features/work/editors/document-font-dialog-script-font-model.d.ts +18 -0
  20. package/dist/internal/features/work/editors/document-font-dialog.d.ts +9 -0
  21. package/dist/internal/features/work/editors/document-home-ribbon.d.ts +2 -1
  22. package/dist/internal/features/work/editors/document-page-chrome-editor.d.ts +6 -0
  23. package/dist/internal/features/work/editors/document-page-chrome-ribbon.d.ts +2 -1
  24. package/dist/internal/features/work/editors/document-strike-ribbon.d.ts +7 -0
  25. package/dist/internal/features/work/editors/document-text-case-ribbon.d.ts +4 -0
  26. package/dist/internal/features/work/editors/document-toolbar.d.ts +3 -1
  27. package/dist/internal/features/work/editors/document-underline-ribbon.d.ts +9 -0
  28. package/dist/internal/features/work/editors/document-wps-shortcuts.d.ts +1 -0
  29. package/dist/internal/features/work/editors/spreadsheet-cell-fill-format.d.ts +11 -0
  30. package/dist/internal/features/work/editors/spreadsheet-cell-format.d.ts +2 -1
  31. package/dist/internal/features/work/editors/spreadsheet-command-controller.d.ts +18 -9
  32. package/dist/internal/features/work/editors/spreadsheet-format-cells-dialog-model.d.ts +13 -2
  33. package/dist/internal/features/work/editors/spreadsheet-format-cells-fill-panel.d.ts +13 -0
  34. package/dist/internal/features/work/editors/spreadsheet-format-cells-fill-preview.d.ts +6 -0
  35. package/dist/internal/features/work/editors/spreadsheet-format-painter.d.ts +1 -1
  36. package/dist/internal/features/work/editors/spreadsheet-operation-projection.d.ts +6 -0
  37. package/dist/internal/features/work/editors/spreadsheet-rich-text-dom-selection.d.ts +11 -0
  38. package/dist/internal/features/work/editors/spreadsheet-rich-text-paste.d.ts +22 -0
  39. package/dist/internal/features/work/editors/spreadsheet-rich-text-selection-controller.d.ts +38 -0
  40. package/dist/internal/features/work/editors/spreadsheet-rich-text-selection-format.d.ts +26 -0
  41. package/dist/internal/features/work/editors/work-office-chrome.d.ts +9 -1
  42. package/dist/internal/features/work/work-css-color.d.ts +1 -0
  43. package/dist/internal/features/work/work-document-character-formatting.d.ts +16 -1
  44. package/dist/internal/features/work/work-document-character-position.d.ts +9 -0
  45. package/dist/internal/features/work/work-document-character-scale.d.ts +8 -0
  46. package/dist/internal/features/work/work-document-character-spacing.d.ts +8 -0
  47. package/dist/internal/features/work/work-document-emphasis.d.ts +7 -0
  48. package/dist/internal/features/work/work-document-equations.d.ts +2 -1
  49. package/dist/internal/features/work/work-document-format-changes.d.ts +16 -2
  50. package/dist/internal/features/work/work-document-hidden-text.d.ts +5 -0
  51. package/dist/internal/features/work/work-document-kerning.d.ts +10 -0
  52. package/dist/internal/features/work/work-document-paragraph-shading.d.ts +1 -1
  53. package/dist/internal/features/work/work-document-script-font-extension.d.ts +2 -0
  54. package/dist/internal/features/work/work-document-script-fonts.d.ts +51 -0
  55. package/dist/internal/features/work/work-document-strike.d.ts +21 -0
  56. package/dist/internal/features/work/work-document-text-case.d.ts +10 -0
  57. package/dist/internal/features/work/work-document-underline.d.ts +37 -0
  58. package/dist/internal/features/work/work-document-word-line-metrics.d.ts +12 -0
  59. package/dist/internal/features/work/work-docx-character-position.d.ts +2 -0
  60. package/dist/internal/features/work/work-docx-character-scale.d.ts +2 -0
  61. package/dist/internal/features/work/work-docx-character-spacing.d.ts +4 -0
  62. package/dist/internal/features/work/work-docx-emphasis-diagnostics.d.ts +3 -0
  63. package/dist/internal/features/work/work-docx-emphasis.d.ts +14 -0
  64. package/dist/internal/features/work/work-docx-hidden-text-diagnostics.d.ts +3 -0
  65. package/dist/internal/features/work/work-docx-hidden-text-export.d.ts +16 -0
  66. package/dist/internal/features/work/work-docx-hidden-text.d.ts +11 -0
  67. package/dist/internal/features/work/work-docx-kerning-diagnostics.d.ts +3 -0
  68. package/dist/internal/features/work/work-docx-kerning.d.ts +14 -0
  69. package/dist/internal/features/work/work-docx-run-fonts-diagnostics.d.ts +3 -0
  70. package/dist/internal/features/work/work-docx-run-fonts-export.d.ts +14 -0
  71. package/dist/internal/features/work/work-docx-run-fonts.d.ts +13 -0
  72. package/dist/internal/features/work/work-docx-run-formatting-import.d.ts +23 -2
  73. package/dist/internal/features/work/work-docx-run-script-font-import.d.ts +9 -0
  74. package/dist/internal/features/work/work-docx-strike.d.ts +8 -0
  75. package/dist/internal/features/work/work-docx-theme-reference.d.ts +1 -1
  76. package/dist/internal/features/work/work-docx-twips.d.ts +6 -0
  77. package/dist/internal/features/work/work-docx-underline.d.ts +3 -0
  78. package/dist/internal/features/work/work-spreadsheet-gradient-fill-canvas.d.ts +10 -0
  79. package/dist/internal/features/work/work-spreadsheet-native-fill-canvas.d.ts +8 -0
  80. package/dist/internal/features/work/work-spreadsheet-pattern-fill-canvas.d.ts +8 -0
  81. package/dist/internal/features/work/work-xlsx-cell-style-origin.d.ts +2 -1
  82. package/dist/internal/features/work/work-xlsx-cell-style-writer.d.ts +3 -0
  83. package/dist/internal/features/work/work-xlsx-cell-styles.d.ts +4 -0
  84. package/dist/internal/features/work/work-xlsx-gradient-fill.d.ts +31 -0
  85. package/dist/internal/features/work/work-xlsx-native-fill.d.ts +17 -0
  86. package/dist/internal/features/work/work-xlsx-pattern-fill.d.ts +21 -0
  87. package/dist/internal/features/work/work-xlsx-rich-text-edit.d.ts +28 -0
  88. package/dist/internal/features/work/work-xlsx-rich-text-model.d.ts +40 -0
  89. package/dist/internal/features/work/work-xlsx-rich-text.d.ts +4 -18
  90. package/dist/office-kernel.wasm +0 -0
  91. package/dist/styles.css +770 -80
  92. package/docs/latest/en/browser-editor-architecture.md +37 -0
  93. package/package.json +32 -1
@@ -6,19 +6,18 @@ 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, Unlink2, X, XCircle, ZoomIn, ZoomOut } from "lucide-react";
9
+ import { AArrowDown, AArrowUp, ALargeSmall, AlignCenter, AlignJustify, AlignLeft, AlignRight, AlignVerticalJustifyCenter, AlignVerticalJustifyEnd, AlignVerticalJustifyStart, ArrowDown, ArrowUp, BetweenHorizontalEnd, BetweenHorizontalStart, BetweenVerticalEnd, BetweenVerticalStart, Bold, BookMarked, BookOpen, Bookmark, CaseUpper, Check, CheckCheck, CheckCircle2, ChevronDown, ChevronRight, ChevronUp, ClipboardCopy, ClipboardPaste, Cloud, Columns3, Eraser, Eye, 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, Type, 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";
13
13
  import extension_text_align from "@tiptap/extension-text-align";
14
- import { TextStyle } from "@tiptap/extension-text-style";
15
- import extension_underline from "@tiptap/extension-underline";
14
+ import font_size from "@tiptap/extension-text-style/font-size";
16
15
  import starter_kit from "@tiptap/starter-kit";
17
16
  import { BubbleMenu } from "@tiptap/react/menus";
18
17
  import { TableMap, isInTable, selectedRect } from "@tiptap/pm/tables";
19
- import { documentTableSizing, transferChangedDocumentTextStatistics, documentPageBordersVisible, DOCUMENT_PAGE_BORDER_EDGES, documentTableRowOptions, normalizeDocumentColumns, clampDocumentMargin, materializeLazyDocumentEditorRoot, DOCUMENT_BOOKMARK_DUPLICATE_MESSAGE, documentCitationCount, nextDocumentTabAlignment, normalizedTabPosition, isDocumentParagraphArtBorderStyle, resolveDocumentPageBorders, documentLazyHtmlChunkFragment, DOCUMENT_CHUNK_VISIBLE_IDS_META, MAX_DOCUMENT_IMAGE_RELATIVE_HEIGHT, retainAnchoredDocumentComments, DocumentTableRowIdentity, work_document_page_margins_twipsToMillimeters, DEFAULT_DOCUMENT_TABLE_CELL_FORMAT, resolveWorkDocumentEditorInput, collectDocumentTextLayoutParagraphs, documentBulletListStyle, readOfficeDocumentCollaboration as readWorkOfficeDocumentCollaboration, documentOrderedListState, normalizeDocumentPageChrome, documentTextStatistics, documentPageMarginsForLayout, invalidateDocumentLazyHtmlProjection, documentTableCellFormat, normalizeDocumentPageGeometry, normalizeDocumentImageLayer, documentImageProperties, isValidDocumentCitationTag, sanitizeDocumentPageChromeHtml, pageTwipsToMillimeters, normalizeDocumentPageBorders, activeDocumentSection, DocumentParagraphFormatting, normalizeDocumentHtml, documentInitialSectionLayout, documentModelHasTrustedInitialIntegrityFeatures, documentModelUsesWindowing, documentParagraphDirection, documentParagraphPagination, documentPageChromeLegacyFields, documentChunkMountedIds, collectDocumentCommentAnchors, canChangeDocumentIndent, DocumentSuperscript, documentSectionById, activeDocumentBookmark, DocumentEquation, documentLazyHtmlProjectionFingerprint, documentLazyHtmlProjection, normalizeDocumentParagraphIndent, updateDocumentGutterPosition, mountWorkLiveDocumentCapture, registerDocumentPageSurfaceGeometry, syncDocumentContentFromHtml, editorDocumentCaptionTargets, resolveDocumentPageChrome, documentImageLayoutOptions, MAX_DOCUMENT_NUMBERING_START, resolveDocumentPageSize, editorDocumentBookmarkReferenceTargets, serializeWorkDocumentNode, DOCUMENT_CHUNK_PAGINATION_META, createOfficeDocumentCollaborationBinding as createWorkOfficeDocumentCollaborationBinding, documentModelForContent, selectedDocumentChunkId, documentCommentViews, documentParagraphSpacing, normalizeDocumentTabStops, patchDocumentLazyHtmlProjection, documentBookmarkNameExists, collectDocumentChanges, DocumentImage, resolveDocumentPageMargins, updateDocumentPageMarginMode, canSetDocumentTableRowRepeatHeader, millimetersToPixels as work_document_layout_millimetersToPixels, DOCUMENT_CHUNK_HYDRATION_META, documentTabLeaderLabel, createSchemaDerivedWorkDocumentModel, updateDocumentCustomPageMillimeters, documentCommentDraftRange, documentParagraphTabStops, documentTableHorizontalAlignment, documentParagraphIndent, canInsertDocumentComment, documentTextLayoutBatches, normalizeDocumentImageWrapSide, updateDocumentPageOrientation, documentCitationStyleDetails, validateDocumentBookmarkName, setCustomDocumentColumns, updateDocumentPageMarginMillimeters, documentCitationStyle, documentTransactionsOnlyHydrateChunks, DEFAULT_DOCUMENT_TABLE_CELL_MARGINS, DOCUMENT_TABLE_STYLE_OPTIONS, updateDocumentColumnWidth, updateDocumentPaperSizePreset, documentPageMetrics, createDocumentBibliography, DocumentSubscript, DocumentParagraphIdentity, updateDocumentPageChromeVariant, updateDocumentMirrorMargins, activeDocumentTableStyle, measureDocumentLayoutBlocksIncrementally, createWorkDocumentExtensions } from "./6282.js";
18
+ import { documentTableSizing, transferChangedDocumentTextStatistics, documentPageBordersVisible, documentUnderlineStyle, DOCUMENT_PAGE_BORDER_EDGES, documentScriptFontDirectFamily, normalizeDocumentColumns, clampDocumentMargin, materializeLazyDocumentEditorRoot, patchDocumentScriptFonts, documentKerningThresholdPoints, nextDocumentTabAlignment, documentTableRowOptions, normalizedTabPosition, DOCUMENT_BOOKMARK_DUPLICATE_MESSAGE, documentCitationCount, isDocumentParagraphArtBorderStyle, resolveDocumentPageBorders, documentLazyHtmlChunkFragment, DocumentFontFamily, normalizeDocumentHiddenText, DOCUMENT_CHUNK_VISIBLE_IDS_META, MAX_DOCUMENT_IMAGE_RELATIVE_HEIGHT, retainAnchoredDocumentComments, DocumentTableRowIdentity, work_document_page_margins_twipsToMillimeters, DEFAULT_DOCUMENT_TABLE_CELL_FORMAT, resolveWorkDocumentEditorInput, documentCharacterPositionPoints, documentBulletListStyle, collectDocumentTextLayoutParagraphs, readOfficeDocumentCollaboration as readWorkOfficeDocumentCollaboration, normalizeDocumentCharacterScalePercent, documentOrderedListState, normalizeDocumentPageChrome, documentTextStatistics, documentPageMarginsForLayout, invalidateDocumentLazyHtmlProjection, documentTableCellFormat, normalizeDocumentPageGeometry, normalizeDocumentImageLayer, documentImageProperties, isValidDocumentCitationTag, sanitizeDocumentPageChromeHtml, pageTwipsToMillimeters, normalizeDocumentPageBorders, parseDocumentScriptFonts, DocumentParagraphFormatting, activeDocumentSection, normalizeDocumentHtml, documentInitialSectionLayout, documentModelHasTrustedInitialIntegrityFeatures, documentParagraphDirection, documentParagraphPagination, documentModelUsesWindowing, documentPageChromeLegacyFields, documentChunkMountedIds, collectDocumentCommentAnchors, documentTextCaseKeyboardShortcuts, DocumentTextStyle, canChangeDocumentIndent, cssDocumentFontFamily, documentCharacterSpacingPoints, documentKerningIsEffective, DocumentSuperscript, documentSectionById, activeDocumentBookmark, DocumentEquation, documentLazyHtmlProjectionFingerprint, documentLazyHtmlProjection, normalizeDocumentParagraphIndent, updateDocumentGutterPosition, DocumentStrike, mountWorkLiveDocumentCapture, registerDocumentPageSurfaceGeometry, documentHiddenTextKeyboardShortcut, syncDocumentContentFromHtml, documentScriptFontSlotFromHint, editorDocumentCaptionTargets, resolveDocumentPageChrome, documentScriptFontFamilyForRendering, documentImageLayoutOptions, MAX_DOCUMENT_NUMBERING_START, resolveDocumentPageSize, editorDocumentBookmarkReferenceTargets, serializeWorkDocumentNode, DOCUMENT_CHUNK_PAGINATION_META, createOfficeDocumentCollaborationBinding as createWorkOfficeDocumentCollaborationBinding, documentModelForContent, normalizeDocumentEmphasisMark, selectedDocumentChunkId, documentCommentViews, documentParagraphSpacing, normalizeDocumentTabStops, patchDocumentLazyHtmlProjection, normalizeDocumentTextCase, serializeDocumentScriptFonts, documentUnderlineColor, documentBookmarkNameExists, collectDocumentChanges, DocumentImage, resolveDocumentPageMargins, updateDocumentPageMarginMode, canSetDocumentTableRowRepeatHeader, normalizeDocumentCharacterSpacingTwips, DocumentCharacterFormatting, millimetersToPixels as work_document_layout_millimetersToPixels, DOCUMENT_CHUNK_HYDRATION_META, documentTabLeaderLabel, createSchemaDerivedWorkDocumentModel, updateDocumentCustomPageMillimeters, DocumentUnderline, documentCommentDraftRange, documentParagraphTabStops, documentScriptFontSegments, documentUnderlineKeyboardShortcuts, documentParagraphIndent, documentFontNameFromCssFamily, DocumentScriptFontFormatting, canInsertDocumentComment, documentTableHorizontalAlignment, documentTextLayoutBatches, normalizeDocumentImageWrapSide, updateDocumentPageOrientation, documentCitationStyleDetails, validateDocumentBookmarkName, setCustomDocumentColumns, updateDocumentPageMarginMillimeters, documentCitationStyle, normalizeDocumentCharacterPositionHalfPoints, documentTransactionsOnlyHydrateChunks, normalizeDocumentKerningThresholdHalfPoints, DEFAULT_DOCUMENT_TABLE_CELL_MARGINS, DOCUMENT_TABLE_STYLE_OPTIONS, updateDocumentColumnWidth, updateDocumentPaperSizePreset, documentPageMetrics, documentStrikeStyle, createDocumentBibliography, DocumentSubscript, DocumentParagraphIdentity, updateDocumentPageChromeVariant, updateDocumentMirrorMargins, activeDocumentTableStyle, normalizeDocumentScriptFontSlot, measureDocumentLayoutBlocksIncrementally, documentWordLineHeightFactor, createWorkDocumentExtensions } from "./6282.js";
20
19
  import { useOfficeTaskPaneEscape, normalizeOfficeFontFamily, OfficeCheckbox, useOfficeDialog, useOfficeTaskPaneModal, CommittedOfficeNumberField, officeFontFamilyLabel, officeFontFamilies, CollectionState, createOfficeKernelClient, OfficeNumberField } from "./0~7048.js";
21
- import { office_text_field_OfficeTextArea, Popover, officeOverlayPortalRoot, button_Button, useOfficePublishPresenceLocation, OfficeTiptapPresenceLayer, icon_button_IconButton, office_text_field_OfficeTextField, useDialogFocusScope, useOfficeEditorWheelZoom, office_text_field_OfficeFileInput } from "./0~6090.js";
20
+ import { moveOfficeMenuFocus, office_text_field_OfficeTextArea, Popover, officeOverlayPortalRoot, button_Button, useOfficePublishPresenceLocation, OfficeTiptapPresenceLayer, icon_button_IconButton, office_text_field_OfficeTextField, useDialogFocusScope, useOfficeEditorWheelZoom, office_text_field_OfficeFileInput } from "./0~6090.js";
22
21
  import { WorkOfficePreviewBar, isWorkspaceContextMenuKeyboardEvent, Tabs, WorkOfficeZoomControls, WorkOfficeStatusBar, Dialog, WorkOfficeRibbon, workspaceContextMenuPosition, OfficeSelect, WorkspaceContextMenu, WorkOfficeRibbonGroup, WorkOfficeRibbonButton } from "./0~4595.js";
23
22
  import { createOfficeId as createWorkId } from "./5184.js";
24
23
  import { normalizeDocumentHref, DOCUMENT_LINK_VALIDATION_MESSAGE } from "./0~work-document-links.js";
@@ -3948,6 +3947,14 @@ function DocumentPageChromeRichTextEditor({ autoFocus = false, className = '', l
3948
3947
  size: 14
3949
3948
  })
3950
3949
  }),
3950
+ /*#__PURE__*/ jsx(PageChromeButton, {
3951
+ label: `${label}删除线`,
3952
+ active: state?.strike,
3953
+ onClick: ()=>editor?.chain().focus().toggleStrike().run(),
3954
+ children: /*#__PURE__*/ jsx(Strikethrough, {
3955
+ size: 14
3956
+ })
3957
+ }),
3951
3958
  /*#__PURE__*/ jsx(PageChromeButton, {
3952
3959
  label: `${label}下标`,
3953
3960
  active: state?.subscript,
@@ -4061,7 +4068,8 @@ function createDocumentPageChromeEditorExtensions(placeholder = '输入页眉或
4061
4068
  defaultProtocol: 'https',
4062
4069
  openOnClick: false
4063
4070
  },
4064
- underline: false
4071
+ underline: false,
4072
+ strike: false
4065
4073
  }),
4066
4074
  TableKit.configure({
4067
4075
  table: {
@@ -4074,9 +4082,14 @@ function createDocumentPageChromeEditorExtensions(placeholder = '输入页眉或
4074
4082
  inline: true
4075
4083
  }),
4076
4084
  DocumentEquation,
4077
- TextStyle,
4085
+ DocumentTextStyle,
4086
+ DocumentScriptFontFormatting,
4087
+ DocumentFontFamily,
4088
+ font_size,
4078
4089
  extension_color,
4079
- extension_underline,
4090
+ DocumentUnderline,
4091
+ DocumentStrike,
4092
+ DocumentCharacterFormatting,
4080
4093
  DocumentSubscript,
4081
4094
  DocumentSuperscript,
4082
4095
  DocumentPageChromeCommands,
@@ -4101,6 +4114,8 @@ function createDocumentPageChromeEditorExtensions(placeholder = '输入页眉或
4101
4114
  function documentPageChromeEditorState(editor) {
4102
4115
  const textStyle = editor.getAttributes('textStyle');
4103
4116
  const link = editor.getAttributes('link');
4117
+ const underlineStyle = documentUnderlineStyle(editor);
4118
+ const strikeStyle = documentStrikeStyle(editor);
4104
4119
  return {
4105
4120
  alignment: editor.isActive('paragraph', {
4106
4121
  textAlign: 'center'
@@ -4115,9 +4130,13 @@ function documentPageChromeEditorState(editor) {
4115
4130
  color: 'string' == typeof textStyle.color ? textStyle.color : DEFAULT_PAGE_CHROME_COLOR,
4116
4131
  italic: editor.isActive('italic'),
4117
4132
  link: 'string' == typeof link.href ? link.href : null,
4133
+ strike: 'none' !== strikeStyle,
4134
+ strikeStyle,
4118
4135
  subscript: editor.isActive("subscript"),
4119
4136
  superscript: editor.isActive("superscript"),
4120
- underline: editor.isActive('underline')
4137
+ underline: 'none' !== underlineStyle,
4138
+ underlineColor: documentUnderlineColor(editor),
4139
+ underlineStyle
4121
4140
  };
4122
4141
  }
4123
4142
  async function loadDocumentPageChromeImage(file) {
@@ -6744,227 +6763,102 @@ function parseFontSizePoints(value) {
6744
6763
  function formatFontSizePoints(value) {
6745
6764
  return Number.isInteger(value) ? String(value) : String(Number(value.toFixed(2)));
6746
6765
  }
6747
- const bubbleMenuOptions = {
6748
- strategy: 'fixed',
6749
- placement: 'top',
6750
- offset: 9,
6751
- flip: {
6752
- padding: 8
6766
+ const strikeOptions = [
6767
+ {
6768
+ value: 'none',
6769
+ label: '无删除线'
6753
6770
  },
6754
- shift: {
6755
- padding: 8
6771
+ {
6772
+ value: 'single',
6773
+ label: '单删除线'
6756
6774
  },
6757
- inline: true
6758
- };
6759
- const selectionToolbarPluginKey = 'documentSelectionToolbar';
6760
- function DocumentSelectionToolbar({ editor, canInsertComment, layoutFonts = [], onInsertComment, reviewOnly = false }) {
6761
- const toolbarRef = useRef(null);
6762
- const fontFamilyValue = documentFontFamilyValue(editor, layoutFonts);
6763
- const fontSizeValue = documentFontSizeValue(editor);
6764
- useEffect(()=>{
6765
- const hideOutsideInteraction = (event)=>{
6766
- const toolbar = toolbarRef.current;
6767
- if (editor.isDestroyed || !(event.target instanceof Node) || editor.view.dom.contains(event.target) || toolbar && selectionToolbarOwnsTarget(toolbar, event.target)) return;
6768
- editor.view.dispatch(editor.state.tr.setMeta(selectionToolbarPluginKey, 'hide'));
6769
- };
6770
- document.addEventListener('focusin', hideOutsideInteraction, true);
6771
- document.addEventListener('pointerdown', hideOutsideInteraction, true);
6772
- return ()=>{
6773
- document.removeEventListener('focusin', hideOutsideInteraction, true);
6774
- document.removeEventListener('pointerdown', hideOutsideInteraction, true);
6775
- };
6775
+ {
6776
+ value: 'double',
6777
+ label: '双删除线'
6778
+ }
6779
+ ];
6780
+ function DocumentStrikeRibbon({ editor, label = '删除线', menuLabel = '删除线样式', className = '' }) {
6781
+ const subscribe = useCallback((notify)=>{
6782
+ if (editor.isDestroyed) return ()=>void 0;
6783
+ editor.on('transaction', notify);
6784
+ return ()=>editor.off('transaction', notify);
6776
6785
  }, [
6777
6786
  editor
6778
6787
  ]);
6779
- return /*#__PURE__*/ jsxs(BubbleMenu, {
6780
- ref: toolbarRef,
6781
- editor: editor,
6782
- pluginKey: selectionToolbarPluginKey,
6783
- className: "work-document-selection-toolbar",
6784
- role: "toolbar",
6785
- "aria-label": "文本快捷工具栏",
6786
- updateDelay: 80,
6787
- resizeDelay: 60,
6788
- appendTo: ()=>officeOverlayPortalRoot(editor.view.dom.ownerDocument, editor.view.dom),
6789
- options: bubbleMenuOptions,
6790
- shouldShow: ({ element, state, view })=>{
6791
- const { selection } = state;
6792
- const hasFocus = view.hasFocus() || element.contains(document.activeElement);
6793
- return hasFocus && editor.isEditable && selection instanceof TextSelection && !selection.empty && Boolean(state.doc.textBetween(selection.from, selection.to, '\n').trim());
6794
- },
6795
- onPointerDown: (event)=>{
6796
- if ('touch' !== event.nativeEvent.pointerType) event.preventDefault();
6797
- },
6798
- children: [
6799
- !reviewOnly && /*#__PURE__*/ jsxs(Fragment, {
6800
- children: [
6801
- /*#__PURE__*/ jsx(OfficeSelect, {
6802
- ariaLabel: "快捷字体",
6803
- className: "work-document-selection-font-family",
6804
- value: fontFamilyValue,
6805
- options: documentFontFamilyOptionsForValue(fontFamilyValue, layoutFonts),
6806
- onValueChange: (value)=>{
6807
- if ('default' === value) editor.chain().focus().unsetFontFamily().run();
6808
- else editor.chain().focus().setFontFamily(value).run();
6809
- }
6810
- }),
6811
- /*#__PURE__*/ jsx(OfficeSelect, {
6812
- ariaLabel: "快捷字号",
6813
- className: "work-document-selection-font-size",
6814
- value: fontSizeValue,
6815
- options: documentFontSizeOptionsForValue(fontSizeValue),
6816
- onValueChange: (value)=>{
6817
- if ('default' === value) editor.chain().focus().unsetFontSize().run();
6818
- else editor.chain().focus().setFontSize(value).run();
6819
- }
6820
- }),
6821
- /*#__PURE__*/ jsx("span", {
6822
- className: "work-document-selection-divider",
6823
- "aria-hidden": "true"
6824
- }),
6825
- /*#__PURE__*/ jsx(SelectionToolbarButton, {
6826
- label: "加粗",
6827
- active: editor.isActive('bold'),
6828
- onClick: ()=>editor.chain().focus().toggleBold().run(),
6829
- children: /*#__PURE__*/ jsx(Bold, {
6830
- size: 15
6831
- })
6832
- }),
6833
- /*#__PURE__*/ jsx(SelectionToolbarButton, {
6834
- label: "斜体",
6835
- active: editor.isActive('italic'),
6836
- onClick: ()=>editor.chain().focus().toggleItalic().run(),
6837
- children: /*#__PURE__*/ jsx(Italic, {
6838
- size: 15
6839
- })
6840
- }),
6841
- /*#__PURE__*/ jsx(SelectionToolbarButton, {
6842
- label: "下划线",
6843
- active: editor.isActive('underline'),
6844
- onClick: ()=>editor.chain().focus().toggleUnderline().run(),
6845
- children: /*#__PURE__*/ jsx(Underline, {
6846
- size: 15
6847
- })
6848
- }),
6849
- /*#__PURE__*/ jsx(SelectionToolbarButton, {
6850
- label: "删除线",
6851
- active: editor.isActive('strike'),
6852
- onClick: ()=>editor.chain().focus().toggleStrike().run(),
6853
- children: /*#__PURE__*/ jsx(Strikethrough, {
6854
- size: 15
6855
- })
6856
- }),
6857
- /*#__PURE__*/ jsx(OfficeColorPicker, {
6858
- compact: true,
6859
- className: "work-document-selection-color",
6860
- value: editor.getAttributes('textStyle').color ?? '#172033',
6861
- ariaLabel: "快捷文字颜色",
6862
- onValueChange: (color)=>editor.chain().focus().setColor(color).run()
6863
- }),
6864
- /*#__PURE__*/ jsx(SelectionToolbarButton, {
6865
- label: "突出显示",
6866
- active: editor.isActive('highlight'),
6867
- onClick: ()=>editor.chain().focus().toggleHighlight({
6868
- color: '#fff0a6'
6869
- }).run(),
6870
- children: /*#__PURE__*/ jsx(Highlighter, {
6871
- size: 15
6872
- })
6873
- }),
6874
- /*#__PURE__*/ jsx(SelectionToolbarButton, {
6875
- className: "secondary",
6876
- label: "清除格式",
6877
- onClick: ()=>editor.commands.clearDocumentFormatting(),
6878
- children: /*#__PURE__*/ jsx(Eraser, {
6879
- size: 15
6880
- })
6881
- }),
6882
- /*#__PURE__*/ jsx("span", {
6883
- className: "work-document-selection-divider",
6884
- "aria-hidden": "true"
6885
- })
6886
- ]
6887
- }),
6888
- /*#__PURE__*/ jsx(SelectionToolbarButton, {
6889
- label: "添加批注",
6890
- disabled: !canInsertComment,
6891
- onClick: onInsertComment,
6892
- children: /*#__PURE__*/ jsx(MessageSquarePlus, {
6893
- size: 15
6894
- })
6895
- })
6896
- ]
6897
- });
6898
- }
6899
- function selectionToolbarOwnsTarget(toolbar, target) {
6900
- if (toolbar.contains(target)) return true;
6901
- return [
6902
- ...toolbar.querySelectorAll('[aria-controls]')
6903
- ].map((controller)=>controller.getAttribute('aria-controls')).some((controlledId)=>{
6904
- if (!controlledId) return false;
6905
- return document.getElementById(controlledId)?.contains(target) ?? false;
6906
- });
6907
- }
6908
- function SelectionToolbarButton({ active, className = '', disabled = false, label, onClick, children }) {
6909
- return /*#__PURE__*/ jsx("button", {
6910
- type: "button",
6911
- className: className,
6912
- "aria-label": label,
6913
- "aria-pressed": active,
6914
- title: label,
6915
- disabled: disabled,
6916
- onClick: onClick,
6917
- children: children
6918
- });
6919
- }
6920
- function DocumentStatisticsDialog({ pageCount, restoreFocusTarget, statistics, onClose }) {
6921
- const rows = [
6922
- [
6923
- '页数',
6924
- pageCount
6925
- ],
6926
- [
6927
- '字数',
6928
- statistics.wordCount
6929
- ],
6930
- [
6931
- '字符数(不计空格)',
6932
- statistics.characterCountWithoutSpaces
6933
- ],
6934
- [
6935
- '字符数(计空格)',
6936
- statistics.characterCountWithSpaces
6937
- ],
6938
- [
6939
- '段落数',
6940
- statistics.paragraphCount
6941
- ]
6942
- ];
6943
- return /*#__PURE__*/ jsx(Dialog, {
6944
- title: "字数统计",
6945
- description: "当前文档的文本统计。",
6946
- className: "work-document-statistics-dialog",
6947
- focusKey: "document-statistics",
6948
- restoreFocusTarget: restoreFocusTarget,
6949
- onClose: onClose,
6950
- footer: /*#__PURE__*/ jsx(button_Button, {
6951
- tone: "primary",
6952
- onClick: onClose,
6953
- children: "确定"
6954
- }),
6955
- children: /*#__PURE__*/ jsx("dl", {
6956
- className: "work-document-statistics",
6957
- "aria-label": "字数统计详情",
6958
- children: rows.map(([label, value])=>/*#__PURE__*/ jsxs("div", {
6788
+ useSyncExternalStore(subscribe, ()=>editor.state, ()=>editor.state);
6789
+ if (editor.isDestroyed) return null;
6790
+ const style = documentStrikeStyle(editor);
6791
+ const active = 'none' !== style;
6792
+ const currentLabel = strikeOptions.find((option)=>option.value === style)?.label ?? strikeOptions[0].label;
6793
+ return /*#__PURE__*/ jsx("span", {
6794
+ className: `work-document-strike-control${className ? ` ${className}` : ''}`,
6795
+ children: /*#__PURE__*/ jsx(Popover, {
6796
+ label: `更多${label}`,
6797
+ panelLabel: menuLabel,
6798
+ panelRole: "menu",
6799
+ portal: true,
6800
+ placement: "bottom-end",
6801
+ className: "work-document-strike-split-root",
6802
+ panelClassName: "work-office-context-menu work-document-strike-menu",
6803
+ focusFirstOnOpen: true,
6804
+ onPanelKeyDown: moveOfficeMenuFocus,
6805
+ trigger: (triggerProps, { open })=>/*#__PURE__*/ jsxs(Fragment, {
6959
6806
  children: [
6960
- /*#__PURE__*/ jsx("dt", {
6961
- children: label
6807
+ /*#__PURE__*/ jsx("button", {
6808
+ type: "button",
6809
+ className: `work-document-strike-primary${active ? ' active' : ''}`,
6810
+ "aria-label": label,
6811
+ "aria-pressed": active,
6812
+ title: `${label}(${currentLabel})`,
6813
+ onMouseDown: (event)=>event.preventDefault(),
6814
+ onClick: ()=>editor.chain().focus().toggleStrike().run(),
6815
+ children: /*#__PURE__*/ jsx(Strikethrough, {
6816
+ size: 16,
6817
+ "aria-hidden": "true"
6818
+ })
6962
6819
  }),
6963
- /*#__PURE__*/ jsx("dd", {
6964
- children: value
6820
+ /*#__PURE__*/ jsx("button", {
6821
+ ...triggerProps,
6822
+ type: "button",
6823
+ className: `work-document-strike-disclosure${open ? ' active' : ''}`,
6824
+ title: `更多${label}`,
6825
+ onMouseDown: (event)=>event.preventDefault(),
6826
+ children: /*#__PURE__*/ jsx(ChevronDown, {
6827
+ size: 11,
6828
+ "aria-hidden": "true"
6829
+ })
6965
6830
  })
6966
6831
  ]
6967
- }, label))
6832
+ }),
6833
+ children: (close)=>strikeOptions.map((option)=>/*#__PURE__*/ jsxs("button", {
6834
+ type: "button",
6835
+ role: "menuitemradio",
6836
+ tabIndex: -1,
6837
+ "aria-label": option.label,
6838
+ "aria-checked": style === option.value,
6839
+ onClick: ()=>{
6840
+ close();
6841
+ editor.chain().focus().setDocumentStrike(option.value).run();
6842
+ },
6843
+ children: [
6844
+ /*#__PURE__*/ jsx(DocumentStrikeGlyph, {
6845
+ style: option.value
6846
+ }),
6847
+ /*#__PURE__*/ jsx("span", {
6848
+ children: option.label
6849
+ })
6850
+ ]
6851
+ }, option.value))
6852
+ })
6853
+ });
6854
+ }
6855
+ function DocumentStrikeGlyph({ style }) {
6856
+ return /*#__PURE__*/ jsx("span", {
6857
+ className: "work-document-strike-glyph",
6858
+ "data-strike-style": style,
6859
+ "aria-hidden": "true",
6860
+ children: /*#__PURE__*/ jsx("span", {
6861
+ children: "Aa"
6968
6862
  })
6969
6863
  });
6970
6864
  }
@@ -7116,6 +7010,22 @@ const documentCommandCatalog = {
7116
7010
  ]
7117
7011
  }
7118
7012
  },
7013
+ fontDialog: {
7014
+ id: 'font.dialog',
7015
+ label: '字体高级设置',
7016
+ location: {
7017
+ area: 'ribbon',
7018
+ tab: 'home',
7019
+ group: 'font'
7020
+ },
7021
+ shortcut: {
7022
+ label: 'Cmd/Ctrl+D',
7023
+ aria: 'Control+D Meta+D',
7024
+ editor: [
7025
+ 'Mod-d'
7026
+ ]
7027
+ }
7028
+ },
7119
7029
  formatPainter: {
7120
7030
  id: 'clipboard.formatPainter',
7121
7031
  label: '格式刷',
@@ -7173,6 +7083,38 @@ const documentCommandCatalog = {
7173
7083
  ]
7174
7084
  }
7175
7085
  },
7086
+ doubleUnderline: {
7087
+ id: 'font.doubleUnderline',
7088
+ label: '双下划线',
7089
+ location: {
7090
+ area: 'ribbon',
7091
+ tab: 'home',
7092
+ group: 'font'
7093
+ },
7094
+ shortcut: {
7095
+ label: 'Cmd/Ctrl+Shift+D',
7096
+ aria: 'Control+Shift+D Meta+Shift+D',
7097
+ editor: [
7098
+ documentUnderlineKeyboardShortcuts.double
7099
+ ]
7100
+ }
7101
+ },
7102
+ wordsUnderline: {
7103
+ id: 'font.wordsUnderline',
7104
+ label: '仅字下划线',
7105
+ location: {
7106
+ area: 'ribbon',
7107
+ tab: 'home',
7108
+ group: 'font'
7109
+ },
7110
+ shortcut: {
7111
+ label: 'Cmd/Ctrl+Shift+W',
7112
+ aria: 'Control+Shift+W Meta+Shift+W',
7113
+ editor: [
7114
+ documentUnderlineKeyboardShortcuts.words
7115
+ ]
7116
+ }
7117
+ },
7176
7118
  strike: {
7177
7119
  id: 'font.strike',
7178
7120
  label: '删除线',
@@ -7182,6 +7124,47 @@ const documentCommandCatalog = {
7182
7124
  group: 'font'
7183
7125
  }
7184
7126
  },
7127
+ doubleStrike: {
7128
+ id: 'font.doubleStrike',
7129
+ label: '双删除线',
7130
+ location: {
7131
+ area: 'ribbon',
7132
+ tab: 'home',
7133
+ group: 'font'
7134
+ }
7135
+ },
7136
+ allCaps: {
7137
+ id: 'font.allCaps',
7138
+ label: '全部大写',
7139
+ location: {
7140
+ area: 'ribbon',
7141
+ tab: 'home',
7142
+ group: 'font'
7143
+ },
7144
+ shortcut: {
7145
+ label: 'Cmd/Ctrl+Shift+A',
7146
+ aria: 'Control+Shift+A Meta+Shift+A',
7147
+ editor: [
7148
+ documentTextCaseKeyboardShortcuts.allCaps
7149
+ ]
7150
+ }
7151
+ },
7152
+ smallCaps: {
7153
+ id: 'font.smallCaps',
7154
+ label: '小型大写',
7155
+ location: {
7156
+ area: 'ribbon',
7157
+ tab: 'home',
7158
+ group: 'font'
7159
+ },
7160
+ shortcut: {
7161
+ label: 'Cmd/Ctrl+Shift+K',
7162
+ aria: 'Control+Shift+K Meta+Shift+K',
7163
+ editor: [
7164
+ documentTextCaseKeyboardShortcuts.smallCaps
7165
+ ]
7166
+ }
7167
+ },
7185
7168
  subscript: {
7186
7169
  id: "font.subscript",
7187
7170
  label: '下标',
@@ -7223,6 +7206,22 @@ const documentCommandCatalog = {
7223
7206
  group: 'font'
7224
7207
  }
7225
7208
  },
7209
+ hiddenText: {
7210
+ id: 'font.hiddenText',
7211
+ label: '隐藏文字',
7212
+ location: {
7213
+ area: 'ribbon',
7214
+ tab: 'home',
7215
+ group: 'font'
7216
+ },
7217
+ shortcut: {
7218
+ label: 'Cmd/Ctrl+Shift+H',
7219
+ aria: 'Control+Shift+H Meta+Shift+H',
7220
+ editor: [
7221
+ documentHiddenTextKeyboardShortcut
7222
+ ]
7223
+ }
7224
+ },
7226
7225
  clearFormatting: {
7227
7226
  id: 'font.clearFormatting',
7228
7227
  label: '清除格式',
@@ -7538,6 +7537,15 @@ const documentCommandCatalog = {
7538
7537
  group: 'show'
7539
7538
  }
7540
7539
  },
7540
+ showHiddenText: {
7541
+ id: 'view.showHiddenText',
7542
+ label: '显示隐藏文字',
7543
+ location: {
7544
+ area: 'ribbon',
7545
+ tab: 'view',
7546
+ group: 'show'
7547
+ }
7548
+ },
7541
7549
  wordCount: {
7542
7550
  id: 'status.wordCount',
7543
7551
  label: '字数统计',
@@ -7556,342 +7564,747 @@ const documentCommandCatalog = {
7556
7564
  function getDocumentCommandDefinition(id) {
7557
7565
  return documentCommandCatalog[id];
7558
7566
  }
7559
- const MIN_DOCUMENT_ZOOM = 50;
7560
- const MAX_DOCUMENT_ZOOM = 200;
7561
- function clampDocumentZoom(zoom) {
7562
- return Math.min(MAX_DOCUMENT_ZOOM, Math.max(MIN_DOCUMENT_ZOOM, Math.round(zoom)));
7563
- }
7564
- function documentZoomForFit(fit, metrics) {
7565
- const availableWidth = Math.max(1, metrics.viewportWidth - metrics.viewportPadding.left - metrics.viewportPadding.right);
7566
- const widthZoom = availableWidth / Math.max(1, metrics.pageWidth) * 100;
7567
- if ('width' === fit) return clampDocumentZoom(widthZoom);
7568
- const availableHeight = Math.max(1, metrics.viewportHeight - metrics.viewportPadding.top - metrics.viewportPadding.bottom);
7569
- const heightZoom = availableHeight / Math.max(1, metrics.pageHeight) * 100;
7570
- return clampDocumentZoom(Math.min(widthZoom, heightZoom));
7571
- }
7572
- function DocumentStatusBar({ bibliographyCount, citationCount, currentPage, pageCount, saveStatus, sectionCount, sectionIndex, spellcheckEnabled, viewMode, wordCount, zoom, onSpellcheckChange, onOpenWordCount, onViewModeChange, onZoomChange }) {
7573
- const wordCountCommand = getDocumentCommandDefinition('wordCount');
7574
- return /*#__PURE__*/ jsxs(WorkOfficeStatusBar, {
7575
- ariaLabel: "文档状态栏",
7576
- controlsLabel: "文档视图与缩放",
7577
- className: "work-document-footer",
7578
- controls: /*#__PURE__*/ jsxs(Fragment, {
7579
- children: [
7580
- /*#__PURE__*/ jsx("button", {
7581
- type: "button",
7582
- "data-document-status-control": "view-mode",
7583
- "aria-label": "页面视图",
7584
- title: "页面视图",
7585
- "aria-pressed": 'page' === viewMode,
7586
- onClick: ()=>onViewModeChange('page'),
7587
- children: /*#__PURE__*/ jsx(FileText, {
7588
- size: 13
7589
- })
7590
- }),
7591
- /*#__PURE__*/ jsx("button", {
7592
- type: "button",
7593
- "data-document-status-control": "view-mode",
7594
- "aria-label": "网页视图",
7595
- title: "网页视图",
7596
- "aria-pressed": 'web' === viewMode,
7597
- onClick: ()=>onViewModeChange('web'),
7598
- children: /*#__PURE__*/ jsx(Globe2, {
7599
- size: 13
7600
- })
7601
- }),
7602
- /*#__PURE__*/ jsx("span", {
7603
- className: "work-office-status-divider",
7604
- "data-document-status-control": "view-mode"
7605
- }),
7606
- /*#__PURE__*/ jsx(WorkOfficeZoomControls, {
7607
- zoom: zoom,
7608
- minimum: 50,
7609
- maximum: 200,
7610
- step: 5,
7611
- decreaseLabel: "缩小文档",
7612
- increaseLabel: "放大文档",
7613
- outputLabel: "文档缩放比例",
7614
- sliderLabel: "文档缩放",
7615
- onChange: (value)=>onZoomChange(clampDocumentZoom(value))
7616
- })
7617
- ]
7618
- }),
7567
+ const underlineOptions = [
7568
+ {
7569
+ value: 'none',
7570
+ label: '无下划线'
7571
+ },
7572
+ {
7573
+ value: 'single',
7574
+ label: '单下划线',
7575
+ command: 'underline'
7576
+ },
7577
+ {
7578
+ value: 'words',
7579
+ label: '仅字下划线',
7580
+ command: 'wordsUnderline'
7581
+ },
7582
+ {
7583
+ value: 'double',
7584
+ label: '双下划线',
7585
+ command: 'doubleUnderline'
7586
+ },
7587
+ {
7588
+ value: 'thick',
7589
+ label: '粗下划线'
7590
+ },
7591
+ {
7592
+ value: 'dotted',
7593
+ label: '点线'
7594
+ },
7595
+ {
7596
+ value: 'dottedHeavy',
7597
+ label: '粗点线'
7598
+ },
7599
+ {
7600
+ value: 'dash',
7601
+ label: '短划线'
7602
+ },
7603
+ {
7604
+ value: 'dashedHeavy',
7605
+ label: '粗短划线'
7606
+ },
7607
+ {
7608
+ value: 'dashLong',
7609
+ label: '长划线'
7610
+ },
7611
+ {
7612
+ value: 'dashLongHeavy',
7613
+ label: '粗长划线'
7614
+ },
7615
+ {
7616
+ value: 'dotDash',
7617
+ label: '点划线'
7618
+ },
7619
+ {
7620
+ value: 'dashDotHeavy',
7621
+ label: '粗点划线'
7622
+ },
7623
+ {
7624
+ value: 'dotDotDash',
7625
+ label: '双点划线'
7626
+ },
7627
+ {
7628
+ value: 'dashDotDotHeavy',
7629
+ label: '粗双点划线'
7630
+ },
7631
+ {
7632
+ value: 'wave',
7633
+ label: '波浪线'
7634
+ },
7635
+ {
7636
+ value: 'wavyHeavy',
7637
+ label: '粗波浪线'
7638
+ },
7639
+ {
7640
+ value: 'wavyDouble',
7641
+ label: '双波浪线'
7642
+ }
7643
+ ];
7644
+ function DocumentUnderlineRibbon({ editor, label = '下划线', menuLabel = '下划线样式', colorLabel = '下划线颜色', showColor = true, className = '' }) {
7645
+ const subscribe = useCallback((notify)=>{
7646
+ if (editor.isDestroyed) return ()=>void 0;
7647
+ editor.on('transaction', notify);
7648
+ return ()=>editor.off('transaction', notify);
7649
+ }, [
7650
+ editor
7651
+ ]);
7652
+ useSyncExternalStore(subscribe, ()=>editor.state, ()=>editor.state);
7653
+ if (editor.isDestroyed) return null;
7654
+ const style = documentUnderlineStyle(editor);
7655
+ const active = 'none' !== style;
7656
+ const color = documentUnderlineColor(editor) ?? '#172033';
7657
+ const currentLabel = underlineOptions.find((option)=>option.value === style)?.label ?? underlineOptions[0].label;
7658
+ const shortcut = getDocumentCommandDefinition('underline').shortcut;
7659
+ return /*#__PURE__*/ jsxs("span", {
7660
+ className: `work-document-underline-control${className ? ` ${className}` : ''}`,
7619
7661
  children: [
7620
- /*#__PURE__*/ jsxs("output", {
7621
- "aria-label": "页码状态",
7622
- "data-document-status-item": "page",
7623
- children: [
7624
- "第 ",
7625
- currentPage,
7626
- " 页,共 ",
7627
- pageCount,
7628
- " 页"
7629
- ]
7630
- }),
7631
- /*#__PURE__*/ jsxs("output", {
7632
- "aria-label": "分节状态",
7633
- "data-document-status-item": "section",
7634
- children: [
7635
- " ",
7636
- sectionIndex + 1,
7637
- " 节,共 ",
7638
- sectionCount,
7639
- " 节"
7640
- ]
7641
- }),
7642
- /*#__PURE__*/ jsxs("button", {
7643
- type: "button",
7644
- className: "work-office-status-text-button",
7645
- "data-document-status-item": "word-count",
7646
- "aria-label": `字数统计:${wordCount}`,
7647
- "aria-keyshortcuts": wordCountCommand.shortcut?.aria,
7648
- title: `${wordCountCommand.label}(${wordCountCommand.shortcut?.label})`,
7649
- onClick: onOpenWordCount,
7650
- children: [
7651
- "字数:",
7652
- wordCount
7653
- ]
7654
- }),
7655
- /*#__PURE__*/ jsx("button", {
7656
- type: "button",
7657
- "data-document-status-item": "spellcheck",
7658
- "aria-label": `校对:${spellcheckEnabled ? '已开启' : '已关闭'}`,
7659
- title: `校对:${spellcheckEnabled ? '已开启' : '已关闭'}`,
7660
- "aria-pressed": spellcheckEnabled,
7661
- onClick: ()=>onSpellcheckChange(!spellcheckEnabled),
7662
- children: /*#__PURE__*/ jsx(CheckCheck, {
7663
- size: 12
7664
- })
7665
- }),
7666
- /*#__PURE__*/ jsxs("output", {
7667
- "aria-label": "引用状态",
7668
- children: [
7669
- bibliographyCount,
7670
- " 条文献 \xb7 ",
7671
- citationCount,
7672
- " 处引文"
7673
- ]
7674
- }),
7675
- /*#__PURE__*/ jsxs("output", {
7676
- "aria-label": "文档保存状态",
7677
- className: "work-office-save-status",
7678
- children: [
7679
- /*#__PURE__*/ jsx(Cloud, {
7680
- size: 12
7662
+ /*#__PURE__*/ jsx(Popover, {
7663
+ label: `更多${label}`,
7664
+ panelLabel: menuLabel,
7665
+ panelRole: "menu",
7666
+ portal: true,
7667
+ placement: "bottom-end",
7668
+ className: "work-document-underline-split-root",
7669
+ panelClassName: "work-office-context-menu work-document-underline-menu",
7670
+ focusFirstOnOpen: true,
7671
+ onPanelKeyDown: moveOfficeMenuFocus,
7672
+ trigger: (triggerProps, { open })=>/*#__PURE__*/ jsxs(Fragment, {
7673
+ children: [
7674
+ /*#__PURE__*/ jsx("button", {
7675
+ type: "button",
7676
+ className: `work-document-underline-primary${active ? ' active' : ''}`,
7677
+ "aria-label": label,
7678
+ "aria-keyshortcuts": shortcut?.aria,
7679
+ "aria-pressed": active,
7680
+ title: `${label}(${currentLabel};${shortcut?.label ?? ''})`,
7681
+ onMouseDown: (event)=>event.preventDefault(),
7682
+ onClick: ()=>editor.chain().focus().toggleUnderline().run(),
7683
+ children: /*#__PURE__*/ jsx(Underline, {
7684
+ size: 16,
7685
+ "aria-hidden": "true"
7686
+ })
7687
+ }),
7688
+ /*#__PURE__*/ jsx("button", {
7689
+ ...triggerProps,
7690
+ type: "button",
7691
+ className: `work-document-underline-disclosure${open ? ' active' : ''}`,
7692
+ title: `更多${label}`,
7693
+ onMouseDown: (event)=>event.preventDefault(),
7694
+ children: /*#__PURE__*/ jsx(ChevronDown, {
7695
+ size: 11,
7696
+ "aria-hidden": "true"
7697
+ })
7698
+ })
7699
+ ]
7681
7700
  }),
7682
- saveStatus
7683
- ]
7701
+ children: (close)=>underlineOptions.map((option)=>{
7702
+ const optionShortcut = 'command' in option ? getDocumentCommandDefinition(option.command).shortcut : void 0;
7703
+ return /*#__PURE__*/ jsxs("button", {
7704
+ type: "button",
7705
+ role: "menuitemradio",
7706
+ tabIndex: -1,
7707
+ "aria-label": option.label,
7708
+ "aria-checked": style === option.value,
7709
+ "aria-keyshortcuts": optionShortcut?.aria,
7710
+ onClick: ()=>{
7711
+ close();
7712
+ editor.chain().focus().setDocumentUnderline(option.value).run();
7713
+ },
7714
+ children: [
7715
+ /*#__PURE__*/ jsx(DocumentUnderlineGlyph, {
7716
+ style: option.value
7717
+ }),
7718
+ /*#__PURE__*/ jsx("span", {
7719
+ children: option.label
7720
+ }),
7721
+ optionShortcut && /*#__PURE__*/ jsx("kbd", {
7722
+ children: optionShortcut.label
7723
+ })
7724
+ ]
7725
+ }, option.value);
7726
+ })
7727
+ }),
7728
+ showColor && /*#__PURE__*/ jsx(OfficeColorPicker, {
7729
+ compact: true,
7730
+ className: "work-document-underline-color",
7731
+ ariaLabel: colorLabel,
7732
+ value: color,
7733
+ resetAction: {
7734
+ kind: 'automatic',
7735
+ label: '自动颜色',
7736
+ onSelect: ()=>editor.chain().focus().setDocumentUnderlineColor(null).run()
7737
+ },
7738
+ onValueChange: (value)=>editor.chain().focus().setDocumentUnderlineColor(value).run()
7684
7739
  })
7685
7740
  ]
7686
7741
  });
7687
7742
  }
7688
- function DocumentFormatTools({ editor }) {
7689
- const hasFormat = useSyncExternalStore(subscribeDocumentFormatClipboard, hasDocumentFormatClipboard, hasDocumentFormatClipboard);
7690
- const [formatPainterActive, setFormatPainterActive] = useState(false);
7691
- const painterSourceRef = useRef(null);
7692
- const copyFormatCommand = getDocumentCommandDefinition('copyFormat');
7693
- const pasteFormatCommand = getDocumentCommandDefinition('pasteFormat');
7743
+ function DocumentUnderlineGlyph({ style }) {
7744
+ return /*#__PURE__*/ jsx("span", {
7745
+ className: "work-document-underline-glyph",
7746
+ "data-underline-style": style,
7747
+ "aria-hidden": "true",
7748
+ children: /*#__PURE__*/ jsx("span", {
7749
+ children: "Aa"
7750
+ })
7751
+ });
7752
+ }
7753
+ const bubbleMenuOptions = {
7754
+ strategy: 'fixed',
7755
+ placement: 'top',
7756
+ offset: 9,
7757
+ flip: {
7758
+ padding: 8
7759
+ },
7760
+ shift: {
7761
+ padding: 8
7762
+ },
7763
+ inline: true
7764
+ };
7765
+ const selectionToolbarPluginKey = 'documentSelectionToolbar';
7766
+ function DocumentSelectionToolbar({ editor, canInsertComment, layoutFonts = [], onInsertComment, reviewOnly = false }) {
7767
+ const toolbarRef = useRef(null);
7768
+ const fontFamilyValue = documentFontFamilyValue(editor, layoutFonts);
7769
+ const fontSizeValue = documentFontSizeValue(editor);
7694
7770
  useEffect(()=>{
7695
- if (!formatPainterActive || editor.isDestroyed) return;
7696
- const editorDom = editor.view.dom;
7697
- editorDom.dataset.documentFormatPainter = 'true';
7698
- const applyFormatPainter = ()=>{
7699
- if (editor.isDestroyed) return;
7700
- const selection = editor.state.selection;
7701
- const source = painterSourceRef.current;
7702
- if (source && source.from === selection.from && source.to === selection.to) return;
7703
- if (pasteDocumentFormatting(editor)) setFormatPainterActive(false);
7704
- };
7705
- const onPointerUp = (event)=>{
7706
- if (0 === event.button) applyFormatPainter();
7707
- };
7708
- const onKeyUp = (event)=>{
7709
- if (event.shiftKey || event.key.startsWith('Arrow') || 'Home' === event.key || 'End' === event.key) applyFormatPainter();
7710
- };
7711
- const onKeyDown = (event)=>{
7712
- if ('Escape' !== event.key) return;
7713
- event.preventDefault();
7714
- setFormatPainterActive(false);
7771
+ const hideOutsideInteraction = (event)=>{
7772
+ const toolbar = toolbarRef.current;
7773
+ if (editor.isDestroyed || !(event.target instanceof Node) || editor.view.dom.contains(event.target) || toolbar && selectionToolbarOwnsTarget(toolbar, event.target)) return;
7774
+ editor.view.dispatch(editor.state.tr.setMeta(selectionToolbarPluginKey, 'hide'));
7715
7775
  };
7716
- editorDom.addEventListener('pointerup', onPointerUp);
7717
- editorDom.addEventListener('keyup', onKeyUp);
7718
- editorDom.addEventListener('keydown', onKeyDown, true);
7776
+ document.addEventListener('focusin', hideOutsideInteraction, true);
7777
+ document.addEventListener('pointerdown', hideOutsideInteraction, true);
7719
7778
  return ()=>{
7720
- delete editorDom.dataset.documentFormatPainter;
7721
- editorDom.removeEventListener('pointerup', onPointerUp);
7722
- editorDom.removeEventListener('keyup', onKeyUp);
7723
- editorDom.removeEventListener('keydown', onKeyDown, true);
7779
+ document.removeEventListener('focusin', hideOutsideInteraction, true);
7780
+ document.removeEventListener('pointerdown', hideOutsideInteraction, true);
7724
7781
  };
7725
7782
  }, [
7726
- editor,
7727
- formatPainterActive
7783
+ editor
7728
7784
  ]);
7729
- const copyFormat = ()=>copyDocumentFormatting(editor);
7730
- const toggleFormatPainter = ()=>{
7731
- if (formatPainterActive) return void setFormatPainterActive(false);
7732
- if (!copyDocumentFormatting(editor)) return;
7733
- painterSourceRef.current = {
7734
- from: editor.state.selection.from,
7735
- to: editor.state.selection.to
7736
- };
7737
- setFormatPainterActive(true);
7738
- };
7739
- return /*#__PURE__*/ jsxs(WorkOfficeRibbonGroup, {
7740
- label: "剪贴板",
7741
- priority: "normal",
7785
+ return /*#__PURE__*/ jsxs(BubbleMenu, {
7786
+ ref: toolbarRef,
7787
+ editor: editor,
7788
+ pluginKey: selectionToolbarPluginKey,
7789
+ className: "work-document-selection-toolbar",
7790
+ role: "toolbar",
7791
+ "aria-label": "文本快捷工具栏",
7792
+ updateDelay: 80,
7793
+ resizeDelay: 60,
7794
+ appendTo: ()=>officeOverlayPortalRoot(editor.view.dom.ownerDocument, editor.view.dom),
7795
+ options: bubbleMenuOptions,
7796
+ shouldShow: ({ element, state, view })=>{
7797
+ const { selection } = state;
7798
+ const hasFocus = view.hasFocus() || element.contains(document.activeElement);
7799
+ return hasFocus && editor.isEditable && selection instanceof TextSelection && !selection.empty && Boolean(state.doc.textBetween(selection.from, selection.to, '\n').trim());
7800
+ },
7801
+ onPointerDown: (event)=>{
7802
+ if ('touch' !== event.nativeEvent.pointerType) event.preventDefault();
7803
+ },
7742
7804
  children: [
7743
- /*#__PURE__*/ jsx(WorkOfficeRibbonButton, {
7744
- label: "复制格式",
7745
- title: `复制格式(${copyFormatCommand.shortcut?.label})`,
7746
- "aria-keyshortcuts": copyFormatCommand.shortcut?.aria,
7747
- onClick: copyFormat,
7748
- children: /*#__PURE__*/ jsx(ClipboardCopy, {
7749
- size: 17
7750
- })
7751
- }),
7752
- /*#__PURE__*/ jsx(WorkOfficeRibbonButton, {
7753
- label: "粘贴格式",
7754
- title: `粘贴格式(${pasteFormatCommand.shortcut?.label})`,
7755
- "aria-keyshortcuts": pasteFormatCommand.shortcut?.aria,
7756
- disabled: !hasFormat,
7757
- onClick: ()=>pasteDocumentFormatting(editor),
7758
- children: /*#__PURE__*/ jsx(ClipboardPaste, {
7759
- size: 17
7760
- })
7805
+ !reviewOnly && /*#__PURE__*/ jsxs(Fragment, {
7806
+ children: [
7807
+ /*#__PURE__*/ jsx(OfficeSelect, {
7808
+ ariaLabel: "快捷字体",
7809
+ className: "work-document-selection-font-family",
7810
+ value: fontFamilyValue,
7811
+ options: documentFontFamilyOptionsForValue(fontFamilyValue, layoutFonts),
7812
+ onValueChange: (value)=>{
7813
+ if ('default' === value) editor.chain().focus().unsetFontFamily().run();
7814
+ else editor.chain().focus().setFontFamily(value).run();
7815
+ }
7816
+ }),
7817
+ /*#__PURE__*/ jsx(OfficeSelect, {
7818
+ ariaLabel: "快捷字号",
7819
+ className: "work-document-selection-font-size",
7820
+ value: fontSizeValue,
7821
+ options: documentFontSizeOptionsForValue(fontSizeValue),
7822
+ onValueChange: (value)=>{
7823
+ if ('default' === value) editor.chain().focus().unsetFontSize().run();
7824
+ else editor.chain().focus().setFontSize(value).run();
7825
+ }
7826
+ }),
7827
+ /*#__PURE__*/ jsx("span", {
7828
+ className: "work-document-selection-divider",
7829
+ "aria-hidden": "true"
7830
+ }),
7831
+ /*#__PURE__*/ jsx(SelectionToolbarButton, {
7832
+ label: "加粗",
7833
+ active: editor.isActive('bold'),
7834
+ onClick: ()=>editor.chain().focus().toggleBold().run(),
7835
+ children: /*#__PURE__*/ jsx(Bold, {
7836
+ size: 15
7837
+ })
7838
+ }),
7839
+ /*#__PURE__*/ jsx(SelectionToolbarButton, {
7840
+ label: "斜体",
7841
+ active: editor.isActive('italic'),
7842
+ onClick: ()=>editor.chain().focus().toggleItalic().run(),
7843
+ children: /*#__PURE__*/ jsx(Italic, {
7844
+ size: 15
7845
+ })
7846
+ }),
7847
+ /*#__PURE__*/ jsx(DocumentUnderlineRibbon, {
7848
+ editor: editor,
7849
+ menuLabel: "快捷下划线样式",
7850
+ showColor: false,
7851
+ className: "work-document-selection-underline"
7852
+ }),
7853
+ /*#__PURE__*/ jsx(DocumentStrikeRibbon, {
7854
+ editor: editor,
7855
+ menuLabel: "快捷删除线样式",
7856
+ className: "work-document-selection-strike"
7857
+ }),
7858
+ /*#__PURE__*/ jsx(OfficeColorPicker, {
7859
+ compact: true,
7860
+ className: "work-document-selection-color",
7861
+ value: editor.getAttributes('textStyle').color ?? '#172033',
7862
+ ariaLabel: "快捷文字颜色",
7863
+ onValueChange: (color)=>editor.chain().focus().setColor(color).run()
7864
+ }),
7865
+ /*#__PURE__*/ jsx(SelectionToolbarButton, {
7866
+ label: "突出显示",
7867
+ active: editor.isActive('highlight'),
7868
+ onClick: ()=>editor.chain().focus().toggleHighlight({
7869
+ color: '#fff0a6'
7870
+ }).run(),
7871
+ children: /*#__PURE__*/ jsx(Highlighter, {
7872
+ size: 15
7873
+ })
7874
+ }),
7875
+ /*#__PURE__*/ jsx(SelectionToolbarButton, {
7876
+ className: "secondary",
7877
+ label: "清除格式",
7878
+ onClick: ()=>editor.commands.clearDocumentFormatting(),
7879
+ children: /*#__PURE__*/ jsx(Eraser, {
7880
+ size: 15
7881
+ })
7882
+ }),
7883
+ /*#__PURE__*/ jsx("span", {
7884
+ className: "work-document-selection-divider",
7885
+ "aria-hidden": "true"
7886
+ })
7887
+ ]
7761
7888
  }),
7762
- /*#__PURE__*/ jsx(WorkOfficeRibbonButton, {
7763
- label: "格式刷",
7764
- title: "格式刷(选择源格式后应用到下一处选择)",
7765
- active: formatPainterActive,
7766
- onClick: toggleFormatPainter,
7767
- children: /*#__PURE__*/ jsx(Paintbrush, {
7768
- size: 17
7889
+ /*#__PURE__*/ jsx(SelectionToolbarButton, {
7890
+ label: "添加批注",
7891
+ disabled: !canInsertComment,
7892
+ onClick: onInsertComment,
7893
+ children: /*#__PURE__*/ jsx(MessageSquarePlus, {
7894
+ size: 15
7769
7895
  })
7770
7896
  })
7771
7897
  ]
7772
7898
  });
7773
7899
  }
7774
- const bulletStyles = [
7775
- {
7776
- value: 'disc',
7777
- label: '实心圆点',
7778
- marker: ''
7779
- },
7780
- {
7781
- value: 'circle',
7782
- label: '空心圆点',
7783
- marker: ''
7784
- },
7785
- {
7786
- value: 'square',
7787
- label: '方块',
7788
- marker: '■'
7789
- }
7790
- ];
7791
- const orderedStyles = [
7792
- {
7793
- value: 'decimal',
7794
- label: '数字',
7795
- markers: [
7796
- '1.',
7797
- '2.',
7798
- '3.'
7799
- ]
7800
- },
7801
- {
7802
- value: 'lower-alpha',
7803
- label: '小写字母',
7804
- markers: [
7805
- 'a.',
7806
- 'b.',
7807
- 'c.'
7808
- ]
7809
- },
7810
- {
7811
- value: 'upper-alpha',
7812
- label: '大写字母',
7813
- markers: [
7814
- 'A.',
7815
- 'B.',
7816
- 'C.'
7817
- ]
7818
- },
7819
- {
7820
- value: 'lower-roman',
7821
- label: '小写罗马数字',
7822
- markers: [
7823
- 'i.',
7824
- 'ii.',
7825
- 'iii.'
7826
- ]
7827
- },
7828
- {
7829
- value: 'upper-roman',
7830
- label: '大写罗马数字',
7831
- markers: [
7832
- 'I.',
7833
- 'II.',
7834
- 'III.'
7900
+ function selectionToolbarOwnsTarget(toolbar, target) {
7901
+ if (toolbar.contains(target)) return true;
7902
+ return [
7903
+ ...toolbar.querySelectorAll('[aria-controls]')
7904
+ ].map((controller)=>controller.getAttribute('aria-controls')).some((controlledId)=>{
7905
+ if (!controlledId) return false;
7906
+ return document.getElementById(controlledId)?.contains(target) ?? false;
7907
+ });
7908
+ }
7909
+ function SelectionToolbarButton({ active, className = '', disabled = false, label, onClick, children }) {
7910
+ return /*#__PURE__*/ jsx("button", {
7911
+ type: "button",
7912
+ className: className,
7913
+ "aria-label": label,
7914
+ "aria-pressed": active,
7915
+ title: label,
7916
+ disabled: disabled,
7917
+ onClick: onClick,
7918
+ children: children
7919
+ });
7920
+ }
7921
+ function DocumentStatisticsDialog({ pageCount, restoreFocusTarget, statistics, onClose }) {
7922
+ const rows = [
7923
+ [
7924
+ '页数',
7925
+ pageCount
7926
+ ],
7927
+ [
7928
+ '字数',
7929
+ statistics.wordCount
7930
+ ],
7931
+ [
7932
+ '字符数(不计空格)',
7933
+ statistics.characterCountWithoutSpaces
7934
+ ],
7935
+ [
7936
+ '字符数(计空格)',
7937
+ statistics.characterCountWithSpaces
7938
+ ],
7939
+ [
7940
+ '段落数',
7941
+ statistics.paragraphCount
7835
7942
  ]
7836
- }
7837
- ];
7838
- function DocumentListGallery({ editor }) {
7839
- const subscribe = useCallback((notify)=>{
7840
- editor.on('transaction', notify);
7841
- return ()=>editor.off('transaction', notify);
7842
- }, [
7843
- editor
7844
- ]);
7845
- useSyncExternalStore(subscribe, ()=>documentListSnapshot(editor), ()=>documentListSnapshot(editor));
7846
- const bulletStyle = documentBulletListStyle(editor);
7847
- const orderedState = documentOrderedListState(editor);
7848
- return /*#__PURE__*/ jsxs("div", {
7849
- className: "work-document-list-tools",
7943
+ ];
7944
+ return /*#__PURE__*/ jsx(Dialog, {
7945
+ title: "字数统计",
7946
+ description: "当前文档的文本统计。",
7947
+ className: "work-document-statistics-dialog",
7948
+ focusKey: "document-statistics",
7949
+ restoreFocusTarget: restoreFocusTarget,
7950
+ onClose: onClose,
7951
+ footer: /*#__PURE__*/ jsx(button_Button, {
7952
+ tone: "primary",
7953
+ onClick: onClose,
7954
+ children: "确定"
7955
+ }),
7956
+ children: /*#__PURE__*/ jsx("dl", {
7957
+ className: "work-document-statistics",
7958
+ "aria-label": "字数统计详情",
7959
+ children: rows.map(([label, value])=>/*#__PURE__*/ jsxs("div", {
7960
+ children: [
7961
+ /*#__PURE__*/ jsx("dt", {
7962
+ children: label
7963
+ }),
7964
+ /*#__PURE__*/ jsx("dd", {
7965
+ children: value
7966
+ })
7967
+ ]
7968
+ }, label))
7969
+ })
7970
+ });
7971
+ }
7972
+ const MIN_DOCUMENT_ZOOM = 50;
7973
+ const MAX_DOCUMENT_ZOOM = 200;
7974
+ function clampDocumentZoom(zoom) {
7975
+ return Math.min(MAX_DOCUMENT_ZOOM, Math.max(MIN_DOCUMENT_ZOOM, Math.round(zoom)));
7976
+ }
7977
+ function documentZoomForFit(fit, metrics) {
7978
+ const availableWidth = Math.max(1, metrics.viewportWidth - metrics.viewportPadding.left - metrics.viewportPadding.right);
7979
+ const widthZoom = availableWidth / Math.max(1, metrics.pageWidth) * 100;
7980
+ if ('width' === fit) return clampDocumentZoom(widthZoom);
7981
+ const availableHeight = Math.max(1, metrics.viewportHeight - metrics.viewportPadding.top - metrics.viewportPadding.bottom);
7982
+ const heightZoom = availableHeight / Math.max(1, metrics.pageHeight) * 100;
7983
+ return clampDocumentZoom(Math.min(widthZoom, heightZoom));
7984
+ }
7985
+ function DocumentStatusBar({ bibliographyCount, citationCount, currentPage, pageCount, saveStatus, sectionCount, sectionIndex, spellcheckEnabled, viewMode, wordCount, zoom, onSpellcheckChange, onOpenWordCount, onViewModeChange, onZoomChange }) {
7986
+ const wordCountCommand = getDocumentCommandDefinition('wordCount');
7987
+ return /*#__PURE__*/ jsxs(WorkOfficeStatusBar, {
7988
+ ariaLabel: "文档状态栏",
7989
+ controlsLabel: "文档视图与缩放",
7990
+ className: "work-document-footer",
7991
+ controls: /*#__PURE__*/ jsxs(Fragment, {
7992
+ children: [
7993
+ /*#__PURE__*/ jsx("button", {
7994
+ type: "button",
7995
+ "data-document-status-control": "view-mode",
7996
+ "aria-label": "页面视图",
7997
+ title: "页面视图",
7998
+ "aria-pressed": 'page' === viewMode,
7999
+ onClick: ()=>onViewModeChange('page'),
8000
+ children: /*#__PURE__*/ jsx(FileText, {
8001
+ size: 13
8002
+ })
8003
+ }),
8004
+ /*#__PURE__*/ jsx("button", {
8005
+ type: "button",
8006
+ "data-document-status-control": "view-mode",
8007
+ "aria-label": "网页视图",
8008
+ title: "网页视图",
8009
+ "aria-pressed": 'web' === viewMode,
8010
+ onClick: ()=>onViewModeChange('web'),
8011
+ children: /*#__PURE__*/ jsx(Globe2, {
8012
+ size: 13
8013
+ })
8014
+ }),
8015
+ /*#__PURE__*/ jsx("span", {
8016
+ className: "work-office-status-divider",
8017
+ "data-document-status-control": "view-mode"
8018
+ }),
8019
+ /*#__PURE__*/ jsx(WorkOfficeZoomControls, {
8020
+ zoom: zoom,
8021
+ minimum: 50,
8022
+ maximum: 200,
8023
+ step: 5,
8024
+ decreaseLabel: "缩小文档",
8025
+ increaseLabel: "放大文档",
8026
+ outputLabel: "文档缩放比例",
8027
+ sliderLabel: "文档缩放",
8028
+ onChange: (value)=>onZoomChange(clampDocumentZoom(value))
8029
+ })
8030
+ ]
8031
+ }),
7850
8032
  children: [
7851
- /*#__PURE__*/ jsx(BulletListControl, {
7852
- editor: editor,
7853
- activeStyle: bulletStyle
8033
+ /*#__PURE__*/ jsxs("output", {
8034
+ "aria-label": "页码状态",
8035
+ "data-document-status-item": "page",
8036
+ children: [
8037
+ "第 ",
8038
+ currentPage,
8039
+ " 页,共 ",
8040
+ pageCount,
8041
+ " 页"
8042
+ ]
7854
8043
  }),
7855
- /*#__PURE__*/ jsx(OrderedListControl, {
7856
- editor: editor,
7857
- activeState: orderedState
8044
+ /*#__PURE__*/ jsxs("output", {
8045
+ "aria-label": "分节状态",
8046
+ "data-document-status-item": "section",
8047
+ children: [
8048
+ "第 ",
8049
+ sectionIndex + 1,
8050
+ " 节,共 ",
8051
+ sectionCount,
8052
+ " 节"
8053
+ ]
8054
+ }),
8055
+ /*#__PURE__*/ jsxs("button", {
8056
+ type: "button",
8057
+ className: "work-office-status-text-button",
8058
+ "data-document-status-item": "word-count",
8059
+ "aria-label": `字数统计:${wordCount}`,
8060
+ "aria-keyshortcuts": wordCountCommand.shortcut?.aria,
8061
+ title: `${wordCountCommand.label}(${wordCountCommand.shortcut?.label})`,
8062
+ onClick: onOpenWordCount,
8063
+ children: [
8064
+ "字数:",
8065
+ wordCount
8066
+ ]
8067
+ }),
8068
+ /*#__PURE__*/ jsx("button", {
8069
+ type: "button",
8070
+ "data-document-status-item": "spellcheck",
8071
+ "aria-label": `校对:${spellcheckEnabled ? '已开启' : '已关闭'}`,
8072
+ title: `校对:${spellcheckEnabled ? '已开启' : '已关闭'}`,
8073
+ "aria-pressed": spellcheckEnabled,
8074
+ onClick: ()=>onSpellcheckChange(!spellcheckEnabled),
8075
+ children: /*#__PURE__*/ jsx(CheckCheck, {
8076
+ size: 12
8077
+ })
8078
+ }),
8079
+ /*#__PURE__*/ jsxs("output", {
8080
+ "aria-label": "引用状态",
8081
+ children: [
8082
+ bibliographyCount,
8083
+ " 条文献 \xb7 ",
8084
+ citationCount,
8085
+ " 处引文"
8086
+ ]
8087
+ }),
8088
+ /*#__PURE__*/ jsxs("output", {
8089
+ "aria-label": "文档保存状态",
8090
+ className: "work-office-save-status",
8091
+ children: [
8092
+ /*#__PURE__*/ jsx(Cloud, {
8093
+ size: 12
8094
+ }),
8095
+ saveStatus
8096
+ ]
7858
8097
  })
7859
8098
  ]
7860
8099
  });
7861
8100
  }
7862
- function BulletListControl({ editor, activeStyle }) {
7863
- const [open, setOpen] = useState(false);
7864
- const optionRefs = useRef([]);
7865
- const activeIndex = Math.max(0, bulletStyles.findIndex((style)=>style.value === activeStyle));
7866
- const [focusIndex, setFocusIndex] = useState(activeIndex);
7867
- const focusActiveOption = ()=>{
7868
- setFocusIndex(activeIndex);
7869
- requestAnimationFrame(()=>optionRefs.current[activeIndex]?.focus({
7870
- preventScroll: true
7871
- }));
7872
- };
7873
- return /*#__PURE__*/ jsxs("div", {
7874
- className: "work-document-list-split",
7875
- "data-active": Boolean(activeStyle),
7876
- children: [
7877
- /*#__PURE__*/ jsx(WorkOfficeRibbonButton, {
7878
- label: "项目符号",
7879
- title: "项目符号",
7880
- displayLabel: false,
7881
- active: Boolean(activeStyle),
7882
- className: "work-document-list-primary",
7883
- onClick: ()=>{
7884
- if (activeStyle) editor.chain().focus().clearDocumentList().run();
7885
- else editor.chain().focus().applyDocumentBulletList('disc').run();
7886
- },
7887
- children: /*#__PURE__*/ jsx(List, {
7888
- size: 16
7889
- })
7890
- }),
7891
- /*#__PURE__*/ jsx(Popover, {
7892
- label: "项目符号库",
7893
- panelLabel: "项目符号库",
7894
- panelRole: "dialog",
8101
+ function DocumentFormatTools({ editor }) {
8102
+ const hasFormat = useSyncExternalStore(subscribeDocumentFormatClipboard, hasDocumentFormatClipboard, hasDocumentFormatClipboard);
8103
+ const [formatPainterActive, setFormatPainterActive] = useState(false);
8104
+ const painterSourceRef = useRef(null);
8105
+ const copyFormatCommand = getDocumentCommandDefinition('copyFormat');
8106
+ const pasteFormatCommand = getDocumentCommandDefinition('pasteFormat');
8107
+ useEffect(()=>{
8108
+ if (!formatPainterActive || editor.isDestroyed) return;
8109
+ const editorDom = editor.view.dom;
8110
+ editorDom.dataset.documentFormatPainter = 'true';
8111
+ const applyFormatPainter = ()=>{
8112
+ if (editor.isDestroyed) return;
8113
+ const selection = editor.state.selection;
8114
+ const source = painterSourceRef.current;
8115
+ if (source && source.from === selection.from && source.to === selection.to) return;
8116
+ if (pasteDocumentFormatting(editor)) setFormatPainterActive(false);
8117
+ };
8118
+ const onPointerUp = (event)=>{
8119
+ if (0 === event.button) applyFormatPainter();
8120
+ };
8121
+ const onKeyUp = (event)=>{
8122
+ if (event.shiftKey || event.key.startsWith('Arrow') || 'Home' === event.key || 'End' === event.key) applyFormatPainter();
8123
+ };
8124
+ const onKeyDown = (event)=>{
8125
+ if ('Escape' !== event.key) return;
8126
+ event.preventDefault();
8127
+ setFormatPainterActive(false);
8128
+ };
8129
+ editorDom.addEventListener('pointerup', onPointerUp);
8130
+ editorDom.addEventListener('keyup', onKeyUp);
8131
+ editorDom.addEventListener('keydown', onKeyDown, true);
8132
+ return ()=>{
8133
+ delete editorDom.dataset.documentFormatPainter;
8134
+ editorDom.removeEventListener('pointerup', onPointerUp);
8135
+ editorDom.removeEventListener('keyup', onKeyUp);
8136
+ editorDom.removeEventListener('keydown', onKeyDown, true);
8137
+ };
8138
+ }, [
8139
+ editor,
8140
+ formatPainterActive
8141
+ ]);
8142
+ const copyFormat = ()=>copyDocumentFormatting(editor);
8143
+ const toggleFormatPainter = ()=>{
8144
+ if (formatPainterActive) return void setFormatPainterActive(false);
8145
+ if (!copyDocumentFormatting(editor)) return;
8146
+ painterSourceRef.current = {
8147
+ from: editor.state.selection.from,
8148
+ to: editor.state.selection.to
8149
+ };
8150
+ setFormatPainterActive(true);
8151
+ };
8152
+ return /*#__PURE__*/ jsxs(WorkOfficeRibbonGroup, {
8153
+ label: "剪贴板",
8154
+ priority: "normal",
8155
+ children: [
8156
+ /*#__PURE__*/ jsx(WorkOfficeRibbonButton, {
8157
+ label: "复制格式",
8158
+ title: `复制格式(${copyFormatCommand.shortcut?.label})`,
8159
+ "aria-keyshortcuts": copyFormatCommand.shortcut?.aria,
8160
+ onClick: copyFormat,
8161
+ children: /*#__PURE__*/ jsx(ClipboardCopy, {
8162
+ size: 17
8163
+ })
8164
+ }),
8165
+ /*#__PURE__*/ jsx(WorkOfficeRibbonButton, {
8166
+ label: "粘贴格式",
8167
+ title: `粘贴格式(${pasteFormatCommand.shortcut?.label})`,
8168
+ "aria-keyshortcuts": pasteFormatCommand.shortcut?.aria,
8169
+ disabled: !hasFormat,
8170
+ onClick: ()=>pasteDocumentFormatting(editor),
8171
+ children: /*#__PURE__*/ jsx(ClipboardPaste, {
8172
+ size: 17
8173
+ })
8174
+ }),
8175
+ /*#__PURE__*/ jsx(WorkOfficeRibbonButton, {
8176
+ label: "格式刷",
8177
+ title: "格式刷(选择源格式后应用到下一处选择)",
8178
+ active: formatPainterActive,
8179
+ onClick: toggleFormatPainter,
8180
+ children: /*#__PURE__*/ jsx(Paintbrush, {
8181
+ size: 17
8182
+ })
8183
+ })
8184
+ ]
8185
+ });
8186
+ }
8187
+ const bulletStyles = [
8188
+ {
8189
+ value: 'disc',
8190
+ label: '实心圆点',
8191
+ marker: '●'
8192
+ },
8193
+ {
8194
+ value: 'circle',
8195
+ label: '空心圆点',
8196
+ marker: '○'
8197
+ },
8198
+ {
8199
+ value: 'square',
8200
+ label: '方块',
8201
+ marker: '■'
8202
+ }
8203
+ ];
8204
+ const orderedStyles = [
8205
+ {
8206
+ value: 'decimal',
8207
+ label: '数字',
8208
+ markers: [
8209
+ '1.',
8210
+ '2.',
8211
+ '3.'
8212
+ ]
8213
+ },
8214
+ {
8215
+ value: 'lower-alpha',
8216
+ label: '小写字母',
8217
+ markers: [
8218
+ 'a.',
8219
+ 'b.',
8220
+ 'c.'
8221
+ ]
8222
+ },
8223
+ {
8224
+ value: 'upper-alpha',
8225
+ label: '大写字母',
8226
+ markers: [
8227
+ 'A.',
8228
+ 'B.',
8229
+ 'C.'
8230
+ ]
8231
+ },
8232
+ {
8233
+ value: 'lower-roman',
8234
+ label: '小写罗马数字',
8235
+ markers: [
8236
+ 'i.',
8237
+ 'ii.',
8238
+ 'iii.'
8239
+ ]
8240
+ },
8241
+ {
8242
+ value: 'upper-roman',
8243
+ label: '大写罗马数字',
8244
+ markers: [
8245
+ 'I.',
8246
+ 'II.',
8247
+ 'III.'
8248
+ ]
8249
+ }
8250
+ ];
8251
+ function DocumentListGallery({ editor }) {
8252
+ const subscribe = useCallback((notify)=>{
8253
+ editor.on('transaction', notify);
8254
+ return ()=>editor.off('transaction', notify);
8255
+ }, [
8256
+ editor
8257
+ ]);
8258
+ useSyncExternalStore(subscribe, ()=>documentListSnapshot(editor), ()=>documentListSnapshot(editor));
8259
+ const bulletStyle = documentBulletListStyle(editor);
8260
+ const orderedState = documentOrderedListState(editor);
8261
+ return /*#__PURE__*/ jsxs("div", {
8262
+ className: "work-document-list-tools",
8263
+ children: [
8264
+ /*#__PURE__*/ jsx(BulletListControl, {
8265
+ editor: editor,
8266
+ activeStyle: bulletStyle
8267
+ }),
8268
+ /*#__PURE__*/ jsx(OrderedListControl, {
8269
+ editor: editor,
8270
+ activeState: orderedState
8271
+ })
8272
+ ]
8273
+ });
8274
+ }
8275
+ function BulletListControl({ editor, activeStyle }) {
8276
+ const [open, setOpen] = useState(false);
8277
+ const optionRefs = useRef([]);
8278
+ const activeIndex = Math.max(0, bulletStyles.findIndex((style)=>style.value === activeStyle));
8279
+ const [focusIndex, setFocusIndex] = useState(activeIndex);
8280
+ const focusActiveOption = ()=>{
8281
+ setFocusIndex(activeIndex);
8282
+ requestAnimationFrame(()=>optionRefs.current[activeIndex]?.focus({
8283
+ preventScroll: true
8284
+ }));
8285
+ };
8286
+ return /*#__PURE__*/ jsxs("div", {
8287
+ className: "work-document-list-split",
8288
+ "data-active": Boolean(activeStyle),
8289
+ children: [
8290
+ /*#__PURE__*/ jsx(WorkOfficeRibbonButton, {
8291
+ label: "项目符号",
8292
+ title: "项目符号",
8293
+ displayLabel: false,
8294
+ active: Boolean(activeStyle),
8295
+ className: "work-document-list-primary",
8296
+ onClick: ()=>{
8297
+ if (activeStyle) editor.chain().focus().clearDocumentList().run();
8298
+ else editor.chain().focus().applyDocumentBulletList('disc').run();
8299
+ },
8300
+ children: /*#__PURE__*/ jsx(List, {
8301
+ size: 16
8302
+ })
8303
+ }),
8304
+ /*#__PURE__*/ jsx(Popover, {
8305
+ label: "项目符号库",
8306
+ panelLabel: "项目符号库",
8307
+ panelRole: "dialog",
7895
8308
  portal: true,
7896
8309
  open: open,
7897
8310
  onOpenChange: (nextOpen)=>{
@@ -8146,516 +8559,1482 @@ function OrderedListControl({ editor, activeState }) {
8146
8559
  ]
8147
8560
  });
8148
8561
  }
8149
- function runDocumentListMenuCommand(editor, close, command) {
8150
- const handled = command();
8151
- if (!handled) return false;
8152
- close();
8153
- queueMicrotask(()=>{
8154
- if (!editor.isDestroyed) editor.commands.focus(void 0, {
8155
- scrollIntoView: false
8156
- });
8562
+ function runDocumentListMenuCommand(editor, close, command) {
8563
+ const handled = command();
8564
+ if (!handled) return false;
8565
+ close();
8566
+ queueMicrotask(()=>{
8567
+ if (!editor.isDestroyed) editor.commands.focus(void 0, {
8568
+ scrollIntoView: false
8569
+ });
8570
+ });
8571
+ return true;
8572
+ }
8573
+ function handleGalleryKeyDown(event, index, count, columns, refs, setFocusIndex, select) {
8574
+ if ('Enter' === event.key || ' ' === event.key) {
8575
+ event.preventDefault();
8576
+ select();
8577
+ return;
8578
+ }
8579
+ let next = index;
8580
+ if ('ArrowRight' === event.key) next = (index + 1) % count;
8581
+ else if ('ArrowLeft' === event.key) next = (index - 1 + count) % count;
8582
+ else if ('ArrowDown' === event.key) next = Math.min(count - 1, index + columns);
8583
+ else if ('ArrowUp' === event.key) next = Math.max(0, index - columns);
8584
+ else if ('Home' === event.key) next = 0;
8585
+ else {
8586
+ if ('End' !== event.key) return;
8587
+ next = count - 1;
8588
+ }
8589
+ event.preventDefault();
8590
+ setFocusIndex(next);
8591
+ refs.current[next]?.focus({
8592
+ preventScroll: true
8593
+ });
8594
+ }
8595
+ function validStartValue(value) {
8596
+ const number = Number(value);
8597
+ return Number.isSafeInteger(number) && number >= 1 && number <= MAX_DOCUMENT_NUMBERING_START ? number : null;
8598
+ }
8599
+ function documentListSnapshot(editor) {
8600
+ const bullet = documentBulletListStyle(editor);
8601
+ const ordered = documentOrderedListState(editor);
8602
+ return `${bullet ?? ''}:${ordered?.style ?? ''}:${ordered?.start ?? ''}`;
8603
+ }
8604
+ const documentParagraphStyles = [
8605
+ {
8606
+ value: 'paragraph',
8607
+ label: '正文',
8608
+ level: null,
8609
+ shortcut: void 0
8610
+ },
8611
+ {
8612
+ value: 'h1',
8613
+ label: '标题 1',
8614
+ level: 1,
8615
+ shortcut: getDocumentCommandDefinition('heading1').shortcut
8616
+ },
8617
+ {
8618
+ value: 'h2',
8619
+ label: '标题 2',
8620
+ level: 2,
8621
+ shortcut: getDocumentCommandDefinition('heading2').shortcut
8622
+ },
8623
+ {
8624
+ value: 'h3',
8625
+ label: '标题 3',
8626
+ level: 3,
8627
+ shortcut: getDocumentCommandDefinition('heading3').shortcut
8628
+ }
8629
+ ];
8630
+ function DocumentStyleGallery({ editor }) {
8631
+ const groupName = useId();
8632
+ const inputsRef = useRef([]);
8633
+ const activeStyle = documentParagraphStyleValue(editor);
8634
+ const moveSelection = (event, nextIndex)=>{
8635
+ event.preventDefault();
8636
+ const normalizedIndex = (nextIndex + documentParagraphStyles.length) % documentParagraphStyles.length;
8637
+ const style = documentParagraphStyles[normalizedIndex];
8638
+ if (!style) return;
8639
+ applyDocumentParagraphStyle(editor, style);
8640
+ inputsRef.current[normalizedIndex]?.focus({
8641
+ preventScroll: true
8642
+ });
8643
+ };
8644
+ return /*#__PURE__*/ jsxs("div", {
8645
+ className: "work-document-style-tools",
8646
+ children: [
8647
+ /*#__PURE__*/ jsx("div", {
8648
+ className: "work-document-style-gallery",
8649
+ role: "radiogroup",
8650
+ "aria-label": "段落样式库",
8651
+ children: documentParagraphStyles.map((style, index)=>{
8652
+ const active = style.value === activeStyle;
8653
+ return /*#__PURE__*/ jsxs("label", {
8654
+ className: active ? 'active' : '',
8655
+ "data-document-style": style.value,
8656
+ title: style.shortcut ? `${style.label}(${style.shortcut.label})` : style.label,
8657
+ children: [
8658
+ /*#__PURE__*/ jsx("input", {
8659
+ ref: (input)=>{
8660
+ inputsRef.current[index] = input;
8661
+ },
8662
+ type: "radio",
8663
+ name: groupName,
8664
+ "aria-label": `应用样式:${style.label}`,
8665
+ "aria-keyshortcuts": style.shortcut?.aria,
8666
+ checked: active,
8667
+ tabIndex: active ? 0 : -1,
8668
+ onChange: ()=>applyDocumentParagraphStyle(editor, style),
8669
+ onKeyDown: (event)=>{
8670
+ if ('ArrowRight' === event.key || 'ArrowDown' === event.key) moveSelection(event, index + 1);
8671
+ else if ('ArrowLeft' === event.key || 'ArrowUp' === event.key) moveSelection(event, index - 1);
8672
+ else if ('Home' === event.key) moveSelection(event, 0);
8673
+ else if ('End' === event.key) moveSelection(event, documentParagraphStyles.length - 1);
8674
+ }
8675
+ }),
8676
+ /*#__PURE__*/ jsx("span", {
8677
+ "aria-hidden": "true",
8678
+ children: style.label
8679
+ })
8680
+ ]
8681
+ }, style.value);
8682
+ })
8683
+ }),
8684
+ /*#__PURE__*/ jsx(OfficeSelect, {
8685
+ ariaLabel: "段落样式",
8686
+ className: "work-document-style-select",
8687
+ value: activeStyle,
8688
+ options: documentParagraphStyles.map((style)=>({
8689
+ ...style,
8690
+ meta: style.shortcut?.label
8691
+ })),
8692
+ onValueChange: (value)=>{
8693
+ const style = documentParagraphStyles.find((candidate)=>candidate.value === value);
8694
+ if (style) applyDocumentParagraphStyle(editor, style);
8695
+ }
8696
+ })
8697
+ ]
8698
+ });
8699
+ }
8700
+ function documentParagraphStyleValue(editor) {
8701
+ if (editor.isActive('heading', {
8702
+ level: 1
8703
+ })) return 'h1';
8704
+ if (editor.isActive('heading', {
8705
+ level: 2
8706
+ })) return 'h2';
8707
+ if (editor.isActive('heading', {
8708
+ level: 3
8709
+ })) return 'h3';
8710
+ return 'paragraph';
8711
+ }
8712
+ function applyDocumentParagraphStyle(editor, style) {
8713
+ if (null === style.level) return editor.chain().focus().setParagraph().run();
8714
+ return editor.chain().focus().setHeading({
8715
+ level: style.level
8716
+ }).run();
8717
+ }
8718
+ const textCaseOptions = [
8719
+ {
8720
+ value: 'none',
8721
+ label: '常规',
8722
+ icon: Type
8723
+ },
8724
+ {
8725
+ value: 'all-caps',
8726
+ label: '全部大写',
8727
+ icon: CaseUpper,
8728
+ command: 'allCaps'
8729
+ },
8730
+ {
8731
+ value: 'small-caps',
8732
+ label: '小型大写',
8733
+ icon: ALargeSmall,
8734
+ command: 'smallCaps'
8735
+ }
8736
+ ];
8737
+ function DocumentTextCaseRibbon({ editor }) {
8738
+ const value = normalizeDocumentTextCase(editor.getAttributes('textStyle').textCase) ?? 'none';
8739
+ const current = textCaseOptions.find((option)=>option.value === value) ?? textCaseOptions[0];
8740
+ return /*#__PURE__*/ jsx(Popover, {
8741
+ label: "大小写效果",
8742
+ panelLabel: "大小写效果",
8743
+ panelRole: "menu",
8744
+ portal: true,
8745
+ placement: "bottom-end",
8746
+ className: "work-document-text-case-root",
8747
+ panelClassName: "work-office-context-menu work-document-text-case-menu",
8748
+ focusFirstOnOpen: true,
8749
+ onPanelKeyDown: moveOfficeMenuFocus,
8750
+ trigger: (triggerProps, { open })=>/*#__PURE__*/ jsx("button", {
8751
+ ...triggerProps,
8752
+ type: "button",
8753
+ className: 'none' !== value || open ? 'active' : '',
8754
+ "aria-pressed": 'none' !== value,
8755
+ title: `大小写效果(${current.label})`,
8756
+ children: /*#__PURE__*/ jsx(ALargeSmall, {
8757
+ size: 16,
8758
+ "aria-hidden": "true"
8759
+ })
8760
+ }),
8761
+ children: (close)=>textCaseOptions.map((option)=>{
8762
+ const Icon = option.icon;
8763
+ const shortcut = 'command' in option ? getDocumentCommandDefinition(option.command).shortcut : void 0;
8764
+ return /*#__PURE__*/ jsxs("button", {
8765
+ type: "button",
8766
+ role: "menuitemradio",
8767
+ tabIndex: -1,
8768
+ "aria-label": option.label,
8769
+ "aria-checked": value === option.value,
8770
+ "aria-keyshortcuts": shortcut?.aria,
8771
+ onClick: ()=>{
8772
+ close();
8773
+ editor.commands.setDocumentTextCase(option.value);
8774
+ },
8775
+ children: [
8776
+ /*#__PURE__*/ jsx(Icon, {
8777
+ "aria-hidden": "true"
8778
+ }),
8779
+ /*#__PURE__*/ jsx("span", {
8780
+ children: option.label
8781
+ }),
8782
+ shortcut && /*#__PURE__*/ jsx("kbd", {
8783
+ children: shortcut.label
8784
+ })
8785
+ ]
8786
+ }, option.value);
8787
+ })
8788
+ });
8789
+ }
8790
+ const documentLineHeightOptions = [
8791
+ {
8792
+ value: 'default',
8793
+ label: '默认行距'
8794
+ },
8795
+ {
8796
+ value: '1',
8797
+ label: '单倍',
8798
+ meta: getDocumentCommandDefinition('lineSpacingSingle').shortcut?.label
8799
+ },
8800
+ {
8801
+ value: '1.15',
8802
+ label: '1.15 倍'
8803
+ },
8804
+ {
8805
+ value: '1.5',
8806
+ label: '1.5 倍',
8807
+ meta: getDocumentCommandDefinition('lineSpacingOneAndHalf').shortcut?.label
8808
+ },
8809
+ {
8810
+ value: '2',
8811
+ label: '2 倍',
8812
+ meta: getDocumentCommandDefinition('lineSpacingDouble').shortcut?.label
8813
+ }
8814
+ ];
8815
+ function DocumentHomeRibbon({ editor, findReplaceMode, layoutFonts = [], onFindText, onOpenFontDialog }) {
8816
+ const subscribe = useCallback((notify)=>{
8817
+ if (editor.isDestroyed) return ()=>void 0;
8818
+ editor.on('transaction', notify);
8819
+ return ()=>editor.off('transaction', notify);
8820
+ }, [
8821
+ editor
8822
+ ]);
8823
+ useSyncExternalStore(subscribe, ()=>editor.state, ()=>editor.state);
8824
+ if (editor.isDestroyed) return null;
8825
+ const fontFamilyValue = documentFontFamilyValue(editor, layoutFonts);
8826
+ const fontSizeValue = documentFontSizeValue(editor);
8827
+ const lineHeightValue = documentLineHeightValue(editor);
8828
+ return /*#__PURE__*/ jsxs(Fragment, {
8829
+ children: [
8830
+ /*#__PURE__*/ jsx(DocumentFormatTools, {
8831
+ editor: editor
8832
+ }),
8833
+ /*#__PURE__*/ jsx(RibbonGroup, {
8834
+ label: "字体",
8835
+ priority: "high",
8836
+ dialogLauncher: onOpenFontDialog ? {
8837
+ label: '字体高级设置',
8838
+ ...commandShortcut('fontDialog'),
8839
+ onClick: onOpenFontDialog
8840
+ } : void 0,
8841
+ children: /*#__PURE__*/ jsxs("div", {
8842
+ className: "work-document-font-tools",
8843
+ children: [
8844
+ /*#__PURE__*/ jsxs("div", {
8845
+ className: "work-document-font-selects",
8846
+ children: [
8847
+ /*#__PURE__*/ jsx(OfficeSelect, {
8848
+ ariaLabel: "字体",
8849
+ className: "work-document-font-family-select",
8850
+ value: fontFamilyValue,
8851
+ options: documentFontFamilyOptionsForValue(fontFamilyValue, layoutFonts),
8852
+ onValueChange: (value)=>{
8853
+ if ('default' === value) editor.chain().focus().unsetFontFamily().run();
8854
+ else editor.chain().focus().setFontFamily(value).run();
8855
+ }
8856
+ }),
8857
+ /*#__PURE__*/ jsx(OfficeSelect, {
8858
+ ariaLabel: "字号",
8859
+ className: "work-document-font-size-select",
8860
+ value: fontSizeValue,
8861
+ options: documentFontSizeOptionsForValue(fontSizeValue),
8862
+ onValueChange: (value)=>{
8863
+ if ('default' === value) editor.chain().focus().unsetFontSize().run();
8864
+ else editor.chain().focus().setFontSize(value).run();
8865
+ }
8866
+ }),
8867
+ /*#__PURE__*/ jsx(ToolbarButton, {
8868
+ label: "增大字号",
8869
+ ...commandShortcut('growFont'),
8870
+ disabled: !canChangeDocumentFontSize(editor, 1),
8871
+ onClick: ()=>changeDocumentFontSize(editor, 1),
8872
+ children: /*#__PURE__*/ jsx(AArrowUp, {
8873
+ size: 16
8874
+ })
8875
+ }),
8876
+ /*#__PURE__*/ jsx(ToolbarButton, {
8877
+ label: "减小字号",
8878
+ ...commandShortcut('shrinkFont'),
8879
+ disabled: !canChangeDocumentFontSize(editor, -1),
8880
+ onClick: ()=>changeDocumentFontSize(editor, -1),
8881
+ children: /*#__PURE__*/ jsx(AArrowDown, {
8882
+ size: 16
8883
+ })
8884
+ })
8885
+ ]
8886
+ }),
8887
+ /*#__PURE__*/ jsxs("div", {
8888
+ className: "work-document-font-actions",
8889
+ children: [
8890
+ /*#__PURE__*/ jsx(ToolbarButton, {
8891
+ label: "加粗",
8892
+ ...commandShortcut('bold'),
8893
+ active: editor.isActive('bold'),
8894
+ onClick: ()=>editor.chain().focus().toggleBold().run(),
8895
+ children: /*#__PURE__*/ jsx(Bold, {
8896
+ size: 16
8897
+ })
8898
+ }),
8899
+ /*#__PURE__*/ jsx(ToolbarButton, {
8900
+ label: "斜体",
8901
+ ...commandShortcut('italic'),
8902
+ active: editor.isActive('italic'),
8903
+ onClick: ()=>editor.chain().focus().toggleItalic().run(),
8904
+ children: /*#__PURE__*/ jsx(Italic, {
8905
+ size: 16
8906
+ })
8907
+ }),
8908
+ /*#__PURE__*/ jsx(DocumentUnderlineRibbon, {
8909
+ editor: editor
8910
+ }),
8911
+ /*#__PURE__*/ jsx(DocumentStrikeRibbon, {
8912
+ editor: editor
8913
+ }),
8914
+ /*#__PURE__*/ jsx(DocumentTextCaseRibbon, {
8915
+ editor: editor
8916
+ }),
8917
+ /*#__PURE__*/ jsx(ToolbarButton, {
8918
+ label: "下标",
8919
+ ...commandShortcut("subscript"),
8920
+ active: editor.isActive("subscript"),
8921
+ onClick: ()=>editor.commands.toggleDocumentSubscript(),
8922
+ children: /*#__PURE__*/ jsx(Subscript, {
8923
+ size: 16
8924
+ })
8925
+ }),
8926
+ /*#__PURE__*/ jsx(ToolbarButton, {
8927
+ label: "上标",
8928
+ ...commandShortcut("superscript"),
8929
+ active: editor.isActive("superscript"),
8930
+ onClick: ()=>editor.commands.toggleDocumentSuperscript(),
8931
+ children: /*#__PURE__*/ jsx(Superscript, {
8932
+ size: 16
8933
+ })
8934
+ }),
8935
+ /*#__PURE__*/ jsx(OfficeColorPicker, {
8936
+ compact: true,
8937
+ className: "work-color-tool",
8938
+ value: editor.getAttributes('textStyle').color ?? '#172033',
8939
+ ariaLabel: "文字颜色",
8940
+ onValueChange: (color)=>editor.chain().focus().setColor(color).run()
8941
+ }),
8942
+ /*#__PURE__*/ jsx(ToolbarButton, {
8943
+ label: "突出显示",
8944
+ active: editor.isActive('highlight'),
8945
+ onClick: ()=>editor.chain().focus().toggleHighlight({
8946
+ color: '#fff0a6'
8947
+ }).run(),
8948
+ children: /*#__PURE__*/ jsx(Highlighter, {
8949
+ size: 16
8950
+ })
8951
+ }),
8952
+ /*#__PURE__*/ jsx(ToolbarButton, {
8953
+ label: "清除格式",
8954
+ onClick: ()=>editor.commands.clearDocumentFormatting(),
8955
+ children: /*#__PURE__*/ jsx(Eraser, {
8956
+ size: 16
8957
+ })
8958
+ })
8959
+ ]
8960
+ })
8961
+ ]
8962
+ })
8963
+ }),
8964
+ /*#__PURE__*/ jsx(RibbonGroup, {
8965
+ label: "段落",
8966
+ priority: "high",
8967
+ children: /*#__PURE__*/ jsxs("div", {
8968
+ className: "work-document-paragraph-tools",
8969
+ children: [
8970
+ /*#__PURE__*/ jsxs("div", {
8971
+ className: "work-document-paragraph-actions",
8972
+ children: [
8973
+ /*#__PURE__*/ jsx(DocumentListGallery, {
8974
+ editor: editor
8975
+ }),
8976
+ /*#__PURE__*/ jsx(ToolbarButton, {
8977
+ label: "减少缩进",
8978
+ disabled: !canChangeDocumentIndent(editor, -1),
8979
+ onClick: ()=>editor.commands.changeDocumentIndent(-1),
8980
+ children: /*#__PURE__*/ jsx(IndentDecrease, {
8981
+ size: 16
8982
+ })
8983
+ }),
8984
+ /*#__PURE__*/ jsx(ToolbarButton, {
8985
+ label: "增加缩进",
8986
+ disabled: !canChangeDocumentIndent(editor, 1),
8987
+ onClick: ()=>editor.commands.changeDocumentIndent(1),
8988
+ children: /*#__PURE__*/ jsx(IndentIncrease, {
8989
+ size: 16
8990
+ })
8991
+ }),
8992
+ /*#__PURE__*/ jsx(OfficeSelect, {
8993
+ ariaLabel: "行距",
8994
+ className: "work-document-line-height-select",
8995
+ value: lineHeightValue,
8996
+ options: documentLineHeightOptionsForValue(lineHeightValue),
8997
+ onValueChange: (value)=>editor.commands.setDocumentLineHeight('default' === value ? null : value)
8998
+ })
8999
+ ]
9000
+ }),
9001
+ /*#__PURE__*/ jsxs("div", {
9002
+ className: "work-document-alignment-actions",
9003
+ children: [
9004
+ /*#__PURE__*/ jsx(ToolbarButton, {
9005
+ label: "左对齐",
9006
+ ...commandShortcut('alignLeft'),
9007
+ active: editor.isActive({
9008
+ textAlign: 'left'
9009
+ }),
9010
+ onClick: ()=>editor.chain().focus().setTextAlign('left').run(),
9011
+ children: /*#__PURE__*/ jsx(AlignLeft, {
9012
+ size: 16
9013
+ })
9014
+ }),
9015
+ /*#__PURE__*/ jsx(ToolbarButton, {
9016
+ label: "居中",
9017
+ ...commandShortcut('alignCenter'),
9018
+ active: editor.isActive({
9019
+ textAlign: 'center'
9020
+ }),
9021
+ onClick: ()=>editor.chain().focus().setTextAlign('center').run(),
9022
+ children: /*#__PURE__*/ jsx(AlignCenter, {
9023
+ size: 16
9024
+ })
9025
+ }),
9026
+ /*#__PURE__*/ jsx(ToolbarButton, {
9027
+ label: "右对齐",
9028
+ ...commandShortcut('alignRight'),
9029
+ active: editor.isActive({
9030
+ textAlign: 'right'
9031
+ }),
9032
+ onClick: ()=>editor.chain().focus().setTextAlign('right').run(),
9033
+ children: /*#__PURE__*/ jsx(AlignRight, {
9034
+ size: 16
9035
+ })
9036
+ }),
9037
+ /*#__PURE__*/ jsx(ToolbarButton, {
9038
+ label: "两端对齐",
9039
+ ...commandShortcut('alignJustify'),
9040
+ active: editor.isActive({
9041
+ textAlign: 'justify'
9042
+ }),
9043
+ onClick: ()=>editor.chain().focus().setTextAlign('justify').run(),
9044
+ children: /*#__PURE__*/ jsx(AlignJustify, {
9045
+ size: 16
9046
+ })
9047
+ }),
9048
+ /*#__PURE__*/ jsx(ToolbarButton, {
9049
+ label: "从左向右",
9050
+ active: 'ltr' === documentParagraphDirection(editor),
9051
+ onClick: ()=>editor.commands.setDocumentParagraphDirection('ltr'),
9052
+ children: /*#__PURE__*/ jsx(PilcrowRight, {
9053
+ size: 16
9054
+ })
9055
+ }),
9056
+ /*#__PURE__*/ jsx(ToolbarButton, {
9057
+ label: "从右向左",
9058
+ active: 'rtl' === documentParagraphDirection(editor),
9059
+ onClick: ()=>editor.commands.setDocumentParagraphDirection('rtl'),
9060
+ children: /*#__PURE__*/ jsx(PilcrowLeft, {
9061
+ size: 16
9062
+ })
9063
+ })
9064
+ ]
9065
+ })
9066
+ ]
9067
+ })
9068
+ }),
9069
+ /*#__PURE__*/ jsx(RibbonGroup, {
9070
+ label: "样式",
9071
+ priority: "low",
9072
+ children: /*#__PURE__*/ jsx(DocumentStyleGallery, {
9073
+ editor: editor
9074
+ })
9075
+ }),
9076
+ /*#__PURE__*/ jsxs(RibbonGroup, {
9077
+ label: "编辑",
9078
+ priority: "low",
9079
+ children: [
9080
+ /*#__PURE__*/ jsx(ToolbarButton, {
9081
+ label: "查找",
9082
+ ...commandShortcut('find'),
9083
+ active: 'find' === findReplaceMode,
9084
+ onClick: ()=>onFindText(false),
9085
+ children: /*#__PURE__*/ jsx(Search, {
9086
+ size: 16
9087
+ })
9088
+ }),
9089
+ /*#__PURE__*/ jsx(ToolbarButton, {
9090
+ label: "替换",
9091
+ ...commandShortcut('replace'),
9092
+ active: 'replace' === findReplaceMode,
9093
+ onClick: ()=>onFindText(true),
9094
+ children: /*#__PURE__*/ jsx(Replace, {
9095
+ size: 16
9096
+ })
9097
+ })
9098
+ ]
9099
+ })
9100
+ ]
9101
+ });
9102
+ }
9103
+ function ToolbarButton({ label, shortcut, ariaKeyShortcuts, active = false, disabled = false, onClick, children }) {
9104
+ return /*#__PURE__*/ jsx(WorkOfficeRibbonButton, {
9105
+ label: label,
9106
+ title: shortcut ? `${label}(${shortcut})` : label,
9107
+ "aria-keyshortcuts": ariaKeyShortcuts,
9108
+ active: active,
9109
+ displayLabel: false,
9110
+ disabled: disabled,
9111
+ onClick: onClick,
9112
+ children: children
8157
9113
  });
8158
- return true;
8159
9114
  }
8160
- function handleGalleryKeyDown(event, index, count, columns, refs, setFocusIndex, select) {
8161
- if ('Enter' === event.key || ' ' === event.key) {
8162
- event.preventDefault();
8163
- select();
9115
+ function commandShortcut(commandId) {
9116
+ const shortcut = getDocumentCommandDefinition(commandId).shortcut;
9117
+ return shortcut ? {
9118
+ shortcut: shortcut.label,
9119
+ ariaKeyShortcuts: shortcut.aria
9120
+ } : {};
9121
+ }
9122
+ const RibbonGroup = WorkOfficeRibbonGroup;
9123
+ function documentLineHeightValue(editor) {
9124
+ const attributes = editor.isActive('heading') ? editor.getAttributes('heading') : editor.getAttributes('paragraph');
9125
+ const value = attributes.lineHeight;
9126
+ if ('string' != typeof value || !value.trim() || 'normal' === value) return 'default';
9127
+ return value.trim();
9128
+ }
9129
+ function documentLineHeightOptionsForValue(value) {
9130
+ if (documentLineHeightOptions.some((option)=>option.value === value)) return documentLineHeightOptions;
9131
+ const numeric = Number(value);
9132
+ return [
9133
+ ...documentLineHeightOptions,
9134
+ {
9135
+ value,
9136
+ label: Number.isFinite(numeric) && numeric > 0 ? `${numeric} 倍` : value
9137
+ }
9138
+ ];
9139
+ }
9140
+ function documentFontFamilyDraftValue(source) {
9141
+ if (source.mixed) return 'mixed';
9142
+ return cssDocumentFontFamily(source.value) ?? 'inherit';
9143
+ }
9144
+ function appendDocumentFontDialogScriptFontPatch(patch, key, source, draft, touched) {
9145
+ if (!touched || 'mixed' === draft) return;
9146
+ const value = 'inherit' === draft ? null : documentFontNameFromCssFamily(draft);
9147
+ if ('inherit' !== draft && !value) return;
9148
+ if (source.mixed || (source.value?.toLocaleLowerCase() ?? null) !== (value?.toLocaleLowerCase() ?? null)) patch[key] = value;
9149
+ }
9150
+ function addDocumentScriptFontValues(latin, eastAsia, complexScript, attributes) {
9151
+ const fonts = parseDocumentScriptFonts('string' == typeof attributes.scriptFonts ? attributes.scriptFonts : void 0);
9152
+ const fallback = documentFontNameFromCssFamily(attributes.fontFamily);
9153
+ if (!fonts) {
9154
+ addFontValue(latin, fallback);
9155
+ addFontValue(eastAsia, fallback);
9156
+ addFontValue(complexScript, fallback);
8164
9157
  return;
8165
9158
  }
8166
- let next = index;
8167
- if ('ArrowRight' === event.key) next = (index + 1) % count;
8168
- else if ('ArrowLeft' === event.key) next = (index - 1 + count) % count;
8169
- else if ('ArrowDown' === event.key) next = Math.min(count - 1, index + columns);
8170
- else if ('ArrowUp' === event.key) next = Math.max(0, index - columns);
8171
- else if ('Home' === event.key) next = 0;
8172
- else {
8173
- if ('End' !== event.key) return;
8174
- next = count - 1;
9159
+ addFontValue(latin, documentScriptFontDirectFamily(fonts, 'ascii'));
9160
+ addFontValue(latin, documentScriptFontDirectFamily(fonts, 'highAnsi'));
9161
+ addFontValue(eastAsia, documentScriptFontDirectFamily(fonts, 'eastAsia'));
9162
+ addFontValue(complexScript, documentScriptFontDirectFamily(fonts, 'complexScript'));
9163
+ }
9164
+ function applyDocumentScriptFontPatch(editor, selection, scalarPatch, scriptFontPatch) {
9165
+ if (!validScriptFontPatch(scriptFontPatch)) return false;
9166
+ const { state } = editor;
9167
+ const textStyle = state.schema.marks.textStyle;
9168
+ if (!textStyle) return false;
9169
+ const transaction = state.tr;
9170
+ try {
9171
+ transaction.setSelection(TextSelection.create(transaction.doc, selection.from, selection.to));
9172
+ } catch {
9173
+ return false;
8175
9174
  }
8176
- event.preventDefault();
8177
- setFocusIndex(next);
8178
- refs.current[next]?.focus({
8179
- preventScroll: true
9175
+ if (selection.from === selection.to) {
9176
+ const marks = transaction.selection.$from.marks();
9177
+ const current = marks.find((mark)=>mark.type === textStyle);
9178
+ const attributes = patchedTextStyleAttributes(current, scalarPatch, scriptFontPatch, normalizeDocumentScriptFontSlot(current?.attrs.scriptFontSlot) ?? documentScriptFontSlotFromHint(parseDocumentScriptFonts(current?.attrs.scriptFonts)?.hint));
9179
+ const retained = marks.filter((mark)=>mark.type !== textStyle);
9180
+ if (textStyleAttributesHaveValue(attributes)) retained.push(textStyle.create(attributes));
9181
+ transaction.setStoredMarks(retained);
9182
+ transaction.scrollIntoView();
9183
+ editor.view.dispatch(transaction);
9184
+ editor.view.focus();
9185
+ return true;
9186
+ }
9187
+ const updates = [];
9188
+ transaction.doc.nodesBetween(selection.from, selection.to, (node, position)=>{
9189
+ if (!node.isText || !node.text) return;
9190
+ const from = Math.max(selection.from, position);
9191
+ const to = Math.min(selection.to, position + node.nodeSize);
9192
+ if (to <= from) return;
9193
+ const current = node.marks.find((mark)=>mark.type === textStyle);
9194
+ const currentFonts = parseDocumentScriptFonts(current?.attrs.scriptFonts);
9195
+ const nextFonts = patchDocumentScriptFonts(currentFonts, scriptFontPatch, current?.attrs.fontFamily);
9196
+ const text = node.text.slice(from - position, to - position);
9197
+ const segments = documentScriptFontSegments(text, nextFonts?.hint);
9198
+ for (const segment of segments)updates.push({
9199
+ from: from + segment.from,
9200
+ to: from + segment.to,
9201
+ current,
9202
+ attributes: patchedTextStyleAttributes(current, scalarPatch, scriptFontPatch, segment.slot, currentFonts, nextFonts)
9203
+ });
8180
9204
  });
9205
+ for (const update of updates){
9206
+ if (update.current) transaction.removeMark(update.from, update.to, update.current);
9207
+ if (textStyleAttributesHaveValue(update.attributes)) transaction.addMark(update.from, update.to, textStyle.create(update.attributes));
9208
+ }
9209
+ if (!transaction.docChanged) return false;
9210
+ editor.view.dispatch(transaction.scrollIntoView());
9211
+ editor.view.focus();
9212
+ return true;
8181
9213
  }
8182
- function validStartValue(value) {
8183
- const number = Number(value);
8184
- return Number.isSafeInteger(number) && number >= 1 && number <= MAX_DOCUMENT_NUMBERING_START ? number : null;
8185
- }
8186
- function documentListSnapshot(editor) {
8187
- const bullet = documentBulletListStyle(editor);
8188
- const ordered = documentOrderedListState(editor);
8189
- return `${bullet ?? ''}:${ordered?.style ?? ''}:${ordered?.start ?? ''}`;
8190
- }
8191
- const documentParagraphStyles = [
8192
- {
8193
- value: 'paragraph',
8194
- label: '正文',
8195
- level: null,
8196
- shortcut: void 0
8197
- },
8198
- {
8199
- value: 'h1',
8200
- label: '标题 1',
8201
- level: 1,
8202
- shortcut: getDocumentCommandDefinition('heading1').shortcut
8203
- },
8204
- {
8205
- value: 'h2',
8206
- label: '标题 2',
8207
- level: 2,
8208
- shortcut: getDocumentCommandDefinition('heading2').shortcut
8209
- },
8210
- {
8211
- value: 'h3',
8212
- label: '标题 3',
8213
- level: 3,
8214
- shortcut: getDocumentCommandDefinition('heading3').shortcut
9214
+ function patchedTextStyleAttributes(current, scalarPatch, scriptFontPatch, slot, currentFonts = parseDocumentScriptFonts(current?.attrs.scriptFonts), nextFonts = patchDocumentScriptFonts(currentFonts, scriptFontPatch, current?.attrs.fontFamily)) {
9215
+ const attributes = {
9216
+ ...current?.attrs ?? {},
9217
+ ...scalarPatch
9218
+ };
9219
+ const serialized = serializeDocumentScriptFonts(nextFonts);
9220
+ if (!nextFonts || !serialized) {
9221
+ attributes.scriptFonts = null;
9222
+ attributes.scriptFontSlot = null;
9223
+ attributes.fontFamily = null;
9224
+ attributes.wordLineHeightFactor = null;
9225
+ return attributes;
8215
9226
  }
8216
- ];
8217
- function DocumentStyleGallery({ editor }) {
8218
- const groupName = useId();
8219
- const inputsRef = useRef([]);
8220
- const activeStyle = documentParagraphStyleValue(editor);
8221
- const moveSelection = (event, nextIndex)=>{
8222
- event.preventDefault();
8223
- const normalizedIndex = (nextIndex + documentParagraphStyles.length) % documentParagraphStyles.length;
8224
- const style = documentParagraphStyles[normalizedIndex];
8225
- if (!style) return;
8226
- applyDocumentParagraphStyle(editor, style);
8227
- inputsRef.current[normalizedIndex]?.focus({
8228
- preventScroll: true
8229
- });
9227
+ const currentOwnsSlot = Boolean(currentFonts && documentScriptFontDirectFamily(currentFonts, slot));
9228
+ const nextOwnsSlot = Boolean(documentScriptFontDirectFamily(nextFonts, slot));
9229
+ const family = nextOwnsSlot || currentOwnsSlot ? documentScriptFontFamilyForRendering(nextFonts, slot, current?.attrs.fontFamily) : 'string' == typeof current?.attrs.fontFamily ? current.attrs.fontFamily : documentScriptFontFamilyForRendering(nextFonts, slot);
9230
+ attributes.scriptFonts = serialized;
9231
+ attributes.scriptFontSlot = slot;
9232
+ attributes.fontFamily = family ?? null;
9233
+ attributes.wordLineHeightFactor = family ? documentWordLineHeightFactor(family) : null;
9234
+ return attributes;
9235
+ }
9236
+ function textStyleAttributesHaveValue(attributes) {
9237
+ return Object.values(attributes).some((value)=>null != value && '' !== value);
9238
+ }
9239
+ function validScriptFontPatch(patch) {
9240
+ return Object.values(patch).every((value)=>null === value || null !== documentFontNameFromCssFamily(value));
9241
+ }
9242
+ function addFontValue(values, value) {
9243
+ const normalized = value?.trim() || null;
9244
+ values.set(normalized?.toLocaleLowerCase() ?? 'inherited', normalized);
9245
+ }
9246
+ function documentFontDialogSource(editor) {
9247
+ const { doc, selection } = editor.state;
9248
+ const scaleValues = new Map();
9249
+ const positionValues = new Map();
9250
+ const spacingValues = new Map();
9251
+ const kerningValues = new Map();
9252
+ const emphasisValues = new Map();
9253
+ const hiddenTextValues = new Map();
9254
+ const latinFontValues = new Map();
9255
+ const eastAsiaFontValues = new Map();
9256
+ const complexScriptFontValues = new Map();
9257
+ const addValues = (attributes)=>{
9258
+ addScaleValue(scaleValues, attributes.characterScalePercent);
9259
+ addPositionValue(positionValues, attributes.characterPositionHalfPoints);
9260
+ addSpacingValue(spacingValues, attributes.characterSpacingTwips);
9261
+ addKerningValue(kerningValues, attributes.kerningThresholdHalfPoints);
9262
+ addEmphasisValue(emphasisValues, attributes.emphasisMark);
9263
+ addHiddenTextValue(hiddenTextValues, attributes.hiddenText);
9264
+ addDocumentScriptFontValues(latinFontValues, eastAsiaFontValues, complexScriptFontValues, attributes);
8230
9265
  };
8231
- return /*#__PURE__*/ jsxs("div", {
8232
- className: "work-document-style-tools",
8233
- children: [
8234
- /*#__PURE__*/ jsx("div", {
8235
- className: "work-document-style-gallery",
8236
- role: "radiogroup",
8237
- "aria-label": "段落样式库",
8238
- children: documentParagraphStyles.map((style, index)=>{
8239
- const active = style.value === activeStyle;
8240
- return /*#__PURE__*/ jsxs("label", {
8241
- className: active ? 'active' : '',
8242
- "data-document-style": style.value,
8243
- title: style.shortcut ? `${style.label}(${style.shortcut.label})` : style.label,
8244
- children: [
8245
- /*#__PURE__*/ jsx("input", {
8246
- ref: (input)=>{
8247
- inputsRef.current[index] = input;
8248
- },
8249
- type: "radio",
8250
- name: groupName,
8251
- "aria-label": `应用样式:${style.label}`,
8252
- "aria-keyshortcuts": style.shortcut?.aria,
8253
- checked: active,
8254
- tabIndex: active ? 0 : -1,
8255
- onChange: ()=>applyDocumentParagraphStyle(editor, style),
8256
- onKeyDown: (event)=>{
8257
- if ('ArrowRight' === event.key || 'ArrowDown' === event.key) moveSelection(event, index + 1);
8258
- else if ('ArrowLeft' === event.key || 'ArrowUp' === event.key) moveSelection(event, index - 1);
8259
- else if ('Home' === event.key) moveSelection(event, 0);
8260
- else if ('End' === event.key) moveSelection(event, documentParagraphStyles.length - 1);
8261
- }
8262
- }),
8263
- /*#__PURE__*/ jsx("span", {
8264
- "aria-hidden": "true",
8265
- children: style.label
8266
- })
8267
- ]
8268
- }, style.value);
8269
- })
8270
- }),
8271
- /*#__PURE__*/ jsx(OfficeSelect, {
8272
- ariaLabel: "段落样式",
8273
- className: "work-document-style-select",
8274
- value: activeStyle,
8275
- options: documentParagraphStyles.map((style)=>({
8276
- ...style,
8277
- meta: style.shortcut?.label
8278
- })),
8279
- onValueChange: (value)=>{
8280
- const style = documentParagraphStyles.find((candidate)=>candidate.value === value);
8281
- if (style) applyDocumentParagraphStyle(editor, style);
8282
- }
8283
- })
8284
- ]
9266
+ if (selection.empty) addValues(editor.getAttributes('textStyle'));
9267
+ else doc.nodesBetween(selection.from, selection.to, (node, position)=>{
9268
+ if (!node.isText || position >= selection.to || position + node.nodeSize <= selection.from) return;
9269
+ const textStyle = node.marks.find((mark)=>'textStyle' === mark.type.name);
9270
+ addValues(textStyle?.attrs ?? {});
8285
9271
  });
9272
+ if (!scaleValues.size || !spacingValues.size || !positionValues.size || !kerningValues.size || !emphasisValues.size || !hiddenTextValues.size || !latinFontValues.size || !eastAsiaFontValues.size || !complexScriptFontValues.size) addValues(editor.getAttributes('textStyle'));
9273
+ const characterScale = selectedValue(scaleValues);
9274
+ const characterPosition = selectedValue(positionValues);
9275
+ const characterSpacing = selectedValue(spacingValues);
9276
+ const kerningThreshold = selectedValue(kerningValues);
9277
+ const emphasisMark = selectedValue(emphasisValues);
9278
+ const hiddenText = selectedValue(hiddenTextValues);
9279
+ const latinFont = selectedValue(latinFontValues);
9280
+ const eastAsiaFont = selectedValue(eastAsiaFontValues);
9281
+ const complexScriptFont = selectedValue(complexScriptFontValues);
9282
+ const textStyle = editor.getAttributes('textStyle');
9283
+ const selectedText = selection.empty ? '' : doc.textBetween(selection.from, selection.to, ' ', ' ').replace(/\s+/g, ' ').trim();
9284
+ return {
9285
+ characterScale,
9286
+ characterPosition,
9287
+ characterSpacing,
9288
+ kerningThreshold,
9289
+ emphasisMark,
9290
+ hiddenText,
9291
+ latinFont,
9292
+ eastAsiaFont,
9293
+ complexScriptFont,
9294
+ fontFamily: 'string' == typeof textStyle.fontFamily && textStyle.fontFamily.trim() ? textStyle.fontFamily : null,
9295
+ fontSize: 'string' == typeof textStyle.fontSize && textStyle.fontSize.trim() ? textStyle.fontSize : null,
9296
+ previewText: selectedText.slice(0, 72) || 'A3S Office 字符格式',
9297
+ selectedCharacters: selectedText.length
9298
+ };
8286
9299
  }
8287
- function documentParagraphStyleValue(editor) {
8288
- if (editor.isActive('heading', {
8289
- level: 1
8290
- })) return 'h1';
8291
- if (editor.isActive('heading', {
8292
- level: 2
8293
- })) return 'h2';
8294
- if (editor.isActive('heading', {
8295
- level: 3
8296
- })) return 'h3';
8297
- return 'paragraph';
9300
+ function createDocumentFontDialogDraft(source) {
9301
+ const scale = source.characterScale.value;
9302
+ const spacing = source.characterSpacing.value;
9303
+ const spacingPoints = Math.abs(documentCharacterSpacingPoints(spacing) ?? 1);
9304
+ const position = source.characterPosition.value;
9305
+ const positionPoints = Math.abs(documentCharacterPositionPoints(position) ?? 1);
9306
+ const kerningThreshold = source.kerningThreshold.value;
9307
+ return {
9308
+ characterScaleMode: source.characterScale.mixed ? 'mixed' : 'value',
9309
+ characterScalePercent: source.characterScale.mixed ? '' : String(scale ?? 100),
9310
+ characterPositionMode: source.characterPosition.mixed ? 'mixed' : null !== position && position < 0 ? 'lowered' : null !== position && position > 0 ? 'raised' : 'normal',
9311
+ characterPositionPoints: formatPoints(positionPoints || 1),
9312
+ characterSpacingMode: source.characterSpacing.mixed ? 'mixed' : null !== spacing && spacing < 0 ? 'condensed' : null !== spacing && spacing > 0 ? 'expanded' : 'normal',
9313
+ characterSpacingPoints: formatPoints(spacingPoints || 1),
9314
+ kerningEnabled: !source.kerningThreshold.mixed && null !== kerningThreshold,
9315
+ kerningThresholdPoints: formatPoints(documentKerningThresholdPoints(kerningThreshold) ?? 12),
9316
+ emphasisMark: source.emphasisMark.mixed ? 'mixed' : source.emphasisMark.value ?? 'inherit',
9317
+ hiddenText: source.hiddenText.value ?? false,
9318
+ latinFont: documentFontFamilyDraftValue(source.latinFont),
9319
+ eastAsiaFont: documentFontFamilyDraftValue(source.eastAsiaFont),
9320
+ complexScriptFont: documentFontFamilyDraftValue(source.complexScriptFont)
9321
+ };
8298
9322
  }
8299
- function applyDocumentParagraphStyle(editor, style) {
8300
- if (null === style.level) return editor.chain().focus().setParagraph().run();
8301
- return editor.chain().focus().setHeading({
8302
- level: style.level
8303
- }).run();
9323
+ function documentFontDialogDraftError(draft) {
9324
+ if ('mixed' !== draft.characterScaleMode && null === characterScalePercentFromDraft(draft)) return "请输入 1 至 600 的整数缩放比例。";
9325
+ if ('mixed' !== draft.characterSpacingMode && 'normal' !== draft.characterSpacingMode && null === characterSpacingTwipsFromDraft(draft)) return "请输入 0.05 至 1584 磅的间距。";
9326
+ if ('mixed' !== draft.characterPositionMode && 'normal' !== draft.characterPositionMode && null === characterPositionHalfPointsFromDraft(draft)) return "请输入 0.5 至 1584 磅、以 0.5 磅递增的位置值。";
9327
+ if (draft.kerningEnabled && null === kerningThresholdHalfPointsFromDraft(draft)) return "请输入 0 至 1638.5 磅、以 0.5 磅递增的字距调整阈值。";
9328
+ return null;
9329
+ }
9330
+ function documentFontDialogPatch(source, draft, touched) {
9331
+ const patch = {};
9332
+ if (touched.characterScale && 'mixed' !== draft.characterScaleMode) {
9333
+ const scale = characterScalePercentFromDraft(draft);
9334
+ if (null !== scale && (source.characterScale.mixed || source.characterScale.value !== scale)) patch.characterScalePercent = scale;
9335
+ }
9336
+ if (touched.characterSpacing && 'mixed' !== draft.characterSpacingMode) {
9337
+ const spacing = characterSpacingTwipsFromDraft(draft);
9338
+ if (null !== spacing && (source.characterSpacing.mixed || source.characterSpacing.value !== spacing)) patch.characterSpacingTwips = spacing;
9339
+ }
9340
+ if (touched.characterPosition && 'mixed' !== draft.characterPositionMode) {
9341
+ const position = characterPositionHalfPointsFromDraft(draft);
9342
+ if (null !== position && (source.characterPosition.mixed || source.characterPosition.value !== position)) patch.characterPositionHalfPoints = position;
9343
+ }
9344
+ if (touched.kerning) {
9345
+ if (draft.kerningEnabled) {
9346
+ const threshold = kerningThresholdHalfPointsFromDraft(draft);
9347
+ if (null !== threshold && (source.kerningThreshold.mixed || source.kerningThreshold.value !== threshold)) patch.kerningThresholdHalfPoints = threshold;
9348
+ } else if (source.kerningThreshold.mixed || null !== source.kerningThreshold.value) patch.kerningThresholdHalfPoints = null;
9349
+ }
9350
+ if (touched.emphasisMark && 'mixed' !== draft.emphasisMark) {
9351
+ const emphasisMark = 'inherit' === draft.emphasisMark ? null : normalizeDocumentEmphasisMark(draft.emphasisMark);
9352
+ if (null !== emphasisMark || 'inherit' === draft.emphasisMark) {
9353
+ if (source.emphasisMark.mixed || source.emphasisMark.value !== emphasisMark) patch.emphasisMark = emphasisMark;
9354
+ }
9355
+ }
9356
+ if (touched.hiddenText && (source.hiddenText.mixed || source.hiddenText.value !== draft.hiddenText)) patch.hiddenText = draft.hiddenText;
9357
+ appendDocumentFontDialogScriptFontPatch(patch, 'latinFont', source.latinFont, draft.latinFont, touched.latinFont);
9358
+ appendDocumentFontDialogScriptFontPatch(patch, 'eastAsiaFont', source.eastAsiaFont, draft.eastAsiaFont, touched.eastAsiaFont);
9359
+ appendDocumentFontDialogScriptFontPatch(patch, 'complexScriptFont', source.complexScriptFont, draft.complexScriptFont, touched.complexScriptFont);
9360
+ return patch;
9361
+ }
9362
+ function applyDocumentFontDialogPatch(editor, selection, patch) {
9363
+ const hasScale = void 0 !== patch.characterScalePercent;
9364
+ const hasPosition = void 0 !== patch.characterPositionHalfPoints;
9365
+ const hasSpacing = void 0 !== patch.characterSpacingTwips;
9366
+ const hasKerning = void 0 !== patch.kerningThresholdHalfPoints;
9367
+ const hasEmphasis = void 0 !== patch.emphasisMark;
9368
+ const hasHiddenText = void 0 !== patch.hiddenText;
9369
+ const scriptFontPatch = {
9370
+ ...void 0 !== patch.latinFont ? {
9371
+ latin: patch.latinFont
9372
+ } : {},
9373
+ ...void 0 !== patch.eastAsiaFont ? {
9374
+ eastAsia: patch.eastAsiaFont
9375
+ } : {},
9376
+ ...void 0 !== patch.complexScriptFont ? {
9377
+ complexScript: patch.complexScriptFont
9378
+ } : {}
9379
+ };
9380
+ const hasScriptFonts = Object.keys(scriptFontPatch).length > 0;
9381
+ const scale = hasScale ? normalizeDocumentCharacterScalePercent(patch.characterScalePercent) : null;
9382
+ const position = hasPosition ? normalizeDocumentCharacterPositionHalfPoints(patch.characterPositionHalfPoints) : null;
9383
+ const spacing = hasSpacing ? normalizeDocumentCharacterSpacingTwips(patch.characterSpacingTwips) : null;
9384
+ const kerningThreshold = hasKerning && null !== patch.kerningThresholdHalfPoints ? normalizeDocumentKerningThresholdHalfPoints(patch.kerningThresholdHalfPoints) : null;
9385
+ const emphasisMark = hasEmphasis && null !== patch.emphasisMark ? normalizeDocumentEmphasisMark(patch.emphasisMark) : null;
9386
+ const maximum = editor.state.doc.content.size;
9387
+ if (editor.isDestroyed || !hasScale && !hasPosition && !hasSpacing && !hasKerning && !hasEmphasis && !hasHiddenText && !hasScriptFonts || hasScale && null === scale || hasPosition && null === position || hasSpacing && null === spacing || hasKerning && null !== patch.kerningThresholdHalfPoints && null === kerningThreshold || hasEmphasis && null !== patch.emphasisMark && null === emphasisMark || hasHiddenText && 'boolean' != typeof patch.hiddenText || !Number.isSafeInteger(selection.from) || !Number.isSafeInteger(selection.to) || selection.from < 0 || selection.to < selection.from || selection.to > maximum) return false;
9388
+ const attributes = {};
9389
+ if (null !== scale) attributes.characterScalePercent = scale;
9390
+ if (null !== position) attributes.characterPositionHalfPoints = position;
9391
+ if (null !== spacing) attributes.characterSpacingTwips = spacing;
9392
+ if (hasKerning) attributes.kerningThresholdHalfPoints = kerningThreshold;
9393
+ if (hasEmphasis) attributes.emphasisMark = emphasisMark;
9394
+ if (hasHiddenText) attributes.hiddenText = patch.hiddenText ?? false;
9395
+ if (hasScriptFonts) return applyDocumentScriptFontPatch(editor, selection, attributes, scriptFontPatch);
9396
+ return editor.chain().setTextSelection(selection).setMark('textStyle', attributes).removeEmptyTextStyle().focus().scrollIntoView().run();
9397
+ }
9398
+ function addScaleValue(values, value) {
9399
+ const scale = normalizeDocumentCharacterScalePercent(value);
9400
+ values.set(null === scale ? 'inherited' : String(scale), scale);
9401
+ }
9402
+ function addPositionValue(values, value) {
9403
+ const position = normalizeDocumentCharacterPositionHalfPoints(value);
9404
+ values.set(null === position ? 'inherited' : String(position), position);
9405
+ }
9406
+ function addSpacingValue(values, value) {
9407
+ const spacing = normalizeDocumentCharacterSpacingTwips(value);
9408
+ values.set(null === spacing ? 'inherited' : String(spacing), spacing);
9409
+ }
9410
+ function addKerningValue(values, value) {
9411
+ const threshold = normalizeDocumentKerningThresholdHalfPoints(value);
9412
+ values.set(null === threshold ? 'inherited' : String(threshold), threshold);
9413
+ }
9414
+ function addEmphasisValue(values, value) {
9415
+ const emphasisMark = normalizeDocumentEmphasisMark(value);
9416
+ values.set(null === emphasisMark ? 'inherited' : emphasisMark, emphasisMark);
9417
+ }
9418
+ function addHiddenTextValue(values, value) {
9419
+ const hiddenText = normalizeDocumentHiddenText(value);
9420
+ values.set(null === hiddenText ? 'inherited' : String(hiddenText), hiddenText);
9421
+ }
9422
+ function characterSpacingTwipsFromDraft(draft) {
9423
+ if ('normal' === draft.characterSpacingMode) return 0;
9424
+ if ('mixed' === draft.characterSpacingMode) return null;
9425
+ const points = Number(draft.characterSpacingPoints);
9426
+ const maximumPoints = 1584;
9427
+ if (!Number.isFinite(points) || points < 0.05 || points > maximumPoints) return null;
9428
+ const magnitude = Math.round(20 * points);
9429
+ if (magnitude <= 0) return null;
9430
+ return normalizeDocumentCharacterSpacingTwips('condensed' === draft.characterSpacingMode ? -magnitude : magnitude);
9431
+ }
9432
+ function characterScalePercentFromDraft(draft) {
9433
+ if ('mixed' === draft.characterScaleMode) return null;
9434
+ return normalizeDocumentCharacterScalePercent(draft.characterScalePercent);
9435
+ }
9436
+ function characterPositionHalfPointsFromDraft(draft) {
9437
+ if ('normal' === draft.characterPositionMode) return 0;
9438
+ if ('mixed' === draft.characterPositionMode) return null;
9439
+ const points = Number(draft.characterPositionPoints);
9440
+ const maximumPoints = 1584;
9441
+ const magnitude = 2 * points;
9442
+ if (!Number.isFinite(points) || points < 0.5 || points > maximumPoints || !Number.isSafeInteger(magnitude)) return null;
9443
+ return normalizeDocumentCharacterPositionHalfPoints('lowered' === draft.characterPositionMode ? -magnitude : magnitude);
9444
+ }
9445
+ function kerningThresholdHalfPointsFromDraft(draft) {
9446
+ if (!draft.kerningEnabled) return null;
9447
+ const points = Number(draft.kerningThresholdPoints);
9448
+ const halfPoints = 2 * points;
9449
+ if (!Number.isFinite(points) || points < 0 || points > 1638.5 || !Number.isSafeInteger(halfPoints)) return null;
9450
+ return normalizeDocumentKerningThresholdHalfPoints(halfPoints);
9451
+ }
9452
+ function selectedValue(values) {
9453
+ const mixed = values.size > 1;
9454
+ return {
9455
+ mixed,
9456
+ value: mixed ? null : values.values().next().value ?? null
9457
+ };
8304
9458
  }
8305
- const documentLineHeightOptions = [
9459
+ function formatPoints(value) {
9460
+ return String(Number(value.toFixed(2)));
9461
+ }
9462
+ const characterSpacingModes = [
8306
9463
  {
8307
- value: 'default',
8308
- label: '默认行距'
9464
+ value: 'mixed',
9465
+ label: '混合(保持不变)',
9466
+ disabled: true
8309
9467
  },
8310
9468
  {
8311
- value: '1',
8312
- label: '单倍',
8313
- meta: getDocumentCommandDefinition('lineSpacingSingle').shortcut?.label
9469
+ value: 'normal',
9470
+ label: '标准'
8314
9471
  },
8315
9472
  {
8316
- value: '1.15',
8317
- label: '1.15 倍'
9473
+ value: 'expanded',
9474
+ label: '加宽'
8318
9475
  },
8319
9476
  {
8320
- value: '1.5',
8321
- label: '1.5 倍',
8322
- meta: getDocumentCommandDefinition('lineSpacingOneAndHalf').shortcut?.label
9477
+ value: 'condensed',
9478
+ label: '紧缩'
9479
+ }
9480
+ ];
9481
+ const characterPositionModes = [
9482
+ {
9483
+ value: 'mixed',
9484
+ label: '混合(保持不变)',
9485
+ disabled: true
8323
9486
  },
8324
9487
  {
8325
- value: '2',
8326
- label: '2 倍',
8327
- meta: getDocumentCommandDefinition('lineSpacingDouble').shortcut?.label
9488
+ value: 'normal',
9489
+ label: '标准'
9490
+ },
9491
+ {
9492
+ value: 'raised',
9493
+ label: '提升'
9494
+ },
9495
+ {
9496
+ value: 'lowered',
9497
+ label: '降低'
8328
9498
  }
8329
9499
  ];
8330
- function DocumentHomeRibbon({ editor, findReplaceMode, layoutFonts = [], onFindText }) {
8331
- const subscribe = useCallback((notify)=>{
8332
- if (editor.isDestroyed) return ()=>void 0;
8333
- editor.on('transaction', notify);
8334
- return ()=>editor.off('transaction', notify);
8335
- }, [
8336
- editor
8337
- ]);
8338
- useSyncExternalStore(subscribe, ()=>editor.state, ()=>editor.state);
8339
- if (editor.isDestroyed) return null;
8340
- const fontFamilyValue = documentFontFamilyValue(editor, layoutFonts);
8341
- const fontSizeValue = documentFontSizeValue(editor);
8342
- const lineHeightValue = documentLineHeightValue(editor);
8343
- return /*#__PURE__*/ jsxs(Fragment, {
8344
- children: [
8345
- /*#__PURE__*/ jsx(DocumentFormatTools, {
8346
- editor: editor
8347
- }),
8348
- /*#__PURE__*/ jsx(RibbonGroup, {
8349
- label: "字体",
8350
- priority: "high",
8351
- children: /*#__PURE__*/ jsxs("div", {
8352
- className: "work-document-font-tools",
9500
+ const emphasisMarkModes = [
9501
+ {
9502
+ value: 'mixed',
9503
+ label: '混合(保持不变)',
9504
+ disabled: true
9505
+ },
9506
+ {
9507
+ value: 'inherit',
9508
+ label: '跟随样式'
9509
+ },
9510
+ {
9511
+ value: 'none',
9512
+ label: '无'
9513
+ },
9514
+ {
9515
+ value: 'dot',
9516
+ label: '上方圆点'
9517
+ },
9518
+ {
9519
+ value: 'comma',
9520
+ label: '上方逗号'
9521
+ },
9522
+ {
9523
+ value: 'circle',
9524
+ label: '上方圆圈'
9525
+ },
9526
+ {
9527
+ value: 'underDot',
9528
+ label: '下方圆点'
9529
+ }
9530
+ ];
9531
+ function DocumentFontDialog({ source, layoutFonts = [], restoreFocusTarget, onApply, onClose }) {
9532
+ const [draft, setDraft] = useState(()=>createDocumentFontDialogDraft(source));
9533
+ const [characterScaleTouched, setCharacterScaleTouched] = useState(false);
9534
+ const [characterSpacingTouched, setCharacterSpacingTouched] = useState(false);
9535
+ const [characterPositionTouched, setCharacterPositionTouched] = useState(false);
9536
+ const [kerningTouched, setKerningTouched] = useState(false);
9537
+ const [emphasisTouched, setEmphasisTouched] = useState(false);
9538
+ const [hiddenTextTouched, setHiddenTextTouched] = useState(false);
9539
+ const [latinFontTouched, setLatinFontTouched] = useState(false);
9540
+ const [eastAsiaFontTouched, setEastAsiaFontTouched] = useState(false);
9541
+ const [complexScriptFontTouched, setComplexScriptFontTouched] = useState(false);
9542
+ const formId = useId();
9543
+ const error = documentFontDialogDraftError(draft);
9544
+ const patch = documentFontDialogPatch(source, draft, {
9545
+ characterPosition: characterPositionTouched,
9546
+ characterScale: characterScaleTouched,
9547
+ characterSpacing: characterSpacingTouched,
9548
+ complexScriptFont: complexScriptFontTouched,
9549
+ eastAsiaFont: eastAsiaFontTouched,
9550
+ emphasisMark: emphasisTouched,
9551
+ hiddenText: hiddenTextTouched,
9552
+ kerning: kerningTouched,
9553
+ latinFont: latinFontTouched
9554
+ });
9555
+ const hasChanges = Object.keys(patch).length > 0;
9556
+ const previewScale = previewCharacterScale(draft);
9557
+ const previewSpacing = previewCharacterSpacing(draft);
9558
+ const previewPosition = previewCharacterPosition(draft);
9559
+ const previewKerning = previewDocumentKerning(draft, source.fontSize);
9560
+ const previewEmphasis = previewDocumentEmphasis(draft.emphasisMark);
9561
+ const submit = (event)=>{
9562
+ event?.preventDefault();
9563
+ if (!hasChanges || error) return;
9564
+ if (onApply(patch)) onClose();
9565
+ };
9566
+ return /*#__PURE__*/ jsx(Dialog, {
9567
+ title: "字体高级设置",
9568
+ description: fontDialogDescription(source),
9569
+ className: "work-document-font-dialog",
9570
+ restoreFocusTarget: restoreFocusTarget,
9571
+ onClose: onClose,
9572
+ footer: /*#__PURE__*/ jsxs(Fragment, {
9573
+ children: [
9574
+ /*#__PURE__*/ jsx(button_Button, {
9575
+ tone: "quiet",
9576
+ onClick: onClose,
9577
+ children: "取消"
9578
+ }),
9579
+ /*#__PURE__*/ jsx(button_Button, {
9580
+ tone: "primary",
9581
+ type: "submit",
9582
+ form: formId,
9583
+ disabled: !hasChanges || Boolean(error),
9584
+ children: "应用"
9585
+ })
9586
+ ]
9587
+ }),
9588
+ children: /*#__PURE__*/ jsxs("form", {
9589
+ id: formId,
9590
+ onSubmit: submit,
9591
+ children: [
9592
+ /*#__PURE__*/ jsxs("fieldset", {
9593
+ className: "work-document-font-dialog-script-fonts",
8353
9594
  children: [
9595
+ /*#__PURE__*/ jsx("legend", {
9596
+ children: "按文字系统设置字体"
9597
+ }),
8354
9598
  /*#__PURE__*/ jsxs("div", {
8355
- className: "work-document-font-selects",
9599
+ className: "work-document-font-dialog-field",
8356
9600
  children: [
9601
+ /*#__PURE__*/ jsx("span", {
9602
+ children: "拉丁文字"
9603
+ }),
8357
9604
  /*#__PURE__*/ jsx(OfficeSelect, {
8358
- ariaLabel: "字体",
8359
- className: "work-document-font-family-select",
8360
- value: fontFamilyValue,
8361
- options: documentFontFamilyOptionsForValue(fontFamilyValue, layoutFonts),
8362
- onValueChange: (value)=>{
8363
- if ('default' === value) editor.chain().focus().unsetFontFamily().run();
8364
- else editor.chain().focus().setFontFamily(value).run();
9605
+ ariaLabel: "拉丁文字字体",
9606
+ initialFocus: true,
9607
+ value: draft.latinFont,
9608
+ options: scriptFontOptions(draft.latinFont, layoutFonts),
9609
+ onValueChange: (latinFont)=>{
9610
+ setDraft((current)=>({
9611
+ ...current,
9612
+ latinFont
9613
+ }));
9614
+ setLatinFontTouched(true);
8365
9615
  }
9616
+ })
9617
+ ]
9618
+ }),
9619
+ /*#__PURE__*/ jsxs("div", {
9620
+ className: "work-document-font-dialog-field",
9621
+ children: [
9622
+ /*#__PURE__*/ jsx("span", {
9623
+ children: "东亚文字"
8366
9624
  }),
8367
9625
  /*#__PURE__*/ jsx(OfficeSelect, {
8368
- ariaLabel: "字号",
8369
- className: "work-document-font-size-select",
8370
- value: fontSizeValue,
8371
- options: documentFontSizeOptionsForValue(fontSizeValue),
8372
- onValueChange: (value)=>{
8373
- if ('default' === value) editor.chain().focus().unsetFontSize().run();
8374
- else editor.chain().focus().setFontSize(value).run();
9626
+ ariaLabel: "东亚文字字体",
9627
+ value: draft.eastAsiaFont,
9628
+ options: scriptFontOptions(draft.eastAsiaFont, layoutFonts),
9629
+ onValueChange: (eastAsiaFont)=>{
9630
+ setDraft((current)=>({
9631
+ ...current,
9632
+ eastAsiaFont
9633
+ }));
9634
+ setEastAsiaFontTouched(true);
8375
9635
  }
8376
- }),
8377
- /*#__PURE__*/ jsx(ToolbarButton, {
8378
- label: "增大字号",
8379
- ...commandShortcut('growFont'),
8380
- disabled: !canChangeDocumentFontSize(editor, 1),
8381
- onClick: ()=>changeDocumentFontSize(editor, 1),
8382
- children: /*#__PURE__*/ jsx(AArrowUp, {
8383
- size: 16
8384
- })
8385
- }),
8386
- /*#__PURE__*/ jsx(ToolbarButton, {
8387
- label: "减小字号",
8388
- ...commandShortcut('shrinkFont'),
8389
- disabled: !canChangeDocumentFontSize(editor, -1),
8390
- onClick: ()=>changeDocumentFontSize(editor, -1),
8391
- children: /*#__PURE__*/ jsx(AArrowDown, {
8392
- size: 16
8393
- })
8394
9636
  })
8395
9637
  ]
8396
9638
  }),
8397
9639
  /*#__PURE__*/ jsxs("div", {
8398
- className: "work-document-font-actions",
9640
+ className: "work-document-font-dialog-field",
8399
9641
  children: [
8400
- /*#__PURE__*/ jsx(ToolbarButton, {
8401
- label: "加粗",
8402
- ...commandShortcut('bold'),
8403
- active: editor.isActive('bold'),
8404
- onClick: ()=>editor.chain().focus().toggleBold().run(),
8405
- children: /*#__PURE__*/ jsx(Bold, {
8406
- size: 16
8407
- })
8408
- }),
8409
- /*#__PURE__*/ jsx(ToolbarButton, {
8410
- label: "斜体",
8411
- ...commandShortcut('italic'),
8412
- active: editor.isActive('italic'),
8413
- onClick: ()=>editor.chain().focus().toggleItalic().run(),
8414
- children: /*#__PURE__*/ jsx(Italic, {
8415
- size: 16
8416
- })
8417
- }),
8418
- /*#__PURE__*/ jsx(ToolbarButton, {
8419
- label: "下划线",
8420
- ...commandShortcut('underline'),
8421
- active: editor.isActive('underline'),
8422
- onClick: ()=>editor.chain().focus().toggleUnderline().run(),
8423
- children: /*#__PURE__*/ jsx(Underline, {
8424
- size: 16
8425
- })
8426
- }),
8427
- /*#__PURE__*/ jsx(ToolbarButton, {
8428
- label: "删除线",
8429
- active: editor.isActive('strike'),
8430
- onClick: ()=>editor.chain().focus().toggleStrike().run(),
8431
- children: /*#__PURE__*/ jsx(Strikethrough, {
8432
- size: 16
8433
- })
9642
+ /*#__PURE__*/ jsx("span", {
9643
+ children: "复杂文字"
8434
9644
  }),
8435
- /*#__PURE__*/ jsx(ToolbarButton, {
8436
- label: "下标",
8437
- ...commandShortcut("subscript"),
8438
- active: editor.isActive("subscript"),
8439
- onClick: ()=>editor.commands.toggleDocumentSubscript(),
8440
- children: /*#__PURE__*/ jsx(Subscript, {
8441
- size: 16
8442
- })
9645
+ /*#__PURE__*/ jsx(OfficeSelect, {
9646
+ ariaLabel: "复杂文字字体",
9647
+ value: draft.complexScriptFont,
9648
+ options: scriptFontOptions(draft.complexScriptFont, layoutFonts),
9649
+ onValueChange: (complexScriptFont)=>{
9650
+ setDraft((current)=>({
9651
+ ...current,
9652
+ complexScriptFont
9653
+ }));
9654
+ setComplexScriptFontTouched(true);
9655
+ }
9656
+ })
9657
+ ]
9658
+ }),
9659
+ source.latinFont.mixed && !latinFontTouched && /*#__PURE__*/ jsx("p", {
9660
+ className: "work-document-font-dialog-mixed",
9661
+ role: "status",
9662
+ children: "当前选区包含不同的拉丁文字字体。选择字体后才会统一修改。"
9663
+ }),
9664
+ source.eastAsiaFont.mixed && !eastAsiaFontTouched && /*#__PURE__*/ jsx("p", {
9665
+ className: "work-document-font-dialog-mixed",
9666
+ role: "status",
9667
+ children: "当前选区包含不同的东亚文字字体。选择字体后才会统一修改。"
9668
+ }),
9669
+ source.complexScriptFont.mixed && !complexScriptFontTouched && /*#__PURE__*/ jsx("p", {
9670
+ className: "work-document-font-dialog-mixed",
9671
+ role: "status",
9672
+ children: "当前选区包含不同的复杂文字字体。选择字体后才会统一修改。"
9673
+ })
9674
+ ]
9675
+ }),
9676
+ /*#__PURE__*/ jsxs("fieldset", {
9677
+ className: "work-document-font-dialog-spacing",
9678
+ children: [
9679
+ /*#__PURE__*/ jsx("legend", {
9680
+ children: "字符缩放、间距、字距调整、位置、着重号与隐藏文字"
9681
+ }),
9682
+ /*#__PURE__*/ jsxs("div", {
9683
+ className: "work-document-font-dialog-field",
9684
+ children: [
9685
+ /*#__PURE__*/ jsx("span", {
9686
+ children: "缩放"
8443
9687
  }),
8444
- /*#__PURE__*/ jsx(ToolbarButton, {
8445
- label: "上标",
8446
- ...commandShortcut("superscript"),
8447
- active: editor.isActive("superscript"),
8448
- onClick: ()=>editor.commands.toggleDocumentSuperscript(),
8449
- children: /*#__PURE__*/ jsx(Superscript, {
8450
- size: 16
8451
- })
9688
+ /*#__PURE__*/ jsxs("span", {
9689
+ className: "work-document-font-dialog-measure",
9690
+ children: [
9691
+ /*#__PURE__*/ jsx(OfficeNumberField, {
9692
+ ariaLabel: "字符缩放比例(%)",
9693
+ value: draft.characterScalePercent,
9694
+ min: 1,
9695
+ max: 600,
9696
+ step: 1,
9697
+ placeholder: 'mixed' === draft.characterScaleMode ? '混合' : void 0,
9698
+ validationInvalid: Boolean(error),
9699
+ onValueChange: (characterScalePercent)=>{
9700
+ setDraft((current)=>({
9701
+ ...current,
9702
+ characterScaleMode: 'value',
9703
+ characterScalePercent
9704
+ }));
9705
+ setCharacterScaleTouched(true);
9706
+ }
9707
+ }),
9708
+ /*#__PURE__*/ jsx("span", {
9709
+ "aria-hidden": "true",
9710
+ children: "%"
9711
+ })
9712
+ ]
9713
+ })
9714
+ ]
9715
+ }),
9716
+ /*#__PURE__*/ jsxs("div", {
9717
+ className: "work-document-font-dialog-field",
9718
+ children: [
9719
+ /*#__PURE__*/ jsx("span", {
9720
+ children: "间距"
8452
9721
  }),
8453
- /*#__PURE__*/ jsx(OfficeColorPicker, {
8454
- compact: true,
8455
- className: "work-color-tool",
8456
- value: editor.getAttributes('textStyle').color ?? '#172033',
8457
- ariaLabel: "文字颜色",
8458
- onValueChange: (color)=>editor.chain().focus().setColor(color).run()
9722
+ /*#__PURE__*/ jsx(OfficeSelect, {
9723
+ ariaLabel: "字符间距",
9724
+ value: draft.characterSpacingMode,
9725
+ options: characterSpacingModes,
9726
+ onValueChange: (characterSpacingMode)=>{
9727
+ setDraft((current)=>({
9728
+ ...current,
9729
+ characterSpacingMode
9730
+ }));
9731
+ setCharacterSpacingTouched(true);
9732
+ }
9733
+ })
9734
+ ]
9735
+ }),
9736
+ /*#__PURE__*/ jsxs("div", {
9737
+ className: "work-document-font-dialog-field",
9738
+ children: [
9739
+ /*#__PURE__*/ jsx("span", {
9740
+ children: "间距值"
8459
9741
  }),
8460
- /*#__PURE__*/ jsx(ToolbarButton, {
8461
- label: "突出显示",
8462
- active: editor.isActive('highlight'),
8463
- onClick: ()=>editor.chain().focus().toggleHighlight({
8464
- color: '#fff0a6'
8465
- }).run(),
8466
- children: /*#__PURE__*/ jsx(Highlighter, {
8467
- size: 16
8468
- })
9742
+ /*#__PURE__*/ jsxs("span", {
9743
+ className: "work-document-font-dialog-measure",
9744
+ children: [
9745
+ /*#__PURE__*/ jsx(OfficeNumberField, {
9746
+ ariaLabel: "间距值(磅)",
9747
+ value: draft.characterSpacingPoints,
9748
+ min: 0.05,
9749
+ max: 1584,
9750
+ step: 0.05,
9751
+ disabled: 'mixed' === draft.characterSpacingMode || 'normal' === draft.characterSpacingMode,
9752
+ validationInvalid: Boolean(error),
9753
+ onValueChange: (characterSpacingPoints)=>{
9754
+ setDraft((current)=>({
9755
+ ...current,
9756
+ characterSpacingPoints
9757
+ }));
9758
+ setCharacterSpacingTouched(true);
9759
+ }
9760
+ }),
9761
+ /*#__PURE__*/ jsx("span", {
9762
+ "aria-hidden": "true",
9763
+ children: "磅"
9764
+ })
9765
+ ]
9766
+ })
9767
+ ]
9768
+ }),
9769
+ /*#__PURE__*/ jsxs("div", {
9770
+ className: "work-document-font-dialog-field",
9771
+ children: [
9772
+ /*#__PURE__*/ jsx(OfficeCheckbox, {
9773
+ ariaLabel: "为字号达到以下值的字体调整字距",
9774
+ checked: draft.kerningEnabled,
9775
+ indeterminate: source.kerningThreshold.mixed && !kerningTouched,
9776
+ onCheckedChange: (kerningEnabled)=>{
9777
+ setDraft((current)=>({
9778
+ ...current,
9779
+ kerningEnabled
9780
+ }));
9781
+ setKerningTouched(true);
9782
+ },
9783
+ children: "为字号达到以下值的字体调整字距"
8469
9784
  }),
8470
- /*#__PURE__*/ jsx(ToolbarButton, {
8471
- label: "清除格式",
8472
- onClick: ()=>editor.commands.clearDocumentFormatting(),
8473
- children: /*#__PURE__*/ jsx(Eraser, {
8474
- size: 16
8475
- })
9785
+ /*#__PURE__*/ jsxs("span", {
9786
+ className: "work-document-font-dialog-measure",
9787
+ children: [
9788
+ /*#__PURE__*/ jsx(OfficeNumberField, {
9789
+ ariaLabel: "字距调整阈值(磅)",
9790
+ value: draft.kerningThresholdPoints,
9791
+ min: 0,
9792
+ max: 1638.5,
9793
+ step: 0.5,
9794
+ disabled: !draft.kerningEnabled,
9795
+ validationInvalid: Boolean(error),
9796
+ onValueChange: (kerningThresholdPoints)=>{
9797
+ setDraft((current)=>({
9798
+ ...current,
9799
+ kerningEnabled: true,
9800
+ kerningThresholdPoints
9801
+ }));
9802
+ setKerningTouched(true);
9803
+ }
9804
+ }),
9805
+ /*#__PURE__*/ jsx("span", {
9806
+ "aria-hidden": "true",
9807
+ children: "磅"
9808
+ })
9809
+ ]
8476
9810
  })
8477
9811
  ]
8478
- })
8479
- ]
8480
- })
8481
- }),
8482
- /*#__PURE__*/ jsx(RibbonGroup, {
8483
- label: "段落",
8484
- priority: "high",
8485
- children: /*#__PURE__*/ jsxs("div", {
8486
- className: "work-document-paragraph-tools",
8487
- children: [
9812
+ }),
8488
9813
  /*#__PURE__*/ jsxs("div", {
8489
- className: "work-document-paragraph-actions",
9814
+ className: "work-document-font-dialog-field",
8490
9815
  children: [
8491
- /*#__PURE__*/ jsx(DocumentListGallery, {
8492
- editor: editor
8493
- }),
8494
- /*#__PURE__*/ jsx(ToolbarButton, {
8495
- label: "减少缩进",
8496
- disabled: !canChangeDocumentIndent(editor, -1),
8497
- onClick: ()=>editor.commands.changeDocumentIndent(-1),
8498
- children: /*#__PURE__*/ jsx(IndentDecrease, {
8499
- size: 16
8500
- })
8501
- }),
8502
- /*#__PURE__*/ jsx(ToolbarButton, {
8503
- label: "增加缩进",
8504
- disabled: !canChangeDocumentIndent(editor, 1),
8505
- onClick: ()=>editor.commands.changeDocumentIndent(1),
8506
- children: /*#__PURE__*/ jsx(IndentIncrease, {
8507
- size: 16
8508
- })
9816
+ /*#__PURE__*/ jsx("span", {
9817
+ children: "位置"
8509
9818
  }),
8510
9819
  /*#__PURE__*/ jsx(OfficeSelect, {
8511
- ariaLabel: "行距",
8512
- className: "work-document-line-height-select",
8513
- value: lineHeightValue,
8514
- options: documentLineHeightOptionsForValue(lineHeightValue),
8515
- onValueChange: (value)=>editor.commands.setDocumentLineHeight('default' === value ? null : value)
9820
+ ariaLabel: "字符位置",
9821
+ value: draft.characterPositionMode,
9822
+ options: characterPositionModes,
9823
+ onValueChange: (characterPositionMode)=>{
9824
+ setDraft((current)=>({
9825
+ ...current,
9826
+ characterPositionMode
9827
+ }));
9828
+ setCharacterPositionTouched(true);
9829
+ }
8516
9830
  })
8517
9831
  ]
8518
9832
  }),
8519
9833
  /*#__PURE__*/ jsxs("div", {
8520
- className: "work-document-alignment-actions",
9834
+ className: "work-document-font-dialog-field",
8521
9835
  children: [
8522
- /*#__PURE__*/ jsx(ToolbarButton, {
8523
- label: "左对齐",
8524
- ...commandShortcut('alignLeft'),
8525
- active: editor.isActive({
8526
- textAlign: 'left'
8527
- }),
8528
- onClick: ()=>editor.chain().focus().setTextAlign('left').run(),
8529
- children: /*#__PURE__*/ jsx(AlignLeft, {
8530
- size: 16
8531
- })
8532
- }),
8533
- /*#__PURE__*/ jsx(ToolbarButton, {
8534
- label: "居中",
8535
- ...commandShortcut('alignCenter'),
8536
- active: editor.isActive({
8537
- textAlign: 'center'
8538
- }),
8539
- onClick: ()=>editor.chain().focus().setTextAlign('center').run(),
8540
- children: /*#__PURE__*/ jsx(AlignCenter, {
8541
- size: 16
8542
- })
8543
- }),
8544
- /*#__PURE__*/ jsx(ToolbarButton, {
8545
- label: "右对齐",
8546
- ...commandShortcut('alignRight'),
8547
- active: editor.isActive({
8548
- textAlign: 'right'
8549
- }),
8550
- onClick: ()=>editor.chain().focus().setTextAlign('right').run(),
8551
- children: /*#__PURE__*/ jsx(AlignRight, {
8552
- size: 16
8553
- })
8554
- }),
8555
- /*#__PURE__*/ jsx(ToolbarButton, {
8556
- label: "两端对齐",
8557
- ...commandShortcut('alignJustify'),
8558
- active: editor.isActive({
8559
- textAlign: 'justify'
8560
- }),
8561
- onClick: ()=>editor.chain().focus().setTextAlign('justify').run(),
8562
- children: /*#__PURE__*/ jsx(AlignJustify, {
8563
- size: 16
8564
- })
9836
+ /*#__PURE__*/ jsx("span", {
9837
+ children: "位置值"
8565
9838
  }),
8566
- /*#__PURE__*/ jsx(ToolbarButton, {
8567
- label: "从左向右",
8568
- active: 'ltr' === documentParagraphDirection(editor),
8569
- onClick: ()=>editor.commands.setDocumentParagraphDirection('ltr'),
8570
- children: /*#__PURE__*/ jsx(PilcrowRight, {
8571
- size: 16
8572
- })
9839
+ /*#__PURE__*/ jsxs("span", {
9840
+ className: "work-document-font-dialog-measure",
9841
+ children: [
9842
+ /*#__PURE__*/ jsx(OfficeNumberField, {
9843
+ ariaLabel: "位置值(磅)",
9844
+ value: draft.characterPositionPoints,
9845
+ min: 0.5,
9846
+ max: 1584,
9847
+ step: 0.5,
9848
+ disabled: 'mixed' === draft.characterPositionMode || 'normal' === draft.characterPositionMode,
9849
+ validationInvalid: Boolean(error),
9850
+ onValueChange: (characterPositionPoints)=>{
9851
+ setDraft((current)=>({
9852
+ ...current,
9853
+ characterPositionPoints
9854
+ }));
9855
+ setCharacterPositionTouched(true);
9856
+ }
9857
+ }),
9858
+ /*#__PURE__*/ jsx("span", {
9859
+ "aria-hidden": "true",
9860
+ children: "磅"
9861
+ })
9862
+ ]
9863
+ })
9864
+ ]
9865
+ }),
9866
+ /*#__PURE__*/ jsxs("div", {
9867
+ className: "work-document-font-dialog-field",
9868
+ children: [
9869
+ /*#__PURE__*/ jsx("span", {
9870
+ children: "着重号"
8573
9871
  }),
8574
- /*#__PURE__*/ jsx(ToolbarButton, {
8575
- label: "从右向左",
8576
- active: 'rtl' === documentParagraphDirection(editor),
8577
- onClick: ()=>editor.commands.setDocumentParagraphDirection('rtl'),
8578
- children: /*#__PURE__*/ jsx(PilcrowLeft, {
8579
- size: 16
8580
- })
9872
+ /*#__PURE__*/ jsx(OfficeSelect, {
9873
+ ariaLabel: "着重号",
9874
+ value: draft.emphasisMark,
9875
+ options: emphasisMarkModes,
9876
+ onValueChange: (emphasisMark)=>{
9877
+ setDraft((current)=>({
9878
+ ...current,
9879
+ emphasisMark
9880
+ }));
9881
+ setEmphasisTouched(true);
9882
+ }
8581
9883
  })
8582
9884
  ]
9885
+ }),
9886
+ /*#__PURE__*/ jsx("div", {
9887
+ className: "work-document-font-dialog-field work-document-font-dialog-hidden-text",
9888
+ children: /*#__PURE__*/ jsx(OfficeCheckbox, {
9889
+ ariaLabel: "隐藏文字",
9890
+ checked: draft.hiddenText,
9891
+ indeterminate: source.hiddenText.mixed && !hiddenTextTouched,
9892
+ onCheckedChange: (hiddenText)=>{
9893
+ setDraft((current)=>({
9894
+ ...current,
9895
+ hiddenText
9896
+ }));
9897
+ setHiddenTextTouched(true);
9898
+ },
9899
+ children: "隐藏文字"
9900
+ })
9901
+ }),
9902
+ source.characterScale.mixed && !characterScaleTouched && /*#__PURE__*/ jsx("p", {
9903
+ className: "work-document-font-dialog-mixed",
9904
+ role: "status",
9905
+ children: "当前选区包含多种字符缩放比例。输入缩放比例后才会统一修改。"
9906
+ }),
9907
+ source.characterSpacing.mixed && !characterSpacingTouched && /*#__PURE__*/ jsx("p", {
9908
+ className: "work-document-font-dialog-mixed",
9909
+ role: "status",
9910
+ children: "当前选区包含多种字符间距。选择一种间距后才会统一修改。"
9911
+ }),
9912
+ source.characterPosition.mixed && !characterPositionTouched && /*#__PURE__*/ jsx("p", {
9913
+ className: "work-document-font-dialog-mixed",
9914
+ role: "status",
9915
+ children: "当前选区包含多种字符位置。选择一种位置后才会统一修改。"
9916
+ }),
9917
+ source.kerningThreshold.mixed && !kerningTouched && /*#__PURE__*/ jsx("p", {
9918
+ className: "work-document-font-dialog-mixed",
9919
+ role: "status",
9920
+ children: "当前选区包含不同的字距调整设置。勾选或取消后才会统一修改。"
9921
+ }),
9922
+ source.emphasisMark.mixed && !emphasisTouched && /*#__PURE__*/ jsx("p", {
9923
+ className: "work-document-font-dialog-mixed",
9924
+ role: "status",
9925
+ children: "当前选区包含不同的着重号。选择一种设置后才会统一修改。"
9926
+ }),
9927
+ source.hiddenText.mixed && !hiddenTextTouched && /*#__PURE__*/ jsx("p", {
9928
+ className: "work-document-font-dialog-mixed",
9929
+ role: "status",
9930
+ children: "当前选区同时包含隐藏和可见文字。勾选或取消后才会统一修改。"
9931
+ }),
9932
+ (characterScaleTouched || characterSpacingTouched || characterPositionTouched || kerningTouched || emphasisTouched || hiddenTextTouched) && error && /*#__PURE__*/ jsx("p", {
9933
+ className: "work-document-font-dialog-error",
9934
+ role: "alert",
9935
+ children: error
8583
9936
  })
8584
9937
  ]
8585
- })
8586
- }),
8587
- /*#__PURE__*/ jsx(RibbonGroup, {
8588
- label: "样式",
8589
- priority: "low",
8590
- children: /*#__PURE__*/ jsx(DocumentStyleGallery, {
8591
- editor: editor
8592
- })
8593
- }),
8594
- /*#__PURE__*/ jsxs(RibbonGroup, {
8595
- label: "编辑",
8596
- priority: "low",
8597
- children: [
8598
- /*#__PURE__*/ jsx(ToolbarButton, {
8599
- label: "查找",
8600
- ...commandShortcut('find'),
8601
- active: 'find' === findReplaceMode,
8602
- onClick: ()=>onFindText(false),
8603
- children: /*#__PURE__*/ jsx(Search, {
8604
- size: 16
8605
- })
8606
- }),
8607
- /*#__PURE__*/ jsx(ToolbarButton, {
8608
- label: "替换",
8609
- ...commandShortcut('replace'),
8610
- active: 'replace' === findReplaceMode,
8611
- onClick: ()=>onFindText(true),
8612
- children: /*#__PURE__*/ jsx(Replace, {
8613
- size: 16
9938
+ }),
9939
+ /*#__PURE__*/ jsxs("section", {
9940
+ className: "work-document-font-dialog-preview",
9941
+ "aria-label": "字符高级格式预览",
9942
+ children: [
9943
+ /*#__PURE__*/ jsx("span", {
9944
+ children: "预览"
9945
+ }),
9946
+ /*#__PURE__*/ jsx("output", {
9947
+ style: {
9948
+ fontFamily: source.fontFamily ?? void 0,
9949
+ fontSize: source.fontSize ?? void 0,
9950
+ fontStretch: `${previewScale}%`,
9951
+ fontKerning: previewKerning,
9952
+ letterSpacing: `${previewSpacing}pt`
9953
+ },
9954
+ children: /*#__PURE__*/ jsx("span", {
9955
+ style: {
9956
+ verticalAlign: `${previewPosition}pt`,
9957
+ ...previewEmphasis,
9958
+ ...draft.hiddenText ? {
9959
+ textDecorationColor: 'currentColor',
9960
+ textDecorationLine: 'underline',
9961
+ textDecorationStyle: 'dotted',
9962
+ textUnderlineOffset: '0.18em'
9963
+ } : {}
9964
+ },
9965
+ children: documentScriptFontSegments(source.previewText).map(({ from, to, slot })=>/*#__PURE__*/ jsx("span", {
9966
+ style: {
9967
+ fontFamily: previewScriptFontFamily('eastAsia' === slot ? draft.eastAsiaFont : 'complexScript' === slot ? draft.complexScriptFont : draft.latinFont, source.fontFamily)
9968
+ },
9969
+ children: source.previewText.slice(from, to)
9970
+ }, `${from}-${slot}`))
9971
+ })
8614
9972
  })
8615
- })
8616
- ]
8617
- })
8618
- ]
8619
- });
8620
- }
8621
- function ToolbarButton({ label, shortcut, ariaKeyShortcuts, active = false, disabled = false, onClick, children }) {
8622
- return /*#__PURE__*/ jsx(WorkOfficeRibbonButton, {
8623
- label: label,
8624
- title: shortcut ? `${label}(${shortcut})` : label,
8625
- "aria-keyshortcuts": ariaKeyShortcuts,
8626
- active: active,
8627
- displayLabel: false,
8628
- disabled: disabled,
8629
- onClick: onClick,
8630
- children: children
9973
+ ]
9974
+ })
9975
+ ]
9976
+ })
8631
9977
  });
8632
9978
  }
8633
- function commandShortcut(commandId) {
8634
- const shortcut = getDocumentCommandDefinition(commandId).shortcut;
8635
- return shortcut ? {
8636
- shortcut: shortcut.label,
8637
- ariaKeyShortcuts: shortcut.aria
8638
- } : {};
8639
- }
8640
- const RibbonGroup = WorkOfficeRibbonGroup;
8641
- function documentLineHeightValue(editor) {
8642
- const attributes = editor.isActive('heading') ? editor.getAttributes('heading') : editor.getAttributes('paragraph');
8643
- const value = attributes.lineHeight;
8644
- if ('string' != typeof value || !value.trim() || 'normal' === value) return 'default';
8645
- return value.trim();
9979
+ function previewCharacterScale(draft) {
9980
+ if ('mixed' === draft.characterScaleMode) return 100;
9981
+ const percent = Number(draft.characterScalePercent);
9982
+ return Number.isFinite(percent) ? percent : 100;
9983
+ }
9984
+ function previewCharacterPosition(draft) {
9985
+ if ('mixed' === draft.characterPositionMode || 'normal' === draft.characterPositionMode) return 0;
9986
+ const points = Number(draft.characterPositionPoints);
9987
+ if (!Number.isFinite(points)) return 0;
9988
+ return 'lowered' === draft.characterPositionMode ? -points : points;
9989
+ }
9990
+ function previewCharacterSpacing(draft) {
9991
+ if ('mixed' === draft.characterSpacingMode || 'normal' === draft.characterSpacingMode) return 0;
9992
+ const points = Number(draft.characterSpacingPoints);
9993
+ if (!Number.isFinite(points)) return 0;
9994
+ return 'condensed' === draft.characterSpacingMode ? -points : points;
9995
+ }
9996
+ function previewDocumentKerning(draft, fontSize) {
9997
+ if (!draft.kerningEnabled) return 'none';
9998
+ const points = Number(draft.kerningThresholdPoints);
9999
+ if (!Number.isFinite(points)) return 'none';
10000
+ return documentKerningIsEffective(2 * points, fontSize) ? 'normal' : 'none';
10001
+ }
10002
+ function previewDocumentEmphasis(emphasisMark) {
10003
+ if ('inherit' === emphasisMark || 'mixed' === emphasisMark || 'none' === emphasisMark) return {
10004
+ textEmphasisStyle: 'none',
10005
+ WebkitTextEmphasisStyle: 'none'
10006
+ };
10007
+ const style = 'comma' === emphasisMark ? '","' : 'circle' === emphasisMark ? 'open circle' : 'filled dot';
10008
+ const position = 'underDot' === emphasisMark ? 'under right' : 'over right';
10009
+ return {
10010
+ textEmphasisStyle: style,
10011
+ textEmphasisPosition: position,
10012
+ WebkitTextEmphasisStyle: style,
10013
+ WebkitTextEmphasisPosition: position
10014
+ };
8646
10015
  }
8647
- function documentLineHeightOptionsForValue(value) {
8648
- if (documentLineHeightOptions.some((option)=>option.value === value)) return documentLineHeightOptions;
8649
- const numeric = Number(value);
10016
+ function scriptFontOptions(value, layoutFonts) {
10017
+ const catalogValue = 'mixed' === value || 'inherit' === value ? 'default' : value;
8650
10018
  return [
8651
- ...documentLineHeightOptions,
8652
10019
  {
8653
- value,
8654
- label: Number.isFinite(numeric) && numeric > 0 ? `${numeric} 倍` : value
8655
- }
10020
+ value: 'mixed',
10021
+ label: '混合(保持不变)',
10022
+ disabled: true
10023
+ },
10024
+ {
10025
+ value: 'inherit',
10026
+ label: '跟随样式'
10027
+ },
10028
+ ...documentFontFamilyOptionsForValue(catalogValue, layoutFonts).filter((option)=>'default' !== option.value)
8656
10029
  ];
8657
10030
  }
8658
- function DocumentPageChromeRibbon({ editor, editingPart, showPageNumber, onEditingPartChange, onTogglePageNumber, onClose }) {
10031
+ function previewScriptFontFamily(value, fallback) {
10032
+ return 'mixed' === value || 'inherit' === value ? fallback ?? void 0 : value;
10033
+ }
10034
+ function fontDialogDescription(source) {
10035
+ return source.selectedCharacters ? `分别设置当前选中内容的拉丁、东亚和复杂文字字体,以及原生字符缩放、间距、字距调整阈值、位置、着重号和隐藏文字(${source.selectedCharacters} 个字符)。` : '分别设置当前位置后续输入文字的拉丁、东亚和复杂文字字体,以及原生字符缩放、间距、字距调整阈值、位置、着重号和隐藏文字。';
10036
+ }
10037
+ function DocumentPageChromeRibbon({ editor, editingPart, showPageNumber, onEditingPartChange, onTogglePageNumber, onOpenFontDialog, onClose }) {
8659
10038
  const imageInputRef = useRef(null);
8660
10039
  const [, setRevision] = useState(0);
8661
10040
  const officeDialog = useOfficeDialog();
@@ -8750,6 +10129,11 @@ function DocumentPageChromeRibbon({ editor, editingPart, showPageNumber, onEditi
8750
10129
  }),
8751
10130
  /*#__PURE__*/ jsxs(WorkOfficeRibbonGroup, {
8752
10131
  label: "文字",
10132
+ dialogLauncher: onOpenFontDialog ? {
10133
+ label: '页眉页脚字体高级设置',
10134
+ ...pageChromeCommandShortcut('fontDialog'),
10135
+ onClick: onOpenFontDialog
10136
+ } : void 0,
8753
10137
  children: [
8754
10138
  /*#__PURE__*/ jsx(PageChromeRibbonButton, {
8755
10139
  label: "页眉页脚加粗",
@@ -8771,15 +10155,18 @@ function DocumentPageChromeRibbon({ editor, editingPart, showPageNumber, onEditi
8771
10155
  size: 16
8772
10156
  })
8773
10157
  }),
8774
- /*#__PURE__*/ jsx(PageChromeRibbonButton, {
10158
+ /*#__PURE__*/ jsx(DocumentUnderlineRibbon, {
10159
+ editor: editor,
8775
10160
  label: "页眉页脚下划线",
8776
- shortcut: "Cmd/Ctrl+U",
8777
- ariaKeyShortcuts: "Control+U Meta+U",
8778
- active: state.underline,
8779
- onClick: ()=>editor.chain().focus().toggleUnderline().run(),
8780
- children: /*#__PURE__*/ jsx(Underline, {
8781
- size: 16
8782
- })
10161
+ menuLabel: "页眉页脚下划线样式",
10162
+ colorLabel: "页眉页脚下划线颜色",
10163
+ className: "work-document-page-chrome-underline"
10164
+ }),
10165
+ /*#__PURE__*/ jsx(DocumentStrikeRibbon, {
10166
+ editor: editor,
10167
+ label: "页眉页脚删除线",
10168
+ menuLabel: "页眉页脚删除线样式",
10169
+ className: "work-document-page-chrome-strike"
8783
10170
  }),
8784
10171
  /*#__PURE__*/ jsx(PageChromeRibbonButton, {
8785
10172
  label: "页眉页脚下标",
@@ -12129,6 +13516,26 @@ function runDocumentWpsShortcut(editor, event, callbacks) {
12129
13516
  return false;
12130
13517
  }
12131
13518
  if (event.shiftKey) {
13519
+ if ('h' === key) {
13520
+ editor.commands.toggleDocumentHiddenText();
13521
+ return true;
13522
+ }
13523
+ if ('d' === key) {
13524
+ editor.commands.toggleDocumentUnderlineStyle('double');
13525
+ return true;
13526
+ }
13527
+ if ('w' === key) {
13528
+ editor.commands.toggleDocumentUnderlineStyle('words');
13529
+ return true;
13530
+ }
13531
+ if ('a' === key) {
13532
+ editor.commands.toggleDocumentTextCase('all-caps');
13533
+ return true;
13534
+ }
13535
+ if ('k' === key) {
13536
+ editor.commands.toggleDocumentTextCase('small-caps');
13537
+ return true;
13538
+ }
12132
13539
  if ('g' === key) {
12133
13540
  callbacks.onOpenWordCount();
12134
13541
  return true;
@@ -12163,6 +13570,10 @@ function runDocumentWpsShortcut(editor, event, callbacks) {
12163
13570
  changeDocumentFontSize(editor, -1);
12164
13571
  return true;
12165
13572
  }
13573
+ if ('d' === key) {
13574
+ callbacks.onOpenFontDialog();
13575
+ return true;
13576
+ }
12166
13577
  const alignment = alignmentForShortcut(key);
12167
13578
  if (alignment) {
12168
13579
  editor.chain().focus().setTextAlign(alignment).run();
@@ -12195,8 +13606,9 @@ function headingLevelForShortcut(code, key) {
12195
13606
  if ('3' === value) return 3;
12196
13607
  return null;
12197
13608
  }
12198
- 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 }) {
13609
+ function DocumentToolbar({ editor, defaultRibbonCollapsed = false, reviewOnly = false, suggestionOnly = false, history, layoutOpen, layout, layoutFonts = [], navigationOpen, pageColor, showPageNumbers, showHiddenText, showRulers, spellcheckEnabled, viewMode, zoom, pageChromeEditor, pageChromeEditingPart, pageChromeShowPageNumber, onRequestImage, onPageChromeEditingPartChange, onClosePageChrome, onTogglePageChromePageNumber, onToggleLayout, onLayoutChange, onOpenLayout, onToggleNavigation, onTogglePageNumbers, onToggleHiddenText, 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 }) {
12199
13610
  const [activeTab, setActiveTab] = useState(reviewOnly ? 'review' : 'home');
13611
+ const [fontDialogRequest, setFontDialogRequest] = useState(null);
12200
13612
  const officeDialog = useOfficeDialog();
12201
13613
  const prompt = officeDialog.prompt;
12202
13614
  const imageSelected = editor.isActive('image');
@@ -12213,6 +13625,18 @@ function DocumentToolbar({ editor, defaultRibbonCollapsed = false, reviewOnly =
12213
13625
  const spellingCommand = getDocumentCommandDefinition('spelling');
12214
13626
  const insertCommentCommand = getDocumentCommandDefinition('insertComment');
12215
13627
  const trackChangesCommand = getDocumentCommandDefinition('trackChanges');
13628
+ const openFontDialog = useCallback((target)=>{
13629
+ if (target.isDestroyed) return;
13630
+ const { from, to } = target.state.selection;
13631
+ setFontDialogRequest({
13632
+ editor: target,
13633
+ selection: {
13634
+ from,
13635
+ to
13636
+ },
13637
+ source: documentFontDialogSource(target)
13638
+ });
13639
+ }, []);
12216
13640
  const ribbonTabs = reviewOnly ? documentRibbonTabs.filter(({ id })=>'review' === id || 'view' === id) : pageChromeEditor ? [
12217
13641
  ...documentRibbonTabs,
12218
13642
  documentPageChromeRibbonTab
@@ -12287,6 +13711,7 @@ function DocumentToolbar({ editor, defaultRibbonCollapsed = false, reviewOnly =
12287
13711
  if (event.defaultPrevented || event.repeat || isOfficeShortcutBlocked(event.target)) return;
12288
13712
  const key = event.key.toLowerCase();
12289
13713
  const insideEditor = event.target instanceof Node && Boolean(editorDom?.contains(event.target));
13714
+ const insidePageChromeEditor = event.target instanceof Node && Boolean(pageChromeEditor?.view.dom.contains(event.target));
12290
13715
  if (reviewOnly) {
12291
13716
  if (insideEditor && (event.metaKey || event.ctrlKey) && event.altKey && !event.shiftKey && 'm' === key) {
12292
13717
  event.preventDefault();
@@ -12294,10 +13719,16 @@ function DocumentToolbar({ editor, defaultRibbonCollapsed = false, reviewOnly =
12294
13719
  }
12295
13720
  return;
12296
13721
  }
13722
+ if (insidePageChromeEditor && (event.metaKey || event.ctrlKey) && !event.altKey && !event.shiftKey && 'd' === key) {
13723
+ event.preventDefault();
13724
+ openFontDialog(pageChromeEditor);
13725
+ return;
13726
+ }
12297
13727
  if (insideEditor && runDocumentWpsShortcut(editor, event, {
12298
13728
  canInsertComment,
12299
13729
  canRefreshFields: hasRefreshableFields,
12300
13730
  onInsertComment,
13731
+ onOpenFontDialog: ()=>openFontDialog(editor),
12301
13732
  onOpenWordCount,
12302
13733
  onRefreshFields,
12303
13734
  onToggleSpellcheck,
@@ -12371,12 +13802,14 @@ function DocumentToolbar({ editor, defaultRibbonCollapsed = false, reviewOnly =
12371
13802
  hasRefreshableFields,
12372
13803
  history,
12373
13804
  onInsertComment,
13805
+ openFontDialog,
12374
13806
  onOpenFindReplace,
12375
13807
  onOpenWordCount,
12376
13808
  onRefreshFields,
12377
13809
  reviewOnly,
12378
13810
  onToggleSpellcheck,
12379
13811
  onToggleTrackChanges,
13812
+ pageChromeEditor,
12380
13813
  toggleLink
12381
13814
  ]);
12382
13815
  const selectDocumentChange = (change)=>{
@@ -12462,6 +13895,7 @@ function DocumentToolbar({ editor, defaultRibbonCollapsed = false, reviewOnly =
12462
13895
  editor: editor,
12463
13896
  findReplaceMode: findReplaceMode,
12464
13897
  layoutFonts: layoutFonts,
13898
+ onOpenFontDialog: ()=>openFontDialog(editor),
12465
13899
  onFindText: (replace)=>onOpenFindReplace(replace ? 'replace' : 'find')
12466
13900
  }),
12467
13901
  insert: reviewOnly ? null : /*#__PURE__*/ jsxs(Fragment, {
@@ -12833,6 +14267,16 @@ function DocumentToolbar({ editor, defaultRibbonCollapsed = false, reviewOnly =
12833
14267
  children: /*#__PURE__*/ jsx(PanelLeftOpen, {
12834
14268
  size: 19
12835
14269
  })
14270
+ }),
14271
+ /*#__PURE__*/ jsx(document_toolbar_ToolbarButton, {
14272
+ label: "显示隐藏文字",
14273
+ displayLabel: true,
14274
+ active: showHiddenText,
14275
+ title: "显示或隐藏以隐藏文字格式标记的内容",
14276
+ onClick: onToggleHiddenText,
14277
+ children: /*#__PURE__*/ jsx(Eye, {
14278
+ size: 19
14279
+ })
12836
14280
  })
12837
14281
  ]
12838
14282
  }),
@@ -12897,10 +14341,27 @@ function DocumentToolbar({ editor, defaultRibbonCollapsed = false, reviewOnly =
12897
14341
  showPageNumber: pageChromeShowPageNumber,
12898
14342
  onEditingPartChange: onPageChromeEditingPartChange,
12899
14343
  onTogglePageNumber: onTogglePageChromePageNumber,
14344
+ onOpenFontDialog: ()=>openFontDialog(pageChromeEditor),
12900
14345
  onClose: onClosePageChrome
12901
14346
  }) : null
12902
14347
  }
12903
14348
  }),
14349
+ fontDialogRequest && /*#__PURE__*/ jsx(DocumentFontDialog, {
14350
+ source: fontDialogRequest.source,
14351
+ layoutFonts: layoutFonts,
14352
+ restoreFocusTarget: ()=>fontDialogRequest.editor.isDestroyed ? null : fontDialogRequest.editor.view.dom,
14353
+ onApply: (patch)=>applyDocumentFontDialogPatch(fontDialogRequest.editor, fontDialogRequest.selection, patch),
14354
+ onClose: ()=>{
14355
+ const { editor: dialogEditor, selection } = fontDialogRequest;
14356
+ setFontDialogRequest(null);
14357
+ requestAnimationFrame(()=>{
14358
+ if (dialogEditor.isDestroyed) return;
14359
+ dialogEditor.chain().setTextSelection(selection).focus(null, {
14360
+ scrollIntoView: false
14361
+ }).run();
14362
+ });
14363
+ }
14364
+ }),
12904
14365
  officeDialog.dialog
12905
14366
  ]
12906
14367
  });
@@ -14917,6 +16378,7 @@ function DocumentEditorSurface({ artifactId, autoFocus = true, collaboration, co
14917
16378
  const findReplaceMode = 'find' === taskPane || 'replace' === taskPane ? taskPane : null;
14918
16379
  const [spellcheckEnabled, setSpellcheckEnabled] = useState(true);
14919
16380
  const [viewMode, setViewMode] = useState('page');
16381
+ const [showHiddenText, setShowHiddenText] = useState(false);
14920
16382
  const [showRulers, setShowRulers] = useState(false);
14921
16383
  const [zoom, setZoom] = useState(90);
14922
16384
  const [selectionMenu, setSelectionMenu] = useState(null);
@@ -15017,7 +16479,6 @@ function DocumentEditorSurface({ artifactId, autoFocus = true, collaboration, co
15017
16479
  model,
15018
16480
  comments: retainAnchoredDocumentComments(previousContent.comments ?? [], anchors, retainedCommentIds)
15019
16481
  };
15020
- appliedSourceKeyRef.current = `model:${model.revision}:${model.htmlFingerprint}`;
15021
16482
  if (!collaborationBindingRef.current) {
15022
16483
  contentRef.current = next;
15023
16484
  onChangeRef.current(next);
@@ -15633,7 +17094,7 @@ function DocumentEditorSurface({ artifactId, autoFocus = true, collaboration, co
15633
17094
  return true;
15634
17095
  };
15635
17096
  return /*#__PURE__*/ jsxs("section", {
15636
- className: `work-document-editor${preview ? ' preview' : ''}`,
17097
+ className: `work-document-editor${preview ? ' preview' : ''}${!preview && showHiddenText ? ' show-hidden-text' : ''}`,
15637
17098
  "data-collaboration-mode": collaboration?.mode,
15638
17099
  "data-work-pdf-artifact": artifactId,
15639
17100
  "data-work-pdf-surface": artifactId ? 'live' : void 0,
@@ -15668,6 +17129,7 @@ function DocumentEditorSurface({ artifactId, autoFocus = true, collaboration, co
15668
17129
  navigationOpen: navigationOpen,
15669
17130
  pageColor: documentPageColor(currentContent.pageColor),
15670
17131
  showPageNumbers: visibleChrome.showPageNumber,
17132
+ showHiddenText: showHiddenText,
15671
17133
  showRulers: showRulers,
15672
17134
  spellcheckEnabled: spellcheckEnabled,
15673
17135
  viewMode: viewMode,
@@ -15683,6 +17145,10 @@ function DocumentEditorSurface({ artifactId, autoFocus = true, collaboration, co
15683
17145
  onLayoutChange: updateToolbarLayout,
15684
17146
  onOpenLayout: openLayoutPanel,
15685
17147
  onToggleNavigation: ()=>void toggleTaskPane('navigation'),
17148
+ onToggleHiddenText: ()=>{
17149
+ setShowHiddenText((value)=>!value);
17150
+ restoreDocumentBodyFocus();
17151
+ },
15686
17152
  onToggleRulers: ()=>{
15687
17153
  setShowRulers((value)=>!value);
15688
17154
  restoreDocumentBodyFocus();