@ai-matrx/design-system 0.18.10 → 0.18.13

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.
Files changed (62) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/dist/content-transfer/alchemy.svg +1 -1
  3. package/dist/content-transfer/icon.cjs +3 -1
  4. package/dist/content-transfer/icon.cjs.map +1 -1
  5. package/dist/content-transfer/icon.d.cts +3 -2
  6. package/dist/content-transfer/icon.d.ts +3 -2
  7. package/dist/content-transfer/icon.js +3 -1
  8. package/dist/content-transfer/icon.js.map +1 -1
  9. package/dist/content-transfer.cjs +323 -277
  10. package/dist/content-transfer.cjs.map +1 -1
  11. package/dist/content-transfer.css +93 -25
  12. package/dist/content-transfer.d.cts +1 -1
  13. package/dist/content-transfer.d.ts +1 -1
  14. package/dist/content-transfer.js +323 -277
  15. package/dist/content-transfer.js.map +1 -1
  16. package/dist/data-table/copy-helpers.d.cts +1 -1
  17. package/dist/data-table/copy-helpers.d.ts +1 -1
  18. package/dist/data-table/copy-types.cjs.map +1 -1
  19. package/dist/data-table/copy-types.d.cts +1 -1
  20. package/dist/data-table/copy-types.d.ts +1 -1
  21. package/dist/data-table/data-row-inspector.cjs +325 -276
  22. package/dist/data-table/data-row-inspector.cjs.map +1 -1
  23. package/dist/data-table/data-row-inspector.js +325 -276
  24. package/dist/data-table/data-row-inspector.js.map +1 -1
  25. package/dist/data-table/data-row-window.cjs +325 -276
  26. package/dist/data-table/data-row-window.cjs.map +1 -1
  27. package/dist/data-table/data-row-window.js +325 -276
  28. package/dist/data-table/data-row-window.js.map +1 -1
  29. package/dist/data-table/filter-engine.d.cts +1 -1
  30. package/dist/data-table/filter-engine.d.ts +1 -1
  31. package/dist/data-table/host.cjs.map +1 -1
  32. package/dist/data-table/host.d.cts +16 -2
  33. package/dist/data-table/host.d.ts +16 -2
  34. package/dist/data-table/host.js.map +1 -1
  35. package/dist/data-table/index.cjs +463 -398
  36. package/dist/data-table/index.cjs.map +1 -1
  37. package/dist/data-table/index.d.cts +3 -3
  38. package/dist/data-table/index.d.ts +3 -3
  39. package/dist/data-table/index.js +464 -399
  40. package/dist/data-table/index.js.map +1 -1
  41. package/dist/data-table/infer-filter.d.cts +1 -1
  42. package/dist/data-table/infer-filter.d.ts +1 -1
  43. package/dist/data-table/layered-filters.d.cts +1 -1
  44. package/dist/data-table/layered-filters.d.ts +1 -1
  45. package/dist/data-table/pagination.cjs.map +1 -1
  46. package/dist/data-table/pagination.js.map +1 -1
  47. package/dist/data-table/query-control.d.cts +1 -1
  48. package/dist/data-table/query-control.d.ts +1 -1
  49. package/dist/data-table/types.cjs.map +1 -1
  50. package/dist/data-table/types.d.cts +1 -1
  51. package/dist/data-table/types.d.ts +1 -1
  52. package/dist/data-table/url-state.d.cts +1 -1
  53. package/dist/data-table/url-state.d.ts +1 -1
  54. package/dist/data-table/uuid-cell.cjs.map +1 -1
  55. package/dist/data-table/uuid-cell.js.map +1 -1
  56. package/dist/data-table/xlsx.d.cts +1 -1
  57. package/dist/data-table/xlsx.d.ts +1 -1
  58. package/dist/index.cjs.map +1 -1
  59. package/dist/index.js.map +1 -1
  60. package/dist/{types-C2xN6W_q.d.ts → types-BuDKVpeF.d.ts} +2 -1
  61. package/dist/{types-D_tpuk6m.d.cts → types-Dqcb7jXO.d.cts} +2 -1
  62. package/package.json +2 -2
@@ -90,9 +90,31 @@ var GripVertical = (p) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Icon, { .
90
90
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "9", cy: "18", r: "1" }),
91
91
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "15", cy: "18", r: "1" })
92
92
  ] });
93
- var SlidersHorizontal = (p) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { ...p, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M4 7h16M4 17h16M9 7v0M15 17v0" }) });
93
+ var SlidersHorizontal = (p) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { ...p, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M21 4h-7M10 4H3M21 12h-9M8 12H3M21 20h-5M12 20H3M14 2v4M8 10v4M16 18v4" }) });
94
94
  var Trash2 = (p) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { ...p, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M4 7h16M10 11v6M14 11v6M9 7l1-2h4l1 2M6 7l1 13h10l1-13" }) });
95
95
  var Loader2 = (p) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { ...p, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M20 12a8 8 0 1 1-2.3-5.7" }) });
96
+ var RefreshCw = (p) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Icon, { ...p, children: [
97
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8" }),
98
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M21 3v5h-5" }),
99
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16" }),
100
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M8 16H3v5" })
101
+ ] });
102
+ function RefreshControlIcon({
103
+ spinning = false,
104
+ className,
105
+ ...props
106
+ }) {
107
+ if (spinning) {
108
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
109
+ Loader2,
110
+ {
111
+ className: [className, "animate-spin"].filter(Boolean).join(" "),
112
+ ...props
113
+ }
114
+ );
115
+ }
116
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RefreshCw, { className, ...props });
117
+ }
96
118
  var Save = (p) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { ...p, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M5 3h12l2 2v16H5zM8 3v6h8V3M8 21v-7h8v7" }) });
97
119
  var Pencil = (p) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { ...p, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m4 20 4-1 11-11-3-3L5 16l-1 4z" }) });
98
120
  var Eye = (p) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Icon, { ...p, children: [
@@ -1949,14 +1971,14 @@ var PopoverContent = React12.forwardRef(
1949
1971
  );
1950
1972
  PopoverContent.displayName = PopoverPrimitive.Content.displayName;
1951
1973
 
1974
+ // src/content-transfer/icon.ts
1975
+ var ALCHEMY_GLYPH_PATHS = ["M9 3h6", "M10 3v6l-5.2 8.7A2 2 0 0 0 6.5 21h11a2 2 0 0 0 1.7-3.3L14 9V3", "M8 15h8"];
1976
+ var ALCHEMY_GLYPH_SVG = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">${ALCHEMY_GLYPH_PATHS.map((d) => `<path d="${d}"/>`).join("")}</svg>`;
1977
+
1952
1978
  // src/content-transfer/index.tsx
1953
1979
  var import_jsx_runtime21 = require("react/jsx-runtime");
1954
1980
  function AlchemyGlyph(props) {
1955
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", ...props, children: [
1956
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("path", { d: "M4.5 5.5h8v11h-8z" }),
1957
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("path", { d: "M8.5 9.5h8v9h-8z" }),
1958
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("path", { d: "m18.5 3 .65 1.85L21 5.5l-1.85.65L18.5 8l-.65-1.85L16 5.5l1.85-.65z" })
1959
- ] });
1981
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", ...props, children: ALCHEMY_GLYPH_PATHS.map((d) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("path", { d }, d)) });
1960
1982
  }
1961
1983
  var CapabilityContext = React13.createContext({});
1962
1984
  var useContentTransferCapabilities = () => React13.useContext(CapabilityContext);
@@ -1970,7 +1992,16 @@ function MenuPresentation({ label, hint, icon: Icon3 }) {
1970
1992
  ] })
1971
1993
  ] });
1972
1994
  }
1973
- function PaletteGlyph({ format, ai = false, file = false }) {
1995
+ function PaletteGlyph({ format, ai = false, file = false, kind }) {
1996
+ if (kind === "ai-copy") return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("svg", { className: "matrx-alchemy-palette-glyph", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
1997
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("rect", { x: "5", y: "5", width: "11", height: "14", rx: "2" }),
1998
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("path", { d: "M9 3h6a2 2 0 0 1 2 2v10" }),
1999
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("path", { d: "m18.5 3 .55 1.45L20.5 5l-1.45.55L18.5 7l-.55-1.45L16.5 5l1.45-.55z" })
2000
+ ] });
2001
+ if (kind === "sliders") return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("svg", { className: "matrx-alchemy-palette-glyph", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
2002
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("path", { d: "M4 6h16M4 12h16M4 18h16" }),
2003
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("path", { d: "M8 3v6M16 9v6M10 15v6" })
2004
+ ] });
1974
2005
  if (ai) return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("svg", { className: "matrx-alchemy-palette-glyph", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
1975
2006
  /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("path", { d: "M12 5a3 3 0 1 0-5.997.125A4 4 0 0 0 3.5 10.9a4 4 0 0 0 .556 6.588A4 4 0 0 0 12 19" }),
1976
2007
  /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("path", { d: "M12 5a3 3 0 1 1 5.997.125 4 4 0 0 1 2.503 5.775 4 4 0 0 1-.556 6.588A4 4 0 0 1 12 19" }),
@@ -2003,15 +2034,15 @@ function PaletteGlyph({ format, ai = false, file = false }) {
2003
2034
  ] }) : format === "html" ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_jsx_runtime21.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("path", { d: "M15 6h6M3 6h7M3 12h18M3 18h12" }) }) : /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_jsx_runtime21.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("path", { d: "M4 7V4h16v3M9 20h6M12 4v16" }) });
2004
2035
  return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("svg", { className: "matrx-alchemy-palette-glyph", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: path2 });
2005
2036
  }
2006
- function PaletteRows({ title, items, onRun, extra, ai = false }) {
2037
+ function PaletteRows({ title, items, onRun, extra, ai = false, glyphKind, fallbackHint }) {
2007
2038
  if (!items.length && !extra) return null;
2008
2039
  return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("section", { className: "matrx-alchemy-palette-section", children: [
2009
2040
  /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("h3", { children: title }),
2010
2041
  items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("button", { type: "button", className: cn("matrx-alchemy-palette-row", ai && "matrx-alchemy-palette-row-ai"), "aria-label": item.ariaLabel, onClick: () => onRun?.(item), children: [
2011
- item.icon ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(item.icon, { className: "matrx-alchemy-menu-icon" }) : /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(PaletteGlyph, { ai }),
2042
+ item.icon ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(item.icon, { className: "matrx-alchemy-menu-icon" }) : /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(PaletteGlyph, { ai, ...glyphKind ? { kind: glyphKind } : {} }),
2012
2043
  /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { children: [
2013
2044
  item.copyLabel ?? item.label,
2014
- item.hint ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("small", { className: "matrx-alchemy-menu-hint", children: item.hint }) : null
2045
+ item.hint ?? fallbackHint ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("small", { className: "matrx-alchemy-menu-hint", children: item.hint ?? fallbackHint }) : null
2015
2046
  ] })
2016
2047
  ] }, item.id)),
2017
2048
  extra
@@ -2408,45 +2439,54 @@ function ContentTransferMenuSession({ source, surface, label, projection, sectio
2408
2439
  }, children: [
2409
2440
  /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { ref: triggerRef, type: "button", className: "matrx-alchemy-trigger", disabled, "aria-label": `Copy, transform or export ${sourceLabel}`, title: "Alchemy \u2014 copy, transform, export", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(AlchemyGlyph, {}) }) }),
2410
2441
  /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(PopoverContent, { align: "end", className: "matrx-alchemy-menu matrx-alchemy-palette", "aria-label": "Alchemy output options", onCloseAutoFocus: () => triggerRef.current?.focus(), children: [
2411
- copyAvailable && downloadAvailable ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "matrx-alchemy-mode", "aria-label": "Output action", children: [
2412
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", "aria-label": "Copy mode", "aria-pressed": resolvedMode === "copy", onClick: () => setMode("copy"), children: "Copy" }),
2413
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", "aria-label": "Download mode", "aria-pressed": resolvedMode === "download", onClick: () => setMode("download"), children: "Download" })
2414
- ] }) : null,
2415
2442
  menuStatus === "loading" ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { className: "matrx-alchemy-palette-status", children: "Inspecting content\u2026" }) : menuStatus !== "idle" ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { className: "matrx-alchemy-error", children: menuStatus }) : null,
2416
- resolvedMode === "copy" && copyAvailable ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
2417
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "matrx-alchemy-palette-grid", children: [
2418
- visibleCopies.map((format) => tile(format, { plain: "Text", markdown: "Markdown", html: "Formatted", json: "JSON", "compact-json": "Compact", csv: "CSV", tsv: "Sheets" }[format], () => void transfer(format, false), { ariaLabel: `Copy ${LABEL[format]}` })),
2419
- visibleAdapters.map((adapter) => tile(adapter.id, adapter.label, () => void transfer(adapter, false), { custom: true }))
2420
- ] }),
2421
- quickVariants("copy").length ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(PaletteRows, { title: "Quick copy", items: quickVariants("copy"), onRun: (variant) => {
2443
+ copyAvailable || downloadAvailable ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("section", { className: "matrx-alchemy-output", children: [
2444
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("h3", { children: resolvedMode === "copy" ? "Copy as" : "Download as" }),
2445
+ copyAvailable && downloadAvailable ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "matrx-alchemy-mode", "aria-label": "Output action", children: [
2446
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", "aria-label": "Copy mode", "aria-pressed": resolvedMode === "copy", onClick: () => setMode("copy"), children: "Copy" }),
2447
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", "aria-label": "Download mode", "aria-pressed": resolvedMode === "download", onClick: () => setMode("download"), children: "Download" })
2448
+ ] }) : null,
2449
+ resolvedMode === "copy" && copyAvailable ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
2450
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "matrx-alchemy-palette-grid", children: [
2451
+ visibleCopies.map((format) => tile(format, { plain: "Text", markdown: "Markdown", html: "Formatted", json: "JSON", "compact-json": "Compact", csv: "CSV", tsv: "Sheets" }[format], () => void transfer(format, false), { ariaLabel: `Copy ${LABEL[format]}` })),
2452
+ visibleAdapters.map((adapter) => tile(adapter.id, adapter.label, () => void transfer(adapter, false), { custom: true }))
2453
+ ] }),
2454
+ quickVariants("copy").length ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(PaletteRows, { title: "Quick copy", items: quickVariants("copy"), onRun: (variant) => {
2455
+ closePalette();
2456
+ void transfer("markdown", false, variant);
2457
+ } }) : null
2458
+ ] }) : null,
2459
+ resolvedMode === "download" && downloadAvailable ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_jsx_runtime21.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "matrx-alchemy-palette-grid", children: [
2460
+ visibleDownloads.map((format) => tile(format, { plain: "Text", markdown: "Markdown", html: "Formatted", json: "JSON", "compact-json": "Compact", csv: "CSV", tsv: "Sheets", xlsx: "Excel" }[format], () => void transfer(format, true), { ariaLabel: `Download ${LABEL[format]}` })),
2461
+ visibleAdapters.map((adapter) => tile(adapter.id, adapter.label, () => void transfer(adapter, true), { custom: true })),
2462
+ downloadActions.map((action) => tile(action.id, action.label, () => void runAction(action), { custom: true, action, file: true }))
2463
+ ] }) }) : null
2464
+ ] }) : null,
2465
+ prepareAvailable ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
2466
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(PaletteRows, { title: "Copy for AI", ai: true, glyphKind: "ai-copy", fallbackHint: "Copies immediately", items: quickVariants("ai"), onRun: (variant) => {
2422
2467
  closePalette();
2423
2468
  void transfer("markdown", false, variant);
2424
- } }) : null
2469
+ } }),
2470
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(PaletteRows, { title: "Edit and prepare", items: [], extra: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("button", { type: "button", className: "matrx-alchemy-palette-row", "aria-label": "Prepare for AI", onClick: () => {
2471
+ closePalette();
2472
+ void openWorkspace();
2473
+ }, children: [
2474
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(PaletteGlyph, { kind: "sliders" }),
2475
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { children: [
2476
+ "Prepare for AI",
2477
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("small", { className: "matrx-alchemy-menu-hint", children: "Review and edit before copying" })
2478
+ ] })
2479
+ ] }) })
2425
2480
  ] }) : null,
2426
- resolvedMode === "download" && downloadAvailable ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_jsx_runtime21.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "matrx-alchemy-palette-grid", children: [
2427
- visibleDownloads.map((format) => tile(format, { plain: "Text", markdown: "Markdown", html: "Formatted", json: "JSON", "compact-json": "Compact", csv: "CSV", tsv: "Sheets", xlsx: "Excel" }[format], () => void transfer(format, true), { ariaLabel: `Download ${LABEL[format]}` })),
2428
- visibleAdapters.map((adapter) => tile(adapter.id, adapter.label, () => void transfer(adapter, true), { custom: true })),
2429
- downloadActions.map((action) => tile(action.id, action.label, () => void runAction(action), { custom: true, action, file: true }))
2430
- ] }) }) : null,
2431
- prepareAvailable ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(PaletteRows, { title: "Prepare", ai: true, items: quickVariants("ai"), onRun: (variant) => {
2432
- closePalette();
2433
- void transfer("markdown", false, variant);
2434
- }, extra: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("button", { type: "button", className: "matrx-alchemy-palette-row", onClick: () => {
2435
- closePalette();
2436
- void openWorkspace();
2437
- }, children: [
2438
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(PaletteGlyph, { ai: true }),
2439
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { children: "Prepare for AI\u2026" })
2440
- ] }) }) : null,
2441
- prepareAvailable && (nearestWorkspaceKey || variants.length) ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(PaletteRows, { title: "Context", items: [], extra: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
2481
+ prepareAvailable && (nearestWorkspaceKey || variants.length) ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(PaletteRows, { title: "Other sources", items: [], extra: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
2442
2482
  nearestWorkspaceKey && nearestSurface ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", className: "matrx-alchemy-palette-row", onClick: () => {
2443
2483
  closePalette();
2444
2484
  void openWorkspace(nearestWorkspaceKey, { source: nearestSurface, label: nearestSurface.surfaceName });
2445
- }, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { children: "Prepare this surface\u2026" }) }) : null,
2485
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { children: "Prepare this surface" }) }) : null,
2446
2486
  variants.map((variant) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", className: "matrx-alchemy-palette-row", "aria-label": variant.ariaLabel, onClick: () => {
2447
2487
  closePalette();
2448
2488
  void openWorkspace(variantWorkspaceKeys.get(variant.id), variant);
2449
- }, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(MenuPresentation, { ...variant, label: `Prepare ${variant.label}\u2026` }) }, variant.id))
2489
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(MenuPresentation, { ...variant, label: `Prepare ${variant.label}` }) }, variant.id))
2450
2490
  ] }) }) : null,
2451
2491
  ordinaryActions.length ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(PaletteRows, { title: "Actions", items: [], extra: ordinaryActions.map((action) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", className: "matrx-alchemy-palette-row", "aria-label": action.ariaLabel, onClick: () => {
2452
2492
  closePalette();
@@ -2724,137 +2764,150 @@ function PreparationWorkspace({ restoreFocus, open, state, scopes, onClose, onCh
2724
2764
  state.snapshot.label
2725
2765
  ] }),
2726
2766
  /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(DialogDescription, { children: [
2727
- "Captured ",
2728
- state.snapshot.unsavedChanges ? "from your unsaved draft" : "as an immutable snapshot",
2729
- ". Your source is never edited."
2767
+ state.snapshot.unsavedChanges ? "Includes your unsaved changes. " : "",
2768
+ "Review and edit this copy. Your original stays unchanged."
2730
2769
  ] })
2731
2770
  ] }),
2732
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "matrx-alchemy-workspace-grid", children: [
2733
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("section", { className: "matrx-alchemy-main", children: [
2734
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "matrx-alchemy-toolbar", children: [
2735
- scopes.length > 1 ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { children: [
2736
- "Scope",
2737
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("select", { "aria-label": "Transfer scope", value: state.scope, disabled: busy !== null, onChange: (e) => void requestCapture(e.target.value), children: scopes.map((scope) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("option", { value: scope, children: SCOPE_LABEL[scope] }, scope)) })
2738
- ] }) : null,
2739
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { children: [
2740
- "Detail",
2741
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("select", { "aria-label": "Detail preset", value: controls.preset, onChange: (e) => changeControls({ ...controls, preset: e.target.value }), children: [
2742
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("option", { value: "full", children: "Full" }),
2743
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("option", { value: "compact", children: "Compact" }),
2744
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("option", { value: "brief", children: "Brief" }),
2745
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("option", { value: "custom", children: "Custom" })
2746
- ] })
2747
- ] }),
2748
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Button, { type: "button", size: "sm", variant: "outline", disabled: !state.draft.history?.length && !controlsHistory.length || busy !== null, onClick: () => {
2749
- setBufferError(null);
2750
- if (controlsHistory.length) {
2751
- const next = controlsHistory[controlsHistory.length - 1];
2771
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "matrx-alchemy-workspace-body", children: [
2772
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "matrx-alchemy-workspace-grid", children: [
2773
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("section", { className: "matrx-alchemy-main", children: [
2774
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "matrx-alchemy-toolbar", children: [
2775
+ scopes.length > 1 ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { children: [
2776
+ "Scope",
2777
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("select", { "aria-label": "Transfer scope", value: state.scope, disabled: busy !== null, onChange: (e) => void requestCapture(e.target.value), children: scopes.map((scope) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("option", { value: scope, children: SCOPE_LABEL[scope] }, scope)) })
2778
+ ] }) : null,
2779
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { children: [
2780
+ "Detail",
2781
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("select", { "aria-label": "Detail preset", value: controls.preset, onChange: (e) => changeControls({ ...controls, preset: e.target.value }), children: [
2782
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("option", { value: "full", children: "Full" }),
2783
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("option", { value: "compact", children: "Compact" }),
2784
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("option", { value: "brief", children: "Brief" }),
2785
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("option", { value: "custom", children: "Custom" })
2786
+ ] })
2787
+ ] }),
2788
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Button, { type: "button", size: "sm", variant: "outline", className: "matrx-alchemy-workspace-secondary", disabled: !state.draft.history?.length && !controlsHistory.length || busy !== null, onClick: () => {
2789
+ setBufferError(null);
2790
+ if (controlsHistory.length) {
2791
+ const next = controlsHistory[controlsHistory.length - 1];
2792
+ setControls(next);
2793
+ setControlsHistory((history) => history.slice(0, -1));
2794
+ onChange({ ...state, draft: rebuild(state, next), error: void 0 });
2795
+ } else onChange({ ...state, draft: (0, import_content_transfer.undoDraft)(state.draft), error: void 0 });
2796
+ }, children: "Undo" }),
2797
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Button, { type: "button", size: "sm", variant: "outline", className: "matrx-alchemy-workspace-secondary", disabled: busy !== null, onClick: () => {
2798
+ const next = initialControls(state);
2752
2799
  setControls(next);
2753
- setControlsHistory((history) => history.slice(0, -1));
2800
+ setControlsHistory([]);
2801
+ setPendingControls(null);
2802
+ setBufferError(null);
2754
2803
  onChange({ ...state, draft: rebuild(state, next), error: void 0 });
2755
- } else onChange({ ...state, draft: (0, import_content_transfer.undoDraft)(state.draft), error: void 0 });
2756
- }, children: "Undo" }),
2757
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Button, { type: "button", size: "sm", variant: "outline", disabled: busy !== null, onClick: () => {
2758
- const next = initialControls(state);
2759
- setControls(next);
2760
- setControlsHistory([]);
2761
- setPendingControls(null);
2762
- setBufferError(null);
2763
- onChange({ ...state, draft: rebuild(state, next), error: void 0 });
2764
- }, children: "Reset" }),
2765
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Button, { type: "button", size: "sm", variant: "outline", disabled: busy !== null, onClick: () => void requestCapture(state.scope), children: "Refresh source" })
2766
- ] }),
2767
- controls.preset === "custom" && (state.draft.payload.kind === "json" || state.draft.payload.kind === "registered") ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("fieldset", { className: "matrx-alchemy-options", children: [
2768
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("legend", { children: "JSON limits" }),
2769
- [["maxDepth", "Maximum depth"], ["maxStringChars", "Maximum string characters"], ["maxArrayItems", "Maximum array items"]].map(([key, text]) => /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { children: [
2770
- text,
2771
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("input", { type: "number", min: "0", value: controls[key] ?? "", onChange: (e) => changeControls({ ...controls, [key]: Number.isNaN(e.target.valueAsNumber) ? null : e.target.valueAsNumber }) })
2772
- ] }, key))
2773
- ] }) : null,
2774
- rows ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(RowControls, { rows, controls, change: changeControls }) : null,
2775
- state.snapshot.sections.length ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("fieldset", { className: "matrx-alchemy-options", children: [
2776
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("legend", { children: "Sections" }),
2777
- state.snapshot.sections.map((section) => /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { children: [
2778
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("input", { type: "checkbox", checked: controls.sections.includes(section.id), onChange: (e) => changeControls({ ...controls, sections: e.target.checked ? [...controls.sections, section.id] : controls.sections.filter((id) => id !== section.id) }) }),
2779
- " ",
2780
- section.label
2781
- ] }, section.id))
2782
- ] }) : null,
2783
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "matrx-alchemy-coverage", children: [
2784
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { children: [
2785
- state.snapshot.coverage.included.toLocaleString(),
2786
- " included",
2787
- state.snapshot.coverage.total == null ? "" : ` of ${state.snapshot.coverage.total.toLocaleString()}`,
2788
- " \xB7 ",
2789
- state.snapshot.coverage.status
2804
+ }, children: "Reset" }),
2805
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Button, { type: "button", size: "sm", variant: "outline", className: "matrx-alchemy-workspace-secondary", disabled: busy !== null, onClick: () => void requestCapture(state.scope), children: "Refresh source" })
2790
2806
  ] }),
2791
- state.snapshot.coverage.reason ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { children: state.snapshot.coverage.reason }) : null,
2792
- limitText ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { children: [
2793
- "Limits: ",
2794
- limitText
2807
+ controls.preset === "custom" && (state.draft.payload.kind === "json" || state.draft.payload.kind === "registered") ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("fieldset", { className: "matrx-alchemy-options", children: [
2808
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("legend", { children: "JSON limits" }),
2809
+ [["maxDepth", "Maximum depth"], ["maxStringChars", "Maximum string characters"], ["maxArrayItems", "Maximum array items"]].map(([key, text]) => /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { children: [
2810
+ text,
2811
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("input", { type: "number", min: "0", value: controls[key] ?? "", onChange: (e) => changeControls({ ...controls, [key]: Number.isNaN(e.target.valueAsNumber) ? null : e.target.valueAsNumber }) })
2812
+ ] }, key))
2795
2813
  ] }) : null,
2796
- displayedOmissions.length ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("details", { children: [
2814
+ rows ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("details", { className: "matrx-alchemy-options matrx-alchemy-data-controls", children: [
2797
2815
  /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("summary", { children: [
2798
- displayedOmissions.length,
2799
- " omissions or adjustments"
2816
+ "Data selection \xB7 ",
2817
+ controls.visibleColumns.length,
2818
+ " columns",
2819
+ controls.search || controls.sort || controls.top != null || controls.selectedOnly || Object.values(controls.filters).some(Boolean) ? " \xB7 customized" : " \xB7 all rows"
2800
2820
  ] }),
2801
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("ul", { children: displayedOmissions.map((o, i) => /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("li", { children: [
2802
- o.path || "/",
2803
- ": ",
2804
- o.reason,
2805
- o.count == null ? "" : ` (${o.count})`
2806
- ] }, `${o.path}-${o.reason}-${i}`)) })
2807
- ] }) : null
2808
- ] }),
2809
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { className: "matrx-alchemy-preview-label", children: [
2810
- "Output format",
2811
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("select", { "aria-label": "Output format", value: format, onChange: (e) => setFormat(e.target.value), children: [
2812
- formats.map((f) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("option", { value: f, children: LABEL[f] }, f)),
2813
- state.draft.payload.kind === "rows" ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("option", { value: "xlsx", children: "Excel workbook" }) : null,
2814
- workspaceAdapters.map((adapter) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("option", { value: adapter.id, children: adapter.label }, adapter.id))
2815
- ] })
2821
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "matrx-alchemy-data-controls-body", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(RowControls, { rows, controls, change: changeControls }) })
2822
+ ] }) : null,
2823
+ state.snapshot.sections.length ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("details", { className: "matrx-alchemy-options", children: [
2824
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("summary", { children: [
2825
+ "Sections \xB7 ",
2826
+ controls.sections.length,
2827
+ " included"
2828
+ ] }),
2829
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("fieldset", { "aria-label": "Included sections", children: state.snapshot.sections.map((section) => /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { children: [
2830
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("input", { type: "checkbox", checked: controls.sections.includes(section.id), onChange: (e) => changeControls({ ...controls, sections: e.target.checked ? [...controls.sections, section.id] : controls.sections.filter((id) => id !== section.id) }) }),
2831
+ " ",
2832
+ section.label
2833
+ ] }, section.id)) })
2834
+ ] }) : null,
2835
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { className: "matrx-alchemy-preview-label", children: [
2836
+ "Output format",
2837
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("select", { "aria-label": "Output format", value: format, onChange: (e) => setFormat(e.target.value), children: [
2838
+ formats.map((f) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("option", { value: f, children: LABEL[f] }, f)),
2839
+ state.draft.payload.kind === "rows" ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("option", { value: "xlsx", children: "Excel workbook" }) : null,
2840
+ workspaceAdapters.map((adapter) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("option", { value: adapter.id, children: adapter.label }, adapter.id))
2841
+ ] })
2842
+ ] }),
2843
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("textarea", { className: "matrx-alchemy-preview", "aria-label": "Prepared output", "aria-invalid": bufferError ? true : void 0, "aria-describedby": bufferError ? "alchemy-buffer-error" : void 0, value: buffer, onChange: (e) => editBuffer(e.target.value) }),
2844
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "matrx-alchemy-coverage", children: [
2845
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { children: [
2846
+ state.snapshot.coverage.included.toLocaleString(),
2847
+ " included",
2848
+ state.snapshot.coverage.total == null ? "" : ` of ${state.snapshot.coverage.total.toLocaleString()}`,
2849
+ " \xB7 ",
2850
+ state.snapshot.coverage.status
2851
+ ] }),
2852
+ state.snapshot.coverage.reason ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { children: state.snapshot.coverage.reason }) : null,
2853
+ limitText ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { children: [
2854
+ "Limits: ",
2855
+ limitText
2856
+ ] }) : null,
2857
+ displayedOmissions.length ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("details", { children: [
2858
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("summary", { children: [
2859
+ displayedOmissions.length,
2860
+ " omissions or adjustments"
2861
+ ] }),
2862
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("ul", { children: displayedOmissions.map((o, i) => /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("li", { children: [
2863
+ o.path || "/",
2864
+ ": ",
2865
+ o.reason,
2866
+ o.count == null ? "" : ` (${o.count})`
2867
+ ] }, `${o.path}-${o.reason}-${i}`)) })
2868
+ ] }) : null
2869
+ ] }),
2870
+ bufferError ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { id: "alchemy-buffer-error", role: "alert", className: "matrx-alchemy-error", children: bufferError }) : null,
2871
+ formatError ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { role: "alert", className: "matrx-alchemy-error", children: formatError }) : null,
2872
+ bufferError ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Button, { className: "matrx-alchemy-workspace-secondary", type: "button", variant: "outline", disabled: busy !== null, onClick: () => {
2873
+ const fallback = (0, import_content_transfer.editDraft)(state.draft, { kind: "text", text: buffer });
2874
+ setBufferError(null);
2875
+ onChange({ ...state, draft: fallback, error: void 0 });
2876
+ setFormat("plain");
2877
+ }, children: "Use invalid JSON as plain text" }) : null
2816
2878
  ] }),
2817
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("textarea", { className: "matrx-alchemy-preview", "aria-label": "Prepared output", "aria-invalid": bufferError ? true : void 0, "aria-describedby": bufferError ? "alchemy-buffer-error" : void 0, value: buffer, onChange: (e) => editBuffer(e.target.value) }),
2818
- bufferError ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { id: "alchemy-buffer-error", role: "alert", className: "matrx-alchemy-error", children: bufferError }) : null,
2819
- formatError ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { role: "alert", className: "matrx-alchemy-error", children: formatError }) : null,
2820
- bufferError ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Button, { type: "button", variant: "outline", disabled: busy !== null, onClick: () => {
2821
- const fallback = (0, import_content_transfer.editDraft)(state.draft, { kind: "text", text: buffer });
2822
- setBufferError(null);
2823
- onChange({ ...state, draft: fallback, error: void 0 });
2824
- setFormat("plain");
2825
- }, children: "Use invalid JSON as plain text" }) : null
2879
+ ai || busy === "capture" || state.error ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("aside", { children: [
2880
+ ai ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
2881
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { children: [
2882
+ "AI instruction",
2883
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("textarea", { value: instruction, onChange: (e) => setInstruction(e.target.value), placeholder: "Tell AI how to prepare this content" })
2884
+ ] }),
2885
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Button, { className: "matrx-alchemy-workspace-secondary", type: "button", variant: "outline", disabled: !aiSession.current || !instruction.trim() || busy !== null || !aiSession.current.supports(state.snapshot), onClick: () => void runAi(false), children: "Generate preview" }),
2886
+ busy === "ai" ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Button, { className: "matrx-alchemy-workspace-secondary", type: "button", variant: "outline", onClick: () => void cancelAi(), children: aiSession.current?.cancel ? "Cancel AI" : "Stop waiting" }) : null
2887
+ ] }) : null,
2888
+ busy === "capture" ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Button, { className: "matrx-alchemy-workspace-secondary", type: "button", variant: "outline", onClick: () => {
2889
+ activeCapture.current?.abort();
2890
+ activeCapture.current = null;
2891
+ setBusy(null);
2892
+ }, children: "Stop loading rows" }) : null,
2893
+ ai && aiFailed && aiSession.current?.recover && busy !== "ai" ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Button, { className: "matrx-alchemy-workspace-secondary", type: "button", variant: "outline", onClick: () => void runAi(true), children: aiFailed ? "Retry or rejoin AI run" : "Rejoin AI run" }) : null,
2894
+ ai ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { className: "matrx-alchemy-meta", children: "AI updates the preview; copy it when you are ready. Closing this window lets the AI run continue." }) : null,
2895
+ state.error ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { role: "alert", className: "matrx-alchemy-error", children: state.error }) : null
2896
+ ] }) : null
2826
2897
  ] }),
2827
- ai || busy === "capture" || state.error ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("aside", { children: [
2828
- ai ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
2829
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { children: [
2830
- "AI instruction",
2831
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("textarea", { value: instruction, onChange: (e) => setInstruction(e.target.value), placeholder: "Tell AI how to prepare this content" })
2832
- ] }),
2833
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Button, { type: "button", variant: "outline", disabled: !aiSession.current || !instruction.trim() || busy !== null || !aiSession.current.supports(state.snapshot), onClick: () => void runAi(false), children: "Generate preview" }),
2834
- busy === "ai" ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Button, { type: "button", variant: "outline", onClick: () => void cancelAi(), children: aiSession.current?.cancel ? "Cancel AI" : "Stop waiting" }) : null
2835
- ] }) : null,
2836
- busy === "capture" ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Button, { type: "button", variant: "outline", onClick: () => {
2837
- activeCapture.current?.abort();
2838
- activeCapture.current = null;
2839
- setBusy(null);
2840
- }, children: "Stop loading rows" }) : null,
2841
- ai && aiFailed && aiSession.current?.recover && busy !== "ai" ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Button, { type: "button", variant: "outline", onClick: () => void runAi(true), children: aiFailed ? "Retry or rejoin AI run" : "Rejoin AI run" }) : null,
2842
- ai ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { className: "matrx-alchemy-meta", children: "AI creates a preview. It never copies automatically. Closing detaches this view without cancelling server work." }) : null,
2843
- state.error ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { role: "alert", className: "matrx-alchemy-error", children: state.error }) : null
2844
- ] }) : null
2898
+ pendingControls ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "matrx-alchemy-decision", role: "alert", children: [
2899
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { children: "This control would replace your manual edit." }),
2900
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Button, { className: "matrx-alchemy-workspace-secondary", type: "button", variant: "outline", onClick: () => setPendingControls(null), children: "Keep edited draft" }),
2901
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Button, { className: "matrx-alchemy-workspace-primary", type: "button", onClick: applyPendingControls, children: "Rebuild from source" })
2902
+ ] }) : null,
2903
+ state.sourceStale ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { role: "alert", className: "matrx-alchemy-decision", children: "The source changed since this draft. Use Refresh source to review the latest data." }) : null,
2904
+ state.pending ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "matrx-alchemy-decision", role: "alert", children: [
2905
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { children: "A fresh source snapshot is ready." }),
2906
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Button, { className: "matrx-alchemy-workspace-secondary", type: "button", variant: "outline", onClick: () => resolveCapture("keep"), children: "Keep current snapshot and draft" }),
2907
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Button, { className: "matrx-alchemy-workspace-primary", type: "button", onClick: () => resolveCapture("regenerate"), children: "Regenerate from fresh source" })
2908
+ ] }) : null,
2909
+ deliveryNotice ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { role: "status", className: "matrx-alchemy-meta", children: deliveryNotice }) : null
2845
2910
  ] }),
2846
- pendingControls ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "matrx-alchemy-decision", role: "alert", children: [
2847
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { children: "This control would replace your manual edit." }),
2848
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Button, { type: "button", variant: "outline", onClick: () => setPendingControls(null), children: "Keep edited draft" }),
2849
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Button, { type: "button", onClick: applyPendingControls, children: "Rebuild from source" })
2850
- ] }) : null,
2851
- state.sourceStale ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { role: "alert", className: "matrx-alchemy-decision", children: "The source changed since this draft. Use Refresh source to review the latest data." }) : null,
2852
- state.pending ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "matrx-alchemy-decision", role: "alert", children: [
2853
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { children: "A fresh source snapshot is ready." }),
2854
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Button, { type: "button", variant: "outline", onClick: () => resolveCapture("keep"), children: "Keep current snapshot and draft" }),
2855
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Button, { type: "button", onClick: () => resolveCapture("regenerate"), children: "Regenerate from fresh source" })
2856
- ] }) : null,
2857
- deliveryNotice ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { role: "status", className: "matrx-alchemy-meta", children: deliveryNotice }) : null,
2858
2911
  /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(DialogFooter, { children: [
2859
2912
  /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { className: "matrx-alchemy-meta", children: [
2860
2913
  buffer.length.toLocaleString(),
@@ -2862,13 +2915,16 @@ function PreparationWorkspace({ restoreFocus, open, state, scopes, onClose, onCh
2862
2915
  estimateTokens(buffer).toLocaleString(),
2863
2916
  " tokens"
2864
2917
  ] }),
2865
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Button, { type: "button", variant: "outline", onClick: close, children: "Close" }),
2866
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Button, { type: "button", variant: "outline", disabled: busy !== null || Boolean(bufferError || formatError) || !preparedArtifact, onClick: () => void deliver(true), children: "Download prepared output" }),
2867
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Button, { type: "button", disabled: busy !== null || Boolean(bufferError || formatError) || !preparedArtifact, onClick: () => void deliver(false), children: "Copy prepared output" })
2918
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Button, { type: "button", variant: "outline", className: "matrx-alchemy-workspace-secondary", onClick: close, children: "Close" }),
2919
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Button, { type: "button", variant: "outline", className: "matrx-alchemy-workspace-secondary", "aria-label": "Download prepared output", disabled: busy !== null || Boolean(bufferError || formatError) || !preparedArtifact, onClick: () => void deliver(true), children: "Download" }),
2920
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Button, { type: "button", className: "matrx-alchemy-workspace-primary", "aria-label": "Copy prepared output", disabled: busy !== null || Boolean(bufferError || formatError) || !preparedArtifact, onClick: () => void deliver(false), children: "Copy" })
2868
2921
  ] })
2869
2922
  ] }) });
2870
2923
  }
2871
2924
  function RowControls({ rows, controls, change }) {
2925
+ const filterCount = Object.values(controls.filters).filter(Boolean).length;
2926
+ const selectionSummary = controls.selectedOnly ? `${controls.selectedIndices.length} selected row${controls.selectedIndices.length === 1 ? "" : "s"}` : "All rows";
2927
+ const dataSummary = [controls.search ? "search active" : "", controls.sort ? `sorted by ${rows.columns.find((column) => column.id === controls.sort)?.label ?? controls.sort}` : "", filterCount ? `${filterCount} filter${filterCount === 1 ? "" : "s"}` : ""].filter(Boolean).join(" \xB7 ");
2872
2928
  return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
2873
2929
  /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "matrx-alchemy-toolbar", children: [
2874
2930
  /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { children: [
@@ -2894,32 +2950,40 @@ function RowControls({ rows, controls, change }) {
2894
2950
  /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("input", { type: "number", min: "0", value: controls.top ?? "", onChange: (e) => change({ ...controls, top: Number.isNaN(e.target.valueAsNumber) ? null : e.target.valueAsNumber }) })
2895
2951
  ] })
2896
2952
  ] }),
2897
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("fieldset", { className: "matrx-alchemy-options", children: [
2898
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("legend", { children: "Columns and filters" }),
2899
- rows.columns.map((column) => /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "matrx-alchemy-column", children: [
2953
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("details", { className: "matrx-alchemy-options", children: [
2954
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("summary", { children: [
2955
+ "Columns and filters",
2956
+ dataSummary ? ` \u2014 ${dataSummary}` : ""
2957
+ ] }),
2958
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("fieldset", { "aria-label": "Columns and filters", children: rows.columns.map((column) => /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "matrx-alchemy-column", children: [
2900
2959
  /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { children: [
2901
2960
  /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("input", { type: "checkbox", checked: controls.visibleColumns.includes(column.id), onChange: (e) => change({ ...controls, visibleColumns: e.target.checked ? [...controls.visibleColumns, column.id] : controls.visibleColumns.filter((id) => id !== column.id) }) }),
2902
2961
  " ",
2903
2962
  column.label
2904
2963
  ] }),
2905
2964
  /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("input", { "aria-label": `Filter ${column.label}`, placeholder: "Filter", value: controls.filters[column.id] ?? "", onChange: (e) => change({ ...controls, filters: { ...controls.filters, [column.id]: e.target.value } }) })
2906
- ] }, column.id))
2965
+ ] }, column.id)) })
2907
2966
  ] }),
2908
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("fieldset", { className: "matrx-alchemy-options", children: [
2909
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("legend", { children: "Rows" }),
2910
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { children: [
2911
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("input", { type: "checkbox", checked: controls.selectedOnly, onChange: (e) => change({ ...controls, selectedOnly: e.target.checked }) }),
2912
- " Only selected rows"
2967
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("details", { className: "matrx-alchemy-options", children: [
2968
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("summary", { children: [
2969
+ "Rows \u2014 ",
2970
+ selectionSummary
2913
2971
  ] }),
2914
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "matrx-alchemy-row-list", children: rows.rows.map((row, index) => {
2915
- const summary = rows.columns.filter((column) => column.visible).slice(0, 2).map((column) => String((0, import_content_transfer.readTransferCell)(row, column) ?? "")).filter(Boolean).join(" \xB7 ");
2916
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { children: [
2917
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("input", { type: "checkbox", checked: controls.selectedIndices.includes(index), onChange: (e) => change({ ...controls, selectedIndices: e.target.checked ? [...controls.selectedIndices, index] : controls.selectedIndices.filter((value) => value !== index) }) }),
2918
- " Row ",
2919
- index + 1,
2920
- summary ? ` \u2014 ${summary}` : ""
2921
- ] }, index);
2922
- }) })
2972
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("fieldset", { "aria-label": "Row selection", children: [
2973
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { children: [
2974
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("input", { type: "checkbox", checked: controls.selectedOnly, onChange: (e) => change({ ...controls, selectedOnly: e.target.checked }) }),
2975
+ " Only selected rows"
2976
+ ] }),
2977
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "matrx-alchemy-row-list", children: rows.rows.map((row, index) => {
2978
+ const summary = rows.columns.filter((column) => column.visible).slice(0, 2).map((column) => String((0, import_content_transfer.readTransferCell)(row, column) ?? "")).filter(Boolean).join(" \xB7 ");
2979
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { children: [
2980
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("input", { type: "checkbox", checked: controls.selectedIndices.includes(index), onChange: (e) => change({ ...controls, selectedIndices: e.target.checked ? [...controls.selectedIndices, index] : controls.selectedIndices.filter((value) => value !== index) }) }),
2981
+ " Row ",
2982
+ index + 1,
2983
+ summary ? ` \u2014 ${summary}` : ""
2984
+ ] }, index);
2985
+ }) })
2986
+ ] })
2923
2987
  ] })
2924
2988
  ] });
2925
2989
  }
@@ -3071,7 +3135,7 @@ function MatrxCopyMenuSession(props) {
3071
3135
  if (aiVisible && props.aiCustom)
3072
3136
  actions.push({
3073
3137
  id: "configure-source",
3074
- label: props.aiCustom.label ?? "Customize source\u2026",
3138
+ label: props.aiCustom.label ?? "Customize source",
3075
3139
  ...props.aiCustom.hint ? { hint: props.aiCustom.hint } : {},
3076
3140
  supports: () => true,
3077
3141
  run: async () => {
@@ -3082,7 +3146,7 @@ function MatrxCopyMenuSession(props) {
3082
3146
  if (aiVisible && props.groomer)
3083
3147
  actions.push({
3084
3148
  id: "groom-source",
3085
- label: "Customize sections\u2026",
3149
+ label: "Customize sections",
3086
3150
  supports: () => true,
3087
3151
  run: async () => {
3088
3152
  setConfiguration({ groomer: props.groomer() });
@@ -3192,7 +3256,8 @@ function MatrxCopyMenuSession(props) {
3192
3256
  className: cn(
3193
3257
  props.className,
3194
3258
  props.size === "xs" && "matrx-alchemy-xs",
3195
- props.size === "sm" && "matrx-alchemy-sm"
3259
+ props.size === "sm" && "matrx-alchemy-sm",
3260
+ props.size === "toolbar" && "matrx-alchemy-toolbar-target"
3196
3261
  ),
3197
3262
  ...props.stopPropagation !== void 0 ? { stopPropagation: props.stopPropagation } : {}
3198
3263
  }
@@ -3297,127 +3362,132 @@ function SourceConfiguration({
3297
3362
  event.preventDefault();
3298
3363
  if (!handingOff.current) restoreFocus();
3299
3364
  },
3300
- className: "matrx-alchemy-workspace",
3365
+ className: "matrx-alchemy-workspace matrx-alchemy-configuration",
3301
3366
  children: [
3302
3367
  /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(DialogHeader, { children: [
3303
3368
  /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(DialogTitle, { children: title }),
3304
3369
  /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(DialogDescription, { children: custom?.dialogDescription ?? "Choose the source detail, then prepare, edit, summarize, copy or export it in Alchemy." })
3305
3370
  ] }),
3306
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "matrx-alchemy-main matrx-alchemy-toolbar", children: [
3307
- custom?.options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("label", { children: [
3308
- option.label,
3309
- "hint" in option && option.hint ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("small", { children: option.hint }) : null,
3310
- option.kind === "toggle" ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3311
- "input",
3312
- {
3313
- type: "checkbox",
3314
- checked: Boolean(values[option.key]),
3315
- onChange: (event) => setValues({ ...values, [option.key]: event.target.checked })
3316
- }
3317
- ) : option.kind === "preset" ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3318
- "select",
3319
- {
3320
- value: Number(values[option.key]),
3321
- onChange: (event) => setValues({
3322
- ...values,
3323
- [option.key]: Number(event.target.value)
3324
- }),
3325
- children: option.options.map((choice) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("option", { value: choice.value, children: choice.label }, choice.value))
3326
- }
3327
- ) : option.kind === "slider" ? /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
3328
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3371
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "matrx-alchemy-workspace-body", children: [
3372
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "matrx-alchemy-main matrx-alchemy-toolbar", children: [
3373
+ custom?.options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("label", { children: [
3374
+ option.label,
3375
+ "hint" in option && option.hint ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("small", { children: option.hint }) : null,
3376
+ option.kind === "toggle" ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3329
3377
  "input",
3330
3378
  {
3331
- type: "range",
3332
- min: 0,
3333
- max: Math.max(0, option.stops.length - 1),
3334
- step: 1,
3335
- value: option.stops.indexOf(Number(values[option.key])),
3336
- onChange: (event) => setValues({
3337
- ...values,
3338
- [option.key]: option.stops[Number(event.target.value)]
3339
- })
3379
+ type: "checkbox",
3380
+ checked: Boolean(values[option.key]),
3381
+ onChange: (event) => setValues({ ...values, [option.key]: event.target.checked })
3340
3382
  }
3341
- ),
3342
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { children: option.formatValue(Number(values[option.key])) })
3343
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
3344
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3345
- "input",
3383
+ ) : option.kind === "preset" ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3384
+ "select",
3346
3385
  {
3347
- type: "number",
3348
- min: option.min,
3349
- step: option.step,
3350
3386
  value: Number(values[option.key]),
3351
3387
  onChange: (event) => setValues({
3352
3388
  ...values,
3353
3389
  [option.key]: Number(event.target.value)
3354
- })
3390
+ }),
3391
+ children: option.options.map((choice) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("option", { value: choice.value, children: choice.label }, choice.value))
3355
3392
  }
3356
- ),
3357
- option.presets?.map((preset) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3393
+ ) : option.kind === "slider" ? /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
3394
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3395
+ "input",
3396
+ {
3397
+ type: "range",
3398
+ min: 0,
3399
+ max: Math.max(0, option.stops.length - 1),
3400
+ step: 1,
3401
+ value: option.stops.indexOf(Number(values[option.key])),
3402
+ onChange: (event) => setValues({
3403
+ ...values,
3404
+ [option.key]: option.stops[Number(event.target.value)]
3405
+ })
3406
+ }
3407
+ ),
3408
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { children: option.formatValue(Number(values[option.key])) })
3409
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
3410
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3411
+ "input",
3412
+ {
3413
+ type: "number",
3414
+ min: option.min,
3415
+ step: option.step,
3416
+ value: Number(values[option.key]),
3417
+ onChange: (event) => setValues({
3418
+ ...values,
3419
+ [option.key]: Number(event.target.value)
3420
+ })
3421
+ }
3422
+ ),
3423
+ option.presets?.map((preset) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3424
+ Button,
3425
+ {
3426
+ type: "button",
3427
+ variant: "ghost",
3428
+ className: "matrx-alchemy-workspace-secondary",
3429
+ onClick: () => setValues({ ...values, [option.key]: preset.value }),
3430
+ children: preset.label
3431
+ },
3432
+ preset.value
3433
+ ))
3434
+ ] })
3435
+ ] }, option.key)),
3436
+ groomer ? /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
3437
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { children: ["full", "compact", "brief"].map((level) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3358
3438
  Button,
3359
3439
  {
3360
3440
  type: "button",
3361
3441
  variant: "ghost",
3362
- onClick: () => setValues({ ...values, [option.key]: preset.value }),
3363
- children: preset.label
3442
+ className: "matrx-alchemy-workspace-secondary",
3443
+ onClick: () => setSections(
3444
+ Object.fromEntries(
3445
+ groomer.sections.map((section) => [
3446
+ section.id,
3447
+ level === "brief" && section.cuttable ? "off" : level
3448
+ ])
3449
+ )
3450
+ ),
3451
+ children: level
3364
3452
  },
3365
- preset.value
3366
- ))
3367
- ] })
3368
- ] }, option.key)),
3369
- groomer ? /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
3370
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { children: ["full", "compact", "brief"].map((level) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3371
- Button,
3372
- {
3373
- type: "button",
3374
- variant: "ghost",
3375
- onClick: () => setSections(
3376
- Object.fromEntries(
3377
- groomer.sections.map((section) => [
3378
- section.id,
3379
- level === "brief" && section.cuttable ? "off" : level
3380
- ])
3381
- )
3453
+ level
3454
+ )) }),
3455
+ groomer.sections.map((section) => /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("label", { children: [
3456
+ section.title,
3457
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
3458
+ "select",
3459
+ {
3460
+ value: sections[section.id],
3461
+ onChange: (event) => setSections({
3462
+ ...sections,
3463
+ [section.id]: event.target.value
3464
+ }),
3465
+ children: [
3466
+ ["full", "compact", "brief"].map((level) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("option", { value: level, children: section.levelLabels?.[level] ?? level }, level)),
3467
+ section.cuttable ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("option", { value: "off", children: "Exclude" }) : null
3468
+ ]
3469
+ }
3382
3470
  ),
3383
- children: level
3384
- },
3385
- level
3386
- )) }),
3387
- groomer.sections.map((section) => /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("label", { children: [
3388
- section.title,
3389
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
3390
- "select",
3391
- {
3392
- value: sections[section.id],
3393
- onChange: (event) => setSections({
3394
- ...sections,
3395
- [section.id]: event.target.value
3396
- }),
3397
- children: [
3398
- ["full", "compact", "brief"].map((level) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("option", { value: level, children: section.levelLabels?.[level] ?? level }, level)),
3399
- section.cuttable ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("option", { value: "off", children: "Exclude" }) : null
3400
- ]
3401
- }
3402
- ),
3403
- section.description ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { children: section.description }) : null
3404
- ] }, section.id))
3405
- ] }) : null
3406
- ] }),
3407
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("p", { children: [
3408
- text.length.toLocaleString(),
3409
- " characters \xB7 approximately",
3410
- " ",
3411
- Math.ceil(text.length / 4).toLocaleString(),
3412
- " tokens"
3471
+ section.description ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { children: section.description }) : null
3472
+ ] }, section.id))
3473
+ ] }) : null
3474
+ ] }),
3475
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("p", { children: [
3476
+ text.length.toLocaleString(),
3477
+ " characters \xB7 approximately",
3478
+ " ",
3479
+ Math.ceil(text.length / 4).toLocaleString(),
3480
+ " tokens"
3481
+ ] }),
3482
+ error || buildError ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { role: "alert", children: error ?? buildError }) : null
3413
3483
  ] }),
3414
- error || buildError ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { role: "alert", children: error ?? buildError }) : null,
3415
3484
  /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(DialogFooter, { children: [
3416
3485
  /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3417
3486
  Button,
3418
3487
  {
3419
3488
  type: "button",
3420
3489
  variant: "ghost",
3490
+ className: "matrx-alchemy-workspace-secondary",
3421
3491
  disabled: busy,
3422
3492
  onClick: onClose,
3423
3493
  children: "Cancel"
@@ -3427,6 +3497,7 @@ function SourceConfiguration({
3427
3497
  Button,
3428
3498
  {
3429
3499
  type: "button",
3500
+ className: "matrx-alchemy-workspace-primary",
3430
3501
  disabled: busy || !prepared || Boolean(buildError),
3431
3502
  onClick: async () => {
3432
3503
  if (!prepared) return;
@@ -4041,7 +4112,7 @@ function CopySubsetDialog({ source, onClose }) {
4041
4112
  ] }) });
4042
4113
  }
4043
4114
  function useCopySubsetVariant() {
4044
- return (getSource) => ({ id: "copy-subset", label: "Filter & sort before copying\u2026", section: "ai", modal: ({ open, onOpenChange }) => open ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(CopySubsetDialog, { source: getSource(), onClose: () => onOpenChange(false) }) : null });
4115
+ return (getSource) => ({ id: "copy-subset", label: "Filter & sort before copying", section: "ai", modal: ({ open, onOpenChange }) => open ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(CopySubsetDialog, { source: getSource(), onClose: () => onOpenChange(false) }) : null });
4045
4116
  }
4046
4117
 
4047
4118
  // src/data-table/clipping.ts
@@ -6745,6 +6816,23 @@ function safeQueryPage(requestedPage, totalItems, pageSize) {
6745
6816
 
6746
6817
  // src/data-table/MatrxDataTable.tsx
6747
6818
  var import_jsx_runtime35 = require("react/jsx-runtime");
6819
+ function TableToolbarAction({
6820
+ HostAction,
6821
+ ariaLabel,
6822
+ tooltip,
6823
+ disabled,
6824
+ busy,
6825
+ onClick,
6826
+ children
6827
+ }) {
6828
+ if (HostAction) {
6829
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(HostAction, { ariaLabel, tooltip, disabled, busy, onClick, children });
6830
+ }
6831
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(Tooltip, { children: [
6832
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "inline-flex", children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(Button, { type: "button", variant: "ghost", size: "icon", className: "h-8 w-8", "aria-label": ariaLabel, "aria-busy": busy || void 0, disabled, onClick, children: (0, import_react13.isValidElement)(children) ? (0, import_react13.cloneElement)(children, { className: cn("h-4 w-4", children.props.className) }) : children }) }) }),
6833
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(TooltipContent, { children: tooltip ?? ariaLabel })
6834
+ ] });
6835
+ }
6748
6836
  function hasSameRowReferences(previous, next) {
6749
6837
  return previous.length === next.length && previous.every((row, index) => row === next[index]);
6750
6838
  }
@@ -8182,29 +8270,21 @@ function MatrxDataTableCore({
8182
8270
  ]
8183
8271
  }
8184
8272
  ) : null,
8185
- /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(Tooltip, { children: [
8186
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "inline-flex", children: /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(
8187
- Button,
8188
- {
8189
- type: "button",
8190
- variant: "ghost",
8191
- size: "sm",
8192
- className: "h-7 gap-1 px-2 text-xs text-muted-foreground",
8193
- onClick: clearAllFilters,
8194
- disabled: !hasActiveFilters,
8195
- "aria-label": "Clear all filters",
8196
- children: [
8197
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(Eraser, { className: "h-3.5 w-3.5" }),
8198
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "max-sm:sr-only", children: "Clear all" })
8199
- ]
8200
- }
8201
- ) }) }),
8202
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(TooltipContent, { children: hasActiveFilters ? "Clear search and filters; keep columns and sort" : "No search or filters to clear" })
8203
- ] }),
8273
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
8274
+ TableToolbarAction,
8275
+ {
8276
+ HostAction: host.ToolbarAction,
8277
+ ariaLabel: "Clear all filters",
8278
+ tooltip: hasActiveFilters ? "Clear search and filters; keep columns and sort" : "No search or filters to clear",
8279
+ disabled: !hasActiveFilters,
8280
+ onClick: clearAllFilters,
8281
+ children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(Eraser, {})
8282
+ }
8283
+ ),
8204
8284
  showToolbarCopy && effectiveCopy ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
8205
8285
  CopyButtons,
8206
8286
  {
8207
- size: "icon",
8287
+ size: "toolbar",
8208
8288
  sourceId: `${tableCopySourceNamespace}:view`,
8209
8289
  label: effectiveCopy.listLabel ?? `${effectiveCopy.label} view`,
8210
8290
  ...copy === void 0 ? {} : {
@@ -8241,92 +8321,66 @@ function MatrxDataTableCore({
8241
8321
  }
8242
8322
  }
8243
8323
  ) : null,
8244
- columns.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(Tooltip, { children: [
8245
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(
8246
- Button,
8247
- {
8248
- type: "button",
8249
- variant: "ghost",
8250
- size: "icon",
8251
- "aria-label": "Columns",
8252
- className: "h-8 w-8",
8253
- onClick: () => setColumnManagerOpen(true),
8254
- children: [
8255
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(SlidersHorizontal, { className: "h-4 w-4" }),
8256
- effectiveHiddenColumnIds.size > 0 ? /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("span", { className: "sr-only", children: [
8257
- effectiveHiddenColumnIds.size,
8258
- " hidden"
8259
- ] }) : null
8260
- ]
8261
- }
8262
- ) }),
8263
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(TooltipContent, { children: "Show, hide, or reorder columns" })
8264
- ] }) : null,
8265
- toolbar?.refresh ? /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(Tooltip, { children: [
8266
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "inline-flex", children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
8267
- Button,
8268
- {
8269
- type: "button",
8270
- variant: "ghost",
8271
- size: "icon",
8272
- className: "h-8 w-8",
8273
- "aria-label": toolbar.refresh.label ?? "Refresh",
8274
- disabled: isFetching || toolbarActionPending.refresh,
8275
- onClick: () => {
8276
- if (toolbarActionPendingRef.current.refresh) return;
8277
- toolbarActionPendingRef.current.refresh = true;
8278
- setToolbarActionPending((current) => ({ ...current, refresh: true }));
8279
- setToolbarActionError(null);
8280
- void Promise.resolve().then(() => toolbar.refresh?.onRefresh()).catch((cause) => {
8281
- const message = cause instanceof Error ? cause.message : String(cause);
8282
- setToolbarActionError(`Refresh failed: ${message}`);
8283
- toast.error(`Refresh failed: ${message}`);
8284
- }).finally(() => {
8285
- toolbarActionPendingRef.current.refresh = false;
8286
- setToolbarActionPending((current) => ({ ...current, refresh: false }));
8287
- });
8288
- },
8289
- children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
8290
- Loader2,
8291
- {
8292
- className: cn(
8293
- "h-4 w-4",
8294
- (isFetching || toolbarActionPending.refresh) && "animate-spin"
8295
- )
8296
- }
8297
- )
8298
- }
8299
- ) }) }),
8300
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(TooltipContent, { children: isFetching ? "Refreshing table data" : toolbar.refresh.label ?? "Refresh" })
8301
- ] }) : null,
8302
- toolbar?.add ? /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(Tooltip, { children: [
8303
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "inline-flex", children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
8304
- Button,
8305
- {
8306
- type: "button",
8307
- size: "icon",
8308
- className: "h-8 w-8",
8309
- "aria-label": "Add",
8310
- disabled: toolbar.add.disabled || toolbarActionPending.add,
8311
- onClick: () => {
8312
- if (toolbarActionPendingRef.current.add) return;
8313
- toolbarActionPendingRef.current.add = true;
8314
- setToolbarActionPending((current) => ({ ...current, add: true }));
8315
- setToolbarActionError(null);
8316
- void Promise.resolve().then(() => toolbar.add?.onAdd()).catch((cause) => {
8317
- const message = cause instanceof Error ? cause.message : String(cause);
8318
- setToolbarActionError(`Add failed: ${message}`);
8319
- toast.error(`Add failed: ${message}`);
8320
- }).finally(() => {
8321
- toolbarActionPendingRef.current.add = false;
8322
- setToolbarActionPending((current) => ({ ...current, add: false }));
8323
- });
8324
- },
8325
- children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(Plus, { className: "h-4 w-4" })
8326
- }
8327
- ) }) }),
8328
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(TooltipContent, { children: toolbar.add.disabled ? toolbar.add.disabledReason ?? "Add unavailable" : "Add" })
8329
- ] }) : null,
8324
+ columns.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
8325
+ TableToolbarAction,
8326
+ {
8327
+ HostAction: host.ToolbarAction,
8328
+ ariaLabel: "Columns",
8329
+ tooltip: "Show, hide, or reorder columns",
8330
+ onClick: () => setColumnManagerOpen(true),
8331
+ children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(SlidersHorizontal, {})
8332
+ }
8333
+ ) : null,
8334
+ toolbar?.refresh ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
8335
+ TableToolbarAction,
8336
+ {
8337
+ HostAction: host.ToolbarAction,
8338
+ ariaLabel: toolbar.refresh.label ?? "Refresh",
8339
+ tooltip: isFetching ? "Refreshing table data" : toolbar.refresh.label ?? "Refresh",
8340
+ disabled: isFetching || toolbarActionPending.refresh,
8341
+ busy: isFetching || toolbarActionPending.refresh,
8342
+ onClick: () => {
8343
+ if (toolbarActionPendingRef.current.refresh) return;
8344
+ toolbarActionPendingRef.current.refresh = true;
8345
+ setToolbarActionPending((current) => ({ ...current, refresh: true }));
8346
+ setToolbarActionError(null);
8347
+ void Promise.resolve().then(() => toolbar.refresh?.onRefresh()).catch((cause) => {
8348
+ const message = cause instanceof Error ? cause.message : String(cause);
8349
+ setToolbarActionError(`Refresh failed: ${message}`);
8350
+ toast.error(`Refresh failed: ${message}`);
8351
+ }).finally(() => {
8352
+ toolbarActionPendingRef.current.refresh = false;
8353
+ setToolbarActionPending((current) => ({ ...current, refresh: false }));
8354
+ });
8355
+ },
8356
+ children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(RefreshControlIcon, { spinning: isFetching || toolbarActionPending.refresh })
8357
+ }
8358
+ ) : null,
8359
+ toolbar?.add ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
8360
+ TableToolbarAction,
8361
+ {
8362
+ HostAction: host.ToolbarAction,
8363
+ ariaLabel: "Add",
8364
+ tooltip: toolbar.add.disabled ? toolbar.add.disabledReason ?? "Add unavailable" : "Add",
8365
+ disabled: toolbar.add.disabled || toolbarActionPending.add,
8366
+ busy: toolbarActionPending.add,
8367
+ onClick: () => {
8368
+ if (toolbarActionPendingRef.current.add) return;
8369
+ toolbarActionPendingRef.current.add = true;
8370
+ setToolbarActionPending((current) => ({ ...current, add: true }));
8371
+ setToolbarActionError(null);
8372
+ void Promise.resolve().then(() => toolbar.add?.onAdd()).catch((cause) => {
8373
+ const message = cause instanceof Error ? cause.message : String(cause);
8374
+ setToolbarActionError(`Add failed: ${message}`);
8375
+ toast.error(`Add failed: ${message}`);
8376
+ }).finally(() => {
8377
+ toolbarActionPendingRef.current.add = false;
8378
+ setToolbarActionPending((current) => ({ ...current, add: false }));
8379
+ });
8380
+ },
8381
+ children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(Plus, {})
8382
+ }
8383
+ ) : null,
8330
8384
  toolbar?.actions
8331
8385
  ]
8332
8386
  }
@@ -8449,13 +8503,13 @@ function MatrxDataTableCore({
8449
8503
  actions: showRowCopy || rowActions ? /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(
8450
8504
  "div",
8451
8505
  {
8452
- className: "inline-flex items-center gap-1",
8506
+ className: "inline-flex items-center gap-0",
8453
8507
  onClick: (event) => event.stopPropagation(),
8454
8508
  children: [
8455
8509
  showRowCopy && effectiveCopy ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
8456
8510
  TableRowCopyControl,
8457
8511
  {
8458
- size: "xs",
8512
+ size: "toolbar",
8459
8513
  copy: effectiveCopy,
8460
8514
  row: displayRow,
8461
8515
  sourceId: `${tableCopySourceNamespace}:row:${getRowId(displayRow)}`,
@@ -8752,13 +8806,13 @@ function MatrxDataTableCore({
8752
8806
  showActionsCol && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("td", { className: "px-2 py-1.5 text-right align-middle lg:py-0.5", children: /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(
8753
8807
  "div",
8754
8808
  {
8755
- className: "inline-flex items-center justify-end gap-0.5",
8809
+ className: "inline-flex items-center justify-end gap-0",
8756
8810
  onClick: (e) => e.stopPropagation(),
8757
8811
  children: [
8758
8812
  showRowCopy && effectiveCopy ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
8759
8813
  TableRowCopyControl,
8760
8814
  {
8761
- size: "xs",
8815
+ size: "toolbar",
8762
8816
  copy: effectiveCopy,
8763
8817
  row: displayRow,
8764
8818
  sourceId: `${tableCopySourceNamespace}:row:${getRowId(displayRow)}`,
@@ -9595,6 +9649,7 @@ function SavedViewsControl({
9595
9649
  onUpdate,
9596
9650
  onReload
9597
9651
  }) {
9652
+ const unsavedChangesId = (0, import_react14.useId)();
9598
9653
  const [saveOpen, setSaveOpen] = (0, import_react14.useState)(false);
9599
9654
  const [name, setName] = (0, import_react14.useState)("");
9600
9655
  const [saving, setSaving] = (0, import_react14.useState)(false);
@@ -9640,10 +9695,26 @@ function SavedViewsControl({
9640
9695
  }
9641
9696
  };
9642
9697
  const activeName = activeId ? views.find((view) => view.id === activeId)?.name : void 0;
9643
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "flex items-center gap-1", "data-matrx-table-saved-views": true, children: [
9698
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "flex min-w-0 flex-wrap items-center gap-1", "data-matrx-table-saved-views": true, children: [
9644
9699
  /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(DropdownMenu, { children: [
9645
9700
  /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(Tooltip, { children: [
9646
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(Button, { type: "button", variant: "outline", size: "sm", className: "h-8 max-w-40 truncate text-xs", "aria-label": "Saved views", disabled: saving, children: loading ? "Loading views\u2026" : `${activeName ?? "Default view"}${dirty ? " \u2022" : ""}` }) }) }),
9701
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(
9702
+ Button,
9703
+ {
9704
+ type: "button",
9705
+ variant: "ghost",
9706
+ size: "sm",
9707
+ className: "h-8 min-w-0 max-w-52 gap-1 px-2 text-xs font-medium",
9708
+ "aria-label": `Table view: ${loading ? "Loading views" : activeName ?? "Default view"}${dirty ? ", unsaved changes" : ""}`,
9709
+ "aria-describedby": dirty ? unsavedChangesId : void 0,
9710
+ disabled: saving,
9711
+ children: [
9712
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "min-w-0 flex-1 truncate", children: loading ? "Loading views\u2026" : activeName ?? "Default view" }),
9713
+ dirty ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { "aria-hidden": "true", className: "size-1.5 shrink-0 rounded-full bg-amber-500" }) : null,
9714
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(ChevronDown, { className: "size-3.5 shrink-0" })
9715
+ ]
9716
+ }
9717
+ ) }) }),
9647
9718
  /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(TooltipContent, { children: "Choose or save a table view" })
9648
9719
  ] }),
9649
9720
  /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(DropdownMenuContent, { align: "end", children: [
@@ -9661,14 +9732,8 @@ function SavedViewsControl({
9661
9732
  onReload ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(DropdownMenuItem, { disabled: saving || loading, onSelect: () => void reload(), children: "Reload views" }) : null
9662
9733
  ] })
9663
9734
  ] }),
9664
- /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(Tooltip, { children: [
9665
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(Button, { type: "button", variant: "ghost", size: "icon", className: "h-8 w-8", "aria-label": "Save current view", disabled: saving, onClick: () => {
9666
- setActionError(null);
9667
- setSaveOpen(true);
9668
- }, children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(Save, { className: "h-4 w-4" }) }) }),
9669
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(TooltipContent, { children: "Save current view" })
9670
- ] }),
9671
- visibleError ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("p", { role: "alert", className: "basis-full text-xs text-destructive", children: visibleError }) : null,
9735
+ dirty ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { id: unsavedChangesId, className: "sr-only", children: "This table view has unsaved changes. Open the view menu to save or update it." }) : null,
9736
+ visibleError ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("p", { role: "alert", className: "basis-full break-words text-xs text-destructive", children: visibleError }) : null,
9672
9737
  /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(Dialog, { open: saveOpen, onOpenChange: setSaveOpen, children: /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(DialogContent, { children: [
9673
9738
  /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(DialogHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(DialogTitle, { children: "Save current view" }) }),
9674
9739
  visibleError ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("p", { role: "alert", className: "text-sm text-destructive", children: visibleError }) : null,