@a3s-lab/office 0.26.0 → 0.28.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 (87) hide show
  1. package/README.md +89 -2
  2. package/dist/0~4595.js +16 -2
  3. package/dist/0~5093.js +563 -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 +2633 -976
  7. package/dist/0~spreadsheet-editor.js +1324 -378
  8. package/dist/0~work-docx-export.js +737 -17
  9. package/dist/0~work-docx-import.js +173 -98
  10. package/dist/0~work-office-diagnostics.js +250 -5
  11. package/dist/{164.js → 1544.js} +1083 -785
  12. package/dist/4104.js +145 -29
  13. package/dist/5184.js +13 -0
  14. package/dist/6282.js +1898 -345
  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 +111 -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-format-cells-dialog-model.d.ts +13 -2
  32. package/dist/internal/features/work/editors/spreadsheet-format-cells-fill-panel.d.ts +13 -0
  33. package/dist/internal/features/work/editors/spreadsheet-format-cells-fill-preview.d.ts +6 -0
  34. package/dist/internal/features/work/editors/spreadsheet-format-painter.d.ts +1 -1
  35. package/dist/internal/features/work/editors/work-office-chrome.d.ts +9 -1
  36. package/dist/internal/features/work/work-document-character-formatting.d.ts +16 -1
  37. package/dist/internal/features/work/work-document-character-position.d.ts +9 -0
  38. package/dist/internal/features/work/work-document-character-scale.d.ts +8 -0
  39. package/dist/internal/features/work/work-document-character-spacing.d.ts +8 -0
  40. package/dist/internal/features/work/work-document-emphasis.d.ts +7 -0
  41. package/dist/internal/features/work/work-document-equations.d.ts +2 -1
  42. package/dist/internal/features/work/work-document-format-changes.d.ts +20 -2
  43. package/dist/internal/features/work/work-document-hidden-text.d.ts +5 -0
  44. package/dist/internal/features/work/work-document-kerning.d.ts +10 -0
  45. package/dist/internal/features/work/work-document-legacy-text-effects.d.ts +27 -0
  46. package/dist/internal/features/work/work-document-script-font-extension.d.ts +2 -0
  47. package/dist/internal/features/work/work-document-script-fonts.d.ts +51 -0
  48. package/dist/internal/features/work/work-document-strike.d.ts +21 -0
  49. package/dist/internal/features/work/work-document-text-case.d.ts +10 -0
  50. package/dist/internal/features/work/work-document-underline.d.ts +37 -0
  51. package/dist/internal/features/work/work-document-word-line-metrics.d.ts +16 -0
  52. package/dist/internal/features/work/work-docx-character-position.d.ts +2 -0
  53. package/dist/internal/features/work/work-docx-character-scale.d.ts +2 -0
  54. package/dist/internal/features/work/work-docx-character-spacing.d.ts +4 -0
  55. package/dist/internal/features/work/work-docx-emphasis-diagnostics.d.ts +3 -0
  56. package/dist/internal/features/work/work-docx-emphasis.d.ts +14 -0
  57. package/dist/internal/features/work/work-docx-hidden-text-diagnostics.d.ts +3 -0
  58. package/dist/internal/features/work/work-docx-hidden-text-export.d.ts +17 -0
  59. package/dist/internal/features/work/work-docx-hidden-text.d.ts +11 -0
  60. package/dist/internal/features/work/work-docx-kerning-diagnostics.d.ts +3 -0
  61. package/dist/internal/features/work/work-docx-kerning.d.ts +14 -0
  62. package/dist/internal/features/work/work-docx-legacy-text-effects-diagnostics.d.ts +3 -0
  63. package/dist/internal/features/work/work-docx-legacy-text-effects-export.d.ts +18 -0
  64. package/dist/internal/features/work/work-docx-legacy-text-effects.d.ts +12 -0
  65. package/dist/internal/features/work/work-docx-run-fonts-diagnostics.d.ts +3 -0
  66. package/dist/internal/features/work/work-docx-run-fonts-export.d.ts +14 -0
  67. package/dist/internal/features/work/work-docx-run-fonts.d.ts +13 -0
  68. package/dist/internal/features/work/work-docx-run-formatting-import.d.ts +27 -2
  69. package/dist/internal/features/work/work-docx-run-property-order.d.ts +2 -0
  70. package/dist/internal/features/work/work-docx-run-script-font-import.d.ts +9 -0
  71. package/dist/internal/features/work/work-docx-strike.d.ts +8 -0
  72. package/dist/internal/features/work/work-docx-theme-reference.d.ts +1 -1
  73. package/dist/internal/features/work/work-docx-twips.d.ts +6 -0
  74. package/dist/internal/features/work/work-docx-underline.d.ts +3 -0
  75. package/dist/internal/features/work/work-spreadsheet-gradient-fill-canvas.d.ts +10 -0
  76. package/dist/internal/features/work/work-spreadsheet-native-fill-canvas.d.ts +8 -0
  77. package/dist/internal/features/work/work-spreadsheet-pattern-fill-canvas.d.ts +8 -0
  78. package/dist/internal/features/work/work-xlsx-cell-style-origin.d.ts +2 -1
  79. package/dist/internal/features/work/work-xlsx-cell-style-writer.d.ts +3 -0
  80. package/dist/internal/features/work/work-xlsx-cell-styles.d.ts +4 -0
  81. package/dist/internal/features/work/work-xlsx-gradient-fill.d.ts +31 -0
  82. package/dist/internal/features/work/work-xlsx-native-fill.d.ts +17 -0
  83. package/dist/internal/features/work/work-xlsx-pattern-fill.d.ts +21 -0
  84. package/dist/office-kernel.wasm +0 -0
  85. package/dist/styles.css +809 -78
  86. package/docs/latest/en/browser-editor-architecture.md +24 -0
  87. package/package.json +35 -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, documentLegacyTextEffectsConflict, 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, documentLegacyTextEffectsCss, documentScriptFontSlotFromHint, editorDocumentCaptionTargets, resolveDocumentPageChrome, documentScriptFontFamilyForRendering, documentImageLayoutOptions, MAX_DOCUMENT_NUMBERING_START, resolveDocumentPageSize, editorDocumentBookmarkReferenceTargets, serializeWorkDocumentNode, DOCUMENT_CHUNK_PAGINATION_META, createOfficeDocumentCollaborationBinding as createWorkOfficeDocumentCollaborationBinding, documentModelForContent, documentLegacyTextEffectsFromTextStyleAttributes, 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, normalizeDocumentLegacyTextEffect, 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,1673 @@ 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;
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;
9226
+ }
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 legacyTextOutlineValues = new Map();
9255
+ const legacyTextShadowValues = new Map();
9256
+ const legacyTextEmbossValues = new Map();
9257
+ const legacyTextImprintValues = new Map();
9258
+ const latinFontValues = new Map();
9259
+ const eastAsiaFontValues = new Map();
9260
+ const complexScriptFontValues = new Map();
9261
+ const addValues = (attributes)=>{
9262
+ addScaleValue(scaleValues, attributes.characterScalePercent);
9263
+ addPositionValue(positionValues, attributes.characterPositionHalfPoints);
9264
+ addSpacingValue(spacingValues, attributes.characterSpacingTwips);
9265
+ addKerningValue(kerningValues, attributes.kerningThresholdHalfPoints);
9266
+ addEmphasisValue(emphasisValues, attributes.emphasisMark);
9267
+ addHiddenTextValue(hiddenTextValues, attributes.hiddenText);
9268
+ addLegacyTextEffectValue(legacyTextOutlineValues, attributes.legacyTextOutline);
9269
+ addLegacyTextEffectValue(legacyTextShadowValues, attributes.legacyTextShadow);
9270
+ addLegacyTextEffectValue(legacyTextEmbossValues, attributes.legacyTextEmboss);
9271
+ addLegacyTextEffectValue(legacyTextImprintValues, attributes.legacyTextImprint);
9272
+ addDocumentScriptFontValues(latinFontValues, eastAsiaFontValues, complexScriptFontValues, attributes);
9273
+ };
9274
+ if (selection.empty) addValues(editor.getAttributes('textStyle'));
9275
+ else doc.nodesBetween(selection.from, selection.to, (node, position)=>{
9276
+ if (!node.isText || position >= selection.to || position + node.nodeSize <= selection.from) return;
9277
+ const textStyle = node.marks.find((mark)=>'textStyle' === mark.type.name);
9278
+ addValues(textStyle?.attrs ?? {});
9279
+ });
9280
+ if (!scaleValues.size || !spacingValues.size || !positionValues.size || !kerningValues.size || !emphasisValues.size || !hiddenTextValues.size || !legacyTextOutlineValues.size || !legacyTextShadowValues.size || !legacyTextEmbossValues.size || !legacyTextImprintValues.size || !latinFontValues.size || !eastAsiaFontValues.size || !complexScriptFontValues.size) addValues(editor.getAttributes('textStyle'));
9281
+ const characterScale = selectedValue(scaleValues);
9282
+ const characterPosition = selectedValue(positionValues);
9283
+ const characterSpacing = selectedValue(spacingValues);
9284
+ const kerningThreshold = selectedValue(kerningValues);
9285
+ const emphasisMark = selectedValue(emphasisValues);
9286
+ const hiddenText = selectedValue(hiddenTextValues);
9287
+ const legacyTextOutline = selectedValue(legacyTextOutlineValues);
9288
+ const legacyTextShadow = selectedValue(legacyTextShadowValues);
9289
+ const legacyTextEmboss = selectedValue(legacyTextEmbossValues);
9290
+ const legacyTextImprint = selectedValue(legacyTextImprintValues);
9291
+ const latinFont = selectedValue(latinFontValues);
9292
+ const eastAsiaFont = selectedValue(eastAsiaFontValues);
9293
+ const complexScriptFont = selectedValue(complexScriptFontValues);
9294
+ const textStyle = editor.getAttributes('textStyle');
9295
+ const selectedText = selection.empty ? '' : doc.textBetween(selection.from, selection.to, ' ', ' ').replace(/\s+/g, ' ').trim();
9296
+ return {
9297
+ characterScale,
9298
+ characterPosition,
9299
+ characterSpacing,
9300
+ kerningThreshold,
9301
+ emphasisMark,
9302
+ hiddenText,
9303
+ legacyTextOutline,
9304
+ legacyTextShadow,
9305
+ legacyTextEmboss,
9306
+ legacyTextImprint,
9307
+ latinFont,
9308
+ eastAsiaFont,
9309
+ complexScriptFont,
9310
+ fontFamily: 'string' == typeof textStyle.fontFamily && textStyle.fontFamily.trim() ? textStyle.fontFamily : null,
9311
+ fontSize: 'string' == typeof textStyle.fontSize && textStyle.fontSize.trim() ? textStyle.fontSize : null,
9312
+ previewText: selectedText.slice(0, 72) || 'A3S Office 字符格式',
9313
+ selectedCharacters: selectedText.length
9314
+ };
8185
9315
  }
8186
- function documentListSnapshot(editor) {
8187
- const bullet = documentBulletListStyle(editor);
8188
- const ordered = documentOrderedListState(editor);
8189
- return `${bullet ?? ''}:${ordered?.style ?? ''}:${ordered?.start ?? ''}`;
9316
+ function createDocumentFontDialogDraft(source) {
9317
+ const scale = source.characterScale.value;
9318
+ const spacing = source.characterSpacing.value;
9319
+ const spacingPoints = Math.abs(documentCharacterSpacingPoints(spacing) ?? 1);
9320
+ const position = source.characterPosition.value;
9321
+ const positionPoints = Math.abs(documentCharacterPositionPoints(position) ?? 1);
9322
+ const kerningThreshold = source.kerningThreshold.value;
9323
+ return {
9324
+ characterScaleMode: source.characterScale.mixed ? 'mixed' : 'value',
9325
+ characterScalePercent: source.characterScale.mixed ? '' : String(scale ?? 100),
9326
+ characterPositionMode: source.characterPosition.mixed ? 'mixed' : null !== position && position < 0 ? 'lowered' : null !== position && position > 0 ? 'raised' : 'normal',
9327
+ characterPositionPoints: formatPoints(positionPoints || 1),
9328
+ characterSpacingMode: source.characterSpacing.mixed ? 'mixed' : null !== spacing && spacing < 0 ? 'condensed' : null !== spacing && spacing > 0 ? 'expanded' : 'normal',
9329
+ characterSpacingPoints: formatPoints(spacingPoints || 1),
9330
+ kerningEnabled: !source.kerningThreshold.mixed && null !== kerningThreshold,
9331
+ kerningThresholdPoints: formatPoints(documentKerningThresholdPoints(kerningThreshold) ?? 12),
9332
+ emphasisMark: source.emphasisMark.mixed ? 'mixed' : source.emphasisMark.value ?? 'inherit',
9333
+ hiddenText: source.hiddenText.value ?? false,
9334
+ legacyTextOutline: source.legacyTextOutline.value ?? false,
9335
+ legacyTextShadow: source.legacyTextShadow.value ?? false,
9336
+ legacyTextEmboss: source.legacyTextEmboss.value ?? false,
9337
+ legacyTextImprint: source.legacyTextImprint.value ?? false,
9338
+ latinFont: documentFontFamilyDraftValue(source.latinFont),
9339
+ eastAsiaFont: documentFontFamilyDraftValue(source.eastAsiaFont),
9340
+ complexScriptFont: documentFontFamilyDraftValue(source.complexScriptFont)
9341
+ };
8190
9342
  }
8191
- const documentParagraphStyles = [
9343
+ function documentFontDialogDraftError(draft) {
9344
+ if ('mixed' !== draft.characterScaleMode && null === characterScalePercentFromDraft(draft)) return "请输入 1 至 600 的整数缩放比例。";
9345
+ if ('mixed' !== draft.characterSpacingMode && 'normal' !== draft.characterSpacingMode && null === characterSpacingTwipsFromDraft(draft)) return "请输入 0.05 至 1584 磅的间距。";
9346
+ if ('mixed' !== draft.characterPositionMode && 'normal' !== draft.characterPositionMode && null === characterPositionHalfPointsFromDraft(draft)) return "请输入 0.5 至 1584 磅、以 0.5 磅递增的位置值。";
9347
+ if (draft.kerningEnabled && null === kerningThresholdHalfPointsFromDraft(draft)) return "请输入 0 至 1638.5 磅、以 0.5 磅递增的字距调整阈值。";
9348
+ return null;
9349
+ }
9350
+ function documentFontDialogPatch(source, draft, touched) {
9351
+ const patch = {};
9352
+ if (touched.characterScale && 'mixed' !== draft.characterScaleMode) {
9353
+ const scale = characterScalePercentFromDraft(draft);
9354
+ if (null !== scale && (source.characterScale.mixed || source.characterScale.value !== scale)) patch.characterScalePercent = scale;
9355
+ }
9356
+ if (touched.characterSpacing && 'mixed' !== draft.characterSpacingMode) {
9357
+ const spacing = characterSpacingTwipsFromDraft(draft);
9358
+ if (null !== spacing && (source.characterSpacing.mixed || source.characterSpacing.value !== spacing)) patch.characterSpacingTwips = spacing;
9359
+ }
9360
+ if (touched.characterPosition && 'mixed' !== draft.characterPositionMode) {
9361
+ const position = characterPositionHalfPointsFromDraft(draft);
9362
+ if (null !== position && (source.characterPosition.mixed || source.characterPosition.value !== position)) patch.characterPositionHalfPoints = position;
9363
+ }
9364
+ if (touched.kerning) {
9365
+ if (draft.kerningEnabled) {
9366
+ const threshold = kerningThresholdHalfPointsFromDraft(draft);
9367
+ if (null !== threshold && (source.kerningThreshold.mixed || source.kerningThreshold.value !== threshold)) patch.kerningThresholdHalfPoints = threshold;
9368
+ } else if (source.kerningThreshold.mixed || null !== source.kerningThreshold.value) patch.kerningThresholdHalfPoints = null;
9369
+ }
9370
+ if (touched.emphasisMark && 'mixed' !== draft.emphasisMark) {
9371
+ const emphasisMark = 'inherit' === draft.emphasisMark ? null : normalizeDocumentEmphasisMark(draft.emphasisMark);
9372
+ if (null !== emphasisMark || 'inherit' === draft.emphasisMark) {
9373
+ if (source.emphasisMark.mixed || source.emphasisMark.value !== emphasisMark) patch.emphasisMark = emphasisMark;
9374
+ }
9375
+ }
9376
+ if (touched.hiddenText && (source.hiddenText.mixed || source.hiddenText.value !== draft.hiddenText)) patch.hiddenText = draft.hiddenText;
9377
+ appendLegacyTextEffectPatch(patch, 'legacyTextOutline', source.legacyTextOutline, draft.legacyTextOutline, touched.legacyTextOutline);
9378
+ appendLegacyTextEffectPatch(patch, 'legacyTextShadow', source.legacyTextShadow, draft.legacyTextShadow, touched.legacyTextShadow);
9379
+ appendLegacyTextEffectPatch(patch, 'legacyTextEmboss', source.legacyTextEmboss, draft.legacyTextEmboss, touched.legacyTextEmboss);
9380
+ appendLegacyTextEffectPatch(patch, 'legacyTextImprint', source.legacyTextImprint, draft.legacyTextImprint, touched.legacyTextImprint);
9381
+ appendDocumentFontDialogScriptFontPatch(patch, 'latinFont', source.latinFont, draft.latinFont, touched.latinFont);
9382
+ appendDocumentFontDialogScriptFontPatch(patch, 'eastAsiaFont', source.eastAsiaFont, draft.eastAsiaFont, touched.eastAsiaFont);
9383
+ appendDocumentFontDialogScriptFontPatch(patch, 'complexScriptFont', source.complexScriptFont, draft.complexScriptFont, touched.complexScriptFont);
9384
+ return patch;
9385
+ }
9386
+ function applyDocumentFontDialogPatch(editor, selection, patch) {
9387
+ const hasScale = void 0 !== patch.characterScalePercent;
9388
+ const hasPosition = void 0 !== patch.characterPositionHalfPoints;
9389
+ const hasSpacing = void 0 !== patch.characterSpacingTwips;
9390
+ const hasKerning = void 0 !== patch.kerningThresholdHalfPoints;
9391
+ const hasEmphasis = void 0 !== patch.emphasisMark;
9392
+ const hasHiddenText = void 0 !== patch.hiddenText;
9393
+ const hasLegacyTextOutline = void 0 !== patch.legacyTextOutline;
9394
+ const hasLegacyTextShadow = void 0 !== patch.legacyTextShadow;
9395
+ const hasLegacyTextEmboss = void 0 !== patch.legacyTextEmboss;
9396
+ const hasLegacyTextImprint = void 0 !== patch.legacyTextImprint;
9397
+ const hasLegacyTextEffects = hasLegacyTextOutline || hasLegacyTextShadow || hasLegacyTextEmboss || hasLegacyTextImprint;
9398
+ const scriptFontPatch = {
9399
+ ...void 0 !== patch.latinFont ? {
9400
+ latin: patch.latinFont
9401
+ } : {},
9402
+ ...void 0 !== patch.eastAsiaFont ? {
9403
+ eastAsia: patch.eastAsiaFont
9404
+ } : {},
9405
+ ...void 0 !== patch.complexScriptFont ? {
9406
+ complexScript: patch.complexScriptFont
9407
+ } : {}
9408
+ };
9409
+ const hasScriptFonts = Object.keys(scriptFontPatch).length > 0;
9410
+ const scale = hasScale ? normalizeDocumentCharacterScalePercent(patch.characterScalePercent) : null;
9411
+ const position = hasPosition ? normalizeDocumentCharacterPositionHalfPoints(patch.characterPositionHalfPoints) : null;
9412
+ const spacing = hasSpacing ? normalizeDocumentCharacterSpacingTwips(patch.characterSpacingTwips) : null;
9413
+ const kerningThreshold = hasKerning && null !== patch.kerningThresholdHalfPoints ? normalizeDocumentKerningThresholdHalfPoints(patch.kerningThresholdHalfPoints) : null;
9414
+ const emphasisMark = hasEmphasis && null !== patch.emphasisMark ? normalizeDocumentEmphasisMark(patch.emphasisMark) : null;
9415
+ const maximum = editor.state.doc.content.size;
9416
+ if (editor.isDestroyed || !hasScale && !hasPosition && !hasSpacing && !hasKerning && !hasEmphasis && !hasHiddenText && !hasLegacyTextEffects && !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 || hasLegacyTextOutline && null === normalizeDocumentLegacyTextEffect(patch.legacyTextOutline) || hasLegacyTextShadow && null === normalizeDocumentLegacyTextEffect(patch.legacyTextShadow) || hasLegacyTextEmboss && null === normalizeDocumentLegacyTextEffect(patch.legacyTextEmboss) || hasLegacyTextImprint && null === normalizeDocumentLegacyTextEffect(patch.legacyTextImprint) || !Number.isSafeInteger(selection.from) || !Number.isSafeInteger(selection.to) || selection.from < 0 || selection.to < selection.from || selection.to > maximum || hasLegacyTextEffects && !documentFontDialogLegacyTextEffectsAreSafe(editor, selection, patch)) return false;
9417
+ const attributes = {};
9418
+ if (null !== scale) attributes.characterScalePercent = scale;
9419
+ if (null !== position) attributes.characterPositionHalfPoints = position;
9420
+ if (null !== spacing) attributes.characterSpacingTwips = spacing;
9421
+ if (hasKerning) attributes.kerningThresholdHalfPoints = kerningThreshold;
9422
+ if (hasEmphasis) attributes.emphasisMark = emphasisMark;
9423
+ if (hasHiddenText) attributes.hiddenText = patch.hiddenText ?? false;
9424
+ if (hasLegacyTextOutline) attributes.legacyTextOutline = patch.legacyTextOutline ?? false;
9425
+ if (hasLegacyTextShadow) attributes.legacyTextShadow = patch.legacyTextShadow ?? false;
9426
+ if (hasLegacyTextEmboss) attributes.legacyTextEmboss = patch.legacyTextEmboss ?? false;
9427
+ if (hasLegacyTextImprint) attributes.legacyTextImprint = patch.legacyTextImprint ?? false;
9428
+ if (hasScriptFonts) return applyDocumentScriptFontPatch(editor, selection, attributes, scriptFontPatch);
9429
+ return editor.chain().setTextSelection(selection).setMark('textStyle', attributes).removeEmptyTextStyle().focus().scrollIntoView().run();
9430
+ }
9431
+ function addScaleValue(values, value) {
9432
+ const scale = normalizeDocumentCharacterScalePercent(value);
9433
+ values.set(null === scale ? 'inherited' : String(scale), scale);
9434
+ }
9435
+ function documentFontDialogLegacyTextEffectsAreSafe(editor, selection, patch) {
9436
+ const patchEffects = {
9437
+ ...void 0 !== patch.legacyTextOutline ? {
9438
+ outline: patch.legacyTextOutline
9439
+ } : {},
9440
+ ...void 0 !== patch.legacyTextShadow ? {
9441
+ shadow: patch.legacyTextShadow
9442
+ } : {},
9443
+ ...void 0 !== patch.legacyTextEmboss ? {
9444
+ emboss: patch.legacyTextEmboss
9445
+ } : {},
9446
+ ...void 0 !== patch.legacyTextImprint ? {
9447
+ imprint: patch.legacyTextImprint
9448
+ } : {}
9449
+ };
9450
+ const attributesAreSafe = (attributes)=>{
9451
+ const current = documentLegacyTextEffectsFromTextStyleAttributes(attributes);
9452
+ return null !== current && !documentLegacyTextEffectsConflict({
9453
+ ...current,
9454
+ ...patchEffects
9455
+ });
9456
+ };
9457
+ if (selection.from === selection.to) return attributesAreSafe(editor.getAttributes('textStyle'));
9458
+ let sawText = false;
9459
+ let safe = true;
9460
+ editor.state.doc.nodesBetween(selection.from, selection.to, (node, position)=>{
9461
+ if (!safe || !node.isText || position >= selection.to || position + node.nodeSize <= selection.from) return;
9462
+ sawText = true;
9463
+ const textStyle = node.marks.find((mark)=>'textStyle' === mark.type.name);
9464
+ safe = attributesAreSafe(textStyle?.attrs ?? {});
9465
+ });
9466
+ return safe && (sawText || attributesAreSafe(editor.getAttributes('textStyle')));
9467
+ }
9468
+ function addPositionValue(values, value) {
9469
+ const position = normalizeDocumentCharacterPositionHalfPoints(value);
9470
+ values.set(null === position ? 'inherited' : String(position), position);
9471
+ }
9472
+ function addSpacingValue(values, value) {
9473
+ const spacing = normalizeDocumentCharacterSpacingTwips(value);
9474
+ values.set(null === spacing ? 'inherited' : String(spacing), spacing);
9475
+ }
9476
+ function addKerningValue(values, value) {
9477
+ const threshold = normalizeDocumentKerningThresholdHalfPoints(value);
9478
+ values.set(null === threshold ? 'inherited' : String(threshold), threshold);
9479
+ }
9480
+ function addEmphasisValue(values, value) {
9481
+ const emphasisMark = normalizeDocumentEmphasisMark(value);
9482
+ values.set(null === emphasisMark ? 'inherited' : emphasisMark, emphasisMark);
9483
+ }
9484
+ function addHiddenTextValue(values, value) {
9485
+ const hiddenText = normalizeDocumentHiddenText(value);
9486
+ values.set(null === hiddenText ? 'inherited' : String(hiddenText), hiddenText);
9487
+ }
9488
+ function appendLegacyTextEffectPatch(patch, name, source, value, touched) {
9489
+ if (touched && (source.mixed || source.value !== value)) patch[name] = value;
9490
+ }
9491
+ function addLegacyTextEffectValue(values, value) {
9492
+ const effect = normalizeDocumentLegacyTextEffect(value);
9493
+ values.set(null === effect ? 'inherited' : String(effect), effect);
9494
+ }
9495
+ function characterSpacingTwipsFromDraft(draft) {
9496
+ if ('normal' === draft.characterSpacingMode) return 0;
9497
+ if ('mixed' === draft.characterSpacingMode) return null;
9498
+ const points = Number(draft.characterSpacingPoints);
9499
+ const maximumPoints = 1584;
9500
+ if (!Number.isFinite(points) || points < 0.05 || points > maximumPoints) return null;
9501
+ const magnitude = Math.round(20 * points);
9502
+ if (magnitude <= 0) return null;
9503
+ return normalizeDocumentCharacterSpacingTwips('condensed' === draft.characterSpacingMode ? -magnitude : magnitude);
9504
+ }
9505
+ function characterScalePercentFromDraft(draft) {
9506
+ if ('mixed' === draft.characterScaleMode) return null;
9507
+ return normalizeDocumentCharacterScalePercent(draft.characterScalePercent);
9508
+ }
9509
+ function characterPositionHalfPointsFromDraft(draft) {
9510
+ if ('normal' === draft.characterPositionMode) return 0;
9511
+ if ('mixed' === draft.characterPositionMode) return null;
9512
+ const points = Number(draft.characterPositionPoints);
9513
+ const maximumPoints = 1584;
9514
+ const magnitude = 2 * points;
9515
+ if (!Number.isFinite(points) || points < 0.5 || points > maximumPoints || !Number.isSafeInteger(magnitude)) return null;
9516
+ return normalizeDocumentCharacterPositionHalfPoints('lowered' === draft.characterPositionMode ? -magnitude : magnitude);
9517
+ }
9518
+ function kerningThresholdHalfPointsFromDraft(draft) {
9519
+ if (!draft.kerningEnabled) return null;
9520
+ const points = Number(draft.kerningThresholdPoints);
9521
+ const halfPoints = 2 * points;
9522
+ if (!Number.isFinite(points) || points < 0 || points > 1638.5 || !Number.isSafeInteger(halfPoints)) return null;
9523
+ return normalizeDocumentKerningThresholdHalfPoints(halfPoints);
9524
+ }
9525
+ function selectedValue(values) {
9526
+ const mixed = values.size > 1;
9527
+ return {
9528
+ mixed,
9529
+ value: mixed ? null : values.values().next().value ?? null
9530
+ };
9531
+ }
9532
+ function formatPoints(value) {
9533
+ return String(Number(value.toFixed(2)));
9534
+ }
9535
+ const characterSpacingModes = [
8192
9536
  {
8193
- value: 'paragraph',
8194
- label: '正文',
8195
- level: null,
8196
- shortcut: void 0
9537
+ value: 'mixed',
9538
+ label: '混合(保持不变)',
9539
+ disabled: true
8197
9540
  },
8198
9541
  {
8199
- value: 'h1',
8200
- label: '标题 1',
8201
- level: 1,
8202
- shortcut: getDocumentCommandDefinition('heading1').shortcut
9542
+ value: 'normal',
9543
+ label: '标准'
8203
9544
  },
8204
9545
  {
8205
- value: 'h2',
8206
- label: '标题 2',
8207
- level: 2,
8208
- shortcut: getDocumentCommandDefinition('heading2').shortcut
9546
+ value: 'expanded',
9547
+ label: '加宽'
8209
9548
  },
8210
9549
  {
8211
- value: 'h3',
8212
- label: '标题 3',
8213
- level: 3,
8214
- shortcut: getDocumentCommandDefinition('heading3').shortcut
9550
+ value: 'condensed',
9551
+ label: '紧缩'
8215
9552
  }
8216
9553
  ];
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
- });
8230
- };
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
- ]
8285
- });
8286
- }
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';
8298
- }
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();
8304
- }
8305
- const documentLineHeightOptions = [
9554
+ const characterPositionModes = [
9555
+ {
9556
+ value: 'mixed',
9557
+ label: '混合(保持不变)',
9558
+ disabled: true
9559
+ },
9560
+ {
9561
+ value: 'normal',
9562
+ label: '标准'
9563
+ },
9564
+ {
9565
+ value: 'raised',
9566
+ label: '提升'
9567
+ },
9568
+ {
9569
+ value: 'lowered',
9570
+ label: '降低'
9571
+ }
9572
+ ];
9573
+ const emphasisMarkModes = [
8306
9574
  {
8307
- value: 'default',
8308
- label: '默认行距'
9575
+ value: 'mixed',
9576
+ label: '混合(保持不变)',
9577
+ disabled: true
8309
9578
  },
8310
9579
  {
8311
- value: '1',
8312
- label: '单倍',
8313
- meta: getDocumentCommandDefinition('lineSpacingSingle').shortcut?.label
9580
+ value: 'inherit',
9581
+ label: '跟随样式'
8314
9582
  },
8315
9583
  {
8316
- value: '1.15',
8317
- label: '1.15 倍'
9584
+ value: 'none',
9585
+ label: ''
8318
9586
  },
8319
9587
  {
8320
- value: '1.5',
8321
- label: '1.5 倍',
8322
- meta: getDocumentCommandDefinition('lineSpacingOneAndHalf').shortcut?.label
9588
+ value: 'dot',
9589
+ label: '上方圆点'
8323
9590
  },
8324
9591
  {
8325
- value: '2',
8326
- label: '2 倍',
8327
- meta: getDocumentCommandDefinition('lineSpacingDouble').shortcut?.label
9592
+ value: 'comma',
9593
+ label: '上方逗号'
9594
+ },
9595
+ {
9596
+ value: 'circle',
9597
+ label: '上方圆圈'
9598
+ },
9599
+ {
9600
+ value: 'underDot',
9601
+ label: '下方圆点'
8328
9602
  }
8329
9603
  ];
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",
9604
+ function DocumentFontDialog({ source, layoutFonts = [], restoreFocusTarget, onApply, onClose }) {
9605
+ const [draft, setDraft] = useState(()=>createDocumentFontDialogDraft(source));
9606
+ const [characterScaleTouched, setCharacterScaleTouched] = useState(false);
9607
+ const [characterSpacingTouched, setCharacterSpacingTouched] = useState(false);
9608
+ const [characterPositionTouched, setCharacterPositionTouched] = useState(false);
9609
+ const [kerningTouched, setKerningTouched] = useState(false);
9610
+ const [emphasisTouched, setEmphasisTouched] = useState(false);
9611
+ const [hiddenTextTouched, setHiddenTextTouched] = useState(false);
9612
+ const [legacyTextOutlineTouched, setLegacyTextOutlineTouched] = useState(false);
9613
+ const [legacyTextShadowTouched, setLegacyTextShadowTouched] = useState(false);
9614
+ const [legacyTextEmbossTouched, setLegacyTextEmbossTouched] = useState(false);
9615
+ const [legacyTextImprintTouched, setLegacyTextImprintTouched] = useState(false);
9616
+ const [latinFontTouched, setLatinFontTouched] = useState(false);
9617
+ const [eastAsiaFontTouched, setEastAsiaFontTouched] = useState(false);
9618
+ const [complexScriptFontTouched, setComplexScriptFontTouched] = useState(false);
9619
+ const formId = useId();
9620
+ const error = documentFontDialogDraftError(draft);
9621
+ const patch = documentFontDialogPatch(source, draft, {
9622
+ characterPosition: characterPositionTouched,
9623
+ characterScale: characterScaleTouched,
9624
+ characterSpacing: characterSpacingTouched,
9625
+ complexScriptFont: complexScriptFontTouched,
9626
+ eastAsiaFont: eastAsiaFontTouched,
9627
+ emphasisMark: emphasisTouched,
9628
+ hiddenText: hiddenTextTouched,
9629
+ legacyTextOutline: legacyTextOutlineTouched,
9630
+ legacyTextShadow: legacyTextShadowTouched,
9631
+ legacyTextEmboss: legacyTextEmbossTouched,
9632
+ legacyTextImprint: legacyTextImprintTouched,
9633
+ kerning: kerningTouched,
9634
+ latinFont: latinFontTouched
9635
+ });
9636
+ const hasChanges = Object.keys(patch).length > 0;
9637
+ const previewScale = previewCharacterScale(draft);
9638
+ const previewSpacing = previewCharacterSpacing(draft);
9639
+ const previewPosition = previewCharacterPosition(draft);
9640
+ const previewKerning = previewDocumentKerning(draft, source.fontSize);
9641
+ const previewEmphasis = previewDocumentEmphasis(draft.emphasisMark);
9642
+ const previewLegacyTextEffects = documentLegacyTextEffectsCss({
9643
+ outline: draft.legacyTextOutline,
9644
+ shadow: draft.legacyTextShadow,
9645
+ emboss: draft.legacyTextEmboss,
9646
+ imprint: draft.legacyTextImprint
9647
+ });
9648
+ const submit = (event)=>{
9649
+ event?.preventDefault();
9650
+ if (!hasChanges || error) return;
9651
+ if (onApply(patch)) onClose();
9652
+ };
9653
+ return /*#__PURE__*/ jsx(Dialog, {
9654
+ title: "字体高级设置",
9655
+ description: fontDialogDescription(source),
9656
+ className: "work-document-font-dialog",
9657
+ restoreFocusTarget: restoreFocusTarget,
9658
+ onClose: onClose,
9659
+ footer: /*#__PURE__*/ jsxs(Fragment, {
9660
+ children: [
9661
+ /*#__PURE__*/ jsx(button_Button, {
9662
+ tone: "quiet",
9663
+ onClick: onClose,
9664
+ children: "取消"
9665
+ }),
9666
+ /*#__PURE__*/ jsx(button_Button, {
9667
+ tone: "primary",
9668
+ type: "submit",
9669
+ form: formId,
9670
+ disabled: !hasChanges || Boolean(error),
9671
+ children: "应用"
9672
+ })
9673
+ ]
9674
+ }),
9675
+ children: /*#__PURE__*/ jsxs("form", {
9676
+ id: formId,
9677
+ onSubmit: submit,
9678
+ children: [
9679
+ /*#__PURE__*/ jsxs("fieldset", {
9680
+ className: "work-document-font-dialog-script-fonts",
8353
9681
  children: [
9682
+ /*#__PURE__*/ jsx("legend", {
9683
+ children: "按文字系统设置字体"
9684
+ }),
8354
9685
  /*#__PURE__*/ jsxs("div", {
8355
- className: "work-document-font-selects",
9686
+ className: "work-document-font-dialog-field",
8356
9687
  children: [
9688
+ /*#__PURE__*/ jsx("span", {
9689
+ children: "拉丁文字"
9690
+ }),
8357
9691
  /*#__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();
9692
+ ariaLabel: "拉丁文字字体",
9693
+ initialFocus: true,
9694
+ value: draft.latinFont,
9695
+ options: scriptFontOptions(draft.latinFont, layoutFonts),
9696
+ onValueChange: (latinFont)=>{
9697
+ setDraft((current)=>({
9698
+ ...current,
9699
+ latinFont
9700
+ }));
9701
+ setLatinFontTouched(true);
8365
9702
  }
9703
+ })
9704
+ ]
9705
+ }),
9706
+ /*#__PURE__*/ jsxs("div", {
9707
+ className: "work-document-font-dialog-field",
9708
+ children: [
9709
+ /*#__PURE__*/ jsx("span", {
9710
+ children: "东亚文字"
8366
9711
  }),
8367
9712
  /*#__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();
9713
+ ariaLabel: "东亚文字字体",
9714
+ value: draft.eastAsiaFont,
9715
+ options: scriptFontOptions(draft.eastAsiaFont, layoutFonts),
9716
+ onValueChange: (eastAsiaFont)=>{
9717
+ setDraft((current)=>({
9718
+ ...current,
9719
+ eastAsiaFont
9720
+ }));
9721
+ setEastAsiaFontTouched(true);
8375
9722
  }
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
9723
  })
8395
9724
  ]
8396
9725
  }),
8397
9726
  /*#__PURE__*/ jsxs("div", {
8398
- className: "work-document-font-actions",
9727
+ className: "work-document-font-dialog-field",
8399
9728
  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
- })
8434
- }),
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
- })
8443
- }),
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
- })
8452
- }),
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()
8459
- }),
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
- })
9729
+ /*#__PURE__*/ jsx("span", {
9730
+ children: "复杂文字"
8469
9731
  }),
8470
- /*#__PURE__*/ jsx(ToolbarButton, {
8471
- label: "清除格式",
8472
- onClick: ()=>editor.commands.clearDocumentFormatting(),
8473
- children: /*#__PURE__*/ jsx(Eraser, {
8474
- size: 16
8475
- })
9732
+ /*#__PURE__*/ jsx(OfficeSelect, {
9733
+ ariaLabel: "复杂文字字体",
9734
+ value: draft.complexScriptFont,
9735
+ options: scriptFontOptions(draft.complexScriptFont, layoutFonts),
9736
+ onValueChange: (complexScriptFont)=>{
9737
+ setDraft((current)=>({
9738
+ ...current,
9739
+ complexScriptFont
9740
+ }));
9741
+ setComplexScriptFontTouched(true);
9742
+ }
8476
9743
  })
8477
9744
  ]
9745
+ }),
9746
+ source.latinFont.mixed && !latinFontTouched && /*#__PURE__*/ jsx("p", {
9747
+ className: "work-document-font-dialog-mixed",
9748
+ role: "status",
9749
+ children: "当前选区包含不同的拉丁文字字体。选择字体后才会统一修改。"
9750
+ }),
9751
+ source.eastAsiaFont.mixed && !eastAsiaFontTouched && /*#__PURE__*/ jsx("p", {
9752
+ className: "work-document-font-dialog-mixed",
9753
+ role: "status",
9754
+ children: "当前选区包含不同的东亚文字字体。选择字体后才会统一修改。"
9755
+ }),
9756
+ source.complexScriptFont.mixed && !complexScriptFontTouched && /*#__PURE__*/ jsx("p", {
9757
+ className: "work-document-font-dialog-mixed",
9758
+ role: "status",
9759
+ children: "当前选区包含不同的复杂文字字体。选择字体后才会统一修改。"
8478
9760
  })
8479
9761
  ]
8480
- })
8481
- }),
8482
- /*#__PURE__*/ jsx(RibbonGroup, {
8483
- label: "段落",
8484
- priority: "high",
8485
- children: /*#__PURE__*/ jsxs("div", {
8486
- className: "work-document-paragraph-tools",
9762
+ }),
9763
+ /*#__PURE__*/ jsxs("fieldset", {
9764
+ className: "work-document-font-dialog-spacing",
8487
9765
  children: [
9766
+ /*#__PURE__*/ jsx("legend", {
9767
+ children: "字符缩放、间距、字距调整、位置与文字效果"
9768
+ }),
8488
9769
  /*#__PURE__*/ jsxs("div", {
8489
- className: "work-document-paragraph-actions",
9770
+ className: "work-document-font-dialog-field",
8490
9771
  children: [
8491
- /*#__PURE__*/ jsx(DocumentListGallery, {
8492
- editor: editor
9772
+ /*#__PURE__*/ jsx("span", {
9773
+ children: "缩放"
8493
9774
  }),
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
- })
9775
+ /*#__PURE__*/ jsxs("span", {
9776
+ className: "work-document-font-dialog-measure",
9777
+ children: [
9778
+ /*#__PURE__*/ jsx(OfficeNumberField, {
9779
+ ariaLabel: "字符缩放比例(%)",
9780
+ value: draft.characterScalePercent,
9781
+ min: 1,
9782
+ max: 600,
9783
+ step: 1,
9784
+ placeholder: 'mixed' === draft.characterScaleMode ? '混合' : void 0,
9785
+ validationInvalid: Boolean(error),
9786
+ onValueChange: (characterScalePercent)=>{
9787
+ setDraft((current)=>({
9788
+ ...current,
9789
+ characterScaleMode: 'value',
9790
+ characterScalePercent
9791
+ }));
9792
+ setCharacterScaleTouched(true);
9793
+ }
9794
+ }),
9795
+ /*#__PURE__*/ jsx("span", {
9796
+ "aria-hidden": "true",
9797
+ children: "%"
9798
+ })
9799
+ ]
9800
+ })
9801
+ ]
9802
+ }),
9803
+ /*#__PURE__*/ jsxs("div", {
9804
+ className: "work-document-font-dialog-field",
9805
+ children: [
9806
+ /*#__PURE__*/ jsx("span", {
9807
+ children: "间距"
8501
9808
  }),
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
- })
9809
+ /*#__PURE__*/ jsx(OfficeSelect, {
9810
+ ariaLabel: "字符间距",
9811
+ value: draft.characterSpacingMode,
9812
+ options: characterSpacingModes,
9813
+ onValueChange: (characterSpacingMode)=>{
9814
+ setDraft((current)=>({
9815
+ ...current,
9816
+ characterSpacingMode
9817
+ }));
9818
+ setCharacterSpacingTouched(true);
9819
+ }
9820
+ })
9821
+ ]
9822
+ }),
9823
+ /*#__PURE__*/ jsxs("div", {
9824
+ className: "work-document-font-dialog-field",
9825
+ children: [
9826
+ /*#__PURE__*/ jsx("span", {
9827
+ children: "间距值"
9828
+ }),
9829
+ /*#__PURE__*/ jsxs("span", {
9830
+ className: "work-document-font-dialog-measure",
9831
+ children: [
9832
+ /*#__PURE__*/ jsx(OfficeNumberField, {
9833
+ ariaLabel: "间距值(磅)",
9834
+ value: draft.characterSpacingPoints,
9835
+ min: 0.05,
9836
+ max: 1584,
9837
+ step: 0.05,
9838
+ disabled: 'mixed' === draft.characterSpacingMode || 'normal' === draft.characterSpacingMode,
9839
+ validationInvalid: Boolean(error),
9840
+ onValueChange: (characterSpacingPoints)=>{
9841
+ setDraft((current)=>({
9842
+ ...current,
9843
+ characterSpacingPoints
9844
+ }));
9845
+ setCharacterSpacingTouched(true);
9846
+ }
9847
+ }),
9848
+ /*#__PURE__*/ jsx("span", {
9849
+ "aria-hidden": "true",
9850
+ children: "磅"
9851
+ })
9852
+ ]
9853
+ })
9854
+ ]
9855
+ }),
9856
+ /*#__PURE__*/ jsxs("div", {
9857
+ className: "work-document-font-dialog-field",
9858
+ children: [
9859
+ /*#__PURE__*/ jsx(OfficeCheckbox, {
9860
+ ariaLabel: "为字号达到以下值的字体调整字距",
9861
+ checked: draft.kerningEnabled,
9862
+ indeterminate: source.kerningThreshold.mixed && !kerningTouched,
9863
+ onCheckedChange: (kerningEnabled)=>{
9864
+ setDraft((current)=>({
9865
+ ...current,
9866
+ kerningEnabled
9867
+ }));
9868
+ setKerningTouched(true);
9869
+ },
9870
+ children: "为字号达到以下值的字体调整字距"
9871
+ }),
9872
+ /*#__PURE__*/ jsxs("span", {
9873
+ className: "work-document-font-dialog-measure",
9874
+ children: [
9875
+ /*#__PURE__*/ jsx(OfficeNumberField, {
9876
+ ariaLabel: "字距调整阈值(磅)",
9877
+ value: draft.kerningThresholdPoints,
9878
+ min: 0,
9879
+ max: 1638.5,
9880
+ step: 0.5,
9881
+ disabled: !draft.kerningEnabled,
9882
+ validationInvalid: Boolean(error),
9883
+ onValueChange: (kerningThresholdPoints)=>{
9884
+ setDraft((current)=>({
9885
+ ...current,
9886
+ kerningEnabled: true,
9887
+ kerningThresholdPoints
9888
+ }));
9889
+ setKerningTouched(true);
9890
+ }
9891
+ }),
9892
+ /*#__PURE__*/ jsx("span", {
9893
+ "aria-hidden": "true",
9894
+ children: "磅"
9895
+ })
9896
+ ]
9897
+ })
9898
+ ]
9899
+ }),
9900
+ /*#__PURE__*/ jsxs("div", {
9901
+ className: "work-document-font-dialog-field",
9902
+ children: [
9903
+ /*#__PURE__*/ jsx("span", {
9904
+ children: "位置"
8509
9905
  }),
8510
9906
  /*#__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)
9907
+ ariaLabel: "字符位置",
9908
+ value: draft.characterPositionMode,
9909
+ options: characterPositionModes,
9910
+ onValueChange: (characterPositionMode)=>{
9911
+ setDraft((current)=>({
9912
+ ...current,
9913
+ characterPositionMode
9914
+ }));
9915
+ setCharacterPositionTouched(true);
9916
+ }
8516
9917
  })
8517
9918
  ]
8518
9919
  }),
8519
9920
  /*#__PURE__*/ jsxs("div", {
8520
- className: "work-document-alignment-actions",
9921
+ className: "work-document-font-dialog-field",
8521
9922
  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
- })
9923
+ /*#__PURE__*/ jsx("span", {
9924
+ children: "位置值"
8532
9925
  }),
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
- })
9926
+ /*#__PURE__*/ jsxs("span", {
9927
+ className: "work-document-font-dialog-measure",
9928
+ children: [
9929
+ /*#__PURE__*/ jsx(OfficeNumberField, {
9930
+ ariaLabel: "位置值(磅)",
9931
+ value: draft.characterPositionPoints,
9932
+ min: 0.5,
9933
+ max: 1584,
9934
+ step: 0.5,
9935
+ disabled: 'mixed' === draft.characterPositionMode || 'normal' === draft.characterPositionMode,
9936
+ validationInvalid: Boolean(error),
9937
+ onValueChange: (characterPositionPoints)=>{
9938
+ setDraft((current)=>({
9939
+ ...current,
9940
+ characterPositionPoints
9941
+ }));
9942
+ setCharacterPositionTouched(true);
9943
+ }
9944
+ }),
9945
+ /*#__PURE__*/ jsx("span", {
9946
+ "aria-hidden": "true",
9947
+ children: "磅"
9948
+ })
9949
+ ]
9950
+ })
9951
+ ]
9952
+ }),
9953
+ /*#__PURE__*/ jsxs("div", {
9954
+ className: "work-document-font-dialog-field",
9955
+ children: [
9956
+ /*#__PURE__*/ jsx("span", {
9957
+ children: "着重号"
8543
9958
  }),
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
- })
9959
+ /*#__PURE__*/ jsx(OfficeSelect, {
9960
+ ariaLabel: "着重号",
9961
+ value: draft.emphasisMark,
9962
+ options: emphasisMarkModes,
9963
+ onValueChange: (emphasisMark)=>{
9964
+ setDraft((current)=>({
9965
+ ...current,
9966
+ emphasisMark
9967
+ }));
9968
+ setEmphasisTouched(true);
9969
+ }
9970
+ })
9971
+ ]
9972
+ }),
9973
+ /*#__PURE__*/ jsx("div", {
9974
+ className: "work-document-font-dialog-field work-document-font-dialog-hidden-text",
9975
+ children: /*#__PURE__*/ jsx(OfficeCheckbox, {
9976
+ ariaLabel: "隐藏文字",
9977
+ checked: draft.hiddenText,
9978
+ indeterminate: source.hiddenText.mixed && !hiddenTextTouched,
9979
+ onCheckedChange: (hiddenText)=>{
9980
+ setDraft((current)=>({
9981
+ ...current,
9982
+ hiddenText
9983
+ }));
9984
+ setHiddenTextTouched(true);
9985
+ },
9986
+ children: "隐藏文字"
9987
+ })
9988
+ }),
9989
+ /*#__PURE__*/ jsxs("fieldset", {
9990
+ className: "work-document-font-dialog-legacy-effects",
9991
+ "aria-label": "文字效果",
9992
+ children: [
9993
+ /*#__PURE__*/ jsx(OfficeCheckbox, {
9994
+ ariaLabel: "空心",
9995
+ checked: draft.legacyTextOutline,
9996
+ indeterminate: source.legacyTextOutline.mixed && !legacyTextOutlineTouched,
9997
+ onCheckedChange: (legacyTextOutline)=>{
9998
+ setDraft((current)=>legacyTextOutline ? {
9999
+ ...current,
10000
+ legacyTextOutline,
10001
+ legacyTextEmboss: false,
10002
+ legacyTextImprint: false
10003
+ } : {
10004
+ ...current,
10005
+ legacyTextOutline
10006
+ });
10007
+ setLegacyTextOutlineTouched(true);
10008
+ if (legacyTextOutline) {
10009
+ setLegacyTextEmbossTouched(true);
10010
+ setLegacyTextImprintTouched(true);
10011
+ }
10012
+ },
10013
+ children: "空心"
8554
10014
  }),
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
- })
10015
+ /*#__PURE__*/ jsx(OfficeCheckbox, {
10016
+ ariaLabel: "阴影",
10017
+ checked: draft.legacyTextShadow,
10018
+ indeterminate: source.legacyTextShadow.mixed && !legacyTextShadowTouched,
10019
+ onCheckedChange: (legacyTextShadow)=>{
10020
+ setDraft((current)=>legacyTextShadow ? {
10021
+ ...current,
10022
+ legacyTextShadow,
10023
+ legacyTextEmboss: false,
10024
+ legacyTextImprint: false
10025
+ } : {
10026
+ ...current,
10027
+ legacyTextShadow
10028
+ });
10029
+ setLegacyTextShadowTouched(true);
10030
+ if (legacyTextShadow) {
10031
+ setLegacyTextEmbossTouched(true);
10032
+ setLegacyTextImprintTouched(true);
10033
+ }
10034
+ },
10035
+ children: "阴影"
8565
10036
  }),
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
- })
10037
+ /*#__PURE__*/ jsx(OfficeCheckbox, {
10038
+ ariaLabel: "阳文",
10039
+ checked: draft.legacyTextEmboss,
10040
+ indeterminate: source.legacyTextEmboss.mixed && !legacyTextEmbossTouched,
10041
+ onCheckedChange: (legacyTextEmboss)=>{
10042
+ setDraft((current)=>legacyTextEmboss ? {
10043
+ ...current,
10044
+ legacyTextOutline: false,
10045
+ legacyTextShadow: false,
10046
+ legacyTextEmboss,
10047
+ legacyTextImprint: false
10048
+ } : {
10049
+ ...current,
10050
+ legacyTextEmboss
10051
+ });
10052
+ setLegacyTextEmbossTouched(true);
10053
+ if (legacyTextEmboss) {
10054
+ setLegacyTextOutlineTouched(true);
10055
+ setLegacyTextShadowTouched(true);
10056
+ setLegacyTextImprintTouched(true);
10057
+ }
10058
+ },
10059
+ children: "阳文"
8573
10060
  }),
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
- })
10061
+ /*#__PURE__*/ jsx(OfficeCheckbox, {
10062
+ ariaLabel: "阴文",
10063
+ checked: draft.legacyTextImprint,
10064
+ indeterminate: source.legacyTextImprint.mixed && !legacyTextImprintTouched,
10065
+ onCheckedChange: (legacyTextImprint)=>{
10066
+ setDraft((current)=>legacyTextImprint ? {
10067
+ ...current,
10068
+ legacyTextOutline: false,
10069
+ legacyTextShadow: false,
10070
+ legacyTextEmboss: false,
10071
+ legacyTextImprint
10072
+ } : {
10073
+ ...current,
10074
+ legacyTextImprint
10075
+ });
10076
+ setLegacyTextImprintTouched(true);
10077
+ if (legacyTextImprint) {
10078
+ setLegacyTextOutlineTouched(true);
10079
+ setLegacyTextShadowTouched(true);
10080
+ setLegacyTextEmbossTouched(true);
10081
+ }
10082
+ },
10083
+ children: "阴文"
8581
10084
  })
8582
10085
  ]
10086
+ }),
10087
+ source.characterScale.mixed && !characterScaleTouched && /*#__PURE__*/ jsx("p", {
10088
+ className: "work-document-font-dialog-mixed",
10089
+ role: "status",
10090
+ children: "当前选区包含多种字符缩放比例。输入缩放比例后才会统一修改。"
10091
+ }),
10092
+ source.characterSpacing.mixed && !characterSpacingTouched && /*#__PURE__*/ jsx("p", {
10093
+ className: "work-document-font-dialog-mixed",
10094
+ role: "status",
10095
+ children: "当前选区包含多种字符间距。选择一种间距后才会统一修改。"
10096
+ }),
10097
+ source.characterPosition.mixed && !characterPositionTouched && /*#__PURE__*/ jsx("p", {
10098
+ className: "work-document-font-dialog-mixed",
10099
+ role: "status",
10100
+ children: "当前选区包含多种字符位置。选择一种位置后才会统一修改。"
10101
+ }),
10102
+ source.kerningThreshold.mixed && !kerningTouched && /*#__PURE__*/ jsx("p", {
10103
+ className: "work-document-font-dialog-mixed",
10104
+ role: "status",
10105
+ children: "当前选区包含不同的字距调整设置。勾选或取消后才会统一修改。"
10106
+ }),
10107
+ source.emphasisMark.mixed && !emphasisTouched && /*#__PURE__*/ jsx("p", {
10108
+ className: "work-document-font-dialog-mixed",
10109
+ role: "status",
10110
+ children: "当前选区包含不同的着重号。选择一种设置后才会统一修改。"
10111
+ }),
10112
+ source.hiddenText.mixed && !hiddenTextTouched && /*#__PURE__*/ jsx("p", {
10113
+ className: "work-document-font-dialog-mixed",
10114
+ role: "status",
10115
+ children: "当前选区同时包含隐藏和可见文字。勾选或取消后才会统一修改。"
10116
+ }),
10117
+ (source.legacyTextOutline.mixed && !legacyTextOutlineTouched || source.legacyTextShadow.mixed && !legacyTextShadowTouched || source.legacyTextEmboss.mixed && !legacyTextEmbossTouched || source.legacyTextImprint.mixed && !legacyTextImprintTouched) && /*#__PURE__*/ jsx("p", {
10118
+ className: "work-document-font-dialog-mixed",
10119
+ role: "status",
10120
+ children: "当前选区包含不同的空心、阴影、阳文或阴文设置。勾选或取消对应选项后才会统一修改。"
10121
+ }),
10122
+ (characterScaleTouched || characterSpacingTouched || characterPositionTouched || kerningTouched || emphasisTouched || hiddenTextTouched || legacyTextOutlineTouched || legacyTextShadowTouched || legacyTextEmbossTouched || legacyTextImprintTouched) && error && /*#__PURE__*/ jsx("p", {
10123
+ className: "work-document-font-dialog-error",
10124
+ role: "alert",
10125
+ children: error
8583
10126
  })
8584
10127
  ]
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
10128
+ }),
10129
+ /*#__PURE__*/ jsxs("section", {
10130
+ className: "work-document-font-dialog-preview",
10131
+ "aria-label": "字符高级格式预览",
10132
+ children: [
10133
+ /*#__PURE__*/ jsx("span", {
10134
+ children: "预览"
10135
+ }),
10136
+ /*#__PURE__*/ jsx("output", {
10137
+ style: {
10138
+ fontFamily: source.fontFamily ?? void 0,
10139
+ fontSize: source.fontSize ?? void 0,
10140
+ fontStretch: `${previewScale}%`,
10141
+ fontKerning: previewKerning,
10142
+ letterSpacing: `${previewSpacing}pt`
10143
+ },
10144
+ children: /*#__PURE__*/ jsx("span", {
10145
+ style: {
10146
+ verticalAlign: `${previewPosition}pt`,
10147
+ ...previewEmphasis,
10148
+ ...previewLegacyTextEffects,
10149
+ ...draft.hiddenText ? {
10150
+ textDecorationColor: 'currentColor',
10151
+ textDecorationLine: 'underline',
10152
+ textDecorationStyle: 'dotted',
10153
+ textUnderlineOffset: '0.18em'
10154
+ } : {}
10155
+ },
10156
+ children: documentScriptFontSegments(source.previewText).map(({ from, to, slot })=>/*#__PURE__*/ jsx("span", {
10157
+ style: {
10158
+ fontFamily: previewScriptFontFamily('eastAsia' === slot ? draft.eastAsiaFont : 'complexScript' === slot ? draft.complexScriptFont : draft.latinFont, source.fontFamily)
10159
+ },
10160
+ children: source.previewText.slice(from, to)
10161
+ }, `${from}-${slot}`))
10162
+ })
8614
10163
  })
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
10164
+ ]
10165
+ })
10166
+ ]
10167
+ })
8631
10168
  });
8632
10169
  }
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();
10170
+ function previewCharacterScale(draft) {
10171
+ if ('mixed' === draft.characterScaleMode) return 100;
10172
+ const percent = Number(draft.characterScalePercent);
10173
+ return Number.isFinite(percent) ? percent : 100;
10174
+ }
10175
+ function previewCharacterPosition(draft) {
10176
+ if ('mixed' === draft.characterPositionMode || 'normal' === draft.characterPositionMode) return 0;
10177
+ const points = Number(draft.characterPositionPoints);
10178
+ if (!Number.isFinite(points)) return 0;
10179
+ return 'lowered' === draft.characterPositionMode ? -points : points;
10180
+ }
10181
+ function previewCharacterSpacing(draft) {
10182
+ if ('mixed' === draft.characterSpacingMode || 'normal' === draft.characterSpacingMode) return 0;
10183
+ const points = Number(draft.characterSpacingPoints);
10184
+ if (!Number.isFinite(points)) return 0;
10185
+ return 'condensed' === draft.characterSpacingMode ? -points : points;
10186
+ }
10187
+ function previewDocumentKerning(draft, fontSize) {
10188
+ if (!draft.kerningEnabled) return 'none';
10189
+ const points = Number(draft.kerningThresholdPoints);
10190
+ if (!Number.isFinite(points)) return 'none';
10191
+ return documentKerningIsEffective(2 * points, fontSize) ? 'normal' : 'none';
10192
+ }
10193
+ function previewDocumentEmphasis(emphasisMark) {
10194
+ if ('inherit' === emphasisMark || 'mixed' === emphasisMark || 'none' === emphasisMark) return {
10195
+ textEmphasisStyle: 'none',
10196
+ WebkitTextEmphasisStyle: 'none'
10197
+ };
10198
+ const style = 'comma' === emphasisMark ? '","' : 'circle' === emphasisMark ? 'open circle' : 'filled dot';
10199
+ const position = 'underDot' === emphasisMark ? 'under right' : 'over right';
10200
+ return {
10201
+ textEmphasisStyle: style,
10202
+ textEmphasisPosition: position,
10203
+ WebkitTextEmphasisStyle: style,
10204
+ WebkitTextEmphasisPosition: position
10205
+ };
8646
10206
  }
8647
- function documentLineHeightOptionsForValue(value) {
8648
- if (documentLineHeightOptions.some((option)=>option.value === value)) return documentLineHeightOptions;
8649
- const numeric = Number(value);
10207
+ function scriptFontOptions(value, layoutFonts) {
10208
+ const catalogValue = 'mixed' === value || 'inherit' === value ? 'default' : value;
8650
10209
  return [
8651
- ...documentLineHeightOptions,
8652
10210
  {
8653
- value,
8654
- label: Number.isFinite(numeric) && numeric > 0 ? `${numeric} 倍` : value
8655
- }
10211
+ value: 'mixed',
10212
+ label: '混合(保持不变)',
10213
+ disabled: true
10214
+ },
10215
+ {
10216
+ value: 'inherit',
10217
+ label: '跟随样式'
10218
+ },
10219
+ ...documentFontFamilyOptionsForValue(catalogValue, layoutFonts).filter((option)=>'default' !== option.value)
8656
10220
  ];
8657
10221
  }
8658
- function DocumentPageChromeRibbon({ editor, editingPart, showPageNumber, onEditingPartChange, onTogglePageNumber, onClose }) {
10222
+ function previewScriptFontFamily(value, fallback) {
10223
+ return 'mixed' === value || 'inherit' === value ? fallback ?? void 0 : value;
10224
+ }
10225
+ function fontDialogDescription(source) {
10226
+ return source.selectedCharacters ? `分别设置当前选中内容的拉丁、东亚和复杂文字字体,以及原生字符缩放、间距、字距调整阈值、位置、着重号、隐藏文字、空心、阴影、阳文和阴文(${source.selectedCharacters} 个字符)。` : '分别设置当前位置后续输入文字的拉丁、东亚和复杂文字字体,以及原生字符缩放、间距、字距调整阈值、位置、着重号、隐藏文字、空心、阴影、阳文和阴文。';
10227
+ }
10228
+ function DocumentPageChromeRibbon({ editor, editingPart, showPageNumber, onEditingPartChange, onTogglePageNumber, onOpenFontDialog, onClose }) {
8659
10229
  const imageInputRef = useRef(null);
8660
10230
  const [, setRevision] = useState(0);
8661
10231
  const officeDialog = useOfficeDialog();
@@ -8750,6 +10320,11 @@ function DocumentPageChromeRibbon({ editor, editingPart, showPageNumber, onEditi
8750
10320
  }),
8751
10321
  /*#__PURE__*/ jsxs(WorkOfficeRibbonGroup, {
8752
10322
  label: "文字",
10323
+ dialogLauncher: onOpenFontDialog ? {
10324
+ label: '页眉页脚字体高级设置',
10325
+ ...pageChromeCommandShortcut('fontDialog'),
10326
+ onClick: onOpenFontDialog
10327
+ } : void 0,
8753
10328
  children: [
8754
10329
  /*#__PURE__*/ jsx(PageChromeRibbonButton, {
8755
10330
  label: "页眉页脚加粗",
@@ -8771,15 +10346,18 @@ function DocumentPageChromeRibbon({ editor, editingPart, showPageNumber, onEditi
8771
10346
  size: 16
8772
10347
  })
8773
10348
  }),
8774
- /*#__PURE__*/ jsx(PageChromeRibbonButton, {
10349
+ /*#__PURE__*/ jsx(DocumentUnderlineRibbon, {
10350
+ editor: editor,
8775
10351
  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
- })
10352
+ menuLabel: "页眉页脚下划线样式",
10353
+ colorLabel: "页眉页脚下划线颜色",
10354
+ className: "work-document-page-chrome-underline"
10355
+ }),
10356
+ /*#__PURE__*/ jsx(DocumentStrikeRibbon, {
10357
+ editor: editor,
10358
+ label: "页眉页脚删除线",
10359
+ menuLabel: "页眉页脚删除线样式",
10360
+ className: "work-document-page-chrome-strike"
8783
10361
  }),
8784
10362
  /*#__PURE__*/ jsx(PageChromeRibbonButton, {
8785
10363
  label: "页眉页脚下标",
@@ -12129,6 +13707,26 @@ function runDocumentWpsShortcut(editor, event, callbacks) {
12129
13707
  return false;
12130
13708
  }
12131
13709
  if (event.shiftKey) {
13710
+ if ('h' === key) {
13711
+ editor.commands.toggleDocumentHiddenText();
13712
+ return true;
13713
+ }
13714
+ if ('d' === key) {
13715
+ editor.commands.toggleDocumentUnderlineStyle('double');
13716
+ return true;
13717
+ }
13718
+ if ('w' === key) {
13719
+ editor.commands.toggleDocumentUnderlineStyle('words');
13720
+ return true;
13721
+ }
13722
+ if ('a' === key) {
13723
+ editor.commands.toggleDocumentTextCase('all-caps');
13724
+ return true;
13725
+ }
13726
+ if ('k' === key) {
13727
+ editor.commands.toggleDocumentTextCase('small-caps');
13728
+ return true;
13729
+ }
12132
13730
  if ('g' === key) {
12133
13731
  callbacks.onOpenWordCount();
12134
13732
  return true;
@@ -12163,6 +13761,10 @@ function runDocumentWpsShortcut(editor, event, callbacks) {
12163
13761
  changeDocumentFontSize(editor, -1);
12164
13762
  return true;
12165
13763
  }
13764
+ if ('d' === key) {
13765
+ callbacks.onOpenFontDialog();
13766
+ return true;
13767
+ }
12166
13768
  const alignment = alignmentForShortcut(key);
12167
13769
  if (alignment) {
12168
13770
  editor.chain().focus().setTextAlign(alignment).run();
@@ -12195,8 +13797,9 @@ function headingLevelForShortcut(code, key) {
12195
13797
  if ('3' === value) return 3;
12196
13798
  return null;
12197
13799
  }
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 }) {
13800
+ 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
13801
  const [activeTab, setActiveTab] = useState(reviewOnly ? 'review' : 'home');
13802
+ const [fontDialogRequest, setFontDialogRequest] = useState(null);
12200
13803
  const officeDialog = useOfficeDialog();
12201
13804
  const prompt = officeDialog.prompt;
12202
13805
  const imageSelected = editor.isActive('image');
@@ -12213,6 +13816,18 @@ function DocumentToolbar({ editor, defaultRibbonCollapsed = false, reviewOnly =
12213
13816
  const spellingCommand = getDocumentCommandDefinition('spelling');
12214
13817
  const insertCommentCommand = getDocumentCommandDefinition('insertComment');
12215
13818
  const trackChangesCommand = getDocumentCommandDefinition('trackChanges');
13819
+ const openFontDialog = useCallback((target)=>{
13820
+ if (target.isDestroyed) return;
13821
+ const { from, to } = target.state.selection;
13822
+ setFontDialogRequest({
13823
+ editor: target,
13824
+ selection: {
13825
+ from,
13826
+ to
13827
+ },
13828
+ source: documentFontDialogSource(target)
13829
+ });
13830
+ }, []);
12216
13831
  const ribbonTabs = reviewOnly ? documentRibbonTabs.filter(({ id })=>'review' === id || 'view' === id) : pageChromeEditor ? [
12217
13832
  ...documentRibbonTabs,
12218
13833
  documentPageChromeRibbonTab
@@ -12287,6 +13902,7 @@ function DocumentToolbar({ editor, defaultRibbonCollapsed = false, reviewOnly =
12287
13902
  if (event.defaultPrevented || event.repeat || isOfficeShortcutBlocked(event.target)) return;
12288
13903
  const key = event.key.toLowerCase();
12289
13904
  const insideEditor = event.target instanceof Node && Boolean(editorDom?.contains(event.target));
13905
+ const insidePageChromeEditor = event.target instanceof Node && Boolean(pageChromeEditor?.view.dom.contains(event.target));
12290
13906
  if (reviewOnly) {
12291
13907
  if (insideEditor && (event.metaKey || event.ctrlKey) && event.altKey && !event.shiftKey && 'm' === key) {
12292
13908
  event.preventDefault();
@@ -12294,10 +13910,16 @@ function DocumentToolbar({ editor, defaultRibbonCollapsed = false, reviewOnly =
12294
13910
  }
12295
13911
  return;
12296
13912
  }
13913
+ if (insidePageChromeEditor && (event.metaKey || event.ctrlKey) && !event.altKey && !event.shiftKey && 'd' === key) {
13914
+ event.preventDefault();
13915
+ openFontDialog(pageChromeEditor);
13916
+ return;
13917
+ }
12297
13918
  if (insideEditor && runDocumentWpsShortcut(editor, event, {
12298
13919
  canInsertComment,
12299
13920
  canRefreshFields: hasRefreshableFields,
12300
13921
  onInsertComment,
13922
+ onOpenFontDialog: ()=>openFontDialog(editor),
12301
13923
  onOpenWordCount,
12302
13924
  onRefreshFields,
12303
13925
  onToggleSpellcheck,
@@ -12371,12 +13993,14 @@ function DocumentToolbar({ editor, defaultRibbonCollapsed = false, reviewOnly =
12371
13993
  hasRefreshableFields,
12372
13994
  history,
12373
13995
  onInsertComment,
13996
+ openFontDialog,
12374
13997
  onOpenFindReplace,
12375
13998
  onOpenWordCount,
12376
13999
  onRefreshFields,
12377
14000
  reviewOnly,
12378
14001
  onToggleSpellcheck,
12379
14002
  onToggleTrackChanges,
14003
+ pageChromeEditor,
12380
14004
  toggleLink
12381
14005
  ]);
12382
14006
  const selectDocumentChange = (change)=>{
@@ -12462,6 +14086,7 @@ function DocumentToolbar({ editor, defaultRibbonCollapsed = false, reviewOnly =
12462
14086
  editor: editor,
12463
14087
  findReplaceMode: findReplaceMode,
12464
14088
  layoutFonts: layoutFonts,
14089
+ onOpenFontDialog: ()=>openFontDialog(editor),
12465
14090
  onFindText: (replace)=>onOpenFindReplace(replace ? 'replace' : 'find')
12466
14091
  }),
12467
14092
  insert: reviewOnly ? null : /*#__PURE__*/ jsxs(Fragment, {
@@ -12833,6 +14458,16 @@ function DocumentToolbar({ editor, defaultRibbonCollapsed = false, reviewOnly =
12833
14458
  children: /*#__PURE__*/ jsx(PanelLeftOpen, {
12834
14459
  size: 19
12835
14460
  })
14461
+ }),
14462
+ /*#__PURE__*/ jsx(document_toolbar_ToolbarButton, {
14463
+ label: "显示隐藏文字",
14464
+ displayLabel: true,
14465
+ active: showHiddenText,
14466
+ title: "显示或隐藏以隐藏文字格式标记的内容",
14467
+ onClick: onToggleHiddenText,
14468
+ children: /*#__PURE__*/ jsx(Eye, {
14469
+ size: 19
14470
+ })
12836
14471
  })
12837
14472
  ]
12838
14473
  }),
@@ -12897,10 +14532,27 @@ function DocumentToolbar({ editor, defaultRibbonCollapsed = false, reviewOnly =
12897
14532
  showPageNumber: pageChromeShowPageNumber,
12898
14533
  onEditingPartChange: onPageChromeEditingPartChange,
12899
14534
  onTogglePageNumber: onTogglePageChromePageNumber,
14535
+ onOpenFontDialog: ()=>openFontDialog(pageChromeEditor),
12900
14536
  onClose: onClosePageChrome
12901
14537
  }) : null
12902
14538
  }
12903
14539
  }),
14540
+ fontDialogRequest && /*#__PURE__*/ jsx(DocumentFontDialog, {
14541
+ source: fontDialogRequest.source,
14542
+ layoutFonts: layoutFonts,
14543
+ restoreFocusTarget: ()=>fontDialogRequest.editor.isDestroyed ? null : fontDialogRequest.editor.view.dom,
14544
+ onApply: (patch)=>applyDocumentFontDialogPatch(fontDialogRequest.editor, fontDialogRequest.selection, patch),
14545
+ onClose: ()=>{
14546
+ const { editor: dialogEditor, selection } = fontDialogRequest;
14547
+ setFontDialogRequest(null);
14548
+ requestAnimationFrame(()=>{
14549
+ if (dialogEditor.isDestroyed) return;
14550
+ dialogEditor.chain().setTextSelection(selection).focus(null, {
14551
+ scrollIntoView: false
14552
+ }).run();
14553
+ });
14554
+ }
14555
+ }),
12904
14556
  officeDialog.dialog
12905
14557
  ]
12906
14558
  });
@@ -14917,6 +16569,7 @@ function DocumentEditorSurface({ artifactId, autoFocus = true, collaboration, co
14917
16569
  const findReplaceMode = 'find' === taskPane || 'replace' === taskPane ? taskPane : null;
14918
16570
  const [spellcheckEnabled, setSpellcheckEnabled] = useState(true);
14919
16571
  const [viewMode, setViewMode] = useState('page');
16572
+ const [showHiddenText, setShowHiddenText] = useState(false);
14920
16573
  const [showRulers, setShowRulers] = useState(false);
14921
16574
  const [zoom, setZoom] = useState(90);
14922
16575
  const [selectionMenu, setSelectionMenu] = useState(null);
@@ -15017,7 +16670,6 @@ function DocumentEditorSurface({ artifactId, autoFocus = true, collaboration, co
15017
16670
  model,
15018
16671
  comments: retainAnchoredDocumentComments(previousContent.comments ?? [], anchors, retainedCommentIds)
15019
16672
  };
15020
- appliedSourceKeyRef.current = `model:${model.revision}:${model.htmlFingerprint}`;
15021
16673
  if (!collaborationBindingRef.current) {
15022
16674
  contentRef.current = next;
15023
16675
  onChangeRef.current(next);
@@ -15633,7 +17285,7 @@ function DocumentEditorSurface({ artifactId, autoFocus = true, collaboration, co
15633
17285
  return true;
15634
17286
  };
15635
17287
  return /*#__PURE__*/ jsxs("section", {
15636
- className: `work-document-editor${preview ? ' preview' : ''}`,
17288
+ className: `work-document-editor${preview ? ' preview' : ''}${!preview && showHiddenText ? ' show-hidden-text' : ''}`,
15637
17289
  "data-collaboration-mode": collaboration?.mode,
15638
17290
  "data-work-pdf-artifact": artifactId,
15639
17291
  "data-work-pdf-surface": artifactId ? 'live' : void 0,
@@ -15668,6 +17320,7 @@ function DocumentEditorSurface({ artifactId, autoFocus = true, collaboration, co
15668
17320
  navigationOpen: navigationOpen,
15669
17321
  pageColor: documentPageColor(currentContent.pageColor),
15670
17322
  showPageNumbers: visibleChrome.showPageNumber,
17323
+ showHiddenText: showHiddenText,
15671
17324
  showRulers: showRulers,
15672
17325
  spellcheckEnabled: spellcheckEnabled,
15673
17326
  viewMode: viewMode,
@@ -15683,6 +17336,10 @@ function DocumentEditorSurface({ artifactId, autoFocus = true, collaboration, co
15683
17336
  onLayoutChange: updateToolbarLayout,
15684
17337
  onOpenLayout: openLayoutPanel,
15685
17338
  onToggleNavigation: ()=>void toggleTaskPane('navigation'),
17339
+ onToggleHiddenText: ()=>{
17340
+ setShowHiddenText((value)=>!value);
17341
+ restoreDocumentBodyFocus();
17342
+ },
15686
17343
  onToggleRulers: ()=>{
15687
17344
  setShowRulers((value)=>!value);
15688
17345
  restoreDocumentBodyFocus();