@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.cjs CHANGED
@@ -6840,6 +6840,13 @@ function Spreadsheet({
6840
6840
  return next;
6841
6841
  });
6842
6842
  }, [onChange]);
6843
+ const deleteSheet = React36.useCallback((index) => {
6844
+ if (!sheets || sheets.length <= 1) return;
6845
+ const next = sheets.filter((_, i) => i !== index);
6846
+ setSheets(next);
6847
+ setActive((a) => Math.max(0, Math.min(index < a ? a - 1 : a, next.length - 1)));
6848
+ onChange?.(next);
6849
+ }, [sheets, onChange]);
6843
6850
  const baseName = React36.useMemo(
6844
6851
  () => (fileName || (typeof source === "object" && "name" in source ? sourceName(source) : null) || "spreadsheet").replace(/\.[^.]+$/, ""),
6845
6852
  [fileName, source]
@@ -6926,39 +6933,21 @@ function Spreadsheet({
6926
6933
  }
6927
6934
  const formats = exportFormats || [];
6928
6935
  const exportLabels = {
6929
- xlsx: "Excel workbook (.xlsx)",
6930
- csv: "CSV \u2014 this sheet (.csv)",
6931
- pdf: "PDF table (.pdf)"
6936
+ xlsx: "Export to Excel (.xlsx)",
6937
+ csv: "Export to CSV (.csv)",
6938
+ pdf: "Export to PDF (.pdf)"
6932
6939
  };
6940
+ const fileItems = formats.map((fmt) => ({ key: fmt, label: exportLabels[fmt], onSelect: () => runExport(fmt) }));
6941
+ const sheetItems = [
6942
+ { key: "insert", label: "Insert sheet", onSelect: addSheet },
6943
+ { key: "delete", label: "Delete sheet", danger: true, disabled: sheets.length <= 1, separatorBefore: true, onSelect: () => deleteSheet(active) }
6944
+ ];
6945
+ const showMenuBar = fileItems.length > 0 || editable;
6946
+ const canDeleteSheet = editable && sheets.length > 1;
6933
6947
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cx("flex flex-col overflow-hidden rounded-lg border border-border bg-surface-raised", className), style: { height, width, ...style }, children: [
6934
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-shrink-0 items-center gap-2 border-b border-border bg-surface px-3 py-1.5", children: [
6935
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate text-sm font-semibold text-foreground", children: sheet?.name || "Sheet 1" }),
6936
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "hidden flex-shrink-0 text-xs tabular-nums text-foreground-muted sm:inline", children: [
6937
- plainRows.length.toLocaleString(),
6938
- " ",
6939
- plainRows.length === 1 ? "row" : "rows",
6940
- " \xB7 ",
6941
- columns.length,
6942
- " cols"
6943
- ] }),
6944
- formats.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
6945
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "h-5 w-px flex-shrink-0 bg-border", "aria-hidden": "true" }),
6946
- /* @__PURE__ */ jsxRuntime.jsx(
6947
- MenuButton,
6948
- {
6949
- label: "Export",
6950
- size: "sm",
6951
- variant: "outline",
6952
- align: "end",
6953
- icon: /* @__PURE__ */ jsxRuntime.jsx(DownloadIcon2, {}),
6954
- items: formats.map((fmt) => ({
6955
- key: fmt,
6956
- label: exportLabels[fmt],
6957
- onSelect: () => runExport(fmt)
6958
- }))
6959
- }
6960
- )
6961
- ] })
6948
+ showMenuBar && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-shrink-0 items-center gap-0.5 border-b border-border bg-surface px-1.5 py-1", children: [
6949
+ fileItems.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(MenuButton, { label: "File", variant: "ghost", size: "sm", hideChevron: true, items: fileItems }),
6950
+ editable && /* @__PURE__ */ jsxRuntime.jsx(MenuButton, { label: "Sheet", variant: "ghost", size: "sm", hideChevron: true, items: sheetItems })
6962
6951
  ] }),
6963
6952
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-0 flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(
6964
6953
  DataGrid,
@@ -6975,41 +6964,76 @@ function Spreadsheet({
6975
6964
  },
6976
6965
  active
6977
6966
  ) }),
6978
- (sheets.length > 1 || canAddSheet) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-shrink-0 items-center gap-1 border-t border-border bg-surface px-2 py-1", children: [
6979
- /* @__PURE__ */ jsxRuntime.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) => {
6980
- const activeTab = i === active;
6981
- return /* @__PURE__ */ jsxRuntime.jsx(
6967
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-shrink-0 items-center gap-2 border-t border-border bg-surface px-2 py-1", children: [
6968
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "tablist", "aria-label": "Sheets", className: "flex min-w-0 flex-1 items-center gap-1 overflow-x-auto", children: [
6969
+ sheets.map((s, i) => {
6970
+ const activeTab = i === active;
6971
+ const name = s.name || `Sheet ${i + 1}`;
6972
+ return /* @__PURE__ */ jsxRuntime.jsxs(
6973
+ "div",
6974
+ {
6975
+ role: "tab",
6976
+ tabIndex: 0,
6977
+ "aria-selected": activeTab,
6978
+ onClick: () => setActive(i),
6979
+ onKeyDown: (e) => {
6980
+ if (e.key === "Enter" || e.key === " ") {
6981
+ e.preventDefault();
6982
+ setActive(i);
6983
+ }
6984
+ },
6985
+ className: cx(
6986
+ "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",
6987
+ "focus:outline-none focus-visible:ring-2 focus-visible:ring-accent",
6988
+ 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"
6989
+ ),
6990
+ children: [
6991
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "max-w-[160px] truncate", children: name }),
6992
+ canDeleteSheet && /* @__PURE__ */ jsxRuntime.jsx(
6993
+ "button",
6994
+ {
6995
+ type: "button",
6996
+ title: "Delete sheet",
6997
+ "aria-label": `Delete ${name}`,
6998
+ onClick: (e) => {
6999
+ e.stopPropagation();
7000
+ deleteSheet(i);
7001
+ },
7002
+ className: cx(
7003
+ "flex h-4 w-4 items-center justify-center rounded text-foreground-muted transition-opacity hover:text-status-error",
7004
+ activeTab ? "opacity-100" : "opacity-0 group-hover:opacity-100"
7005
+ ),
7006
+ children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2.5, className: "h-3 w-3", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", d: "M6 6l12 12M18 6 6 18" }) })
7007
+ }
7008
+ )
7009
+ ]
7010
+ },
7011
+ `${s.name}-${i}`
7012
+ );
7013
+ }),
7014
+ canAddSheet && /* @__PURE__ */ jsxRuntime.jsx(
6982
7015
  "button",
6983
7016
  {
6984
- role: "tab",
6985
7017
  type: "button",
6986
- "aria-selected": activeTab,
6987
- onClick: () => setActive(i),
6988
- className: cx(
6989
- "flex-shrink-0 rounded-t-md border-t-2 px-3 py-1 text-xs transition-colors",
6990
- "focus:outline-none focus-visible:ring-2 focus-visible:ring-accent",
6991
- 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"
6992
- ),
6993
- children: s.name || `Sheet ${i + 1}`
6994
- },
6995
- `${s.name}-${i}`
6996
- );
6997
- }) }),
6998
- canAddSheet && /* @__PURE__ */ jsxRuntime.jsx(
6999
- "button",
7000
- {
7001
- type: "button",
7002
- onClick: addSheet,
7003
- title: "Add sheet",
7004
- "aria-label": "Add sheet",
7005
- className: "flex h-6 w-6 flex-shrink-0 items-center justify-center rounded-md text-foreground-muted transition-colors hover:bg-surface-raised hover:text-foreground focus:outline-none focus-visible:ring-2 focus-visible:ring-accent",
7006
- children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "h-4 w-4", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", d: "M12 5v14M5 12h14" }) })
7007
- }
7008
- )
7018
+ onClick: addSheet,
7019
+ title: "Add sheet",
7020
+ "aria-label": "Add sheet",
7021
+ 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",
7022
+ children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "h-4 w-4", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", d: "M12 5v14M5 12h14" }) })
7023
+ }
7024
+ )
7025
+ ] }),
7026
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "hidden flex-shrink-0 text-xs tabular-nums text-foreground-muted sm:inline", children: [
7027
+ plainRows.length.toLocaleString(),
7028
+ " ",
7029
+ plainRows.length === 1 ? "row" : "rows",
7030
+ " \xB7 ",
7031
+ columns.length,
7032
+ " cols"
7033
+ ] })
7009
7034
  ] })
7010
7035
  ] });
7011
7036
  }
7012
- var DownloadIcon2 = () => /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "h-4 w-4", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 3v12m0 0 4-4m-4 4-4-4M4 21h16" }) });
7013
7037
  function ThemeSwitch({ checked, onChange, label = "Toggle dark mode", className = "" }) {
7014
7038
  const id = React36.useId();
7015
7039
  return /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: id, className: `flex items-center gap-2 cursor-pointer select-none ${className}`.trim(), children: /* @__PURE__ */ jsxRuntime.jsx(