@rowsncolumns/rnc-engine 1.0.0 → 1.1.1
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/esm/command-handlers.d.ts +50 -11
- package/dist/esm/command-handlers.d.ts.map +1 -1
- package/dist/esm/command-handlers.js +132 -12
- package/dist/esm/fold.d.ts.map +1 -1
- package/dist/esm/fold.js +7 -1
- package/dist/esm/index.d.ts +37 -2
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/use-engine-core.d.ts +28 -3
- package/dist/esm/use-engine-core.d.ts.map +1 -1
- package/dist/esm/use-engine-core.js +202 -29
- package/dist/esm/use-spreadsheet-engine.d.ts +10 -1
- package/dist/esm/use-spreadsheet-engine.d.ts.map +1 -1
- package/dist/esm/use-spreadsheet-engine.js +76 -8
- package/dist/esm/use-spreadsheet-ui.d.ts +2 -2
- package/dist/esm/use-spreadsheet-ui.d.ts.map +1 -1
- package/dist/esm/use-spreadsheet-ui.js +19 -0
- package/dist/esm/wasm/rnc_wasm_bg.wasm +0 -0
- package/package.json +9 -7
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* the folded render state plus the read accessors a grid needs (`getCellData`/`getEffectiveFormat`/…).
|
|
17
17
|
*/
|
|
18
18
|
import type { CellData, CellFormat, CellInterface, Citation, GridRange, NamedCellStyle, SelectionArea, SheetCoordinate, SheetRange } from "@rowsncolumns/common-types";
|
|
19
|
-
import { type AvailableIcon, type ConditionalFormatRule, type EmbeddedChart, type EmbeddedObject, type HIDDEN_DIMENSION_STRATEGY, type NamedRange, type ProtectedRange, type Sheet, type Slicer, type SpreadsheetTheme, type TableView } from "@rowsncolumns/spreadsheet";
|
|
19
|
+
import { type AvailableIcon, type ConditionalFormatRule, type EmbeddedChart, type MoveChartTarget, type OverlayToAnchor, type EmbeddedObject, type HIDDEN_DIMENSION_STRATEGY, type NamedRange, type ProtectedRange, type Sheet, type Slicer, type SpreadsheetTheme, type TableView } from "@rowsncolumns/spreadsheet";
|
|
20
20
|
import { type useSpreadsheetState } from "@rowsncolumns/spreadsheet-state";
|
|
21
21
|
import { type FormulaLocale, type FormulaLocaleInput } from "@rowsncolumns/utils";
|
|
22
22
|
import { type EngineSpreadsheetHandlers } from "./command-handlers";
|
|
@@ -103,6 +103,18 @@ export interface UseEngineSpreadsheetOptions {
|
|
|
103
103
|
* direction, case-insensitive) ahead of the locale month/weekday lists. Read through a live ref —
|
|
104
104
|
* the identity may change freely. */
|
|
105
105
|
customAutofillLists?: string[][];
|
|
106
|
+
/** Excel's "Include new rows and columns in table" AutoCorrect option — the same option as
|
|
107
|
+
* `useSpreadsheetState({ autoExpandTables })`. `false` makes every `set-value` / `change-batch` /
|
|
108
|
+
* `fill` / `paste` command carry `autoExpandTables: false`, so the engine never grows a table over
|
|
109
|
+
* the written cells (the smart tag's "Stop Automatically Expanding Tables"). Read through a live
|
|
110
|
+
* ref. @default true */
|
|
111
|
+
autoExpandTables?: boolean;
|
|
112
|
+
/** Excel's "Fill formulas in tables to create calculated columns" AutoCorrect option — the same
|
|
113
|
+
* option as `useSpreadsheetState({ autoCalculatedColumns })`. `false` makes every `set-value` /
|
|
114
|
+
* `change-batch` / `paste` command carry `autoCalculatedColumns: false`, so the engine never fills a table
|
|
115
|
+
* column from a typed formula (the smart tag's "Stop automatically creating calculated columns").
|
|
116
|
+
* Read through a live ref. @default true */
|
|
117
|
+
autoCalculatedColumns?: boolean;
|
|
106
118
|
/** Windowed mode only: the EFFECTIVE frozen-pane counts for a sheet, so every window read also loads
|
|
107
119
|
* the frozen top/left bands (which must never be evicted — frozen panes stay on screen at any scroll
|
|
108
120
|
* position). A collab host should answer from its authoritative source (e.g. the `rncSheetMeta` doc
|
|
@@ -158,6 +170,12 @@ export interface EngineSpreadsheet extends EngineRenderState, EngineSpreadsheetH
|
|
|
158
170
|
clearStreamPreview: () => void;
|
|
159
171
|
undo: () => void;
|
|
160
172
|
redo: () => void;
|
|
173
|
+
/** Run `action` with every command it issues collected and applied afterwards as ONE `batch` —
|
|
174
|
+
* one commit, one undo step, one view snapshot (the same shape as `SS["batchHistory"]`, which
|
|
175
|
+
* folds the legacy hooks' history entries). The engine is unchanged while `action` runs, so
|
|
176
|
+
* `action` must not read back what it just wrote — the data tools' plan-then-apply flows
|
|
177
|
+
* (Data → Subtotal) never do. A batch started inside another joins the outer one. */
|
|
178
|
+
batchHistory: SS["batchHistory"];
|
|
161
179
|
/** Toolbar aliases for {@link undo}/{@link redo} (the reference toolbar consumes `onUndo`/`onRedo`). */
|
|
162
180
|
onUndo: () => void;
|
|
163
181
|
onRedo: () => void;
|
|
@@ -187,8 +205,11 @@ export interface EngineSpreadsheet extends EngineRenderState, EngineSpreadsheetH
|
|
|
187
205
|
/** Data → Advanced filter: the shared criteria planner over an engine window read, applied
|
|
188
206
|
* through hide-row / show-row / change-batch (same shape as `SS["onAdvancedFilter"]`). */
|
|
189
207
|
onAdvancedFilter: SS["onAdvancedFilter"];
|
|
190
|
-
onMoveChart: (chartId: EmbeddedChart["chartId"], anchorCell: CellInterface, offsetXPixels: number, offsetYPixels: number) => void;
|
|
191
|
-
onResizeChart: (chartId: EmbeddedChart["chartId"], anchorCell: CellInterface, offsetXPixels: number, offsetYPixels: number, width: number, height: number) => void;
|
|
208
|
+
onMoveChart: (chartId: EmbeddedChart["chartId"], anchorCell: CellInterface, offsetXPixels: number, offsetYPixels: number, toAnchor?: OverlayToAnchor) => void;
|
|
209
|
+
onResizeChart: (chartId: EmbeddedChart["chartId"], anchorCell: CellInterface, offsetXPixels: number, offsetYPixels: number, width: number, height: number, toAnchor?: OverlayToAnchor) => void;
|
|
210
|
+
/** Excel's "Move Chart…" (#668 C-17): to a new chartsheet or onto another worksheet at A1. Returns
|
|
211
|
+
* the destination sheet id (undefined when nothing moved) and follows the chart there. */
|
|
212
|
+
onMoveChartToSheet: (chart: EmbeddedChart, target: MoveChartTarget) => number | undefined;
|
|
192
213
|
onCreateConditionalFormattingRule: (rule: ConditionalFormatRule) => void;
|
|
193
214
|
onSavePaintFormat: SS["onSavePaintFormat"];
|
|
194
215
|
onApplyPaintFormat: SS["onApplyPaintFormat"];
|
|
@@ -304,12 +325,16 @@ export interface EngineSpreadsheet extends EngineRenderState, EngineSpreadsheetH
|
|
|
304
325
|
isDarkMode: SS["isDarkMode"];
|
|
305
326
|
namedCellStyles: SS["namedCellStyles"];
|
|
306
327
|
bandedRanges: SS["bandedRanges"];
|
|
328
|
+
/** Gallery live preview: paint `preview`'s style over its table in `bandedRanges` (UI state, no command). */
|
|
329
|
+
onPreviewTableStyle: SS["onPreviewTableStyle"];
|
|
307
330
|
basicFilter: SS["basicFilter"];
|
|
308
331
|
arrows: SS["arrows"];
|
|
309
332
|
conditionalFormats: ConditionalFormatRule[];
|
|
310
333
|
tables: TableView[];
|
|
311
334
|
namedRanges: NamedRange[];
|
|
312
335
|
protectedRanges: ProtectedRange[];
|
|
336
|
+
/** Custom table styles (Excel's New Table Style) — the workbook facet the gallery lists (#668 T-103). */
|
|
337
|
+
customTableStyles: SS["customTableStyles"];
|
|
313
338
|
embeds: EmbeddedObject[];
|
|
314
339
|
slicers: Slicer[];
|
|
315
340
|
/** The data-validation rule covering a cell (resolved by range membership). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-engine-core.d.ts","sourceRoot":"","sources":["../../src/use-engine-core.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,KAAK,EACV,QAAQ,EACR,UAAU,EACV,aAAa,EACb,QAAQ,EACR,SAAS,EACT,cAAc,EACd,aAAa,EACb,eAAe,EACf,UAAU,EACX,MAAM,4BAA4B,CAAC;AAYpC,OAAO,EACL,KAAK,aAAa,
|
|
1
|
+
{"version":3,"file":"use-engine-core.d.ts","sourceRoot":"","sources":["../../src/use-engine-core.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
// Lightweight dependency-graph NODE classes (data holders — NOT the JS calculator) used to shape the
|
|
2
2
|
// real `getPrecedents`/`getDependents` results, which the engine now backs with actual graph data.
|
|
3
3
|
import { CellNode, CellRangeNode, isCellCoordinate, isCellNode, makeKey, } from "@rowsncolumns/dag";
|
|
4
|
-
import { DEFAULT_ACTIVE_CELL, DEFAULT_ARRAY, defaultSpreadsheetTheme, getBandedCells, getInitialActiveSheetId, ICON_SET_COLORS, ICON_SET_GLYPHS, useFonts, } from "@rowsncolumns/spreadsheet";
|
|
5
|
-
import { applyAdvancedFilterPlan, applySubtotalPlan, CellXfsRegistry, collectPaintMerges, generateDataFromClipboard, getBandedCellFormat, isStyleReference, layerBandedFormat, paintSourceForActiveCell, pickFormula, pickValue, planAdvancedFilter, planSubtotals, resolvePasteSpecialOptions, SharedStringRegistry, spreadMergeAnchorFormats,
|
|
4
|
+
import { DEFAULT_ACTIVE_CELL, DEFAULT_ARRAY, defaultSpreadsheetTheme, getBandedCells, getInitialActiveSheetId, ICON_SET_COLORS, ICON_SET_GLYPHS, useFocusEmbedOrChart, useFonts, useSetTableAutoExpansion, useSetCalculatedColumnFill, } from "@rowsncolumns/spreadsheet";
|
|
5
|
+
import { applyAdvancedFilterPlan, applySubtotalPlan, CellXfsRegistry, collectPaintMerges, generateDataFromClipboard, getBandedCellFormat, isStyleReference, layerBandedFormat, paintSourceForActiveCell, pickFormula, pickValue, planAdvancedFilter, planSubtotals, resolvePasteSpecialOptions, SharedStringRegistry, spreadMergeAnchorFormats, tilePaintMerges, transpose, useOnCopy, previewTableStyle, useOnTraceDependentsPrecedents, useShowError, } from "@rowsncolumns/spreadsheet-state";
|
|
6
6
|
import { getCellUserEnteredFormat, getCellUserEnteredValue, getExtendedValueBool, getExtendedValueFormula, getExtendedValueNumber, getExtendedValueString, getFormulaLocale, normalizeExternalUrl, resolveDefaultHorizontalAlignment, } from "@rowsncolumns/utils";
|
|
7
7
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
8
|
-
import { createCommandHandlers, } from "./command-handlers";
|
|
8
|
+
import { createCommandHandlers, rejectionDialog, } from "./command-handlers";
|
|
9
9
|
import { emptyRenderState, foldCommit, foldCommitStructuralOnly, foldWindow, foldWindows, frozenBandRanges, reconcileSheets, } from "./fold";
|
|
10
10
|
import { RncEngine, } from "./index";
|
|
11
11
|
import { cellKey, parseCellKey } from "./keys";
|
|
@@ -140,6 +140,7 @@ const EMPTY_FACETS = {
|
|
|
140
140
|
embeds: [],
|
|
141
141
|
slicers: [],
|
|
142
142
|
bandedRanges: [],
|
|
143
|
+
customTableStyles: [],
|
|
143
144
|
protectedRanges: [],
|
|
144
145
|
basicFilters: [],
|
|
145
146
|
citations: [],
|
|
@@ -252,9 +253,6 @@ function parseInternalLocation(location) {
|
|
|
252
253
|
},
|
|
253
254
|
};
|
|
254
255
|
}
|
|
255
|
-
/** The rnc engine's structural-edit refusals (`off-sheet-push`, `torn-merge`, `torn-table`,
|
|
256
|
-
* `torn-array`) — the codes the legacy engine's `constants.ts` defines, surfaced as a dialog. */
|
|
257
|
-
const isStructuralRejection = (rejection) => rejection.code in STRUCTURAL_REFUSAL_MESSAGES;
|
|
258
256
|
// `useEngineCore` is the engine-only surface (data / calc / commands / accessors) — NOT a standalone
|
|
259
257
|
// drop-in for `useSpreadsheetState`. The chrome (dialogs + host intents) lives in `useSpreadsheetUI`;
|
|
260
258
|
// the drop-in parity lock is asserted on their composition, `useSpreadsheetEngine`.
|
|
@@ -284,6 +282,7 @@ export function useEngineCore(options) {
|
|
|
284
282
|
const onCustomEvalCancelRef = useRef(options.onCustomEvalCancel);
|
|
285
283
|
onCustomEvalCancelRef.current = options.onCustomEvalCancel;
|
|
286
284
|
const showError = useShowError();
|
|
285
|
+
const focusEmbedOrChart = useFocusEmbedOrChart();
|
|
287
286
|
// Latest-refs for the streaming batch-write observers (identities may change every render).
|
|
288
287
|
const onStreamStartRef = useRef(options.onStreamStart);
|
|
289
288
|
onStreamStartRef.current = options.onStreamStart;
|
|
@@ -313,6 +312,16 @@ export function useEngineCore(options) {
|
|
|
313
312
|
stateSheetsRef.current = state.sheets;
|
|
314
313
|
const customAutofillListsRef = useRef(options.customAutofillLists);
|
|
315
314
|
customAutofillListsRef.current = options.customAutofillLists;
|
|
315
|
+
const autoExpandTablesRef = useRef(options.autoExpandTables);
|
|
316
|
+
autoExpandTablesRef.current = options.autoExpandTables;
|
|
317
|
+
const autoCalculatedColumnsRef = useRef(options.autoCalculatedColumns);
|
|
318
|
+
autoCalculatedColumnsRef.current = options.autoCalculatedColumns;
|
|
319
|
+
// Excel's AutoCorrect smart tag after a table auto-expanded — armed from the commit's
|
|
320
|
+
// `tableAutoExpansion` record when a value-writing command grew a table; `CanvasGrid` renders it.
|
|
321
|
+
const setTableAutoExpansion = useSetTableAutoExpansion();
|
|
322
|
+
// Excel's AutoCorrect smart tag after a formula typed into a table column — armed from the
|
|
323
|
+
// commit's `calculatedColumnFill` record; `CanvasGrid` renders it.
|
|
324
|
+
const setCalculatedColumnFill = useSetCalculatedColumnFill();
|
|
316
325
|
// One windowed read = the buffered window + the sheet's frozen bands + the sheet's active cell
|
|
317
326
|
// (pinned so the formula bar's active-cell read survives scrolling it out of the window — see
|
|
318
327
|
// `readWindowWithFrozenBands`). Frozen counts come from the host's getter when provided (see
|
|
@@ -653,6 +662,12 @@ export function useEngineCore(options) {
|
|
|
653
662
|
const preview = streamPreviewRef.current;
|
|
654
663
|
if (!preview?.size)
|
|
655
664
|
return;
|
|
665
|
+
// A batch retires what each of its members covers.
|
|
666
|
+
if (command.command === "batch") {
|
|
667
|
+
for (const member of command.commands)
|
|
668
|
+
retireStreamPreviewForCommand(member);
|
|
669
|
+
return;
|
|
670
|
+
}
|
|
656
671
|
const cmd = command;
|
|
657
672
|
if (cmd.command === "change-theme")
|
|
658
673
|
return;
|
|
@@ -687,10 +702,16 @@ export function useEngineCore(options) {
|
|
|
687
702
|
sheetDataRef.current = state.sheetData;
|
|
688
703
|
const committedFvAt = useCallback((sheetId, rowIndex, columnIndex) => sheetDataRef.current?.[sheetId]?.[rowIndex]?.values?.[columnIndex]?.fv ??
|
|
689
704
|
undefined, []);
|
|
705
|
+
// Commands issued while a `batchHistory` action runs, applied together when it returns.
|
|
706
|
+
const batchCommandsRef = useRef(null);
|
|
690
707
|
const onCommand = useCallback((command) => {
|
|
691
708
|
const engine = engineRef.current;
|
|
692
709
|
if (!engine)
|
|
693
710
|
return;
|
|
711
|
+
if (batchCommandsRef.current) {
|
|
712
|
+
batchCommandsRef.current.push(command);
|
|
713
|
+
return;
|
|
714
|
+
}
|
|
694
715
|
// The host's apply (or any other local write) is the authority — retire the preview for the cells
|
|
695
716
|
// it covers in this same render, so the committed value replaces the previewed one with no blank
|
|
696
717
|
// frame in between.
|
|
@@ -705,17 +726,22 @@ export function useEngineCore(options) {
|
|
|
705
726
|
// Snapshot the view BEFORE applying — that's where undo should return the user.
|
|
706
727
|
const before = viewRef.current;
|
|
707
728
|
const commit = engine.applyCommand(command);
|
|
708
|
-
//
|
|
709
|
-
// the
|
|
710
|
-
//
|
|
729
|
+
// A value-writing command grew a table over the written cells: arm the AutoCorrect smart tag
|
|
730
|
+
// with the engine's record of the growth (rowsncolumns/spreadsheet#668 T-12) — "Undo Table
|
|
731
|
+
// AutoExpansion" resizes back and clears the cells the growth wrote (`writes`, T-89).
|
|
732
|
+
if (commit.tableAutoExpansion) {
|
|
733
|
+
setTableAutoExpansion(commit.tableAutoExpansion);
|
|
734
|
+
}
|
|
735
|
+
if (commit.calculatedColumnFill) {
|
|
736
|
+
setCalculatedColumnFill(commit.calculatedColumnFill);
|
|
737
|
+
}
|
|
738
|
+
// A refusal wrote nothing — show the user Excel's dialog text through the same channel the
|
|
739
|
+
// legacy engine's hooks use (`useShowError`), once: `createCommandHandlers` skips the
|
|
740
|
+
// refusals that have a dialog here. The rest keep riding `commit.rejections` to it.
|
|
711
741
|
for (const rejection of commit.rejections ?? []) {
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
else if (rejection.code === "merged-cell-move") {
|
|
716
|
-
// A refused move / cut + paste ("We can't do that to a merged cell.") wrote nothing; the
|
|
717
|
-
// legacy engine's move / paste hooks open the shared error dialog for it, so do the same.
|
|
718
|
-
showError({ message: rejection.message });
|
|
742
|
+
const dialog = rejectionDialog(rejection);
|
|
743
|
+
if (dialog) {
|
|
744
|
+
showError(dialog);
|
|
719
745
|
}
|
|
720
746
|
}
|
|
721
747
|
// Only record a view snapshot if the command actually pushed a document undo entry (skips
|
|
@@ -725,6 +751,12 @@ export function useEngineCore(options) {
|
|
|
725
751
|
viewRedo.current = [];
|
|
726
752
|
}
|
|
727
753
|
lastUndoDepth.current = engine.undoDepth();
|
|
754
|
+
// Excel selects a freshly inserted chart; a batch ends up on the last one it inserted.
|
|
755
|
+
for (const member of command.command === "batch" ? command.commands : [command]) {
|
|
756
|
+
if (member.command === "create-chart") {
|
|
757
|
+
focusEmbedOrChart(member.spec.chartId);
|
|
758
|
+
}
|
|
759
|
+
}
|
|
728
760
|
// The engine's move-range relocates cells but never re-scopes range-scoped CF/DV rules —
|
|
729
761
|
// carry the touched rules to the destination right after the move (Excel/Sheets behavior).
|
|
730
762
|
if (command.command === "move-range") {
|
|
@@ -734,7 +766,25 @@ export function useEngineCore(options) {
|
|
|
734
766
|
}
|
|
735
767
|
// Handed back so the command handlers can surface an engine refusal (`commit.rejections`).
|
|
736
768
|
return commit;
|
|
737
|
-
}, [retireStreamPreviewForCommand, showError]);
|
|
769
|
+
}, [retireStreamPreviewForCommand, showError, focusEmbedOrChart, setTableAutoExpansion, setCalculatedColumnFill]);
|
|
770
|
+
const batchHistory = useCallback((action) => {
|
|
771
|
+
if (batchCommandsRef.current) {
|
|
772
|
+
return action();
|
|
773
|
+
}
|
|
774
|
+
const commands = [];
|
|
775
|
+
batchCommandsRef.current = commands;
|
|
776
|
+
let result;
|
|
777
|
+
try {
|
|
778
|
+
result = action();
|
|
779
|
+
}
|
|
780
|
+
finally {
|
|
781
|
+
batchCommandsRef.current = null;
|
|
782
|
+
}
|
|
783
|
+
if (commands.length) {
|
|
784
|
+
onCommand({ command: "batch", commands });
|
|
785
|
+
}
|
|
786
|
+
return result;
|
|
787
|
+
}, [onCommand]);
|
|
738
788
|
// "Calculate Now" (F9): force a full recalculation so volatile functions (NOW/TODAY/RAND/…) refresh.
|
|
739
789
|
// The engine re-evaluates + streams the changed cells through the normal commit (folded like any edit);
|
|
740
790
|
// it mutates no document state, so it isn't undoable. The reference's `options` (reset-graph /
|
|
@@ -803,6 +853,19 @@ export function useEngineCore(options) {
|
|
|
803
853
|
customFnsRef.current.set(name, impl);
|
|
804
854
|
engineRef.current?.registerCustomFunction(name);
|
|
805
855
|
}, []);
|
|
856
|
+
// Chart selection after an undo/redo step (Excel: the chart an undo brings back, or a redo
|
|
857
|
+
// re-creates / re-positions, ends up selected; one whose step removed it is deselected). The
|
|
858
|
+
// engine's chart deltas are the signal — same as the legacy history's `selectedEmbedOrChart`.
|
|
859
|
+
const restoreChartSelection = useCallback((commit) => {
|
|
860
|
+
for (const change of commit.chartChanges) {
|
|
861
|
+
if (change.chart) {
|
|
862
|
+
focusEmbedOrChart(change.chartId);
|
|
863
|
+
}
|
|
864
|
+
else {
|
|
865
|
+
focusEmbedOrChart((prev) => prev === change.chartId ? undefined : prev);
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
}, [focusEmbedOrChart]);
|
|
806
869
|
// Undo AND redo of an edit both return the cursor to the EDIT location — mirroring the reference's
|
|
807
870
|
// `{ activeCell: { undo: coords, redo: coords } }`. So when an entry crosses between the undo/redo
|
|
808
871
|
// stacks we move the SAME stored view, NOT the live cursor (pushing the live cursor would make redo
|
|
@@ -812,7 +875,7 @@ export function useEngineCore(options) {
|
|
|
812
875
|
if (!engine)
|
|
813
876
|
return;
|
|
814
877
|
const prevDepth = engine.undoDepth();
|
|
815
|
-
engine.undo();
|
|
878
|
+
const commit = engine.undo();
|
|
816
879
|
if (engine.undoDepth() < prevDepth) {
|
|
817
880
|
const restore = viewUndo.current.pop();
|
|
818
881
|
if (restore) {
|
|
@@ -821,13 +884,14 @@ export function useEngineCore(options) {
|
|
|
821
884
|
}
|
|
822
885
|
}
|
|
823
886
|
lastUndoDepth.current = engine.undoDepth();
|
|
824
|
-
|
|
887
|
+
restoreChartSelection(commit);
|
|
888
|
+
}, [applyView, restoreChartSelection]);
|
|
825
889
|
const redo = useCallback(() => {
|
|
826
890
|
const engine = engineRef.current;
|
|
827
891
|
if (!engine)
|
|
828
892
|
return;
|
|
829
893
|
const prevRedoDepth = engine.redoDepth();
|
|
830
|
-
engine.redo();
|
|
894
|
+
const commit = engine.redo();
|
|
831
895
|
if (engine.redoDepth() < prevRedoDepth) {
|
|
832
896
|
const restore = viewRedo.current.pop();
|
|
833
897
|
if (restore) {
|
|
@@ -836,7 +900,8 @@ export function useEngineCore(options) {
|
|
|
836
900
|
}
|
|
837
901
|
}
|
|
838
902
|
lastUndoDepth.current = engine.undoDepth();
|
|
839
|
-
|
|
903
|
+
restoreChartSelection(commit);
|
|
904
|
+
}, [applyView, restoreChartSelection]);
|
|
840
905
|
const load = useCallback((document) => {
|
|
841
906
|
engineRef.current?.load(document);
|
|
842
907
|
}, []);
|
|
@@ -865,6 +930,9 @@ export function useEngineCore(options) {
|
|
|
865
930
|
hidden: es.hidden,
|
|
866
931
|
tabColor: es.tabColor,
|
|
867
932
|
defaultRowHeight: es.defaultRowHeight,
|
|
933
|
+
defaultColumnWidth: es.defaultColumnWidth,
|
|
934
|
+
type: es.type,
|
|
935
|
+
chartId: es.chartId,
|
|
868
936
|
}));
|
|
869
937
|
const firstId = engineSheets[0]?.sheetId ?? viewRef.current.activeSheetId;
|
|
870
938
|
windowRef.current = windowedRef.current
|
|
@@ -1763,6 +1831,8 @@ export function useEngineCore(options) {
|
|
|
1763
1831
|
// handler→command mapping; nothing here touches the document directly.
|
|
1764
1832
|
const handlers = useMemo(() => createCommandHandlers(onCommand, {
|
|
1765
1833
|
getCustomAutofillLists: () => customAutofillListsRef.current,
|
|
1834
|
+
getAutoExpandTables: () => autoExpandTablesRef.current,
|
|
1835
|
+
getAutoCalculatedColumns: () => autoCalculatedColumnsRef.current,
|
|
1766
1836
|
}), [onCommand]);
|
|
1767
1837
|
// Data tools composed over the streamed commands. The planners need the WHOLE list range (a
|
|
1768
1838
|
// windowed host holds only the viewport), so they read it straight from the engine in one
|
|
@@ -1782,15 +1852,18 @@ export function useEngineCore(options) {
|
|
|
1782
1852
|
});
|
|
1783
1853
|
if (!plan)
|
|
1784
1854
|
return undefined;
|
|
1785
|
-
|
|
1855
|
+
// Excel undoes a Subtotal in ONE step: the plan's row deletes / inserts, total-row writes and
|
|
1856
|
+
// outline groups apply as one `batch` — one commit to fold, one undo entry on either history
|
|
1857
|
+
// backend, one view snapshot — instead of ten Ctrl+Z presses.
|
|
1858
|
+
batchHistory(() => applySubtotalPlan(sheetId, plan, {
|
|
1786
1859
|
onDeleteRow: handlers.onDeleteRow,
|
|
1787
1860
|
onInsertRow: handlers.onInsertRow,
|
|
1788
1861
|
onChangeBatch: (s, range, values) => handlers.onChangeBatch(s, range, values),
|
|
1789
1862
|
onGroupRows: handlers.onGroupRows,
|
|
1790
1863
|
onUngroupRows: handlers.onUngroupRows,
|
|
1791
|
-
});
|
|
1864
|
+
}));
|
|
1792
1865
|
return plan;
|
|
1793
|
-
}, [handlers, readRect, dimMeta]);
|
|
1866
|
+
}, [batchHistory, handlers, readRect, dimMeta]);
|
|
1794
1867
|
const onAdvancedFilter = useCallback((sheetId, options) => {
|
|
1795
1868
|
const list = readRect(sheetId, options.listRange, "raw");
|
|
1796
1869
|
const criteria = readRect(sheetId, options.criteriaRange, "raw");
|
|
@@ -1818,15 +1891,46 @@ export function useEngineCore(options) {
|
|
|
1818
1891
|
// (the live active sheet) instead of closing over `activeSheetId`, so identity never changes. The
|
|
1819
1892
|
// grid omits sheetId from chart move/resize (charts live on the active sheet) and passes just the rule
|
|
1820
1893
|
// to create-conditional-format.
|
|
1821
|
-
const onMoveChart = useCallback((chartId, anchorCell, offsetXPixels, offsetYPixels) => onCommand({
|
|
1894
|
+
const onMoveChart = useCallback((chartId, anchorCell, offsetXPixels, offsetYPixels, toAnchor) => onCommand({
|
|
1822
1895
|
command: "move-chart",
|
|
1823
1896
|
chartId,
|
|
1824
1897
|
sheetId: viewRef.current.activeSheetId,
|
|
1825
1898
|
anchorCell,
|
|
1826
1899
|
offsetXPixels,
|
|
1827
1900
|
offsetYPixels,
|
|
1901
|
+
...toAnchor,
|
|
1828
1902
|
}), [onCommand]);
|
|
1829
|
-
|
|
1903
|
+
// Excel's "Move Chart…" (#668 C-17): the engine relocates the chart (minting / deleting the
|
|
1904
|
+
// chartsheet); the view follows the chart to its destination sheet and keeps it selected.
|
|
1905
|
+
const onMoveChartToSheet = useCallback((chart, target) => {
|
|
1906
|
+
const engine = engineRef.current;
|
|
1907
|
+
if (!engine)
|
|
1908
|
+
return undefined;
|
|
1909
|
+
const sourceSheetId = chart.position.sheetId;
|
|
1910
|
+
if (target.kind === "sheet" && target.sheetId === sourceSheetId) {
|
|
1911
|
+
return undefined;
|
|
1912
|
+
}
|
|
1913
|
+
onCommand({
|
|
1914
|
+
command: "move-chart-to-sheet",
|
|
1915
|
+
chartId: chart.chartId,
|
|
1916
|
+
...(target.kind === "sheet"
|
|
1917
|
+
? { sheetId: target.sheetId }
|
|
1918
|
+
: { title: target.title }),
|
|
1919
|
+
});
|
|
1920
|
+
const destination = target.kind === "sheet"
|
|
1921
|
+
? target.sheetId
|
|
1922
|
+
: engine
|
|
1923
|
+
.sheets?.()
|
|
1924
|
+
.find((sheet) => sheet.type === "chartsheet" &&
|
|
1925
|
+
String(sheet.chartId) === String(chart.chartId))?.sheetId;
|
|
1926
|
+
if (destination === undefined || destination === sourceSheetId) {
|
|
1927
|
+
return undefined;
|
|
1928
|
+
}
|
|
1929
|
+
onChangeActiveSheet(destination);
|
|
1930
|
+
focusEmbedOrChart(chart.chartId);
|
|
1931
|
+
return destination;
|
|
1932
|
+
}, [onCommand, onChangeActiveSheet, focusEmbedOrChart]);
|
|
1933
|
+
const onResizeChart = useCallback((chartId, anchorCell, offsetXPixels, offsetYPixels, width, height, toAnchor) => onCommand({
|
|
1830
1934
|
command: "resize-chart",
|
|
1831
1935
|
chartId,
|
|
1832
1936
|
sheetId: viewRef.current.activeSheetId,
|
|
@@ -1835,6 +1939,7 @@ export function useEngineCore(options) {
|
|
|
1835
1939
|
offsetYPixels,
|
|
1836
1940
|
width,
|
|
1837
1941
|
height,
|
|
1942
|
+
...toAnchor,
|
|
1838
1943
|
}), [onCommand]);
|
|
1839
1944
|
const onCreateConditionalFormattingRule = useCallback((rule) => onCommand({
|
|
1840
1945
|
command: "create-conditional-format",
|
|
@@ -1860,6 +1965,9 @@ export function useEngineCore(options) {
|
|
|
1860
1965
|
.filter((t) => t.sheetId === sheetId && t.bandedRange != null)
|
|
1861
1966
|
.map((t) => ({
|
|
1862
1967
|
bandedRangeId: `${t.id}-${t.theme}`,
|
|
1968
|
+
showFirstColumn: t.showFirstColumn,
|
|
1969
|
+
showLastColumn: t.showLastColumn,
|
|
1970
|
+
totalRow: t.totalRow ?? false,
|
|
1863
1971
|
range: { ...t.range, sheetId },
|
|
1864
1972
|
...t.bandedRange,
|
|
1865
1973
|
})),
|
|
@@ -1909,6 +2017,44 @@ export function useEngineCore(options) {
|
|
|
1909
2017
|
}
|
|
1910
2018
|
}
|
|
1911
2019
|
}, [onCommand]);
|
|
2020
|
+
// Convert to Range keeps the table's look (Excel bakes the table style into the cell formats):
|
|
2021
|
+
// the banded formats the grid painted under the table become static cell formats — the same
|
|
2022
|
+
// capture the format painter makes (#620) — replayed over the table's range in one batch with
|
|
2023
|
+
// the removal, so one undo restores the table and the unbaked cells together.
|
|
2024
|
+
const onRemoveTable = useCallback((tableView) => {
|
|
2025
|
+
const { sheetId, range } = tableView;
|
|
2026
|
+
const banded = paintBandedCells(sheetId);
|
|
2027
|
+
batchHistory(() => {
|
|
2028
|
+
if (banded?.size) {
|
|
2029
|
+
let baked = false;
|
|
2030
|
+
const grid = [];
|
|
2031
|
+
for (let r = range.startRowIndex; r <= range.endRowIndex; r++) {
|
|
2032
|
+
const row = [];
|
|
2033
|
+
for (let c = range.startColumnIndex; c <= range.endColumnIndex; c++) {
|
|
2034
|
+
// The hook's own formats are consolidated `CellFormat`s (never a style reference).
|
|
2035
|
+
const own = getUserEnteredFormat(sheetId, r, c);
|
|
2036
|
+
const band = getBandedCellFormat(banded, r, c);
|
|
2037
|
+
if (band)
|
|
2038
|
+
baked = true;
|
|
2039
|
+
// `replace` re-writes every cell of the range: a cell without a band keeps its own format.
|
|
2040
|
+
row.push((band ? layerBandedFormat(own, band) : own) ?? null);
|
|
2041
|
+
}
|
|
2042
|
+
grid.push(row);
|
|
2043
|
+
}
|
|
2044
|
+
if (baked) {
|
|
2045
|
+
onCommand({
|
|
2046
|
+
command: "change-formatting",
|
|
2047
|
+
sheetId,
|
|
2048
|
+
activeCell: { rowIndex: range.startRowIndex, columnIndex: range.startColumnIndex },
|
|
2049
|
+
selections: [{ range }],
|
|
2050
|
+
cellFormat: grid,
|
|
2051
|
+
options: { replace: true },
|
|
2052
|
+
});
|
|
2053
|
+
}
|
|
2054
|
+
}
|
|
2055
|
+
handlers.onRemoveTable(tableView);
|
|
2056
|
+
});
|
|
2057
|
+
}, [paintBandedCells, getUserEnteredFormat, batchHistory, onCommand, handlers]);
|
|
1912
2058
|
const onSavePaintFormat = useCallback((sheetId, activeCell, selections) => {
|
|
1913
2059
|
// A plain click on a merged cell arms the painter with the anchor and NO selection (the
|
|
1914
2060
|
// grid clears the list) — Excel treats that click as the whole merged area.
|
|
@@ -2059,11 +2205,22 @@ export function useEngineCore(options) {
|
|
|
2059
2205
|
// style is materialized on its facet entry as `bandedRange` (never as per-cell format), so derive
|
|
2060
2206
|
// those here exactly like `useSpreadsheetState` — this single array is what the grid paints and the
|
|
2061
2207
|
// copy path serializes table styling from.
|
|
2208
|
+
// The gallery's hovered style paints over the table's own while the pointer rests on the
|
|
2209
|
+
// swatch — UI state only, never a command.
|
|
2210
|
+
const [tableStylePreview, setTableStylePreview] = useState(null);
|
|
2211
|
+
const onPreviewTableStyle = useCallback((preview) => setTableStylePreview(preview), []);
|
|
2062
2212
|
const bandedRanges = useMemo(() => {
|
|
2063
2213
|
const tableBands = (tables ?? [])
|
|
2064
|
-
.filter((t) => t.sheetId === activeSheetId
|
|
2214
|
+
.filter((t) => t.sheetId === activeSheetId)
|
|
2215
|
+
.map((t) => tableStylePreview?.sheetId === t.sheetId && tableStylePreview.tableId === t.id
|
|
2216
|
+
? previewTableStyle(t, tableStylePreview)
|
|
2217
|
+
: t)
|
|
2218
|
+
.filter((t) => t.bandedRange != null)
|
|
2065
2219
|
.map((t) => ({
|
|
2066
2220
|
bandedRangeId: `${t.id}-${t.theme}`,
|
|
2221
|
+
showFirstColumn: t.showFirstColumn,
|
|
2222
|
+
showLastColumn: t.showLastColumn,
|
|
2223
|
+
totalRow: t.totalRow ?? false,
|
|
2067
2224
|
range: { ...t.range, sheetId: activeSheetId },
|
|
2068
2225
|
...t.bandedRange,
|
|
2069
2226
|
}));
|
|
@@ -2071,7 +2228,7 @@ export function useEngineCore(options) {
|
|
|
2071
2228
|
...facets.bandedRanges.filter((b) => b.range?.sheetId === activeSheetId),
|
|
2072
2229
|
...tableBands,
|
|
2073
2230
|
];
|
|
2074
|
-
}, [facets, tables, activeSheetId]);
|
|
2231
|
+
}, [facets, tables, activeSheetId, tableStylePreview]);
|
|
2075
2232
|
const basicFilter = useMemo(() => facets.basicFilters.find((f) => f.sheetId === activeSheetId)?.filter, [facets, activeSheetId]);
|
|
2076
2233
|
// Body rows the engine hid for the active sheet (basic filter OR a table-column filter), as compact
|
|
2077
2234
|
// [start,end] 1-based inclusive ranges. CanvasGrid derives `visibleRowRanges` from these — the
|
|
@@ -2151,7 +2308,7 @@ export function useEngineCore(options) {
|
|
|
2151
2308
|
// still reads `=B1*2`) and only repoints references INTO the moved block — the engine does
|
|
2152
2309
|
// that remap (`repoint_formulas_into_moved_block`), so the clipboard parse must not
|
|
2153
2310
|
// relativize cut formulas the way it does copied ones.
|
|
2154
|
-
const parsed = await generateDataFromClipboard(e, pasteActiveCell, destinationSheetId, getSheetName(destinationSheetId), true, initial.current.locale, undefined, undefined, undefined,
|
|
2311
|
+
const parsed = await generateDataFromClipboard(e, pasteActiveCell, destinationSheetId, getSheetName(destinationSheetId), true, initial.current.locale, undefined, undefined, undefined, { relocateFormulas: !isCutOperation });
|
|
2155
2312
|
let results = parsed?.results ?? [];
|
|
2156
2313
|
if (!results.length)
|
|
2157
2314
|
return;
|
|
@@ -2266,11 +2423,16 @@ export function useEngineCore(options) {
|
|
|
2266
2423
|
? { sheetId: sourceSheetId, range: from }
|
|
2267
2424
|
: null,
|
|
2268
2425
|
formatOnly,
|
|
2426
|
+
...(autoExpandTablesRef.current === false ? { autoExpandTables: false } : {}),
|
|
2427
|
+
...(autoCalculatedColumnsRef.current === false
|
|
2428
|
+
? { autoCalculatedColumns: false }
|
|
2429
|
+
: {}),
|
|
2269
2430
|
});
|
|
2270
2431
|
}, [getSheetName, getCellData, getUserEnteredFormat, getNote, onCommand]);
|
|
2271
2432
|
return useMemo(() => ({
|
|
2272
2433
|
...state,
|
|
2273
2434
|
...handlers,
|
|
2435
|
+
onRemoveTable,
|
|
2274
2436
|
ready,
|
|
2275
2437
|
engine: engineRef.current,
|
|
2276
2438
|
canUndo: hist.canUndo,
|
|
@@ -2282,6 +2444,7 @@ export function useEngineCore(options) {
|
|
|
2282
2444
|
onUndo: undo,
|
|
2283
2445
|
onRedo: redo,
|
|
2284
2446
|
onMoveChart,
|
|
2447
|
+
onMoveChartToSheet,
|
|
2285
2448
|
onResizeChart,
|
|
2286
2449
|
onCreateConditionalFormattingRule,
|
|
2287
2450
|
// Repeat last formatting (the action itself is recorded in `onCommand`).
|
|
@@ -2356,8 +2519,11 @@ export function useEngineCore(options) {
|
|
|
2356
2519
|
// Undefined when the file didn't specify — CanvasGrid falls back to its own default.
|
|
2357
2520
|
defaultRowHeight: state.sheets.find((s) => s.sheetId === activeSheetId)
|
|
2358
2521
|
?.defaultRowHeight ?? undefined,
|
|
2522
|
+
defaultColumnWidth: state.sheets.find((s) => s.sheetId === activeSheetId)
|
|
2523
|
+
?.defaultColumnWidth ?? undefined,
|
|
2359
2524
|
isDarkMode: false,
|
|
2360
2525
|
bandedRanges,
|
|
2526
|
+
onPreviewTableStyle,
|
|
2361
2527
|
basicFilter,
|
|
2362
2528
|
hostHiddenRowRanges,
|
|
2363
2529
|
arrows,
|
|
@@ -2365,6 +2531,7 @@ export function useEngineCore(options) {
|
|
|
2365
2531
|
tables,
|
|
2366
2532
|
namedRanges,
|
|
2367
2533
|
protectedRanges,
|
|
2534
|
+
customTableStyles: facets.customTableStyles,
|
|
2368
2535
|
embeds,
|
|
2369
2536
|
slicers,
|
|
2370
2537
|
getDataValidation,
|
|
@@ -2401,6 +2568,7 @@ export function useEngineCore(options) {
|
|
|
2401
2568
|
applyPatch,
|
|
2402
2569
|
generateStatePatches,
|
|
2403
2570
|
createHistory,
|
|
2571
|
+
batchHistory,
|
|
2404
2572
|
onClearHistory,
|
|
2405
2573
|
getFormattingFromRange,
|
|
2406
2574
|
getFormulasFromRange,
|
|
@@ -2420,12 +2588,15 @@ export function useEngineCore(options) {
|
|
|
2420
2588
|
formulaLocale,
|
|
2421
2589
|
state,
|
|
2422
2590
|
handlers,
|
|
2591
|
+
onRemoveTable,
|
|
2423
2592
|
ready,
|
|
2424
2593
|
hist,
|
|
2425
2594
|
onCommand,
|
|
2426
2595
|
undo,
|
|
2427
2596
|
redo,
|
|
2597
|
+
batchHistory,
|
|
2428
2598
|
onMoveChart,
|
|
2599
|
+
onMoveChartToSheet,
|
|
2429
2600
|
onResizeChart,
|
|
2430
2601
|
onCreateConditionalFormattingRule,
|
|
2431
2602
|
onRepeatFormatting,
|
|
@@ -2488,6 +2659,7 @@ export function useEngineCore(options) {
|
|
|
2488
2659
|
onSelectNextSheet,
|
|
2489
2660
|
onSelectPreviousSheet,
|
|
2490
2661
|
bandedRanges,
|
|
2662
|
+
onPreviewTableStyle,
|
|
2491
2663
|
basicFilter,
|
|
2492
2664
|
hostHiddenRowRanges,
|
|
2493
2665
|
arrows,
|
|
@@ -2495,6 +2667,7 @@ export function useEngineCore(options) {
|
|
|
2495
2667
|
tables,
|
|
2496
2668
|
namedRanges,
|
|
2497
2669
|
protectedRanges,
|
|
2670
|
+
facets.customTableStyles,
|
|
2498
2671
|
embeds,
|
|
2499
2672
|
slicers,
|
|
2500
2673
|
getDataValidation,
|
|
@@ -1,7 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `useSpreadsheetEngine` — the batteries-included **Option B** hook: the engine-backed data/calc core
|
|
3
|
+
* ({@link useEngineCore}) composed with the backend-agnostic chrome ({@link useSpreadsheetUI}). It's
|
|
4
|
+
* the Option-B peer of `useSpreadsheetState` — one hook a component drives the whole grid + dialogs
|
|
5
|
+
* from. The core owns the engine surface (data/calc/commands/accessors); the chrome owns the dialogs +
|
|
6
|
+
* host intents (clipboard/citations/comments/…). Their UNION is what makes this a structural drop-in
|
|
7
|
+
* for `useSpreadsheetState` — the parity lock below is asserted here, not on either layer alone.
|
|
8
|
+
*/
|
|
9
|
+
import { type SparklineGroupHandlers } from "@rowsncolumns/spreadsheet-state";
|
|
1
10
|
import { type EngineSpreadsheet, type UseEngineSpreadsheetOptions } from "./use-engine-core";
|
|
2
11
|
import { type SpreadsheetUI } from "./use-spreadsheet-ui";
|
|
3
12
|
/** The composed surface: the engine core (data/calc/commands/accessors) + the chrome (dialogs + host
|
|
4
13
|
* intents). This — not `useEngineCore` alone — is the drop-in replacement for `useSpreadsheetState`. */
|
|
5
|
-
export type SpreadsheetEngine = EngineSpreadsheet & SpreadsheetUI;
|
|
14
|
+
export type SpreadsheetEngine = EngineSpreadsheet & SpreadsheetUI & SparklineGroupHandlers;
|
|
6
15
|
export declare function useSpreadsheetEngine(options: UseEngineSpreadsheetOptions): SpreadsheetEngine;
|
|
7
16
|
//# sourceMappingURL=use-spreadsheet-engine.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-spreadsheet-engine.d.ts","sourceRoot":"","sources":["../../src/use-spreadsheet-engine.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"use-spreadsheet-engine.d.ts","sourceRoot":"","sources":["../../src/use-spreadsheet-engine.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EACL,KAAK,sBAAsB,EAQ5B,MAAM,iCAAiC,CAAC;AAGzC,OAAO,EACL,KAAK,iBAAiB,EAEtB,KAAK,2BAA2B,EACjC,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,KAAK,aAAa,EAAoB,MAAM,sBAAsB,CAAC;AAE5E;wGACwG;AACxG,MAAM,MAAM,iBAAiB,GAAG,iBAAiB,GAC/C,aAAa,GACb,sBAAsB,CAAC;AAazB,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,2BAA2B,GACnC,iBAAiB,CA0GnB"}
|