@a3s-lab/office 0.37.2 → 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 +4 -1
- package/dist/0~spreadsheet-editor.js +488 -53
- 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/office-kernel.wasm +0 -0
- package/dist/styles.css +109 -0
- package/docs/latest/en/browser-editor-architecture.md +12 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -309,9 +309,12 @@ and [CLI reference](./docs/latest/en/cli-reference.md).
|
|
|
309
309
|
|
|
310
310
|
## Current release
|
|
311
311
|
|
|
312
|
-
Version `0.37.
|
|
312
|
+
Version `0.37.3` keeps the release surface focused on local, testable
|
|
313
313
|
workflows:
|
|
314
314
|
|
|
315
|
+
- Spreadsheet Custom Sort now includes a responsive, keyboard-accessible
|
|
316
|
+
preference manager for creating, editing, deleting, and reordering bounded
|
|
317
|
+
user sequences while keeping the seven built-in sequences read-only.
|
|
315
318
|
- Document, visual Markdown, and Presentation text composition is safe for
|
|
316
319
|
Chinese and other IMEs: pre-edit text remains local, controlled replacement
|
|
317
320
|
waits for settlement, and only the committed value reaches the host.
|
|
@@ -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";
|
|
@@ -27408,6 +27408,385 @@ function SpreadsheetSortCustomListEditor({ error, level, text, onCancel, onChang
|
|
|
27408
27408
|
]
|
|
27409
27409
|
});
|
|
27410
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
|
+
}
|
|
27411
27790
|
function SpreadsheetSortOptionsDialog({ value, restoreFocusTarget, onApply, onClose }) {
|
|
27412
27791
|
const [draft, setDraft] = useState(value);
|
|
27413
27792
|
const formId = useId();
|
|
@@ -27866,7 +28245,7 @@ function spreadsheetSortPositionLabel(orientation, position) {
|
|
|
27866
28245
|
function isSpreadsheetSortAppearanceKind(value) {
|
|
27867
28246
|
return 'cell-color' === value || 'font-color' === value || 'icon' === value;
|
|
27868
28247
|
}
|
|
27869
|
-
function SpreadsheetSortDialog({ source, restoreFocusTarget, onApply, onRememberCustomList, onClose }) {
|
|
28248
|
+
function SpreadsheetSortDialog({ source, restoreFocusTarget, onApply, onRememberCustomList, onUpdateCustomLists, onClose }) {
|
|
27870
28249
|
const [value, setValue] = useState(()=>({
|
|
27871
28250
|
hasHeader: source.value.hasHeader,
|
|
27872
28251
|
keys: source.value.keys.map(cloneSpreadsheetSortKey),
|
|
@@ -27876,6 +28255,7 @@ function SpreadsheetSortDialog({ source, restoreFocusTarget, onApply, onRemember
|
|
|
27876
28255
|
}));
|
|
27877
28256
|
const [verticalHasHeader, setVerticalHasHeader] = useState(source.value.hasHeader);
|
|
27878
28257
|
const [optionsOpen, setOptionsOpen] = useState(false);
|
|
28258
|
+
const [customListManagerOpen, setCustomListManagerOpen] = useState(false);
|
|
27879
28259
|
const [customLists, setCustomLists] = useState(()=>initialSpreadsheetSortCustomLists(source));
|
|
27880
28260
|
const fields = 'top-to-bottom' === value.orientation ? source.columns : source.rows;
|
|
27881
28261
|
const appearanceFields = useMemo(()=>spreadsheetSortAppearanceFields(source.appearanceRows, source.range, value.orientation, value.hasHeader), [
|
|
@@ -27887,6 +28267,7 @@ function SpreadsheetSortDialog({ source, restoreFocusTarget, onApply, onRemember
|
|
|
27887
28267
|
const [customListDraft, setCustomListDraft] = useState(null);
|
|
27888
28268
|
const formId = useId();
|
|
27889
28269
|
const optionsButtonRef = useRef(null);
|
|
28270
|
+
const customListManagerButtonRef = useRef(null);
|
|
27890
28271
|
const nextKey = value.keys.length < 64 ? nextSpreadsheetSortKey(value.keys, fields, appearanceFields) : null;
|
|
27891
28272
|
const replaceKey = (index, replacement)=>{
|
|
27892
28273
|
setValue((current)=>({
|
|
@@ -27985,6 +28366,18 @@ function SpreadsheetSortDialog({ source, restoreFocusTarget, onApply, onRemember
|
|
|
27985
28366
|
]
|
|
27986
28367
|
});
|
|
27987
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
|
+
};
|
|
27988
28381
|
return /*#__PURE__*/ jsxs(Fragment, {
|
|
27989
28382
|
children: [
|
|
27990
28383
|
/*#__PURE__*/ jsx(Dialog, {
|
|
@@ -28015,40 +28408,60 @@ function SpreadsheetSortDialog({ source, restoreFocusTarget, onApply, onRemember
|
|
|
28015
28408
|
/*#__PURE__*/ jsxs("div", {
|
|
28016
28409
|
className: "work-spreadsheet-sort-toolbar",
|
|
28017
28410
|
children: [
|
|
28018
|
-
/*#__PURE__*/ jsxs(
|
|
28019
|
-
|
|
28020
|
-
type: "button",
|
|
28021
|
-
disabled: !nextKey,
|
|
28022
|
-
onClick: ()=>{
|
|
28023
|
-
if (!nextKey) return;
|
|
28024
|
-
setCustomListDraft(null);
|
|
28025
|
-
setValue((current)=>({
|
|
28026
|
-
...current,
|
|
28027
|
-
keys: [
|
|
28028
|
-
...current.keys,
|
|
28029
|
-
cloneSpreadsheetSortKey(nextKey)
|
|
28030
|
-
]
|
|
28031
|
-
}));
|
|
28032
|
-
},
|
|
28411
|
+
/*#__PURE__*/ jsxs("div", {
|
|
28412
|
+
className: "work-spreadsheet-sort-toolbar-actions",
|
|
28033
28413
|
children: [
|
|
28034
|
-
/*#__PURE__*/
|
|
28035
|
-
|
|
28036
|
-
|
|
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
|
+
]
|
|
28037
28436
|
}),
|
|
28038
|
-
|
|
28039
|
-
|
|
28040
|
-
|
|
28041
|
-
|
|
28042
|
-
|
|
28043
|
-
|
|
28044
|
-
|
|
28045
|
-
|
|
28046
|
-
|
|
28047
|
-
|
|
28048
|
-
|
|
28049
|
-
|
|
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
|
+
]
|
|
28050
28449
|
}),
|
|
28051
|
-
|
|
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
|
+
})
|
|
28052
28465
|
]
|
|
28053
28466
|
}),
|
|
28054
28467
|
/*#__PURE__*/ jsx(OfficeCheckbox, {
|
|
@@ -28202,10 +28615,30 @@ function SpreadsheetSortDialog({ source, restoreFocusTarget, onApply, onRemember
|
|
|
28202
28615
|
restoreFocusTarget: ()=>optionsButtonRef.current,
|
|
28203
28616
|
onApply: applyOptions,
|
|
28204
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)
|
|
28205
28624
|
}) : null
|
|
28206
28625
|
]
|
|
28207
28626
|
});
|
|
28208
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
|
+
}
|
|
28209
28642
|
function cloneSpreadsheetSortKey(key) {
|
|
28210
28643
|
if ('cell-color' === key.sortOn || 'font-color' === key.sortOn) return {
|
|
28211
28644
|
...key
|
|
@@ -28395,6 +28828,22 @@ function useSpreadsheetSort({ commandsRef, contentRef, focusGrid, getGridFocusTa
|
|
|
28395
28828
|
}, [
|
|
28396
28829
|
customListStore
|
|
28397
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
|
+
]);
|
|
28398
28847
|
const sourceForCandidate = useCallback((request, candidate)=>{
|
|
28399
28848
|
if (!candidate.available) return null;
|
|
28400
28849
|
const sheet = contentRef.current.sheets.find((item)=>item.id === request.sheetId);
|
|
@@ -28421,28 +28870,13 @@ function useSpreadsheetSort({ commandsRef, contentRef, focusGrid, getGridFocusTa
|
|
|
28421
28870
|
const list = createSpreadsheetSortCustomList(candidate.entries, source);
|
|
28422
28871
|
if (!list) return candidate;
|
|
28423
28872
|
if (customListsRef.current.length >= 32) return candidate;
|
|
28424
|
-
const next =
|
|
28425
|
-
...customListsRef.current,
|
|
28426
|
-
list
|
|
28873
|
+
const next = updateCustomLists([
|
|
28874
|
+
...customListsRef.current.map((item)=>item.entries),
|
|
28875
|
+
list.entries
|
|
28427
28876
|
]);
|
|
28428
|
-
|
|
28429
|
-
customListStore.save(next.filter((item)=>'stored' === item.source).map((item)=>item.entries));
|
|
28430
|
-
} catch {
|
|
28431
|
-
showToast('无法写入本地自定义序列;该序列仅在本次会话中保留。', 'error');
|
|
28432
|
-
const session = createSpreadsheetSortCustomList(candidate.entries, 'session') ?? candidate;
|
|
28433
|
-
const fallback = Object.freeze([
|
|
28434
|
-
...customListsRef.current,
|
|
28435
|
-
session
|
|
28436
|
-
]);
|
|
28437
|
-
customListsRef.current = fallback;
|
|
28438
|
-
setCustomLists(fallback);
|
|
28439
|
-
return session;
|
|
28440
|
-
}
|
|
28441
|
-
customListsRef.current = next;
|
|
28442
|
-
setCustomLists(next);
|
|
28443
|
-
return list;
|
|
28877
|
+
return next.find((item)=>spreadsheetSortCustomListsEqual(item.entries, list.entries)) ?? list;
|
|
28444
28878
|
}, [
|
|
28445
|
-
|
|
28879
|
+
updateCustomLists
|
|
28446
28880
|
]);
|
|
28447
28881
|
const applyAuthorizedRequest = useCallback((request, selectedRange)=>{
|
|
28448
28882
|
authorizedRequestRef.current = {
|
|
@@ -28594,6 +29028,7 @@ function useSpreadsheetSort({ commandsRef, contentRef, focusGrid, getGridFocusTa
|
|
|
28594
29028
|
restoreFocusTarget: restoreFocusTarget,
|
|
28595
29029
|
onApply: apply,
|
|
28596
29030
|
onRememberCustomList: rememberCustomList,
|
|
29031
|
+
onUpdateCustomLists: updateCustomLists,
|
|
28597
29032
|
onClose: close
|
|
28598
29033
|
}) : surface?.kind === 'range' ? /*#__PURE__*/ jsx(SpreadsheetSortRangeDialog, {
|
|
28599
29034
|
source: surface.source,
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type SpreadsheetSortCustomList } from './spreadsheet-sort-custom-list';
|
|
2
|
+
export interface SpreadsheetSortCustomListManagementChange {
|
|
3
|
+
next: readonly string[] | null;
|
|
4
|
+
previous: readonly string[];
|
|
5
|
+
}
|
|
6
|
+
export interface SpreadsheetSortCustomListManagementResult {
|
|
7
|
+
changes: readonly SpreadsheetSortCustomListManagementChange[];
|
|
8
|
+
lists: readonly (readonly string[])[];
|
|
9
|
+
}
|
|
10
|
+
export declare function SpreadsheetSortCustomListManagerDialog({ customLists, restoreFocusTarget, onApply, onClose, }: {
|
|
11
|
+
customLists: readonly SpreadsheetSortCustomList[];
|
|
12
|
+
restoreFocusTarget: () => HTMLElement | null;
|
|
13
|
+
onApply: (value: SpreadsheetSortCustomListManagementResult) => void;
|
|
14
|
+
onClose: () => void;
|
|
15
|
+
}): import("react").JSX.Element;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { type SpreadsheetSortDialogSource, type SpreadsheetSortDialogValue } from './spreadsheet-sort';
|
|
2
2
|
import { type SpreadsheetSortCustomList } from './spreadsheet-sort-custom-list';
|
|
3
|
-
export declare function SpreadsheetSortDialog({ source, restoreFocusTarget, onApply, onRememberCustomList, onClose, }: {
|
|
3
|
+
export declare function SpreadsheetSortDialog({ source, restoreFocusTarget, onApply, onRememberCustomList, onUpdateCustomLists, onClose, }: {
|
|
4
4
|
source: SpreadsheetSortDialogSource;
|
|
5
5
|
restoreFocusTarget: () => HTMLElement | null;
|
|
6
6
|
onApply: (value: SpreadsheetSortDialogValue) => boolean;
|
|
7
|
-
onRememberCustomList?: (list: SpreadsheetSortCustomList) => SpreadsheetSortCustomList |
|
|
7
|
+
onRememberCustomList?: (list: SpreadsheetSortCustomList) => SpreadsheetSortCustomList | undefined;
|
|
8
|
+
onUpdateCustomLists?: (lists: readonly (readonly string[])[]) => readonly SpreadsheetSortCustomList[] | undefined;
|
|
8
9
|
onClose: () => void;
|
|
9
10
|
}): import("react").JSX.Element;
|
package/dist/office-kernel.wasm
CHANGED
|
Binary file
|
package/dist/styles.css
CHANGED
|
@@ -18122,6 +18122,13 @@ sub [data-office-character-position-half-points], sup [data-office-character-pos
|
|
|
18122
18122
|
gap: 6px;
|
|
18123
18123
|
}
|
|
18124
18124
|
|
|
18125
|
+
.work-spreadsheet-sort-toolbar-actions {
|
|
18126
|
+
align-items: center;
|
|
18127
|
+
gap: 6px;
|
|
18128
|
+
min-width: 0;
|
|
18129
|
+
display: flex;
|
|
18130
|
+
}
|
|
18131
|
+
|
|
18125
18132
|
.work-spreadsheet-sort-toolbar .work-office-checkbox {
|
|
18126
18133
|
min-height: 34px;
|
|
18127
18134
|
padding: 6px 9px;
|
|
@@ -18314,6 +18321,96 @@ sub [data-office-character-position-half-points], sup [data-office-character-pos
|
|
|
18314
18321
|
line-height: 1.45;
|
|
18315
18322
|
}
|
|
18316
18323
|
|
|
18324
|
+
.work-spreadsheet-sort-custom-list-manager {
|
|
18325
|
+
--work-office-control-accent: var(--work-spreadsheet-accent, #159469);
|
|
18326
|
+
width: min(720px, 100%);
|
|
18327
|
+
}
|
|
18328
|
+
|
|
18329
|
+
.work-spreadsheet-sort-custom-list-manager-layout {
|
|
18330
|
+
grid-template-columns: minmax(220px, .85fr) minmax(280px, 1.15fr);
|
|
18331
|
+
gap: 14px;
|
|
18332
|
+
display: grid;
|
|
18333
|
+
}
|
|
18334
|
+
|
|
18335
|
+
.work-spreadsheet-sort-custom-list-manager-layout > section, .work-spreadsheet-sort-custom-list-manager-layout label {
|
|
18336
|
+
gap: 7px;
|
|
18337
|
+
min-width: 0;
|
|
18338
|
+
display: grid;
|
|
18339
|
+
}
|
|
18340
|
+
|
|
18341
|
+
.work-spreadsheet-sort-custom-list-manager-layout > section {
|
|
18342
|
+
align-content: start;
|
|
18343
|
+
}
|
|
18344
|
+
|
|
18345
|
+
.work-spreadsheet-sort-custom-list-manager-layout label > span {
|
|
18346
|
+
color: var(--a3s-muted);
|
|
18347
|
+
font-size: 10px;
|
|
18348
|
+
font-weight: 650;
|
|
18349
|
+
}
|
|
18350
|
+
|
|
18351
|
+
.work-spreadsheet-sort-custom-list-manager select, .work-spreadsheet-sort-custom-list-manager textarea {
|
|
18352
|
+
box-sizing: border-box;
|
|
18353
|
+
border: 1px solid var(--a3s-line-strong);
|
|
18354
|
+
background: var(--a3s-panel);
|
|
18355
|
+
width: 100%;
|
|
18356
|
+
min-width: 0;
|
|
18357
|
+
min-height: 252px;
|
|
18358
|
+
color: var(--a3s-ink);
|
|
18359
|
+
font: inherit;
|
|
18360
|
+
border-radius: 6px;
|
|
18361
|
+
padding: 8px;
|
|
18362
|
+
font-size: 11px;
|
|
18363
|
+
line-height: 1.5;
|
|
18364
|
+
}
|
|
18365
|
+
|
|
18366
|
+
.work-spreadsheet-sort-custom-list-manager textarea {
|
|
18367
|
+
resize: vertical;
|
|
18368
|
+
}
|
|
18369
|
+
|
|
18370
|
+
.work-spreadsheet-sort-custom-list-manager textarea[readonly] {
|
|
18371
|
+
background: var(--a3s-panel-soft);
|
|
18372
|
+
color: var(--a3s-muted);
|
|
18373
|
+
}
|
|
18374
|
+
|
|
18375
|
+
.work-spreadsheet-sort-custom-list-manager select:focus-visible, .work-spreadsheet-sort-custom-list-manager textarea:focus-visible {
|
|
18376
|
+
border-color: var(--work-spreadsheet-accent, #159469);
|
|
18377
|
+
outline: 2px solid
|
|
18378
|
+
color-mix(in srgb, var(--work-spreadsheet-accent, #159469) 24%, transparent);
|
|
18379
|
+
outline-offset: 1px;
|
|
18380
|
+
}
|
|
18381
|
+
|
|
18382
|
+
.work-spreadsheet-sort-custom-list-manager-layout section > p, .work-spreadsheet-sort-custom-list-manager-note {
|
|
18383
|
+
color: var(--a3s-muted);
|
|
18384
|
+
margin: 0;
|
|
18385
|
+
font-size: 10px;
|
|
18386
|
+
line-height: 1.45;
|
|
18387
|
+
}
|
|
18388
|
+
|
|
18389
|
+
.work-spreadsheet-sort-custom-list-manager-layout section > .work-spreadsheet-sort-custom-list-error {
|
|
18390
|
+
color: var(--a3s-danger, #b42318);
|
|
18391
|
+
}
|
|
18392
|
+
|
|
18393
|
+
.work-spreadsheet-sort-custom-list-manager-actions {
|
|
18394
|
+
justify-content: flex-end;
|
|
18395
|
+
align-items: center;
|
|
18396
|
+
gap: 6px;
|
|
18397
|
+
display: flex;
|
|
18398
|
+
}
|
|
18399
|
+
|
|
18400
|
+
.work-spreadsheet-sort-custom-list-manager-actions .ds-button {
|
|
18401
|
+
gap: 6px;
|
|
18402
|
+
}
|
|
18403
|
+
|
|
18404
|
+
.work-spreadsheet-sort-custom-list-manager-actions .ds-button[aria-label] {
|
|
18405
|
+
width: 34px;
|
|
18406
|
+
min-width: 34px;
|
|
18407
|
+
padding-inline: 0;
|
|
18408
|
+
}
|
|
18409
|
+
|
|
18410
|
+
.work-spreadsheet-sort-custom-list-manager-note {
|
|
18411
|
+
margin-block-start: 12px;
|
|
18412
|
+
}
|
|
18413
|
+
|
|
18317
18414
|
.work-spreadsheet-sort-range-dialog {
|
|
18318
18415
|
--work-office-control-accent: var(--work-spreadsheet-accent, #159469);
|
|
18319
18416
|
width: min(500px, 100%);
|
|
@@ -18395,6 +18492,18 @@ sub [data-office-character-position-half-points], sup [data-office-character-pos
|
|
|
18395
18492
|
align-items: stretch;
|
|
18396
18493
|
}
|
|
18397
18494
|
|
|
18495
|
+
.work-spreadsheet-sort-toolbar-actions {
|
|
18496
|
+
flex-wrap: wrap;
|
|
18497
|
+
}
|
|
18498
|
+
|
|
18499
|
+
.work-spreadsheet-sort-custom-list-manager-layout {
|
|
18500
|
+
grid-template-columns: minmax(0, 1fr);
|
|
18501
|
+
}
|
|
18502
|
+
|
|
18503
|
+
.work-spreadsheet-sort-custom-list-manager select, .work-spreadsheet-sort-custom-list-manager textarea {
|
|
18504
|
+
min-height: 180px;
|
|
18505
|
+
}
|
|
18506
|
+
|
|
18398
18507
|
.work-spreadsheet-sort-level {
|
|
18399
18508
|
grid-template-columns: minmax(0, 1fr);
|
|
18400
18509
|
}
|
|
@@ -1471,14 +1471,19 @@ first/last placement. The
|
|
|
1471
1471
|
normalization, duplicate and size guards, seven immutable month/weekday lists,
|
|
1472
1472
|
and rank matching; the validated request clones custom entries so command
|
|
1473
1473
|
execution has no dependency on mutable UI state. The browser adapters own a
|
|
1474
|
-
bounded user-list registry and never
|
|
1475
|
-
|
|
1474
|
+
bounded user-list registry and never write preferences into controlled workbook
|
|
1475
|
+
content. A dedicated manager stages create, edit, delete, and reorder operations
|
|
1476
|
+
against stable list identities, then publishes one normalized preference set.
|
|
1477
|
+
Built-ins remain read-only, no-op confirmation skips the storage boundary,
|
|
1478
|
+
edited active keys receive the replacement sequence, and deleted active keys
|
|
1479
|
+
fall back to ascending value order. Without a store the registry remains scoped
|
|
1480
|
+
to the mounted session.
|
|
1476
1481
|
The optional typed `SpreadsheetSortCustomListStore` synchronously loads and
|
|
1477
1482
|
saves canonical lists through a host-selected local backend. The provided
|
|
1478
1483
|
`LocalStorageSpreadsheetSortCustomListStore` accepts an injected Storage
|
|
1479
1484
|
object, uses a versioned key, and validates, deduplicates, and caps reads at 32
|
|
1480
|
-
lists. Corrupt reads fail closed; a rejected write visibly downgrades the
|
|
1481
|
-
|
|
1485
|
+
lists. Corrupt reads fail closed; a rejected write visibly downgrades the
|
|
1486
|
+
complete changed preference set to session scope. A stored list precedes an identical request-carried
|
|
1482
1487
|
session copy so persistence identity remains stable. The separate
|
|
1483
1488
|
`spreadsheet-sort-appearance` model snapshots direct native styles plus
|
|
1484
1489
|
calculated conditional-format output, preserves no-fill/automatic identities,
|
|
@@ -1497,9 +1502,9 @@ One accepted operation crosses the Fortune boundary as one range write and one
|
|
|
1497
1502
|
controlled Undo record. Table, worksheet-AutoFilter, hyperlink-map,
|
|
1498
1503
|
imported-formula-metadata, and border-sidecar intersections fail closed because
|
|
1499
1504
|
those models still own coordinates outside the cell matrix. Moving large sorts,
|
|
1500
|
-
large aggregate/rank scans, remaining advanced filter predicates,
|
|
1501
|
-
|
|
1502
|
-
|
|
1505
|
+
large aggregate/rank scans, remaining advanced filter predicates, and
|
|
1506
|
+
structural sidecar reconciliation into the Worker/WASM kernel remains Stage 3
|
|
1507
|
+
work.
|
|
1503
1508
|
Direct host focus of the native grid now enters the same bounded focus observer
|
|
1504
1509
|
used by ribbon commands. If a controlled workbook update replaces the focused
|
|
1505
1510
|
Fortune overlay, focus transfers to its connected replacement; deliberate
|