@a3s-lab/office 0.29.0 → 0.30.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 (50) hide show
  1. package/README.md +100 -3
  2. package/dist/{0~7043.js → 0~7231.js} +160 -2
  3. package/dist/{0~5093.js → 0~7360.js} +233 -52
  4. package/dist/0~document-editor.js +1159 -149
  5. package/dist/0~spreadsheet-editor.js +183 -34
  6. package/dist/0~work-docx-export.js +299 -11
  7. package/dist/0~work-docx-import.js +30 -7
  8. package/dist/0~work-office-diagnostics.js +125 -5
  9. package/dist/1544.js +13 -1
  10. package/dist/4104.js +29 -6
  11. package/dist/4121.js +1939 -1
  12. package/dist/6282.js +501 -1006
  13. package/dist/internal/features/work/editors/document-command-catalog.d.ts +18 -0
  14. package/dist/internal/features/work/editors/document-font-dialog-model.d.ts +5 -2
  15. package/dist/internal/features/work/editors/document-font-dialog-run-shading-model.d.ts +23 -0
  16. package/dist/internal/features/work/editors/document-font-dialog-run-shading-section.d.ts +8 -0
  17. package/dist/internal/features/work/editors/document-page-chrome-ribbon.d.ts +2 -1
  18. package/dist/internal/features/work/editors/document-proofing-dialog-model.d.ts +22 -0
  19. package/dist/internal/features/work/editors/document-proofing-dialog.d.ts +7 -0
  20. package/dist/internal/features/work/editors/document-table-of-contents-dialog.d.ts +10 -0
  21. package/dist/internal/features/work/editors/document-toolbar.d.ts +3 -1
  22. package/dist/internal/features/work/editors/spreadsheet-data-validation.d.ts +7 -1
  23. package/dist/internal/features/work/editors/use-document-insert-commands.d.ts +2 -0
  24. package/dist/internal/features/work/work-document-character-formatting.d.ts +8 -0
  25. package/dist/internal/features/work/work-document-format-changes.d.ts +6 -0
  26. package/dist/internal/features/work/work-document-highlight.d.ts +9 -0
  27. package/dist/internal/features/work/work-document-outline.d.ts +1 -0
  28. package/dist/internal/features/work/work-document-paragraph-shading.d.ts +6 -0
  29. package/dist/internal/features/work/work-document-proofing.d.ts +19 -0
  30. package/dist/internal/features/work/work-document-run-shading.d.ts +12 -0
  31. package/dist/internal/features/work/work-document-table-of-contents-node.d.ts +18 -0
  32. package/dist/internal/features/work/work-document-table-of-contents.d.ts +51 -0
  33. package/dist/internal/features/work/work-document-word-line-metrics.d.ts +3 -0
  34. package/dist/internal/features/work/work-docx-field-instructions.d.ts +1 -1
  35. package/dist/internal/features/work/work-docx-import.d.ts +3 -1
  36. package/dist/internal/features/work/work-docx-proofing-diagnostics.d.ts +3 -0
  37. package/dist/internal/features/work/work-docx-proofing.d.ts +38 -0
  38. package/dist/internal/features/work/work-docx-run-formatting-import.d.ts +7 -0
  39. package/dist/internal/features/work/work-docx-run-shading-diagnostics.d.ts +3 -0
  40. package/dist/internal/features/work/work-docx-run-shading-export.d.ts +17 -0
  41. package/dist/internal/features/work/work-docx-run-shading.d.ts +20 -0
  42. package/dist/internal/features/work/work-docx-table-of-contents-export.d.ts +11 -0
  43. package/dist/internal/features/work/work-docx-table-of-contents-import.d.ts +15 -0
  44. package/dist/internal/features/work/work-spreadsheet-data-validation.d.ts +7 -0
  45. package/dist/internal/features/work/work-types.d.ts +9 -0
  46. package/dist/internal/kernel/office-kernel-protocol.d.ts +1 -0
  47. package/dist/office-kernel.wasm +0 -0
  48. package/dist/styles.css +311 -4
  49. package/docs/latest/en/browser-editor-architecture.md +50 -1
  50. package/package.json +12 -2
@@ -6,7 +6,7 @@ import { Fragment as external_react_Fragment, forwardRef, useCallback, useEffect
6
6
  import { Extension, createNodeFromContent } from "@tiptap/core";
7
7
  import { NodeSelection, Plugin, PluginKey, TextSelection } from "@tiptap/pm/state";
8
8
  import { Decoration, DecorationSet } from "@tiptap/pm/view";
9
- import { AArrowDown, AArrowUp, 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, Square, StretchHorizontal, Strikethrough, Subscript, Superscript, Table2, TableCellsMerge, TableCellsSplit, TableProperties, TextWrap, Trash2, TriangleAlert, Type, 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, Languages, Link2, List, ListChecks, ListOrdered, ListTree, 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, Square, 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";
@@ -15,11 +15,11 @@ import font_size from "@tiptap/extension-text-style/font-size";
15
15
  import starter_kit from "@tiptap/starter-kit";
16
16
  import { BubbleMenu } from "@tiptap/react/menus";
17
17
  import { TableMap, isInTable, selectedRect } from "@tiptap/pm/tables";
18
- import { documentTableSizing, transferChangedDocumentTextStatistics, documentPageBordersVisible, documentUnderlineStyle, DOCUMENT_PAGE_BORDER_EDGES, documentScriptFontDirectFamily, normalizeDocumentColumns, clampDocumentMargin, materializeLazyDocumentEditorRoot, patchDocumentScriptFonts, documentKerningThresholdPoints, nextDocumentTabAlignment, documentTableRowOptions, normalizedTabPosition, DOCUMENT_BOOKMARK_DUPLICATE_MESSAGE, documentCitationCount, 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";
18
+ import { documentTableSizing, transferChangedDocumentTextStatistics, documentPageBordersVisible, documentUnderlineStyle, DOCUMENT_PAGE_BORDER_EDGES, documentTableRowOptions, normalizeDocumentColumns, clampDocumentMargin, materializeLazyDocumentEditorRoot, documentKerningThresholdPoints, DOCUMENT_BOOKMARK_DUPLICATE_MESSAGE, nextDocumentTabAlignment, documentCitationCount, normalizedTabPosition, 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, activeDocumentSection, DocumentParagraphFormatting, normalizeDocumentHtml, documentInitialSectionLayout, documentModelHasTrustedInitialIntegrityFeatures, documentModelUsesWindowing, documentParagraphDirection, documentParagraphPagination, documentPageChromeLegacyFields, documentChunkMountedIds, collectDocumentCommentAnchors, documentTextCaseKeyboardShortcuts, DocumentTextStyle, canChangeDocumentIndent, documentCharacterSpacingPoints, documentKerningIsEffective, DocumentSuperscript, documentSectionById, activeDocumentBookmark, DocumentEquation, documentLazyHtmlProjectionFingerprint, documentLazyHtmlProjection, normalizeDocumentParagraphIndent, updateDocumentGutterPosition, DocumentStrike, mountWorkLiveDocumentCapture, registerDocumentPageSurfaceGeometry, documentHiddenTextKeyboardShortcut, syncDocumentContentFromHtml, documentLegacyTextEffectsCss, editorDocumentCaptionTargets, resolveDocumentPageChrome, documentImageLayoutOptions, MAX_DOCUMENT_NUMBERING_START, resolveDocumentPageSize, editorDocumentBookmarkReferenceTargets, serializeWorkDocumentNode, DOCUMENT_CHUNK_PAGINATION_META, createOfficeDocumentCollaborationBinding as createWorkOfficeDocumentCollaborationBinding, documentModelForContent, documentLegacyTextEffectsFromTextStyleAttributes, normalizeDocumentEmphasisMark, selectedDocumentChunkId, documentCommentViews, documentParagraphSpacing, normalizeDocumentTabStops, patchDocumentLazyHtmlProjection, normalizeDocumentTextCase, documentUnderlineColor, documentBookmarkNameExists, collectDocumentChanges, DocumentImage, selectedDocumentTableOfContentsOptions, resolveDocumentPageMargins, updateDocumentPageMarginMode, canSetDocumentTableRowRepeatHeader, normalizeDocumentCharacterSpacingTwips, DocumentCharacterFormatting, millimetersToPixels as work_document_layout_millimetersToPixels, DOCUMENT_CHUNK_HYDRATION_META, documentTabLeaderLabel, createSchemaDerivedWorkDocumentModel, updateDocumentCustomPageMillimeters, DocumentUnderline, documentCommentDraftRange, documentParagraphTabStops, documentTableHorizontalAlignment, documentUnderlineKeyboardShortcuts, documentParagraphIndent, DocumentScriptFontFormatting, canInsertDocumentComment, documentHasTableOfContents, documentTextLayoutBatches, normalizeDocumentImageWrapSide, updateDocumentPageOrientation, documentCitationStyleDetails, validateDocumentBookmarkName, setCustomDocumentColumns, updateDocumentPageMarginMillimeters, documentCitationStyle, normalizeDocumentCharacterPositionHalfPoints, documentTransactionsOnlyHydrateChunks, normalizeDocumentKerningThresholdHalfPoints, DEFAULT_DOCUMENT_TABLE_CELL_MARGINS, DOCUMENT_TABLE_STYLE_OPTIONS, updateDocumentColumnWidth, updateDocumentPaperSizePreset, documentPageMetrics, documentStrikeStyle, DocumentHighlight, createDocumentBibliography, DocumentSubscript, updateDocumentPageChromeVariant, updateDocumentMirrorMargins, activeDocumentTableStyle, measureDocumentLayoutBlocksIncrementally, documentWordLineHeightFactor, normalizeDocumentLegacyTextEffect, createWorkDocumentExtensions } from "./6282.js";
19
19
  import { useOfficeTaskPaneEscape, normalizeOfficeFontFamily, OfficeCheckbox, useOfficeDialog, useOfficeTaskPaneModal, CommittedOfficeNumberField, officeFontFamilyLabel, officeFontFamilies, CollectionState, createOfficeKernelClient, OfficeNumberField } from "./0~7048.js";
20
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";
21
21
  import { WorkOfficePreviewBar, isWorkspaceContextMenuKeyboardEvent, Tabs, WorkOfficeZoomControls, WorkOfficeStatusBar, Dialog, WorkOfficeRibbon, workspaceContextMenuPosition, OfficeSelect, WorkspaceContextMenu, WorkOfficeRibbonGroup, WorkOfficeRibbonButton } from "./0~4595.js";
22
- import { documentBorderPresentation, normalizeDocumentRunBorder, parseDocumentRunBorder, DOCUMENT_RUN_BORDER_STYLES, isDocumentParagraphArtBorderStyle, serializeDocumentRunBorder, createOfficeId as createWorkId, documentRunBorderIsVisible } from "./4121.js";
22
+ import { documentFontNameFromCssFamily, normalizeDocumentRunBorder, parseDocumentScriptFonts, parseDocumentRunShading, DOCUMENT_RUN_BORDER_STYLES, serializeDocumentRunBorder, documentScriptFontDirectFamily, serializeDocumentRunShading, patchDocumentScriptFonts, serializeDocumentScriptFonts, documentRunBorderIsVisible, cssDocumentFontFamily, isDocumentParagraphArtBorderStyle, visibleWorkDocumentOutlineItems, DEFAULT_DOCUMENT_TABLE_OF_CONTENTS_OPTIONS, createOfficeId as createWorkId, normalizeDocumentLanguageTag, currentWorkDocumentOutlineItem, normalizeDocumentNoProof, parseDocumentRunBorder, DocumentParagraphIdentity, parseDocumentProofingLanguages, collectWorkDocumentOutline, documentScriptFontSlotFromHint, documentBorderPresentation, documentScriptFontFamilyForRendering, normalizeDocumentRunShading, normalizeDocumentScriptFontSlot, documentScriptFontSegments, patchDocumentProofingLanguages, serializeDocumentProofingLanguages, documentRunShadingDomAttributes } from "./4121.js";
23
23
  import { normalizeDocumentHref, DOCUMENT_LINK_VALIDATION_MESSAGE } from "./0~work-document-links.js";
24
24
  import { OfficeColorPicker, isOfficeShortcutBlocked } from "./0~3635.js";
25
25
  import { OfficeTableInsertPopover, readOfficeFileAsDataUrl } from "./0~9445.js";
@@ -4087,6 +4087,9 @@ function createDocumentPageChromeEditorExtensions(placeholder = '输入页眉或
4087
4087
  DocumentFontFamily,
4088
4088
  font_size,
4089
4089
  extension_color,
4090
+ DocumentHighlight.configure({
4091
+ multicolor: true
4092
+ }),
4090
4093
  DocumentUnderline,
4091
4094
  DocumentStrike,
4092
4095
  DocumentCharacterFormatting,
@@ -4804,65 +4807,6 @@ function normalizeDocumentPageNumberInput(value) {
4804
4807
  const number = Number(value);
4805
4808
  return Number.isFinite(number) ? Math.min(9999, Math.max(1, Math.round(number))) : null;
4806
4809
  }
4807
- function collectWorkDocumentOutline(document1) {
4808
- const items = [];
4809
- const hierarchy = [];
4810
- document1.descendants((node, position)=>{
4811
- if ('heading' !== node.type.name) return;
4812
- const level = documentHeadingLevel(node.attrs.level);
4813
- while((hierarchy.at(-1)?.level ?? 0) >= level)hierarchy.pop();
4814
- const parent = hierarchy.at(-1);
4815
- const from = position + 1;
4816
- const item = {
4817
- id: `heading-${position}`,
4818
- text: normalizedDocumentHeadingText(node.textContent),
4819
- level,
4820
- depth: hierarchy.length,
4821
- from,
4822
- to: from + node.content.size,
4823
- ...parent ? {
4824
- parentId: parent.id
4825
- } : {}
4826
- };
4827
- items.push(item);
4828
- hierarchy.push(item);
4829
- });
4830
- return items.map((item, index)=>({
4831
- ...item,
4832
- hasChildren: (items[index + 1]?.depth ?? -1) > item.depth
4833
- }));
4834
- }
4835
- function currentWorkDocumentOutlineItem(items, position) {
4836
- let current = null;
4837
- for (const item of items){
4838
- if (item.from > position) break;
4839
- current = item;
4840
- }
4841
- return current;
4842
- }
4843
- function visibleWorkDocumentOutlineItems(items, collapsedIds, rawQuery) {
4844
- const query = normalizedDocumentOutlineQuery(rawQuery);
4845
- if (query) return items.filter((item)=>normalizedDocumentOutlineQuery(item.text).includes(query));
4846
- const visible = [];
4847
- let hiddenBelowDepth = null;
4848
- for (const item of items){
4849
- if (null !== hiddenBelowDepth && item.depth <= hiddenBelowDepth) hiddenBelowDepth = null;
4850
- if (null === hiddenBelowDepth) {
4851
- visible.push(item);
4852
- if (item.hasChildren && collapsedIds.has(item.id)) hiddenBelowDepth = item.depth;
4853
- }
4854
- }
4855
- return visible;
4856
- }
4857
- function documentHeadingLevel(value) {
4858
- return 'number' == typeof value && Number.isInteger(value) && value >= 1 && value <= 6 ? value : 1;
4859
- }
4860
- function normalizedDocumentHeadingText(value) {
4861
- return value.replace(/\s+/g, ' ').trim() || '未命名标题';
4862
- }
4863
- function normalizedDocumentOutlineQuery(value) {
4864
- return value.normalize('NFKC').trim().toLocaleLowerCase();
4865
- }
4866
4810
  const DOCUMENT_OUTLINE_ITEM_HEIGHT = 31;
4867
4811
  const DOCUMENT_OUTLINE_LIST_PADDING_TOP = 6;
4868
4812
  const document_outline_navigation_DocumentOutlineNavigation = /*#__PURE__*/ forwardRef(function({ activeItemId, collapsedIds, items, rovingId, onNavigate, onRovingIdChange, onToggleCollapsed }, ref) {
@@ -7521,6 +7465,24 @@ const documentCommandCatalog = {
7521
7465
  ]
7522
7466
  }
7523
7467
  },
7468
+ tableOfContents: {
7469
+ id: 'references.tableOfContents',
7470
+ label: '插入或自定义目录',
7471
+ location: {
7472
+ area: 'ribbon',
7473
+ tab: 'references',
7474
+ group: 'tableOfContents'
7475
+ }
7476
+ },
7477
+ refreshTableOfContents: {
7478
+ id: 'references.refreshTableOfContents',
7479
+ label: '更新目录',
7480
+ location: {
7481
+ area: 'ribbon',
7482
+ tab: 'references',
7483
+ group: 'tableOfContents'
7484
+ }
7485
+ },
7524
7486
  refreshFields: {
7525
7487
  id: 'references.refreshFields',
7526
7488
  label: '更新域',
@@ -8107,6 +8069,428 @@ function DocumentStatusBar({ bibliographyCount, citationCount, currentPage, page
8107
8069
  ]
8108
8070
  });
8109
8071
  }
8072
+ const proofingStateOptions = [
8073
+ {
8074
+ value: 'mixed',
8075
+ label: '混合(保持不变)',
8076
+ disabled: true
8077
+ },
8078
+ {
8079
+ value: 'inherit',
8080
+ label: '跟随样式'
8081
+ },
8082
+ {
8083
+ value: 'check',
8084
+ label: '检查拼写和语法'
8085
+ },
8086
+ {
8087
+ value: 'skip',
8088
+ label: '不检查拼写或语法'
8089
+ }
8090
+ ];
8091
+ const proofingLanguageSuggestions = [
8092
+ 'en-US',
8093
+ 'en-GB',
8094
+ 'zh-CN',
8095
+ 'zh-TW',
8096
+ 'ja-JP',
8097
+ 'ko-KR',
8098
+ 'ar-SA',
8099
+ 'he-IL',
8100
+ 'fr-FR',
8101
+ 'de-DE',
8102
+ 'es-ES',
8103
+ 'x-none'
8104
+ ];
8105
+ function DocumentProofingDialog({ source, restoreFocusTarget, onApply, onClose }) {
8106
+ const [draft, setDraft] = useState(()=>({
8107
+ latin: source.latin.value ?? '',
8108
+ eastAsia: source.eastAsia.value ?? '',
8109
+ bidi: source.bidi.value ?? '',
8110
+ noProof: proofingStateDraft(source)
8111
+ }));
8112
+ const [touched, setTouched] = useState({
8113
+ latin: false,
8114
+ eastAsia: false,
8115
+ bidi: false,
8116
+ noProof: false
8117
+ });
8118
+ const formId = useId();
8119
+ const datalistId = useId();
8120
+ const error = proofingDialogError(draft, touched);
8121
+ const patch = proofingDialogPatch(source, draft, touched);
8122
+ const hasChanges = Object.keys(patch).length > 0;
8123
+ const submit = (event)=>{
8124
+ event?.preventDefault();
8125
+ if (!hasChanges || error) return;
8126
+ if (onApply(patch)) onClose();
8127
+ };
8128
+ return /*#__PURE__*/ jsx(Dialog, {
8129
+ title: "设置校对语言",
8130
+ description: source.selectedCharacters ? `为选中的 ${source.selectedCharacters} 个字符分别设置拉丁、东亚和双向文字校对语言。` : '设置当前位置后续输入文字的校对语言。',
8131
+ className: "work-document-proofing-dialog",
8132
+ restoreFocusTarget: restoreFocusTarget,
8133
+ onClose: onClose,
8134
+ footer: /*#__PURE__*/ jsxs(Fragment, {
8135
+ children: [
8136
+ /*#__PURE__*/ jsx(button_Button, {
8137
+ tone: "quiet",
8138
+ onClick: onClose,
8139
+ children: "取消"
8140
+ }),
8141
+ /*#__PURE__*/ jsx(button_Button, {
8142
+ tone: "primary",
8143
+ type: "submit",
8144
+ form: formId,
8145
+ disabled: !hasChanges || Boolean(error),
8146
+ children: "应用"
8147
+ })
8148
+ ]
8149
+ }),
8150
+ children: /*#__PURE__*/ jsxs("form", {
8151
+ id: formId,
8152
+ onSubmit: submit,
8153
+ children: [
8154
+ /*#__PURE__*/ jsxs("fieldset", {
8155
+ children: [
8156
+ /*#__PURE__*/ jsx("legend", {
8157
+ children: "按文字系统设置语言"
8158
+ }),
8159
+ /*#__PURE__*/ jsx(ProofingLanguageField, {
8160
+ label: "拉丁文字",
8161
+ languageKey: "latin",
8162
+ value: draft.latin,
8163
+ mixed: source.latin.mixed && !touched.latin,
8164
+ list: datalistId,
8165
+ initialFocus: true,
8166
+ error: touched.latin && !validLanguageDraft(draft.latin),
8167
+ onChange: (value)=>{
8168
+ setDraft((current)=>({
8169
+ ...current,
8170
+ latin: value
8171
+ }));
8172
+ setTouched((current)=>({
8173
+ ...current,
8174
+ latin: true
8175
+ }));
8176
+ }
8177
+ }),
8178
+ /*#__PURE__*/ jsx(ProofingLanguageField, {
8179
+ label: "东亚文字",
8180
+ languageKey: "eastAsia",
8181
+ value: draft.eastAsia,
8182
+ mixed: source.eastAsia.mixed && !touched.eastAsia,
8183
+ list: datalistId,
8184
+ error: touched.eastAsia && !validLanguageDraft(draft.eastAsia),
8185
+ onChange: (value)=>{
8186
+ setDraft((current)=>({
8187
+ ...current,
8188
+ eastAsia: value
8189
+ }));
8190
+ setTouched((current)=>({
8191
+ ...current,
8192
+ eastAsia: true
8193
+ }));
8194
+ }
8195
+ }),
8196
+ /*#__PURE__*/ jsx(ProofingLanguageField, {
8197
+ label: "双向文字",
8198
+ languageKey: "bidi",
8199
+ value: draft.bidi,
8200
+ mixed: source.bidi.mixed && !touched.bidi,
8201
+ list: datalistId,
8202
+ error: touched.bidi && !validLanguageDraft(draft.bidi),
8203
+ onChange: (value)=>{
8204
+ setDraft((current)=>({
8205
+ ...current,
8206
+ bidi: value
8207
+ }));
8208
+ setTouched((current)=>({
8209
+ ...current,
8210
+ bidi: true
8211
+ }));
8212
+ }
8213
+ }),
8214
+ /*#__PURE__*/ jsx("datalist", {
8215
+ id: datalistId,
8216
+ children: proofingLanguageSuggestions.map((language)=>/*#__PURE__*/ jsx("option", {
8217
+ value: language
8218
+ }, language))
8219
+ })
8220
+ ]
8221
+ }),
8222
+ /*#__PURE__*/ jsxs("div", {
8223
+ className: "work-document-proofing-dialog-state",
8224
+ children: [
8225
+ /*#__PURE__*/ jsx("span", {
8226
+ className: "work-document-proofing-dialog-state-label",
8227
+ "aria-hidden": "true",
8228
+ children: "校对行为"
8229
+ }),
8230
+ /*#__PURE__*/ jsx(OfficeSelect, {
8231
+ ariaLabel: "校对行为",
8232
+ value: draft.noProof,
8233
+ options: proofingStateOptions,
8234
+ onValueChange: (noProof)=>{
8235
+ setDraft((current)=>({
8236
+ ...current,
8237
+ noProof
8238
+ }));
8239
+ setTouched((current)=>({
8240
+ ...current,
8241
+ noProof: true
8242
+ }));
8243
+ }
8244
+ }),
8245
+ source.noProof.mixed && !touched.noProof && /*#__PURE__*/ jsx("p", {
8246
+ role: "status",
8247
+ children: "当前选区包含不同的校对行为,保持不变。"
8248
+ })
8249
+ ]
8250
+ }),
8251
+ /*#__PURE__*/ jsxs("p", {
8252
+ className: "work-document-proofing-dialog-help",
8253
+ children: [
8254
+ "使用 BCP 47 语言标记,例如 ",
8255
+ /*#__PURE__*/ jsx("code", {
8256
+ children: "en-US"
8257
+ }),
8258
+ "、",
8259
+ /*#__PURE__*/ jsx("code", {
8260
+ children: "zh-CN"
8261
+ }),
8262
+ " 或",
8263
+ ' ',
8264
+ /*#__PURE__*/ jsx("code", {
8265
+ children: "ar-SA"
8266
+ }),
8267
+ "。留空或选择“跟随样式”会移除直接格式。"
8268
+ ]
8269
+ }),
8270
+ error && /*#__PURE__*/ jsx("p", {
8271
+ className: "work-document-proofing-dialog-error",
8272
+ role: "alert",
8273
+ children: error
8274
+ })
8275
+ ]
8276
+ })
8277
+ });
8278
+ }
8279
+ function ProofingLanguageField({ label, languageKey, value, mixed, list, initialFocus = false, error, onChange }) {
8280
+ return /*#__PURE__*/ jsxs("div", {
8281
+ className: "work-document-proofing-dialog-language",
8282
+ children: [
8283
+ /*#__PURE__*/ jsx("label", {
8284
+ htmlFor: `work-document-proofing-${languageKey}`,
8285
+ children: label
8286
+ }),
8287
+ /*#__PURE__*/ jsxs("div", {
8288
+ children: [
8289
+ /*#__PURE__*/ jsx(office_text_field_OfficeTextField, {
8290
+ id: `work-document-proofing-${languageKey}`,
8291
+ "aria-label": `${label}校对语言`,
8292
+ "aria-invalid": error || void 0,
8293
+ "data-autofocus": initialFocus ? 'true' : void 0,
8294
+ list: list,
8295
+ value: value,
8296
+ placeholder: mixed ? '混合(保持不变)' : '跟随样式',
8297
+ spellCheck: false,
8298
+ onChange: (event)=>onChange(event.currentTarget.value)
8299
+ }),
8300
+ /*#__PURE__*/ jsx(button_Button, {
8301
+ tone: "quiet",
8302
+ type: "button",
8303
+ "aria-label": `${label}跟随样式`,
8304
+ onClick: ()=>onChange(''),
8305
+ children: "跟随样式"
8306
+ })
8307
+ ]
8308
+ }),
8309
+ mixed && /*#__PURE__*/ jsxs("p", {
8310
+ role: "status",
8311
+ children: [
8312
+ "当前选区包含不同的",
8313
+ label,
8314
+ "校对语言,输入后才会统一修改。"
8315
+ ]
8316
+ })
8317
+ ]
8318
+ });
8319
+ }
8320
+ function proofingStateDraft(source) {
8321
+ if (source.noProof.mixed) return 'mixed';
8322
+ if (null === source.noProof.value) return 'inherit';
8323
+ return source.noProof.value ? 'skip' : 'check';
8324
+ }
8325
+ function proofingDialogPatch(source, draft, touched) {
8326
+ const languages = {};
8327
+ for (const key of [
8328
+ 'latin',
8329
+ 'eastAsia',
8330
+ 'bidi'
8331
+ ]){
8332
+ if (!touched[key] || !validLanguageDraft(draft[key])) continue;
8333
+ const value = draft[key] || null;
8334
+ if (source[key].mixed || source[key].value !== value) languages[key] = value;
8335
+ }
8336
+ const patch = {};
8337
+ if (Object.keys(languages).length) patch.languages = languages;
8338
+ if (touched.noProof && 'mixed' !== draft.noProof) {
8339
+ const noProof = 'inherit' === draft.noProof ? null : 'skip' === draft.noProof;
8340
+ if (source.noProof.mixed || source.noProof.value !== noProof) patch.noProof = noProof;
8341
+ }
8342
+ return patch;
8343
+ }
8344
+ function proofingDialogError(draft, touched) {
8345
+ for (const key of [
8346
+ 'latin',
8347
+ 'eastAsia',
8348
+ 'bidi'
8349
+ ])if (touched[key] && !validLanguageDraft(draft[key])) return '请输入有效的 BCP 47 语言标记;不能包含空格、下划线或控制字符。';
8350
+ return null;
8351
+ }
8352
+ function validLanguageDraft(value) {
8353
+ return '' === value || null !== normalizeDocumentLanguageTag(value);
8354
+ }
8355
+ const PROOFING_LANGUAGE_SLOTS = [
8356
+ 'latin',
8357
+ 'eastAsia',
8358
+ 'bidi'
8359
+ ];
8360
+ const PROOFING_LANGUAGE_SLOT_SET = new Set(PROOFING_LANGUAGE_SLOTS);
8361
+ function documentProofingDialogSource(editor) {
8362
+ const latin = new Map();
8363
+ const eastAsia = new Map();
8364
+ const bidi = new Map();
8365
+ const noProof = new Map();
8366
+ const { doc, selection } = editor.state;
8367
+ const addValues = (attributes)=>{
8368
+ const languages = parseDocumentProofingLanguages(attributes.proofingLanguages);
8369
+ addSelectedValue(latin, languages?.latin ?? null);
8370
+ addSelectedValue(eastAsia, languages?.eastAsia ?? null);
8371
+ addSelectedValue(bidi, languages?.bidi ?? null);
8372
+ addSelectedValue(noProof, normalizeDocumentNoProof(attributes.noProof));
8373
+ };
8374
+ if (selection.empty) addValues(editor.getAttributes('textStyle'));
8375
+ else doc.nodesBetween(selection.from, selection.to, (node, position)=>{
8376
+ if (!node.isText || position >= selection.to || position + node.nodeSize <= selection.from) return;
8377
+ const textStyle = node.marks.find((mark)=>'textStyle' === mark.type.name);
8378
+ addValues(textStyle?.attrs ?? {});
8379
+ });
8380
+ if (!latin.size) addValues(editor.getAttributes('textStyle'));
8381
+ const selectedText = selection.empty ? '' : doc.textBetween(selection.from, selection.to, '', '');
8382
+ return {
8383
+ latin: selectedValue(latin),
8384
+ eastAsia: selectedValue(eastAsia),
8385
+ bidi: selectedValue(bidi),
8386
+ noProof: selectedValue(noProof),
8387
+ selectedCharacters: Array.from(selectedText).length
8388
+ };
8389
+ }
8390
+ function applyDocumentProofingDialogPatch(editor, selection, patch) {
8391
+ if (!validDocumentProofingDialogPatch(patch) || editor.isDestroyed) return false;
8392
+ const maximum = editor.state.doc.content.size;
8393
+ if (!Number.isSafeInteger(selection.from) || !Number.isSafeInteger(selection.to) || selection.from < 0 || selection.to < selection.from || selection.to > maximum) return false;
8394
+ const textStyle = editor.state.schema.marks.textStyle;
8395
+ if (!textStyle) return false;
8396
+ const transaction = editor.state.tr;
8397
+ try {
8398
+ transaction.setSelection(TextSelection.create(transaction.doc, selection.from, selection.to));
8399
+ } catch {
8400
+ return false;
8401
+ }
8402
+ if (selection.from === selection.to) {
8403
+ const marks = transaction.selection.$from.marks();
8404
+ const current = marks.find((mark)=>mark.type === textStyle);
8405
+ const attributes = patchedProofingAttributes(current, patch);
8406
+ if (!attributes) return false;
8407
+ const retained = marks.filter((mark)=>mark.type !== textStyle);
8408
+ if (textStyleAttributesHaveValue(attributes)) retained.push(textStyle.create(attributes));
8409
+ transaction.setStoredMarks(retained);
8410
+ transaction.scrollIntoView();
8411
+ editor.view.dispatch(transaction);
8412
+ editor.view.focus();
8413
+ return true;
8414
+ }
8415
+ const updates = [];
8416
+ transaction.doc.nodesBetween(selection.from, selection.to, (node, position)=>{
8417
+ if (!node.isText || !node.text) return;
8418
+ const from = Math.max(selection.from, position);
8419
+ const to = Math.min(selection.to, position + node.nodeSize);
8420
+ if (to <= from) return;
8421
+ const current = node.marks.find((mark)=>mark.type === textStyle);
8422
+ const attributes = patchedProofingAttributes(current, patch);
8423
+ if (attributes) updates.push({
8424
+ from,
8425
+ to,
8426
+ current,
8427
+ attributes
8428
+ });
8429
+ });
8430
+ for (const update of updates){
8431
+ if (update.current) transaction.removeMark(update.from, update.to, update.current);
8432
+ if (textStyleAttributesHaveValue(update.attributes)) transaction.addMark(update.from, update.to, textStyle.create(update.attributes));
8433
+ }
8434
+ if (!transaction.docChanged) return false;
8435
+ editor.view.dispatch(transaction.scrollIntoView());
8436
+ editor.view.focus();
8437
+ return true;
8438
+ }
8439
+ function patchedProofingAttributes(current, patch) {
8440
+ const attributes = {
8441
+ ...current?.attrs ?? {}
8442
+ };
8443
+ let changed = false;
8444
+ if (patch.languages) {
8445
+ const currentLanguages = parseDocumentProofingLanguages(current?.attrs.proofingLanguages);
8446
+ const nextLanguages = patchDocumentProofingLanguages(currentLanguages, patch.languages);
8447
+ const currentSerialized = serializeDocumentProofingLanguages(currentLanguages) ?? null;
8448
+ const nextSerialized = serializeDocumentProofingLanguages(nextLanguages) ?? null;
8449
+ if (currentSerialized !== nextSerialized) {
8450
+ attributes.proofingLanguages = nextSerialized;
8451
+ changed = true;
8452
+ }
8453
+ }
8454
+ if (void 0 !== patch.noProof) {
8455
+ const currentNoProof = normalizeDocumentNoProof(current?.attrs.noProof);
8456
+ if (currentNoProof !== patch.noProof) {
8457
+ attributes.noProof = patch.noProof;
8458
+ changed = true;
8459
+ }
8460
+ }
8461
+ return changed ? attributes : null;
8462
+ }
8463
+ function validDocumentProofingDialogPatch(patch) {
8464
+ if (!isRecord(patch)) return false;
8465
+ const keys = Object.keys(patch);
8466
+ if (!keys.length || keys.some((key)=>'languages' !== key && 'noProof' !== key)) return false;
8467
+ if (void 0 !== patch.noProof && null !== patch.noProof && null === normalizeDocumentNoProof(patch.noProof)) return false;
8468
+ if (void 0 !== patch.languages) {
8469
+ if (!isRecord(patch.languages)) return false;
8470
+ const languageEntries = Object.entries(patch.languages);
8471
+ if (!languageEntries.length || languageEntries.some(([slot, language])=>!PROOFING_LANGUAGE_SLOT_SET.has(slot) || null !== language && null === normalizeDocumentLanguageTag(language))) return false;
8472
+ }
8473
+ return void 0 !== patch.languages || void 0 !== patch.noProof;
8474
+ }
8475
+ function addSelectedValue(values, value) {
8476
+ values.set(null === value ? 'inherited' : String(value), value);
8477
+ }
8478
+ function selectedValue(values) {
8479
+ if (1 !== values.size) return {
8480
+ mixed: true,
8481
+ value: null
8482
+ };
8483
+ return {
8484
+ mixed: false,
8485
+ value: values.values().next().value ?? null
8486
+ };
8487
+ }
8488
+ function textStyleAttributesHaveValue(attributes) {
8489
+ return Object.values(attributes).some((value)=>null != value && '' !== value);
8490
+ }
8491
+ function isRecord(source) {
8492
+ return 'object' == typeof source && null !== source && !Array.isArray(source);
8493
+ }
8110
8494
  function DocumentFormatTools({ editor }) {
8111
8495
  const hasFormat = useSyncExternalStore(subscribeDocumentFormatClipboard, hasDocumentFormatClipboard, hasDocumentFormatClipboard);
8112
8496
  const [formatPainterActive, setFormatPainterActive] = useState(false);
@@ -9194,7 +9578,7 @@ function applyDocumentScriptFontPatch(editor, selection, scalarPatch, scriptFont
9194
9578
  const current = marks.find((mark)=>mark.type === textStyle);
9195
9579
  const attributes = patchedTextStyleAttributes(current, scalarPatch, scriptFontPatch, normalizeDocumentScriptFontSlot(current?.attrs.scriptFontSlot) ?? documentScriptFontSlotFromHint(parseDocumentScriptFonts(current?.attrs.scriptFonts)?.hint));
9196
9580
  const retained = marks.filter((mark)=>mark.type !== textStyle);
9197
- if (textStyleAttributesHaveValue(attributes)) retained.push(textStyle.create(attributes));
9581
+ if (document_font_dialog_script_font_model_textStyleAttributesHaveValue(attributes)) retained.push(textStyle.create(attributes));
9198
9582
  transaction.setStoredMarks(retained);
9199
9583
  transaction.scrollIntoView();
9200
9584
  editor.view.dispatch(transaction);
@@ -9221,7 +9605,7 @@ function applyDocumentScriptFontPatch(editor, selection, scalarPatch, scriptFont
9221
9605
  });
9222
9606
  for (const update of updates){
9223
9607
  if (update.current) transaction.removeMark(update.from, update.to, update.current);
9224
- if (textStyleAttributesHaveValue(update.attributes)) transaction.addMark(update.from, update.to, textStyle.create(update.attributes));
9608
+ if (document_font_dialog_script_font_model_textStyleAttributesHaveValue(update.attributes)) transaction.addMark(update.from, update.to, textStyle.create(update.attributes));
9225
9609
  }
9226
9610
  if (!transaction.docChanged) return false;
9227
9611
  editor.view.dispatch(transaction.scrollIntoView());
@@ -9250,7 +9634,7 @@ function patchedTextStyleAttributes(current, scalarPatch, scriptFontPatch, slot,
9250
9634
  attributes.wordLineHeightFactor = family ? documentWordLineHeightFactor(family) : null;
9251
9635
  return attributes;
9252
9636
  }
9253
- function textStyleAttributesHaveValue(attributes) {
9637
+ function document_font_dialog_script_font_model_textStyleAttributesHaveValue(attributes) {
9254
9638
  return Object.values(attributes).some((value)=>null != value && '' !== value);
9255
9639
  }
9256
9640
  function validScriptFontPatch(patch) {
@@ -9343,6 +9727,87 @@ function runBorderSpaceFromDraft(draft) {
9343
9727
  function formatPoints(value) {
9344
9728
  return Number(value.toFixed(3)).toString();
9345
9729
  }
9730
+ function addDocumentFontDialogRunShadingValue(values, source) {
9731
+ const shading = parseDocumentRunShading(source);
9732
+ const serialized = serializeDocumentRunShading(shading);
9733
+ values.set(serialized ?? 'inherited', shading);
9734
+ }
9735
+ function selectedDocumentFontDialogRunShadingValue(values) {
9736
+ return 1 === values.size ? {
9737
+ mixed: false,
9738
+ value: values.values().next().value ?? null
9739
+ } : {
9740
+ mixed: true,
9741
+ value: null
9742
+ };
9743
+ }
9744
+ function createDocumentFontDialogRunShadingDraft(source) {
9745
+ const shading = source.value;
9746
+ return {
9747
+ runShadingMode: source.mixed ? 'mixed' : shading ? 'nil' === shading.pattern ? 'none' : 'value' : 'inherit',
9748
+ runShadingPattern: shading && 'nil' !== shading.pattern ? shading.pattern : 'clear',
9749
+ runShadingColor: shading?.color?.value ?? 'auto',
9750
+ runShadingFill: shading?.fill?.value ?? 'auto'
9751
+ };
9752
+ }
9753
+ function documentFontDialogRunShadingDraftError(draft) {
9754
+ if ('value' !== draft.runShadingMode) return null;
9755
+ if (!validColor(draft.runShadingColor)) return '请选择有效的字符底纹前景色。';
9756
+ if (!validColor(draft.runShadingFill)) return '请选择有效的字符底纹背景色。';
9757
+ return null;
9758
+ }
9759
+ function documentFontDialogRunShadingPatch(source, draft, touched) {
9760
+ if (!touched || 'mixed' === draft.runShadingMode) return {};
9761
+ if ('inherit' === draft.runShadingMode) return source.mixed || source.value ? {
9762
+ runShading: null
9763
+ } : {};
9764
+ const shading = 'none' === draft.runShadingMode ? {
9765
+ pattern: 'nil'
9766
+ } : documentFontDialogRunShadingFromDraft(source, draft);
9767
+ if (!shading) return {};
9768
+ return serializeDocumentRunShading(source.value) === serializeDocumentRunShading(shading) ? {} : {
9769
+ runShading: shading
9770
+ };
9771
+ }
9772
+ function documentFontDialogRunShadingFromDraft(source, draft) {
9773
+ if ('none' === draft.runShadingMode) return {
9774
+ pattern: 'nil'
9775
+ };
9776
+ if ('value' !== draft.runShadingMode) return source.value;
9777
+ return normalizeDocumentRunShading({
9778
+ pattern: draft.runShadingPattern,
9779
+ ...shadingColorPatch('color', draft.runShadingColor, source.value?.color),
9780
+ ...shadingColorPatch('fill', draft.runShadingFill, source.value?.fill)
9781
+ });
9782
+ }
9783
+ function documentFontDialogRunShadingPreviewStyle(source, draft) {
9784
+ const shading = documentFontDialogRunShadingFromDraft(source, draft);
9785
+ const cssText = documentRunShadingDomAttributes(shading).style;
9786
+ if (!cssText) return {};
9787
+ const probe = document.createElement('span');
9788
+ probe.style.cssText = cssText;
9789
+ return {
9790
+ backgroundColor: probe.style.backgroundColor || void 0,
9791
+ backgroundImage: probe.style.backgroundImage || void 0,
9792
+ backgroundSize: probe.style.backgroundSize || void 0,
9793
+ boxDecorationBreak: 'clone',
9794
+ WebkitBoxDecorationBreak: 'clone'
9795
+ };
9796
+ }
9797
+ function shadingColorPatch(name, value, source) {
9798
+ if (!source && 'auto' === value) return {};
9799
+ return {
9800
+ [name]: {
9801
+ value,
9802
+ ...source?.theme && source.value === value ? {
9803
+ theme: source.theme
9804
+ } : {}
9805
+ }
9806
+ };
9807
+ }
9808
+ function validColor(value) {
9809
+ return 'auto' === value || /^#[0-9a-f]{6}$/i.test(value);
9810
+ }
9346
9811
  function documentFontDialogSource(editor) {
9347
9812
  const { doc, selection } = editor.state;
9348
9813
  const scaleValues = new Map();
@@ -9356,6 +9821,7 @@ function documentFontDialogSource(editor) {
9356
9821
  const legacyTextEmbossValues = new Map();
9357
9822
  const legacyTextImprintValues = new Map();
9358
9823
  const runBorderValues = new Map();
9824
+ const runShadingValues = new Map();
9359
9825
  const latinFontValues = new Map();
9360
9826
  const eastAsiaFontValues = new Map();
9361
9827
  const complexScriptFontValues = new Map();
@@ -9371,6 +9837,7 @@ function documentFontDialogSource(editor) {
9371
9837
  addLegacyTextEffectValue(legacyTextEmbossValues, attributes.legacyTextEmboss);
9372
9838
  addLegacyTextEffectValue(legacyTextImprintValues, attributes.legacyTextImprint);
9373
9839
  addDocumentFontDialogRunBorderValue(runBorderValues, attributes.runBorder);
9840
+ addDocumentFontDialogRunShadingValue(runShadingValues, attributes.runShading);
9374
9841
  addDocumentScriptFontValues(latinFontValues, eastAsiaFontValues, complexScriptFontValues, attributes);
9375
9842
  };
9376
9843
  if (selection.empty) addValues(editor.getAttributes('textStyle'));
@@ -9379,21 +9846,22 @@ function documentFontDialogSource(editor) {
9379
9846
  const textStyle = node.marks.find((mark)=>'textStyle' === mark.type.name);
9380
9847
  addValues(textStyle?.attrs ?? {});
9381
9848
  });
9382
- if (!scaleValues.size || !spacingValues.size || !positionValues.size || !kerningValues.size || !emphasisValues.size || !hiddenTextValues.size || !legacyTextOutlineValues.size || !legacyTextShadowValues.size || !legacyTextEmbossValues.size || !legacyTextImprintValues.size || !runBorderValues.size || !latinFontValues.size || !eastAsiaFontValues.size || !complexScriptFontValues.size) addValues(editor.getAttributes('textStyle'));
9383
- const characterScale = selectedValue(scaleValues);
9384
- const characterPosition = selectedValue(positionValues);
9385
- const characterSpacing = selectedValue(spacingValues);
9386
- const kerningThreshold = selectedValue(kerningValues);
9387
- const emphasisMark = selectedValue(emphasisValues);
9388
- const hiddenText = selectedValue(hiddenTextValues);
9389
- const legacyTextOutline = selectedValue(legacyTextOutlineValues);
9390
- const legacyTextShadow = selectedValue(legacyTextShadowValues);
9391
- const legacyTextEmboss = selectedValue(legacyTextEmbossValues);
9392
- const legacyTextImprint = selectedValue(legacyTextImprintValues);
9849
+ if (!scaleValues.size || !spacingValues.size || !positionValues.size || !kerningValues.size || !emphasisValues.size || !hiddenTextValues.size || !legacyTextOutlineValues.size || !legacyTextShadowValues.size || !legacyTextEmbossValues.size || !legacyTextImprintValues.size || !runBorderValues.size || !runShadingValues.size || !latinFontValues.size || !eastAsiaFontValues.size || !complexScriptFontValues.size) addValues(editor.getAttributes('textStyle'));
9850
+ const characterScale = document_font_dialog_model_selectedValue(scaleValues);
9851
+ const characterPosition = document_font_dialog_model_selectedValue(positionValues);
9852
+ const characterSpacing = document_font_dialog_model_selectedValue(spacingValues);
9853
+ const kerningThreshold = document_font_dialog_model_selectedValue(kerningValues);
9854
+ const emphasisMark = document_font_dialog_model_selectedValue(emphasisValues);
9855
+ const hiddenText = document_font_dialog_model_selectedValue(hiddenTextValues);
9856
+ const legacyTextOutline = document_font_dialog_model_selectedValue(legacyTextOutlineValues);
9857
+ const legacyTextShadow = document_font_dialog_model_selectedValue(legacyTextShadowValues);
9858
+ const legacyTextEmboss = document_font_dialog_model_selectedValue(legacyTextEmbossValues);
9859
+ const legacyTextImprint = document_font_dialog_model_selectedValue(legacyTextImprintValues);
9393
9860
  const runBorder = selectedDocumentFontDialogRunBorderValue(runBorderValues);
9394
- const latinFont = selectedValue(latinFontValues);
9395
- const eastAsiaFont = selectedValue(eastAsiaFontValues);
9396
- const complexScriptFont = selectedValue(complexScriptFontValues);
9861
+ const runShading = selectedDocumentFontDialogRunShadingValue(runShadingValues);
9862
+ const latinFont = document_font_dialog_model_selectedValue(latinFontValues);
9863
+ const eastAsiaFont = document_font_dialog_model_selectedValue(eastAsiaFontValues);
9864
+ const complexScriptFont = document_font_dialog_model_selectedValue(complexScriptFontValues);
9397
9865
  const textStyle = editor.getAttributes('textStyle');
9398
9866
  const selectedText = selection.empty ? '' : doc.textBetween(selection.from, selection.to, ' ', ' ').replace(/\s+/g, ' ').trim();
9399
9867
  return {
@@ -9408,6 +9876,7 @@ function documentFontDialogSource(editor) {
9408
9876
  legacyTextEmboss,
9409
9877
  legacyTextImprint,
9410
9878
  runBorder,
9879
+ runShading,
9411
9880
  latinFont,
9412
9881
  eastAsiaFont,
9413
9882
  complexScriptFont,
@@ -9440,6 +9909,7 @@ function createDocumentFontDialogDraft(source) {
9440
9909
  legacyTextEmboss: source.legacyTextEmboss.value ?? false,
9441
9910
  legacyTextImprint: source.legacyTextImprint.value ?? false,
9442
9911
  ...createDocumentFontDialogRunBorderDraft(source.runBorder),
9912
+ ...createDocumentFontDialogRunShadingDraft(source.runShading),
9443
9913
  latinFont: documentFontFamilyDraftValue(source.latinFont),
9444
9914
  eastAsiaFont: documentFontFamilyDraftValue(source.eastAsiaFont),
9445
9915
  complexScriptFont: documentFontFamilyDraftValue(source.complexScriptFont)
@@ -9448,6 +9918,8 @@ function createDocumentFontDialogDraft(source) {
9448
9918
  function documentFontDialogDraftError(draft) {
9449
9919
  const runBorderError = documentFontDialogRunBorderDraftError(draft);
9450
9920
  if (runBorderError) return runBorderError;
9921
+ const runShadingError = documentFontDialogRunShadingDraftError(draft);
9922
+ if (runShadingError) return runShadingError;
9451
9923
  if ('mixed' !== draft.characterScaleMode && null === characterScalePercentFromDraft(draft)) return "请输入 1 至 600 的整数缩放比例。";
9452
9924
  if ('mixed' !== draft.characterSpacingMode && 'normal' !== draft.characterSpacingMode && null === characterSpacingTwipsFromDraft(draft)) return "请输入 0.05 至 1584 磅的间距。";
9453
9925
  if ('mixed' !== draft.characterPositionMode && 'normal' !== draft.characterPositionMode && null === characterPositionHalfPointsFromDraft(draft)) return "请输入 0.5 至 1584 磅、以 0.5 磅递增的位置值。";
@@ -9483,6 +9955,7 @@ function documentFontDialogPatch(source, draft, touched) {
9483
9955
  if (touched.hiddenText && (source.hiddenText.mixed || source.hiddenText.value !== draft.hiddenText)) patch.hiddenText = draft.hiddenText;
9484
9956
  appendLegacyTextEffectPatch(patch, 'legacyTextOutline', source.legacyTextOutline, draft.legacyTextOutline, touched.legacyTextOutline);
9485
9957
  Object.assign(patch, documentFontDialogRunBorderPatch(source.runBorder, draft, touched.runBorder));
9958
+ Object.assign(patch, documentFontDialogRunShadingPatch(source.runShading, draft, touched.runShading));
9486
9959
  appendLegacyTextEffectPatch(patch, 'legacyTextShadow', source.legacyTextShadow, draft.legacyTextShadow, touched.legacyTextShadow);
9487
9960
  appendLegacyTextEffectPatch(patch, 'legacyTextEmboss', source.legacyTextEmboss, draft.legacyTextEmboss, touched.legacyTextEmboss);
9488
9961
  appendLegacyTextEffectPatch(patch, 'legacyTextImprint', source.legacyTextImprint, draft.legacyTextImprint, touched.legacyTextImprint);
@@ -9503,6 +9976,7 @@ function applyDocumentFontDialogPatch(editor, selection, patch) {
9503
9976
  const hasLegacyTextEmboss = void 0 !== patch.legacyTextEmboss;
9504
9977
  const hasLegacyTextImprint = void 0 !== patch.legacyTextImprint;
9505
9978
  const hasRunBorder = void 0 !== patch.runBorder;
9979
+ const hasRunShading = void 0 !== patch.runShading;
9506
9980
  const hasLegacyTextEffects = hasLegacyTextOutline || hasLegacyTextShadow || hasLegacyTextEmboss || hasLegacyTextImprint;
9507
9981
  const scriptFontPatch = {
9508
9982
  ...void 0 !== patch.latinFont ? {
@@ -9522,8 +9996,9 @@ function applyDocumentFontDialogPatch(editor, selection, patch) {
9522
9996
  const kerningThreshold = hasKerning && null !== patch.kerningThresholdHalfPoints ? normalizeDocumentKerningThresholdHalfPoints(patch.kerningThresholdHalfPoints) : null;
9523
9997
  const emphasisMark = hasEmphasis && null !== patch.emphasisMark ? normalizeDocumentEmphasisMark(patch.emphasisMark) : null;
9524
9998
  const runBorder = hasRunBorder && null !== patch.runBorder ? normalizeDocumentRunBorder(patch.runBorder) : null;
9999
+ const runShading = hasRunShading && null !== patch.runShading ? normalizeDocumentRunShading(patch.runShading) : null;
9525
10000
  const maximum = editor.state.doc.content.size;
9526
- if (editor.isDestroyed || !hasScale && !hasPosition && !hasSpacing && !hasKerning && !hasEmphasis && !hasHiddenText && !hasLegacyTextEffects && !hasRunBorder && !hasScriptFonts || hasScale && null === scale || hasPosition && null === position || hasSpacing && null === spacing || hasKerning && null !== patch.kerningThresholdHalfPoints && null === kerningThreshold || hasEmphasis && null !== patch.emphasisMark && null === emphasisMark || hasRunBorder && null !== patch.runBorder && null === runBorder || 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;
10001
+ if (editor.isDestroyed || !hasScale && !hasPosition && !hasSpacing && !hasKerning && !hasEmphasis && !hasHiddenText && !hasLegacyTextEffects && !hasRunBorder && !hasRunShading && !hasScriptFonts || hasScale && null === scale || hasPosition && null === position || hasSpacing && null === spacing || hasKerning && null !== patch.kerningThresholdHalfPoints && null === kerningThreshold || hasEmphasis && null !== patch.emphasisMark && null === emphasisMark || hasRunBorder && null !== patch.runBorder && null === runBorder || hasRunShading && null !== patch.runShading && null === runShading || 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;
9527
10002
  const attributes = {};
9528
10003
  if (null !== scale) attributes.characterScalePercent = scale;
9529
10004
  if (null !== position) attributes.characterPositionHalfPoints = position;
@@ -9536,6 +10011,7 @@ function applyDocumentFontDialogPatch(editor, selection, patch) {
9536
10011
  if (hasLegacyTextEmboss) attributes.legacyTextEmboss = patch.legacyTextEmboss ?? false;
9537
10012
  if (hasLegacyTextImprint) attributes.legacyTextImprint = patch.legacyTextImprint ?? false;
9538
10013
  if (hasRunBorder) attributes.runBorder = null === patch.runBorder ? null : serializeDocumentRunBorder(runBorder) ?? null;
10014
+ if (hasRunShading) attributes.runShading = null === patch.runShading ? null : serializeDocumentRunShading(runShading) ?? null;
9539
10015
  if (hasScriptFonts) return applyDocumentScriptFontPatch(editor, selection, attributes, scriptFontPatch);
9540
10016
  return editor.chain().setTextSelection(selection).setMark('textStyle', attributes).removeEmptyTextStyle().focus().scrollIntoView().run();
9541
10017
  }
@@ -9633,7 +10109,7 @@ function kerningThresholdHalfPointsFromDraft(draft) {
9633
10109
  if (!Number.isFinite(points) || points < 0 || points > 1638.5 || !Number.isSafeInteger(halfPoints)) return null;
9634
10110
  return normalizeDocumentKerningThresholdHalfPoints(halfPoints);
9635
10111
  }
9636
- function selectedValue(values) {
10112
+ function document_font_dialog_model_selectedValue(values) {
9637
10113
  const mixed = values.size > 1;
9638
10114
  return {
9639
10115
  mixed,
@@ -9861,7 +10337,232 @@ function DocumentFontDialogRunBorderSection({ source, draft, touched, onDraftCha
9861
10337
  "aria-hidden": "true",
9862
10338
  children: "磅"
9863
10339
  })
9864
- ]
10340
+ ]
10341
+ })
10342
+ ]
10343
+ }),
10344
+ /*#__PURE__*/ jsxs("div", {
10345
+ className: "work-document-font-dialog-field",
10346
+ children: [
10347
+ /*#__PURE__*/ jsx("span", {
10348
+ children: "文字间距"
10349
+ }),
10350
+ /*#__PURE__*/ jsxs("span", {
10351
+ className: "work-document-font-dialog-measure",
10352
+ children: [
10353
+ /*#__PURE__*/ jsx(OfficeNumberField, {
10354
+ ariaLabel: "字符边框间距(磅)",
10355
+ value: draft.runBorderSpacingPoints,
10356
+ min: 0,
10357
+ max: 31,
10358
+ step: 1,
10359
+ disabled: !enabled,
10360
+ onValueChange: (runBorderSpacingPoints)=>update({
10361
+ runBorderMode: 'value',
10362
+ runBorderSpacingPoints
10363
+ })
10364
+ }),
10365
+ /*#__PURE__*/ jsx("span", {
10366
+ "aria-hidden": "true",
10367
+ children: "磅"
10368
+ })
10369
+ ]
10370
+ })
10371
+ ]
10372
+ }),
10373
+ /*#__PURE__*/ jsxs("div", {
10374
+ className: "work-document-font-dialog-run-border-effects",
10375
+ children: [
10376
+ /*#__PURE__*/ jsx(OfficeCheckbox, {
10377
+ ariaLabel: "字符边框阴影",
10378
+ checked: draft.runBorderShadow,
10379
+ disabled: !enabled,
10380
+ onCheckedChange: (runBorderShadow)=>update({
10381
+ runBorderMode: 'value',
10382
+ runBorderShadow
10383
+ }),
10384
+ children: "阴影"
10385
+ }),
10386
+ /*#__PURE__*/ jsx(OfficeCheckbox, {
10387
+ ariaLabel: "字符边框框架",
10388
+ checked: draft.runBorderFrame,
10389
+ disabled: !enabled,
10390
+ onCheckedChange: (runBorderFrame)=>update({
10391
+ runBorderMode: 'value',
10392
+ runBorderFrame
10393
+ }),
10394
+ children: "框架"
10395
+ })
10396
+ ]
10397
+ }),
10398
+ source.mixed && !touched ? /*#__PURE__*/ jsx("p", {
10399
+ className: "work-document-font-dialog-mixed",
10400
+ role: "status",
10401
+ children: "当前选区包含不同的字符边框。选择一种应用方式后才会统一修改。"
10402
+ }) : null
10403
+ ]
10404
+ });
10405
+ }
10406
+ function documentFontDialogRunBorderPreviewStyle(source, draft) {
10407
+ const border = documentFontDialogRunBorderFromDraft(source, draft);
10408
+ if (!border) return {};
10409
+ const presentation = documentBorderPresentation(border);
10410
+ return {
10411
+ border: `${presentation.width}px ${presentation.style} ${presentation.color}`,
10412
+ padding: `${(border.space ?? 0) * (96 / 72)}px`,
10413
+ boxDecorationBreak: 'clone',
10414
+ WebkitBoxDecorationBreak: 'clone',
10415
+ ...border.shadow && presentation.width > 0 ? {
10416
+ boxShadow: `2px 2px 0 ${presentation.color}`
10417
+ } : {}
10418
+ };
10419
+ }
10420
+ const shadingModes = [
10421
+ {
10422
+ value: 'mixed',
10423
+ label: '混合(保持不变)',
10424
+ disabled: true
10425
+ },
10426
+ {
10427
+ value: 'inherit',
10428
+ label: '跟随样式'
10429
+ },
10430
+ {
10431
+ value: 'none',
10432
+ label: '无(显式重置)'
10433
+ },
10434
+ {
10435
+ value: 'value',
10436
+ label: '底纹'
10437
+ }
10438
+ ];
10439
+ const shadingPatterns = [
10440
+ {
10441
+ value: 'clear',
10442
+ label: '清除(背景色)',
10443
+ group: '基本'
10444
+ },
10445
+ {
10446
+ value: 'solid',
10447
+ label: '实心(前景色)',
10448
+ group: '基本'
10449
+ },
10450
+ {
10451
+ value: 'horzStripe',
10452
+ label: '水平条纹',
10453
+ group: '条纹'
10454
+ },
10455
+ {
10456
+ value: 'vertStripe',
10457
+ label: '垂直条纹',
10458
+ group: '条纹'
10459
+ },
10460
+ {
10461
+ value: 'reverseDiagStripe',
10462
+ label: '反向对角条纹',
10463
+ group: '条纹'
10464
+ },
10465
+ {
10466
+ value: 'diagStripe',
10467
+ label: '对角条纹',
10468
+ group: '条纹'
10469
+ },
10470
+ {
10471
+ value: 'horzCross',
10472
+ label: '水平交叉',
10473
+ group: '交叉'
10474
+ },
10475
+ {
10476
+ value: 'diagCross',
10477
+ label: '对角交叉',
10478
+ group: '交叉'
10479
+ },
10480
+ {
10481
+ value: 'thinHorzStripe',
10482
+ label: '细水平条纹',
10483
+ group: '细线'
10484
+ },
10485
+ {
10486
+ value: 'thinVertStripe',
10487
+ label: '细垂直条纹',
10488
+ group: '细线'
10489
+ },
10490
+ {
10491
+ value: 'thinReverseDiagStripe',
10492
+ label: '细反向对角条纹',
10493
+ group: '细线'
10494
+ },
10495
+ {
10496
+ value: 'thinDiagStripe',
10497
+ label: '细对角条纹',
10498
+ group: '细线'
10499
+ },
10500
+ {
10501
+ value: 'thinHorzCross',
10502
+ label: '细水平交叉',
10503
+ group: '细线'
10504
+ },
10505
+ {
10506
+ value: 'thinDiagCross',
10507
+ label: '细对角交叉',
10508
+ group: '细线'
10509
+ },
10510
+ ...[
10511
+ 5,
10512
+ 10,
10513
+ 12,
10514
+ 15,
10515
+ 20,
10516
+ 25,
10517
+ 30,
10518
+ 35,
10519
+ 37,
10520
+ 40,
10521
+ 45,
10522
+ 50,
10523
+ 55,
10524
+ 60,
10525
+ 62,
10526
+ 65,
10527
+ 70,
10528
+ 75,
10529
+ 80,
10530
+ 85,
10531
+ 87,
10532
+ 90,
10533
+ 95
10534
+ ].map((percentage)=>({
10535
+ value: `pct${percentage}`,
10536
+ label: `${percentage}%`,
10537
+ group: '密度'
10538
+ }))
10539
+ ];
10540
+ function DocumentFontDialogRunShadingSection({ source, draft, touched, onDraftChange, onTouched }) {
10541
+ const enabled = 'value' === draft.runShadingMode;
10542
+ const update = (patch)=>{
10543
+ onDraftChange(patch);
10544
+ onTouched();
10545
+ };
10546
+ return /*#__PURE__*/ jsxs("fieldset", {
10547
+ className: "work-document-font-dialog-run-shading",
10548
+ "aria-label": "字符底纹设置",
10549
+ children: [
10550
+ /*#__PURE__*/ jsx("legend", {
10551
+ children: "字符底纹"
10552
+ }),
10553
+ /*#__PURE__*/ jsxs("div", {
10554
+ className: "work-document-font-dialog-field",
10555
+ children: [
10556
+ /*#__PURE__*/ jsx("span", {
10557
+ children: "应用方式"
10558
+ }),
10559
+ /*#__PURE__*/ jsx(OfficeSelect, {
10560
+ ariaLabel: "字符底纹",
10561
+ value: draft.runShadingMode,
10562
+ options: shadingModes,
10563
+ onValueChange: (runShadingMode)=>update({
10564
+ runShadingMode
10565
+ })
9865
10566
  })
9866
10567
  ]
9867
10568
  }),
@@ -9869,78 +10570,78 @@ function DocumentFontDialogRunBorderSection({ source, draft, touched, onDraftCha
9869
10570
  className: "work-document-font-dialog-field",
9870
10571
  children: [
9871
10572
  /*#__PURE__*/ jsx("span", {
9872
- children: "文字间距"
10573
+ children: "图案"
9873
10574
  }),
9874
- /*#__PURE__*/ jsxs("span", {
9875
- className: "work-document-font-dialog-measure",
9876
- children: [
9877
- /*#__PURE__*/ jsx(OfficeNumberField, {
9878
- ariaLabel: "字符边框间距(磅)",
9879
- value: draft.runBorderSpacingPoints,
9880
- min: 0,
9881
- max: 31,
9882
- step: 1,
9883
- disabled: !enabled,
9884
- onValueChange: (runBorderSpacingPoints)=>update({
9885
- runBorderMode: 'value',
9886
- runBorderSpacingPoints
9887
- })
9888
- }),
9889
- /*#__PURE__*/ jsx("span", {
9890
- "aria-hidden": "true",
9891
- children: "磅"
10575
+ /*#__PURE__*/ jsx(OfficeSelect, {
10576
+ ariaLabel: "字符底纹图案",
10577
+ value: draft.runShadingPattern,
10578
+ options: shadingPatterns,
10579
+ disabled: !enabled,
10580
+ onValueChange: (runShadingPattern)=>update({
10581
+ runShadingMode: 'value',
10582
+ runShadingPattern
9892
10583
  })
9893
- ]
9894
10584
  })
9895
10585
  ]
9896
10586
  }),
9897
10587
  /*#__PURE__*/ jsxs("div", {
9898
- className: "work-document-font-dialog-run-border-effects",
10588
+ className: "work-document-font-dialog-field",
9899
10589
  children: [
9900
- /*#__PURE__*/ jsx(OfficeCheckbox, {
9901
- ariaLabel: "字符边框阴影",
9902
- checked: draft.runBorderShadow,
10590
+ /*#__PURE__*/ jsx("span", {
10591
+ children: "前景色"
10592
+ }),
10593
+ /*#__PURE__*/ jsx(OfficeColorPicker, {
10594
+ ariaLabel: "字符底纹前景色",
10595
+ value: 'auto' === draft.runShadingColor ? '#000000' : draft.runShadingColor,
9903
10596
  disabled: !enabled,
9904
- onCheckedChange: (runBorderShadow)=>update({
9905
- runBorderMode: 'value',
9906
- runBorderShadow
9907
- }),
9908
- children: "阴影"
10597
+ resetAction: {
10598
+ kind: 'automatic',
10599
+ label: '自动前景色',
10600
+ onSelect: ()=>update({
10601
+ runShadingMode: 'value',
10602
+ runShadingColor: 'auto'
10603
+ })
10604
+ },
10605
+ onValueChange: (runShadingColor)=>update({
10606
+ runShadingMode: 'value',
10607
+ runShadingColor: runShadingColor
10608
+ })
10609
+ })
10610
+ ]
10611
+ }),
10612
+ /*#__PURE__*/ jsxs("div", {
10613
+ className: "work-document-font-dialog-field",
10614
+ children: [
10615
+ /*#__PURE__*/ jsx("span", {
10616
+ children: "背景色"
9909
10617
  }),
9910
- /*#__PURE__*/ jsx(OfficeCheckbox, {
9911
- ariaLabel: "字符边框框架",
9912
- checked: draft.runBorderFrame,
10618
+ /*#__PURE__*/ jsx(OfficeColorPicker, {
10619
+ ariaLabel: "字符底纹背景色",
10620
+ value: 'auto' === draft.runShadingFill ? '#ffffff' : draft.runShadingFill,
9913
10621
  disabled: !enabled,
9914
- onCheckedChange: (runBorderFrame)=>update({
9915
- runBorderMode: 'value',
9916
- runBorderFrame
9917
- }),
9918
- children: "框架"
10622
+ resetAction: {
10623
+ kind: 'automatic',
10624
+ label: '自动背景色',
10625
+ onSelect: ()=>update({
10626
+ runShadingMode: 'value',
10627
+ runShadingFill: 'auto'
10628
+ })
10629
+ },
10630
+ onValueChange: (runShadingFill)=>update({
10631
+ runShadingMode: 'value',
10632
+ runShadingFill: runShadingFill
10633
+ })
9919
10634
  })
9920
10635
  ]
9921
10636
  }),
9922
10637
  source.mixed && !touched ? /*#__PURE__*/ jsx("p", {
9923
10638
  className: "work-document-font-dialog-mixed",
9924
10639
  role: "status",
9925
- children: "当前选区包含不同的字符边框。选择一种应用方式后才会统一修改。"
10640
+ children: "当前选区包含不同的字符底纹。选择一种应用方式后才会统一修改。"
9926
10641
  }) : null
9927
10642
  ]
9928
10643
  });
9929
10644
  }
9930
- function documentFontDialogRunBorderPreviewStyle(source, draft) {
9931
- const border = documentFontDialogRunBorderFromDraft(source, draft);
9932
- if (!border) return {};
9933
- const presentation = documentBorderPresentation(border);
9934
- return {
9935
- border: `${presentation.width}px ${presentation.style} ${presentation.color}`,
9936
- padding: `${(border.space ?? 0) * (96 / 72)}px`,
9937
- boxDecorationBreak: 'clone',
9938
- WebkitBoxDecorationBreak: 'clone',
9939
- ...border.shadow && presentation.width > 0 ? {
9940
- boxShadow: `2px 2px 0 ${presentation.color}`
9941
- } : {}
9942
- };
9943
- }
9944
10645
  const characterSpacingModes = [
9945
10646
  {
9946
10647
  value: 'mixed',
@@ -10023,6 +10724,7 @@ function DocumentFontDialog({ source, layoutFonts = [], restoreFocusTarget, onAp
10023
10724
  const [legacyTextEmbossTouched, setLegacyTextEmbossTouched] = useState(false);
10024
10725
  const [legacyTextImprintTouched, setLegacyTextImprintTouched] = useState(false);
10025
10726
  const [runBorderTouched, setRunBorderTouched] = useState(false);
10727
+ const [runShadingTouched, setRunShadingTouched] = useState(false);
10026
10728
  const [latinFontTouched, setLatinFontTouched] = useState(false);
10027
10729
  const [eastAsiaFontTouched, setEastAsiaFontTouched] = useState(false);
10028
10730
  const [complexScriptFontTouched, setComplexScriptFontTouched] = useState(false);
@@ -10041,6 +10743,7 @@ function DocumentFontDialog({ source, layoutFonts = [], restoreFocusTarget, onAp
10041
10743
  legacyTextEmboss: legacyTextEmbossTouched,
10042
10744
  legacyTextImprint: legacyTextImprintTouched,
10043
10745
  runBorder: runBorderTouched,
10746
+ runShading: runShadingTouched,
10044
10747
  kerning: kerningTouched,
10045
10748
  latinFont: latinFontTouched
10046
10749
  });
@@ -10057,6 +10760,7 @@ function DocumentFontDialog({ source, layoutFonts = [], restoreFocusTarget, onAp
10057
10760
  imprint: draft.legacyTextImprint
10058
10761
  });
10059
10762
  const previewRunBorder = documentFontDialogRunBorderPreviewStyle(source.runBorder, draft);
10763
+ const previewRunShading = documentFontDialogRunShadingPreviewStyle(source.runShading, draft);
10060
10764
  const submit = (event)=>{
10061
10765
  event?.preventDefault();
10062
10766
  if (!hasChanges || error) return;
@@ -10506,6 +11210,16 @@ function DocumentFontDialog({ source, layoutFonts = [], restoreFocusTarget, onAp
10506
11210
  })),
10507
11211
  onTouched: ()=>setRunBorderTouched(true)
10508
11212
  }),
11213
+ /*#__PURE__*/ jsx(DocumentFontDialogRunShadingSection, {
11214
+ source: source.runShading,
11215
+ draft: draft,
11216
+ touched: runShadingTouched,
11217
+ onDraftChange: (runShadingDraft)=>setDraft((current)=>({
11218
+ ...current,
11219
+ ...runShadingDraft
11220
+ })),
11221
+ onTouched: ()=>setRunShadingTouched(true)
11222
+ }),
10509
11223
  source.characterScale.mixed && !characterScaleTouched && /*#__PURE__*/ jsx("p", {
10510
11224
  className: "work-document-font-dialog-mixed",
10511
11225
  role: "status",
@@ -10541,7 +11255,7 @@ function DocumentFontDialog({ source, layoutFonts = [], restoreFocusTarget, onAp
10541
11255
  role: "status",
10542
11256
  children: "当前选区包含不同的空心、阴影、阳文或阴文设置。勾选或取消对应选项后才会统一修改。"
10543
11257
  }),
10544
- (characterScaleTouched || characterSpacingTouched || characterPositionTouched || kerningTouched || emphasisTouched || hiddenTextTouched || legacyTextOutlineTouched || legacyTextShadowTouched || legacyTextEmbossTouched || legacyTextImprintTouched || runBorderTouched) && error && /*#__PURE__*/ jsx("p", {
11258
+ (characterScaleTouched || characterSpacingTouched || characterPositionTouched || kerningTouched || emphasisTouched || hiddenTextTouched || legacyTextOutlineTouched || legacyTextShadowTouched || legacyTextEmbossTouched || legacyTextImprintTouched || runBorderTouched || runShadingTouched) && error && /*#__PURE__*/ jsx("p", {
10545
11259
  className: "work-document-font-dialog-error",
10546
11260
  role: "alert",
10547
11261
  children: error
@@ -10568,6 +11282,7 @@ function DocumentFontDialog({ source, layoutFonts = [], restoreFocusTarget, onAp
10568
11282
  verticalAlign: `${previewPosition}pt`,
10569
11283
  ...previewEmphasis,
10570
11284
  ...previewLegacyTextEffects,
11285
+ ...previewRunShading,
10571
11286
  ...previewRunBorder,
10572
11287
  ...draft.hiddenText ? {
10573
11288
  textDecorationColor: 'currentColor',
@@ -10648,7 +11363,7 @@ function previewScriptFontFamily(value, fallback) {
10648
11363
  function fontDialogDescription(source) {
10649
11364
  return source.selectedCharacters ? `分别设置当前选中内容的拉丁、东亚和复杂文字字体,以及原生字符缩放、间距、字距调整阈值、位置、着重号、隐藏文字、空心、阴影、阳文和阴文(${source.selectedCharacters} 个字符)。` : '分别设置当前位置后续输入文字的拉丁、东亚和复杂文字字体,以及原生字符缩放、间距、字距调整阈值、位置、着重号、隐藏文字、空心、阴影、阳文和阴文。';
10650
11365
  }
10651
- function DocumentPageChromeRibbon({ editor, editingPart, showPageNumber, onEditingPartChange, onTogglePageNumber, onOpenFontDialog, onClose }) {
11366
+ function DocumentPageChromeRibbon({ editor, editingPart, showPageNumber, onEditingPartChange, onTogglePageNumber, onOpenFontDialog, onOpenProofingDialog, onClose }) {
10652
11367
  const imageInputRef = useRef(null);
10653
11368
  const [, setRevision] = useState(0);
10654
11369
  const officeDialog = useOfficeDialog();
@@ -10806,6 +11521,13 @@ function DocumentPageChromeRibbon({ editor, editingPart, showPageNumber, onEditi
10806
11521
  ariaLabel: "页眉页脚文字颜色",
10807
11522
  value: pickerColor(state.color),
10808
11523
  onValueChange: (color)=>editor.chain().focus().setColor(color).run()
11524
+ }),
11525
+ onOpenProofingDialog && /*#__PURE__*/ jsx(PageChromeRibbonButton, {
11526
+ label: "页眉页脚校对语言",
11527
+ onClick: onOpenProofingDialog,
11528
+ children: /*#__PURE__*/ jsx(Languages, {
11529
+ size: 16
11530
+ })
10809
11531
  })
10810
11532
  ]
10811
11533
  }),
@@ -14220,15 +14942,17 @@ function headingLevelForShortcut(code, key) {
14220
14942
  if ('3' === value) return 3;
14221
14943
  return null;
14222
14944
  }
14223
- 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 }) {
14945
+ 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, onOpenTableOfContents, citationsOpen, citationSourceCount, onToggleCitations, onInsertField, onRefreshFields, onRefreshTableOfContents, canInsertComment, onInsertComment, commentsOpen, commentCount, onToggleComments, trackChanges, changesOpen, changeCount, findReplaceMode, fileActions, onRibbonTabChange, onToggleTrackChanges, onToggleChanges, onDecideChange, onOpenWordCount, onOpenFindReplace }) {
14224
14946
  const [activeTab, setActiveTab] = useState(reviewOnly ? 'review' : 'home');
14225
14947
  const [fontDialogRequest, setFontDialogRequest] = useState(null);
14948
+ const [proofingDialogRequest, setProofingDialogRequest] = useState(null);
14226
14949
  const officeDialog = useOfficeDialog();
14227
14950
  const prompt = officeDialog.prompt;
14228
14951
  const imageSelected = editor.isActive('image');
14229
14952
  const tableSelected = editor.isActive('table');
14230
14953
  const activeBookmark = activeDocumentBookmark(editor);
14231
14954
  const hasRefreshableFields = documentHasRefreshableFields(editor);
14955
+ const hasTableOfContents = documentHasTableOfContents(editor);
14232
14956
  const documentChanges = collectDocumentChanges(editor.state.doc);
14233
14957
  const previousChangeIndex = adjacentDocumentChangeIndex(documentChanges, editor.state.selection, -1);
14234
14958
  const nextChangeIndex = adjacentDocumentChangeIndex(documentChanges, editor.state.selection, 1);
@@ -14251,6 +14975,18 @@ function DocumentToolbar({ editor, defaultRibbonCollapsed = false, reviewOnly =
14251
14975
  source: documentFontDialogSource(target)
14252
14976
  });
14253
14977
  }, []);
14978
+ const openProofingDialog = useCallback((target)=>{
14979
+ if (target.isDestroyed) return;
14980
+ const { from, to } = target.state.selection;
14981
+ setProofingDialogRequest({
14982
+ editor: target,
14983
+ selection: {
14984
+ from,
14985
+ to
14986
+ },
14987
+ source: documentProofingDialogSource(target)
14988
+ });
14989
+ }, []);
14254
14990
  const ribbonTabs = reviewOnly ? documentRibbonTabs.filter(({ id })=>'review' === id || 'view' === id) : pageChromeEditor ? [
14255
14991
  ...documentRibbonTabs,
14256
14992
  documentPageChromeRibbonTab
@@ -14626,6 +15362,30 @@ function DocumentToolbar({ editor, defaultRibbonCollapsed = false, reviewOnly =
14626
15362
  }),
14627
15363
  references: reviewOnly ? null : /*#__PURE__*/ jsxs(Fragment, {
14628
15364
  children: [
15365
+ /*#__PURE__*/ jsxs(document_toolbar_RibbonGroup, {
15366
+ label: "目录",
15367
+ priority: "high",
15368
+ children: [
15369
+ /*#__PURE__*/ jsx(document_toolbar_ToolbarButton, {
15370
+ label: "插入或自定义目录",
15371
+ displayLabel: true,
15372
+ onClick: onOpenTableOfContents,
15373
+ children: /*#__PURE__*/ jsx(ListTree, {
15374
+ size: 19
15375
+ })
15376
+ }),
15377
+ /*#__PURE__*/ jsx(document_toolbar_ToolbarButton, {
15378
+ label: "更新目录",
15379
+ displayLabel: true,
15380
+ disabled: !hasTableOfContents,
15381
+ title: hasTableOfContents ? '根据当前标题和页码更新目录' : '文档中没有可更新的目录',
15382
+ onClick: onRefreshTableOfContents,
15383
+ children: /*#__PURE__*/ jsx(RefreshCw, {
15384
+ size: 19
15385
+ })
15386
+ })
15387
+ ]
15388
+ }),
14629
15389
  /*#__PURE__*/ jsxs(document_toolbar_RibbonGroup, {
14630
15390
  label: "脚注",
14631
15391
  priority: "high",
@@ -14712,20 +15472,30 @@ function DocumentToolbar({ editor, defaultRibbonCollapsed = false, reviewOnly =
14712
15472
  }),
14713
15473
  review: /*#__PURE__*/ jsxs(Fragment, {
14714
15474
  children: [
14715
- !reviewOnly && /*#__PURE__*/ jsx(document_toolbar_RibbonGroup, {
15475
+ !reviewOnly && /*#__PURE__*/ jsxs(document_toolbar_RibbonGroup, {
14716
15476
  label: "校对",
14717
15477
  priority: "high",
14718
- children: /*#__PURE__*/ jsx(document_toolbar_ToolbarButton, {
14719
- label: "拼写检查",
14720
- displayLabel: true,
14721
- shortcut: spellingCommand.shortcut?.label,
14722
- ariaKeyShortcuts: spellingCommand.shortcut?.aria,
14723
- active: spellcheckEnabled,
14724
- onClick: onToggleSpellcheck,
14725
- children: /*#__PURE__*/ jsx(CheckCheck, {
14726
- size: 19
15478
+ children: [
15479
+ /*#__PURE__*/ jsx(document_toolbar_ToolbarButton, {
15480
+ label: "拼写检查",
15481
+ displayLabel: true,
15482
+ shortcut: spellingCommand.shortcut?.label,
15483
+ ariaKeyShortcuts: spellingCommand.shortcut?.aria,
15484
+ active: spellcheckEnabled,
15485
+ onClick: onToggleSpellcheck,
15486
+ children: /*#__PURE__*/ jsx(CheckCheck, {
15487
+ size: 19
15488
+ })
15489
+ }),
15490
+ /*#__PURE__*/ jsx(document_toolbar_ToolbarButton, {
15491
+ label: "设置校对语言",
15492
+ displayLabel: true,
15493
+ onClick: ()=>openProofingDialog(editor),
15494
+ children: /*#__PURE__*/ jsx(Languages, {
15495
+ size: 19
15496
+ })
14727
15497
  })
14728
- })
15498
+ ]
14729
15499
  }),
14730
15500
  !suggestionOnly && /*#__PURE__*/ jsxs(document_toolbar_RibbonGroup, {
14731
15501
  label: "批注",
@@ -14956,6 +15726,7 @@ function DocumentToolbar({ editor, defaultRibbonCollapsed = false, reviewOnly =
14956
15726
  onEditingPartChange: onPageChromeEditingPartChange,
14957
15727
  onTogglePageNumber: onTogglePageChromePageNumber,
14958
15728
  onOpenFontDialog: ()=>openFontDialog(pageChromeEditor),
15729
+ onOpenProofingDialog: ()=>openProofingDialog(pageChromeEditor),
14959
15730
  onClose: onClosePageChrome
14960
15731
  }) : null
14961
15732
  }
@@ -14976,6 +15747,21 @@ function DocumentToolbar({ editor, defaultRibbonCollapsed = false, reviewOnly =
14976
15747
  });
14977
15748
  }
14978
15749
  }),
15750
+ proofingDialogRequest && /*#__PURE__*/ jsx(DocumentProofingDialog, {
15751
+ source: proofingDialogRequest.source,
15752
+ restoreFocusTarget: ()=>proofingDialogRequest.editor.isDestroyed ? null : proofingDialogRequest.editor.view.dom,
15753
+ onApply: (patch)=>applyDocumentProofingDialogPatch(proofingDialogRequest.editor, proofingDialogRequest.selection, patch),
15754
+ onClose: ()=>{
15755
+ const { editor: dialogEditor, selection } = proofingDialogRequest;
15756
+ setProofingDialogRequest(null);
15757
+ requestAnimationFrame(()=>{
15758
+ if (dialogEditor.isDestroyed) return;
15759
+ dialogEditor.chain().setTextSelection(selection).focus(null, {
15760
+ scrollIntoView: false
15761
+ }).run();
15762
+ });
15763
+ }
15764
+ }),
14979
15765
  officeDialog.dialog
14980
15766
  ]
14981
15767
  });
@@ -15360,6 +16146,182 @@ function commentActor(actor) {
15360
16146
  author: CURRENT_COMMENT_AUTHOR
15361
16147
  };
15362
16148
  }
16149
+ function DocumentTableOfContentsDialog({ editing, options, restoreFocusTarget, onCancel, onOptionsChange, onSubmit }) {
16150
+ const updateOptions = (update)=>onOptionsChange({
16151
+ ...options,
16152
+ ...update
16153
+ });
16154
+ return /*#__PURE__*/ jsxs(Dialog, {
16155
+ title: editing ? '自定义目录' : '插入目录',
16156
+ description: "从文档标题生成可更新目录,并保留原生 DOCX 目录域。",
16157
+ className: "work-document-table-of-contents-dialog",
16158
+ restoreFocusTarget: restoreFocusTarget,
16159
+ onClose: onCancel,
16160
+ footer: /*#__PURE__*/ jsxs(Fragment, {
16161
+ children: [
16162
+ /*#__PURE__*/ jsx(button_Button, {
16163
+ tone: "quiet",
16164
+ onClick: onCancel,
16165
+ children: "取消"
16166
+ }),
16167
+ /*#__PURE__*/ jsx(button_Button, {
16168
+ tone: "primary",
16169
+ onClick: onSubmit,
16170
+ children: editing ? '应用' : '插入目录'
16171
+ })
16172
+ ]
16173
+ }),
16174
+ children: [
16175
+ /*#__PURE__*/ jsxs("div", {
16176
+ className: "work-document-table-of-contents-dialog-grid",
16177
+ children: [
16178
+ /*#__PURE__*/ jsxs("div", {
16179
+ className: "work-document-table-of-contents-dialog-field",
16180
+ children: [
16181
+ /*#__PURE__*/ jsx("span", {
16182
+ children: "起始标题级别"
16183
+ }),
16184
+ /*#__PURE__*/ jsx(OfficeSelect, {
16185
+ initialFocus: true,
16186
+ ariaLabel: "起始标题级别",
16187
+ value: String(options.minLevel),
16188
+ options: tableOfContentsLevelOptions,
16189
+ onValueChange: (value)=>{
16190
+ const minLevel = Number(value);
16191
+ updateOptions({
16192
+ minLevel,
16193
+ maxLevel: Math.max(minLevel, options.maxLevel)
16194
+ });
16195
+ }
16196
+ })
16197
+ ]
16198
+ }),
16199
+ /*#__PURE__*/ jsxs("div", {
16200
+ className: "work-document-table-of-contents-dialog-field",
16201
+ children: [
16202
+ /*#__PURE__*/ jsx("span", {
16203
+ children: "结束标题级别"
16204
+ }),
16205
+ /*#__PURE__*/ jsx(OfficeSelect, {
16206
+ ariaLabel: "结束标题级别",
16207
+ value: String(options.maxLevel),
16208
+ options: tableOfContentsLevelOptions.map((option)=>({
16209
+ ...option,
16210
+ disabled: Number(option.value) < options.minLevel
16211
+ })),
16212
+ onValueChange: (value)=>updateOptions({
16213
+ maxLevel: Number(value)
16214
+ })
16215
+ })
16216
+ ]
16217
+ })
16218
+ ]
16219
+ }),
16220
+ /*#__PURE__*/ jsxs("div", {
16221
+ className: "work-document-table-of-contents-dialog-options",
16222
+ children: [
16223
+ /*#__PURE__*/ jsx(OfficeCheckbox, {
16224
+ ariaLabel: "目录项使用超链接",
16225
+ checked: options.hyperlinks,
16226
+ onCheckedChange: (hyperlinks)=>updateOptions({
16227
+ hyperlinks
16228
+ }),
16229
+ children: "目录项使用超链接"
16230
+ }),
16231
+ /*#__PURE__*/ jsx(OfficeCheckbox, {
16232
+ ariaLabel: "显示页码",
16233
+ checked: options.showPageNumbers,
16234
+ onCheckedChange: (showPageNumbers)=>updateOptions({
16235
+ showPageNumbers,
16236
+ rightAlignPageNumbers: showPageNumbers && options.rightAlignPageNumbers
16237
+ }),
16238
+ children: "显示页码"
16239
+ }),
16240
+ /*#__PURE__*/ jsx(OfficeCheckbox, {
16241
+ ariaLabel: "页码右对齐",
16242
+ checked: options.rightAlignPageNumbers,
16243
+ disabled: !options.showPageNumbers,
16244
+ onCheckedChange: (rightAlignPageNumbers)=>updateOptions({
16245
+ rightAlignPageNumbers
16246
+ }),
16247
+ children: "页码右对齐"
16248
+ })
16249
+ ]
16250
+ }),
16251
+ /*#__PURE__*/ jsxs("div", {
16252
+ className: "work-document-table-of-contents-dialog-leader",
16253
+ children: [
16254
+ /*#__PURE__*/ jsx("span", {
16255
+ children: "前导符"
16256
+ }),
16257
+ /*#__PURE__*/ jsx(OfficeSelect, {
16258
+ ariaLabel: "目录前导符",
16259
+ value: options.leader,
16260
+ options: tableOfContentsLeaderOptions,
16261
+ disabled: !options.showPageNumbers || !options.rightAlignPageNumbers,
16262
+ onValueChange: (leader)=>updateOptions({
16263
+ leader
16264
+ })
16265
+ })
16266
+ ]
16267
+ }),
16268
+ /*#__PURE__*/ jsxs("fieldset", {
16269
+ className: "work-document-table-of-contents-dialog-preview",
16270
+ "aria-label": "目录预览",
16271
+ "data-toc-leader": options.leader,
16272
+ "data-toc-right-align-page-numbers": String(options.rightAlignPageNumbers),
16273
+ children: [
16274
+ /*#__PURE__*/ jsx("legend", {
16275
+ children: "目录"
16276
+ }),
16277
+ /*#__PURE__*/ jsxs("span", {
16278
+ children: [
16279
+ "项目概述 ",
16280
+ /*#__PURE__*/ jsx("i", {
16281
+ "aria-hidden": "true"
16282
+ }),
16283
+ options.showPageNumbers ? '1' : ''
16284
+ ]
16285
+ }),
16286
+ /*#__PURE__*/ jsxs("span", {
16287
+ className: "nested",
16288
+ children: [
16289
+ "实施计划 ",
16290
+ /*#__PURE__*/ jsx("i", {
16291
+ "aria-hidden": "true"
16292
+ }),
16293
+ options.showPageNumbers ? '3' : ''
16294
+ ]
16295
+ })
16296
+ ]
16297
+ })
16298
+ ]
16299
+ });
16300
+ }
16301
+ const tableOfContentsLevelOptions = Array.from({
16302
+ length: 9
16303
+ }, (_, index)=>({
16304
+ value: String(index + 1),
16305
+ label: `标题 ${index + 1}`
16306
+ }));
16307
+ const tableOfContentsLeaderOptions = [
16308
+ {
16309
+ value: 'dot',
16310
+ label: '点线(……)'
16311
+ },
16312
+ {
16313
+ value: 'dash',
16314
+ label: '短横线(----)'
16315
+ },
16316
+ {
16317
+ value: 'underline',
16318
+ label: '下划线(____)'
16319
+ },
16320
+ {
16321
+ value: 'none',
16322
+ label: '无'
16323
+ }
16324
+ ];
15363
16325
  function useDocumentInsertCommands({ contentRef, editor, resolveFieldContext }) {
15364
16326
  const officeDialog = useOfficeDialog();
15365
16327
  const [insertDialog, setInsertDialog] = useState(null);
@@ -15453,6 +16415,19 @@ function useDocumentInsertCommands({ contentRef, editor, resolveFieldContext })
15453
16415
  editor,
15454
16416
  resolveFieldContext
15455
16417
  ]);
16418
+ const openTableOfContents = useCallback(()=>{
16419
+ if (!editor) return;
16420
+ rememberInvoker();
16421
+ const selected = selectedDocumentTableOfContentsOptions(editor);
16422
+ setInsertDialog({
16423
+ kind: 'tableOfContents',
16424
+ editing: Boolean(selected),
16425
+ options: selected ?? DEFAULT_DOCUMENT_TABLE_OF_CONTENTS_OPTIONS
16426
+ });
16427
+ }, [
16428
+ editor,
16429
+ rememberInvoker
16430
+ ]);
15456
16431
  const refreshFields = useCallback(()=>editor?.commands.refreshDocumentFields(contentRef.current, {
15457
16432
  resolveContext: resolveFieldContext ?? void 0
15458
16433
  }) ?? false, [
@@ -15460,6 +16435,12 @@ function useDocumentInsertCommands({ contentRef, editor, resolveFieldContext })
15460
16435
  editor,
15461
16436
  resolveFieldContext
15462
16437
  ]);
16438
+ const refreshTableOfContents = useCallback(()=>editor?.commands.refreshDocumentTablesOfContents({
16439
+ resolveContext: resolveFieldContext ?? void 0
16440
+ }) ?? false, [
16441
+ editor,
16442
+ resolveFieldContext
16443
+ ]);
15463
16444
  const submitCaption = ()=>{
15464
16445
  if (!editor || insertDialog?.kind !== 'caption') return;
15465
16446
  const inserted = editor.chain().focus().insertDocumentCaption(insertDialog.captionKind, insertDialog.title.trim()).run();
@@ -15476,6 +16457,16 @@ function useDocumentInsertCommands({ contentRef, editor, resolveFieldContext })
15476
16457
  invokerRef.current = editor.view.dom;
15477
16458
  setInsertDialog(null);
15478
16459
  };
16460
+ const submitTableOfContents = ()=>{
16461
+ if (!editor || insertDialog?.kind !== 'tableOfContents') return;
16462
+ const buildOptions = {
16463
+ resolveContext: resolveFieldContext ?? void 0
16464
+ };
16465
+ const applied = insertDialog.editing ? editor.commands.updateDocumentTableOfContents(insertDialog.options, buildOptions) : editor.commands.insertDocumentTableOfContents(insertDialog.options, buildOptions);
16466
+ if (!applied) return;
16467
+ invokerRef.current = editor.view.dom;
16468
+ setInsertDialog(null);
16469
+ };
15479
16470
  const moveReferenceSelection = (event, currentIndex)=>{
15480
16471
  if (insertDialog?.kind !== 'crossReference') return;
15481
16472
  let nextIndex = currentIndex;
@@ -15606,6 +16597,17 @@ function useDocumentInsertCommands({ contentRef, editor, resolveFieldContext })
15606
16597
  }, targetKey);
15607
16598
  })
15608
16599
  })
16600
+ }),
16601
+ insertDialog?.kind === 'tableOfContents' && /*#__PURE__*/ jsx(DocumentTableOfContentsDialog, {
16602
+ editing: insertDialog.editing,
16603
+ options: insertDialog.options,
16604
+ restoreFocusTarget: ()=>invokerRef.current,
16605
+ onCancel: ()=>setInsertDialog(null),
16606
+ onOptionsChange: (options)=>setInsertDialog({
16607
+ ...insertDialog,
16608
+ options
16609
+ }),
16610
+ onSubmit: submitTableOfContents
15609
16611
  })
15610
16612
  ]
15611
16613
  });
@@ -15616,7 +16618,9 @@ function useDocumentInsertCommands({ contentRef, editor, resolveFieldContext })
15616
16618
  insertField,
15617
16619
  insertImage,
15618
16620
  insertNote,
15619
- refreshFields
16621
+ openTableOfContents,
16622
+ refreshFields,
16623
+ refreshTableOfContents
15620
16624
  };
15621
16625
  }
15622
16626
  function referenceTargetKey(target) {
@@ -17681,6 +18685,10 @@ function DocumentEditorSurface({ artifactId, autoFocus = true, collaboration, co
17681
18685
  documentInsert.refreshFields();
17682
18686
  restoreDocumentBodyFocus();
17683
18687
  };
18688
+ const refreshDocumentTableOfContents = ()=>{
18689
+ documentInsert.refreshTableOfContents();
18690
+ restoreDocumentBodyFocus();
18691
+ };
17684
18692
  const openSelectionContextMenu = (event)=>{
17685
18693
  if (!canEditDocument || !getSelectionMenuItems && !onAgentRequest) return false;
17686
18694
  const snapshot = createWorkDocumentSelectionSnapshot(editor, contentRef.current);
@@ -17777,11 +18785,13 @@ function DocumentEditorSurface({ artifactId, autoFocus = true, collaboration, co
17777
18785
  onInsertNote: documentInsert.insertNote,
17778
18786
  onInsertCaption: documentInsert.insertCaption,
17779
18787
  onInsertCrossReference: documentInsert.insertCrossReference,
18788
+ onOpenTableOfContents: documentInsert.openTableOfContents,
17780
18789
  citationsOpen: citationsOpen,
17781
18790
  citationSourceCount: currentContent.bibliography?.sources.length ?? 0,
17782
18791
  onToggleCitations: ()=>void toggleTaskPane('citations'),
17783
18792
  onInsertField: documentInsert.insertField,
17784
18793
  onRefreshFields: refreshDocumentFields,
18794
+ onRefreshTableOfContents: refreshDocumentTableOfContents,
17785
18795
  canInsertComment: documentComments.canInsert,
17786
18796
  onInsertComment: ()=>void startCommentDraft(),
17787
18797
  commentsOpen: documentComments.open,