@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.js
CHANGED
|
@@ -6,7 +6,7 @@ import React36, { useMemo, createContext, useState, useEffect, useId, useCallbac
|
|
|
6
6
|
import { createPortal } from 'react-dom';
|
|
7
7
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
8
8
|
import * as AvatarPrimitive from '@radix-ui/react-avatar';
|
|
9
|
-
import * as
|
|
9
|
+
import * as DropdownMenu from '@radix-ui/react-dropdown-menu';
|
|
10
10
|
import * as Dialog from '@radix-ui/react-dialog';
|
|
11
11
|
import { useReducedMotion, AnimatePresence, motion, useScroll, useTransform } from 'framer-motion';
|
|
12
12
|
import * as TooltipPrimitive from '@radix-ui/react-tooltip';
|
|
@@ -631,6 +631,39 @@ var Chevron = () => /* @__PURE__ */ jsx(
|
|
|
631
631
|
children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 9l6 6 6-6" })
|
|
632
632
|
}
|
|
633
633
|
);
|
|
634
|
+
var ChevronRight = () => /* @__PURE__ */ 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__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9 5l7 7-7 7" }) });
|
|
635
|
+
var ITEM_CLASS = [
|
|
636
|
+
"flex items-center gap-2.5 rounded-md px-2.5 py-1.5 text-sm outline-none cursor-pointer select-none transition-colors",
|
|
637
|
+
"data-[disabled]:opacity-50 data-[disabled]:pointer-events-none"
|
|
638
|
+
].join(" ");
|
|
639
|
+
var itemTone = (danger) => danger ? "text-status-error data-[highlighted]:bg-status-error/10" : "text-foreground data-[highlighted]:bg-surface-raised";
|
|
640
|
+
var Label = ({ item }) => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
641
|
+
item.icon && /* @__PURE__ */ jsx("span", { className: "flex h-4 w-4 flex-shrink-0 items-center justify-center", children: item.icon }),
|
|
642
|
+
/* @__PURE__ */ jsx("span", { className: "flex-1 truncate", children: item.label })
|
|
643
|
+
] });
|
|
644
|
+
function renderItem(item) {
|
|
645
|
+
if (item.children && item.children.length > 0) {
|
|
646
|
+
return /* @__PURE__ */ jsxs(DropdownMenu.Sub, { children: [
|
|
647
|
+
/* @__PURE__ */ jsxs(DropdownMenu.SubTrigger, { disabled: item.disabled, className: `${ITEM_CLASS} ${itemTone(item.danger)}`, children: [
|
|
648
|
+
/* @__PURE__ */ jsx(Label, { item }),
|
|
649
|
+
/* @__PURE__ */ jsx(ChevronRight, {})
|
|
650
|
+
] }),
|
|
651
|
+
/* @__PURE__ */ jsx(DropdownMenu.Portal, { children: /* @__PURE__ */ jsx(
|
|
652
|
+
DropdownMenu.SubContent,
|
|
653
|
+
{
|
|
654
|
+
sideOffset: 4,
|
|
655
|
+
collisionPadding: 8,
|
|
656
|
+
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",
|
|
657
|
+
children: item.children.map((sub) => /* @__PURE__ */ jsxs(React36.Fragment, { children: [
|
|
658
|
+
sub.separatorBefore && /* @__PURE__ */ jsx(DropdownMenu.Separator, { className: "my-1 h-px bg-border" }),
|
|
659
|
+
renderItem(sub)
|
|
660
|
+
] }, sub.key))
|
|
661
|
+
}
|
|
662
|
+
) })
|
|
663
|
+
] });
|
|
664
|
+
}
|
|
665
|
+
return /* @__PURE__ */ jsx(DropdownMenu.Item, { disabled: item.disabled, onSelect: () => item.onSelect?.(), className: `${ITEM_CLASS} ${itemTone(item.danger)}`, children: /* @__PURE__ */ jsx(Label, { item }) });
|
|
666
|
+
}
|
|
634
667
|
function MenuButton({
|
|
635
668
|
label,
|
|
636
669
|
items,
|
|
@@ -643,8 +676,8 @@ function MenuButton({
|
|
|
643
676
|
side = "bottom",
|
|
644
677
|
className = ""
|
|
645
678
|
}) {
|
|
646
|
-
return /* @__PURE__ */ jsxs(
|
|
647
|
-
/* @__PURE__ */ jsx(
|
|
679
|
+
return /* @__PURE__ */ jsxs(DropdownMenu.Root, { children: [
|
|
680
|
+
/* @__PURE__ */ jsx(DropdownMenu.Trigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
648
681
|
Button_default,
|
|
649
682
|
{
|
|
650
683
|
variant,
|
|
@@ -658,8 +691,8 @@ function MenuButton({
|
|
|
658
691
|
] })
|
|
659
692
|
}
|
|
660
693
|
) }),
|
|
661
|
-
/* @__PURE__ */ jsx(
|
|
662
|
-
|
|
694
|
+
/* @__PURE__ */ jsx(DropdownMenu.Portal, { children: /* @__PURE__ */ jsx(
|
|
695
|
+
DropdownMenu.Content,
|
|
663
696
|
{
|
|
664
697
|
align,
|
|
665
698
|
side,
|
|
@@ -671,23 +704,8 @@ function MenuButton({
|
|
|
671
704
|
"data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95"
|
|
672
705
|
].join(" "),
|
|
673
706
|
children: items.map((item) => /* @__PURE__ */ jsxs(React36.Fragment, { children: [
|
|
674
|
-
item.separatorBefore && /* @__PURE__ */ jsx(
|
|
675
|
-
|
|
676
|
-
DropdownMenu2.Item,
|
|
677
|
-
{
|
|
678
|
-
disabled: item.disabled,
|
|
679
|
-
onSelect: () => item.onSelect?.(),
|
|
680
|
-
className: [
|
|
681
|
-
"flex items-center gap-2.5 rounded-md px-2.5 py-1.5 text-sm outline-none cursor-pointer select-none transition-colors",
|
|
682
|
-
"data-[disabled]:opacity-50 data-[disabled]:pointer-events-none",
|
|
683
|
-
item.danger ? "text-status-error data-[highlighted]:bg-status-error/10" : "text-foreground data-[highlighted]:bg-surface-raised"
|
|
684
|
-
].join(" "),
|
|
685
|
-
children: [
|
|
686
|
-
item.icon && /* @__PURE__ */ jsx("span", { className: "flex h-4 w-4 flex-shrink-0 items-center justify-center", children: item.icon }),
|
|
687
|
-
/* @__PURE__ */ jsx("span", { className: "flex-1 truncate", children: item.label })
|
|
688
|
-
]
|
|
689
|
-
}
|
|
690
|
-
)
|
|
707
|
+
item.separatorBefore && /* @__PURE__ */ jsx(DropdownMenu.Separator, { className: "my-1 h-px bg-border" }),
|
|
708
|
+
renderItem(item)
|
|
691
709
|
] }, item.key))
|
|
692
710
|
}
|
|
693
711
|
) })
|
|
@@ -1729,7 +1747,7 @@ function Stepper({
|
|
|
1729
1747
|
const vertical = orientation === "vertical" || forcedVertical;
|
|
1730
1748
|
const s = SIZES[size];
|
|
1731
1749
|
const stateOf = (i) => i < current ? "completed" : i === current ? status : "pending";
|
|
1732
|
-
const
|
|
1750
|
+
const Label3 = ({ step, state, align }) => /* @__PURE__ */ jsxs("div", { className: align === "center" ? "mt-2 text-center" : "pt-0.5", children: [
|
|
1733
1751
|
/* @__PURE__ */ jsx("div", { className: `font-medium leading-tight ${s.title} ${state === "pending" ? "text-foreground-muted" : "text-foreground"}`, children: step.title }),
|
|
1734
1752
|
step.description && /* @__PURE__ */ jsx("div", { className: `mt-0.5 leading-snug text-foreground-muted ${s.desc}`, children: step.description })
|
|
1735
1753
|
] });
|
|
@@ -1744,7 +1762,7 @@ function Stepper({
|
|
|
1744
1762
|
stepButton(i, /* @__PURE__ */ jsx(Indicator, { state, index: i, step, sizeKey: size })),
|
|
1745
1763
|
!last && /* @__PURE__ */ jsx(VConnector, { filled: i < current, reduced })
|
|
1746
1764
|
] }),
|
|
1747
|
-
/* @__PURE__ */ jsx("div", { className: last ? "" : "pb-6", children: stepButton(i, /* @__PURE__ */ jsx(
|
|
1765
|
+
/* @__PURE__ */ jsx("div", { className: last ? "" : "pb-6", children: stepButton(i, /* @__PURE__ */ jsx(Label3, { step, state, align: "left" })) })
|
|
1748
1766
|
] }, step.key);
|
|
1749
1767
|
}) });
|
|
1750
1768
|
}
|
|
@@ -1763,7 +1781,7 @@ function Stepper({
|
|
|
1763
1781
|
) }),
|
|
1764
1782
|
stepButton(i, /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center", children: [
|
|
1765
1783
|
/* @__PURE__ */ jsx(Indicator, { state, index: i, step, sizeKey: size }),
|
|
1766
|
-
/* @__PURE__ */ jsx(
|
|
1784
|
+
/* @__PURE__ */ jsx(Label3, { step, state, align: "center" })
|
|
1767
1785
|
] }))
|
|
1768
1786
|
] }, step.key);
|
|
1769
1787
|
}) });
|
|
@@ -4929,7 +4947,7 @@ function ContextMenu({ items, children, className = "" }) {
|
|
|
4929
4947
|
{
|
|
4930
4948
|
className: `${CONTENT_CLASSNAME} ${className}`.trim(),
|
|
4931
4949
|
collisionPadding: 8,
|
|
4932
|
-
children: items.map((item) =>
|
|
4950
|
+
children: items.map((item) => renderItem2(item))
|
|
4933
4951
|
}
|
|
4934
4952
|
) })
|
|
4935
4953
|
] });
|
|
@@ -4951,7 +4969,7 @@ var ITEM_CLASSNAME = [
|
|
|
4951
4969
|
"data-[disabled]:opacity-40 data-[disabled]:cursor-not-allowed data-[disabled]:bg-transparent data-[disabled]:text-foreground-muted",
|
|
4952
4970
|
"focus:outline-none"
|
|
4953
4971
|
].join(" ");
|
|
4954
|
-
function
|
|
4972
|
+
function renderItem2(item) {
|
|
4955
4973
|
if (item.children && item.children.length > 0) {
|
|
4956
4974
|
return /* @__PURE__ */ jsxs(ContextMenuPrimitive.Sub, { children: [
|
|
4957
4975
|
/* @__PURE__ */ jsxs(
|
|
@@ -4961,7 +4979,7 @@ function renderItem(item) {
|
|
|
4961
4979
|
className: ITEM_CLASSNAME,
|
|
4962
4980
|
children: [
|
|
4963
4981
|
/* @__PURE__ */ jsx(ContextMenuLabel, { icon: item.icon, value: item.value }),
|
|
4964
|
-
/* @__PURE__ */ jsx(
|
|
4982
|
+
/* @__PURE__ */ jsx(ChevronRight2, {})
|
|
4965
4983
|
]
|
|
4966
4984
|
}
|
|
4967
4985
|
),
|
|
@@ -4972,7 +4990,7 @@ function renderItem(item) {
|
|
|
4972
4990
|
sideOffset: 2,
|
|
4973
4991
|
alignOffset: -4,
|
|
4974
4992
|
collisionPadding: 8,
|
|
4975
|
-
children: item.children.map((sub) =>
|
|
4993
|
+
children: item.children.map((sub) => renderItem2(sub))
|
|
4976
4994
|
}
|
|
4977
4995
|
) })
|
|
4978
4996
|
] }, item.key);
|
|
@@ -4994,7 +5012,7 @@ function ContextMenuLabel({ icon, value }) {
|
|
|
4994
5012
|
/* @__PURE__ */ jsx("span", { className: "truncate", children: value })
|
|
4995
5013
|
] });
|
|
4996
5014
|
}
|
|
4997
|
-
function
|
|
5015
|
+
function ChevronRight2() {
|
|
4998
5016
|
return /* @__PURE__ */ 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__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9 5l7 7-7 7" }) });
|
|
4999
5017
|
}
|
|
5000
5018
|
function readDismissed(key) {
|
|
@@ -5847,7 +5865,7 @@ var useIsoLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEf
|
|
|
5847
5865
|
function VirtualList({
|
|
5848
5866
|
items,
|
|
5849
5867
|
rowHeight,
|
|
5850
|
-
renderItem:
|
|
5868
|
+
renderItem: renderItem3,
|
|
5851
5869
|
height = 400,
|
|
5852
5870
|
getKey,
|
|
5853
5871
|
overscan = 6,
|
|
@@ -5912,7 +5930,7 @@ function VirtualList({
|
|
|
5912
5930
|
role: "listitem",
|
|
5913
5931
|
style: { height: rowHeight },
|
|
5914
5932
|
className: "box-border",
|
|
5915
|
-
children:
|
|
5933
|
+
children: renderItem3(item, index)
|
|
5916
5934
|
},
|
|
5917
5935
|
getKey ? getKey(item, index) : index
|
|
5918
5936
|
);
|
|
@@ -6469,6 +6487,9 @@ function DataGrid({
|
|
|
6469
6487
|
rowNumbers = true,
|
|
6470
6488
|
trailingRows = 0,
|
|
6471
6489
|
onCellEdit,
|
|
6490
|
+
contextMenu = false,
|
|
6491
|
+
onInsertRow,
|
|
6492
|
+
onDeleteRow,
|
|
6472
6493
|
className = "",
|
|
6473
6494
|
style,
|
|
6474
6495
|
emptyState = "No data"
|
|
@@ -6476,6 +6497,9 @@ function DataGrid({
|
|
|
6476
6497
|
const scrollRef = useRef(null);
|
|
6477
6498
|
const [scroll, setScroll] = useState({ top: 0, left: 0 });
|
|
6478
6499
|
const [viewport, setViewport] = useState({ w: 0, h: 0 });
|
|
6500
|
+
const [selected, setSelected] = useState(null);
|
|
6501
|
+
const [hoveredRow, setHoveredRow] = useState(null);
|
|
6502
|
+
const [ctxTarget, setCtxTarget] = useState(null);
|
|
6479
6503
|
const [editing, setEditing] = useState(null);
|
|
6480
6504
|
const [draft, setDraft] = useState("");
|
|
6481
6505
|
const [internalSort, setInternalSort] = useState(null);
|
|
@@ -6546,114 +6570,179 @@ function DataGrid({
|
|
|
6546
6570
|
setDraft(displayValue(rows[rowIndexForDisp(disp)]?.[c.key] ?? ""));
|
|
6547
6571
|
setEditing({ disp, col });
|
|
6548
6572
|
};
|
|
6573
|
+
const cellText = (sel) => displayValue(rows[rowIndexForDisp(sel.disp)]?.[columns[sel.col].key] ?? "");
|
|
6574
|
+
const copyCell = useCallback(async () => {
|
|
6575
|
+
if (!selected) return;
|
|
6576
|
+
try {
|
|
6577
|
+
await navigator.clipboard?.writeText(cellText(selected));
|
|
6578
|
+
} catch {
|
|
6579
|
+
}
|
|
6580
|
+
}, [selected, rows, columns, order]);
|
|
6581
|
+
const cutCell = useCallback(async () => {
|
|
6582
|
+
if (!selected) return;
|
|
6583
|
+
await copyCell();
|
|
6584
|
+
onCellEdit?.({ row: rowIndexForDisp(selected.disp), column: columns[selected.col].key, value: "" });
|
|
6585
|
+
}, [selected, copyCell, onCellEdit, columns, order, rows.length]);
|
|
6586
|
+
const pasteCell = useCallback(async () => {
|
|
6587
|
+
if (!selected) return;
|
|
6588
|
+
let text = "";
|
|
6589
|
+
try {
|
|
6590
|
+
text = await navigator.clipboard?.readText() ?? "";
|
|
6591
|
+
} catch {
|
|
6592
|
+
return;
|
|
6593
|
+
}
|
|
6594
|
+
onCellEdit?.({ row: rowIndexForDisp(selected.disp), column: columns[selected.col].key, value: text });
|
|
6595
|
+
}, [selected, onCellEdit, columns, order, rows.length]);
|
|
6596
|
+
const ctxItems = useMemo(() => {
|
|
6597
|
+
if (ctxTarget?.kind === "row") {
|
|
6598
|
+
const ri = rowIndexForDisp(ctxTarget.disp);
|
|
6599
|
+
const isData = ctxTarget.disp < rows.length;
|
|
6600
|
+
return [
|
|
6601
|
+
{ key: "above", value: "Add row above", disabled: !onInsertRow, onClick: () => onInsertRow?.(ri) },
|
|
6602
|
+
{ key: "below", value: "Add row below", disabled: !onInsertRow, onClick: () => onInsertRow?.(Math.min(rows.length, ri + 1)) },
|
|
6603
|
+
{ key: "delete", value: "Delete row", disabled: !isData || !onDeleteRow, onClick: () => onDeleteRow?.(ri) }
|
|
6604
|
+
];
|
|
6605
|
+
}
|
|
6606
|
+
return [
|
|
6607
|
+
{ key: "copy", value: "Copy", onClick: () => void copyCell() },
|
|
6608
|
+
{ key: "cut", value: "Cut", disabled: !editable, onClick: () => void cutCell() },
|
|
6609
|
+
{ key: "paste", value: "Paste", disabled: !editable, onClick: () => void pasteCell() }
|
|
6610
|
+
];
|
|
6611
|
+
}, [ctxTarget, rows.length, editable, onInsertRow, onDeleteRow, copyCell, cutCell, pasteCell, order]);
|
|
6612
|
+
const rowHighlighted = (disp) => hoveredRow === disp || selected?.disp === disp;
|
|
6613
|
+
const gridInner = /* @__PURE__ */ jsxs("div", { style: { position: "relative", width: gutter + totalWidth + END_PAD, height: headerHeight + totalHeight + END_PAD }, children: [
|
|
6614
|
+
rowNumbers && /* @__PURE__ */ jsx(
|
|
6615
|
+
"div",
|
|
6616
|
+
{
|
|
6617
|
+
className: "border-b border-r border-border bg-surface",
|
|
6618
|
+
style: { position: "absolute", top: scroll.top, left: scroll.left, width: gutter, height: headerHeight, zIndex: 3 }
|
|
6619
|
+
}
|
|
6620
|
+
),
|
|
6621
|
+
visibleCols.map((ci) => {
|
|
6622
|
+
const c = columns[ci];
|
|
6623
|
+
const sortDir = sort?.key === c.key ? sort.dir : null;
|
|
6624
|
+
const canSort = colSortable(c);
|
|
6625
|
+
return /* @__PURE__ */ jsxs(
|
|
6626
|
+
"div",
|
|
6627
|
+
{
|
|
6628
|
+
role: "columnheader",
|
|
6629
|
+
"aria-sort": sortDir ? sortDir === "asc" ? "ascending" : "descending" : void 0,
|
|
6630
|
+
onClick: canSort ? () => toggleSort(c.key) : void 0,
|
|
6631
|
+
className: cx(
|
|
6632
|
+
"flex items-center gap-1 border-b border-r border-border bg-surface px-3 font-medium text-foreground-secondary",
|
|
6633
|
+
canSort && "cursor-pointer select-none hover:text-foreground"
|
|
6634
|
+
),
|
|
6635
|
+
style: {
|
|
6636
|
+
position: "absolute",
|
|
6637
|
+
top: scroll.top,
|
|
6638
|
+
left: gutter + offsets[ci],
|
|
6639
|
+
width: widths[ci],
|
|
6640
|
+
height: headerHeight,
|
|
6641
|
+
zIndex: 2,
|
|
6642
|
+
justifyContent: c.align === "right" ? "flex-end" : c.align === "center" ? "center" : "flex-start"
|
|
6643
|
+
},
|
|
6644
|
+
children: [
|
|
6645
|
+
/* @__PURE__ */ jsx("span", { className: "truncate", children: c.label ?? c.key }),
|
|
6646
|
+
canSort && /* @__PURE__ */ jsx(SortCaret, { dir: sortDir })
|
|
6647
|
+
]
|
|
6648
|
+
},
|
|
6649
|
+
`h-${c.key}`
|
|
6650
|
+
);
|
|
6651
|
+
}),
|
|
6652
|
+
rowNumbers && visibleRows.map((disp) => {
|
|
6653
|
+
const hi = rowHighlighted(disp);
|
|
6654
|
+
return /* @__PURE__ */ jsx(
|
|
6655
|
+
"div",
|
|
6656
|
+
{
|
|
6657
|
+
onMouseEnter: () => setHoveredRow(disp),
|
|
6658
|
+
onContextMenu: contextMenu ? () => setCtxTarget({ kind: "row", disp }) : void 0,
|
|
6659
|
+
className: cx(
|
|
6660
|
+
"flex items-center justify-center border-b border-r border-border bg-surface text-xs tabular-nums",
|
|
6661
|
+
hi ? "font-medium text-foreground" : "text-foreground-muted"
|
|
6662
|
+
),
|
|
6663
|
+
style: { position: "absolute", left: scroll.left, top: headerHeight + disp * rowHeight, width: gutter, height: rowHeight, zIndex: 1, backgroundColor: hi ? HILITE : void 0 },
|
|
6664
|
+
children: disp + 1
|
|
6665
|
+
},
|
|
6666
|
+
`g-${disp}`
|
|
6667
|
+
);
|
|
6668
|
+
}),
|
|
6669
|
+
visibleRows.map((disp) => {
|
|
6670
|
+
const ri = rowIndexForDisp(disp);
|
|
6671
|
+
const hi = rowHighlighted(disp);
|
|
6672
|
+
return visibleCols.map((ci) => {
|
|
6673
|
+
const c = columns[ci];
|
|
6674
|
+
const isEditing = editing?.disp === disp && editing?.col === ci;
|
|
6675
|
+
const isSelected = selected?.disp === disp && selected?.col === ci;
|
|
6676
|
+
const canEdit = c.editable ?? editable;
|
|
6677
|
+
return /* @__PURE__ */ jsx(
|
|
6678
|
+
"div",
|
|
6679
|
+
{
|
|
6680
|
+
role: "gridcell",
|
|
6681
|
+
"aria-selected": isSelected || void 0,
|
|
6682
|
+
onClick: () => setSelected({ disp, col: ci }),
|
|
6683
|
+
onDoubleClick: () => startEdit(disp, ci),
|
|
6684
|
+
onMouseEnter: () => setHoveredRow(disp),
|
|
6685
|
+
onContextMenu: contextMenu ? () => {
|
|
6686
|
+
setSelected({ disp, col: ci });
|
|
6687
|
+
setCtxTarget({ kind: "cell", disp });
|
|
6688
|
+
} : void 0,
|
|
6689
|
+
className: cx(
|
|
6690
|
+
"flex items-center border-b border-r border-border px-3",
|
|
6691
|
+
disp % 2 ? "bg-surface-raised" : "bg-surface",
|
|
6692
|
+
canEdit ? "cursor-text" : "cursor-default"
|
|
6693
|
+
),
|
|
6694
|
+
style: {
|
|
6695
|
+
position: "absolute",
|
|
6696
|
+
top: headerHeight + disp * rowHeight,
|
|
6697
|
+
left: gutter + offsets[ci],
|
|
6698
|
+
width: widths[ci],
|
|
6699
|
+
height: rowHeight,
|
|
6700
|
+
zIndex: isSelected ? 1 : void 0,
|
|
6701
|
+
backgroundColor: isSelected ? SELECT_BG : hi ? HILITE : void 0,
|
|
6702
|
+
boxShadow: isSelected ? SELECT_RING : void 0,
|
|
6703
|
+
justifyContent: c.align === "right" ? "flex-end" : c.align === "center" ? "center" : "flex-start"
|
|
6704
|
+
},
|
|
6705
|
+
children: isEditing ? /* @__PURE__ */ jsx(
|
|
6706
|
+
"input",
|
|
6707
|
+
{
|
|
6708
|
+
autoFocus: true,
|
|
6709
|
+
value: draft,
|
|
6710
|
+
onChange: (e) => setDraft(e.target.value),
|
|
6711
|
+
onBlur: commit,
|
|
6712
|
+
onKeyDown: (e) => {
|
|
6713
|
+
if (e.key === "Enter") commit();
|
|
6714
|
+
else if (e.key === "Escape") setEditing(null);
|
|
6715
|
+
},
|
|
6716
|
+
className: "h-full w-full bg-transparent text-foreground outline-none"
|
|
6717
|
+
}
|
|
6718
|
+
) : /* @__PURE__ */ jsx("span", { className: "truncate text-foreground", children: displayValue(rows[ri]?.[c.key] ?? "") })
|
|
6719
|
+
},
|
|
6720
|
+
`${disp}-${c.key}`
|
|
6721
|
+
);
|
|
6722
|
+
});
|
|
6723
|
+
})
|
|
6724
|
+
] });
|
|
6549
6725
|
return /* @__PURE__ */ jsxs(
|
|
6550
6726
|
"div",
|
|
6551
6727
|
{
|
|
6552
6728
|
ref: scrollRef,
|
|
6553
6729
|
onScroll: (e) => setScroll({ top: e.currentTarget.scrollTop, left: e.currentTarget.scrollLeft }),
|
|
6730
|
+
onMouseLeave: () => setHoveredRow(null),
|
|
6554
6731
|
className: cx("relative overflow-auto rounded-lg border border-border bg-surface-raised text-sm", className),
|
|
6555
6732
|
style: { height, width, ...style },
|
|
6556
6733
|
role: "grid",
|
|
6557
6734
|
"aria-rowcount": rows.length,
|
|
6558
6735
|
"aria-colcount": columns.length,
|
|
6559
6736
|
children: [
|
|
6560
|
-
/* @__PURE__ */
|
|
6561
|
-
rowNumbers && /* @__PURE__ */ jsx(
|
|
6562
|
-
"div",
|
|
6563
|
-
{
|
|
6564
|
-
className: "border-b border-r border-border bg-surface",
|
|
6565
|
-
style: { position: "absolute", top: scroll.top, left: scroll.left, width: gutter, height: headerHeight, zIndex: 3 }
|
|
6566
|
-
}
|
|
6567
|
-
),
|
|
6568
|
-
visibleCols.map((ci) => {
|
|
6569
|
-
const c = columns[ci];
|
|
6570
|
-
const sortDir = sort?.key === c.key ? sort.dir : null;
|
|
6571
|
-
const canSort = colSortable(c);
|
|
6572
|
-
return /* @__PURE__ */ jsxs(
|
|
6573
|
-
"div",
|
|
6574
|
-
{
|
|
6575
|
-
role: "columnheader",
|
|
6576
|
-
"aria-sort": sortDir ? sortDir === "asc" ? "ascending" : "descending" : void 0,
|
|
6577
|
-
onClick: canSort ? () => toggleSort(c.key) : void 0,
|
|
6578
|
-
className: cx(
|
|
6579
|
-
"flex items-center gap-1 border-b border-r border-border bg-surface px-3 font-medium text-foreground-secondary",
|
|
6580
|
-
canSort && "cursor-pointer select-none hover:text-foreground"
|
|
6581
|
-
),
|
|
6582
|
-
style: {
|
|
6583
|
-
position: "absolute",
|
|
6584
|
-
top: scroll.top,
|
|
6585
|
-
left: gutter + offsets[ci],
|
|
6586
|
-
width: widths[ci],
|
|
6587
|
-
height: headerHeight,
|
|
6588
|
-
zIndex: 2,
|
|
6589
|
-
justifyContent: c.align === "right" ? "flex-end" : c.align === "center" ? "center" : "flex-start"
|
|
6590
|
-
},
|
|
6591
|
-
children: [
|
|
6592
|
-
/* @__PURE__ */ jsx("span", { className: "truncate", children: c.label ?? c.key }),
|
|
6593
|
-
canSort && /* @__PURE__ */ jsx(SortCaret, { dir: sortDir })
|
|
6594
|
-
]
|
|
6595
|
-
},
|
|
6596
|
-
`h-${c.key}`
|
|
6597
|
-
);
|
|
6598
|
-
}),
|
|
6599
|
-
rowNumbers && visibleRows.map((disp) => /* @__PURE__ */ jsx(
|
|
6600
|
-
"div",
|
|
6601
|
-
{
|
|
6602
|
-
className: "flex items-center justify-center border-b border-r border-border bg-surface text-xs tabular-nums text-foreground-muted",
|
|
6603
|
-
style: { position: "absolute", left: scroll.left, top: headerHeight + disp * rowHeight, width: gutter, height: rowHeight, zIndex: 1 },
|
|
6604
|
-
children: disp + 1
|
|
6605
|
-
},
|
|
6606
|
-
`g-${disp}`
|
|
6607
|
-
)),
|
|
6608
|
-
visibleRows.map((disp) => {
|
|
6609
|
-
const ri = rowIndexForDisp(disp);
|
|
6610
|
-
return visibleCols.map((ci) => {
|
|
6611
|
-
const c = columns[ci];
|
|
6612
|
-
const isEditing = editing?.disp === disp && editing?.col === ci;
|
|
6613
|
-
const canEdit = c.editable ?? editable;
|
|
6614
|
-
return /* @__PURE__ */ jsx(
|
|
6615
|
-
"div",
|
|
6616
|
-
{
|
|
6617
|
-
role: "gridcell",
|
|
6618
|
-
onDoubleClick: () => startEdit(disp, ci),
|
|
6619
|
-
className: cx(
|
|
6620
|
-
"flex items-center border-b border-r border-border px-3",
|
|
6621
|
-
disp % 2 ? "bg-surface-raised" : "bg-surface",
|
|
6622
|
-
canEdit && "cursor-text"
|
|
6623
|
-
),
|
|
6624
|
-
style: {
|
|
6625
|
-
position: "absolute",
|
|
6626
|
-
top: headerHeight + disp * rowHeight,
|
|
6627
|
-
left: gutter + offsets[ci],
|
|
6628
|
-
width: widths[ci],
|
|
6629
|
-
height: rowHeight,
|
|
6630
|
-
justifyContent: c.align === "right" ? "flex-end" : c.align === "center" ? "center" : "flex-start"
|
|
6631
|
-
},
|
|
6632
|
-
children: isEditing ? /* @__PURE__ */ jsx(
|
|
6633
|
-
"input",
|
|
6634
|
-
{
|
|
6635
|
-
autoFocus: true,
|
|
6636
|
-
value: draft,
|
|
6637
|
-
onChange: (e) => setDraft(e.target.value),
|
|
6638
|
-
onBlur: commit,
|
|
6639
|
-
onKeyDown: (e) => {
|
|
6640
|
-
if (e.key === "Enter") commit();
|
|
6641
|
-
else if (e.key === "Escape") setEditing(null);
|
|
6642
|
-
},
|
|
6643
|
-
className: "h-full w-full bg-transparent text-foreground outline-none"
|
|
6644
|
-
}
|
|
6645
|
-
) : /* @__PURE__ */ jsx("span", { className: "truncate text-foreground", children: displayValue(rows[ri]?.[c.key] ?? "") })
|
|
6646
|
-
},
|
|
6647
|
-
`${disp}-${c.key}`
|
|
6648
|
-
);
|
|
6649
|
-
});
|
|
6650
|
-
})
|
|
6651
|
-
] }),
|
|
6737
|
+
contextMenu ? /* @__PURE__ */ jsx(ContextMenu, { items: ctxItems, children: gridInner }) : gridInner,
|
|
6652
6738
|
displayRowCount === 0 && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center text-foreground-muted", style: { top: headerHeight }, children: emptyState })
|
|
6653
6739
|
]
|
|
6654
6740
|
}
|
|
6655
6741
|
);
|
|
6656
6742
|
}
|
|
6743
|
+
var HILITE = "color-mix(in srgb, var(--color-accent) 9%, transparent)";
|
|
6744
|
+
var SELECT_BG = "color-mix(in srgb, var(--color-accent) 16%, transparent)";
|
|
6745
|
+
var SELECT_RING = "inset 0 0 0 2px var(--color-accent)";
|
|
6657
6746
|
function SortCaret({ dir }) {
|
|
6658
6747
|
return /* @__PURE__ */ 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: [
|
|
6659
6748
|
/* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M5 6.5 8 3.5l3 3", className: dir === "asc" ? "text-accent" : "text-foreground-muted opacity-50" }),
|
|
@@ -6679,6 +6768,26 @@ function columnLetter(i) {
|
|
|
6679
6768
|
function blankSheet(name, cols = 8) {
|
|
6680
6769
|
return { name, columns: Array.from({ length: cols }, (_, i) => ({ key: columnLetter(i), label: columnLetter(i) })), rows: [] };
|
|
6681
6770
|
}
|
|
6771
|
+
function parseWorkbook(XLSX, bytes) {
|
|
6772
|
+
const wb = XLSX.read(bytes, { type: "array" });
|
|
6773
|
+
return wb.SheetNames.map((name) => {
|
|
6774
|
+
const ws = wb.Sheets[name];
|
|
6775
|
+
const aoa = XLSX.utils.sheet_to_json(ws, { header: 1, blankrows: false, defval: null });
|
|
6776
|
+
const headerRow = aoa[0] ?? [];
|
|
6777
|
+
const columns = headerRow.map((h, i) => ({
|
|
6778
|
+
key: h != null && String(h).length ? String(h) : `col_${i}`,
|
|
6779
|
+
label: h != null && String(h).length ? String(h) : `Column ${i + 1}`
|
|
6780
|
+
}));
|
|
6781
|
+
const rows = aoa.slice(1).map((r) => {
|
|
6782
|
+
const rec = {};
|
|
6783
|
+
columns.forEach((c, i) => {
|
|
6784
|
+
rec[c.key] = r[i] ?? null;
|
|
6785
|
+
});
|
|
6786
|
+
return rec;
|
|
6787
|
+
});
|
|
6788
|
+
return { name, columns, rows };
|
|
6789
|
+
});
|
|
6790
|
+
}
|
|
6682
6791
|
function toPlainRows(sheet, columns) {
|
|
6683
6792
|
return sheet.rows.map((row) => {
|
|
6684
6793
|
const out = {};
|
|
@@ -6737,24 +6846,7 @@ function Spreadsheet({
|
|
|
6737
6846
|
try {
|
|
6738
6847
|
const bytes = await sourceToBytes(source, remote);
|
|
6739
6848
|
const XLSX = await loadXlsx();
|
|
6740
|
-
const
|
|
6741
|
-
const parsed = wb.SheetNames.map((name) => {
|
|
6742
|
-
const ws = wb.Sheets[name];
|
|
6743
|
-
const aoa = XLSX.utils.sheet_to_json(ws, { header: 1, blankrows: false, defval: null });
|
|
6744
|
-
const headerRow = aoa[0] ?? [];
|
|
6745
|
-
const columns2 = headerRow.map((h, i) => ({
|
|
6746
|
-
key: h != null && String(h).length ? String(h) : `col_${i}`,
|
|
6747
|
-
label: h != null && String(h).length ? String(h) : `Column ${i + 1}`
|
|
6748
|
-
}));
|
|
6749
|
-
const rows = aoa.slice(1).map((r) => {
|
|
6750
|
-
const rec = {};
|
|
6751
|
-
columns2.forEach((c, i) => {
|
|
6752
|
-
rec[c.key] = r[i] ?? null;
|
|
6753
|
-
});
|
|
6754
|
-
return rec;
|
|
6755
|
-
});
|
|
6756
|
-
return { name, columns: columns2, rows };
|
|
6757
|
-
});
|
|
6849
|
+
const parsed = parseWorkbook(XLSX, bytes);
|
|
6758
6850
|
if (cancelled) return;
|
|
6759
6851
|
setSheets(parsed);
|
|
6760
6852
|
setActive(0);
|
|
@@ -6804,6 +6896,63 @@ function Spreadsheet({
|
|
|
6804
6896
|
return next;
|
|
6805
6897
|
});
|
|
6806
6898
|
}, [onChange]);
|
|
6899
|
+
const deleteSheet = useCallback((index) => {
|
|
6900
|
+
if (!sheets || sheets.length <= 1) return;
|
|
6901
|
+
const next = sheets.filter((_, i) => i !== index);
|
|
6902
|
+
setSheets(next);
|
|
6903
|
+
setActive((a) => Math.max(0, Math.min(index < a ? a - 1 : a, next.length - 1)));
|
|
6904
|
+
onChange?.(next);
|
|
6905
|
+
}, [sheets, onChange]);
|
|
6906
|
+
const add100Rows = useCallback(() => {
|
|
6907
|
+
setSheets((prev) => {
|
|
6908
|
+
if (!prev) return prev;
|
|
6909
|
+
const next = prev.map((s, i) => i === active ? { ...s, rows: [...s.rows, ...Array.from({ length: 100 }, () => ({}))] } : s);
|
|
6910
|
+
onChange?.(next);
|
|
6911
|
+
return next;
|
|
6912
|
+
});
|
|
6913
|
+
}, [active, onChange]);
|
|
6914
|
+
const insertRow = useCallback((index) => {
|
|
6915
|
+
setSheets((prev) => {
|
|
6916
|
+
if (!prev) return prev;
|
|
6917
|
+
const next = prev.map((s, i) => {
|
|
6918
|
+
if (i !== active) return s;
|
|
6919
|
+
const rows = [...s.rows];
|
|
6920
|
+
rows.splice(Math.max(0, Math.min(index, rows.length)), 0, {});
|
|
6921
|
+
return { ...s, rows };
|
|
6922
|
+
});
|
|
6923
|
+
onChange?.(next);
|
|
6924
|
+
return next;
|
|
6925
|
+
});
|
|
6926
|
+
}, [active, onChange]);
|
|
6927
|
+
const deleteRow = useCallback((index) => {
|
|
6928
|
+
setSheets((prev) => {
|
|
6929
|
+
if (!prev) return prev;
|
|
6930
|
+
const next = prev.map((s, i) => i === active && index < s.rows.length ? { ...s, rows: s.rows.filter((_, r) => r !== index) } : s);
|
|
6931
|
+
onChange?.(next);
|
|
6932
|
+
return next;
|
|
6933
|
+
});
|
|
6934
|
+
}, [active, onChange]);
|
|
6935
|
+
const fileInputRef = useRef(null);
|
|
6936
|
+
const openFile = () => fileInputRef.current?.click();
|
|
6937
|
+
const onFilePicked = useCallback(async (e) => {
|
|
6938
|
+
const file = e.target.files?.[0];
|
|
6939
|
+
e.target.value = "";
|
|
6940
|
+
if (!file) return;
|
|
6941
|
+
setStatus("loading");
|
|
6942
|
+
setError(null);
|
|
6943
|
+
try {
|
|
6944
|
+
const bytes = new Uint8Array(await file.arrayBuffer());
|
|
6945
|
+
const XLSX = await loadXlsx();
|
|
6946
|
+
const parsed = parseWorkbook(XLSX, bytes);
|
|
6947
|
+
setSheets(parsed);
|
|
6948
|
+
setActive(0);
|
|
6949
|
+
setStatus("ready");
|
|
6950
|
+
onChange?.(parsed);
|
|
6951
|
+
} catch (err) {
|
|
6952
|
+
setError(err);
|
|
6953
|
+
setStatus("error");
|
|
6954
|
+
}
|
|
6955
|
+
}, [onChange]);
|
|
6807
6956
|
const baseName = useMemo(
|
|
6808
6957
|
() => (fileName || (typeof source === "object" && "name" in source ? sourceName(source) : null) || "spreadsheet").replace(/\.[^.]+$/, ""),
|
|
6809
6958
|
[fileName, source]
|
|
@@ -6890,40 +7039,37 @@ function Spreadsheet({
|
|
|
6890
7039
|
}
|
|
6891
7040
|
const formats = exportFormats || [];
|
|
6892
7041
|
const exportLabels = {
|
|
6893
|
-
xlsx: "Excel
|
|
6894
|
-
csv: "CSV
|
|
6895
|
-
pdf: "PDF
|
|
7042
|
+
xlsx: "Excel (.xlsx)",
|
|
7043
|
+
csv: "CSV (.csv)",
|
|
7044
|
+
pdf: "PDF (.pdf)"
|
|
6896
7045
|
};
|
|
7046
|
+
const fileItems = [
|
|
7047
|
+
{ key: "open", label: "Open", onSelect: openFile },
|
|
7048
|
+
...formats.length > 0 ? [{ key: "export", label: "Export", separatorBefore: true, children: formats.map((fmt) => ({ key: fmt, label: exportLabels[fmt], onSelect: () => runExport(fmt) })) }] : []
|
|
7049
|
+
];
|
|
7050
|
+
const sheetItems = [
|
|
7051
|
+
{ key: "add", label: "Add Sheet", onSelect: addSheet },
|
|
7052
|
+
{ key: "delete", label: "Delete Sheet", danger: true, disabled: sheets.length <= 1, onSelect: () => deleteSheet(active) },
|
|
7053
|
+
{ key: "add100", label: "Add 100 rows", separatorBefore: true, onSelect: add100Rows }
|
|
7054
|
+
];
|
|
7055
|
+
const canDeleteSheet = editable && sheets.length > 1;
|
|
6897
7056
|
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: [
|
|
6898
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-shrink-0 items-center gap-
|
|
6899
|
-
/* @__PURE__ */ jsx(
|
|
6900
|
-
/* @__PURE__ */
|
|
6901
|
-
plainRows.length.toLocaleString(),
|
|
6902
|
-
" ",
|
|
6903
|
-
plainRows.length === 1 ? "row" : "rows",
|
|
6904
|
-
" \xB7 ",
|
|
6905
|
-
columns.length,
|
|
6906
|
-
" cols"
|
|
6907
|
-
] }),
|
|
6908
|
-
formats.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
6909
|
-
/* @__PURE__ */ jsx("span", { className: "h-5 w-px flex-shrink-0 bg-border", "aria-hidden": "true" }),
|
|
6910
|
-
/* @__PURE__ */ jsx(
|
|
6911
|
-
MenuButton,
|
|
6912
|
-
{
|
|
6913
|
-
label: "Export",
|
|
6914
|
-
size: "sm",
|
|
6915
|
-
variant: "outline",
|
|
6916
|
-
align: "end",
|
|
6917
|
-
icon: /* @__PURE__ */ jsx(DownloadIcon2, {}),
|
|
6918
|
-
items: formats.map((fmt) => ({
|
|
6919
|
-
key: fmt,
|
|
6920
|
-
label: exportLabels[fmt],
|
|
6921
|
-
onSelect: () => runExport(fmt)
|
|
6922
|
-
}))
|
|
6923
|
-
}
|
|
6924
|
-
)
|
|
6925
|
-
] })
|
|
7057
|
+
/* @__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: [
|
|
7058
|
+
/* @__PURE__ */ jsx(MenuButton, { label: "File", variant: "ghost", size: "sm", hideChevron: true, items: fileItems }),
|
|
7059
|
+
editable && /* @__PURE__ */ jsx(MenuButton, { label: "Sheet", variant: "ghost", size: "sm", hideChevron: true, items: sheetItems })
|
|
6926
7060
|
] }),
|
|
7061
|
+
/* @__PURE__ */ jsx(
|
|
7062
|
+
"input",
|
|
7063
|
+
{
|
|
7064
|
+
ref: fileInputRef,
|
|
7065
|
+
type: "file",
|
|
7066
|
+
accept: ".xlsx,.xls,.csv,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
7067
|
+
onChange: onFilePicked,
|
|
7068
|
+
className: "hidden",
|
|
7069
|
+
"aria-hidden": "true",
|
|
7070
|
+
tabIndex: -1
|
|
7071
|
+
}
|
|
7072
|
+
),
|
|
6927
7073
|
/* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1", children: /* @__PURE__ */ jsx(
|
|
6928
7074
|
DataGrid,
|
|
6929
7075
|
{
|
|
@@ -6933,47 +7079,85 @@ function Spreadsheet({
|
|
|
6933
7079
|
sortable,
|
|
6934
7080
|
virtualize,
|
|
6935
7081
|
trailingRows: emptyRows,
|
|
7082
|
+
contextMenu: true,
|
|
7083
|
+
onInsertRow: editable ? insertRow : void 0,
|
|
7084
|
+
onDeleteRow: editable ? deleteRow : void 0,
|
|
6936
7085
|
onCellEdit: handleCellEdit,
|
|
6937
7086
|
height: "100%",
|
|
6938
7087
|
className: "!rounded-none !border-0"
|
|
6939
7088
|
},
|
|
6940
7089
|
active
|
|
6941
7090
|
) }),
|
|
6942
|
-
|
|
6943
|
-
/* @__PURE__ */
|
|
6944
|
-
|
|
6945
|
-
|
|
7091
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-shrink-0 items-center gap-2 border-t border-border bg-surface px-2 py-1", children: [
|
|
7092
|
+
/* @__PURE__ */ jsxs("div", { role: "tablist", "aria-label": "Sheets", className: "flex min-w-0 flex-1 items-center gap-1 overflow-x-auto", children: [
|
|
7093
|
+
sheets.map((s, i) => {
|
|
7094
|
+
const activeTab = i === active;
|
|
7095
|
+
const name = s.name || `Sheet ${i + 1}`;
|
|
7096
|
+
return /* @__PURE__ */ jsxs(
|
|
7097
|
+
"div",
|
|
7098
|
+
{
|
|
7099
|
+
role: "tab",
|
|
7100
|
+
tabIndex: 0,
|
|
7101
|
+
"aria-selected": activeTab,
|
|
7102
|
+
onClick: () => setActive(i),
|
|
7103
|
+
onKeyDown: (e) => {
|
|
7104
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
7105
|
+
e.preventDefault();
|
|
7106
|
+
setActive(i);
|
|
7107
|
+
}
|
|
7108
|
+
},
|
|
7109
|
+
className: cx(
|
|
7110
|
+
"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",
|
|
7111
|
+
"focus:outline-none focus-visible:ring-2 focus-visible:ring-accent",
|
|
7112
|
+
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"
|
|
7113
|
+
),
|
|
7114
|
+
children: [
|
|
7115
|
+
/* @__PURE__ */ jsx("span", { className: "max-w-[160px] truncate", children: name }),
|
|
7116
|
+
canDeleteSheet && /* @__PURE__ */ jsx(
|
|
7117
|
+
"button",
|
|
7118
|
+
{
|
|
7119
|
+
type: "button",
|
|
7120
|
+
title: "Delete sheet",
|
|
7121
|
+
"aria-label": `Delete ${name}`,
|
|
7122
|
+
onClick: (e) => {
|
|
7123
|
+
e.stopPropagation();
|
|
7124
|
+
deleteSheet(i);
|
|
7125
|
+
},
|
|
7126
|
+
className: cx(
|
|
7127
|
+
"flex h-4 w-4 items-center justify-center rounded text-foreground-muted transition-opacity hover:text-status-error",
|
|
7128
|
+
activeTab ? "opacity-100" : "opacity-0 group-hover:opacity-100"
|
|
7129
|
+
),
|
|
7130
|
+
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" }) })
|
|
7131
|
+
}
|
|
7132
|
+
)
|
|
7133
|
+
]
|
|
7134
|
+
},
|
|
7135
|
+
`${s.name}-${i}`
|
|
7136
|
+
);
|
|
7137
|
+
}),
|
|
7138
|
+
canAddSheet && /* @__PURE__ */ jsx(
|
|
6946
7139
|
"button",
|
|
6947
7140
|
{
|
|
6948
|
-
role: "tab",
|
|
6949
7141
|
type: "button",
|
|
6950
|
-
|
|
6951
|
-
|
|
6952
|
-
|
|
6953
|
-
|
|
6954
|
-
|
|
6955
|
-
|
|
6956
|
-
|
|
6957
|
-
|
|
6958
|
-
|
|
6959
|
-
|
|
6960
|
-
|
|
6961
|
-
|
|
6962
|
-
|
|
6963
|
-
|
|
6964
|
-
|
|
6965
|
-
|
|
6966
|
-
onClick: addSheet,
|
|
6967
|
-
title: "Add sheet",
|
|
6968
|
-
"aria-label": "Add sheet",
|
|
6969
|
-
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",
|
|
6970
|
-
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" }) })
|
|
6971
|
-
}
|
|
6972
|
-
)
|
|
7142
|
+
onClick: addSheet,
|
|
7143
|
+
title: "Add sheet",
|
|
7144
|
+
"aria-label": "Add sheet",
|
|
7145
|
+
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",
|
|
7146
|
+
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" }) })
|
|
7147
|
+
}
|
|
7148
|
+
)
|
|
7149
|
+
] }),
|
|
7150
|
+
/* @__PURE__ */ jsxs("span", { className: "hidden flex-shrink-0 text-xs tabular-nums text-foreground-muted sm:inline", children: [
|
|
7151
|
+
plainRows.length.toLocaleString(),
|
|
7152
|
+
" ",
|
|
7153
|
+
plainRows.length === 1 ? "row" : "rows",
|
|
7154
|
+
" \xB7 ",
|
|
7155
|
+
columns.length,
|
|
7156
|
+
" cols"
|
|
7157
|
+
] })
|
|
6973
7158
|
] })
|
|
6974
7159
|
] });
|
|
6975
7160
|
}
|
|
6976
|
-
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" }) });
|
|
6977
7161
|
function ThemeSwitch({ checked, onChange, label = "Toggle dark mode", className = "" }) {
|
|
6978
7162
|
const id = useId();
|
|
6979
7163
|
return /* @__PURE__ */ jsx("label", { htmlFor: id, className: `flex items-center gap-2 cursor-pointer select-none ${className}`.trim(), children: /* @__PURE__ */ jsx(
|
|
@@ -7061,15 +7245,15 @@ function FlyoutItems({ items }) {
|
|
|
7061
7245
|
child.badge !== void 0 && child.badge > 0 && /* @__PURE__ */ 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 })
|
|
7062
7246
|
] });
|
|
7063
7247
|
if (child.items?.length) {
|
|
7064
|
-
return /* @__PURE__ */ jsxs(
|
|
7065
|
-
/* @__PURE__ */ jsxs(
|
|
7248
|
+
return /* @__PURE__ */ jsxs(DropdownMenu.Sub, { children: [
|
|
7249
|
+
/* @__PURE__ */ jsxs(DropdownMenu.SubTrigger, { className: cls, children: [
|
|
7066
7250
|
label,
|
|
7067
7251
|
/* @__PURE__ */ 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__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "m9 6 6 6-6 6" }) })
|
|
7068
7252
|
] }),
|
|
7069
|
-
/* @__PURE__ */ jsx(
|
|
7253
|
+
/* @__PURE__ */ jsx(DropdownMenu.Portal, { children: /* @__PURE__ */ jsx(DropdownMenu.SubContent, { sideOffset: 6, collisionPadding: 8, className: FLYOUT_PANEL, children: /* @__PURE__ */ jsx(FlyoutItems, { items: child.items }) }) })
|
|
7070
7254
|
] }, child.key);
|
|
7071
7255
|
}
|
|
7072
|
-
return /* @__PURE__ */ jsx(
|
|
7256
|
+
return /* @__PURE__ */ jsx(DropdownMenu.Item, { onSelect: () => child.onClick?.(), className: cls, children: label }, child.key);
|
|
7073
7257
|
}) });
|
|
7074
7258
|
}
|
|
7075
7259
|
function CollapsedFlyout({ item, trigger }) {
|
|
@@ -7084,9 +7268,9 @@ function CollapsedFlyout({ item, trigger }) {
|
|
|
7084
7268
|
closeTimer.current = window.setTimeout(() => setOpen(false), 150);
|
|
7085
7269
|
};
|
|
7086
7270
|
React36.useEffect(() => () => window.clearTimeout(closeTimer.current), []);
|
|
7087
|
-
return /* @__PURE__ */ jsxs(
|
|
7271
|
+
return /* @__PURE__ */ jsxs(DropdownMenu.Root, { open, onOpenChange: setOpen, modal: false, children: [
|
|
7088
7272
|
/* @__PURE__ */ jsx(
|
|
7089
|
-
|
|
7273
|
+
DropdownMenu.Trigger,
|
|
7090
7274
|
{
|
|
7091
7275
|
asChild: true,
|
|
7092
7276
|
onPointerEnter: openNow,
|
|
@@ -7097,8 +7281,8 @@ function CollapsedFlyout({ item, trigger }) {
|
|
|
7097
7281
|
children: trigger
|
|
7098
7282
|
}
|
|
7099
7283
|
),
|
|
7100
|
-
/* @__PURE__ */ jsx(
|
|
7101
|
-
|
|
7284
|
+
/* @__PURE__ */ jsx(DropdownMenu.Portal, { children: /* @__PURE__ */ jsxs(
|
|
7285
|
+
DropdownMenu.Content,
|
|
7102
7286
|
{
|
|
7103
7287
|
side: "right",
|
|
7104
7288
|
align: "start",
|
|
@@ -7108,7 +7292,7 @@ function CollapsedFlyout({ item, trigger }) {
|
|
|
7108
7292
|
onPointerEnter: openNow,
|
|
7109
7293
|
onPointerLeave: closeSoon,
|
|
7110
7294
|
children: [
|
|
7111
|
-
/* @__PURE__ */ jsx(
|
|
7295
|
+
/* @__PURE__ */ jsx(DropdownMenu.Label, { className: "px-2.5 pb-1 pt-1.5 text-xs font-semibold text-foreground-muted", children: item.label }),
|
|
7112
7296
|
/* @__PURE__ */ jsx(FlyoutItems, { items: item.items })
|
|
7113
7297
|
]
|
|
7114
7298
|
}
|
|
@@ -9626,7 +9810,7 @@ function DatePicker({
|
|
|
9626
9810
|
},
|
|
9627
9811
|
"aria-label": view === "days" ? "Next month" : view === "months" ? "Next year" : "Next decade",
|
|
9628
9812
|
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",
|
|
9629
|
-
children: /* @__PURE__ */ jsx(
|
|
9813
|
+
children: /* @__PURE__ */ jsx(ChevronRight3, {})
|
|
9630
9814
|
}
|
|
9631
9815
|
)
|
|
9632
9816
|
] }),
|
|
@@ -9744,7 +9928,7 @@ function CalendarIcon() {
|
|
|
9744
9928
|
function ChevronLeft() {
|
|
9745
9929
|
return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "w-4 h-4", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M15 19l-7-7 7-7" }) });
|
|
9746
9930
|
}
|
|
9747
|
-
function
|
|
9931
|
+
function ChevronRight3() {
|
|
9748
9932
|
return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "w-4 h-4", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9 5l7 7-7 7" }) });
|
|
9749
9933
|
}
|
|
9750
9934
|
var LINE_HEIGHT_PX = 21;
|