@ricsam/react-spreadsheets 0.0.6 → 0.0.8

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/cjs/lib.cjs CHANGED
@@ -1457,6 +1457,99 @@ var withReadableTextColor = (style) => {
1457
1457
  return { ...style, color };
1458
1458
  };
1459
1459
  var hasBorderStyle = (style) => Boolean(style?.borderColor || style?.borderTopColor || style?.borderRightColor || style?.borderBottomColor || style?.borderLeftColor);
1460
+ var normalizeFiniteCount = (count) => {
1461
+ if (count === undefined || count === Infinity)
1462
+ return;
1463
+ if (!Number.isFinite(count))
1464
+ return 0;
1465
+ return Math.max(0, Math.floor(count));
1466
+ };
1467
+ var countToSelectionBound = (count) => count === undefined ? { type: "infinity" } : { type: "number", value: count };
1468
+ var alignScrollOffset = (current, itemStart, itemEnd, viewportSize, align) => {
1469
+ if (viewportSize <= 0)
1470
+ return current;
1471
+ if (align === "start")
1472
+ return itemStart;
1473
+ if (align === "end")
1474
+ return itemEnd - viewportSize;
1475
+ if (itemStart < current)
1476
+ return itemStart;
1477
+ if (itemEnd > current + viewportSize)
1478
+ return itemEnd - viewportSize;
1479
+ return current;
1480
+ };
1481
+ var hasCellData = (value) => value !== undefined && value !== "";
1482
+ var getSparseUsedRange = (cellData, rowCount, columnCount) => {
1483
+ let minRow = Infinity;
1484
+ let maxRow = -1;
1485
+ let minCol = Infinity;
1486
+ let maxCol = -1;
1487
+ for (const [reference, value] of cellData) {
1488
+ if (!hasCellData(value))
1489
+ continue;
1490
+ let rowIndex;
1491
+ let columnIndex;
1492
+ try {
1493
+ ({ rowIndex, columnIndex } = parseCellReference(reference));
1494
+ } catch {
1495
+ continue;
1496
+ }
1497
+ if (rowIndex < 0 || columnIndex < 0 || rowCount !== undefined && rowIndex >= rowCount || columnCount !== undefined && columnIndex >= columnCount) {
1498
+ continue;
1499
+ }
1500
+ minRow = Math.min(minRow, rowIndex);
1501
+ maxRow = Math.max(maxRow, rowIndex);
1502
+ minCol = Math.min(minCol, columnIndex);
1503
+ maxCol = Math.max(maxCol, columnIndex);
1504
+ }
1505
+ if (maxRow < 0 || maxCol < 0)
1506
+ return;
1507
+ return {
1508
+ start: { row: minRow, col: minCol },
1509
+ end: {
1510
+ row: { type: "number", value: maxRow },
1511
+ col: { type: "number", value: maxCol }
1512
+ }
1513
+ };
1514
+ };
1515
+ var resolveSparseNavigationTarget = (request, cellData) => {
1516
+ if (request.kind !== "jump" || request.table)
1517
+ return;
1518
+ const isVertical = request.direction === "up" || request.direction === "down";
1519
+ const movingForward = request.direction === "down" || request.direction === "right";
1520
+ const originAxis = isVertical ? request.origin.row : request.origin.col;
1521
+ const fixedAxis = isVertical ? request.origin.col : request.origin.row;
1522
+ const occupied = new Set;
1523
+ for (const [reference, value] of cellData) {
1524
+ if (!hasCellData(value))
1525
+ continue;
1526
+ let rowIndex;
1527
+ let columnIndex;
1528
+ try {
1529
+ ({ rowIndex, columnIndex } = parseCellReference(reference));
1530
+ } catch {
1531
+ continue;
1532
+ }
1533
+ if ((isVertical ? columnIndex : rowIndex) === fixedAxis) {
1534
+ occupied.add(isVertical ? rowIndex : columnIndex);
1535
+ }
1536
+ }
1537
+ const step = movingForward ? 1 : -1;
1538
+ let targetAxis;
1539
+ if (occupied.has(originAxis + step)) {
1540
+ targetAxis = originAxis + step;
1541
+ while (occupied.has(targetAxis + step))
1542
+ targetAxis += step;
1543
+ } else {
1544
+ const candidates = [...occupied].filter((index) => movingForward ? index > originAxis : index < originAxis);
1545
+ if (candidates.length > 0) {
1546
+ targetAxis = movingForward ? Math.min(...candidates) : Math.max(...candidates);
1547
+ }
1548
+ }
1549
+ if (targetAxis === undefined)
1550
+ return;
1551
+ return isVertical ? { row: targetAxis, col: request.origin.col } : { row: request.origin.row, col: targetAxis };
1552
+ };
1460
1553
  var CellComponent = import_react4.default.memo(({
1461
1554
  value,
1462
1555
  row,
@@ -1760,6 +1853,8 @@ var Spreadsheet = import_react4.forwardRef(({
1760
1853
  cellData: controlledCellData,
1761
1854
  onCellDataChange,
1762
1855
  onCellDataChangeError,
1856
+ rowCount,
1857
+ columnCount,
1763
1858
  columnWidths: controlledColumnWidths,
1764
1859
  onColumnWidthsChange,
1765
1860
  rowHeights: controlledRowHeights,
@@ -1781,14 +1876,35 @@ var Spreadsheet = import_react4.forwardRef(({
1781
1876
  const [containerDivRef, setContainerDivRef] = import_react4.useState(null);
1782
1877
  const colorScheme = useColorScheme(containerDivRef);
1783
1878
  const gridLineProbeRef = import_react4.useRef(null);
1879
+ const [internalCellData, setInternalCellData] = import_react4.useState(new Map);
1880
+ const [retryingEdit, setRetryingEdit] = import_react4.useState(null);
1881
+ const retryingEditVersionRef = import_react4.useRef(0);
1882
+ const cellData = controlledCellData ?? internalCellData;
1883
+ const cellDataRef = import_react4.useRef(cellData);
1884
+ cellDataRef.current = cellData;
1885
+ const finiteRowCount = normalizeFiniteCount(rowCount);
1886
+ const finiteColumnCount = normalizeFiniteCount(columnCount);
1887
+ const gridCountsRef = import_react4.useRef({ rows: finiteRowCount, columns: finiteColumnCount });
1888
+ gridCountsRef.current = { rows: finiteRowCount, columns: finiteColumnCount };
1889
+ const getNumRows = import_react4.useCallback(() => countToSelectionBound(gridCountsRef.current.rows), []);
1890
+ const getNumCols = import_react4.useCallback(() => countToSelectionBound(gridCountsRef.current.columns), []);
1891
+ const getDefaultUsedRange = import_react4.useCallback(() => getSparseUsedRange(cellDataRef.current, gridCountsRef.current.rows, gridCountsRef.current.columns), []);
1892
+ const defaultResolveTarget = import_react4.useCallback((request) => resolveSparseNavigationTarget(request, cellDataRef.current), []);
1893
+ const consumerNavigation = selection?.navigation;
1894
+ const navigation = import_react4.useMemo(() => ({
1895
+ getUsedRange: consumerNavigation?.getUsedRange ?? getDefaultUsedRange,
1896
+ ...consumerNavigation?.getTableAt ? { getTableAt: consumerNavigation.getTableAt } : {},
1897
+ resolveTarget: consumerNavigation?.resolveTarget ?? defaultResolveTarget
1898
+ }), [consumerNavigation, defaultResolveTarget, getDefaultUsedRange]);
1784
1899
  const selectionManager = import_selection_manager.useInitializeSelectionManager({
1785
- getNumCols: () => ({ type: "infinity" }),
1786
- getNumRows: () => ({ type: "infinity" }),
1900
+ getNumCols,
1901
+ getNumRows,
1787
1902
  initialState: selection?.initialState,
1788
1903
  state: selection?.state,
1789
1904
  onStateChange: selection?.onStateChange,
1790
1905
  containerElement: containerDivRef,
1791
1906
  formats: selection?.formats,
1907
+ navigation,
1792
1908
  disableAutoClipboard: true
1793
1909
  });
1794
1910
  const effects = selection?.effects;
@@ -1797,12 +1913,6 @@ var Spreadsheet = import_react4.forwardRef(({
1797
1913
  return effects(selectionManager);
1798
1914
  }
1799
1915
  }, [selectionManager, effects]);
1800
- const [internalCellData, setInternalCellData] = import_react4.useState(new Map);
1801
- const [retryingEdit, setRetryingEdit] = import_react4.useState(null);
1802
- const retryingEditVersionRef = import_react4.useRef(0);
1803
- const cellData = controlledCellData ?? internalCellData;
1804
- const cellDataRef = import_react4.useRef(cellData);
1805
- cellDataRef.current = cellData;
1806
1916
  const isControlled = controlledCellData !== undefined;
1807
1917
  const prevIsControlledRef = import_react4.useRef(isControlled);
1808
1918
  selectionManager.getCellsWithData = (area) => {
@@ -1978,7 +2088,7 @@ var Spreadsheet = import_react4.forwardRef(({
1978
2088
  ctx.lineWidth = 1;
1979
2089
  let x = gridDims.headerWidth;
1980
2090
  let colIndex = 0;
1981
- while (x < viewport.scrollX + gridDims.headerWidth) {
2091
+ while (x < viewport.scrollX + gridDims.headerWidth && (finiteColumnCount === undefined || colIndex < finiteColumnCount)) {
1982
2092
  const colWidth = (columnWidths.get(indexToColumn(colIndex)) || DEFAULT_CELL_WIDTH) * viewport.zoom;
1983
2093
  if (x + colWidth > viewport.scrollX + gridDims.headerWidth) {
1984
2094
  break;
@@ -1986,7 +2096,7 @@ var Spreadsheet = import_react4.forwardRef(({
1986
2096
  x += colWidth;
1987
2097
  colIndex++;
1988
2098
  }
1989
- while (x - viewport.scrollX < width) {
2099
+ while (x - viewport.scrollX < width && (finiteColumnCount === undefined || colIndex < finiteColumnCount)) {
1990
2100
  const drawX = x - viewport.scrollX;
1991
2101
  if (drawX >= gridDims.headerWidth && drawX <= width) {
1992
2102
  ctx.beginPath();
@@ -2000,7 +2110,7 @@ var Spreadsheet = import_react4.forwardRef(({
2000
2110
  }
2001
2111
  let y = gridDims.headerHeight;
2002
2112
  let rowNum = 1;
2003
- while (y < viewport.scrollY + gridDims.headerHeight) {
2113
+ while (y < viewport.scrollY + gridDims.headerHeight && (finiteRowCount === undefined || rowNum <= finiteRowCount)) {
2004
2114
  const rowHeight = (rowHeights.get(rowNum) || DEFAULT_CELL_HEIGHT) * viewport.zoom;
2005
2115
  if (y + rowHeight > viewport.scrollY + gridDims.headerHeight) {
2006
2116
  break;
@@ -2008,7 +2118,7 @@ var Spreadsheet = import_react4.forwardRef(({
2008
2118
  y += rowHeight;
2009
2119
  rowNum++;
2010
2120
  }
2011
- while (y - viewport.scrollY < height) {
2121
+ while (y - viewport.scrollY < height && (finiteRowCount === undefined || rowNum <= finiteRowCount)) {
2012
2122
  const drawY = y - viewport.scrollY;
2013
2123
  if (drawY >= gridDims.headerHeight && drawY <= height) {
2014
2124
  ctx.beginPath();
@@ -2022,6 +2132,8 @@ var Spreadsheet = import_react4.forwardRef(({
2022
2132
  }
2023
2133
  }, [
2024
2134
  columnWidths,
2135
+ finiteColumnCount,
2136
+ finiteRowCount,
2025
2137
  gridDims.headerHeight,
2026
2138
  gridDims.headerWidth,
2027
2139
  height,
@@ -2039,7 +2151,7 @@ var Spreadsheet = import_react4.forwardRef(({
2039
2151
  const cells = [];
2040
2152
  let x = 0;
2041
2153
  let startCol = 0;
2042
- while (x < viewport.scrollX) {
2154
+ while (x < viewport.scrollX && (finiteColumnCount === undefined || startCol < finiteColumnCount)) {
2043
2155
  const colWidth = (columnWidths.get(indexToColumn(startCol)) || DEFAULT_CELL_WIDTH) * viewport.zoom;
2044
2156
  if (x + colWidth > viewport.scrollX) {
2045
2157
  break;
@@ -2049,7 +2161,7 @@ var Spreadsheet = import_react4.forwardRef(({
2049
2161
  }
2050
2162
  let y = 0;
2051
2163
  let startRow = 0;
2052
- while (y < viewport.scrollY) {
2164
+ while (y < viewport.scrollY && (finiteRowCount === undefined || startRow < finiteRowCount)) {
2053
2165
  const rowHeight = (rowHeights.get(startRow + 1) || DEFAULT_CELL_HEIGHT) * viewport.zoom;
2054
2166
  if (y + rowHeight > viewport.scrollY) {
2055
2167
  break;
@@ -2059,10 +2171,10 @@ var Spreadsheet = import_react4.forwardRef(({
2059
2171
  }
2060
2172
  let rowY = y;
2061
2173
  let row = startRow;
2062
- while (rowY < viewport.scrollY + height) {
2174
+ while (rowY < viewport.scrollY + height && (finiteRowCount === undefined || row < finiteRowCount)) {
2063
2175
  let colX = x;
2064
2176
  let col = startCol;
2065
- while (colX < viewport.scrollX + width) {
2177
+ while (colX < viewport.scrollX + width && (finiteColumnCount === undefined || col < finiteColumnCount)) {
2066
2178
  const colKey = indexToColumn(col);
2067
2179
  const rowNum = getRowNumber(row);
2068
2180
  const cellKey = `${colKey}${rowNum}`;
@@ -2083,6 +2195,8 @@ var Spreadsheet = import_react4.forwardRef(({
2083
2195
  }, [
2084
2196
  cellData,
2085
2197
  columnWidths,
2198
+ finiteColumnCount,
2199
+ finiteRowCount,
2086
2200
  height,
2087
2201
  rowHeights,
2088
2202
  viewport.scrollX,
@@ -2110,6 +2224,64 @@ var Spreadsheet = import_react4.forwardRef(({
2110
2224
  }
2111
2225
  return { x, y };
2112
2226
  }, [columnWidths, rowHeights]);
2227
+ const clampViewportOffsets = import_react4.useCallback((scrollX, scrollY, zoom) => {
2228
+ const bodyWidth = Math.max(0, width - HEADER_WIDTH * zoom);
2229
+ const bodyHeight = Math.max(0, height - HEADER_HEIGHT * zoom);
2230
+ const maxScrollX = finiteColumnCount === undefined ? Infinity : Math.max(0, getColumnEdgePosition(finiteColumnCount, columnWidths) * zoom - bodyWidth);
2231
+ const maxScrollY = finiteRowCount === undefined ? Infinity : Math.max(0, getRowEdgePosition(finiteRowCount, rowHeights) * zoom - bodyHeight);
2232
+ return {
2233
+ scrollX: Math.min(Math.max(0, scrollX), maxScrollX),
2234
+ scrollY: Math.min(Math.max(0, scrollY), maxScrollY)
2235
+ };
2236
+ }, [columnWidths, finiteColumnCount, finiteRowCount, height, rowHeights, width]);
2237
+ const revealCell = import_react4.useCallback((cell, options = {}) => {
2238
+ if (finiteRowCount === 0 || finiteColumnCount === 0)
2239
+ return;
2240
+ if (!Number.isFinite(cell.row) || !Number.isFinite(cell.col))
2241
+ return;
2242
+ const requestedRow = Math.max(0, Math.floor(cell.row));
2243
+ const requestedCol = Math.max(0, Math.floor(cell.col));
2244
+ const row = finiteRowCount === undefined ? requestedRow : Math.min(requestedRow, finiteRowCount - 1);
2245
+ const col = finiteColumnCount === undefined ? requestedCol : Math.min(requestedCol, finiteColumnCount - 1);
2246
+ setViewport((previous) => {
2247
+ const bodyWidth = Math.max(0, width - HEADER_WIDTH * previous.zoom);
2248
+ const bodyHeight = Math.max(0, height - HEADER_HEIGHT * previous.zoom);
2249
+ const left = getColumnEdgePosition(col, columnWidths) * previous.zoom;
2250
+ const right = getColumnEdgePosition(col + 1, columnWidths) * previous.zoom;
2251
+ const top = getRowEdgePosition(row, rowHeights) * previous.zoom;
2252
+ const bottom = getRowEdgePosition(row + 1, rowHeights) * previous.zoom;
2253
+ const desired = clampViewportOffsets(alignScrollOffset(previous.scrollX, left, right, bodyWidth, options.columnAlign ?? "nearest"), alignScrollOffset(previous.scrollY, top, bottom, bodyHeight, options.rowAlign ?? "nearest"), previous.zoom);
2254
+ if (desired.scrollX === previous.scrollX && desired.scrollY === previous.scrollY) {
2255
+ return previous;
2256
+ }
2257
+ return { ...previous, ...desired };
2258
+ });
2259
+ }, [
2260
+ clampViewportOffsets,
2261
+ columnWidths,
2262
+ finiteColumnCount,
2263
+ finiteRowCount,
2264
+ height,
2265
+ rowHeights,
2266
+ width
2267
+ ]);
2268
+ const scrollToCell = import_react4.useCallback((cell, options = {}) => {
2269
+ const align = options.align ?? "nearest";
2270
+ revealCell(cell, { rowAlign: align, columnAlign: align });
2271
+ }, [revealCell]);
2272
+ import_react4.useEffect(() => selectionManager.listenToViewportRequest((request) => {
2273
+ const isVertical = request.direction === "up" || request.direction === "down";
2274
+ revealCell(request.cell, {
2275
+ rowAlign: isVertical ? request.align : "nearest",
2276
+ columnAlign: isVertical ? "nearest" : request.align
2277
+ });
2278
+ }), [revealCell, selectionManager]);
2279
+ import_react4.useEffect(() => {
2280
+ setViewport((previous) => {
2281
+ const next = clampViewportOffsets(previous.scrollX, previous.scrollY, previous.zoom);
2282
+ return next.scrollX === previous.scrollX && next.scrollY === previous.scrollY ? previous : { ...previous, ...next };
2283
+ });
2284
+ }, [clampViewportOffsets]);
2113
2285
  import_react4.default.useEffect(() => {
2114
2286
  return selectionManager.listenToUpdateData((updates) => {
2115
2287
  const editingState = selectionManager.isEditing;
@@ -2184,12 +2356,11 @@ var Spreadsheet = import_react4.forwardRef(({
2184
2356
  const handleWheel = import_react4.useCallback((e) => {
2185
2357
  e.preventDefault();
2186
2358
  e.stopPropagation();
2187
- setViewport((prev) => ({
2188
- ...prev,
2189
- scrollX: Math.max(0, prev.scrollX + e.deltaX),
2190
- scrollY: Math.max(0, prev.scrollY + e.deltaY)
2359
+ setViewport((previous) => ({
2360
+ ...previous,
2361
+ ...clampViewportOffsets(previous.scrollX + e.deltaX, previous.scrollY + e.deltaY, previous.zoom)
2191
2362
  }));
2192
- }, []);
2363
+ }, [clampViewportOffsets]);
2193
2364
  const commitOverlayChildren = import_react4.useCallback((children) => {
2194
2365
  overlayChildrenRef.current = children;
2195
2366
  if (onOverlayChildrenChange) {
@@ -2608,7 +2779,7 @@ var Spreadsheet = import_react4.forwardRef(({
2608
2779
  const headers = [];
2609
2780
  let x = 0;
2610
2781
  let startCol = 0;
2611
- while (x < viewport.scrollX) {
2782
+ while (x < viewport.scrollX && (finiteColumnCount === undefined || startCol < finiteColumnCount)) {
2612
2783
  const col = indexToColumn(startCol);
2613
2784
  const colWidth = getColumnWidth(col) * viewport.zoom;
2614
2785
  if (x + colWidth > viewport.scrollX) {
@@ -2617,7 +2788,7 @@ var Spreadsheet = import_react4.forwardRef(({
2617
2788
  x += colWidth;
2618
2789
  startCol++;
2619
2790
  }
2620
- while (x < viewport.scrollX + width) {
2791
+ while (x < viewport.scrollX + width && (finiteColumnCount === undefined || startCol < finiteColumnCount)) {
2621
2792
  const col = indexToColumn(startCol);
2622
2793
  const colWidth = getColumnWidth(col) * viewport.zoom;
2623
2794
  headers.push({
@@ -2628,14 +2799,14 @@ var Spreadsheet = import_react4.forwardRef(({
2628
2799
  startCol++;
2629
2800
  }
2630
2801
  return headers;
2631
- }, [width, viewport, getColumnWidth]);
2802
+ }, [finiteColumnCount, width, viewport, getColumnWidth]);
2632
2803
  const getVisibleRowHeaders = import_react4.useCallback(() => {
2633
2804
  if (!height)
2634
2805
  return [];
2635
2806
  const headers = [];
2636
2807
  let y = 0;
2637
2808
  let rowNum = 1;
2638
- while (y < viewport.scrollY) {
2809
+ while (y < viewport.scrollY && (finiteRowCount === undefined || rowNum <= finiteRowCount)) {
2639
2810
  const rowHeight = getRowHeight(rowNum) * viewport.zoom;
2640
2811
  if (y + rowHeight > viewport.scrollY) {
2641
2812
  break;
@@ -2643,7 +2814,7 @@ var Spreadsheet = import_react4.forwardRef(({
2643
2814
  y += rowHeight;
2644
2815
  rowNum++;
2645
2816
  }
2646
- while (y < viewport.scrollY + height) {
2817
+ while (y < viewport.scrollY + height && (finiteRowCount === undefined || rowNum <= finiteRowCount)) {
2647
2818
  const rowHeight = getRowHeight(rowNum) * viewport.zoom;
2648
2819
  headers.push({
2649
2820
  row: rowNum,
@@ -2653,7 +2824,7 @@ var Spreadsheet = import_react4.forwardRef(({
2653
2824
  rowNum++;
2654
2825
  }
2655
2826
  return headers;
2656
- }, [height, viewport, getRowHeight]);
2827
+ }, [finiteRowCount, height, viewport, getRowHeight]);
2657
2828
  const { visibleOverlays, overlaysToRender } = import_react4.useMemo(() => {
2658
2829
  if (!width || !height || !overlayChildren) {
2659
2830
  return { visibleOverlays: [], overlaysToRender: [] };
@@ -2701,6 +2872,43 @@ var Spreadsheet = import_react4.forwardRef(({
2701
2872
  const visibleColumnHeaders = import_react4.default.useMemo(() => getVisibleColumnHeaders(), [getVisibleColumnHeaders]);
2702
2873
  const visibleRowHeaders = import_react4.default.useMemo(() => getVisibleRowHeaders(), [getVisibleRowHeaders]);
2703
2874
  const hasFocus = import_selection_manager.useSelectionManager(selectionManager, () => selectionManager.hasFocus);
2875
+ const referenceSelection = import_selection_manager.useSelectionManager(selectionManager, () => selectionManager.referenceSelection);
2876
+ const referenceSelectionRect = import_react4.useMemo(() => {
2877
+ if (referenceSelection.type === "none")
2878
+ return;
2879
+ if (finiteRowCount === 0 || finiteColumnCount === 0)
2880
+ return;
2881
+ const range = referenceSelection.range;
2882
+ const lastVisibleRow = visibleCells.reduce((maximum, cell) => Math.max(maximum, cell.row - 1), range.start.row);
2883
+ const lastVisibleCol = visibleCells.reduce((maximum, cell) => Math.max(maximum, columnToIndex(cell.col)), range.start.col);
2884
+ const rawEndRow = range.end.row.type === "number" ? range.end.row.value : finiteRowCount === undefined ? lastVisibleRow : finiteRowCount - 1;
2885
+ const rawEndCol = range.end.col.type === "number" ? range.end.col.value : finiteColumnCount === undefined ? lastVisibleCol : finiteColumnCount - 1;
2886
+ const maxRow = finiteRowCount === undefined ? Infinity : finiteRowCount - 1;
2887
+ const maxCol = finiteColumnCount === undefined ? Infinity : finiteColumnCount - 1;
2888
+ const startRow = Math.min(Math.max(0, Math.min(range.start.row, rawEndRow)), maxRow);
2889
+ const endRow = Math.min(Math.max(0, Math.max(range.start.row, rawEndRow)), maxRow);
2890
+ const startCol = Math.min(Math.max(0, Math.min(range.start.col, rawEndCol)), maxCol);
2891
+ const endCol = Math.min(Math.max(0, Math.max(range.start.col, rawEndCol)), maxCol);
2892
+ const rect = getRectFromCellSnapAnchor({
2893
+ startCol,
2894
+ startRow,
2895
+ endCol: endCol + 1,
2896
+ endRow: endRow + 1
2897
+ }, columnWidths, rowHeights);
2898
+ return {
2899
+ left: HEADER_WIDTH + rect.x,
2900
+ top: HEADER_HEIGHT + rect.y,
2901
+ width: rect.width,
2902
+ height: rect.height
2903
+ };
2904
+ }, [
2905
+ columnWidths,
2906
+ finiteColumnCount,
2907
+ finiteRowCount,
2908
+ referenceSelection,
2909
+ rowHeights,
2910
+ visibleCells
2911
+ ]);
2704
2912
  import_react4.default.useEffect(() => {
2705
2913
  if (!containerDivRef || !hasFocus || !parentSelected) {
2706
2914
  return;
@@ -2718,8 +2926,9 @@ var Spreadsheet = import_react4.forwardRef(({
2718
2926
  },
2719
2927
  blur: () => {
2720
2928
  selectionManager.blur();
2721
- }
2722
- }), [selectionManager]);
2929
+ },
2930
+ scrollToCell
2931
+ }), [scrollToCell, selectionManager]);
2723
2932
  return /* @__PURE__ */ jsx_runtime3.jsx("div", {
2724
2933
  className: cn("rsp-root", className),
2725
2934
  "data-rsp-scheme": colorScheme,
@@ -2823,28 +3032,38 @@ var Spreadsheet = import_react4.forwardRef(({
2823
3032
  zIndex: 40
2824
3033
  }
2825
3034
  }),
2826
- /* @__PURE__ */ jsx_runtime3.jsx("div", {
3035
+ /* @__PURE__ */ jsx_runtime3.jsxs("div", {
2827
3036
  className: "rsp-cells",
2828
3037
  "data-testid": "spreadsheet-cells",
2829
3038
  style: {
2830
3039
  transform: `translate(${-viewport.scrollX}px, ${-viewport.scrollY}px) scale(${viewport.zoom})`,
2831
3040
  transformOrigin: "0 0"
2832
3041
  },
2833
- children: visibleCells.map((cell) => /* @__PURE__ */ jsx_runtime3.jsx(CellComponent, {
2834
- value: cellData.get(`${cell.col}${cell.row}`) ?? "",
2835
- row: cell.row,
2836
- col: cell.col,
2837
- selectionManager,
2838
- cellToPixelBase,
2839
- getColumnWidth,
2840
- getRowHeight,
2841
- customCellStyle,
2842
- customCellRenderer,
2843
- inputValue: cellData.get(`${cell.col}${cell.row}`) ?? "",
2844
- editInputVersion: retryingEdit?.rowIndex === cell.row - 1 && retryingEdit?.colIndex === columnToIndex(cell.col) ? retryingEdit.version : 0,
2845
- width,
2846
- height
2847
- }, `${cell.col}${cell.row}`))
3042
+ children: [
3043
+ visibleCells.map((cell) => /* @__PURE__ */ jsx_runtime3.jsx(CellComponent, {
3044
+ value: cellData.get(`${cell.col}${cell.row}`) ?? "",
3045
+ row: cell.row,
3046
+ col: cell.col,
3047
+ selectionManager,
3048
+ cellToPixelBase,
3049
+ getColumnWidth,
3050
+ getRowHeight,
3051
+ customCellStyle,
3052
+ customCellRenderer,
3053
+ inputValue: cellData.get(`${cell.col}${cell.row}`) ?? "",
3054
+ editInputVersion: retryingEdit?.rowIndex === cell.row - 1 && retryingEdit?.colIndex === columnToIndex(cell.col) ? retryingEdit.version : 0,
3055
+ width,
3056
+ height
3057
+ }, `${cell.col}${cell.row}`)),
3058
+ referenceSelectionRect && referenceSelection.type !== "none" && /* @__PURE__ */ jsx_runtime3.jsx("div", {
3059
+ "aria-hidden": "true",
3060
+ className: cn("rsp-reference-selection", `rsp-reference-selection-${referenceSelection.type}`),
3061
+ "data-testid": "spreadsheet-reference-selection",
3062
+ "data-reference-id": referenceSelection.id,
3063
+ "data-reference-phase": referenceSelection.type,
3064
+ style: referenceSelectionRect
3065
+ })
3066
+ ]
2848
3067
  }),
2849
3068
  components && overlayChildren && overlayChildren.length > 0 && /* @__PURE__ */ jsx_runtime3.jsxs("div", {
2850
3069
  ref: overlayContainerRef,
@@ -3450,6 +3669,42 @@ function FormulaSheet({
3450
3669
  const clipboardManager = import_react6.default.useMemo(() => controlledClipboardManager ?? new WorkbookClipboardManager(engine), [controlledClipboardManager, engine]);
3451
3670
  const state = useEngine(engine);
3452
3671
  const sheet = state.workbooks.get(workbookName)?.sheets.get(sheetName);
3672
+ const getEngineTableAt = import_react6.useCallback((cell) => {
3673
+ const table = engine.isCellInTable({
3674
+ workbookName,
3675
+ sheetName,
3676
+ rowIndex: cell.row,
3677
+ colIndex: cell.col
3678
+ });
3679
+ if (!table)
3680
+ return;
3681
+ const endRow = table.endRow.type === "number" ? { type: "number", value: table.endRow.value } : { type: "infinity" };
3682
+ const endCol = {
3683
+ type: "number",
3684
+ value: table.start.colIndex + table.headers.size - 1
3685
+ };
3686
+ const hasDataRows = endRow.type === "infinity" || endRow.value > table.start.rowIndex;
3687
+ return {
3688
+ id: `${table.workbookName}/${table.name}`,
3689
+ bounds: {
3690
+ start: { row: table.start.rowIndex, col: table.start.colIndex },
3691
+ end: { row: endRow, col: endCol }
3692
+ },
3693
+ ...hasDataRows ? {
3694
+ dataBounds: {
3695
+ start: {
3696
+ row: table.start.rowIndex + 1,
3697
+ col: table.start.colIndex
3698
+ },
3699
+ end: { row: endRow, col: endCol }
3700
+ }
3701
+ } : {}
3702
+ };
3703
+ }, [engine, sheetName, workbookName]);
3704
+ const formulaNavigation = import_react6.useMemo(() => ({
3705
+ ...selection?.navigation,
3706
+ getTableAt: selection?.navigation?.getTableAt ?? getEngineTableAt
3707
+ }), [getEngineTableAt, selection?.navigation]);
3453
3708
  const onCellDataChange = import_react6.useCallback((updatedSpreadsheet) => {
3454
3709
  const data = new Map(updatedSpreadsheet);
3455
3710
  data.forEach((value, key) => {
@@ -3623,6 +3878,7 @@ function FormulaSheet({
3623
3878
  parentSelected: isSelected,
3624
3879
  selection: {
3625
3880
  ...selection,
3881
+ navigation: formulaNavigation,
3626
3882
  effects: selectionManagerEffects
3627
3883
  },
3628
3884
  containerProps: isSelected && selectedArea ? {
@@ -3642,31 +3898,29 @@ function FormulaSheet({
3642
3898
  workbookName
3643
3899
  });
3644
3900
  if (!tableInfo) {
3645
- if (conditionalStyle) {
3646
- return {
3647
- ...conditionalStyle.backgroundColor && {
3648
- backgroundColor: conditionalStyle.backgroundColor
3649
- },
3650
- ...conditionalStyle.color && {
3651
- color: conditionalStyle.color
3652
- },
3653
- ...conditionalStyle.fontSize && {
3654
- fontSize: conditionalStyle.fontSize
3655
- },
3656
- ...conditionalStyle.bold && {
3657
- fontWeight: "bold"
3658
- },
3659
- ...conditionalStyle.italic && {
3660
- fontStyle: "italic"
3661
- },
3662
- ...conditionalStyle.underline && {
3663
- textDecoration: "underline"
3664
- },
3665
- ...getBorderCellStyle(conditionalStyle),
3666
- ...getWrapCellStyle(conditionalStyle)
3667
- };
3668
- }
3669
- return {};
3901
+ const style2 = conditionalStyle ? {
3902
+ ...conditionalStyle.backgroundColor && {
3903
+ backgroundColor: conditionalStyle.backgroundColor
3904
+ },
3905
+ ...conditionalStyle.color && {
3906
+ color: conditionalStyle.color
3907
+ },
3908
+ ...conditionalStyle.fontSize && {
3909
+ fontSize: conditionalStyle.fontSize
3910
+ },
3911
+ ...conditionalStyle.bold && {
3912
+ fontWeight: "bold"
3913
+ },
3914
+ ...conditionalStyle.italic && {
3915
+ fontStyle: "italic"
3916
+ },
3917
+ ...conditionalStyle.underline && {
3918
+ textDecoration: "underline"
3919
+ },
3920
+ ...getBorderCellStyle(conditionalStyle),
3921
+ ...getWrapCellStyle(conditionalStyle)
3922
+ } : {};
3923
+ return customCellStyle ? customCellStyle(cell, style2) : style2;
3670
3924
  }
3671
3925
  const isHeaderRow = cell.rowIndex === tableInfo.start.rowIndex;
3672
3926
  const isFirstColumn = cell.colIndex === tableInfo.start.colIndex;
@@ -4163,4 +4417,4 @@ var useClickAway = (ref, callback) => {
4163
4417
  }, [ref, callback]);
4164
4418
  };
4165
4419
 
4166
- //# debugId=1230B1E8DDE11E4864756E2164756E21
4420
+ //# debugId=5EB66D4C826F4D2464756E2164756E21