@ai-matrx/design-system 0.17.4 → 0.18.1

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 (54) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/README.md +1 -0
  3. package/dist/content-transfer/alchemy.svg +1 -0
  4. package/dist/content-transfer/icon.cjs +28 -0
  5. package/dist/content-transfer/icon.cjs.map +1 -0
  6. package/dist/content-transfer/icon.d.cts +4 -0
  7. package/dist/content-transfer/icon.d.ts +4 -0
  8. package/dist/content-transfer/icon.js +8 -0
  9. package/dist/content-transfer/icon.js.map +1 -0
  10. package/dist/content-transfer.cjs +1978 -0
  11. package/dist/content-transfer.cjs.map +1 -0
  12. package/dist/content-transfer.css +382 -0
  13. package/dist/content-transfer.d.cts +208 -0
  14. package/dist/content-transfer.d.ts +208 -0
  15. package/dist/content-transfer.js +1974 -0
  16. package/dist/content-transfer.js.map +1 -0
  17. package/dist/data-table/copy-helpers.d.cts +1 -1
  18. package/dist/data-table/copy-helpers.d.ts +1 -1
  19. package/dist/data-table/copy-types.cjs.map +1 -1
  20. package/dist/data-table/copy-types.d.cts +2 -0
  21. package/dist/data-table/copy-types.d.ts +2 -0
  22. package/dist/data-table/data-row-inspector.cjs +1603 -319
  23. package/dist/data-table/data-row-inspector.cjs.map +1 -1
  24. package/dist/data-table/data-row-inspector.js +1634 -324
  25. package/dist/data-table/data-row-inspector.js.map +1 -1
  26. package/dist/data-table/data-row-window.cjs +1531 -245
  27. package/dist/data-table/data-row-window.cjs.map +1 -1
  28. package/dist/data-table/data-row-window.js +1561 -249
  29. package/dist/data-table/data-row-window.js.map +1 -1
  30. package/dist/data-table/filter-engine.d.cts +1 -1
  31. package/dist/data-table/filter-engine.d.ts +1 -1
  32. package/dist/data-table/index.cjs +2455 -1055
  33. package/dist/data-table/index.cjs.map +1 -1
  34. package/dist/data-table/index.d.cts +2 -2
  35. package/dist/data-table/index.d.ts +2 -2
  36. package/dist/data-table/index.js +2472 -1042
  37. package/dist/data-table/index.js.map +1 -1
  38. package/dist/data-table/infer-filter.d.cts +1 -1
  39. package/dist/data-table/infer-filter.d.ts +1 -1
  40. package/dist/data-table/layered-filters.d.cts +1 -1
  41. package/dist/data-table/layered-filters.d.ts +1 -1
  42. package/dist/data-table/query-control.d.cts +1 -1
  43. package/dist/data-table/query-control.d.ts +1 -1
  44. package/dist/data-table/types.cjs.map +1 -1
  45. package/dist/data-table/types.d.cts +1 -1
  46. package/dist/data-table/types.d.ts +1 -1
  47. package/dist/data-table/url-state.d.cts +1 -1
  48. package/dist/data-table/url-state.d.ts +1 -1
  49. package/dist/data-table/xlsx.d.cts +1 -1
  50. package/dist/data-table/xlsx.d.ts +1 -1
  51. package/dist/styles.css +2 -0
  52. package/dist/{types-pZ95iFk5.d.ts → types-BhSkeZQ_.d.ts} +14 -0
  53. package/dist/{types-4fmLG5AN.d.cts → types-CD4xGL5Z.d.cts} +14 -0
  54. package/package.json +25 -2
@@ -43,9 +43,13 @@ function cn(...inputs) {
43
43
  return (0, import_tailwind_merge.twMerge)((0, import_clsx.clsx)(inputs));
44
44
  }
45
45
 
46
- // src/data-table/copy.tsx
47
- var import_react3 = require("react");
48
- var import_clipboard = require("@ai-matrx/kit/clipboard");
46
+ // src/content-transfer/matrx-copy.tsx
47
+ var React8 = __toESM(require("react"), 1);
48
+ var import_content_transfer2 = require("@ai-matrx/kit/content-transfer");
49
+
50
+ // src/content-transfer/index.tsx
51
+ var React7 = __toESM(require("react"), 1);
52
+ var import_content_transfer = require("@ai-matrx/kit/content-transfer");
49
53
 
50
54
  // src/button.tsx
51
55
  var import_react_slot = require("@radix-ui/react-slot");
@@ -118,9 +122,11 @@ var Button = React.forwardRef(
118
122
  );
119
123
  Button.displayName = "Button";
120
124
 
121
- // src/popover.tsx
122
- var PopoverPrimitive = __toESM(require("@radix-ui/react-popover"), 1);
123
- var React3 = __toESM(require("react"), 1);
125
+ // src/dialog.tsx
126
+ var DialogPrimitive = __toESM(require("@radix-ui/react-dialog"), 1);
127
+ var VisuallyHidden = __toESM(require("@radix-ui/react-visually-hidden"), 1);
128
+ var import_react_tree = require("@ai-matrx/kit/react-tree");
129
+ var React5 = __toESM(require("react"), 1);
124
130
 
125
131
  // src/motion.ts
126
132
  var MOTION_OVERLAY = "matrx-motion-overlay";
@@ -146,72 +152,8 @@ var ALL_MOTION_CLASSES = [
146
152
  MOTION_SPIN
147
153
  ];
148
154
 
149
- // src/portal-container.tsx
150
- var React2 = __toESM(require("react"), 1);
151
- var import_jsx_runtime2 = require("react/jsx-runtime");
152
- var CONTEXT_SLOT = /* @__PURE__ */ Symbol.for("ai-matrx.design-system.portal-container-context");
153
- var contextRegistry = globalThis;
154
- var PortalContainerContext = contextRegistry[CONTEXT_SLOT] ??= React2.createContext(void 0);
155
- function PortalContainerProvider({
156
- container,
157
- children
158
- }) {
159
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(PortalContainerContext.Provider, { value: container ?? void 0, children });
160
- }
161
- function usePortalContainer(explicit) {
162
- const injected = React2.useContext(PortalContainerContext);
163
- if (explicit !== void 0) {
164
- return explicit ?? void 0;
165
- }
166
- return injected ?? void 0;
167
- }
168
-
169
- // src/popover.tsx
170
- var import_jsx_runtime3 = require("react/jsx-runtime");
171
- var Popover = PopoverPrimitive.Root;
172
- var PopoverTrigger = PopoverPrimitive.Trigger;
173
- var PopoverContent = React3.forwardRef(
174
- ({
175
- className,
176
- align = "center",
177
- sideOffset = 4,
178
- container,
179
- animated = true,
180
- ...props
181
- }, ref) => {
182
- const portalContainer = usePortalContainer(container);
183
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PopoverPrimitive.Portal, { container: portalContainer, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
184
- PopoverPrimitive.Content,
185
- {
186
- ref,
187
- align,
188
- sideOffset,
189
- className: cn(
190
- // Cap to the viewport space Radix measured and scroll — a popover taller
191
- // than the screen must never trap the user with unreachable content.
192
- // z must EQUAL the dialog layer (z-[10000]), never exceed it: with equal
193
- // z, DOM portal order decides, so a dialog opened FROM a popover stacks
194
- // above it, and a popover opened from a dialog still stacks above the
195
- // dialog. z-[10001] buried dialogs behind fullscreen popovers.
196
- "z-[10000] w-72 max-h-[var(--radix-popover-content-available-height)] overflow-y-auto overscroll-contain rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none",
197
- animated && MOTION_POPPER,
198
- className
199
- ),
200
- ...props
201
- }
202
- ) });
203
- }
204
- );
205
- PopoverContent.displayName = PopoverPrimitive.Content.displayName;
206
-
207
- // src/dialog.tsx
208
- var DialogPrimitive = __toESM(require("@radix-ui/react-dialog"), 1);
209
- var VisuallyHidden = __toESM(require("@radix-ui/react-visually-hidden"), 1);
210
- var import_react_tree = require("@ai-matrx/kit/react-tree");
211
- var React6 = __toESM(require("react"), 1);
212
-
213
155
  // src/icons.tsx
214
- var import_jsx_runtime4 = require("react/jsx-runtime");
156
+ var import_jsx_runtime2 = require("react/jsx-runtime");
215
157
  function lucideProps(props) {
216
158
  return {
217
159
  xmlns: "http://www.w3.org/2000/svg",
@@ -226,35 +168,97 @@ function lucideProps(props) {
226
168
  };
227
169
  }
228
170
  function XIcon(props) {
229
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { ...lucideProps(props), children: [
230
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M18 6 6 18" }),
231
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "m6 6 12 12" })
171
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("svg", { ...lucideProps(props), children: [
172
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M18 6 6 18" }),
173
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "m6 6 12 12" })
232
174
  ] });
233
175
  }
176
+ function radixProps(props) {
177
+ return {
178
+ xmlns: "http://www.w3.org/2000/svg",
179
+ viewBox: "0 0 15 15",
180
+ width: 15,
181
+ height: 15,
182
+ fill: "none",
183
+ "aria-hidden": true,
184
+ ...props
185
+ };
186
+ }
187
+ function CheckIcon(props) {
188
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { ...radixProps(props), children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
189
+ "path",
190
+ {
191
+ d: "M11.4669 3.72684C11.7558 3.91574 11.8369 4.30308 11.648 4.59198L7.39799 11.092C7.29783 11.2452 7.13556 11.3467 6.95402 11.3699C6.77247 11.3931 6.58989 11.3355 6.45446 11.2124L3.70446 8.71241C3.44905 8.48022 3.43023 8.08494 3.66242 7.82953C3.89461 7.57412 4.28989 7.55529 4.5453 7.78749L6.75292 9.79441L10.6018 3.90792C10.7907 3.61902 11.178 3.53795 11.4669 3.72684Z",
192
+ fill: "currentColor",
193
+ fillRule: "evenodd",
194
+ clipRule: "evenodd"
195
+ }
196
+ ) });
197
+ }
198
+ function DotFilledIcon(props) {
199
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { ...radixProps(props), children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
200
+ "path",
201
+ {
202
+ d: "M9.875 7.5C9.875 8.81168 8.81168 9.875 7.5 9.875C6.18832 9.875 5.125 8.81168 5.125 7.5C5.125 6.18832 6.18832 5.125 7.5 5.125C8.81168 5.125 9.875 6.18832 9.875 7.5Z",
203
+ fill: "currentColor"
204
+ }
205
+ ) });
206
+ }
207
+ function RadixChevronRightIcon(props) {
208
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { ...radixProps(props), children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
209
+ "path",
210
+ {
211
+ d: "M6.1584 3.13508C6.35985 2.94621 6.67627 2.95642 6.86514 3.15788L10.6151 7.15788C10.7954 7.3502 10.7954 7.64949 10.6151 7.84182L6.86514 11.8418C6.67627 12.0433 6.35985 12.0535 6.1584 11.8646C5.95694 11.6757 5.94673 11.3593 6.1356 11.1579L9.565 7.49985L6.1356 3.84182C5.94673 3.64036 5.95694 3.32394 6.1584 3.13508Z",
212
+ fill: "currentColor",
213
+ fillRule: "evenodd",
214
+ clipRule: "evenodd"
215
+ }
216
+ ) });
217
+ }
218
+
219
+ // src/portal-container.tsx
220
+ var React2 = __toESM(require("react"), 1);
221
+ var import_jsx_runtime3 = require("react/jsx-runtime");
222
+ var CONTEXT_SLOT = /* @__PURE__ */ Symbol.for("ai-matrx.design-system.portal-container-context");
223
+ var contextRegistry = globalThis;
224
+ var PortalContainerContext = contextRegistry[CONTEXT_SLOT] ??= React2.createContext(void 0);
225
+ function PortalContainerProvider({
226
+ container,
227
+ children
228
+ }) {
229
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PortalContainerContext.Provider, { value: container ?? void 0, children });
230
+ }
231
+ function usePortalContainer(explicit) {
232
+ const injected = React2.useContext(PortalContainerContext);
233
+ if (explicit !== void 0) {
234
+ return explicit ?? void 0;
235
+ }
236
+ return injected ?? void 0;
237
+ }
234
238
 
235
239
  // src/radix-dialog-modal-context.tsx
236
- var React4 = __toESM(require("react"), 1);
237
- var import_jsx_runtime5 = require("react/jsx-runtime");
240
+ var React3 = __toESM(require("react"), 1);
241
+ var import_jsx_runtime4 = require("react/jsx-runtime");
238
242
  var CONTEXT_SLOT2 = /* @__PURE__ */ Symbol.for("ai-matrx.design-system.dialog-modal-context");
239
243
  var contextRegistry2 = globalThis;
240
- var RadixDialogModalContext = contextRegistry2[CONTEXT_SLOT2] ??= React4.createContext(true);
244
+ var RadixDialogModalContext = contextRegistry2[CONTEXT_SLOT2] ??= React3.createContext(true);
241
245
  function RadixDialogModalProvider({
242
246
  children,
243
247
  modal
244
248
  }) {
245
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(RadixDialogModalContext.Provider, { value: modal, children });
249
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(RadixDialogModalContext.Provider, { value: modal, children });
246
250
  }
247
251
  function useRadixDialogModal() {
248
- return React4.useContext(RadixDialogModalContext);
252
+ return React3.useContext(RadixDialogModalContext);
249
253
  }
250
254
 
251
255
  // src/use-is-mobile.ts
252
- var React5 = __toESM(require("react"), 1);
256
+ var React4 = __toESM(require("react"), 1);
253
257
  var MOBILE_BREAKPOINT = 768;
254
258
  function useIsMobile() {
255
- const [isMobile, setIsMobile] = React5.useState(false);
256
- const [hasMounted, setHasMounted] = React5.useState(false);
257
- React5.useEffect(() => {
259
+ const [isMobile, setIsMobile] = React4.useState(false);
260
+ const [hasMounted, setHasMounted] = React4.useState(false);
261
+ React4.useEffect(() => {
258
262
  setHasMounted(true);
259
263
  const onChange = () => {
260
264
  setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
@@ -274,13 +278,13 @@ function useIsMobile() {
274
278
  }
275
279
 
276
280
  // src/dialog.tsx
277
- var import_jsx_runtime6 = require("react/jsx-runtime");
281
+ var import_jsx_runtime5 = require("react/jsx-runtime");
278
282
  var Dialog = ({
279
283
  children,
280
284
  ...props
281
285
  }) => {
282
286
  const modal = props.modal ?? true;
283
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(RadixDialogModalProvider, { modal, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DialogPrimitive.Root, { ...props, modal, children }) });
287
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(RadixDialogModalProvider, { modal, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(DialogPrimitive.Root, { ...props, modal, children }) });
284
288
  };
285
289
  Dialog.displayName = "Dialog";
286
290
  var DialogPortal = ({
@@ -288,13 +292,13 @@ var DialogPortal = ({
288
292
  ...props
289
293
  }) => {
290
294
  const resolved = usePortalContainer(container);
291
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DialogPrimitive.Portal, { container: resolved ?? null, ...props });
295
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(DialogPrimitive.Portal, { container: resolved ?? null, ...props });
292
296
  };
293
297
  DialogPortal.displayName = "DialogPortal";
294
298
  var CONTEXT_SLOT3 = /* @__PURE__ */ Symbol.for("ai-matrx.design-system.dialog-container-context");
295
299
  var contextRegistry3 = globalThis;
296
- var DialogContainerContext = contextRegistry3[CONTEXT_SLOT3] ??= React6.createContext(null);
297
- var DialogOverlay = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
300
+ var DialogContainerContext = contextRegistry3[CONTEXT_SLOT3] ??= React5.createContext(null);
301
+ var DialogOverlay = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
298
302
  DialogPrimitive.Overlay,
299
303
  {
300
304
  ref,
@@ -310,9 +314,9 @@ var DialogOverlay = React6.forwardRef(({ className, ...props }, ref) => /* @__PU
310
314
  }
311
315
  ));
312
316
  DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
313
- var DialogContentPrimitive = React6.forwardRef((props, ref) => {
317
+ var DialogContentPrimitive = React5.forwardRef((props, ref) => {
314
318
  const isModal = useRadixDialogModal();
315
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
319
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
316
320
  DialogPrimitive.Content,
317
321
  {
318
322
  ...props,
@@ -325,7 +329,7 @@ DialogContentPrimitive.displayName = "DialogContentPrimitive";
325
329
  var DIALOG_DESKTOP_CLASSES = "matrx-dialog-card fixed inset-0 z-[10000] m-auto grid h-fit min-w-0 w-full max-w-lg gap-4 max-h-[85dvh] overflow-y-auto overscroll-contain [--dialog-pad:1.5rem] overflow-x-clip border bg-background p-6 shadow-lg [overflow-wrap:anywhere] [&>*]:min-w-0 [&>*]:max-w-full sm:rounded-lg";
326
330
  var DIALOG_MOBILE_SHEET_CLASSES = "matrx-mobile-sheet matrx-dialog-card fixed inset-x-0 bottom-0 left-0 right-0 top-auto z-[10000] flex min-w-0 flex-col w-full max-w-full max-h-[90dvh] gap-4 [--dialog-pad:1rem] overflow-x-clip border-t bg-background p-4 pb-safe shadow-lg [overflow-wrap:anywhere] [&>*]:min-w-0 [&>*]:max-w-full rounded-t-2xl rounded-b-none overflow-y-auto overscroll-contain";
327
331
  var DIALOG_MOBILE_SHEET_OVERRIDE = "inset-x-0 bottom-0 left-0 right-0 top-auto translate-none w-full max-w-full max-h-[90dvh] rounded-b-none rounded-t-2xl overflow-y-auto";
328
- var DialogContent = React6.forwardRef(
332
+ var DialogContent = React5.forwardRef(
329
333
  ({
330
334
  className,
331
335
  children,
@@ -339,10 +343,10 @@ var DialogContent = React6.forwardRef(
339
343
  const isModal = useRadixDialogModal();
340
344
  const injectedContainer = usePortalContainer(container);
341
345
  const asSheet = mobileSheet && isMobile;
342
- const [containerEl, setContainerEl] = React6.useState(
346
+ const [containerEl, setContainerEl] = React5.useState(
343
347
  null
344
348
  );
345
- const mergedRef = React6.useCallback(
349
+ const mergedRef = React5.useCallback(
346
350
  (node) => {
347
351
  setContainerEl(node);
348
352
  if (typeof ref === "function") ref(node);
@@ -353,9 +357,9 @@ var DialogContent = React6.forwardRef(
353
357
  );
354
358
  const hasTitle = (0, import_react_tree.treeContainsComponent)(children, DialogTitle) || (0, import_react_tree.treeContainsComponent)(children, DialogPrimitive.Title);
355
359
  const hasDescription = (0, import_react_tree.treeContainsComponent)(children, DialogDescription) || (0, import_react_tree.treeContainsComponent)(children, DialogPrimitive.Description);
356
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(DialogPortal, { container, children: [
357
- isModal ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DialogOverlay, {}) : null,
358
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
360
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(DialogPortal, { container, children: [
361
+ isModal ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(DialogOverlay, {}) : null,
362
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
359
363
  DialogContentPrimitive,
360
364
  {
361
365
  ref: mergedRef,
@@ -374,23 +378,23 @@ var DialogContent = React6.forwardRef(
374
378
  ...hasDescription ? {} : { "aria-describedby": void 0 },
375
379
  ...props,
376
380
  children: [
377
- hasTitle ? null : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(VisuallyHidden.Root, { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DialogPrimitive.Title, { children: "Dialog" }) }),
378
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DialogContainerContext.Provider, { value: containerEl, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
381
+ hasTitle ? null : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(VisuallyHidden.Root, { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(DialogPrimitive.Title, { children: "Dialog" }) }),
382
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(DialogContainerContext.Provider, { value: containerEl, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
379
383
  PortalContainerProvider,
380
384
  {
381
385
  container: containerEl ?? injectedContainer ?? null,
382
386
  children
383
387
  }
384
388
  ) }),
385
- showCloseButton ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
389
+ showCloseButton ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
386
390
  DialogPrimitive.Close,
387
391
  {
388
392
  "data-slot": "dialog-close",
389
393
  "aria-label": "Close",
390
394
  className: "absolute right-2 top-4 flex h-11 w-11 items-center justify-center rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground sm:right-4 lg:h-10 lg:w-10",
391
395
  children: [
392
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(XIcon, { className: "h-4 w-4" }),
393
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "sr-only", children: "Close" })
396
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(XIcon, { className: "h-4 w-4" }),
397
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "sr-only", children: "Close" })
394
398
  ]
395
399
  }
396
400
  ) : null
@@ -404,7 +408,7 @@ DialogContent.displayName = DialogPrimitive.Content.displayName;
404
408
  var DialogHeader = ({
405
409
  className,
406
410
  ...props
407
- }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
411
+ }) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
408
412
  "div",
409
413
  {
410
414
  "data-slot": "dialog-header",
@@ -421,7 +425,7 @@ DialogHeader.displayName = "DialogHeader";
421
425
  var DialogFooter = ({
422
426
  className,
423
427
  ...props
424
- }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
428
+ }) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
425
429
  "div",
426
430
  {
427
431
  "data-slot": "dialog-footer",
@@ -453,7 +457,7 @@ var DialogFooter = ({
453
457
  }
454
458
  );
455
459
  DialogFooter.displayName = "DialogFooter";
456
- var DialogTitle = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
460
+ var DialogTitle = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
457
461
  DialogPrimitive.Title,
458
462
  {
459
463
  ref,
@@ -463,7 +467,7 @@ var DialogTitle = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE
463
467
  }
464
468
  ));
465
469
  DialogTitle.displayName = DialogPrimitive.Title.displayName;
466
- var DialogDescription = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
470
+ var DialogDescription = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
467
471
  DialogPrimitive.Description,
468
472
  {
469
473
  ref,
@@ -474,28 +478,1430 @@ var DialogDescription = React6.forwardRef(({ className, ...props }, ref) => /* @
474
478
  ));
475
479
  DialogDescription.displayName = DialogPrimitive.Description.displayName;
476
480
 
477
- // src/data-table/icons.tsx
481
+ // src/dropdown-menu.tsx
482
+ var DropdownMenuPrimitive = __toESM(require("@radix-ui/react-dropdown-menu"), 1);
483
+ var React6 = __toESM(require("react"), 1);
484
+ var import_jsx_runtime6 = require("react/jsx-runtime");
485
+ var DropdownMenu = DropdownMenuPrimitive.Root;
486
+ var DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
487
+ var MENU_SURFACE_CLASS = "z-[10001] min-w-[8rem] max-h-[var(--radix-dropdown-menu-content-available-height)] overflow-y-auto overflow-x-hidden overscroll-contain rounded-md border bg-popover p-1 text-popover-foreground";
488
+ var MENU_ITEM_CLASS = "relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50";
489
+ var MENU_INDICATOR_ITEM_CLASS = "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50";
490
+ var DropdownMenuSubTrigger = React6.forwardRef(({ className, inset, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
491
+ DropdownMenuPrimitive.SubTrigger,
492
+ {
493
+ ref,
494
+ "data-slot": "dropdown-menu-sub-trigger",
495
+ className: cn(
496
+ "flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent",
497
+ inset && "pl-8",
498
+ className
499
+ ),
500
+ ...props,
501
+ children: [
502
+ children,
503
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(RadixChevronRightIcon, { className: "ml-auto h-4 w-4" })
504
+ ]
505
+ }
506
+ ));
507
+ DropdownMenuSubTrigger.displayName = DropdownMenuPrimitive.SubTrigger.displayName;
508
+ var DropdownMenuSubContent = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
509
+ DropdownMenuPrimitive.SubContent,
510
+ {
511
+ ref,
512
+ "data-slot": "dropdown-menu-sub-content",
513
+ className: cn(MENU_SURFACE_CLASS, "shadow-lg", MOTION_POPPER, className),
514
+ ...props
515
+ }
516
+ ));
517
+ DropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName;
518
+ var DropdownMenuContent = React6.forwardRef(({ className, sideOffset = 4, container, ...props }, ref) => {
519
+ const portalContainer = usePortalContainer(container);
520
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DropdownMenuPrimitive.Portal, { container: portalContainer, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
521
+ DropdownMenuPrimitive.Content,
522
+ {
523
+ ref,
524
+ "data-slot": "dropdown-menu-content",
525
+ sideOffset,
526
+ className: cn(
527
+ MENU_SURFACE_CLASS,
528
+ "shadow-md",
529
+ MOTION_POPPER,
530
+ className
531
+ ),
532
+ ...props
533
+ }
534
+ ) });
535
+ });
536
+ DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
537
+ var DropdownMenuItem = React6.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
538
+ DropdownMenuPrimitive.Item,
539
+ {
540
+ ref,
541
+ "data-slot": "dropdown-menu-item",
542
+ className: cn(MENU_ITEM_CLASS, inset && "pl-8", className),
543
+ ...props
544
+ }
545
+ ));
546
+ DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
547
+ var DropdownMenuCheckboxItem = React6.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
548
+ DropdownMenuPrimitive.CheckboxItem,
549
+ {
550
+ ref,
551
+ "data-slot": "dropdown-menu-checkbox-item",
552
+ className: cn(MENU_INDICATOR_ITEM_CLASS, className),
553
+ ...props,
554
+ children: [
555
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DropdownMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CheckIcon, { className: "h-4 w-4" }) }) }),
556
+ children
557
+ ]
558
+ }
559
+ ));
560
+ DropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName;
561
+ var DropdownMenuRadioItem = React6.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
562
+ DropdownMenuPrimitive.RadioItem,
563
+ {
564
+ ref,
565
+ "data-slot": "dropdown-menu-radio-item",
566
+ className: cn(MENU_INDICATOR_ITEM_CLASS, className),
567
+ ...props,
568
+ children: [
569
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DropdownMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DotFilledIcon, { className: "h-4 w-4 fill-current" }) }) }),
570
+ children
571
+ ]
572
+ }
573
+ ));
574
+ DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
575
+ var DropdownMenuLabel = React6.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
576
+ DropdownMenuPrimitive.Label,
577
+ {
578
+ ref,
579
+ "data-slot": "dropdown-menu-label",
580
+ className: cn("px-2 py-1.5 text-sm font-semibold", inset && "pl-8", className),
581
+ ...props
582
+ }
583
+ ));
584
+ DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
585
+ var DropdownMenuSeparator = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
586
+ DropdownMenuPrimitive.Separator,
587
+ {
588
+ ref,
589
+ "data-slot": "dropdown-menu-separator",
590
+ className: cn("-mx-1 my-1 h-px bg-muted", className),
591
+ ...props
592
+ }
593
+ ));
594
+ DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
595
+ var DropdownMenuShortcut = ({
596
+ className,
597
+ ...props
598
+ }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
599
+ "span",
600
+ {
601
+ "data-slot": "dropdown-menu-shortcut",
602
+ className: cn("ml-auto text-xs tracking-widest opacity-60", className),
603
+ ...props
604
+ }
605
+ );
606
+ DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
607
+
608
+ // src/content-transfer/index.tsx
478
609
  var import_jsx_runtime7 = require("react/jsx-runtime");
479
- function Icon({ children, ...props }) {
480
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", "aria-hidden": "true", ...props, children });
610
+ function AlchemyGlyph(props) {
611
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", ...props, children: [
612
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M4.5 5.5h8v11h-8z" }),
613
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M8.5 9.5h8v9h-8z" }),
614
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "m18.5 3 .65 1.85L21 5.5l-1.85.65L18.5 8l-.65-1.85L16 5.5l1.85-.65z" })
615
+ ] });
616
+ }
617
+ var CapabilityContext = React7.createContext({});
618
+ var useContentTransferCapabilities = () => React7.useContext(CapabilityContext);
619
+ var SurfaceContext = React7.createContext(null);
620
+ function MenuPresentation({ label, hint, icon: Icon2 }) {
621
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
622
+ Icon2 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Icon2, { className: "matrx-alchemy-menu-icon" }) : null,
623
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { children: [
624
+ label,
625
+ hint ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("small", { className: "matrx-alchemy-menu-hint", children: hint }) : null
626
+ ] })
627
+ ] });
628
+ }
629
+ var LABEL = { plain: "Plain text", markdown: "Markdown", html: "Formatted", json: "JSON", "compact-json": "Compact JSON", csv: "CSV", tsv: "Google Sheets", xlsx: "Excel workbook" };
630
+ var BUILT_INS = Object.freeze(Object.keys(LABEL).map((id) => ({ id })));
631
+ var COPIES = ["plain", "markdown", "html", "json", "compact-json", "csv", "tsv"];
632
+ var DOWNLOADS = [...COPIES, "xlsx"];
633
+ var EMPTY_VARIANTS = [];
634
+ var SCOPE_LABEL = { target: "This content", row: "This row", selected: "Selected rows", view: "Current view", loaded: "Loaded rows", "all-matching": "All matching rows" };
635
+ var filenameFor = (label) => label.toLocaleLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "") || "export";
636
+ var estimateTokens = (text) => Math.ceil(text.length / 4);
637
+ var errorMessage = (error, fallback) => error instanceof Error ? error.message : fallback;
638
+ var isAbort = (error) => error instanceof DOMException && error.name === "AbortError";
639
+ var supportsBuiltIn = (format, payload) => !["csv", "tsv", "xlsx"].includes(format) || payload.kind === "rows";
640
+ var outcomeMessage = (result) => {
641
+ if (result.status === "success") {
642
+ const success = result;
643
+ return success.delivered === "action" ? success.message ?? "Action completed" : success.delivered === "download-started" ? "Download started" : success.message ?? "Copied";
644
+ }
645
+ return result.status === "degraded" ? `Copied as plain text: ${result.reason}` : result.status === "cancelled" ? "Cancelled" : result.message;
646
+ };
647
+ var materialIds = /* @__PURE__ */ new WeakMap();
648
+ var nextMaterialId = 0;
649
+ function materialIdentity(material) {
650
+ if (!material) return "missing";
651
+ if ("instanceId" in material) return `surface:${material.instanceId}`;
652
+ if ("id" in material) return `source:${material.id}`;
653
+ let id = materialIds.get(material);
654
+ if (id === void 0) {
655
+ id = ++nextMaterialId;
656
+ materialIds.set(material, id);
657
+ }
658
+ return `payload:${id}`;
659
+ }
660
+ function useFence() {
661
+ const mounted = React7.useRef(true);
662
+ const nextId = React7.useRef(0);
663
+ const active = React7.useRef(/* @__PURE__ */ new Set());
664
+ React7.useEffect(() => {
665
+ mounted.current = true;
666
+ return () => {
667
+ mounted.current = false;
668
+ nextId.current += 1;
669
+ active.current.forEach((c) => c.abort());
670
+ active.current.clear();
671
+ };
672
+ }, []);
673
+ const begin = React7.useCallback(() => {
674
+ const controller = new AbortController();
675
+ active.current.add(controller);
676
+ return { controller, id: ++nextId.current };
677
+ }, []);
678
+ const finish = React7.useCallback((controller) => active.current.delete(controller), []);
679
+ const valid = React7.useCallback((id, controller) => mounted.current && !controller.signal.aborted && nextId.current === id, []);
680
+ const abortAll = React7.useCallback(() => {
681
+ nextId.current += 1;
682
+ active.current.forEach((c) => c.abort());
683
+ active.current.clear();
684
+ }, []);
685
+ return { begin, finish, valid, abortAll };
686
+ }
687
+ async function xlsxArtifact(draft, label) {
688
+ if (draft.payload.kind !== "rows") throw new Error("Excel workbook export requires tabular content.");
689
+ const XLSX = await import("xlsx");
690
+ const columns = draft.payload.columns.filter((c) => c.visible && c.exportable !== false && c.classification !== "secret" && c.classification !== "credential");
691
+ const cells = draft.payload.rows.map((row) => columns.map((column) => {
692
+ const value = (0, import_content_transfer.readTransferCell)(row, column);
693
+ return value === null || ["string", "number", "boolean"].includes(typeof value) ? value : value === void 0 ? "" : JSON.stringify(value);
694
+ }));
695
+ const sheet = XLSX.utils.aoa_to_sheet([columns.map((c) => c.label), ...cells]);
696
+ const book = XLSX.utils.book_new();
697
+ XLSX.utils.book_append_sheet(book, sheet, label.replace(/[\\/?*[\]:]/g, " ").trim().slice(0, 31) || "Data");
698
+ const written = XLSX.write(book, { type: "array", bookType: "xlsx", compression: true });
699
+ return (0, import_content_transfer.sealTransferArtifact)({ snapshotId: draft.snapshotId, draftRevision: draft.revision, format: "xlsx", plainText: (0, import_content_transfer.serialize)(draft, "tsv", { spreadsheetSafe: true }).plainText, file: { filename: `${filenameFor(label)}.xlsx`, mime: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", bytes: written instanceof Uint8Array ? written : new Uint8Array(written) }, omissions: [...draft.omissions] });
700
+ }
701
+ async function buildArtifact(draft, format, label) {
702
+ if (!supportsBuiltIn(format, draft.payload)) throw new Error(`${LABEL[format]} is available for tabular content only.`);
703
+ if (format === "xlsx") return xlsxArtifact(draft, label);
704
+ if (format === "html" && draft.payload.kind === "markdown") return (0, import_content_transfer.serializeMarkdownRich)(draft, `${filenameFor(label)}.html`);
705
+ const extension = format === "plain" ? "txt" : format === "compact-json" ? "json" : format;
706
+ return (0, import_content_transfer.serialize)(draft, format, { spreadsheetSafe: format === "csv" || format === "tsv", filename: `${filenameFor(label)}.${extension}` });
707
+ }
708
+ function ContentTransferMenu({ source, surface, label, projection, sections, preferences, table, formatSources, variants = EMPTY_VARIANTS, actions = [], capabilities: local, disabled, enabled = true, className, stopPropagation = true, hide = [], controllerRef }) {
709
+ const triggerRef = React7.useRef(null);
710
+ const inherited = React7.useContext(CapabilityContext);
711
+ const nearestSurface = React7.useContext(SurfaceContext);
712
+ const fence = useFence();
713
+ const [menuCapture, setMenuCapture] = React7.useState(null);
714
+ const [menuStatus, setMenuStatus] = React7.useState("idle");
715
+ const [workspaces, setWorkspaces] = React7.useState({});
716
+ const [workspaceKey, setWorkspaceKey] = React7.useState(null);
717
+ const [workspaceOpen, setWorkspaceOpen] = React7.useState(false);
718
+ const workspaceCaptures = React7.useRef(/* @__PURE__ */ new Map());
719
+ const externalWorkspaceKeys = React7.useRef(/* @__PURE__ */ new Set());
720
+ const [notice, setNotice] = React7.useState(null);
721
+ const scopes = React7.useMemo(() => table?.availableScopes ?? ["target"], [table]);
722
+ const initialScope = table?.initialScope ?? "target";
723
+ if (!scopes.includes(initialScope)) throw new Error("Alchemy initialScope must be included in availableScopes.");
724
+ const primary = surface ?? source ?? nearestSurface;
725
+ const sourceLabel = label ?? (surface?.surfaceName ?? (source && "label" in source ? source.label : nearestSurface?.surfaceName) ?? "content");
726
+ const primaryWorkspaceKey = `primary:${materialIdentity(primary)}`;
727
+ const nearestWorkspaceKey = source && !surface && nearestSurface ? `surface:${materialIdentity(nearestSurface)}` : null;
728
+ const variantWorkspaceKeys = React7.useMemo(() => new Map(variants.map((variant) => [variant.id, `variant:${variant.id}:${materialIdentity(variant.source)}`])), [variants]);
729
+ const transport = local?.transport ?? inherited.transport ?? (0, import_content_transfer.createBrowserTransport)();
730
+ const ai = local?.ai ?? inherited.ai;
731
+ const providerPreferences = React7.useMemo(() => (0, import_content_transfer.resolveTransferPreferences)(inherited.preferences, local?.preferences), [inherited.preferences, local?.preferences]);
732
+ const adapters = React7.useMemo(() => (0, import_content_transfer.resolveTransferRegistry)(BUILT_INS, inherited.formats ?? [], local?.formats ?? []).filter((x) => "build" in x), [inherited.formats, local?.formats]);
733
+ const registeredActions = React7.useMemo(() => (0, import_content_transfer.resolveTransferRegistry)(inherited.actions ?? [], local?.actions ?? [], actions), [actions, inherited.actions, local?.actions]);
734
+ React7.useMemo(() => (0, import_content_transfer.resolveTransferRegistry)(variants), [variants]);
735
+ const report = React7.useCallback((result) => {
736
+ inherited.onOutcome?.(result);
737
+ local?.onOutcome?.(result);
738
+ setNotice(outcomeMessage(result));
739
+ }, [inherited, local]);
740
+ React7.useEffect(() => {
741
+ const valid = /* @__PURE__ */ new Set([primaryWorkspaceKey, ...nearestWorkspaceKey ? [nearestWorkspaceKey] : [], ...variantWorkspaceKeys.values(), ...externalWorkspaceKeys.current]);
742
+ setWorkspaces((current) => Object.fromEntries(Object.entries(current).filter(([key]) => valid.has(key))));
743
+ for (const key of workspaceCaptures.current.keys()) if (!valid.has(key)) workspaceCaptures.current.delete(key);
744
+ if (workspaceKey && !valid.has(workspaceKey)) {
745
+ setWorkspaceKey(null);
746
+ setWorkspaceOpen(false);
747
+ }
748
+ }, [nearestWorkspaceKey, primaryWorkspaceKey, variantWorkspaceKeys, workspaceKey]);
749
+ const captureOne = React7.useCallback(async (material, scope, signal, applyMenuProjection = false, collectPages = true) => {
750
+ if (!material) throw new Error("Alchemy needs a source or a mounted transfer surface.");
751
+ let sourceMaterial;
752
+ if ("instanceId" in material) {
753
+ if (!material.isMounted()) throw new Error("The requested transfer surface is no longer mounted.");
754
+ const captured = await material.capture(signal);
755
+ sourceMaterial = { id: captured.snapshot.sourceId, label: captured.snapshot.label, capture: async () => captured };
756
+ } else if ("kind" in material) {
757
+ sourceMaterial = applyMenuProjection ? { id: "direct", label: sourceLabel, capture: async () => (0, import_content_transfer.directSource)(material, { label: sourceLabel, ...projection ? { projection } : {}, ...sections ? { sections } : {} }) } : material;
758
+ } else if (applyMenuProjection && (projection || sections)) {
759
+ sourceMaterial = {
760
+ id: material.id,
761
+ label: material.label,
762
+ capture: async (request) => {
763
+ const captured = await material.capture(request);
764
+ return {
765
+ ...captured,
766
+ projection: { rules: [...captured.projection.rules, ...projection?.rules ?? []] },
767
+ snapshot: { ...captured.snapshot, ...sections ? { sections } : {} }
768
+ };
769
+ }
770
+ };
771
+ } else {
772
+ sourceMaterial = material;
773
+ }
774
+ const raw = "kind" in sourceMaterial ? (0, import_content_transfer.directSource)(sourceMaterial) : await sourceMaterial.capture({ scope, signal });
775
+ const constrained = (0, import_content_transfer.resolveTransferPreferences)(providerPreferences, preferences, raw.snapshot.limits);
776
+ const result = await (0, import_content_transfer.capture)({ id: raw.snapshot.sourceId, label: raw.snapshot.label, capture: async () => ({ ...raw, snapshot: { ...raw.snapshot, limits: constrained.limits } }) }, signal, scope);
777
+ if (scope !== "all-matching" || !collectPages) return result;
778
+ if (!result.allMatching) throw new Error("This source cannot provide a stable all-matching export.");
779
+ const collected = await (0, import_content_transfer.collectAllMatching)(result.allMatching, signal);
780
+ if (result.snapshot.payload.kind !== "rows") throw new Error("All-matching export requires tabular content.");
781
+ return { snapshot: (0, import_content_transfer.projectSnapshot)({ ...result.snapshot, payload: { kind: "rows", rows: collected.rows, columns: result.snapshot.payload.columns }, coverage: collected.coverage, omissions: [...collected.omissions] }, { rules: [] }), allMatching: result.allMatching, ...collected.error ? { collectionError: collected.error.message } : {} };
782
+ }, [preferences, projection, providerPreferences, sections, sourceLabel]);
783
+ const capturePrimary = React7.useCallback((scope, signal) => captureOne(primary, scope, signal, true), [captureOne, primary]);
784
+ workspaceCaptures.current.set(primaryWorkspaceKey, capturePrimary);
785
+ if (nearestWorkspaceKey && nearestSurface) workspaceCaptures.current.set(nearestWorkspaceKey, (scope, signal) => captureOne(nearestSurface, scope, signal, true));
786
+ for (const variant of variants) {
787
+ const key = variantWorkspaceKeys.get(variant.id);
788
+ workspaceCaptures.current.set(key, (scope, signal) => captureOne(variant.source, scope, signal, true));
789
+ }
790
+ const preflight = React7.useCallback(async () => {
791
+ const { controller, id } = fence.begin();
792
+ setMenuCapture(null);
793
+ setMenuStatus("loading");
794
+ try {
795
+ const result = await captureOne(primary, initialScope, controller.signal, true, false);
796
+ if (fence.valid(id, controller)) {
797
+ setMenuCapture(result);
798
+ setMenuStatus("idle");
799
+ }
800
+ } catch (error) {
801
+ if (fence.valid(id, controller)) {
802
+ setMenuCapture(null);
803
+ setMenuStatus(errorMessage(error, "Could not inspect content"));
804
+ }
805
+ } finally {
806
+ fence.finish(controller);
807
+ }
808
+ }, [captureOne, fence, initialScope, primary]);
809
+ const transfer = React7.useCallback(async (format, download, alternate) => {
810
+ const { controller, id } = fence.begin();
811
+ try {
812
+ const explicit = alternate?.source ?? (typeof format === "string" && format !== "xlsx" ? formatSources?.[format] : void 0);
813
+ const result = await (explicit ? captureOne(explicit, initialScope, controller.signal, true) : capturePrimary(initialScope, controller.signal));
814
+ if (result.collectionError) throw new Error(`The complete source could not be collected: ${result.collectionError}`);
815
+ if (result.snapshot.coverage.status !== "complete" || result.snapshot.omissions.length > 0) {
816
+ const reason = result.snapshot.coverage.reason ?? `${result.snapshot.omissions.length} omission${result.snapshot.omissions.length === 1 ? "" : "s"}`;
817
+ throw new Error(`Quick transfer is partial (${reason}). Open Prepare for AI to review it before delivery.`);
818
+ }
819
+ const resolved = (0, import_content_transfer.resolveTransferPreferences)(providerPreferences, preferences, result.snapshot.limits);
820
+ const draft = (0, import_content_transfer.applyTransferLimits)((0, import_content_transfer.createDraft)(result.snapshot), resolved.limits);
821
+ const revision = draft.revision;
822
+ if (draft.omissions.length > result.snapshot.omissions.length) throw new Error("Quick transfer requires content reductions. Open Prepare for AI to review them before delivery.");
823
+ const artifact = typeof format === "string" ? await buildArtifact(draft, format, result.snapshot.label) : await format.build(draft, controller.signal);
824
+ if (artifact.omissions.length > draft.omissions.length) throw new Error(`Quick format requires ${artifact.omissions.length - draft.omissions.length} adjustment${artifact.omissions.length - draft.omissions.length === 1 ? "" : "s"}. Open Prepare for AI to review before delivery.`);
825
+ if (!fence.valid(id, controller) || artifact.snapshotId !== result.snapshot.id || artifact.draftRevision !== revision) return;
826
+ const outcome = await transport[download ? "download" : "copy"](artifact, controller.signal);
827
+ if (fence.valid(id, controller)) report(outcome.status === "success" && alternate?.successMessage ? { ...outcome, message: alternate.successMessage } : outcome);
828
+ } catch (error) {
829
+ if (fence.valid(id, controller)) report({ status: "error", code: "prepare-failed", message: errorMessage(error, "Preparation failed"), retryable: true });
830
+ } finally {
831
+ fence.finish(controller);
832
+ }
833
+ }, [captureOne, capturePrimary, fence, formatSources, initialScope, preferences, providerPreferences, report, transport]);
834
+ const openWorkspace = React7.useCallback(async (key = primaryWorkspaceKey, variant) => {
835
+ const variantMaterial = variant && "kind" in variant.source ? { id: `variant:${key}`, label: variant.label, capture: async () => (0, import_content_transfer.directSource)(variant.source, { label: variant.label }) } : variant?.source;
836
+ const captureWorkspace = variantMaterial ? (scope, signal) => captureOne(variantMaterial, scope, signal, true) : capturePrimary;
837
+ workspaceCaptures.current.set(key, captureWorkspace);
838
+ if (workspaces[key]) {
839
+ setWorkspaceKey(key);
840
+ setWorkspaceOpen(true);
841
+ return;
842
+ }
843
+ const { controller, id } = fence.begin();
844
+ try {
845
+ const result = await captureWorkspace(initialScope, controller.signal);
846
+ if (!fence.valid(id, controller)) return;
847
+ const resolved = (0, import_content_transfer.resolveTransferPreferences)(providerPreferences, preferences, result.snapshot.limits);
848
+ const original = (0, import_content_transfer.createDraft)(result.snapshot);
849
+ const base = { ...result, key, original, draft: original, scope: initialScope, preferences: resolved, ...result.collectionError ? { error: result.collectionError } : {} };
850
+ setWorkspaces((current) => ({ ...current, [key]: { ...base, draft: rebuild(base, initialControls(base)) } }));
851
+ setWorkspaceKey(key);
852
+ setWorkspaceOpen(true);
853
+ } catch (error) {
854
+ if (fence.valid(id, controller)) setNotice(errorMessage(error, "Could not capture content"));
855
+ } finally {
856
+ fence.finish(controller);
857
+ }
858
+ }, [captureOne, capturePrimary, fence, initialScope, preferences, primaryWorkspaceKey, providerPreferences, workspaces]);
859
+ React7.useImperativeHandle(controllerRef, () => ({
860
+ focusTrigger: () => triggerRef.current?.focus(),
861
+ prepare: async (requestedSource, options) => {
862
+ const requestedLabel = options?.label ?? ("label" in requestedSource ? requestedSource.label : "content");
863
+ const requestedKey = `controller:${options?.id ?? "source"}:${materialIdentity(requestedSource)}`;
864
+ externalWorkspaceKeys.current.add(requestedKey);
865
+ await openWorkspace(requestedKey, { source: requestedSource, label: requestedLabel });
866
+ }
867
+ }), [openWorkspace]);
868
+ const runAction = React7.useCallback(async (action) => {
869
+ const { controller, id } = fence.begin();
870
+ try {
871
+ const actionSource = action.source;
872
+ const { snapshot } = actionSource ? await captureOne(actionSource, initialScope, controller.signal, true) : await capturePrimary(initialScope, controller.signal);
873
+ const resolved = (0, import_content_transfer.resolveTransferPreferences)(providerPreferences, preferences, snapshot.limits);
874
+ const draft = (0, import_content_transfer.applyTransferLimits)((0, import_content_transfer.createDraft)(snapshot), resolved.limits);
875
+ if (!action.supports(snapshot)) throw new Error(`${action.label} is unavailable for this content.`);
876
+ const result = await action.run({ snapshot, draft, signal: controller.signal });
877
+ if (fence.valid(id, controller) && draft.snapshotId === snapshot.id) report(result);
878
+ } catch (error) {
879
+ if (fence.valid(id, controller)) report({ status: "error", code: "action-failed", message: errorMessage(error, "Action failed"), retryable: true });
880
+ } finally {
881
+ fence.finish(controller);
882
+ }
883
+ }, [captureOne, capturePrimary, fence, initialScope, preferences, providerPreferences, report]);
884
+ if (!enabled) return null;
885
+ const payload = menuCapture?.snapshot.payload ?? (source && "kind" in source ? source : void 0);
886
+ const quickVariants = (section) => variants.filter((v) => v.copyLabel && (v.section ?? "ai") === section).map((v) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(DropdownMenuItem, { "aria-label": v.ariaLabel, onSelect: () => void transfer("markdown", false, v), children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(MenuPresentation, { ...v, label: v.copyLabel }) }, `copy:${v.id}`));
887
+ const visibleCopies = COPIES.filter((f) => Boolean(formatSources?.[f]) || !["csv", "tsv"].includes(f) || payload?.kind === "rows");
888
+ const visibleDownloads = DOWNLOADS.filter((f) => f !== "xlsx" && Boolean(formatSources?.[f]) || !["csv", "tsv", "xlsx"].includes(f) || payload?.kind === "rows");
889
+ const visibleAdapters = menuCapture ? adapters.filter((a) => a.supports(menuCapture.snapshot.payload)) : [];
890
+ const visibleActions = menuCapture ? registeredActions.filter((a) => a.supports(menuCapture.snapshot)) : [];
891
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: cn("matrx-alchemy", className), onClick: stopPropagation ? (event) => event.stopPropagation() : void 0, children: [
892
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(DropdownMenu, { onOpenChange: (open) => {
893
+ if (open) void preflight();
894
+ }, children: [
895
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime7.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_runtime7.jsx)(AlchemyGlyph, {}) }) }),
896
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(DropdownMenuContent, { align: "end", className: "matrx-alchemy-menu", children: [
897
+ menuStatus === "loading" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(DropdownMenuItem, { disabled: true, children: "Inspecting content\u2026" }) : menuStatus !== "idle" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(DropdownMenuItem, { disabled: true, children: menuStatus }) : null,
898
+ !hide.includes("copy") ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
899
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(DropdownMenuLabel, { children: "Copy" }),
900
+ quickVariants("copy"),
901
+ visibleCopies.map((format) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(DropdownMenuItem, { onSelect: () => void transfer(format, false), children: format === "plain" ? "Copy" : `Copy ${LABEL[format]}` }, format)),
902
+ visibleAdapters.map((adapter) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(DropdownMenuItem, { onSelect: () => void transfer(adapter, false), children: [
903
+ "Copy ",
904
+ adapter.label
905
+ ] }, adapter.id))
906
+ ] }) : null,
907
+ !hide.includes("prepare") ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
908
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(DropdownMenuSeparator, {}),
909
+ quickVariants("ai"),
910
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(DropdownMenuItem, { onSelect: () => void openWorkspace(), children: "Prepare for AI\u2026" }),
911
+ nearestWorkspaceKey && nearestSurface ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(DropdownMenuItem, { onSelect: () => void openWorkspace(nearestWorkspaceKey, { source: nearestSurface, label: nearestSurface.surfaceName }), children: "Prepare this surface\u2026" }) : null,
912
+ variants.map((variant) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(DropdownMenuItem, { onSelect: () => void openWorkspace(variantWorkspaceKeys.get(variant.id), variant), children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(MenuPresentation, { ...variant, label: `Prepare ${variant.label}\u2026` }) }, variant.id))
913
+ ] }) : null,
914
+ !hide.includes("download") ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
915
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(DropdownMenuSeparator, {}),
916
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(DropdownMenuLabel, { children: "Download" }),
917
+ visibleDownloads.map((format) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(DropdownMenuItem, { onSelect: () => void transfer(format, true), children: [
918
+ "Download ",
919
+ LABEL[format]
920
+ ] }, format)),
921
+ visibleAdapters.map((adapter) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(DropdownMenuItem, { onSelect: () => void transfer(adapter, true), children: [
922
+ "Download ",
923
+ adapter.label
924
+ ] }, `download:${adapter.id}`))
925
+ ] }) : null,
926
+ visibleActions.length ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(DropdownMenuSeparator, {}) : null,
927
+ visibleActions.map((action) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(DropdownMenuItem, { "aria-label": action.ariaLabel, onSelect: () => void runAction(action), children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(MenuPresentation, { ...action, label: action.label }) }, action.id))
928
+ ] })
929
+ ] }),
930
+ notice ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "matrx-alchemy-notice", role: "status", children: notice }) : null,
931
+ Object.values(workspaces).map((saved) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(PreparationWorkspace, { restoreFocus: () => triggerRef.current?.focus(), open: workspaceOpen && workspaceKey === saved.key, state: saved, scopes, onClose: () => setWorkspaceOpen(false), onChange: (next) => setWorkspaces((current) => ({ ...current, [saved.key]: next })), transport, adapters, captureScope: workspaceCaptures.current.get(saved.key) ?? capturePrimary, ...ai ? { ai } : {}, onOutcome: report }, saved.key))
932
+ ] });
933
+ }
934
+ function initialControls(state) {
935
+ const rows = state.original.payload.kind === "rows" ? state.original.payload : null;
936
+ return {
937
+ preset: state.preferences.initialPreset,
938
+ sections: state.snapshot.sections.filter((s) => s.includedByDefault).map((s) => s.id),
939
+ search: "",
940
+ filters: {},
941
+ sort: "",
942
+ direction: "asc",
943
+ top: state.preferences.limits.maxRows,
944
+ visibleColumns: rows?.columns.filter((c) => c.visible).map((c) => c.id) ?? [],
945
+ selectedOnly: false,
946
+ selectedIndices: [],
947
+ maxDepth: state.preferences.limits.maxDepth,
948
+ maxStringChars: state.preferences.limits.maxStringChars,
949
+ maxArrayItems: state.preferences.limits.maxArrayItems ?? null
950
+ };
951
+ }
952
+ function presetLimits(preset, controls, preferences) {
953
+ const min = (choice, cap) => choice == null ? cap : cap == null ? choice : Math.min(choice, cap);
954
+ if (preset === "full") return preferences.limits;
955
+ const request = preset === "brief" ? { maxDepth: 4, maxStringChars: 800, maxArrayItems: 25 } : preset === "compact" ? { maxDepth: 8, maxStringChars: 4e3, maxArrayItems: 100 } : { maxDepth: controls.maxDepth, maxStringChars: controls.maxStringChars, maxArrayItems: controls.maxArrayItems };
956
+ return { ...preferences.limits, maxDepth: min(request.maxDepth, preferences.limits.maxDepth), maxStringChars: min(request.maxStringChars, preferences.limits.maxStringChars), maxArrayItems: min(request.maxArrayItems, preferences.limits.maxArrayItems ?? null) };
957
+ }
958
+ function rebuild(state, controls) {
959
+ let draft = (0, import_content_transfer.resetDraft)(state.snapshot);
960
+ if (state.snapshot.sections.length) draft = (0, import_content_transfer.applySectionSelection)(draft, state.snapshot, controls.sections);
961
+ if (draft.payload.kind === "rows") draft = (0, import_content_transfer.transformRows)(draft, {
962
+ search: controls.search,
963
+ filters: controls.filters,
964
+ ...controls.sort ? { sort: { column: controls.sort, direction: controls.direction } } : {},
965
+ ...controls.selectedOnly ? { selectedIndices: controls.selectedIndices } : {},
966
+ visibleColumns: controls.visibleColumns,
967
+ structuredProjection: "visible",
968
+ top: controls.top
969
+ });
970
+ const limits = presetLimits(controls.preset, controls, state.preferences);
971
+ if (draft.payload.kind === "json" || draft.payload.kind === "registered") {
972
+ draft = (0, import_content_transfer.reduceJson)(draft, { maxDepth: limits.maxDepth, maxStringChars: limits.maxStringChars, maxArrayItems: limits.maxArrayItems ?? null });
973
+ }
974
+ return (0, import_content_transfer.applyTransferLimits)(draft, limits);
975
+ }
976
+ function isBuiltInFormat(format) {
977
+ return format in LABEL;
978
+ }
979
+ function preview(draft, format) {
980
+ const resolved = isBuiltInFormat(format) ? format : "plain";
981
+ return (0, import_content_transfer.serialize)(draft, resolved === "xlsx" ? "tsv" : resolved, { spreadsheetSafe: resolved === "csv" || resolved === "tsv" || resolved === "xlsx" }).plainText;
982
+ }
983
+ function PreparationWorkspace({ restoreFocus, open, state, scopes, onClose, onChange, transport, ai, adapters, onOutcome, captureScope }) {
984
+ const fence = useFence();
985
+ const latest = React7.useRef(state);
986
+ latest.current = state;
987
+ const aiSession = React7.useRef(void 0);
988
+ if (!aiSession.current && ai) aiSession.current = ai.fork?.() ?? ai;
989
+ const [controls, setControls] = React7.useState(() => initialControls(state));
990
+ const [controlsHistory, setControlsHistory] = React7.useState([]);
991
+ const [pendingControls, setPendingControls] = React7.useState(null);
992
+ const requestedFormat = state.preferences.initialFormat;
993
+ const [format, setFormat] = React7.useState(() => isBuiltInFormat(requestedFormat) ? supportsBuiltIn(requestedFormat, state.draft.payload) ? requestedFormat : "plain" : adapters.some((adapter) => adapter.id === requestedFormat && adapter.supports(state.draft.payload)) ? requestedFormat : "plain");
994
+ const [buffer, setBuffer] = React7.useState(() => isBuiltInFormat(format) ? preview(state.draft, format) : "Preparing format preview\u2026");
995
+ const [bufferError, setBufferError] = React7.useState(null);
996
+ const [formatError, setFormatError] = React7.useState(null);
997
+ const [preparedArtifact, setPreparedArtifact] = React7.useState(null);
998
+ const [instruction, setInstruction] = React7.useState("");
999
+ const [busy, setBusy] = React7.useState(null);
1000
+ const [aiFailed, setAiFailed] = React7.useState(false);
1001
+ const activeAi = React7.useRef(null);
1002
+ const activeCapture = React7.useRef(null);
1003
+ React7.useEffect(() => {
1004
+ if (bufferError) return;
1005
+ const adapter = adapters.find((candidate) => candidate.id === format);
1006
+ const controller = new AbortController();
1007
+ const snapshotId = state.snapshot.id;
1008
+ const revision = state.draft.revision;
1009
+ setPreparedArtifact(null);
1010
+ setFormatError(null);
1011
+ if (adapter) setBuffer("Preparing format preview\u2026");
1012
+ const artifactPromise = adapter ? adapter.build(state.draft, controller.signal) : buildArtifact(state.draft, isBuiltInFormat(format) ? format : "plain", state.snapshot.label);
1013
+ void artifactPromise.then((artifact) => {
1014
+ if (!controller.signal.aborted && artifact.snapshotId === snapshotId && artifact.draftRevision === revision) {
1015
+ setPreparedArtifact(artifact);
1016
+ setBuffer(artifact.plainText);
1017
+ }
1018
+ }).catch((error) => {
1019
+ if (!controller.signal.aborted) setFormatError(errorMessage(error, "Format preview failed"));
1020
+ });
1021
+ return () => controller.abort();
1022
+ }, [adapters, bufferError, format, state.draft, state.snapshot.id]);
1023
+ const close = React7.useCallback(() => {
1024
+ activeAi.current?.abort();
1025
+ activeCapture.current?.abort();
1026
+ activeAi.current = null;
1027
+ activeCapture.current = null;
1028
+ fence.abortAll();
1029
+ setBusy(null);
1030
+ onClose();
1031
+ }, [fence, onClose]);
1032
+ const changeControls = (next) => {
1033
+ if (state.draft.manuallyEdited) {
1034
+ setPendingControls(next);
1035
+ return;
1036
+ }
1037
+ setControlsHistory((history) => [...history, controls]);
1038
+ setControls(next);
1039
+ onChange({ ...state, draft: rebuild(state, next), error: void 0 });
1040
+ };
1041
+ const applyPendingControls = () => {
1042
+ if (!pendingControls) return;
1043
+ setControlsHistory((history) => [...history, controls]);
1044
+ setControls(pendingControls);
1045
+ setBufferError(null);
1046
+ onChange({ ...state, draft: rebuild(state, pendingControls), error: void 0 });
1047
+ setPendingControls(null);
1048
+ };
1049
+ const editBuffer = (text) => {
1050
+ setBuffer(text);
1051
+ setPreparedArtifact(null);
1052
+ setFormatError(null);
1053
+ const payload = state.draft.payload;
1054
+ if (payload.kind === "json" || payload.kind === "registered") {
1055
+ try {
1056
+ const value = JSON.parse(text);
1057
+ const next = payload.kind === "json" ? { kind: "json", value } : { kind: "registered", format: payload.format, value };
1058
+ setBufferError(null);
1059
+ onChange({ ...state, draft: (0, import_content_transfer.editDraft)(state.draft, next), error: void 0 });
1060
+ } catch {
1061
+ setBufferError("JSON is incomplete or invalid. Fix it before copying or downloading.");
1062
+ }
1063
+ return;
1064
+ }
1065
+ setBufferError(null);
1066
+ const kind = payload.kind === "markdown" || format === "markdown" ? "markdown" : "text";
1067
+ if (payload.kind === "rows" || !isBuiltInFormat(format)) setFormat("plain");
1068
+ onChange({ ...state, draft: (0, import_content_transfer.editDraft)(state.draft, { kind, text }), error: void 0 });
1069
+ };
1070
+ const requestCapture = async (scope) => {
1071
+ activeCapture.current?.abort();
1072
+ const { controller, id } = fence.begin();
1073
+ activeCapture.current = controller;
1074
+ const revision = state.draft.revision;
1075
+ setBusy("capture");
1076
+ try {
1077
+ const result = await captureScope(scope, controller.signal);
1078
+ if (fence.valid(id, controller) && latest.current.draft.revision === revision) onChange({ ...latest.current, pending: { ...result, scope }, error: result.collectionError });
1079
+ } catch (error) {
1080
+ if (fence.valid(id, controller)) onChange({ ...latest.current, error: errorMessage(error, "Refresh failed") });
1081
+ } finally {
1082
+ fence.finish(controller);
1083
+ if (activeCapture.current === controller) activeCapture.current = null;
1084
+ if (fence.valid(id, controller)) setBusy(null);
1085
+ }
1086
+ };
1087
+ const resolveCapture = (choice) => {
1088
+ if (!state.pending) return;
1089
+ if (choice === "keep") {
1090
+ const { pending: _pending, ...kept } = state;
1091
+ onChange({ ...kept, error: void 0 });
1092
+ return;
1093
+ }
1094
+ const pending = state.pending;
1095
+ const preferences = (0, import_content_transfer.resolveTransferPreferences)({}, state.preferences, pending.snapshot.limits);
1096
+ const base = { ...pending, key: state.key, original: (0, import_content_transfer.createDraft)(pending.snapshot), draft: (0, import_content_transfer.createDraft)(pending.snapshot), scope: pending.scope, preferences, ...pending.collectionError ? { error: pending.collectionError } : {} };
1097
+ const nextControls = initialControls(base);
1098
+ setControls(nextControls);
1099
+ setControlsHistory([]);
1100
+ setPendingControls(null);
1101
+ setBufferError(null);
1102
+ onChange({ ...base, draft: rebuild(base, nextControls) });
1103
+ };
1104
+ const runAi = async (recover = false) => {
1105
+ const adapter = aiSession.current;
1106
+ if (!adapter || !adapter.supports(state.snapshot) || !recover && !instruction.trim() || recover && !adapter.recover) return;
1107
+ activeAi.current?.abort();
1108
+ const { controller, id } = fence.begin();
1109
+ activeAi.current = controller;
1110
+ const snapshotId = state.snapshot.id;
1111
+ const revision = state.draft.revision;
1112
+ setBusy("ai");
1113
+ setAiFailed(false);
1114
+ try {
1115
+ const next = recover ? await adapter.recover({ snapshot: state.snapshot, draft: state.draft, signal: controller.signal }) : await adapter.run({ snapshot: state.snapshot, draft: state.draft, instruction, signal: controller.signal });
1116
+ const current = latest.current;
1117
+ if (!fence.valid(id, controller) || current.snapshot.id !== snapshotId || current.draft.revision !== revision || next.snapshotId !== snapshotId || next.sourceId !== state.draft.sourceId || next.sourceRevision !== state.draft.sourceRevision || next.revision <= revision) return;
1118
+ try {
1119
+ (0, import_content_transfer.serialize)(next, "plain");
1120
+ } catch {
1121
+ onChange({ ...current, error: "AI returned an invalid transfer draft." });
1122
+ setAiFailed(true);
1123
+ return;
1124
+ }
1125
+ onChange({ ...current, draft: next, error: void 0 });
1126
+ setBufferError(null);
1127
+ } catch (error) {
1128
+ if (!isAbort(error) && fence.valid(id, controller)) {
1129
+ setAiFailed(true);
1130
+ onChange({ ...latest.current, error: errorMessage(error, "AI preparation failed") });
1131
+ }
1132
+ } finally {
1133
+ fence.finish(controller);
1134
+ if (activeAi.current === controller) activeAi.current = null;
1135
+ if (fence.valid(id, controller)) setBusy(null);
1136
+ }
1137
+ };
1138
+ const cancelAi = async () => {
1139
+ const aiController = activeAi.current;
1140
+ const { controller, id } = fence.begin();
1141
+ try {
1142
+ await aiSession.current?.cancel?.();
1143
+ } catch (error) {
1144
+ if (fence.valid(id, controller)) onChange({ ...latest.current, error: errorMessage(error, "AI cancellation failed") });
1145
+ } finally {
1146
+ aiController?.abort();
1147
+ fence.finish(controller);
1148
+ if (activeAi.current === aiController) activeAi.current = null;
1149
+ if (fence.valid(id, controller)) setBusy(null);
1150
+ }
1151
+ };
1152
+ const [deliveryNotice, setDeliveryNotice] = React7.useState(null);
1153
+ React7.useEffect(() => {
1154
+ setDeliveryNotice(null);
1155
+ }, [state.draft.revision]);
1156
+ const reportDelivery = (outcome) => {
1157
+ setDeliveryNotice(outcomeMessage(outcome));
1158
+ onOutcome(outcome);
1159
+ };
1160
+ const deliver = async (download) => {
1161
+ if (bufferError) return;
1162
+ const { controller, id } = fence.begin();
1163
+ const snapshotId = state.snapshot.id;
1164
+ const revision = state.draft.revision;
1165
+ setBusy(download ? "download" : "copy");
1166
+ try {
1167
+ if (!preparedArtifact) throw new Error("Wait for the selected format preview before delivery.");
1168
+ const artifact = preparedArtifact;
1169
+ const current = latest.current;
1170
+ if (!fence.valid(id, controller) || current.snapshot.id !== snapshotId || current.draft.revision !== revision || artifact.snapshotId !== snapshotId || artifact.draftRevision !== revision) return;
1171
+ const result = await transport[download ? "download" : "copy"](artifact, controller.signal);
1172
+ if (fence.valid(id, controller)) reportDelivery(result);
1173
+ } catch (error) {
1174
+ if (fence.valid(id, controller)) reportDelivery({ status: "error", code: "prepare-failed", message: errorMessage(error, "Preparation failed"), retryable: true });
1175
+ } finally {
1176
+ fence.finish(controller);
1177
+ if (fence.valid(id, controller)) setBusy(null);
1178
+ }
1179
+ };
1180
+ const rows = state.original.payload.kind === "rows" ? state.original.payload : null;
1181
+ const formats = COPIES.filter((f) => supportsBuiltIn(f, state.draft.payload));
1182
+ const workspaceAdapters = adapters.filter((adapter) => adapter.supports(state.draft.payload));
1183
+ const displayedOmissions = preparedArtifact?.omissions ?? state.draft.omissions;
1184
+ const limitText = Object.entries(state.preferences.limits).filter(([, value]) => value != null).map(([key, value]) => `${key.replace(/^max/, "max ")} ${Number(value).toLocaleString()}`).join(" \xB7 ");
1185
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Dialog, { open, onOpenChange: (next) => {
1186
+ if (!next) close();
1187
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(DialogContent, { onCloseAutoFocus: (event) => {
1188
+ event.preventDefault();
1189
+ restoreFocus();
1190
+ }, className: "matrx-alchemy-workspace max-w-5xl", "aria-busy": busy !== null, children: [
1191
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(DialogHeader, { children: [
1192
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(DialogTitle, { children: [
1193
+ "Prepare ",
1194
+ state.snapshot.label
1195
+ ] }),
1196
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(DialogDescription, { children: [
1197
+ "Captured ",
1198
+ state.snapshot.unsavedChanges ? "from your unsaved draft" : "as an immutable snapshot",
1199
+ ". Your source is never edited."
1200
+ ] })
1201
+ ] }),
1202
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "matrx-alchemy-workspace-grid", children: [
1203
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("section", { className: "matrx-alchemy-main", children: [
1204
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "matrx-alchemy-toolbar", children: [
1205
+ scopes.length > 1 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { children: [
1206
+ "Scope",
1207
+ /* @__PURE__ */ (0, import_jsx_runtime7.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_runtime7.jsx)("option", { value: scope, children: SCOPE_LABEL[scope] }, scope)) })
1208
+ ] }) : null,
1209
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { children: [
1210
+ "Detail",
1211
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("select", { "aria-label": "Detail preset", value: controls.preset, onChange: (e) => changeControls({ ...controls, preset: e.target.value }), children: [
1212
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: "full", children: "Full" }),
1213
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: "compact", children: "Compact" }),
1214
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: "brief", children: "Brief" }),
1215
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: "custom", children: "Custom" })
1216
+ ] })
1217
+ ] }),
1218
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Button, { type: "button", size: "sm", variant: "outline", disabled: !state.draft.history?.length && !controlsHistory.length || busy !== null, onClick: () => {
1219
+ setBufferError(null);
1220
+ if (controlsHistory.length) {
1221
+ const next = controlsHistory[controlsHistory.length - 1];
1222
+ setControls(next);
1223
+ setControlsHistory((history) => history.slice(0, -1));
1224
+ onChange({ ...state, draft: rebuild(state, next), error: void 0 });
1225
+ } else onChange({ ...state, draft: (0, import_content_transfer.undoDraft)(state.draft), error: void 0 });
1226
+ }, children: "Undo" }),
1227
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Button, { type: "button", size: "sm", variant: "outline", disabled: busy !== null, onClick: () => {
1228
+ const next = initialControls(state);
1229
+ setControls(next);
1230
+ setControlsHistory([]);
1231
+ setPendingControls(null);
1232
+ setBufferError(null);
1233
+ onChange({ ...state, draft: rebuild(state, next), error: void 0 });
1234
+ }, children: "Reset" }),
1235
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Button, { type: "button", size: "sm", variant: "outline", disabled: busy !== null, onClick: () => void requestCapture(state.scope), children: "Refresh source" })
1236
+ ] }),
1237
+ controls.preset === "custom" && (state.draft.payload.kind === "json" || state.draft.payload.kind === "registered") ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("fieldset", { className: "matrx-alchemy-options", children: [
1238
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("legend", { children: "JSON limits" }),
1239
+ [["maxDepth", "Maximum depth"], ["maxStringChars", "Maximum string characters"], ["maxArrayItems", "Maximum array items"]].map(([key, text]) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { children: [
1240
+ text,
1241
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("input", { type: "number", min: "0", value: controls[key] ?? "", onChange: (e) => changeControls({ ...controls, [key]: Number.isNaN(e.target.valueAsNumber) ? null : e.target.valueAsNumber }) })
1242
+ ] }, key))
1243
+ ] }) : null,
1244
+ rows ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(RowControls, { rows, controls, change: changeControls }) : null,
1245
+ state.snapshot.sections.length ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("fieldset", { className: "matrx-alchemy-options", children: [
1246
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("legend", { children: "Sections" }),
1247
+ state.snapshot.sections.map((section) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { children: [
1248
+ /* @__PURE__ */ (0, import_jsx_runtime7.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) }) }),
1249
+ " ",
1250
+ section.label
1251
+ ] }, section.id))
1252
+ ] }) : null,
1253
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "matrx-alchemy-coverage", children: [
1254
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { children: [
1255
+ state.snapshot.coverage.included.toLocaleString(),
1256
+ " included",
1257
+ state.snapshot.coverage.total == null ? "" : ` of ${state.snapshot.coverage.total.toLocaleString()}`,
1258
+ " \xB7 ",
1259
+ state.snapshot.coverage.status
1260
+ ] }),
1261
+ state.snapshot.coverage.reason ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: state.snapshot.coverage.reason }) : null,
1262
+ limitText ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { children: [
1263
+ "Limits: ",
1264
+ limitText
1265
+ ] }) : null,
1266
+ displayedOmissions.length ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("details", { children: [
1267
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("summary", { children: [
1268
+ displayedOmissions.length,
1269
+ " omissions or adjustments"
1270
+ ] }),
1271
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("ul", { children: displayedOmissions.map((o, i) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("li", { children: [
1272
+ o.path || "/",
1273
+ ": ",
1274
+ o.reason,
1275
+ o.count == null ? "" : ` (${o.count})`
1276
+ ] }, `${o.path}-${o.reason}-${i}`)) })
1277
+ ] }) : null
1278
+ ] }),
1279
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "matrx-alchemy-preview-label", children: [
1280
+ "Output format",
1281
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("select", { "aria-label": "Output format", value: format, onChange: (e) => setFormat(e.target.value), children: [
1282
+ formats.map((f) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: f, children: LABEL[f] }, f)),
1283
+ state.draft.payload.kind === "rows" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: "xlsx", children: "Excel workbook" }) : null,
1284
+ workspaceAdapters.map((adapter) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: adapter.id, children: adapter.label }, adapter.id))
1285
+ ] })
1286
+ ] }),
1287
+ /* @__PURE__ */ (0, import_jsx_runtime7.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) }),
1288
+ bufferError ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { id: "alchemy-buffer-error", role: "alert", className: "matrx-alchemy-error", children: bufferError }) : null,
1289
+ formatError ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { role: "alert", className: "matrx-alchemy-error", children: formatError }) : null,
1290
+ bufferError ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Button, { type: "button", variant: "outline", disabled: busy !== null, onClick: () => {
1291
+ const fallback = (0, import_content_transfer.editDraft)(state.draft, { kind: "text", text: buffer });
1292
+ setBufferError(null);
1293
+ onChange({ ...state, draft: fallback, error: void 0 });
1294
+ setFormat("plain");
1295
+ }, children: "Use invalid JSON as plain text" }) : null
1296
+ ] }),
1297
+ ai || busy === "capture" || state.error ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("aside", { children: [
1298
+ ai ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
1299
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { children: [
1300
+ "AI instruction",
1301
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("textarea", { value: instruction, onChange: (e) => setInstruction(e.target.value), placeholder: "Tell AI how to prepare this content" })
1302
+ ] }),
1303
+ /* @__PURE__ */ (0, import_jsx_runtime7.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" }),
1304
+ busy === "ai" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Button, { type: "button", variant: "outline", onClick: () => void cancelAi(), children: aiSession.current?.cancel ? "Cancel AI" : "Stop waiting" }) : null
1305
+ ] }) : null,
1306
+ busy === "capture" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Button, { type: "button", variant: "outline", onClick: () => {
1307
+ activeCapture.current?.abort();
1308
+ activeCapture.current = null;
1309
+ setBusy(null);
1310
+ }, children: "Stop loading rows" }) : null,
1311
+ ai && aiSession.current?.recover && busy !== "ai" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Button, { type: "button", variant: "outline", onClick: () => void runAi(true), children: aiFailed ? "Retry or rejoin AI run" : "Rejoin AI run" }) : null,
1312
+ ai ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "matrx-alchemy-meta", children: "AI creates a preview. It never copies automatically. Closing detaches this view without cancelling server work." }) : null,
1313
+ state.error ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { role: "alert", className: "matrx-alchemy-error", children: state.error }) : null
1314
+ ] }) : null
1315
+ ] }),
1316
+ pendingControls ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "matrx-alchemy-decision", role: "alert", children: [
1317
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { children: "This control would replace your manual edit." }),
1318
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Button, { type: "button", variant: "outline", onClick: () => setPendingControls(null), children: "Keep edited draft" }),
1319
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Button, { type: "button", onClick: applyPendingControls, children: "Rebuild from source" })
1320
+ ] }) : null,
1321
+ state.pending ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "matrx-alchemy-decision", role: "alert", children: [
1322
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { children: "A fresh source snapshot is ready." }),
1323
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Button, { type: "button", variant: "outline", onClick: () => resolveCapture("keep"), children: "Keep current snapshot and draft" }),
1324
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Button, { type: "button", onClick: () => resolveCapture("regenerate"), children: "Regenerate from fresh source" })
1325
+ ] }) : null,
1326
+ deliveryNotice ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { role: "status", className: "matrx-alchemy-meta", children: deliveryNotice }) : null,
1327
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(DialogFooter, { children: [
1328
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "matrx-alchemy-meta", children: [
1329
+ buffer.length.toLocaleString(),
1330
+ " characters \xB7 ~",
1331
+ estimateTokens(buffer).toLocaleString(),
1332
+ " tokens"
1333
+ ] }),
1334
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Button, { type: "button", variant: "outline", onClick: close, children: "Close" }),
1335
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Button, { type: "button", variant: "outline", disabled: busy !== null || Boolean(bufferError || formatError) || !preparedArtifact, onClick: () => void deliver(true), children: "Download prepared output" }),
1336
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Button, { type: "button", disabled: busy !== null || Boolean(bufferError || formatError) || !preparedArtifact, onClick: () => void deliver(false), children: "Copy prepared output" })
1337
+ ] })
1338
+ ] }) });
1339
+ }
1340
+ function RowControls({ rows, controls, change }) {
1341
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
1342
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "matrx-alchemy-toolbar", children: [
1343
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { children: [
1344
+ "Search",
1345
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("input", { value: controls.search, onChange: (e) => change({ ...controls, search: e.target.value }) })
1346
+ ] }),
1347
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { children: [
1348
+ "Sort",
1349
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("select", { value: controls.sort, onChange: (e) => change({ ...controls, sort: e.target.value }), children: [
1350
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: "", children: "None" }),
1351
+ rows.columns.map((column) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: column.id, children: column.label }, column.id))
1352
+ ] })
1353
+ ] }),
1354
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { children: [
1355
+ "Direction",
1356
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("select", { value: controls.direction, disabled: !controls.sort, onChange: (e) => change({ ...controls, direction: e.target.value }), children: [
1357
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: "asc", children: "Ascending" }),
1358
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: "desc", children: "Descending" })
1359
+ ] })
1360
+ ] }),
1361
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { children: [
1362
+ "Top rows",
1363
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("input", { type: "number", min: "0", value: controls.top ?? "", onChange: (e) => change({ ...controls, top: Number.isNaN(e.target.valueAsNumber) ? null : e.target.valueAsNumber }) })
1364
+ ] })
1365
+ ] }),
1366
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("fieldset", { className: "matrx-alchemy-options", children: [
1367
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("legend", { children: "Columns and filters" }),
1368
+ rows.columns.map((column) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "matrx-alchemy-column", children: [
1369
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { children: [
1370
+ /* @__PURE__ */ (0, import_jsx_runtime7.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) }) }),
1371
+ " ",
1372
+ column.label
1373
+ ] }),
1374
+ /* @__PURE__ */ (0, import_jsx_runtime7.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 } }) })
1375
+ ] }, column.id))
1376
+ ] }),
1377
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("fieldset", { className: "matrx-alchemy-options", children: [
1378
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("legend", { children: "Rows" }),
1379
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { children: [
1380
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("input", { type: "checkbox", checked: controls.selectedOnly, onChange: (e) => change({ ...controls, selectedOnly: e.target.checked }) }),
1381
+ " Only selected rows"
1382
+ ] }),
1383
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "matrx-alchemy-row-list", children: rows.rows.map((row, index) => {
1384
+ 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 ");
1385
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { children: [
1386
+ /* @__PURE__ */ (0, import_jsx_runtime7.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) }) }),
1387
+ " Row ",
1388
+ index + 1,
1389
+ summary ? ` \u2014 ${summary}` : ""
1390
+ ] }, index);
1391
+ }) })
1392
+ ] })
1393
+ ] });
1394
+ }
1395
+
1396
+ // src/content-transfer/matrx-copy.tsx
1397
+ var import_jsx_runtime8 = require("react/jsx-runtime");
1398
+ var resolve = (value) => typeof value === "function" ? value() : value;
1399
+ var asPayload = (value) => ({
1400
+ kind: "markdown",
1401
+ text: typeof value === "string" ? value : (0, import_content_transfer2.buildAgentPayload)(value)
1402
+ });
1403
+ var structuredPayload = (value) => {
1404
+ if (typeof value === "string") return { kind: "markdown", text: value };
1405
+ const clean = (record) => Object.fromEntries(
1406
+ Object.entries(record ?? {}).filter(([, entry]) => entry !== void 0)
1407
+ );
1408
+ return {
1409
+ kind: "json",
1410
+ value: (0, import_content_transfer2.normalizeTransferJson)({
1411
+ kind: value.kind,
1412
+ location: value.location,
1413
+ description: value.description,
1414
+ data: value.data,
1415
+ ...value.summary !== void 0 ? { summary: value.summary } : {},
1416
+ attributes: clean(value.attributes),
1417
+ context: clean(value.context)
1418
+ })
1419
+ };
1420
+ };
1421
+ var actionDone = (message) => ({
1422
+ status: "success",
1423
+ delivered: "action",
1424
+ mimeTypes: [],
1425
+ message
1426
+ });
1427
+ var sourceFor = (id, label, build) => ({
1428
+ id,
1429
+ label,
1430
+ capture: async ({ signal }) => {
1431
+ signal.throwIfAborted();
1432
+ const payload = await build();
1433
+ signal.throwIfAborted();
1434
+ return (0, import_content_transfer2.directSource)(payload, { sourceId: id, label });
1435
+ }
1436
+ });
1437
+ function MatrxCopyMenu(props) {
1438
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(MatrxCopyMenuSession, { ...props }, props.sourceId ?? props.label);
1439
+ }
1440
+ function MatrxCopyMenuSession(props) {
1441
+ const instance = React8.useId();
1442
+ const controller = React8.useRef(null);
1443
+ const capabilities = useContentTransferCapabilities();
1444
+ const transport = capabilities.transport ?? (0, import_content_transfer2.createBrowserTransport)();
1445
+ const [modal, setModal] = React8.useState(null);
1446
+ const [configuration, setConfiguration] = React8.useState(null);
1447
+ const copyVisible = !props.hide?.includes("copy");
1448
+ const aiVisible = !props.hide?.includes("ai");
1449
+ const exportVisible = !props.hide?.includes("export");
1450
+ const make = (suffix, build, label = props.label) => sourceFor(
1451
+ `${props.sourceId ?? `${instance}:${props.label}`}:${suffix}`,
1452
+ label,
1453
+ build
1454
+ );
1455
+ const human = copyVisible && props.human !== void 0 ? make("human", () => ({ kind: "text", text: resolve(props.human) })) : void 0;
1456
+ const humanMarkdown = copyVisible && props.human !== void 0 ? make("human-markdown", () => ({
1457
+ kind: "markdown",
1458
+ text: resolve(props.human)
1459
+ })) : void 0;
1460
+ const json = aiVisible && props.json !== void 0 ? make("json", () => ({
1461
+ kind: "json",
1462
+ value: (0, import_content_transfer2.normalizeTransferJson)(resolve(props.json))
1463
+ })) : void 0;
1464
+ const agent = aiVisible && props.agent !== void 0 ? make("agent", () => asPayload(resolve(props.agent))) : void 0;
1465
+ const structuredAgent = aiVisible && props.agent !== void 0 ? make("structured-agent", () => structuredPayload(resolve(props.agent))) : void 0;
1466
+ const table = exportVisible && props.export?.sheetRows ? make("rows", () => {
1467
+ const value = (0, import_content_transfer2.normalizeTransferJson)(props.export.sheetRows());
1468
+ if (!Array.isArray(value) || value.some(
1469
+ (row) => row === null || typeof row !== "object" || Array.isArray(row)
1470
+ ))
1471
+ throw new Error("Sheet rows must be JSON objects.");
1472
+ const rows = value;
1473
+ const keys = [...new Set(rows.flatMap((row) => Object.keys(row)))];
1474
+ return {
1475
+ kind: "rows",
1476
+ rows,
1477
+ columns: keys.map((key) => ({
1478
+ id: key,
1479
+ label: key,
1480
+ path: `/${key.replace(/~/g, "~0").replace(/\//g, "~1")}`,
1481
+ visible: true
1482
+ }))
1483
+ };
1484
+ }) : void 0;
1485
+ const builderVariants = aiVisible ? (props.aiVariants ?? []).filter(
1486
+ (variant) => variant.build && !variant.onSelect && !variant.modal
1487
+ ).map((variant) => ({
1488
+ ...variant,
1489
+ copyLabel: variant.label,
1490
+ source: make(
1491
+ `variant:${variant.id}`,
1492
+ async () => asPayload(await variant.build()),
1493
+ variant.label
1494
+ )
1495
+ })) : [];
1496
+ const faithful = agent ? [
1497
+ {
1498
+ id: props.agentVariant?.id ?? "faithful",
1499
+ label: props.agentVariant?.label ?? "Full AI context",
1500
+ source: agent,
1501
+ copyLabel: props.agentVariant?.label ?? "Copy for AI",
1502
+ ...props.agentVariant?.hint ? { hint: props.agentVariant.hint } : {}
1503
+ }
1504
+ ] : [];
1505
+ const variants = props.agentVariant?.position === "last" ? [...builderVariants, ...faithful] : [...faithful, ...builderVariants];
1506
+ const actions = [];
1507
+ if (aiVisible)
1508
+ for (const variant of props.aiVariants ?? []) {
1509
+ if (!variant.onSelect && !variant.modal) continue;
1510
+ actions.push({
1511
+ ...variant,
1512
+ id: `variant-action:${variant.id}`,
1513
+ label: variant.label,
1514
+ supports: () => true,
1515
+ run: async () => {
1516
+ if (variant.onSelect) await variant.onSelect();
1517
+ else setModal(variant);
1518
+ return actionDone(`Opened ${variant.label}`);
1519
+ }
1520
+ });
1521
+ }
1522
+ if (aiVisible && props.aiCustom)
1523
+ actions.push({
1524
+ id: "configure-source",
1525
+ label: props.aiCustom.label ?? "Customize source\u2026",
1526
+ ...props.aiCustom.hint ? { hint: props.aiCustom.hint } : {},
1527
+ supports: () => true,
1528
+ run: async () => {
1529
+ setConfiguration({ custom: props.aiCustom });
1530
+ return actionDone("Source options opened");
1531
+ }
1532
+ });
1533
+ if (aiVisible && props.groomer)
1534
+ actions.push({
1535
+ id: "groom-source",
1536
+ label: "Customize sections\u2026",
1537
+ supports: () => true,
1538
+ run: async () => {
1539
+ setConfiguration({ groomer: props.groomer() });
1540
+ return actionDone("Section options opened");
1541
+ }
1542
+ });
1543
+ if (exportVisible)
1544
+ for (const item of props.export?.items ?? [])
1545
+ actions.push({
1546
+ id: `export:${item.id}`,
1547
+ label: item.label,
1548
+ supports: () => true,
1549
+ ...item.build && !item.onSelect ? {
1550
+ source: make(
1551
+ `export:${item.id}`,
1552
+ async () => {
1553
+ const file = item.build();
1554
+ const bytes = new Uint8Array(
1555
+ await new Blob([file.content], {
1556
+ type: file.mime
1557
+ }).arrayBuffer()
1558
+ );
1559
+ return {
1560
+ kind: "registered",
1561
+ format: "matrx-file",
1562
+ value: {
1563
+ bytes: Array.from(bytes),
1564
+ mime: file.mime,
1565
+ extension: file.extension
1566
+ }
1567
+ };
1568
+ },
1569
+ item.label
1570
+ )
1571
+ } : {},
1572
+ run: async ({ snapshot, draft, signal }) => {
1573
+ if (item.onSelect) {
1574
+ await item.onSelect();
1575
+ return actionDone(`Opened ${item.label}`);
1576
+ }
1577
+ const value = draft.payload.kind === "registered" ? draft.payload.value : null;
1578
+ if (!value || Array.isArray(value) || typeof value !== "object" || !Array.isArray(value.bytes) || typeof value.mime !== "string" || typeof value.extension !== "string" || value.bytes.some(
1579
+ (byte) => typeof byte !== "number" || !Number.isInteger(byte) || byte < 0 || byte > 255
1580
+ ))
1581
+ throw new Error(`${item.label} did not capture a valid file.`);
1582
+ if (draft.omissions.some((omission) => omission.reason !== "duplicate"))
1583
+ throw new Error(
1584
+ "This custom file exceeds the configured export limits or contains excluded content. Use a standard format or revise the source options."
1585
+ );
1586
+ const bytes = new Uint8Array(value.bytes);
1587
+ const filename = `${props.label.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "export"}.${value.extension.replace(/[^a-zA-Z0-9.-]/g, "") || "bin"}`;
1588
+ return transport.download(
1589
+ (0, import_content_transfer2.sealTransferArtifact)({
1590
+ snapshotId: snapshot.id,
1591
+ draftRevision: draft.revision,
1592
+ format: `export:${item.id}`,
1593
+ plainText: "",
1594
+ file: { filename, mime: value.mime, bytes },
1595
+ omissions: [...draft.omissions]
1596
+ }),
1597
+ signal
1598
+ );
1599
+ }
1600
+ });
1601
+ if (exportVisible && table && props.sendToSheet)
1602
+ actions.push({
1603
+ id: "send-google-sheet",
1604
+ label: "Send to Google Sheet",
1605
+ source: table,
1606
+ supports: () => true,
1607
+ run: async ({ draft }) => {
1608
+ if (draft.payload.kind !== "rows")
1609
+ throw new Error("Google Sheets requires captured rows.");
1610
+ return props.sendToSheet(draft.payload.rows, props.label);
1611
+ }
1612
+ });
1613
+ const source = json ?? table ?? structuredAgent ?? human ?? builderVariants[0]?.source;
1614
+ if (!source && !actions.length) return null;
1615
+ const target = source ?? make("actions", () => ({ kind: "text", text: props.label }));
1616
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
1617
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1618
+ ContentTransferMenu,
1619
+ {
1620
+ source: target,
1621
+ controllerRef: controller,
1622
+ label: props.label,
1623
+ variants,
1624
+ actions,
1625
+ hide: [
1626
+ ...!copyVisible || !source ? ["copy"] : [],
1627
+ ...!aiVisible || !source ? ["prepare"] : [],
1628
+ ...!exportVisible || !source ? ["download"] : []
1629
+ ],
1630
+ formatSources: {
1631
+ ...human ? { plain: human, markdown: humanMarkdown, html: humanMarkdown } : {},
1632
+ ...json ? { json, "compact-json": json } : {},
1633
+ ...table ? { csv: table, tsv: table } : {}
1634
+ },
1635
+ ...props.disabled !== void 0 ? { disabled: props.disabled } : {},
1636
+ className: cn(
1637
+ props.className,
1638
+ props.size === "xs" && "matrx-alchemy-xs",
1639
+ props.size === "sm" && "matrx-alchemy-sm"
1640
+ ),
1641
+ ...props.stopPropagation !== void 0 ? { stopPropagation: props.stopPropagation } : {}
1642
+ }
1643
+ ),
1644
+ modal?.modal?.({
1645
+ open: true,
1646
+ onOpenChange: (open) => {
1647
+ if (!open) setModal(null);
1648
+ }
1649
+ }),
1650
+ configuration ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1651
+ SourceConfiguration,
1652
+ {
1653
+ restoreFocus: () => controller.current?.focusTrigger(),
1654
+ configuration,
1655
+ onClose: () => setConfiguration(null),
1656
+ onPrepare: async (payload, label) => {
1657
+ if (!controller.current)
1658
+ throw new Error("Alchemy is no longer mounted.");
1659
+ await controller.current.prepare(payload, {
1660
+ label,
1661
+ id: `${instance}:configured:${crypto.randomUUID()}`
1662
+ });
1663
+ setConfiguration(null);
1664
+ }
1665
+ },
1666
+ `${instance}:configuration`
1667
+ ) : null
1668
+ ] });
1669
+ }
1670
+ function SourceConfiguration({
1671
+ restoreFocus,
1672
+ configuration,
1673
+ onClose,
1674
+ onPrepare
1675
+ }) {
1676
+ const custom = configuration.custom;
1677
+ const handingOff = React8.useRef(false);
1678
+ const groomer = configuration.groomer;
1679
+ const [values, setValues] = React8.useState(
1680
+ () => Object.fromEntries(
1681
+ custom?.options.map((option) => [option.key, option.default]) ?? []
1682
+ )
1683
+ );
1684
+ const [sections, setSections] = React8.useState(
1685
+ () => Object.fromEntries(
1686
+ groomer?.sections.map((section) => [
1687
+ section.id,
1688
+ section.defaultSelection ?? "full"
1689
+ ]) ?? []
1690
+ )
1691
+ );
1692
+ const [error, setError] = React8.useState(null);
1693
+ const [busy, setBusy] = React8.useState(false);
1694
+ const title = custom?.dialogTitle ?? groomer?.label ?? "Customize source";
1695
+ let prepared = null;
1696
+ let buildError = null;
1697
+ let text = "";
1698
+ try {
1699
+ if (custom) {
1700
+ const result = custom.build(values);
1701
+ prepared = custom.wrap(result.text, values, result.meta);
1702
+ } else if (groomer) {
1703
+ const data = {};
1704
+ const omitted = [];
1705
+ for (const section of groomer.sections) {
1706
+ const level = sections[section.id] ?? "full";
1707
+ if (level === "off") omitted.push(section.id);
1708
+ else {
1709
+ const value = section.build(level);
1710
+ if (value !== void 0 && value !== null) data[section.id] = value;
1711
+ }
1712
+ }
1713
+ prepared = {
1714
+ kind: groomer.kind,
1715
+ location: groomer.location,
1716
+ description: groomer.description,
1717
+ data,
1718
+ ...groomer.summary ? { summary: groomer.summary } : {},
1719
+ attributes: {
1720
+ ...groomer.attributes,
1721
+ dropped_sections: omitted.join(",")
1722
+ },
1723
+ ...groomer.context ? { context: groomer.context } : {}
1724
+ };
1725
+ }
1726
+ text = prepared ? (0, import_content_transfer2.buildAgentPayload)(prepared) : "";
1727
+ } catch (cause) {
1728
+ buildError = cause instanceof Error ? cause.message : "Could not prepare this source.";
1729
+ }
1730
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1731
+ Dialog,
1732
+ {
1733
+ open: true,
1734
+ onOpenChange: (open) => {
1735
+ if (!open && !busy) onClose();
1736
+ },
1737
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1738
+ DialogContent,
1739
+ {
1740
+ onCloseAutoFocus: (event) => {
1741
+ event.preventDefault();
1742
+ if (!handingOff.current) restoreFocus();
1743
+ },
1744
+ className: "matrx-alchemy-workspace",
1745
+ children: [
1746
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(DialogHeader, { children: [
1747
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(DialogTitle, { children: title }),
1748
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(DialogDescription, { children: custom?.dialogDescription ?? "Choose the source detail, then prepare, edit, summarize, copy or export it in Alchemy." })
1749
+ ] }),
1750
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "matrx-alchemy-main matrx-alchemy-toolbar", children: [
1751
+ custom?.options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { children: [
1752
+ option.label,
1753
+ "hint" in option && option.hint ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("small", { children: option.hint }) : null,
1754
+ option.kind === "toggle" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1755
+ "input",
1756
+ {
1757
+ type: "checkbox",
1758
+ checked: Boolean(values[option.key]),
1759
+ onChange: (event) => setValues({ ...values, [option.key]: event.target.checked })
1760
+ }
1761
+ ) : option.kind === "preset" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1762
+ "select",
1763
+ {
1764
+ value: Number(values[option.key]),
1765
+ onChange: (event) => setValues({
1766
+ ...values,
1767
+ [option.key]: Number(event.target.value)
1768
+ }),
1769
+ children: option.options.map((choice) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: choice.value, children: choice.label }, choice.value))
1770
+ }
1771
+ ) : option.kind === "slider" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
1772
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1773
+ "input",
1774
+ {
1775
+ type: "range",
1776
+ min: 0,
1777
+ max: Math.max(0, option.stops.length - 1),
1778
+ step: 1,
1779
+ value: option.stops.indexOf(Number(values[option.key])),
1780
+ onChange: (event) => setValues({
1781
+ ...values,
1782
+ [option.key]: option.stops[Number(event.target.value)]
1783
+ })
1784
+ }
1785
+ ),
1786
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: option.formatValue(Number(values[option.key])) })
1787
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
1788
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1789
+ "input",
1790
+ {
1791
+ type: "number",
1792
+ min: option.min,
1793
+ step: option.step,
1794
+ value: Number(values[option.key]),
1795
+ onChange: (event) => setValues({
1796
+ ...values,
1797
+ [option.key]: Number(event.target.value)
1798
+ })
1799
+ }
1800
+ ),
1801
+ option.presets?.map((preset) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1802
+ Button,
1803
+ {
1804
+ type: "button",
1805
+ variant: "ghost",
1806
+ onClick: () => setValues({ ...values, [option.key]: preset.value }),
1807
+ children: preset.label
1808
+ },
1809
+ preset.value
1810
+ ))
1811
+ ] })
1812
+ ] }, option.key)),
1813
+ groomer ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
1814
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { children: ["full", "compact", "brief"].map((level) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1815
+ Button,
1816
+ {
1817
+ type: "button",
1818
+ variant: "ghost",
1819
+ onClick: () => setSections(
1820
+ Object.fromEntries(
1821
+ groomer.sections.map((section) => [
1822
+ section.id,
1823
+ level === "brief" && section.cuttable ? "off" : level
1824
+ ])
1825
+ )
1826
+ ),
1827
+ children: level
1828
+ },
1829
+ level
1830
+ )) }),
1831
+ groomer.sections.map((section) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { children: [
1832
+ section.title,
1833
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1834
+ "select",
1835
+ {
1836
+ value: sections[section.id],
1837
+ onChange: (event) => setSections({
1838
+ ...sections,
1839
+ [section.id]: event.target.value
1840
+ }),
1841
+ children: [
1842
+ ["full", "compact", "brief"].map((level) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: level, children: section.levelLabels?.[level] ?? level }, level)),
1843
+ section.cuttable ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: "off", children: "Exclude" }) : null
1844
+ ]
1845
+ }
1846
+ ),
1847
+ section.description ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: section.description }) : null
1848
+ ] }, section.id))
1849
+ ] }) : null
1850
+ ] }),
1851
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("p", { children: [
1852
+ text.length.toLocaleString(),
1853
+ " characters \xB7 approximately",
1854
+ " ",
1855
+ Math.ceil(text.length / 4).toLocaleString(),
1856
+ " tokens"
1857
+ ] }),
1858
+ error || buildError ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { role: "alert", children: error ?? buildError }) : null,
1859
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(DialogFooter, { children: [
1860
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1861
+ Button,
1862
+ {
1863
+ type: "button",
1864
+ variant: "ghost",
1865
+ disabled: busy,
1866
+ onClick: onClose,
1867
+ children: "Cancel"
1868
+ }
1869
+ ),
1870
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1871
+ Button,
1872
+ {
1873
+ type: "button",
1874
+ disabled: busy || !prepared || Boolean(buildError),
1875
+ onClick: async () => {
1876
+ if (!prepared) return;
1877
+ setBusy(true);
1878
+ setError(null);
1879
+ try {
1880
+ handingOff.current = true;
1881
+ await onPrepare(structuredPayload(prepared), title);
1882
+ } catch (cause) {
1883
+ handingOff.current = false;
1884
+ setError(
1885
+ cause instanceof Error ? cause.message : "Could not open Alchemy."
1886
+ );
1887
+ } finally {
1888
+ setBusy(false);
1889
+ }
1890
+ },
1891
+ children: busy ? "Preparing\u2026" : "Prepare in Alchemy"
1892
+ }
1893
+ )
1894
+ ] })
1895
+ ]
1896
+ }
1897
+ )
1898
+ }
1899
+ );
481
1900
  }
482
- var Check = (p) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Icon, { ...p, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "m5 12 4 4L19 6" }) });
483
- var SlidersHorizontal = (p) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Icon, { ...p, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M4 7h16M4 17h16M9 7v0M15 17v0" }) });
484
- var PanelRight = (p) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Icon, { ...p, children: [
485
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("rect", { x: "3", y: "4", width: "18", height: "16", rx: "2" }),
486
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M15 4v16" })
487
- ] });
488
- var ExternalLink = (p) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Icon, { ...p, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M14 4h6v6M20 4l-9 9M19 13v6H5V5h6" }) });
489
- var Copy = (p) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Icon, { ...p, children: [
490
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("rect", { x: "9", y: "9", width: "11", height: "11", rx: "2" }),
491
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M15 9V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h3" })
492
- ] });
493
- var Lightbulb = (p) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Icon, { ...p, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M9 18h6M10 22h4M8 14a6 6 0 1 1 8 0c-1 1-1 2-1 3H9c0-1 0-2-1-3z" }) });
494
- var ShieldOff = (p) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Icon, { ...p, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "m3 3 18 18M12 3l7 3v5c0 4-3 7-7 9-4-2-7-5-7-9V6l4-2" }) });
495
1901
 
496
1902
  // src/data-table/host.tsx
497
1903
  var import_react = require("react");
498
- var import_jsx_runtime8 = require("react/jsx-runtime");
1904
+ var import_jsx_runtime9 = require("react/jsx-runtime");
499
1905
  var HOST_SLOT = /* @__PURE__ */ Symbol.for("ai-matrx.design-system.table-host-context");
500
1906
  var hostRegistry = globalThis;
501
1907
  var HostContext = hostRegistry[HOST_SLOT] ??= (0, import_react.createContext)({});
@@ -503,9 +1909,38 @@ function useMatrxDataTableHost() {
503
1909
  return (0, import_react.useContext)(HostContext);
504
1910
  }
505
1911
 
1912
+ // src/data-table/copy.tsx
1913
+ var import_jsx_runtime10 = require("react/jsx-runtime");
1914
+ function CopyButtons(props) {
1915
+ const { CopyControls } = useMatrxDataTableHost();
1916
+ if (CopyControls) return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(CopyControls, { ...props });
1917
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(MatrxCopyMenu, { ...props });
1918
+ }
1919
+
1920
+ // src/data-table/MatrxUuidCell.tsx
1921
+ var import_react3 = require("react");
1922
+
1923
+ // src/data-table/icons.tsx
1924
+ var import_jsx_runtime11 = require("react/jsx-runtime");
1925
+ function Icon({ children, ...props }) {
1926
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", "aria-hidden": "true", ...props, children });
1927
+ }
1928
+ var Check = (p) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Icon, { ...p, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "m5 12 4 4L19 6" }) });
1929
+ var PanelRight = (p) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Icon, { ...p, children: [
1930
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("rect", { x: "3", y: "4", width: "18", height: "16", rx: "2" }),
1931
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "M15 4v16" })
1932
+ ] });
1933
+ var ExternalLink = (p) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Icon, { ...p, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "M14 4h6v6M20 4l-9 9M19 13v6H5V5h6" }) });
1934
+ var Copy = (p) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Icon, { ...p, children: [
1935
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("rect", { x: "9", y: "9", width: "11", height: "11", rx: "2" }),
1936
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "M15 9V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h3" })
1937
+ ] });
1938
+ var Lightbulb = (p) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Icon, { ...p, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "M9 18h6M10 22h4M8 14a6 6 0 1 1 8 0c-1 1-1 2-1 3H9c0-1 0-2-1-3z" }) });
1939
+ var ShieldOff = (p) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Icon, { ...p, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "m3 3 18 18M12 3l7 3v5c0 4-3 7-7 9-4-2-7-5-7-9V6l4-2" }) });
1940
+
506
1941
  // src/data-table/useTableNotice.tsx
507
1942
  var import_react2 = require("react");
508
- var import_jsx_runtime9 = require("react/jsx-runtime");
1943
+ var import_jsx_runtime12 = require("react/jsx-runtime");
509
1944
  function useTableNotice() {
510
1945
  const host = useMatrxDataTableHost();
511
1946
  const [message, setMessage] = (0, import_react2.useState)(null);
@@ -519,174 +1954,23 @@ function useTableNotice() {
519
1954
  else setMessage({ text, error: true });
520
1955
  }
521
1956
  };
522
- const notice = message ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { role: message.error ? "alert" : "status", className: message.error ? "text-xs text-destructive" : "text-xs text-muted-foreground", children: [
1957
+ const notice = message ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { role: message.error ? "alert" : "status", className: message.error ? "text-xs text-destructive" : "text-xs text-muted-foreground", children: [
523
1958
  message.text,
524
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", "aria-label": "Dismiss notification", className: "ml-2 underline", onClick: () => setMessage(null), children: "Dismiss" })
1959
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { type: "button", "aria-label": "Dismiss notification", className: "ml-2 underline", onClick: () => setMessage(null), children: "Dismiss" })
525
1960
  ] }) : null;
526
1961
  return { notify, notice };
527
1962
  }
528
1963
 
529
- // src/data-table/copy-payload.ts
530
- function tableAgentText(value) {
531
- if (typeof value === "string") return value;
532
- const attributes = Object.entries(value.attributes ?? {}).filter(([, entry]) => entry !== null && entry !== void 0 && entry !== "").map(([key, entry]) => ` ${key}="${String(entry)}"`).join("");
533
- const context = Object.entries(value.context ?? {}).filter(([, entry]) => entry !== null && entry !== void 0 && entry !== "").map(([key, entry]) => `<${key}>${String(entry)}</${key}>`).join("\n");
534
- const url = typeof window === "undefined" ? "" : window.location.href;
535
- const route = typeof window === "undefined" ? "" : window.location.pathname;
536
- return `<${value.kind}${attributes}>
537
- <context>
538
- <location>${value.location}</location>
539
- ${url ? `<url>${url}</url>` : ""}
540
- ${route ? `<route>${route}</route>` : ""}
541
- <copied>${value.description}</copied>
542
- <copied-at>${(/* @__PURE__ */ new Date()).toISOString()}</copied-at>
543
- ${context}
544
- </context>
545
- ${value.summary ? `<summary>
546
- ${value.summary}
547
- </summary>
548
- ` : ""}<data format="json">
549
- \`\`\`json
550
- ${JSON.stringify(value.data, null, 2)}
551
- \`\`\`
552
- </data>
553
- </${value.kind}>`;
554
- }
555
-
556
- // src/data-table/copy.tsx
557
- var import_jsx_runtime10 = require("react/jsx-runtime");
558
- function resolve(value) {
559
- return typeof value === "function" ? value() : value;
560
- }
561
- function download(item) {
562
- if (!item.build) throw new Error(`No export action is available for ${item.label}.`);
563
- const file = item.build();
564
- const url = URL.createObjectURL(new Blob([file.content], { type: file.mime }));
565
- try {
566
- const link = document.createElement("a");
567
- link.href = url;
568
- link.download = `${item.label.replace(/[^a-z0-9]+/gi, "-")}.${file.extension}`;
569
- document.body.append(link);
570
- link.click();
571
- link.remove();
572
- } finally {
573
- URL.revokeObjectURL(url);
574
- }
575
- }
576
- function CopyButtons(props) {
577
- const { CopyControls } = useMatrxDataTableHost();
578
- if (CopyControls) return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(CopyControls, { ...props });
579
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(DefaultCopyButtons, { ...props });
580
- }
581
- function DefaultCopyButtons({ human, agent, json, label, size = "icon", appearance = "segmented", disabled = false, stopPropagation = true, className, aiVariants = [], agentVariant, aiCustom, export: exportConfig, hide }) {
582
- const { notify, notice } = useTableNotice();
583
- const clipboard = (0, import_clipboard.useClipboard)({ notify: (message, kind) => notify[kind](message) });
584
- const [busy, setBusy] = (0, import_react3.useState)(false);
585
- const [modal, setModal] = (0, import_react3.useState)(null);
586
- const run = async (operation) => {
587
- if (busy) return;
588
- setBusy(true);
589
- try {
590
- await operation();
591
- } catch (error) {
592
- notify.error(error instanceof Error ? error.message : String(error));
593
- } finally {
594
- setBusy(false);
595
- }
596
- };
597
- const faithfulAgent = agent === void 0 ? [] : [{
598
- id: agentVariant?.id ?? "copy-for-ai",
599
- label: agentVariant?.label ?? "Copy for AI",
600
- ...agentVariant?.hint === void 0 ? {} : { hint: agentVariant.hint },
601
- section: "ai",
602
- build: () => resolve(agent)
603
- }];
604
- const orderedAgent = agentVariant?.position === "last" ? [...aiVariants, ...faithfulAgent] : [...faithfulAgent, ...aiVariants];
605
- const variants = [
606
- ...json === void 0 ? [] : [{ id: "json", label: "Copy JSON", section: "copy", build: () => JSON.stringify(resolve(json), null, 2) }],
607
- ...orderedAgent
608
- ].filter((variant) => !hide?.includes(variant.section ?? "ai"));
609
- const exports = hide?.includes("export") ? void 0 : exportConfig;
610
- const showCustom = aiCustom && !hide?.includes("ai");
611
- const buttonClass = `${size === "xs" ? "h-8 w-8 lg:h-5 lg:w-8" : ""} ${appearance === "bare" ? "border-0 bg-transparent shadow-none" : ""}`;
612
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: `inline-flex flex-wrap items-center gap-0.5 ${className ?? ""}`, onClick: stopPropagation ? (event) => event.stopPropagation() : void 0, children: [
613
- human !== void 0 && !hide?.includes("copy") ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Button, { type: "button", variant: "ghost", size: "icon", className: buttonClass, disabled: disabled || busy, "aria-label": `Copy ${label}`, onClick: () => void run(() => clipboard.copyText(resolve(human), `${label} copied`)), children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Copy, { className: "h-3.5 w-3.5" }) }) : null,
614
- variants.length > 0 || showCustom || exports ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Popover, { children: [
615
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Button, { type: "button", variant: "ghost", size: "icon", className: buttonClass, disabled: disabled || busy, "aria-label": `Copy ${label} for AI or export`, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SlidersHorizontal, { className: "h-3.5 w-3.5" }) }) }),
616
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(PopoverContent, { align: "end", className: "w-64 p-1", children: [
617
- variants.map((variant) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Button, { type: "button", variant: "ghost", size: "sm", className: "w-full justify-start", disabled: busy, onClick: () => void run(async () => {
618
- if (variant.onSelect) variant.onSelect();
619
- else if (variant.modal) setModal(variant.id);
620
- else if (variant.build) await clipboard.copyText(tableAgentText(await variant.build()), variant.successMessage ?? `${label} copied`);
621
- else throw new Error(`No copy action is available for ${variant.label}.`);
622
- }), children: variant.label }, variant.id)),
623
- showCustom ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Button, { type: "button", variant: "ghost", size: "sm", className: "w-full justify-start", onClick: () => setModal("custom"), children: aiCustom.label ?? "Custom copy\u2026" }) : null,
624
- exports?.items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Button, { type: "button", variant: "ghost", size: "sm", className: "w-full justify-start", disabled: busy, onClick: () => void run(async () => {
625
- if (item.onSelect) await item.onSelect();
626
- else download(item);
627
- }), children: item.label }, item.id)),
628
- exports?.sheetRows ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Button, { type: "button", variant: "ghost", size: "sm", className: "w-full justify-start", onClick: () => void run(async () => {
629
- const rows = exports.sheetRows?.();
630
- if (!rows) return;
631
- const keys = [...new Set(rows.flatMap((row) => Object.keys(row)))];
632
- const value = (input) => String(input ?? "").replace(/[\t\r\n]+/g, " ");
633
- await clipboard.copyText([keys.map(value).join(" "), ...rows.map((row) => keys.map((key) => value(row[key])).join(" "))].join("\n"), "Copied for pasting into Google Sheets");
634
- }), children: "Copy for Google Sheets" }) : null
635
- ] })
636
- ] }) : null,
637
- variants.map((variant) => variant.modal && modal === variant.id ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: variant.modal({ open: true, onOpenChange: (open) => setModal(open ? variant.id : null) }) }, variant.id) : null),
638
- modal === "custom" && aiCustom ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(CustomCopy, { source: aiCustom, onClose: () => setModal(null) }) : null,
639
- notice
640
- ] });
641
- }
642
- function CustomCopy({ source, onClose }) {
643
- const [values, setValues] = (0, import_react3.useState)(() => Object.fromEntries(source.options.map((option) => [option.key, option.default])));
644
- const { notify, notice } = useTableNotice();
645
- const clipboard = (0, import_clipboard.useClipboard)({ notify: (message, kind) => notify[kind](message) });
646
- let text = "";
647
- let error = null;
648
- try {
649
- const built = source.build(values);
650
- text = tableAgentText(source.wrap(built.text, values, built.meta));
651
- } catch (raw) {
652
- error = raw instanceof Error ? raw.message : String(raw);
653
- }
654
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Dialog, { open: true, onOpenChange: (open) => {
655
- if (!open) onClose();
656
- }, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(DialogContent, { children: [
657
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(DialogHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(DialogTitle, { children: source.dialogTitle ?? "Custom copy" }) }),
658
- source.dialogDescription ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "text-sm", children: source.dialogDescription }) : null,
659
- source.options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { className: "flex items-center justify-between gap-3 text-sm", children: [
660
- option.label,
661
- option.kind === "toggle" ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("input", { type: "checkbox", checked: values[option.key] === true, onChange: (e) => setValues({ ...values, [option.key]: e.target.checked }) }) : option.kind === "preset" ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("select", { "aria-label": option.label, value: Number(values[option.key]), onChange: (e) => setValues({ ...values, [option.key]: Number(e.target.value) }), children: option.options.map((choice) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: choice.value, children: choice.label }, choice.value)) }) : option.kind === "slider" ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("input", { "aria-label": option.label, type: "range", min: 0, max: option.stops.length - 1, step: 1, value: Math.max(0, option.stops.indexOf(Number(values[option.key]))), onChange: (e) => setValues({ ...values, [option.key]: option.stops[Number(e.target.value)] ?? option.default }) }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "flex gap-1", children: [
662
- option.presets?.map((choice) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Button, { type: "button", size: "sm", variant: "outline", onClick: () => setValues({ ...values, [option.key]: choice.value }), children: choice.label }, choice.value)),
663
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("input", { "aria-label": option.label, type: "number", value: Number(values[option.key]), min: option.min, step: option.step, onChange: (e) => {
664
- if (Number.isFinite(e.target.valueAsNumber)) setValues({ ...values, [option.key]: e.target.valueAsNumber });
665
- } })
666
- ] })
667
- ] }, option.key)),
668
- error ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { role: "alert", className: "text-destructive", children: error }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("pre", { className: "max-h-48 overflow-auto whitespace-pre-wrap text-xs", children: text }),
669
- notice,
670
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(DialogFooter, { children: [
671
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Button, { type: "button", variant: "outline", onClick: onClose, children: "Close" }),
672
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Button, { type: "button", disabled: error !== null, onClick: () => void clipboard.copyText(text, "Custom copy copied"), children: "Copy" })
673
- ] })
674
- ] }) });
675
- }
676
-
677
- // src/data-table/MatrxUuidCell.tsx
678
- var import_react4 = require("react");
679
-
680
1964
  // src/tooltip.tsx
681
1965
  var TooltipPrimitive = __toESM(require("@radix-ui/react-tooltip"), 1);
682
- var React7 = __toESM(require("react"), 1);
683
- var import_jsx_runtime11 = require("react/jsx-runtime");
1966
+ var React9 = __toESM(require("react"), 1);
1967
+ var import_jsx_runtime13 = require("react/jsx-runtime");
684
1968
  var TooltipProvider = TooltipPrimitive.Provider;
685
1969
  var Tooltip = TooltipPrimitive.Root;
686
1970
  var TooltipTrigger = TooltipPrimitive.Trigger;
687
- var TooltipContent = React7.forwardRef(({ className, sideOffset = 4, container, animated = true, ...props }, ref) => {
1971
+ var TooltipContent = React9.forwardRef(({ className, sideOffset = 4, container, animated = true, ...props }, ref) => {
688
1972
  const resolved = usePortalContainer(container);
689
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(TooltipPrimitive.Portal, { container: resolved ?? null, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1973
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TooltipPrimitive.Portal, { container: resolved ?? null, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
690
1974
  TooltipPrimitive.Content,
691
1975
  {
692
1976
  ref,
@@ -704,7 +1988,7 @@ var TooltipContent = React7.forwardRef(({ className, sideOffset = 4, container,
704
1988
  TooltipContent.displayName = TooltipPrimitive.Content.displayName;
705
1989
 
706
1990
  // src/data-table/MatrxUuidCell.tsx
707
- var import_jsx_runtime12 = require("react/jsx-runtime");
1991
+ var import_jsx_runtime14 = require("react/jsx-runtime");
708
1992
  var SHORT_LEN = 8;
709
1993
  function shortUuid(id, len = SHORT_LEN) {
710
1994
  return id.slice(0, len);
@@ -743,18 +2027,18 @@ function MatrxUuidCell({
743
2027
  }) {
744
2028
  const { resolveEntityDoors, ResourcePeek } = useMatrxDataTableHost();
745
2029
  const { notify, notice } = useTableNotice();
746
- const [copied, setCopied] = (0, import_react4.useState)(false);
747
- const [opening, setOpening] = (0, import_react4.useState)(false);
748
- const [peekOpen, setPeekOpen] = (0, import_react4.useState)(false);
749
- const timer = (0, import_react4.useRef)(null);
750
- (0, import_react4.useEffect)(
2030
+ const [copied, setCopied] = (0, import_react3.useState)(false);
2031
+ const [opening, setOpening] = (0, import_react3.useState)(false);
2032
+ const [peekOpen, setPeekOpen] = (0, import_react3.useState)(false);
2033
+ const timer = (0, import_react3.useRef)(null);
2034
+ (0, import_react3.useEffect)(
751
2035
  () => () => {
752
2036
  if (timer.current) clearTimeout(timer.current);
753
2037
  },
754
2038
  []
755
2039
  );
756
2040
  if (!value) {
757
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "text-muted-foreground/40", children: "\u2014" });
2041
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "text-muted-foreground/40", children: "\u2014" });
758
2042
  }
759
2043
  const doors = token ? resolveEntityDoors?.(token, value, href) ?? null : null;
760
2044
  const resolvedHref = doors?.href ?? href ?? null;
@@ -797,13 +2081,13 @@ function MatrxUuidCell({
797
2081
  };
798
2082
  const idNode = (() => {
799
2083
  if (forbidden) {
800
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "inline-flex min-w-0 items-center gap-1 font-mono text-xs text-muted-foreground/70 tabular-nums", children: [
801
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "min-w-0 truncate", children: display }),
802
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ShieldOff, { className: "h-3 w-3 shrink-0 opacity-60", "aria-hidden": true })
2084
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("span", { className: "inline-flex min-w-0 items-center gap-1 font-mono text-xs text-muted-foreground/70 tabular-nums", children: [
2085
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "min-w-0 truncate", children: display }),
2086
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ShieldOff, { className: "h-3 w-3 shrink-0 opacity-60", "aria-hidden": true })
803
2087
  ] });
804
2088
  }
805
2089
  if (onOpen) {
806
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
2090
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
807
2091
  "button",
808
2092
  {
809
2093
  type: "button",
@@ -812,14 +2096,14 @@ function MatrxUuidCell({
812
2096
  disabled: opening,
813
2097
  className: "inline-flex min-w-0 items-center gap-1 font-mono text-xs text-sky-600 hover:underline dark:text-sky-400 disabled:opacity-60",
814
2098
  children: [
815
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "min-w-0 truncate tabular-nums", children: display }),
816
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(PanelRight, { className: "h-3 w-3 shrink-0 opacity-50" })
2099
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "min-w-0 truncate tabular-nums", children: display }),
2100
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(PanelRight, { className: "h-3 w-3 shrink-0 opacity-50" })
817
2101
  ]
818
2102
  }
819
2103
  );
820
2104
  }
821
2105
  if (resolvedHref) {
822
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
2106
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
823
2107
  "a",
824
2108
  {
825
2109
  href: resolvedHref,
@@ -829,15 +2113,15 @@ function MatrxUuidCell({
829
2113
  onClick: stop,
830
2114
  className: "inline-flex min-w-0 items-center gap-1 font-mono text-xs text-sky-600 hover:underline dark:text-sky-400",
831
2115
  children: [
832
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "min-w-0 truncate tabular-nums", children: display }),
833
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ExternalLink, { className: "h-3 w-3 shrink-0 opacity-50" })
2116
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "min-w-0 truncate tabular-nums", children: display }),
2117
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ExternalLink, { className: "h-3 w-3 shrink-0 opacity-50" })
834
2118
  ]
835
2119
  }
836
2120
  );
837
2121
  }
838
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "min-w-0 truncate font-mono text-xs text-muted-foreground tabular-nums select-all", children: display });
2122
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "min-w-0 truncate font-mono text-xs text-muted-foreground tabular-nums select-all", children: display });
839
2123
  })();
840
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
2124
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
841
2125
  "span",
842
2126
  {
843
2127
  "data-matrx-cell-control": true,
@@ -847,11 +2131,11 @@ function MatrxUuidCell({
847
2131
  ),
848
2132
  onClick: stop,
849
2133
  children: [
850
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(TooltipProvider, { delayDuration: 200, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Tooltip, { children: [
851
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "inline-flex min-w-0 max-w-full items-center", children: idNode }) }),
852
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(TooltipContent, { side: "top", className: "max-w-sm break-all font-mono", children: forbidden ? `No access \xB7 ${tip}` : tip })
2134
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(TooltipProvider, { delayDuration: 200, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(Tooltip, { children: [
2135
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "inline-flex min-w-0 max-w-full items-center", children: idNode }) }),
2136
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(TooltipContent, { side: "top", className: "max-w-sm break-all font-mono", children: forbidden ? `No access \xB7 ${tip}` : tip })
853
2137
  ] }) }),
854
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2138
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
855
2139
  "button",
856
2140
  {
857
2141
  type: "button",
@@ -862,10 +2146,10 @@ function MatrxUuidCell({
862
2146
  "inline-flex h-4 w-4 shrink-0 items-center justify-center rounded text-muted-foreground transition-colors hover:text-foreground focus:outline-none",
863
2147
  copied && "text-primary"
864
2148
  ),
865
- children: copied ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Check, { className: "h-3 w-3" }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Copy, { className: "h-3 w-3" })
2149
+ children: copied ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Check, { className: "h-3 w-3" }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Copy, { className: "h-3 w-3" })
866
2150
  }
867
2151
  ),
868
- canPeek ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2152
+ canPeek ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
869
2153
  "button",
870
2154
  {
871
2155
  type: "button",
@@ -876,10 +2160,10 @@ function MatrxUuidCell({
876
2160
  "aria-label": `Quick look at ${label ?? "record"}`,
877
2161
  title: `Quick look at ${label ?? "record"}`,
878
2162
  className: "inline-flex h-4 w-4 shrink-0 items-center justify-center rounded text-muted-foreground transition-colors hover:text-foreground focus:outline-none",
879
- children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Lightbulb, { className: "h-3 w-3" })
2163
+ children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Lightbulb, { className: "h-3 w-3" })
880
2164
  }
881
2165
  ) : null,
882
- onOpen && resolvedHref && !forbidden ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2166
+ onOpen && resolvedHref && !forbidden ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
883
2167
  "a",
884
2168
  {
885
2169
  href: resolvedHref,
@@ -889,12 +2173,12 @@ function MatrxUuidCell({
889
2173
  "aria-label": `Open ${label ?? "record"} in a new tab`,
890
2174
  title: `Open ${label ?? "record"} in a new tab`,
891
2175
  className: "inline-flex h-4 w-4 shrink-0 items-center justify-center rounded text-muted-foreground transition-colors hover:text-foreground focus:outline-none",
892
- children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ExternalLink, { className: "h-3 w-3" })
2176
+ children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ExternalLink, { className: "h-3 w-3" })
893
2177
  }
894
2178
  ) : null,
895
2179
  trailing,
896
2180
  notice,
897
- canPeek && peekOpen && ResourcePeek ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2181
+ canPeek && peekOpen && ResourcePeek ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
898
2182
  ResourcePeek,
899
2183
  {
900
2184
  kind: doors?.peekKind ?? token ?? "record",
@@ -914,7 +2198,7 @@ function isUuidValue(value) {
914
2198
  }
915
2199
 
916
2200
  // src/data-table/DataRowInspector.tsx
917
- var import_jsx_runtime13 = require("react/jsx-runtime");
2201
+ var import_jsx_runtime15 = require("react/jsx-runtime");
918
2202
  var noFieldToken = () => null;
919
2203
  function formatValue(value) {
920
2204
  if (value == null) return "\u2014";
@@ -943,7 +2227,7 @@ function DataRowInspector({
943
2227
  tokenForField = noFieldToken
944
2228
  }) {
945
2229
  const entries = isPlainObject(row) ? Object.entries(row) : [["value", row]];
946
- const fieldButtons = (key, value) => fieldCopy ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "absolute right-1 top-1 opacity-0 transition-opacity focus-within:opacity-100 group-hover/field:opacity-100", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2230
+ const fieldButtons = (key, value) => fieldCopy ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "absolute right-1 top-1 opacity-0 transition-opacity focus-within:opacity-100 group-hover/field:opacity-100", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
947
2231
  CopyButtons,
948
2232
  {
949
2233
  size: "xs",
@@ -958,21 +2242,21 @@ function DataRowInspector({
958
2242
  })
959
2243
  }
960
2244
  ) }) : null;
961
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
2245
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
962
2246
  "div",
963
2247
  {
964
2248
  className: cn("flex h-full min-h-0 flex-col overflow-hidden", className),
965
2249
  children: [
966
- title ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "shrink-0 border-b border-border px-3 py-2 text-sm font-medium", children: title }) : null,
967
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "min-h-0 flex-1 overflow-auto p-3", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("dl", { className: "space-y-2", children: entries.map(([key, value]) => {
2250
+ title ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "shrink-0 border-b border-border px-3 py-2 text-sm font-medium", children: title }) : null,
2251
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "min-h-0 flex-1 overflow-auto p-3", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("dl", { className: "space-y-2", children: entries.map(([key, value]) => {
968
2252
  if (isUuidValue(value)) {
969
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
2253
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
970
2254
  "div",
971
2255
  {
972
2256
  className: "group/field relative grid grid-cols-[minmax(7rem,9rem)_1fr] gap-2 rounded-md border border-border/60 bg-muted/20 px-2.5 py-2",
973
2257
  children: [
974
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("dt", { className: "truncate text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: key }),
975
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("dd", { className: "min-w-0", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2258
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("dt", { className: "truncate text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: key }),
2259
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("dd", { className: "min-w-0", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
976
2260
  MatrxUuidCell,
977
2261
  {
978
2262
  value,
@@ -987,13 +2271,13 @@ function DataRowInspector({
987
2271
  }
988
2272
  const formatted = formatValue(value);
989
2273
  const multiline = formatted.includes("\n") || formatted.length > 80;
990
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
2274
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
991
2275
  "div",
992
2276
  {
993
2277
  className: "group/field relative grid grid-cols-[minmax(7rem,9rem)_1fr] gap-2 rounded-md border border-border/60 bg-muted/20 py-2 pl-2.5 pr-12",
994
2278
  children: [
995
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("dt", { className: "truncate text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: key }),
996
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2279
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("dt", { className: "truncate text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: key }),
2280
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
997
2281
  "dd",
998
2282
  {
999
2283
  className: cn(