@a3s-lab/office 0.37.1 → 0.37.3
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 +285 -1549
- package/dist/0~9073.js +2 -2
- package/dist/0~controlled-editor-composition.js +54 -0
- package/dist/0~document-editor.js +60 -10
- package/dist/0~markdown-editor.js +62 -21
- package/dist/0~presentation-editor.js +57 -31
- package/dist/0~spreadsheet-editor.js +556 -71
- package/dist/internal/features/work/editors/controlled-editor-composition.d.ts +20 -0
- package/dist/internal/features/work/editors/spreadsheet-editor-support.d.ts +1 -0
- package/dist/internal/features/work/editors/spreadsheet-editor.d.ts +2 -1
- package/dist/internal/features/work/editors/spreadsheet-sort-custom-list-manager.d.ts +15 -0
- package/dist/internal/features/work/editors/spreadsheet-sort-dialog.d.ts +3 -2
- package/dist/internal/features/work/editors/use-document-review-conflicts.d.ts +3 -1
- package/dist/office-kernel.wasm +0 -0
- package/dist/styles.css +109 -0
- package/docs/latest/en/browser-editor-architecture.md +28 -7
- package/package.json +2 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { __webpack_require__ } from "./0~rslib-runtime.js";
|
|
2
2
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { Workbook } from "@fortune-sheet/react";
|
|
4
|
-
import { AArrowDown, AArrowUp, AlignCenter, AlignLeft, AlignRight, AlignVerticalJustifyCenter, AlignVerticalJustifyEnd, AlignVerticalJustifyStart, ArrowDown, ArrowDownToLine, ArrowLeft, ArrowLeftToLine, ArrowRight, ArrowRightToLine, ArrowUp, ArrowUpToLine, BadgeJapaneseYen, BarChart3, BetweenHorizontalEnd, BetweenHorizontalStart, BetweenVerticalEnd, BetweenVerticalStart, Bold, Bookmark, Calculator, CalendarClock, CalendarDays, Check, ChevronDown, ChevronLeft, ChevronRight, ClipboardPaste, Clock, Cloud, Columns3, Copy, CopyPlus, DecimalsArrowLeft, DecimalsArrowRight, Eraser, Eye, EyeOff, FileX2, Globe2, Grid2X2, Grid3X3, Hash, Info, Italic, KeyRound, Layers2, Link2, Link2Off, ListChecks, ListFilter, ListPlus, LocateFixed, Merge, MessageSquareX, MoveHorizontal, MoveVertical, Paintbrush, Palette, PanelLeft, PanelTop, PanelsTopLeft, Pencil, Percent, Plus, Printer, Redo2, RefreshCw, Rows3, Save, Scissors, Search, Settings2, ShieldCheck, Sigma, SlidersHorizontal, SortAsc, SortDesc, Strikethrough, SwatchBook, Table2, TableProperties, Trash2, TriangleAlert, Underline, Undo2, WrapText, X } from "lucide-react";
|
|
4
|
+
import { AArrowDown, AArrowUp, AlignCenter, AlignLeft, AlignRight, AlignVerticalJustifyCenter, AlignVerticalJustifyEnd, AlignVerticalJustifyStart, ArrowDown, ArrowDownToLine, ArrowLeft, ArrowLeftToLine, ArrowRight, ArrowRightToLine, ArrowUp, ArrowUpToLine, BadgeJapaneseYen, BarChart3, BetweenHorizontalEnd, BetweenHorizontalStart, BetweenVerticalEnd, BetweenVerticalStart, Bold, Bookmark, Calculator, CalendarClock, CalendarDays, Check, ChevronDown, ChevronLeft, ChevronRight, ClipboardPaste, Clock, Cloud, Columns3, Copy, CopyPlus, DecimalsArrowLeft, DecimalsArrowRight, Eraser, Eye, EyeOff, FileX2, Globe2, Grid2X2, Grid3X3, Hash, Info, Italic, KeyRound, Layers2, Link2, Link2Off, ListChecks, ListFilter, ListOrdered, ListPlus, LocateFixed, Merge, MessageSquareX, MoveHorizontal, MoveVertical, Paintbrush, Palette, PanelLeft, PanelTop, PanelsTopLeft, Pencil, Percent, Plus, Printer, Redo2, RefreshCw, Rows3, Save, Scissors, Search, Settings2, ShieldCheck, Sigma, SlidersHorizontal, SortAsc, SortDesc, Strikethrough, SwatchBook, Table2, TableProperties, Trash2, TriangleAlert, Underline, Undo2, WrapText, X } from "lucide-react";
|
|
5
5
|
import { Fragment as external_react_Fragment, cloneElement, createElement, memo, useCallback, useEffect, useId, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
6
6
|
import { convertSpanToShareString, genarate, indexToColumnChar, update as core_update } from "@fortune-sheet/core";
|
|
7
7
|
import { freezeImportedSpreadsheetCell, normalizeXlsxSemanticColorOrigin, spreadsheetMatrixProfile, withXlsxPatternFill, withoutEditableRange, normalizeSpreadsheetConditionalVisualOptions, xlsxSemanticColorMatchesValue, withXlsxGradientFill, effectiveSpreadsheetPageSetup, attachSpreadsheetShownCommentCells, normalizeXlsxPatternFill, withEditableRange, sameSpreadsheetHistoryValue, isSpreadsheetConditionalComparisonOperator, spreadsheetConditionalIconForValue, defaultSpreadsheetConditionalIconThresholds, xlsxPatternFillTypes, sheetProtectionAuthority, normalizeXlsxGradientFill, xlsxGradientFillFallbackColor, editableRangeCellCount, unlockedCellCount, registerDerivedSpreadsheetMatrix, editableRangeRequiresCredentials, SPREADSHEET_CONDITIONAL_COMPARISON_OPERATORS, normalizeSpreadsheetConditionalIconSetFormat, defaultSpreadsheetDataBarOptions, spreadsheetConditionalThresholdValue, normalizeSheetProtectionAuthority, withSheetProtection, spreadsheetProtectionKey, defaultSpreadsheetColorScaleThresholds, protectedSheetCount, SPREADSHEET_CONDITIONAL_ICON_SETS, withSheetSelectionPermissions, spreadsheetConditionalComparisonNeedsUpperValue, drawSpreadsheetConditionalIcon, isSpreadsheetConditionalIconSetName, spreadsheetConditionalThresholdsEqual, spreadsheetConditionalIconSetCount, spreadsheetConditionalIconAppearance } from "./9333.js";
|
|
@@ -4561,6 +4561,7 @@ function isSpreadsheetNativeTextUndoTarget(target) {
|
|
|
4561
4561
|
return target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement || target instanceof HTMLSelectElement || target.isContentEditable || Boolean(target.closest('[contenteditable="true"]'));
|
|
4562
4562
|
}
|
|
4563
4563
|
function isSpreadsheetCellEditingTarget(target) {
|
|
4564
|
+
if (!isSpreadsheetCellEditorTarget(target)) return false;
|
|
4564
4565
|
if (!(target instanceof Element)) return false;
|
|
4565
4566
|
const formulaInput = target.closest('.fortune-fx-input');
|
|
4566
4567
|
if (formulaInput) return true;
|
|
@@ -4571,6 +4572,9 @@ function isSpreadsheetCellEditingTarget(target) {
|
|
|
4571
4572
|
const zIndex = Number.parseInt(inputBox.style.zIndex || getComputedStyle(inputBox).zIndex, 10);
|
|
4572
4573
|
return !Number.isFinite(zIndex) || zIndex >= 0;
|
|
4573
4574
|
}
|
|
4575
|
+
function isSpreadsheetCellEditorTarget(target) {
|
|
4576
|
+
return target instanceof Element && Boolean(target.closest('.fortune-fx-input, .luckysheet-cell-input'));
|
|
4577
|
+
}
|
|
4574
4578
|
function spreadsheetFormulaBarSelectAllTarget(event) {
|
|
4575
4579
|
if (event.defaultPrevented || event.repeat || event.altKey || event.shiftKey || !(event.metaKey || event.ctrlKey) || 'a' !== event.key.toLocaleLowerCase() || !(event.target instanceof Element)) return null;
|
|
4576
4580
|
const formulaBar = event.target.closest('.fortune-fx-input');
|
|
@@ -25185,6 +25189,11 @@ function spreadsheetClipboardSnapshotForText(plainText) {
|
|
|
25185
25189
|
}
|
|
25186
25190
|
return createSpreadsheetTextClipboardSnapshot(normalized);
|
|
25187
25191
|
}
|
|
25192
|
+
function clearRichSpreadsheetClipboard() {
|
|
25193
|
+
richSpreadsheetClipboard = null;
|
|
25194
|
+
browserClipboardWriteRevision += 1;
|
|
25195
|
+
preferLocalSpreadsheetClipboardRead = false;
|
|
25196
|
+
}
|
|
25188
25197
|
async function readSpreadsheetClipboardText(readSystem, readLocal, timeoutMs = spreadsheetSystemClipboardTimeoutMs, canReadSystem = ()=>true) {
|
|
25189
25198
|
if (readSystem && await canReadSystem()) try {
|
|
25190
25199
|
const value = await withSpreadsheetClipboardTimeout(readSystem(), timeoutMs);
|
|
@@ -25758,25 +25767,26 @@ function useSpreadsheetClipboard({ clipboard = browserSpreadsheetClipboard, canA
|
|
|
25758
25767
|
}, [
|
|
25759
25768
|
editable
|
|
25760
25769
|
]);
|
|
25761
|
-
const
|
|
25770
|
+
const currentSource = useCallback(()=>{
|
|
25762
25771
|
if (!editable) return null;
|
|
25763
25772
|
const selection = getSelection();
|
|
25764
25773
|
if (!selection) return null;
|
|
25765
25774
|
const snapshot = captureSpreadsheetClipboardSnapshot(contentRef.current, selection.sheetId, selection.range, selection.plainText);
|
|
25766
|
-
return
|
|
25775
|
+
return {
|
|
25767
25776
|
selection,
|
|
25768
25777
|
snapshot
|
|
25769
|
-
}
|
|
25778
|
+
};
|
|
25770
25779
|
}, [
|
|
25771
25780
|
contentRef,
|
|
25772
25781
|
editable,
|
|
25773
25782
|
getSelection
|
|
25774
25783
|
]);
|
|
25775
25784
|
const copy = useCallback((cut)=>{
|
|
25776
|
-
const source =
|
|
25785
|
+
const source = currentSource();
|
|
25777
25786
|
if (!source) return false;
|
|
25778
|
-
storeRichSpreadsheetClipboard(source.snapshot);
|
|
25779
|
-
|
|
25787
|
+
if (source.snapshot) storeRichSpreadsheetClipboard(source.snapshot);
|
|
25788
|
+
else clearRichSpreadsheetClipboard();
|
|
25789
|
+
copySpreadsheetSelection(clipboard, source.selection.plainText, cut);
|
|
25780
25790
|
if (cut && !clearSelection()) {
|
|
25781
25791
|
showToast('选区已复制,但无法清除原内容。', 'error');
|
|
25782
25792
|
return false;
|
|
@@ -25785,7 +25795,7 @@ function useSpreadsheetClipboard({ clipboard = browserSpreadsheetClipboard, canA
|
|
|
25785
25795
|
}, [
|
|
25786
25796
|
clearSelection,
|
|
25787
25797
|
clipboard,
|
|
25788
|
-
|
|
25798
|
+
currentSource
|
|
25789
25799
|
]);
|
|
25790
25800
|
const applySnapshot = useCallback((snapshot, targetSheetId, targetRange, options, notify = true)=>{
|
|
25791
25801
|
const request = {
|
|
@@ -25913,15 +25923,16 @@ function useSpreadsheetClipboard({ clipboard = browserSpreadsheetClipboard, canA
|
|
|
25913
25923
|
fallbackFocusTarget
|
|
25914
25924
|
]);
|
|
25915
25925
|
const copyToDataTransfer = useCallback((data, cut)=>{
|
|
25916
|
-
const source =
|
|
25926
|
+
const source = currentSource();
|
|
25917
25927
|
if (!source) return false;
|
|
25918
|
-
storeRichSpreadsheetClipboard(source.snapshot);
|
|
25919
|
-
|
|
25928
|
+
if (source.snapshot) storeRichSpreadsheetClipboard(source.snapshot);
|
|
25929
|
+
else clearRichSpreadsheetClipboard();
|
|
25930
|
+
data.setData('text/plain', source.selection.plainText);
|
|
25920
25931
|
if (cut && !clearSelection()) return false;
|
|
25921
25932
|
return true;
|
|
25922
25933
|
}, [
|
|
25923
25934
|
clearSelection,
|
|
25924
|
-
|
|
25935
|
+
currentSource
|
|
25925
25936
|
]);
|
|
25926
25937
|
return {
|
|
25927
25938
|
applyDialog,
|
|
@@ -27397,6 +27408,385 @@ function SpreadsheetSortCustomListEditor({ error, level, text, onCancel, onChang
|
|
|
27397
27408
|
]
|
|
27398
27409
|
});
|
|
27399
27410
|
}
|
|
27411
|
+
function SpreadsheetSortCustomListManagerDialog({ customLists, restoreFocusTarget, onApply, onClose }) {
|
|
27412
|
+
const builtInLists = useMemo(()=>customLists.filter((list)=>'built-in' === list.source), [
|
|
27413
|
+
customLists
|
|
27414
|
+
]);
|
|
27415
|
+
const initialUserListsRef = useRef(null);
|
|
27416
|
+
initialUserListsRef.current ??= customLists.filter((list)=>'built-in' !== list.source).map((list, index)=>({
|
|
27417
|
+
id: index,
|
|
27418
|
+
entries: Object.freeze([
|
|
27419
|
+
...list.entries
|
|
27420
|
+
]),
|
|
27421
|
+
originalEntries: Object.freeze([
|
|
27422
|
+
...list.entries
|
|
27423
|
+
])
|
|
27424
|
+
}));
|
|
27425
|
+
const initialUserLists = initialUserListsRef.current;
|
|
27426
|
+
const nextIdRef = useRef(initialUserLists.length);
|
|
27427
|
+
const listRef = useRef(null);
|
|
27428
|
+
const [userLists, setUserLists] = useState(()=>initialUserLists.map(cloneManagedCustomList));
|
|
27429
|
+
const [selection, setSelection] = useState('built-in:0');
|
|
27430
|
+
const [text, setText] = useState(builtInLists[0]?.entries.join('\n') ?? '');
|
|
27431
|
+
const [error, setError] = useState(null);
|
|
27432
|
+
const userListLabels = useMemo(()=>new Map(userLists.map((list)=>[
|
|
27433
|
+
list.id,
|
|
27434
|
+
managedCustomListLabel(list.entries)
|
|
27435
|
+
])), [
|
|
27436
|
+
userLists
|
|
27437
|
+
]);
|
|
27438
|
+
useEffect(()=>listRef.current?.focus(), []);
|
|
27439
|
+
const selectedUserIndex = managedUserListIndex(selection, userLists);
|
|
27440
|
+
const selectedUser = userLists[selectedUserIndex];
|
|
27441
|
+
const selectedBuiltIn = managedBuiltInList(selection, builtInLists);
|
|
27442
|
+
const editingNewList = 'new' === selection;
|
|
27443
|
+
const validateDraft = (rows, excludedId)=>{
|
|
27444
|
+
const validation = parseSpreadsheetSortCustomList(text);
|
|
27445
|
+
if (!validation.ok) {
|
|
27446
|
+
setError(validation.message);
|
|
27447
|
+
return null;
|
|
27448
|
+
}
|
|
27449
|
+
const duplicate = [
|
|
27450
|
+
...builtInLists.map((list)=>list.entries),
|
|
27451
|
+
...rows.filter((row)=>row.id !== excludedId).map((row)=>row.entries)
|
|
27452
|
+
].some((entries)=>spreadsheetSortCustomListsEqual(entries, validation.entries));
|
|
27453
|
+
if (duplicate) {
|
|
27454
|
+
setError('该自定义序列已存在。');
|
|
27455
|
+
return null;
|
|
27456
|
+
}
|
|
27457
|
+
setError(null);
|
|
27458
|
+
return Object.freeze([
|
|
27459
|
+
...validation.entries
|
|
27460
|
+
]);
|
|
27461
|
+
};
|
|
27462
|
+
const commitSelectedUser = (rows)=>{
|
|
27463
|
+
const index = managedUserListIndex(selection, rows);
|
|
27464
|
+
const selected = rows[index];
|
|
27465
|
+
if (!selected) return rows;
|
|
27466
|
+
const entries = validateDraft(rows, selected.id);
|
|
27467
|
+
if (!entries) return null;
|
|
27468
|
+
return rows.map((row)=>row.id === selected.id ? {
|
|
27469
|
+
...row,
|
|
27470
|
+
entries
|
|
27471
|
+
} : row);
|
|
27472
|
+
};
|
|
27473
|
+
const select = (nextSelection)=>{
|
|
27474
|
+
let rows = userLists;
|
|
27475
|
+
if (selectedUser) {
|
|
27476
|
+
const committed = commitSelectedUser(rows);
|
|
27477
|
+
if (!committed) return;
|
|
27478
|
+
rows = committed;
|
|
27479
|
+
setUserLists(rows);
|
|
27480
|
+
} else if (editingNewList && text.trim()) return void setError('请先添加当前序列,或清空项目后再切换。');
|
|
27481
|
+
setSelection(nextSelection);
|
|
27482
|
+
setText(managedSelectionText(nextSelection, builtInLists, rows));
|
|
27483
|
+
setError(null);
|
|
27484
|
+
};
|
|
27485
|
+
const saveSelectedUser = ()=>{
|
|
27486
|
+
const committed = commitSelectedUser(userLists);
|
|
27487
|
+
if (!committed) return;
|
|
27488
|
+
setUserLists(committed);
|
|
27489
|
+
setText(managedSelectionText(selection, builtInLists, committed));
|
|
27490
|
+
};
|
|
27491
|
+
const addNewList = ()=>{
|
|
27492
|
+
if (userLists.length >= 32) return void setError("当前编辑器最多保留 32 个自定义序列。");
|
|
27493
|
+
const entries = validateDraft(userLists, null);
|
|
27494
|
+
if (!entries) return;
|
|
27495
|
+
const id = nextIdRef.current;
|
|
27496
|
+
nextIdRef.current += 1;
|
|
27497
|
+
const next = [
|
|
27498
|
+
...userLists,
|
|
27499
|
+
{
|
|
27500
|
+
id,
|
|
27501
|
+
entries,
|
|
27502
|
+
originalEntries: null
|
|
27503
|
+
}
|
|
27504
|
+
];
|
|
27505
|
+
setUserLists(next);
|
|
27506
|
+
setSelection(`user:${id}`);
|
|
27507
|
+
setText(entries.join('\n'));
|
|
27508
|
+
};
|
|
27509
|
+
const moveSelectedUser = (offset)=>{
|
|
27510
|
+
const committed = commitSelectedUser(userLists);
|
|
27511
|
+
if (!committed) return;
|
|
27512
|
+
const index = managedUserListIndex(selection, committed);
|
|
27513
|
+
const nextIndex = index + offset;
|
|
27514
|
+
if (index < 0 || nextIndex < 0 || nextIndex >= committed.length) return;
|
|
27515
|
+
const next = committed.map(cloneManagedCustomList);
|
|
27516
|
+
const selected = next[index];
|
|
27517
|
+
const target = next[nextIndex];
|
|
27518
|
+
if (!selected || !target) return;
|
|
27519
|
+
next[index] = target;
|
|
27520
|
+
next[nextIndex] = selected;
|
|
27521
|
+
setUserLists(next);
|
|
27522
|
+
setText(selected.entries.join('\n'));
|
|
27523
|
+
};
|
|
27524
|
+
const deleteSelectedUser = ()=>{
|
|
27525
|
+
if (!selectedUser) return;
|
|
27526
|
+
const next = userLists.filter((row)=>row.id !== selectedUser.id);
|
|
27527
|
+
setUserLists(next);
|
|
27528
|
+
const fallback = next[selectedUserIndex] ?? next[selectedUserIndex - 1];
|
|
27529
|
+
const nextSelection = fallback ? `user:${fallback.id}` : 'built-in:0';
|
|
27530
|
+
setSelection(nextSelection);
|
|
27531
|
+
setText(managedSelectionText(nextSelection, builtInLists, next));
|
|
27532
|
+
setError(null);
|
|
27533
|
+
};
|
|
27534
|
+
const apply = ()=>{
|
|
27535
|
+
let rows = userLists;
|
|
27536
|
+
if (selectedUser) {
|
|
27537
|
+
const committed = commitSelectedUser(rows);
|
|
27538
|
+
if (!committed) return;
|
|
27539
|
+
rows = committed;
|
|
27540
|
+
} else if (editingNewList && text.trim()) {
|
|
27541
|
+
if (rows.length >= 32) return void setError("当前编辑器最多保留 32 个自定义序列。");
|
|
27542
|
+
const entries = validateDraft(rows, null);
|
|
27543
|
+
if (!entries) return;
|
|
27544
|
+
const id = nextIdRef.current;
|
|
27545
|
+
nextIdRef.current += 1;
|
|
27546
|
+
rows = [
|
|
27547
|
+
...rows,
|
|
27548
|
+
{
|
|
27549
|
+
id,
|
|
27550
|
+
entries,
|
|
27551
|
+
originalEntries: null
|
|
27552
|
+
}
|
|
27553
|
+
];
|
|
27554
|
+
}
|
|
27555
|
+
onApply(managedCustomListResult(initialUserLists, rows));
|
|
27556
|
+
onClose();
|
|
27557
|
+
};
|
|
27558
|
+
return /*#__PURE__*/ jsxs(Dialog, {
|
|
27559
|
+
title: "自定义序列",
|
|
27560
|
+
description: "管理排序时可复用的本地序列。内置月份和星期序列保持只读。",
|
|
27561
|
+
className: "work-spreadsheet-sort-custom-list-manager",
|
|
27562
|
+
restoreFocusTarget: restoreFocusTarget,
|
|
27563
|
+
onClose: onClose,
|
|
27564
|
+
footer: /*#__PURE__*/ jsxs(Fragment, {
|
|
27565
|
+
children: [
|
|
27566
|
+
/*#__PURE__*/ jsx(button_Button, {
|
|
27567
|
+
tone: "quiet",
|
|
27568
|
+
onClick: onClose,
|
|
27569
|
+
children: "取消"
|
|
27570
|
+
}),
|
|
27571
|
+
/*#__PURE__*/ jsx(button_Button, {
|
|
27572
|
+
tone: "primary",
|
|
27573
|
+
onClick: apply,
|
|
27574
|
+
children: "确定"
|
|
27575
|
+
})
|
|
27576
|
+
]
|
|
27577
|
+
}),
|
|
27578
|
+
children: [
|
|
27579
|
+
/*#__PURE__*/ jsxs("div", {
|
|
27580
|
+
className: "work-spreadsheet-sort-custom-list-manager-layout",
|
|
27581
|
+
children: [
|
|
27582
|
+
/*#__PURE__*/ jsxs("section", {
|
|
27583
|
+
"aria-label": "可用序列",
|
|
27584
|
+
children: [
|
|
27585
|
+
/*#__PURE__*/ jsxs("label", {
|
|
27586
|
+
children: [
|
|
27587
|
+
/*#__PURE__*/ jsx("span", {
|
|
27588
|
+
children: "自定义序列"
|
|
27589
|
+
}),
|
|
27590
|
+
/*#__PURE__*/ jsxs("select", {
|
|
27591
|
+
ref: listRef,
|
|
27592
|
+
"aria-label": "自定义序列列表",
|
|
27593
|
+
size: 10,
|
|
27594
|
+
value: selection,
|
|
27595
|
+
onChange: (event)=>select(event.currentTarget.value),
|
|
27596
|
+
children: [
|
|
27597
|
+
/*#__PURE__*/ jsx("optgroup", {
|
|
27598
|
+
label: "内置序列",
|
|
27599
|
+
children: builtInLists.map((list, index)=>/*#__PURE__*/ jsx("option", {
|
|
27600
|
+
value: `built-in:${index}`,
|
|
27601
|
+
children: list.label
|
|
27602
|
+
}, `built-in:${index}`))
|
|
27603
|
+
}),
|
|
27604
|
+
userLists.length ? /*#__PURE__*/ jsx("optgroup", {
|
|
27605
|
+
label: "用户序列",
|
|
27606
|
+
children: userLists.map((list)=>/*#__PURE__*/ jsx("option", {
|
|
27607
|
+
value: `user:${list.id}`,
|
|
27608
|
+
children: userListLabels.get(list.id)
|
|
27609
|
+
}, list.id))
|
|
27610
|
+
}) : null
|
|
27611
|
+
]
|
|
27612
|
+
})
|
|
27613
|
+
]
|
|
27614
|
+
}),
|
|
27615
|
+
/*#__PURE__*/ jsxs(button_Button, {
|
|
27616
|
+
tone: "quiet",
|
|
27617
|
+
type: "button",
|
|
27618
|
+
disabled: userLists.length >= 32,
|
|
27619
|
+
onClick: ()=>select('new'),
|
|
27620
|
+
children: [
|
|
27621
|
+
/*#__PURE__*/ jsx(ListPlus, {
|
|
27622
|
+
size: 15,
|
|
27623
|
+
"aria-hidden": "true"
|
|
27624
|
+
}),
|
|
27625
|
+
"新建序列"
|
|
27626
|
+
]
|
|
27627
|
+
})
|
|
27628
|
+
]
|
|
27629
|
+
}),
|
|
27630
|
+
/*#__PURE__*/ jsxs("section", {
|
|
27631
|
+
"aria-label": "序列项目",
|
|
27632
|
+
children: [
|
|
27633
|
+
/*#__PURE__*/ jsxs("label", {
|
|
27634
|
+
children: [
|
|
27635
|
+
/*#__PURE__*/ jsx("span", {
|
|
27636
|
+
children: "序列项目(每行一个项目)"
|
|
27637
|
+
}),
|
|
27638
|
+
/*#__PURE__*/ jsx("textarea", {
|
|
27639
|
+
"aria-label": "自定义序列项目",
|
|
27640
|
+
"aria-invalid": error ? true : void 0,
|
|
27641
|
+
readOnly: Boolean(selectedBuiltIn),
|
|
27642
|
+
rows: 12,
|
|
27643
|
+
value: text,
|
|
27644
|
+
onChange: (event)=>{
|
|
27645
|
+
setText(event.currentTarget.value);
|
|
27646
|
+
setError(null);
|
|
27647
|
+
}
|
|
27648
|
+
})
|
|
27649
|
+
]
|
|
27650
|
+
}),
|
|
27651
|
+
/*#__PURE__*/ jsx("p", {
|
|
27652
|
+
children: selectedBuiltIn ? '内置序列不可修改或删除。' : editingNewList ? '每行、英文逗号或中文逗号可分隔一个项目。' : '修改项目后保存;排序和删除在点击“确定”后统一提交。'
|
|
27653
|
+
}),
|
|
27654
|
+
error ? /*#__PURE__*/ jsx("p", {
|
|
27655
|
+
className: "work-spreadsheet-sort-custom-list-error",
|
|
27656
|
+
role: "alert",
|
|
27657
|
+
children: error
|
|
27658
|
+
}) : null,
|
|
27659
|
+
/*#__PURE__*/ jsxs("div", {
|
|
27660
|
+
className: "work-spreadsheet-sort-custom-list-manager-actions",
|
|
27661
|
+
children: [
|
|
27662
|
+
editingNewList ? /*#__PURE__*/ jsxs(button_Button, {
|
|
27663
|
+
tone: "primary",
|
|
27664
|
+
type: "button",
|
|
27665
|
+
onClick: addNewList,
|
|
27666
|
+
children: [
|
|
27667
|
+
/*#__PURE__*/ jsx(ListPlus, {
|
|
27668
|
+
size: 15,
|
|
27669
|
+
"aria-hidden": "true"
|
|
27670
|
+
}),
|
|
27671
|
+
"添加序列"
|
|
27672
|
+
]
|
|
27673
|
+
}) : selectedUser ? /*#__PURE__*/ jsxs(button_Button, {
|
|
27674
|
+
tone: "primary",
|
|
27675
|
+
type: "button",
|
|
27676
|
+
onClick: saveSelectedUser,
|
|
27677
|
+
children: [
|
|
27678
|
+
/*#__PURE__*/ jsx(Save, {
|
|
27679
|
+
size: 15,
|
|
27680
|
+
"aria-hidden": "true"
|
|
27681
|
+
}),
|
|
27682
|
+
"保存更改"
|
|
27683
|
+
]
|
|
27684
|
+
}) : null,
|
|
27685
|
+
/*#__PURE__*/ jsx(button_Button, {
|
|
27686
|
+
tone: "quiet",
|
|
27687
|
+
type: "button",
|
|
27688
|
+
"aria-label": "上移序列",
|
|
27689
|
+
title: "上移序列",
|
|
27690
|
+
disabled: selectedUserIndex <= 0,
|
|
27691
|
+
onClick: ()=>moveSelectedUser(-1),
|
|
27692
|
+
children: /*#__PURE__*/ jsx(ArrowUp, {
|
|
27693
|
+
size: 15,
|
|
27694
|
+
"aria-hidden": "true"
|
|
27695
|
+
})
|
|
27696
|
+
}),
|
|
27697
|
+
/*#__PURE__*/ jsx(button_Button, {
|
|
27698
|
+
tone: "quiet",
|
|
27699
|
+
type: "button",
|
|
27700
|
+
"aria-label": "下移序列",
|
|
27701
|
+
title: "下移序列",
|
|
27702
|
+
disabled: selectedUserIndex < 0 || selectedUserIndex >= userLists.length - 1,
|
|
27703
|
+
onClick: ()=>moveSelectedUser(1),
|
|
27704
|
+
children: /*#__PURE__*/ jsx(ArrowDown, {
|
|
27705
|
+
size: 15,
|
|
27706
|
+
"aria-hidden": "true"
|
|
27707
|
+
})
|
|
27708
|
+
}),
|
|
27709
|
+
/*#__PURE__*/ jsx(button_Button, {
|
|
27710
|
+
tone: "quiet",
|
|
27711
|
+
type: "button",
|
|
27712
|
+
"aria-label": "删除序列",
|
|
27713
|
+
title: "删除序列",
|
|
27714
|
+
disabled: !selectedUser,
|
|
27715
|
+
onClick: deleteSelectedUser,
|
|
27716
|
+
children: /*#__PURE__*/ jsx(Trash2, {
|
|
27717
|
+
size: 15,
|
|
27718
|
+
"aria-hidden": "true"
|
|
27719
|
+
})
|
|
27720
|
+
})
|
|
27721
|
+
]
|
|
27722
|
+
})
|
|
27723
|
+
]
|
|
27724
|
+
})
|
|
27725
|
+
]
|
|
27726
|
+
}),
|
|
27727
|
+
/*#__PURE__*/ jsxs("p", {
|
|
27728
|
+
className: "work-spreadsheet-sort-custom-list-manager-note",
|
|
27729
|
+
children: [
|
|
27730
|
+
"最多保存 ",
|
|
27731
|
+
32,
|
|
27732
|
+
' ',
|
|
27733
|
+
"个用户序列。修改或删除当前使用的序列会同步更新对应排序条件。"
|
|
27734
|
+
]
|
|
27735
|
+
})
|
|
27736
|
+
]
|
|
27737
|
+
});
|
|
27738
|
+
}
|
|
27739
|
+
function managedCustomListResult(initial, current) {
|
|
27740
|
+
const changes = [];
|
|
27741
|
+
for (const original of initial){
|
|
27742
|
+
if (!original.originalEntries) continue;
|
|
27743
|
+
const next = current.find((row)=>row.id === original.id);
|
|
27744
|
+
if (next) {
|
|
27745
|
+
if (!spreadsheetSortCustomListsEqual(original.originalEntries, next.entries)) changes.push({
|
|
27746
|
+
previous: original.originalEntries,
|
|
27747
|
+
next: Object.freeze([
|
|
27748
|
+
...next.entries
|
|
27749
|
+
])
|
|
27750
|
+
});
|
|
27751
|
+
} else changes.push({
|
|
27752
|
+
previous: original.originalEntries,
|
|
27753
|
+
next: null
|
|
27754
|
+
});
|
|
27755
|
+
}
|
|
27756
|
+
return Object.freeze({
|
|
27757
|
+
lists: Object.freeze(current.map((row)=>Object.freeze([
|
|
27758
|
+
...row.entries
|
|
27759
|
+
]))),
|
|
27760
|
+
changes: Object.freeze(changes)
|
|
27761
|
+
});
|
|
27762
|
+
}
|
|
27763
|
+
function managedUserListIndex(selection, lists) {
|
|
27764
|
+
if (!selection.startsWith('user:')) return -1;
|
|
27765
|
+
const id = Number(selection.slice(5));
|
|
27766
|
+
return Number.isSafeInteger(id) ? lists.findIndex((list)=>list.id === id) : -1;
|
|
27767
|
+
}
|
|
27768
|
+
function managedBuiltInList(selection, lists) {
|
|
27769
|
+
if (!selection.startsWith('built-in:')) return null;
|
|
27770
|
+
const index = Number(selection.slice(9));
|
|
27771
|
+
return Number.isSafeInteger(index) ? lists[index] ?? null : null;
|
|
27772
|
+
}
|
|
27773
|
+
function managedSelectionText(selection, builtInLists, userLists) {
|
|
27774
|
+
return (managedBuiltInList(selection, builtInLists)?.entries ?? userLists[managedUserListIndex(selection, userLists)]?.entries ?? []).join('\n');
|
|
27775
|
+
}
|
|
27776
|
+
function cloneManagedCustomList(list) {
|
|
27777
|
+
return {
|
|
27778
|
+
...list,
|
|
27779
|
+
entries: Object.freeze([
|
|
27780
|
+
...list.entries
|
|
27781
|
+
]),
|
|
27782
|
+
originalEntries: list.originalEntries ? Object.freeze([
|
|
27783
|
+
...list.originalEntries
|
|
27784
|
+
]) : null
|
|
27785
|
+
};
|
|
27786
|
+
}
|
|
27787
|
+
function managedCustomListLabel(entries) {
|
|
27788
|
+
return createSpreadsheetSortCustomList(entries, 'session')?.label ?? entries.join(' → ');
|
|
27789
|
+
}
|
|
27400
27790
|
function SpreadsheetSortOptionsDialog({ value, restoreFocusTarget, onApply, onClose }) {
|
|
27401
27791
|
const [draft, setDraft] = useState(value);
|
|
27402
27792
|
const formId = useId();
|
|
@@ -27855,7 +28245,7 @@ function spreadsheetSortPositionLabel(orientation, position) {
|
|
|
27855
28245
|
function isSpreadsheetSortAppearanceKind(value) {
|
|
27856
28246
|
return 'cell-color' === value || 'font-color' === value || 'icon' === value;
|
|
27857
28247
|
}
|
|
27858
|
-
function SpreadsheetSortDialog({ source, restoreFocusTarget, onApply, onRememberCustomList, onClose }) {
|
|
28248
|
+
function SpreadsheetSortDialog({ source, restoreFocusTarget, onApply, onRememberCustomList, onUpdateCustomLists, onClose }) {
|
|
27859
28249
|
const [value, setValue] = useState(()=>({
|
|
27860
28250
|
hasHeader: source.value.hasHeader,
|
|
27861
28251
|
keys: source.value.keys.map(cloneSpreadsheetSortKey),
|
|
@@ -27865,6 +28255,7 @@ function SpreadsheetSortDialog({ source, restoreFocusTarget, onApply, onRemember
|
|
|
27865
28255
|
}));
|
|
27866
28256
|
const [verticalHasHeader, setVerticalHasHeader] = useState(source.value.hasHeader);
|
|
27867
28257
|
const [optionsOpen, setOptionsOpen] = useState(false);
|
|
28258
|
+
const [customListManagerOpen, setCustomListManagerOpen] = useState(false);
|
|
27868
28259
|
const [customLists, setCustomLists] = useState(()=>initialSpreadsheetSortCustomLists(source));
|
|
27869
28260
|
const fields = 'top-to-bottom' === value.orientation ? source.columns : source.rows;
|
|
27870
28261
|
const appearanceFields = useMemo(()=>spreadsheetSortAppearanceFields(source.appearanceRows, source.range, value.orientation, value.hasHeader), [
|
|
@@ -27876,6 +28267,7 @@ function SpreadsheetSortDialog({ source, restoreFocusTarget, onApply, onRemember
|
|
|
27876
28267
|
const [customListDraft, setCustomListDraft] = useState(null);
|
|
27877
28268
|
const formId = useId();
|
|
27878
28269
|
const optionsButtonRef = useRef(null);
|
|
28270
|
+
const customListManagerButtonRef = useRef(null);
|
|
27879
28271
|
const nextKey = value.keys.length < 64 ? nextSpreadsheetSortKey(value.keys, fields, appearanceFields) : null;
|
|
27880
28272
|
const replaceKey = (index, replacement)=>{
|
|
27881
28273
|
setValue((current)=>({
|
|
@@ -27974,6 +28366,18 @@ function SpreadsheetSortDialog({ source, restoreFocusTarget, onApply, onRemember
|
|
|
27974
28366
|
]
|
|
27975
28367
|
});
|
|
27976
28368
|
};
|
|
28369
|
+
const applyCustomListManagement = (result)=>{
|
|
28370
|
+
const currentUserLists = customLists.filter((list)=>'built-in' !== list.source);
|
|
28371
|
+
const preferencesChanged = currentUserLists.length !== result.lists.length || result.lists.some((entries, index)=>!spreadsheetSortCustomListsEqual(currentUserLists[index]?.entries ?? [], entries));
|
|
28372
|
+
const fallback = result.lists.map((entries)=>createSpreadsheetSortCustomList(entries, 'session')).filter((list)=>null !== list);
|
|
28373
|
+
const updated = preferencesChanged ? onUpdateCustomLists?.(result.lists) ?? fallback : currentUserLists;
|
|
28374
|
+
setCustomLists(mergeSpreadsheetSortCustomLists(updated));
|
|
28375
|
+
setCustomListDraft(null);
|
|
28376
|
+
setValue((current)=>({
|
|
28377
|
+
...current,
|
|
28378
|
+
keys: current.keys.map((key)=>reconcileManagedCustomListKey(key, result.changes))
|
|
28379
|
+
}));
|
|
28380
|
+
};
|
|
27977
28381
|
return /*#__PURE__*/ jsxs(Fragment, {
|
|
27978
28382
|
children: [
|
|
27979
28383
|
/*#__PURE__*/ jsx(Dialog, {
|
|
@@ -28004,40 +28408,60 @@ function SpreadsheetSortDialog({ source, restoreFocusTarget, onApply, onRemember
|
|
|
28004
28408
|
/*#__PURE__*/ jsxs("div", {
|
|
28005
28409
|
className: "work-spreadsheet-sort-toolbar",
|
|
28006
28410
|
children: [
|
|
28007
|
-
/*#__PURE__*/ jsxs(
|
|
28008
|
-
|
|
28009
|
-
type: "button",
|
|
28010
|
-
disabled: !nextKey,
|
|
28011
|
-
onClick: ()=>{
|
|
28012
|
-
if (!nextKey) return;
|
|
28013
|
-
setCustomListDraft(null);
|
|
28014
|
-
setValue((current)=>({
|
|
28015
|
-
...current,
|
|
28016
|
-
keys: [
|
|
28017
|
-
...current.keys,
|
|
28018
|
-
cloneSpreadsheetSortKey(nextKey)
|
|
28019
|
-
]
|
|
28020
|
-
}));
|
|
28021
|
-
},
|
|
28411
|
+
/*#__PURE__*/ jsxs("div", {
|
|
28412
|
+
className: "work-spreadsheet-sort-toolbar-actions",
|
|
28022
28413
|
children: [
|
|
28023
|
-
/*#__PURE__*/
|
|
28024
|
-
|
|
28025
|
-
|
|
28414
|
+
/*#__PURE__*/ jsxs(button_Button, {
|
|
28415
|
+
tone: "quiet",
|
|
28416
|
+
type: "button",
|
|
28417
|
+
disabled: !nextKey,
|
|
28418
|
+
onClick: ()=>{
|
|
28419
|
+
if (!nextKey) return;
|
|
28420
|
+
setCustomListDraft(null);
|
|
28421
|
+
setValue((current)=>({
|
|
28422
|
+
...current,
|
|
28423
|
+
keys: [
|
|
28424
|
+
...current.keys,
|
|
28425
|
+
cloneSpreadsheetSortKey(nextKey)
|
|
28426
|
+
]
|
|
28427
|
+
}));
|
|
28428
|
+
},
|
|
28429
|
+
children: [
|
|
28430
|
+
/*#__PURE__*/ jsx(ListPlus, {
|
|
28431
|
+
size: 15,
|
|
28432
|
+
"aria-hidden": "true"
|
|
28433
|
+
}),
|
|
28434
|
+
"添加条件"
|
|
28435
|
+
]
|
|
28026
28436
|
}),
|
|
28027
|
-
|
|
28028
|
-
|
|
28029
|
-
|
|
28030
|
-
|
|
28031
|
-
|
|
28032
|
-
|
|
28033
|
-
|
|
28034
|
-
|
|
28035
|
-
|
|
28036
|
-
|
|
28037
|
-
|
|
28038
|
-
|
|
28437
|
+
/*#__PURE__*/ jsxs(button_Button, {
|
|
28438
|
+
ref: optionsButtonRef,
|
|
28439
|
+
tone: "quiet",
|
|
28440
|
+
type: "button",
|
|
28441
|
+
onClick: ()=>setOptionsOpen(true),
|
|
28442
|
+
children: [
|
|
28443
|
+
/*#__PURE__*/ jsx(Settings2, {
|
|
28444
|
+
size: 15,
|
|
28445
|
+
"aria-hidden": "true"
|
|
28446
|
+
}),
|
|
28447
|
+
"选项…"
|
|
28448
|
+
]
|
|
28039
28449
|
}),
|
|
28040
|
-
|
|
28450
|
+
/*#__PURE__*/ jsxs(button_Button, {
|
|
28451
|
+
ref: customListManagerButtonRef,
|
|
28452
|
+
tone: "quiet",
|
|
28453
|
+
type: "button",
|
|
28454
|
+
"aria-label": "管理自定义序列",
|
|
28455
|
+
title: "管理自定义序列",
|
|
28456
|
+
onClick: ()=>setCustomListManagerOpen(true),
|
|
28457
|
+
children: [
|
|
28458
|
+
/*#__PURE__*/ jsx(ListOrdered, {
|
|
28459
|
+
size: 15,
|
|
28460
|
+
"aria-hidden": "true"
|
|
28461
|
+
}),
|
|
28462
|
+
"自定义序列…"
|
|
28463
|
+
]
|
|
28464
|
+
})
|
|
28041
28465
|
]
|
|
28042
28466
|
}),
|
|
28043
28467
|
/*#__PURE__*/ jsx(OfficeCheckbox, {
|
|
@@ -28191,10 +28615,30 @@ function SpreadsheetSortDialog({ source, restoreFocusTarget, onApply, onRemember
|
|
|
28191
28615
|
restoreFocusTarget: ()=>optionsButtonRef.current,
|
|
28192
28616
|
onApply: applyOptions,
|
|
28193
28617
|
onClose: ()=>setOptionsOpen(false)
|
|
28618
|
+
}) : null,
|
|
28619
|
+
customListManagerOpen ? /*#__PURE__*/ jsx(SpreadsheetSortCustomListManagerDialog, {
|
|
28620
|
+
customLists: customLists,
|
|
28621
|
+
restoreFocusTarget: ()=>customListManagerButtonRef.current,
|
|
28622
|
+
onApply: applyCustomListManagement,
|
|
28623
|
+
onClose: ()=>setCustomListManagerOpen(false)
|
|
28194
28624
|
}) : null
|
|
28195
28625
|
]
|
|
28196
28626
|
});
|
|
28197
28627
|
}
|
|
28628
|
+
function reconcileManagedCustomListKey(key, changes) {
|
|
28629
|
+
if (void 0 === key.customList) return key;
|
|
28630
|
+
const change = changes.find((candidate)=>spreadsheetSortCustomListsEqual(candidate.previous, key.customList ?? []));
|
|
28631
|
+
if (!change) return key;
|
|
28632
|
+
return change.next ? {
|
|
28633
|
+
index: key.index,
|
|
28634
|
+
customList: [
|
|
28635
|
+
...change.next
|
|
28636
|
+
]
|
|
28637
|
+
} : {
|
|
28638
|
+
index: key.index,
|
|
28639
|
+
direction: 'ascending'
|
|
28640
|
+
};
|
|
28641
|
+
}
|
|
28198
28642
|
function cloneSpreadsheetSortKey(key) {
|
|
28199
28643
|
if ('cell-color' === key.sortOn || 'font-color' === key.sortOn) return {
|
|
28200
28644
|
...key
|
|
@@ -28384,6 +28828,22 @@ function useSpreadsheetSort({ commandsRef, contentRef, focusGrid, getGridFocusTa
|
|
|
28384
28828
|
}, [
|
|
28385
28829
|
customListStore
|
|
28386
28830
|
]);
|
|
28831
|
+
const updateCustomLists = useCallback((lists)=>{
|
|
28832
|
+
const normalized = normalizeStoredSpreadsheetSortCustomLists(lists);
|
|
28833
|
+
let source = customListStore ? 'stored' : 'session';
|
|
28834
|
+
if (customListStore) try {
|
|
28835
|
+
customListStore.save(normalized);
|
|
28836
|
+
} catch {
|
|
28837
|
+
source = 'session';
|
|
28838
|
+
showToast('无法写入本地自定义序列;本次更改仅在当前会话中保留。', 'error');
|
|
28839
|
+
}
|
|
28840
|
+
const next = Object.freeze(normalized.map((entries)=>createSpreadsheetSortCustomList(entries, source)).filter((list)=>null !== list));
|
|
28841
|
+
customListsRef.current = next;
|
|
28842
|
+
setCustomLists(next);
|
|
28843
|
+
return next;
|
|
28844
|
+
}, [
|
|
28845
|
+
customListStore
|
|
28846
|
+
]);
|
|
28387
28847
|
const sourceForCandidate = useCallback((request, candidate)=>{
|
|
28388
28848
|
if (!candidate.available) return null;
|
|
28389
28849
|
const sheet = contentRef.current.sheets.find((item)=>item.id === request.sheetId);
|
|
@@ -28410,28 +28870,13 @@ function useSpreadsheetSort({ commandsRef, contentRef, focusGrid, getGridFocusTa
|
|
|
28410
28870
|
const list = createSpreadsheetSortCustomList(candidate.entries, source);
|
|
28411
28871
|
if (!list) return candidate;
|
|
28412
28872
|
if (customListsRef.current.length >= 32) return candidate;
|
|
28413
|
-
const next =
|
|
28414
|
-
...customListsRef.current,
|
|
28415
|
-
list
|
|
28873
|
+
const next = updateCustomLists([
|
|
28874
|
+
...customListsRef.current.map((item)=>item.entries),
|
|
28875
|
+
list.entries
|
|
28416
28876
|
]);
|
|
28417
|
-
|
|
28418
|
-
customListStore.save(next.filter((item)=>'stored' === item.source).map((item)=>item.entries));
|
|
28419
|
-
} catch {
|
|
28420
|
-
showToast('无法写入本地自定义序列;该序列仅在本次会话中保留。', 'error');
|
|
28421
|
-
const session = createSpreadsheetSortCustomList(candidate.entries, 'session') ?? candidate;
|
|
28422
|
-
const fallback = Object.freeze([
|
|
28423
|
-
...customListsRef.current,
|
|
28424
|
-
session
|
|
28425
|
-
]);
|
|
28426
|
-
customListsRef.current = fallback;
|
|
28427
|
-
setCustomLists(fallback);
|
|
28428
|
-
return session;
|
|
28429
|
-
}
|
|
28430
|
-
customListsRef.current = next;
|
|
28431
|
-
setCustomLists(next);
|
|
28432
|
-
return list;
|
|
28877
|
+
return next.find((item)=>spreadsheetSortCustomListsEqual(item.entries, list.entries)) ?? list;
|
|
28433
28878
|
}, [
|
|
28434
|
-
|
|
28879
|
+
updateCustomLists
|
|
28435
28880
|
]);
|
|
28436
28881
|
const applyAuthorizedRequest = useCallback((request, selectedRange)=>{
|
|
28437
28882
|
authorizedRequestRef.current = {
|
|
@@ -28583,6 +29028,7 @@ function useSpreadsheetSort({ commandsRef, contentRef, focusGrid, getGridFocusTa
|
|
|
28583
29028
|
restoreFocusTarget: restoreFocusTarget,
|
|
28584
29029
|
onApply: apply,
|
|
28585
29030
|
onRememberCustomList: rememberCustomList,
|
|
29031
|
+
onUpdateCustomLists: updateCustomLists,
|
|
28586
29032
|
onClose: close
|
|
28587
29033
|
}) : surface?.kind === 'range' ? /*#__PURE__*/ jsx(SpreadsheetSortRangeDialog, {
|
|
28588
29034
|
source: surface.source,
|
|
@@ -28896,6 +29342,7 @@ function SpreadsheetEditorSurface({ autoFocus = true, content, collaborationHist
|
|
|
28896
29342
|
const previewRef = useRef(preview);
|
|
28897
29343
|
const spreadsheetRootRef = useRef(null);
|
|
28898
29344
|
const spreadsheetCanvasRef = useRef(null);
|
|
29345
|
+
const spreadsheetEditingEscapePendingRef = useRef(false);
|
|
28899
29346
|
const editorFocusOrigin = useOfficeEditorFocusOrigin();
|
|
28900
29347
|
const workbookRef = useRef(null);
|
|
28901
29348
|
const projectedWorkbookSheetsRef = useRef([]);
|
|
@@ -28953,6 +29400,32 @@ function SpreadsheetEditorSurface({ autoFocus = true, content, collaborationHist
|
|
|
28953
29400
|
}, [
|
|
28954
29401
|
preview
|
|
28955
29402
|
]);
|
|
29403
|
+
useEffect(()=>{
|
|
29404
|
+
const container = spreadsheetCanvasRef.current;
|
|
29405
|
+
if (!container || preview) return;
|
|
29406
|
+
const restoreGridFocus = ()=>requestAnimationFrame(()=>focusSpreadsheetGrid(container, {
|
|
29407
|
+
forceCellEditingExit: true
|
|
29408
|
+
}));
|
|
29409
|
+
const handleKeyDown = (event)=>{
|
|
29410
|
+
if ('Escape' !== event.key || !isSpreadsheetCellEditorTarget(event.target)) return;
|
|
29411
|
+
spreadsheetEditingEscapePendingRef.current = true;
|
|
29412
|
+
restoreGridFocus();
|
|
29413
|
+
};
|
|
29414
|
+
const handleKeyUp = (event)=>{
|
|
29415
|
+
if ('Escape' !== event.key || !spreadsheetEditingEscapePendingRef.current) return;
|
|
29416
|
+
spreadsheetEditingEscapePendingRef.current = false;
|
|
29417
|
+
restoreGridFocus();
|
|
29418
|
+
};
|
|
29419
|
+
container.addEventListener('keydown', handleKeyDown, true);
|
|
29420
|
+
container.addEventListener('keyup', handleKeyUp, true);
|
|
29421
|
+
return ()=>{
|
|
29422
|
+
container.removeEventListener('keydown', handleKeyDown, true);
|
|
29423
|
+
container.removeEventListener('keyup', handleKeyUp, true);
|
|
29424
|
+
spreadsheetEditingEscapePendingRef.current = false;
|
|
29425
|
+
};
|
|
29426
|
+
}, [
|
|
29427
|
+
preview
|
|
29428
|
+
]);
|
|
28956
29429
|
const spreadsheetZoomRef = useRef(100);
|
|
28957
29430
|
const [workbookInstance, setWorkbookInstance] = useState(null);
|
|
28958
29431
|
const bindWorkbookInstance = useCallback((instance)=>{
|
|
@@ -29383,6 +29856,20 @@ function SpreadsheetEditorSurface({ autoFocus = true, content, collaborationHist
|
|
|
29383
29856
|
});
|
|
29384
29857
|
const currentClipboardSelection = useCallback(()=>{
|
|
29385
29858
|
if (previewRef.current) return null;
|
|
29859
|
+
if (contextMenu) return {
|
|
29860
|
+
sheetId: contextMenu.selection.sheetId,
|
|
29861
|
+
range: {
|
|
29862
|
+
row: [
|
|
29863
|
+
contextMenu.range.row[0] ?? 0,
|
|
29864
|
+
contextMenu.range.row[1] ?? contextMenu.range.row[0] ?? 0
|
|
29865
|
+
],
|
|
29866
|
+
column: [
|
|
29867
|
+
contextMenu.range.column[0] ?? 0,
|
|
29868
|
+
contextMenu.range.column[1] ?? contextMenu.range.column[0] ?? 0
|
|
29869
|
+
]
|
|
29870
|
+
},
|
|
29871
|
+
plainText: contextMenu.selection.clipboard
|
|
29872
|
+
};
|
|
29386
29873
|
const sheetId = selectionState?.sheetId ?? activeSheetIdRef.current;
|
|
29387
29874
|
const sheet = contentRef.current.sheets.find((candidate)=>candidate.id === sheetId);
|
|
29388
29875
|
const selection = selectionState?.selection ?? sheet?.luckysheet_select_save?.at(-1);
|
|
@@ -29406,6 +29893,7 @@ function SpreadsheetEditorSurface({ autoFocus = true, content, collaborationHist
|
|
|
29406
29893
|
plainText: agentSelection.clipboard
|
|
29407
29894
|
} : null;
|
|
29408
29895
|
}, [
|
|
29896
|
+
contextMenu,
|
|
29409
29897
|
selectionState
|
|
29410
29898
|
]);
|
|
29411
29899
|
const spreadsheetClipboard = useSpreadsheetClipboard({
|
|
@@ -29754,9 +30242,6 @@ function SpreadsheetEditorSurface({ autoFocus = true, content, collaborationHist
|
|
|
29754
30242
|
onZoomIn: ()=>changeSpreadsheetWheelZoom('in'),
|
|
29755
30243
|
onZoomOut: ()=>changeSpreadsheetWheelZoom('out')
|
|
29756
30244
|
});
|
|
29757
|
-
const handleSpreadsheetEditingEscape = (event)=>{
|
|
29758
|
-
if ('Escape' === event.key && isSpreadsheetCellEditingTarget(event.target)) requestAnimationFrame(()=>focusSpreadsheetGrid(spreadsheetCanvasRef.current));
|
|
29759
|
-
};
|
|
29760
30245
|
const handleSpreadsheetKeyDownCapture = (event)=>{
|
|
29761
30246
|
releaseSpreadsheetSelectionRequest(selectionStateRef.current);
|
|
29762
30247
|
if ('Alt' === event.key && !event.repeat && event.target instanceof Element && event.target.closest('.fortune-sheet-overlay') && reserveAutoFilterAltKey()) {
|
|
@@ -29764,7 +30249,6 @@ function SpreadsheetEditorSurface({ autoFocus = true, content, collaborationHist
|
|
|
29764
30249
|
event.stopPropagation();
|
|
29765
30250
|
return;
|
|
29766
30251
|
}
|
|
29767
|
-
handleSpreadsheetEditingEscape(event);
|
|
29768
30252
|
};
|
|
29769
30253
|
const handleSpreadsheetPointerDownCapture = (event)=>{
|
|
29770
30254
|
releaseSpreadsheetSelectionRequest(selectionStateRef.current);
|
|
@@ -30135,7 +30619,7 @@ function SpreadsheetEditorSurface({ autoFocus = true, content, collaborationHist
|
|
|
30135
30619
|
]
|
|
30136
30620
|
});
|
|
30137
30621
|
}
|
|
30138
|
-
function focusSpreadsheetGrid(container, { focusOrigin = document.activeElement, forceInitial = true } = {}) {
|
|
30622
|
+
function focusSpreadsheetGrid(container, { focusOrigin = document.activeElement, forceCellEditingExit = false, forceInitial = true } = {}) {
|
|
30139
30623
|
if (!container) return;
|
|
30140
30624
|
spreadsheetFocusCleanups.get(container)?.();
|
|
30141
30625
|
let remainingFrames = spreadsheetFocusRetryFrames;
|
|
@@ -30174,8 +30658,9 @@ function focusSpreadsheetGrid(container, { focusOrigin = document.activeElement,
|
|
|
30174
30658
|
const restoreFocus = (force)=>{
|
|
30175
30659
|
if (focusRestorationStopped) return;
|
|
30176
30660
|
const activeElement = document.activeElement;
|
|
30177
|
-
|
|
30178
|
-
if (!force &&
|
|
30661
|
+
const activeCellEditor = isSpreadsheetCellEditorTarget(activeElement);
|
|
30662
|
+
if (!force && !forceCellEditingExit && isSpreadsheetCellEditingTarget(activeElement)) return void stopObservingFocusTarget();
|
|
30663
|
+
if (!force && !(forceCellEditingExit && activeCellEditor) && activeElement !== document.body && activeElement !== document.documentElement && activeElement !== commandTrigger && activeElement !== lastFocusedTarget) return void stopObservingFocusTarget();
|
|
30179
30664
|
const focusTarget = spreadsheetGridFocusTarget(container);
|
|
30180
30665
|
if (focusTarget) {
|
|
30181
30666
|
focusTarget.focus({
|