@ai-matrx/design-system 0.18.10 → 0.18.12

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 +23 -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 +312 -278
  10. package/dist/content-transfer.cjs.map +1 -1
  11. package/dist/content-transfer.css +87 -24
  12. package/dist/content-transfer.d.cts +1 -1
  13. package/dist/content-transfer.d.ts +1 -1
  14. package/dist/content-transfer.js +312 -278
  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 +314 -277
  22. package/dist/data-table/data-row-inspector.cjs.map +1 -1
  23. package/dist/data-table/data-row-inspector.js +314 -277
  24. package/dist/data-table/data-row-inspector.js.map +1 -1
  25. package/dist/data-table/data-row-window.cjs +314 -277
  26. package/dist/data-table/data-row-window.cjs.map +1 -1
  27. package/dist/data-table/data-row-window.js +314 -277
  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 +452 -399
  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 +453 -400
  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,138 @@ 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))
2813
+ ] }) : null,
2814
+ rows ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(RowControls, { rows, controls, change: changeControls }) : null,
2815
+ state.snapshot.sections.length ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("fieldset", { className: "matrx-alchemy-options", children: [
2816
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("legend", { children: "Sections" }),
2817
+ state.snapshot.sections.map((section) => /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { children: [
2818
+ /* @__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) }) }),
2819
+ " ",
2820
+ section.label
2821
+ ] }, section.id))
2795
2822
  ] }) : null,
2796
- displayedOmissions.length ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("details", { children: [
2797
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("summary", { children: [
2798
- displayedOmissions.length,
2799
- " omissions or adjustments"
2823
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "matrx-alchemy-coverage", children: [
2824
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { children: [
2825
+ state.snapshot.coverage.included.toLocaleString(),
2826
+ " included",
2827
+ state.snapshot.coverage.total == null ? "" : ` of ${state.snapshot.coverage.total.toLocaleString()}`,
2828
+ " \xB7 ",
2829
+ state.snapshot.coverage.status
2800
2830
  ] }),
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
- ] })
2831
+ state.snapshot.coverage.reason ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { children: state.snapshot.coverage.reason }) : null,
2832
+ limitText ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { children: [
2833
+ "Limits: ",
2834
+ limitText
2835
+ ] }) : null,
2836
+ displayedOmissions.length ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("details", { children: [
2837
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("summary", { children: [
2838
+ displayedOmissions.length,
2839
+ " omissions or adjustments"
2840
+ ] }),
2841
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("ul", { children: displayedOmissions.map((o, i) => /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("li", { children: [
2842
+ o.path || "/",
2843
+ ": ",
2844
+ o.reason,
2845
+ o.count == null ? "" : ` (${o.count})`
2846
+ ] }, `${o.path}-${o.reason}-${i}`)) })
2847
+ ] }) : null
2848
+ ] }),
2849
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { className: "matrx-alchemy-preview-label", children: [
2850
+ "Output format",
2851
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("select", { "aria-label": "Output format", value: format, onChange: (e) => setFormat(e.target.value), children: [
2852
+ formats.map((f) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("option", { value: f, children: LABEL[f] }, f)),
2853
+ state.draft.payload.kind === "rows" ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("option", { value: "xlsx", children: "Excel workbook" }) : null,
2854
+ workspaceAdapters.map((adapter) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("option", { value: adapter.id, children: adapter.label }, adapter.id))
2855
+ ] })
2856
+ ] }),
2857
+ /* @__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) }),
2858
+ bufferError ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { id: "alchemy-buffer-error", role: "alert", className: "matrx-alchemy-error", children: bufferError }) : null,
2859
+ formatError ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { role: "alert", className: "matrx-alchemy-error", children: formatError }) : null,
2860
+ bufferError ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Button, { className: "matrx-alchemy-workspace-secondary", type: "button", variant: "outline", disabled: busy !== null, onClick: () => {
2861
+ const fallback = (0, import_content_transfer.editDraft)(state.draft, { kind: "text", text: buffer });
2862
+ setBufferError(null);
2863
+ onChange({ ...state, draft: fallback, error: void 0 });
2864
+ setFormat("plain");
2865
+ }, children: "Use invalid JSON as plain text" }) : null
2816
2866
  ] }),
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
2867
+ ai || busy === "capture" || state.error ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("aside", { children: [
2868
+ ai ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
2869
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { children: [
2870
+ "AI instruction",
2871
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("textarea", { value: instruction, onChange: (e) => setInstruction(e.target.value), placeholder: "Tell AI how to prepare this content" })
2872
+ ] }),
2873
+ /* @__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" }),
2874
+ 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
2875
+ ] }) : null,
2876
+ busy === "capture" ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Button, { className: "matrx-alchemy-workspace-secondary", type: "button", variant: "outline", onClick: () => {
2877
+ activeCapture.current?.abort();
2878
+ activeCapture.current = null;
2879
+ setBusy(null);
2880
+ }, children: "Stop loading rows" }) : null,
2881
+ 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,
2882
+ 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,
2883
+ state.error ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { role: "alert", className: "matrx-alchemy-error", children: state.error }) : null
2884
+ ] }) : null
2826
2885
  ] }),
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
2886
+ pendingControls ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "matrx-alchemy-decision", role: "alert", children: [
2887
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { children: "This control would replace your manual edit." }),
2888
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Button, { className: "matrx-alchemy-workspace-secondary", type: "button", variant: "outline", onClick: () => setPendingControls(null), children: "Keep edited draft" }),
2889
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Button, { className: "matrx-alchemy-workspace-primary", type: "button", onClick: applyPendingControls, children: "Rebuild from source" })
2890
+ ] }) : null,
2891
+ 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,
2892
+ state.pending ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "matrx-alchemy-decision", role: "alert", children: [
2893
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { children: "A fresh source snapshot is ready." }),
2894
+ /* @__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" }),
2895
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Button, { className: "matrx-alchemy-workspace-primary", type: "button", onClick: () => resolveCapture("regenerate"), children: "Regenerate from fresh source" })
2896
+ ] }) : null,
2897
+ deliveryNotice ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { role: "status", className: "matrx-alchemy-meta", children: deliveryNotice }) : null
2845
2898
  ] }),
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
2899
  /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(DialogFooter, { children: [
2859
2900
  /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("span", { className: "matrx-alchemy-meta", children: [
2860
2901
  buffer.length.toLocaleString(),
@@ -2862,13 +2903,16 @@ function PreparationWorkspace({ restoreFocus, open, state, scopes, onClose, onCh
2862
2903
  estimateTokens(buffer).toLocaleString(),
2863
2904
  " tokens"
2864
2905
  ] }),
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" })
2906
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Button, { type: "button", variant: "outline", className: "matrx-alchemy-workspace-secondary", onClick: close, children: "Close" }),
2907
+ /* @__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" }),
2908
+ /* @__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
2909
  ] })
2869
2910
  ] }) });
2870
2911
  }
2871
2912
  function RowControls({ rows, controls, change }) {
2913
+ const filterCount = Object.values(controls.filters).filter(Boolean).length;
2914
+ const selectionSummary = controls.selectedOnly ? `${controls.selectedIndices.length} selected row${controls.selectedIndices.length === 1 ? "" : "s"}` : "All rows";
2915
+ 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
2916
  return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
2873
2917
  /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "matrx-alchemy-toolbar", children: [
2874
2918
  /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { children: [
@@ -2894,32 +2938,40 @@ function RowControls({ rows, controls, change }) {
2894
2938
  /* @__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
2939
  ] })
2896
2940
  ] }),
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: [
2941
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("details", { className: "matrx-alchemy-options", children: [
2942
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("summary", { children: [
2943
+ "Columns and filters",
2944
+ dataSummary ? ` \u2014 ${dataSummary}` : ""
2945
+ ] }),
2946
+ /* @__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
2947
  /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { children: [
2901
2948
  /* @__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
2949
  " ",
2903
2950
  column.label
2904
2951
  ] }),
2905
2952
  /* @__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))
2953
+ ] }, column.id)) })
2907
2954
  ] }),
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"
2955
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("details", { className: "matrx-alchemy-options", children: [
2956
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("summary", { children: [
2957
+ "Rows \u2014 ",
2958
+ selectionSummary
2913
2959
  ] }),
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
- }) })
2960
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("fieldset", { "aria-label": "Row selection", children: [
2961
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { children: [
2962
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("input", { type: "checkbox", checked: controls.selectedOnly, onChange: (e) => change({ ...controls, selectedOnly: e.target.checked }) }),
2963
+ " Only selected rows"
2964
+ ] }),
2965
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "matrx-alchemy-row-list", children: rows.rows.map((row, index) => {
2966
+ 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 ");
2967
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("label", { children: [
2968
+ /* @__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) }) }),
2969
+ " Row ",
2970
+ index + 1,
2971
+ summary ? ` \u2014 ${summary}` : ""
2972
+ ] }, index);
2973
+ }) })
2974
+ ] })
2923
2975
  ] })
2924
2976
  ] });
2925
2977
  }
@@ -3071,7 +3123,7 @@ function MatrxCopyMenuSession(props) {
3071
3123
  if (aiVisible && props.aiCustom)
3072
3124
  actions.push({
3073
3125
  id: "configure-source",
3074
- label: props.aiCustom.label ?? "Customize source\u2026",
3126
+ label: props.aiCustom.label ?? "Customize source",
3075
3127
  ...props.aiCustom.hint ? { hint: props.aiCustom.hint } : {},
3076
3128
  supports: () => true,
3077
3129
  run: async () => {
@@ -3082,7 +3134,7 @@ function MatrxCopyMenuSession(props) {
3082
3134
  if (aiVisible && props.groomer)
3083
3135
  actions.push({
3084
3136
  id: "groom-source",
3085
- label: "Customize sections\u2026",
3137
+ label: "Customize sections",
3086
3138
  supports: () => true,
3087
3139
  run: async () => {
3088
3140
  setConfiguration({ groomer: props.groomer() });
@@ -3192,7 +3244,8 @@ function MatrxCopyMenuSession(props) {
3192
3244
  className: cn(
3193
3245
  props.className,
3194
3246
  props.size === "xs" && "matrx-alchemy-xs",
3195
- props.size === "sm" && "matrx-alchemy-sm"
3247
+ props.size === "sm" && "matrx-alchemy-sm",
3248
+ props.size === "toolbar" && "matrx-alchemy-toolbar-target"
3196
3249
  ),
3197
3250
  ...props.stopPropagation !== void 0 ? { stopPropagation: props.stopPropagation } : {}
3198
3251
  }
@@ -3297,127 +3350,132 @@ function SourceConfiguration({
3297
3350
  event.preventDefault();
3298
3351
  if (!handingOff.current) restoreFocus();
3299
3352
  },
3300
- className: "matrx-alchemy-workspace",
3353
+ className: "matrx-alchemy-workspace matrx-alchemy-configuration",
3301
3354
  children: [
3302
3355
  /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(DialogHeader, { children: [
3303
3356
  /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(DialogTitle, { children: title }),
3304
3357
  /* @__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
3358
  ] }),
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)(
3359
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "matrx-alchemy-workspace-body", children: [
3360
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "matrx-alchemy-main matrx-alchemy-toolbar", children: [
3361
+ custom?.options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("label", { children: [
3362
+ option.label,
3363
+ "hint" in option && option.hint ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("small", { children: option.hint }) : null,
3364
+ option.kind === "toggle" ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3329
3365
  "input",
3330
3366
  {
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
- })
3367
+ type: "checkbox",
3368
+ checked: Boolean(values[option.key]),
3369
+ onChange: (event) => setValues({ ...values, [option.key]: event.target.checked })
3340
3370
  }
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",
3371
+ ) : option.kind === "preset" ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3372
+ "select",
3346
3373
  {
3347
- type: "number",
3348
- min: option.min,
3349
- step: option.step,
3350
3374
  value: Number(values[option.key]),
3351
3375
  onChange: (event) => setValues({
3352
3376
  ...values,
3353
3377
  [option.key]: Number(event.target.value)
3354
- })
3378
+ }),
3379
+ children: option.options.map((choice) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("option", { value: choice.value, children: choice.label }, choice.value))
3355
3380
  }
3356
- ),
3357
- option.presets?.map((preset) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3381
+ ) : option.kind === "slider" ? /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
3382
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3383
+ "input",
3384
+ {
3385
+ type: "range",
3386
+ min: 0,
3387
+ max: Math.max(0, option.stops.length - 1),
3388
+ step: 1,
3389
+ value: option.stops.indexOf(Number(values[option.key])),
3390
+ onChange: (event) => setValues({
3391
+ ...values,
3392
+ [option.key]: option.stops[Number(event.target.value)]
3393
+ })
3394
+ }
3395
+ ),
3396
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { children: option.formatValue(Number(values[option.key])) })
3397
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
3398
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3399
+ "input",
3400
+ {
3401
+ type: "number",
3402
+ min: option.min,
3403
+ step: option.step,
3404
+ value: Number(values[option.key]),
3405
+ onChange: (event) => setValues({
3406
+ ...values,
3407
+ [option.key]: Number(event.target.value)
3408
+ })
3409
+ }
3410
+ ),
3411
+ option.presets?.map((preset) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3412
+ Button,
3413
+ {
3414
+ type: "button",
3415
+ variant: "ghost",
3416
+ className: "matrx-alchemy-workspace-secondary",
3417
+ onClick: () => setValues({ ...values, [option.key]: preset.value }),
3418
+ children: preset.label
3419
+ },
3420
+ preset.value
3421
+ ))
3422
+ ] })
3423
+ ] }, option.key)),
3424
+ groomer ? /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
3425
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { children: ["full", "compact", "brief"].map((level) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3358
3426
  Button,
3359
3427
  {
3360
3428
  type: "button",
3361
3429
  variant: "ghost",
3362
- onClick: () => setValues({ ...values, [option.key]: preset.value }),
3363
- children: preset.label
3430
+ className: "matrx-alchemy-workspace-secondary",
3431
+ onClick: () => setSections(
3432
+ Object.fromEntries(
3433
+ groomer.sections.map((section) => [
3434
+ section.id,
3435
+ level === "brief" && section.cuttable ? "off" : level
3436
+ ])
3437
+ )
3438
+ ),
3439
+ children: level
3364
3440
  },
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
- )
3441
+ level
3442
+ )) }),
3443
+ groomer.sections.map((section) => /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("label", { children: [
3444
+ section.title,
3445
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
3446
+ "select",
3447
+ {
3448
+ value: sections[section.id],
3449
+ onChange: (event) => setSections({
3450
+ ...sections,
3451
+ [section.id]: event.target.value
3452
+ }),
3453
+ children: [
3454
+ ["full", "compact", "brief"].map((level) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("option", { value: level, children: section.levelLabels?.[level] ?? level }, level)),
3455
+ section.cuttable ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("option", { value: "off", children: "Exclude" }) : null
3456
+ ]
3457
+ }
3382
3458
  ),
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"
3459
+ section.description ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { children: section.description }) : null
3460
+ ] }, section.id))
3461
+ ] }) : null
3462
+ ] }),
3463
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("p", { children: [
3464
+ text.length.toLocaleString(),
3465
+ " characters \xB7 approximately",
3466
+ " ",
3467
+ Math.ceil(text.length / 4).toLocaleString(),
3468
+ " tokens"
3469
+ ] }),
3470
+ error || buildError ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { role: "alert", children: error ?? buildError }) : null
3413
3471
  ] }),
3414
- error || buildError ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { role: "alert", children: error ?? buildError }) : null,
3415
3472
  /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(DialogFooter, { children: [
3416
3473
  /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3417
3474
  Button,
3418
3475
  {
3419
3476
  type: "button",
3420
3477
  variant: "ghost",
3478
+ className: "matrx-alchemy-workspace-secondary",
3421
3479
  disabled: busy,
3422
3480
  onClick: onClose,
3423
3481
  children: "Cancel"
@@ -3427,6 +3485,7 @@ function SourceConfiguration({
3427
3485
  Button,
3428
3486
  {
3429
3487
  type: "button",
3488
+ className: "matrx-alchemy-workspace-primary",
3430
3489
  disabled: busy || !prepared || Boolean(buildError),
3431
3490
  onClick: async () => {
3432
3491
  if (!prepared) return;
@@ -4041,7 +4100,7 @@ function CopySubsetDialog({ source, onClose }) {
4041
4100
  ] }) });
4042
4101
  }
4043
4102
  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 });
4103
+ 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
4104
  }
4046
4105
 
4047
4106
  // src/data-table/clipping.ts
@@ -6745,6 +6804,23 @@ function safeQueryPage(requestedPage, totalItems, pageSize) {
6745
6804
 
6746
6805
  // src/data-table/MatrxDataTable.tsx
6747
6806
  var import_jsx_runtime35 = require("react/jsx-runtime");
6807
+ function TableToolbarAction({
6808
+ HostAction,
6809
+ ariaLabel,
6810
+ tooltip,
6811
+ disabled,
6812
+ busy,
6813
+ onClick,
6814
+ children
6815
+ }) {
6816
+ if (HostAction) {
6817
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(HostAction, { ariaLabel, tooltip, disabled, busy, onClick, children });
6818
+ }
6819
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(Tooltip, { children: [
6820
+ /* @__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 }) }) }),
6821
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(TooltipContent, { children: tooltip ?? ariaLabel })
6822
+ ] });
6823
+ }
6748
6824
  function hasSameRowReferences(previous, next) {
6749
6825
  return previous.length === next.length && previous.every((row, index) => row === next[index]);
6750
6826
  }
@@ -8182,29 +8258,21 @@ function MatrxDataTableCore({
8182
8258
  ]
8183
8259
  }
8184
8260
  ) : 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
- ] }),
8261
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
8262
+ TableToolbarAction,
8263
+ {
8264
+ HostAction: host.ToolbarAction,
8265
+ ariaLabel: "Clear all filters",
8266
+ tooltip: hasActiveFilters ? "Clear search and filters; keep columns and sort" : "No search or filters to clear",
8267
+ disabled: !hasActiveFilters,
8268
+ onClick: clearAllFilters,
8269
+ children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(Eraser, {})
8270
+ }
8271
+ ),
8204
8272
  showToolbarCopy && effectiveCopy ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
8205
8273
  CopyButtons,
8206
8274
  {
8207
- size: "icon",
8275
+ size: "toolbar",
8208
8276
  sourceId: `${tableCopySourceNamespace}:view`,
8209
8277
  label: effectiveCopy.listLabel ?? `${effectiveCopy.label} view`,
8210
8278
  ...copy === void 0 ? {} : {
@@ -8241,92 +8309,66 @@ function MatrxDataTableCore({
8241
8309
  }
8242
8310
  }
8243
8311
  ) : 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,
8312
+ columns.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
8313
+ TableToolbarAction,
8314
+ {
8315
+ HostAction: host.ToolbarAction,
8316
+ ariaLabel: "Columns",
8317
+ tooltip: "Show, hide, or reorder columns",
8318
+ onClick: () => setColumnManagerOpen(true),
8319
+ children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(SlidersHorizontal, {})
8320
+ }
8321
+ ) : null,
8322
+ toolbar?.refresh ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
8323
+ TableToolbarAction,
8324
+ {
8325
+ HostAction: host.ToolbarAction,
8326
+ ariaLabel: toolbar.refresh.label ?? "Refresh",
8327
+ tooltip: isFetching ? "Refreshing table data" : toolbar.refresh.label ?? "Refresh",
8328
+ disabled: isFetching || toolbarActionPending.refresh,
8329
+ busy: isFetching || toolbarActionPending.refresh,
8330
+ onClick: () => {
8331
+ if (toolbarActionPendingRef.current.refresh) return;
8332
+ toolbarActionPendingRef.current.refresh = true;
8333
+ setToolbarActionPending((current) => ({ ...current, refresh: true }));
8334
+ setToolbarActionError(null);
8335
+ void Promise.resolve().then(() => toolbar.refresh?.onRefresh()).catch((cause) => {
8336
+ const message = cause instanceof Error ? cause.message : String(cause);
8337
+ setToolbarActionError(`Refresh failed: ${message}`);
8338
+ toast.error(`Refresh failed: ${message}`);
8339
+ }).finally(() => {
8340
+ toolbarActionPendingRef.current.refresh = false;
8341
+ setToolbarActionPending((current) => ({ ...current, refresh: false }));
8342
+ });
8343
+ },
8344
+ children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(RefreshControlIcon, { spinning: isFetching || toolbarActionPending.refresh })
8345
+ }
8346
+ ) : null,
8347
+ toolbar?.add ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
8348
+ TableToolbarAction,
8349
+ {
8350
+ HostAction: host.ToolbarAction,
8351
+ ariaLabel: "Add",
8352
+ tooltip: toolbar.add.disabled ? toolbar.add.disabledReason ?? "Add unavailable" : "Add",
8353
+ disabled: toolbar.add.disabled || toolbarActionPending.add,
8354
+ busy: toolbarActionPending.add,
8355
+ onClick: () => {
8356
+ if (toolbarActionPendingRef.current.add) return;
8357
+ toolbarActionPendingRef.current.add = true;
8358
+ setToolbarActionPending((current) => ({ ...current, add: true }));
8359
+ setToolbarActionError(null);
8360
+ void Promise.resolve().then(() => toolbar.add?.onAdd()).catch((cause) => {
8361
+ const message = cause instanceof Error ? cause.message : String(cause);
8362
+ setToolbarActionError(`Add failed: ${message}`);
8363
+ toast.error(`Add failed: ${message}`);
8364
+ }).finally(() => {
8365
+ toolbarActionPendingRef.current.add = false;
8366
+ setToolbarActionPending((current) => ({ ...current, add: false }));
8367
+ });
8368
+ },
8369
+ children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(Plus, {})
8370
+ }
8371
+ ) : null,
8330
8372
  toolbar?.actions
8331
8373
  ]
8332
8374
  }
@@ -8449,13 +8491,13 @@ function MatrxDataTableCore({
8449
8491
  actions: showRowCopy || rowActions ? /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(
8450
8492
  "div",
8451
8493
  {
8452
- className: "inline-flex items-center gap-1",
8494
+ className: "inline-flex items-center gap-0",
8453
8495
  onClick: (event) => event.stopPropagation(),
8454
8496
  children: [
8455
8497
  showRowCopy && effectiveCopy ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
8456
8498
  TableRowCopyControl,
8457
8499
  {
8458
- size: "xs",
8500
+ size: "toolbar",
8459
8501
  copy: effectiveCopy,
8460
8502
  row: displayRow,
8461
8503
  sourceId: `${tableCopySourceNamespace}:row:${getRowId(displayRow)}`,
@@ -8752,13 +8794,13 @@ function MatrxDataTableCore({
8752
8794
  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
8795
  "div",
8754
8796
  {
8755
- className: "inline-flex items-center justify-end gap-0.5",
8797
+ className: "inline-flex items-center justify-end gap-0",
8756
8798
  onClick: (e) => e.stopPropagation(),
8757
8799
  children: [
8758
8800
  showRowCopy && effectiveCopy ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
8759
8801
  TableRowCopyControl,
8760
8802
  {
8761
- size: "xs",
8803
+ size: "toolbar",
8762
8804
  copy: effectiveCopy,
8763
8805
  row: displayRow,
8764
8806
  sourceId: `${tableCopySourceNamespace}:row:${getRowId(displayRow)}`,
@@ -9595,6 +9637,7 @@ function SavedViewsControl({
9595
9637
  onUpdate,
9596
9638
  onReload
9597
9639
  }) {
9640
+ const unsavedChangesId = (0, import_react14.useId)();
9598
9641
  const [saveOpen, setSaveOpen] = (0, import_react14.useState)(false);
9599
9642
  const [name, setName] = (0, import_react14.useState)("");
9600
9643
  const [saving, setSaving] = (0, import_react14.useState)(false);
@@ -9640,10 +9683,26 @@ function SavedViewsControl({
9640
9683
  }
9641
9684
  };
9642
9685
  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: [
9686
+ 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
9687
  /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(DropdownMenu, { children: [
9645
9688
  /* @__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" : ""}` }) }) }),
9689
+ /* @__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)(
9690
+ Button,
9691
+ {
9692
+ type: "button",
9693
+ variant: "ghost",
9694
+ size: "sm",
9695
+ className: "h-8 min-w-0 max-w-52 gap-1 px-2 text-xs font-medium",
9696
+ "aria-label": `Table view: ${loading ? "Loading views" : activeName ?? "Default view"}${dirty ? ", unsaved changes" : ""}`,
9697
+ "aria-describedby": dirty ? unsavedChangesId : void 0,
9698
+ disabled: saving,
9699
+ children: [
9700
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "min-w-0 flex-1 truncate", children: loading ? "Loading views\u2026" : activeName ?? "Default view" }),
9701
+ dirty ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { "aria-hidden": "true", className: "size-1.5 shrink-0 rounded-full bg-amber-500" }) : null,
9702
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(ChevronDown, { className: "size-3.5 shrink-0" })
9703
+ ]
9704
+ }
9705
+ ) }) }),
9647
9706
  /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(TooltipContent, { children: "Choose or save a table view" })
9648
9707
  ] }),
9649
9708
  /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(DropdownMenuContent, { align: "end", children: [
@@ -9661,14 +9720,8 @@ function SavedViewsControl({
9661
9720
  onReload ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(DropdownMenuItem, { disabled: saving || loading, onSelect: () => void reload(), children: "Reload views" }) : null
9662
9721
  ] })
9663
9722
  ] }),
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,
9723
+ 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,
9724
+ visibleError ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("p", { role: "alert", className: "basis-full break-words text-xs text-destructive", children: visibleError }) : null,
9672
9725
  /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(Dialog, { open: saveOpen, onOpenChange: setSaveOpen, children: /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(DialogContent, { children: [
9673
9726
  /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(DialogHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(DialogTitle, { children: "Save current view" }) }),
9674
9727
  visibleError ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("p", { role: "alert", className: "text-sm text-destructive", children: visibleError }) : null,