@a3s-lab/office 0.37.2 → 0.37.4

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/dist/5416.js CHANGED
@@ -2756,6 +2756,33 @@ function workSpreadsheetAutoFilterManuallyHiddenRows(sheet) {
2756
2756
  }
2757
2757
  return manuallyHidden;
2758
2758
  }
2759
+ function workSpreadsheetAutoFilterOwnedRows(sheet) {
2760
+ return filterHiddenRows(sheet.filter);
2761
+ }
2762
+ function workSpreadsheetFilterHiddenRows(sheet, range, column, criteria, context = {
2763
+ now: new Date()
2764
+ }) {
2765
+ const normalizedCriteria = normalizeWorkSpreadsheetFilterCriteria(criteria);
2766
+ const normalizedRange = normalizedWorkSpreadsheetAutoFilterRange(range);
2767
+ if (!normalizedCriteria || !normalizedRange || !columnInRange(normalizedRange, column)) return null;
2768
+ return hiddenRowsForCriteria(sheet, normalizedRange, column, normalizedCriteria, context);
2769
+ }
2770
+ function workSpreadsheetSheetWithReappliedAutoFilterCriteria(sheet, criteriaSource, manuallyHiddenRows, context = {
2771
+ now: new Date()
2772
+ }) {
2773
+ const range = normalizedWorkSpreadsheetAutoFilterRange(sheet.filter_select);
2774
+ if (!range) return sheet;
2775
+ const entries = workSpreadsheetAutoFilterCriteriaEntries(criteriaSource);
2776
+ const filter = {};
2777
+ for (const entry of entries){
2778
+ const column = range.column[0] + entry.column;
2779
+ const criteria = normalizeWorkSpreadsheetFilterCriteria(entry.criteria);
2780
+ if (!criteria || !columnInRange(range, column)) continue;
2781
+ const rowhidden = hiddenRowsForCriteria(sheet, range, column, criteria, context);
2782
+ if (rowhidden) filter[String(entry.column)] = filterColumnState(range, column, criteria, rowhidden);
2783
+ }
2784
+ return sheetWithFilterState(sheet, filter, manuallyHiddenRows);
2785
+ }
2759
2786
  function workSpreadsheetSheetWithImportedAutoFilterCriteria(sheet, entries, context = {
2760
2787
  now: new Date()
2761
2788
  }) {
@@ -4047,4 +4074,4 @@ function normalizeStoredSpreadsheetSortCustomLists(input) {
4047
4074
  function spreadsheet_sort_custom_list_store_isRecord(value) {
4048
4075
  return Boolean(value && 'object' == typeof value && !Array.isArray(value));
4049
4076
  }
4050
- export { DEFAULT_SPREADSHEET_SORT_CUSTOM_LIST_STORAGE_KEY, LocalStorageSpreadsheetSortCustomListStore, SPREADSHEET_TABLE_TOTALS_FUNCTIONS, activeXlsxNativeFill, activeXlsxSemanticColorOrigin, applyImportedXlsxRichText, boundedSpreadsheetDataValidationText, coalesceXlsxRichTextRuns, createSpreadsheetSortCustomList, createWorkOfficeSpreadsheetCollaborationBinding as createOfficeSpreadsheetCollaborationBinding, createXlsxRichTextReadContext, deleteXlsxNativeFills, directXlsxAlignment, directXlsxFontStyle, fillSpreadsheetTableCalculatedColumns, hasXlsxDirectFontStyle, initializeWorkOfficeSpreadsheetCollaboration as initializeOfficeSpreadsheetCollaboration, isHighSurrogate, isLowSurrogate, isSpreadsheetTextOrientationId, isSpreadsheetUnderlineStyle, mergeSpreadsheetSortCustomLists, normalizeSpreadsheetDataValidationErrorStyle, normalizeSpreadsheetDateValidationBoundary, normalizeSpreadsheetTableCalculatedFormula, normalizeSpreadsheetTableTotalsFormula, normalizeSpreadsheetTableTotalsLabel, normalizeStoredSpreadsheetSortCustomLists, normalizeWorkSpreadsheetFilterCriteria, normalizeXlsxRichTextCell, normalizeXlsxRichTextColor, normalizeXlsxRichTextEditSource, normalizeXlsxRichTextRun, normalizedWorkSpreadsheetAutoFilterRange, parseSpreadsheetSortCustomList, patchSpreadsheetRichTextFontRuns, readWorkOfficeSpreadsheetCollaboration as readOfficeSpreadsheetCollaboration, readXlsxRichTextCells, reconcileSpreadsheetTableCalculatedColumns, reconcileSpreadsheetTableTotalsColumns, replaceWorkOfficeSpreadsheetCollaboration as replaceOfficeSpreadsheetCollaboration, sameXlsxRichTextRunStyle, sheetHasXlsxRichTextCells, spreadsheetCellValueWithDiagonalBorder, spreadsheetDateValidationFormula, spreadsheetDiagonalBorderFromCellValue, spreadsheetExplicitTextOrientationFromCell, spreadsheetSortCustomListMatchKey, spreadsheetSortCustomListsEqual, spreadsheetTableTotalsColumnPatch, spreadsheetTableTotalsFunctionFromOoxml, spreadsheetTableTotalsFunctionLabel, spreadsheetTableTotalsFunctionToOoxml, spreadsheetTableTotalsRowHasContent, spreadsheetTextOrientationCellStyle, spreadsheetTextOrientationChoiceFromCell, spreadsheetTextOrientationFromAngle, spreadsheetTextOrientationFromCell, spreadsheetTextOrientationFromChoice, spreadsheetTextOrientationFromXlsx, spreadsheetUnderlineCellValue, spreadsheetUnderlineCellValueFromSheetJs, spreadsheetUnderlineCellValueFromXlsx, spreadsheetUnderlineStyle, spreadsheetVisibleTextRotationFromCell, synchronizeSpreadsheetTableTotalsRow, validXlsxRichText, validateSpreadsheetSortCustomList, withDefaultSpreadsheetTableTotalsLabel, workSpreadsheetAutoFilterCriteria, workSpreadsheetAutoFilterCriteriaEntries, workSpreadsheetAutoFilterManuallyHiddenRows, workSpreadsheetCellIsDate, workSpreadsheetFilterTextCharacters, workSpreadsheetHasUnescapedWildcard, workSpreadsheetSheetWithAutoFilterCriteria, workSpreadsheetSheetWithImportedAutoFilterCriteria, workSpreadsheetSheetWithoutAutoFilterCriteria, writeXlsxRichTextCells, xlsxAlignmentMatches, xlsxBooleanAttribute, xlsxBorderLineMatches, xlsxColorMatches, xlsxNativeFillCellKeys, xlsxNativeFillKey, xlsxNativeFillSemanticColors, xlsxRichTextCellText, xlsxRichTextStyleOrigins, xlsxStyleCollectionIndex, xlsxToggleEnabled, xlsxUnderlineStyle };
4077
+ export { DEFAULT_SPREADSHEET_SORT_CUSTOM_LIST_STORAGE_KEY, LocalStorageSpreadsheetSortCustomListStore, SPREADSHEET_TABLE_TOTALS_FUNCTIONS, activeXlsxNativeFill, activeXlsxSemanticColorOrigin, applyImportedXlsxRichText, boundedSpreadsheetDataValidationText, coalesceXlsxRichTextRuns, createSpreadsheetSortCustomList, createWorkOfficeSpreadsheetCollaborationBinding as createOfficeSpreadsheetCollaborationBinding, createXlsxRichTextReadContext, deleteXlsxNativeFills, directXlsxAlignment, directXlsxFontStyle, fillSpreadsheetTableCalculatedColumns, hasXlsxDirectFontStyle, initializeWorkOfficeSpreadsheetCollaboration as initializeOfficeSpreadsheetCollaboration, isHighSurrogate, isLowSurrogate, isSpreadsheetTextOrientationId, isSpreadsheetUnderlineStyle, mergeSpreadsheetSortCustomLists, normalizeSpreadsheetDataValidationErrorStyle, normalizeSpreadsheetDateValidationBoundary, normalizeSpreadsheetTableCalculatedFormula, normalizeSpreadsheetTableTotalsFormula, normalizeSpreadsheetTableTotalsLabel, normalizeStoredSpreadsheetSortCustomLists, normalizeWorkSpreadsheetFilterCriteria, normalizeXlsxRichTextCell, normalizeXlsxRichTextColor, normalizeXlsxRichTextEditSource, normalizeXlsxRichTextRun, normalizedWorkSpreadsheetAutoFilterRange, parseSpreadsheetSortCustomList, patchSpreadsheetRichTextFontRuns, readWorkOfficeSpreadsheetCollaboration as readOfficeSpreadsheetCollaboration, readXlsxRichTextCells, reconcileSpreadsheetTableCalculatedColumns, reconcileSpreadsheetTableTotalsColumns, replaceWorkOfficeSpreadsheetCollaboration as replaceOfficeSpreadsheetCollaboration, sameXlsxRichTextRunStyle, sheetHasXlsxRichTextCells, spreadsheetCellValueWithDiagonalBorder, spreadsheetDateValidationFormula, spreadsheetDiagonalBorderFromCellValue, spreadsheetExplicitTextOrientationFromCell, spreadsheetSortCustomListMatchKey, spreadsheetSortCustomListsEqual, spreadsheetTableTotalsColumnPatch, spreadsheetTableTotalsFunctionFromOoxml, spreadsheetTableTotalsFunctionLabel, spreadsheetTableTotalsFunctionToOoxml, spreadsheetTableTotalsRowHasContent, spreadsheetTextOrientationCellStyle, spreadsheetTextOrientationChoiceFromCell, spreadsheetTextOrientationFromAngle, spreadsheetTextOrientationFromCell, spreadsheetTextOrientationFromChoice, spreadsheetTextOrientationFromXlsx, spreadsheetUnderlineCellValue, spreadsheetUnderlineCellValueFromSheetJs, spreadsheetUnderlineCellValueFromXlsx, spreadsheetUnderlineStyle, spreadsheetVisibleTextRotationFromCell, synchronizeSpreadsheetTableTotalsRow, validXlsxRichText, validateSpreadsheetSortCustomList, withDefaultSpreadsheetTableTotalsLabel, workSpreadsheetAutoFilterCriteria, workSpreadsheetAutoFilterCriteriaEntries, workSpreadsheetAutoFilterManuallyHiddenRows, workSpreadsheetAutoFilterOwnedRows, workSpreadsheetCellIsDate, workSpreadsheetFilterHiddenRows, workSpreadsheetFilterTextCharacters, workSpreadsheetHasUnescapedWildcard, workSpreadsheetSheetWithAutoFilterCriteria, workSpreadsheetSheetWithImportedAutoFilterCriteria, workSpreadsheetSheetWithReappliedAutoFilterCriteria, workSpreadsheetSheetWithoutAutoFilterCriteria, writeXlsxRichTextCells, xlsxAlignmentMatches, xlsxBooleanAttribute, xlsxBorderLineMatches, xlsxColorMatches, xlsxNativeFillCellKeys, xlsxNativeFillKey, xlsxNativeFillSemanticColors, xlsxRichTextCellText, xlsxRichTextStyleOrigins, xlsxStyleCollectionIndex, xlsxToggleEnabled, xlsxUnderlineStyle };
@@ -0,0 +1,6 @@
1
+ import type { Op } from '@fortune-sheet/core';
2
+ import type { WorkSpreadsheetContent, WorkSpreadsheetSheet } from '../work-types';
3
+ import type { SpreadsheetCellRange } from './spreadsheet-cell-range';
4
+ export declare function reconcileSpreadsheetFiltersAfterFortune(sheets: WorkSpreadsheetContent['sheets'], sourceSheets: WorkSpreadsheetContent['sheets'], operations?: readonly Op[]): WorkSpreadsheetContent['sheets'];
5
+ export declare function reconcileSpreadsheetFiltersAfterSort(sheet: WorkSpreadsheetSheet, source: WorkSpreadsheetSheet, range: SpreadsheetCellRange, sourceIndexes: readonly number[]): WorkSpreadsheetSheet | null;
6
+ export declare function spreadsheetFilterReconciliationIsBounded(sheet: WorkSpreadsheetSheet): boolean;
@@ -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 | void;
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;
@@ -1,6 +1,7 @@
1
1
  import type { SpreadsheetSortOptions } from './spreadsheet-sort';
2
- export declare function SpreadsheetSortOptionsDialog({ value, restoreFocusTarget, onApply, onClose, }: {
2
+ export declare function SpreadsheetSortOptionsDialog({ value, orientationLocked, restoreFocusTarget, onApply, onClose, }: {
3
3
  value: SpreadsheetSortOptions;
4
+ orientationLocked?: boolean;
4
5
  restoreFocusTarget: () => HTMLElement | null;
5
6
  onApply: (value: SpreadsheetSortOptions) => void;
6
7
  onClose: () => void;
@@ -55,10 +55,24 @@ export interface SpreadsheetSortTarget {
55
55
  activeColumn: number;
56
56
  activeRow: number;
57
57
  range: SpreadsheetCellRange;
58
+ scope?: SpreadsheetSortOwnedScope;
59
+ }
60
+ export type SpreadsheetSortOwnedScope = {
61
+ hasHeader: true;
62
+ kind: 'auto-filter';
63
+ } | {
64
+ hasHeader: boolean;
65
+ kind: 'table';
66
+ tableId: string;
67
+ };
68
+ export interface SpreadsheetSortOwnedRange {
69
+ range: SpreadsheetCellRange;
70
+ scope: SpreadsheetSortOwnedScope;
58
71
  }
59
72
  export interface SpreadsheetSortRangeCandidate {
60
73
  available: boolean;
61
74
  range: SpreadsheetCellRange;
75
+ scope?: SpreadsheetSortOwnedScope;
62
76
  }
63
77
  export type SpreadsheetSortIntent = {
64
78
  type: 'custom';
@@ -83,15 +97,18 @@ export interface SpreadsheetSortRangeDialogSource {
83
97
  canSortExpandedRange: boolean;
84
98
  canSortSelection: boolean;
85
99
  expandedRangeReference: string;
100
+ ownedScope?: SpreadsheetSortOwnedScope;
86
101
  selectedRangeReference: string;
87
102
  sheetName: string;
88
103
  }
89
104
  export type SpreadsheetSortRequest = Omit<SpreadsheetSortDialogValue, keyof SpreadsheetSortTextOptions> & Partial<SpreadsheetSortTextOptions> & {
90
105
  range: SpreadsheetCellRange;
106
+ scope?: SpreadsheetSortOwnedScope;
91
107
  sheetId: string;
92
108
  };
93
109
  export interface SpreadsheetSortNormalizedRequest extends SpreadsheetSortDialogValue {
94
110
  range: SpreadsheetCellRange;
111
+ scope?: SpreadsheetSortOwnedScope;
95
112
  sheetId: string;
96
113
  }
97
114
  export interface SpreadsheetSortField {
@@ -106,11 +123,12 @@ export interface SpreadsheetSortDialogSource {
106
123
  range: SpreadsheetCellRange;
107
124
  rangeReference: string;
108
125
  rows: SpreadsheetSortField[];
126
+ scope?: SpreadsheetSortOwnedScope;
109
127
  sheetId: string;
110
128
  sheetName: string;
111
129
  value: SpreadsheetSortDialogValue;
112
130
  }
113
- export type SpreadsheetSortErrorCode = 'column-out-of-range' | 'duplicate-key' | 'formula-reference-out-of-range' | 'invalid-appearance' | 'invalid-case-sensitivity' | 'invalid-custom-list' | 'invalid-direction' | 'invalid-header' | 'invalid-matrix' | 'invalid-orientation' | 'invalid-range' | 'invalid-text-method' | 'missing-key' | 'not-enough-columns' | 'not-enough-rows' | 'range-too-large' | 'row-out-of-range' | 'too-many-keys' | 'unsupported-text-method' | 'unsupported-linked-cell';
131
+ export type SpreadsheetSortErrorCode = 'column-out-of-range' | 'duplicate-key' | 'formula-reference-out-of-range' | 'invalid-appearance' | 'invalid-case-sensitivity' | 'invalid-custom-list' | 'invalid-direction' | 'invalid-header' | 'invalid-matrix' | 'invalid-orientation' | 'invalid-range' | 'invalid-scope' | 'invalid-text-method' | 'missing-key' | 'not-enough-columns' | 'not-enough-rows' | 'range-too-large' | 'row-out-of-range' | 'too-many-keys' | 'unsupported-text-method' | 'unsupported-linked-cell';
114
132
  export type SpreadsheetSortValidationResult = {
115
133
  ok: true;
116
134
  request: SpreadsheetSortNormalizedRequest;
@@ -122,6 +140,7 @@ export type SpreadsheetSortValidationResult = {
122
140
  export type SpreadsheetSortResult = {
123
141
  ok: true;
124
142
  rows: (Cell | null)[][];
143
+ sourceIndexes: number[];
125
144
  } | {
126
145
  code: SpreadsheetSortErrorCode;
127
146
  message: string;
@@ -130,6 +149,9 @@ export type SpreadsheetSortResult = {
130
149
  export declare function createSpreadsheetSortRangePlan(sheet: WorkSpreadsheetSheet, selectedRange: SpreadsheetCellRange): SpreadsheetSortRangePlan | null;
131
150
  export declare function createSpreadsheetSortRangeDialogSource(sheetName: string, request: SpreadsheetSortOpenRequest): SpreadsheetSortRangeDialogSource | null;
132
151
  export declare function createSpreadsheetSortDialogSource(sheetId: string, sheetName: string, target: SpreadsheetSortTarget, rows: readonly (readonly (Cell | null)[])[], customLists?: readonly SpreadsheetSortCustomList[], appearanceRows?: SpreadsheetSortAppearanceRows): SpreadsheetSortDialogSource | null;
152
+ export declare function spreadsheetSortRowsMatchRange(rows: readonly (readonly (Cell | null)[])[], range: SpreadsheetCellRange): boolean;
153
+ export declare function spreadsheetSortRowsFromSheet(sheet: WorkSpreadsheetSheet, range: SpreadsheetCellRange): (Cell | null)[][] | null;
154
+ export declare function spreadsheetSortOwnedRangeForExactRange(sheet: WorkSpreadsheetSheet, range: SpreadsheetCellRange): SpreadsheetSortOwnedRange | null;
133
155
  export declare function validateSpreadsheetSortRequest(request: SpreadsheetSortRequest): SpreadsheetSortValidationResult;
134
156
  export declare function spreadsheetSortFailureMessage(result: SpreadsheetSortValidationResult | SpreadsheetSortResult): string | null;
135
157
  export declare function spreadsheetSortAppearanceRowsMatch(rows: readonly (readonly (Cell | null)[])[], appearances: SpreadsheetSortAppearanceRows): boolean;
@@ -10,5 +10,8 @@ export declare function workSpreadsheetAutoFilterCriteriaEntries(sheet: WorkSpre
10
10
  export declare function workSpreadsheetSheetWithAutoFilterCriteria(sheet: WorkSpreadsheetSheet, column: number, criteria: WorkSpreadsheetFilterCriteria, context?: WorkSpreadsheetDynamicFilterContext): WorkSpreadsheetSheet | null;
11
11
  export declare function workSpreadsheetSheetWithoutAutoFilterCriteria(sheet: WorkSpreadsheetSheet, column: number): WorkSpreadsheetSheet | null;
12
12
  export declare function workSpreadsheetAutoFilterManuallyHiddenRows(sheet: WorkSpreadsheetSheet): Set<string>;
13
+ export declare function workSpreadsheetAutoFilterOwnedRows(sheet: WorkSpreadsheetSheet): Set<string>;
14
+ export declare function workSpreadsheetFilterHiddenRows(sheet: WorkSpreadsheetSheet, range: WorkSpreadsheetAutoFilterRange, column: number, criteria: WorkSpreadsheetFilterCriteria, context?: WorkSpreadsheetDynamicFilterContext): Record<string, 0> | null;
15
+ export declare function workSpreadsheetSheetWithReappliedAutoFilterCriteria(sheet: WorkSpreadsheetSheet, criteriaSource: WorkSpreadsheetSheet, manuallyHiddenRows: ReadonlySet<string>, context?: WorkSpreadsheetDynamicFilterContext): WorkSpreadsheetSheet;
13
16
  export declare function workSpreadsheetSheetWithImportedAutoFilterCriteria(sheet: WorkSpreadsheetSheet, entries: readonly WorkSpreadsheetFilter[], context?: WorkSpreadsheetDynamicFilterContext): WorkSpreadsheetSheet;
14
17
  export declare function normalizeWorkSpreadsheetFilterCriteria(criteria: unknown): WorkSpreadsheetFilterCriteria | null;
Binary file
package/dist/styles.css CHANGED
@@ -18068,6 +18068,13 @@ sub [data-office-character-position-half-points], sup [data-office-character-pos
18068
18068
  font-weight: 700;
18069
18069
  }
18070
18070
 
18071
+ .work-spreadsheet-sort-options-lock-note {
18072
+ color: var(--a3s-muted);
18073
+ margin: 0 0 2px;
18074
+ font-size: 11px;
18075
+ line-height: 1.45;
18076
+ }
18077
+
18071
18078
  .work-spreadsheet-sort-options > label {
18072
18079
  border: 1px solid var(--a3s-line);
18073
18080
  cursor: pointer;
@@ -18122,6 +18129,13 @@ sub [data-office-character-position-half-points], sup [data-office-character-pos
18122
18129
  gap: 6px;
18123
18130
  }
18124
18131
 
18132
+ .work-spreadsheet-sort-toolbar-actions {
18133
+ align-items: center;
18134
+ gap: 6px;
18135
+ min-width: 0;
18136
+ display: flex;
18137
+ }
18138
+
18125
18139
  .work-spreadsheet-sort-toolbar .work-office-checkbox {
18126
18140
  min-height: 34px;
18127
18141
  padding: 6px 9px;
@@ -18314,6 +18328,96 @@ sub [data-office-character-position-half-points], sup [data-office-character-pos
18314
18328
  line-height: 1.45;
18315
18329
  }
18316
18330
 
18331
+ .work-spreadsheet-sort-custom-list-manager {
18332
+ --work-office-control-accent: var(--work-spreadsheet-accent, #159469);
18333
+ width: min(720px, 100%);
18334
+ }
18335
+
18336
+ .work-spreadsheet-sort-custom-list-manager-layout {
18337
+ grid-template-columns: minmax(220px, .85fr) minmax(280px, 1.15fr);
18338
+ gap: 14px;
18339
+ display: grid;
18340
+ }
18341
+
18342
+ .work-spreadsheet-sort-custom-list-manager-layout > section, .work-spreadsheet-sort-custom-list-manager-layout label {
18343
+ gap: 7px;
18344
+ min-width: 0;
18345
+ display: grid;
18346
+ }
18347
+
18348
+ .work-spreadsheet-sort-custom-list-manager-layout > section {
18349
+ align-content: start;
18350
+ }
18351
+
18352
+ .work-spreadsheet-sort-custom-list-manager-layout label > span {
18353
+ color: var(--a3s-muted);
18354
+ font-size: 10px;
18355
+ font-weight: 650;
18356
+ }
18357
+
18358
+ .work-spreadsheet-sort-custom-list-manager select, .work-spreadsheet-sort-custom-list-manager textarea {
18359
+ box-sizing: border-box;
18360
+ border: 1px solid var(--a3s-line-strong);
18361
+ background: var(--a3s-panel);
18362
+ width: 100%;
18363
+ min-width: 0;
18364
+ min-height: 252px;
18365
+ color: var(--a3s-ink);
18366
+ font: inherit;
18367
+ border-radius: 6px;
18368
+ padding: 8px;
18369
+ font-size: 11px;
18370
+ line-height: 1.5;
18371
+ }
18372
+
18373
+ .work-spreadsheet-sort-custom-list-manager textarea {
18374
+ resize: vertical;
18375
+ }
18376
+
18377
+ .work-spreadsheet-sort-custom-list-manager textarea[readonly] {
18378
+ background: var(--a3s-panel-soft);
18379
+ color: var(--a3s-muted);
18380
+ }
18381
+
18382
+ .work-spreadsheet-sort-custom-list-manager select:focus-visible, .work-spreadsheet-sort-custom-list-manager textarea:focus-visible {
18383
+ border-color: var(--work-spreadsheet-accent, #159469);
18384
+ outline: 2px solid
18385
+ color-mix(in srgb, var(--work-spreadsheet-accent, #159469) 24%, transparent);
18386
+ outline-offset: 1px;
18387
+ }
18388
+
18389
+ .work-spreadsheet-sort-custom-list-manager-layout section > p, .work-spreadsheet-sort-custom-list-manager-note {
18390
+ color: var(--a3s-muted);
18391
+ margin: 0;
18392
+ font-size: 10px;
18393
+ line-height: 1.45;
18394
+ }
18395
+
18396
+ .work-spreadsheet-sort-custom-list-manager-layout section > .work-spreadsheet-sort-custom-list-error {
18397
+ color: var(--a3s-danger, #b42318);
18398
+ }
18399
+
18400
+ .work-spreadsheet-sort-custom-list-manager-actions {
18401
+ justify-content: flex-end;
18402
+ align-items: center;
18403
+ gap: 6px;
18404
+ display: flex;
18405
+ }
18406
+
18407
+ .work-spreadsheet-sort-custom-list-manager-actions .ds-button {
18408
+ gap: 6px;
18409
+ }
18410
+
18411
+ .work-spreadsheet-sort-custom-list-manager-actions .ds-button[aria-label] {
18412
+ width: 34px;
18413
+ min-width: 34px;
18414
+ padding-inline: 0;
18415
+ }
18416
+
18417
+ .work-spreadsheet-sort-custom-list-manager-note {
18418
+ margin-block-start: 12px;
18419
+ }
18420
+
18317
18421
  .work-spreadsheet-sort-range-dialog {
18318
18422
  --work-office-control-accent: var(--work-spreadsheet-accent, #159469);
18319
18423
  width: min(500px, 100%);
@@ -18395,6 +18499,18 @@ sub [data-office-character-position-half-points], sup [data-office-character-pos
18395
18499
  align-items: stretch;
18396
18500
  }
18397
18501
 
18502
+ .work-spreadsheet-sort-toolbar-actions {
18503
+ flex-wrap: wrap;
18504
+ }
18505
+
18506
+ .work-spreadsheet-sort-custom-list-manager-layout {
18507
+ grid-template-columns: minmax(0, 1fr);
18508
+ }
18509
+
18510
+ .work-spreadsheet-sort-custom-list-manager select, .work-spreadsheet-sort-custom-list-manager textarea {
18511
+ min-height: 180px;
18512
+ }
18513
+
18398
18514
  .work-spreadsheet-sort-level {
18399
18515
  grid-template-columns: minmax(0, 1fr);
18400
18516
  }
@@ -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 writes preferences into controlled
1475
- workbook content. Without a store it remains scoped to the mounted session.
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 new
1481
- list to session scope. A stored list precedes an identical request-carried
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,
@@ -1493,13 +1498,30 @@ view, then uses one stable comparator for both orientations. Relative formula
1493
1498
  references are translated along the moved row or column axis with the same
1494
1499
  bounded reference engine used by Paste Special, while absolute references stay
1495
1500
  fixed.
1496
- One accepted operation crosses the Fortune boundary as one range write and one
1497
- controlled Undo record. Table, worksheet-AutoFilter, hyperlink-map,
1498
- imported-formula-metadata, and border-sidecar intersections fail closed because
1499
- those models still own coordinates outside the cell matrix. Moving large sorts,
1500
- large aggregate/rank scans, remaining advanced filter predicates, full custom-list preference
1501
- management, and structural sidecar reconciliation into the Worker/WASM kernel
1502
- remains Stage 3 work.
1501
+ An unfiltered accepted operation crosses the Fortune boundary as one range
1502
+ write and one controlled Undo record. A separate structural-owner planner
1503
+ recognizes the exact sortable range of one native table or worksheet AutoFilter
1504
+ from any contained selection. It excludes table totals, freezes the structural
1505
+ header, locks top-to-bottom movement, and carries the owner kind plus table ID
1506
+ when applicable. The command derives that fingerprint again at apply time;
1507
+ changed ownership fails before allocation or mutation.
1508
+
1509
+ Filter-active owned sorts use one controlled workbook replacement instead of a
1510
+ range write. The matrix engine returns its stable source-row permutation beside
1511
+ the translated cells. `spreadsheet-filter-reconciliation` evaluates typed
1512
+ worksheet and table criteria against the sorted dense/sparse sheet, remaps
1513
+ opaque Fortune value/color `rowhidden` ownership through that permutation, and
1514
+ rebuilds the combined hidden-row map while retaining independent manual rows.
1515
+ Fortune range reads that omit hidden rows fall back to the bounded controlled
1516
+ snapshot. Sort area and filter rescans have explicit one-million-cell budgets,
1517
+ and unrelated filters do not divert ordinary ranges from the native path.
1518
+
1519
+ Partial intersections that do not resolve to one exact structural owner, plus
1520
+ hyperlink-map, imported-formula-metadata, and border-sidecar intersections,
1521
+ still fail closed because those sidecars own coordinates outside the cell
1522
+ matrix. Moving large sorts, large aggregate/rank scans, remaining advanced
1523
+ filter predicates, and structural sidecar reconciliation into the Worker/WASM
1524
+ kernel remains Stage 3 work.
1503
1525
  Direct host focus of the native grid now enters the same bounded focus observer
1504
1526
  used by ribbon commands. If a controlled workbook update replaces the focused
1505
1527
  Fortune overlay, focus transfers to its connected replacement; deliberate
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@a3s-lab/office",
3
- "version": "0.37.2",
3
+ "version": "0.37.4",
4
4
  "description": "Open-source collaborative browser editors for documents, Markdown, spreadsheets, presentations, and PDFs.",
5
5
  "keywords": [
6
6
  "office",
@@ -111,6 +111,7 @@
111
111
  "playground:visual:spreadsheet-row-sort": "playwright test visual-tests/spreadsheet-row-sort.functional.spec.ts --config playwright.config.ts",
112
112
  "playground:visual:spreadsheet-text-sort": "playwright test visual-tests/spreadsheet-text-sort.functional.spec.ts --config playwright.config.ts",
113
113
  "playground:visual:spreadsheet-sort-range": "playwright test visual-tests/spreadsheet-sort-range.functional.spec.ts --config playwright.config.ts",
114
+ "playground:visual:spreadsheet-owned-range-sort": "playwright test visual-tests/spreadsheet-owned-range-sort.functional.spec.ts --config playwright.config.ts",
114
115
  "playground:visual:spreadsheet-font-dialog-shortcuts": "playwright test visual-tests/spreadsheet-font-dialog-shortcuts.functional.spec.ts --config playwright.config.ts",
115
116
  "playground:visual:spreadsheet-diagonal-borders": "playwright test visual-tests/spreadsheet-diagonal-borders.functional.spec.ts --config playwright.config.ts",
116
117
  "playground:visual:spreadsheet-font-colors-shortcuts": "playwright test visual-tests/spreadsheet-font-colors-shortcuts.functional.spec.ts --config playwright.config.ts",
@@ -202,6 +203,8 @@
202
203
  "test:e2e:spreadsheet-text-sort:check": "a3s-test check tests/e2e/spreadsheet-text-sort.acl --json",
203
204
  "test:e2e:spreadsheet-sort-range": "A3S_TEST_SUITE=tests/e2e/spreadsheet-sort-range.acl bash scripts/run-a3s-test-web-gate.sh",
204
205
  "test:e2e:spreadsheet-sort-range:check": "a3s-test check tests/e2e/spreadsheet-sort-range.acl --json",
206
+ "test:e2e:spreadsheet-owned-range-sort": "A3S_TEST_SUITE=tests/e2e/spreadsheet-owned-range-sort.acl bash scripts/run-a3s-test-web-gate.sh",
207
+ "test:e2e:spreadsheet-owned-range-sort:check": "a3s-test check tests/e2e/spreadsheet-owned-range-sort.acl --json",
205
208
  "test:e2e:spreadsheet-cell-fill": "a3s-test run tests/e2e/spreadsheet-cell-fill.acl --json",
206
209
  "test:e2e:spreadsheet-cell-fill:check": "a3s-test check tests/e2e/spreadsheet-cell-fill.acl --json",
207
210
  "test:e2e:spreadsheet-auto-sum": "a3s-test run tests/e2e/spreadsheet-auto-sum.acl --json",