@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
|
@@ -1,3 +1,12 @@
|
|
|
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 { useOnRequestCreateTable, useOnRequestDataValidation, useOnRequestEditTable, useOnRequestInsertSlicer, useOnRequestResizeTable, useSparklineGroups, } from "@rowsncolumns/spreadsheet-state";
|
|
1
10
|
import { useCallback, useMemo } from "react";
|
|
2
11
|
import { useEngineCore, } from "./use-engine-core";
|
|
3
12
|
import { useSpreadsheetUI } from "./use-spreadsheet-ui";
|
|
@@ -7,17 +16,76 @@ export function useSpreadsheetEngine(options) {
|
|
|
7
16
|
const core = useEngineCore(options);
|
|
8
17
|
const ui = useSpreadsheetUI();
|
|
9
18
|
// Insert → Checkbox / Dropdown pass a pre-built rule (checkbox with `showEditUI: false`). The
|
|
10
|
-
// chrome opener alone would drop it and only show the dialog —
|
|
11
|
-
//
|
|
12
|
-
//
|
|
19
|
+
// chrome opener alone would drop it and only show the dialog — compose the JS host's
|
|
20
|
+
// `useOnRequestDataValidation` (it hands a rule the dialog will show to the editor as a DRAFT the
|
|
21
|
+
// user's Save creates, and creates a dialog-less rule through the engine immediately), then flip
|
|
22
|
+
// the chrome flag so a `dialogs`-driven host opens the same editor.
|
|
23
|
+
const requestDataValidation = useOnRequestDataValidation({
|
|
24
|
+
onCreateDataValidationRule: core.onCreateDataValidationRule,
|
|
25
|
+
});
|
|
13
26
|
const onRequestDataValidation = useCallback((sheetId, activeCell, selections, rule, showEditUI = true) => {
|
|
14
|
-
|
|
15
|
-
core.onCreateDataValidationRule?.(rule);
|
|
16
|
-
}
|
|
27
|
+
requestDataValidation(sheetId, activeCell, selections, rule, showEditUI);
|
|
17
28
|
if (showEditUI) {
|
|
18
29
|
ui.onRequestDataValidation(sheetId, activeCell, selections, rule, showEditUI);
|
|
19
30
|
}
|
|
20
|
-
}, [
|
|
31
|
+
}, [requestDataValidation, ui]);
|
|
32
|
+
// The Create Table dialog pre-fills its range and guesses "My table has headers" from the
|
|
33
|
+
// engine's cells, so the opener is composed here (the chrome alone has no cell access): it
|
|
34
|
+
// writes the request the `TableEditor` create dialog reads and stashes the chrome context too.
|
|
35
|
+
const requestCreateTable = useOnRequestCreateTable({
|
|
36
|
+
getEffectiveExtendedValue: core.getEffectiveExtendedValue,
|
|
37
|
+
});
|
|
38
|
+
const onRequestCreateTable = useCallback((sheetId, activeCell, selections, theme, bandedRange) => {
|
|
39
|
+
requestCreateTable(sheetId, activeCell, selections, theme, bandedRange);
|
|
40
|
+
ui.onRequestCreateTable(sheetId, activeCell, selections, theme, bandedRange);
|
|
41
|
+
}, [requestCreateTable, ui]);
|
|
42
|
+
// The Edit Table dialog is the jotai-driven `TableEditor` one (the grid's context menu, Table
|
|
43
|
+
// Design → Properties): stash the table for it and the chrome context too.
|
|
44
|
+
const requestEditTable = useOnRequestEditTable();
|
|
45
|
+
const onRequestEditTable = useCallback((table) => {
|
|
46
|
+
requestEditTable(table);
|
|
47
|
+
ui.onRequestEditTable(table);
|
|
48
|
+
}, [requestEditTable, ui]);
|
|
49
|
+
// The Resize Table dialog is the jotai-driven `TableEditor` one: stash the table for it and
|
|
50
|
+
// the chrome context too.
|
|
51
|
+
const requestResizeTable = useOnRequestResizeTable();
|
|
52
|
+
const onRequestResizeTable = useCallback((table) => {
|
|
53
|
+
requestResizeTable(table);
|
|
54
|
+
ui.onRequestResizeTable(table);
|
|
55
|
+
}, [requestResizeTable, ui]);
|
|
56
|
+
// The Insert Slicers dialog is the jotai-driven `TableEditor` one too: stash the table for it and
|
|
57
|
+
// the chrome context.
|
|
58
|
+
const requestInsertSlicer = useOnRequestInsertSlicer();
|
|
59
|
+
const onRequestInsertSlicer = useCallback((table) => {
|
|
60
|
+
requestInsertSlicer(table);
|
|
61
|
+
ui.onRequestInsertSlicer(table);
|
|
62
|
+
}, [requestInsertSlicer, ui]);
|
|
63
|
+
// Excel sparkline groups ride the engine's own `change-batch` / `delete-cells` commands, one
|
|
64
|
+
// `batch` per action — the shared hook only needs the core's writes + formula reads.
|
|
65
|
+
const sparklineGroups = useSparklineGroups({
|
|
66
|
+
onChangeBatch: core.onChangeBatch,
|
|
67
|
+
onDelete: core.onDelete,
|
|
68
|
+
batchHistory: core.batchHistory,
|
|
69
|
+
getUserEnteredValue: core.getUserEnteredValue,
|
|
70
|
+
});
|
|
21
71
|
// `ui` last: its dialog-openers + host-intent defaults complete the engine core's surface.
|
|
22
|
-
return useMemo(() => ({
|
|
72
|
+
return useMemo(() => ({
|
|
73
|
+
...core,
|
|
74
|
+
...ui,
|
|
75
|
+
...sparklineGroups,
|
|
76
|
+
onRequestDataValidation,
|
|
77
|
+
onRequestCreateTable,
|
|
78
|
+
onRequestEditTable,
|
|
79
|
+
onRequestResizeTable,
|
|
80
|
+
onRequestInsertSlicer,
|
|
81
|
+
}), [
|
|
82
|
+
core,
|
|
83
|
+
ui,
|
|
84
|
+
sparklineGroups,
|
|
85
|
+
onRequestDataValidation,
|
|
86
|
+
onRequestCreateTable,
|
|
87
|
+
onRequestEditTable,
|
|
88
|
+
onRequestResizeTable,
|
|
89
|
+
onRequestInsertSlicer,
|
|
90
|
+
]);
|
|
23
91
|
}
|
|
@@ -15,12 +15,12 @@ import type { useSpreadsheetState } from "@rowsncolumns/spreadsheet-state";
|
|
|
15
15
|
* exposes it (so they're drop-in for CanvasGrid's props). Erased at runtime. */
|
|
16
16
|
type SS = ReturnType<typeof useSpreadsheetState>;
|
|
17
17
|
/** The dialogs the chrome can open. */
|
|
18
|
-
export type DialogName = "editTable" | "editEmbed" | "editSlicer" | "deleteSheet" | "namedRange" | "resize" | "formatCells" | "conditionalFormat" | "insertImage" | "insertLink" | "dataValidation" | "note";
|
|
18
|
+
export type DialogName = "editTable" | "createTable" | "resizeTable" | "insertSlicer" | "editEmbed" | "editSlicer" | "deleteSheet" | "namedRange" | "resize" | "formatCells" | "conditionalFormat" | "insertImage" | "insertLink" | "dataValidation" | "note";
|
|
19
19
|
/** The host/chrome slice of `useSpreadsheetState`: dialog-openers (`onRequest*`, `onInsertNote`) plus
|
|
20
20
|
* the few intents the HOST genuinely owns (file drag/drop/insert). Picked from `SS` so signatures stay
|
|
21
21
|
* exact. Everything that reads or mutates engine data — paint format, citations, comments, link follow,
|
|
22
22
|
* CF preview — moved to {@link useEngineCore}; the chrome is backend-agnostic UI only. */
|
|
23
|
-
export type ChromeParityStubs = Pick<SS, "onRequestConditionalFormat" | "onRequestDataValidation" | "onRequestDefineNamedRange" | "onRequestDeleteSheet" | "onRequestEditEmbed" | "onRequestEditSlicer" | "onRequestEditTable" | "onRequestFormatCells" | "onRequestInsertImage" | "onRequestInsertLink" | "onRequestResize" | "onRequestUpdateNamedRange" | "onInsertNote" | "onDragOver" | "onDrop" | "onInsertFile">;
|
|
23
|
+
export type ChromeParityStubs = Pick<SS, "onRequestConditionalFormat" | "onRequestCreateTable" | "onRequestDataValidation" | "onRequestDefineNamedRange" | "onRequestDeleteSheet" | "onRequestEditEmbed" | "onRequestEditSlicer" | "onRequestEditTable" | "onRequestResizeTable" | "onRequestInsertSlicer" | "onRequestFormatCells" | "onRequestInsertImage" | "onRequestInsertLink" | "onRequestResize" | "onRequestUpdateNamedRange" | "onInsertNote" | "onDragOver" | "onDrop" | "onInsertFile">;
|
|
24
24
|
/** Chrome state + the dialog-opener handlers + host-owned UI intents. Spread into
|
|
25
25
|
* {@link useSpreadsheetEngine}'s return, where these override the engine core's omitted surface. */
|
|
26
26
|
export interface SpreadsheetUI extends ChromeParityStubs {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-spreadsheet-ui.d.ts","sourceRoot":"","sources":["../../src/use-spreadsheet-ui.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAG3E;gFACgF;AAChF,KAAK,EAAE,GAAG,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEjD,uCAAuC;AACvC,MAAM,MAAM,UAAU,GAClB,WAAW,GACX,WAAW,GACX,YAAY,GACZ,aAAa,GACb,YAAY,GACZ,QAAQ,GACR,aAAa,GACb,mBAAmB,GACnB,aAAa,GACb,YAAY,GACZ,gBAAgB,GAChB,MAAM,CAAC;AAEX;;;0FAG0F;AAC1F,MAAM,MAAM,iBAAiB,GAAG,IAAI,CAClC,EAAE,EACA,4BAA4B,GAC5B,yBAAyB,GACzB,2BAA2B,GAC3B,sBAAsB,GACtB,oBAAoB,GACpB,qBAAqB,GACrB,oBAAoB,GACpB,sBAAsB,GACtB,sBAAsB,GACtB,qBAAqB,GACrB,iBAAiB,GACjB,2BAA2B,GAC3B,cAAc,GACd,YAAY,GACZ,QAAQ,GACR,cAAc,CACjB,CAAC;AAYF;oGACoG;AACpG,MAAM,WAAW,aAAc,SAAQ,iBAAiB;IACtD,wCAAwC;IACxC,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;IAC9C;kEAC8D;IAC9D,aAAa,EAAE,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;IACpD,wDAAwD;IACxD,UAAU,EAAE,CAAC,IAAI,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IAC1D,sBAAsB;IACtB,WAAW,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,CAAC;CACzC;AAED,wBAAgB,gBAAgB,IAAI,aAAa,
|
|
1
|
+
{"version":3,"file":"use-spreadsheet-ui.d.ts","sourceRoot":"","sources":["../../src/use-spreadsheet-ui.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAG3E;gFACgF;AAChF,KAAK,EAAE,GAAG,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEjD,uCAAuC;AACvC,MAAM,MAAM,UAAU,GAClB,WAAW,GACX,aAAa,GACb,aAAa,GACb,cAAc,GACd,WAAW,GACX,YAAY,GACZ,aAAa,GACb,YAAY,GACZ,QAAQ,GACR,aAAa,GACb,mBAAmB,GACnB,aAAa,GACb,YAAY,GACZ,gBAAgB,GAChB,MAAM,CAAC;AAEX;;;0FAG0F;AAC1F,MAAM,MAAM,iBAAiB,GAAG,IAAI,CAClC,EAAE,EACA,4BAA4B,GAC5B,sBAAsB,GACtB,yBAAyB,GACzB,2BAA2B,GAC3B,sBAAsB,GACtB,oBAAoB,GACpB,qBAAqB,GACrB,oBAAoB,GACpB,sBAAsB,GACtB,uBAAuB,GACvB,sBAAsB,GACtB,sBAAsB,GACtB,qBAAqB,GACrB,iBAAiB,GACjB,2BAA2B,GAC3B,cAAc,GACd,YAAY,GACZ,QAAQ,GACR,cAAc,CACjB,CAAC;AAYF;oGACoG;AACpG,MAAM,WAAW,aAAc,SAAQ,iBAAiB;IACtD,wCAAwC;IACxC,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;IAC9C;kEAC8D;IAC9D,aAAa,EAAE,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;IACpD,wDAAwD;IACxD,UAAU,EAAE,CAAC,IAAI,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IAC1D,sBAAsB;IACtB,WAAW,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,CAAC;CACzC;AAED,wBAAgB,gBAAgB,IAAI,aAAa,CA4JhD"}
|
|
@@ -19,6 +19,19 @@ export function useSpreadsheetUI() {
|
|
|
19
19
|
// Each opener stashes the value the dialog edits, then opens it. Arg shapes come from `SS[K]`, so
|
|
20
20
|
// they match exactly what CanvasGrid passes.
|
|
21
21
|
const onRequestEditTable = useCallback((table) => openDialog("editTable", table), [openDialog]);
|
|
22
|
+
// The Resize Table dialog (Table Design → Resize Table, Table → Resize Table…).
|
|
23
|
+
const onRequestResizeTable = useCallback((table) => openDialog("resizeTable", table), [openDialog]);
|
|
24
|
+
// The Insert Slicers dialog (Table Design → Insert Slicer, Table → Insert Slicer…).
|
|
25
|
+
const onRequestInsertSlicer = useCallback((table) => openDialog("insertSlicer", table), [openDialog]);
|
|
26
|
+
// The Create Table dialog (Ctrl+T / Insert → Table / Format as Table). `useSpreadsheetEngine`
|
|
27
|
+
// layers the data-aware opener (pre-filled range + headers guess) over this one.
|
|
28
|
+
const onRequestCreateTable = useCallback((sheetId, activeCell, selections, theme, bandedRange) => openDialog("createTable", {
|
|
29
|
+
sheetId,
|
|
30
|
+
activeCell,
|
|
31
|
+
selections,
|
|
32
|
+
theme,
|
|
33
|
+
bandedRange,
|
|
34
|
+
}), [openDialog]);
|
|
22
35
|
const onRequestEditEmbed = useCallback((embed) => openDialog("editEmbed", embed), [openDialog]);
|
|
23
36
|
const onRequestEditSlicer = useCallback((slicer) => openDialog("editSlicer", slicer), [openDialog]);
|
|
24
37
|
const onRequestDeleteSheet = useCallback((sheetId) => openDialog("deleteSheet", sheetId), [openDialog]);
|
|
@@ -40,6 +53,9 @@ export function useSpreadsheetUI() {
|
|
|
40
53
|
closeDialog,
|
|
41
54
|
// dialog-openers (real)
|
|
42
55
|
onRequestEditTable,
|
|
56
|
+
onRequestResizeTable,
|
|
57
|
+
onRequestInsertSlicer,
|
|
58
|
+
onRequestCreateTable,
|
|
43
59
|
onRequestEditEmbed,
|
|
44
60
|
onRequestEditSlicer,
|
|
45
61
|
onRequestDeleteSheet,
|
|
@@ -62,6 +78,9 @@ export function useSpreadsheetUI() {
|
|
|
62
78
|
openDialog,
|
|
63
79
|
closeDialog,
|
|
64
80
|
onRequestEditTable,
|
|
81
|
+
onRequestResizeTable,
|
|
82
|
+
onRequestInsertSlicer,
|
|
83
|
+
onRequestCreateTable,
|
|
65
84
|
onRequestEditEmbed,
|
|
66
85
|
onRequestEditSlicer,
|
|
67
86
|
onRequestDeleteSheet,
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rowsncolumns/rnc-engine",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"author": "Vinay M",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
6
6
|
"description": "Typed JS/TS interop for the Rust→WASM spreadsheet calc engine (rnc-wasm). Ergonomic JSON-in/out wrapper over the wasm-bindgen surface: applyCommand(Command)→CommitResult, readWindow→WindowSnapshot, and Map<\"sheet!A1\",CellFormat> style folding. Pluggable backend — single-user `SpreadsheetEngine` (default) or collaborative `CollabSpreadsheetEngine` (Yjs sync) — plus the Option-B `useSpreadsheetEngine` React hook.",
|
|
@@ -20,7 +20,9 @@
|
|
|
20
20
|
"build:wasm": "cd ../../rust && RUSTUP_TOOLCHAIN=nightly wasm-pack build crates/rnc-wasm --target web --out-dir pkg -- --features collab && cp -f crates/rnc-wasm/pkg/rnc_wasm.js crates/rnc-wasm/pkg/rnc_wasm_bg.wasm crates/rnc-wasm/pkg/rnc_wasm.d.ts crates/rnc-wasm/pkg/rnc_wasm_bg.wasm.d.ts ../libs/rnc-engine/src/wasm/",
|
|
21
21
|
"clean": "rimraf dist",
|
|
22
22
|
"build:watch": "tsc -p ./tsconfig.esm.json --watch",
|
|
23
|
-
"test": "vitest --run"
|
|
23
|
+
"test": "vitest --run",
|
|
24
|
+
"types:specs": "node ../../scripts/typecheck-specs.mjs",
|
|
25
|
+
"types:specs:update": "node ../../scripts/typecheck-specs.mjs --update"
|
|
24
26
|
},
|
|
25
27
|
"files": [
|
|
26
28
|
"dist"
|
|
@@ -43,13 +45,13 @@
|
|
|
43
45
|
"react": ">=18"
|
|
44
46
|
},
|
|
45
47
|
"devDependencies": {
|
|
46
|
-
"@rowsncolumns/common-types": ">=5.2.
|
|
48
|
+
"@rowsncolumns/common-types": ">=5.2.34",
|
|
47
49
|
"@rowsncolumns/dag": ">=7.2.30",
|
|
48
50
|
"@rowsncolumns/grid": ">=13.2.33",
|
|
49
|
-
"@rowsncolumns/spreadsheet": ">=10.
|
|
50
|
-
"@rowsncolumns/spreadsheet-state": ">=29.
|
|
51
|
-
"@rowsncolumns/toolkit": ">=24.
|
|
52
|
-
"@rowsncolumns/utils": ">=9.
|
|
51
|
+
"@rowsncolumns/spreadsheet": ">=10.4.0",
|
|
52
|
+
"@rowsncolumns/spreadsheet-state": ">=29.1.2",
|
|
53
|
+
"@rowsncolumns/toolkit": ">=24.5.0",
|
|
54
|
+
"@rowsncolumns/utils": ">=9.4.0",
|
|
53
55
|
"fflate": "^0.8.2"
|
|
54
56
|
}
|
|
55
57
|
}
|