@geomak/ui 7.12.0 → 7.14.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.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 DropdownMenu2 from '@radix-ui/react-dropdown-menu';
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(DropdownMenu2.Root, { children: [
647
- /* @__PURE__ */ jsx(DropdownMenu2.Trigger, { asChild: true, children: /* @__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(DropdownMenu2.Portal, { children: /* @__PURE__ */ jsx(
662
- DropdownMenu2.Content,
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(DropdownMenu2.Separator, { className: "my-1 h-px bg-border" }),
675
- /* @__PURE__ */ jsxs(
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 Label2 = ({ step, state, align }) => /* @__PURE__ */ jsxs("div", { className: align === "center" ? "mt-2 text-center" : "pt-0.5", children: [
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(Label2, { step, state, align: "left" })) })
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(Label2, { step, state, align: "center" })
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) => renderItem(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 renderItem(item) {
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(ChevronRight, {})
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) => renderItem(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 ChevronRight() {
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: renderItem2,
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: renderItem2(item, index)
5933
+ children: renderItem3(item, index)
5916
5934
  },
5917
5935
  getKey ? getKey(item, index) : index
5918
5936
  );
@@ -6453,6 +6471,15 @@ function displayValue(v) {
6453
6471
  if (v == null) return "";
6454
6472
  return String(v);
6455
6473
  }
6474
+ function colLetter(i) {
6475
+ let s = "";
6476
+ let n = i;
6477
+ do {
6478
+ s = String.fromCharCode(65 + n % 26) + s;
6479
+ n = Math.floor(n / 26) - 1;
6480
+ } while (n >= 0);
6481
+ return s;
6482
+ }
6456
6483
  function DataGrid({
6457
6484
  columns,
6458
6485
  rows,
@@ -6468,7 +6495,12 @@ function DataGrid({
6468
6495
  overscan = 4,
6469
6496
  rowNumbers = true,
6470
6497
  trailingRows = 0,
6498
+ trailingCols = 0,
6471
6499
  onCellEdit,
6500
+ contextMenu = false,
6501
+ onInsertRow,
6502
+ onDeleteRow,
6503
+ onInsertColumn,
6472
6504
  className = "",
6473
6505
  style,
6474
6506
  emptyState = "No data"
@@ -6476,14 +6508,25 @@ function DataGrid({
6476
6508
  const scrollRef = useRef(null);
6477
6509
  const [scroll, setScroll] = useState({ top: 0, left: 0 });
6478
6510
  const [viewport, setViewport] = useState({ w: 0, h: 0 });
6511
+ const [selected, setSelected] = useState(null);
6512
+ const [hoveredRow, setHoveredRow] = useState(null);
6513
+ const [ctxTarget, setCtxTarget] = useState(null);
6479
6514
  const [editing, setEditing] = useState(null);
6480
6515
  const [draft, setDraft] = useState("");
6481
6516
  const [internalSort, setInternalSort] = useState(null);
6482
6517
  const sort = sortProp !== void 0 ? sortProp : internalSort;
6483
6518
  const gutter = rowNumbers ? GUTTER : 0;
6484
6519
  const colSortable = (c) => c.sortable ?? sortable;
6520
+ const cols = useMemo(() => {
6521
+ if (trailingCols <= 0) return columns;
6522
+ const extra = Array.from({ length: trailingCols }, (_, k) => {
6523
+ const idx = columns.length + k;
6524
+ return { key: `__c${idx}`, label: colLetter(idx), editable: false, sortable: false };
6525
+ });
6526
+ return [...columns, ...extra];
6527
+ }, [columns, trailingCols]);
6485
6528
  const { widths, offsets, totalWidth } = useMemo(() => {
6486
- const widths2 = columns.map((c) => resolveWidth(c.width));
6529
+ const widths2 = cols.map((c) => resolveWidth(c.width));
6487
6530
  const offsets2 = [];
6488
6531
  let acc = 0;
6489
6532
  for (const w of widths2) {
@@ -6491,7 +6534,7 @@ function DataGrid({
6491
6534
  acc += w;
6492
6535
  }
6493
6536
  return { widths: widths2, offsets: offsets2, totalWidth: acc };
6494
- }, [columns]);
6537
+ }, [cols]);
6495
6538
  const order = useMemo(() => {
6496
6539
  const idx = rows.map((_, i) => i);
6497
6540
  if (!sort) return idx;
@@ -6520,140 +6563,213 @@ function DataGrid({
6520
6563
  const rowStart = virtualize ? Math.max(0, Math.floor(scroll.top / rowHeight) - overscan) : 0;
6521
6564
  const rowEnd = virtualize ? Math.min(displayRowCount, Math.ceil((scroll.top + bodyH) / rowHeight) + overscan) : displayRowCount;
6522
6565
  let colStart = 0;
6523
- let colEnd = columns.length;
6566
+ let colEnd = cols.length;
6524
6567
  if (virtualize && viewport.w) {
6525
6568
  const viewLeft = scroll.left;
6526
6569
  const viewRight = scroll.left + (viewport.w - gutter);
6527
6570
  colStart = Math.max(0, offsets.findIndex((o, i) => o + widths[i] > viewLeft));
6528
6571
  if (colStart < 0) colStart = 0;
6529
6572
  colEnd = offsets.findIndex((o) => o > viewRight);
6530
- colEnd = colEnd === -1 ? columns.length : Math.min(columns.length, colEnd + 1);
6573
+ colEnd = colEnd === -1 ? cols.length : Math.min(cols.length, colEnd + 1);
6531
6574
  colStart = Math.max(0, colStart - overscan);
6532
- colEnd = Math.min(columns.length, colEnd + overscan);
6575
+ colEnd = Math.min(cols.length, colEnd + overscan);
6533
6576
  }
6534
6577
  const visibleRows = Array.from({ length: Math.max(0, rowEnd - rowStart) }, (_, i) => rowStart + i);
6535
6578
  const visibleCols = Array.from({ length: Math.max(0, colEnd - colStart) }, (_, i) => colStart + i);
6536
6579
  const commit = useCallback(() => {
6537
6580
  if (!editing) return;
6538
- const col = columns[editing.col];
6581
+ const col = cols[editing.col];
6539
6582
  const ri = editing.disp < rows.length ? order[editing.disp] : editing.disp;
6540
6583
  onCellEdit?.({ row: ri, column: col.key, value: draft });
6541
6584
  setEditing(null);
6542
- }, [editing, columns, draft, onCellEdit, order, rows.length]);
6585
+ }, [editing, cols, draft, onCellEdit, order, rows.length]);
6543
6586
  const startEdit = (disp, col) => {
6544
- const c = columns[col];
6587
+ const c = cols[col];
6545
6588
  if (!(c.editable ?? editable)) return;
6546
6589
  setDraft(displayValue(rows[rowIndexForDisp(disp)]?.[c.key] ?? ""));
6547
6590
  setEditing({ disp, col });
6548
6591
  };
6592
+ const cellText = (sel) => displayValue(rows[rowIndexForDisp(sel.disp)]?.[cols[sel.col].key] ?? "");
6593
+ const copyCell = useCallback(async () => {
6594
+ if (!selected) return;
6595
+ try {
6596
+ await navigator.clipboard?.writeText(cellText(selected));
6597
+ } catch {
6598
+ }
6599
+ }, [selected, rows, cols, order]);
6600
+ const cutCell = useCallback(async () => {
6601
+ if (!selected) return;
6602
+ await copyCell();
6603
+ onCellEdit?.({ row: rowIndexForDisp(selected.disp), column: cols[selected.col].key, value: "" });
6604
+ }, [selected, copyCell, onCellEdit, cols, order, rows.length]);
6605
+ const pasteCell = useCallback(async () => {
6606
+ if (!selected) return;
6607
+ let text = "";
6608
+ try {
6609
+ text = await navigator.clipboard?.readText() ?? "";
6610
+ } catch {
6611
+ return;
6612
+ }
6613
+ onCellEdit?.({ row: rowIndexForDisp(selected.disp), column: cols[selected.col].key, value: text });
6614
+ }, [selected, onCellEdit, cols, order, rows.length]);
6615
+ const ctxItems = useMemo(() => {
6616
+ if (ctxTarget?.kind === "header") {
6617
+ const ci = ctxTarget.col;
6618
+ return [
6619
+ { key: "left", value: "Add column to the left", disabled: !onInsertColumn, onClick: () => onInsertColumn?.(ci) },
6620
+ { key: "right", value: "Add column to the right", disabled: !onInsertColumn, onClick: () => onInsertColumn?.(ci + 1) }
6621
+ ];
6622
+ }
6623
+ if (ctxTarget?.kind === "row") {
6624
+ const ri = rowIndexForDisp(ctxTarget.disp);
6625
+ const isData = ctxTarget.disp < rows.length;
6626
+ return [
6627
+ { key: "above", value: "Add row above", disabled: !onInsertRow, onClick: () => onInsertRow?.(ri) },
6628
+ { key: "below", value: "Add row below", disabled: !onInsertRow, onClick: () => onInsertRow?.(Math.min(rows.length, ri + 1)) },
6629
+ { key: "delete", value: "Delete row", disabled: !isData || !onDeleteRow, onClick: () => onDeleteRow?.(ri) }
6630
+ ];
6631
+ }
6632
+ return [
6633
+ { key: "copy", value: "Copy", onClick: () => void copyCell() },
6634
+ { key: "cut", value: "Cut", disabled: !editable, onClick: () => void cutCell() },
6635
+ { key: "paste", value: "Paste", disabled: !editable, onClick: () => void pasteCell() }
6636
+ ];
6637
+ }, [ctxTarget, rows.length, editable, onInsertRow, onDeleteRow, onInsertColumn, copyCell, cutCell, pasteCell, order]);
6638
+ const rowHighlighted = (disp) => hoveredRow === disp || selected?.disp === disp;
6639
+ const gridInner = /* @__PURE__ */ jsxs("div", { style: { position: "relative", width: gutter + totalWidth + END_PAD, height: headerHeight + totalHeight + END_PAD }, children: [
6640
+ rowNumbers && /* @__PURE__ */ jsx(
6641
+ "div",
6642
+ {
6643
+ className: "border-b border-r border-border bg-surface",
6644
+ style: { position: "absolute", top: scroll.top, left: scroll.left, width: gutter, height: headerHeight, zIndex: 3 }
6645
+ }
6646
+ ),
6647
+ visibleCols.map((ci) => {
6648
+ const c = cols[ci];
6649
+ const sortDir = sort?.key === c.key ? sort.dir : null;
6650
+ const canSort = colSortable(c);
6651
+ return /* @__PURE__ */ jsxs(
6652
+ "div",
6653
+ {
6654
+ role: "columnheader",
6655
+ "aria-sort": sortDir ? sortDir === "asc" ? "ascending" : "descending" : void 0,
6656
+ onClick: canSort ? () => toggleSort(c.key) : void 0,
6657
+ onContextMenu: contextMenu ? () => setCtxTarget({ kind: "header", col: ci }) : void 0,
6658
+ className: cx(
6659
+ "flex items-center gap-1 border-b border-r border-border bg-surface px-3 font-medium text-foreground-secondary",
6660
+ canSort && "cursor-pointer select-none hover:text-foreground"
6661
+ ),
6662
+ style: {
6663
+ position: "absolute",
6664
+ top: scroll.top,
6665
+ left: gutter + offsets[ci],
6666
+ width: widths[ci],
6667
+ height: headerHeight,
6668
+ zIndex: 2,
6669
+ justifyContent: c.align === "right" ? "flex-end" : c.align === "center" ? "center" : "flex-start"
6670
+ },
6671
+ children: [
6672
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: c.label ?? c.key }),
6673
+ canSort && /* @__PURE__ */ jsx(SortCaret, { dir: sortDir })
6674
+ ]
6675
+ },
6676
+ `h-${c.key}`
6677
+ );
6678
+ }),
6679
+ rowNumbers && visibleRows.map((disp) => {
6680
+ const hi = rowHighlighted(disp);
6681
+ return /* @__PURE__ */ jsx(
6682
+ "div",
6683
+ {
6684
+ onMouseEnter: () => setHoveredRow(disp),
6685
+ onContextMenu: contextMenu ? () => setCtxTarget({ kind: "row", disp }) : void 0,
6686
+ className: cx(
6687
+ "flex items-center justify-center border-b border-r border-border bg-surface text-xs tabular-nums",
6688
+ hi ? "font-medium text-foreground" : "text-foreground-muted"
6689
+ ),
6690
+ style: { position: "absolute", left: scroll.left, top: headerHeight + disp * rowHeight, width: gutter, height: rowHeight, zIndex: 1, backgroundColor: hi ? HILITE : void 0 },
6691
+ children: disp + 1
6692
+ },
6693
+ `g-${disp}`
6694
+ );
6695
+ }),
6696
+ visibleRows.map((disp) => {
6697
+ const ri = rowIndexForDisp(disp);
6698
+ const hi = rowHighlighted(disp);
6699
+ return visibleCols.map((ci) => {
6700
+ const c = cols[ci];
6701
+ const isEditing = editing?.disp === disp && editing?.col === ci;
6702
+ const isSelected = selected?.disp === disp && selected?.col === ci;
6703
+ const canEdit = c.editable ?? editable;
6704
+ return /* @__PURE__ */ jsx(
6705
+ "div",
6706
+ {
6707
+ role: "gridcell",
6708
+ "aria-selected": isSelected || void 0,
6709
+ onClick: () => setSelected({ disp, col: ci }),
6710
+ onDoubleClick: () => startEdit(disp, ci),
6711
+ onMouseEnter: () => setHoveredRow(disp),
6712
+ onContextMenu: contextMenu ? () => {
6713
+ setSelected({ disp, col: ci });
6714
+ setCtxTarget({ kind: "cell", disp });
6715
+ } : void 0,
6716
+ className: cx(
6717
+ "flex items-center border-b border-r border-border px-3",
6718
+ disp % 2 ? "bg-surface-raised" : "bg-surface",
6719
+ canEdit ? "cursor-text" : "cursor-default"
6720
+ ),
6721
+ style: {
6722
+ position: "absolute",
6723
+ top: headerHeight + disp * rowHeight,
6724
+ left: gutter + offsets[ci],
6725
+ width: widths[ci],
6726
+ height: rowHeight,
6727
+ zIndex: isSelected ? 1 : void 0,
6728
+ backgroundColor: isSelected ? SELECT_BG : hi ? HILITE : void 0,
6729
+ boxShadow: isSelected ? SELECT_RING : void 0,
6730
+ justifyContent: c.align === "right" ? "flex-end" : c.align === "center" ? "center" : "flex-start"
6731
+ },
6732
+ children: isEditing ? /* @__PURE__ */ jsx(
6733
+ "input",
6734
+ {
6735
+ autoFocus: true,
6736
+ value: draft,
6737
+ onChange: (e) => setDraft(e.target.value),
6738
+ onBlur: commit,
6739
+ onKeyDown: (e) => {
6740
+ if (e.key === "Enter") commit();
6741
+ else if (e.key === "Escape") setEditing(null);
6742
+ },
6743
+ className: "h-full w-full bg-transparent text-foreground outline-none"
6744
+ }
6745
+ ) : /* @__PURE__ */ jsx("span", { className: "truncate text-foreground", children: displayValue(rows[ri]?.[c.key] ?? "") })
6746
+ },
6747
+ `${disp}-${c.key}`
6748
+ );
6749
+ });
6750
+ })
6751
+ ] });
6549
6752
  return /* @__PURE__ */ jsxs(
6550
6753
  "div",
6551
6754
  {
6552
6755
  ref: scrollRef,
6553
6756
  onScroll: (e) => setScroll({ top: e.currentTarget.scrollTop, left: e.currentTarget.scrollLeft }),
6757
+ onMouseLeave: () => setHoveredRow(null),
6554
6758
  className: cx("relative overflow-auto rounded-lg border border-border bg-surface-raised text-sm", className),
6555
6759
  style: { height, width, ...style },
6556
6760
  role: "grid",
6557
6761
  "aria-rowcount": rows.length,
6558
6762
  "aria-colcount": columns.length,
6559
6763
  children: [
6560
- /* @__PURE__ */ jsxs("div", { style: { position: "relative", width: gutter + totalWidth + END_PAD, height: headerHeight + totalHeight + END_PAD }, children: [
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
- ] }),
6764
+ contextMenu ? /* @__PURE__ */ jsx(ContextMenu, { items: ctxItems, children: gridInner }) : gridInner,
6652
6765
  displayRowCount === 0 && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center text-foreground-muted", style: { top: headerHeight }, children: emptyState })
6653
6766
  ]
6654
6767
  }
6655
6768
  );
6656
6769
  }
6770
+ var HILITE = "color-mix(in srgb, var(--color-accent) 9%, transparent)";
6771
+ var SELECT_BG = "color-mix(in srgb, var(--color-accent) 16%, transparent)";
6772
+ var SELECT_RING = "inset 0 0 0 2px var(--color-accent)";
6657
6773
  function SortCaret({ dir }) {
6658
6774
  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
6775
  /* @__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" }),
@@ -6676,8 +6792,44 @@ function columnLetter(i) {
6676
6792
  } while (n >= 0);
6677
6793
  return s;
6678
6794
  }
6795
+ function makeColumns(existing, count) {
6796
+ const used = new Set(existing.map((c) => c.key));
6797
+ const out = [];
6798
+ let n = existing.length;
6799
+ for (let k = 0; k < count; k++) {
6800
+ let key = columnLetter(n);
6801
+ while (used.has(key)) {
6802
+ n++;
6803
+ key = columnLetter(n);
6804
+ }
6805
+ used.add(key);
6806
+ out.push({ key, label: key });
6807
+ n++;
6808
+ }
6809
+ return out;
6810
+ }
6679
6811
  function blankSheet(name, cols = 8) {
6680
- return { name, columns: Array.from({ length: cols }, (_, i) => ({ key: columnLetter(i), label: columnLetter(i) })), rows: [] };
6812
+ return { name, columns: makeColumns([], cols), rows: [] };
6813
+ }
6814
+ function parseWorkbook(XLSX, bytes) {
6815
+ const wb = XLSX.read(bytes, { type: "array" });
6816
+ return wb.SheetNames.map((name) => {
6817
+ const ws = wb.Sheets[name];
6818
+ const aoa = XLSX.utils.sheet_to_json(ws, { header: 1, blankrows: false, defval: null });
6819
+ const headerRow = aoa[0] ?? [];
6820
+ const columns = headerRow.map((h, i) => ({
6821
+ key: h != null && String(h).length ? String(h) : `col_${i}`,
6822
+ label: h != null && String(h).length ? String(h) : `Column ${i + 1}`
6823
+ }));
6824
+ const rows = aoa.slice(1).map((r) => {
6825
+ const rec = {};
6826
+ columns.forEach((c, i) => {
6827
+ rec[c.key] = r[i] ?? null;
6828
+ });
6829
+ return rec;
6830
+ });
6831
+ return { name, columns, rows };
6832
+ });
6681
6833
  }
6682
6834
  function toPlainRows(sheet, columns) {
6683
6835
  return sheet.rows.map((row) => {
@@ -6712,6 +6864,7 @@ function Spreadsheet({
6712
6864
  virtualize = true,
6713
6865
  sortable = true,
6714
6866
  emptyRows = 50,
6867
+ emptyCols = 6,
6715
6868
  allowAddSheet,
6716
6869
  height = 480,
6717
6870
  width,
@@ -6737,24 +6890,7 @@ function Spreadsheet({
6737
6890
  try {
6738
6891
  const bytes = await sourceToBytes(source, remote);
6739
6892
  const XLSX = await loadXlsx();
6740
- const wb = XLSX.read(bytes, { type: "array" });
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
- });
6893
+ const parsed = parseWorkbook(XLSX, bytes);
6758
6894
  if (cancelled) return;
6759
6895
  setSheets(parsed);
6760
6896
  setActive(0);
@@ -6811,6 +6947,83 @@ function Spreadsheet({
6811
6947
  setActive((a) => Math.max(0, Math.min(index < a ? a - 1 : a, next.length - 1)));
6812
6948
  onChange?.(next);
6813
6949
  }, [sheets, onChange]);
6950
+ const add100Rows = useCallback(() => {
6951
+ setSheets((prev) => {
6952
+ if (!prev) return prev;
6953
+ const next = prev.map((s, i) => i === active ? { ...s, rows: [...s.rows, ...Array.from({ length: 100 }, () => ({}))] } : s);
6954
+ onChange?.(next);
6955
+ return next;
6956
+ });
6957
+ }, [active, onChange]);
6958
+ const add10Columns = useCallback(() => {
6959
+ setSheets((prev) => {
6960
+ if (!prev) return prev;
6961
+ const next = prev.map((s, i) => {
6962
+ if (i !== active) return s;
6963
+ const cols = toColumns(s.columns);
6964
+ return { ...s, columns: [...cols, ...makeColumns(cols, 10)] };
6965
+ });
6966
+ onChange?.(next);
6967
+ return next;
6968
+ });
6969
+ }, [active, onChange]);
6970
+ const insertColumn = useCallback((index) => {
6971
+ setSheets((prev) => {
6972
+ if (!prev) return prev;
6973
+ const next = prev.map((s, i) => {
6974
+ if (i !== active) return s;
6975
+ const cols = toColumns(s.columns);
6976
+ const at = Math.max(0, Math.min(index, cols.length));
6977
+ const out = [...cols];
6978
+ out.splice(at, 0, makeColumns(cols, 1)[0]);
6979
+ return { ...s, columns: out };
6980
+ });
6981
+ onChange?.(next);
6982
+ return next;
6983
+ });
6984
+ }, [active, onChange]);
6985
+ const insertRow = useCallback((index) => {
6986
+ setSheets((prev) => {
6987
+ if (!prev) return prev;
6988
+ const next = prev.map((s, i) => {
6989
+ if (i !== active) return s;
6990
+ const rows = [...s.rows];
6991
+ rows.splice(Math.max(0, Math.min(index, rows.length)), 0, {});
6992
+ return { ...s, rows };
6993
+ });
6994
+ onChange?.(next);
6995
+ return next;
6996
+ });
6997
+ }, [active, onChange]);
6998
+ const deleteRow = useCallback((index) => {
6999
+ setSheets((prev) => {
7000
+ if (!prev) return prev;
7001
+ const next = prev.map((s, i) => i === active && index < s.rows.length ? { ...s, rows: s.rows.filter((_, r) => r !== index) } : s);
7002
+ onChange?.(next);
7003
+ return next;
7004
+ });
7005
+ }, [active, onChange]);
7006
+ const fileInputRef = useRef(null);
7007
+ const openFile = () => fileInputRef.current?.click();
7008
+ const onFilePicked = useCallback(async (e) => {
7009
+ const file = e.target.files?.[0];
7010
+ e.target.value = "";
7011
+ if (!file) return;
7012
+ setStatus("loading");
7013
+ setError(null);
7014
+ try {
7015
+ const bytes = new Uint8Array(await file.arrayBuffer());
7016
+ const XLSX = await loadXlsx();
7017
+ const parsed = parseWorkbook(XLSX, bytes);
7018
+ setSheets(parsed);
7019
+ setActive(0);
7020
+ setStatus("ready");
7021
+ onChange?.(parsed);
7022
+ } catch (err) {
7023
+ setError(err);
7024
+ setStatus("error");
7025
+ }
7026
+ }, [onChange]);
6814
7027
  const baseName = useMemo(
6815
7028
  () => (fileName || (typeof source === "object" && "name" in source ? sourceName(source) : null) || "spreadsheet").replace(/\.[^.]+$/, ""),
6816
7029
  [fileName, source]
@@ -6897,22 +7110,38 @@ function Spreadsheet({
6897
7110
  }
6898
7111
  const formats = exportFormats || [];
6899
7112
  const exportLabels = {
6900
- xlsx: "Export to Excel (.xlsx)",
6901
- csv: "Export to CSV (.csv)",
6902
- pdf: "Export to PDF (.pdf)"
7113
+ xlsx: "Excel (.xlsx)",
7114
+ csv: "CSV (.csv)",
7115
+ pdf: "PDF (.pdf)"
6903
7116
  };
6904
- const fileItems = formats.map((fmt) => ({ key: fmt, label: exportLabels[fmt], onSelect: () => runExport(fmt) }));
7117
+ const fileItems = [
7118
+ { key: "open", label: "Open", onSelect: openFile },
7119
+ ...formats.length > 0 ? [{ key: "export", label: "Export", separatorBefore: true, children: formats.map((fmt) => ({ key: fmt, label: exportLabels[fmt], onSelect: () => runExport(fmt) })) }] : []
7120
+ ];
6905
7121
  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) }
7122
+ { key: "add", label: "Add Sheet", onSelect: addSheet },
7123
+ { key: "delete", label: "Delete Sheet", danger: true, disabled: sheets.length <= 1, onSelect: () => deleteSheet(active) },
7124
+ { key: "add100", label: "Add 100 rows", separatorBefore: true, onSelect: add100Rows },
7125
+ { key: "add10cols", label: "Add 10 columns", onSelect: add10Columns }
6908
7126
  ];
6909
- const showMenuBar = fileItems.length > 0 || editable;
6910
7127
  const canDeleteSheet = editable && sheets.length > 1;
6911
7128
  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: [
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 }),
7129
+ /* @__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: [
7130
+ /* @__PURE__ */ jsx(MenuButton, { label: "File", variant: "ghost", size: "sm", hideChevron: true, items: fileItems }),
6914
7131
  editable && /* @__PURE__ */ jsx(MenuButton, { label: "Sheet", variant: "ghost", size: "sm", hideChevron: true, items: sheetItems })
6915
7132
  ] }),
7133
+ /* @__PURE__ */ jsx(
7134
+ "input",
7135
+ {
7136
+ ref: fileInputRef,
7137
+ type: "file",
7138
+ accept: ".xlsx,.xls,.csv,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
7139
+ onChange: onFilePicked,
7140
+ className: "hidden",
7141
+ "aria-hidden": "true",
7142
+ tabIndex: -1
7143
+ }
7144
+ ),
6916
7145
  /* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1", children: /* @__PURE__ */ jsx(
6917
7146
  DataGrid,
6918
7147
  {
@@ -6922,6 +7151,11 @@ function Spreadsheet({
6922
7151
  sortable,
6923
7152
  virtualize,
6924
7153
  trailingRows: emptyRows,
7154
+ trailingCols: emptyCols,
7155
+ contextMenu: true,
7156
+ onInsertRow: editable ? insertRow : void 0,
7157
+ onDeleteRow: editable ? deleteRow : void 0,
7158
+ onInsertColumn: editable ? insertColumn : void 0,
6925
7159
  onCellEdit: handleCellEdit,
6926
7160
  height: "100%",
6927
7161
  className: "!rounded-none !border-0"
@@ -7085,15 +7319,15 @@ function FlyoutItems({ items }) {
7085
7319
  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 })
7086
7320
  ] });
7087
7321
  if (child.items?.length) {
7088
- return /* @__PURE__ */ jsxs(DropdownMenu2.Sub, { children: [
7089
- /* @__PURE__ */ jsxs(DropdownMenu2.SubTrigger, { className: cls, children: [
7322
+ return /* @__PURE__ */ jsxs(DropdownMenu.Sub, { children: [
7323
+ /* @__PURE__ */ jsxs(DropdownMenu.SubTrigger, { className: cls, children: [
7090
7324
  label,
7091
7325
  /* @__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" }) })
7092
7326
  ] }),
7093
- /* @__PURE__ */ jsx(DropdownMenu2.Portal, { children: /* @__PURE__ */ jsx(DropdownMenu2.SubContent, { sideOffset: 6, collisionPadding: 8, className: FLYOUT_PANEL, children: /* @__PURE__ */ jsx(FlyoutItems, { items: child.items }) }) })
7327
+ /* @__PURE__ */ jsx(DropdownMenu.Portal, { children: /* @__PURE__ */ jsx(DropdownMenu.SubContent, { sideOffset: 6, collisionPadding: 8, className: FLYOUT_PANEL, children: /* @__PURE__ */ jsx(FlyoutItems, { items: child.items }) }) })
7094
7328
  ] }, child.key);
7095
7329
  }
7096
- return /* @__PURE__ */ jsx(DropdownMenu2.Item, { onSelect: () => child.onClick?.(), className: cls, children: label }, child.key);
7330
+ return /* @__PURE__ */ jsx(DropdownMenu.Item, { onSelect: () => child.onClick?.(), className: cls, children: label }, child.key);
7097
7331
  }) });
7098
7332
  }
7099
7333
  function CollapsedFlyout({ item, trigger }) {
@@ -7108,9 +7342,9 @@ function CollapsedFlyout({ item, trigger }) {
7108
7342
  closeTimer.current = window.setTimeout(() => setOpen(false), 150);
7109
7343
  };
7110
7344
  React36.useEffect(() => () => window.clearTimeout(closeTimer.current), []);
7111
- return /* @__PURE__ */ jsxs(DropdownMenu2.Root, { open, onOpenChange: setOpen, modal: false, children: [
7345
+ return /* @__PURE__ */ jsxs(DropdownMenu.Root, { open, onOpenChange: setOpen, modal: false, children: [
7112
7346
  /* @__PURE__ */ jsx(
7113
- DropdownMenu2.Trigger,
7347
+ DropdownMenu.Trigger,
7114
7348
  {
7115
7349
  asChild: true,
7116
7350
  onPointerEnter: openNow,
@@ -7121,8 +7355,8 @@ function CollapsedFlyout({ item, trigger }) {
7121
7355
  children: trigger
7122
7356
  }
7123
7357
  ),
7124
- /* @__PURE__ */ jsx(DropdownMenu2.Portal, { children: /* @__PURE__ */ jsxs(
7125
- DropdownMenu2.Content,
7358
+ /* @__PURE__ */ jsx(DropdownMenu.Portal, { children: /* @__PURE__ */ jsxs(
7359
+ DropdownMenu.Content,
7126
7360
  {
7127
7361
  side: "right",
7128
7362
  align: "start",
@@ -7132,7 +7366,7 @@ function CollapsedFlyout({ item, trigger }) {
7132
7366
  onPointerEnter: openNow,
7133
7367
  onPointerLeave: closeSoon,
7134
7368
  children: [
7135
- /* @__PURE__ */ jsx(DropdownMenu2.Label, { className: "px-2.5 pb-1 pt-1.5 text-xs font-semibold text-foreground-muted", children: item.label }),
7369
+ /* @__PURE__ */ jsx(DropdownMenu.Label, { className: "px-2.5 pb-1 pt-1.5 text-xs font-semibold text-foreground-muted", children: item.label }),
7136
7370
  /* @__PURE__ */ jsx(FlyoutItems, { items: item.items })
7137
7371
  ]
7138
7372
  }
@@ -9650,7 +9884,7 @@ function DatePicker({
9650
9884
  },
9651
9885
  "aria-label": view === "days" ? "Next month" : view === "months" ? "Next year" : "Next decade",
9652
9886
  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",
9653
- children: /* @__PURE__ */ jsx(ChevronRight2, {})
9887
+ children: /* @__PURE__ */ jsx(ChevronRight3, {})
9654
9888
  }
9655
9889
  )
9656
9890
  ] }),
@@ -9768,7 +10002,7 @@ function CalendarIcon() {
9768
10002
  function ChevronLeft() {
9769
10003
  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" }) });
9770
10004
  }
9771
- function ChevronRight2() {
10005
+ function ChevronRight3() {
9772
10006
  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" }) });
9773
10007
  }
9774
10008
  var LINE_HEIGHT_PX = 21;