@ricsam/react-spreadsheets 0.0.7 → 0.0.9
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/README.md +86 -4
- package/dist/cjs/lib.cjs +411 -62
- package/dist/cjs/lib.cjs.map +5 -5
- package/dist/cjs/package.json +1 -1
- package/dist/mjs/lib.mjs +412 -63
- package/dist/mjs/lib.mjs.map +5 -5
- package/dist/mjs/package.json +1 -1
- package/dist/styles.css +36 -0
- package/dist/types/lib.d.ts +3 -1
- package/dist/types/spreadsheet/spreadsheet.d.ts +18 -1
- package/dist/types/workbook/workbook-selection-manager.d.ts +23 -3
- package/package.json +3 -3
package/dist/cjs/lib.cjs
CHANGED
|
@@ -1457,6 +1457,124 @@ 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 (itemEnd - itemStart > viewportSize) {
|
|
1476
|
+
if (itemEnd <= current)
|
|
1477
|
+
return itemEnd - viewportSize;
|
|
1478
|
+
if (itemStart >= current + viewportSize)
|
|
1479
|
+
return itemStart;
|
|
1480
|
+
return current;
|
|
1481
|
+
}
|
|
1482
|
+
if (itemStart < current)
|
|
1483
|
+
return itemStart;
|
|
1484
|
+
if (itemEnd > current + viewportSize)
|
|
1485
|
+
return itemEnd - viewportSize;
|
|
1486
|
+
return current;
|
|
1487
|
+
};
|
|
1488
|
+
var normalizeScrollRangeAxis = (start, end, finiteCount) => {
|
|
1489
|
+
if (!Number.isFinite(start) || end.type === "number" && !Number.isFinite(end.value)) {
|
|
1490
|
+
return;
|
|
1491
|
+
}
|
|
1492
|
+
const normalizedStart = Math.max(0, Math.floor(start));
|
|
1493
|
+
const normalizedEnd = end.type === "infinity" ? finiteCount === undefined ? normalizedStart : Math.max(0, finiteCount - 1) : Math.max(0, Math.floor(end.value));
|
|
1494
|
+
const lower = Math.min(normalizedStart, normalizedEnd);
|
|
1495
|
+
const upper = Math.max(normalizedStart, normalizedEnd);
|
|
1496
|
+
if (finiteCount === undefined)
|
|
1497
|
+
return { start: lower, end: upper };
|
|
1498
|
+
if (finiteCount === 0)
|
|
1499
|
+
return;
|
|
1500
|
+
const lastIndex = finiteCount - 1;
|
|
1501
|
+
return {
|
|
1502
|
+
start: Math.min(lower, lastIndex),
|
|
1503
|
+
end: Math.min(upper, lastIndex)
|
|
1504
|
+
};
|
|
1505
|
+
};
|
|
1506
|
+
var hasCellData = (value) => value !== undefined && value !== "";
|
|
1507
|
+
var getSparseUsedRange = (cellData, rowCount, columnCount) => {
|
|
1508
|
+
let minRow = Infinity;
|
|
1509
|
+
let maxRow = -1;
|
|
1510
|
+
let minCol = Infinity;
|
|
1511
|
+
let maxCol = -1;
|
|
1512
|
+
for (const [reference, value] of cellData) {
|
|
1513
|
+
if (!hasCellData(value))
|
|
1514
|
+
continue;
|
|
1515
|
+
let rowIndex;
|
|
1516
|
+
let columnIndex;
|
|
1517
|
+
try {
|
|
1518
|
+
({ rowIndex, columnIndex } = parseCellReference(reference));
|
|
1519
|
+
} catch {
|
|
1520
|
+
continue;
|
|
1521
|
+
}
|
|
1522
|
+
if (rowIndex < 0 || columnIndex < 0 || rowCount !== undefined && rowIndex >= rowCount || columnCount !== undefined && columnIndex >= columnCount) {
|
|
1523
|
+
continue;
|
|
1524
|
+
}
|
|
1525
|
+
minRow = Math.min(minRow, rowIndex);
|
|
1526
|
+
maxRow = Math.max(maxRow, rowIndex);
|
|
1527
|
+
minCol = Math.min(minCol, columnIndex);
|
|
1528
|
+
maxCol = Math.max(maxCol, columnIndex);
|
|
1529
|
+
}
|
|
1530
|
+
if (maxRow < 0 || maxCol < 0)
|
|
1531
|
+
return;
|
|
1532
|
+
return {
|
|
1533
|
+
start: { row: minRow, col: minCol },
|
|
1534
|
+
end: {
|
|
1535
|
+
row: { type: "number", value: maxRow },
|
|
1536
|
+
col: { type: "number", value: maxCol }
|
|
1537
|
+
}
|
|
1538
|
+
};
|
|
1539
|
+
};
|
|
1540
|
+
var resolveSparseNavigationTarget = (request, cellData) => {
|
|
1541
|
+
if (request.kind !== "jump" || request.table)
|
|
1542
|
+
return;
|
|
1543
|
+
const isVertical = request.direction === "up" || request.direction === "down";
|
|
1544
|
+
const movingForward = request.direction === "down" || request.direction === "right";
|
|
1545
|
+
const originAxis = isVertical ? request.origin.row : request.origin.col;
|
|
1546
|
+
const fixedAxis = isVertical ? request.origin.col : request.origin.row;
|
|
1547
|
+
const occupied = new Set;
|
|
1548
|
+
for (const [reference, value] of cellData) {
|
|
1549
|
+
if (!hasCellData(value))
|
|
1550
|
+
continue;
|
|
1551
|
+
let rowIndex;
|
|
1552
|
+
let columnIndex;
|
|
1553
|
+
try {
|
|
1554
|
+
({ rowIndex, columnIndex } = parseCellReference(reference));
|
|
1555
|
+
} catch {
|
|
1556
|
+
continue;
|
|
1557
|
+
}
|
|
1558
|
+
if ((isVertical ? columnIndex : rowIndex) === fixedAxis) {
|
|
1559
|
+
occupied.add(isVertical ? rowIndex : columnIndex);
|
|
1560
|
+
}
|
|
1561
|
+
}
|
|
1562
|
+
const step = movingForward ? 1 : -1;
|
|
1563
|
+
let targetAxis;
|
|
1564
|
+
if (occupied.has(originAxis + step)) {
|
|
1565
|
+
targetAxis = originAxis + step;
|
|
1566
|
+
while (occupied.has(targetAxis + step))
|
|
1567
|
+
targetAxis += step;
|
|
1568
|
+
} else {
|
|
1569
|
+
const candidates = [...occupied].filter((index) => movingForward ? index > originAxis : index < originAxis);
|
|
1570
|
+
if (candidates.length > 0) {
|
|
1571
|
+
targetAxis = movingForward ? Math.min(...candidates) : Math.max(...candidates);
|
|
1572
|
+
}
|
|
1573
|
+
}
|
|
1574
|
+
if (targetAxis === undefined)
|
|
1575
|
+
return;
|
|
1576
|
+
return isVertical ? { row: targetAxis, col: request.origin.col } : { row: request.origin.row, col: targetAxis };
|
|
1577
|
+
};
|
|
1460
1578
|
var CellComponent = import_react4.default.memo(({
|
|
1461
1579
|
value,
|
|
1462
1580
|
row,
|
|
@@ -1760,6 +1878,8 @@ var Spreadsheet = import_react4.forwardRef(({
|
|
|
1760
1878
|
cellData: controlledCellData,
|
|
1761
1879
|
onCellDataChange,
|
|
1762
1880
|
onCellDataChangeError,
|
|
1881
|
+
rowCount,
|
|
1882
|
+
columnCount,
|
|
1763
1883
|
columnWidths: controlledColumnWidths,
|
|
1764
1884
|
onColumnWidthsChange,
|
|
1765
1885
|
rowHeights: controlledRowHeights,
|
|
@@ -1781,14 +1901,35 @@ var Spreadsheet = import_react4.forwardRef(({
|
|
|
1781
1901
|
const [containerDivRef, setContainerDivRef] = import_react4.useState(null);
|
|
1782
1902
|
const colorScheme = useColorScheme(containerDivRef);
|
|
1783
1903
|
const gridLineProbeRef = import_react4.useRef(null);
|
|
1904
|
+
const [internalCellData, setInternalCellData] = import_react4.useState(new Map);
|
|
1905
|
+
const [retryingEdit, setRetryingEdit] = import_react4.useState(null);
|
|
1906
|
+
const retryingEditVersionRef = import_react4.useRef(0);
|
|
1907
|
+
const cellData = controlledCellData ?? internalCellData;
|
|
1908
|
+
const cellDataRef = import_react4.useRef(cellData);
|
|
1909
|
+
cellDataRef.current = cellData;
|
|
1910
|
+
const finiteRowCount = normalizeFiniteCount(rowCount);
|
|
1911
|
+
const finiteColumnCount = normalizeFiniteCount(columnCount);
|
|
1912
|
+
const gridCountsRef = import_react4.useRef({ rows: finiteRowCount, columns: finiteColumnCount });
|
|
1913
|
+
gridCountsRef.current = { rows: finiteRowCount, columns: finiteColumnCount };
|
|
1914
|
+
const getNumRows = import_react4.useCallback(() => countToSelectionBound(gridCountsRef.current.rows), []);
|
|
1915
|
+
const getNumCols = import_react4.useCallback(() => countToSelectionBound(gridCountsRef.current.columns), []);
|
|
1916
|
+
const getDefaultUsedRange = import_react4.useCallback(() => getSparseUsedRange(cellDataRef.current, gridCountsRef.current.rows, gridCountsRef.current.columns), []);
|
|
1917
|
+
const defaultResolveTarget = import_react4.useCallback((request) => resolveSparseNavigationTarget(request, cellDataRef.current), []);
|
|
1918
|
+
const consumerNavigation = selection?.navigation;
|
|
1919
|
+
const navigation = import_react4.useMemo(() => ({
|
|
1920
|
+
getUsedRange: consumerNavigation?.getUsedRange ?? getDefaultUsedRange,
|
|
1921
|
+
...consumerNavigation?.getTableAt ? { getTableAt: consumerNavigation.getTableAt } : {},
|
|
1922
|
+
resolveTarget: consumerNavigation?.resolveTarget ?? defaultResolveTarget
|
|
1923
|
+
}), [consumerNavigation, defaultResolveTarget, getDefaultUsedRange]);
|
|
1784
1924
|
const selectionManager = import_selection_manager.useInitializeSelectionManager({
|
|
1785
|
-
getNumCols
|
|
1786
|
-
getNumRows
|
|
1925
|
+
getNumCols,
|
|
1926
|
+
getNumRows,
|
|
1787
1927
|
initialState: selection?.initialState,
|
|
1788
1928
|
state: selection?.state,
|
|
1789
1929
|
onStateChange: selection?.onStateChange,
|
|
1790
1930
|
containerElement: containerDivRef,
|
|
1791
1931
|
formats: selection?.formats,
|
|
1932
|
+
navigation,
|
|
1792
1933
|
disableAutoClipboard: true
|
|
1793
1934
|
});
|
|
1794
1935
|
const effects = selection?.effects;
|
|
@@ -1797,12 +1938,6 @@ var Spreadsheet = import_react4.forwardRef(({
|
|
|
1797
1938
|
return effects(selectionManager);
|
|
1798
1939
|
}
|
|
1799
1940
|
}, [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
1941
|
const isControlled = controlledCellData !== undefined;
|
|
1807
1942
|
const prevIsControlledRef = import_react4.useRef(isControlled);
|
|
1808
1943
|
selectionManager.getCellsWithData = (area) => {
|
|
@@ -1978,7 +2113,7 @@ var Spreadsheet = import_react4.forwardRef(({
|
|
|
1978
2113
|
ctx.lineWidth = 1;
|
|
1979
2114
|
let x = gridDims.headerWidth;
|
|
1980
2115
|
let colIndex = 0;
|
|
1981
|
-
while (x < viewport.scrollX + gridDims.headerWidth) {
|
|
2116
|
+
while (x < viewport.scrollX + gridDims.headerWidth && (finiteColumnCount === undefined || colIndex < finiteColumnCount)) {
|
|
1982
2117
|
const colWidth = (columnWidths.get(indexToColumn(colIndex)) || DEFAULT_CELL_WIDTH) * viewport.zoom;
|
|
1983
2118
|
if (x + colWidth > viewport.scrollX + gridDims.headerWidth) {
|
|
1984
2119
|
break;
|
|
@@ -1986,7 +2121,7 @@ var Spreadsheet = import_react4.forwardRef(({
|
|
|
1986
2121
|
x += colWidth;
|
|
1987
2122
|
colIndex++;
|
|
1988
2123
|
}
|
|
1989
|
-
while (x - viewport.scrollX < width) {
|
|
2124
|
+
while (x - viewport.scrollX < width && (finiteColumnCount === undefined || colIndex < finiteColumnCount)) {
|
|
1990
2125
|
const drawX = x - viewport.scrollX;
|
|
1991
2126
|
if (drawX >= gridDims.headerWidth && drawX <= width) {
|
|
1992
2127
|
ctx.beginPath();
|
|
@@ -2000,7 +2135,7 @@ var Spreadsheet = import_react4.forwardRef(({
|
|
|
2000
2135
|
}
|
|
2001
2136
|
let y = gridDims.headerHeight;
|
|
2002
2137
|
let rowNum = 1;
|
|
2003
|
-
while (y < viewport.scrollY + gridDims.headerHeight) {
|
|
2138
|
+
while (y < viewport.scrollY + gridDims.headerHeight && (finiteRowCount === undefined || rowNum <= finiteRowCount)) {
|
|
2004
2139
|
const rowHeight = (rowHeights.get(rowNum) || DEFAULT_CELL_HEIGHT) * viewport.zoom;
|
|
2005
2140
|
if (y + rowHeight > viewport.scrollY + gridDims.headerHeight) {
|
|
2006
2141
|
break;
|
|
@@ -2008,7 +2143,7 @@ var Spreadsheet = import_react4.forwardRef(({
|
|
|
2008
2143
|
y += rowHeight;
|
|
2009
2144
|
rowNum++;
|
|
2010
2145
|
}
|
|
2011
|
-
while (y - viewport.scrollY < height) {
|
|
2146
|
+
while (y - viewport.scrollY < height && (finiteRowCount === undefined || rowNum <= finiteRowCount)) {
|
|
2012
2147
|
const drawY = y - viewport.scrollY;
|
|
2013
2148
|
if (drawY >= gridDims.headerHeight && drawY <= height) {
|
|
2014
2149
|
ctx.beginPath();
|
|
@@ -2022,6 +2157,8 @@ var Spreadsheet = import_react4.forwardRef(({
|
|
|
2022
2157
|
}
|
|
2023
2158
|
}, [
|
|
2024
2159
|
columnWidths,
|
|
2160
|
+
finiteColumnCount,
|
|
2161
|
+
finiteRowCount,
|
|
2025
2162
|
gridDims.headerHeight,
|
|
2026
2163
|
gridDims.headerWidth,
|
|
2027
2164
|
height,
|
|
@@ -2039,7 +2176,7 @@ var Spreadsheet = import_react4.forwardRef(({
|
|
|
2039
2176
|
const cells = [];
|
|
2040
2177
|
let x = 0;
|
|
2041
2178
|
let startCol = 0;
|
|
2042
|
-
while (x < viewport.scrollX) {
|
|
2179
|
+
while (x < viewport.scrollX && (finiteColumnCount === undefined || startCol < finiteColumnCount)) {
|
|
2043
2180
|
const colWidth = (columnWidths.get(indexToColumn(startCol)) || DEFAULT_CELL_WIDTH) * viewport.zoom;
|
|
2044
2181
|
if (x + colWidth > viewport.scrollX) {
|
|
2045
2182
|
break;
|
|
@@ -2049,7 +2186,7 @@ var Spreadsheet = import_react4.forwardRef(({
|
|
|
2049
2186
|
}
|
|
2050
2187
|
let y = 0;
|
|
2051
2188
|
let startRow = 0;
|
|
2052
|
-
while (y < viewport.scrollY) {
|
|
2189
|
+
while (y < viewport.scrollY && (finiteRowCount === undefined || startRow < finiteRowCount)) {
|
|
2053
2190
|
const rowHeight = (rowHeights.get(startRow + 1) || DEFAULT_CELL_HEIGHT) * viewport.zoom;
|
|
2054
2191
|
if (y + rowHeight > viewport.scrollY) {
|
|
2055
2192
|
break;
|
|
@@ -2059,10 +2196,10 @@ var Spreadsheet = import_react4.forwardRef(({
|
|
|
2059
2196
|
}
|
|
2060
2197
|
let rowY = y;
|
|
2061
2198
|
let row = startRow;
|
|
2062
|
-
while (rowY < viewport.scrollY + height) {
|
|
2199
|
+
while (rowY < viewport.scrollY + height && (finiteRowCount === undefined || row < finiteRowCount)) {
|
|
2063
2200
|
let colX = x;
|
|
2064
2201
|
let col = startCol;
|
|
2065
|
-
while (colX < viewport.scrollX + width) {
|
|
2202
|
+
while (colX < viewport.scrollX + width && (finiteColumnCount === undefined || col < finiteColumnCount)) {
|
|
2066
2203
|
const colKey = indexToColumn(col);
|
|
2067
2204
|
const rowNum = getRowNumber(row);
|
|
2068
2205
|
const cellKey = `${colKey}${rowNum}`;
|
|
@@ -2083,6 +2220,8 @@ var Spreadsheet = import_react4.forwardRef(({
|
|
|
2083
2220
|
}, [
|
|
2084
2221
|
cellData,
|
|
2085
2222
|
columnWidths,
|
|
2223
|
+
finiteColumnCount,
|
|
2224
|
+
finiteRowCount,
|
|
2086
2225
|
height,
|
|
2087
2226
|
rowHeights,
|
|
2088
2227
|
viewport.scrollX,
|
|
@@ -2110,6 +2249,79 @@ var Spreadsheet = import_react4.forwardRef(({
|
|
|
2110
2249
|
}
|
|
2111
2250
|
return { x, y };
|
|
2112
2251
|
}, [columnWidths, rowHeights]);
|
|
2252
|
+
const clampViewportOffsets = import_react4.useCallback((scrollX, scrollY, zoom) => {
|
|
2253
|
+
const bodyWidth = Math.max(0, width - HEADER_WIDTH * zoom);
|
|
2254
|
+
const bodyHeight = Math.max(0, height - HEADER_HEIGHT * zoom);
|
|
2255
|
+
const maxScrollX = finiteColumnCount === undefined ? Infinity : Math.max(0, getColumnEdgePosition(finiteColumnCount, columnWidths) * zoom - bodyWidth);
|
|
2256
|
+
const maxScrollY = finiteRowCount === undefined ? Infinity : Math.max(0, getRowEdgePosition(finiteRowCount, rowHeights) * zoom - bodyHeight);
|
|
2257
|
+
return {
|
|
2258
|
+
scrollX: Math.min(Math.max(0, scrollX), maxScrollX),
|
|
2259
|
+
scrollY: Math.min(Math.max(0, scrollY), maxScrollY)
|
|
2260
|
+
};
|
|
2261
|
+
}, [columnWidths, finiteColumnCount, finiteRowCount, height, rowHeights, width]);
|
|
2262
|
+
const revealRange = import_react4.useCallback((range, options = {}) => {
|
|
2263
|
+
if (finiteRowCount === 0 || finiteColumnCount === 0)
|
|
2264
|
+
return;
|
|
2265
|
+
const rows = normalizeScrollRangeAxis(range.start.row, range.end.row, finiteRowCount);
|
|
2266
|
+
const columns = normalizeScrollRangeAxis(range.start.col, range.end.col, finiteColumnCount);
|
|
2267
|
+
if (!rows || !columns)
|
|
2268
|
+
return;
|
|
2269
|
+
setViewport((previous) => {
|
|
2270
|
+
const bodyWidth = Math.max(0, width - HEADER_WIDTH * previous.zoom);
|
|
2271
|
+
const bodyHeight = Math.max(0, height - HEADER_HEIGHT * previous.zoom);
|
|
2272
|
+
const left = getColumnEdgePosition(columns.start, columnWidths) * previous.zoom;
|
|
2273
|
+
const right = getColumnEdgePosition(columns.end + 1, columnWidths) * previous.zoom;
|
|
2274
|
+
const top = getRowEdgePosition(rows.start, rowHeights) * previous.zoom;
|
|
2275
|
+
const bottom = getRowEdgePosition(rows.end + 1, rowHeights) * previous.zoom;
|
|
2276
|
+
const desired = clampViewportOffsets(alignScrollOffset(previous.scrollX, left, right, bodyWidth, options.columnAlign ?? "nearest"), alignScrollOffset(previous.scrollY, top, bottom, bodyHeight, options.rowAlign ?? "nearest"), previous.zoom);
|
|
2277
|
+
if (desired.scrollX === previous.scrollX && desired.scrollY === previous.scrollY) {
|
|
2278
|
+
return previous;
|
|
2279
|
+
}
|
|
2280
|
+
return { ...previous, ...desired };
|
|
2281
|
+
});
|
|
2282
|
+
}, [
|
|
2283
|
+
clampViewportOffsets,
|
|
2284
|
+
columnWidths,
|
|
2285
|
+
finiteColumnCount,
|
|
2286
|
+
finiteRowCount,
|
|
2287
|
+
height,
|
|
2288
|
+
rowHeights,
|
|
2289
|
+
width
|
|
2290
|
+
]);
|
|
2291
|
+
const revealCell = import_react4.useCallback((cell, options = {}) => {
|
|
2292
|
+
revealRange({
|
|
2293
|
+
start: { row: cell.row, col: cell.col },
|
|
2294
|
+
end: {
|
|
2295
|
+
row: { type: "number", value: cell.row },
|
|
2296
|
+
col: { type: "number", value: cell.col }
|
|
2297
|
+
}
|
|
2298
|
+
}, options);
|
|
2299
|
+
}, [revealRange]);
|
|
2300
|
+
const scrollToCell = import_react4.useCallback((cell, options = {}) => {
|
|
2301
|
+
const align = options.align ?? "nearest";
|
|
2302
|
+
revealCell(cell, { rowAlign: align, columnAlign: align });
|
|
2303
|
+
}, [revealCell]);
|
|
2304
|
+
const scrollToRange = import_react4.useCallback((range, options = {}) => {
|
|
2305
|
+
const align = options.align ?? "nearest";
|
|
2306
|
+
revealRange(range, { rowAlign: align, columnAlign: align });
|
|
2307
|
+
}, [revealRange]);
|
|
2308
|
+
import_react4.useEffect(() => selectionManager.listenToViewportRequest((request) => {
|
|
2309
|
+
if (request.type === "reveal-range") {
|
|
2310
|
+
scrollToRange(request.range, { align: request.align });
|
|
2311
|
+
return;
|
|
2312
|
+
}
|
|
2313
|
+
const isVertical = request.direction === "up" || request.direction === "down";
|
|
2314
|
+
revealCell(request.cell, {
|
|
2315
|
+
rowAlign: isVertical ? request.align : "nearest",
|
|
2316
|
+
columnAlign: isVertical ? "nearest" : request.align
|
|
2317
|
+
});
|
|
2318
|
+
}), [revealCell, scrollToRange, selectionManager]);
|
|
2319
|
+
import_react4.useEffect(() => {
|
|
2320
|
+
setViewport((previous) => {
|
|
2321
|
+
const next = clampViewportOffsets(previous.scrollX, previous.scrollY, previous.zoom);
|
|
2322
|
+
return next.scrollX === previous.scrollX && next.scrollY === previous.scrollY ? previous : { ...previous, ...next };
|
|
2323
|
+
});
|
|
2324
|
+
}, [clampViewportOffsets]);
|
|
2113
2325
|
import_react4.default.useEffect(() => {
|
|
2114
2326
|
return selectionManager.listenToUpdateData((updates) => {
|
|
2115
2327
|
const editingState = selectionManager.isEditing;
|
|
@@ -2184,12 +2396,11 @@ var Spreadsheet = import_react4.forwardRef(({
|
|
|
2184
2396
|
const handleWheel = import_react4.useCallback((e) => {
|
|
2185
2397
|
e.preventDefault();
|
|
2186
2398
|
e.stopPropagation();
|
|
2187
|
-
setViewport((
|
|
2188
|
-
...
|
|
2189
|
-
scrollX
|
|
2190
|
-
scrollY: Math.max(0, prev.scrollY + e.deltaY)
|
|
2399
|
+
setViewport((previous) => ({
|
|
2400
|
+
...previous,
|
|
2401
|
+
...clampViewportOffsets(previous.scrollX + e.deltaX, previous.scrollY + e.deltaY, previous.zoom)
|
|
2191
2402
|
}));
|
|
2192
|
-
}, []);
|
|
2403
|
+
}, [clampViewportOffsets]);
|
|
2193
2404
|
const commitOverlayChildren = import_react4.useCallback((children) => {
|
|
2194
2405
|
overlayChildrenRef.current = children;
|
|
2195
2406
|
if (onOverlayChildrenChange) {
|
|
@@ -2608,7 +2819,7 @@ var Spreadsheet = import_react4.forwardRef(({
|
|
|
2608
2819
|
const headers = [];
|
|
2609
2820
|
let x = 0;
|
|
2610
2821
|
let startCol = 0;
|
|
2611
|
-
while (x < viewport.scrollX) {
|
|
2822
|
+
while (x < viewport.scrollX && (finiteColumnCount === undefined || startCol < finiteColumnCount)) {
|
|
2612
2823
|
const col = indexToColumn(startCol);
|
|
2613
2824
|
const colWidth = getColumnWidth(col) * viewport.zoom;
|
|
2614
2825
|
if (x + colWidth > viewport.scrollX) {
|
|
@@ -2617,7 +2828,7 @@ var Spreadsheet = import_react4.forwardRef(({
|
|
|
2617
2828
|
x += colWidth;
|
|
2618
2829
|
startCol++;
|
|
2619
2830
|
}
|
|
2620
|
-
while (x < viewport.scrollX + width) {
|
|
2831
|
+
while (x < viewport.scrollX + width && (finiteColumnCount === undefined || startCol < finiteColumnCount)) {
|
|
2621
2832
|
const col = indexToColumn(startCol);
|
|
2622
2833
|
const colWidth = getColumnWidth(col) * viewport.zoom;
|
|
2623
2834
|
headers.push({
|
|
@@ -2628,14 +2839,14 @@ var Spreadsheet = import_react4.forwardRef(({
|
|
|
2628
2839
|
startCol++;
|
|
2629
2840
|
}
|
|
2630
2841
|
return headers;
|
|
2631
|
-
}, [width, viewport, getColumnWidth]);
|
|
2842
|
+
}, [finiteColumnCount, width, viewport, getColumnWidth]);
|
|
2632
2843
|
const getVisibleRowHeaders = import_react4.useCallback(() => {
|
|
2633
2844
|
if (!height)
|
|
2634
2845
|
return [];
|
|
2635
2846
|
const headers = [];
|
|
2636
2847
|
let y = 0;
|
|
2637
2848
|
let rowNum = 1;
|
|
2638
|
-
while (y < viewport.scrollY) {
|
|
2849
|
+
while (y < viewport.scrollY && (finiteRowCount === undefined || rowNum <= finiteRowCount)) {
|
|
2639
2850
|
const rowHeight = getRowHeight(rowNum) * viewport.zoom;
|
|
2640
2851
|
if (y + rowHeight > viewport.scrollY) {
|
|
2641
2852
|
break;
|
|
@@ -2643,7 +2854,7 @@ var Spreadsheet = import_react4.forwardRef(({
|
|
|
2643
2854
|
y += rowHeight;
|
|
2644
2855
|
rowNum++;
|
|
2645
2856
|
}
|
|
2646
|
-
while (y < viewport.scrollY + height) {
|
|
2857
|
+
while (y < viewport.scrollY + height && (finiteRowCount === undefined || rowNum <= finiteRowCount)) {
|
|
2647
2858
|
const rowHeight = getRowHeight(rowNum) * viewport.zoom;
|
|
2648
2859
|
headers.push({
|
|
2649
2860
|
row: rowNum,
|
|
@@ -2653,7 +2864,7 @@ var Spreadsheet = import_react4.forwardRef(({
|
|
|
2653
2864
|
rowNum++;
|
|
2654
2865
|
}
|
|
2655
2866
|
return headers;
|
|
2656
|
-
}, [height, viewport, getRowHeight]);
|
|
2867
|
+
}, [finiteRowCount, height, viewport, getRowHeight]);
|
|
2657
2868
|
const { visibleOverlays, overlaysToRender } = import_react4.useMemo(() => {
|
|
2658
2869
|
if (!width || !height || !overlayChildren) {
|
|
2659
2870
|
return { visibleOverlays: [], overlaysToRender: [] };
|
|
@@ -2701,8 +2912,45 @@ var Spreadsheet = import_react4.forwardRef(({
|
|
|
2701
2912
|
const visibleColumnHeaders = import_react4.default.useMemo(() => getVisibleColumnHeaders(), [getVisibleColumnHeaders]);
|
|
2702
2913
|
const visibleRowHeaders = import_react4.default.useMemo(() => getVisibleRowHeaders(), [getVisibleRowHeaders]);
|
|
2703
2914
|
const hasFocus = import_selection_manager.useSelectionManager(selectionManager, () => selectionManager.hasFocus);
|
|
2915
|
+
const referenceSelection = import_selection_manager.useSelectionManager(selectionManager, () => selectionManager.referenceSelection);
|
|
2916
|
+
const referenceSelectionRect = import_react4.useMemo(() => {
|
|
2917
|
+
if (referenceSelection.type === "none")
|
|
2918
|
+
return;
|
|
2919
|
+
if (finiteRowCount === 0 || finiteColumnCount === 0)
|
|
2920
|
+
return;
|
|
2921
|
+
const range = referenceSelection.range;
|
|
2922
|
+
const lastVisibleRow = visibleCells.reduce((maximum, cell) => Math.max(maximum, cell.row - 1), range.start.row);
|
|
2923
|
+
const lastVisibleCol = visibleCells.reduce((maximum, cell) => Math.max(maximum, columnToIndex(cell.col)), range.start.col);
|
|
2924
|
+
const rawEndRow = range.end.row.type === "number" ? range.end.row.value : finiteRowCount === undefined ? lastVisibleRow : finiteRowCount - 1;
|
|
2925
|
+
const rawEndCol = range.end.col.type === "number" ? range.end.col.value : finiteColumnCount === undefined ? lastVisibleCol : finiteColumnCount - 1;
|
|
2926
|
+
const maxRow = finiteRowCount === undefined ? Infinity : finiteRowCount - 1;
|
|
2927
|
+
const maxCol = finiteColumnCount === undefined ? Infinity : finiteColumnCount - 1;
|
|
2928
|
+
const startRow = Math.min(Math.max(0, Math.min(range.start.row, rawEndRow)), maxRow);
|
|
2929
|
+
const endRow = Math.min(Math.max(0, Math.max(range.start.row, rawEndRow)), maxRow);
|
|
2930
|
+
const startCol = Math.min(Math.max(0, Math.min(range.start.col, rawEndCol)), maxCol);
|
|
2931
|
+
const endCol = Math.min(Math.max(0, Math.max(range.start.col, rawEndCol)), maxCol);
|
|
2932
|
+
const rect = getRectFromCellSnapAnchor({
|
|
2933
|
+
startCol,
|
|
2934
|
+
startRow,
|
|
2935
|
+
endCol: endCol + 1,
|
|
2936
|
+
endRow: endRow + 1
|
|
2937
|
+
}, columnWidths, rowHeights);
|
|
2938
|
+
return {
|
|
2939
|
+
left: HEADER_WIDTH + rect.x,
|
|
2940
|
+
top: HEADER_HEIGHT + rect.y,
|
|
2941
|
+
width: rect.width,
|
|
2942
|
+
height: rect.height
|
|
2943
|
+
};
|
|
2944
|
+
}, [
|
|
2945
|
+
columnWidths,
|
|
2946
|
+
finiteColumnCount,
|
|
2947
|
+
finiteRowCount,
|
|
2948
|
+
referenceSelection,
|
|
2949
|
+
rowHeights,
|
|
2950
|
+
visibleCells
|
|
2951
|
+
]);
|
|
2704
2952
|
import_react4.default.useEffect(() => {
|
|
2705
|
-
if (!containerDivRef || !
|
|
2953
|
+
if (!containerDivRef || !parentSelected) {
|
|
2706
2954
|
return;
|
|
2707
2955
|
}
|
|
2708
2956
|
containerDivRef.addEventListener("wheel", handleWheel, {
|
|
@@ -2711,15 +2959,17 @@ var Spreadsheet = import_react4.forwardRef(({
|
|
|
2711
2959
|
return () => {
|
|
2712
2960
|
containerDivRef.removeEventListener("wheel", handleWheel);
|
|
2713
2961
|
};
|
|
2714
|
-
}, [containerDivRef, handleWheel,
|
|
2962
|
+
}, [containerDivRef, handleWheel, parentSelected]);
|
|
2715
2963
|
import_react4.useImperativeHandle(ref, () => ({
|
|
2716
2964
|
focus: () => {
|
|
2717
2965
|
selectionManager.focus();
|
|
2718
2966
|
},
|
|
2719
2967
|
blur: () => {
|
|
2720
2968
|
selectionManager.blur();
|
|
2721
|
-
}
|
|
2722
|
-
|
|
2969
|
+
},
|
|
2970
|
+
scrollToCell,
|
|
2971
|
+
scrollToRange
|
|
2972
|
+
}), [scrollToCell, scrollToRange, selectionManager]);
|
|
2723
2973
|
return /* @__PURE__ */ jsx_runtime3.jsx("div", {
|
|
2724
2974
|
className: cn("rsp-root", className),
|
|
2725
2975
|
"data-rsp-scheme": colorScheme,
|
|
@@ -2823,28 +3073,38 @@ var Spreadsheet = import_react4.forwardRef(({
|
|
|
2823
3073
|
zIndex: 40
|
|
2824
3074
|
}
|
|
2825
3075
|
}),
|
|
2826
|
-
/* @__PURE__ */ jsx_runtime3.
|
|
3076
|
+
/* @__PURE__ */ jsx_runtime3.jsxs("div", {
|
|
2827
3077
|
className: "rsp-cells",
|
|
2828
3078
|
"data-testid": "spreadsheet-cells",
|
|
2829
3079
|
style: {
|
|
2830
3080
|
transform: `translate(${-viewport.scrollX}px, ${-viewport.scrollY}px) scale(${viewport.zoom})`,
|
|
2831
3081
|
transformOrigin: "0 0"
|
|
2832
3082
|
},
|
|
2833
|
-
children:
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
3083
|
+
children: [
|
|
3084
|
+
visibleCells.map((cell) => /* @__PURE__ */ jsx_runtime3.jsx(CellComponent, {
|
|
3085
|
+
value: cellData.get(`${cell.col}${cell.row}`) ?? "",
|
|
3086
|
+
row: cell.row,
|
|
3087
|
+
col: cell.col,
|
|
3088
|
+
selectionManager,
|
|
3089
|
+
cellToPixelBase,
|
|
3090
|
+
getColumnWidth,
|
|
3091
|
+
getRowHeight,
|
|
3092
|
+
customCellStyle,
|
|
3093
|
+
customCellRenderer,
|
|
3094
|
+
inputValue: cellData.get(`${cell.col}${cell.row}`) ?? "",
|
|
3095
|
+
editInputVersion: retryingEdit?.rowIndex === cell.row - 1 && retryingEdit?.colIndex === columnToIndex(cell.col) ? retryingEdit.version : 0,
|
|
3096
|
+
width,
|
|
3097
|
+
height
|
|
3098
|
+
}, `${cell.col}${cell.row}`)),
|
|
3099
|
+
referenceSelectionRect && referenceSelection.type !== "none" && /* @__PURE__ */ jsx_runtime3.jsx("div", {
|
|
3100
|
+
"aria-hidden": "true",
|
|
3101
|
+
className: cn("rsp-reference-selection", `rsp-reference-selection-${referenceSelection.type}`),
|
|
3102
|
+
"data-testid": "spreadsheet-reference-selection",
|
|
3103
|
+
"data-reference-id": referenceSelection.id,
|
|
3104
|
+
"data-reference-phase": referenceSelection.type,
|
|
3105
|
+
style: referenceSelectionRect
|
|
3106
|
+
})
|
|
3107
|
+
]
|
|
2848
3108
|
}),
|
|
2849
3109
|
components && overlayChildren && overlayChildren.length > 0 && /* @__PURE__ */ jsx_runtime3.jsxs("div", {
|
|
2850
3110
|
ref: overlayContainerRef,
|
|
@@ -3054,6 +3314,7 @@ class WorkbookSelectionManager {
|
|
|
3054
3314
|
lastFocusedManager = null;
|
|
3055
3315
|
listeners = new Set;
|
|
3056
3316
|
cleanupFunctions = new Map;
|
|
3317
|
+
pendingRangeFocus = null;
|
|
3057
3318
|
smAreaToSpreadsheetRange(area) {
|
|
3058
3319
|
const rowEnd = area.end.row.type === "infinity" ? { type: "infinity", sign: "positive" } : { type: "number", value: area.end.row.value };
|
|
3059
3320
|
const colEnd = area.end.col.type === "infinity" ? { type: "infinity", sign: "positive" } : { type: "number", value: area.end.col.value };
|
|
@@ -3068,6 +3329,47 @@ class WorkbookSelectionManager {
|
|
|
3068
3329
|
}
|
|
3069
3330
|
};
|
|
3070
3331
|
}
|
|
3332
|
+
spreadsheetRangeToSmArea(range) {
|
|
3333
|
+
return {
|
|
3334
|
+
start: { row: range.start.row, col: range.start.col },
|
|
3335
|
+
end: {
|
|
3336
|
+
row: range.end.row.type === "infinity" ? { type: "infinity" } : { type: "number", value: range.end.row.value },
|
|
3337
|
+
col: range.end.col.type === "infinity" ? { type: "infinity" } : { type: "number", value: range.end.col.value }
|
|
3338
|
+
}
|
|
3339
|
+
};
|
|
3340
|
+
}
|
|
3341
|
+
cloneRangeAddress(address) {
|
|
3342
|
+
return {
|
|
3343
|
+
workbookName: address.workbookName,
|
|
3344
|
+
sheetName: address.sheetName,
|
|
3345
|
+
range: this.smAreaToSpreadsheetRange(this.spreadsheetRangeToSmArea(address.range))
|
|
3346
|
+
};
|
|
3347
|
+
}
|
|
3348
|
+
matchesContext(address, context) {
|
|
3349
|
+
return address.workbookName === context.workbookName && address.sheetName === context.sheetName;
|
|
3350
|
+
}
|
|
3351
|
+
applyRangeFocus(manager, context, request) {
|
|
3352
|
+
const selection = this.spreadsheetRangeToSmArea(request.address.range);
|
|
3353
|
+
manager.setState({ selections: [selection] });
|
|
3354
|
+
manager.focus();
|
|
3355
|
+
manager.revealRange(selection, request.options);
|
|
3356
|
+
this.lastFocusedManager = { sm: manager, context };
|
|
3357
|
+
this.emitChange();
|
|
3358
|
+
}
|
|
3359
|
+
applyPendingRangeFocusOnMount(manager, context) {
|
|
3360
|
+
const pending = this.pendingRangeFocus;
|
|
3361
|
+
if (!pending || !this.matchesContext(pending.address, context))
|
|
3362
|
+
return;
|
|
3363
|
+
queueMicrotask(() => {
|
|
3364
|
+
if (this.pendingRangeFocus !== pending)
|
|
3365
|
+
return;
|
|
3366
|
+
const mountedContext = this.managers.get(manager);
|
|
3367
|
+
if (!mountedContext || !this.matchesContext(pending.address, mountedContext))
|
|
3368
|
+
return;
|
|
3369
|
+
this.pendingRangeFocus = null;
|
|
3370
|
+
this.applyRangeFocus(manager, mountedContext, pending);
|
|
3371
|
+
});
|
|
3372
|
+
}
|
|
3071
3373
|
add(manager, context) {
|
|
3072
3374
|
this.managers.set(manager, context);
|
|
3073
3375
|
const focusCleanup = manager.observeStateChange((state) => state.hasFocus, (hasFocus) => {
|
|
@@ -3093,6 +3395,7 @@ class WorkbookSelectionManager {
|
|
|
3093
3395
|
}
|
|
3094
3396
|
};
|
|
3095
3397
|
this.cleanupFunctions.set(manager, cleanup);
|
|
3398
|
+
this.applyPendingRangeFocusOnMount(manager, context);
|
|
3096
3399
|
return cleanup;
|
|
3097
3400
|
}
|
|
3098
3401
|
getLastFocusedSelectionManager() {
|
|
@@ -3186,22 +3489,31 @@ class WorkbookSelectionManager {
|
|
|
3186
3489
|
return false;
|
|
3187
3490
|
}
|
|
3188
3491
|
focusCell(workbookName, sheetName, row, col) {
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
}
|
|
3197
|
-
}
|
|
3198
|
-
manager.setState({ selections: [selection] });
|
|
3199
|
-
manager.focus();
|
|
3200
|
-
this.lastFocusedManager = { sm: manager, context };
|
|
3201
|
-
this.emitChange();
|
|
3202
|
-
return true;
|
|
3492
|
+
return this.focusRange({
|
|
3493
|
+
workbookName,
|
|
3494
|
+
sheetName,
|
|
3495
|
+
range: {
|
|
3496
|
+
start: { row, col },
|
|
3497
|
+
end: {
|
|
3498
|
+
row: { type: "number", value: row },
|
|
3499
|
+
col: { type: "number", value: col }
|
|
3500
|
+
}
|
|
3203
3501
|
}
|
|
3502
|
+
});
|
|
3503
|
+
}
|
|
3504
|
+
focusRange(address, options = {}) {
|
|
3505
|
+
const request = {
|
|
3506
|
+
address: this.cloneRangeAddress(address),
|
|
3507
|
+
options: { ...options }
|
|
3508
|
+
};
|
|
3509
|
+
for (const [manager, context] of this.managers) {
|
|
3510
|
+
if (!this.matchesContext(request.address, context))
|
|
3511
|
+
continue;
|
|
3512
|
+
this.pendingRangeFocus = null;
|
|
3513
|
+
this.applyRangeFocus(manager, context, request);
|
|
3514
|
+
return true;
|
|
3204
3515
|
}
|
|
3516
|
+
this.pendingRangeFocus = request;
|
|
3205
3517
|
return false;
|
|
3206
3518
|
}
|
|
3207
3519
|
emitChange() {
|
|
@@ -3450,6 +3762,42 @@ function FormulaSheet({
|
|
|
3450
3762
|
const clipboardManager = import_react6.default.useMemo(() => controlledClipboardManager ?? new WorkbookClipboardManager(engine), [controlledClipboardManager, engine]);
|
|
3451
3763
|
const state = useEngine(engine);
|
|
3452
3764
|
const sheet = state.workbooks.get(workbookName)?.sheets.get(sheetName);
|
|
3765
|
+
const getEngineTableAt = import_react6.useCallback((cell) => {
|
|
3766
|
+
const table = engine.isCellInTable({
|
|
3767
|
+
workbookName,
|
|
3768
|
+
sheetName,
|
|
3769
|
+
rowIndex: cell.row,
|
|
3770
|
+
colIndex: cell.col
|
|
3771
|
+
});
|
|
3772
|
+
if (!table)
|
|
3773
|
+
return;
|
|
3774
|
+
const endRow = table.endRow.type === "number" ? { type: "number", value: table.endRow.value } : { type: "infinity" };
|
|
3775
|
+
const endCol = {
|
|
3776
|
+
type: "number",
|
|
3777
|
+
value: table.start.colIndex + table.headers.size - 1
|
|
3778
|
+
};
|
|
3779
|
+
const hasDataRows = endRow.type === "infinity" || endRow.value > table.start.rowIndex;
|
|
3780
|
+
return {
|
|
3781
|
+
id: `${table.workbookName}/${table.name}`,
|
|
3782
|
+
bounds: {
|
|
3783
|
+
start: { row: table.start.rowIndex, col: table.start.colIndex },
|
|
3784
|
+
end: { row: endRow, col: endCol }
|
|
3785
|
+
},
|
|
3786
|
+
...hasDataRows ? {
|
|
3787
|
+
dataBounds: {
|
|
3788
|
+
start: {
|
|
3789
|
+
row: table.start.rowIndex + 1,
|
|
3790
|
+
col: table.start.colIndex
|
|
3791
|
+
},
|
|
3792
|
+
end: { row: endRow, col: endCol }
|
|
3793
|
+
}
|
|
3794
|
+
} : {}
|
|
3795
|
+
};
|
|
3796
|
+
}, [engine, sheetName, workbookName]);
|
|
3797
|
+
const formulaNavigation = import_react6.useMemo(() => ({
|
|
3798
|
+
...selection?.navigation,
|
|
3799
|
+
getTableAt: selection?.navigation?.getTableAt ?? getEngineTableAt
|
|
3800
|
+
}), [getEngineTableAt, selection?.navigation]);
|
|
3453
3801
|
const onCellDataChange = import_react6.useCallback((updatedSpreadsheet) => {
|
|
3454
3802
|
const data = new Map(updatedSpreadsheet);
|
|
3455
3803
|
data.forEach((value, key) => {
|
|
@@ -3623,6 +3971,7 @@ function FormulaSheet({
|
|
|
3623
3971
|
parentSelected: isSelected,
|
|
3624
3972
|
selection: {
|
|
3625
3973
|
...selection,
|
|
3974
|
+
navigation: formulaNavigation,
|
|
3626
3975
|
effects: selectionManagerEffects
|
|
3627
3976
|
},
|
|
3628
3977
|
containerProps: isSelected && selectedArea ? {
|
|
@@ -4161,4 +4510,4 @@ var useClickAway = (ref, callback) => {
|
|
|
4161
4510
|
}, [ref, callback]);
|
|
4162
4511
|
};
|
|
4163
4512
|
|
|
4164
|
-
//# debugId=
|
|
4513
|
+
//# debugId=81701030D90BCDFB64756E2164756E21
|