@geomak/ui 7.11.0 → 7.13.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 +398 -214
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.js +397 -213
- package/dist/index.js.map +1 -1
- package/dist/styles.css +6 -0
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -6,7 +6,7 @@ var React36 = require('react');
|
|
|
6
6
|
var reactDom = require('react-dom');
|
|
7
7
|
var jsxRuntime = require('react/jsx-runtime');
|
|
8
8
|
var AvatarPrimitive = require('@radix-ui/react-avatar');
|
|
9
|
-
var
|
|
9
|
+
var DropdownMenu = require('@radix-ui/react-dropdown-menu');
|
|
10
10
|
var Dialog = require('@radix-ui/react-dialog');
|
|
11
11
|
var framerMotion = require('framer-motion');
|
|
12
12
|
var TooltipPrimitive = require('@radix-ui/react-tooltip');
|
|
@@ -43,7 +43,7 @@ function _interopNamespace(e) {
|
|
|
43
43
|
|
|
44
44
|
var React36__default = /*#__PURE__*/_interopDefault(React36);
|
|
45
45
|
var AvatarPrimitive__namespace = /*#__PURE__*/_interopNamespace(AvatarPrimitive);
|
|
46
|
-
var
|
|
46
|
+
var DropdownMenu__namespace = /*#__PURE__*/_interopNamespace(DropdownMenu);
|
|
47
47
|
var Dialog__namespace = /*#__PURE__*/_interopNamespace(Dialog);
|
|
48
48
|
var TooltipPrimitive__namespace = /*#__PURE__*/_interopNamespace(TooltipPrimitive);
|
|
49
49
|
var TabsPrimitive__namespace = /*#__PURE__*/_interopNamespace(TabsPrimitive);
|
|
@@ -667,6 +667,39 @@ var Chevron = () => /* @__PURE__ */ jsxRuntime.jsx(
|
|
|
667
667
|
children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 9l6 6 6-6" })
|
|
668
668
|
}
|
|
669
669
|
);
|
|
670
|
+
var ChevronRight = () => /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, "aria-hidden": "true", className: "ml-auto h-4 w-4", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9 5l7 7-7 7" }) });
|
|
671
|
+
var ITEM_CLASS = [
|
|
672
|
+
"flex items-center gap-2.5 rounded-md px-2.5 py-1.5 text-sm outline-none cursor-pointer select-none transition-colors",
|
|
673
|
+
"data-[disabled]:opacity-50 data-[disabled]:pointer-events-none"
|
|
674
|
+
].join(" ");
|
|
675
|
+
var itemTone = (danger) => danger ? "text-status-error data-[highlighted]:bg-status-error/10" : "text-foreground data-[highlighted]:bg-surface-raised";
|
|
676
|
+
var Label = ({ item }) => /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
677
|
+
item.icon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-4 w-4 flex-shrink-0 items-center justify-center", children: item.icon }),
|
|
678
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 truncate", children: item.label })
|
|
679
|
+
] });
|
|
680
|
+
function renderItem(item) {
|
|
681
|
+
if (item.children && item.children.length > 0) {
|
|
682
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenu__namespace.Sub, { children: [
|
|
683
|
+
/* @__PURE__ */ jsxRuntime.jsxs(DropdownMenu__namespace.SubTrigger, { disabled: item.disabled, className: `${ITEM_CLASS} ${itemTone(item.danger)}`, children: [
|
|
684
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { item }),
|
|
685
|
+
/* @__PURE__ */ jsxRuntime.jsx(ChevronRight, {})
|
|
686
|
+
] }),
|
|
687
|
+
/* @__PURE__ */ jsxRuntime.jsx(DropdownMenu__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
688
|
+
DropdownMenu__namespace.SubContent,
|
|
689
|
+
{
|
|
690
|
+
sideOffset: 4,
|
|
691
|
+
collisionPadding: 8,
|
|
692
|
+
className: "z-[400] min-w-[10rem] rounded-lg border border-border bg-surface p-1 shadow-lg data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
|
|
693
|
+
children: item.children.map((sub) => /* @__PURE__ */ jsxRuntime.jsxs(React36__default.default.Fragment, { children: [
|
|
694
|
+
sub.separatorBefore && /* @__PURE__ */ jsxRuntime.jsx(DropdownMenu__namespace.Separator, { className: "my-1 h-px bg-border" }),
|
|
695
|
+
renderItem(sub)
|
|
696
|
+
] }, sub.key))
|
|
697
|
+
}
|
|
698
|
+
) })
|
|
699
|
+
] });
|
|
700
|
+
}
|
|
701
|
+
return /* @__PURE__ */ jsxRuntime.jsx(DropdownMenu__namespace.Item, { disabled: item.disabled, onSelect: () => item.onSelect?.(), className: `${ITEM_CLASS} ${itemTone(item.danger)}`, children: /* @__PURE__ */ jsxRuntime.jsx(Label, { item }) });
|
|
702
|
+
}
|
|
670
703
|
function MenuButton({
|
|
671
704
|
label,
|
|
672
705
|
items,
|
|
@@ -679,8 +712,8 @@ function MenuButton({
|
|
|
679
712
|
side = "bottom",
|
|
680
713
|
className = ""
|
|
681
714
|
}) {
|
|
682
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
683
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
715
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenu__namespace.Root, { children: [
|
|
716
|
+
/* @__PURE__ */ jsxRuntime.jsx(DropdownMenu__namespace.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
684
717
|
Button_default,
|
|
685
718
|
{
|
|
686
719
|
variant,
|
|
@@ -694,8 +727,8 @@ function MenuButton({
|
|
|
694
727
|
] })
|
|
695
728
|
}
|
|
696
729
|
) }),
|
|
697
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
698
|
-
|
|
730
|
+
/* @__PURE__ */ jsxRuntime.jsx(DropdownMenu__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
731
|
+
DropdownMenu__namespace.Content,
|
|
699
732
|
{
|
|
700
733
|
align,
|
|
701
734
|
side,
|
|
@@ -707,23 +740,8 @@ function MenuButton({
|
|
|
707
740
|
"data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95"
|
|
708
741
|
].join(" "),
|
|
709
742
|
children: items.map((item) => /* @__PURE__ */ jsxRuntime.jsxs(React36__default.default.Fragment, { children: [
|
|
710
|
-
item.separatorBefore && /* @__PURE__ */ jsxRuntime.jsx(
|
|
711
|
-
|
|
712
|
-
DropdownMenu2__namespace.Item,
|
|
713
|
-
{
|
|
714
|
-
disabled: item.disabled,
|
|
715
|
-
onSelect: () => item.onSelect?.(),
|
|
716
|
-
className: [
|
|
717
|
-
"flex items-center gap-2.5 rounded-md px-2.5 py-1.5 text-sm outline-none cursor-pointer select-none transition-colors",
|
|
718
|
-
"data-[disabled]:opacity-50 data-[disabled]:pointer-events-none",
|
|
719
|
-
item.danger ? "text-status-error data-[highlighted]:bg-status-error/10" : "text-foreground data-[highlighted]:bg-surface-raised"
|
|
720
|
-
].join(" "),
|
|
721
|
-
children: [
|
|
722
|
-
item.icon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-4 w-4 flex-shrink-0 items-center justify-center", children: item.icon }),
|
|
723
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 truncate", children: item.label })
|
|
724
|
-
]
|
|
725
|
-
}
|
|
726
|
-
)
|
|
743
|
+
item.separatorBefore && /* @__PURE__ */ jsxRuntime.jsx(DropdownMenu__namespace.Separator, { className: "my-1 h-px bg-border" }),
|
|
744
|
+
renderItem(item)
|
|
727
745
|
] }, item.key))
|
|
728
746
|
}
|
|
729
747
|
) })
|
|
@@ -1765,7 +1783,7 @@ function Stepper({
|
|
|
1765
1783
|
const vertical = orientation === "vertical" || forcedVertical;
|
|
1766
1784
|
const s = SIZES[size];
|
|
1767
1785
|
const stateOf = (i) => i < current ? "completed" : i === current ? status : "pending";
|
|
1768
|
-
const
|
|
1786
|
+
const Label3 = ({ step, state, align }) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: align === "center" ? "mt-2 text-center" : "pt-0.5", children: [
|
|
1769
1787
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: `font-medium leading-tight ${s.title} ${state === "pending" ? "text-foreground-muted" : "text-foreground"}`, children: step.title }),
|
|
1770
1788
|
step.description && /* @__PURE__ */ jsxRuntime.jsx("div", { className: `mt-0.5 leading-snug text-foreground-muted ${s.desc}`, children: step.description })
|
|
1771
1789
|
] });
|
|
@@ -1780,7 +1798,7 @@ function Stepper({
|
|
|
1780
1798
|
stepButton(i, /* @__PURE__ */ jsxRuntime.jsx(Indicator, { state, index: i, step, sizeKey: size })),
|
|
1781
1799
|
!last && /* @__PURE__ */ jsxRuntime.jsx(VConnector, { filled: i < current, reduced })
|
|
1782
1800
|
] }),
|
|
1783
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: last ? "" : "pb-6", children: stepButton(i, /* @__PURE__ */ jsxRuntime.jsx(
|
|
1801
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: last ? "" : "pb-6", children: stepButton(i, /* @__PURE__ */ jsxRuntime.jsx(Label3, { step, state, align: "left" })) })
|
|
1784
1802
|
] }, step.key);
|
|
1785
1803
|
}) });
|
|
1786
1804
|
}
|
|
@@ -1799,7 +1817,7 @@ function Stepper({
|
|
|
1799
1817
|
) }),
|
|
1800
1818
|
stepButton(i, /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center", children: [
|
|
1801
1819
|
/* @__PURE__ */ jsxRuntime.jsx(Indicator, { state, index: i, step, sizeKey: size }),
|
|
1802
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1820
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label3, { step, state, align: "center" })
|
|
1803
1821
|
] }))
|
|
1804
1822
|
] }, step.key);
|
|
1805
1823
|
}) });
|
|
@@ -4965,7 +4983,7 @@ function ContextMenu({ items, children, className = "" }) {
|
|
|
4965
4983
|
{
|
|
4966
4984
|
className: `${CONTENT_CLASSNAME} ${className}`.trim(),
|
|
4967
4985
|
collisionPadding: 8,
|
|
4968
|
-
children: items.map((item) =>
|
|
4986
|
+
children: items.map((item) => renderItem2(item))
|
|
4969
4987
|
}
|
|
4970
4988
|
) })
|
|
4971
4989
|
] });
|
|
@@ -4987,7 +5005,7 @@ var ITEM_CLASSNAME = [
|
|
|
4987
5005
|
"data-[disabled]:opacity-40 data-[disabled]:cursor-not-allowed data-[disabled]:bg-transparent data-[disabled]:text-foreground-muted",
|
|
4988
5006
|
"focus:outline-none"
|
|
4989
5007
|
].join(" ");
|
|
4990
|
-
function
|
|
5008
|
+
function renderItem2(item) {
|
|
4991
5009
|
if (item.children && item.children.length > 0) {
|
|
4992
5010
|
return /* @__PURE__ */ jsxRuntime.jsxs(ContextMenuPrimitive__namespace.Sub, { children: [
|
|
4993
5011
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -4997,7 +5015,7 @@ function renderItem(item) {
|
|
|
4997
5015
|
className: ITEM_CLASSNAME,
|
|
4998
5016
|
children: [
|
|
4999
5017
|
/* @__PURE__ */ jsxRuntime.jsx(ContextMenuLabel, { icon: item.icon, value: item.value }),
|
|
5000
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5018
|
+
/* @__PURE__ */ jsxRuntime.jsx(ChevronRight2, {})
|
|
5001
5019
|
]
|
|
5002
5020
|
}
|
|
5003
5021
|
),
|
|
@@ -5008,7 +5026,7 @@ function renderItem(item) {
|
|
|
5008
5026
|
sideOffset: 2,
|
|
5009
5027
|
alignOffset: -4,
|
|
5010
5028
|
collisionPadding: 8,
|
|
5011
|
-
children: item.children.map((sub) =>
|
|
5029
|
+
children: item.children.map((sub) => renderItem2(sub))
|
|
5012
5030
|
}
|
|
5013
5031
|
) })
|
|
5014
5032
|
] }, item.key);
|
|
@@ -5030,7 +5048,7 @@ function ContextMenuLabel({ icon, value }) {
|
|
|
5030
5048
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: value })
|
|
5031
5049
|
] });
|
|
5032
5050
|
}
|
|
5033
|
-
function
|
|
5051
|
+
function ChevronRight2() {
|
|
5034
5052
|
return /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "h-4 w-4 flex-shrink-0", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9 5l7 7-7 7" }) });
|
|
5035
5053
|
}
|
|
5036
5054
|
function readDismissed(key) {
|
|
@@ -5883,7 +5901,7 @@ var useIsoLayoutEffect = typeof window !== "undefined" ? React36.useLayoutEffect
|
|
|
5883
5901
|
function VirtualList({
|
|
5884
5902
|
items,
|
|
5885
5903
|
rowHeight,
|
|
5886
|
-
renderItem:
|
|
5904
|
+
renderItem: renderItem3,
|
|
5887
5905
|
height = 400,
|
|
5888
5906
|
getKey,
|
|
5889
5907
|
overscan = 6,
|
|
@@ -5948,7 +5966,7 @@ function VirtualList({
|
|
|
5948
5966
|
role: "listitem",
|
|
5949
5967
|
style: { height: rowHeight },
|
|
5950
5968
|
className: "box-border",
|
|
5951
|
-
children:
|
|
5969
|
+
children: renderItem3(item, index)
|
|
5952
5970
|
},
|
|
5953
5971
|
getKey ? getKey(item, index) : index
|
|
5954
5972
|
);
|
|
@@ -6505,6 +6523,9 @@ function DataGrid({
|
|
|
6505
6523
|
rowNumbers = true,
|
|
6506
6524
|
trailingRows = 0,
|
|
6507
6525
|
onCellEdit,
|
|
6526
|
+
contextMenu = false,
|
|
6527
|
+
onInsertRow,
|
|
6528
|
+
onDeleteRow,
|
|
6508
6529
|
className = "",
|
|
6509
6530
|
style,
|
|
6510
6531
|
emptyState = "No data"
|
|
@@ -6512,6 +6533,9 @@ function DataGrid({
|
|
|
6512
6533
|
const scrollRef = React36.useRef(null);
|
|
6513
6534
|
const [scroll, setScroll] = React36.useState({ top: 0, left: 0 });
|
|
6514
6535
|
const [viewport, setViewport] = React36.useState({ w: 0, h: 0 });
|
|
6536
|
+
const [selected, setSelected] = React36.useState(null);
|
|
6537
|
+
const [hoveredRow, setHoveredRow] = React36.useState(null);
|
|
6538
|
+
const [ctxTarget, setCtxTarget] = React36.useState(null);
|
|
6515
6539
|
const [editing, setEditing] = React36.useState(null);
|
|
6516
6540
|
const [draft, setDraft] = React36.useState("");
|
|
6517
6541
|
const [internalSort, setInternalSort] = React36.useState(null);
|
|
@@ -6582,114 +6606,179 @@ function DataGrid({
|
|
|
6582
6606
|
setDraft(displayValue(rows[rowIndexForDisp(disp)]?.[c.key] ?? ""));
|
|
6583
6607
|
setEditing({ disp, col });
|
|
6584
6608
|
};
|
|
6609
|
+
const cellText = (sel) => displayValue(rows[rowIndexForDisp(sel.disp)]?.[columns[sel.col].key] ?? "");
|
|
6610
|
+
const copyCell = React36.useCallback(async () => {
|
|
6611
|
+
if (!selected) return;
|
|
6612
|
+
try {
|
|
6613
|
+
await navigator.clipboard?.writeText(cellText(selected));
|
|
6614
|
+
} catch {
|
|
6615
|
+
}
|
|
6616
|
+
}, [selected, rows, columns, order]);
|
|
6617
|
+
const cutCell = React36.useCallback(async () => {
|
|
6618
|
+
if (!selected) return;
|
|
6619
|
+
await copyCell();
|
|
6620
|
+
onCellEdit?.({ row: rowIndexForDisp(selected.disp), column: columns[selected.col].key, value: "" });
|
|
6621
|
+
}, [selected, copyCell, onCellEdit, columns, order, rows.length]);
|
|
6622
|
+
const pasteCell = React36.useCallback(async () => {
|
|
6623
|
+
if (!selected) return;
|
|
6624
|
+
let text = "";
|
|
6625
|
+
try {
|
|
6626
|
+
text = await navigator.clipboard?.readText() ?? "";
|
|
6627
|
+
} catch {
|
|
6628
|
+
return;
|
|
6629
|
+
}
|
|
6630
|
+
onCellEdit?.({ row: rowIndexForDisp(selected.disp), column: columns[selected.col].key, value: text });
|
|
6631
|
+
}, [selected, onCellEdit, columns, order, rows.length]);
|
|
6632
|
+
const ctxItems = React36.useMemo(() => {
|
|
6633
|
+
if (ctxTarget?.kind === "row") {
|
|
6634
|
+
const ri = rowIndexForDisp(ctxTarget.disp);
|
|
6635
|
+
const isData = ctxTarget.disp < rows.length;
|
|
6636
|
+
return [
|
|
6637
|
+
{ key: "above", value: "Add row above", disabled: !onInsertRow, onClick: () => onInsertRow?.(ri) },
|
|
6638
|
+
{ key: "below", value: "Add row below", disabled: !onInsertRow, onClick: () => onInsertRow?.(Math.min(rows.length, ri + 1)) },
|
|
6639
|
+
{ key: "delete", value: "Delete row", disabled: !isData || !onDeleteRow, onClick: () => onDeleteRow?.(ri) }
|
|
6640
|
+
];
|
|
6641
|
+
}
|
|
6642
|
+
return [
|
|
6643
|
+
{ key: "copy", value: "Copy", onClick: () => void copyCell() },
|
|
6644
|
+
{ key: "cut", value: "Cut", disabled: !editable, onClick: () => void cutCell() },
|
|
6645
|
+
{ key: "paste", value: "Paste", disabled: !editable, onClick: () => void pasteCell() }
|
|
6646
|
+
];
|
|
6647
|
+
}, [ctxTarget, rows.length, editable, onInsertRow, onDeleteRow, copyCell, cutCell, pasteCell, order]);
|
|
6648
|
+
const rowHighlighted = (disp) => hoveredRow === disp || selected?.disp === disp;
|
|
6649
|
+
const gridInner = /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { position: "relative", width: gutter + totalWidth + END_PAD, height: headerHeight + totalHeight + END_PAD }, children: [
|
|
6650
|
+
rowNumbers && /* @__PURE__ */ jsxRuntime.jsx(
|
|
6651
|
+
"div",
|
|
6652
|
+
{
|
|
6653
|
+
className: "border-b border-r border-border bg-surface",
|
|
6654
|
+
style: { position: "absolute", top: scroll.top, left: scroll.left, width: gutter, height: headerHeight, zIndex: 3 }
|
|
6655
|
+
}
|
|
6656
|
+
),
|
|
6657
|
+
visibleCols.map((ci) => {
|
|
6658
|
+
const c = columns[ci];
|
|
6659
|
+
const sortDir = sort?.key === c.key ? sort.dir : null;
|
|
6660
|
+
const canSort = colSortable(c);
|
|
6661
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6662
|
+
"div",
|
|
6663
|
+
{
|
|
6664
|
+
role: "columnheader",
|
|
6665
|
+
"aria-sort": sortDir ? sortDir === "asc" ? "ascending" : "descending" : void 0,
|
|
6666
|
+
onClick: canSort ? () => toggleSort(c.key) : void 0,
|
|
6667
|
+
className: cx(
|
|
6668
|
+
"flex items-center gap-1 border-b border-r border-border bg-surface px-3 font-medium text-foreground-secondary",
|
|
6669
|
+
canSort && "cursor-pointer select-none hover:text-foreground"
|
|
6670
|
+
),
|
|
6671
|
+
style: {
|
|
6672
|
+
position: "absolute",
|
|
6673
|
+
top: scroll.top,
|
|
6674
|
+
left: gutter + offsets[ci],
|
|
6675
|
+
width: widths[ci],
|
|
6676
|
+
height: headerHeight,
|
|
6677
|
+
zIndex: 2,
|
|
6678
|
+
justifyContent: c.align === "right" ? "flex-end" : c.align === "center" ? "center" : "flex-start"
|
|
6679
|
+
},
|
|
6680
|
+
children: [
|
|
6681
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: c.label ?? c.key }),
|
|
6682
|
+
canSort && /* @__PURE__ */ jsxRuntime.jsx(SortCaret, { dir: sortDir })
|
|
6683
|
+
]
|
|
6684
|
+
},
|
|
6685
|
+
`h-${c.key}`
|
|
6686
|
+
);
|
|
6687
|
+
}),
|
|
6688
|
+
rowNumbers && visibleRows.map((disp) => {
|
|
6689
|
+
const hi = rowHighlighted(disp);
|
|
6690
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
6691
|
+
"div",
|
|
6692
|
+
{
|
|
6693
|
+
onMouseEnter: () => setHoveredRow(disp),
|
|
6694
|
+
onContextMenu: contextMenu ? () => setCtxTarget({ kind: "row", disp }) : void 0,
|
|
6695
|
+
className: cx(
|
|
6696
|
+
"flex items-center justify-center border-b border-r border-border bg-surface text-xs tabular-nums",
|
|
6697
|
+
hi ? "font-medium text-foreground" : "text-foreground-muted"
|
|
6698
|
+
),
|
|
6699
|
+
style: { position: "absolute", left: scroll.left, top: headerHeight + disp * rowHeight, width: gutter, height: rowHeight, zIndex: 1, backgroundColor: hi ? HILITE : void 0 },
|
|
6700
|
+
children: disp + 1
|
|
6701
|
+
},
|
|
6702
|
+
`g-${disp}`
|
|
6703
|
+
);
|
|
6704
|
+
}),
|
|
6705
|
+
visibleRows.map((disp) => {
|
|
6706
|
+
const ri = rowIndexForDisp(disp);
|
|
6707
|
+
const hi = rowHighlighted(disp);
|
|
6708
|
+
return visibleCols.map((ci) => {
|
|
6709
|
+
const c = columns[ci];
|
|
6710
|
+
const isEditing = editing?.disp === disp && editing?.col === ci;
|
|
6711
|
+
const isSelected = selected?.disp === disp && selected?.col === ci;
|
|
6712
|
+
const canEdit = c.editable ?? editable;
|
|
6713
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
6714
|
+
"div",
|
|
6715
|
+
{
|
|
6716
|
+
role: "gridcell",
|
|
6717
|
+
"aria-selected": isSelected || void 0,
|
|
6718
|
+
onClick: () => setSelected({ disp, col: ci }),
|
|
6719
|
+
onDoubleClick: () => startEdit(disp, ci),
|
|
6720
|
+
onMouseEnter: () => setHoveredRow(disp),
|
|
6721
|
+
onContextMenu: contextMenu ? () => {
|
|
6722
|
+
setSelected({ disp, col: ci });
|
|
6723
|
+
setCtxTarget({ kind: "cell", disp });
|
|
6724
|
+
} : void 0,
|
|
6725
|
+
className: cx(
|
|
6726
|
+
"flex items-center border-b border-r border-border px-3",
|
|
6727
|
+
disp % 2 ? "bg-surface-raised" : "bg-surface",
|
|
6728
|
+
canEdit ? "cursor-text" : "cursor-default"
|
|
6729
|
+
),
|
|
6730
|
+
style: {
|
|
6731
|
+
position: "absolute",
|
|
6732
|
+
top: headerHeight + disp * rowHeight,
|
|
6733
|
+
left: gutter + offsets[ci],
|
|
6734
|
+
width: widths[ci],
|
|
6735
|
+
height: rowHeight,
|
|
6736
|
+
zIndex: isSelected ? 1 : void 0,
|
|
6737
|
+
backgroundColor: isSelected ? SELECT_BG : hi ? HILITE : void 0,
|
|
6738
|
+
boxShadow: isSelected ? SELECT_RING : void 0,
|
|
6739
|
+
justifyContent: c.align === "right" ? "flex-end" : c.align === "center" ? "center" : "flex-start"
|
|
6740
|
+
},
|
|
6741
|
+
children: isEditing ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
6742
|
+
"input",
|
|
6743
|
+
{
|
|
6744
|
+
autoFocus: true,
|
|
6745
|
+
value: draft,
|
|
6746
|
+
onChange: (e) => setDraft(e.target.value),
|
|
6747
|
+
onBlur: commit,
|
|
6748
|
+
onKeyDown: (e) => {
|
|
6749
|
+
if (e.key === "Enter") commit();
|
|
6750
|
+
else if (e.key === "Escape") setEditing(null);
|
|
6751
|
+
},
|
|
6752
|
+
className: "h-full w-full bg-transparent text-foreground outline-none"
|
|
6753
|
+
}
|
|
6754
|
+
) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-foreground", children: displayValue(rows[ri]?.[c.key] ?? "") })
|
|
6755
|
+
},
|
|
6756
|
+
`${disp}-${c.key}`
|
|
6757
|
+
);
|
|
6758
|
+
});
|
|
6759
|
+
})
|
|
6760
|
+
] });
|
|
6585
6761
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6586
6762
|
"div",
|
|
6587
6763
|
{
|
|
6588
6764
|
ref: scrollRef,
|
|
6589
6765
|
onScroll: (e) => setScroll({ top: e.currentTarget.scrollTop, left: e.currentTarget.scrollLeft }),
|
|
6766
|
+
onMouseLeave: () => setHoveredRow(null),
|
|
6590
6767
|
className: cx("relative overflow-auto rounded-lg border border-border bg-surface-raised text-sm", className),
|
|
6591
6768
|
style: { height, width, ...style },
|
|
6592
6769
|
role: "grid",
|
|
6593
6770
|
"aria-rowcount": rows.length,
|
|
6594
6771
|
"aria-colcount": columns.length,
|
|
6595
6772
|
children: [
|
|
6596
|
-
/* @__PURE__ */ jsxRuntime.
|
|
6597
|
-
rowNumbers && /* @__PURE__ */ jsxRuntime.jsx(
|
|
6598
|
-
"div",
|
|
6599
|
-
{
|
|
6600
|
-
className: "border-b border-r border-border bg-surface",
|
|
6601
|
-
style: { position: "absolute", top: scroll.top, left: scroll.left, width: gutter, height: headerHeight, zIndex: 3 }
|
|
6602
|
-
}
|
|
6603
|
-
),
|
|
6604
|
-
visibleCols.map((ci) => {
|
|
6605
|
-
const c = columns[ci];
|
|
6606
|
-
const sortDir = sort?.key === c.key ? sort.dir : null;
|
|
6607
|
-
const canSort = colSortable(c);
|
|
6608
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
6609
|
-
"div",
|
|
6610
|
-
{
|
|
6611
|
-
role: "columnheader",
|
|
6612
|
-
"aria-sort": sortDir ? sortDir === "asc" ? "ascending" : "descending" : void 0,
|
|
6613
|
-
onClick: canSort ? () => toggleSort(c.key) : void 0,
|
|
6614
|
-
className: cx(
|
|
6615
|
-
"flex items-center gap-1 border-b border-r border-border bg-surface px-3 font-medium text-foreground-secondary",
|
|
6616
|
-
canSort && "cursor-pointer select-none hover:text-foreground"
|
|
6617
|
-
),
|
|
6618
|
-
style: {
|
|
6619
|
-
position: "absolute",
|
|
6620
|
-
top: scroll.top,
|
|
6621
|
-
left: gutter + offsets[ci],
|
|
6622
|
-
width: widths[ci],
|
|
6623
|
-
height: headerHeight,
|
|
6624
|
-
zIndex: 2,
|
|
6625
|
-
justifyContent: c.align === "right" ? "flex-end" : c.align === "center" ? "center" : "flex-start"
|
|
6626
|
-
},
|
|
6627
|
-
children: [
|
|
6628
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: c.label ?? c.key }),
|
|
6629
|
-
canSort && /* @__PURE__ */ jsxRuntime.jsx(SortCaret, { dir: sortDir })
|
|
6630
|
-
]
|
|
6631
|
-
},
|
|
6632
|
-
`h-${c.key}`
|
|
6633
|
-
);
|
|
6634
|
-
}),
|
|
6635
|
-
rowNumbers && visibleRows.map((disp) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
6636
|
-
"div",
|
|
6637
|
-
{
|
|
6638
|
-
className: "flex items-center justify-center border-b border-r border-border bg-surface text-xs tabular-nums text-foreground-muted",
|
|
6639
|
-
style: { position: "absolute", left: scroll.left, top: headerHeight + disp * rowHeight, width: gutter, height: rowHeight, zIndex: 1 },
|
|
6640
|
-
children: disp + 1
|
|
6641
|
-
},
|
|
6642
|
-
`g-${disp}`
|
|
6643
|
-
)),
|
|
6644
|
-
visibleRows.map((disp) => {
|
|
6645
|
-
const ri = rowIndexForDisp(disp);
|
|
6646
|
-
return visibleCols.map((ci) => {
|
|
6647
|
-
const c = columns[ci];
|
|
6648
|
-
const isEditing = editing?.disp === disp && editing?.col === ci;
|
|
6649
|
-
const canEdit = c.editable ?? editable;
|
|
6650
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
6651
|
-
"div",
|
|
6652
|
-
{
|
|
6653
|
-
role: "gridcell",
|
|
6654
|
-
onDoubleClick: () => startEdit(disp, ci),
|
|
6655
|
-
className: cx(
|
|
6656
|
-
"flex items-center border-b border-r border-border px-3",
|
|
6657
|
-
disp % 2 ? "bg-surface-raised" : "bg-surface",
|
|
6658
|
-
canEdit && "cursor-text"
|
|
6659
|
-
),
|
|
6660
|
-
style: {
|
|
6661
|
-
position: "absolute",
|
|
6662
|
-
top: headerHeight + disp * rowHeight,
|
|
6663
|
-
left: gutter + offsets[ci],
|
|
6664
|
-
width: widths[ci],
|
|
6665
|
-
height: rowHeight,
|
|
6666
|
-
justifyContent: c.align === "right" ? "flex-end" : c.align === "center" ? "center" : "flex-start"
|
|
6667
|
-
},
|
|
6668
|
-
children: isEditing ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
6669
|
-
"input",
|
|
6670
|
-
{
|
|
6671
|
-
autoFocus: true,
|
|
6672
|
-
value: draft,
|
|
6673
|
-
onChange: (e) => setDraft(e.target.value),
|
|
6674
|
-
onBlur: commit,
|
|
6675
|
-
onKeyDown: (e) => {
|
|
6676
|
-
if (e.key === "Enter") commit();
|
|
6677
|
-
else if (e.key === "Escape") setEditing(null);
|
|
6678
|
-
},
|
|
6679
|
-
className: "h-full w-full bg-transparent text-foreground outline-none"
|
|
6680
|
-
}
|
|
6681
|
-
) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-foreground", children: displayValue(rows[ri]?.[c.key] ?? "") })
|
|
6682
|
-
},
|
|
6683
|
-
`${disp}-${c.key}`
|
|
6684
|
-
);
|
|
6685
|
-
});
|
|
6686
|
-
})
|
|
6687
|
-
] }),
|
|
6773
|
+
contextMenu ? /* @__PURE__ */ jsxRuntime.jsx(ContextMenu, { items: ctxItems, children: gridInner }) : gridInner,
|
|
6688
6774
|
displayRowCount === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 flex items-center justify-center text-foreground-muted", style: { top: headerHeight }, children: emptyState })
|
|
6689
6775
|
]
|
|
6690
6776
|
}
|
|
6691
6777
|
);
|
|
6692
6778
|
}
|
|
6779
|
+
var HILITE = "color-mix(in srgb, var(--color-accent) 9%, transparent)";
|
|
6780
|
+
var SELECT_BG = "color-mix(in srgb, var(--color-accent) 16%, transparent)";
|
|
6781
|
+
var SELECT_RING = "inset 0 0 0 2px var(--color-accent)";
|
|
6693
6782
|
function SortCaret({ dir }) {
|
|
6694
6783
|
return /* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: "0 0 16 16", className: "h-3 w-3 flex-shrink-0", fill: "none", stroke: "currentColor", strokeWidth: 1.75, "aria-hidden": "true", children: [
|
|
6695
6784
|
/* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M5 6.5 8 3.5l3 3", className: dir === "asc" ? "text-accent" : "text-foreground-muted opacity-50" }),
|
|
@@ -6715,6 +6804,26 @@ function columnLetter(i) {
|
|
|
6715
6804
|
function blankSheet(name, cols = 8) {
|
|
6716
6805
|
return { name, columns: Array.from({ length: cols }, (_, i) => ({ key: columnLetter(i), label: columnLetter(i) })), rows: [] };
|
|
6717
6806
|
}
|
|
6807
|
+
function parseWorkbook(XLSX, bytes) {
|
|
6808
|
+
const wb = XLSX.read(bytes, { type: "array" });
|
|
6809
|
+
return wb.SheetNames.map((name) => {
|
|
6810
|
+
const ws = wb.Sheets[name];
|
|
6811
|
+
const aoa = XLSX.utils.sheet_to_json(ws, { header: 1, blankrows: false, defval: null });
|
|
6812
|
+
const headerRow = aoa[0] ?? [];
|
|
6813
|
+
const columns = headerRow.map((h, i) => ({
|
|
6814
|
+
key: h != null && String(h).length ? String(h) : `col_${i}`,
|
|
6815
|
+
label: h != null && String(h).length ? String(h) : `Column ${i + 1}`
|
|
6816
|
+
}));
|
|
6817
|
+
const rows = aoa.slice(1).map((r) => {
|
|
6818
|
+
const rec = {};
|
|
6819
|
+
columns.forEach((c, i) => {
|
|
6820
|
+
rec[c.key] = r[i] ?? null;
|
|
6821
|
+
});
|
|
6822
|
+
return rec;
|
|
6823
|
+
});
|
|
6824
|
+
return { name, columns, rows };
|
|
6825
|
+
});
|
|
6826
|
+
}
|
|
6718
6827
|
function toPlainRows(sheet, columns) {
|
|
6719
6828
|
return sheet.rows.map((row) => {
|
|
6720
6829
|
const out = {};
|
|
@@ -6773,24 +6882,7 @@ function Spreadsheet({
|
|
|
6773
6882
|
try {
|
|
6774
6883
|
const bytes = await sourceToBytes(source, remote);
|
|
6775
6884
|
const XLSX = await loadXlsx();
|
|
6776
|
-
const
|
|
6777
|
-
const parsed = wb.SheetNames.map((name) => {
|
|
6778
|
-
const ws = wb.Sheets[name];
|
|
6779
|
-
const aoa = XLSX.utils.sheet_to_json(ws, { header: 1, blankrows: false, defval: null });
|
|
6780
|
-
const headerRow = aoa[0] ?? [];
|
|
6781
|
-
const columns2 = headerRow.map((h, i) => ({
|
|
6782
|
-
key: h != null && String(h).length ? String(h) : `col_${i}`,
|
|
6783
|
-
label: h != null && String(h).length ? String(h) : `Column ${i + 1}`
|
|
6784
|
-
}));
|
|
6785
|
-
const rows = aoa.slice(1).map((r) => {
|
|
6786
|
-
const rec = {};
|
|
6787
|
-
columns2.forEach((c, i) => {
|
|
6788
|
-
rec[c.key] = r[i] ?? null;
|
|
6789
|
-
});
|
|
6790
|
-
return rec;
|
|
6791
|
-
});
|
|
6792
|
-
return { name, columns: columns2, rows };
|
|
6793
|
-
});
|
|
6885
|
+
const parsed = parseWorkbook(XLSX, bytes);
|
|
6794
6886
|
if (cancelled) return;
|
|
6795
6887
|
setSheets(parsed);
|
|
6796
6888
|
setActive(0);
|
|
@@ -6840,6 +6932,63 @@ function Spreadsheet({
|
|
|
6840
6932
|
return next;
|
|
6841
6933
|
});
|
|
6842
6934
|
}, [onChange]);
|
|
6935
|
+
const deleteSheet = React36.useCallback((index) => {
|
|
6936
|
+
if (!sheets || sheets.length <= 1) return;
|
|
6937
|
+
const next = sheets.filter((_, i) => i !== index);
|
|
6938
|
+
setSheets(next);
|
|
6939
|
+
setActive((a) => Math.max(0, Math.min(index < a ? a - 1 : a, next.length - 1)));
|
|
6940
|
+
onChange?.(next);
|
|
6941
|
+
}, [sheets, onChange]);
|
|
6942
|
+
const add100Rows = React36.useCallback(() => {
|
|
6943
|
+
setSheets((prev) => {
|
|
6944
|
+
if (!prev) return prev;
|
|
6945
|
+
const next = prev.map((s, i) => i === active ? { ...s, rows: [...s.rows, ...Array.from({ length: 100 }, () => ({}))] } : s);
|
|
6946
|
+
onChange?.(next);
|
|
6947
|
+
return next;
|
|
6948
|
+
});
|
|
6949
|
+
}, [active, onChange]);
|
|
6950
|
+
const insertRow = React36.useCallback((index) => {
|
|
6951
|
+
setSheets((prev) => {
|
|
6952
|
+
if (!prev) return prev;
|
|
6953
|
+
const next = prev.map((s, i) => {
|
|
6954
|
+
if (i !== active) return s;
|
|
6955
|
+
const rows = [...s.rows];
|
|
6956
|
+
rows.splice(Math.max(0, Math.min(index, rows.length)), 0, {});
|
|
6957
|
+
return { ...s, rows };
|
|
6958
|
+
});
|
|
6959
|
+
onChange?.(next);
|
|
6960
|
+
return next;
|
|
6961
|
+
});
|
|
6962
|
+
}, [active, onChange]);
|
|
6963
|
+
const deleteRow = React36.useCallback((index) => {
|
|
6964
|
+
setSheets((prev) => {
|
|
6965
|
+
if (!prev) return prev;
|
|
6966
|
+
const next = prev.map((s, i) => i === active && index < s.rows.length ? { ...s, rows: s.rows.filter((_, r) => r !== index) } : s);
|
|
6967
|
+
onChange?.(next);
|
|
6968
|
+
return next;
|
|
6969
|
+
});
|
|
6970
|
+
}, [active, onChange]);
|
|
6971
|
+
const fileInputRef = React36.useRef(null);
|
|
6972
|
+
const openFile = () => fileInputRef.current?.click();
|
|
6973
|
+
const onFilePicked = React36.useCallback(async (e) => {
|
|
6974
|
+
const file = e.target.files?.[0];
|
|
6975
|
+
e.target.value = "";
|
|
6976
|
+
if (!file) return;
|
|
6977
|
+
setStatus("loading");
|
|
6978
|
+
setError(null);
|
|
6979
|
+
try {
|
|
6980
|
+
const bytes = new Uint8Array(await file.arrayBuffer());
|
|
6981
|
+
const XLSX = await loadXlsx();
|
|
6982
|
+
const parsed = parseWorkbook(XLSX, bytes);
|
|
6983
|
+
setSheets(parsed);
|
|
6984
|
+
setActive(0);
|
|
6985
|
+
setStatus("ready");
|
|
6986
|
+
onChange?.(parsed);
|
|
6987
|
+
} catch (err) {
|
|
6988
|
+
setError(err);
|
|
6989
|
+
setStatus("error");
|
|
6990
|
+
}
|
|
6991
|
+
}, [onChange]);
|
|
6843
6992
|
const baseName = React36.useMemo(
|
|
6844
6993
|
() => (fileName || (typeof source === "object" && "name" in source ? sourceName(source) : null) || "spreadsheet").replace(/\.[^.]+$/, ""),
|
|
6845
6994
|
[fileName, source]
|
|
@@ -6926,40 +7075,37 @@ function Spreadsheet({
|
|
|
6926
7075
|
}
|
|
6927
7076
|
const formats = exportFormats || [];
|
|
6928
7077
|
const exportLabels = {
|
|
6929
|
-
xlsx: "Excel
|
|
6930
|
-
csv: "CSV
|
|
6931
|
-
pdf: "PDF
|
|
7078
|
+
xlsx: "Excel (.xlsx)",
|
|
7079
|
+
csv: "CSV (.csv)",
|
|
7080
|
+
pdf: "PDF (.pdf)"
|
|
6932
7081
|
};
|
|
7082
|
+
const fileItems = [
|
|
7083
|
+
{ key: "open", label: "Open", onSelect: openFile },
|
|
7084
|
+
...formats.length > 0 ? [{ key: "export", label: "Export", separatorBefore: true, children: formats.map((fmt) => ({ key: fmt, label: exportLabels[fmt], onSelect: () => runExport(fmt) })) }] : []
|
|
7085
|
+
];
|
|
7086
|
+
const sheetItems = [
|
|
7087
|
+
{ key: "add", label: "Add Sheet", onSelect: addSheet },
|
|
7088
|
+
{ key: "delete", label: "Delete Sheet", danger: true, disabled: sheets.length <= 1, onSelect: () => deleteSheet(active) },
|
|
7089
|
+
{ key: "add100", label: "Add 100 rows", separatorBefore: true, onSelect: add100Rows }
|
|
7090
|
+
];
|
|
7091
|
+
const canDeleteSheet = editable && sheets.length > 1;
|
|
6933
7092
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cx("flex flex-col overflow-hidden rounded-lg border border-border bg-surface-raised", className), style: { height, width, ...style }, children: [
|
|
6934
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-shrink-0 items-center gap-
|
|
6935
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6936
|
-
/* @__PURE__ */ jsxRuntime.
|
|
6937
|
-
plainRows.length.toLocaleString(),
|
|
6938
|
-
" ",
|
|
6939
|
-
plainRows.length === 1 ? "row" : "rows",
|
|
6940
|
-
" \xB7 ",
|
|
6941
|
-
columns.length,
|
|
6942
|
-
" cols"
|
|
6943
|
-
] }),
|
|
6944
|
-
formats.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
6945
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "h-5 w-px flex-shrink-0 bg-border", "aria-hidden": "true" }),
|
|
6946
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6947
|
-
MenuButton,
|
|
6948
|
-
{
|
|
6949
|
-
label: "Export",
|
|
6950
|
-
size: "sm",
|
|
6951
|
-
variant: "outline",
|
|
6952
|
-
align: "end",
|
|
6953
|
-
icon: /* @__PURE__ */ jsxRuntime.jsx(DownloadIcon2, {}),
|
|
6954
|
-
items: formats.map((fmt) => ({
|
|
6955
|
-
key: fmt,
|
|
6956
|
-
label: exportLabels[fmt],
|
|
6957
|
-
onSelect: () => runExport(fmt)
|
|
6958
|
-
}))
|
|
6959
|
-
}
|
|
6960
|
-
)
|
|
6961
|
-
] })
|
|
7093
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-shrink-0 items-center gap-0.5 border-b border-border bg-surface px-1.5 py-1", children: [
|
|
7094
|
+
/* @__PURE__ */ jsxRuntime.jsx(MenuButton, { label: "File", variant: "ghost", size: "sm", hideChevron: true, items: fileItems }),
|
|
7095
|
+
editable && /* @__PURE__ */ jsxRuntime.jsx(MenuButton, { label: "Sheet", variant: "ghost", size: "sm", hideChevron: true, items: sheetItems })
|
|
6962
7096
|
] }),
|
|
7097
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7098
|
+
"input",
|
|
7099
|
+
{
|
|
7100
|
+
ref: fileInputRef,
|
|
7101
|
+
type: "file",
|
|
7102
|
+
accept: ".xlsx,.xls,.csv,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
7103
|
+
onChange: onFilePicked,
|
|
7104
|
+
className: "hidden",
|
|
7105
|
+
"aria-hidden": "true",
|
|
7106
|
+
tabIndex: -1
|
|
7107
|
+
}
|
|
7108
|
+
),
|
|
6963
7109
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-0 flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
6964
7110
|
DataGrid,
|
|
6965
7111
|
{
|
|
@@ -6969,47 +7115,85 @@ function Spreadsheet({
|
|
|
6969
7115
|
sortable,
|
|
6970
7116
|
virtualize,
|
|
6971
7117
|
trailingRows: emptyRows,
|
|
7118
|
+
contextMenu: true,
|
|
7119
|
+
onInsertRow: editable ? insertRow : void 0,
|
|
7120
|
+
onDeleteRow: editable ? deleteRow : void 0,
|
|
6972
7121
|
onCellEdit: handleCellEdit,
|
|
6973
7122
|
height: "100%",
|
|
6974
7123
|
className: "!rounded-none !border-0"
|
|
6975
7124
|
},
|
|
6976
7125
|
active
|
|
6977
7126
|
) }),
|
|
6978
|
-
|
|
6979
|
-
/* @__PURE__ */ jsxRuntime.
|
|
6980
|
-
|
|
6981
|
-
|
|
7127
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-shrink-0 items-center gap-2 border-t border-border bg-surface px-2 py-1", children: [
|
|
7128
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { role: "tablist", "aria-label": "Sheets", className: "flex min-w-0 flex-1 items-center gap-1 overflow-x-auto", children: [
|
|
7129
|
+
sheets.map((s, i) => {
|
|
7130
|
+
const activeTab = i === active;
|
|
7131
|
+
const name = s.name || `Sheet ${i + 1}`;
|
|
7132
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
7133
|
+
"div",
|
|
7134
|
+
{
|
|
7135
|
+
role: "tab",
|
|
7136
|
+
tabIndex: 0,
|
|
7137
|
+
"aria-selected": activeTab,
|
|
7138
|
+
onClick: () => setActive(i),
|
|
7139
|
+
onKeyDown: (e) => {
|
|
7140
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
7141
|
+
e.preventDefault();
|
|
7142
|
+
setActive(i);
|
|
7143
|
+
}
|
|
7144
|
+
},
|
|
7145
|
+
className: cx(
|
|
7146
|
+
"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",
|
|
7147
|
+
"focus:outline-none focus-visible:ring-2 focus-visible:ring-accent",
|
|
7148
|
+
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"
|
|
7149
|
+
),
|
|
7150
|
+
children: [
|
|
7151
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "max-w-[160px] truncate", children: name }),
|
|
7152
|
+
canDeleteSheet && /* @__PURE__ */ jsxRuntime.jsx(
|
|
7153
|
+
"button",
|
|
7154
|
+
{
|
|
7155
|
+
type: "button",
|
|
7156
|
+
title: "Delete sheet",
|
|
7157
|
+
"aria-label": `Delete ${name}`,
|
|
7158
|
+
onClick: (e) => {
|
|
7159
|
+
e.stopPropagation();
|
|
7160
|
+
deleteSheet(i);
|
|
7161
|
+
},
|
|
7162
|
+
className: cx(
|
|
7163
|
+
"flex h-4 w-4 items-center justify-center rounded text-foreground-muted transition-opacity hover:text-status-error",
|
|
7164
|
+
activeTab ? "opacity-100" : "opacity-0 group-hover:opacity-100"
|
|
7165
|
+
),
|
|
7166
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2.5, className: "h-3 w-3", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", d: "M6 6l12 12M18 6 6 18" }) })
|
|
7167
|
+
}
|
|
7168
|
+
)
|
|
7169
|
+
]
|
|
7170
|
+
},
|
|
7171
|
+
`${s.name}-${i}`
|
|
7172
|
+
);
|
|
7173
|
+
}),
|
|
7174
|
+
canAddSheet && /* @__PURE__ */ jsxRuntime.jsx(
|
|
6982
7175
|
"button",
|
|
6983
7176
|
{
|
|
6984
|
-
role: "tab",
|
|
6985
7177
|
type: "button",
|
|
6986
|
-
|
|
6987
|
-
|
|
6988
|
-
|
|
6989
|
-
|
|
6990
|
-
|
|
6991
|
-
|
|
6992
|
-
|
|
6993
|
-
|
|
6994
|
-
|
|
6995
|
-
|
|
6996
|
-
|
|
6997
|
-
|
|
6998
|
-
|
|
6999
|
-
|
|
7000
|
-
|
|
7001
|
-
|
|
7002
|
-
onClick: addSheet,
|
|
7003
|
-
title: "Add sheet",
|
|
7004
|
-
"aria-label": "Add sheet",
|
|
7005
|
-
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",
|
|
7006
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "h-4 w-4", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", d: "M12 5v14M5 12h14" }) })
|
|
7007
|
-
}
|
|
7008
|
-
)
|
|
7178
|
+
onClick: addSheet,
|
|
7179
|
+
title: "Add sheet",
|
|
7180
|
+
"aria-label": "Add sheet",
|
|
7181
|
+
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",
|
|
7182
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "h-4 w-4", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", d: "M12 5v14M5 12h14" }) })
|
|
7183
|
+
}
|
|
7184
|
+
)
|
|
7185
|
+
] }),
|
|
7186
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "hidden flex-shrink-0 text-xs tabular-nums text-foreground-muted sm:inline", children: [
|
|
7187
|
+
plainRows.length.toLocaleString(),
|
|
7188
|
+
" ",
|
|
7189
|
+
plainRows.length === 1 ? "row" : "rows",
|
|
7190
|
+
" \xB7 ",
|
|
7191
|
+
columns.length,
|
|
7192
|
+
" cols"
|
|
7193
|
+
] })
|
|
7009
7194
|
] })
|
|
7010
7195
|
] });
|
|
7011
7196
|
}
|
|
7012
|
-
var DownloadIcon2 = () => /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "h-4 w-4", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 3v12m0 0 4-4m-4 4-4-4M4 21h16" }) });
|
|
7013
7197
|
function ThemeSwitch({ checked, onChange, label = "Toggle dark mode", className = "" }) {
|
|
7014
7198
|
const id = React36.useId();
|
|
7015
7199
|
return /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: id, className: `flex items-center gap-2 cursor-pointer select-none ${className}`.trim(), children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -7097,15 +7281,15 @@ function FlyoutItems({ items }) {
|
|
|
7097
7281
|
child.badge !== void 0 && child.badge > 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-4 min-w-4 items-center justify-center rounded-full bg-status-error px-1 text-[9px] font-bold leading-none text-white", children: child.badge > 99 ? "99+" : child.badge })
|
|
7098
7282
|
] });
|
|
7099
7283
|
if (child.items?.length) {
|
|
7100
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
7101
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
7284
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenu__namespace.Sub, { children: [
|
|
7285
|
+
/* @__PURE__ */ jsxRuntime.jsxs(DropdownMenu__namespace.SubTrigger, { className: cls, children: [
|
|
7102
7286
|
label,
|
|
7103
7287
|
/* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, "aria-hidden": "true", className: "h-3.5 w-3.5 flex-shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "m9 6 6 6-6 6" }) })
|
|
7104
7288
|
] }),
|
|
7105
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7289
|
+
/* @__PURE__ */ jsxRuntime.jsx(DropdownMenu__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(DropdownMenu__namespace.SubContent, { sideOffset: 6, collisionPadding: 8, className: FLYOUT_PANEL, children: /* @__PURE__ */ jsxRuntime.jsx(FlyoutItems, { items: child.items }) }) })
|
|
7106
7290
|
] }, child.key);
|
|
7107
7291
|
}
|
|
7108
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
7292
|
+
return /* @__PURE__ */ jsxRuntime.jsx(DropdownMenu__namespace.Item, { onSelect: () => child.onClick?.(), className: cls, children: label }, child.key);
|
|
7109
7293
|
}) });
|
|
7110
7294
|
}
|
|
7111
7295
|
function CollapsedFlyout({ item, trigger }) {
|
|
@@ -7120,9 +7304,9 @@ function CollapsedFlyout({ item, trigger }) {
|
|
|
7120
7304
|
closeTimer.current = window.setTimeout(() => setOpen(false), 150);
|
|
7121
7305
|
};
|
|
7122
7306
|
React36__default.default.useEffect(() => () => window.clearTimeout(closeTimer.current), []);
|
|
7123
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
7307
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenu__namespace.Root, { open, onOpenChange: setOpen, modal: false, children: [
|
|
7124
7308
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7125
|
-
|
|
7309
|
+
DropdownMenu__namespace.Trigger,
|
|
7126
7310
|
{
|
|
7127
7311
|
asChild: true,
|
|
7128
7312
|
onPointerEnter: openNow,
|
|
@@ -7133,8 +7317,8 @@ function CollapsedFlyout({ item, trigger }) {
|
|
|
7133
7317
|
children: trigger
|
|
7134
7318
|
}
|
|
7135
7319
|
),
|
|
7136
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7137
|
-
|
|
7320
|
+
/* @__PURE__ */ jsxRuntime.jsx(DropdownMenu__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
7321
|
+
DropdownMenu__namespace.Content,
|
|
7138
7322
|
{
|
|
7139
7323
|
side: "right",
|
|
7140
7324
|
align: "start",
|
|
@@ -7144,7 +7328,7 @@ function CollapsedFlyout({ item, trigger }) {
|
|
|
7144
7328
|
onPointerEnter: openNow,
|
|
7145
7329
|
onPointerLeave: closeSoon,
|
|
7146
7330
|
children: [
|
|
7147
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7331
|
+
/* @__PURE__ */ jsxRuntime.jsx(DropdownMenu__namespace.Label, { className: "px-2.5 pb-1 pt-1.5 text-xs font-semibold text-foreground-muted", children: item.label }),
|
|
7148
7332
|
/* @__PURE__ */ jsxRuntime.jsx(FlyoutItems, { items: item.items })
|
|
7149
7333
|
]
|
|
7150
7334
|
}
|
|
@@ -9662,7 +9846,7 @@ function DatePicker({
|
|
|
9662
9846
|
},
|
|
9663
9847
|
"aria-label": view === "days" ? "Next month" : view === "months" ? "Next year" : "Next decade",
|
|
9664
9848
|
className: "w-7 h-7 inline-flex items-center justify-center rounded-md hover:bg-surface-raised focus:outline-none focus-visible:ring-2 focus-visible:ring-accent transition-colors",
|
|
9665
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
9849
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ChevronRight3, {})
|
|
9666
9850
|
}
|
|
9667
9851
|
)
|
|
9668
9852
|
] }),
|
|
@@ -9780,7 +9964,7 @@ function CalendarIcon() {
|
|
|
9780
9964
|
function ChevronLeft() {
|
|
9781
9965
|
return /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "w-4 h-4", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M15 19l-7-7 7-7" }) });
|
|
9782
9966
|
}
|
|
9783
|
-
function
|
|
9967
|
+
function ChevronRight3() {
|
|
9784
9968
|
return /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "w-4 h-4", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9 5l7 7-7 7" }) });
|
|
9785
9969
|
}
|
|
9786
9970
|
var LINE_HEIGHT_PX = 21;
|