@ricsam/react-spreadsheets 0.0.10 → 0.0.12
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 +31 -0
- package/dist/cjs/lib.cjs +111 -49
- package/dist/cjs/lib.cjs.map +3 -3
- package/dist/cjs/package.json +1 -1
- package/dist/mjs/lib.mjs +110 -46
- package/dist/mjs/lib.mjs.map +3 -3
- package/dist/mjs/package.json +1 -1
- package/dist/types/spreadsheet/spreadsheet.d.ts +4 -0
- package/package.json +2 -2
package/dist/cjs/package.json
CHANGED
package/dist/mjs/lib.mjs
CHANGED
|
@@ -8,6 +8,8 @@ import React2, {
|
|
|
8
8
|
useCallback as useCallback3,
|
|
9
9
|
useEffect as useEffect3,
|
|
10
10
|
useImperativeHandle,
|
|
11
|
+
useId,
|
|
12
|
+
useLayoutEffect,
|
|
11
13
|
useMemo,
|
|
12
14
|
useRef as useRef3,
|
|
13
15
|
useState as useState4
|
|
@@ -1326,6 +1328,7 @@ var resizeCellSnapAnchorToNearestEdges = (anchor, rect, handle, columnWidths, ro
|
|
|
1326
1328
|
|
|
1327
1329
|
// src/spreadsheet/spreadsheet.tsx
|
|
1328
1330
|
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
1331
|
+
var SPREADSHEET_OVERLAY_SELECTOR = "[data-rsp-overlay]";
|
|
1329
1332
|
var resolveGridLineColor = (probe, colorScheme) => {
|
|
1330
1333
|
const fallback = colorScheme === "dark" ? "#232c3d" : "#e8ebf1";
|
|
1331
1334
|
if (!probe || typeof getComputedStyle !== "function") {
|
|
@@ -1471,6 +1474,7 @@ var CellComponent = React2.memo(({
|
|
|
1471
1474
|
value,
|
|
1472
1475
|
row,
|
|
1473
1476
|
col,
|
|
1477
|
+
domId,
|
|
1474
1478
|
selectionManager,
|
|
1475
1479
|
cellToPixelBase,
|
|
1476
1480
|
getColumnWidth,
|
|
@@ -1484,11 +1488,11 @@ var CellComponent = React2.memo(({
|
|
|
1484
1488
|
}) => {
|
|
1485
1489
|
const cellRef = useCallback3((el) => {
|
|
1486
1490
|
if (el) {
|
|
1487
|
-
const
|
|
1488
|
-
const
|
|
1491
|
+
const rowIndex = row - 1;
|
|
1492
|
+
const colIndex = columnToIndex(col);
|
|
1489
1493
|
return selectionManager.setupCellElement(el, {
|
|
1490
|
-
row:
|
|
1491
|
-
col:
|
|
1494
|
+
row: rowIndex,
|
|
1495
|
+
col: colIndex
|
|
1492
1496
|
});
|
|
1493
1497
|
}
|
|
1494
1498
|
}, [row, col, selectionManager]);
|
|
@@ -1516,16 +1520,22 @@ var CellComponent = React2.memo(({
|
|
|
1516
1520
|
});
|
|
1517
1521
|
const inputRef = useCallback3((el) => {
|
|
1518
1522
|
if (el) {
|
|
1519
|
-
const
|
|
1520
|
-
const
|
|
1523
|
+
const rowIndex = row - 1;
|
|
1524
|
+
const colIndex = columnToIndex(col);
|
|
1521
1525
|
return selectionManager.setupInputElement(el, {
|
|
1522
|
-
rowIndex
|
|
1523
|
-
colIndex
|
|
1526
|
+
rowIndex,
|
|
1527
|
+
colIndex
|
|
1524
1528
|
});
|
|
1525
1529
|
}
|
|
1526
1530
|
}, [row, col, selectionManager]);
|
|
1527
1531
|
return /* @__PURE__ */ jsxs2("div", {
|
|
1528
1532
|
ref: cellRef,
|
|
1533
|
+
id: domId,
|
|
1534
|
+
role: "gridcell",
|
|
1535
|
+
"aria-rowindex": row + 1,
|
|
1536
|
+
"aria-colindex": colIndex + 2,
|
|
1537
|
+
"aria-selected": isSelected,
|
|
1538
|
+
"data-cell-address": `${col}${row}`,
|
|
1529
1539
|
className: cn("rsp-cell", {
|
|
1530
1540
|
"rsp-cell-multiline": typeof value === "string" && value.includes(`
|
|
1531
1541
|
`),
|
|
@@ -1545,6 +1555,7 @@ var CellComponent = React2.memo(({
|
|
|
1545
1555
|
children: [
|
|
1546
1556
|
isBeingEdited ? /* @__PURE__ */ jsx3("textarea", {
|
|
1547
1557
|
className: "rsp-cell-editor",
|
|
1558
|
+
"aria-label": `Edit ${col}${row}`,
|
|
1548
1559
|
"data-testid": `spreadsheet-cell-input-${col}${row}`,
|
|
1549
1560
|
ref: inputRef,
|
|
1550
1561
|
defaultValue: inputValue?.toString() ?? "",
|
|
@@ -1623,6 +1634,10 @@ var HeaderComponent = React2.memo(({
|
|
|
1623
1634
|
const content = type === "col" ? reverseHeaders ? index + 1 : indexToColumn(index) : reverseHeaders ? rowToLetter(index + 1) : index + 1;
|
|
1624
1635
|
return /* @__PURE__ */ jsxs2("div", {
|
|
1625
1636
|
ref: headerRef,
|
|
1637
|
+
role: type === "col" ? "columnheader" : "rowheader",
|
|
1638
|
+
"aria-colindex": type === "col" ? index + 2 : 1,
|
|
1639
|
+
"aria-rowindex": type === "row" ? index + 2 : 1,
|
|
1640
|
+
"aria-selected": isSelected,
|
|
1626
1641
|
className: cn("rsp-header", `rsp-header-${type}`, {
|
|
1627
1642
|
"rsp-header-selected": isSelected
|
|
1628
1643
|
}),
|
|
@@ -1767,6 +1782,9 @@ var Spreadsheet = forwardRef(({
|
|
|
1767
1782
|
style,
|
|
1768
1783
|
className,
|
|
1769
1784
|
containerProps,
|
|
1785
|
+
"aria-label": ariaLabel = "Spreadsheet",
|
|
1786
|
+
"aria-labelledby": ariaLabelledBy,
|
|
1787
|
+
"aria-describedby": ariaDescribedBy,
|
|
1770
1788
|
cellData: controlledCellData,
|
|
1771
1789
|
onCellDataChange,
|
|
1772
1790
|
onCellDataChangeError,
|
|
@@ -1789,6 +1807,7 @@ var Spreadsheet = forwardRef(({
|
|
|
1789
1807
|
parentSelected = true,
|
|
1790
1808
|
disableClipboard = false
|
|
1791
1809
|
}, ref) => {
|
|
1810
|
+
const gridId = useId();
|
|
1792
1811
|
const [{ width, height }, containerRef] = useResizeObserver();
|
|
1793
1812
|
const [containerDivRef, setContainerDivRef] = useState4(null);
|
|
1794
1813
|
const colorScheme = useColorScheme(containerDivRef);
|
|
@@ -1982,15 +2001,15 @@ var Spreadsheet = forwardRef(({
|
|
|
1982
2001
|
};
|
|
1983
2002
|
const effectsRef = useRef3(effectsRefOb);
|
|
1984
2003
|
effectsRef.current = effectsRefOb;
|
|
1985
|
-
const setupCanvas = useCallback3((canvas,
|
|
2004
|
+
const setupCanvas = useCallback3((canvas, width, height) => {
|
|
1986
2005
|
const ctx = canvas.getContext("2d");
|
|
1987
2006
|
if (!ctx)
|
|
1988
2007
|
return null;
|
|
1989
2008
|
const devicePixelRatio = window.devicePixelRatio || 1;
|
|
1990
|
-
canvas.width =
|
|
1991
|
-
canvas.height =
|
|
1992
|
-
canvas.style.width =
|
|
1993
|
-
canvas.style.height =
|
|
2009
|
+
canvas.width = width * devicePixelRatio;
|
|
2010
|
+
canvas.height = height * devicePixelRatio;
|
|
2011
|
+
canvas.style.width = width + "px";
|
|
2012
|
+
canvas.style.height = height + "px";
|
|
1994
2013
|
ctx.scale(devicePixelRatio, devicePixelRatio);
|
|
1995
2014
|
return ctx;
|
|
1996
2015
|
}, []);
|
|
@@ -2218,36 +2237,36 @@ var Spreadsheet = forwardRef(({
|
|
|
2218
2237
|
return selectionManager.listenToUpdateData((updates) => {
|
|
2219
2238
|
const editingState = selectionManager.isEditing;
|
|
2220
2239
|
try {
|
|
2221
|
-
const { cellData
|
|
2222
|
-
const newData = new Map(
|
|
2240
|
+
const { cellData, onCellDataChange } = effectsRef.current;
|
|
2241
|
+
const newData = new Map(cellData);
|
|
2223
2242
|
updates.forEach(({ value, rowIndex, colIndex }) => {
|
|
2224
2243
|
const key = `${indexToColumn(colIndex)}${rowIndex + 1}`;
|
|
2225
|
-
const
|
|
2244
|
+
const parseValue = effectsRef.current.parseValue;
|
|
2226
2245
|
if (value === "") {
|
|
2227
2246
|
newData.delete(key);
|
|
2228
2247
|
} else {
|
|
2229
2248
|
let parsedValue = value;
|
|
2230
|
-
if (
|
|
2249
|
+
if (parseValue && typeof value === "string") {
|
|
2231
2250
|
const match = key.match(/^([A-Z]+)(\d+)$/);
|
|
2232
2251
|
const col = match?.[1];
|
|
2233
2252
|
const rowText = match?.[2];
|
|
2234
2253
|
if (col && rowText) {
|
|
2235
2254
|
const row = parseInt(rowText, 10);
|
|
2236
|
-
const
|
|
2237
|
-
const
|
|
2238
|
-
parsedValue =
|
|
2255
|
+
const colIndex = columnToIndex(col);
|
|
2256
|
+
const rowIndex = row - 1;
|
|
2257
|
+
parsedValue = parseValue(value, {
|
|
2239
2258
|
id: key,
|
|
2240
2259
|
row,
|
|
2241
2260
|
col,
|
|
2242
|
-
rowIndex
|
|
2243
|
-
colIndex
|
|
2261
|
+
rowIndex,
|
|
2262
|
+
colIndex
|
|
2244
2263
|
});
|
|
2245
2264
|
}
|
|
2246
2265
|
}
|
|
2247
2266
|
newData.set(key, parsedValue);
|
|
2248
2267
|
}
|
|
2249
2268
|
});
|
|
2250
|
-
|
|
2269
|
+
onCellDataChange?.(newData);
|
|
2251
2270
|
setInternalCellData(newData);
|
|
2252
2271
|
} catch (error) {
|
|
2253
2272
|
console.error("Failed to update spreadsheet cell data:", error);
|
|
@@ -2286,6 +2305,12 @@ var Spreadsheet = forwardRef(({
|
|
|
2286
2305
|
});
|
|
2287
2306
|
}, [selectionManager, clipboardManager, disableClipboard]);
|
|
2288
2307
|
const handleWheel = useCallback3((e) => {
|
|
2308
|
+
const target = e.target;
|
|
2309
|
+
const currentTarget = e.currentTarget;
|
|
2310
|
+
const overlay = target instanceof Element ? target.closest(SPREADSHEET_OVERLAY_SELECTOR) : null;
|
|
2311
|
+
if (overlay && currentTarget instanceof Node && currentTarget.contains(overlay)) {
|
|
2312
|
+
return;
|
|
2313
|
+
}
|
|
2289
2314
|
e.preventDefault();
|
|
2290
2315
|
e.stopPropagation();
|
|
2291
2316
|
setViewport((previous) => ({
|
|
@@ -2424,13 +2449,13 @@ var Spreadsheet = forwardRef(({
|
|
|
2424
2449
|
const handleColumnResizeDoubleClick = useCallback3((e, col) => {
|
|
2425
2450
|
e.preventDefault();
|
|
2426
2451
|
e.stopPropagation();
|
|
2427
|
-
const { viewport
|
|
2452
|
+
const { viewport, gridDims, height, cellData } = effectsRef.current;
|
|
2428
2453
|
let maxWidth = 50;
|
|
2429
|
-
const startRow = Math.max(0, Math.floor(
|
|
2430
|
-
const endRow = Math.ceil((
|
|
2454
|
+
const startRow = Math.max(0, Math.floor(viewport.scrollY / gridDims.cellHeight));
|
|
2455
|
+
const endRow = Math.ceil((viewport.scrollY + height) / gridDims.cellHeight) + 1;
|
|
2431
2456
|
for (let row = startRow;row <= endRow; row++) {
|
|
2432
2457
|
const cellKey = `${col}${getRowNumber(row)}`;
|
|
2433
|
-
const content =
|
|
2458
|
+
const content = cellData.get(cellKey) ?? "";
|
|
2434
2459
|
if (content) {
|
|
2435
2460
|
const estimatedWidth = String(content).length * 8 + 20;
|
|
2436
2461
|
maxWidth = Math.max(maxWidth, estimatedWidth);
|
|
@@ -2699,8 +2724,8 @@ var Spreadsheet = forwardRef(({
|
|
|
2699
2724
|
return editingCleanup;
|
|
2700
2725
|
}, [selectionManager]);
|
|
2701
2726
|
React2.useEffect(() => {
|
|
2702
|
-
return selectionManager.observeStateChange((state) => state.hasFocus, (
|
|
2703
|
-
if (
|
|
2727
|
+
return selectionManager.observeStateChange((state) => state.hasFocus, (hasFocus) => {
|
|
2728
|
+
if (hasFocus && selectedOverlayId) {
|
|
2704
2729
|
setSelectedOverlay(null);
|
|
2705
2730
|
}
|
|
2706
2731
|
});
|
|
@@ -2803,6 +2828,21 @@ var Spreadsheet = forwardRef(({
|
|
|
2803
2828
|
const visibleCells = React2.useMemo(() => getVisibleCells(), [getVisibleCells]);
|
|
2804
2829
|
const visibleColumnHeaders = React2.useMemo(() => getVisibleColumnHeaders(), [getVisibleColumnHeaders]);
|
|
2805
2830
|
const visibleRowHeaders = React2.useMemo(() => getVisibleRowHeaders(), [getVisibleRowHeaders]);
|
|
2831
|
+
const activeAddress = useSelectionManager(selectionManager, () => {
|
|
2832
|
+
const cell = selectionManager.getTopLeftCellInSelection();
|
|
2833
|
+
return cell ? `${indexToColumn(cell.col)}${cell.row + 1}` : undefined;
|
|
2834
|
+
});
|
|
2835
|
+
const activeCellId = visibleCells.some((cell) => `${cell.col}${cell.row}` === activeAddress) ? `${gridId}-cell-${activeAddress}` : undefined;
|
|
2836
|
+
const accessibilityManager = selectionManager;
|
|
2837
|
+
useLayoutEffect(() => {
|
|
2838
|
+
accessibilityManager.setInputCaptureAccessibility?.({
|
|
2839
|
+
label: `${ariaLabel} keyboard input`,
|
|
2840
|
+
controls: gridId,
|
|
2841
|
+
activeDescendant: activeCellId,
|
|
2842
|
+
describedBy: ariaDescribedBy
|
|
2843
|
+
});
|
|
2844
|
+
return () => accessibilityManager.setInputCaptureAccessibility?.({});
|
|
2845
|
+
}, [accessibilityManager, ariaLabel, ariaDescribedBy, gridId, activeCellId]);
|
|
2806
2846
|
const hasFocus = useSelectionManager(selectionManager, () => selectionManager.hasFocus);
|
|
2807
2847
|
const referenceSelection = useSelectionManager(selectionManager, () => selectionManager.referenceSelection);
|
|
2808
2848
|
const referenceSelectionRect = useMemo(() => {
|
|
@@ -2878,7 +2918,21 @@ var Spreadsheet = forwardRef(({
|
|
|
2878
2918
|
width,
|
|
2879
2919
|
height
|
|
2880
2920
|
},
|
|
2921
|
+
id: gridId,
|
|
2922
|
+
role: "grid",
|
|
2923
|
+
"aria-activedescendant": activeCellId,
|
|
2924
|
+
"aria-label": ariaLabel,
|
|
2925
|
+
"aria-labelledby": ariaLabelledBy,
|
|
2926
|
+
"aria-describedby": ariaDescribedBy,
|
|
2927
|
+
"aria-rowcount": finiteRowCount === undefined ? -1 : finiteRowCount + 1,
|
|
2928
|
+
"aria-colcount": finiteColumnCount === undefined ? -1 : finiteColumnCount + 1,
|
|
2929
|
+
"aria-multiselectable": "true",
|
|
2881
2930
|
tabIndex: 0,
|
|
2931
|
+
onFocus: (event) => {
|
|
2932
|
+
if (event.target === event.currentTarget && !selectionManager.hasFocus) {
|
|
2933
|
+
selectionManager.focus();
|
|
2934
|
+
}
|
|
2935
|
+
},
|
|
2882
2936
|
children: [
|
|
2883
2937
|
/* @__PURE__ */ jsx3("span", {
|
|
2884
2938
|
ref: gridLineProbeRef,
|
|
@@ -2894,12 +2948,15 @@ var Spreadsheet = forwardRef(({
|
|
|
2894
2948
|
}),
|
|
2895
2949
|
/* @__PURE__ */ jsx3("canvas", {
|
|
2896
2950
|
ref: canvasRef,
|
|
2951
|
+
"aria-hidden": "true",
|
|
2897
2952
|
className: "rsp-canvas",
|
|
2898
2953
|
"data-testid": "spreadsheet-canvas",
|
|
2899
2954
|
style: { width, height }
|
|
2900
2955
|
}),
|
|
2901
2956
|
/* @__PURE__ */ jsx3("div", {
|
|
2902
2957
|
className: "rsp-column-headers",
|
|
2958
|
+
role: "row",
|
|
2959
|
+
"aria-rowindex": 1,
|
|
2903
2960
|
"data-testid": "spreadsheet-column-headers",
|
|
2904
2961
|
style: {
|
|
2905
2962
|
left: gridDims.headerWidth,
|
|
@@ -2942,16 +2999,21 @@ var Spreadsheet = forwardRef(({
|
|
|
2942
2999
|
transformOrigin: "0 0"
|
|
2943
3000
|
},
|
|
2944
3001
|
children: visibleRowHeaders.map(({ row, rowIndex }) => {
|
|
2945
|
-
return /* @__PURE__ */ jsx3(
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
3002
|
+
return /* @__PURE__ */ jsx3("div", {
|
|
3003
|
+
role: "row",
|
|
3004
|
+
"aria-rowindex": row + 1,
|
|
3005
|
+
"aria-owns": visibleCells.filter((cell) => cell.row === row).map((cell) => `${gridId}-cell-${cell.col}${cell.row}`).join(" ") || undefined,
|
|
3006
|
+
children: /* @__PURE__ */ jsx3(HeaderComponent, {
|
|
3007
|
+
index: rowIndex,
|
|
3008
|
+
type: "row",
|
|
3009
|
+
selectionManager,
|
|
3010
|
+
getColumnWidth,
|
|
3011
|
+
getRowHeight,
|
|
3012
|
+
handleColumnResizeStart,
|
|
3013
|
+
handleColumnResizeDoubleClick,
|
|
3014
|
+
handleRowResizeStart,
|
|
3015
|
+
handleRowResizeDoubleClick
|
|
3016
|
+
})
|
|
2955
3017
|
}, row);
|
|
2956
3018
|
})
|
|
2957
3019
|
})
|
|
@@ -2974,6 +3036,7 @@ var Spreadsheet = forwardRef(({
|
|
|
2974
3036
|
},
|
|
2975
3037
|
children: [
|
|
2976
3038
|
visibleCells.map((cell) => /* @__PURE__ */ jsx3(CellComponent, {
|
|
3039
|
+
domId: `${gridId}-cell-${cell.col}${cell.row}`,
|
|
2977
3040
|
value: cellData.get(`${cell.col}${cell.row}`) ?? "",
|
|
2978
3041
|
row: cell.row,
|
|
2979
3042
|
col: cell.col,
|
|
@@ -3011,6 +3074,7 @@ var Spreadsheet = forwardRef(({
|
|
|
3011
3074
|
const isTextBox = child.component === "RichText";
|
|
3012
3075
|
const isMinimized = Boolean(child.minimized && !isTextBox);
|
|
3013
3076
|
return /* @__PURE__ */ jsxs2("div", {
|
|
3077
|
+
"data-rsp-overlay": child.id,
|
|
3014
3078
|
style: {
|
|
3015
3079
|
position: "absolute",
|
|
3016
3080
|
width: child.width,
|
|
@@ -3807,11 +3871,11 @@ function FormulaSheet({
|
|
|
3807
3871
|
});
|
|
3808
3872
|
}
|
|
3809
3873
|
}),
|
|
3810
|
-
spreadsheetSelectionManager.observeStateChange((
|
|
3811
|
-
const currentSelection =
|
|
3874
|
+
spreadsheetSelectionManager.observeStateChange((state) => {
|
|
3875
|
+
const currentSelection = state.selections.length === 1 ? state.selections[0] : undefined;
|
|
3812
3876
|
return currentSelection;
|
|
3813
|
-
}, (
|
|
3814
|
-
setSelectedArea(
|
|
3877
|
+
}, (selection) => {
|
|
3878
|
+
setSelectedArea(selection ?? null);
|
|
3815
3879
|
})
|
|
3816
3880
|
];
|
|
3817
3881
|
const handleUndoRedoKeyDown = (event) => {
|
|
@@ -3927,7 +3991,7 @@ function FormulaSheet({
|
|
|
3927
3991
|
workbookName
|
|
3928
3992
|
});
|
|
3929
3993
|
if (!tableInfo) {
|
|
3930
|
-
const
|
|
3994
|
+
const style = conditionalStyle ? {
|
|
3931
3995
|
...conditionalStyle.backgroundColor && {
|
|
3932
3996
|
backgroundColor: conditionalStyle.backgroundColor
|
|
3933
3997
|
},
|
|
@@ -3949,7 +4013,7 @@ function FormulaSheet({
|
|
|
3949
4013
|
...getBorderCellStyle(conditionalStyle),
|
|
3950
4014
|
...getWrapCellStyle(conditionalStyle)
|
|
3951
4015
|
} : {};
|
|
3952
|
-
return customCellStyle ? customCellStyle(cell,
|
|
4016
|
+
return customCellStyle ? customCellStyle(cell, style) : style;
|
|
3953
4017
|
}
|
|
3954
4018
|
const isHeaderRow = cell.rowIndex === tableInfo.start.rowIndex;
|
|
3955
4019
|
const isFirstColumn = cell.colIndex === tableInfo.start.colIndex;
|
|
@@ -4499,4 +4563,4 @@ export {
|
|
|
4499
4563
|
useResizeObserver
|
|
4500
4564
|
};
|
|
4501
4565
|
|
|
4502
|
-
//# debugId=
|
|
4566
|
+
//# debugId=FA27216279C90A7964756E2164756E21
|