@ai-matrx/design-system 0.18.9 → 0.18.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/dist/content-transfer/alchemy.svg +1 -1
  3. package/dist/content-transfer/icon.cjs +3 -1
  4. package/dist/content-transfer/icon.cjs.map +1 -1
  5. package/dist/content-transfer/icon.d.cts +3 -2
  6. package/dist/content-transfer/icon.d.ts +3 -2
  7. package/dist/content-transfer/icon.js +3 -1
  8. package/dist/content-transfer/icon.js.map +1 -1
  9. package/dist/content-transfer.cjs +442 -447
  10. package/dist/content-transfer.cjs.map +1 -1
  11. package/dist/content-transfer.css +130 -54
  12. package/dist/content-transfer.d.cts +5 -1
  13. package/dist/content-transfer.d.ts +5 -1
  14. package/dist/content-transfer.js +467 -472
  15. package/dist/content-transfer.js.map +1 -1
  16. package/dist/data-table/copy-helpers.d.cts +1 -1
  17. package/dist/data-table/copy-helpers.d.ts +1 -1
  18. package/dist/data-table/copy-types.cjs.map +1 -1
  19. package/dist/data-table/copy-types.d.cts +1 -1
  20. package/dist/data-table/copy-types.d.ts +1 -1
  21. package/dist/data-table/data-row-inspector.cjs +444 -446
  22. package/dist/data-table/data-row-inspector.cjs.map +1 -1
  23. package/dist/data-table/data-row-inspector.js +489 -491
  24. package/dist/data-table/data-row-inspector.js.map +1 -1
  25. package/dist/data-table/data-row-window.cjs +444 -446
  26. package/dist/data-table/data-row-window.cjs.map +1 -1
  27. package/dist/data-table/data-row-window.js +489 -491
  28. package/dist/data-table/data-row-window.js.map +1 -1
  29. package/dist/data-table/filter-engine.d.cts +1 -1
  30. package/dist/data-table/filter-engine.d.ts +1 -1
  31. package/dist/data-table/host.cjs.map +1 -1
  32. package/dist/data-table/host.d.cts +17 -1
  33. package/dist/data-table/host.d.ts +17 -1
  34. package/dist/data-table/host.js.map +1 -1
  35. package/dist/data-table/index.cjs +1524 -1011
  36. package/dist/data-table/index.cjs.map +1 -1
  37. package/dist/data-table/index.d.cts +25 -4
  38. package/dist/data-table/index.d.ts +25 -4
  39. package/dist/data-table/index.js +1560 -1047
  40. package/dist/data-table/index.js.map +1 -1
  41. package/dist/data-table/infer-filter.d.cts +1 -1
  42. package/dist/data-table/infer-filter.d.ts +1 -1
  43. package/dist/data-table/layered-filters.d.cts +1 -1
  44. package/dist/data-table/layered-filters.d.ts +1 -1
  45. package/dist/data-table/pagination.cjs +5 -5
  46. package/dist/data-table/pagination.cjs.map +1 -1
  47. package/dist/data-table/pagination.js +5 -5
  48. package/dist/data-table/pagination.js.map +1 -1
  49. package/dist/data-table/query-control.d.cts +1 -1
  50. package/dist/data-table/query-control.d.ts +1 -1
  51. package/dist/data-table/types.cjs.map +1 -1
  52. package/dist/data-table/types.d.cts +1 -1
  53. package/dist/data-table/types.d.ts +1 -1
  54. package/dist/data-table/url-state.d.cts +1 -1
  55. package/dist/data-table/url-state.d.ts +1 -1
  56. package/dist/data-table/uuid-cell.cjs.map +1 -1
  57. package/dist/data-table/uuid-cell.js.map +1 -1
  58. package/dist/data-table/xlsx.d.cts +1 -1
  59. package/dist/data-table/xlsx.d.ts +1 -1
  60. package/dist/index.cjs +5 -5
  61. package/dist/index.cjs.map +1 -1
  62. package/dist/index.js +5 -5
  63. package/dist/index.js.map +1 -1
  64. package/dist/styles.css +4 -0
  65. package/dist/tokens.css +2 -0
  66. package/dist/{types-cH8oLqUx.d.ts → types-BuDKVpeF.d.ts} +47 -3
  67. package/dist/{types-0CNCWvdK.d.cts → types-Dqcb7jXO.d.cts} +47 -3
  68. package/package.json +2 -2
@@ -181,48 +181,6 @@ function XIcon(props) {
181
181
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "m6 6 12 12" })
182
182
  ] });
183
183
  }
184
- function radixProps(props) {
185
- return {
186
- xmlns: "http://www.w3.org/2000/svg",
187
- viewBox: "0 0 15 15",
188
- width: 15,
189
- height: 15,
190
- fill: "none",
191
- "aria-hidden": true,
192
- ...props
193
- };
194
- }
195
- function CheckIcon(props) {
196
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { ...radixProps(props), children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
197
- "path",
198
- {
199
- 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",
200
- fill: "currentColor",
201
- fillRule: "evenodd",
202
- clipRule: "evenodd"
203
- }
204
- ) });
205
- }
206
- function DotFilledIcon(props) {
207
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { ...radixProps(props), children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
208
- "path",
209
- {
210
- 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",
211
- fill: "currentColor"
212
- }
213
- ) });
214
- }
215
- function RadixChevronRightIcon(props) {
216
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { ...radixProps(props), children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
217
- "path",
218
- {
219
- 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",
220
- fill: "currentColor",
221
- fillRule: "evenodd",
222
- clipRule: "evenodd"
223
- }
224
- ) });
225
- }
226
184
 
227
185
  // src/portal-container.tsx
228
186
  var React2 = __toESM(require("react"), 1);
@@ -486,135 +444,49 @@ var DialogDescription = React5.forwardRef(({ className, ...props }, ref) => /* @
486
444
  ));
487
445
  DialogDescription.displayName = DialogPrimitive.Description.displayName;
488
446
 
489
- // src/dropdown-menu.tsx
490
- var DropdownMenuPrimitive = __toESM(require("@radix-ui/react-dropdown-menu"), 1);
447
+ // src/popover.tsx
448
+ var PopoverPrimitive = __toESM(require("@radix-ui/react-popover"), 1);
491
449
  var React6 = __toESM(require("react"), 1);
492
450
  var import_jsx_runtime6 = require("react/jsx-runtime");
493
- var DropdownMenu = DropdownMenuPrimitive.Root;
494
- var DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
495
- 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";
496
- 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";
497
- 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";
498
- var DropdownMenuSubTrigger = React6.forwardRef(({ className, inset, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
499
- DropdownMenuPrimitive.SubTrigger,
500
- {
501
- ref,
502
- "data-slot": "dropdown-menu-sub-trigger",
503
- className: cn(
504
- "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",
505
- inset && "pl-8",
506
- className
507
- ),
508
- ...props,
509
- children: [
510
- children,
511
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(RadixChevronRightIcon, { className: "ml-auto h-4 w-4" })
512
- ]
513
- }
514
- ));
515
- DropdownMenuSubTrigger.displayName = DropdownMenuPrimitive.SubTrigger.displayName;
516
- var DropdownMenuSubContent = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
517
- DropdownMenuPrimitive.SubContent,
518
- {
519
- ref,
520
- "data-slot": "dropdown-menu-sub-content",
521
- className: cn(MENU_SURFACE_CLASS, "shadow-lg", MOTION_POPPER, className),
522
- ...props
523
- }
524
- ));
525
- DropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName;
526
- var DropdownMenuContent = React6.forwardRef(({ className, sideOffset = 4, container, ...props }, ref) => {
527
- const portalContainer = usePortalContainer(container);
528
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DropdownMenuPrimitive.Portal, { container: portalContainer, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
529
- DropdownMenuPrimitive.Content,
530
- {
531
- ref,
532
- "data-slot": "dropdown-menu-content",
533
- sideOffset,
534
- className: cn(
535
- MENU_SURFACE_CLASS,
536
- "shadow-md",
537
- MOTION_POPPER,
538
- className
539
- ),
540
- ...props
541
- }
542
- ) });
543
- });
544
- DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
545
- var DropdownMenuItem = React6.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
546
- DropdownMenuPrimitive.Item,
547
- {
548
- ref,
549
- "data-slot": "dropdown-menu-item",
550
- className: cn(MENU_ITEM_CLASS, inset && "pl-8", className),
551
- ...props
552
- }
553
- ));
554
- DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
555
- var DropdownMenuCheckboxItem = React6.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
556
- DropdownMenuPrimitive.CheckboxItem,
557
- {
558
- ref,
559
- "data-slot": "dropdown-menu-checkbox-item",
560
- className: cn(MENU_INDICATOR_ITEM_CLASS, className),
561
- ...props,
562
- children: [
563
- /* @__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" }) }) }),
564
- children
565
- ]
566
- }
567
- ));
568
- DropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName;
569
- var DropdownMenuRadioItem = React6.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
570
- DropdownMenuPrimitive.RadioItem,
571
- {
572
- ref,
573
- "data-slot": "dropdown-menu-radio-item",
574
- className: cn(MENU_INDICATOR_ITEM_CLASS, className),
575
- ...props,
576
- children: [
577
- /* @__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" }) }) }),
578
- children
579
- ]
580
- }
581
- ));
582
- DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
583
- var DropdownMenuLabel = React6.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
584
- DropdownMenuPrimitive.Label,
585
- {
586
- ref,
587
- "data-slot": "dropdown-menu-label",
588
- className: cn("px-2 py-1.5 text-sm font-semibold", inset && "pl-8", className),
589
- ...props
590
- }
591
- ));
592
- DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
593
- var DropdownMenuSeparator = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
594
- DropdownMenuPrimitive.Separator,
595
- {
596
- ref,
597
- "data-slot": "dropdown-menu-separator",
598
- className: cn("-mx-1 my-1 h-px bg-muted", className),
599
- ...props
600
- }
601
- ));
602
- DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
603
- var DropdownMenuShortcut = ({
604
- className,
605
- ...props
606
- }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
607
- "span",
608
- {
609
- "data-slot": "dropdown-menu-shortcut",
610
- className: cn("ml-auto text-xs tracking-widest opacity-60", className),
451
+ var Popover = PopoverPrimitive.Root;
452
+ var PopoverTrigger = PopoverPrimitive.Trigger;
453
+ var PopoverContent = React6.forwardRef(
454
+ ({
455
+ className,
456
+ align = "center",
457
+ sideOffset = 4,
458
+ container,
459
+ animated = true,
611
460
  ...props
461
+ }, ref) => {
462
+ const portalContainer = usePortalContainer(container);
463
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PopoverPrimitive.Portal, { container: portalContainer, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
464
+ PopoverPrimitive.Content,
465
+ {
466
+ ref,
467
+ align,
468
+ sideOffset,
469
+ className: cn(
470
+ // Cap to the viewport space Radix measured and scroll — a popover taller
471
+ // than the screen must never trap the user with unreachable content.
472
+ // z must EQUAL the dialog layer (z-[10000]), never exceed it: with equal
473
+ // z, DOM portal order decides, so a dialog opened FROM a popover stacks
474
+ // above it, and a popover opened from a dialog still stacks above the
475
+ // dialog. z-[10001] buried dialogs behind fullscreen popovers.
476
+ "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",
477
+ animated && MOTION_POPPER,
478
+ className
479
+ ),
480
+ ...props
481
+ }
482
+ ) });
612
483
  }
613
484
  );
614
- DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
485
+ PopoverContent.displayName = PopoverPrimitive.Content.displayName;
615
486
 
616
487
  // src/content-transfer/icon.ts
617
- var ALCHEMY_GLYPH_SVG = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4.5 5.5h8v11h-8z"/><path d="M8.5 9.5h8v9h-8z"/><path d="m18.5 3 .65 1.85L21 5.5l-1.85.65L18.5 8l-.65-1.85L16 5.5l1.85-.65z"/></svg>';
488
+ var ALCHEMY_GLYPH_PATHS = ["M9 3h6", "M10 3v6l-5.2 8.7A2 2 0 0 0 6.5 21h11a2 2 0 0 0 1.7-3.3L14 9V3", "M8 15h8"];
489
+ var ALCHEMY_GLYPH_SVG = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">${ALCHEMY_GLYPH_PATHS.map((d) => `<path d="${d}"/>`).join("")}</svg>`;
618
490
 
619
491
  // src/content-transfer/matrx-copy.tsx
620
492
  var React7 = __toESM(require("react"), 1);
@@ -765,7 +637,7 @@ function MatrxCopyMenuSession(props) {
765
637
  if (aiVisible && props.aiCustom)
766
638
  actions.push({
767
639
  id: "configure-source",
768
- label: props.aiCustom.label ?? "Customize source\u2026",
640
+ label: props.aiCustom.label ?? "Customize source",
769
641
  ...props.aiCustom.hint ? { hint: props.aiCustom.hint } : {},
770
642
  supports: () => true,
771
643
  run: async () => {
@@ -776,7 +648,7 @@ function MatrxCopyMenuSession(props) {
776
648
  if (aiVisible && props.groomer)
777
649
  actions.push({
778
650
  id: "groom-source",
779
- label: "Customize sections\u2026",
651
+ label: "Customize sections",
780
652
  supports: () => true,
781
653
  run: async () => {
782
654
  setConfiguration({ groomer: props.groomer() });
@@ -790,6 +662,7 @@ function MatrxCopyMenuSession(props) {
790
662
  label: item.label,
791
663
  supports: () => true,
792
664
  ...item.build && !item.onSelect ? {
665
+ placement: "download",
793
666
  source: make(
794
667
  `export:${item.id}`,
795
668
  async () => {
@@ -870,10 +743,11 @@ function MatrxCopyMenuSession(props) {
870
743
  label: props.label,
871
744
  variants,
872
745
  actions,
746
+ sourceFormats: Boolean(source),
873
747
  hide: [
874
748
  ...!copyVisible || !source ? ["copy"] : [],
875
749
  ...!aiVisible || !source ? ["prepare"] : [],
876
- ...!exportVisible || !source ? ["download"] : []
750
+ ...!exportVisible ? ["download"] : []
877
751
  ],
878
752
  formatSources: {
879
753
  ...human ? { plain: human, markdown: humanMarkdown, html: humanMarkdown } : {},
@@ -884,7 +758,8 @@ function MatrxCopyMenuSession(props) {
884
758
  className: cn(
885
759
  props.className,
886
760
  props.size === "xs" && "matrx-alchemy-xs",
887
- props.size === "sm" && "matrx-alchemy-sm"
761
+ props.size === "sm" && "matrx-alchemy-sm",
762
+ props.size === "toolbar" && "matrx-alchemy-toolbar-target"
888
763
  ),
889
764
  ...props.stopPropagation !== void 0 ? { stopPropagation: props.stopPropagation } : {}
890
765
  }
@@ -989,127 +864,132 @@ function SourceConfiguration({
989
864
  event.preventDefault();
990
865
  if (!handingOff.current) restoreFocus();
991
866
  },
992
- className: "matrx-alchemy-workspace",
867
+ className: "matrx-alchemy-workspace matrx-alchemy-configuration",
993
868
  children: [
994
869
  /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(DialogHeader, { children: [
995
870
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(DialogTitle, { children: title }),
996
871
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(DialogDescription, { children: custom?.dialogDescription ?? "Choose the source detail, then prepare, edit, summarize, copy or export it in Alchemy." })
997
872
  ] }),
998
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "matrx-alchemy-main matrx-alchemy-toolbar", children: [
999
- custom?.options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { children: [
1000
- option.label,
1001
- "hint" in option && option.hint ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("small", { children: option.hint }) : null,
1002
- option.kind === "toggle" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1003
- "input",
1004
- {
1005
- type: "checkbox",
1006
- checked: Boolean(values[option.key]),
1007
- onChange: (event) => setValues({ ...values, [option.key]: event.target.checked })
1008
- }
1009
- ) : option.kind === "preset" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1010
- "select",
1011
- {
1012
- value: Number(values[option.key]),
1013
- onChange: (event) => setValues({
1014
- ...values,
1015
- [option.key]: Number(event.target.value)
1016
- }),
1017
- children: option.options.map((choice) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: choice.value, children: choice.label }, choice.value))
1018
- }
1019
- ) : option.kind === "slider" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
1020
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
873
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "matrx-alchemy-workspace-body", children: [
874
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "matrx-alchemy-main matrx-alchemy-toolbar", children: [
875
+ custom?.options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { children: [
876
+ option.label,
877
+ "hint" in option && option.hint ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("small", { children: option.hint }) : null,
878
+ option.kind === "toggle" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1021
879
  "input",
1022
880
  {
1023
- type: "range",
1024
- min: 0,
1025
- max: Math.max(0, option.stops.length - 1),
1026
- step: 1,
1027
- value: option.stops.indexOf(Number(values[option.key])),
1028
- onChange: (event) => setValues({
1029
- ...values,
1030
- [option.key]: option.stops[Number(event.target.value)]
1031
- })
881
+ type: "checkbox",
882
+ checked: Boolean(values[option.key]),
883
+ onChange: (event) => setValues({ ...values, [option.key]: event.target.checked })
1032
884
  }
1033
- ),
1034
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: option.formatValue(Number(values[option.key])) })
1035
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
1036
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1037
- "input",
885
+ ) : option.kind === "preset" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
886
+ "select",
1038
887
  {
1039
- type: "number",
1040
- min: option.min,
1041
- step: option.step,
1042
888
  value: Number(values[option.key]),
1043
889
  onChange: (event) => setValues({
1044
890
  ...values,
1045
891
  [option.key]: Number(event.target.value)
1046
- })
892
+ }),
893
+ children: option.options.map((choice) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: choice.value, children: choice.label }, choice.value))
1047
894
  }
1048
- ),
1049
- option.presets?.map((preset) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
895
+ ) : option.kind === "slider" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
896
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
897
+ "input",
898
+ {
899
+ type: "range",
900
+ min: 0,
901
+ max: Math.max(0, option.stops.length - 1),
902
+ step: 1,
903
+ value: option.stops.indexOf(Number(values[option.key])),
904
+ onChange: (event) => setValues({
905
+ ...values,
906
+ [option.key]: option.stops[Number(event.target.value)]
907
+ })
908
+ }
909
+ ),
910
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: option.formatValue(Number(values[option.key])) })
911
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
912
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
913
+ "input",
914
+ {
915
+ type: "number",
916
+ min: option.min,
917
+ step: option.step,
918
+ value: Number(values[option.key]),
919
+ onChange: (event) => setValues({
920
+ ...values,
921
+ [option.key]: Number(event.target.value)
922
+ })
923
+ }
924
+ ),
925
+ option.presets?.map((preset) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
926
+ Button,
927
+ {
928
+ type: "button",
929
+ variant: "ghost",
930
+ className: "matrx-alchemy-workspace-secondary",
931
+ onClick: () => setValues({ ...values, [option.key]: preset.value }),
932
+ children: preset.label
933
+ },
934
+ preset.value
935
+ ))
936
+ ] })
937
+ ] }, option.key)),
938
+ groomer ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
939
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { children: ["full", "compact", "brief"].map((level) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1050
940
  Button,
1051
941
  {
1052
942
  type: "button",
1053
943
  variant: "ghost",
1054
- onClick: () => setValues({ ...values, [option.key]: preset.value }),
1055
- children: preset.label
944
+ className: "matrx-alchemy-workspace-secondary",
945
+ onClick: () => setSections(
946
+ Object.fromEntries(
947
+ groomer.sections.map((section) => [
948
+ section.id,
949
+ level === "brief" && section.cuttable ? "off" : level
950
+ ])
951
+ )
952
+ ),
953
+ children: level
1056
954
  },
1057
- preset.value
1058
- ))
1059
- ] })
1060
- ] }, option.key)),
1061
- groomer ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
1062
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { children: ["full", "compact", "brief"].map((level) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1063
- Button,
1064
- {
1065
- type: "button",
1066
- variant: "ghost",
1067
- onClick: () => setSections(
1068
- Object.fromEntries(
1069
- groomer.sections.map((section) => [
1070
- section.id,
1071
- level === "brief" && section.cuttable ? "off" : level
1072
- ])
1073
- )
955
+ level
956
+ )) }),
957
+ groomer.sections.map((section) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { children: [
958
+ section.title,
959
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
960
+ "select",
961
+ {
962
+ value: sections[section.id],
963
+ onChange: (event) => setSections({
964
+ ...sections,
965
+ [section.id]: event.target.value
966
+ }),
967
+ children: [
968
+ ["full", "compact", "brief"].map((level) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: level, children: section.levelLabels?.[level] ?? level }, level)),
969
+ section.cuttable ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: "off", children: "Exclude" }) : null
970
+ ]
971
+ }
1074
972
  ),
1075
- children: level
1076
- },
1077
- level
1078
- )) }),
1079
- groomer.sections.map((section) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { children: [
1080
- section.title,
1081
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1082
- "select",
1083
- {
1084
- value: sections[section.id],
1085
- onChange: (event) => setSections({
1086
- ...sections,
1087
- [section.id]: event.target.value
1088
- }),
1089
- children: [
1090
- ["full", "compact", "brief"].map((level) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: level, children: section.levelLabels?.[level] ?? level }, level)),
1091
- section.cuttable ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: "off", children: "Exclude" }) : null
1092
- ]
1093
- }
1094
- ),
1095
- section.description ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: section.description }) : null
1096
- ] }, section.id))
1097
- ] }) : null
1098
- ] }),
1099
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("p", { children: [
1100
- text.length.toLocaleString(),
1101
- " characters \xB7 approximately",
1102
- " ",
1103
- Math.ceil(text.length / 4).toLocaleString(),
1104
- " tokens"
973
+ section.description ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: section.description }) : null
974
+ ] }, section.id))
975
+ ] }) : null
976
+ ] }),
977
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("p", { children: [
978
+ text.length.toLocaleString(),
979
+ " characters \xB7 approximately",
980
+ " ",
981
+ Math.ceil(text.length / 4).toLocaleString(),
982
+ " tokens"
983
+ ] }),
984
+ error || buildError ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { role: "alert", children: error ?? buildError }) : null
1105
985
  ] }),
1106
- error || buildError ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { role: "alert", children: error ?? buildError }) : null,
1107
986
  /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(DialogFooter, { children: [
1108
987
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1109
988
  Button,
1110
989
  {
1111
990
  type: "button",
1112
991
  variant: "ghost",
992
+ className: "matrx-alchemy-workspace-secondary",
1113
993
  disabled: busy,
1114
994
  onClick: onClose,
1115
995
  children: "Cancel"
@@ -1119,6 +999,7 @@ function SourceConfiguration({
1119
999
  Button,
1120
1000
  {
1121
1001
  type: "button",
1002
+ className: "matrx-alchemy-workspace-primary",
1122
1003
  disabled: busy || !prepared || Boolean(buildError),
1123
1004
  onClick: async () => {
1124
1005
  if (!prepared) return;
@@ -1207,11 +1088,7 @@ function groomerPresetVariants(getConfig) {
1207
1088
  // src/content-transfer/index.tsx
1208
1089
  var import_jsx_runtime8 = require("react/jsx-runtime");
1209
1090
  function AlchemyGlyph(props) {
1210
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", ...props, children: [
1211
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M4.5 5.5h8v11h-8z" }),
1212
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M8.5 9.5h8v9h-8z" }),
1213
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "m18.5 3 .65 1.85L21 5.5l-1.85.65L18.5 8l-.65-1.85L16 5.5l1.85-.65z" })
1214
- ] });
1091
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", ...props, children: ALCHEMY_GLYPH_PATHS.map((d) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d }, d)) });
1215
1092
  }
1216
1093
  var CapabilityContext = React8.createContext({});
1217
1094
  function ContentTransferCapabilitiesProvider({ value, children }) {
@@ -1232,6 +1109,62 @@ function MenuPresentation({ label, hint, icon: Icon }) {
1232
1109
  ] })
1233
1110
  ] });
1234
1111
  }
1112
+ function PaletteGlyph({ format, ai = false, file = false, kind }) {
1113
+ if (kind === "ai-copy") return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("svg", { className: "matrx-alchemy-palette-glyph", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
1114
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("rect", { x: "5", y: "5", width: "11", height: "14", rx: "2" }),
1115
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M9 3h6a2 2 0 0 1 2 2v10" }),
1116
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "m18.5 3 .55 1.45L20.5 5l-1.45.55L18.5 7l-.55-1.45L16.5 5l1.45-.55z" })
1117
+ ] });
1118
+ if (kind === "sliders") return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("svg", { className: "matrx-alchemy-palette-glyph", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
1119
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M4 6h16M4 12h16M4 18h16" }),
1120
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M8 3v6M16 9v6M10 15v6" })
1121
+ ] });
1122
+ if (ai) return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("svg", { className: "matrx-alchemy-palette-glyph", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
1123
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M12 5a3 3 0 1 0-5.997.125A4 4 0 0 0 3.5 10.9a4 4 0 0 0 .556 6.588A4 4 0 0 0 12 19" }),
1124
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M12 5a3 3 0 1 1 5.997.125 4 4 0 0 1 2.503 5.775 4 4 0 0 1-.556 6.588A4 4 0 0 1 12 19" }),
1125
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M12 5v14M8 9h1M15 9h1M8 15h1M15 15h1" })
1126
+ ] });
1127
+ if (file) return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("svg", { className: "matrx-alchemy-palette-glyph", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
1128
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M6 3h8l4 4v14H6z" }),
1129
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M14 3v5h5M9 13h6M9 17h6" })
1130
+ ] });
1131
+ const path = format === "json" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
1132
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M9 4C7 4 7 7 5 7v3c2 0 2 1 2 2s0 2-2 2v3c2 0 2 3 4 3" }),
1133
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M15 4c2 0 2 3 4 3v3c-2 0-2 1-2 2s0 2 2 2v3c-2 0-2 3-4 3" })
1134
+ ] }) : format === "compact-json" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
1135
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "m14 10 7-7" }),
1136
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M20 10h-6V4" }),
1137
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "m3 21 7-7" }),
1138
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M4 14h6v6" })
1139
+ ] }) : format === "csv" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
1140
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("rect", { x: "4", y: "4", width: "16", height: "16", rx: "1" }),
1141
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M4 10h16M10 4v16" })
1142
+ ] }) : format === "tsv" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
1143
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" }),
1144
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M14 2v6h6M8 13h2M14 13h2M8 17h2M14 17h2" })
1145
+ ] }) : format === "xlsx" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
1146
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" }),
1147
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M14 2v6h6M8 13h8M8 17h8M12 11v8" })
1148
+ ] }) : format === "markdown" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
1149
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5z" }),
1150
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M14 2v6h6M10 13l-2 2 2 2M14 17l2-2-2-2" })
1151
+ ] }) : format === "html" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_jsx_runtime8.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M15 6h6M3 6h7M3 12h18M3 18h12" }) }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_jsx_runtime8.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M4 7V4h16v3M9 20h6M12 4v16" }) });
1152
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("svg", { className: "matrx-alchemy-palette-glyph", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: path });
1153
+ }
1154
+ function PaletteRows({ title, items, onRun, extra, ai = false, glyphKind, fallbackHint }) {
1155
+ if (!items.length && !extra) return null;
1156
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("section", { className: "matrx-alchemy-palette-section", children: [
1157
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h3", { children: title }),
1158
+ items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("button", { type: "button", className: cn("matrx-alchemy-palette-row", ai && "matrx-alchemy-palette-row-ai"), "aria-label": item.ariaLabel, onClick: () => onRun?.(item), children: [
1159
+ item.icon ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(item.icon, { className: "matrx-alchemy-menu-icon" }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(PaletteGlyph, { ai, ...glyphKind ? { kind: glyphKind } : {} }),
1160
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { children: [
1161
+ item.copyLabel ?? item.label,
1162
+ item.hint ?? fallbackHint ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("small", { className: "matrx-alchemy-menu-hint", children: item.hint ?? fallbackHint }) : null
1163
+ ] })
1164
+ ] }, item.id)),
1165
+ extra
1166
+ ] });
1167
+ }
1235
1168
  var LABEL = { plain: "Plain text", markdown: "Markdown", html: "Formatted", json: "JSON", "compact-json": "Compact JSON", csv: "CSV", tsv: "Google Sheets", xlsx: "Excel workbook" };
1236
1169
  var BUILT_INS = Object.freeze(Object.keys(LABEL).map((id) => ({ id })));
1237
1170
  var COPIES = ["plain", "markdown", "html", "json", "compact-json", "csv", "tsv"];
@@ -1320,7 +1253,7 @@ function ContentTransferMenu(props) {
1320
1253
  const identityKey = props.capabilities?.identityKey ?? inherited.identityKey;
1321
1254
  return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ContentTransferMenuSession, { ...props }, identityKey ?? "anonymous");
1322
1255
  }
1323
- function ContentTransferMenuSession({ source, surface, label, projection, sections, preferences, table, formatSources, variants = EMPTY_VARIANTS, actions = [], capabilities: local, disabled, enabled = true, className, stopPropagation = true, hide = [], controllerRef }) {
1256
+ function ContentTransferMenuSession({ source, surface, label, projection, sections, preferences, table, formatSources, sourceFormats = true, variants = EMPTY_VARIANTS, actions = [], capabilities: local, disabled, enabled = true, className, stopPropagation = true, hide = [], controllerRef }) {
1324
1257
  const triggerRef = React8.useRef(null);
1325
1258
  const inherited = React8.useContext(CapabilityContext);
1326
1259
  const nearestSurface = React8.useContext(SurfaceContext);
@@ -1333,6 +1266,8 @@ function ContentTransferMenuSession({ source, surface, label, projection, sectio
1333
1266
  const workspaceCaptures = React8.useRef(/* @__PURE__ */ new Map());
1334
1267
  const externalWorkspaceKeys = React8.useRef(/* @__PURE__ */ new Set());
1335
1268
  const [notice, setNotice] = React8.useState(null);
1269
+ const [paletteOpen, setPaletteOpen] = React8.useState(false);
1270
+ const [mode, setMode] = React8.useState("copy");
1336
1271
  const scopes = React8.useMemo(() => table?.availableScopes ?? ["target"], [table]);
1337
1272
  const initialScope = table?.initialScope ?? "target";
1338
1273
  if (!scopes.includes(initialScope)) throw new Error("Alchemy initialScope must be included in availableScopes.");
@@ -1584,48 +1519,96 @@ function ContentTransferMenuSession({ source, surface, label, projection, sectio
1584
1519
  }, [captureOne, capturePrimary, fence, initialScope, preferences, providerPreferences, report]);
1585
1520
  if (!enabled) return null;
1586
1521
  const payload = menuCapture?.snapshot.payload ?? (source && "kind" in source ? source : void 0);
1587
- const quickVariants = (section) => variants.filter((v) => v.copyLabel && (v.section ?? "ai") === section).map((v) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(DropdownMenuItem, { "aria-label": v.ariaLabel, onSelect: () => void transfer("markdown", false, v), children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(MenuPresentation, { ...v, label: v.copyLabel }) }, `copy:${v.id}`));
1588
- const visibleCopies = COPIES.filter((f) => Boolean(formatSources?.[f]) || !["csv", "tsv"].includes(f) || payload?.kind === "rows");
1589
- const visibleDownloads = DOWNLOADS.filter((f) => f !== "xlsx" && Boolean(formatSources?.[f]) || !["csv", "tsv", "xlsx"].includes(f) || payload?.kind === "rows");
1590
- const visibleAdapters = menuCapture ? adapters.filter((a) => a.supports(menuCapture.snapshot.payload)) : [];
1522
+ const quickVariants = (section) => variants.filter((v) => v.copyLabel && (v.section ?? "ai") === section);
1523
+ const visibleCopies = sourceFormats ? COPIES.filter((f) => Boolean(formatSources?.[f]) || !["csv", "tsv"].includes(f) || payload?.kind === "rows") : [];
1524
+ const visibleDownloads = sourceFormats ? DOWNLOADS.filter((f) => f !== "xlsx" && Boolean(formatSources?.[f]) || !["csv", "tsv", "xlsx"].includes(f) || payload?.kind === "rows") : [];
1525
+ const visibleAdapters = sourceFormats && menuCapture ? adapters.filter((a) => a.supports(menuCapture.snapshot.payload)) : [];
1591
1526
  const visibleActions = menuCapture ? registeredActions.filter((a) => a.supports(menuCapture.snapshot)) : [];
1527
+ const downloadActions = visibleActions.filter((action) => action.placement === "download");
1528
+ const ordinaryActions = visibleActions.filter((action) => action.placement !== "download");
1529
+ const copyAvailable = !hide.includes("copy") && visibleCopies.length + visibleAdapters.length + quickVariants("copy").length > 0;
1530
+ const downloadAvailable = !hide.includes("download") && visibleDownloads.length + visibleAdapters.length + downloadActions.length > 0;
1531
+ const prepareAvailable = !hide.includes("prepare") && (quickVariants("ai").length > 0 || Boolean(primary) || Boolean(nearestWorkspaceKey) || variants.length > 0);
1532
+ const resolvedMode = mode === "copy" && !copyAvailable ? "download" : mode === "download" && !downloadAvailable ? "copy" : mode;
1533
+ const closePalette = () => setPaletteOpen(false);
1534
+ const tile = (id, label2, onClick, options = {}) => {
1535
+ const presentation = options.action;
1536
+ const Icon = presentation?.icon;
1537
+ const fallbackLabel = options.file && !/^download\b/i.test(label2) ? `Download ${label2}` : label2;
1538
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("button", { type: "button", className: "matrx-alchemy-palette-tile", "aria-label": presentation?.ariaLabel ?? (presentation ? fallbackLabel : options.ariaLabel ?? `${resolvedMode === "copy" ? "Copy" : "Download"} ${label2}`), onClick: () => {
1539
+ closePalette();
1540
+ onClick();
1541
+ }, children: [
1542
+ Icon ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Icon, { className: "matrx-alchemy-menu-icon" }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(PaletteGlyph, { ...!options.custom ? { format: id } : {}, ...options.ai ? { ai: true } : {}, ...options.file ? { file: true } : {} }),
1543
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { children: [
1544
+ label2,
1545
+ presentation?.hint ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("small", { className: "matrx-alchemy-menu-hint", children: presentation.hint }) : null
1546
+ ] })
1547
+ ] }, id);
1548
+ };
1592
1549
  return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: cn("matrx-alchemy", className), onClick: stopPropagation ? (event) => event.stopPropagation() : void 0, children: [
1593
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(DropdownMenu, { onOpenChange: (open) => {
1594
- if (open) void preflight();
1550
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Popover, { open: paletteOpen, onOpenChange: (open) => {
1551
+ setPaletteOpen(open);
1552
+ if (open) {
1553
+ setMode("copy");
1554
+ void preflight();
1555
+ }
1595
1556
  }, children: [
1596
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime8.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_runtime8.jsx)(AlchemyGlyph, {}) }) }),
1597
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(DropdownMenuContent, { align: "end", className: "matrx-alchemy-menu", children: [
1598
- menuStatus === "loading" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(DropdownMenuItem, { disabled: true, children: "Inspecting content\u2026" }) : menuStatus !== "idle" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(DropdownMenuItem, { disabled: true, children: menuStatus }) : null,
1599
- !hide.includes("copy") ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
1600
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(DropdownMenuLabel, { children: "Copy" }),
1601
- quickVariants("copy"),
1602
- visibleCopies.map((format) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(DropdownMenuItem, { onSelect: () => void transfer(format, false), children: format === "plain" ? "Copy" : `Copy ${LABEL[format]}` }, format)),
1603
- visibleAdapters.map((adapter) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(DropdownMenuItem, { onSelect: () => void transfer(adapter, false), children: [
1604
- "Copy ",
1605
- adapter.label
1606
- ] }, adapter.id))
1607
- ] }) : null,
1608
- !hide.includes("prepare") ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
1609
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(DropdownMenuSeparator, {}),
1610
- quickVariants("ai"),
1611
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(DropdownMenuItem, { onSelect: () => void openWorkspace(), children: "Prepare for AI\u2026" }),
1612
- nearestWorkspaceKey && nearestSurface ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(DropdownMenuItem, { onSelect: () => void openWorkspace(nearestWorkspaceKey, { source: nearestSurface, label: nearestSurface.surfaceName }), children: "Prepare this surface\u2026" }) : null,
1613
- variants.map((variant) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(DropdownMenuItem, { onSelect: () => void openWorkspace(variantWorkspaceKeys.get(variant.id), variant), children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(MenuPresentation, { ...variant, label: `Prepare ${variant.label}\u2026` }) }, variant.id))
1557
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime8.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_runtime8.jsx)(AlchemyGlyph, {}) }) }),
1558
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(PopoverContent, { align: "end", className: "matrx-alchemy-menu matrx-alchemy-palette", "aria-label": "Alchemy output options", onCloseAutoFocus: () => triggerRef.current?.focus(), children: [
1559
+ menuStatus === "loading" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "matrx-alchemy-palette-status", children: "Inspecting content\u2026" }) : menuStatus !== "idle" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "matrx-alchemy-error", children: menuStatus }) : null,
1560
+ copyAvailable || downloadAvailable ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("section", { className: "matrx-alchemy-output", children: [
1561
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h3", { children: resolvedMode === "copy" ? "Copy as" : "Download as" }),
1562
+ copyAvailable && downloadAvailable ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "matrx-alchemy-mode", "aria-label": "Output action", children: [
1563
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", "aria-label": "Copy mode", "aria-pressed": resolvedMode === "copy", onClick: () => setMode("copy"), children: "Copy" }),
1564
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", "aria-label": "Download mode", "aria-pressed": resolvedMode === "download", onClick: () => setMode("download"), children: "Download" })
1565
+ ] }) : null,
1566
+ resolvedMode === "copy" && copyAvailable ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
1567
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "matrx-alchemy-palette-grid", children: [
1568
+ visibleCopies.map((format) => tile(format, { plain: "Text", markdown: "Markdown", html: "Formatted", json: "JSON", "compact-json": "Compact", csv: "CSV", tsv: "Sheets" }[format], () => void transfer(format, false), { ariaLabel: `Copy ${LABEL[format]}` })),
1569
+ visibleAdapters.map((adapter) => tile(adapter.id, adapter.label, () => void transfer(adapter, false), { custom: true }))
1570
+ ] }),
1571
+ quickVariants("copy").length ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(PaletteRows, { title: "Quick copy", items: quickVariants("copy"), onRun: (variant) => {
1572
+ closePalette();
1573
+ void transfer("markdown", false, variant);
1574
+ } }) : null
1575
+ ] }) : null,
1576
+ resolvedMode === "download" && downloadAvailable ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_jsx_runtime8.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "matrx-alchemy-palette-grid", children: [
1577
+ visibleDownloads.map((format) => tile(format, { plain: "Text", markdown: "Markdown", html: "Formatted", json: "JSON", "compact-json": "Compact", csv: "CSV", tsv: "Sheets", xlsx: "Excel" }[format], () => void transfer(format, true), { ariaLabel: `Download ${LABEL[format]}` })),
1578
+ visibleAdapters.map((adapter) => tile(adapter.id, adapter.label, () => void transfer(adapter, true), { custom: true })),
1579
+ downloadActions.map((action) => tile(action.id, action.label, () => void runAction(action), { custom: true, action, file: true }))
1580
+ ] }) }) : null
1614
1581
  ] }) : null,
1615
- !hide.includes("download") ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
1616
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(DropdownMenuSeparator, {}),
1617
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(DropdownMenuLabel, { children: "Download" }),
1618
- visibleDownloads.map((format) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(DropdownMenuItem, { onSelect: () => void transfer(format, true), children: [
1619
- "Download ",
1620
- LABEL[format]
1621
- ] }, format)),
1622
- visibleAdapters.map((adapter) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(DropdownMenuItem, { onSelect: () => void transfer(adapter, true), children: [
1623
- "Download ",
1624
- adapter.label
1625
- ] }, `download:${adapter.id}`))
1582
+ prepareAvailable ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
1583
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(PaletteRows, { title: "Copy for AI", ai: true, glyphKind: "ai-copy", fallbackHint: "Copies immediately", items: quickVariants("ai"), onRun: (variant) => {
1584
+ closePalette();
1585
+ void transfer("markdown", false, variant);
1586
+ } }),
1587
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(PaletteRows, { title: "Edit and prepare", items: [], extra: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("button", { type: "button", className: "matrx-alchemy-palette-row", "aria-label": "Prepare for AI", onClick: () => {
1588
+ closePalette();
1589
+ void openWorkspace();
1590
+ }, children: [
1591
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(PaletteGlyph, { kind: "sliders" }),
1592
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { children: [
1593
+ "Prepare for AI",
1594
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("small", { className: "matrx-alchemy-menu-hint", children: "Review and edit before copying" })
1595
+ ] })
1596
+ ] }) })
1626
1597
  ] }) : null,
1627
- visibleActions.length ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(DropdownMenuSeparator, {}) : null,
1628
- visibleActions.map((action) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(DropdownMenuItem, { "aria-label": action.ariaLabel, onSelect: () => void runAction(action), children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(MenuPresentation, { ...action, label: action.label }) }, action.id))
1598
+ prepareAvailable && (nearestWorkspaceKey || variants.length) ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(PaletteRows, { title: "Other sources", items: [], extra: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
1599
+ nearestWorkspaceKey && nearestSurface ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: "matrx-alchemy-palette-row", onClick: () => {
1600
+ closePalette();
1601
+ void openWorkspace(nearestWorkspaceKey, { source: nearestSurface, label: nearestSurface.surfaceName });
1602
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: "Prepare this surface" }) }) : null,
1603
+ variants.map((variant) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: "matrx-alchemy-palette-row", "aria-label": variant.ariaLabel, onClick: () => {
1604
+ closePalette();
1605
+ void openWorkspace(variantWorkspaceKeys.get(variant.id), variant);
1606
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(MenuPresentation, { ...variant, label: `Prepare ${variant.label}` }) }, variant.id))
1607
+ ] }) }) : null,
1608
+ ordinaryActions.length ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(PaletteRows, { title: "Actions", items: [], extra: ordinaryActions.map((action) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", className: "matrx-alchemy-palette-row", "aria-label": action.ariaLabel, onClick: () => {
1609
+ closePalette();
1610
+ void runAction(action);
1611
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(MenuPresentation, { ...action, label: action.label }) }, action.id)) }) : null
1629
1612
  ] })
1630
1613
  ] }),
1631
1614
  notice ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "matrx-alchemy-notice", role: "status", children: notice }) : null,
@@ -1898,137 +1881,138 @@ function PreparationWorkspace({ restoreFocus, open, state, scopes, onClose, onCh
1898
1881
  state.snapshot.label
1899
1882
  ] }),
1900
1883
  /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(DialogDescription, { children: [
1901
- "Captured ",
1902
- state.snapshot.unsavedChanges ? "from your unsaved draft" : "as an immutable snapshot",
1903
- ". Your source is never edited."
1884
+ state.snapshot.unsavedChanges ? "Includes your unsaved changes. " : "",
1885
+ "Review and edit this copy. Your original stays unchanged."
1904
1886
  ] })
1905
1887
  ] }),
1906
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "matrx-alchemy-workspace-grid", children: [
1907
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("section", { className: "matrx-alchemy-main", children: [
1908
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "matrx-alchemy-toolbar", children: [
1909
- scopes.length > 1 ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { children: [
1910
- "Scope",
1911
- /* @__PURE__ */ (0, import_jsx_runtime8.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_runtime8.jsx)("option", { value: scope, children: SCOPE_LABEL[scope] }, scope)) })
1912
- ] }) : null,
1913
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { children: [
1914
- "Detail",
1915
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("select", { "aria-label": "Detail preset", value: controls.preset, onChange: (e) => changeControls({ ...controls, preset: e.target.value }), children: [
1916
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: "full", children: "Full" }),
1917
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: "compact", children: "Compact" }),
1918
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: "brief", children: "Brief" }),
1919
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: "custom", children: "Custom" })
1920
- ] })
1921
- ] }),
1922
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Button, { type: "button", size: "sm", variant: "outline", disabled: !state.draft.history?.length && !controlsHistory.length || busy !== null, onClick: () => {
1923
- setBufferError(null);
1924
- if (controlsHistory.length) {
1925
- const next = controlsHistory[controlsHistory.length - 1];
1888
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "matrx-alchemy-workspace-body", children: [
1889
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "matrx-alchemy-workspace-grid", children: [
1890
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("section", { className: "matrx-alchemy-main", children: [
1891
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "matrx-alchemy-toolbar", children: [
1892
+ scopes.length > 1 ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { children: [
1893
+ "Scope",
1894
+ /* @__PURE__ */ (0, import_jsx_runtime8.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_runtime8.jsx)("option", { value: scope, children: SCOPE_LABEL[scope] }, scope)) })
1895
+ ] }) : null,
1896
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { children: [
1897
+ "Detail",
1898
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("select", { "aria-label": "Detail preset", value: controls.preset, onChange: (e) => changeControls({ ...controls, preset: e.target.value }), children: [
1899
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: "full", children: "Full" }),
1900
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: "compact", children: "Compact" }),
1901
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: "brief", children: "Brief" }),
1902
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: "custom", children: "Custom" })
1903
+ ] })
1904
+ ] }),
1905
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Button, { type: "button", size: "sm", variant: "outline", className: "matrx-alchemy-workspace-secondary", disabled: !state.draft.history?.length && !controlsHistory.length || busy !== null, onClick: () => {
1906
+ setBufferError(null);
1907
+ if (controlsHistory.length) {
1908
+ const next = controlsHistory[controlsHistory.length - 1];
1909
+ setControls(next);
1910
+ setControlsHistory((history) => history.slice(0, -1));
1911
+ onChange({ ...state, draft: rebuild(state, next), error: void 0 });
1912
+ } else onChange({ ...state, draft: (0, import_content_transfer2.undoDraft)(state.draft), error: void 0 });
1913
+ }, children: "Undo" }),
1914
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Button, { type: "button", size: "sm", variant: "outline", className: "matrx-alchemy-workspace-secondary", disabled: busy !== null, onClick: () => {
1915
+ const next = initialControls(state);
1926
1916
  setControls(next);
1927
- setControlsHistory((history) => history.slice(0, -1));
1917
+ setControlsHistory([]);
1918
+ setPendingControls(null);
1919
+ setBufferError(null);
1928
1920
  onChange({ ...state, draft: rebuild(state, next), error: void 0 });
1929
- } else onChange({ ...state, draft: (0, import_content_transfer2.undoDraft)(state.draft), error: void 0 });
1930
- }, children: "Undo" }),
1931
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Button, { type: "button", size: "sm", variant: "outline", disabled: busy !== null, onClick: () => {
1932
- const next = initialControls(state);
1933
- setControls(next);
1934
- setControlsHistory([]);
1935
- setPendingControls(null);
1936
- setBufferError(null);
1937
- onChange({ ...state, draft: rebuild(state, next), error: void 0 });
1938
- }, children: "Reset" }),
1939
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Button, { type: "button", size: "sm", variant: "outline", disabled: busy !== null, onClick: () => void requestCapture(state.scope), children: "Refresh source" })
1940
- ] }),
1941
- controls.preset === "custom" && (state.draft.payload.kind === "json" || state.draft.payload.kind === "registered") ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("fieldset", { className: "matrx-alchemy-options", children: [
1942
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("legend", { children: "JSON limits" }),
1943
- [["maxDepth", "Maximum depth"], ["maxStringChars", "Maximum string characters"], ["maxArrayItems", "Maximum array items"]].map(([key, text]) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { children: [
1944
- text,
1945
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("input", { type: "number", min: "0", value: controls[key] ?? "", onChange: (e) => changeControls({ ...controls, [key]: Number.isNaN(e.target.valueAsNumber) ? null : e.target.valueAsNumber }) })
1946
- ] }, key))
1947
- ] }) : null,
1948
- rows ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(RowControls, { rows, controls, change: changeControls }) : null,
1949
- state.snapshot.sections.length ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("fieldset", { className: "matrx-alchemy-options", children: [
1950
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("legend", { children: "Sections" }),
1951
- state.snapshot.sections.map((section) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { children: [
1952
- /* @__PURE__ */ (0, import_jsx_runtime8.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) }) }),
1953
- " ",
1954
- section.label
1955
- ] }, section.id))
1956
- ] }) : null,
1957
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "matrx-alchemy-coverage", children: [
1958
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { children: [
1959
- state.snapshot.coverage.included.toLocaleString(),
1960
- " included",
1961
- state.snapshot.coverage.total == null ? "" : ` of ${state.snapshot.coverage.total.toLocaleString()}`,
1962
- " \xB7 ",
1963
- state.snapshot.coverage.status
1921
+ }, children: "Reset" }),
1922
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Button, { type: "button", size: "sm", variant: "outline", className: "matrx-alchemy-workspace-secondary", disabled: busy !== null, onClick: () => void requestCapture(state.scope), children: "Refresh source" })
1964
1923
  ] }),
1965
- state.snapshot.coverage.reason ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: state.snapshot.coverage.reason }) : null,
1966
- limitText ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { children: [
1967
- "Limits: ",
1968
- limitText
1924
+ controls.preset === "custom" && (state.draft.payload.kind === "json" || state.draft.payload.kind === "registered") ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("fieldset", { className: "matrx-alchemy-options", children: [
1925
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("legend", { children: "JSON limits" }),
1926
+ [["maxDepth", "Maximum depth"], ["maxStringChars", "Maximum string characters"], ["maxArrayItems", "Maximum array items"]].map(([key, text]) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { children: [
1927
+ text,
1928
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("input", { type: "number", min: "0", value: controls[key] ?? "", onChange: (e) => changeControls({ ...controls, [key]: Number.isNaN(e.target.valueAsNumber) ? null : e.target.valueAsNumber }) })
1929
+ ] }, key))
1969
1930
  ] }) : null,
1970
- displayedOmissions.length ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("details", { children: [
1971
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("summary", { children: [
1972
- displayedOmissions.length,
1973
- " omissions or adjustments"
1931
+ rows ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(RowControls, { rows, controls, change: changeControls }) : null,
1932
+ state.snapshot.sections.length ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("fieldset", { className: "matrx-alchemy-options", children: [
1933
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("legend", { children: "Sections" }),
1934
+ state.snapshot.sections.map((section) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { children: [
1935
+ /* @__PURE__ */ (0, import_jsx_runtime8.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) }) }),
1936
+ " ",
1937
+ section.label
1938
+ ] }, section.id))
1939
+ ] }) : null,
1940
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "matrx-alchemy-coverage", children: [
1941
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { children: [
1942
+ state.snapshot.coverage.included.toLocaleString(),
1943
+ " included",
1944
+ state.snapshot.coverage.total == null ? "" : ` of ${state.snapshot.coverage.total.toLocaleString()}`,
1945
+ " \xB7 ",
1946
+ state.snapshot.coverage.status
1974
1947
  ] }),
1975
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("ul", { children: displayedOmissions.map((o, i) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("li", { children: [
1976
- o.path || "/",
1977
- ": ",
1978
- o.reason,
1979
- o.count == null ? "" : ` (${o.count})`
1980
- ] }, `${o.path}-${o.reason}-${i}`)) })
1981
- ] }) : null
1982
- ] }),
1983
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { className: "matrx-alchemy-preview-label", children: [
1984
- "Output format",
1985
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("select", { "aria-label": "Output format", value: format, onChange: (e) => setFormat(e.target.value), children: [
1986
- formats.map((f) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: f, children: LABEL[f] }, f)),
1987
- state.draft.payload.kind === "rows" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: "xlsx", children: "Excel workbook" }) : null,
1988
- workspaceAdapters.map((adapter) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: adapter.id, children: adapter.label }, adapter.id))
1989
- ] })
1948
+ state.snapshot.coverage.reason ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: state.snapshot.coverage.reason }) : null,
1949
+ limitText ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { children: [
1950
+ "Limits: ",
1951
+ limitText
1952
+ ] }) : null,
1953
+ displayedOmissions.length ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("details", { children: [
1954
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("summary", { children: [
1955
+ displayedOmissions.length,
1956
+ " omissions or adjustments"
1957
+ ] }),
1958
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("ul", { children: displayedOmissions.map((o, i) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("li", { children: [
1959
+ o.path || "/",
1960
+ ": ",
1961
+ o.reason,
1962
+ o.count == null ? "" : ` (${o.count})`
1963
+ ] }, `${o.path}-${o.reason}-${i}`)) })
1964
+ ] }) : null
1965
+ ] }),
1966
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { className: "matrx-alchemy-preview-label", children: [
1967
+ "Output format",
1968
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("select", { "aria-label": "Output format", value: format, onChange: (e) => setFormat(e.target.value), children: [
1969
+ formats.map((f) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: f, children: LABEL[f] }, f)),
1970
+ state.draft.payload.kind === "rows" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: "xlsx", children: "Excel workbook" }) : null,
1971
+ workspaceAdapters.map((adapter) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: adapter.id, children: adapter.label }, adapter.id))
1972
+ ] })
1973
+ ] }),
1974
+ /* @__PURE__ */ (0, import_jsx_runtime8.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) }),
1975
+ bufferError ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { id: "alchemy-buffer-error", role: "alert", className: "matrx-alchemy-error", children: bufferError }) : null,
1976
+ formatError ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { role: "alert", className: "matrx-alchemy-error", children: formatError }) : null,
1977
+ bufferError ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Button, { className: "matrx-alchemy-workspace-secondary", type: "button", variant: "outline", disabled: busy !== null, onClick: () => {
1978
+ const fallback = (0, import_content_transfer2.editDraft)(state.draft, { kind: "text", text: buffer });
1979
+ setBufferError(null);
1980
+ onChange({ ...state, draft: fallback, error: void 0 });
1981
+ setFormat("plain");
1982
+ }, children: "Use invalid JSON as plain text" }) : null
1990
1983
  ] }),
1991
- /* @__PURE__ */ (0, import_jsx_runtime8.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) }),
1992
- bufferError ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { id: "alchemy-buffer-error", role: "alert", className: "matrx-alchemy-error", children: bufferError }) : null,
1993
- formatError ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { role: "alert", className: "matrx-alchemy-error", children: formatError }) : null,
1994
- bufferError ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Button, { type: "button", variant: "outline", disabled: busy !== null, onClick: () => {
1995
- const fallback = (0, import_content_transfer2.editDraft)(state.draft, { kind: "text", text: buffer });
1996
- setBufferError(null);
1997
- onChange({ ...state, draft: fallback, error: void 0 });
1998
- setFormat("plain");
1999
- }, children: "Use invalid JSON as plain text" }) : null
1984
+ ai || busy === "capture" || state.error ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("aside", { children: [
1985
+ ai ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
1986
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { children: [
1987
+ "AI instruction",
1988
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("textarea", { value: instruction, onChange: (e) => setInstruction(e.target.value), placeholder: "Tell AI how to prepare this content" })
1989
+ ] }),
1990
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Button, { className: "matrx-alchemy-workspace-secondary", type: "button", variant: "outline", disabled: !aiSession.current || !instruction.trim() || busy !== null || !aiSession.current.supports(state.snapshot), onClick: () => void runAi(false), children: "Generate preview" }),
1991
+ busy === "ai" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Button, { className: "matrx-alchemy-workspace-secondary", type: "button", variant: "outline", onClick: () => void cancelAi(), children: aiSession.current?.cancel ? "Cancel AI" : "Stop waiting" }) : null
1992
+ ] }) : null,
1993
+ busy === "capture" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Button, { className: "matrx-alchemy-workspace-secondary", type: "button", variant: "outline", onClick: () => {
1994
+ activeCapture.current?.abort();
1995
+ activeCapture.current = null;
1996
+ setBusy(null);
1997
+ }, children: "Stop loading rows" }) : null,
1998
+ ai && aiFailed && aiSession.current?.recover && busy !== "ai" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Button, { className: "matrx-alchemy-workspace-secondary", type: "button", variant: "outline", onClick: () => void runAi(true), children: aiFailed ? "Retry or rejoin AI run" : "Rejoin AI run" }) : null,
1999
+ ai ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "matrx-alchemy-meta", children: "AI updates the preview; copy it when you are ready. Closing this window lets the AI run continue." }) : null,
2000
+ state.error ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { role: "alert", className: "matrx-alchemy-error", children: state.error }) : null
2001
+ ] }) : null
2000
2002
  ] }),
2001
- ai || busy === "capture" || state.error ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("aside", { children: [
2002
- ai ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
2003
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { children: [
2004
- "AI instruction",
2005
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("textarea", { value: instruction, onChange: (e) => setInstruction(e.target.value), placeholder: "Tell AI how to prepare this content" })
2006
- ] }),
2007
- /* @__PURE__ */ (0, import_jsx_runtime8.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" }),
2008
- busy === "ai" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Button, { type: "button", variant: "outline", onClick: () => void cancelAi(), children: aiSession.current?.cancel ? "Cancel AI" : "Stop waiting" }) : null
2009
- ] }) : null,
2010
- busy === "capture" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Button, { type: "button", variant: "outline", onClick: () => {
2011
- activeCapture.current?.abort();
2012
- activeCapture.current = null;
2013
- setBusy(null);
2014
- }, children: "Stop loading rows" }) : null,
2015
- ai && aiFailed && aiSession.current?.recover && busy !== "ai" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Button, { type: "button", variant: "outline", onClick: () => void runAi(true), children: aiFailed ? "Retry or rejoin AI run" : "Rejoin AI run" }) : null,
2016
- ai ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "matrx-alchemy-meta", children: "AI creates a preview. It never copies automatically. Closing detaches this view without cancelling server work." }) : null,
2017
- state.error ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { role: "alert", className: "matrx-alchemy-error", children: state.error }) : null
2018
- ] }) : null
2003
+ pendingControls ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "matrx-alchemy-decision", role: "alert", children: [
2004
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { children: "This control would replace your manual edit." }),
2005
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Button, { className: "matrx-alchemy-workspace-secondary", type: "button", variant: "outline", onClick: () => setPendingControls(null), children: "Keep edited draft" }),
2006
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Button, { className: "matrx-alchemy-workspace-primary", type: "button", onClick: applyPendingControls, children: "Rebuild from source" })
2007
+ ] }) : null,
2008
+ state.sourceStale ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { role: "alert", className: "matrx-alchemy-decision", children: "The source changed since this draft. Use Refresh source to review the latest data." }) : null,
2009
+ state.pending ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "matrx-alchemy-decision", role: "alert", children: [
2010
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { children: "A fresh source snapshot is ready." }),
2011
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Button, { className: "matrx-alchemy-workspace-secondary", type: "button", variant: "outline", onClick: () => resolveCapture("keep"), children: "Keep current snapshot and draft" }),
2012
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Button, { className: "matrx-alchemy-workspace-primary", type: "button", onClick: () => resolveCapture("regenerate"), children: "Regenerate from fresh source" })
2013
+ ] }) : null,
2014
+ deliveryNotice ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { role: "status", className: "matrx-alchemy-meta", children: deliveryNotice }) : null
2019
2015
  ] }),
2020
- pendingControls ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "matrx-alchemy-decision", role: "alert", children: [
2021
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { children: "This control would replace your manual edit." }),
2022
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Button, { type: "button", variant: "outline", onClick: () => setPendingControls(null), children: "Keep edited draft" }),
2023
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Button, { type: "button", onClick: applyPendingControls, children: "Rebuild from source" })
2024
- ] }) : null,
2025
- state.sourceStale ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { role: "alert", className: "matrx-alchemy-decision", children: "The source changed since this draft. Use Refresh source to review the latest data." }) : null,
2026
- state.pending ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "matrx-alchemy-decision", role: "alert", children: [
2027
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { children: "A fresh source snapshot is ready." }),
2028
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Button, { type: "button", variant: "outline", onClick: () => resolveCapture("keep"), children: "Keep current snapshot and draft" }),
2029
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Button, { type: "button", onClick: () => resolveCapture("regenerate"), children: "Regenerate from fresh source" })
2030
- ] }) : null,
2031
- deliveryNotice ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { role: "status", className: "matrx-alchemy-meta", children: deliveryNotice }) : null,
2032
2016
  /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(DialogFooter, { children: [
2033
2017
  /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "matrx-alchemy-meta", children: [
2034
2018
  buffer.length.toLocaleString(),
@@ -2036,13 +2020,16 @@ function PreparationWorkspace({ restoreFocus, open, state, scopes, onClose, onCh
2036
2020
  estimateTokens(buffer).toLocaleString(),
2037
2021
  " tokens"
2038
2022
  ] }),
2039
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Button, { type: "button", variant: "outline", onClick: close, children: "Close" }),
2040
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Button, { type: "button", variant: "outline", disabled: busy !== null || Boolean(bufferError || formatError) || !preparedArtifact, onClick: () => void deliver(true), children: "Download prepared output" }),
2041
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Button, { type: "button", disabled: busy !== null || Boolean(bufferError || formatError) || !preparedArtifact, onClick: () => void deliver(false), children: "Copy prepared output" })
2023
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Button, { type: "button", variant: "outline", className: "matrx-alchemy-workspace-secondary", onClick: close, children: "Close" }),
2024
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Button, { type: "button", variant: "outline", className: "matrx-alchemy-workspace-secondary", "aria-label": "Download prepared output", disabled: busy !== null || Boolean(bufferError || formatError) || !preparedArtifact, onClick: () => void deliver(true), children: "Download" }),
2025
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Button, { type: "button", className: "matrx-alchemy-workspace-primary", "aria-label": "Copy prepared output", disabled: busy !== null || Boolean(bufferError || formatError) || !preparedArtifact, onClick: () => void deliver(false), children: "Copy" })
2042
2026
  ] })
2043
2027
  ] }) });
2044
2028
  }
2045
2029
  function RowControls({ rows, controls, change }) {
2030
+ const filterCount = Object.values(controls.filters).filter(Boolean).length;
2031
+ const selectionSummary = controls.selectedOnly ? `${controls.selectedIndices.length} selected row${controls.selectedIndices.length === 1 ? "" : "s"}` : "All rows";
2032
+ const dataSummary = [controls.search ? "search active" : "", controls.sort ? `sorted by ${rows.columns.find((column) => column.id === controls.sort)?.label ?? controls.sort}` : "", filterCount ? `${filterCount} filter${filterCount === 1 ? "" : "s"}` : ""].filter(Boolean).join(" \xB7 ");
2046
2033
  return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
2047
2034
  /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "matrx-alchemy-toolbar", children: [
2048
2035
  /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { children: [
@@ -2068,32 +2055,40 @@ function RowControls({ rows, controls, change }) {
2068
2055
  /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("input", { type: "number", min: "0", value: controls.top ?? "", onChange: (e) => change({ ...controls, top: Number.isNaN(e.target.valueAsNumber) ? null : e.target.valueAsNumber }) })
2069
2056
  ] })
2070
2057
  ] }),
2071
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("fieldset", { className: "matrx-alchemy-options", children: [
2072
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("legend", { children: "Columns and filters" }),
2073
- rows.columns.map((column) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "matrx-alchemy-column", children: [
2058
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("details", { className: "matrx-alchemy-options", children: [
2059
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("summary", { children: [
2060
+ "Columns and filters",
2061
+ dataSummary ? ` \u2014 ${dataSummary}` : ""
2062
+ ] }),
2063
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("fieldset", { "aria-label": "Columns and filters", children: rows.columns.map((column) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "matrx-alchemy-column", children: [
2074
2064
  /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { children: [
2075
2065
  /* @__PURE__ */ (0, import_jsx_runtime8.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) }) }),
2076
2066
  " ",
2077
2067
  column.label
2078
2068
  ] }),
2079
2069
  /* @__PURE__ */ (0, import_jsx_runtime8.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 } }) })
2080
- ] }, column.id))
2070
+ ] }, column.id)) })
2081
2071
  ] }),
2082
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("fieldset", { className: "matrx-alchemy-options", children: [
2083
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("legend", { children: "Rows" }),
2084
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { children: [
2085
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("input", { type: "checkbox", checked: controls.selectedOnly, onChange: (e) => change({ ...controls, selectedOnly: e.target.checked }) }),
2086
- " Only selected rows"
2072
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("details", { className: "matrx-alchemy-options", children: [
2073
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("summary", { children: [
2074
+ "Rows \u2014 ",
2075
+ selectionSummary
2087
2076
  ] }),
2088
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "matrx-alchemy-row-list", children: rows.rows.map((row, index) => {
2089
- const summary = rows.columns.filter((column) => column.visible).slice(0, 2).map((column) => String((0, import_content_transfer2.readTransferCell)(row, column) ?? "")).filter(Boolean).join(" \xB7 ");
2090
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { children: [
2091
- /* @__PURE__ */ (0, import_jsx_runtime8.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) }) }),
2092
- " Row ",
2093
- index + 1,
2094
- summary ? ` \u2014 ${summary}` : ""
2095
- ] }, index);
2096
- }) })
2077
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("fieldset", { "aria-label": "Row selection", children: [
2078
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { children: [
2079
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("input", { type: "checkbox", checked: controls.selectedOnly, onChange: (e) => change({ ...controls, selectedOnly: e.target.checked }) }),
2080
+ " Only selected rows"
2081
+ ] }),
2082
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "matrx-alchemy-row-list", children: rows.rows.map((row, index) => {
2083
+ const summary = rows.columns.filter((column) => column.visible).slice(0, 2).map((column) => String((0, import_content_transfer2.readTransferCell)(row, column) ?? "")).filter(Boolean).join(" \xB7 ");
2084
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { children: [
2085
+ /* @__PURE__ */ (0, import_jsx_runtime8.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) }) }),
2086
+ " Row ",
2087
+ index + 1,
2088
+ summary ? ` \u2014 ${summary}` : ""
2089
+ ] }, index);
2090
+ }) })
2091
+ ] })
2097
2092
  ] })
2098
2093
  ] });
2099
2094
  }