@a3s-lab/office 0.1.0 → 0.2.2
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.
- package/README.md +101 -24
- package/dist/0~2582.js +485 -0
- package/dist/0~4595.js +14 -7
- package/dist/0~4750.js +939 -0
- package/dist/{0~work-document-paragraph-formatting.js → 0~5861.js} +174 -3
- package/dist/0~7048.js +8 -6
- package/dist/0~9512.js +7 -4
- package/dist/0~document-editor.js +3147 -531
- package/dist/0~markdown-editor.js +26 -1
- package/dist/0~presentation-editor.js +68 -12
- package/dist/0~spreadsheet-editor.js +37 -17
- package/dist/0~work-document-extensions.js +588 -13
- package/dist/0~work-document-model-codec.js +1 -1
- package/dist/0~work-docx-bibliography.js +1 -1
- package/dist/0~work-docx-export.js +116 -55
- package/dist/0~work-docx-import.js +766 -107
- package/dist/0~work-office-diagnostics.js +2 -2
- package/dist/{4704.js → 2881.js} +162 -71
- package/dist/4104.js +2 -62
- package/dist/internal/features/work/editors/document-comment-window.d.ts +37 -0
- package/dist/internal/features/work/editors/document-navigation-panel.d.ts +3 -1
- package/dist/internal/features/work/editors/document-navigation-window.d.ts +64 -0
- package/dist/internal/features/work/editors/document-outline-navigation.d.ts +11 -0
- package/dist/internal/features/work/editors/document-page-navigation.d.ts +11 -1
- package/dist/internal/features/work/editors/document-page-thumbnail.d.ts +31 -0
- package/dist/internal/features/work/editors/document-picture-properties-dialog-model.d.ts +28 -0
- package/dist/internal/features/work/editors/document-picture-properties-dialog.d.ts +4 -0
- package/dist/internal/features/work/editors/document-search-navigation.d.ts +12 -0
- package/dist/internal/features/work/editors/document-table-margins-popover.d.ts +4 -0
- package/dist/internal/features/work/editors/document-table-properties-dialog-model.d.ts +51 -0
- package/dist/internal/features/work/editors/document-table-properties-dialog-sections.d.ts +19 -0
- package/dist/internal/features/work/editors/document-table-properties-dialog.d.ts +8 -0
- package/dist/internal/features/work/editors/office-task-pane.d.ts +1 -1
- package/dist/internal/features/work/editors/presentation-chart-panel.d.ts +2 -1
- package/dist/internal/features/work/editors/presentation-comments-panel.d.ts +2 -1
- package/dist/internal/features/work/editors/spreadsheet-workbook-panel.d.ts +2 -1
- package/dist/internal/features/work/editors/use-document-pagination.d.ts +6 -0
- package/dist/internal/features/work/editors/use-presentation-review-commands.d.ts +1 -1
- package/dist/internal/features/work/work-document-image-layout.d.ts +11 -0
- package/dist/internal/features/work/work-document-page-capture.d.ts +15 -0
- package/dist/internal/features/work/work-document-paragraph-formatting.d.ts +4 -0
- package/dist/internal/features/work/work-document-section.d.ts +3 -1
- package/dist/internal/features/work/work-document-table-borders.d.ts +20 -0
- package/dist/internal/features/work/work-document-table-cell-formatting.d.ts +8 -5
- package/dist/internal/features/work/work-document-table-geometry.d.ts +41 -0
- package/dist/internal/features/work/work-document-table-property-changes.d.ts +25 -0
- package/dist/internal/features/work/work-document-table-sizing.d.ts +15 -2
- package/dist/internal/features/work/work-document-word-line-metrics.d.ts +11 -0
- package/dist/internal/features/work/work-docx-document-layout.d.ts +2 -0
- package/dist/internal/features/work/work-docx-paragraph-alignment-import.d.ts +2 -1
- package/dist/internal/features/work/work-docx-paragraph-direction-import.d.ts +2 -1
- package/dist/internal/features/work/work-docx-paragraph-indent-import.d.ts +2 -1
- package/dist/internal/features/work/work-docx-paragraph-pagination-import.d.ts +2 -1
- package/dist/internal/features/work/work-docx-paragraph-spacing-import.d.ts +3 -2
- package/dist/internal/features/work/work-docx-paragraph-styles.d.ts +2 -2
- package/dist/internal/features/work/work-docx-run-formatting-import.d.ts +8 -1
- package/dist/internal/features/work/work-docx-tab-stop-import.d.ts +2 -1
- package/dist/internal/features/work/work-docx-table-cell-export.d.ts +1 -1
- package/dist/internal/features/work/work-docx-table-cell-import.d.ts +14 -4
- package/dist/internal/features/work/work-docx-table-sizing-export.d.ts +1 -1
- package/dist/internal/features/work/work-docx-table-sizing-import.d.ts +4 -3
- package/dist/internal/features/work/work-docx-table-styles.d.ts +22 -0
- package/dist/internal/features/work/work-types.d.ts +6 -0
- package/dist/office-kernel.wasm +0 -0
- package/dist/styles.css +1288 -233
- package/docs/{browser-editor-architecture.md → latest/en/browser-editor-architecture.md} +144 -35
- package/package.json +9 -5
- package/dist/0~6552.js +0 -787
- package/dist/0~8155.js +0 -299
|
@@ -2,11 +2,11 @@ import { __webpack_require__ } from "./0~rslib-runtime.js";
|
|
|
2
2
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import extension_placeholder from "@tiptap/extension-placeholder";
|
|
4
4
|
import { EditorContent, useEditor } from "@tiptap/react";
|
|
5
|
-
import { Fragment as external_react_Fragment, forwardRef, useCallback, useEffect, useId, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
5
|
+
import { Fragment as external_react_Fragment, forwardRef, useCallback, useEffect, useId, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
6
6
|
import { Extension } 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, Check, CheckCheck, CheckCircle2, ChevronDown, ChevronRight, Cloud, Columns3, Eraser, FileDiff, FilePlus2, FileText, Globe2, Grid2X2, Hash, Highlighter, Image, IndentDecrease, IndentIncrease, Italic, Link2, List, ListChecks, ListOrdered, MessageSquarePlus, MessageSquareReply, MessagesSquare, MoveVertical, Palette, PanelBottom, PanelBottomOpen, PanelLeftOpen, PanelTop, PanelTopOpen, Pilcrow, PilcrowLeft, PilcrowRight, Plus, Quote, Redo2, RefreshCw, Replace, ReplaceAll, RotateCcw, Rows3, Ruler,
|
|
9
|
+
import { AArrowDown, AArrowUp, AlignCenter, AlignJustify, AlignLeft, AlignRight, AlignVerticalJustifyCenter, AlignVerticalJustifyEnd, AlignVerticalJustifyStart, ArrowDown, ArrowUp, BetweenHorizontalEnd, BetweenHorizontalStart, BetweenVerticalEnd, BetweenVerticalStart, Bold, BookMarked, BookOpen, Check, CheckCheck, CheckCircle2, ChevronDown, ChevronRight, Cloud, Columns3, Eraser, FileDiff, FilePlus2, FileText, Globe2, Grid2X2, Hash, Highlighter, Image, IndentDecrease, IndentIncrease, Italic, Link2, List, ListChecks, ListOrdered, MessageSquarePlus, MessageSquareReply, MessagesSquare, MoveVertical, Palette, PanelBottom, PanelBottomOpen, PanelLeftOpen, PanelTop, PanelTopOpen, Pilcrow, PilcrowLeft, PilcrowRight, Plus, Quote, Redo2, RefreshCw, Replace, ReplaceAll, RotateCcw, Rows3, Ruler, Search, Settings2, Strikethrough, Subscript, Superscript, Table2, TableCellsMerge, TableCellsSplit, TableProperties, TextWrap, Trash2, Underline, Undo2, Unlink, X, XCircle, ZoomIn, ZoomOut } from "lucide-react";
|
|
10
10
|
import extension_color from "@tiptap/extension-color";
|
|
11
11
|
import extension_image from "@tiptap/extension-image";
|
|
12
12
|
import { TableKit } from "@tiptap/extension-table";
|
|
@@ -16,18 +16,18 @@ import extension_underline from "@tiptap/extension-underline";
|
|
|
16
16
|
import starter_kit from "@tiptap/starter-kit";
|
|
17
17
|
import { BubbleMenu } from "@tiptap/react/menus";
|
|
18
18
|
import { TableMap, isInTable, selectedRect } from "@tiptap/pm/tables";
|
|
19
|
-
import { nextDocumentTabAlignment, normalizedTabPosition, documentParagraphTabStops, documentImageLayoutOptions,
|
|
20
|
-
import {
|
|
21
|
-
import { normalizeDocumentHtml, documentInitialSectionLayout, isValidDocumentCitationTag, sanitizeDocumentPageChromeHtml, resolveWorkDocumentEditorInput, createDocumentBibliography, syncDocumentContentFromHtml, clampDocumentMargin, documentMargins, millimetersToPixels as work_document_layout_millimetersToPixels, documentCitationStyleDetails, updateDocumentPageChromeVariant, normalizeDocumentColumns, documentPageChromeLegacyFields, resolveDocumentPageChrome, setCustomDocumentColumns, documentCitationStyle, normalizeDocumentPageChrome, createWorkDocumentModel, documentSectionLayoutFromNodeAttributes, updateDocumentColumnWidth } from "./
|
|
19
|
+
import { nextDocumentTabAlignment, normalizedTabPosition, documentParagraphTabStops, DEFAULT_DOCUMENT_TABLE_CELL_MARGINS, documentImageLayoutOptions, documentImageProperties, normalizeDocumentTabStops } from "./0~4750.js";
|
|
20
|
+
import { documentTableRowRepeats, documentTableRowOptions, documentTableCellFormat, activeDocumentTableStyle, DEFAULT_DOCUMENT_TABLE_CELL_FORMAT, documentTableRowCantSplit, documentTableHorizontalAlignment, DOCUMENT_TABLE_STYLE_OPTIONS, canSetDocumentTableRowRepeatHeader } from "./0~2582.js";
|
|
21
|
+
import { normalizeDocumentHtml, documentInitialSectionLayout, isValidDocumentCitationTag, sanitizeDocumentPageChromeHtml, mountWorkLiveDocumentCapture, resolveWorkDocumentEditorInput, createDocumentBibliography, syncDocumentContentFromHtml, clampDocumentMargin, documentMargins, millimetersToPixels as work_document_layout_millimetersToPixels, documentCitationStyleDetails, updateDocumentPageChromeVariant, normalizeDocumentColumns, documentPageChromeLegacyFields, resolveDocumentPageChrome, setCustomDocumentColumns, documentCitationStyle, normalizeDocumentPageChrome, createWorkDocumentModel, documentSectionLayoutFromNodeAttributes, updateDocumentColumnWidth } from "./2881.js";
|
|
22
22
|
import { useOfficeTaskPaneEscape, normalizeOfficeFontFamily, OfficeCheckbox, useOfficeDialog, useOfficeTaskPaneModal, CommittedOfficeNumberField, officeFontFamilyLabel, officeFontFamilies, CollectionState, createOfficeKernelClient, OfficeNumberField } from "./0~7048.js";
|
|
23
23
|
import { office_text_field_OfficeTextArea, Popover, officeOverlayPortalRoot, button_Button, icon_button_IconButton, office_text_field_OfficeTextField, useDialogFocusScope, useOfficeEditorWheelZoom, office_text_field_OfficeFileInput } from "./0~9512.js";
|
|
24
24
|
import { WorkOfficePreviewBar, isWorkspaceContextMenuKeyboardEvent, Tabs, WorkOfficeZoomControls, WorkOfficeStatusBar, Dialog, WorkOfficeRibbon, workspaceContextMenuPosition, OfficeSelect, WorkspaceContextMenu, WorkOfficeRibbonGroup, WorkOfficeRibbonButton } from "./0~4595.js";
|
|
25
25
|
import { createOfficeId as createWorkId } from "./1134.js";
|
|
26
|
-
import { canInsertDocumentComment, activeDocumentSection, documentCommentViews, retainAnchoredDocumentComments, DocumentSubscript, documentCitationCount, documentBulletListStyle, editorDocumentCaptionTargets, collectDocumentChanges, collectDocumentCommentAnchors, documentTabLeaderLabel, documentOrderedListState, MAX_DOCUMENT_NUMBERING_START, documentCommentDraftRange, DocumentSuperscript, documentSectionById, createWorkDocumentExtensions } from "./0~work-document-extensions.js";
|
|
26
|
+
import { canInsertDocumentComment, documentTableSizing, activeDocumentSection, documentCommentViews, retainAnchoredDocumentComments, DocumentSubscript, documentCitationCount, documentBulletListStyle, editorDocumentCaptionTargets, collectDocumentChanges, collectDocumentCommentAnchors, documentTabLeaderLabel, documentOrderedListState, MAX_DOCUMENT_NUMBERING_START, documentCommentDraftRange, DocumentSuperscript, documentSectionById, createWorkDocumentExtensions } from "./0~work-document-extensions.js";
|
|
27
27
|
import { normalizeDocumentHref, DOCUMENT_LINK_VALIDATION_MESSAGE } from "./0~work-document-links.js";
|
|
28
28
|
import { OfficeColorPicker, isOfficeShortcutBlocked } from "./0~3635.js";
|
|
29
29
|
import { OfficeTableInsertPopover, readOfficeFileAsDataUrl } from "./0~9445.js";
|
|
30
|
-
import { documentParagraphSpacing, normalizeDocumentParagraphIndent, documentParagraphDirection, documentParagraphPagination, documentParagraphIndent, canChangeDocumentIndent } from "./0~
|
|
30
|
+
import { documentParagraphSpacing, normalizeDocumentParagraphIndent, documentParagraphDirection, documentParagraphPagination, documentParagraphIndent, canChangeDocumentIndent } from "./0~5861.js";
|
|
31
31
|
import { createWorkDocumentSelectionAction, documentPlainTextAsHtml, mergeOfficeTiptapExtensions, documentCurrentPage, documentAgentMenuItems, clampDocumentZoom, documentPageCount, documentWordCount, documentCustomSelectionMenuItems, createWorkDocumentSelectionSnapshot } from "./0~5050.js";
|
|
32
32
|
import { OFFICE_DOCUMENT_LAYOUT_HEBREW_FONT_ID, WorkEditorLoadingState, OFFICE_DOCUMENT_LAYOUT_FONT_ID, OFFICE_DOCUMENT_LAYOUT_ARABIC_FONT_ID, documentLayoutFontKey, OFFICE_DOCUMENT_LAYOUT_LATIN_FONT_ID } from "./432.js";
|
|
33
33
|
import { useOfficeDraft } from "./0~use-office-draft.js";
|
|
@@ -934,7 +934,7 @@ function createDocumentTableRowFragmentPlan(cells, rowHeight, maximumFragmentedR
|
|
|
934
934
|
] : [])
|
|
935
935
|
}
|
|
936
936
|
];
|
|
937
|
-
if (!cells.length || !Number.isFinite(maximumFragmentedRowHeight) ||
|
|
937
|
+
if (!cells.length || !Number.isFinite(maximumFragmentedRowHeight) || maximumFragmentedRowHeight <= 0) return atomic();
|
|
938
938
|
const candidates = normalizedDocumentTableBreakCoordinates(cells.flatMap((cell)=>cell.boundaries.slice(1, -1).map((boundary)=>boundary.y).filter((y)=>y > 0.5 && y < height - 0.5))).slice(0, MAX_DOCUMENT_TABLE_ROW_FRAGMENTS - 1);
|
|
939
939
|
if (!candidates.length) return atomic();
|
|
940
940
|
const coordinates = [
|
|
@@ -1530,6 +1530,266 @@ function reusableDocumentListLayoutBlocks(previous, listId, nodeTo, dirtyFrom) {
|
|
|
1530
1530
|
}
|
|
1531
1531
|
}));
|
|
1532
1532
|
}
|
|
1533
|
+
const DOCUMENT_NAVIGATION_COLLECTION_WINDOW_THRESHOLD = 48;
|
|
1534
|
+
const DOCUMENT_NAVIGATION_COLLECTION_WINDOW_LIMIT = 32;
|
|
1535
|
+
const DOCUMENT_NAVIGATION_COLLECTION_WINDOW_OVERSCAN = 4;
|
|
1536
|
+
const DOCUMENT_NAVIGATION_FALLBACK_VIEWPORT_HEIGHT = 720;
|
|
1537
|
+
function useDocumentNavigationWindow({ estimatedItemHeight, itemGap, keys, listPaddingTop, onRovingKeyChange, pinnedKeys = [], rovingKey }) {
|
|
1538
|
+
const viewportRef = useRef(null);
|
|
1539
|
+
const itemRefs = useRef(new Map());
|
|
1540
|
+
const keysRef = useRef(keys);
|
|
1541
|
+
const pendingFocusKeyRef = useRef(null);
|
|
1542
|
+
const rovingIndex = rovingKey ? keys.indexOf(rovingKey) : -1;
|
|
1543
|
+
const [anchorIndex, setAnchorIndex] = useState(Math.max(0, rovingIndex));
|
|
1544
|
+
const [viewportHeight, setViewportHeight] = useState(DOCUMENT_NAVIGATION_FALLBACK_VIEWPORT_HEIGHT);
|
|
1545
|
+
keysRef.current = keys;
|
|
1546
|
+
useEffect(()=>{
|
|
1547
|
+
if (rovingIndex < 0) return;
|
|
1548
|
+
setAnchorIndex(rovingIndex);
|
|
1549
|
+
}, [
|
|
1550
|
+
rovingIndex,
|
|
1551
|
+
rovingKey
|
|
1552
|
+
]);
|
|
1553
|
+
useLayoutEffect(()=>{
|
|
1554
|
+
const viewport = viewportRef.current;
|
|
1555
|
+
if (!viewport) return;
|
|
1556
|
+
const update = ()=>{
|
|
1557
|
+
const nextHeight = viewport.clientHeight || DOCUMENT_NAVIGATION_FALLBACK_VIEWPORT_HEIGHT;
|
|
1558
|
+
setViewportHeight((current)=>current === nextHeight ? current : nextHeight);
|
|
1559
|
+
};
|
|
1560
|
+
update();
|
|
1561
|
+
if ("u" < typeof ResizeObserver) return;
|
|
1562
|
+
const observer = new ResizeObserver(update);
|
|
1563
|
+
observer.observe(viewport);
|
|
1564
|
+
return ()=>observer.disconnect();
|
|
1565
|
+
}, [
|
|
1566
|
+
keys.length
|
|
1567
|
+
]);
|
|
1568
|
+
const itemHeights = useMemo(()=>Array.from({
|
|
1569
|
+
length: keys.length
|
|
1570
|
+
}, ()=>Math.max(1, estimatedItemHeight)), [
|
|
1571
|
+
estimatedItemHeight,
|
|
1572
|
+
keys.length
|
|
1573
|
+
]);
|
|
1574
|
+
const itemStarts = useMemo(()=>documentNavigationItemStarts(itemHeights, itemGap), [
|
|
1575
|
+
itemGap,
|
|
1576
|
+
itemHeights
|
|
1577
|
+
]);
|
|
1578
|
+
const averageItemHeight = itemHeights.length ? (itemStarts[itemStarts.length - 1] ?? 1) / itemHeights.length : 1;
|
|
1579
|
+
const range = useMemo(()=>calculateDocumentNavigationWindowRange({
|
|
1580
|
+
anchorIndex,
|
|
1581
|
+
averageItemHeight,
|
|
1582
|
+
itemCount: keys.length,
|
|
1583
|
+
limit: DOCUMENT_NAVIGATION_COLLECTION_WINDOW_LIMIT,
|
|
1584
|
+
overscan: DOCUMENT_NAVIGATION_COLLECTION_WINDOW_OVERSCAN,
|
|
1585
|
+
threshold: DOCUMENT_NAVIGATION_COLLECTION_WINDOW_THRESHOLD,
|
|
1586
|
+
viewportHeight
|
|
1587
|
+
}), [
|
|
1588
|
+
anchorIndex,
|
|
1589
|
+
averageItemHeight,
|
|
1590
|
+
keys.length,
|
|
1591
|
+
viewportHeight
|
|
1592
|
+
]);
|
|
1593
|
+
const pinnedIndices = useMemo(()=>{
|
|
1594
|
+
const indices = new Set();
|
|
1595
|
+
if (rovingIndex >= 0) indices.add(rovingIndex);
|
|
1596
|
+
for (const key of pinnedKeys){
|
|
1597
|
+
if (!key) continue;
|
|
1598
|
+
const index = keys.indexOf(key);
|
|
1599
|
+
if (index >= 0) indices.add(index);
|
|
1600
|
+
}
|
|
1601
|
+
return [
|
|
1602
|
+
...indices
|
|
1603
|
+
];
|
|
1604
|
+
}, [
|
|
1605
|
+
keys,
|
|
1606
|
+
pinnedKeys,
|
|
1607
|
+
rovingIndex
|
|
1608
|
+
]);
|
|
1609
|
+
const mountedIndices = useMemo(()=>documentNavigationWindowIndices({
|
|
1610
|
+
itemCount: keys.length,
|
|
1611
|
+
pinnedIndices,
|
|
1612
|
+
range
|
|
1613
|
+
}), [
|
|
1614
|
+
keys.length,
|
|
1615
|
+
pinnedIndices,
|
|
1616
|
+
range
|
|
1617
|
+
]);
|
|
1618
|
+
const entries = useMemo(()=>documentNavigationWindowEntries(mountedIndices, itemStarts, keys.length, itemGap), [
|
|
1619
|
+
itemGap,
|
|
1620
|
+
itemStarts,
|
|
1621
|
+
keys.length,
|
|
1622
|
+
mountedIndices
|
|
1623
|
+
]);
|
|
1624
|
+
const mountedIndicesKey = mountedIndices.join(',');
|
|
1625
|
+
const registerItem = useCallback((key, element)=>{
|
|
1626
|
+
if (element) itemRefs.current.set(key, element);
|
|
1627
|
+
else itemRefs.current.delete(key);
|
|
1628
|
+
}, []);
|
|
1629
|
+
const focusAt = useCallback((requestedIndex)=>{
|
|
1630
|
+
const currentKeys = keysRef.current;
|
|
1631
|
+
if (!currentKeys.length) return;
|
|
1632
|
+
const index = Math.min(currentKeys.length - 1, Math.max(0, Math.floor(requestedIndex)));
|
|
1633
|
+
const key = currentKeys[index];
|
|
1634
|
+
if (!key) return;
|
|
1635
|
+
setAnchorIndex(index);
|
|
1636
|
+
onRovingKeyChange(key);
|
|
1637
|
+
const mounted = itemRefs.current.get(key);
|
|
1638
|
+
if (mounted) {
|
|
1639
|
+
pendingFocusKeyRef.current = null;
|
|
1640
|
+
focusDocumentNavigationItem(mounted);
|
|
1641
|
+
return;
|
|
1642
|
+
}
|
|
1643
|
+
pendingFocusKeyRef.current = key;
|
|
1644
|
+
}, [
|
|
1645
|
+
onRovingKeyChange
|
|
1646
|
+
]);
|
|
1647
|
+
const onItemFocus = useCallback((index)=>{
|
|
1648
|
+
const key = keysRef.current[index];
|
|
1649
|
+
if (!key) return;
|
|
1650
|
+
pendingFocusKeyRef.current = null;
|
|
1651
|
+
setAnchorIndex(index);
|
|
1652
|
+
onRovingKeyChange(key);
|
|
1653
|
+
}, [
|
|
1654
|
+
onRovingKeyChange
|
|
1655
|
+
]);
|
|
1656
|
+
useLayoutEffect(()=>{
|
|
1657
|
+
const pendingKey = pendingFocusKeyRef.current;
|
|
1658
|
+
if (!pendingKey) return;
|
|
1659
|
+
if (!keys.includes(pendingKey)) {
|
|
1660
|
+
pendingFocusKeyRef.current = null;
|
|
1661
|
+
return;
|
|
1662
|
+
}
|
|
1663
|
+
const element = itemRefs.current.get(pendingKey);
|
|
1664
|
+
if (!element) return;
|
|
1665
|
+
pendingFocusKeyRef.current = null;
|
|
1666
|
+
focusDocumentNavigationItem(element);
|
|
1667
|
+
}, [
|
|
1668
|
+
keys,
|
|
1669
|
+
mountedIndicesKey,
|
|
1670
|
+
rovingKey
|
|
1671
|
+
]);
|
|
1672
|
+
const onScroll = useCallback((event)=>{
|
|
1673
|
+
if (!range.windowed) return;
|
|
1674
|
+
const nextAnchor = documentNavigationIndexAtOffset(itemStarts, Math.max(0, event.currentTarget.scrollTop - listPaddingTop), keys.length);
|
|
1675
|
+
setAnchorIndex((current)=>current === nextAnchor ? current : nextAnchor);
|
|
1676
|
+
}, [
|
|
1677
|
+
itemStarts,
|
|
1678
|
+
keys.length,
|
|
1679
|
+
listPaddingTop,
|
|
1680
|
+
range.windowed
|
|
1681
|
+
]);
|
|
1682
|
+
return {
|
|
1683
|
+
entries,
|
|
1684
|
+
focusAt,
|
|
1685
|
+
mountedCount: mountedIndices.length,
|
|
1686
|
+
onItemFocus,
|
|
1687
|
+
onScroll,
|
|
1688
|
+
range,
|
|
1689
|
+
registerItem,
|
|
1690
|
+
rovingIndex,
|
|
1691
|
+
viewportRef
|
|
1692
|
+
};
|
|
1693
|
+
}
|
|
1694
|
+
function DocumentNavigationWindowSpacer({ entry }) {
|
|
1695
|
+
return /*#__PURE__*/ jsx("li", {
|
|
1696
|
+
"aria-hidden": "true",
|
|
1697
|
+
className: "work-document-navigation-window-spacer",
|
|
1698
|
+
"data-document-navigation-spacer": entry.position,
|
|
1699
|
+
"data-document-navigation-spacer-end": entry.end,
|
|
1700
|
+
"data-document-navigation-spacer-start": entry.start + 1,
|
|
1701
|
+
role: "presentation",
|
|
1702
|
+
style: {
|
|
1703
|
+
height: `${entry.height}px`
|
|
1704
|
+
}
|
|
1705
|
+
});
|
|
1706
|
+
}
|
|
1707
|
+
function calculateDocumentNavigationWindowRange({ anchorIndex, averageItemHeight, itemCount, limit, overscan, threshold, viewportHeight }) {
|
|
1708
|
+
const count = Math.max(0, Math.floor(itemCount));
|
|
1709
|
+
if (count <= Math.max(0, Math.floor(threshold))) return {
|
|
1710
|
+
end: count,
|
|
1711
|
+
start: 0,
|
|
1712
|
+
windowed: false
|
|
1713
|
+
};
|
|
1714
|
+
const visibleCount = Math.max(1, Math.ceil(Math.max(1, viewportHeight) / Math.max(1, averageItemHeight)));
|
|
1715
|
+
const boundedOverscan = Math.max(0, Math.floor(overscan));
|
|
1716
|
+
const windowCount = Math.min(count, Math.max(1, Math.floor(limit)), visibleCount + 2 * boundedOverscan);
|
|
1717
|
+
const boundedAnchor = Math.min(count - 1, Math.max(0, Math.floor(anchorIndex)));
|
|
1718
|
+
const start = Math.min(count - windowCount, Math.max(0, boundedAnchor - boundedOverscan));
|
|
1719
|
+
return {
|
|
1720
|
+
end: start + windowCount,
|
|
1721
|
+
start,
|
|
1722
|
+
windowed: true
|
|
1723
|
+
};
|
|
1724
|
+
}
|
|
1725
|
+
function documentNavigationItemStarts(itemHeights, itemGap) {
|
|
1726
|
+
const starts = [
|
|
1727
|
+
0
|
|
1728
|
+
];
|
|
1729
|
+
const gap = Math.max(0, itemGap);
|
|
1730
|
+
for (const height of itemHeights)starts.push((starts[starts.length - 1] ?? 0) + Math.max(1, height) + gap);
|
|
1731
|
+
return starts;
|
|
1732
|
+
}
|
|
1733
|
+
function documentNavigationWindowIndices({ itemCount, pinnedIndices, range }) {
|
|
1734
|
+
const count = Math.max(0, Math.floor(itemCount));
|
|
1735
|
+
if (!range.windowed) return Array.from({
|
|
1736
|
+
length: count
|
|
1737
|
+
}, (_, index)=>index);
|
|
1738
|
+
const mounted = new Set();
|
|
1739
|
+
for(let index = range.start; index < range.end; index += 1)if (index >= 0 && index < count) mounted.add(index);
|
|
1740
|
+
for (const index of pinnedIndices)if (index >= 0 && index < count) mounted.add(index);
|
|
1741
|
+
return [
|
|
1742
|
+
...mounted
|
|
1743
|
+
].sort((left, right)=>left - right);
|
|
1744
|
+
}
|
|
1745
|
+
function documentNavigationWindowEntries(mountedIndices, itemStarts, itemCount, itemGap) {
|
|
1746
|
+
const entries = [];
|
|
1747
|
+
let cursor = 0;
|
|
1748
|
+
for (const index of mountedIndices){
|
|
1749
|
+
if (index > cursor) entries.push(documentNavigationWindowSpacerEntry(cursor, index, itemStarts, itemCount, itemGap));
|
|
1750
|
+
entries.push({
|
|
1751
|
+
index,
|
|
1752
|
+
kind: 'item'
|
|
1753
|
+
});
|
|
1754
|
+
cursor = index + 1;
|
|
1755
|
+
}
|
|
1756
|
+
if (cursor < itemCount) entries.push(documentNavigationWindowSpacerEntry(cursor, itemCount, itemStarts, itemCount, itemGap));
|
|
1757
|
+
return entries;
|
|
1758
|
+
}
|
|
1759
|
+
function documentNavigationIndexAtOffset(itemStarts, offset, itemCount) {
|
|
1760
|
+
if (itemCount <= 1) return 0;
|
|
1761
|
+
let low = 0;
|
|
1762
|
+
let high = itemCount - 1;
|
|
1763
|
+
while(low <= high){
|
|
1764
|
+
const middle = Math.floor((low + high) / 2);
|
|
1765
|
+
const start = itemStarts[middle] ?? 0;
|
|
1766
|
+
const next = itemStarts[middle + 1] ?? 1 / 0;
|
|
1767
|
+
if (offset < start) high = middle - 1;
|
|
1768
|
+
else {
|
|
1769
|
+
if (!(offset >= next)) return middle;
|
|
1770
|
+
low = middle + 1;
|
|
1771
|
+
}
|
|
1772
|
+
}
|
|
1773
|
+
return Math.min(itemCount - 1, Math.max(0, low));
|
|
1774
|
+
}
|
|
1775
|
+
function documentNavigationWindowSpacerEntry(start, end, itemStarts, itemCount, itemGap) {
|
|
1776
|
+
return {
|
|
1777
|
+
end,
|
|
1778
|
+
height: Math.max(0, (itemStarts[end] ?? 0) - (itemStarts[start] ?? 0) - Math.max(0, itemGap)),
|
|
1779
|
+
kind: 'spacer',
|
|
1780
|
+
position: 0 === start ? 'before' : end === itemCount ? 'after' : 'between',
|
|
1781
|
+
start
|
|
1782
|
+
};
|
|
1783
|
+
}
|
|
1784
|
+
function focusDocumentNavigationItem(element) {
|
|
1785
|
+
element.focus({
|
|
1786
|
+
preventScroll: true
|
|
1787
|
+
});
|
|
1788
|
+
element.scrollIntoView?.({
|
|
1789
|
+
block: 'nearest',
|
|
1790
|
+
inline: 'nearest'
|
|
1791
|
+
});
|
|
1792
|
+
}
|
|
1533
1793
|
function DocumentTaskPane({ ariaLabel, title, description, closeLabel, className, children, onClose, onKeyDown }) {
|
|
1534
1794
|
const titleId = useId();
|
|
1535
1795
|
const descriptionId = useId();
|
|
@@ -1582,37 +1842,69 @@ function DocumentTaskPane({ ariaLabel, title, description, closeLabel, className
|
|
|
1582
1842
|
]
|
|
1583
1843
|
});
|
|
1584
1844
|
}
|
|
1845
|
+
const DOCUMENT_CHANGE_ITEM_HEIGHT = 84;
|
|
1846
|
+
const DOCUMENT_CHANGE_ITEM_GAP = 7;
|
|
1847
|
+
const DOCUMENT_CHANGE_LIST_PADDING_TOP = 10;
|
|
1585
1848
|
function DocumentChangesPanel({ editor, changes, trackChanges, onTrackChangesChange, onClose }) {
|
|
1586
1849
|
const officeDialog = useOfficeDialog();
|
|
1587
1850
|
const decisionButtonRefs = useRef(new Map());
|
|
1588
1851
|
const pendingFocusRef = useRef(null);
|
|
1852
|
+
const changeKeys = useMemo(()=>changes.map(documentChangeWindowKey), [
|
|
1853
|
+
changes
|
|
1854
|
+
]);
|
|
1855
|
+
const [rovingChangeKey, setRovingChangeKey] = useState(()=>changeKeys[0] ?? null);
|
|
1856
|
+
const effectiveRovingChangeKey = rovingChangeKey && changeKeys.includes(rovingChangeKey) ? rovingChangeKey : changeKeys[0] ?? null;
|
|
1857
|
+
const changeWindow = useDocumentNavigationWindow({
|
|
1858
|
+
estimatedItemHeight: DOCUMENT_CHANGE_ITEM_HEIGHT,
|
|
1859
|
+
itemGap: DOCUMENT_CHANGE_ITEM_GAP,
|
|
1860
|
+
keys: changeKeys,
|
|
1861
|
+
listPaddingTop: DOCUMENT_CHANGE_LIST_PADDING_TOP,
|
|
1862
|
+
onRovingKeyChange: setRovingChangeKey,
|
|
1863
|
+
rovingKey: effectiveRovingChangeKey
|
|
1864
|
+
});
|
|
1589
1865
|
useLayoutEffect(()=>{
|
|
1590
1866
|
const pending = pendingFocusRef.current;
|
|
1591
1867
|
if (!pending) return;
|
|
1592
|
-
|
|
1593
|
-
const nextButton = pending.changeId ? decisionButtonRefs.current.get(documentChangeDecisionKey(pending.changeId, pending.decision)) : void 0;
|
|
1868
|
+
const nextButton = pending.changeKey ? decisionButtonRefs.current.get(documentChangeDecisionKey(pending.changeKey, pending.decision)) : void 0;
|
|
1594
1869
|
if (nextButton) {
|
|
1870
|
+
pendingFocusRef.current = null;
|
|
1595
1871
|
nextButton.focus({
|
|
1596
1872
|
preventScroll: true
|
|
1597
1873
|
});
|
|
1598
1874
|
nextButton.scrollIntoView({
|
|
1599
1875
|
block: 'nearest'
|
|
1600
1876
|
});
|
|
1601
|
-
} else if (!editor.isDestroyed)
|
|
1602
|
-
|
|
1603
|
-
|
|
1877
|
+
} else if (!pending.changeKey && !editor.isDestroyed) {
|
|
1878
|
+
pendingFocusRef.current = null;
|
|
1879
|
+
editor.view.dom.focus({
|
|
1880
|
+
preventScroll: true
|
|
1881
|
+
});
|
|
1882
|
+
}
|
|
1604
1883
|
}, [
|
|
1884
|
+
changeWindow.mountedCount,
|
|
1605
1885
|
changes,
|
|
1606
1886
|
editor
|
|
1607
1887
|
]);
|
|
1608
1888
|
const decideChange = (change, index, decision)=>{
|
|
1609
1889
|
const nextChange = changes[index + 1] ?? changes[index - 1] ?? null;
|
|
1890
|
+
const currentChangeKey = documentChangeWindowKey(change);
|
|
1891
|
+
const nextChangeKey = nextChange ? documentChangeWindowKey(nextChange) : null;
|
|
1610
1892
|
pendingFocusRef.current = {
|
|
1611
|
-
|
|
1893
|
+
changeKey: nextChangeKey,
|
|
1612
1894
|
decision
|
|
1613
1895
|
};
|
|
1896
|
+
setRovingChangeKey(nextChangeKey);
|
|
1614
1897
|
const handled = 'accept' === decision ? editor.commands.acceptDocumentChange(change.id) : editor.commands.rejectDocumentChange(change.id);
|
|
1615
|
-
if (!handled)
|
|
1898
|
+
if (!handled) {
|
|
1899
|
+
pendingFocusRef.current = null;
|
|
1900
|
+
setRovingChangeKey(currentChangeKey);
|
|
1901
|
+
}
|
|
1902
|
+
};
|
|
1903
|
+
const handleSummaryKeyDown = (event, index)=>{
|
|
1904
|
+
const nextIndex = documentChangeKeyboardDestination(event.key, index, changes.length);
|
|
1905
|
+
if (null === nextIndex) return;
|
|
1906
|
+
event.preventDefault();
|
|
1907
|
+
changeWindow.focusAt(nextIndex);
|
|
1616
1908
|
};
|
|
1617
1909
|
const acceptAll = async ()=>{
|
|
1618
1910
|
const confirmed = await officeDialog.confirm({
|
|
@@ -1675,87 +1967,111 @@ function DocumentChangesPanel({ editor, changes, trackChanges, onTrackChangesCha
|
|
|
1675
1967
|
})
|
|
1676
1968
|
]
|
|
1677
1969
|
}),
|
|
1678
|
-
/*#__PURE__*/
|
|
1970
|
+
changes.length > 0 ? /*#__PURE__*/ jsx("ol", {
|
|
1971
|
+
ref: changeWindow.viewportRef,
|
|
1679
1972
|
className: "work-document-change-list work-document-task-pane-body",
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1973
|
+
"aria-label": "待处理修订",
|
|
1974
|
+
"data-document-change-count": changes.length,
|
|
1975
|
+
"data-document-change-mounted-count": changeWindow.mountedCount,
|
|
1976
|
+
"data-document-change-window-end": changeWindow.range.end,
|
|
1977
|
+
"data-document-change-window-limit": 32,
|
|
1978
|
+
"data-document-change-window-start": changeWindow.range.start,
|
|
1979
|
+
"data-document-change-windowed": changeWindow.range.windowed ? 'true' : 'false',
|
|
1980
|
+
onScroll: changeWindow.onScroll,
|
|
1981
|
+
children: changeWindow.entries.map((entry)=>{
|
|
1982
|
+
if ('spacer' === entry.kind) return /*#__PURE__*/ jsx(DocumentChangeWindowSpacer, {
|
|
1983
|
+
entry: entry
|
|
1984
|
+
}, `spacer-${entry.start}-${entry.end}`);
|
|
1985
|
+
const change = changes[entry.index];
|
|
1986
|
+
if (!change) return null;
|
|
1987
|
+
const changeKey = documentChangeWindowKey(change);
|
|
1988
|
+
return /*#__PURE__*/ jsxs("li", {
|
|
1989
|
+
"aria-posinset": entry.index + 1,
|
|
1990
|
+
"aria-setsize": changes.length,
|
|
1991
|
+
className: `work-document-change-item ${change.kind}`,
|
|
1992
|
+
"data-document-change-item": entry.index + 1,
|
|
1993
|
+
onFocusCapture: ()=>changeWindow.onItemFocus(entry.index),
|
|
1994
|
+
children: [
|
|
1995
|
+
/*#__PURE__*/ jsxs("button", {
|
|
1996
|
+
ref: (element)=>changeWindow.registerItem(changeKey, element),
|
|
1997
|
+
type: "button",
|
|
1998
|
+
className: "work-document-change-summary",
|
|
1999
|
+
tabIndex: changeWindow.rovingIndex === entry.index ? 0 : -1,
|
|
2000
|
+
"aria-label": `定位修订 ${entry.index + 1}`,
|
|
2001
|
+
onKeyDown: (event)=>handleSummaryKeyDown(event, entry.index),
|
|
2002
|
+
onClick: ()=>editor.chain().focus().setTextSelection({
|
|
2003
|
+
from: Math.min(change.from, editor.state.doc.content.size),
|
|
2004
|
+
to: Math.min(change.to, editor.state.doc.content.size)
|
|
2005
|
+
}).run(),
|
|
2006
|
+
children: [
|
|
2007
|
+
/*#__PURE__*/ jsx("span", {
|
|
2008
|
+
children: 'insertion' === change.kind ? '插入' : '删除'
|
|
2009
|
+
}),
|
|
2010
|
+
/*#__PURE__*/ jsx("strong", {
|
|
2011
|
+
children: change.text.trim() || '(空白字符)'
|
|
2012
|
+
}),
|
|
2013
|
+
/*#__PURE__*/ jsxs("small", {
|
|
2014
|
+
children: [
|
|
2015
|
+
change.author,
|
|
2016
|
+
change.date ? ` · ${formatChangeDate(change.date)}` : ''
|
|
2017
|
+
]
|
|
2018
|
+
})
|
|
2019
|
+
]
|
|
2020
|
+
}),
|
|
2021
|
+
/*#__PURE__*/ jsxs("div", {
|
|
2022
|
+
children: [
|
|
2023
|
+
/*#__PURE__*/ jsxs(button_Button, {
|
|
2024
|
+
ref: (element)=>{
|
|
2025
|
+
const key = documentChangeDecisionKey(changeKey, 'accept');
|
|
2026
|
+
if (element) decisionButtonRefs.current.set(key, element);
|
|
2027
|
+
else decisionButtonRefs.current.delete(key);
|
|
2028
|
+
},
|
|
2029
|
+
tone: "quiet",
|
|
2030
|
+
"aria-label": `接受修订 ${entry.index + 1}`,
|
|
2031
|
+
onClick: ()=>decideChange(change, entry.index, 'accept'),
|
|
2032
|
+
children: [
|
|
2033
|
+
/*#__PURE__*/ jsx(Check, {
|
|
2034
|
+
size: 13
|
|
2035
|
+
}),
|
|
2036
|
+
"接受"
|
|
2037
|
+
]
|
|
2038
|
+
}),
|
|
2039
|
+
/*#__PURE__*/ jsxs(button_Button, {
|
|
2040
|
+
ref: (element)=>{
|
|
2041
|
+
const key = documentChangeDecisionKey(changeKey, 'reject');
|
|
2042
|
+
if (element) decisionButtonRefs.current.set(key, element);
|
|
2043
|
+
else decisionButtonRefs.current.delete(key);
|
|
2044
|
+
},
|
|
2045
|
+
tone: "quiet",
|
|
2046
|
+
"aria-label": `拒绝修订 ${entry.index + 1}`,
|
|
2047
|
+
onClick: ()=>decideChange(change, entry.index, 'reject'),
|
|
2048
|
+
children: [
|
|
2049
|
+
/*#__PURE__*/ jsx(XCircle, {
|
|
2050
|
+
size: 13
|
|
2051
|
+
}),
|
|
2052
|
+
"拒绝"
|
|
2053
|
+
]
|
|
2054
|
+
})
|
|
2055
|
+
]
|
|
2056
|
+
})
|
|
2057
|
+
]
|
|
2058
|
+
}, changeKey);
|
|
2059
|
+
})
|
|
2060
|
+
}) : /*#__PURE__*/ jsx("div", {
|
|
2061
|
+
className: "work-document-change-list work-document-task-pane-body",
|
|
2062
|
+
children: /*#__PURE__*/ jsx(CollectionState, {
|
|
2063
|
+
className: "work-document-changes-empty",
|
|
2064
|
+
icon: /*#__PURE__*/ jsx(FileDiff, {}),
|
|
2065
|
+
actions: /*#__PURE__*/ jsx(button_Button, {
|
|
2066
|
+
size: "compact",
|
|
2067
|
+
tone: trackChanges ? 'quiet' : 'primary',
|
|
2068
|
+
onClick: ()=>onTrackChangesChange(!trackChanges),
|
|
2069
|
+
children: trackChanges ? '停止记录' : '开启修订'
|
|
2070
|
+
}),
|
|
2071
|
+
tone: trackChanges ? 'info' : 'neutral',
|
|
2072
|
+
role: "status",
|
|
2073
|
+
children: trackChanges ? '正在记录新的改动。' : '当前没有记录新的改动。'
|
|
2074
|
+
})
|
|
1759
2075
|
})
|
|
1760
2076
|
]
|
|
1761
2077
|
}),
|
|
@@ -1763,8 +2079,34 @@ function DocumentChangesPanel({ editor, changes, trackChanges, onTrackChangesCha
|
|
|
1763
2079
|
]
|
|
1764
2080
|
});
|
|
1765
2081
|
}
|
|
1766
|
-
function documentChangeDecisionKey(
|
|
1767
|
-
return `${
|
|
2082
|
+
function documentChangeDecisionKey(changeKey, decision) {
|
|
2083
|
+
return `${changeKey}:${decision}`;
|
|
2084
|
+
}
|
|
2085
|
+
function documentChangeWindowKey(change) {
|
|
2086
|
+
return `${change.kind}:${change.id}`;
|
|
2087
|
+
}
|
|
2088
|
+
function documentChangeKeyboardDestination(key, index, itemCount) {
|
|
2089
|
+
if (!itemCount) return null;
|
|
2090
|
+
if ('ArrowDown' === key) return Math.min(itemCount - 1, index + 1);
|
|
2091
|
+
if ('ArrowUp' === key) return Math.max(0, index - 1);
|
|
2092
|
+
if ('PageDown' === key) return Math.min(itemCount - 1, index + 8);
|
|
2093
|
+
if ('PageUp' === key) return Math.max(0, index - 8);
|
|
2094
|
+
if ('Home' === key) return 0;
|
|
2095
|
+
if ('End' === key) return itemCount - 1;
|
|
2096
|
+
return null;
|
|
2097
|
+
}
|
|
2098
|
+
function DocumentChangeWindowSpacer({ entry }) {
|
|
2099
|
+
return /*#__PURE__*/ jsx("li", {
|
|
2100
|
+
"aria-hidden": "true",
|
|
2101
|
+
className: "work-document-change-window-spacer",
|
|
2102
|
+
"data-document-change-spacer": entry.position,
|
|
2103
|
+
"data-document-change-spacer-end": entry.end,
|
|
2104
|
+
"data-document-change-spacer-start": entry.start + 1,
|
|
2105
|
+
role: "presentation",
|
|
2106
|
+
style: {
|
|
2107
|
+
height: `${entry.height}px`
|
|
2108
|
+
}
|
|
2109
|
+
});
|
|
1768
2110
|
}
|
|
1769
2111
|
function formatChangeDate(value) {
|
|
1770
2112
|
const time = Date.parse(value);
|
|
@@ -2614,6 +2956,191 @@ const document_comment_composer_DocumentCommentComposer = /*#__PURE__*/ forwardR
|
|
|
2614
2956
|
]
|
|
2615
2957
|
});
|
|
2616
2958
|
});
|
|
2959
|
+
const DOCUMENT_COMMENT_WINDOW_THRESHOLD = 48;
|
|
2960
|
+
const DOCUMENT_COMMENT_WINDOW_LIMIT = 32;
|
|
2961
|
+
const DOCUMENT_COMMENT_WINDOW_OVERSCAN = 4;
|
|
2962
|
+
function useDocumentCommentWindow({ keys, onRovingKeyChange, pinnedKeys = [], rovingKey }) {
|
|
2963
|
+
const itemRefs = useRef(new Map());
|
|
2964
|
+
const keysRef = useRef(keys);
|
|
2965
|
+
const pendingFocusKeyRef = useRef(null);
|
|
2966
|
+
const rovingIndex = rovingKey ? keys.indexOf(rovingKey) : -1;
|
|
2967
|
+
const [anchorIndex, setAnchorIndex] = useState(Math.max(0, rovingIndex));
|
|
2968
|
+
keysRef.current = keys;
|
|
2969
|
+
useEffect(()=>{
|
|
2970
|
+
if (rovingIndex < 0) return;
|
|
2971
|
+
setAnchorIndex(rovingIndex);
|
|
2972
|
+
}, [
|
|
2973
|
+
rovingIndex,
|
|
2974
|
+
rovingKey
|
|
2975
|
+
]);
|
|
2976
|
+
const range = useMemo(()=>calculateDocumentCommentWindowRange({
|
|
2977
|
+
anchorIndex,
|
|
2978
|
+
itemCount: keys.length
|
|
2979
|
+
}), [
|
|
2980
|
+
anchorIndex,
|
|
2981
|
+
keys.length
|
|
2982
|
+
]);
|
|
2983
|
+
const pinnedIndices = useMemo(()=>{
|
|
2984
|
+
const indices = new Set();
|
|
2985
|
+
if (rovingIndex >= 0) indices.add(rovingIndex);
|
|
2986
|
+
for (const key of pinnedKeys){
|
|
2987
|
+
if (!key) continue;
|
|
2988
|
+
const index = keys.indexOf(key);
|
|
2989
|
+
if (index >= 0) indices.add(index);
|
|
2990
|
+
}
|
|
2991
|
+
return [
|
|
2992
|
+
...indices
|
|
2993
|
+
];
|
|
2994
|
+
}, [
|
|
2995
|
+
keys,
|
|
2996
|
+
pinnedKeys,
|
|
2997
|
+
rovingIndex
|
|
2998
|
+
]);
|
|
2999
|
+
const mountedIndices = useMemo(()=>documentCommentWindowIndices({
|
|
3000
|
+
itemCount: keys.length,
|
|
3001
|
+
pinnedIndices,
|
|
3002
|
+
range
|
|
3003
|
+
}), [
|
|
3004
|
+
keys.length,
|
|
3005
|
+
pinnedIndices,
|
|
3006
|
+
range
|
|
3007
|
+
]);
|
|
3008
|
+
const mountedIndicesKey = mountedIndices.join(',');
|
|
3009
|
+
const registerItem = useCallback((key, element)=>{
|
|
3010
|
+
if (element) itemRefs.current.set(key, element);
|
|
3011
|
+
else itemRefs.current.delete(key);
|
|
3012
|
+
}, []);
|
|
3013
|
+
const focusAt = useCallback((requestedIndex)=>{
|
|
3014
|
+
const currentKeys = keysRef.current;
|
|
3015
|
+
if (!currentKeys.length) return;
|
|
3016
|
+
const index = Math.min(currentKeys.length - 1, Math.max(0, Math.floor(requestedIndex)));
|
|
3017
|
+
const key = currentKeys[index];
|
|
3018
|
+
if (!key) return;
|
|
3019
|
+
setAnchorIndex(index);
|
|
3020
|
+
onRovingKeyChange(key);
|
|
3021
|
+
const mounted = itemRefs.current.get(key);
|
|
3022
|
+
if (mounted) {
|
|
3023
|
+
pendingFocusKeyRef.current = null;
|
|
3024
|
+
focusDocumentCommentItem(mounted);
|
|
3025
|
+
return;
|
|
3026
|
+
}
|
|
3027
|
+
pendingFocusKeyRef.current = key;
|
|
3028
|
+
}, [
|
|
3029
|
+
onRovingKeyChange
|
|
3030
|
+
]);
|
|
3031
|
+
const onItemFocus = useCallback((index)=>{
|
|
3032
|
+
const key = keysRef.current[index];
|
|
3033
|
+
if (!key) return;
|
|
3034
|
+
pendingFocusKeyRef.current = null;
|
|
3035
|
+
setAnchorIndex(index);
|
|
3036
|
+
onRovingKeyChange(key);
|
|
3037
|
+
}, [
|
|
3038
|
+
onRovingKeyChange
|
|
3039
|
+
]);
|
|
3040
|
+
const onViewportAnchorChange = useCallback((index)=>{
|
|
3041
|
+
setAnchorIndex((current)=>current === index ? current : index);
|
|
3042
|
+
}, []);
|
|
3043
|
+
useLayoutEffect(()=>{
|
|
3044
|
+
const pendingKey = pendingFocusKeyRef.current;
|
|
3045
|
+
if (!pendingKey) return;
|
|
3046
|
+
if (!keys.includes(pendingKey)) {
|
|
3047
|
+
pendingFocusKeyRef.current = null;
|
|
3048
|
+
return;
|
|
3049
|
+
}
|
|
3050
|
+
const element = itemRefs.current.get(pendingKey);
|
|
3051
|
+
if (!element) return;
|
|
3052
|
+
pendingFocusKeyRef.current = null;
|
|
3053
|
+
focusDocumentCommentItem(element);
|
|
3054
|
+
}, [
|
|
3055
|
+
keys,
|
|
3056
|
+
mountedIndicesKey,
|
|
3057
|
+
rovingKey
|
|
3058
|
+
]);
|
|
3059
|
+
return {
|
|
3060
|
+
focusAt,
|
|
3061
|
+
mountedIndices,
|
|
3062
|
+
onItemFocus,
|
|
3063
|
+
onViewportAnchorChange,
|
|
3064
|
+
range,
|
|
3065
|
+
registerItem,
|
|
3066
|
+
rovingIndex
|
|
3067
|
+
};
|
|
3068
|
+
}
|
|
3069
|
+
function calculateDocumentCommentWindowRange({ anchorIndex, itemCount, limit = DOCUMENT_COMMENT_WINDOW_LIMIT, overscan = DOCUMENT_COMMENT_WINDOW_OVERSCAN, threshold = DOCUMENT_COMMENT_WINDOW_THRESHOLD }) {
|
|
3070
|
+
const count = Math.max(0, Math.floor(itemCount));
|
|
3071
|
+
if (count <= Math.max(0, Math.floor(threshold))) return {
|
|
3072
|
+
end: count,
|
|
3073
|
+
start: 0,
|
|
3074
|
+
windowed: false
|
|
3075
|
+
};
|
|
3076
|
+
const windowCount = Math.min(count, Math.max(1, Math.floor(limit)));
|
|
3077
|
+
const boundedAnchor = Math.min(count - 1, Math.max(0, Math.floor(anchorIndex)));
|
|
3078
|
+
const start = Math.min(count - windowCount, Math.max(0, boundedAnchor - Math.max(0, Math.floor(overscan))));
|
|
3079
|
+
return {
|
|
3080
|
+
end: start + windowCount,
|
|
3081
|
+
start,
|
|
3082
|
+
windowed: true
|
|
3083
|
+
};
|
|
3084
|
+
}
|
|
3085
|
+
function documentCommentWindowIndices({ itemCount, pinnedIndices, range }) {
|
|
3086
|
+
const count = Math.max(0, Math.floor(itemCount));
|
|
3087
|
+
if (!range.windowed) return Array.from({
|
|
3088
|
+
length: count
|
|
3089
|
+
}, (_, index)=>index);
|
|
3090
|
+
const mounted = new Set();
|
|
3091
|
+
for(let index = range.start; index < range.end; index += 1)if (index >= 0 && index < count) mounted.add(index);
|
|
3092
|
+
for (const index of pinnedIndices)if (index >= 0 && index < count) mounted.add(index);
|
|
3093
|
+
return [
|
|
3094
|
+
...mounted
|
|
3095
|
+
].sort((left, right)=>left - right);
|
|
3096
|
+
}
|
|
3097
|
+
function documentCommentKeyboardDestination(key, index, itemCount) {
|
|
3098
|
+
if (!itemCount) return null;
|
|
3099
|
+
if ('ArrowDown' === key) return Math.min(itemCount - 1, index + 1);
|
|
3100
|
+
if ('ArrowUp' === key) return Math.max(0, index - 1);
|
|
3101
|
+
if ('PageDown' === key) return Math.min(itemCount - 1, index + 8);
|
|
3102
|
+
if ('PageUp' === key) return Math.max(0, index - 8);
|
|
3103
|
+
if ('Home' === key) return 0;
|
|
3104
|
+
if ('End' === key) return itemCount - 1;
|
|
3105
|
+
return null;
|
|
3106
|
+
}
|
|
3107
|
+
function focusDocumentCommentItem(element) {
|
|
3108
|
+
element.focus({
|
|
3109
|
+
preventScroll: true
|
|
3110
|
+
});
|
|
3111
|
+
scrollDocumentCommentItemIntoView(element);
|
|
3112
|
+
}
|
|
3113
|
+
function scrollDocumentCommentItemIntoView(element) {
|
|
3114
|
+
const panel = element.closest('.work-document-comments-panel');
|
|
3115
|
+
const view = element.ownerDocument.defaultView;
|
|
3116
|
+
const panelOverflow = panel ? view?.getComputedStyle(panel).overflowY : void 0;
|
|
3117
|
+
const panelOwnsScroll = Boolean(panel) && /^(auto|scroll)$/.test(panelOverflow ?? '') && (panel?.scrollHeight ?? 0) > (panel?.clientHeight ?? 0) + 1;
|
|
3118
|
+
const scrollContainer = panelOwnsScroll ? panel : panel?.closest('.work-document-scroll');
|
|
3119
|
+
if (!scrollContainer) return void element.scrollIntoView?.({
|
|
3120
|
+
block: 'nearest'
|
|
3121
|
+
});
|
|
3122
|
+
const scrollTarget = element.closest('.work-document-comment-card') ?? element;
|
|
3123
|
+
const elementRect = scrollTarget.getBoundingClientRect();
|
|
3124
|
+
const containerRect = scrollContainer.getBoundingClientRect();
|
|
3125
|
+
const header = panel?.querySelector(':scope > header');
|
|
3126
|
+
const headerHeight = header?.getBoundingClientRect().height ?? 0;
|
|
3127
|
+
const visibleTop = containerRect.top + headerHeight + 8;
|
|
3128
|
+
const visibleBottom = containerRect.bottom - 8;
|
|
3129
|
+
let nextScrollTop = null;
|
|
3130
|
+
if (elementRect.top < visibleTop) nextScrollTop = scrollContainer.scrollTop + elementRect.top - visibleTop;
|
|
3131
|
+
else if (elementRect.bottom > visibleBottom) nextScrollTop = scrollContainer.scrollTop + elementRect.bottom - visibleBottom;
|
|
3132
|
+
if (null === nextScrollTop) return;
|
|
3133
|
+
const top = Math.max(0, nextScrollTop);
|
|
3134
|
+
if ('function' == typeof scrollContainer.scrollTo) return void scrollContainer.scrollTo({
|
|
3135
|
+
behavior: 'instant',
|
|
3136
|
+
top
|
|
3137
|
+
});
|
|
3138
|
+
const previousScrollBehavior = scrollContainer.style.scrollBehavior;
|
|
3139
|
+
scrollContainer.style.scrollBehavior = 'auto';
|
|
3140
|
+
view?.getComputedStyle(scrollContainer).scrollBehavior;
|
|
3141
|
+
scrollContainer.scrollTop = top;
|
|
3142
|
+
scrollContainer.style.scrollBehavior = previousScrollBehavior;
|
|
3143
|
+
}
|
|
2617
3144
|
const emptyLayout = {
|
|
2618
3145
|
width: 1,
|
|
2619
3146
|
height: 1,
|
|
@@ -2628,8 +3155,15 @@ function DocumentCommentsPanel({ editor, comments, draft, surfaceRef, onReply, o
|
|
|
2628
3155
|
const panelRef = useRef(null);
|
|
2629
3156
|
const trackRef = useRef(null);
|
|
2630
3157
|
const cardRefs = useRef(new Map());
|
|
3158
|
+
const anchorRefs = useRef(new Map());
|
|
3159
|
+
const measuredCardHeightsRef = useRef(new Map());
|
|
3160
|
+
const layoutRef = useRef(emptyLayout);
|
|
2631
3161
|
const completedDraftIdRef = useRef(null);
|
|
3162
|
+
const pendingFocusRef = useRef(null);
|
|
3163
|
+
const pendingRevealCommentIdRef = useRef(null);
|
|
2632
3164
|
const frameRef = useRef(0);
|
|
3165
|
+
const pendingFocusFrameRef = useRef(0);
|
|
3166
|
+
const windowFrameRef = useRef(0);
|
|
2633
3167
|
const officeDialog = useOfficeDialog();
|
|
2634
3168
|
const modal = useOfficeTaskPaneModal();
|
|
2635
3169
|
const modalAttributes = modal ? {
|
|
@@ -2639,6 +3173,51 @@ function DocumentCommentsPanel({ editor, comments, draft, surfaceRef, onReply, o
|
|
|
2639
3173
|
const unresolved = comments.filter((comment)=>!comment.resolved).length;
|
|
2640
3174
|
const repliesDirty = Object.values(drafts).some((value)=>Boolean(value.trim()));
|
|
2641
3175
|
const commentsDirty = draftDirty || repliesDirty;
|
|
3176
|
+
const commentsById = useMemo(()=>new Map(comments.map((comment)=>[
|
|
3177
|
+
comment.id,
|
|
3178
|
+
comment
|
|
3179
|
+
])), [
|
|
3180
|
+
comments
|
|
3181
|
+
]);
|
|
3182
|
+
const commentKeys = useMemo(()=>comments.map((comment)=>comment.id), [
|
|
3183
|
+
comments
|
|
3184
|
+
]);
|
|
3185
|
+
const commentIndexById = useMemo(()=>new Map(commentKeys.map((id, index)=>[
|
|
3186
|
+
id,
|
|
3187
|
+
index
|
|
3188
|
+
])), [
|
|
3189
|
+
commentKeys
|
|
3190
|
+
]);
|
|
3191
|
+
const effectiveActiveCommentId = activeCommentId && commentsById.has(activeCommentId) ? activeCommentId : comments.find((comment)=>!comment.resolved)?.id ?? comments[0]?.id ?? null;
|
|
3192
|
+
const dirtyReplyKeys = useMemo(()=>Object.entries(drafts).filter(([, value])=>Boolean(value.trim())).map(([id])=>id), [
|
|
3193
|
+
drafts
|
|
3194
|
+
]);
|
|
3195
|
+
const commentWindow = useDocumentCommentWindow({
|
|
3196
|
+
keys: commentKeys,
|
|
3197
|
+
onRovingKeyChange: setActiveCommentId,
|
|
3198
|
+
pinnedKeys: dirtyReplyKeys,
|
|
3199
|
+
rovingKey: effectiveActiveCommentId
|
|
3200
|
+
});
|
|
3201
|
+
const mountedCommentIndicesKey = commentWindow.mountedIndices.join(',');
|
|
3202
|
+
const mountedCommentIds = useMemo(()=>new Set(commentWindow.mountedIndices.flatMap((index)=>{
|
|
3203
|
+
const id = commentKeys[index];
|
|
3204
|
+
return id ? [
|
|
3205
|
+
id
|
|
3206
|
+
] : [];
|
|
3207
|
+
})), [
|
|
3208
|
+
commentKeys,
|
|
3209
|
+
commentWindow.mountedIndices
|
|
3210
|
+
]);
|
|
3211
|
+
const layoutItemsById = useMemo(()=>new Map(layout.items.map((item)=>[
|
|
3212
|
+
item.id,
|
|
3213
|
+
item
|
|
3214
|
+
])), [
|
|
3215
|
+
layout.items
|
|
3216
|
+
]);
|
|
3217
|
+
const visibleConnectorItems = useMemo(()=>layout.items.filter((item)=>'draft' === item.kind || mountedCommentIds.has(item.id)), [
|
|
3218
|
+
layout.items,
|
|
3219
|
+
mountedCommentIds
|
|
3220
|
+
]);
|
|
2642
3221
|
useEffect(()=>{
|
|
2643
3222
|
onDirtyChange?.(commentsDirty);
|
|
2644
3223
|
}, [
|
|
@@ -2696,6 +3275,10 @@ function DocumentCommentsPanel({ editor, comments, draft, surfaceRef, onReply, o
|
|
|
2696
3275
|
});
|
|
2697
3276
|
if (!confirmed) return;
|
|
2698
3277
|
const nextComment = comments[index + 1] ?? comments[index - 1];
|
|
3278
|
+
pendingFocusRef.current = {
|
|
3279
|
+
commentId: nextComment?.id ?? null
|
|
3280
|
+
};
|
|
3281
|
+
setActiveCommentId(nextComment?.id ?? null);
|
|
2699
3282
|
setDrafts((current)=>{
|
|
2700
3283
|
const next = {
|
|
2701
3284
|
...current
|
|
@@ -2704,15 +3287,15 @@ function DocumentCommentsPanel({ editor, comments, draft, surfaceRef, onReply, o
|
|
|
2704
3287
|
return next;
|
|
2705
3288
|
});
|
|
2706
3289
|
onDelete(commentId);
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
3290
|
+
if (nextComment) selectDocumentComment(editor, nextComment);
|
|
3291
|
+
};
|
|
3292
|
+
const handleCommentAnchorKeyDown = (event, index)=>{
|
|
3293
|
+
const nextIndex = documentCommentKeyboardDestination(event.key, index, comments.length);
|
|
3294
|
+
if (null === nextIndex) return;
|
|
3295
|
+
event.preventDefault();
|
|
3296
|
+
const nextComment = comments[nextIndex];
|
|
3297
|
+
if (nextComment) selectDocumentComment(editor, nextComment);
|
|
3298
|
+
commentWindow.focusAt(nextIndex);
|
|
2716
3299
|
};
|
|
2717
3300
|
const measure = useCallback(()=>{
|
|
2718
3301
|
if (editor.isDestroyed) return;
|
|
@@ -2730,34 +3313,30 @@ function DocumentCommentsPanel({ editor, comments, draft, surfaceRef, onReply, o
|
|
|
2730
3313
|
const trackOffset = trackRect.top - surfaceRect.top;
|
|
2731
3314
|
const visibleTrackTop = Math.max(8, Math.max(scrollRect?.top ?? trackRect.top, panelHeaderRect?.bottom ?? trackRect.top) - trackRect.top + 8);
|
|
2732
3315
|
const visibleTrackBottom = Math.min(scrollRect?.bottom ?? trackRect.bottom, panelRect.bottom) - trackRect.top - 8;
|
|
2733
|
-
const commentsById = new Map(comments.map((comment)=>[
|
|
2734
|
-
comment.id,
|
|
2735
|
-
comment
|
|
2736
|
-
]));
|
|
2737
3316
|
const marks = [
|
|
2738
3317
|
...editor.view.dom.querySelectorAll('[data-document-comment][data-comment-id]')
|
|
2739
3318
|
];
|
|
3319
|
+
const anchorRectsById = new Map();
|
|
2740
3320
|
for (const mark of marks){
|
|
2741
3321
|
const id = mark.dataset.commentId ?? '';
|
|
2742
|
-
mark.classList.toggle('is-active-comment', id ===
|
|
3322
|
+
mark.classList.toggle('is-active-comment', id === effectiveActiveCommentId);
|
|
2743
3323
|
mark.classList.toggle('is-resolved-comment', Boolean(commentsById.get(id)?.resolved));
|
|
3324
|
+
const anchorRect = [
|
|
3325
|
+
...mark.getClientRects()
|
|
3326
|
+
].at(-1);
|
|
3327
|
+
if (id && anchorRect) anchorRectsById.set(id, {
|
|
3328
|
+
right: anchorRect.right,
|
|
3329
|
+
top: anchorRect.top,
|
|
3330
|
+
height: anchorRect.height
|
|
3331
|
+
});
|
|
2744
3332
|
}
|
|
2745
|
-
const entries = comments.map((comment)=>{
|
|
2746
|
-
const anchorRect = marks.filter((mark)=>mark.dataset.commentId === comment.id).flatMap((mark)=>[
|
|
2747
|
-
...mark.getClientRects()
|
|
2748
|
-
]).at(-1);
|
|
2749
|
-
return {
|
|
3333
|
+
const entries = comments.map((comment)=>({
|
|
2750
3334
|
id: comment.id,
|
|
2751
3335
|
kind: 'comment',
|
|
2752
3336
|
commentId: comment.id,
|
|
2753
3337
|
from: comment.from,
|
|
2754
|
-
anchorRect:
|
|
2755
|
-
|
|
2756
|
-
top: anchorRect.top,
|
|
2757
|
-
height: anchorRect.height
|
|
2758
|
-
} : void 0
|
|
2759
|
-
};
|
|
2760
|
-
});
|
|
3338
|
+
anchorRect: anchorRectsById.get(comment.id)
|
|
3339
|
+
}));
|
|
2761
3340
|
if (draft) {
|
|
2762
3341
|
const range = documentCommentDraftRange(editor) ?? draft;
|
|
2763
3342
|
entries.push({
|
|
@@ -2771,7 +3350,15 @@ function DocumentCommentsPanel({ editor, comments, draft, surfaceRef, onReply, o
|
|
|
2771
3350
|
let nextCardTop = 8;
|
|
2772
3351
|
const items = entries.map((entry)=>{
|
|
2773
3352
|
const { anchorRect } = entry;
|
|
2774
|
-
const
|
|
3353
|
+
const card = cardRefs.current.get(entry.id);
|
|
3354
|
+
const measuredCardHeight = card?.getBoundingClientRect().height ?? 0;
|
|
3355
|
+
let cardHeight = 164;
|
|
3356
|
+
if ('comment' === entry.kind) {
|
|
3357
|
+
const comment = commentsById.get(entry.id);
|
|
3358
|
+
const measurementKey = comment ? commentCardMeasurementKey(comment, comment.id === effectiveActiveCommentId) : entry.id;
|
|
3359
|
+
if (measuredCardHeight > 0) measuredCardHeightsRef.current.set(measurementKey, measuredCardHeight);
|
|
3360
|
+
cardHeight = measuredCardHeightsRef.current.get(measurementKey) ?? (comment ? estimateCommentCardHeight(comment, comment.id === effectiveActiveCommentId) : 112);
|
|
3361
|
+
} else if (measuredCardHeight > 0) cardHeight = measuredCardHeight;
|
|
2775
3362
|
const preferredTop = anchorRect ? anchorRect.top - trackRect.top - 18 : nextCardTop;
|
|
2776
3363
|
const minimumTop = Math.max(8, nextCardTop);
|
|
2777
3364
|
let cardTop = Math.max(minimumTop, preferredTop);
|
|
@@ -2801,12 +3388,14 @@ function DocumentCommentsPanel({ editor, comments, draft, surfaceRef, onReply, o
|
|
|
2801
3388
|
trackHeight: Math.max(1, nextCardTop),
|
|
2802
3389
|
items
|
|
2803
3390
|
};
|
|
3391
|
+
layoutRef.current = nextLayout;
|
|
2804
3392
|
setLayout((current)=>sameCommentTrackLayout(current, nextLayout) ? current : nextLayout);
|
|
2805
3393
|
}, [
|
|
2806
|
-
activeCommentId,
|
|
2807
3394
|
comments,
|
|
3395
|
+
commentsById,
|
|
2808
3396
|
draft,
|
|
2809
3397
|
editor,
|
|
3398
|
+
effectiveActiveCommentId,
|
|
2810
3399
|
surfaceRef
|
|
2811
3400
|
]);
|
|
2812
3401
|
const scheduleMeasure = useCallback(()=>{
|
|
@@ -2815,9 +3404,47 @@ function DocumentCommentsPanel({ editor, comments, draft, surfaceRef, onReply, o
|
|
|
2815
3404
|
}, [
|
|
2816
3405
|
measure
|
|
2817
3406
|
]);
|
|
3407
|
+
const updateWindowFromViewport = useCallback(()=>{
|
|
3408
|
+
const surface = surfaceRef.current;
|
|
3409
|
+
const panel = panelRef.current;
|
|
3410
|
+
const track = trackRef.current;
|
|
3411
|
+
if (!surface || !panel || !track) return;
|
|
3412
|
+
const focusedCard = panel.ownerDocument.activeElement?.closest('.work-document-comment-card[data-comment-id]');
|
|
3413
|
+
const focusedCommentId = focusedCard?.dataset.commentId;
|
|
3414
|
+
const focusedIndex = focusedCommentId ? commentIndexById.get(focusedCommentId) : void 0;
|
|
3415
|
+
if (void 0 !== focusedIndex) return void commentWindow.onViewportAnchorChange(focusedIndex);
|
|
3416
|
+
const scroll = surface.closest('.work-document-scroll');
|
|
3417
|
+
const scrollRect = scroll?.getBoundingClientRect();
|
|
3418
|
+
const panelRect = panel.getBoundingClientRect();
|
|
3419
|
+
const trackRect = track.getBoundingClientRect();
|
|
3420
|
+
const panelHeader = panel.firstElementChild;
|
|
3421
|
+
const panelHeaderRect = panelHeader instanceof HTMLElement ? panelHeader.getBoundingClientRect() : void 0;
|
|
3422
|
+
const visibleTop = Math.max(scrollRect?.top ?? trackRect.top, panelRect.top, panelHeaderRect?.bottom ?? panelRect.top) - trackRect.top;
|
|
3423
|
+
const visibleComments = layoutRef.current.items.filter((item)=>'comment' === item.kind);
|
|
3424
|
+
let anchor = visibleComments[0];
|
|
3425
|
+
for (const item of visibleComments){
|
|
3426
|
+
if (item.cardTop > visibleTop + 8) break;
|
|
3427
|
+
anchor = item;
|
|
3428
|
+
}
|
|
3429
|
+
const index = anchor ? commentIndexById.get(anchor.id) : void 0;
|
|
3430
|
+
if (void 0 !== index) commentWindow.onViewportAnchorChange(index);
|
|
3431
|
+
}, [
|
|
3432
|
+
commentIndexById,
|
|
3433
|
+
commentWindow.onViewportAnchorChange,
|
|
3434
|
+
surfaceRef
|
|
3435
|
+
]);
|
|
3436
|
+
const scheduleWindowUpdate = useCallback(()=>{
|
|
3437
|
+
cancelAnimationFrame(windowFrameRef.current);
|
|
3438
|
+
windowFrameRef.current = requestAnimationFrame(updateWindowFromViewport);
|
|
3439
|
+
}, [
|
|
3440
|
+
updateWindowFromViewport
|
|
3441
|
+
]);
|
|
2818
3442
|
useLayoutEffect(()=>{
|
|
2819
3443
|
measure();
|
|
2820
|
-
return ()=>
|
|
3444
|
+
return ()=>{
|
|
3445
|
+
cancelAnimationFrame(frameRef.current);
|
|
3446
|
+
cancelAnimationFrame(windowFrameRef.current);
|
|
3447
|
+
};
|
|
2821
3448
|
}, [
|
|
2822
3449
|
measure
|
|
2823
3450
|
]);
|
|
@@ -2840,6 +3467,35 @@ function DocumentCommentsPanel({ editor, comments, draft, surfaceRef, onReply, o
|
|
|
2840
3467
|
comments,
|
|
2841
3468
|
draft
|
|
2842
3469
|
]);
|
|
3470
|
+
useLayoutEffect(()=>{
|
|
3471
|
+
const pending = pendingFocusRef.current;
|
|
3472
|
+
if (!pending || pendingFocusFrameRef.current) return;
|
|
3473
|
+
pendingFocusFrameRef.current = requestAnimationFrame(()=>{
|
|
3474
|
+
pendingFocusFrameRef.current = 0;
|
|
3475
|
+
const current = pendingFocusRef.current;
|
|
3476
|
+
if (!current) return;
|
|
3477
|
+
const target = current.commentId ? anchorRefs.current.get(current.commentId) : panelRef.current?.querySelector('.ds-icon-button.close');
|
|
3478
|
+
if (!target) return;
|
|
3479
|
+
pendingFocusRef.current = null;
|
|
3480
|
+
focusDocumentCommentItem(target);
|
|
3481
|
+
});
|
|
3482
|
+
}, [
|
|
3483
|
+
comments,
|
|
3484
|
+
effectiveActiveCommentId,
|
|
3485
|
+
mountedCommentIndicesKey
|
|
3486
|
+
]);
|
|
3487
|
+
useEffect(()=>()=>cancelAnimationFrame(pendingFocusFrameRef.current), []);
|
|
3488
|
+
useLayoutEffect(()=>{
|
|
3489
|
+
const commentId = pendingRevealCommentIdRef.current;
|
|
3490
|
+
if (!commentId) return;
|
|
3491
|
+
const card = cardRefs.current.get(commentId);
|
|
3492
|
+
if (!card) return;
|
|
3493
|
+
pendingRevealCommentIdRef.current = null;
|
|
3494
|
+
scrollDocumentCommentItemIntoView(card);
|
|
3495
|
+
}, [
|
|
3496
|
+
effectiveActiveCommentId,
|
|
3497
|
+
mountedCommentIndicesKey
|
|
3498
|
+
]);
|
|
2843
3499
|
useEffect(()=>{
|
|
2844
3500
|
const surface = surfaceRef.current;
|
|
2845
3501
|
const panel = panelRef.current;
|
|
@@ -2857,19 +3513,27 @@ function DocumentCommentsPanel({ editor, comments, draft, surfaceRef, onReply, o
|
|
|
2857
3513
|
subtree: true
|
|
2858
3514
|
});
|
|
2859
3515
|
const scroll = surface.closest('.work-document-scroll');
|
|
2860
|
-
|
|
3516
|
+
const handleScroll = draft ? scheduleMeasure : scheduleWindowUpdate;
|
|
3517
|
+
scroll?.addEventListener('scroll', handleScroll, {
|
|
3518
|
+
passive: true
|
|
3519
|
+
});
|
|
3520
|
+
panel.addEventListener('scroll', handleScroll, {
|
|
2861
3521
|
passive: true
|
|
2862
3522
|
});
|
|
2863
3523
|
window.addEventListener('resize', scheduleMeasure);
|
|
2864
3524
|
return ()=>{
|
|
2865
3525
|
observer?.disconnect();
|
|
2866
3526
|
mutationObserver?.disconnect();
|
|
2867
|
-
scroll?.removeEventListener('scroll',
|
|
3527
|
+
scroll?.removeEventListener('scroll', handleScroll);
|
|
3528
|
+
panel.removeEventListener('scroll', handleScroll);
|
|
2868
3529
|
window.removeEventListener('resize', scheduleMeasure);
|
|
2869
3530
|
};
|
|
2870
3531
|
}, [
|
|
3532
|
+
draft,
|
|
2871
3533
|
editor,
|
|
3534
|
+
mountedCommentIndicesKey,
|
|
2872
3535
|
scheduleMeasure,
|
|
3536
|
+
scheduleWindowUpdate,
|
|
2873
3537
|
surfaceRef
|
|
2874
3538
|
]);
|
|
2875
3539
|
useEffect(()=>{
|
|
@@ -2880,7 +3544,10 @@ function DocumentCommentsPanel({ editor, comments, draft, surfaceRef, onReply, o
|
|
|
2880
3544
|
if (!(target instanceof Element)) return;
|
|
2881
3545
|
const anchor = target.closest('[data-document-comment][data-comment-id]');
|
|
2882
3546
|
const id = anchor?.dataset.commentId;
|
|
2883
|
-
if (id && comments.some((comment)=>comment.id === id))
|
|
3547
|
+
if (id && comments.some((comment)=>comment.id === id)) {
|
|
3548
|
+
pendingRevealCommentIdRef.current = id;
|
|
3549
|
+
setActiveCommentId(id);
|
|
3550
|
+
}
|
|
2884
3551
|
};
|
|
2885
3552
|
editorDom.addEventListener('click', openAnchoredComment);
|
|
2886
3553
|
return ()=>editorDom.removeEventListener('click', openAnchoredComment);
|
|
@@ -2895,12 +3562,12 @@ function DocumentCommentsPanel({ editor, comments, draft, surfaceRef, onReply, o
|
|
|
2895
3562
|
viewBox: `0 0 ${layout.width} ${layout.height}`,
|
|
2896
3563
|
preserveAspectRatio: "none",
|
|
2897
3564
|
"aria-hidden": "true",
|
|
2898
|
-
children:
|
|
2899
|
-
const comment =
|
|
3565
|
+
children: visibleConnectorItems.map((item)=>{
|
|
3566
|
+
const comment = item.commentId ? commentsById.get(item.commentId) : void 0;
|
|
2900
3567
|
const bendX = Math.max(item.startX + 16, item.endX - 28);
|
|
2901
3568
|
const className = [
|
|
2902
3569
|
comment?.resolved ? 'resolved' : '',
|
|
2903
|
-
|
|
3570
|
+
effectiveActiveCommentId === item.commentId ? 'active' : '',
|
|
2904
3571
|
'draft' === item.kind ? 'draft active' : ''
|
|
2905
3572
|
].filter(Boolean).join(' ');
|
|
2906
3573
|
return /*#__PURE__*/ jsxs("g", {
|
|
@@ -2947,50 +3614,72 @@ function DocumentCommentsPanel({ editor, comments, draft, surfaceRef, onReply, o
|
|
|
2947
3614
|
})
|
|
2948
3615
|
]
|
|
2949
3616
|
}),
|
|
2950
|
-
/*#__PURE__*/ jsxs("
|
|
3617
|
+
/*#__PURE__*/ jsxs("ol", {
|
|
2951
3618
|
ref: trackRef,
|
|
2952
3619
|
className: "work-document-comment-track",
|
|
3620
|
+
"aria-label": "文档批注",
|
|
3621
|
+
"data-document-comment-count": comments.length,
|
|
3622
|
+
"data-document-comment-mounted-count": commentWindow.mountedIndices.length,
|
|
3623
|
+
"data-document-comment-track-height": Math.round(layout.trackHeight),
|
|
3624
|
+
"data-document-comment-window-end": commentWindow.range.end,
|
|
3625
|
+
"data-document-comment-window-limit": 32,
|
|
3626
|
+
"data-document-comment-window-start": commentWindow.range.start,
|
|
3627
|
+
"data-document-comment-windowed": commentWindow.range.windowed ? 'true' : 'false',
|
|
2953
3628
|
style: {
|
|
2954
3629
|
minHeight: `${layout.trackHeight}px`
|
|
2955
3630
|
},
|
|
2956
3631
|
children: [
|
|
2957
|
-
draft && /*#__PURE__*/ jsx(
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
3632
|
+
draft && /*#__PURE__*/ jsx("li", {
|
|
3633
|
+
className: "work-document-comment-draft-item",
|
|
3634
|
+
children: /*#__PURE__*/ jsx(document_comment_composer_DocumentCommentComposer, {
|
|
3635
|
+
ref: (element)=>{
|
|
3636
|
+
const id = `draft:${draft.id}`;
|
|
3637
|
+
if (element) cardRefs.current.set(id, element);
|
|
3638
|
+
else cardRefs.current.delete(id);
|
|
3639
|
+
},
|
|
3640
|
+
draft: draft,
|
|
3641
|
+
top: layoutItemsById.get(`draft:${draft.id}`)?.cardTop ?? 8,
|
|
3642
|
+
onCancel: ()=>void cancelDraft(),
|
|
3643
|
+
onDirtyChange: setDraftDirty,
|
|
3644
|
+
onSubmit: onSubmitDraft
|
|
3645
|
+
})
|
|
2968
3646
|
}, draft.id),
|
|
2969
|
-
|
|
2970
|
-
const
|
|
2971
|
-
|
|
2972
|
-
|
|
3647
|
+
commentWindow.mountedIndices.map((index)=>{
|
|
3648
|
+
const comment = comments[index];
|
|
3649
|
+
if (!comment) return null;
|
|
3650
|
+
const item = layoutItemsById.get(comment.id);
|
|
3651
|
+
const active = effectiveActiveCommentId === comment.id;
|
|
3652
|
+
return /*#__PURE__*/ jsxs("li", {
|
|
3653
|
+
"aria-posinset": index + 1,
|
|
3654
|
+
"aria-setsize": comments.length,
|
|
2973
3655
|
ref: (element)=>{
|
|
2974
3656
|
if (element) cardRefs.current.set(comment.id, element);
|
|
2975
3657
|
else cardRefs.current.delete(comment.id);
|
|
2976
3658
|
},
|
|
2977
|
-
className:
|
|
3659
|
+
className: `work-document-comment-card${comment.resolved ? ' resolved' : ''}${active ? ' active' : ''}`,
|
|
2978
3660
|
"data-comment-id": comment.id,
|
|
3661
|
+
"data-document-comment-card-top": Math.round(item?.cardTop ?? 8),
|
|
3662
|
+
"data-document-comment-item": index + 1,
|
|
2979
3663
|
style: {
|
|
2980
3664
|
top: `${item?.cardTop ?? 8}px`
|
|
2981
3665
|
},
|
|
2982
|
-
onFocusCapture: ()=>
|
|
3666
|
+
onFocusCapture: ()=>commentWindow.onItemFocus(index),
|
|
2983
3667
|
children: [
|
|
2984
3668
|
/*#__PURE__*/ jsxs("button", {
|
|
3669
|
+
ref: (element)=>{
|
|
3670
|
+
commentWindow.registerItem(comment.id, element);
|
|
3671
|
+
if (element) anchorRefs.current.set(comment.id, element);
|
|
3672
|
+
else anchorRefs.current.delete(comment.id);
|
|
3673
|
+
},
|
|
2985
3674
|
type: "button",
|
|
2986
3675
|
className: "work-document-comment-anchor",
|
|
2987
3676
|
"aria-label": `定位批注 ${index + 1}`,
|
|
3677
|
+
"aria-current": active ? 'location' : void 0,
|
|
3678
|
+
tabIndex: commentWindow.rovingIndex === index ? 0 : -1,
|
|
3679
|
+
onKeyDown: (event)=>handleCommentAnchorKeyDown(event, index),
|
|
2988
3680
|
onClick: ()=>{
|
|
2989
3681
|
setActiveCommentId(comment.id);
|
|
2990
|
-
editor.chain().focus().setTextSelection(
|
|
2991
|
-
from: Math.min(comment.from, editor.state.doc.content.size),
|
|
2992
|
-
to: Math.min(comment.to, editor.state.doc.content.size)
|
|
2993
|
-
}).run();
|
|
3682
|
+
editor.chain().focus().setTextSelection(documentCommentSelection(editor, comment)).run();
|
|
2994
3683
|
},
|
|
2995
3684
|
children: [
|
|
2996
3685
|
/*#__PURE__*/ jsx("span", {
|
|
@@ -3107,10 +3796,13 @@ function DocumentCommentsPanel({ editor, comments, draft, surfaceRef, onReply, o
|
|
|
3107
3796
|
]
|
|
3108
3797
|
}, comment.id);
|
|
3109
3798
|
}),
|
|
3110
|
-
!comments.length && !draft && /*#__PURE__*/ jsx(
|
|
3111
|
-
className: "work-document-
|
|
3112
|
-
|
|
3113
|
-
|
|
3799
|
+
!comments.length && !draft && /*#__PURE__*/ jsx("li", {
|
|
3800
|
+
className: "work-document-comment-empty-item",
|
|
3801
|
+
children: /*#__PURE__*/ jsx(CollectionState, {
|
|
3802
|
+
className: "work-document-comments-empty",
|
|
3803
|
+
role: "status",
|
|
3804
|
+
children: "选择文字并添加批注。"
|
|
3805
|
+
})
|
|
3114
3806
|
})
|
|
3115
3807
|
]
|
|
3116
3808
|
})
|
|
@@ -3140,6 +3832,29 @@ function sameCommentTrackLayout(current, next) {
|
|
|
3140
3832
|
return candidate?.id === item.id && candidate.kind === item.kind && candidate.commentId === item.commentId && Math.abs(candidate.cardTop - item.cardTop) <= 0.5 && Math.abs(candidate.startX - item.startX) <= 0.5 && Math.abs(candidate.startY - item.startY) <= 0.5 && Math.abs(candidate.endX - item.endX) <= 0.5 && Math.abs(candidate.endY - item.endY) <= 0.5;
|
|
3141
3833
|
});
|
|
3142
3834
|
}
|
|
3835
|
+
function commentCardMeasurementKey(comment, active) {
|
|
3836
|
+
const replies = (comment.replies ?? []).map((reply)=>`${reply.id}:${reply.text.length}`).join('|');
|
|
3837
|
+
return `${comment.id}:${active ? 'active' : 'idle'}:${comment.text.length}:${replies}`;
|
|
3838
|
+
}
|
|
3839
|
+
function estimateCommentCardHeight(comment, active) {
|
|
3840
|
+
const bodyLines = estimatedWrappedLines(comment.text, 34);
|
|
3841
|
+
const replyHeight = (comment.replies ?? []).reduce((height, reply)=>height + 32 + 14 * estimatedWrappedLines(reply.text, 31), 0);
|
|
3842
|
+
return 78 + 15 * bodyLines + replyHeight + (active ? 92 : 0);
|
|
3843
|
+
}
|
|
3844
|
+
function selectDocumentComment(editor, comment) {
|
|
3845
|
+
if (editor.isDestroyed) return;
|
|
3846
|
+
editor.commands.setTextSelection(documentCommentSelection(editor, comment));
|
|
3847
|
+
}
|
|
3848
|
+
function documentCommentSelection(editor, comment) {
|
|
3849
|
+
const maximum = Math.max(1, editor.state.doc.content.size - 1);
|
|
3850
|
+
return {
|
|
3851
|
+
from: Math.min(comment.from, maximum),
|
|
3852
|
+
to: Math.min(comment.to, maximum)
|
|
3853
|
+
};
|
|
3854
|
+
}
|
|
3855
|
+
function estimatedWrappedLines(value, charactersPerLine) {
|
|
3856
|
+
return Math.max(1, value.split('\n').reduce((lines, line)=>lines + Math.max(1, Math.ceil(line.length / charactersPerLine)), 0));
|
|
3857
|
+
}
|
|
3143
3858
|
function commentAuthorInitials(author) {
|
|
3144
3859
|
const words = author.trim().split(/\s+/).filter(Boolean);
|
|
3145
3860
|
if (!words.length) return '审';
|
|
@@ -4543,43 +5258,401 @@ function normalizedDocumentHeadingText(value) {
|
|
|
4543
5258
|
function normalizedDocumentOutlineQuery(value) {
|
|
4544
5259
|
return value.normalize('NFKC').trim().toLocaleLowerCase();
|
|
4545
5260
|
}
|
|
4546
|
-
|
|
5261
|
+
const DOCUMENT_OUTLINE_ITEM_HEIGHT = 31;
|
|
5262
|
+
const DOCUMENT_OUTLINE_LIST_PADDING_TOP = 6;
|
|
5263
|
+
const document_outline_navigation_DocumentOutlineNavigation = /*#__PURE__*/ forwardRef(function({ activeItemId, collapsedIds, items, rovingId, onNavigate, onRovingIdChange, onToggleCollapsed }, ref) {
|
|
5264
|
+
const keys = useMemo(()=>items.map((item)=>item.id), [
|
|
5265
|
+
items
|
|
5266
|
+
]);
|
|
5267
|
+
const pinnedKeys = useMemo(()=>[
|
|
5268
|
+
activeItemId
|
|
5269
|
+
], [
|
|
5270
|
+
activeItemId
|
|
5271
|
+
]);
|
|
5272
|
+
const navigation = useDocumentNavigationWindow({
|
|
5273
|
+
estimatedItemHeight: DOCUMENT_OUTLINE_ITEM_HEIGHT,
|
|
5274
|
+
itemGap: 0,
|
|
5275
|
+
keys,
|
|
5276
|
+
listPaddingTop: DOCUMENT_OUTLINE_LIST_PADDING_TOP,
|
|
5277
|
+
onRovingKeyChange: onRovingIdChange,
|
|
5278
|
+
pinnedKeys,
|
|
5279
|
+
rovingKey: rovingId
|
|
5280
|
+
});
|
|
5281
|
+
useImperativeHandle(ref, ()=>({
|
|
5282
|
+
focusFirst: ()=>navigation.focusAt(0),
|
|
5283
|
+
focusLast: ()=>navigation.focusAt(items.length - 1)
|
|
5284
|
+
}), [
|
|
5285
|
+
items.length,
|
|
5286
|
+
navigation.focusAt
|
|
5287
|
+
]);
|
|
5288
|
+
const handleItemKeyDown = (event, item, index)=>{
|
|
5289
|
+
if ('ArrowDown' === event.key) {
|
|
5290
|
+
event.preventDefault();
|
|
5291
|
+
navigation.focusAt(Math.min(items.length - 1, index + 1));
|
|
5292
|
+
} else if ('ArrowUp' === event.key) {
|
|
5293
|
+
event.preventDefault();
|
|
5294
|
+
navigation.focusAt(Math.max(0, index - 1));
|
|
5295
|
+
} else if ('Home' === event.key) {
|
|
5296
|
+
event.preventDefault();
|
|
5297
|
+
navigation.focusAt(0);
|
|
5298
|
+
} else if ('End' === event.key) {
|
|
5299
|
+
event.preventDefault();
|
|
5300
|
+
navigation.focusAt(items.length - 1);
|
|
5301
|
+
} else if ('ArrowRight' === event.key && item.hasChildren && collapsedIds.has(item.id)) {
|
|
5302
|
+
event.preventDefault();
|
|
5303
|
+
onToggleCollapsed(item.id);
|
|
5304
|
+
} else if ('ArrowRight' === event.key && item.hasChildren) {
|
|
5305
|
+
event.preventDefault();
|
|
5306
|
+
const child = items[index + 1];
|
|
5307
|
+
if (child?.depth > item.depth) navigation.focusAt(index + 1);
|
|
5308
|
+
} else if ('ArrowLeft' === event.key) {
|
|
5309
|
+
event.preventDefault();
|
|
5310
|
+
if (item.hasChildren && !collapsedIds.has(item.id)) onToggleCollapsed(item.id);
|
|
5311
|
+
else if (item.parentId) navigation.focusAt(items.findIndex((candidate)=>candidate.id === item.parentId));
|
|
5312
|
+
}
|
|
5313
|
+
};
|
|
5314
|
+
return /*#__PURE__*/ jsx("nav", {
|
|
5315
|
+
ref: navigation.viewportRef,
|
|
5316
|
+
className: "work-document-task-pane-body work-document-outline",
|
|
5317
|
+
"aria-label": "文档标题",
|
|
5318
|
+
"data-document-navigation-collection": "outline",
|
|
5319
|
+
"data-document-navigation-item-count": items.length,
|
|
5320
|
+
"data-document-navigation-mounted-count": navigation.mountedCount,
|
|
5321
|
+
"data-document-navigation-window-end": navigation.range.end,
|
|
5322
|
+
"data-document-navigation-window-limit": 32,
|
|
5323
|
+
"data-document-navigation-window-start": navigation.range.start,
|
|
5324
|
+
"data-document-navigation-windowed": navigation.range.windowed ? 'true' : 'false',
|
|
5325
|
+
onScroll: navigation.onScroll,
|
|
5326
|
+
children: items.length ? /*#__PURE__*/ jsx("ol", {
|
|
5327
|
+
children: navigation.entries.map((entry)=>{
|
|
5328
|
+
if ('spacer' === entry.kind) return /*#__PURE__*/ jsx(DocumentNavigationWindowSpacer, {
|
|
5329
|
+
entry: entry
|
|
5330
|
+
}, `spacer-${entry.start}-${entry.end}`);
|
|
5331
|
+
const item = items[entry.index];
|
|
5332
|
+
if (!item) return null;
|
|
5333
|
+
const collapsed = collapsedIds.has(item.id);
|
|
5334
|
+
return /*#__PURE__*/ jsxs("li", {
|
|
5335
|
+
"aria-posinset": entry.index + 1,
|
|
5336
|
+
"aria-setsize": items.length,
|
|
5337
|
+
className: activeItemId === item.id ? 'active' : void 0,
|
|
5338
|
+
"data-document-navigation-item": entry.index + 1,
|
|
5339
|
+
style: {
|
|
5340
|
+
'--work-document-outline-indent': `${14 * item.depth}px`
|
|
5341
|
+
},
|
|
5342
|
+
children: [
|
|
5343
|
+
item.hasChildren ? /*#__PURE__*/ jsx("button", {
|
|
5344
|
+
type: "button",
|
|
5345
|
+
tabIndex: -1,
|
|
5346
|
+
className: "work-document-outline-toggle",
|
|
5347
|
+
"aria-label": `${collapsed ? '展开' : '折叠'} ${item.text}`,
|
|
5348
|
+
title: collapsed ? '展开下级标题' : '折叠下级标题',
|
|
5349
|
+
onClick: ()=>onToggleCollapsed(item.id),
|
|
5350
|
+
children: collapsed ? /*#__PURE__*/ jsx(ChevronRight, {
|
|
5351
|
+
size: 13
|
|
5352
|
+
}) : /*#__PURE__*/ jsx(ChevronDown, {
|
|
5353
|
+
size: 13
|
|
5354
|
+
})
|
|
5355
|
+
}) : /*#__PURE__*/ jsx("span", {
|
|
5356
|
+
className: "work-document-outline-toggle-spacer"
|
|
5357
|
+
}),
|
|
5358
|
+
/*#__PURE__*/ jsx("button", {
|
|
5359
|
+
ref: (element)=>navigation.registerItem(item.id, element),
|
|
5360
|
+
type: "button",
|
|
5361
|
+
className: "work-document-outline-item",
|
|
5362
|
+
tabIndex: navigation.rovingIndex === entry.index ? 0 : -1,
|
|
5363
|
+
"aria-current": activeItemId === item.id ? 'location' : void 0,
|
|
5364
|
+
"aria-expanded": item.hasChildren ? !collapsed : void 0,
|
|
5365
|
+
title: item.text,
|
|
5366
|
+
onFocus: ()=>navigation.onItemFocus(entry.index),
|
|
5367
|
+
onKeyDown: (event)=>handleItemKeyDown(event, item, entry.index),
|
|
5368
|
+
onClick: ()=>onNavigate(item.from),
|
|
5369
|
+
children: item.text
|
|
5370
|
+
})
|
|
5371
|
+
]
|
|
5372
|
+
}, item.id);
|
|
5373
|
+
})
|
|
5374
|
+
}) : /*#__PURE__*/ jsx("div", {
|
|
5375
|
+
className: "work-document-outline-empty",
|
|
5376
|
+
children: "应用标题样式后,可在这里快速跳转"
|
|
5377
|
+
})
|
|
5378
|
+
});
|
|
5379
|
+
});
|
|
5380
|
+
let thumbnailCaptureQueue = Promise.resolve();
|
|
5381
|
+
function DocumentPageThumbnail({ backgroundColor, fallbackText, orientation, pageIndex, priority = false, source, renderThumbnail = renderDocumentPageThumbnail }) {
|
|
5382
|
+
const rootRef = useRef(null);
|
|
5383
|
+
const nearViewport = useNearThumbnailViewport(rootRef);
|
|
5384
|
+
const captureActive = priority || nearViewport;
|
|
5385
|
+
const sourceMutation = useThumbnailSourceMutation(source, captureActive);
|
|
5386
|
+
const [image, setImage] = useState(null);
|
|
5387
|
+
const [state, setState] = useState(source ? 'loading' : 'idle');
|
|
5388
|
+
useEffect(()=>{
|
|
5389
|
+
if (!source || !captureActive) {
|
|
5390
|
+
setImage(null);
|
|
5391
|
+
setState('idle');
|
|
5392
|
+
return;
|
|
5393
|
+
}
|
|
5394
|
+
if (pageIndex < 0 || pageIndex >= source.pageCount) {
|
|
5395
|
+
setImage(null);
|
|
5396
|
+
setState('failed');
|
|
5397
|
+
return;
|
|
5398
|
+
}
|
|
5399
|
+
let cancelled = false;
|
|
5400
|
+
setState((current)=>'ready' === current ? 'refreshing' : 'loading');
|
|
5401
|
+
const targetPixelWidth = 'landscape' === orientation ? 340 : 276;
|
|
5402
|
+
const task = async ()=>{
|
|
5403
|
+
if (cancelled) return;
|
|
5404
|
+
const nextImage = await renderThumbnail(source, pageIndex, targetPixelWidth);
|
|
5405
|
+
if (cancelled) return;
|
|
5406
|
+
setImage(nextImage);
|
|
5407
|
+
setState('ready');
|
|
5408
|
+
};
|
|
5409
|
+
const queued = thumbnailCaptureQueue.then(task, task);
|
|
5410
|
+
thumbnailCaptureQueue = queued.catch(()=>void 0);
|
|
5411
|
+
queued.catch(()=>{
|
|
5412
|
+
if (cancelled) return;
|
|
5413
|
+
setImage(null);
|
|
5414
|
+
setState('failed');
|
|
5415
|
+
});
|
|
5416
|
+
return ()=>{
|
|
5417
|
+
cancelled = true;
|
|
5418
|
+
};
|
|
5419
|
+
}, [
|
|
5420
|
+
captureActive,
|
|
5421
|
+
orientation,
|
|
5422
|
+
pageIndex,
|
|
5423
|
+
renderThumbnail,
|
|
5424
|
+
source?.element,
|
|
5425
|
+
source?.pageCount,
|
|
5426
|
+
source?.pageGap,
|
|
5427
|
+
source?.pageHeight,
|
|
5428
|
+
source?.pageWidth,
|
|
5429
|
+
source?.revision,
|
|
5430
|
+
sourceMutation
|
|
5431
|
+
]);
|
|
5432
|
+
return /*#__PURE__*/ jsx("span", {
|
|
5433
|
+
ref: rootRef,
|
|
5434
|
+
className: `work-document-page-thumbnail ${orientation}`,
|
|
5435
|
+
"data-testid": "document-page-thumbnail",
|
|
5436
|
+
"data-thumbnail-source": source ? 'live-page' : 'text-fallback',
|
|
5437
|
+
"data-thumbnail-state": state,
|
|
5438
|
+
"aria-hidden": "true",
|
|
5439
|
+
style: {
|
|
5440
|
+
aspectRatio: source ? `${source.pageWidth} / ${source.pageHeight}` : void 0,
|
|
5441
|
+
backgroundColor
|
|
5442
|
+
},
|
|
5443
|
+
children: image ? /*#__PURE__*/ jsx("img", {
|
|
5444
|
+
alt: "",
|
|
5445
|
+
"data-document-page-raster": pageIndex + 1,
|
|
5446
|
+
draggable: false,
|
|
5447
|
+
src: image
|
|
5448
|
+
}) : /*#__PURE__*/ jsx("span", {
|
|
5449
|
+
className: "work-document-page-thumbnail-fallback",
|
|
5450
|
+
children: fallbackText || '空白页'
|
|
5451
|
+
})
|
|
5452
|
+
});
|
|
5453
|
+
}
|
|
5454
|
+
async function renderDocumentPageThumbnail(source, pageIndex, targetPixelWidth, renderCanvas = renderDocumentPageCanvas) {
|
|
5455
|
+
if (!Number.isSafeInteger(pageIndex) || pageIndex < 0 || pageIndex >= source.pageCount) throw new Error('The requested document thumbnail page is out of range.');
|
|
5456
|
+
const capture = mountWorkLiveDocumentCapture(source, pageIndex);
|
|
5457
|
+
try {
|
|
5458
|
+
const scale = Math.max(0.1, Math.min(1, targetPixelWidth / source.pageWidth));
|
|
5459
|
+
const canvas = await renderCanvas(capture.viewport, {
|
|
5460
|
+
backgroundColor: capture.backgroundColor,
|
|
5461
|
+
fontReadyTimeout: 0,
|
|
5462
|
+
height: source.pageHeight,
|
|
5463
|
+
logging: false,
|
|
5464
|
+
scale,
|
|
5465
|
+
useCORS: true,
|
|
5466
|
+
width: source.pageWidth,
|
|
5467
|
+
windowHeight: Math.ceil(source.pageHeight),
|
|
5468
|
+
windowWidth: Math.ceil(source.pageWidth)
|
|
5469
|
+
});
|
|
5470
|
+
return canvas.toDataURL('image/png');
|
|
5471
|
+
} finally{
|
|
5472
|
+
capture.host.remove();
|
|
5473
|
+
}
|
|
5474
|
+
}
|
|
5475
|
+
async function renderDocumentPageCanvas(element, options) {
|
|
5476
|
+
const { default: html2canvas } = await import("html2canvas");
|
|
5477
|
+
return html2canvas(element, options);
|
|
5478
|
+
}
|
|
5479
|
+
function useNearThumbnailViewport(rootRef) {
|
|
5480
|
+
const [nearViewport, setNearViewport] = useState(()=>"u" < typeof IntersectionObserver);
|
|
5481
|
+
useEffect(()=>{
|
|
5482
|
+
const element = rootRef.current;
|
|
5483
|
+
if (!element) return;
|
|
5484
|
+
if ("u" < typeof IntersectionObserver) return void setNearViewport(true);
|
|
5485
|
+
const root = element.closest('.work-document-page-navigation');
|
|
5486
|
+
const observer = new IntersectionObserver((entries)=>{
|
|
5487
|
+
const entry = entries[0];
|
|
5488
|
+
if (entry) setNearViewport(entry.isIntersecting);
|
|
5489
|
+
}, {
|
|
5490
|
+
root,
|
|
5491
|
+
rootMargin: '280px 0px'
|
|
5492
|
+
});
|
|
5493
|
+
observer.observe(element);
|
|
5494
|
+
return ()=>observer.disconnect();
|
|
5495
|
+
}, [
|
|
5496
|
+
rootRef
|
|
5497
|
+
]);
|
|
5498
|
+
return nearViewport;
|
|
5499
|
+
}
|
|
5500
|
+
function useThumbnailSourceMutation(source, active) {
|
|
5501
|
+
const [revision, setRevision] = useState(0);
|
|
5502
|
+
useEffect(()=>{
|
|
5503
|
+
if (!source || !active || "u" < typeof MutationObserver) return;
|
|
5504
|
+
let timer = 0;
|
|
5505
|
+
const observer = new MutationObserver(()=>{
|
|
5506
|
+
window.clearTimeout(timer);
|
|
5507
|
+
timer = window.setTimeout(()=>setRevision((current)=>current + 1), 160);
|
|
5508
|
+
});
|
|
5509
|
+
observer.observe(source.element, {
|
|
5510
|
+
attributes: true,
|
|
5511
|
+
characterData: true,
|
|
5512
|
+
childList: true,
|
|
5513
|
+
subtree: true
|
|
5514
|
+
});
|
|
5515
|
+
return ()=>{
|
|
5516
|
+
observer.disconnect();
|
|
5517
|
+
window.clearTimeout(timer);
|
|
5518
|
+
};
|
|
5519
|
+
}, [
|
|
5520
|
+
active,
|
|
5521
|
+
source?.element,
|
|
5522
|
+
source?.revision
|
|
5523
|
+
]);
|
|
5524
|
+
return revision;
|
|
5525
|
+
}
|
|
5526
|
+
const DOCUMENT_PAGE_WINDOW_THRESHOLD = 48;
|
|
5527
|
+
const DOCUMENT_PAGE_WINDOW_OVERSCAN = 4;
|
|
5528
|
+
const DOCUMENT_PAGE_FALLBACK_VIEWPORT_HEIGHT = 720;
|
|
5529
|
+
const DOCUMENT_PAGE_LIST_PADDING_TOP = 12;
|
|
5530
|
+
const DOCUMENT_PAGE_ITEM_GAP = 12;
|
|
5531
|
+
const DOCUMENT_PAGE_PORTRAIT_WIDTH = 138;
|
|
5532
|
+
const DOCUMENT_PAGE_LANDSCAPE_WIDTH = 170;
|
|
5533
|
+
const DOCUMENT_PAGE_BUTTON_CHROME_HEIGHT = 36;
|
|
5534
|
+
const DOCUMENT_PAGE_WINDOW_LIMIT = 24;
|
|
5535
|
+
function DocumentPageNavigation({ currentPage, pages, thumbnailSource, onSelectPage }) {
|
|
5536
|
+
const viewportRef = useRef(null);
|
|
4547
5537
|
const pageRefs = useRef(new Map());
|
|
4548
|
-
const
|
|
4549
|
-
const
|
|
5538
|
+
const pagesRef = useRef(pages);
|
|
5539
|
+
const pendingFocusPageRef = useRef(null);
|
|
5540
|
+
const initialIndex = documentPageIndex(pages, currentPage);
|
|
5541
|
+
const initialPhysicalPage = pages[initialIndex]?.physicalPage ?? currentPage;
|
|
5542
|
+
const [selectedPage, setSelectedPage] = useState(initialPhysicalPage);
|
|
5543
|
+
const [rovingPage, setRovingPage] = useState(initialPhysicalPage);
|
|
5544
|
+
const [anchorIndex, setAnchorIndex] = useState(Math.max(0, initialIndex));
|
|
5545
|
+
const [viewportHeight, setViewportHeight] = useState(DOCUMENT_PAGE_FALLBACK_VIEWPORT_HEIGHT);
|
|
5546
|
+
pagesRef.current = pages;
|
|
5547
|
+
const currentPageIndex = documentPageIndex(pages, currentPage);
|
|
5548
|
+
const resolvedCurrentPage = pages[currentPageIndex]?.physicalPage ?? null;
|
|
4550
5549
|
useEffect(()=>{
|
|
4551
|
-
|
|
4552
|
-
|
|
5550
|
+
if (null === resolvedCurrentPage) return;
|
|
5551
|
+
setSelectedPage(resolvedCurrentPage);
|
|
5552
|
+
setRovingPage(resolvedCurrentPage);
|
|
5553
|
+
setAnchorIndex(currentPageIndex);
|
|
4553
5554
|
}, [
|
|
4554
|
-
|
|
5555
|
+
currentPageIndex,
|
|
5556
|
+
resolvedCurrentPage
|
|
4555
5557
|
]);
|
|
4556
5558
|
useEffect(()=>{
|
|
4557
|
-
if (pages.
|
|
4558
|
-
const fallback = pages.
|
|
4559
|
-
if (fallback)
|
|
5559
|
+
if (!pages.length) return;
|
|
5560
|
+
const fallback = pages[Math.max(0, currentPageIndex)] ?? pages[0];
|
|
5561
|
+
if (!fallback) return;
|
|
5562
|
+
if (!pages.some((page)=>page.physicalPage === selectedPage)) setSelectedPage(fallback.physicalPage);
|
|
5563
|
+
if (!pages.some((page)=>page.physicalPage === rovingPage)) setRovingPage(fallback.physicalPage);
|
|
4560
5564
|
}, [
|
|
4561
|
-
|
|
5565
|
+
currentPageIndex,
|
|
4562
5566
|
pages,
|
|
4563
|
-
rovingPage
|
|
5567
|
+
rovingPage,
|
|
5568
|
+
selectedPage
|
|
4564
5569
|
]);
|
|
4565
|
-
|
|
4566
|
-
|
|
5570
|
+
useLayoutEffect(()=>{
|
|
5571
|
+
const viewport = viewportRef.current;
|
|
5572
|
+
if (!viewport) return;
|
|
5573
|
+
const update = ()=>{
|
|
5574
|
+
const nextHeight = viewport.clientHeight || DOCUMENT_PAGE_FALLBACK_VIEWPORT_HEIGHT;
|
|
5575
|
+
setViewportHeight((current)=>current === nextHeight ? current : nextHeight);
|
|
5576
|
+
};
|
|
5577
|
+
update();
|
|
5578
|
+
if ("u" < typeof ResizeObserver) return;
|
|
5579
|
+
const observer = new ResizeObserver(update);
|
|
5580
|
+
observer.observe(viewport);
|
|
5581
|
+
return ()=>observer.disconnect();
|
|
5582
|
+
}, []);
|
|
5583
|
+
const itemHeights = useMemo(()=>pages.map((page)=>estimatedDocumentPageItemHeight(page, thumbnailSource)), [
|
|
5584
|
+
pages,
|
|
5585
|
+
thumbnailSource?.pageHeight,
|
|
5586
|
+
thumbnailSource?.pageWidth
|
|
5587
|
+
]);
|
|
5588
|
+
const pageStarts = useMemo(()=>documentNavigationItemStarts(itemHeights, DOCUMENT_PAGE_ITEM_GAP), [
|
|
5589
|
+
itemHeights
|
|
5590
|
+
]);
|
|
5591
|
+
const averageItemHeight = itemHeights.length ? (pageStarts[pageStarts.length - 1] ?? 1) / itemHeights.length : 1;
|
|
5592
|
+
const range = useMemo(()=>calculateDocumentPageRange({
|
|
5593
|
+
anchorIndex,
|
|
5594
|
+
averageItemHeight,
|
|
5595
|
+
pageCount: pages.length,
|
|
5596
|
+
viewportHeight
|
|
5597
|
+
}), [
|
|
5598
|
+
anchorIndex,
|
|
5599
|
+
averageItemHeight,
|
|
5600
|
+
pages.length,
|
|
5601
|
+
viewportHeight
|
|
5602
|
+
]);
|
|
5603
|
+
const mountedIndices = useMemo(()=>documentNavigationWindowIndices({
|
|
5604
|
+
itemCount: pages.length,
|
|
5605
|
+
pinnedIndices: [
|
|
5606
|
+
documentPageIndex(pages, selectedPage),
|
|
5607
|
+
documentPageIndex(pages, rovingPage)
|
|
5608
|
+
],
|
|
5609
|
+
range
|
|
5610
|
+
}), [
|
|
5611
|
+
pages,
|
|
5612
|
+
range,
|
|
5613
|
+
rovingPage,
|
|
5614
|
+
selectedPage
|
|
5615
|
+
]);
|
|
5616
|
+
const listEntries = useMemo(()=>documentNavigationWindowEntries(mountedIndices, pageStarts, pages.length, DOCUMENT_PAGE_ITEM_GAP), [
|
|
5617
|
+
mountedIndices,
|
|
5618
|
+
pageStarts,
|
|
5619
|
+
pages.length
|
|
5620
|
+
]);
|
|
5621
|
+
const mountedPageKey = mountedIndices.join(',');
|
|
5622
|
+
useLayoutEffect(()=>{
|
|
5623
|
+
pageRefs.current.get(selectedPage)?.scrollIntoView?.({
|
|
4567
5624
|
block: 'nearest',
|
|
4568
5625
|
inline: 'nearest'
|
|
4569
5626
|
});
|
|
4570
5627
|
}, [
|
|
4571
5628
|
selectedPage
|
|
4572
5629
|
]);
|
|
5630
|
+
useLayoutEffect(()=>{
|
|
5631
|
+
const pendingPage = pendingFocusPageRef.current;
|
|
5632
|
+
if (null === pendingPage) return;
|
|
5633
|
+
const element = pageRefs.current.get(pendingPage);
|
|
5634
|
+
if (!element) return;
|
|
5635
|
+
pendingFocusPageRef.current = null;
|
|
5636
|
+
focusDocumentPageButton(element);
|
|
5637
|
+
}, [
|
|
5638
|
+
mountedPageKey,
|
|
5639
|
+
rovingPage
|
|
5640
|
+
]);
|
|
4573
5641
|
const focusPage = useCallback((pageNumber)=>{
|
|
5642
|
+
const pageIndex = documentPageIndex(pagesRef.current, pageNumber);
|
|
5643
|
+
if (pageIndex < 0) return;
|
|
4574
5644
|
setRovingPage(pageNumber);
|
|
4575
|
-
|
|
4576
|
-
|
|
4577
|
-
|
|
4578
|
-
|
|
4579
|
-
|
|
5645
|
+
setAnchorIndex(pageIndex);
|
|
5646
|
+
const mounted = pageRefs.current.get(pageNumber);
|
|
5647
|
+
if (mounted) {
|
|
5648
|
+
pendingFocusPageRef.current = null;
|
|
5649
|
+
focusDocumentPageButton(mounted);
|
|
5650
|
+
return;
|
|
5651
|
+
}
|
|
5652
|
+
pendingFocusPageRef.current = pageNumber;
|
|
4580
5653
|
}, []);
|
|
4581
5654
|
const handleKeyDown = (event, page)=>{
|
|
4582
|
-
const index = pages
|
|
5655
|
+
const index = documentPageIndex(pages, page.physicalPage);
|
|
4583
5656
|
const focusAt = (requestedIndex)=>{
|
|
4584
5657
|
const next = pages[requestedIndex];
|
|
4585
5658
|
if (next) focusPage(next.physicalPage);
|
|
@@ -4599,12 +5672,41 @@ function DocumentPageNavigation({ currentPage, pages, onSelectPage }) {
|
|
|
4599
5672
|
}
|
|
4600
5673
|
};
|
|
4601
5674
|
return /*#__PURE__*/ jsx("nav", {
|
|
5675
|
+
ref: viewportRef,
|
|
4602
5676
|
className: "work-document-task-pane-body work-document-page-navigation",
|
|
4603
5677
|
"aria-label": "文档页面",
|
|
5678
|
+
"data-document-page-count": pages.length,
|
|
5679
|
+
"data-document-page-mounted-count": mountedIndices.length,
|
|
5680
|
+
"data-document-page-window-end": range.end,
|
|
5681
|
+
"data-document-page-window-limit": DOCUMENT_PAGE_WINDOW_LIMIT,
|
|
5682
|
+
"data-document-page-window-start": range.start,
|
|
5683
|
+
"data-document-page-windowed": range.windowed ? 'true' : 'false',
|
|
5684
|
+
onScroll: (event)=>{
|
|
5685
|
+
if (!range.windowed) return;
|
|
5686
|
+
const nextAnchor = documentNavigationIndexAtOffset(pageStarts, Math.max(0, event.currentTarget.scrollTop - DOCUMENT_PAGE_LIST_PADDING_TOP), pages.length);
|
|
5687
|
+
setAnchorIndex((current)=>current === nextAnchor ? current : nextAnchor);
|
|
5688
|
+
},
|
|
4604
5689
|
children: pages.length ? /*#__PURE__*/ jsx("ol", {
|
|
4605
|
-
children:
|
|
5690
|
+
children: listEntries.map((entry)=>{
|
|
5691
|
+
if ('spacer' === entry.kind) return /*#__PURE__*/ jsx("li", {
|
|
5692
|
+
"aria-hidden": "true",
|
|
5693
|
+
className: "work-document-page-navigation-spacer",
|
|
5694
|
+
"data-document-page-spacer": entry.position,
|
|
5695
|
+
"data-document-page-spacer-end": entry.end,
|
|
5696
|
+
"data-document-page-spacer-start": entry.start + 1,
|
|
5697
|
+
role: "presentation",
|
|
5698
|
+
style: {
|
|
5699
|
+
height: `${entry.height}px`
|
|
5700
|
+
}
|
|
5701
|
+
}, `spacer-${entry.start}-${entry.end}`);
|
|
5702
|
+
const page = pages[entry.index];
|
|
5703
|
+
if (!page) return null;
|
|
4606
5704
|
const current = page.physicalPage === selectedPage;
|
|
4607
5705
|
return /*#__PURE__*/ jsx("li", {
|
|
5706
|
+
"aria-posinset": entry.index + 1,
|
|
5707
|
+
"aria-setsize": pages.length,
|
|
5708
|
+
"data-document-page-item": page.physicalPage,
|
|
5709
|
+
"data-document-page-orientation": page.orientation,
|
|
4608
5710
|
children: /*#__PURE__*/ jsxs("button", {
|
|
4609
5711
|
ref: (element)=>{
|
|
4610
5712
|
if (element) pageRefs.current.set(page.physicalPage, element);
|
|
@@ -4620,18 +5722,17 @@ function DocumentPageNavigation({ currentPage, pages, onSelectPage }) {
|
|
|
4620
5722
|
onKeyDown: (event)=>handleKeyDown(event, page),
|
|
4621
5723
|
onClick: ()=>{
|
|
4622
5724
|
setSelectedPage(page.physicalPage);
|
|
5725
|
+
setAnchorIndex(entry.index);
|
|
4623
5726
|
onSelectPage(page);
|
|
4624
5727
|
},
|
|
4625
5728
|
children: [
|
|
4626
|
-
/*#__PURE__*/ jsx(
|
|
4627
|
-
|
|
4628
|
-
|
|
4629
|
-
|
|
4630
|
-
|
|
4631
|
-
|
|
4632
|
-
|
|
4633
|
-
children: page.previewText || '空白页'
|
|
4634
|
-
})
|
|
5729
|
+
/*#__PURE__*/ jsx(DocumentPageThumbnail, {
|
|
5730
|
+
backgroundColor: page.backgroundColor,
|
|
5731
|
+
fallbackText: page.previewText,
|
|
5732
|
+
orientation: page.orientation,
|
|
5733
|
+
pageIndex: page.physicalPage - 1,
|
|
5734
|
+
priority: Math.abs(page.physicalPage - selectedPage) <= 1,
|
|
5735
|
+
source: thumbnailSource
|
|
4635
5736
|
}),
|
|
4636
5737
|
/*#__PURE__*/ jsxs("span", {
|
|
4637
5738
|
className: "work-document-page-thumbnail-label",
|
|
@@ -4657,11 +5758,151 @@ function DocumentPageNavigation({ currentPage, pages, onSelectPage }) {
|
|
|
4657
5758
|
})
|
|
4658
5759
|
});
|
|
4659
5760
|
}
|
|
4660
|
-
function
|
|
5761
|
+
function calculateDocumentPageRange({ anchorIndex, averageItemHeight, pageCount, viewportHeight }) {
|
|
5762
|
+
return calculateDocumentNavigationWindowRange({
|
|
5763
|
+
anchorIndex,
|
|
5764
|
+
averageItemHeight,
|
|
5765
|
+
itemCount: pageCount,
|
|
5766
|
+
limit: DOCUMENT_PAGE_WINDOW_LIMIT,
|
|
5767
|
+
overscan: DOCUMENT_PAGE_WINDOW_OVERSCAN,
|
|
5768
|
+
threshold: DOCUMENT_PAGE_WINDOW_THRESHOLD,
|
|
5769
|
+
viewportHeight
|
|
5770
|
+
});
|
|
5771
|
+
}
|
|
5772
|
+
function documentPageIndex(pages, physicalPage) {
|
|
5773
|
+
return pages.findIndex((page)=>page.physicalPage === physicalPage);
|
|
5774
|
+
}
|
|
5775
|
+
function estimatedDocumentPageItemHeight(page, source) {
|
|
5776
|
+
const width = 'landscape' === page.orientation ? DOCUMENT_PAGE_LANDSCAPE_WIDTH : DOCUMENT_PAGE_PORTRAIT_WIDTH;
|
|
5777
|
+
const sourceRatio = source && source.pageWidth > 0 && source.pageHeight > 0 ? source.pageHeight / source.pageWidth : null;
|
|
5778
|
+
const fallbackRatio = 'landscape' === page.orientation ? 210 / 297 : 297 / 210;
|
|
5779
|
+
return Math.ceil(width * (sourceRatio ?? fallbackRatio) + DOCUMENT_PAGE_BUTTON_CHROME_HEIGHT);
|
|
5780
|
+
}
|
|
5781
|
+
function focusDocumentPageButton(element) {
|
|
5782
|
+
element.focus({
|
|
5783
|
+
preventScroll: true
|
|
5784
|
+
});
|
|
5785
|
+
element.scrollIntoView?.({
|
|
5786
|
+
block: 'nearest',
|
|
5787
|
+
inline: 'nearest'
|
|
5788
|
+
});
|
|
5789
|
+
}
|
|
5790
|
+
const DOCUMENT_SEARCH_RESULT_HEIGHT = 56;
|
|
5791
|
+
const DOCUMENT_SEARCH_RESULT_GAP = 5;
|
|
5792
|
+
const DOCUMENT_SEARCH_LIST_PADDING_TOP = 7;
|
|
5793
|
+
const document_search_navigation_DocumentSearchNavigation = /*#__PURE__*/ forwardRef(function({ matches, outline, rovingId, selectedMatchIndex, onRovingIdChange, onSelect }, ref) {
|
|
5794
|
+
const keys = useMemo(()=>matches.map(documentNavigationMatchId), [
|
|
5795
|
+
matches
|
|
5796
|
+
]);
|
|
5797
|
+
const selectedMatch = matches[selectedMatchIndex];
|
|
5798
|
+
const selectedKey = selectedMatch ? documentNavigationMatchId(selectedMatch) : null;
|
|
5799
|
+
const pinnedKeys = useMemo(()=>[
|
|
5800
|
+
selectedKey
|
|
5801
|
+
], [
|
|
5802
|
+
selectedKey
|
|
5803
|
+
]);
|
|
5804
|
+
const navigation = useDocumentNavigationWindow({
|
|
5805
|
+
estimatedItemHeight: DOCUMENT_SEARCH_RESULT_HEIGHT,
|
|
5806
|
+
itemGap: DOCUMENT_SEARCH_RESULT_GAP,
|
|
5807
|
+
keys,
|
|
5808
|
+
listPaddingTop: DOCUMENT_SEARCH_LIST_PADDING_TOP,
|
|
5809
|
+
onRovingKeyChange: onRovingIdChange,
|
|
5810
|
+
pinnedKeys,
|
|
5811
|
+
rovingKey: rovingId
|
|
5812
|
+
});
|
|
5813
|
+
useImperativeHandle(ref, ()=>({
|
|
5814
|
+
focusFirst: ()=>navigation.focusAt(0),
|
|
5815
|
+
focusLast: ()=>navigation.focusAt(matches.length - 1)
|
|
5816
|
+
}), [
|
|
5817
|
+
matches.length,
|
|
5818
|
+
navigation.focusAt
|
|
5819
|
+
]);
|
|
5820
|
+
const handleResultKeyDown = (event, index)=>{
|
|
5821
|
+
if ('ArrowDown' === event.key) {
|
|
5822
|
+
event.preventDefault();
|
|
5823
|
+
navigation.focusAt(Math.min(matches.length - 1, index + 1));
|
|
5824
|
+
} else if ('ArrowUp' === event.key) {
|
|
5825
|
+
event.preventDefault();
|
|
5826
|
+
navigation.focusAt(Math.max(0, index - 1));
|
|
5827
|
+
} else if ('Home' === event.key) {
|
|
5828
|
+
event.preventDefault();
|
|
5829
|
+
navigation.focusAt(0);
|
|
5830
|
+
} else if ('End' === event.key) {
|
|
5831
|
+
event.preventDefault();
|
|
5832
|
+
navigation.focusAt(matches.length - 1);
|
|
5833
|
+
}
|
|
5834
|
+
};
|
|
5835
|
+
return /*#__PURE__*/ jsx("nav", {
|
|
5836
|
+
ref: navigation.viewportRef,
|
|
5837
|
+
className: "work-document-task-pane-body work-document-search-results",
|
|
5838
|
+
"aria-label": "文档搜索结果",
|
|
5839
|
+
"data-document-navigation-collection": "search",
|
|
5840
|
+
"data-document-navigation-item-count": matches.length,
|
|
5841
|
+
"data-document-navigation-mounted-count": navigation.mountedCount,
|
|
5842
|
+
"data-document-navigation-window-end": navigation.range.end,
|
|
5843
|
+
"data-document-navigation-window-limit": 32,
|
|
5844
|
+
"data-document-navigation-window-start": navigation.range.start,
|
|
5845
|
+
"data-document-navigation-windowed": navigation.range.windowed ? 'true' : 'false',
|
|
5846
|
+
onScroll: navigation.onScroll,
|
|
5847
|
+
children: matches.length ? /*#__PURE__*/ jsx("ol", {
|
|
5848
|
+
children: navigation.entries.map((entry)=>{
|
|
5849
|
+
if ('spacer' === entry.kind) return /*#__PURE__*/ jsx(DocumentNavigationWindowSpacer, {
|
|
5850
|
+
entry: entry
|
|
5851
|
+
}, `spacer-${entry.start}-${entry.end}`);
|
|
5852
|
+
const match = matches[entry.index];
|
|
5853
|
+
if (!match) return null;
|
|
5854
|
+
const resultId = documentNavigationMatchId(match);
|
|
5855
|
+
const section = currentWorkDocumentOutlineItem(outline, match.from)?.text ?? '文档开头';
|
|
5856
|
+
return /*#__PURE__*/ jsx("li", {
|
|
5857
|
+
"aria-posinset": entry.index + 1,
|
|
5858
|
+
"aria-setsize": matches.length,
|
|
5859
|
+
"data-document-navigation-item": entry.index + 1,
|
|
5860
|
+
children: /*#__PURE__*/ jsxs("button", {
|
|
5861
|
+
ref: (element)=>navigation.registerItem(resultId, element),
|
|
5862
|
+
type: "button",
|
|
5863
|
+
className: "work-document-search-result",
|
|
5864
|
+
tabIndex: navigation.rovingIndex === entry.index ? 0 : -1,
|
|
5865
|
+
"aria-label": `第 ${entry.index + 1} 个匹配:${match.matchedText}`,
|
|
5866
|
+
"aria-current": selectedMatchIndex === entry.index ? 'location' : void 0,
|
|
5867
|
+
onFocus: ()=>navigation.onItemFocus(entry.index),
|
|
5868
|
+
onKeyDown: (event)=>handleResultKeyDown(event, entry.index),
|
|
5869
|
+
onClick: ()=>onSelect(match),
|
|
5870
|
+
children: [
|
|
5871
|
+
/*#__PURE__*/ jsx("span", {
|
|
5872
|
+
className: "work-document-search-section",
|
|
5873
|
+
children: section
|
|
5874
|
+
}),
|
|
5875
|
+
/*#__PURE__*/ jsxs("span", {
|
|
5876
|
+
className: "work-document-search-excerpt",
|
|
5877
|
+
children: [
|
|
5878
|
+
match.truncatedBefore && '…',
|
|
5879
|
+
match.before,
|
|
5880
|
+
/*#__PURE__*/ jsx("mark", {
|
|
5881
|
+
children: match.matchedText
|
|
5882
|
+
}),
|
|
5883
|
+
match.after,
|
|
5884
|
+
match.truncatedAfter && '…'
|
|
5885
|
+
]
|
|
5886
|
+
})
|
|
5887
|
+
]
|
|
5888
|
+
})
|
|
5889
|
+
}, resultId);
|
|
5890
|
+
})
|
|
5891
|
+
}) : /*#__PURE__*/ jsx("div", {
|
|
5892
|
+
className: "work-document-outline-empty",
|
|
5893
|
+
children: "尝试更短或不同的文字"
|
|
5894
|
+
})
|
|
5895
|
+
});
|
|
5896
|
+
});
|
|
5897
|
+
function documentNavigationMatchId(match) {
|
|
5898
|
+
return `match-${match.from}-${match.to}`;
|
|
5899
|
+
}
|
|
5900
|
+
const instantDocumentScrollStates = new WeakMap();
|
|
5901
|
+
function DocumentNavigationPanel({ currentPage = 1, editor, modal = false, pages = [], pageThumbnailSource, onClose }) {
|
|
4661
5902
|
const tabsId = useId();
|
|
4662
5903
|
const searchRef = useRef(null);
|
|
4663
|
-
const
|
|
4664
|
-
const
|
|
5904
|
+
const outlineNavigationRef = useRef(null);
|
|
5905
|
+
const searchNavigationRef = useRef(null);
|
|
4665
5906
|
const [, renderEditorState] = useState(0);
|
|
4666
5907
|
const [navigationView, setNavigationView] = useState('headings');
|
|
4667
5908
|
const [query, setQuery] = useState('');
|
|
@@ -4732,28 +5973,12 @@ function DocumentNavigationPanel({ currentPage = 1, editor, modal = false, pages
|
|
|
4732
5973
|
]);
|
|
4733
5974
|
useEffect(()=>{
|
|
4734
5975
|
if (!normalizedQuery) return;
|
|
4735
|
-
const validResultIds = new Set(matches.map(
|
|
4736
|
-
setRovingResultId((current)=>current && validResultIds.has(current) ? current : matches[0] ?
|
|
5976
|
+
const validResultIds = new Set(matches.map(documentNavigationMatchId));
|
|
5977
|
+
setRovingResultId((current)=>current && validResultIds.has(current) ? current : matches[0] ? documentNavigationMatchId(matches[0]) : null);
|
|
4737
5978
|
}, [
|
|
4738
5979
|
matches,
|
|
4739
5980
|
normalizedQuery
|
|
4740
5981
|
]);
|
|
4741
|
-
const focusItem = useCallback((itemId)=>{
|
|
4742
|
-
setRovingId(itemId);
|
|
4743
|
-
requestAnimationFrame(()=>{
|
|
4744
|
-
itemRefs.current.get(itemId)?.focus({
|
|
4745
|
-
preventScroll: true
|
|
4746
|
-
});
|
|
4747
|
-
});
|
|
4748
|
-
}, []);
|
|
4749
|
-
const focusResult = useCallback((resultId)=>{
|
|
4750
|
-
setRovingResultId(resultId);
|
|
4751
|
-
requestAnimationFrame(()=>{
|
|
4752
|
-
resultRefs.current.get(resultId)?.focus({
|
|
4753
|
-
preventScroll: true
|
|
4754
|
-
});
|
|
4755
|
-
});
|
|
4756
|
-
}, []);
|
|
4757
5982
|
const toggleCollapsed = useCallback((itemId)=>{
|
|
4758
5983
|
setCollapsedIds((current)=>{
|
|
4759
5984
|
const next = new Set(current);
|
|
@@ -4762,45 +5987,15 @@ function DocumentNavigationPanel({ currentPage = 1, editor, modal = false, pages
|
|
|
4762
5987
|
return next;
|
|
4763
5988
|
});
|
|
4764
5989
|
}, []);
|
|
4765
|
-
const
|
|
4766
|
-
const
|
|
4767
|
-
const focusAt = (requestedIndex)=>{
|
|
4768
|
-
const next = visibleItems[requestedIndex];
|
|
4769
|
-
if (next) focusItem(next.id);
|
|
4770
|
-
};
|
|
4771
|
-
if ('ArrowDown' === event.key) {
|
|
4772
|
-
event.preventDefault();
|
|
4773
|
-
focusAt(Math.min(visibleItems.length - 1, index + 1));
|
|
4774
|
-
} else if ('ArrowUp' === event.key) {
|
|
4775
|
-
event.preventDefault();
|
|
4776
|
-
focusAt(Math.max(0, index - 1));
|
|
4777
|
-
} else if ('Home' === event.key) {
|
|
4778
|
-
event.preventDefault();
|
|
4779
|
-
focusAt(0);
|
|
4780
|
-
} else if ('End' === event.key) {
|
|
4781
|
-
event.preventDefault();
|
|
4782
|
-
focusAt(visibleItems.length - 1);
|
|
4783
|
-
} else if ('ArrowRight' === event.key && !normalizedQuery && item.hasChildren && collapsedIds.has(item.id)) {
|
|
4784
|
-
event.preventDefault();
|
|
4785
|
-
toggleCollapsed(item.id);
|
|
4786
|
-
} else if ('ArrowRight' === event.key && !normalizedQuery && item.hasChildren) {
|
|
4787
|
-
event.preventDefault();
|
|
4788
|
-
const child = visibleItems[index + 1];
|
|
4789
|
-
if (child?.depth > item.depth) focusItem(child.id);
|
|
4790
|
-
} else if ('ArrowLeft' === event.key && !normalizedQuery) {
|
|
4791
|
-
event.preventDefault();
|
|
4792
|
-
if (item.hasChildren && !collapsedIds.has(item.id)) toggleCollapsed(item.id);
|
|
4793
|
-
else if (item.parentId) focusItem(item.parentId);
|
|
4794
|
-
}
|
|
4795
|
-
};
|
|
4796
|
-
const navigateTo = async (selection)=>{
|
|
5990
|
+
const navigateTo = async (selection, focusEditor = true)=>{
|
|
5991
|
+
const resolvedSelection = 'number' == typeof selection ? TextSelection.near(editor.state.doc.resolve(Math.min(editor.state.doc.content.size, Math.max(0, selection))), 1).from : selection;
|
|
4797
5992
|
const chain = editor.chain();
|
|
4798
|
-
if (!modal) chain.focus();
|
|
4799
|
-
chain.setTextSelection(
|
|
5993
|
+
if (!modal && focusEditor) chain.focus();
|
|
5994
|
+
runWithInstantDocumentScroll(editor, ()=>chain.setTextSelection(resolvedSelection).scrollIntoView().run());
|
|
4800
5995
|
if (!modal) return;
|
|
4801
5996
|
await onClose();
|
|
4802
5997
|
requestAnimationFrame(()=>{
|
|
4803
|
-
if (!editor.isDestroyed) editor.chain().focus().scrollIntoView().run();
|
|
5998
|
+
if (!editor.isDestroyed) runWithInstantDocumentScroll(editor, ()=>editor.chain().focus().scrollIntoView().run());
|
|
4804
5999
|
});
|
|
4805
6000
|
};
|
|
4806
6001
|
const selectMatch = (match)=>{
|
|
@@ -4809,26 +6004,6 @@ function DocumentNavigationPanel({ currentPage = 1, editor, modal = false, pages
|
|
|
4809
6004
|
to: match.to
|
|
4810
6005
|
});
|
|
4811
6006
|
};
|
|
4812
|
-
const handleResultKeyDown = (event, match)=>{
|
|
4813
|
-
const index = matches.findIndex((candidate)=>documentMatchId(candidate) === documentMatchId(match));
|
|
4814
|
-
const focusAt = (requestedIndex)=>{
|
|
4815
|
-
const next = matches[requestedIndex];
|
|
4816
|
-
if (next) focusResult(documentMatchId(next));
|
|
4817
|
-
};
|
|
4818
|
-
if ('ArrowDown' === event.key) {
|
|
4819
|
-
event.preventDefault();
|
|
4820
|
-
focusAt(Math.min(matches.length - 1, index + 1));
|
|
4821
|
-
} else if ('ArrowUp' === event.key) {
|
|
4822
|
-
event.preventDefault();
|
|
4823
|
-
focusAt(Math.max(0, index - 1));
|
|
4824
|
-
} else if ('Home' === event.key) {
|
|
4825
|
-
event.preventDefault();
|
|
4826
|
-
focusAt(0);
|
|
4827
|
-
} else if ('End' === event.key) {
|
|
4828
|
-
event.preventDefault();
|
|
4829
|
-
focusAt(matches.length - 1);
|
|
4830
|
-
}
|
|
4831
|
-
};
|
|
4832
6007
|
return /*#__PURE__*/ jsxs(DocumentTaskPane, {
|
|
4833
6008
|
ariaLabel: "文档导航",
|
|
4834
6009
|
className: "work-document-navigation-panel",
|
|
@@ -4873,7 +6048,8 @@ function DocumentNavigationPanel({ currentPage = 1, editor, modal = false, pages
|
|
|
4873
6048
|
/*#__PURE__*/ jsx(DocumentPageNavigation, {
|
|
4874
6049
|
currentPage: currentPage,
|
|
4875
6050
|
pages: pages,
|
|
4876
|
-
|
|
6051
|
+
thumbnailSource: pageThumbnailSource,
|
|
6052
|
+
onSelectPage: (page)=>navigateTo(page.selectionPosition, false)
|
|
4877
6053
|
})
|
|
4878
6054
|
]
|
|
4879
6055
|
}) : /*#__PURE__*/ jsxs("div", {
|
|
@@ -4901,11 +6077,10 @@ function DocumentNavigationPanel({ currentPage = 1, editor, modal = false, pages
|
|
|
4901
6077
|
event.preventDefault();
|
|
4902
6078
|
selectMatch(matches[0]);
|
|
4903
6079
|
} else if ('ArrowDown' === event.key) {
|
|
4904
|
-
const
|
|
4905
|
-
if (!
|
|
6080
|
+
const target = normalizedQuery ? searchNavigationRef.current : outlineNavigationRef.current;
|
|
6081
|
+
if (!target) return;
|
|
4906
6082
|
event.preventDefault();
|
|
4907
|
-
|
|
4908
|
-
else focusItem(firstTarget);
|
|
6083
|
+
target.focusFirst();
|
|
4909
6084
|
}
|
|
4910
6085
|
}
|
|
4911
6086
|
})
|
|
@@ -4916,112 +6091,58 @@ function DocumentNavigationPanel({ currentPage = 1, editor, modal = false, pages
|
|
|
4916
6091
|
"aria-live": "polite",
|
|
4917
6092
|
children: normalizedQuery ? matches.length ? `${matches.length} 个匹配` : '没有匹配内容' : `${outline.length} 个标题`
|
|
4918
6093
|
}),
|
|
4919
|
-
normalizedQuery ? /*#__PURE__*/ jsx(
|
|
4920
|
-
|
|
4921
|
-
|
|
4922
|
-
|
|
4923
|
-
|
|
4924
|
-
|
|
4925
|
-
|
|
4926
|
-
|
|
4927
|
-
|
|
4928
|
-
|
|
4929
|
-
|
|
4930
|
-
|
|
4931
|
-
|
|
4932
|
-
|
|
4933
|
-
|
|
4934
|
-
|
|
4935
|
-
|
|
4936
|
-
"aria-current": selectedMatchIndex === index ? 'location' : void 0,
|
|
4937
|
-
onFocus: ()=>setRovingResultId(resultId),
|
|
4938
|
-
onKeyDown: (event)=>handleResultKeyDown(event, match),
|
|
4939
|
-
onClick: ()=>selectMatch(match),
|
|
4940
|
-
children: [
|
|
4941
|
-
/*#__PURE__*/ jsx("span", {
|
|
4942
|
-
className: "work-document-search-section",
|
|
4943
|
-
children: section
|
|
4944
|
-
}),
|
|
4945
|
-
/*#__PURE__*/ jsxs("span", {
|
|
4946
|
-
className: "work-document-search-excerpt",
|
|
4947
|
-
children: [
|
|
4948
|
-
match.truncatedBefore && '…',
|
|
4949
|
-
match.before,
|
|
4950
|
-
/*#__PURE__*/ jsx("mark", {
|
|
4951
|
-
children: match.matchedText
|
|
4952
|
-
}),
|
|
4953
|
-
match.after,
|
|
4954
|
-
match.truncatedAfter && '…'
|
|
4955
|
-
]
|
|
4956
|
-
})
|
|
4957
|
-
]
|
|
4958
|
-
})
|
|
4959
|
-
}, resultId);
|
|
4960
|
-
})
|
|
4961
|
-
}) : /*#__PURE__*/ jsx("div", {
|
|
4962
|
-
className: "work-document-outline-empty",
|
|
4963
|
-
children: "尝试更短或不同的文字"
|
|
4964
|
-
})
|
|
4965
|
-
}) : /*#__PURE__*/ jsx("nav", {
|
|
4966
|
-
className: "work-document-task-pane-body work-document-outline",
|
|
4967
|
-
"aria-label": "文档标题",
|
|
4968
|
-
children: visibleItems.length ? /*#__PURE__*/ jsx("ol", {
|
|
4969
|
-
children: visibleItems.map((item)=>{
|
|
4970
|
-
const collapsed = collapsedIds.has(item.id);
|
|
4971
|
-
return /*#__PURE__*/ jsxs("li", {
|
|
4972
|
-
className: activeItem?.id === item.id ? 'active' : void 0,
|
|
4973
|
-
style: {
|
|
4974
|
-
'--work-document-outline-indent': `${14 * item.depth}px`
|
|
4975
|
-
},
|
|
4976
|
-
children: [
|
|
4977
|
-
item.hasChildren ? /*#__PURE__*/ jsx("button", {
|
|
4978
|
-
type: "button",
|
|
4979
|
-
tabIndex: -1,
|
|
4980
|
-
className: "work-document-outline-toggle",
|
|
4981
|
-
"aria-label": `${collapsed ? '展开' : '折叠'} ${item.text}`,
|
|
4982
|
-
title: collapsed ? '展开下级标题' : '折叠下级标题',
|
|
4983
|
-
onClick: ()=>toggleCollapsed(item.id),
|
|
4984
|
-
children: collapsed ? /*#__PURE__*/ jsx(ChevronRight, {
|
|
4985
|
-
size: 13
|
|
4986
|
-
}) : /*#__PURE__*/ jsx(ChevronDown, {
|
|
4987
|
-
size: 13
|
|
4988
|
-
})
|
|
4989
|
-
}) : /*#__PURE__*/ jsx("span", {
|
|
4990
|
-
className: "work-document-outline-toggle-spacer"
|
|
4991
|
-
}),
|
|
4992
|
-
/*#__PURE__*/ jsx("button", {
|
|
4993
|
-
ref: (element)=>{
|
|
4994
|
-
if (element) itemRefs.current.set(item.id, element);
|
|
4995
|
-
else itemRefs.current.delete(item.id);
|
|
4996
|
-
},
|
|
4997
|
-
type: "button",
|
|
4998
|
-
className: "work-document-outline-item",
|
|
4999
|
-
tabIndex: item.id === rovingId ? 0 : -1,
|
|
5000
|
-
"aria-current": activeItem?.id === item.id ? 'location' : void 0,
|
|
5001
|
-
"aria-expanded": item.hasChildren ? !collapsed : void 0,
|
|
5002
|
-
title: item.text,
|
|
5003
|
-
onFocus: ()=>setRovingId(item.id),
|
|
5004
|
-
onKeyDown: (event)=>handleItemKeyDown(event, item),
|
|
5005
|
-
onClick: ()=>{
|
|
5006
|
-
navigateTo(item.from);
|
|
5007
|
-
},
|
|
5008
|
-
children: item.text
|
|
5009
|
-
})
|
|
5010
|
-
]
|
|
5011
|
-
}, item.id);
|
|
5012
|
-
})
|
|
5013
|
-
}) : /*#__PURE__*/ jsx("div", {
|
|
5014
|
-
className: "work-document-outline-empty",
|
|
5015
|
-
children: "应用标题样式后,可在这里快速跳转"
|
|
5016
|
-
})
|
|
6094
|
+
normalizedQuery ? /*#__PURE__*/ jsx(document_search_navigation_DocumentSearchNavigation, {
|
|
6095
|
+
ref: searchNavigationRef,
|
|
6096
|
+
matches: matches,
|
|
6097
|
+
outline: outline,
|
|
6098
|
+
rovingId: rovingResultId,
|
|
6099
|
+
selectedMatchIndex: selectedMatchIndex,
|
|
6100
|
+
onRovingIdChange: setRovingResultId,
|
|
6101
|
+
onSelect: selectMatch
|
|
6102
|
+
}) : /*#__PURE__*/ jsx(document_outline_navigation_DocumentOutlineNavigation, {
|
|
6103
|
+
ref: outlineNavigationRef,
|
|
6104
|
+
activeItemId: activeItem?.id ?? null,
|
|
6105
|
+
collapsedIds: collapsedIds,
|
|
6106
|
+
items: visibleItems,
|
|
6107
|
+
rovingId: rovingId,
|
|
6108
|
+
onNavigate: (position)=>void navigateTo(position),
|
|
6109
|
+
onRovingIdChange: setRovingId,
|
|
6110
|
+
onToggleCollapsed: toggleCollapsed
|
|
5017
6111
|
})
|
|
5018
6112
|
]
|
|
5019
6113
|
})
|
|
5020
6114
|
]
|
|
5021
6115
|
});
|
|
5022
6116
|
}
|
|
5023
|
-
function
|
|
5024
|
-
|
|
6117
|
+
function runWithInstantDocumentScroll(editor, run) {
|
|
6118
|
+
const scrollSurface = editor.view.dom.closest('.work-document-scroll');
|
|
6119
|
+
if (!scrollSurface) return run();
|
|
6120
|
+
let state = instantDocumentScrollStates.get(scrollSurface);
|
|
6121
|
+
if (state) {
|
|
6122
|
+
if (null !== state.restoreFrame && 'function' == typeof cancelAnimationFrame) {
|
|
6123
|
+
cancelAnimationFrame(state.restoreFrame);
|
|
6124
|
+
state.restoreFrame = null;
|
|
6125
|
+
}
|
|
6126
|
+
} else {
|
|
6127
|
+
state = {
|
|
6128
|
+
previousBehavior: scrollSurface.style.scrollBehavior,
|
|
6129
|
+
restoreFrame: null
|
|
6130
|
+
};
|
|
6131
|
+
instantDocumentScrollStates.set(scrollSurface, state);
|
|
6132
|
+
}
|
|
6133
|
+
scrollSurface.style.scrollBehavior = 'auto';
|
|
6134
|
+
scrollSurface.getBoundingClientRect();
|
|
6135
|
+
try {
|
|
6136
|
+
return run();
|
|
6137
|
+
} finally{
|
|
6138
|
+
const restore = ()=>{
|
|
6139
|
+
if (instantDocumentScrollStates.get(scrollSurface) !== state) return;
|
|
6140
|
+
scrollSurface.style.scrollBehavior = state.previousBehavior;
|
|
6141
|
+
instantDocumentScrollStates.delete(scrollSurface);
|
|
6142
|
+
};
|
|
6143
|
+
if ('function' == typeof requestAnimationFrame) state.restoreFrame = requestAnimationFrame(restore);
|
|
6144
|
+
else restore();
|
|
6145
|
+
}
|
|
5025
6146
|
}
|
|
5026
6147
|
function DocumentPageStack({ pageColor, pageCount, pageGap, pageHeight }) {
|
|
5027
6148
|
const count = Math.max(1, Math.trunc(pageCount));
|
|
@@ -6421,7 +7542,11 @@ function runDocumentListMenuCommand(editor, close, command) {
|
|
|
6421
7542
|
const handled = command();
|
|
6422
7543
|
if (!handled) return false;
|
|
6423
7544
|
close();
|
|
6424
|
-
|
|
7545
|
+
queueMicrotask(()=>{
|
|
7546
|
+
if (!editor.isDestroyed) editor.commands.focus(void 0, {
|
|
7547
|
+
scrollIntoView: false
|
|
7548
|
+
});
|
|
7549
|
+
});
|
|
6425
7550
|
return true;
|
|
6426
7551
|
}
|
|
6427
7552
|
function handleGalleryKeyDown(event, index, count, columns, refs, setFocusIndex, select) {
|
|
@@ -7439,11 +8564,457 @@ function documentPaginationSnapshot(editor) {
|
|
|
7439
8564
|
}
|
|
7440
8565
|
});
|
|
7441
8566
|
}
|
|
7442
|
-
const
|
|
7443
|
-
|
|
7444
|
-
|
|
7445
|
-
|
|
7446
|
-
|
|
8567
|
+
const IMAGE_PIXELS_PER_CENTIMETER = 96 / 2.54;
|
|
8568
|
+
const FALLBACK_IMAGE_WIDTH_PIXELS = 320;
|
|
8569
|
+
const FALLBACK_IMAGE_HEIGHT_PIXELS = 180;
|
|
8570
|
+
const MINIMUM_IMAGE_SIZE_CENTIMETERS = 0.01;
|
|
8571
|
+
const MAXIMUM_IMAGE_SIZE_CENTIMETERS = 55.87;
|
|
8572
|
+
const MAXIMUM_WRAP_DISTANCE_MILLIMETERS = 25;
|
|
8573
|
+
function createDocumentPicturePropertiesDraft(source) {
|
|
8574
|
+
const width = effectiveDimension(source.properties.width, source.renderedWidth, FALLBACK_IMAGE_WIDTH_PIXELS);
|
|
8575
|
+
const height = effectiveDimension(source.properties.height, source.renderedHeight, FALLBACK_IMAGE_HEIGHT_PIXELS);
|
|
8576
|
+
return {
|
|
8577
|
+
width: document_picture_properties_dialog_model_centimeters(width),
|
|
8578
|
+
height: document_picture_properties_dialog_model_centimeters(height),
|
|
8579
|
+
lockAspectRatio: source.properties.lockAspectRatio,
|
|
8580
|
+
aspectRatio: validAspectRatio(width, height),
|
|
8581
|
+
layout: source.properties.layout,
|
|
8582
|
+
alignment: source.properties.alignment,
|
|
8583
|
+
wrapDistance: formatNumber(source.properties.wrapDistance),
|
|
8584
|
+
alternativeText: source.properties.alternativeText
|
|
8585
|
+
};
|
|
8586
|
+
}
|
|
8587
|
+
function withDocumentPictureDimension(draft, dimension, value) {
|
|
8588
|
+
const next = {
|
|
8589
|
+
...draft,
|
|
8590
|
+
[dimension]: value
|
|
8591
|
+
};
|
|
8592
|
+
const numeric = numericDraft(value);
|
|
8593
|
+
if (!draft.lockAspectRatio || null === numeric) return next;
|
|
8594
|
+
if ('width' === dimension) return {
|
|
8595
|
+
...next,
|
|
8596
|
+
height: formatNumber(numeric / draft.aspectRatio)
|
|
8597
|
+
};
|
|
8598
|
+
return {
|
|
8599
|
+
...next,
|
|
8600
|
+
width: formatNumber(numeric * draft.aspectRatio)
|
|
8601
|
+
};
|
|
8602
|
+
}
|
|
8603
|
+
function withDocumentPictureAspectRatioLock(draft, lockAspectRatio) {
|
|
8604
|
+
if (!lockAspectRatio) return {
|
|
8605
|
+
...draft,
|
|
8606
|
+
lockAspectRatio: false
|
|
8607
|
+
};
|
|
8608
|
+
const width = numericDraft(draft.width);
|
|
8609
|
+
const height = numericDraft(draft.height);
|
|
8610
|
+
return {
|
|
8611
|
+
...draft,
|
|
8612
|
+
lockAspectRatio: true,
|
|
8613
|
+
aspectRatio: null !== width && null !== height ? validAspectRatio(width, height) : draft.aspectRatio
|
|
8614
|
+
};
|
|
8615
|
+
}
|
|
8616
|
+
function documentPicturePropertiesErrors(draft) {
|
|
8617
|
+
return {
|
|
8618
|
+
width: imageDimensionError(draft.width),
|
|
8619
|
+
height: imageDimensionError(draft.height),
|
|
8620
|
+
wrapDistance: 'inline' === draft.layout || validNumber(draft.wrapDistance, 0, MAXIMUM_WRAP_DISTANCE_MILLIMETERS) ? null : '请输入 0 到 25 之间的毫米数。'
|
|
8621
|
+
};
|
|
8622
|
+
}
|
|
8623
|
+
function hasDocumentPicturePropertiesErrors(errors) {
|
|
8624
|
+
return Boolean(errors.width || errors.height || errors.wrapDistance);
|
|
8625
|
+
}
|
|
8626
|
+
function documentPicturePropertyChanges(initial, current) {
|
|
8627
|
+
const errors = documentPicturePropertiesErrors(current);
|
|
8628
|
+
if (hasDocumentPicturePropertiesErrors(errors)) return null;
|
|
8629
|
+
const changes = {};
|
|
8630
|
+
if (!sameDraftNumber(initial.width, current.width)) changes.width = rounded(Number(current.width) * IMAGE_PIXELS_PER_CENTIMETER);
|
|
8631
|
+
if (!sameDraftNumber(initial.height, current.height)) changes.height = rounded(Number(current.height) * IMAGE_PIXELS_PER_CENTIMETER);
|
|
8632
|
+
if (initial.lockAspectRatio !== current.lockAspectRatio) changes.lockAspectRatio = current.lockAspectRatio;
|
|
8633
|
+
if (initial.layout !== current.layout) changes.layout = current.layout;
|
|
8634
|
+
if (initial.alignment !== current.alignment) changes.alignment = current.alignment;
|
|
8635
|
+
if (!sameDraftNumber(initial.wrapDistance, current.wrapDistance)) changes.wrapDistance = Number(current.wrapDistance);
|
|
8636
|
+
const alternativeText = current.alternativeText.trim();
|
|
8637
|
+
if (initial.alternativeText.trim() !== alternativeText) changes.alternativeText = alternativeText;
|
|
8638
|
+
return Object.keys(changes).length ? changes : null;
|
|
8639
|
+
}
|
|
8640
|
+
function effectiveDimension(explicit, rendered, fallback) {
|
|
8641
|
+
if (null !== explicit && Number.isFinite(explicit) && explicit > 0) return explicit;
|
|
8642
|
+
if (void 0 !== rendered && Number.isFinite(rendered) && rendered > 0) return rendered;
|
|
8643
|
+
return fallback;
|
|
8644
|
+
}
|
|
8645
|
+
function imageDimensionError(value) {
|
|
8646
|
+
return validNumber(value, MINIMUM_IMAGE_SIZE_CENTIMETERS, MAXIMUM_IMAGE_SIZE_CENTIMETERS) ? null : '请输入 0.01 到 55.87 之间的厘米数。';
|
|
8647
|
+
}
|
|
8648
|
+
function validNumber(value, minimum, maximum) {
|
|
8649
|
+
const number = numericDraft(value);
|
|
8650
|
+
return null !== number && number >= minimum && number <= maximum;
|
|
8651
|
+
}
|
|
8652
|
+
function numericDraft(value) {
|
|
8653
|
+
if (!value.trim()) return null;
|
|
8654
|
+
const number = Number(value);
|
|
8655
|
+
return Number.isFinite(number) && number >= 0 ? number : null;
|
|
8656
|
+
}
|
|
8657
|
+
function sameDraftNumber(left, right) {
|
|
8658
|
+
if (!left.trim() || !right.trim()) return left === right;
|
|
8659
|
+
return Number(left) === Number(right);
|
|
8660
|
+
}
|
|
8661
|
+
function validAspectRatio(width, height) {
|
|
8662
|
+
const ratio = width / height;
|
|
8663
|
+
return Number.isFinite(ratio) && ratio > 0 ? ratio : 1;
|
|
8664
|
+
}
|
|
8665
|
+
function document_picture_properties_dialog_model_centimeters(pixels) {
|
|
8666
|
+
return formatNumber(pixels / IMAGE_PIXELS_PER_CENTIMETER);
|
|
8667
|
+
}
|
|
8668
|
+
function formatNumber(value) {
|
|
8669
|
+
return Number.isFinite(value) ? value.toFixed(2).replace(/\.?0+$/, '') : '';
|
|
8670
|
+
}
|
|
8671
|
+
function rounded(value) {
|
|
8672
|
+
return Math.round(100 * value) / 100;
|
|
8673
|
+
}
|
|
8674
|
+
const document_picture_properties_dialog_layoutOptions = [
|
|
8675
|
+
{
|
|
8676
|
+
value: 'inline',
|
|
8677
|
+
label: '嵌入文字',
|
|
8678
|
+
icon: Rows3
|
|
8679
|
+
},
|
|
8680
|
+
{
|
|
8681
|
+
value: 'square',
|
|
8682
|
+
label: '四周环绕',
|
|
8683
|
+
icon: TextWrap
|
|
8684
|
+
},
|
|
8685
|
+
{
|
|
8686
|
+
value: 'topBottom',
|
|
8687
|
+
label: '上下环绕',
|
|
8688
|
+
icon: Rows3
|
|
8689
|
+
}
|
|
8690
|
+
];
|
|
8691
|
+
const alignmentOptions = [
|
|
8692
|
+
{
|
|
8693
|
+
value: 'left',
|
|
8694
|
+
label: '左对齐',
|
|
8695
|
+
icon: AlignLeft
|
|
8696
|
+
},
|
|
8697
|
+
{
|
|
8698
|
+
value: 'center',
|
|
8699
|
+
label: '居中',
|
|
8700
|
+
icon: AlignCenter
|
|
8701
|
+
},
|
|
8702
|
+
{
|
|
8703
|
+
value: 'right',
|
|
8704
|
+
label: '右对齐',
|
|
8705
|
+
icon: AlignRight
|
|
8706
|
+
}
|
|
8707
|
+
];
|
|
8708
|
+
function DocumentPicturePropertiesControl({ editor }) {
|
|
8709
|
+
const [source, setSource] = useState(null);
|
|
8710
|
+
const triggerRef = useRef(null);
|
|
8711
|
+
const openDialog = (event)=>{
|
|
8712
|
+
const position = selectedDocumentImagePosition(editor);
|
|
8713
|
+
if (null === position) return;
|
|
8714
|
+
const rendered = selectedDocumentImageDimensions(editor, position);
|
|
8715
|
+
triggerRef.current = event.currentTarget;
|
|
8716
|
+
setSource({
|
|
8717
|
+
position,
|
|
8718
|
+
properties: documentImageProperties(editor),
|
|
8719
|
+
renderedWidth: rendered?.width,
|
|
8720
|
+
renderedHeight: rendered?.height
|
|
8721
|
+
});
|
|
8722
|
+
};
|
|
8723
|
+
return /*#__PURE__*/ jsxs(Fragment, {
|
|
8724
|
+
children: [
|
|
8725
|
+
/*#__PURE__*/ jsx(WorkOfficeRibbonButton, {
|
|
8726
|
+
label: "图片属性",
|
|
8727
|
+
visibleLabel: "图片属性",
|
|
8728
|
+
disabled: !editor.isActive('image'),
|
|
8729
|
+
onClick: openDialog,
|
|
8730
|
+
children: /*#__PURE__*/ jsx(Settings2, {
|
|
8731
|
+
size: 18
|
|
8732
|
+
})
|
|
8733
|
+
}),
|
|
8734
|
+
source && /*#__PURE__*/ jsx(DocumentPicturePropertiesDialog, {
|
|
8735
|
+
editor: editor,
|
|
8736
|
+
source: source,
|
|
8737
|
+
restoreFocusTarget: ()=>triggerRef.current,
|
|
8738
|
+
onClose: ()=>setSource(null)
|
|
8739
|
+
})
|
|
8740
|
+
]
|
|
8741
|
+
});
|
|
8742
|
+
}
|
|
8743
|
+
function DocumentPicturePropertiesDialog({ editor, source, restoreFocusTarget, onClose }) {
|
|
8744
|
+
const [initial] = useState(()=>createDocumentPicturePropertiesDraft(source));
|
|
8745
|
+
const [draft, setDraft] = useState(initial);
|
|
8746
|
+
const formId = useId();
|
|
8747
|
+
const alternativeTextId = useId();
|
|
8748
|
+
const errors = documentPicturePropertiesErrors(draft);
|
|
8749
|
+
const invalid = hasDocumentPicturePropertiesErrors(errors);
|
|
8750
|
+
const submit = (event)=>{
|
|
8751
|
+
event?.preventDefault();
|
|
8752
|
+
if (invalid) return;
|
|
8753
|
+
const changes = documentPicturePropertyChanges(initial, draft);
|
|
8754
|
+
if (!changes) return void onClose();
|
|
8755
|
+
if (editor.state.doc.nodeAt(source.position)?.type.name !== 'image') return void onClose();
|
|
8756
|
+
const applied = editor.chain().setNodeSelection(source.position).setDocumentImageProperties(changes, {
|
|
8757
|
+
restoreFocus: false
|
|
8758
|
+
}).run();
|
|
8759
|
+
if (applied) onClose();
|
|
8760
|
+
};
|
|
8761
|
+
return /*#__PURE__*/ jsx(Dialog, {
|
|
8762
|
+
title: "图片属性",
|
|
8763
|
+
description: "调整当前图片的大小、排列方式和辅助说明。",
|
|
8764
|
+
className: "work-document-picture-properties-dialog",
|
|
8765
|
+
restoreFocusTarget: restoreFocusTarget,
|
|
8766
|
+
onClose: onClose,
|
|
8767
|
+
footer: /*#__PURE__*/ jsxs(Fragment, {
|
|
8768
|
+
children: [
|
|
8769
|
+
/*#__PURE__*/ jsx(button_Button, {
|
|
8770
|
+
tone: "quiet",
|
|
8771
|
+
onClick: onClose,
|
|
8772
|
+
children: "取消"
|
|
8773
|
+
}),
|
|
8774
|
+
/*#__PURE__*/ jsx(button_Button, {
|
|
8775
|
+
tone: "primary",
|
|
8776
|
+
type: "submit",
|
|
8777
|
+
form: formId,
|
|
8778
|
+
disabled: invalid,
|
|
8779
|
+
children: "确定"
|
|
8780
|
+
})
|
|
8781
|
+
]
|
|
8782
|
+
}),
|
|
8783
|
+
children: /*#__PURE__*/ jsxs("form", {
|
|
8784
|
+
id: formId,
|
|
8785
|
+
onSubmit: submit,
|
|
8786
|
+
children: [
|
|
8787
|
+
/*#__PURE__*/ jsx(PictureSizeSection, {
|
|
8788
|
+
draft: draft,
|
|
8789
|
+
errors: errors,
|
|
8790
|
+
onDraftChange: setDraft
|
|
8791
|
+
}),
|
|
8792
|
+
/*#__PURE__*/ jsx(PictureLayoutSection, {
|
|
8793
|
+
draft: draft,
|
|
8794
|
+
onDraftChange: setDraft
|
|
8795
|
+
}),
|
|
8796
|
+
/*#__PURE__*/ jsx(PictureAlignmentSection, {
|
|
8797
|
+
draft: draft,
|
|
8798
|
+
onDraftChange: setDraft
|
|
8799
|
+
}),
|
|
8800
|
+
/*#__PURE__*/ jsxs("label", {
|
|
8801
|
+
className: "work-document-picture-properties-alt-text",
|
|
8802
|
+
htmlFor: alternativeTextId,
|
|
8803
|
+
children: [
|
|
8804
|
+
/*#__PURE__*/ jsx("span", {
|
|
8805
|
+
children: "替代文字"
|
|
8806
|
+
}),
|
|
8807
|
+
/*#__PURE__*/ jsx(office_text_field_OfficeTextArea, {
|
|
8808
|
+
id: alternativeTextId,
|
|
8809
|
+
"aria-label": "图片替代文字",
|
|
8810
|
+
value: draft.alternativeText,
|
|
8811
|
+
maxLength: 512,
|
|
8812
|
+
placeholder: "描述图片中的关键信息;装饰性图片可留空",
|
|
8813
|
+
onChange: (event)=>{
|
|
8814
|
+
const alternativeText = event.currentTarget.value;
|
|
8815
|
+
setDraft((current)=>({
|
|
8816
|
+
...current,
|
|
8817
|
+
alternativeText
|
|
8818
|
+
}));
|
|
8819
|
+
}
|
|
8820
|
+
}),
|
|
8821
|
+
/*#__PURE__*/ jsx("small", {
|
|
8822
|
+
children: "供屏幕阅读器使用,不会显示在正文中。"
|
|
8823
|
+
})
|
|
8824
|
+
]
|
|
8825
|
+
})
|
|
8826
|
+
]
|
|
8827
|
+
})
|
|
8828
|
+
});
|
|
8829
|
+
}
|
|
8830
|
+
function PictureSizeSection({ draft, errors, onDraftChange }) {
|
|
8831
|
+
return /*#__PURE__*/ jsxs("fieldset", {
|
|
8832
|
+
className: "work-document-picture-properties-section size",
|
|
8833
|
+
children: [
|
|
8834
|
+
/*#__PURE__*/ jsx("legend", {
|
|
8835
|
+
children: "大小"
|
|
8836
|
+
}),
|
|
8837
|
+
/*#__PURE__*/ jsx(PictureNumberRow, {
|
|
8838
|
+
label: "宽度",
|
|
8839
|
+
ariaLabel: "图片宽度(厘米)",
|
|
8840
|
+
value: draft.width,
|
|
8841
|
+
unit: "厘米",
|
|
8842
|
+
min: 0.01,
|
|
8843
|
+
max: 55.87,
|
|
8844
|
+
step: 0.1,
|
|
8845
|
+
invalid: Boolean(errors.width),
|
|
8846
|
+
onValueChange: (width)=>onDraftChange((current)=>withDocumentPictureDimension(current, 'width', width))
|
|
8847
|
+
}),
|
|
8848
|
+
errors.width && /*#__PURE__*/ jsx("p", {
|
|
8849
|
+
role: "alert",
|
|
8850
|
+
children: errors.width
|
|
8851
|
+
}),
|
|
8852
|
+
/*#__PURE__*/ jsx(PictureNumberRow, {
|
|
8853
|
+
label: "高度",
|
|
8854
|
+
ariaLabel: "图片高度(厘米)",
|
|
8855
|
+
value: draft.height,
|
|
8856
|
+
unit: "厘米",
|
|
8857
|
+
min: 0.01,
|
|
8858
|
+
max: 55.87,
|
|
8859
|
+
step: 0.1,
|
|
8860
|
+
invalid: Boolean(errors.height),
|
|
8861
|
+
onValueChange: (height)=>onDraftChange((current)=>withDocumentPictureDimension(current, 'height', height))
|
|
8862
|
+
}),
|
|
8863
|
+
errors.height && /*#__PURE__*/ jsx("p", {
|
|
8864
|
+
role: "alert",
|
|
8865
|
+
children: errors.height
|
|
8866
|
+
}),
|
|
8867
|
+
/*#__PURE__*/ jsx(OfficeCheckbox, {
|
|
8868
|
+
ariaLabel: "锁定纵横比",
|
|
8869
|
+
checked: draft.lockAspectRatio,
|
|
8870
|
+
onCheckedChange: (locked)=>onDraftChange((current)=>withDocumentPictureAspectRatioLock(current, locked)),
|
|
8871
|
+
children: "锁定纵横比"
|
|
8872
|
+
})
|
|
8873
|
+
]
|
|
8874
|
+
});
|
|
8875
|
+
}
|
|
8876
|
+
function PictureLayoutSection({ draft, onDraftChange }) {
|
|
8877
|
+
const errors = documentPicturePropertiesErrors(draft);
|
|
8878
|
+
return /*#__PURE__*/ jsxs("fieldset", {
|
|
8879
|
+
className: "work-document-picture-properties-section layout",
|
|
8880
|
+
children: [
|
|
8881
|
+
/*#__PURE__*/ jsx("legend", {
|
|
8882
|
+
children: "文字环绕"
|
|
8883
|
+
}),
|
|
8884
|
+
/*#__PURE__*/ jsx("div", {
|
|
8885
|
+
className: "work-document-picture-properties-choice-grid",
|
|
8886
|
+
children: document_picture_properties_dialog_layoutOptions.map((option)=>{
|
|
8887
|
+
const Icon = option.icon;
|
|
8888
|
+
return /*#__PURE__*/ jsxs("label", {
|
|
8889
|
+
children: [
|
|
8890
|
+
/*#__PURE__*/ jsx("input", {
|
|
8891
|
+
type: "radio",
|
|
8892
|
+
name: "picture-properties-layout",
|
|
8893
|
+
value: option.value,
|
|
8894
|
+
checked: draft.layout === option.value,
|
|
8895
|
+
onChange: ()=>onDraftChange((current)=>({
|
|
8896
|
+
...current,
|
|
8897
|
+
layout: option.value
|
|
8898
|
+
}))
|
|
8899
|
+
}),
|
|
8900
|
+
/*#__PURE__*/ jsxs("span", {
|
|
8901
|
+
children: [
|
|
8902
|
+
/*#__PURE__*/ jsx(Icon, {
|
|
8903
|
+
size: 16,
|
|
8904
|
+
"aria-hidden": "true"
|
|
8905
|
+
}),
|
|
8906
|
+
option.label
|
|
8907
|
+
]
|
|
8908
|
+
})
|
|
8909
|
+
]
|
|
8910
|
+
}, option.value);
|
|
8911
|
+
})
|
|
8912
|
+
}),
|
|
8913
|
+
/*#__PURE__*/ jsx(PictureNumberRow, {
|
|
8914
|
+
label: "文字距离",
|
|
8915
|
+
ariaLabel: "图片与文字距离(毫米)",
|
|
8916
|
+
value: draft.wrapDistance,
|
|
8917
|
+
unit: "毫米",
|
|
8918
|
+
min: 0,
|
|
8919
|
+
max: 25,
|
|
8920
|
+
step: 0.5,
|
|
8921
|
+
disabled: 'inline' === draft.layout,
|
|
8922
|
+
invalid: Boolean(errors.wrapDistance),
|
|
8923
|
+
onValueChange: (wrapDistance)=>onDraftChange((current)=>({
|
|
8924
|
+
...current,
|
|
8925
|
+
wrapDistance
|
|
8926
|
+
}))
|
|
8927
|
+
}),
|
|
8928
|
+
errors.wrapDistance && /*#__PURE__*/ jsx("p", {
|
|
8929
|
+
role: "alert",
|
|
8930
|
+
children: errors.wrapDistance
|
|
8931
|
+
})
|
|
8932
|
+
]
|
|
8933
|
+
});
|
|
8934
|
+
}
|
|
8935
|
+
function PictureAlignmentSection({ draft, onDraftChange }) {
|
|
8936
|
+
return /*#__PURE__*/ jsxs("fieldset", {
|
|
8937
|
+
className: "work-document-picture-properties-section position",
|
|
8938
|
+
children: [
|
|
8939
|
+
/*#__PURE__*/ jsx("legend", {
|
|
8940
|
+
children: "位置"
|
|
8941
|
+
}),
|
|
8942
|
+
/*#__PURE__*/ jsx("div", {
|
|
8943
|
+
className: "work-document-picture-properties-choice-grid",
|
|
8944
|
+
children: alignmentOptions.map((option)=>{
|
|
8945
|
+
const Icon = option.icon;
|
|
8946
|
+
return /*#__PURE__*/ jsxs("label", {
|
|
8947
|
+
children: [
|
|
8948
|
+
/*#__PURE__*/ jsx("input", {
|
|
8949
|
+
type: "radio",
|
|
8950
|
+
name: "picture-properties-alignment",
|
|
8951
|
+
value: option.value,
|
|
8952
|
+
checked: draft.alignment === option.value,
|
|
8953
|
+
onChange: ()=>onDraftChange((current)=>({
|
|
8954
|
+
...current,
|
|
8955
|
+
alignment: option.value
|
|
8956
|
+
}))
|
|
8957
|
+
}),
|
|
8958
|
+
/*#__PURE__*/ jsxs("span", {
|
|
8959
|
+
children: [
|
|
8960
|
+
/*#__PURE__*/ jsx(Icon, {
|
|
8961
|
+
size: 16,
|
|
8962
|
+
"aria-hidden": "true"
|
|
8963
|
+
}),
|
|
8964
|
+
option.label
|
|
8965
|
+
]
|
|
8966
|
+
})
|
|
8967
|
+
]
|
|
8968
|
+
}, option.value);
|
|
8969
|
+
})
|
|
8970
|
+
})
|
|
8971
|
+
]
|
|
8972
|
+
});
|
|
8973
|
+
}
|
|
8974
|
+
function PictureNumberRow({ label, ariaLabel, value, unit, min, max, step, disabled = false, invalid, onValueChange }) {
|
|
8975
|
+
return /*#__PURE__*/ jsxs("div", {
|
|
8976
|
+
className: "work-document-picture-properties-number-row",
|
|
8977
|
+
children: [
|
|
8978
|
+
/*#__PURE__*/ jsx("span", {
|
|
8979
|
+
children: label
|
|
8980
|
+
}),
|
|
8981
|
+
/*#__PURE__*/ jsx(OfficeNumberField, {
|
|
8982
|
+
ariaLabel: ariaLabel,
|
|
8983
|
+
value: value,
|
|
8984
|
+
min: min,
|
|
8985
|
+
max: max,
|
|
8986
|
+
step: step,
|
|
8987
|
+
disabled: disabled,
|
|
8988
|
+
validationInvalid: invalid,
|
|
8989
|
+
onValueChange: onValueChange
|
|
8990
|
+
}),
|
|
8991
|
+
/*#__PURE__*/ jsx("small", {
|
|
8992
|
+
children: unit
|
|
8993
|
+
})
|
|
8994
|
+
]
|
|
8995
|
+
});
|
|
8996
|
+
}
|
|
8997
|
+
function selectedDocumentImagePosition(editor) {
|
|
8998
|
+
const selection = editor.state.selection;
|
|
8999
|
+
return selection instanceof NodeSelection && 'image' === selection.node.type.name ? selection.from : null;
|
|
9000
|
+
}
|
|
9001
|
+
function selectedDocumentImageDimensions(editor, position) {
|
|
9002
|
+
const node = editor.view.nodeDOM(position);
|
|
9003
|
+
const image = node instanceof HTMLImageElement ? node : node instanceof HTMLElement ? node.querySelector('img') : null;
|
|
9004
|
+
if (!(image instanceof HTMLImageElement)) return null;
|
|
9005
|
+
const bounds = image.getBoundingClientRect();
|
|
9006
|
+
const width = bounds.width || image.width || image.naturalWidth;
|
|
9007
|
+
const height = bounds.height || image.height || image.naturalHeight;
|
|
9008
|
+
return width > 0 && height > 0 ? {
|
|
9009
|
+
width,
|
|
9010
|
+
height
|
|
9011
|
+
} : null;
|
|
9012
|
+
}
|
|
9013
|
+
const imageWrapDistanceOptions = [
|
|
9014
|
+
{
|
|
9015
|
+
value: '0',
|
|
9016
|
+
label: '无间距'
|
|
9017
|
+
},
|
|
7447
9018
|
{
|
|
7448
9019
|
value: '2',
|
|
7449
9020
|
label: '2 毫米'
|
|
@@ -7465,7 +9036,6 @@ function DocumentPictureRibbon({ editor }) {
|
|
|
7465
9036
|
const image = documentImageLayoutOptions(editor);
|
|
7466
9037
|
const imageSelected = editor.isActive('image');
|
|
7467
9038
|
const wrapDistanceValue = String(image.wrapDistance);
|
|
7468
|
-
const officeDialog = useOfficeDialog();
|
|
7469
9039
|
const updateLayout = (layout)=>editor.commands.setDocumentImageLayoutOptions({
|
|
7470
9040
|
layout
|
|
7471
9041
|
});
|
|
@@ -7486,143 +9056,1034 @@ function DocumentPictureRibbon({ editor }) {
|
|
|
7486
9056
|
size: 18
|
|
7487
9057
|
})
|
|
7488
9058
|
}),
|
|
7489
|
-
/*#__PURE__*/ jsx(PictureButton, {
|
|
7490
|
-
label: "四周环绕",
|
|
7491
|
-
active: 'square' === image.layout,
|
|
7492
|
-
disabled: !imageSelected,
|
|
7493
|
-
onClick: ()=>updateLayout('square'),
|
|
7494
|
-
children: /*#__PURE__*/ jsx(TextWrap, {
|
|
7495
|
-
size: 18
|
|
7496
|
-
})
|
|
9059
|
+
/*#__PURE__*/ jsx(PictureButton, {
|
|
9060
|
+
label: "四周环绕",
|
|
9061
|
+
active: 'square' === image.layout,
|
|
9062
|
+
disabled: !imageSelected,
|
|
9063
|
+
onClick: ()=>updateLayout('square'),
|
|
9064
|
+
children: /*#__PURE__*/ jsx(TextWrap, {
|
|
9065
|
+
size: 18
|
|
9066
|
+
})
|
|
9067
|
+
}),
|
|
9068
|
+
/*#__PURE__*/ jsx(PictureButton, {
|
|
9069
|
+
label: "上下环绕",
|
|
9070
|
+
active: 'topBottom' === image.layout,
|
|
9071
|
+
disabled: !imageSelected,
|
|
9072
|
+
onClick: ()=>updateLayout('topBottom'),
|
|
9073
|
+
children: /*#__PURE__*/ jsx(Rows3, {
|
|
9074
|
+
size: 18
|
|
9075
|
+
})
|
|
9076
|
+
})
|
|
9077
|
+
]
|
|
9078
|
+
}),
|
|
9079
|
+
/*#__PURE__*/ jsxs(WorkOfficeRibbonGroup, {
|
|
9080
|
+
label: "位置",
|
|
9081
|
+
children: [
|
|
9082
|
+
/*#__PURE__*/ jsx(PictureButton, {
|
|
9083
|
+
label: "左对齐",
|
|
9084
|
+
active: 'left' === image.alignment,
|
|
9085
|
+
disabled: !imageSelected,
|
|
9086
|
+
onClick: ()=>updateAlignment('left'),
|
|
9087
|
+
children: /*#__PURE__*/ jsx(AlignLeft, {
|
|
9088
|
+
size: 18
|
|
9089
|
+
})
|
|
9090
|
+
}),
|
|
9091
|
+
/*#__PURE__*/ jsx(PictureButton, {
|
|
9092
|
+
label: "居中",
|
|
9093
|
+
active: 'center' === image.alignment,
|
|
9094
|
+
disabled: !imageSelected,
|
|
9095
|
+
onClick: ()=>updateAlignment('center'),
|
|
9096
|
+
children: /*#__PURE__*/ jsx(AlignCenter, {
|
|
9097
|
+
size: 18
|
|
9098
|
+
})
|
|
9099
|
+
}),
|
|
9100
|
+
/*#__PURE__*/ jsx(PictureButton, {
|
|
9101
|
+
label: "右对齐",
|
|
9102
|
+
active: 'right' === image.alignment,
|
|
9103
|
+
disabled: !imageSelected,
|
|
9104
|
+
onClick: ()=>updateAlignment('right'),
|
|
9105
|
+
children: /*#__PURE__*/ jsx(AlignRight, {
|
|
9106
|
+
size: 18
|
|
9107
|
+
})
|
|
9108
|
+
})
|
|
9109
|
+
]
|
|
9110
|
+
}),
|
|
9111
|
+
/*#__PURE__*/ jsx(WorkOfficeRibbonGroup, {
|
|
9112
|
+
label: "与文字距离",
|
|
9113
|
+
children: /*#__PURE__*/ jsx(OfficeSelect, {
|
|
9114
|
+
ariaLabel: "图片与文字距离",
|
|
9115
|
+
value: wrapDistanceValue,
|
|
9116
|
+
options: imageWrapDistanceOptionsForValue(wrapDistanceValue),
|
|
9117
|
+
disabled: !imageSelected || 'inline' === image.layout,
|
|
9118
|
+
onValueChange: (value)=>editor.commands.setDocumentImageLayoutOptions({
|
|
9119
|
+
wrapDistance: Number(value)
|
|
9120
|
+
})
|
|
9121
|
+
})
|
|
9122
|
+
}),
|
|
9123
|
+
/*#__PURE__*/ jsxs(WorkOfficeRibbonGroup, {
|
|
9124
|
+
label: "图片",
|
|
9125
|
+
children: [
|
|
9126
|
+
/*#__PURE__*/ jsx(DocumentPicturePropertiesControl, {
|
|
9127
|
+
editor: editor
|
|
9128
|
+
}),
|
|
9129
|
+
/*#__PURE__*/ jsx(PictureButton, {
|
|
9130
|
+
label: "删除图片",
|
|
9131
|
+
disabled: !imageSelected,
|
|
9132
|
+
onClick: ()=>editor.chain().focus().deleteSelection().run(),
|
|
9133
|
+
children: /*#__PURE__*/ jsx(Trash2, {
|
|
9134
|
+
size: 18
|
|
9135
|
+
})
|
|
9136
|
+
})
|
|
9137
|
+
]
|
|
9138
|
+
})
|
|
9139
|
+
]
|
|
9140
|
+
});
|
|
9141
|
+
}
|
|
9142
|
+
function imageWrapDistanceOptionsForValue(value) {
|
|
9143
|
+
if (imageWrapDistanceOptions.some((option)=>option.value === value)) return imageWrapDistanceOptions;
|
|
9144
|
+
return [
|
|
9145
|
+
...imageWrapDistanceOptions,
|
|
9146
|
+
{
|
|
9147
|
+
value,
|
|
9148
|
+
label: `${value} 毫米`
|
|
9149
|
+
}
|
|
9150
|
+
];
|
|
9151
|
+
}
|
|
9152
|
+
function PictureButton({ label, active = false, disabled = false, onClick, children }) {
|
|
9153
|
+
return /*#__PURE__*/ jsx(WorkOfficeRibbonButton, {
|
|
9154
|
+
label: label,
|
|
9155
|
+
displayLabel: true,
|
|
9156
|
+
active: active,
|
|
9157
|
+
disabled: disabled,
|
|
9158
|
+
onClick: onClick,
|
|
9159
|
+
children: children
|
|
9160
|
+
});
|
|
9161
|
+
}
|
|
9162
|
+
function DocumentTableInsertPopover({ editor }) {
|
|
9163
|
+
return /*#__PURE__*/ jsx(OfficeTableInsertPopover, {
|
|
9164
|
+
className: "work-document-table-insert-popover",
|
|
9165
|
+
label: "插入表格",
|
|
9166
|
+
onInsert: (dimensions)=>editor.commands.insertDocumentTable(dimensions)
|
|
9167
|
+
});
|
|
9168
|
+
}
|
|
9169
|
+
const PIXELS_PER_CENTIMETER = 96 / 2.54;
|
|
9170
|
+
const document_table_margins_popover_marginFields = [
|
|
9171
|
+
{
|
|
9172
|
+
side: 'top',
|
|
9173
|
+
label: '上',
|
|
9174
|
+
ariaLabel: '单元格上边距(厘米)'
|
|
9175
|
+
},
|
|
9176
|
+
{
|
|
9177
|
+
side: 'bottom',
|
|
9178
|
+
label: '下',
|
|
9179
|
+
ariaLabel: '单元格下边距(厘米)'
|
|
9180
|
+
},
|
|
9181
|
+
{
|
|
9182
|
+
side: 'left',
|
|
9183
|
+
label: '左',
|
|
9184
|
+
ariaLabel: '单元格左边距(厘米)'
|
|
9185
|
+
},
|
|
9186
|
+
{
|
|
9187
|
+
side: 'right',
|
|
9188
|
+
label: '右',
|
|
9189
|
+
ariaLabel: '单元格右边距(厘米)'
|
|
9190
|
+
}
|
|
9191
|
+
];
|
|
9192
|
+
function DocumentTableMarginsPopover({ editor }) {
|
|
9193
|
+
const margins = currentMargins(editor);
|
|
9194
|
+
const [open, setOpen] = useState(false);
|
|
9195
|
+
const [drafts, setDrafts] = useState(()=>marginDrafts(margins));
|
|
9196
|
+
const customized = !sameMargins(margins, DEFAULT_DOCUMENT_TABLE_CELL_MARGINS);
|
|
9197
|
+
const commit = (side, rawValue)=>{
|
|
9198
|
+
const centimeters = Number(rawValue);
|
|
9199
|
+
if (!Number.isFinite(centimeters) || centimeters < 0 || centimeters > 5) return void setDrafts(marginDrafts(currentMargins(editor)));
|
|
9200
|
+
const value = Math.round(centimeters * PIXELS_PER_CENTIMETER * 100) / 100;
|
|
9201
|
+
const next = {
|
|
9202
|
+
...currentMargins(editor),
|
|
9203
|
+
[side]: value
|
|
9204
|
+
};
|
|
9205
|
+
editor.commands.setDocumentTableCellMargins(next) ? setDrafts(marginDrafts(next)) : setDrafts(marginDrafts(currentMargins(editor)));
|
|
9206
|
+
};
|
|
9207
|
+
const restoreDefault = ()=>{
|
|
9208
|
+
const next = {
|
|
9209
|
+
...DEFAULT_DOCUMENT_TABLE_CELL_MARGINS
|
|
9210
|
+
};
|
|
9211
|
+
if (editor.commands.setDocumentTableCellMargins(next)) setDrafts(marginDrafts(next));
|
|
9212
|
+
};
|
|
9213
|
+
return /*#__PURE__*/ jsx(Popover, {
|
|
9214
|
+
label: "单元格边距",
|
|
9215
|
+
panelLabel: "单元格边距设置",
|
|
9216
|
+
panelRole: "dialog",
|
|
9217
|
+
portal: true,
|
|
9218
|
+
open: open,
|
|
9219
|
+
onOpenChange: (nextOpen)=>{
|
|
9220
|
+
setOpen(nextOpen);
|
|
9221
|
+
if (nextOpen) setDrafts(marginDrafts(currentMargins(editor)));
|
|
9222
|
+
},
|
|
9223
|
+
focusFirstOnOpen: true,
|
|
9224
|
+
className: "work-document-table-margins-popover",
|
|
9225
|
+
panelClassName: "work-document-table-margins-panel",
|
|
9226
|
+
trigger: (triggerProps, { open: popoverOpen })=>/*#__PURE__*/ jsxs("button", {
|
|
9227
|
+
...triggerProps,
|
|
9228
|
+
className: `with-label${customized || popoverOpen ? ' active' : ''}`,
|
|
9229
|
+
"aria-pressed": customized,
|
|
9230
|
+
children: [
|
|
9231
|
+
/*#__PURE__*/ jsx(Grid2X2, {
|
|
9232
|
+
size: 18
|
|
9233
|
+
}),
|
|
9234
|
+
/*#__PURE__*/ jsx("span", {
|
|
9235
|
+
children: "单元格边距"
|
|
9236
|
+
})
|
|
9237
|
+
]
|
|
9238
|
+
}),
|
|
9239
|
+
children: /*#__PURE__*/ jsxs("fieldset", {
|
|
9240
|
+
children: [
|
|
9241
|
+
/*#__PURE__*/ jsx("legend", {
|
|
9242
|
+
children: "单元格边距"
|
|
9243
|
+
}),
|
|
9244
|
+
/*#__PURE__*/ jsx("p", {
|
|
9245
|
+
children: "设置文字到单元格边框的距离。"
|
|
9246
|
+
}),
|
|
9247
|
+
/*#__PURE__*/ jsx("div", {
|
|
9248
|
+
className: "work-document-table-margins-grid",
|
|
9249
|
+
children: document_table_margins_popover_marginFields.map(({ side, label, ariaLabel })=>/*#__PURE__*/ jsxs("fieldset", {
|
|
9250
|
+
className: "work-document-table-margin-field",
|
|
9251
|
+
children: [
|
|
9252
|
+
/*#__PURE__*/ jsxs("legend", {
|
|
9253
|
+
className: "sr-only",
|
|
9254
|
+
children: [
|
|
9255
|
+
label,
|
|
9256
|
+
"边距"
|
|
9257
|
+
]
|
|
9258
|
+
}),
|
|
9259
|
+
/*#__PURE__*/ jsx("span", {
|
|
9260
|
+
"aria-hidden": "true",
|
|
9261
|
+
children: label
|
|
9262
|
+
}),
|
|
9263
|
+
/*#__PURE__*/ jsx(OfficeNumberField, {
|
|
9264
|
+
ariaLabel: ariaLabel,
|
|
9265
|
+
value: drafts[side],
|
|
9266
|
+
min: 0,
|
|
9267
|
+
max: 5,
|
|
9268
|
+
step: 0.05,
|
|
9269
|
+
onValueChange: (value)=>setDrafts((current)=>({
|
|
9270
|
+
...current,
|
|
9271
|
+
[side]: value
|
|
9272
|
+
})),
|
|
9273
|
+
onCommit: (value)=>commit(side, value),
|
|
9274
|
+
onCancel: ()=>setDrafts(marginDrafts(currentMargins(editor)))
|
|
9275
|
+
}),
|
|
9276
|
+
/*#__PURE__*/ jsx("small", {
|
|
9277
|
+
children: "厘米"
|
|
9278
|
+
})
|
|
9279
|
+
]
|
|
9280
|
+
}, side))
|
|
9281
|
+
}),
|
|
9282
|
+
/*#__PURE__*/ jsx("button", {
|
|
9283
|
+
type: "button",
|
|
9284
|
+
className: "work-document-table-margins-reset",
|
|
9285
|
+
disabled: !customized,
|
|
9286
|
+
onClick: restoreDefault,
|
|
9287
|
+
children: "恢复标准边距"
|
|
9288
|
+
})
|
|
9289
|
+
]
|
|
9290
|
+
})
|
|
9291
|
+
});
|
|
9292
|
+
}
|
|
9293
|
+
function currentMargins(editor) {
|
|
9294
|
+
return documentTableSizing(editor.state)?.cellMargins ?? {
|
|
9295
|
+
...DEFAULT_DOCUMENT_TABLE_CELL_MARGINS
|
|
9296
|
+
};
|
|
9297
|
+
}
|
|
9298
|
+
function marginDrafts(margins) {
|
|
9299
|
+
return {
|
|
9300
|
+
top: document_table_margins_popover_centimeters(margins.top),
|
|
9301
|
+
right: document_table_margins_popover_centimeters(margins.right),
|
|
9302
|
+
bottom: document_table_margins_popover_centimeters(margins.bottom),
|
|
9303
|
+
left: document_table_margins_popover_centimeters(margins.left)
|
|
9304
|
+
};
|
|
9305
|
+
}
|
|
9306
|
+
function document_table_margins_popover_centimeters(pixels) {
|
|
9307
|
+
return (pixels / PIXELS_PER_CENTIMETER).toFixed(2).replace(/\.?0+$/, '');
|
|
9308
|
+
}
|
|
9309
|
+
function sameMargins(left, right) {
|
|
9310
|
+
return document_table_margins_popover_marginFields.every(({ side })=>Math.abs(left[side] - right[side]) < 0.01);
|
|
9311
|
+
}
|
|
9312
|
+
const document_table_properties_dialog_model_PIXELS_PER_CENTIMETER = 96 / 2.54;
|
|
9313
|
+
const FALLBACK_TABLE_WIDTH_CENTIMETERS = 15;
|
|
9314
|
+
const FALLBACK_ROW_HEIGHT_CENTIMETERS = 0.95;
|
|
9315
|
+
const FALLBACK_COLUMN_WIDTH_CENTIMETERS = 3.18;
|
|
9316
|
+
const marginSides = [
|
|
9317
|
+
'top',
|
|
9318
|
+
'right',
|
|
9319
|
+
'bottom',
|
|
9320
|
+
'left'
|
|
9321
|
+
];
|
|
9322
|
+
function createDocumentTablePropertiesDraft(source) {
|
|
9323
|
+
const widthType = source.sizing.preferredWidthType;
|
|
9324
|
+
const effectiveMargins = effectiveCellMargins(source.cellFormat, source.sizing.cellMargins);
|
|
9325
|
+
return {
|
|
9326
|
+
table: {
|
|
9327
|
+
widthType,
|
|
9328
|
+
width: 'percent' === widthType ? document_table_properties_dialog_model_formatNumber(source.sizing.preferredWidth ?? 100) : 'pixels' === widthType ? document_table_properties_dialog_model_centimeters(source.sizing.preferredWidth ?? source.renderedTableWidth ?? FALLBACK_TABLE_WIDTH_CENTIMETERS * document_table_properties_dialog_model_PIXELS_PER_CENTIMETER) : '',
|
|
9329
|
+
alignment: source.sizing.alignment,
|
|
9330
|
+
indent: document_table_properties_dialog_model_centimeters(source.sizing.indent)
|
|
9331
|
+
},
|
|
9332
|
+
row: {
|
|
9333
|
+
heightEnabled: null !== source.sizing.rowHeight,
|
|
9334
|
+
height: document_table_properties_dialog_model_centimeters(source.sizing.rowHeight ?? source.renderedRowHeight ?? FALLBACK_ROW_HEIGHT_CENTIMETERS * document_table_properties_dialog_model_PIXELS_PER_CENTIMETER),
|
|
9335
|
+
heightRule: source.sizing.rowHeightRule ?? 'atLeast',
|
|
9336
|
+
cantSplit: source.rowOptions.cantSplit,
|
|
9337
|
+
repeatHeader: source.rowOptions.repeatHeader
|
|
9338
|
+
},
|
|
9339
|
+
column: {
|
|
9340
|
+
width: document_table_properties_dialog_model_centimeters(source.renderedColumnWidth ?? source.sizing.columnWidth ?? FALLBACK_COLUMN_WIDTH_CENTIMETERS * document_table_properties_dialog_model_PIXELS_PER_CENTIMETER)
|
|
9341
|
+
},
|
|
9342
|
+
cell: {
|
|
9343
|
+
verticalAlign: source.cellFormat.verticalAlign,
|
|
9344
|
+
useTableMargins: null === source.cellFormat.margins,
|
|
9345
|
+
margins: document_table_properties_dialog_model_marginDrafts(effectiveMargins)
|
|
9346
|
+
}
|
|
9347
|
+
};
|
|
9348
|
+
}
|
|
9349
|
+
function documentTablePropertiesErrors(draft) {
|
|
9350
|
+
const cellMargins = {};
|
|
9351
|
+
if (!draft.cell.useTableMargins) {
|
|
9352
|
+
for (const side of marginSides)if (!document_table_properties_dialog_model_validNumber(draft.cell.margins[side], 0, 5)) cellMargins[side] = '请输入 0 到 5 之间的厘米数。';
|
|
9353
|
+
}
|
|
9354
|
+
return {
|
|
9355
|
+
tableWidth: tableWidthError(draft),
|
|
9356
|
+
tableIndent: tableIndentError(draft),
|
|
9357
|
+
rowHeight: draft.row.heightEnabled ? dimensionError(draft.row.height) : null,
|
|
9358
|
+
columnWidth: dimensionError(draft.column.width),
|
|
9359
|
+
cellMargins
|
|
9360
|
+
};
|
|
9361
|
+
}
|
|
9362
|
+
function hasDocumentTablePropertiesErrors(errors) {
|
|
9363
|
+
return Boolean(errors.tableWidth || errors.tableIndent || errors.rowHeight || errors.columnWidth || Object.keys(errors.cellMargins).length);
|
|
9364
|
+
}
|
|
9365
|
+
function draftForTableWidthType(current, widthType, renderedTableWidth) {
|
|
9366
|
+
if (widthType === current.table.widthType) return current;
|
|
9367
|
+
const width = 'auto' === widthType ? '' : 'percent' === widthType ? '100' : document_table_properties_dialog_model_centimeters(renderedTableWidth ?? FALLBACK_TABLE_WIDTH_CENTIMETERS * document_table_properties_dialog_model_PIXELS_PER_CENTIMETER);
|
|
9368
|
+
return {
|
|
9369
|
+
...current,
|
|
9370
|
+
table: {
|
|
9371
|
+
...current.table,
|
|
9372
|
+
widthType,
|
|
9373
|
+
width
|
|
9374
|
+
}
|
|
9375
|
+
};
|
|
9376
|
+
}
|
|
9377
|
+
function documentTablePropertyChanges(initial, current, source) {
|
|
9378
|
+
const errors = documentTablePropertiesErrors(current);
|
|
9379
|
+
if (hasDocumentTablePropertiesErrors(errors)) return null;
|
|
9380
|
+
const changes = {};
|
|
9381
|
+
const tableChanged = initial.table.widthType !== current.table.widthType || !document_table_properties_dialog_model_sameDraftNumber(initial.table.width, current.table.width) || initial.table.alignment !== current.table.alignment || !document_table_properties_dialog_model_sameDraftNumber(initial.table.indent, current.table.indent);
|
|
9382
|
+
if (tableChanged) changes.table = tablePropertiesForChanges(initial, current, source.sizing);
|
|
9383
|
+
const rowChanged = initial.row.heightEnabled !== current.row.heightEnabled || current.row.heightEnabled && !document_table_properties_dialog_model_sameDraftNumber(initial.row.height, current.row.height) || initial.row.heightRule !== current.row.heightRule || initial.row.cantSplit !== current.row.cantSplit || source.canRepeatHeader && initial.row.repeatHeader !== current.row.repeatHeader;
|
|
9384
|
+
if (rowChanged) changes.row = {
|
|
9385
|
+
height: rowHeightForChanges(initial, current, source.sizing),
|
|
9386
|
+
heightRule: current.row.heightRule,
|
|
9387
|
+
cantSplit: current.row.cantSplit,
|
|
9388
|
+
...source.canRepeatHeader ? {
|
|
9389
|
+
repeatHeader: current.row.repeatHeader
|
|
9390
|
+
} : {}
|
|
9391
|
+
};
|
|
9392
|
+
if (!document_table_properties_dialog_model_sameDraftNumber(initial.column.width, current.column.width)) changes.column = {
|
|
9393
|
+
width: document_table_properties_dialog_model_rounded(Number(current.column.width) * document_table_properties_dialog_model_PIXELS_PER_CENTIMETER),
|
|
9394
|
+
renderedColumnWidths: source.renderedColumnWidths
|
|
9395
|
+
};
|
|
9396
|
+
const marginsChanged = initial.cell.useTableMargins !== current.cell.useTableMargins || !current.cell.useTableMargins && marginSides.some((side)=>!document_table_properties_dialog_model_sameDraftNumber(initial.cell.margins[side], current.cell.margins[side]));
|
|
9397
|
+
if (initial.cell.verticalAlign !== current.cell.verticalAlign || marginsChanged) changes.cell = {
|
|
9398
|
+
verticalAlign: current.cell.verticalAlign,
|
|
9399
|
+
margins: cellMarginsForChanges(initial, current, source)
|
|
9400
|
+
};
|
|
9401
|
+
return Object.keys(changes).length ? changes : null;
|
|
9402
|
+
}
|
|
9403
|
+
function tablePropertiesForChanges(initial, current, sizing) {
|
|
9404
|
+
const widthType = current.table.widthType;
|
|
9405
|
+
const preserveWidth = initial.table.widthType === widthType && document_table_properties_dialog_model_sameDraftNumber(initial.table.width, current.table.width) && sizing.preferredWidthType === widthType;
|
|
9406
|
+
const widthValue = 'auto' === widthType ? null : preserveWidth && null !== sizing.preferredWidth ? sizing.preferredWidth : 'percent' === widthType ? Number(current.table.width) : Number(current.table.width) * document_table_properties_dialog_model_PIXELS_PER_CENTIMETER;
|
|
9407
|
+
return {
|
|
9408
|
+
width: {
|
|
9409
|
+
type: widthType,
|
|
9410
|
+
value: null === widthValue ? null : document_table_properties_dialog_model_rounded(widthValue)
|
|
9411
|
+
},
|
|
9412
|
+
alignment: current.table.alignment,
|
|
9413
|
+
indent: document_table_properties_dialog_model_sameDraftNumber(initial.table.indent, current.table.indent) ? sizing.indent : document_table_properties_dialog_model_rounded(Number(current.table.indent) * document_table_properties_dialog_model_PIXELS_PER_CENTIMETER)
|
|
9414
|
+
};
|
|
9415
|
+
}
|
|
9416
|
+
function rowHeightForChanges(initial, current, sizing) {
|
|
9417
|
+
if (!current.row.heightEnabled) return null;
|
|
9418
|
+
if (initial.row.heightEnabled && document_table_properties_dialog_model_sameDraftNumber(initial.row.height, current.row.height) && null !== sizing.rowHeight) return sizing.rowHeight;
|
|
9419
|
+
return document_table_properties_dialog_model_rounded(Number(current.row.height) * document_table_properties_dialog_model_PIXELS_PER_CENTIMETER);
|
|
9420
|
+
}
|
|
9421
|
+
function cellMarginsForChanges(initial, current, source) {
|
|
9422
|
+
if (current.cell.useTableMargins) return null;
|
|
9423
|
+
const margins = initial.cell.useTableMargins ? {
|
|
9424
|
+
...source.sizing.cellMargins
|
|
9425
|
+
} : {
|
|
9426
|
+
...source.cellFormat.margins ?? {}
|
|
9427
|
+
};
|
|
9428
|
+
for (const side of marginSides)if (!document_table_properties_dialog_model_sameDraftNumber(initial.cell.margins[side], current.cell.margins[side])) margins[side] = document_table_properties_dialog_model_rounded(Number(current.cell.margins[side]) * document_table_properties_dialog_model_PIXELS_PER_CENTIMETER);
|
|
9429
|
+
return margins;
|
|
9430
|
+
}
|
|
9431
|
+
function effectiveCellMargins(format, tableMargins) {
|
|
9432
|
+
return {
|
|
9433
|
+
top: format.margins?.top ?? tableMargins.top,
|
|
9434
|
+
right: format.margins?.right ?? tableMargins.right,
|
|
9435
|
+
bottom: format.margins?.bottom ?? tableMargins.bottom,
|
|
9436
|
+
left: format.margins?.left ?? tableMargins.left
|
|
9437
|
+
};
|
|
9438
|
+
}
|
|
9439
|
+
function document_table_properties_dialog_model_marginDrafts(margins) {
|
|
9440
|
+
return {
|
|
9441
|
+
top: document_table_properties_dialog_model_centimeters(margins.top),
|
|
9442
|
+
right: document_table_properties_dialog_model_centimeters(margins.right),
|
|
9443
|
+
bottom: document_table_properties_dialog_model_centimeters(margins.bottom),
|
|
9444
|
+
left: document_table_properties_dialog_model_centimeters(margins.left)
|
|
9445
|
+
};
|
|
9446
|
+
}
|
|
9447
|
+
function tableWidthError(draft) {
|
|
9448
|
+
if ('auto' === draft.table.widthType) return null;
|
|
9449
|
+
if ('percent' === draft.table.widthType) return document_table_properties_dialog_model_validNumber(draft.table.width, 1, 100) ? null : '请输入 1 到 100 之间的百分比。';
|
|
9450
|
+
return document_table_properties_dialog_model_validNumber(draft.table.width, 0.5, 30) ? null : '请输入 0.5 到 30 之间的厘米数。';
|
|
9451
|
+
}
|
|
9452
|
+
function tableIndentError(draft) {
|
|
9453
|
+
if ('left' !== draft.table.alignment) return null;
|
|
9454
|
+
return document_table_properties_dialog_model_validNumber(draft.table.indent, 0, 30) ? null : '请输入 0 到 30 之间的厘米数。';
|
|
9455
|
+
}
|
|
9456
|
+
function dimensionError(value) {
|
|
9457
|
+
return document_table_properties_dialog_model_validNumber(value, 0.5, 30) ? null : '请输入 0.5 到 30 之间的厘米数。';
|
|
9458
|
+
}
|
|
9459
|
+
function document_table_properties_dialog_model_validNumber(value, minimum, maximum) {
|
|
9460
|
+
if (!value.trim()) return false;
|
|
9461
|
+
const numeric = Number(value);
|
|
9462
|
+
return Number.isFinite(numeric) && numeric >= minimum && numeric <= maximum;
|
|
9463
|
+
}
|
|
9464
|
+
function document_table_properties_dialog_model_sameDraftNumber(left, right) {
|
|
9465
|
+
if (!left.trim() || !right.trim()) return left === right;
|
|
9466
|
+
return Number(left) === Number(right);
|
|
9467
|
+
}
|
|
9468
|
+
function document_table_properties_dialog_model_centimeters(pixels) {
|
|
9469
|
+
return document_table_properties_dialog_model_formatNumber(pixels / document_table_properties_dialog_model_PIXELS_PER_CENTIMETER);
|
|
9470
|
+
}
|
|
9471
|
+
function document_table_properties_dialog_model_formatNumber(value) {
|
|
9472
|
+
return Number.isFinite(value) ? value.toFixed(2).replace(/\.?0+$/, '') : '';
|
|
9473
|
+
}
|
|
9474
|
+
function document_table_properties_dialog_model_rounded(value) {
|
|
9475
|
+
return Math.round(100 * value) / 100;
|
|
9476
|
+
}
|
|
9477
|
+
const tabs = [
|
|
9478
|
+
{
|
|
9479
|
+
value: 'table',
|
|
9480
|
+
label: '表格'
|
|
9481
|
+
},
|
|
9482
|
+
{
|
|
9483
|
+
value: 'row',
|
|
9484
|
+
label: '行'
|
|
9485
|
+
},
|
|
9486
|
+
{
|
|
9487
|
+
value: 'column',
|
|
9488
|
+
label: '列'
|
|
9489
|
+
},
|
|
9490
|
+
{
|
|
9491
|
+
value: 'cell',
|
|
9492
|
+
label: '单元格'
|
|
9493
|
+
}
|
|
9494
|
+
];
|
|
9495
|
+
const widthOptions = [
|
|
9496
|
+
{
|
|
9497
|
+
value: 'auto',
|
|
9498
|
+
label: '自动'
|
|
9499
|
+
},
|
|
9500
|
+
{
|
|
9501
|
+
value: 'percent',
|
|
9502
|
+
label: '百分比'
|
|
9503
|
+
},
|
|
9504
|
+
{
|
|
9505
|
+
value: 'pixels',
|
|
9506
|
+
label: '厘米'
|
|
9507
|
+
}
|
|
9508
|
+
];
|
|
9509
|
+
const document_table_properties_dialog_sections_alignmentOptions = [
|
|
9510
|
+
{
|
|
9511
|
+
value: 'left',
|
|
9512
|
+
label: '左对齐',
|
|
9513
|
+
icon: AlignLeft
|
|
9514
|
+
},
|
|
9515
|
+
{
|
|
9516
|
+
value: 'center',
|
|
9517
|
+
label: '居中',
|
|
9518
|
+
icon: AlignCenter
|
|
9519
|
+
},
|
|
9520
|
+
{
|
|
9521
|
+
value: 'right',
|
|
9522
|
+
label: '右对齐',
|
|
9523
|
+
icon: AlignRight
|
|
9524
|
+
}
|
|
9525
|
+
];
|
|
9526
|
+
const rowHeightRuleOptions = [
|
|
9527
|
+
{
|
|
9528
|
+
value: 'atLeast',
|
|
9529
|
+
label: '最小值'
|
|
9530
|
+
},
|
|
9531
|
+
{
|
|
9532
|
+
value: 'exact',
|
|
9533
|
+
label: '固定值'
|
|
9534
|
+
}
|
|
9535
|
+
];
|
|
9536
|
+
const verticalAlignmentOptions = [
|
|
9537
|
+
{
|
|
9538
|
+
value: 'top',
|
|
9539
|
+
label: '顶端',
|
|
9540
|
+
icon: AlignVerticalJustifyStart
|
|
9541
|
+
},
|
|
9542
|
+
{
|
|
9543
|
+
value: 'middle',
|
|
9544
|
+
label: '居中',
|
|
9545
|
+
icon: AlignVerticalJustifyCenter
|
|
9546
|
+
},
|
|
9547
|
+
{
|
|
9548
|
+
value: 'bottom',
|
|
9549
|
+
label: '底端',
|
|
9550
|
+
icon: AlignVerticalJustifyEnd
|
|
9551
|
+
}
|
|
9552
|
+
];
|
|
9553
|
+
const document_table_properties_dialog_sections_marginFields = [
|
|
9554
|
+
{
|
|
9555
|
+
side: 'top',
|
|
9556
|
+
label: '上',
|
|
9557
|
+
ariaLabel: '当前单元格上边距(厘米)'
|
|
9558
|
+
},
|
|
9559
|
+
{
|
|
9560
|
+
side: 'bottom',
|
|
9561
|
+
label: '下',
|
|
9562
|
+
ariaLabel: '当前单元格下边距(厘米)'
|
|
9563
|
+
},
|
|
9564
|
+
{
|
|
9565
|
+
side: 'left',
|
|
9566
|
+
label: '左',
|
|
9567
|
+
ariaLabel: '当前单元格左边距(厘米)'
|
|
9568
|
+
},
|
|
9569
|
+
{
|
|
9570
|
+
side: 'right',
|
|
9571
|
+
label: '右',
|
|
9572
|
+
ariaLabel: '当前单元格右边距(厘米)'
|
|
9573
|
+
}
|
|
9574
|
+
];
|
|
9575
|
+
function DocumentTablePropertiesTabs({ activeTab, idBase, onTabChange }) {
|
|
9576
|
+
return /*#__PURE__*/ jsx("div", {
|
|
9577
|
+
className: "work-document-table-properties-tabs",
|
|
9578
|
+
role: "tablist",
|
|
9579
|
+
"aria-label": "表格属性分类",
|
|
9580
|
+
children: tabs.map((tab)=>/*#__PURE__*/ jsx("button", {
|
|
9581
|
+
type: "button",
|
|
9582
|
+
id: `${idBase}-${tab.value}-tab`,
|
|
9583
|
+
role: "tab",
|
|
9584
|
+
"aria-controls": `${idBase}-${tab.value}-panel`,
|
|
9585
|
+
"aria-selected": activeTab === tab.value,
|
|
9586
|
+
tabIndex: activeTab === tab.value ? 0 : -1,
|
|
9587
|
+
onClick: ()=>onTabChange(tab.value),
|
|
9588
|
+
children: tab.label
|
|
9589
|
+
}, tab.value))
|
|
9590
|
+
});
|
|
9591
|
+
}
|
|
9592
|
+
function DocumentTablePropertiesPanel({ activeTab, idBase, ...props }) {
|
|
9593
|
+
return /*#__PURE__*/ jsxs("section", {
|
|
9594
|
+
id: `${idBase}-${activeTab}-panel`,
|
|
9595
|
+
className: "work-document-table-properties-panel",
|
|
9596
|
+
role: "tabpanel",
|
|
9597
|
+
"aria-labelledby": `${idBase}-${activeTab}-tab`,
|
|
9598
|
+
tabIndex: -1,
|
|
9599
|
+
children: [
|
|
9600
|
+
'table' === activeTab && /*#__PURE__*/ jsx(TableSection, {
|
|
9601
|
+
...props
|
|
9602
|
+
}),
|
|
9603
|
+
'row' === activeTab && /*#__PURE__*/ jsx(RowSection, {
|
|
9604
|
+
...props
|
|
9605
|
+
}),
|
|
9606
|
+
'column' === activeTab && /*#__PURE__*/ jsx(ColumnSection, {
|
|
9607
|
+
...props
|
|
9608
|
+
}),
|
|
9609
|
+
'cell' === activeTab && /*#__PURE__*/ jsx(CellSection, {
|
|
9610
|
+
...props
|
|
9611
|
+
})
|
|
9612
|
+
]
|
|
9613
|
+
});
|
|
9614
|
+
}
|
|
9615
|
+
function TableSection({ draft, setDraft, errors, source }) {
|
|
9616
|
+
return /*#__PURE__*/ jsxs(Fragment, {
|
|
9617
|
+
children: [
|
|
9618
|
+
/*#__PURE__*/ jsxs("fieldset", {
|
|
9619
|
+
className: "work-document-table-properties-section",
|
|
9620
|
+
children: [
|
|
9621
|
+
/*#__PURE__*/ jsx("legend", {
|
|
9622
|
+
children: "首选宽度"
|
|
9623
|
+
}),
|
|
9624
|
+
/*#__PURE__*/ jsx("div", {
|
|
9625
|
+
className: "work-document-table-properties-choice-grid width",
|
|
9626
|
+
children: widthOptions.map((option)=>/*#__PURE__*/ jsxs("label", {
|
|
9627
|
+
children: [
|
|
9628
|
+
/*#__PURE__*/ jsx("input", {
|
|
9629
|
+
type: "radio",
|
|
9630
|
+
name: "table-properties-width",
|
|
9631
|
+
value: option.value,
|
|
9632
|
+
checked: draft.table.widthType === option.value,
|
|
9633
|
+
"data-autofocus": draft.table.widthType === option.value || void 0,
|
|
9634
|
+
onChange: ()=>setDraft((current)=>draftForTableWidthType(current, option.value, source.renderedTableWidth))
|
|
9635
|
+
}),
|
|
9636
|
+
/*#__PURE__*/ jsx("span", {
|
|
9637
|
+
children: option.label
|
|
9638
|
+
})
|
|
9639
|
+
]
|
|
9640
|
+
}, option.value))
|
|
9641
|
+
}),
|
|
9642
|
+
'auto' !== draft.table.widthType && /*#__PURE__*/ jsx(NumberRow, {
|
|
9643
|
+
label: "宽度",
|
|
9644
|
+
ariaLabel: 'percent' === draft.table.widthType ? '表格宽度(百分比)' : '表格宽度(厘米)',
|
|
9645
|
+
value: draft.table.width,
|
|
9646
|
+
unit: 'percent' === draft.table.widthType ? '%' : '厘米',
|
|
9647
|
+
min: 'percent' === draft.table.widthType ? 1 : 0.5,
|
|
9648
|
+
max: 'percent' === draft.table.widthType ? 100 : 30,
|
|
9649
|
+
step: 'percent' === draft.table.widthType ? 1 : 0.1,
|
|
9650
|
+
invalid: Boolean(errors.tableWidth),
|
|
9651
|
+
onValueChange: (width)=>setDraft((current)=>({
|
|
9652
|
+
...current,
|
|
9653
|
+
table: {
|
|
9654
|
+
...current.table,
|
|
9655
|
+
width
|
|
9656
|
+
}
|
|
9657
|
+
}))
|
|
9658
|
+
}),
|
|
9659
|
+
errors.tableWidth && /*#__PURE__*/ jsx("p", {
|
|
9660
|
+
role: "alert",
|
|
9661
|
+
children: errors.tableWidth
|
|
9662
|
+
})
|
|
9663
|
+
]
|
|
9664
|
+
}),
|
|
9665
|
+
/*#__PURE__*/ jsxs("fieldset", {
|
|
9666
|
+
className: "work-document-table-properties-section",
|
|
9667
|
+
children: [
|
|
9668
|
+
/*#__PURE__*/ jsx("legend", {
|
|
9669
|
+
children: "位置"
|
|
9670
|
+
}),
|
|
9671
|
+
/*#__PURE__*/ jsx("div", {
|
|
9672
|
+
className: "work-document-table-properties-choice-grid alignment",
|
|
9673
|
+
children: document_table_properties_dialog_sections_alignmentOptions.map((option)=>{
|
|
9674
|
+
const Icon = option.icon;
|
|
9675
|
+
return /*#__PURE__*/ jsxs("label", {
|
|
9676
|
+
children: [
|
|
9677
|
+
/*#__PURE__*/ jsx("input", {
|
|
9678
|
+
type: "radio",
|
|
9679
|
+
name: "table-properties-alignment",
|
|
9680
|
+
value: option.value,
|
|
9681
|
+
checked: draft.table.alignment === option.value,
|
|
9682
|
+
onChange: ()=>setDraft((current)=>({
|
|
9683
|
+
...current,
|
|
9684
|
+
table: {
|
|
9685
|
+
...current.table,
|
|
9686
|
+
alignment: option.value
|
|
9687
|
+
}
|
|
9688
|
+
}))
|
|
9689
|
+
}),
|
|
9690
|
+
/*#__PURE__*/ jsxs("span", {
|
|
9691
|
+
children: [
|
|
9692
|
+
/*#__PURE__*/ jsx(Icon, {
|
|
9693
|
+
size: 16,
|
|
9694
|
+
"aria-hidden": "true"
|
|
9695
|
+
}),
|
|
9696
|
+
option.label
|
|
9697
|
+
]
|
|
9698
|
+
})
|
|
9699
|
+
]
|
|
9700
|
+
}, option.value);
|
|
9701
|
+
})
|
|
9702
|
+
}),
|
|
9703
|
+
/*#__PURE__*/ jsx(NumberRow, {
|
|
9704
|
+
label: "左缩进",
|
|
9705
|
+
ariaLabel: "表格左缩进(厘米)",
|
|
9706
|
+
value: draft.table.indent,
|
|
9707
|
+
unit: "厘米",
|
|
9708
|
+
min: 0,
|
|
9709
|
+
max: 30,
|
|
9710
|
+
step: 0.1,
|
|
9711
|
+
disabled: 'left' !== draft.table.alignment,
|
|
9712
|
+
invalid: Boolean(errors.tableIndent),
|
|
9713
|
+
onValueChange: (indent)=>setDraft((current)=>({
|
|
9714
|
+
...current,
|
|
9715
|
+
table: {
|
|
9716
|
+
...current.table,
|
|
9717
|
+
indent
|
|
9718
|
+
}
|
|
9719
|
+
}))
|
|
9720
|
+
}),
|
|
9721
|
+
errors.tableIndent && /*#__PURE__*/ jsx("p", {
|
|
9722
|
+
role: "alert",
|
|
9723
|
+
children: errors.tableIndent
|
|
9724
|
+
})
|
|
9725
|
+
]
|
|
9726
|
+
})
|
|
9727
|
+
]
|
|
9728
|
+
});
|
|
9729
|
+
}
|
|
9730
|
+
function RowSection({ draft, setDraft, errors, source }) {
|
|
9731
|
+
return /*#__PURE__*/ jsxs(Fragment, {
|
|
9732
|
+
children: [
|
|
9733
|
+
/*#__PURE__*/ jsxs("fieldset", {
|
|
9734
|
+
className: "work-document-table-properties-section",
|
|
9735
|
+
children: [
|
|
9736
|
+
/*#__PURE__*/ jsx("legend", {
|
|
9737
|
+
children: "当前行尺寸"
|
|
9738
|
+
}),
|
|
9739
|
+
/*#__PURE__*/ jsx(OfficeCheckbox, {
|
|
9740
|
+
ariaLabel: "指定行高",
|
|
9741
|
+
checked: draft.row.heightEnabled,
|
|
9742
|
+
onCheckedChange: (heightEnabled)=>setDraft((current)=>({
|
|
9743
|
+
...current,
|
|
9744
|
+
row: {
|
|
9745
|
+
...current.row,
|
|
9746
|
+
heightEnabled
|
|
9747
|
+
}
|
|
9748
|
+
})),
|
|
9749
|
+
children: "指定行高"
|
|
9750
|
+
}),
|
|
9751
|
+
/*#__PURE__*/ jsx(NumberRow, {
|
|
9752
|
+
label: "行高",
|
|
9753
|
+
ariaLabel: "当前行高(厘米)",
|
|
9754
|
+
value: draft.row.height,
|
|
9755
|
+
unit: "厘米",
|
|
9756
|
+
min: 0.5,
|
|
9757
|
+
max: 30,
|
|
9758
|
+
step: 0.1,
|
|
9759
|
+
disabled: !draft.row.heightEnabled,
|
|
9760
|
+
invalid: Boolean(errors.rowHeight),
|
|
9761
|
+
onValueChange: (height)=>setDraft((current)=>({
|
|
9762
|
+
...current,
|
|
9763
|
+
row: {
|
|
9764
|
+
...current.row,
|
|
9765
|
+
height
|
|
9766
|
+
}
|
|
9767
|
+
}))
|
|
9768
|
+
}),
|
|
9769
|
+
/*#__PURE__*/ jsxs("div", {
|
|
9770
|
+
className: "work-document-table-properties-select-row",
|
|
9771
|
+
children: [
|
|
9772
|
+
/*#__PURE__*/ jsx("span", {
|
|
9773
|
+
children: "行高规则"
|
|
9774
|
+
}),
|
|
9775
|
+
/*#__PURE__*/ jsx(OfficeSelect, {
|
|
9776
|
+
ariaLabel: "行高规则",
|
|
9777
|
+
value: draft.row.heightRule,
|
|
9778
|
+
options: rowHeightRuleOptions,
|
|
9779
|
+
disabled: !draft.row.heightEnabled,
|
|
9780
|
+
onValueChange: (heightRule)=>setDraft((current)=>({
|
|
9781
|
+
...current,
|
|
9782
|
+
row: {
|
|
9783
|
+
...current.row,
|
|
9784
|
+
heightRule
|
|
9785
|
+
}
|
|
9786
|
+
}))
|
|
9787
|
+
})
|
|
9788
|
+
]
|
|
7497
9789
|
}),
|
|
7498
|
-
/*#__PURE__*/ jsx(
|
|
7499
|
-
|
|
7500
|
-
|
|
7501
|
-
disabled: !imageSelected,
|
|
7502
|
-
onClick: ()=>updateLayout('topBottom'),
|
|
7503
|
-
children: /*#__PURE__*/ jsx(Rows3, {
|
|
7504
|
-
size: 18
|
|
7505
|
-
})
|
|
9790
|
+
errors.rowHeight && /*#__PURE__*/ jsx("p", {
|
|
9791
|
+
role: "alert",
|
|
9792
|
+
children: errors.rowHeight
|
|
7506
9793
|
})
|
|
7507
9794
|
]
|
|
7508
9795
|
}),
|
|
7509
|
-
/*#__PURE__*/ jsxs(
|
|
7510
|
-
|
|
9796
|
+
/*#__PURE__*/ jsxs("fieldset", {
|
|
9797
|
+
className: "work-document-table-properties-section",
|
|
7511
9798
|
children: [
|
|
7512
|
-
/*#__PURE__*/ jsx(
|
|
7513
|
-
|
|
7514
|
-
active: 'left' === image.alignment,
|
|
7515
|
-
disabled: !imageSelected,
|
|
7516
|
-
onClick: ()=>updateAlignment('left'),
|
|
7517
|
-
children: /*#__PURE__*/ jsx(AlignLeft, {
|
|
7518
|
-
size: 18
|
|
7519
|
-
})
|
|
7520
|
-
}),
|
|
7521
|
-
/*#__PURE__*/ jsx(PictureButton, {
|
|
7522
|
-
label: "居中",
|
|
7523
|
-
active: 'center' === image.alignment,
|
|
7524
|
-
disabled: !imageSelected,
|
|
7525
|
-
onClick: ()=>updateAlignment('center'),
|
|
7526
|
-
children: /*#__PURE__*/ jsx(AlignCenter, {
|
|
7527
|
-
size: 18
|
|
7528
|
-
})
|
|
9799
|
+
/*#__PURE__*/ jsx("legend", {
|
|
9800
|
+
children: "分页"
|
|
7529
9801
|
}),
|
|
7530
|
-
/*#__PURE__*/
|
|
7531
|
-
|
|
7532
|
-
|
|
7533
|
-
|
|
7534
|
-
|
|
7535
|
-
|
|
7536
|
-
|
|
7537
|
-
|
|
9802
|
+
/*#__PURE__*/ jsxs("div", {
|
|
9803
|
+
className: "work-document-table-properties-checkboxes",
|
|
9804
|
+
children: [
|
|
9805
|
+
/*#__PURE__*/ jsx(OfficeCheckbox, {
|
|
9806
|
+
ariaLabel: "允许跨页断行",
|
|
9807
|
+
checked: !draft.row.cantSplit,
|
|
9808
|
+
onCheckedChange: (allowSplit)=>setDraft((current)=>({
|
|
9809
|
+
...current,
|
|
9810
|
+
row: {
|
|
9811
|
+
...current.row,
|
|
9812
|
+
cantSplit: !allowSplit
|
|
9813
|
+
}
|
|
9814
|
+
})),
|
|
9815
|
+
children: "允许跨页断行"
|
|
9816
|
+
}),
|
|
9817
|
+
/*#__PURE__*/ jsx(OfficeCheckbox, {
|
|
9818
|
+
ariaLabel: "在各页顶端重复标题行",
|
|
9819
|
+
checked: draft.row.repeatHeader,
|
|
9820
|
+
disabled: !source.canRepeatHeader,
|
|
9821
|
+
onCheckedChange: (repeatHeader)=>setDraft((current)=>({
|
|
9822
|
+
...current,
|
|
9823
|
+
row: {
|
|
9824
|
+
...current.row,
|
|
9825
|
+
repeatHeader
|
|
9826
|
+
}
|
|
9827
|
+
})),
|
|
9828
|
+
children: "在各页顶端重复标题行"
|
|
9829
|
+
})
|
|
9830
|
+
]
|
|
7538
9831
|
})
|
|
7539
9832
|
]
|
|
9833
|
+
})
|
|
9834
|
+
]
|
|
9835
|
+
});
|
|
9836
|
+
}
|
|
9837
|
+
function ColumnSection({ draft, setDraft, errors }) {
|
|
9838
|
+
return /*#__PURE__*/ jsxs("fieldset", {
|
|
9839
|
+
className: "work-document-table-properties-section",
|
|
9840
|
+
children: [
|
|
9841
|
+
/*#__PURE__*/ jsx("legend", {
|
|
9842
|
+
children: "当前列尺寸"
|
|
7540
9843
|
}),
|
|
7541
|
-
/*#__PURE__*/ jsx(
|
|
7542
|
-
label: "
|
|
7543
|
-
|
|
7544
|
-
|
|
7545
|
-
|
|
7546
|
-
|
|
7547
|
-
|
|
7548
|
-
|
|
7549
|
-
|
|
7550
|
-
|
|
7551
|
-
|
|
9844
|
+
/*#__PURE__*/ jsx(NumberRow, {
|
|
9845
|
+
label: "列宽",
|
|
9846
|
+
ariaLabel: "当前列宽(厘米)",
|
|
9847
|
+
value: draft.column.width,
|
|
9848
|
+
unit: "厘米",
|
|
9849
|
+
min: 0.5,
|
|
9850
|
+
max: 30,
|
|
9851
|
+
step: 0.1,
|
|
9852
|
+
invalid: Boolean(errors.columnWidth),
|
|
9853
|
+
onValueChange: (width)=>setDraft((current)=>({
|
|
9854
|
+
...current,
|
|
9855
|
+
column: {
|
|
9856
|
+
width
|
|
9857
|
+
}
|
|
9858
|
+
}))
|
|
7552
9859
|
}),
|
|
7553
|
-
/*#__PURE__*/
|
|
7554
|
-
|
|
9860
|
+
errors.columnWidth && /*#__PURE__*/ jsx("p", {
|
|
9861
|
+
role: "alert",
|
|
9862
|
+
children: errors.columnWidth
|
|
9863
|
+
})
|
|
9864
|
+
]
|
|
9865
|
+
});
|
|
9866
|
+
}
|
|
9867
|
+
function CellSection({ draft, setDraft, errors }) {
|
|
9868
|
+
return /*#__PURE__*/ jsxs(Fragment, {
|
|
9869
|
+
children: [
|
|
9870
|
+
/*#__PURE__*/ jsxs("fieldset", {
|
|
9871
|
+
className: "work-document-table-properties-section",
|
|
7555
9872
|
children: [
|
|
7556
|
-
/*#__PURE__*/ jsx(
|
|
7557
|
-
|
|
7558
|
-
disabled: !imageSelected,
|
|
7559
|
-
onClick: ()=>{
|
|
7560
|
-
const imagePosition = selectedDocumentImagePosition(editor);
|
|
7561
|
-
officeDialog.prompt({
|
|
7562
|
-
title: '图片说明',
|
|
7563
|
-
description: '简要描述图片中的关键信息,留空表示装饰性图片。',
|
|
7564
|
-
fieldLabel: '图片替代文字',
|
|
7565
|
-
initialValue: documentImageAlternativeText(editor),
|
|
7566
|
-
multiline: true,
|
|
7567
|
-
confirmLabel: '保存'
|
|
7568
|
-
}).then((value)=>{
|
|
7569
|
-
if (!restoreDocumentImageSelection(editor, imagePosition)) return;
|
|
7570
|
-
if (null !== value) editor.commands.setDocumentImageAlternativeText(value, {
|
|
7571
|
-
restoreFocus: false
|
|
7572
|
-
});
|
|
7573
|
-
});
|
|
7574
|
-
},
|
|
7575
|
-
children: /*#__PURE__*/ jsx(ScanText, {
|
|
7576
|
-
size: 18
|
|
7577
|
-
})
|
|
9873
|
+
/*#__PURE__*/ jsx("legend", {
|
|
9874
|
+
children: "垂直对齐"
|
|
7578
9875
|
}),
|
|
7579
|
-
/*#__PURE__*/ jsx(
|
|
7580
|
-
|
|
7581
|
-
|
|
7582
|
-
|
|
7583
|
-
|
|
7584
|
-
|
|
9876
|
+
/*#__PURE__*/ jsx("div", {
|
|
9877
|
+
className: "work-document-table-properties-choice-grid alignment",
|
|
9878
|
+
children: verticalAlignmentOptions.map((option)=>{
|
|
9879
|
+
const Icon = option.icon;
|
|
9880
|
+
return /*#__PURE__*/ jsxs("label", {
|
|
9881
|
+
children: [
|
|
9882
|
+
/*#__PURE__*/ jsx("input", {
|
|
9883
|
+
type: "radio",
|
|
9884
|
+
name: "table-properties-vertical-alignment",
|
|
9885
|
+
value: option.value,
|
|
9886
|
+
checked: draft.cell.verticalAlign === option.value,
|
|
9887
|
+
onChange: ()=>setDraft((current)=>({
|
|
9888
|
+
...current,
|
|
9889
|
+
cell: {
|
|
9890
|
+
...current.cell,
|
|
9891
|
+
verticalAlign: option.value
|
|
9892
|
+
}
|
|
9893
|
+
}))
|
|
9894
|
+
}),
|
|
9895
|
+
/*#__PURE__*/ jsxs("span", {
|
|
9896
|
+
children: [
|
|
9897
|
+
/*#__PURE__*/ jsx(Icon, {
|
|
9898
|
+
size: 16,
|
|
9899
|
+
"aria-hidden": "true"
|
|
9900
|
+
}),
|
|
9901
|
+
option.label
|
|
9902
|
+
]
|
|
9903
|
+
})
|
|
9904
|
+
]
|
|
9905
|
+
}, option.value);
|
|
7585
9906
|
})
|
|
7586
9907
|
})
|
|
7587
9908
|
]
|
|
7588
9909
|
}),
|
|
7589
|
-
|
|
9910
|
+
/*#__PURE__*/ jsxs("fieldset", {
|
|
9911
|
+
className: "work-document-table-properties-section",
|
|
9912
|
+
children: [
|
|
9913
|
+
/*#__PURE__*/ jsx("legend", {
|
|
9914
|
+
children: "单元格边距"
|
|
9915
|
+
}),
|
|
9916
|
+
/*#__PURE__*/ jsx(OfficeCheckbox, {
|
|
9917
|
+
ariaLabel: "使用表格默认边距",
|
|
9918
|
+
checked: draft.cell.useTableMargins,
|
|
9919
|
+
onCheckedChange: (useTableMargins)=>setDraft((current)=>({
|
|
9920
|
+
...current,
|
|
9921
|
+
cell: {
|
|
9922
|
+
...current.cell,
|
|
9923
|
+
useTableMargins
|
|
9924
|
+
}
|
|
9925
|
+
})),
|
|
9926
|
+
children: "使用表格默认边距"
|
|
9927
|
+
}),
|
|
9928
|
+
/*#__PURE__*/ jsx("div", {
|
|
9929
|
+
className: "work-document-table-properties-margin-grid",
|
|
9930
|
+
children: document_table_properties_dialog_sections_marginFields.map(({ side, label, ariaLabel })=>/*#__PURE__*/ jsxs("div", {
|
|
9931
|
+
className: "work-document-table-properties-margin",
|
|
9932
|
+
children: [
|
|
9933
|
+
/*#__PURE__*/ jsx("span", {
|
|
9934
|
+
children: label
|
|
9935
|
+
}),
|
|
9936
|
+
/*#__PURE__*/ jsx(OfficeNumberField, {
|
|
9937
|
+
ariaLabel: ariaLabel,
|
|
9938
|
+
value: draft.cell.margins[side],
|
|
9939
|
+
min: 0,
|
|
9940
|
+
max: 5,
|
|
9941
|
+
step: 0.05,
|
|
9942
|
+
disabled: draft.cell.useTableMargins,
|
|
9943
|
+
validationInvalid: Boolean(errors.cellMargins[side]),
|
|
9944
|
+
onValueChange: (value)=>setDraft((current)=>({
|
|
9945
|
+
...current,
|
|
9946
|
+
cell: {
|
|
9947
|
+
...current.cell,
|
|
9948
|
+
margins: {
|
|
9949
|
+
...current.cell.margins,
|
|
9950
|
+
[side]: value
|
|
9951
|
+
}
|
|
9952
|
+
}
|
|
9953
|
+
}))
|
|
9954
|
+
}),
|
|
9955
|
+
/*#__PURE__*/ jsx("small", {
|
|
9956
|
+
children: "厘米"
|
|
9957
|
+
}),
|
|
9958
|
+
errors.cellMargins[side] && /*#__PURE__*/ jsx("p", {
|
|
9959
|
+
role: "alert",
|
|
9960
|
+
children: errors.cellMargins[side]
|
|
9961
|
+
})
|
|
9962
|
+
]
|
|
9963
|
+
}, side))
|
|
9964
|
+
})
|
|
9965
|
+
]
|
|
9966
|
+
})
|
|
7590
9967
|
]
|
|
7591
9968
|
});
|
|
7592
9969
|
}
|
|
7593
|
-
function
|
|
7594
|
-
|
|
7595
|
-
|
|
7596
|
-
|
|
7597
|
-
|
|
7598
|
-
|
|
7599
|
-
|
|
7600
|
-
|
|
7601
|
-
|
|
7602
|
-
|
|
7603
|
-
|
|
7604
|
-
|
|
7605
|
-
|
|
7606
|
-
|
|
7607
|
-
|
|
7608
|
-
|
|
7609
|
-
|
|
9970
|
+
function NumberRow({ label, ariaLabel, value, unit, min, max, step, disabled = false, invalid = false, onValueChange }) {
|
|
9971
|
+
return /*#__PURE__*/ jsxs("div", {
|
|
9972
|
+
className: "work-document-table-properties-number-row",
|
|
9973
|
+
children: [
|
|
9974
|
+
/*#__PURE__*/ jsx("span", {
|
|
9975
|
+
children: label
|
|
9976
|
+
}),
|
|
9977
|
+
/*#__PURE__*/ jsx(OfficeNumberField, {
|
|
9978
|
+
ariaLabel: ariaLabel,
|
|
9979
|
+
value: value,
|
|
9980
|
+
min: min,
|
|
9981
|
+
max: max,
|
|
9982
|
+
step: step,
|
|
9983
|
+
disabled: disabled,
|
|
9984
|
+
validationInvalid: invalid,
|
|
9985
|
+
onValueChange: onValueChange
|
|
9986
|
+
}),
|
|
9987
|
+
/*#__PURE__*/ jsx("small", {
|
|
9988
|
+
children: unit
|
|
9989
|
+
})
|
|
9990
|
+
]
|
|
9991
|
+
});
|
|
7610
9992
|
}
|
|
7611
|
-
function
|
|
7612
|
-
|
|
7613
|
-
|
|
7614
|
-
|
|
7615
|
-
|
|
7616
|
-
|
|
7617
|
-
|
|
7618
|
-
|
|
9993
|
+
function DocumentTablePropertiesControl({ editor, renderedTableWidth, renderedRowHeight, renderedColumnWidth, renderedColumnWidths }) {
|
|
9994
|
+
const [source, setSource] = useState(null);
|
|
9995
|
+
const triggerRef = useRef(null);
|
|
9996
|
+
const openDialog = (event)=>{
|
|
9997
|
+
const sizing = documentTableSizing(editor.state);
|
|
9998
|
+
const cellFormat = documentTableCellFormat(editor.state);
|
|
9999
|
+
if (!sizing || !cellFormat) return;
|
|
10000
|
+
triggerRef.current = event.currentTarget;
|
|
10001
|
+
setSource({
|
|
10002
|
+
sizing,
|
|
10003
|
+
cellFormat,
|
|
10004
|
+
rowOptions: documentTableRowOptions(editor),
|
|
10005
|
+
canRepeatHeader: canSetDocumentTableRowRepeatHeader(editor),
|
|
10006
|
+
renderedTableWidth,
|
|
10007
|
+
renderedRowHeight,
|
|
10008
|
+
renderedColumnWidth,
|
|
10009
|
+
renderedColumnWidths
|
|
10010
|
+
});
|
|
10011
|
+
};
|
|
10012
|
+
return /*#__PURE__*/ jsxs(Fragment, {
|
|
10013
|
+
children: [
|
|
10014
|
+
/*#__PURE__*/ jsx(WorkOfficeRibbonButton, {
|
|
10015
|
+
label: "表格属性",
|
|
10016
|
+
visibleLabel: "表格属性",
|
|
10017
|
+
disabled: !documentTableSizing(editor.state),
|
|
10018
|
+
onClick: openDialog,
|
|
10019
|
+
children: /*#__PURE__*/ jsx(TableProperties, {
|
|
10020
|
+
size: 18
|
|
10021
|
+
})
|
|
10022
|
+
}),
|
|
10023
|
+
source && /*#__PURE__*/ jsx(DocumentTablePropertiesDialog, {
|
|
10024
|
+
editor: editor,
|
|
10025
|
+
source: source,
|
|
10026
|
+
restoreFocusTarget: ()=>triggerRef.current,
|
|
10027
|
+
onClose: ()=>setSource(null)
|
|
10028
|
+
})
|
|
10029
|
+
]
|
|
7619
10030
|
});
|
|
7620
10031
|
}
|
|
7621
|
-
function
|
|
7622
|
-
|
|
7623
|
-
|
|
7624
|
-
|
|
7625
|
-
|
|
10032
|
+
function DocumentTablePropertiesDialog({ editor, source, restoreFocusTarget, onClose }) {
|
|
10033
|
+
const [initial] = useState(()=>createDocumentTablePropertiesDraft(source));
|
|
10034
|
+
const [draft, setDraft] = useState(initial);
|
|
10035
|
+
const [activeTab, setActiveTab] = useState('table');
|
|
10036
|
+
const formId = useId();
|
|
10037
|
+
const idBase = `document-table-properties-${useId().replaceAll(':', '')}`;
|
|
10038
|
+
const errors = documentTablePropertiesErrors(draft);
|
|
10039
|
+
const invalid = hasDocumentTablePropertiesErrors(errors);
|
|
10040
|
+
const submit = (event)=>{
|
|
10041
|
+
event?.preventDefault();
|
|
10042
|
+
if (invalid) return;
|
|
10043
|
+
const changes = documentTablePropertyChanges(initial, draft, source);
|
|
10044
|
+
if (!changes || editor.commands.setDocumentTablePropertyChanges(changes)) onClose();
|
|
10045
|
+
};
|
|
10046
|
+
return /*#__PURE__*/ jsxs(Dialog, {
|
|
10047
|
+
title: "表格属性",
|
|
10048
|
+
description: "设置当前表格、行、列和单元格。",
|
|
10049
|
+
className: "work-document-table-properties-dialog",
|
|
10050
|
+
restoreFocusTarget: restoreFocusTarget,
|
|
10051
|
+
onClose: onClose,
|
|
10052
|
+
footer: /*#__PURE__*/ jsxs(Fragment, {
|
|
10053
|
+
children: [
|
|
10054
|
+
/*#__PURE__*/ jsx(button_Button, {
|
|
10055
|
+
tone: "quiet",
|
|
10056
|
+
onClick: onClose,
|
|
10057
|
+
children: "取消"
|
|
10058
|
+
}),
|
|
10059
|
+
/*#__PURE__*/ jsx(button_Button, {
|
|
10060
|
+
tone: "primary",
|
|
10061
|
+
type: "submit",
|
|
10062
|
+
form: formId,
|
|
10063
|
+
disabled: invalid,
|
|
10064
|
+
children: "确定"
|
|
10065
|
+
})
|
|
10066
|
+
]
|
|
10067
|
+
}),
|
|
10068
|
+
children: [
|
|
10069
|
+
/*#__PURE__*/ jsx(DocumentTablePropertiesTabs, {
|
|
10070
|
+
activeTab: activeTab,
|
|
10071
|
+
idBase: idBase,
|
|
10072
|
+
onTabChange: setActiveTab
|
|
10073
|
+
}),
|
|
10074
|
+
/*#__PURE__*/ jsx("form", {
|
|
10075
|
+
id: formId,
|
|
10076
|
+
onSubmit: submit,
|
|
10077
|
+
children: /*#__PURE__*/ jsx(DocumentTablePropertiesPanel, {
|
|
10078
|
+
activeTab: activeTab,
|
|
10079
|
+
idBase: idBase,
|
|
10080
|
+
draft: draft,
|
|
10081
|
+
setDraft: setDraft,
|
|
10082
|
+
errors: errors,
|
|
10083
|
+
source: source
|
|
10084
|
+
})
|
|
10085
|
+
})
|
|
10086
|
+
]
|
|
7626
10087
|
});
|
|
7627
10088
|
}
|
|
7628
10089
|
const borderOptions = [
|
|
@@ -7655,12 +10116,48 @@ const borderOptions = [
|
|
|
7655
10116
|
label: '双线',
|
|
7656
10117
|
style: 'double',
|
|
7657
10118
|
width: 2
|
|
10119
|
+
}
|
|
10120
|
+
];
|
|
10121
|
+
const borderTargetOptions = [
|
|
10122
|
+
{
|
|
10123
|
+
value: 'clear',
|
|
10124
|
+
label: '无框线'
|
|
10125
|
+
},
|
|
10126
|
+
{
|
|
10127
|
+
value: 'all',
|
|
10128
|
+
label: '所有框线'
|
|
10129
|
+
},
|
|
10130
|
+
{
|
|
10131
|
+
value: 'outside',
|
|
10132
|
+
label: '外侧框线'
|
|
10133
|
+
},
|
|
10134
|
+
{
|
|
10135
|
+
value: 'inside',
|
|
10136
|
+
label: '内部框线'
|
|
10137
|
+
},
|
|
10138
|
+
{
|
|
10139
|
+
value: 'top',
|
|
10140
|
+
label: '上框线'
|
|
7658
10141
|
},
|
|
7659
10142
|
{
|
|
7660
|
-
value: '
|
|
7661
|
-
label: '
|
|
7662
|
-
|
|
7663
|
-
|
|
10143
|
+
value: 'bottom',
|
|
10144
|
+
label: '下框线'
|
|
10145
|
+
},
|
|
10146
|
+
{
|
|
10147
|
+
value: 'left',
|
|
10148
|
+
label: '左框线'
|
|
10149
|
+
},
|
|
10150
|
+
{
|
|
10151
|
+
value: 'right',
|
|
10152
|
+
label: '右框线'
|
|
10153
|
+
},
|
|
10154
|
+
{
|
|
10155
|
+
value: 'insideHorizontal',
|
|
10156
|
+
label: '内部横框线'
|
|
10157
|
+
},
|
|
10158
|
+
{
|
|
10159
|
+
value: 'insideVertical',
|
|
10160
|
+
label: '内部竖框线'
|
|
7664
10161
|
}
|
|
7665
10162
|
];
|
|
7666
10163
|
const tableLayoutOptions = [
|
|
@@ -7677,11 +10174,22 @@ const tableLayoutOptions = [
|
|
|
7677
10174
|
label: '固定列宽'
|
|
7678
10175
|
}
|
|
7679
10176
|
];
|
|
7680
|
-
const
|
|
10177
|
+
const currentTableLayoutOption = {
|
|
10178
|
+
value: 'current',
|
|
10179
|
+
label: '当前宽度',
|
|
10180
|
+
disabled: true
|
|
10181
|
+
};
|
|
10182
|
+
const document_table_ribbon_PIXELS_PER_CENTIMETER = 96 / 2.54;
|
|
7681
10183
|
function DocumentTableDesignRibbon({ editor }) {
|
|
7682
10184
|
const format = documentTableCellFormat(editor.state) ?? DEFAULT_DOCUMENT_TABLE_CELL_FORMAT;
|
|
7683
|
-
const
|
|
7684
|
-
|
|
10185
|
+
const [borderPen, setBorderPen] = useState(()=>({
|
|
10186
|
+
color: format.borderColor,
|
|
10187
|
+
style: 'none' === format.borderStyle ? 'solid' : format.borderStyle,
|
|
10188
|
+
width: 'none' === format.borderStyle || 0 === format.borderWidth ? 1 : format.borderWidth
|
|
10189
|
+
}));
|
|
10190
|
+
const [borderTarget, setBorderTarget] = useState('all');
|
|
10191
|
+
const borderValue = borderOptionValue(borderPen.style, borderPen.width);
|
|
10192
|
+
const currentBorderOptions = borderOptionsForFormat(borderPen.style, borderPen.width);
|
|
7685
10193
|
return /*#__PURE__*/ jsxs(Fragment, {
|
|
7686
10194
|
children: [
|
|
7687
10195
|
/*#__PURE__*/ jsx(document_table_ribbon_RibbonGroup, {
|
|
@@ -7722,10 +10230,11 @@ function DocumentTableDesignRibbon({ editor }) {
|
|
|
7722
10230
|
ariaLabel: "边框颜色",
|
|
7723
10231
|
className: "work-document-table-color-picker",
|
|
7724
10232
|
compact: true,
|
|
7725
|
-
value:
|
|
7726
|
-
onValueChange: (borderColor)=>
|
|
7727
|
-
|
|
7728
|
-
|
|
10233
|
+
value: borderPen.color,
|
|
10234
|
+
onValueChange: (borderColor)=>setBorderPen((current)=>({
|
|
10235
|
+
...current,
|
|
10236
|
+
color: borderColor
|
|
10237
|
+
}))
|
|
7729
10238
|
}),
|
|
7730
10239
|
/*#__PURE__*/ jsx(OfficeSelect, {
|
|
7731
10240
|
ariaLabel: "边框样式",
|
|
@@ -7735,10 +10244,26 @@ function DocumentTableDesignRibbon({ editor }) {
|
|
|
7735
10244
|
onValueChange: (value)=>{
|
|
7736
10245
|
const option = currentBorderOptions.find((candidate)=>candidate.value === value);
|
|
7737
10246
|
if (!option) return;
|
|
7738
|
-
|
|
7739
|
-
|
|
7740
|
-
|
|
7741
|
-
|
|
10247
|
+
setBorderPen((current)=>({
|
|
10248
|
+
...current,
|
|
10249
|
+
style: option.style,
|
|
10250
|
+
width: option.width
|
|
10251
|
+
}));
|
|
10252
|
+
}
|
|
10253
|
+
}),
|
|
10254
|
+
/*#__PURE__*/ jsx(OfficeSelect, {
|
|
10255
|
+
ariaLabel: "应用边框",
|
|
10256
|
+
className: "work-document-table-border-target-select",
|
|
10257
|
+
value: borderTarget,
|
|
10258
|
+
options: borderTargetOptions,
|
|
10259
|
+
onValueChange: (value)=>{
|
|
10260
|
+
setBorderTarget(value);
|
|
10261
|
+
const clear = 'clear' === value;
|
|
10262
|
+
editor.chain().focus().setDocumentTableBorders(clear ? 'all' : value, clear ? {
|
|
10263
|
+
color: borderPen.color,
|
|
10264
|
+
style: 'none',
|
|
10265
|
+
width: 0
|
|
10266
|
+
} : borderPen).run();
|
|
7742
10267
|
}
|
|
7743
10268
|
})
|
|
7744
10269
|
]
|
|
@@ -7847,6 +10372,21 @@ function DocumentTableLayoutRibbon({ editor }) {
|
|
|
7847
10372
|
editor: editor,
|
|
7848
10373
|
sizing: sizing
|
|
7849
10374
|
}),
|
|
10375
|
+
/*#__PURE__*/ jsxs(document_table_ribbon_RibbonGroup, {
|
|
10376
|
+
label: "表格属性",
|
|
10377
|
+
children: [
|
|
10378
|
+
/*#__PURE__*/ jsx(DocumentTablePropertiesControl, {
|
|
10379
|
+
editor: editor,
|
|
10380
|
+
renderedTableWidth: measuredTableWidth(editor),
|
|
10381
|
+
renderedRowHeight: measuredCurrentTableDimension(editor, 'rows') ?? void 0,
|
|
10382
|
+
renderedColumnWidth: measuredCurrentTableDimension(editor, 'columns') ?? void 0,
|
|
10383
|
+
renderedColumnWidths: measuredTableColumnWidths(editor)
|
|
10384
|
+
}),
|
|
10385
|
+
/*#__PURE__*/ jsx(DocumentTableMarginsPopover, {
|
|
10386
|
+
editor: editor
|
|
10387
|
+
})
|
|
10388
|
+
]
|
|
10389
|
+
}),
|
|
7850
10390
|
/*#__PURE__*/ jsxs(document_table_ribbon_RibbonGroup, {
|
|
7851
10391
|
label: "单元格对齐",
|
|
7852
10392
|
children: [
|
|
@@ -7955,6 +10495,13 @@ function DocumentTableLayoutRibbon({ editor }) {
|
|
|
7955
10495
|
function DocumentTableSizeRibbonGroup({ editor, sizing }) {
|
|
7956
10496
|
const measuredRowSelection = measuredTableSelectionSize(editor, 'rows');
|
|
7957
10497
|
const measuredColumnSelection = measuredTableSelectionSize(editor, 'columns');
|
|
10498
|
+
const measuredColumnWidth = measuredCurrentTableDimension(editor, 'columns');
|
|
10499
|
+
const displayedColumnWidth = sizing?.layoutAlgorithm === 'autofit' ? measuredColumnWidth ?? sizing.columnWidth : sizing?.columnWidth ?? measuredColumnWidth;
|
|
10500
|
+
const tableLayoutValue = sizing?.layoutAlgorithm === 'autofit' && 'fixed' === sizing.layoutMode ? 'current' : sizing?.layoutMode ?? 'window';
|
|
10501
|
+
const displayedTableLayoutOptions = 'current' === tableLayoutValue ? [
|
|
10502
|
+
currentTableLayoutOption,
|
|
10503
|
+
...tableLayoutOptions
|
|
10504
|
+
] : tableLayoutOptions;
|
|
7958
10505
|
const canDistributeRows = editor.can().chain().focus().distributeDocumentTableRows(measuredRowSelection).run();
|
|
7959
10506
|
const canDistributeColumns = editor.can().chain().focus().distributeDocumentTableColumns(measuredColumnSelection).run();
|
|
7960
10507
|
return /*#__PURE__*/ jsxs(document_table_ribbon_RibbonGroup, {
|
|
@@ -7972,7 +10519,7 @@ function DocumentTableSizeRibbonGroup({ editor, sizing }) {
|
|
|
7972
10519
|
/*#__PURE__*/ jsx(TableDimensionField, {
|
|
7973
10520
|
label: "宽度",
|
|
7974
10521
|
ariaLabel: "列宽(厘米)",
|
|
7975
|
-
value:
|
|
10522
|
+
value: displayedColumnWidth,
|
|
7976
10523
|
onValueChange: (width)=>editor.chain().focus().setDocumentTableColumnWidth(width, measuredTableColumnWidths(editor)).run()
|
|
7977
10524
|
})
|
|
7978
10525
|
]
|
|
@@ -7980,9 +10527,12 @@ function DocumentTableSizeRibbonGroup({ editor, sizing }) {
|
|
|
7980
10527
|
/*#__PURE__*/ jsx(OfficeSelect, {
|
|
7981
10528
|
ariaLabel: "表格自动调整",
|
|
7982
10529
|
className: "work-document-table-layout-select",
|
|
7983
|
-
value:
|
|
7984
|
-
options:
|
|
7985
|
-
onValueChange: (layoutMode)=>
|
|
10530
|
+
value: tableLayoutValue,
|
|
10531
|
+
options: displayedTableLayoutOptions,
|
|
10532
|
+
onValueChange: (layoutMode)=>{
|
|
10533
|
+
if ('current' === layoutMode) return;
|
|
10534
|
+
editor.chain().focus().setDocumentTableLayoutMode(layoutMode, 'fixed' === layoutMode ? measuredTableWidth(editor) : void 0).run();
|
|
10535
|
+
}
|
|
7986
10536
|
}),
|
|
7987
10537
|
/*#__PURE__*/ jsx(RibbonButton, {
|
|
7988
10538
|
label: "平均分布行",
|
|
@@ -8006,7 +10556,7 @@ function DocumentTableSizeRibbonGroup({ editor, sizing }) {
|
|
|
8006
10556
|
});
|
|
8007
10557
|
}
|
|
8008
10558
|
function TableDimensionField({ label, ariaLabel, value, onValueChange }) {
|
|
8009
|
-
const formattedValue = null === value ? '' : document_table_ribbon_formatCentimeters(value /
|
|
10559
|
+
const formattedValue = null === value ? '' : document_table_ribbon_formatCentimeters(value / document_table_ribbon_PIXELS_PER_CENTIMETER);
|
|
8010
10560
|
const { cancelDraft, dirty, draft, replaceDraft, setDraft, syncDraft } = useOfficeDraft(()=>formattedValue);
|
|
8011
10561
|
useEffect(()=>syncDraft(formattedValue), [
|
|
8012
10562
|
formattedValue,
|
|
@@ -8032,7 +10582,7 @@ function TableDimensionField({ label, ariaLabel, value, onValueChange }) {
|
|
|
8032
10582
|
const centimeters = Number(nextValue);
|
|
8033
10583
|
if (!Number.isFinite(centimeters) || centimeters < 0.5 || centimeters > 30) return void cancelDraft();
|
|
8034
10584
|
const normalizedDraft = document_table_ribbon_formatCentimeters(centimeters);
|
|
8035
|
-
const committed = onValueChange(Math.round(centimeters *
|
|
10585
|
+
const committed = onValueChange(Math.round(centimeters * document_table_ribbon_PIXELS_PER_CENTIMETER * 100) / 100);
|
|
8036
10586
|
if (committed) replaceDraft(normalizedDraft);
|
|
8037
10587
|
else cancelDraft();
|
|
8038
10588
|
}
|
|
@@ -8334,13 +10884,14 @@ function DocumentToolbar({ editor, layoutOpen, layoutFonts = [], navigationOpen,
|
|
|
8334
10884
|
if (event.defaultPrevented || event.repeat || event.altKey || isOfficeShortcutBlocked(event.target) || !(event.metaKey || event.ctrlKey)) return;
|
|
8335
10885
|
const key = event.key.toLowerCase();
|
|
8336
10886
|
const insideEditor = event.target instanceof Node && Boolean(editorDom?.contains(event.target));
|
|
8337
|
-
|
|
10887
|
+
const documentHistoryTarget = insideEditor || !isDocumentNativeTextUndoTarget(event.target);
|
|
10888
|
+
if (documentHistoryTarget && 'z' === key) {
|
|
8338
10889
|
event.preventDefault();
|
|
8339
10890
|
const command = event.shiftKey ? editor.chain().focus().redo() : editor.chain().focus().undo();
|
|
8340
10891
|
command.run();
|
|
8341
10892
|
return;
|
|
8342
10893
|
}
|
|
8343
|
-
if (
|
|
10894
|
+
if (documentHistoryTarget && 'y' === key && !event.shiftKey) {
|
|
8344
10895
|
event.preventDefault();
|
|
8345
10896
|
editor.chain().focus().redo().run();
|
|
8346
10897
|
return;
|
|
@@ -8822,6 +11373,24 @@ function DocumentToolbar({ editor, layoutOpen, layoutFonts = [], navigationOpen,
|
|
|
8822
11373
|
]
|
|
8823
11374
|
});
|
|
8824
11375
|
}
|
|
11376
|
+
function isDocumentNativeTextUndoTarget(target) {
|
|
11377
|
+
if (!(target instanceof HTMLElement)) return false;
|
|
11378
|
+
return target instanceof HTMLInputElement && documentNativeUndoInputTypes.has(target.type) || target instanceof HTMLTextAreaElement || target instanceof HTMLSelectElement || target.isContentEditable || Boolean(target.closest('[contenteditable="true"]'));
|
|
11379
|
+
}
|
|
11380
|
+
const documentNativeUndoInputTypes = new Set([
|
|
11381
|
+
'date',
|
|
11382
|
+
'datetime-local',
|
|
11383
|
+
'email',
|
|
11384
|
+
'month',
|
|
11385
|
+
'number',
|
|
11386
|
+
'password',
|
|
11387
|
+
'search',
|
|
11388
|
+
'tel',
|
|
11389
|
+
'text',
|
|
11390
|
+
'time',
|
|
11391
|
+
'url',
|
|
11392
|
+
'week'
|
|
11393
|
+
]);
|
|
8825
11394
|
function document_toolbar_ToolbarButton({ label, title, shortcut, ariaKeyShortcuts, active = false, disabled = false, displayLabel = false, onClick, children }) {
|
|
8826
11395
|
return /*#__PURE__*/ jsx(WorkOfficeRibbonButton, {
|
|
8827
11396
|
label: label,
|
|
@@ -9219,7 +11788,9 @@ function useDocumentPagination({ editor, documentRevision, enabled, layoutKey, p
|
|
|
9219
11788
|
delete editorDom.dataset.paginationLaidOutBlocks;
|
|
9220
11789
|
delete editorDom.dataset.paginationPages;
|
|
9221
11790
|
delete editorDom.dataset.paginationReusedBlocks;
|
|
11791
|
+
delete editorDom.dataset.paginationReusedPageChrome;
|
|
9222
11792
|
delete editorDom.dataset.paginationReusedPages;
|
|
11793
|
+
delete editorDom.dataset.paginationDerivedPageChrome;
|
|
9223
11794
|
delete editorDom.dataset.paginationShapedParagraphs;
|
|
9224
11795
|
delete editorDom.dataset.paginationShapedRuns;
|
|
9225
11796
|
delete editorDom.dataset.paginationTextCandidates;
|
|
@@ -9275,6 +11846,8 @@ function useDocumentPagination({ editor, documentRevision, enabled, layoutKey, p
|
|
|
9275
11846
|
activeRequest.current = controller;
|
|
9276
11847
|
editor.commands.clearDocumentPagination(nextRevision);
|
|
9277
11848
|
editorDom.dataset.paginationState = 'measuring';
|
|
11849
|
+
editorDom.dataset.paginationReusedPageChrome = '0';
|
|
11850
|
+
editorDom.dataset.paginationDerivedPageChrome = '0';
|
|
9278
11851
|
delete editorDom.dataset.paginationError;
|
|
9279
11852
|
const measurementStart = dirtyMeasurementFrom.current;
|
|
9280
11853
|
dirtyMeasurementFrom.current = 1 / 0;
|
|
@@ -9349,7 +11922,10 @@ function useDocumentPagination({ editor, documentRevision, enabled, layoutKey, p
|
|
|
9349
11922
|
block.block.id,
|
|
9350
11923
|
block
|
|
9351
11924
|
]));
|
|
9352
|
-
const
|
|
11925
|
+
const pageDescriptorDerivation = deriveDocumentPaginationPageDescriptors(layout, snapshot.blocks, editor.state.doc, previousPagination?.pages, layoutPlan.reusedPageCount);
|
|
11926
|
+
const pages = pageDescriptorDerivation.pages;
|
|
11927
|
+
editorDom.dataset.paginationReusedPageChrome = String(pageDescriptorDerivation.reusedPageCount);
|
|
11928
|
+
editorDom.dataset.paginationDerivedPageChrome = String(pageDescriptorDerivation.derivedPageCount);
|
|
9353
11929
|
const pageByIndex = new Map(pages.map((descriptor)=>[
|
|
9354
11930
|
descriptor.pageIndex,
|
|
9355
11931
|
descriptor
|
|
@@ -9467,13 +12043,20 @@ function useDocumentPagination({ editor, documentRevision, enabled, layoutKey, p
|
|
|
9467
12043
|
selectionVersion
|
|
9468
12044
|
]);
|
|
9469
12045
|
}
|
|
9470
|
-
function
|
|
12046
|
+
function deriveDocumentPaginationPageDescriptors(layout, blocks, documentNode, previousPages = [], requestedReusedPageCount = 0) {
|
|
9471
12047
|
const blockById = new Map(blocks.map((candidate)=>[
|
|
9472
12048
|
candidate.block.id,
|
|
9473
12049
|
candidate
|
|
9474
12050
|
]));
|
|
12051
|
+
const previousPageByIndex = new Map(previousPages.map((page)=>[
|
|
12052
|
+
page.pageIndex,
|
|
12053
|
+
page
|
|
12054
|
+
]));
|
|
12055
|
+
const reusablePhysicalPageCount = Number.isSafeInteger(requestedReusedPageCount) ? Math.max(0, Math.min(requestedReusedPageCount, layout.pages.length)) : 0;
|
|
9475
12056
|
const sectionPages = new Map();
|
|
9476
12057
|
const descriptors = [];
|
|
12058
|
+
let reuseOpen = reusablePhysicalPageCount > 0;
|
|
12059
|
+
let reusedPageCount = 0;
|
|
9477
12060
|
for (const page of layout.pages){
|
|
9478
12061
|
const pageBlocks = Array.from(new Map(page.placements.flatMap((placement)=>{
|
|
9479
12062
|
const block = blockById.get(placement.blockId);
|
|
@@ -9501,6 +12084,13 @@ function documentPaginationPageDescriptors(layout, blocks, documentNode) {
|
|
|
9501
12084
|
const previousPageNumber = descriptors.at(-1)?.pageNumber ?? 0;
|
|
9502
12085
|
const firstSectionPage = 1 === sectionPage;
|
|
9503
12086
|
const pageNumber = firstSectionPage && void 0 !== section.layout.pageNumberStart ? section.layout.pageNumberStart : Math.max(1, previousPageNumber + 1);
|
|
12087
|
+
const previousPage = previousPageByIndex.get(page.index);
|
|
12088
|
+
if (reuseOpen && page.index < reusablePhysicalPageCount && previousPage && reusableDocumentPageDescriptor(previousPage, physicalPage, pageNumber, sectionPage, section.id, section.index, section.layout)) {
|
|
12089
|
+
descriptors.push(previousPage);
|
|
12090
|
+
reusedPageCount += 1;
|
|
12091
|
+
continue;
|
|
12092
|
+
}
|
|
12093
|
+
if (page.index < reusablePhysicalPageCount) reuseOpen = false;
|
|
9504
12094
|
descriptors.push({
|
|
9505
12095
|
pageIndex: page.index,
|
|
9506
12096
|
physicalPage,
|
|
@@ -9514,7 +12104,14 @@ function documentPaginationPageDescriptors(layout, blocks, documentNode) {
|
|
|
9514
12104
|
pageChrome: resolveDocumentPageChrome(section.layout, sectionPage, physicalPage)
|
|
9515
12105
|
});
|
|
9516
12106
|
}
|
|
9517
|
-
return
|
|
12107
|
+
return {
|
|
12108
|
+
pages: descriptors,
|
|
12109
|
+
reusedPageCount,
|
|
12110
|
+
derivedPageCount: descriptors.length - reusedPageCount
|
|
12111
|
+
};
|
|
12112
|
+
}
|
|
12113
|
+
function reusableDocumentPageDescriptor(candidate, physicalPage, pageNumber, sectionPage, sectionId, sectionIndex, layout) {
|
|
12114
|
+
return candidate.pageIndex === physicalPage - 1 && candidate.physicalPage === physicalPage && candidate.pageNumber === pageNumber && candidate.sectionPage === sectionPage && candidate.sectionId === sectionId && candidate.sectionIndex === sectionIndex && JSON.stringify(candidate.layout) === JSON.stringify(layout);
|
|
9518
12115
|
}
|
|
9519
12116
|
function documentPagePreviewText(blocks, documentNode) {
|
|
9520
12117
|
const measuredText = documentNode ? documentPageTextRanges(blocks).reduce((preview, range)=>{
|
|
@@ -10150,6 +12747,7 @@ function DocumentEditor({ artifactId, content, extensions = EMPTY_DOCUMENT_EXTEN
|
|
|
10150
12747
|
const pageFooterRef = useRef(null);
|
|
10151
12748
|
const workspaceRef = useRef(null);
|
|
10152
12749
|
const reviewSurfaceRef = useRef(null);
|
|
12750
|
+
const pageSurfaceRef = useRef(null);
|
|
10153
12751
|
const taskPaneInvokerRef = useRef(null);
|
|
10154
12752
|
const commentsDraftFocusRef = useRef(null);
|
|
10155
12753
|
const citationsDraftFocusRef = useRef(null);
|
|
@@ -10253,6 +12851,13 @@ function DocumentEditor({ artifactId, content, extensions = EMPTY_DOCUMENT_EXTEN
|
|
|
10253
12851
|
const active = document.activeElement;
|
|
10254
12852
|
if (active instanceof HTMLElement && active.isConnected) taskPaneInvokerRef.current = active;
|
|
10255
12853
|
}, []);
|
|
12854
|
+
const taskPaneRestoreTarget = useCallback(()=>{
|
|
12855
|
+
const invoker = taskPaneInvokerRef.current;
|
|
12856
|
+
if (invoker?.isConnected && !invoker.matches(':disabled') && !invoker.closest('[hidden], [aria-hidden="true"]')) return invoker;
|
|
12857
|
+
return editor && !editor.isDestroyed ? editor.view.dom : null;
|
|
12858
|
+
}, [
|
|
12859
|
+
editor
|
|
12860
|
+
]);
|
|
10256
12861
|
const rememberTaskPaneDraftFocus = useCallback((event)=>{
|
|
10257
12862
|
const target = event.target;
|
|
10258
12863
|
if (!(target instanceof HTMLElement) || !target.matches('input:not([type="hidden"]), textarea, [contenteditable="true"], [role="combobox"]')) return;
|
|
@@ -10317,25 +12922,31 @@ function DocumentEditor({ artifactId, content, extensions = EMPTY_DOCUMENT_EXTEN
|
|
|
10317
12922
|
taskPane,
|
|
10318
12923
|
taskPaneDialog.confirm
|
|
10319
12924
|
]);
|
|
10320
|
-
const
|
|
10321
|
-
|
|
10322
|
-
|
|
10323
|
-
|
|
12925
|
+
const restoreClosedTaskPaneFocus = useCallback(()=>{
|
|
12926
|
+
requestAnimationFrame(()=>{
|
|
12927
|
+
const target = taskPaneModal ? taskPaneRestoreTarget() : editor && !editor.isDestroyed ? editor.view.dom : null;
|
|
12928
|
+
target?.focus({
|
|
12929
|
+
preventScroll: true
|
|
12930
|
+
});
|
|
10324
12931
|
});
|
|
10325
12932
|
}, [
|
|
10326
12933
|
editor,
|
|
12934
|
+
taskPaneModal,
|
|
12935
|
+
taskPaneRestoreTarget
|
|
12936
|
+
]);
|
|
12937
|
+
const closeTaskPane = useCallback(async ()=>{
|
|
12938
|
+
if (!await requestEditorViewChange(null, false)) return;
|
|
12939
|
+
restoreClosedTaskPaneFocus();
|
|
12940
|
+
}, [
|
|
10327
12941
|
requestEditorViewChange,
|
|
10328
|
-
|
|
12942
|
+
restoreClosedTaskPaneFocus
|
|
10329
12943
|
]);
|
|
10330
12944
|
const closeCommentsPanel = useCallback(async ()=>{
|
|
10331
12945
|
if (!await requestEditorViewChange(null, true)) return;
|
|
10332
|
-
|
|
10333
|
-
if (editor && !editor.isDestroyed) editor.view.dom.focus();
|
|
10334
|
-
});
|
|
12946
|
+
restoreClosedTaskPaneFocus();
|
|
10335
12947
|
}, [
|
|
10336
|
-
editor,
|
|
10337
12948
|
requestEditorViewChange,
|
|
10338
|
-
|
|
12949
|
+
restoreClosedTaskPaneFocus
|
|
10339
12950
|
]);
|
|
10340
12951
|
const toggleTaskPane = useCallback(async (pane)=>{
|
|
10341
12952
|
if (taskPane !== pane) rememberTaskPaneInvoker();
|
|
@@ -10398,11 +13009,7 @@ function DocumentEditor({ artifactId, content, extensions = EMPTY_DOCUMENT_EXTEN
|
|
|
10398
13009
|
return pane?.querySelector('.ds-icon-button.close') ?? null;
|
|
10399
13010
|
},
|
|
10400
13011
|
getActiveScope: activeTaskPaneElement,
|
|
10401
|
-
restoreFocusTarget:
|
|
10402
|
-
const invoker = taskPaneInvokerRef.current;
|
|
10403
|
-
if (invoker?.isConnected && !invoker.matches(':disabled') && !invoker.closest('[hidden], [aria-hidden="true"]')) return invoker;
|
|
10404
|
-
return editor && !editor.isDestroyed ? editor.view.dom : null;
|
|
10405
|
-
}
|
|
13012
|
+
restoreFocusTarget: taskPaneRestoreTarget
|
|
10406
13013
|
});
|
|
10407
13014
|
useOfficeTaskPaneEscape(Boolean(taskPane) && !taskPaneModal, closeTaskPane);
|
|
10408
13015
|
useOfficeTaskPaneEscape(documentComments.open && !documentComments.draft && !taskPaneModal, closeCommentsPanel);
|
|
@@ -10703,6 +13310,14 @@ function DocumentEditor({ artifactId, content, extensions = EMPTY_DOCUMENT_EXTEN
|
|
|
10703
13310
|
currentPage: currentPage,
|
|
10704
13311
|
editor: editor,
|
|
10705
13312
|
modal: taskPaneModal,
|
|
13313
|
+
pageThumbnailSource: pageSurfaceRef.current && pagination.pageCount ? {
|
|
13314
|
+
element: pageSurfaceRef.current,
|
|
13315
|
+
pageCount: pagination.pageCount,
|
|
13316
|
+
pageGap: kernelPage.pageGap,
|
|
13317
|
+
pageHeight: kernelPage.height,
|
|
13318
|
+
pageWidth: kernelPage.width,
|
|
13319
|
+
revision: editorInput.sourceKey
|
|
13320
|
+
} : void 0,
|
|
10706
13321
|
pages: (pagination.pages.length ? pagination.pages : [
|
|
10707
13322
|
firstPageDescriptor
|
|
10708
13323
|
]).map((page)=>({
|
|
@@ -10748,6 +13363,7 @@ function DocumentEditor({ artifactId, content, extensions = EMPTY_DOCUMENT_EXTEN
|
|
|
10748
13363
|
onLayoutChange: updateLayout
|
|
10749
13364
|
}),
|
|
10750
13365
|
/*#__PURE__*/ jsxs("article", {
|
|
13366
|
+
ref: pageSurfaceRef,
|
|
10751
13367
|
className: `work-document-page${preview ? ' work-document-preview-page' : ''} ${layout.pageSize} ${layout.orientation}${pagination.pageCount ? ' paginated' : ''}${!preview && pageChromeEditing ? ' page-chrome-editing' : ''}`,
|
|
10752
13368
|
"data-work-pdf-live-document": artifactId && pagination.pageCount ? '' : void 0,
|
|
10753
13369
|
"data-pdf-orientation": artifactId && pagination.pageCount ? layout.orientation : void 0,
|