@particle-academy/fancy-sheets 0.3.1 → 0.4.0
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/index.cjs +136 -73
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +137 -74
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1601,14 +1601,19 @@ function ColumnResizeHandle({ colIndex }) {
|
|
|
1601
1601
|
}
|
|
1602
1602
|
ColumnResizeHandle.displayName = "ColumnResizeHandle";
|
|
1603
1603
|
function ColumnHeaders() {
|
|
1604
|
-
const { columnCount, rowCount, rowHeight, getColumnWidth, selectRange } = useSpreadsheet();
|
|
1604
|
+
const { columnCount, rowCount, rowHeight, getColumnWidth, selection, selectRange } = useSpreadsheet();
|
|
1605
1605
|
const handleColumnClick = react.useCallback(
|
|
1606
|
-
(colIdx) => {
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1606
|
+
(colIdx, e) => {
|
|
1607
|
+
if (e.shiftKey) {
|
|
1608
|
+
const activeCol = parseAddress(selection.activeCell).col;
|
|
1609
|
+
const minCol = Math.min(activeCol, colIdx);
|
|
1610
|
+
const maxCol = Math.max(activeCol, colIdx);
|
|
1611
|
+
selectRange(toAddress(0, minCol), toAddress(rowCount - 1, maxCol));
|
|
1612
|
+
} else {
|
|
1613
|
+
selectRange(toAddress(0, colIdx), toAddress(rowCount - 1, colIdx));
|
|
1614
|
+
}
|
|
1610
1615
|
},
|
|
1611
|
-
[rowCount, selectRange]
|
|
1616
|
+
[rowCount, selectRange, selection.activeCell]
|
|
1612
1617
|
);
|
|
1613
1618
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1614
1619
|
"div",
|
|
@@ -1629,7 +1634,7 @@ function ColumnHeaders() {
|
|
|
1629
1634
|
{
|
|
1630
1635
|
className: "relative flex shrink-0 cursor-pointer items-center justify-center border-r border-zinc-300 text-[11px] font-medium text-zinc-500 select-none hover:bg-zinc-200 dark:border-zinc-600 dark:text-zinc-400 dark:hover:bg-zinc-700",
|
|
1631
1636
|
style: { width: getColumnWidth(i), minWidth: getColumnWidth(i) },
|
|
1632
|
-
onClick: () => handleColumnClick(i),
|
|
1637
|
+
onClick: (e) => handleColumnClick(i, e),
|
|
1633
1638
|
children: [
|
|
1634
1639
|
columnToLetter(i),
|
|
1635
1640
|
/* @__PURE__ */ jsxRuntime.jsx(ColumnResizeHandle, { colIndex: i })
|
|
@@ -1643,12 +1648,20 @@ function ColumnHeaders() {
|
|
|
1643
1648
|
}
|
|
1644
1649
|
ColumnHeaders.displayName = "ColumnHeaders";
|
|
1645
1650
|
function RowHeader({ rowIndex }) {
|
|
1646
|
-
const { rowHeight, columnCount, selectRange } = useSpreadsheet();
|
|
1647
|
-
const handleClick = react.useCallback(
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1651
|
+
const { rowHeight, columnCount, selection, selectRange, extendSelection } = useSpreadsheet();
|
|
1652
|
+
const handleClick = react.useCallback(
|
|
1653
|
+
(e) => {
|
|
1654
|
+
if (e.shiftKey) {
|
|
1655
|
+
const activeRow = parseAddress(selection.activeCell).row;
|
|
1656
|
+
const minRow = Math.min(activeRow, rowIndex);
|
|
1657
|
+
const maxRow = Math.max(activeRow, rowIndex);
|
|
1658
|
+
selectRange(toAddress(minRow, 0), toAddress(maxRow, columnCount - 1));
|
|
1659
|
+
} else {
|
|
1660
|
+
selectRange(toAddress(rowIndex, 0), toAddress(rowIndex, columnCount - 1));
|
|
1661
|
+
}
|
|
1662
|
+
},
|
|
1663
|
+
[rowIndex, columnCount, selectRange, selection.activeCell]
|
|
1664
|
+
);
|
|
1652
1665
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1653
1666
|
"div",
|
|
1654
1667
|
{
|
|
@@ -1754,9 +1767,9 @@ var Cell = react.memo(function Cell2({ address, row, col }) {
|
|
|
1754
1767
|
"data-active": isActive || void 0,
|
|
1755
1768
|
role: "gridcell",
|
|
1756
1769
|
className: reactFancy.cn(
|
|
1757
|
-
"relative flex items-center truncate border-r border-b border-zinc-200 px-1.5 text-[13px] dark:border-zinc-700",
|
|
1770
|
+
"relative flex items-center truncate border-r border-b border-zinc-200 bg-white px-1.5 text-[13px] dark:border-zinc-700 dark:bg-zinc-900",
|
|
1758
1771
|
isActive && "ring-2 ring-inset ring-blue-500",
|
|
1759
|
-
isSelected && !isActive && "bg-blue-
|
|
1772
|
+
isSelected && !isActive && "bg-blue-50 dark:bg-blue-950/40"
|
|
1760
1773
|
),
|
|
1761
1774
|
style: { width, minWidth: width, height: rowHeight, ...formatStyle },
|
|
1762
1775
|
onMouseDown: handleMouseDown,
|
|
@@ -1899,6 +1912,8 @@ function SpreadsheetGrid({ className }) {
|
|
|
1899
1912
|
confirmEdit,
|
|
1900
1913
|
cancelEdit,
|
|
1901
1914
|
setCellValue,
|
|
1915
|
+
setFrozenRows,
|
|
1916
|
+
setFrozenCols,
|
|
1902
1917
|
undo,
|
|
1903
1918
|
redo
|
|
1904
1919
|
} = useSpreadsheet();
|
|
@@ -1988,66 +2003,114 @@ function SpreadsheetGrid({ className }) {
|
|
|
1988
2003
|
const top = row * rowHeight;
|
|
1989
2004
|
return { left, top };
|
|
1990
2005
|
})() : null;
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
{
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2006
|
+
const handleCopy = react.useCallback(() => {
|
|
2007
|
+
const range = selection.ranges[0];
|
|
2008
|
+
if (range) {
|
|
2009
|
+
const tsv = cellsToTSV(activeSheet.cells, range);
|
|
2010
|
+
navigator.clipboard.writeText(tsv);
|
|
2011
|
+
}
|
|
2012
|
+
}, [selection, activeSheet]);
|
|
2013
|
+
const handlePaste = react.useCallback(() => {
|
|
2014
|
+
navigator.clipboard.readText().then((text) => {
|
|
2015
|
+
if (!text) return;
|
|
2016
|
+
const { values } = tsvToCells(text);
|
|
2017
|
+
const { row: startRow, col: startCol } = parseAddress(selection.activeCell);
|
|
2018
|
+
for (let r = 0; r < values.length; r++) {
|
|
2019
|
+
for (let c = 0; c < values[r].length; c++) {
|
|
2020
|
+
setCellValue(toAddress(startRow + r, startCol + c), values[r][c]);
|
|
2021
|
+
}
|
|
2022
|
+
}
|
|
2023
|
+
});
|
|
2024
|
+
}, [selection, setCellValue]);
|
|
2025
|
+
const handleClearSelection = react.useCallback(() => {
|
|
2026
|
+
const range = selection.ranges[0];
|
|
2027
|
+
if (!range) return;
|
|
2028
|
+
const { start, end } = range;
|
|
2029
|
+
const s = parseAddress(start);
|
|
2030
|
+
const e = parseAddress(end);
|
|
2031
|
+
const minR = Math.min(s.row, e.row), maxR = Math.max(s.row, e.row);
|
|
2032
|
+
const minC = Math.min(s.col, e.col), maxC = Math.max(s.col, e.col);
|
|
2033
|
+
for (let r = minR; r <= maxR; r++) {
|
|
2034
|
+
for (let c = minC; c <= maxC; c++) {
|
|
2035
|
+
setCellValue(toAddress(r, c), "");
|
|
2036
|
+
}
|
|
2037
|
+
}
|
|
2038
|
+
}, [selection, setCellValue]);
|
|
2039
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(reactFancy.ContextMenu, { children: [
|
|
2040
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactFancy.ContextMenu.Trigger, { className: "min-h-0 flex-1", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2041
|
+
"div",
|
|
2042
|
+
{
|
|
2043
|
+
ref: containerRef,
|
|
2044
|
+
"data-fancy-sheets-grid": "",
|
|
2045
|
+
className: reactFancy.cn("relative h-full overflow-auto bg-white focus:outline-none dark:bg-zinc-900", className),
|
|
2046
|
+
tabIndex: 0,
|
|
2047
|
+
onKeyDown: handleKeyDown,
|
|
2048
|
+
children: [
|
|
2049
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "sticky top-0 z-10", children: /* @__PURE__ */ jsxRuntime.jsx(ColumnHeaders, {}) }),
|
|
2050
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
|
|
2051
|
+
Array.from({ length: rowCount }, (_, rowIdx) => {
|
|
2052
|
+
const isFrozenRow = rowIdx < activeSheet.frozenRows;
|
|
2053
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2054
|
+
"div",
|
|
2055
|
+
{
|
|
2056
|
+
className: "flex",
|
|
2057
|
+
style: isFrozenRow ? {
|
|
2058
|
+
position: "sticky",
|
|
2059
|
+
top: rowHeight + rowIdx * rowHeight,
|
|
2060
|
+
zIndex: 8
|
|
2061
|
+
} : void 0,
|
|
2062
|
+
children: [
|
|
2063
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "sticky left-0 z-[5]", children: /* @__PURE__ */ jsxRuntime.jsx(RowHeader, { rowIndex: rowIdx }) }),
|
|
2064
|
+
Array.from({ length: columnCount }, (_2, colIdx) => {
|
|
2065
|
+
const addr = toAddress(rowIdx, colIdx);
|
|
2066
|
+
const isFrozenCol = colIdx < activeSheet.frozenCols;
|
|
2067
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2068
|
+
"div",
|
|
2069
|
+
{
|
|
2070
|
+
style: isFrozenCol ? {
|
|
2071
|
+
position: "sticky",
|
|
2072
|
+
left: 48 + Array.from({ length: colIdx }, (_3, c) => getColumnWidth(c)).reduce((a, b) => a + b, 0),
|
|
2073
|
+
zIndex: isFrozenRow ? 9 : 6
|
|
2074
|
+
} : void 0,
|
|
2075
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Cell, { address: addr, row: rowIdx, col: colIdx })
|
|
2076
|
+
},
|
|
2077
|
+
addr
|
|
2078
|
+
);
|
|
2079
|
+
})
|
|
2080
|
+
]
|
|
2081
|
+
},
|
|
2082
|
+
rowIdx
|
|
2083
|
+
);
|
|
2084
|
+
}),
|
|
2085
|
+
/* @__PURE__ */ jsxRuntime.jsx(SelectionOverlay, {}),
|
|
2086
|
+
editorPosition && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2005
2087
|
"div",
|
|
2006
2088
|
{
|
|
2007
|
-
className: "
|
|
2008
|
-
style:
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
})
|
|
2033
|
-
]
|
|
2034
|
-
},
|
|
2035
|
-
rowIdx
|
|
2036
|
-
);
|
|
2037
|
-
}),
|
|
2038
|
-
/* @__PURE__ */ jsxRuntime.jsx(SelectionOverlay, {}),
|
|
2039
|
-
editorPosition && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2040
|
-
"div",
|
|
2041
|
-
{
|
|
2042
|
-
className: "absolute z-20",
|
|
2043
|
-
style: { left: editorPosition.left, top: editorPosition.top },
|
|
2044
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(CellEditor, {})
|
|
2045
|
-
}
|
|
2046
|
-
)
|
|
2047
|
-
] })
|
|
2048
|
-
]
|
|
2049
|
-
}
|
|
2050
|
-
);
|
|
2089
|
+
className: "absolute z-20",
|
|
2090
|
+
style: { left: editorPosition.left, top: editorPosition.top },
|
|
2091
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(CellEditor, {})
|
|
2092
|
+
}
|
|
2093
|
+
)
|
|
2094
|
+
] })
|
|
2095
|
+
]
|
|
2096
|
+
}
|
|
2097
|
+
) }),
|
|
2098
|
+
/* @__PURE__ */ jsxRuntime.jsxs(reactFancy.ContextMenu.Content, { children: [
|
|
2099
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactFancy.ContextMenu.Item, { onClick: handleCopy, children: "Copy" }),
|
|
2100
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactFancy.ContextMenu.Item, { onClick: handlePaste, disabled: readOnly, children: "Paste" }),
|
|
2101
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactFancy.ContextMenu.Separator, {}),
|
|
2102
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactFancy.ContextMenu.Item, { onClick: handleClearSelection, disabled: readOnly, children: "Clear cells" }),
|
|
2103
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactFancy.ContextMenu.Separator, {}),
|
|
2104
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactFancy.ContextMenu.Item, { onClick: () => {
|
|
2105
|
+
const row = parseAddress(selection.activeCell).row;
|
|
2106
|
+
setFrozenRows(activeSheet.frozenRows > 0 ? 0 : row);
|
|
2107
|
+
}, disabled: readOnly, children: activeSheet.frozenRows > 0 ? "Unfreeze rows" : "Freeze rows above" }),
|
|
2108
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactFancy.ContextMenu.Item, { onClick: () => {
|
|
2109
|
+
const col = parseAddress(selection.activeCell).col;
|
|
2110
|
+
setFrozenCols(activeSheet.frozenCols > 0 ? 0 : col);
|
|
2111
|
+
}, disabled: readOnly, children: activeSheet.frozenCols > 0 ? "Unfreeze columns" : "Freeze columns left" })
|
|
2112
|
+
] })
|
|
2113
|
+
] });
|
|
2051
2114
|
}
|
|
2052
2115
|
SpreadsheetGrid.displayName = "SpreadsheetGrid";
|
|
2053
2116
|
var btnClass = "inline-flex items-center justify-center rounded px-2 py-1 text-[12px] font-medium text-zinc-600 transition-colors hover:bg-zinc-100 disabled:opacity-40 dark:text-zinc-300 dark:hover:bg-zinc-800";
|