@geomak/ui 7.10.0 → 7.12.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 +128 -55
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -3
- package/dist/index.d.ts +13 -3
- package/dist/index.js +128 -55
- package/dist/index.js.map +1 -1
- package/dist/styles.css +12 -0
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -2745,7 +2745,13 @@ interface DataGridProps {
|
|
|
2745
2745
|
overscan?: number;
|
|
2746
2746
|
/** Show the left row-number gutter. Default true. */
|
|
2747
2747
|
rowNumbers?: boolean;
|
|
2748
|
-
/**
|
|
2748
|
+
/**
|
|
2749
|
+
* Blank rows rendered below the data, like a real spreadsheet's empty grid.
|
|
2750
|
+
* Default 0. When `editable`, typing into one emits `onCellEdit` with a
|
|
2751
|
+
* `row` index at/after `rows.length` so the consumer can append the row.
|
|
2752
|
+
*/
|
|
2753
|
+
trailingRows?: number;
|
|
2754
|
+
/** `row` is the index into `rows` (stable across sorting; may equal `rows.length`+ for a blank trailing row). */
|
|
2749
2755
|
onCellEdit?: (e: {
|
|
2750
2756
|
row: number;
|
|
2751
2757
|
column: string;
|
|
@@ -2767,7 +2773,7 @@ interface DataGridProps {
|
|
|
2767
2773
|
* `onCellEdit` on commit. Wrap it with {@link Spreadsheet} for multi-sheet
|
|
2768
2774
|
* switching, file parsing and export.
|
|
2769
2775
|
*/
|
|
2770
|
-
declare function DataGrid({ columns, rows, rowHeight, headerHeight, height, width, editable, sortable, sort: sortProp, onSortChange, virtualize, overscan, rowNumbers, onCellEdit, className, style, emptyState, }: DataGridProps): react_jsx_runtime.JSX.Element;
|
|
2776
|
+
declare function DataGrid({ columns, rows, rowHeight, headerHeight, height, width, editable, sortable, sort: sortProp, onSortChange, virtualize, overscan, rowNumbers, trailingRows, onCellEdit, className, style, emptyState, }: DataGridProps): react_jsx_runtime.JSX.Element;
|
|
2771
2777
|
|
|
2772
2778
|
interface Cell {
|
|
2773
2779
|
value: CellValue;
|
|
@@ -2799,6 +2805,10 @@ interface SpreadsheetProps {
|
|
|
2799
2805
|
virtualize?: boolean;
|
|
2800
2806
|
/** Click column headers to sort. Default true. */
|
|
2801
2807
|
sortable?: boolean;
|
|
2808
|
+
/** Blank rows kept below the data (the spreadsheet "slack"). Default 50. */
|
|
2809
|
+
emptyRows?: number;
|
|
2810
|
+
/** Show a “+” to add a blank sheet. Defaults to `editable`. */
|
|
2811
|
+
allowAddSheet?: boolean;
|
|
2802
2812
|
/** Overall height. Default 480. */
|
|
2803
2813
|
height?: number | string;
|
|
2804
2814
|
/** Overall width. Defaults to filling the container. */
|
|
@@ -2815,7 +2825,7 @@ interface SpreadsheetProps {
|
|
|
2815
2825
|
* Exports to multi-sheet `.xlsx`, `.csv` (active sheet, BOM-prefixed) or a
|
|
2816
2826
|
* paginated table `.pdf` (jsPDF, lazy).
|
|
2817
2827
|
*/
|
|
2818
|
-
declare function Spreadsheet({ source, remote, editable, onCellEdit, onChange, export: exportFormats, fileName, virtualize, sortable, height, width, className, style, }: SpreadsheetProps): react_jsx_runtime.JSX.Element;
|
|
2828
|
+
declare function Spreadsheet({ source, remote, editable, onCellEdit, onChange, export: exportFormats, fileName, virtualize, sortable, emptyRows, allowAddSheet, height, width, className, style, }: SpreadsheetProps): react_jsx_runtime.JSX.Element;
|
|
2819
2829
|
|
|
2820
2830
|
interface ThemeSwitchProps {
|
|
2821
2831
|
checked: boolean;
|
package/dist/index.d.ts
CHANGED
|
@@ -2745,7 +2745,13 @@ interface DataGridProps {
|
|
|
2745
2745
|
overscan?: number;
|
|
2746
2746
|
/** Show the left row-number gutter. Default true. */
|
|
2747
2747
|
rowNumbers?: boolean;
|
|
2748
|
-
/**
|
|
2748
|
+
/**
|
|
2749
|
+
* Blank rows rendered below the data, like a real spreadsheet's empty grid.
|
|
2750
|
+
* Default 0. When `editable`, typing into one emits `onCellEdit` with a
|
|
2751
|
+
* `row` index at/after `rows.length` so the consumer can append the row.
|
|
2752
|
+
*/
|
|
2753
|
+
trailingRows?: number;
|
|
2754
|
+
/** `row` is the index into `rows` (stable across sorting; may equal `rows.length`+ for a blank trailing row). */
|
|
2749
2755
|
onCellEdit?: (e: {
|
|
2750
2756
|
row: number;
|
|
2751
2757
|
column: string;
|
|
@@ -2767,7 +2773,7 @@ interface DataGridProps {
|
|
|
2767
2773
|
* `onCellEdit` on commit. Wrap it with {@link Spreadsheet} for multi-sheet
|
|
2768
2774
|
* switching, file parsing and export.
|
|
2769
2775
|
*/
|
|
2770
|
-
declare function DataGrid({ columns, rows, rowHeight, headerHeight, height, width, editable, sortable, sort: sortProp, onSortChange, virtualize, overscan, rowNumbers, onCellEdit, className, style, emptyState, }: DataGridProps): react_jsx_runtime.JSX.Element;
|
|
2776
|
+
declare function DataGrid({ columns, rows, rowHeight, headerHeight, height, width, editable, sortable, sort: sortProp, onSortChange, virtualize, overscan, rowNumbers, trailingRows, onCellEdit, className, style, emptyState, }: DataGridProps): react_jsx_runtime.JSX.Element;
|
|
2771
2777
|
|
|
2772
2778
|
interface Cell {
|
|
2773
2779
|
value: CellValue;
|
|
@@ -2799,6 +2805,10 @@ interface SpreadsheetProps {
|
|
|
2799
2805
|
virtualize?: boolean;
|
|
2800
2806
|
/** Click column headers to sort. Default true. */
|
|
2801
2807
|
sortable?: boolean;
|
|
2808
|
+
/** Blank rows kept below the data (the spreadsheet "slack"). Default 50. */
|
|
2809
|
+
emptyRows?: number;
|
|
2810
|
+
/** Show a “+” to add a blank sheet. Defaults to `editable`. */
|
|
2811
|
+
allowAddSheet?: boolean;
|
|
2802
2812
|
/** Overall height. Default 480. */
|
|
2803
2813
|
height?: number | string;
|
|
2804
2814
|
/** Overall width. Defaults to filling the container. */
|
|
@@ -2815,7 +2825,7 @@ interface SpreadsheetProps {
|
|
|
2815
2825
|
* Exports to multi-sheet `.xlsx`, `.csv` (active sheet, BOM-prefixed) or a
|
|
2816
2826
|
* paginated table `.pdf` (jsPDF, lazy).
|
|
2817
2827
|
*/
|
|
2818
|
-
declare function Spreadsheet({ source, remote, editable, onCellEdit, onChange, export: exportFormats, fileName, virtualize, sortable, height, width, className, style, }: SpreadsheetProps): react_jsx_runtime.JSX.Element;
|
|
2828
|
+
declare function Spreadsheet({ source, remote, editable, onCellEdit, onChange, export: exportFormats, fileName, virtualize, sortable, emptyRows, allowAddSheet, height, width, className, style, }: SpreadsheetProps): react_jsx_runtime.JSX.Element;
|
|
2819
2829
|
|
|
2820
2830
|
interface ThemeSwitchProps {
|
|
2821
2831
|
checked: boolean;
|
package/dist/index.js
CHANGED
|
@@ -6467,6 +6467,7 @@ function DataGrid({
|
|
|
6467
6467
|
virtualize = true,
|
|
6468
6468
|
overscan = 4,
|
|
6469
6469
|
rowNumbers = true,
|
|
6470
|
+
trailingRows = 0,
|
|
6470
6471
|
onCellEdit,
|
|
6471
6472
|
className = "",
|
|
6472
6473
|
style,
|
|
@@ -6503,7 +6504,9 @@ function DataGrid({
|
|
|
6503
6504
|
if (sortProp === void 0) setInternalSort(next);
|
|
6504
6505
|
onSortChange?.(next);
|
|
6505
6506
|
};
|
|
6506
|
-
const
|
|
6507
|
+
const displayRowCount = rows.length + Math.max(0, trailingRows);
|
|
6508
|
+
const totalHeight = displayRowCount * rowHeight;
|
|
6509
|
+
const rowIndexForDisp = (disp) => disp < rows.length ? order[disp] : disp;
|
|
6507
6510
|
useEffect(() => {
|
|
6508
6511
|
const el = scrollRef.current;
|
|
6509
6512
|
if (!el || typeof ResizeObserver === "undefined") return;
|
|
@@ -6515,7 +6518,7 @@ function DataGrid({
|
|
|
6515
6518
|
}, []);
|
|
6516
6519
|
const bodyH = (viewport.h || (typeof height === "number" ? height : 480)) - headerHeight;
|
|
6517
6520
|
const rowStart = virtualize ? Math.max(0, Math.floor(scroll.top / rowHeight) - overscan) : 0;
|
|
6518
|
-
const rowEnd = virtualize ? Math.min(
|
|
6521
|
+
const rowEnd = virtualize ? Math.min(displayRowCount, Math.ceil((scroll.top + bodyH) / rowHeight) + overscan) : displayRowCount;
|
|
6519
6522
|
let colStart = 0;
|
|
6520
6523
|
let colEnd = columns.length;
|
|
6521
6524
|
if (virtualize && viewport.w) {
|
|
@@ -6533,13 +6536,14 @@ function DataGrid({
|
|
|
6533
6536
|
const commit = useCallback(() => {
|
|
6534
6537
|
if (!editing) return;
|
|
6535
6538
|
const col = columns[editing.col];
|
|
6536
|
-
|
|
6539
|
+
const ri = editing.disp < rows.length ? order[editing.disp] : editing.disp;
|
|
6540
|
+
onCellEdit?.({ row: ri, column: col.key, value: draft });
|
|
6537
6541
|
setEditing(null);
|
|
6538
|
-
}, [editing, columns, draft, onCellEdit, order]);
|
|
6542
|
+
}, [editing, columns, draft, onCellEdit, order, rows.length]);
|
|
6539
6543
|
const startEdit = (disp, col) => {
|
|
6540
6544
|
const c = columns[col];
|
|
6541
6545
|
if (!(c.editable ?? editable)) return;
|
|
6542
|
-
setDraft(displayValue(rows[
|
|
6546
|
+
setDraft(displayValue(rows[rowIndexForDisp(disp)]?.[c.key] ?? ""));
|
|
6543
6547
|
setEditing({ disp, col });
|
|
6544
6548
|
};
|
|
6545
6549
|
return /* @__PURE__ */ jsxs(
|
|
@@ -6602,7 +6606,7 @@ function DataGrid({
|
|
|
6602
6606
|
`g-${disp}`
|
|
6603
6607
|
)),
|
|
6604
6608
|
visibleRows.map((disp) => {
|
|
6605
|
-
const ri =
|
|
6609
|
+
const ri = rowIndexForDisp(disp);
|
|
6606
6610
|
return visibleCols.map((ci) => {
|
|
6607
6611
|
const c = columns[ci];
|
|
6608
6612
|
const isEditing = editing?.disp === disp && editing?.col === ci;
|
|
@@ -6645,7 +6649,7 @@ function DataGrid({
|
|
|
6645
6649
|
});
|
|
6646
6650
|
})
|
|
6647
6651
|
] }),
|
|
6648
|
-
|
|
6652
|
+
displayRowCount === 0 && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center text-foreground-muted", style: { top: headerHeight }, children: emptyState })
|
|
6649
6653
|
]
|
|
6650
6654
|
}
|
|
6651
6655
|
);
|
|
@@ -6663,6 +6667,18 @@ function cellValue(v) {
|
|
|
6663
6667
|
if (v != null && typeof v === "object" && "value" in v) return v.value;
|
|
6664
6668
|
return v;
|
|
6665
6669
|
}
|
|
6670
|
+
function columnLetter(i) {
|
|
6671
|
+
let s = "";
|
|
6672
|
+
let n = i;
|
|
6673
|
+
do {
|
|
6674
|
+
s = String.fromCharCode(65 + n % 26) + s;
|
|
6675
|
+
n = Math.floor(n / 26) - 1;
|
|
6676
|
+
} while (n >= 0);
|
|
6677
|
+
return s;
|
|
6678
|
+
}
|
|
6679
|
+
function blankSheet(name, cols = 8) {
|
|
6680
|
+
return { name, columns: Array.from({ length: cols }, (_, i) => ({ key: columnLetter(i), label: columnLetter(i) })), rows: [] };
|
|
6681
|
+
}
|
|
6666
6682
|
function toPlainRows(sheet, columns) {
|
|
6667
6683
|
return sheet.rows.map((row) => {
|
|
6668
6684
|
const out = {};
|
|
@@ -6695,11 +6711,14 @@ function Spreadsheet({
|
|
|
6695
6711
|
fileName,
|
|
6696
6712
|
virtualize = true,
|
|
6697
6713
|
sortable = true,
|
|
6714
|
+
emptyRows = 50,
|
|
6715
|
+
allowAddSheet,
|
|
6698
6716
|
height = 480,
|
|
6699
6717
|
width,
|
|
6700
6718
|
className = "",
|
|
6701
6719
|
style
|
|
6702
6720
|
}) {
|
|
6721
|
+
const canAddSheet = allowAddSheet ?? editable;
|
|
6703
6722
|
const [sheets, setSheets] = useState(Array.isArray(source) ? source : null);
|
|
6704
6723
|
const [active, setActive] = useState(0);
|
|
6705
6724
|
const [status, setStatus] = useState(Array.isArray(source) ? "ready" : "loading");
|
|
@@ -6759,6 +6778,7 @@ function Spreadsheet({
|
|
|
6759
6778
|
if (!prev) return prev;
|
|
6760
6779
|
const next = prev.map((s, i) => i === active ? { ...s, rows: s.rows.map((r) => ({ ...r })) } : s);
|
|
6761
6780
|
const target = next[active];
|
|
6781
|
+
while (target.rows.length <= row) target.rows.push({});
|
|
6762
6782
|
const existing = target.rows[row]?.[column];
|
|
6763
6783
|
const prevValue = cellValue(existing);
|
|
6764
6784
|
coerced = coerceToCellType(prevValue, value);
|
|
@@ -6772,6 +6792,25 @@ function Spreadsheet({
|
|
|
6772
6792
|
});
|
|
6773
6793
|
onCellEdit?.({ sheet: sheets?.[active]?.name ?? "", row, column, value: coerced });
|
|
6774
6794
|
}, [active, onCellEdit, onChange, sheets]);
|
|
6795
|
+
const addSheet = useCallback(() => {
|
|
6796
|
+
setSheets((prev) => {
|
|
6797
|
+
const list = prev ?? [];
|
|
6798
|
+
const used = new Set(list.map((s) => s.name));
|
|
6799
|
+
let n = list.length + 1;
|
|
6800
|
+
while (used.has(`Sheet ${n}`)) n++;
|
|
6801
|
+
const next = [...list, blankSheet(`Sheet ${n}`)];
|
|
6802
|
+
setActive(next.length - 1);
|
|
6803
|
+
onChange?.(next);
|
|
6804
|
+
return next;
|
|
6805
|
+
});
|
|
6806
|
+
}, [onChange]);
|
|
6807
|
+
const deleteSheet = useCallback((index) => {
|
|
6808
|
+
if (!sheets || sheets.length <= 1) return;
|
|
6809
|
+
const next = sheets.filter((_, i) => i !== index);
|
|
6810
|
+
setSheets(next);
|
|
6811
|
+
setActive((a) => Math.max(0, Math.min(index < a ? a - 1 : a, next.length - 1)));
|
|
6812
|
+
onChange?.(next);
|
|
6813
|
+
}, [sheets, onChange]);
|
|
6775
6814
|
const baseName = useMemo(
|
|
6776
6815
|
() => (fileName || (typeof source === "object" && "name" in source ? sourceName(source) : null) || "spreadsheet").replace(/\.[^.]+$/, ""),
|
|
6777
6816
|
[fileName, source]
|
|
@@ -6858,39 +6897,21 @@ function Spreadsheet({
|
|
|
6858
6897
|
}
|
|
6859
6898
|
const formats = exportFormats || [];
|
|
6860
6899
|
const exportLabels = {
|
|
6861
|
-
xlsx: "Excel
|
|
6862
|
-
csv: "
|
|
6863
|
-
pdf: "PDF
|
|
6900
|
+
xlsx: "Export to Excel (.xlsx)",
|
|
6901
|
+
csv: "Export to CSV (.csv)",
|
|
6902
|
+
pdf: "Export to PDF (.pdf)"
|
|
6864
6903
|
};
|
|
6904
|
+
const fileItems = formats.map((fmt) => ({ key: fmt, label: exportLabels[fmt], onSelect: () => runExport(fmt) }));
|
|
6905
|
+
const sheetItems = [
|
|
6906
|
+
{ key: "insert", label: "Insert sheet", onSelect: addSheet },
|
|
6907
|
+
{ key: "delete", label: "Delete sheet", danger: true, disabled: sheets.length <= 1, separatorBefore: true, onSelect: () => deleteSheet(active) }
|
|
6908
|
+
];
|
|
6909
|
+
const showMenuBar = fileItems.length > 0 || editable;
|
|
6910
|
+
const canDeleteSheet = editable && sheets.length > 1;
|
|
6865
6911
|
return /* @__PURE__ */ jsxs("div", { className: cx("flex flex-col overflow-hidden rounded-lg border border-border bg-surface-raised", className), style: { height, width, ...style }, children: [
|
|
6866
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-shrink-0 items-center gap-
|
|
6867
|
-
/* @__PURE__ */ jsx(
|
|
6868
|
-
/* @__PURE__ */
|
|
6869
|
-
plainRows.length.toLocaleString(),
|
|
6870
|
-
" ",
|
|
6871
|
-
plainRows.length === 1 ? "row" : "rows",
|
|
6872
|
-
" \xB7 ",
|
|
6873
|
-
columns.length,
|
|
6874
|
-
" cols"
|
|
6875
|
-
] }),
|
|
6876
|
-
formats.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
6877
|
-
/* @__PURE__ */ jsx("span", { className: "h-5 w-px flex-shrink-0 bg-border", "aria-hidden": "true" }),
|
|
6878
|
-
/* @__PURE__ */ jsx(
|
|
6879
|
-
MenuButton,
|
|
6880
|
-
{
|
|
6881
|
-
label: "Export",
|
|
6882
|
-
size: "sm",
|
|
6883
|
-
variant: "outline",
|
|
6884
|
-
align: "end",
|
|
6885
|
-
icon: /* @__PURE__ */ jsx(DownloadIcon2, {}),
|
|
6886
|
-
items: formats.map((fmt) => ({
|
|
6887
|
-
key: fmt,
|
|
6888
|
-
label: exportLabels[fmt],
|
|
6889
|
-
onSelect: () => runExport(fmt)
|
|
6890
|
-
}))
|
|
6891
|
-
}
|
|
6892
|
-
)
|
|
6893
|
-
] })
|
|
6912
|
+
showMenuBar && /* @__PURE__ */ jsxs("div", { className: "flex flex-shrink-0 items-center gap-0.5 border-b border-border bg-surface px-1.5 py-1", children: [
|
|
6913
|
+
fileItems.length > 0 && /* @__PURE__ */ jsx(MenuButton, { label: "File", variant: "ghost", size: "sm", hideChevron: true, items: fileItems }),
|
|
6914
|
+
editable && /* @__PURE__ */ jsx(MenuButton, { label: "Sheet", variant: "ghost", size: "sm", hideChevron: true, items: sheetItems })
|
|
6894
6915
|
] }),
|
|
6895
6916
|
/* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1", children: /* @__PURE__ */ jsx(
|
|
6896
6917
|
DataGrid,
|
|
@@ -6900,31 +6921,83 @@ function Spreadsheet({
|
|
|
6900
6921
|
editable,
|
|
6901
6922
|
sortable,
|
|
6902
6923
|
virtualize,
|
|
6924
|
+
trailingRows: emptyRows,
|
|
6903
6925
|
onCellEdit: handleCellEdit,
|
|
6904
6926
|
height: "100%",
|
|
6905
6927
|
className: "!rounded-none !border-0"
|
|
6906
6928
|
},
|
|
6907
6929
|
active
|
|
6908
6930
|
) }),
|
|
6909
|
-
|
|
6910
|
-
"
|
|
6911
|
-
|
|
6912
|
-
|
|
6913
|
-
|
|
6914
|
-
|
|
6915
|
-
|
|
6916
|
-
|
|
6917
|
-
|
|
6918
|
-
|
|
6919
|
-
|
|
6920
|
-
|
|
6921
|
-
|
|
6922
|
-
|
|
6923
|
-
|
|
6924
|
-
|
|
6931
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-shrink-0 items-center gap-2 border-t border-border bg-surface px-2 py-1", children: [
|
|
6932
|
+
/* @__PURE__ */ jsxs("div", { role: "tablist", "aria-label": "Sheets", className: "flex min-w-0 flex-1 items-center gap-1 overflow-x-auto", children: [
|
|
6933
|
+
sheets.map((s, i) => {
|
|
6934
|
+
const activeTab = i === active;
|
|
6935
|
+
const name = s.name || `Sheet ${i + 1}`;
|
|
6936
|
+
return /* @__PURE__ */ jsxs(
|
|
6937
|
+
"div",
|
|
6938
|
+
{
|
|
6939
|
+
role: "tab",
|
|
6940
|
+
tabIndex: 0,
|
|
6941
|
+
"aria-selected": activeTab,
|
|
6942
|
+
onClick: () => setActive(i),
|
|
6943
|
+
onKeyDown: (e) => {
|
|
6944
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
6945
|
+
e.preventDefault();
|
|
6946
|
+
setActive(i);
|
|
6947
|
+
}
|
|
6948
|
+
},
|
|
6949
|
+
className: cx(
|
|
6950
|
+
"group flex flex-shrink-0 cursor-pointer items-center gap-1 rounded-t-md border-t-2 px-3 py-1 text-xs transition-colors",
|
|
6951
|
+
"focus:outline-none focus-visible:ring-2 focus-visible:ring-accent",
|
|
6952
|
+
activeTab ? "border-t-accent bg-surface-raised font-semibold text-foreground shadow-sm" : "border-t-transparent font-medium text-foreground-secondary hover:bg-surface-raised hover:text-foreground"
|
|
6953
|
+
),
|
|
6954
|
+
children: [
|
|
6955
|
+
/* @__PURE__ */ jsx("span", { className: "max-w-[160px] truncate", children: name }),
|
|
6956
|
+
canDeleteSheet && /* @__PURE__ */ jsx(
|
|
6957
|
+
"button",
|
|
6958
|
+
{
|
|
6959
|
+
type: "button",
|
|
6960
|
+
title: "Delete sheet",
|
|
6961
|
+
"aria-label": `Delete ${name}`,
|
|
6962
|
+
onClick: (e) => {
|
|
6963
|
+
e.stopPropagation();
|
|
6964
|
+
deleteSheet(i);
|
|
6965
|
+
},
|
|
6966
|
+
className: cx(
|
|
6967
|
+
"flex h-4 w-4 items-center justify-center rounded text-foreground-muted transition-opacity hover:text-status-error",
|
|
6968
|
+
activeTab ? "opacity-100" : "opacity-0 group-hover:opacity-100"
|
|
6969
|
+
),
|
|
6970
|
+
children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2.5, className: "h-3 w-3", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", d: "M6 6l12 12M18 6 6 18" }) })
|
|
6971
|
+
}
|
|
6972
|
+
)
|
|
6973
|
+
]
|
|
6974
|
+
},
|
|
6975
|
+
`${s.name}-${i}`
|
|
6976
|
+
);
|
|
6977
|
+
}),
|
|
6978
|
+
canAddSheet && /* @__PURE__ */ jsx(
|
|
6979
|
+
"button",
|
|
6980
|
+
{
|
|
6981
|
+
type: "button",
|
|
6982
|
+
onClick: addSheet,
|
|
6983
|
+
title: "Add sheet",
|
|
6984
|
+
"aria-label": "Add sheet",
|
|
6985
|
+
className: "flex h-6 w-6 flex-shrink-0 items-center justify-center rounded-md text-foreground-muted transition-colors hover:bg-surface-raised hover:text-foreground focus:outline-none focus-visible:ring-2 focus-visible:ring-accent",
|
|
6986
|
+
children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "h-4 w-4", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", d: "M12 5v14M5 12h14" }) })
|
|
6987
|
+
}
|
|
6988
|
+
)
|
|
6989
|
+
] }),
|
|
6990
|
+
/* @__PURE__ */ jsxs("span", { className: "hidden flex-shrink-0 text-xs tabular-nums text-foreground-muted sm:inline", children: [
|
|
6991
|
+
plainRows.length.toLocaleString(),
|
|
6992
|
+
" ",
|
|
6993
|
+
plainRows.length === 1 ? "row" : "rows",
|
|
6994
|
+
" \xB7 ",
|
|
6995
|
+
columns.length,
|
|
6996
|
+
" cols"
|
|
6997
|
+
] })
|
|
6998
|
+
] })
|
|
6925
6999
|
] });
|
|
6926
7000
|
}
|
|
6927
|
-
var DownloadIcon2 = () => /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "h-4 w-4", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 3v12m0 0 4-4m-4 4-4-4M4 21h16" }) });
|
|
6928
7001
|
function ThemeSwitch({ checked, onChange, label = "Toggle dark mode", className = "" }) {
|
|
6929
7002
|
const id = useId();
|
|
6930
7003
|
return /* @__PURE__ */ jsx("label", { htmlFor: id, className: `flex items-center gap-2 cursor-pointer select-none ${className}`.trim(), children: /* @__PURE__ */ jsx(
|