@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.
@@ -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 — create the rule through the engine
11
- // first, then open the dialog unless suppressed, mirroring the JS host's
12
- // `useOnRequestDataValidation` (create immediately; dialog is optional edit UI on top).
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
- if (rule) {
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
- }, [core, ui]);
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(() => ({ ...core, ...ui, onRequestDataValidation }), [core, ui, onRequestDataValidation]);
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,CA+HhD"}
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.0.0",
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.33",
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.3.0",
50
- "@rowsncolumns/spreadsheet-state": ">=29.0.0",
51
- "@rowsncolumns/toolkit": ">=24.4.5",
52
- "@rowsncolumns/utils": ">=9.3.0",
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
  }