@geomak/ui 7.11.0 → 7.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -6804,6 +6804,13 @@ function Spreadsheet({
6804
6804
  return next;
6805
6805
  });
6806
6806
  }, [onChange]);
6807
+ const deleteSheet = useCallback((index) => {
6808
+ if (!sheets || sheets.length <= 1) return;
6809
+ const next = sheets.filter((_, i) => i !== index);
6810
+ setSheets(next);
6811
+ setActive((a) => Math.max(0, Math.min(index < a ? a - 1 : a, next.length - 1)));
6812
+ onChange?.(next);
6813
+ }, [sheets, onChange]);
6807
6814
  const baseName = useMemo(
6808
6815
  () => (fileName || (typeof source === "object" && "name" in source ? sourceName(source) : null) || "spreadsheet").replace(/\.[^.]+$/, ""),
6809
6816
  [fileName, source]
@@ -6890,39 +6897,21 @@ function Spreadsheet({
6890
6897
  }
6891
6898
  const formats = exportFormats || [];
6892
6899
  const exportLabels = {
6893
- xlsx: "Excel workbook (.xlsx)",
6894
- csv: "CSV \u2014 this sheet (.csv)",
6895
- pdf: "PDF table (.pdf)"
6900
+ xlsx: "Export to Excel (.xlsx)",
6901
+ csv: "Export to CSV (.csv)",
6902
+ pdf: "Export to PDF (.pdf)"
6896
6903
  };
6904
+ const fileItems = formats.map((fmt) => ({ key: fmt, label: exportLabels[fmt], onSelect: () => runExport(fmt) }));
6905
+ const sheetItems = [
6906
+ { key: "insert", label: "Insert sheet", onSelect: addSheet },
6907
+ { key: "delete", label: "Delete sheet", danger: true, disabled: sheets.length <= 1, separatorBefore: true, onSelect: () => deleteSheet(active) }
6908
+ ];
6909
+ const showMenuBar = fileItems.length > 0 || editable;
6910
+ const canDeleteSheet = editable && sheets.length > 1;
6897
6911
  return /* @__PURE__ */ jsxs("div", { className: cx("flex flex-col overflow-hidden rounded-lg border border-border bg-surface-raised", className), style: { height, width, ...style }, children: [
6898
- /* @__PURE__ */ jsxs("div", { className: "flex flex-shrink-0 items-center gap-2 border-b border-border bg-surface px-3 py-1.5", children: [
6899
- /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate text-sm font-semibold text-foreground", children: sheet?.name || "Sheet 1" }),
6900
- /* @__PURE__ */ jsxs("span", { className: "hidden flex-shrink-0 text-xs tabular-nums text-foreground-muted sm:inline", children: [
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
- ] })
6912
+ showMenuBar && /* @__PURE__ */ jsxs("div", { className: "flex flex-shrink-0 items-center gap-0.5 border-b border-border bg-surface px-1.5 py-1", children: [
6913
+ fileItems.length > 0 && /* @__PURE__ */ jsx(MenuButton, { label: "File", variant: "ghost", size: "sm", hideChevron: true, items: fileItems }),
6914
+ editable && /* @__PURE__ */ jsx(MenuButton, { label: "Sheet", variant: "ghost", size: "sm", hideChevron: true, items: sheetItems })
6926
6915
  ] }),
6927
6916
  /* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1", children: /* @__PURE__ */ jsx(
6928
6917
  DataGrid,
@@ -6939,41 +6928,76 @@ function Spreadsheet({
6939
6928
  },
6940
6929
  active
6941
6930
  ) }),
6942
- (sheets.length > 1 || canAddSheet) && /* @__PURE__ */ jsxs("div", { className: "flex flex-shrink-0 items-center gap-1 border-t border-border bg-surface px-2 py-1", children: [
6943
- /* @__PURE__ */ jsx("div", { role: "tablist", "aria-label": "Sheets", className: "flex min-w-0 flex-1 items-center gap-1 overflow-x-auto", children: sheets.map((s, i) => {
6944
- const activeTab = i === active;
6945
- return /* @__PURE__ */ jsx(
6931
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-shrink-0 items-center gap-2 border-t border-border bg-surface px-2 py-1", children: [
6932
+ /* @__PURE__ */ jsxs("div", { role: "tablist", "aria-label": "Sheets", className: "flex min-w-0 flex-1 items-center gap-1 overflow-x-auto", children: [
6933
+ sheets.map((s, i) => {
6934
+ const activeTab = i === active;
6935
+ const name = s.name || `Sheet ${i + 1}`;
6936
+ return /* @__PURE__ */ jsxs(
6937
+ "div",
6938
+ {
6939
+ role: "tab",
6940
+ tabIndex: 0,
6941
+ "aria-selected": activeTab,
6942
+ onClick: () => setActive(i),
6943
+ onKeyDown: (e) => {
6944
+ if (e.key === "Enter" || e.key === " ") {
6945
+ e.preventDefault();
6946
+ setActive(i);
6947
+ }
6948
+ },
6949
+ className: cx(
6950
+ "group flex flex-shrink-0 cursor-pointer items-center gap-1 rounded-t-md border-t-2 px-3 py-1 text-xs transition-colors",
6951
+ "focus:outline-none focus-visible:ring-2 focus-visible:ring-accent",
6952
+ activeTab ? "border-t-accent bg-surface-raised font-semibold text-foreground shadow-sm" : "border-t-transparent font-medium text-foreground-secondary hover:bg-surface-raised hover:text-foreground"
6953
+ ),
6954
+ children: [
6955
+ /* @__PURE__ */ jsx("span", { className: "max-w-[160px] truncate", children: name }),
6956
+ canDeleteSheet && /* @__PURE__ */ jsx(
6957
+ "button",
6958
+ {
6959
+ type: "button",
6960
+ title: "Delete sheet",
6961
+ "aria-label": `Delete ${name}`,
6962
+ onClick: (e) => {
6963
+ e.stopPropagation();
6964
+ deleteSheet(i);
6965
+ },
6966
+ className: cx(
6967
+ "flex h-4 w-4 items-center justify-center rounded text-foreground-muted transition-opacity hover:text-status-error",
6968
+ activeTab ? "opacity-100" : "opacity-0 group-hover:opacity-100"
6969
+ ),
6970
+ children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2.5, className: "h-3 w-3", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", d: "M6 6l12 12M18 6 6 18" }) })
6971
+ }
6972
+ )
6973
+ ]
6974
+ },
6975
+ `${s.name}-${i}`
6976
+ );
6977
+ }),
6978
+ canAddSheet && /* @__PURE__ */ jsx(
6946
6979
  "button",
6947
6980
  {
6948
- role: "tab",
6949
6981
  type: "button",
6950
- "aria-selected": activeTab,
6951
- onClick: () => setActive(i),
6952
- className: cx(
6953
- "flex-shrink-0 rounded-t-md border-t-2 px-3 py-1 text-xs transition-colors",
6954
- "focus:outline-none focus-visible:ring-2 focus-visible:ring-accent",
6955
- 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"
6956
- ),
6957
- children: s.name || `Sheet ${i + 1}`
6958
- },
6959
- `${s.name}-${i}`
6960
- );
6961
- }) }),
6962
- canAddSheet && /* @__PURE__ */ jsx(
6963
- "button",
6964
- {
6965
- type: "button",
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
- )
6982
+ onClick: addSheet,
6983
+ title: "Add sheet",
6984
+ "aria-label": "Add sheet",
6985
+ className: "flex h-6 w-6 flex-shrink-0 items-center justify-center rounded-md text-foreground-muted transition-colors hover:bg-surface-raised hover:text-foreground focus:outline-none focus-visible:ring-2 focus-visible:ring-accent",
6986
+ children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "h-4 w-4", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", d: "M12 5v14M5 12h14" }) })
6987
+ }
6988
+ )
6989
+ ] }),
6990
+ /* @__PURE__ */ jsxs("span", { className: "hidden flex-shrink-0 text-xs tabular-nums text-foreground-muted sm:inline", children: [
6991
+ plainRows.length.toLocaleString(),
6992
+ " ",
6993
+ plainRows.length === 1 ? "row" : "rows",
6994
+ " \xB7 ",
6995
+ columns.length,
6996
+ " cols"
6997
+ ] })
6973
6998
  ] })
6974
6999
  ] });
6975
7000
  }
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
7001
  function ThemeSwitch({ checked, onChange, label = "Toggle dark mode", className = "" }) {
6978
7002
  const id = useId();
6979
7003
  return /* @__PURE__ */ jsx("label", { htmlFor: id, className: `flex items-center gap-2 cursor-pointer select-none ${className}`.trim(), children: /* @__PURE__ */ jsx(