@ai-matrx/design-system 0.17.3 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +36 -0
- package/README.md +1 -0
- package/dist/content-transfer/alchemy.svg +1 -0
- package/dist/content-transfer/icon.cjs +28 -0
- package/dist/content-transfer/icon.cjs.map +1 -0
- package/dist/content-transfer/icon.d.cts +4 -0
- package/dist/content-transfer/icon.d.ts +4 -0
- package/dist/content-transfer/icon.js +8 -0
- package/dist/content-transfer/icon.js.map +1 -0
- package/dist/content-transfer.cjs +1978 -0
- package/dist/content-transfer.cjs.map +1 -0
- package/dist/content-transfer.css +382 -0
- package/dist/content-transfer.d.cts +208 -0
- package/dist/content-transfer.d.ts +208 -0
- package/dist/content-transfer.js +1974 -0
- package/dist/content-transfer.js.map +1 -0
- package/dist/data-table/copy-helpers.d.cts +1 -1
- package/dist/data-table/copy-helpers.d.ts +1 -1
- package/dist/data-table/copy-types.cjs.map +1 -1
- package/dist/data-table/copy-types.d.cts +2 -0
- package/dist/data-table/copy-types.d.ts +2 -0
- package/dist/data-table/data-row-inspector.cjs +1603 -319
- package/dist/data-table/data-row-inspector.cjs.map +1 -1
- package/dist/data-table/data-row-inspector.js +1634 -324
- package/dist/data-table/data-row-inspector.js.map +1 -1
- package/dist/data-table/data-row-window.cjs +1531 -245
- package/dist/data-table/data-row-window.cjs.map +1 -1
- package/dist/data-table/data-row-window.js +1561 -249
- package/dist/data-table/data-row-window.js.map +1 -1
- package/dist/data-table/filter-engine.d.cts +1 -1
- package/dist/data-table/filter-engine.d.ts +1 -1
- package/dist/data-table/index.cjs +2558 -1146
- package/dist/data-table/index.cjs.map +1 -1
- package/dist/data-table/index.d.cts +2 -2
- package/dist/data-table/index.d.ts +2 -2
- package/dist/data-table/index.js +2589 -1151
- package/dist/data-table/index.js.map +1 -1
- package/dist/data-table/infer-filter.d.cts +1 -1
- package/dist/data-table/infer-filter.d.ts +1 -1
- package/dist/data-table/layered-filters.d.cts +1 -1
- package/dist/data-table/layered-filters.d.ts +1 -1
- package/dist/data-table/query-control.d.cts +1 -1
- package/dist/data-table/query-control.d.ts +1 -1
- package/dist/data-table/types.cjs.map +1 -1
- package/dist/data-table/types.d.cts +1 -1
- package/dist/data-table/types.d.ts +1 -1
- package/dist/data-table/url-state.d.cts +1 -1
- package/dist/data-table/url-state.d.ts +1 -1
- package/dist/data-table/xlsx.d.cts +1 -1
- package/dist/data-table/xlsx.d.ts +1 -1
- package/dist/styles.css +2 -0
- package/dist/{types-pZ95iFk5.d.ts → types-BhSkeZQ_.d.ts} +14 -0
- package/dist/{types-4fmLG5AN.d.cts → types-CD4xGL5Z.d.cts} +14 -0
- package/package.json +25 -2
|
@@ -35,7 +35,7 @@ __export(DataRowWindow_exports, {
|
|
|
35
35
|
DataRowWindow: () => DataRowWindow
|
|
36
36
|
});
|
|
37
37
|
module.exports = __toCommonJS(DataRowWindow_exports);
|
|
38
|
-
var
|
|
38
|
+
var import_react4 = require("react");
|
|
39
39
|
|
|
40
40
|
// src/dialog.tsx
|
|
41
41
|
var DialogPrimitive = __toESM(require("@radix-ui/react-dialog"), 1);
|
|
@@ -95,6 +95,48 @@ function XIcon(props) {
|
|
|
95
95
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m6 6 12 12" })
|
|
96
96
|
] });
|
|
97
97
|
}
|
|
98
|
+
function radixProps(props) {
|
|
99
|
+
return {
|
|
100
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
101
|
+
viewBox: "0 0 15 15",
|
|
102
|
+
width: 15,
|
|
103
|
+
height: 15,
|
|
104
|
+
fill: "none",
|
|
105
|
+
"aria-hidden": true,
|
|
106
|
+
...props
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
function CheckIcon(props) {
|
|
110
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { ...radixProps(props), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
111
|
+
"path",
|
|
112
|
+
{
|
|
113
|
+
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",
|
|
114
|
+
fill: "currentColor",
|
|
115
|
+
fillRule: "evenodd",
|
|
116
|
+
clipRule: "evenodd"
|
|
117
|
+
}
|
|
118
|
+
) });
|
|
119
|
+
}
|
|
120
|
+
function DotFilledIcon(props) {
|
|
121
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { ...radixProps(props), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
122
|
+
"path",
|
|
123
|
+
{
|
|
124
|
+
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",
|
|
125
|
+
fill: "currentColor"
|
|
126
|
+
}
|
|
127
|
+
) });
|
|
128
|
+
}
|
|
129
|
+
function RadixChevronRightIcon(props) {
|
|
130
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { ...radixProps(props), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
131
|
+
"path",
|
|
132
|
+
{
|
|
133
|
+
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",
|
|
134
|
+
fill: "currentColor",
|
|
135
|
+
fillRule: "evenodd",
|
|
136
|
+
clipRule: "evenodd"
|
|
137
|
+
}
|
|
138
|
+
) });
|
|
139
|
+
}
|
|
98
140
|
|
|
99
141
|
// src/portal-container.tsx
|
|
100
142
|
var React = __toESM(require("react"), 1);
|
|
@@ -381,7 +423,6 @@ function Icon({ children, ...props }) {
|
|
|
381
423
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", "aria-hidden": "true", ...props, children });
|
|
382
424
|
}
|
|
383
425
|
var Check = (p) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Icon, { ...p, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "m5 12 4 4L19 6" }) });
|
|
384
|
-
var SlidersHorizontal = (p) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Icon, { ...p, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M4 7h16M4 17h16M9 7v0M15 17v0" }) });
|
|
385
426
|
var Pencil = (p) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Icon, { ...p, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "m4 20 4-1 11-11-3-3L5 16l-1 4z" }) });
|
|
386
427
|
var Eye = (p) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Icon, { ...p, children: [
|
|
387
428
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M2 12s3-6 10-6 10 6 10 6-3 6-10 6S2 12 2 12z" }),
|
|
@@ -409,9 +450,13 @@ function useMatrxDataTableHost() {
|
|
|
409
450
|
return (0, import_react.useContext)(HostContext);
|
|
410
451
|
}
|
|
411
452
|
|
|
412
|
-
// src/
|
|
413
|
-
var
|
|
414
|
-
var
|
|
453
|
+
// src/content-transfer/matrx-copy.tsx
|
|
454
|
+
var React8 = __toESM(require("react"), 1);
|
|
455
|
+
var import_content_transfer2 = require("@ai-matrx/kit/content-transfer");
|
|
456
|
+
|
|
457
|
+
// src/content-transfer/index.tsx
|
|
458
|
+
var React7 = __toESM(require("react"), 1);
|
|
459
|
+
var import_content_transfer = require("@ai-matrx/kit/content-transfer");
|
|
415
460
|
|
|
416
461
|
// src/button.tsx
|
|
417
462
|
var import_react_slot = require("@radix-ui/react-slot");
|
|
@@ -484,230 +529,1471 @@ var Button = React5.forwardRef(
|
|
|
484
529
|
);
|
|
485
530
|
Button.displayName = "Button";
|
|
486
531
|
|
|
487
|
-
// src/
|
|
488
|
-
var
|
|
532
|
+
// src/dropdown-menu.tsx
|
|
533
|
+
var DropdownMenuPrimitive = __toESM(require("@radix-ui/react-dropdown-menu"), 1);
|
|
489
534
|
var React6 = __toESM(require("react"), 1);
|
|
490
535
|
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
491
|
-
var
|
|
492
|
-
var
|
|
493
|
-
var
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
536
|
+
var DropdownMenu = DropdownMenuPrimitive.Root;
|
|
537
|
+
var DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
|
|
538
|
+
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";
|
|
539
|
+
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";
|
|
540
|
+
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";
|
|
541
|
+
var DropdownMenuSubTrigger = React6.forwardRef(({ className, inset, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
542
|
+
DropdownMenuPrimitive.SubTrigger,
|
|
543
|
+
{
|
|
544
|
+
ref,
|
|
545
|
+
"data-slot": "dropdown-menu-sub-trigger",
|
|
546
|
+
className: cn(
|
|
547
|
+
"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",
|
|
548
|
+
inset && "pl-8",
|
|
549
|
+
className
|
|
550
|
+
),
|
|
551
|
+
...props,
|
|
552
|
+
children: [
|
|
553
|
+
children,
|
|
554
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(RadixChevronRightIcon, { className: "ml-auto h-4 w-4" })
|
|
555
|
+
]
|
|
556
|
+
}
|
|
557
|
+
));
|
|
558
|
+
DropdownMenuSubTrigger.displayName = DropdownMenuPrimitive.SubTrigger.displayName;
|
|
559
|
+
var DropdownMenuSubContent = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
560
|
+
DropdownMenuPrimitive.SubContent,
|
|
561
|
+
{
|
|
562
|
+
ref,
|
|
563
|
+
"data-slot": "dropdown-menu-sub-content",
|
|
564
|
+
className: cn(MENU_SURFACE_CLASS, "shadow-lg", MOTION_POPPER, className),
|
|
565
|
+
...props
|
|
566
|
+
}
|
|
567
|
+
));
|
|
568
|
+
DropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName;
|
|
569
|
+
var DropdownMenuContent = React6.forwardRef(({ className, sideOffset = 4, container, ...props }, ref) => {
|
|
570
|
+
const portalContainer = usePortalContainer(container);
|
|
571
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(DropdownMenuPrimitive.Portal, { container: portalContainer, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
572
|
+
DropdownMenuPrimitive.Content,
|
|
573
|
+
{
|
|
574
|
+
ref,
|
|
575
|
+
"data-slot": "dropdown-menu-content",
|
|
576
|
+
sideOffset,
|
|
577
|
+
className: cn(
|
|
578
|
+
MENU_SURFACE_CLASS,
|
|
579
|
+
"shadow-md",
|
|
580
|
+
MOTION_POPPER,
|
|
581
|
+
className
|
|
582
|
+
),
|
|
583
|
+
...props
|
|
584
|
+
}
|
|
585
|
+
) });
|
|
586
|
+
});
|
|
587
|
+
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
|
|
588
|
+
var DropdownMenuItem = React6.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
589
|
+
DropdownMenuPrimitive.Item,
|
|
590
|
+
{
|
|
591
|
+
ref,
|
|
592
|
+
"data-slot": "dropdown-menu-item",
|
|
593
|
+
className: cn(MENU_ITEM_CLASS, inset && "pl-8", className),
|
|
594
|
+
...props
|
|
595
|
+
}
|
|
596
|
+
));
|
|
597
|
+
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
|
|
598
|
+
var DropdownMenuCheckboxItem = React6.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
599
|
+
DropdownMenuPrimitive.CheckboxItem,
|
|
600
|
+
{
|
|
601
|
+
ref,
|
|
602
|
+
"data-slot": "dropdown-menu-checkbox-item",
|
|
603
|
+
className: cn(MENU_INDICATOR_ITEM_CLASS, className),
|
|
604
|
+
...props,
|
|
605
|
+
children: [
|
|
606
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(DropdownMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(CheckIcon, { className: "h-4 w-4" }) }) }),
|
|
607
|
+
children
|
|
608
|
+
]
|
|
609
|
+
}
|
|
610
|
+
));
|
|
611
|
+
DropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName;
|
|
612
|
+
var DropdownMenuRadioItem = React6.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
613
|
+
DropdownMenuPrimitive.RadioItem,
|
|
614
|
+
{
|
|
615
|
+
ref,
|
|
616
|
+
"data-slot": "dropdown-menu-radio-item",
|
|
617
|
+
className: cn(MENU_INDICATOR_ITEM_CLASS, className),
|
|
618
|
+
...props,
|
|
619
|
+
children: [
|
|
620
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(DropdownMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(DotFilledIcon, { className: "h-4 w-4 fill-current" }) }) }),
|
|
621
|
+
children
|
|
622
|
+
]
|
|
623
|
+
}
|
|
624
|
+
));
|
|
625
|
+
DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
|
|
626
|
+
var DropdownMenuLabel = React6.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
627
|
+
DropdownMenuPrimitive.Label,
|
|
628
|
+
{
|
|
629
|
+
ref,
|
|
630
|
+
"data-slot": "dropdown-menu-label",
|
|
631
|
+
className: cn("px-2 py-1.5 text-sm font-semibold", inset && "pl-8", className),
|
|
632
|
+
...props
|
|
633
|
+
}
|
|
634
|
+
));
|
|
635
|
+
DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
|
|
636
|
+
var DropdownMenuSeparator = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
637
|
+
DropdownMenuPrimitive.Separator,
|
|
638
|
+
{
|
|
639
|
+
ref,
|
|
640
|
+
"data-slot": "dropdown-menu-separator",
|
|
641
|
+
className: cn("-mx-1 my-1 h-px bg-muted", className),
|
|
642
|
+
...props
|
|
643
|
+
}
|
|
644
|
+
));
|
|
645
|
+
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
|
|
646
|
+
var DropdownMenuShortcut = ({
|
|
647
|
+
className,
|
|
648
|
+
...props
|
|
649
|
+
}) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
650
|
+
"span",
|
|
651
|
+
{
|
|
652
|
+
"data-slot": "dropdown-menu-shortcut",
|
|
653
|
+
className: cn("ml-auto text-xs tracking-widest opacity-60", className),
|
|
500
654
|
...props
|
|
501
|
-
}, ref) => {
|
|
502
|
-
const portalContainer = usePortalContainer(container);
|
|
503
|
-
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(PopoverPrimitive.Portal, { container: portalContainer, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
504
|
-
PopoverPrimitive.Content,
|
|
505
|
-
{
|
|
506
|
-
ref,
|
|
507
|
-
align,
|
|
508
|
-
sideOffset,
|
|
509
|
-
className: cn(
|
|
510
|
-
// Cap to the viewport space Radix measured and scroll — a popover taller
|
|
511
|
-
// than the screen must never trap the user with unreachable content.
|
|
512
|
-
// z must EQUAL the dialog layer (z-[10000]), never exceed it: with equal
|
|
513
|
-
// z, DOM portal order decides, so a dialog opened FROM a popover stacks
|
|
514
|
-
// above it, and a popover opened from a dialog still stacks above the
|
|
515
|
-
// dialog. z-[10001] buried dialogs behind fullscreen popovers.
|
|
516
|
-
"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",
|
|
517
|
-
animated && MOTION_POPPER,
|
|
518
|
-
className
|
|
519
|
-
),
|
|
520
|
-
...props
|
|
521
|
-
}
|
|
522
|
-
) });
|
|
523
655
|
}
|
|
524
656
|
);
|
|
525
|
-
|
|
657
|
+
DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
|
|
526
658
|
|
|
527
|
-
// src/
|
|
528
|
-
var import_react2 = require("react");
|
|
659
|
+
// src/content-transfer/index.tsx
|
|
529
660
|
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
530
|
-
function
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
661
|
+
function AlchemyGlyph(props) {
|
|
662
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", ...props, children: [
|
|
663
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "M4.5 5.5h8v11h-8z" }),
|
|
664
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "M8.5 9.5h8v9h-8z" }),
|
|
665
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("path", { d: "m18.5 3 .65 1.85L21 5.5l-1.85.65L18.5 8l-.65-1.85L16 5.5l1.85-.65z" })
|
|
666
|
+
] });
|
|
667
|
+
}
|
|
668
|
+
var CapabilityContext = React7.createContext({});
|
|
669
|
+
var useContentTransferCapabilities = () => React7.useContext(CapabilityContext);
|
|
670
|
+
var SurfaceContext = React7.createContext(null);
|
|
671
|
+
function MenuPresentation({ label, hint, icon: Icon2 }) {
|
|
672
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
|
|
673
|
+
Icon2 ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Icon2, { className: "matrx-alchemy-menu-icon" }) : null,
|
|
674
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { children: [
|
|
675
|
+
label,
|
|
676
|
+
hint ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("small", { className: "matrx-alchemy-menu-hint", children: hint }) : null
|
|
677
|
+
] })
|
|
678
|
+
] });
|
|
679
|
+
}
|
|
680
|
+
var LABEL = { plain: "Plain text", markdown: "Markdown", html: "Formatted", json: "JSON", "compact-json": "Compact JSON", csv: "CSV", tsv: "Google Sheets", xlsx: "Excel workbook" };
|
|
681
|
+
var BUILT_INS = Object.freeze(Object.keys(LABEL).map((id) => ({ id })));
|
|
682
|
+
var COPIES = ["plain", "markdown", "html", "json", "compact-json", "csv", "tsv"];
|
|
683
|
+
var DOWNLOADS = [...COPIES, "xlsx"];
|
|
684
|
+
var EMPTY_VARIANTS = [];
|
|
685
|
+
var SCOPE_LABEL = { target: "This content", row: "This row", selected: "Selected rows", view: "Current view", loaded: "Loaded rows", "all-matching": "All matching rows" };
|
|
686
|
+
var filenameFor = (label) => label.toLocaleLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "") || "export";
|
|
687
|
+
var estimateTokens = (text) => Math.ceil(text.length / 4);
|
|
688
|
+
var errorMessage = (error, fallback) => error instanceof Error ? error.message : fallback;
|
|
689
|
+
var isAbort = (error) => error instanceof DOMException && error.name === "AbortError";
|
|
690
|
+
var supportsBuiltIn = (format, payload) => !["csv", "tsv", "xlsx"].includes(format) || payload.kind === "rows";
|
|
691
|
+
var outcomeMessage = (result) => {
|
|
692
|
+
if (result.status === "success") {
|
|
693
|
+
const success = result;
|
|
694
|
+
return success.delivered === "action" ? success.message ?? "Action completed" : success.delivered === "download-started" ? "Download started" : success.message ?? "Copied";
|
|
695
|
+
}
|
|
696
|
+
return result.status === "degraded" ? `Copied as plain text: ${result.reason}` : result.status === "cancelled" ? "Cancelled" : result.message;
|
|
697
|
+
};
|
|
698
|
+
var materialIds = /* @__PURE__ */ new WeakMap();
|
|
699
|
+
var nextMaterialId = 0;
|
|
700
|
+
function materialIdentity(material) {
|
|
701
|
+
if (!material) return "missing";
|
|
702
|
+
if ("instanceId" in material) return `surface:${material.instanceId}`;
|
|
703
|
+
if ("id" in material) return `source:${material.id}`;
|
|
704
|
+
let id = materialIds.get(material);
|
|
705
|
+
if (id === void 0) {
|
|
706
|
+
id = ++nextMaterialId;
|
|
707
|
+
materialIds.set(material, id);
|
|
708
|
+
}
|
|
709
|
+
return `payload:${id}`;
|
|
710
|
+
}
|
|
711
|
+
function useFence() {
|
|
712
|
+
const mounted = React7.useRef(true);
|
|
713
|
+
const nextId = React7.useRef(0);
|
|
714
|
+
const active = React7.useRef(/* @__PURE__ */ new Set());
|
|
715
|
+
React7.useEffect(() => {
|
|
716
|
+
mounted.current = true;
|
|
717
|
+
return () => {
|
|
718
|
+
mounted.current = false;
|
|
719
|
+
nextId.current += 1;
|
|
720
|
+
active.current.forEach((c) => c.abort());
|
|
721
|
+
active.current.clear();
|
|
722
|
+
};
|
|
723
|
+
}, []);
|
|
724
|
+
const begin = React7.useCallback(() => {
|
|
725
|
+
const controller = new AbortController();
|
|
726
|
+
active.current.add(controller);
|
|
727
|
+
return { controller, id: ++nextId.current };
|
|
728
|
+
}, []);
|
|
729
|
+
const finish = React7.useCallback((controller) => active.current.delete(controller), []);
|
|
730
|
+
const valid = React7.useCallback((id, controller) => mounted.current && !controller.signal.aborted && nextId.current === id, []);
|
|
731
|
+
const abortAll = React7.useCallback(() => {
|
|
732
|
+
nextId.current += 1;
|
|
733
|
+
active.current.forEach((c) => c.abort());
|
|
734
|
+
active.current.clear();
|
|
735
|
+
}, []);
|
|
736
|
+
return { begin, finish, valid, abortAll };
|
|
737
|
+
}
|
|
738
|
+
async function xlsxArtifact(draft, label) {
|
|
739
|
+
if (draft.payload.kind !== "rows") throw new Error("Excel workbook export requires tabular content.");
|
|
740
|
+
const XLSX = await import("xlsx");
|
|
741
|
+
const columns = draft.payload.columns.filter((c) => c.visible && c.exportable !== false && c.classification !== "secret" && c.classification !== "credential");
|
|
742
|
+
const cells = draft.payload.rows.map((row) => columns.map((column) => {
|
|
743
|
+
const value = (0, import_content_transfer.readTransferCell)(row, column);
|
|
744
|
+
return value === null || ["string", "number", "boolean"].includes(typeof value) ? value : value === void 0 ? "" : JSON.stringify(value);
|
|
745
|
+
}));
|
|
746
|
+
const sheet = XLSX.utils.aoa_to_sheet([columns.map((c) => c.label), ...cells]);
|
|
747
|
+
const book = XLSX.utils.book_new();
|
|
748
|
+
XLSX.utils.book_append_sheet(book, sheet, label.replace(/[\\/?*[\]:]/g, " ").trim().slice(0, 31) || "Data");
|
|
749
|
+
const written = XLSX.write(book, { type: "array", bookType: "xlsx", compression: true });
|
|
750
|
+
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] });
|
|
751
|
+
}
|
|
752
|
+
async function buildArtifact(draft, format, label) {
|
|
753
|
+
if (!supportsBuiltIn(format, draft.payload)) throw new Error(`${LABEL[format]} is available for tabular content only.`);
|
|
754
|
+
if (format === "xlsx") return xlsxArtifact(draft, label);
|
|
755
|
+
if (format === "html" && draft.payload.kind === "markdown") return (0, import_content_transfer.serializeMarkdownRich)(draft, `${filenameFor(label)}.html`);
|
|
756
|
+
const extension = format === "plain" ? "txt" : format === "compact-json" ? "json" : format;
|
|
757
|
+
return (0, import_content_transfer.serialize)(draft, format, { spreadsheetSafe: format === "csv" || format === "tsv", filename: `${filenameFor(label)}.${extension}` });
|
|
758
|
+
}
|
|
759
|
+
function ContentTransferMenu({ source, surface, label, projection, sections, preferences, table, formatSources, variants = EMPTY_VARIANTS, actions = [], capabilities: local, disabled, enabled = true, className, stopPropagation = true, hide = [], controllerRef }) {
|
|
760
|
+
const triggerRef = React7.useRef(null);
|
|
761
|
+
const inherited = React7.useContext(CapabilityContext);
|
|
762
|
+
const nearestSurface = React7.useContext(SurfaceContext);
|
|
763
|
+
const fence = useFence();
|
|
764
|
+
const [menuCapture, setMenuCapture] = React7.useState(null);
|
|
765
|
+
const [menuStatus, setMenuStatus] = React7.useState("idle");
|
|
766
|
+
const [workspaces, setWorkspaces] = React7.useState({});
|
|
767
|
+
const [workspaceKey, setWorkspaceKey] = React7.useState(null);
|
|
768
|
+
const [workspaceOpen, setWorkspaceOpen] = React7.useState(false);
|
|
769
|
+
const workspaceCaptures = React7.useRef(/* @__PURE__ */ new Map());
|
|
770
|
+
const externalWorkspaceKeys = React7.useRef(/* @__PURE__ */ new Set());
|
|
771
|
+
const [notice, setNotice] = React7.useState(null);
|
|
772
|
+
const scopes = React7.useMemo(() => table?.availableScopes ?? ["target"], [table]);
|
|
773
|
+
const initialScope = table?.initialScope ?? "target";
|
|
774
|
+
if (!scopes.includes(initialScope)) throw new Error("Alchemy initialScope must be included in availableScopes.");
|
|
775
|
+
const primary = surface ?? source ?? nearestSurface;
|
|
776
|
+
const sourceLabel = label ?? (surface?.surfaceName ?? (source && "label" in source ? source.label : nearestSurface?.surfaceName) ?? "content");
|
|
777
|
+
const primaryWorkspaceKey = `primary:${materialIdentity(primary)}`;
|
|
778
|
+
const nearestWorkspaceKey = source && !surface && nearestSurface ? `surface:${materialIdentity(nearestSurface)}` : null;
|
|
779
|
+
const variantWorkspaceKeys = React7.useMemo(() => new Map(variants.map((variant) => [variant.id, `variant:${variant.id}:${materialIdentity(variant.source)}`])), [variants]);
|
|
780
|
+
const transport = local?.transport ?? inherited.transport ?? (0, import_content_transfer.createBrowserTransport)();
|
|
781
|
+
const ai = local?.ai ?? inherited.ai;
|
|
782
|
+
const providerPreferences = React7.useMemo(() => (0, import_content_transfer.resolveTransferPreferences)(inherited.preferences, local?.preferences), [inherited.preferences, local?.preferences]);
|
|
783
|
+
const adapters = React7.useMemo(() => (0, import_content_transfer.resolveTransferRegistry)(BUILT_INS, inherited.formats ?? [], local?.formats ?? []).filter((x) => "build" in x), [inherited.formats, local?.formats]);
|
|
784
|
+
const registeredActions = React7.useMemo(() => (0, import_content_transfer.resolveTransferRegistry)(inherited.actions ?? [], local?.actions ?? [], actions), [actions, inherited.actions, local?.actions]);
|
|
785
|
+
React7.useMemo(() => (0, import_content_transfer.resolveTransferRegistry)(variants), [variants]);
|
|
786
|
+
const report = React7.useCallback((result) => {
|
|
787
|
+
inherited.onOutcome?.(result);
|
|
788
|
+
local?.onOutcome?.(result);
|
|
789
|
+
setNotice(outcomeMessage(result));
|
|
790
|
+
}, [inherited, local]);
|
|
791
|
+
React7.useEffect(() => {
|
|
792
|
+
const valid = /* @__PURE__ */ new Set([primaryWorkspaceKey, ...nearestWorkspaceKey ? [nearestWorkspaceKey] : [], ...variantWorkspaceKeys.values(), ...externalWorkspaceKeys.current]);
|
|
793
|
+
setWorkspaces((current) => Object.fromEntries(Object.entries(current).filter(([key]) => valid.has(key))));
|
|
794
|
+
for (const key of workspaceCaptures.current.keys()) if (!valid.has(key)) workspaceCaptures.current.delete(key);
|
|
795
|
+
if (workspaceKey && !valid.has(workspaceKey)) {
|
|
796
|
+
setWorkspaceKey(null);
|
|
797
|
+
setWorkspaceOpen(false);
|
|
541
798
|
}
|
|
542
|
-
};
|
|
543
|
-
const
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
799
|
+
}, [nearestWorkspaceKey, primaryWorkspaceKey, variantWorkspaceKeys, workspaceKey]);
|
|
800
|
+
const captureOne = React7.useCallback(async (material, scope, signal, applyMenuProjection = false, collectPages = true) => {
|
|
801
|
+
if (!material) throw new Error("Alchemy needs a source or a mounted transfer surface.");
|
|
802
|
+
let sourceMaterial;
|
|
803
|
+
if ("instanceId" in material) {
|
|
804
|
+
if (!material.isMounted()) throw new Error("The requested transfer surface is no longer mounted.");
|
|
805
|
+
const captured = await material.capture(signal);
|
|
806
|
+
sourceMaterial = { id: captured.snapshot.sourceId, label: captured.snapshot.label, capture: async () => captured };
|
|
807
|
+
} else if ("kind" in material) {
|
|
808
|
+
sourceMaterial = applyMenuProjection ? { id: "direct", label: sourceLabel, capture: async () => (0, import_content_transfer.directSource)(material, { label: sourceLabel, ...projection ? { projection } : {}, ...sections ? { sections } : {} }) } : material;
|
|
809
|
+
} else if (applyMenuProjection && (projection || sections)) {
|
|
810
|
+
sourceMaterial = {
|
|
811
|
+
id: material.id,
|
|
812
|
+
label: material.label,
|
|
813
|
+
capture: async (request) => {
|
|
814
|
+
const captured = await material.capture(request);
|
|
815
|
+
return {
|
|
816
|
+
...captured,
|
|
817
|
+
projection: { rules: [...captured.projection.rules, ...projection?.rules ?? []] },
|
|
818
|
+
snapshot: { ...captured.snapshot, ...sections ? { sections } : {} }
|
|
819
|
+
};
|
|
820
|
+
}
|
|
821
|
+
};
|
|
822
|
+
} else {
|
|
823
|
+
sourceMaterial = material;
|
|
824
|
+
}
|
|
825
|
+
const raw = "kind" in sourceMaterial ? (0, import_content_transfer.directSource)(sourceMaterial) : await sourceMaterial.capture({ scope, signal });
|
|
826
|
+
const constrained = (0, import_content_transfer.resolveTransferPreferences)(providerPreferences, preferences, raw.snapshot.limits);
|
|
827
|
+
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);
|
|
828
|
+
if (scope !== "all-matching" || !collectPages) return result;
|
|
829
|
+
if (!result.allMatching) throw new Error("This source cannot provide a stable all-matching export.");
|
|
830
|
+
const collected = await (0, import_content_transfer.collectAllMatching)(result.allMatching, signal);
|
|
831
|
+
if (result.snapshot.payload.kind !== "rows") throw new Error("All-matching export requires tabular content.");
|
|
832
|
+
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 } : {} };
|
|
833
|
+
}, [preferences, projection, providerPreferences, sections, sourceLabel]);
|
|
834
|
+
const capturePrimary = React7.useCallback((scope, signal) => captureOne(primary, scope, signal, true), [captureOne, primary]);
|
|
835
|
+
workspaceCaptures.current.set(primaryWorkspaceKey, capturePrimary);
|
|
836
|
+
if (nearestWorkspaceKey && nearestSurface) workspaceCaptures.current.set(nearestWorkspaceKey, (scope, signal) => captureOne(nearestSurface, scope, signal, true));
|
|
837
|
+
for (const variant of variants) {
|
|
838
|
+
const key = variantWorkspaceKeys.get(variant.id);
|
|
839
|
+
workspaceCaptures.current.set(key, (scope, signal) => captureOne(variant.source, scope, signal, true));
|
|
840
|
+
}
|
|
841
|
+
const preflight = React7.useCallback(async () => {
|
|
842
|
+
const { controller, id } = fence.begin();
|
|
843
|
+
setMenuCapture(null);
|
|
844
|
+
setMenuStatus("loading");
|
|
845
|
+
try {
|
|
846
|
+
const result = await captureOne(primary, initialScope, controller.signal, true, false);
|
|
847
|
+
if (fence.valid(id, controller)) {
|
|
848
|
+
setMenuCapture(result);
|
|
849
|
+
setMenuStatus("idle");
|
|
850
|
+
}
|
|
851
|
+
} catch (error) {
|
|
852
|
+
if (fence.valid(id, controller)) {
|
|
853
|
+
setMenuCapture(null);
|
|
854
|
+
setMenuStatus(errorMessage(error, "Could not inspect content"));
|
|
855
|
+
}
|
|
856
|
+
} finally {
|
|
857
|
+
fence.finish(controller);
|
|
858
|
+
}
|
|
859
|
+
}, [captureOne, fence, initialScope, primary]);
|
|
860
|
+
const transfer = React7.useCallback(async (format, download, alternate) => {
|
|
861
|
+
const { controller, id } = fence.begin();
|
|
862
|
+
try {
|
|
863
|
+
const explicit = alternate?.source ?? (typeof format === "string" && format !== "xlsx" ? formatSources?.[format] : void 0);
|
|
864
|
+
const result = await (explicit ? captureOne(explicit, initialScope, controller.signal, true) : capturePrimary(initialScope, controller.signal));
|
|
865
|
+
if (result.collectionError) throw new Error(`The complete source could not be collected: ${result.collectionError}`);
|
|
866
|
+
if (result.snapshot.coverage.status !== "complete" || result.snapshot.omissions.length > 0) {
|
|
867
|
+
const reason = result.snapshot.coverage.reason ?? `${result.snapshot.omissions.length} omission${result.snapshot.omissions.length === 1 ? "" : "s"}`;
|
|
868
|
+
throw new Error(`Quick transfer is partial (${reason}). Open Prepare for AI to review it before delivery.`);
|
|
869
|
+
}
|
|
870
|
+
const resolved = (0, import_content_transfer.resolveTransferPreferences)(providerPreferences, preferences, result.snapshot.limits);
|
|
871
|
+
const draft = (0, import_content_transfer.applyTransferLimits)((0, import_content_transfer.createDraft)(result.snapshot), resolved.limits);
|
|
872
|
+
const revision = draft.revision;
|
|
873
|
+
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.");
|
|
874
|
+
const artifact = typeof format === "string" ? await buildArtifact(draft, format, result.snapshot.label) : await format.build(draft, controller.signal);
|
|
875
|
+
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.`);
|
|
876
|
+
if (!fence.valid(id, controller) || artifact.snapshotId !== result.snapshot.id || artifact.draftRevision !== revision) return;
|
|
877
|
+
const outcome = await transport[download ? "download" : "copy"](artifact, controller.signal);
|
|
878
|
+
if (fence.valid(id, controller)) report(outcome.status === "success" && alternate?.successMessage ? { ...outcome, message: alternate.successMessage } : outcome);
|
|
879
|
+
} catch (error) {
|
|
880
|
+
if (fence.valid(id, controller)) report({ status: "error", code: "prepare-failed", message: errorMessage(error, "Preparation failed"), retryable: true });
|
|
881
|
+
} finally {
|
|
882
|
+
fence.finish(controller);
|
|
883
|
+
}
|
|
884
|
+
}, [captureOne, capturePrimary, fence, formatSources, initialScope, preferences, providerPreferences, report, transport]);
|
|
885
|
+
const openWorkspace = React7.useCallback(async (key = primaryWorkspaceKey, variant) => {
|
|
886
|
+
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;
|
|
887
|
+
const captureWorkspace = variantMaterial ? (scope, signal) => captureOne(variantMaterial, scope, signal, true) : capturePrimary;
|
|
888
|
+
workspaceCaptures.current.set(key, captureWorkspace);
|
|
889
|
+
if (workspaces[key]) {
|
|
890
|
+
setWorkspaceKey(key);
|
|
891
|
+
setWorkspaceOpen(true);
|
|
892
|
+
return;
|
|
893
|
+
}
|
|
894
|
+
const { controller, id } = fence.begin();
|
|
895
|
+
try {
|
|
896
|
+
const result = await captureWorkspace(initialScope, controller.signal);
|
|
897
|
+
if (!fence.valid(id, controller)) return;
|
|
898
|
+
const resolved = (0, import_content_transfer.resolveTransferPreferences)(providerPreferences, preferences, result.snapshot.limits);
|
|
899
|
+
const original = (0, import_content_transfer.createDraft)(result.snapshot);
|
|
900
|
+
const base = { ...result, key, original, draft: original, scope: initialScope, preferences: resolved, ...result.collectionError ? { error: result.collectionError } : {} };
|
|
901
|
+
setWorkspaces((current) => ({ ...current, [key]: { ...base, draft: rebuild(base, initialControls(base)) } }));
|
|
902
|
+
setWorkspaceKey(key);
|
|
903
|
+
setWorkspaceOpen(true);
|
|
904
|
+
} catch (error) {
|
|
905
|
+
if (fence.valid(id, controller)) setNotice(errorMessage(error, "Could not capture content"));
|
|
906
|
+
} finally {
|
|
907
|
+
fence.finish(controller);
|
|
908
|
+
}
|
|
909
|
+
}, [captureOne, capturePrimary, fence, initialScope, preferences, primaryWorkspaceKey, providerPreferences, workspaces]);
|
|
910
|
+
React7.useImperativeHandle(controllerRef, () => ({
|
|
911
|
+
focusTrigger: () => triggerRef.current?.focus(),
|
|
912
|
+
prepare: async (requestedSource, options) => {
|
|
913
|
+
const requestedLabel = options?.label ?? ("label" in requestedSource ? requestedSource.label : "content");
|
|
914
|
+
const requestedKey = `controller:${options?.id ?? "source"}:${materialIdentity(requestedSource)}`;
|
|
915
|
+
externalWorkspaceKeys.current.add(requestedKey);
|
|
916
|
+
await openWorkspace(requestedKey, { source: requestedSource, label: requestedLabel });
|
|
917
|
+
}
|
|
918
|
+
}), [openWorkspace]);
|
|
919
|
+
const runAction = React7.useCallback(async (action) => {
|
|
920
|
+
const { controller, id } = fence.begin();
|
|
921
|
+
try {
|
|
922
|
+
const actionSource = action.source;
|
|
923
|
+
const { snapshot } = actionSource ? await captureOne(actionSource, initialScope, controller.signal, true) : await capturePrimary(initialScope, controller.signal);
|
|
924
|
+
const resolved = (0, import_content_transfer.resolveTransferPreferences)(providerPreferences, preferences, snapshot.limits);
|
|
925
|
+
const draft = (0, import_content_transfer.applyTransferLimits)((0, import_content_transfer.createDraft)(snapshot), resolved.limits);
|
|
926
|
+
if (!action.supports(snapshot)) throw new Error(`${action.label} is unavailable for this content.`);
|
|
927
|
+
const result = await action.run({ snapshot, draft, signal: controller.signal });
|
|
928
|
+
if (fence.valid(id, controller) && draft.snapshotId === snapshot.id) report(result);
|
|
929
|
+
} catch (error) {
|
|
930
|
+
if (fence.valid(id, controller)) report({ status: "error", code: "action-failed", message: errorMessage(error, "Action failed"), retryable: true });
|
|
931
|
+
} finally {
|
|
932
|
+
fence.finish(controller);
|
|
933
|
+
}
|
|
934
|
+
}, [captureOne, capturePrimary, fence, initialScope, preferences, providerPreferences, report]);
|
|
935
|
+
if (!enabled) return null;
|
|
936
|
+
const payload = menuCapture?.snapshot.payload ?? (source && "kind" in source ? source : void 0);
|
|
937
|
+
const quickVariants = (section) => variants.filter((v) => v.copyLabel && (v.section ?? "ai") === section).map((v) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(DropdownMenuItem, { "aria-label": v.ariaLabel, onSelect: () => void transfer("markdown", false, v), children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(MenuPresentation, { ...v, label: v.copyLabel }) }, `copy:${v.id}`));
|
|
938
|
+
const visibleCopies = COPIES.filter((f) => Boolean(formatSources?.[f]) || !["csv", "tsv"].includes(f) || payload?.kind === "rows");
|
|
939
|
+
const visibleDownloads = DOWNLOADS.filter((f) => f !== "xlsx" && Boolean(formatSources?.[f]) || !["csv", "tsv", "xlsx"].includes(f) || payload?.kind === "rows");
|
|
940
|
+
const visibleAdapters = menuCapture ? adapters.filter((a) => a.supports(menuCapture.snapshot.payload)) : [];
|
|
941
|
+
const visibleActions = menuCapture ? registeredActions.filter((a) => a.supports(menuCapture.snapshot)) : [];
|
|
942
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: cn("matrx-alchemy", className), onClick: stopPropagation ? (event) => event.stopPropagation() : void 0, children: [
|
|
943
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(DropdownMenu, { onOpenChange: (open) => {
|
|
944
|
+
if (open) void preflight();
|
|
945
|
+
}, children: [
|
|
946
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime10.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_runtime10.jsx)(AlchemyGlyph, {}) }) }),
|
|
947
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(DropdownMenuContent, { align: "end", className: "matrx-alchemy-menu", children: [
|
|
948
|
+
menuStatus === "loading" ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(DropdownMenuItem, { disabled: true, children: "Inspecting content\u2026" }) : menuStatus !== "idle" ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(DropdownMenuItem, { disabled: true, children: menuStatus }) : null,
|
|
949
|
+
!hide.includes("copy") ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
|
|
950
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(DropdownMenuLabel, { children: "Copy" }),
|
|
951
|
+
quickVariants("copy"),
|
|
952
|
+
visibleCopies.map((format) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(DropdownMenuItem, { onSelect: () => void transfer(format, false), children: format === "plain" ? "Copy" : `Copy ${LABEL[format]}` }, format)),
|
|
953
|
+
visibleAdapters.map((adapter) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(DropdownMenuItem, { onSelect: () => void transfer(adapter, false), children: [
|
|
954
|
+
"Copy ",
|
|
955
|
+
adapter.label
|
|
956
|
+
] }, adapter.id))
|
|
957
|
+
] }) : null,
|
|
958
|
+
!hide.includes("prepare") ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
|
|
959
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(DropdownMenuSeparator, {}),
|
|
960
|
+
quickVariants("ai"),
|
|
961
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(DropdownMenuItem, { onSelect: () => void openWorkspace(), children: "Prepare for AI\u2026" }),
|
|
962
|
+
nearestWorkspaceKey && nearestSurface ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(DropdownMenuItem, { onSelect: () => void openWorkspace(nearestWorkspaceKey, { source: nearestSurface, label: nearestSurface.surfaceName }), children: "Prepare this surface\u2026" }) : null,
|
|
963
|
+
variants.map((variant) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(DropdownMenuItem, { onSelect: () => void openWorkspace(variantWorkspaceKeys.get(variant.id), variant), children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(MenuPresentation, { ...variant, label: `Prepare ${variant.label}\u2026` }) }, variant.id))
|
|
964
|
+
] }) : null,
|
|
965
|
+
!hide.includes("download") ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
|
|
966
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(DropdownMenuSeparator, {}),
|
|
967
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(DropdownMenuLabel, { children: "Download" }),
|
|
968
|
+
visibleDownloads.map((format) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(DropdownMenuItem, { onSelect: () => void transfer(format, true), children: [
|
|
969
|
+
"Download ",
|
|
970
|
+
LABEL[format]
|
|
971
|
+
] }, format)),
|
|
972
|
+
visibleAdapters.map((adapter) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(DropdownMenuItem, { onSelect: () => void transfer(adapter, true), children: [
|
|
973
|
+
"Download ",
|
|
974
|
+
adapter.label
|
|
975
|
+
] }, `download:${adapter.id}`))
|
|
976
|
+
] }) : null,
|
|
977
|
+
visibleActions.length ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(DropdownMenuSeparator, {}) : null,
|
|
978
|
+
visibleActions.map((action) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(DropdownMenuItem, { "aria-label": action.ariaLabel, onSelect: () => void runAction(action), children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(MenuPresentation, { ...action, label: action.label }) }, action.id))
|
|
979
|
+
] })
|
|
980
|
+
] }),
|
|
981
|
+
notice ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "matrx-alchemy-notice", role: "status", children: notice }) : null,
|
|
982
|
+
Object.values(workspaces).map((saved) => /* @__PURE__ */ (0, import_jsx_runtime10.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))
|
|
983
|
+
] });
|
|
548
984
|
}
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
${value.summary ? `<summary>
|
|
567
|
-
${value.summary}
|
|
568
|
-
</summary>
|
|
569
|
-
` : ""}<data format="json">
|
|
570
|
-
\`\`\`json
|
|
571
|
-
${JSON.stringify(value.data, null, 2)}
|
|
572
|
-
\`\`\`
|
|
573
|
-
</data>
|
|
574
|
-
</${value.kind}>`;
|
|
985
|
+
function initialControls(state) {
|
|
986
|
+
const rows = state.original.payload.kind === "rows" ? state.original.payload : null;
|
|
987
|
+
return {
|
|
988
|
+
preset: state.preferences.initialPreset,
|
|
989
|
+
sections: state.snapshot.sections.filter((s) => s.includedByDefault).map((s) => s.id),
|
|
990
|
+
search: "",
|
|
991
|
+
filters: {},
|
|
992
|
+
sort: "",
|
|
993
|
+
direction: "asc",
|
|
994
|
+
top: state.preferences.limits.maxRows,
|
|
995
|
+
visibleColumns: rows?.columns.filter((c) => c.visible).map((c) => c.id) ?? [],
|
|
996
|
+
selectedOnly: false,
|
|
997
|
+
selectedIndices: [],
|
|
998
|
+
maxDepth: state.preferences.limits.maxDepth,
|
|
999
|
+
maxStringChars: state.preferences.limits.maxStringChars,
|
|
1000
|
+
maxArrayItems: state.preferences.limits.maxArrayItems ?? null
|
|
1001
|
+
};
|
|
575
1002
|
}
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
return
|
|
1003
|
+
function presetLimits(preset, controls, preferences) {
|
|
1004
|
+
const min = (choice, cap) => choice == null ? cap : cap == null ? choice : Math.min(choice, cap);
|
|
1005
|
+
if (preset === "full") return preferences.limits;
|
|
1006
|
+
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 };
|
|
1007
|
+
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) };
|
|
581
1008
|
}
|
|
582
|
-
function
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
}
|
|
594
|
-
|
|
1009
|
+
function rebuild(state, controls) {
|
|
1010
|
+
let draft = (0, import_content_transfer.resetDraft)(state.snapshot);
|
|
1011
|
+
if (state.snapshot.sections.length) draft = (0, import_content_transfer.applySectionSelection)(draft, state.snapshot, controls.sections);
|
|
1012
|
+
if (draft.payload.kind === "rows") draft = (0, import_content_transfer.transformRows)(draft, {
|
|
1013
|
+
search: controls.search,
|
|
1014
|
+
filters: controls.filters,
|
|
1015
|
+
...controls.sort ? { sort: { column: controls.sort, direction: controls.direction } } : {},
|
|
1016
|
+
...controls.selectedOnly ? { selectedIndices: controls.selectedIndices } : {},
|
|
1017
|
+
visibleColumns: controls.visibleColumns,
|
|
1018
|
+
structuredProjection: "visible",
|
|
1019
|
+
top: controls.top
|
|
1020
|
+
});
|
|
1021
|
+
const limits = presetLimits(controls.preset, controls, state.preferences);
|
|
1022
|
+
if (draft.payload.kind === "json" || draft.payload.kind === "registered") {
|
|
1023
|
+
draft = (0, import_content_transfer.reduceJson)(draft, { maxDepth: limits.maxDepth, maxStringChars: limits.maxStringChars, maxArrayItems: limits.maxArrayItems ?? null });
|
|
595
1024
|
}
|
|
1025
|
+
return (0, import_content_transfer.applyTransferLimits)(draft, limits);
|
|
596
1026
|
}
|
|
597
|
-
function
|
|
598
|
-
|
|
599
|
-
if (CopyControls) return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(CopyControls, { ...props });
|
|
600
|
-
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(DefaultCopyButtons, { ...props });
|
|
1027
|
+
function isBuiltInFormat(format) {
|
|
1028
|
+
return format in LABEL;
|
|
601
1029
|
}
|
|
602
|
-
function
|
|
603
|
-
const
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
const
|
|
608
|
-
|
|
609
|
-
|
|
1030
|
+
function preview(draft, format) {
|
|
1031
|
+
const resolved = isBuiltInFormat(format) ? format : "plain";
|
|
1032
|
+
return (0, import_content_transfer.serialize)(draft, resolved === "xlsx" ? "tsv" : resolved, { spreadsheetSafe: resolved === "csv" || resolved === "tsv" || resolved === "xlsx" }).plainText;
|
|
1033
|
+
}
|
|
1034
|
+
function PreparationWorkspace({ restoreFocus, open, state, scopes, onClose, onChange, transport, ai, adapters, onOutcome, captureScope }) {
|
|
1035
|
+
const fence = useFence();
|
|
1036
|
+
const latest = React7.useRef(state);
|
|
1037
|
+
latest.current = state;
|
|
1038
|
+
const aiSession = React7.useRef(void 0);
|
|
1039
|
+
if (!aiSession.current && ai) aiSession.current = ai.fork?.() ?? ai;
|
|
1040
|
+
const [controls, setControls] = React7.useState(() => initialControls(state));
|
|
1041
|
+
const [controlsHistory, setControlsHistory] = React7.useState([]);
|
|
1042
|
+
const [pendingControls, setPendingControls] = React7.useState(null);
|
|
1043
|
+
const requestedFormat = state.preferences.initialFormat;
|
|
1044
|
+
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");
|
|
1045
|
+
const [buffer, setBuffer] = React7.useState(() => isBuiltInFormat(format) ? preview(state.draft, format) : "Preparing format preview\u2026");
|
|
1046
|
+
const [bufferError, setBufferError] = React7.useState(null);
|
|
1047
|
+
const [formatError, setFormatError] = React7.useState(null);
|
|
1048
|
+
const [preparedArtifact, setPreparedArtifact] = React7.useState(null);
|
|
1049
|
+
const [instruction, setInstruction] = React7.useState("");
|
|
1050
|
+
const [busy, setBusy] = React7.useState(null);
|
|
1051
|
+
const [aiFailed, setAiFailed] = React7.useState(false);
|
|
1052
|
+
const activeAi = React7.useRef(null);
|
|
1053
|
+
const activeCapture = React7.useRef(null);
|
|
1054
|
+
React7.useEffect(() => {
|
|
1055
|
+
if (bufferError) return;
|
|
1056
|
+
const adapter = adapters.find((candidate) => candidate.id === format);
|
|
1057
|
+
const controller = new AbortController();
|
|
1058
|
+
const snapshotId = state.snapshot.id;
|
|
1059
|
+
const revision = state.draft.revision;
|
|
1060
|
+
setPreparedArtifact(null);
|
|
1061
|
+
setFormatError(null);
|
|
1062
|
+
if (adapter) setBuffer("Preparing format preview\u2026");
|
|
1063
|
+
const artifactPromise = adapter ? adapter.build(state.draft, controller.signal) : buildArtifact(state.draft, isBuiltInFormat(format) ? format : "plain", state.snapshot.label);
|
|
1064
|
+
void artifactPromise.then((artifact) => {
|
|
1065
|
+
if (!controller.signal.aborted && artifact.snapshotId === snapshotId && artifact.draftRevision === revision) {
|
|
1066
|
+
setPreparedArtifact(artifact);
|
|
1067
|
+
setBuffer(artifact.plainText);
|
|
1068
|
+
}
|
|
1069
|
+
}).catch((error) => {
|
|
1070
|
+
if (!controller.signal.aborted) setFormatError(errorMessage(error, "Format preview failed"));
|
|
1071
|
+
});
|
|
1072
|
+
return () => controller.abort();
|
|
1073
|
+
}, [adapters, bufferError, format, state.draft, state.snapshot.id]);
|
|
1074
|
+
const close = React7.useCallback(() => {
|
|
1075
|
+
activeAi.current?.abort();
|
|
1076
|
+
activeCapture.current?.abort();
|
|
1077
|
+
activeAi.current = null;
|
|
1078
|
+
activeCapture.current = null;
|
|
1079
|
+
fence.abortAll();
|
|
1080
|
+
setBusy(null);
|
|
1081
|
+
onClose();
|
|
1082
|
+
}, [fence, onClose]);
|
|
1083
|
+
const changeControls = (next) => {
|
|
1084
|
+
if (state.draft.manuallyEdited) {
|
|
1085
|
+
setPendingControls(next);
|
|
1086
|
+
return;
|
|
1087
|
+
}
|
|
1088
|
+
setControlsHistory((history) => [...history, controls]);
|
|
1089
|
+
setControls(next);
|
|
1090
|
+
onChange({ ...state, draft: rebuild(state, next), error: void 0 });
|
|
1091
|
+
};
|
|
1092
|
+
const applyPendingControls = () => {
|
|
1093
|
+
if (!pendingControls) return;
|
|
1094
|
+
setControlsHistory((history) => [...history, controls]);
|
|
1095
|
+
setControls(pendingControls);
|
|
1096
|
+
setBufferError(null);
|
|
1097
|
+
onChange({ ...state, draft: rebuild(state, pendingControls), error: void 0 });
|
|
1098
|
+
setPendingControls(null);
|
|
1099
|
+
};
|
|
1100
|
+
const editBuffer = (text) => {
|
|
1101
|
+
setBuffer(text);
|
|
1102
|
+
setPreparedArtifact(null);
|
|
1103
|
+
setFormatError(null);
|
|
1104
|
+
const payload = state.draft.payload;
|
|
1105
|
+
if (payload.kind === "json" || payload.kind === "registered") {
|
|
1106
|
+
try {
|
|
1107
|
+
const value = JSON.parse(text);
|
|
1108
|
+
const next = payload.kind === "json" ? { kind: "json", value } : { kind: "registered", format: payload.format, value };
|
|
1109
|
+
setBufferError(null);
|
|
1110
|
+
onChange({ ...state, draft: (0, import_content_transfer.editDraft)(state.draft, next), error: void 0 });
|
|
1111
|
+
} catch {
|
|
1112
|
+
setBufferError("JSON is incomplete or invalid. Fix it before copying or downloading.");
|
|
1113
|
+
}
|
|
1114
|
+
return;
|
|
1115
|
+
}
|
|
1116
|
+
setBufferError(null);
|
|
1117
|
+
const kind = payload.kind === "markdown" || format === "markdown" ? "markdown" : "text";
|
|
1118
|
+
if (payload.kind === "rows" || !isBuiltInFormat(format)) setFormat("plain");
|
|
1119
|
+
onChange({ ...state, draft: (0, import_content_transfer.editDraft)(state.draft, { kind, text }), error: void 0 });
|
|
1120
|
+
};
|
|
1121
|
+
const requestCapture = async (scope) => {
|
|
1122
|
+
activeCapture.current?.abort();
|
|
1123
|
+
const { controller, id } = fence.begin();
|
|
1124
|
+
activeCapture.current = controller;
|
|
1125
|
+
const revision = state.draft.revision;
|
|
1126
|
+
setBusy("capture");
|
|
1127
|
+
try {
|
|
1128
|
+
const result = await captureScope(scope, controller.signal);
|
|
1129
|
+
if (fence.valid(id, controller) && latest.current.draft.revision === revision) onChange({ ...latest.current, pending: { ...result, scope }, error: result.collectionError });
|
|
1130
|
+
} catch (error) {
|
|
1131
|
+
if (fence.valid(id, controller)) onChange({ ...latest.current, error: errorMessage(error, "Refresh failed") });
|
|
1132
|
+
} finally {
|
|
1133
|
+
fence.finish(controller);
|
|
1134
|
+
if (activeCapture.current === controller) activeCapture.current = null;
|
|
1135
|
+
if (fence.valid(id, controller)) setBusy(null);
|
|
1136
|
+
}
|
|
1137
|
+
};
|
|
1138
|
+
const resolveCapture = (choice) => {
|
|
1139
|
+
if (!state.pending) return;
|
|
1140
|
+
if (choice === "keep") {
|
|
1141
|
+
const { pending: _pending, ...kept } = state;
|
|
1142
|
+
onChange({ ...kept, error: void 0 });
|
|
1143
|
+
return;
|
|
1144
|
+
}
|
|
1145
|
+
const pending = state.pending;
|
|
1146
|
+
const preferences = (0, import_content_transfer.resolveTransferPreferences)({}, state.preferences, pending.snapshot.limits);
|
|
1147
|
+
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 } : {} };
|
|
1148
|
+
const nextControls = initialControls(base);
|
|
1149
|
+
setControls(nextControls);
|
|
1150
|
+
setControlsHistory([]);
|
|
1151
|
+
setPendingControls(null);
|
|
1152
|
+
setBufferError(null);
|
|
1153
|
+
onChange({ ...base, draft: rebuild(base, nextControls) });
|
|
1154
|
+
};
|
|
1155
|
+
const runAi = async (recover = false) => {
|
|
1156
|
+
const adapter = aiSession.current;
|
|
1157
|
+
if (!adapter || !adapter.supports(state.snapshot) || !recover && !instruction.trim() || recover && !adapter.recover) return;
|
|
1158
|
+
activeAi.current?.abort();
|
|
1159
|
+
const { controller, id } = fence.begin();
|
|
1160
|
+
activeAi.current = controller;
|
|
1161
|
+
const snapshotId = state.snapshot.id;
|
|
1162
|
+
const revision = state.draft.revision;
|
|
1163
|
+
setBusy("ai");
|
|
1164
|
+
setAiFailed(false);
|
|
610
1165
|
try {
|
|
611
|
-
await
|
|
1166
|
+
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 });
|
|
1167
|
+
const current = latest.current;
|
|
1168
|
+
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;
|
|
1169
|
+
try {
|
|
1170
|
+
(0, import_content_transfer.serialize)(next, "plain");
|
|
1171
|
+
} catch {
|
|
1172
|
+
onChange({ ...current, error: "AI returned an invalid transfer draft." });
|
|
1173
|
+
setAiFailed(true);
|
|
1174
|
+
return;
|
|
1175
|
+
}
|
|
1176
|
+
onChange({ ...current, draft: next, error: void 0 });
|
|
1177
|
+
setBufferError(null);
|
|
612
1178
|
} catch (error) {
|
|
613
|
-
|
|
1179
|
+
if (!isAbort(error) && fence.valid(id, controller)) {
|
|
1180
|
+
setAiFailed(true);
|
|
1181
|
+
onChange({ ...latest.current, error: errorMessage(error, "AI preparation failed") });
|
|
1182
|
+
}
|
|
614
1183
|
} finally {
|
|
615
|
-
|
|
1184
|
+
fence.finish(controller);
|
|
1185
|
+
if (activeAi.current === controller) activeAi.current = null;
|
|
1186
|
+
if (fence.valid(id, controller)) setBusy(null);
|
|
616
1187
|
}
|
|
617
1188
|
};
|
|
618
|
-
const
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
const
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
1189
|
+
const cancelAi = async () => {
|
|
1190
|
+
const aiController = activeAi.current;
|
|
1191
|
+
const { controller, id } = fence.begin();
|
|
1192
|
+
try {
|
|
1193
|
+
await aiSession.current?.cancel?.();
|
|
1194
|
+
} catch (error) {
|
|
1195
|
+
if (fence.valid(id, controller)) onChange({ ...latest.current, error: errorMessage(error, "AI cancellation failed") });
|
|
1196
|
+
} finally {
|
|
1197
|
+
aiController?.abort();
|
|
1198
|
+
fence.finish(controller);
|
|
1199
|
+
if (activeAi.current === aiController) activeAi.current = null;
|
|
1200
|
+
if (fence.valid(id, controller)) setBusy(null);
|
|
1201
|
+
}
|
|
1202
|
+
};
|
|
1203
|
+
const [deliveryNotice, setDeliveryNotice] = React7.useState(null);
|
|
1204
|
+
React7.useEffect(() => {
|
|
1205
|
+
setDeliveryNotice(null);
|
|
1206
|
+
}, [state.draft.revision]);
|
|
1207
|
+
const reportDelivery = (outcome) => {
|
|
1208
|
+
setDeliveryNotice(outcomeMessage(outcome));
|
|
1209
|
+
onOutcome(outcome);
|
|
1210
|
+
};
|
|
1211
|
+
const deliver = async (download) => {
|
|
1212
|
+
if (bufferError) return;
|
|
1213
|
+
const { controller, id } = fence.begin();
|
|
1214
|
+
const snapshotId = state.snapshot.id;
|
|
1215
|
+
const revision = state.draft.revision;
|
|
1216
|
+
setBusy(download ? "download" : "copy");
|
|
1217
|
+
try {
|
|
1218
|
+
if (!preparedArtifact) throw new Error("Wait for the selected format preview before delivery.");
|
|
1219
|
+
const artifact = preparedArtifact;
|
|
1220
|
+
const current = latest.current;
|
|
1221
|
+
if (!fence.valid(id, controller) || current.snapshot.id !== snapshotId || current.draft.revision !== revision || artifact.snapshotId !== snapshotId || artifact.draftRevision !== revision) return;
|
|
1222
|
+
const result = await transport[download ? "download" : "copy"](artifact, controller.signal);
|
|
1223
|
+
if (fence.valid(id, controller)) reportDelivery(result);
|
|
1224
|
+
} catch (error) {
|
|
1225
|
+
if (fence.valid(id, controller)) reportDelivery({ status: "error", code: "prepare-failed", message: errorMessage(error, "Preparation failed"), retryable: true });
|
|
1226
|
+
} finally {
|
|
1227
|
+
fence.finish(controller);
|
|
1228
|
+
if (fence.valid(id, controller)) setBusy(null);
|
|
1229
|
+
}
|
|
1230
|
+
};
|
|
1231
|
+
const rows = state.original.payload.kind === "rows" ? state.original.payload : null;
|
|
1232
|
+
const formats = COPIES.filter((f) => supportsBuiltIn(f, state.draft.payload));
|
|
1233
|
+
const workspaceAdapters = adapters.filter((adapter) => adapter.supports(state.draft.payload));
|
|
1234
|
+
const displayedOmissions = preparedArtifact?.omissions ?? state.draft.omissions;
|
|
1235
|
+
const limitText = Object.entries(state.preferences.limits).filter(([, value]) => value != null).map(([key, value]) => `${key.replace(/^max/, "max ")} ${Number(value).toLocaleString()}`).join(" \xB7 ");
|
|
1236
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Dialog, { open, onOpenChange: (next) => {
|
|
1237
|
+
if (!next) close();
|
|
1238
|
+
}, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(DialogContent, { onCloseAutoFocus: (event) => {
|
|
1239
|
+
event.preventDefault();
|
|
1240
|
+
restoreFocus();
|
|
1241
|
+
}, className: "matrx-alchemy-workspace max-w-5xl", "aria-busy": busy !== null, children: [
|
|
1242
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(DialogHeader, { children: [
|
|
1243
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(DialogTitle, { children: [
|
|
1244
|
+
"Prepare ",
|
|
1245
|
+
state.snapshot.label
|
|
1246
|
+
] }),
|
|
1247
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(DialogDescription, { children: [
|
|
1248
|
+
"Captured ",
|
|
1249
|
+
state.snapshot.unsavedChanges ? "from your unsaved draft" : "as an immutable snapshot",
|
|
1250
|
+
". Your source is never edited."
|
|
656
1251
|
] })
|
|
1252
|
+
] }),
|
|
1253
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "matrx-alchemy-workspace-grid", children: [
|
|
1254
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("section", { className: "matrx-alchemy-main", children: [
|
|
1255
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "matrx-alchemy-toolbar", children: [
|
|
1256
|
+
scopes.length > 1 ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { children: [
|
|
1257
|
+
"Scope",
|
|
1258
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.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_runtime10.jsx)("option", { value: scope, children: SCOPE_LABEL[scope] }, scope)) })
|
|
1259
|
+
] }) : null,
|
|
1260
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { children: [
|
|
1261
|
+
"Detail",
|
|
1262
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("select", { "aria-label": "Detail preset", value: controls.preset, onChange: (e) => changeControls({ ...controls, preset: e.target.value }), children: [
|
|
1263
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: "full", children: "Full" }),
|
|
1264
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: "compact", children: "Compact" }),
|
|
1265
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: "brief", children: "Brief" }),
|
|
1266
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: "custom", children: "Custom" })
|
|
1267
|
+
] })
|
|
1268
|
+
] }),
|
|
1269
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Button, { type: "button", size: "sm", variant: "outline", disabled: !state.draft.history?.length && !controlsHistory.length || busy !== null, onClick: () => {
|
|
1270
|
+
setBufferError(null);
|
|
1271
|
+
if (controlsHistory.length) {
|
|
1272
|
+
const next = controlsHistory[controlsHistory.length - 1];
|
|
1273
|
+
setControls(next);
|
|
1274
|
+
setControlsHistory((history) => history.slice(0, -1));
|
|
1275
|
+
onChange({ ...state, draft: rebuild(state, next), error: void 0 });
|
|
1276
|
+
} else onChange({ ...state, draft: (0, import_content_transfer.undoDraft)(state.draft), error: void 0 });
|
|
1277
|
+
}, children: "Undo" }),
|
|
1278
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Button, { type: "button", size: "sm", variant: "outline", disabled: busy !== null, onClick: () => {
|
|
1279
|
+
const next = initialControls(state);
|
|
1280
|
+
setControls(next);
|
|
1281
|
+
setControlsHistory([]);
|
|
1282
|
+
setPendingControls(null);
|
|
1283
|
+
setBufferError(null);
|
|
1284
|
+
onChange({ ...state, draft: rebuild(state, next), error: void 0 });
|
|
1285
|
+
}, children: "Reset" }),
|
|
1286
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Button, { type: "button", size: "sm", variant: "outline", disabled: busy !== null, onClick: () => void requestCapture(state.scope), children: "Refresh source" })
|
|
1287
|
+
] }),
|
|
1288
|
+
controls.preset === "custom" && (state.draft.payload.kind === "json" || state.draft.payload.kind === "registered") ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("fieldset", { className: "matrx-alchemy-options", children: [
|
|
1289
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("legend", { children: "JSON limits" }),
|
|
1290
|
+
[["maxDepth", "Maximum depth"], ["maxStringChars", "Maximum string characters"], ["maxArrayItems", "Maximum array items"]].map(([key, text]) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { children: [
|
|
1291
|
+
text,
|
|
1292
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("input", { type: "number", min: "0", value: controls[key] ?? "", onChange: (e) => changeControls({ ...controls, [key]: Number.isNaN(e.target.valueAsNumber) ? null : e.target.valueAsNumber }) })
|
|
1293
|
+
] }, key))
|
|
1294
|
+
] }) : null,
|
|
1295
|
+
rows ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(RowControls, { rows, controls, change: changeControls }) : null,
|
|
1296
|
+
state.snapshot.sections.length ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("fieldset", { className: "matrx-alchemy-options", children: [
|
|
1297
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("legend", { children: "Sections" }),
|
|
1298
|
+
state.snapshot.sections.map((section) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { children: [
|
|
1299
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.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) }) }),
|
|
1300
|
+
" ",
|
|
1301
|
+
section.label
|
|
1302
|
+
] }, section.id))
|
|
1303
|
+
] }) : null,
|
|
1304
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "matrx-alchemy-coverage", children: [
|
|
1305
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { children: [
|
|
1306
|
+
state.snapshot.coverage.included.toLocaleString(),
|
|
1307
|
+
" included",
|
|
1308
|
+
state.snapshot.coverage.total == null ? "" : ` of ${state.snapshot.coverage.total.toLocaleString()}`,
|
|
1309
|
+
" \xB7 ",
|
|
1310
|
+
state.snapshot.coverage.status
|
|
1311
|
+
] }),
|
|
1312
|
+
state.snapshot.coverage.reason ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: state.snapshot.coverage.reason }) : null,
|
|
1313
|
+
limitText ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { children: [
|
|
1314
|
+
"Limits: ",
|
|
1315
|
+
limitText
|
|
1316
|
+
] }) : null,
|
|
1317
|
+
displayedOmissions.length ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("details", { children: [
|
|
1318
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("summary", { children: [
|
|
1319
|
+
displayedOmissions.length,
|
|
1320
|
+
" omissions or adjustments"
|
|
1321
|
+
] }),
|
|
1322
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("ul", { children: displayedOmissions.map((o, i) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("li", { children: [
|
|
1323
|
+
o.path || "/",
|
|
1324
|
+
": ",
|
|
1325
|
+
o.reason,
|
|
1326
|
+
o.count == null ? "" : ` (${o.count})`
|
|
1327
|
+
] }, `${o.path}-${o.reason}-${i}`)) })
|
|
1328
|
+
] }) : null
|
|
1329
|
+
] }),
|
|
1330
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { className: "matrx-alchemy-preview-label", children: [
|
|
1331
|
+
"Output format",
|
|
1332
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("select", { "aria-label": "Output format", value: format, onChange: (e) => setFormat(e.target.value), children: [
|
|
1333
|
+
formats.map((f) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: f, children: LABEL[f] }, f)),
|
|
1334
|
+
state.draft.payload.kind === "rows" ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: "xlsx", children: "Excel workbook" }) : null,
|
|
1335
|
+
workspaceAdapters.map((adapter) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: adapter.id, children: adapter.label }, adapter.id))
|
|
1336
|
+
] })
|
|
1337
|
+
] }),
|
|
1338
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.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) }),
|
|
1339
|
+
bufferError ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { id: "alchemy-buffer-error", role: "alert", className: "matrx-alchemy-error", children: bufferError }) : null,
|
|
1340
|
+
formatError ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { role: "alert", className: "matrx-alchemy-error", children: formatError }) : null,
|
|
1341
|
+
bufferError ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Button, { type: "button", variant: "outline", disabled: busy !== null, onClick: () => {
|
|
1342
|
+
const fallback = (0, import_content_transfer.editDraft)(state.draft, { kind: "text", text: buffer });
|
|
1343
|
+
setBufferError(null);
|
|
1344
|
+
onChange({ ...state, draft: fallback, error: void 0 });
|
|
1345
|
+
setFormat("plain");
|
|
1346
|
+
}, children: "Use invalid JSON as plain text" }) : null
|
|
1347
|
+
] }),
|
|
1348
|
+
ai || busy === "capture" || state.error ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("aside", { children: [
|
|
1349
|
+
ai ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
|
|
1350
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { children: [
|
|
1351
|
+
"AI instruction",
|
|
1352
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("textarea", { value: instruction, onChange: (e) => setInstruction(e.target.value), placeholder: "Tell AI how to prepare this content" })
|
|
1353
|
+
] }),
|
|
1354
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.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" }),
|
|
1355
|
+
busy === "ai" ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Button, { type: "button", variant: "outline", onClick: () => void cancelAi(), children: aiSession.current?.cancel ? "Cancel AI" : "Stop waiting" }) : null
|
|
1356
|
+
] }) : null,
|
|
1357
|
+
busy === "capture" ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Button, { type: "button", variant: "outline", onClick: () => {
|
|
1358
|
+
activeCapture.current?.abort();
|
|
1359
|
+
activeCapture.current = null;
|
|
1360
|
+
setBusy(null);
|
|
1361
|
+
}, children: "Stop loading rows" }) : null,
|
|
1362
|
+
ai && aiSession.current?.recover && busy !== "ai" ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Button, { type: "button", variant: "outline", onClick: () => void runAi(true), children: aiFailed ? "Retry or rejoin AI run" : "Rejoin AI run" }) : null,
|
|
1363
|
+
ai ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "matrx-alchemy-meta", children: "AI creates a preview. It never copies automatically. Closing detaches this view without cancelling server work." }) : null,
|
|
1364
|
+
state.error ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { role: "alert", className: "matrx-alchemy-error", children: state.error }) : null
|
|
1365
|
+
] }) : null
|
|
1366
|
+
] }),
|
|
1367
|
+
pendingControls ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "matrx-alchemy-decision", role: "alert", children: [
|
|
1368
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { children: "This control would replace your manual edit." }),
|
|
1369
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Button, { type: "button", variant: "outline", onClick: () => setPendingControls(null), children: "Keep edited draft" }),
|
|
1370
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Button, { type: "button", onClick: applyPendingControls, children: "Rebuild from source" })
|
|
1371
|
+
] }) : null,
|
|
1372
|
+
state.pending ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "matrx-alchemy-decision", role: "alert", children: [
|
|
1373
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { children: "A fresh source snapshot is ready." }),
|
|
1374
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Button, { type: "button", variant: "outline", onClick: () => resolveCapture("keep"), children: "Keep current snapshot and draft" }),
|
|
1375
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Button, { type: "button", onClick: () => resolveCapture("regenerate"), children: "Regenerate from fresh source" })
|
|
657
1376
|
] }) : null,
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
1377
|
+
deliveryNotice ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { role: "status", className: "matrx-alchemy-meta", children: deliveryNotice }) : null,
|
|
1378
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(DialogFooter, { children: [
|
|
1379
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "matrx-alchemy-meta", children: [
|
|
1380
|
+
buffer.length.toLocaleString(),
|
|
1381
|
+
" characters \xB7 ~",
|
|
1382
|
+
estimateTokens(buffer).toLocaleString(),
|
|
1383
|
+
" tokens"
|
|
1384
|
+
] }),
|
|
1385
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Button, { type: "button", variant: "outline", onClick: close, children: "Close" }),
|
|
1386
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Button, { type: "button", variant: "outline", disabled: busy !== null || Boolean(bufferError || formatError) || !preparedArtifact, onClick: () => void deliver(true), children: "Download prepared output" }),
|
|
1387
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Button, { type: "button", disabled: busy !== null || Boolean(bufferError || formatError) || !preparedArtifact, onClick: () => void deliver(false), children: "Copy prepared output" })
|
|
1388
|
+
] })
|
|
1389
|
+
] }) });
|
|
1390
|
+
}
|
|
1391
|
+
function RowControls({ rows, controls, change }) {
|
|
1392
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
|
|
1393
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "matrx-alchemy-toolbar", children: [
|
|
1394
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { children: [
|
|
1395
|
+
"Search",
|
|
1396
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("input", { value: controls.search, onChange: (e) => change({ ...controls, search: e.target.value }) })
|
|
1397
|
+
] }),
|
|
1398
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { children: [
|
|
1399
|
+
"Sort",
|
|
1400
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("select", { value: controls.sort, onChange: (e) => change({ ...controls, sort: e.target.value }), children: [
|
|
1401
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: "", children: "None" }),
|
|
1402
|
+
rows.columns.map((column) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: column.id, children: column.label }, column.id))
|
|
1403
|
+
] })
|
|
1404
|
+
] }),
|
|
1405
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { children: [
|
|
1406
|
+
"Direction",
|
|
1407
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("select", { value: controls.direction, disabled: !controls.sort, onChange: (e) => change({ ...controls, direction: e.target.value }), children: [
|
|
1408
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: "asc", children: "Ascending" }),
|
|
1409
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: "desc", children: "Descending" })
|
|
1410
|
+
] })
|
|
1411
|
+
] }),
|
|
1412
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { children: [
|
|
1413
|
+
"Top rows",
|
|
1414
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("input", { type: "number", min: "0", value: controls.top ?? "", onChange: (e) => change({ ...controls, top: Number.isNaN(e.target.valueAsNumber) ? null : e.target.valueAsNumber }) })
|
|
1415
|
+
] })
|
|
1416
|
+
] }),
|
|
1417
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("fieldset", { className: "matrx-alchemy-options", children: [
|
|
1418
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("legend", { children: "Columns and filters" }),
|
|
1419
|
+
rows.columns.map((column) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "matrx-alchemy-column", children: [
|
|
1420
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { children: [
|
|
1421
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.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) }) }),
|
|
1422
|
+
" ",
|
|
1423
|
+
column.label
|
|
1424
|
+
] }),
|
|
1425
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.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 } }) })
|
|
1426
|
+
] }, column.id))
|
|
1427
|
+
] }),
|
|
1428
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("fieldset", { className: "matrx-alchemy-options", children: [
|
|
1429
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("legend", { children: "Rows" }),
|
|
1430
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { children: [
|
|
1431
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("input", { type: "checkbox", checked: controls.selectedOnly, onChange: (e) => change({ ...controls, selectedOnly: e.target.checked }) }),
|
|
1432
|
+
" Only selected rows"
|
|
1433
|
+
] }),
|
|
1434
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "matrx-alchemy-row-list", children: rows.rows.map((row, index) => {
|
|
1435
|
+
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 ");
|
|
1436
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("label", { children: [
|
|
1437
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.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) }) }),
|
|
1438
|
+
" Row ",
|
|
1439
|
+
index + 1,
|
|
1440
|
+
summary ? ` \u2014 ${summary}` : ""
|
|
1441
|
+
] }, index);
|
|
1442
|
+
}) })
|
|
1443
|
+
] })
|
|
661
1444
|
] });
|
|
662
1445
|
}
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
1446
|
+
|
|
1447
|
+
// src/content-transfer/matrx-copy.tsx
|
|
1448
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
1449
|
+
var resolve = (value) => typeof value === "function" ? value() : value;
|
|
1450
|
+
var asPayload = (value) => ({
|
|
1451
|
+
kind: "markdown",
|
|
1452
|
+
text: typeof value === "string" ? value : (0, import_content_transfer2.buildAgentPayload)(value)
|
|
1453
|
+
});
|
|
1454
|
+
var structuredPayload = (value) => {
|
|
1455
|
+
if (typeof value === "string") return { kind: "markdown", text: value };
|
|
1456
|
+
const clean = (record) => Object.fromEntries(
|
|
1457
|
+
Object.entries(record ?? {}).filter(([, entry]) => entry !== void 0)
|
|
1458
|
+
);
|
|
1459
|
+
return {
|
|
1460
|
+
kind: "json",
|
|
1461
|
+
value: (0, import_content_transfer2.normalizeTransferJson)({
|
|
1462
|
+
kind: value.kind,
|
|
1463
|
+
location: value.location,
|
|
1464
|
+
description: value.description,
|
|
1465
|
+
data: value.data,
|
|
1466
|
+
...value.summary !== void 0 ? { summary: value.summary } : {},
|
|
1467
|
+
attributes: clean(value.attributes),
|
|
1468
|
+
context: clean(value.context)
|
|
1469
|
+
})
|
|
1470
|
+
};
|
|
1471
|
+
};
|
|
1472
|
+
var actionDone = (message) => ({
|
|
1473
|
+
status: "success",
|
|
1474
|
+
delivered: "action",
|
|
1475
|
+
mimeTypes: [],
|
|
1476
|
+
message
|
|
1477
|
+
});
|
|
1478
|
+
var sourceFor = (id, label, build) => ({
|
|
1479
|
+
id,
|
|
1480
|
+
label,
|
|
1481
|
+
capture: async ({ signal }) => {
|
|
1482
|
+
signal.throwIfAborted();
|
|
1483
|
+
const payload = await build();
|
|
1484
|
+
signal.throwIfAborted();
|
|
1485
|
+
return (0, import_content_transfer2.directSource)(payload, { sourceId: id, label });
|
|
1486
|
+
}
|
|
1487
|
+
});
|
|
1488
|
+
function MatrxCopyMenu(props) {
|
|
1489
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(MatrxCopyMenuSession, { ...props }, props.sourceId ?? props.label);
|
|
1490
|
+
}
|
|
1491
|
+
function MatrxCopyMenuSession(props) {
|
|
1492
|
+
const instance = React8.useId();
|
|
1493
|
+
const controller = React8.useRef(null);
|
|
1494
|
+
const capabilities = useContentTransferCapabilities();
|
|
1495
|
+
const transport = capabilities.transport ?? (0, import_content_transfer2.createBrowserTransport)();
|
|
1496
|
+
const [modal, setModal] = React8.useState(null);
|
|
1497
|
+
const [configuration, setConfiguration] = React8.useState(null);
|
|
1498
|
+
const copyVisible = !props.hide?.includes("copy");
|
|
1499
|
+
const aiVisible = !props.hide?.includes("ai");
|
|
1500
|
+
const exportVisible = !props.hide?.includes("export");
|
|
1501
|
+
const make = (suffix, build, label = props.label) => sourceFor(
|
|
1502
|
+
`${props.sourceId ?? `${instance}:${props.label}`}:${suffix}`,
|
|
1503
|
+
label,
|
|
1504
|
+
build
|
|
1505
|
+
);
|
|
1506
|
+
const human = copyVisible && props.human !== void 0 ? make("human", () => ({ kind: "text", text: resolve(props.human) })) : void 0;
|
|
1507
|
+
const humanMarkdown = copyVisible && props.human !== void 0 ? make("human-markdown", () => ({
|
|
1508
|
+
kind: "markdown",
|
|
1509
|
+
text: resolve(props.human)
|
|
1510
|
+
})) : void 0;
|
|
1511
|
+
const json = aiVisible && props.json !== void 0 ? make("json", () => ({
|
|
1512
|
+
kind: "json",
|
|
1513
|
+
value: (0, import_content_transfer2.normalizeTransferJson)(resolve(props.json))
|
|
1514
|
+
})) : void 0;
|
|
1515
|
+
const agent = aiVisible && props.agent !== void 0 ? make("agent", () => asPayload(resolve(props.agent))) : void 0;
|
|
1516
|
+
const structuredAgent = aiVisible && props.agent !== void 0 ? make("structured-agent", () => structuredPayload(resolve(props.agent))) : void 0;
|
|
1517
|
+
const table = exportVisible && props.export?.sheetRows ? make("rows", () => {
|
|
1518
|
+
const value = (0, import_content_transfer2.normalizeTransferJson)(props.export.sheetRows());
|
|
1519
|
+
if (!Array.isArray(value) || value.some(
|
|
1520
|
+
(row) => row === null || typeof row !== "object" || Array.isArray(row)
|
|
1521
|
+
))
|
|
1522
|
+
throw new Error("Sheet rows must be JSON objects.");
|
|
1523
|
+
const rows = value;
|
|
1524
|
+
const keys = [...new Set(rows.flatMap((row) => Object.keys(row)))];
|
|
1525
|
+
return {
|
|
1526
|
+
kind: "rows",
|
|
1527
|
+
rows,
|
|
1528
|
+
columns: keys.map((key) => ({
|
|
1529
|
+
id: key,
|
|
1530
|
+
label: key,
|
|
1531
|
+
path: `/${key.replace(/~/g, "~0").replace(/\//g, "~1")}`,
|
|
1532
|
+
visible: true
|
|
1533
|
+
}))
|
|
1534
|
+
};
|
|
1535
|
+
}) : void 0;
|
|
1536
|
+
const builderVariants = aiVisible ? (props.aiVariants ?? []).filter(
|
|
1537
|
+
(variant) => variant.build && !variant.onSelect && !variant.modal
|
|
1538
|
+
).map((variant) => ({
|
|
1539
|
+
...variant,
|
|
1540
|
+
copyLabel: variant.label,
|
|
1541
|
+
source: make(
|
|
1542
|
+
`variant:${variant.id}`,
|
|
1543
|
+
async () => asPayload(await variant.build()),
|
|
1544
|
+
variant.label
|
|
1545
|
+
)
|
|
1546
|
+
})) : [];
|
|
1547
|
+
const faithful = agent ? [
|
|
1548
|
+
{
|
|
1549
|
+
id: props.agentVariant?.id ?? "faithful",
|
|
1550
|
+
label: props.agentVariant?.label ?? "Full AI context",
|
|
1551
|
+
source: agent,
|
|
1552
|
+
copyLabel: props.agentVariant?.label ?? "Copy for AI",
|
|
1553
|
+
...props.agentVariant?.hint ? { hint: props.agentVariant.hint } : {}
|
|
1554
|
+
}
|
|
1555
|
+
] : [];
|
|
1556
|
+
const variants = props.agentVariant?.position === "last" ? [...builderVariants, ...faithful] : [...faithful, ...builderVariants];
|
|
1557
|
+
const actions = [];
|
|
1558
|
+
if (aiVisible)
|
|
1559
|
+
for (const variant of props.aiVariants ?? []) {
|
|
1560
|
+
if (!variant.onSelect && !variant.modal) continue;
|
|
1561
|
+
actions.push({
|
|
1562
|
+
...variant,
|
|
1563
|
+
id: `variant-action:${variant.id}`,
|
|
1564
|
+
label: variant.label,
|
|
1565
|
+
supports: () => true,
|
|
1566
|
+
run: async () => {
|
|
1567
|
+
if (variant.onSelect) await variant.onSelect();
|
|
1568
|
+
else setModal(variant);
|
|
1569
|
+
return actionDone(`Opened ${variant.label}`);
|
|
1570
|
+
}
|
|
1571
|
+
});
|
|
1572
|
+
}
|
|
1573
|
+
if (aiVisible && props.aiCustom)
|
|
1574
|
+
actions.push({
|
|
1575
|
+
id: "configure-source",
|
|
1576
|
+
label: props.aiCustom.label ?? "Customize source\u2026",
|
|
1577
|
+
...props.aiCustom.hint ? { hint: props.aiCustom.hint } : {},
|
|
1578
|
+
supports: () => true,
|
|
1579
|
+
run: async () => {
|
|
1580
|
+
setConfiguration({ custom: props.aiCustom });
|
|
1581
|
+
return actionDone("Source options opened");
|
|
1582
|
+
}
|
|
1583
|
+
});
|
|
1584
|
+
if (aiVisible && props.groomer)
|
|
1585
|
+
actions.push({
|
|
1586
|
+
id: "groom-source",
|
|
1587
|
+
label: "Customize sections\u2026",
|
|
1588
|
+
supports: () => true,
|
|
1589
|
+
run: async () => {
|
|
1590
|
+
setConfiguration({ groomer: props.groomer() });
|
|
1591
|
+
return actionDone("Section options opened");
|
|
1592
|
+
}
|
|
1593
|
+
});
|
|
1594
|
+
if (exportVisible)
|
|
1595
|
+
for (const item of props.export?.items ?? [])
|
|
1596
|
+
actions.push({
|
|
1597
|
+
id: `export:${item.id}`,
|
|
1598
|
+
label: item.label,
|
|
1599
|
+
supports: () => true,
|
|
1600
|
+
...item.build && !item.onSelect ? {
|
|
1601
|
+
source: make(
|
|
1602
|
+
`export:${item.id}`,
|
|
1603
|
+
async () => {
|
|
1604
|
+
const file = item.build();
|
|
1605
|
+
const bytes = new Uint8Array(
|
|
1606
|
+
await new Blob([file.content], {
|
|
1607
|
+
type: file.mime
|
|
1608
|
+
}).arrayBuffer()
|
|
1609
|
+
);
|
|
1610
|
+
return {
|
|
1611
|
+
kind: "registered",
|
|
1612
|
+
format: "matrx-file",
|
|
1613
|
+
value: {
|
|
1614
|
+
bytes: Array.from(bytes),
|
|
1615
|
+
mime: file.mime,
|
|
1616
|
+
extension: file.extension
|
|
1617
|
+
}
|
|
1618
|
+
};
|
|
1619
|
+
},
|
|
1620
|
+
item.label
|
|
1621
|
+
)
|
|
1622
|
+
} : {},
|
|
1623
|
+
run: async ({ snapshot, draft, signal }) => {
|
|
1624
|
+
if (item.onSelect) {
|
|
1625
|
+
await item.onSelect();
|
|
1626
|
+
return actionDone(`Opened ${item.label}`);
|
|
1627
|
+
}
|
|
1628
|
+
const value = draft.payload.kind === "registered" ? draft.payload.value : null;
|
|
1629
|
+
if (!value || Array.isArray(value) || typeof value !== "object" || !Array.isArray(value.bytes) || typeof value.mime !== "string" || typeof value.extension !== "string" || value.bytes.some(
|
|
1630
|
+
(byte) => typeof byte !== "number" || !Number.isInteger(byte) || byte < 0 || byte > 255
|
|
1631
|
+
))
|
|
1632
|
+
throw new Error(`${item.label} did not capture a valid file.`);
|
|
1633
|
+
if (draft.omissions.some((omission) => omission.reason !== "duplicate"))
|
|
1634
|
+
throw new Error(
|
|
1635
|
+
"This custom file exceeds the configured export limits or contains excluded content. Use a standard format or revise the source options."
|
|
1636
|
+
);
|
|
1637
|
+
const bytes = new Uint8Array(value.bytes);
|
|
1638
|
+
const filename = `${props.label.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "export"}.${value.extension.replace(/[^a-zA-Z0-9.-]/g, "") || "bin"}`;
|
|
1639
|
+
return transport.download(
|
|
1640
|
+
(0, import_content_transfer2.sealTransferArtifact)({
|
|
1641
|
+
snapshotId: snapshot.id,
|
|
1642
|
+
draftRevision: draft.revision,
|
|
1643
|
+
format: `export:${item.id}`,
|
|
1644
|
+
plainText: "",
|
|
1645
|
+
file: { filename, mime: value.mime, bytes },
|
|
1646
|
+
omissions: [...draft.omissions]
|
|
1647
|
+
}),
|
|
1648
|
+
signal
|
|
1649
|
+
);
|
|
1650
|
+
}
|
|
1651
|
+
});
|
|
1652
|
+
if (exportVisible && table && props.sendToSheet)
|
|
1653
|
+
actions.push({
|
|
1654
|
+
id: "send-google-sheet",
|
|
1655
|
+
label: "Send to Google Sheet",
|
|
1656
|
+
source: table,
|
|
1657
|
+
supports: () => true,
|
|
1658
|
+
run: async ({ draft }) => {
|
|
1659
|
+
if (draft.payload.kind !== "rows")
|
|
1660
|
+
throw new Error("Google Sheets requires captured rows.");
|
|
1661
|
+
return props.sendToSheet(draft.payload.rows, props.label);
|
|
1662
|
+
}
|
|
1663
|
+
});
|
|
1664
|
+
const source = json ?? table ?? structuredAgent ?? human ?? builderVariants[0]?.source;
|
|
1665
|
+
if (!source && !actions.length) return null;
|
|
1666
|
+
const target = source ?? make("actions", () => ({ kind: "text", text: props.label }));
|
|
1667
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
|
|
1668
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1669
|
+
ContentTransferMenu,
|
|
1670
|
+
{
|
|
1671
|
+
source: target,
|
|
1672
|
+
controllerRef: controller,
|
|
1673
|
+
label: props.label,
|
|
1674
|
+
variants,
|
|
1675
|
+
actions,
|
|
1676
|
+
hide: [
|
|
1677
|
+
...!copyVisible || !source ? ["copy"] : [],
|
|
1678
|
+
...!aiVisible || !source ? ["prepare"] : [],
|
|
1679
|
+
...!exportVisible || !source ? ["download"] : []
|
|
1680
|
+
],
|
|
1681
|
+
formatSources: {
|
|
1682
|
+
...human ? { plain: human, markdown: humanMarkdown, html: humanMarkdown } : {},
|
|
1683
|
+
...json ? { json, "compact-json": json } : {},
|
|
1684
|
+
...table ? { csv: table, tsv: table } : {}
|
|
1685
|
+
},
|
|
1686
|
+
...props.disabled !== void 0 ? { disabled: props.disabled } : {},
|
|
1687
|
+
className: cn(
|
|
1688
|
+
props.className,
|
|
1689
|
+
props.size === "xs" && "matrx-alchemy-xs",
|
|
1690
|
+
props.size === "sm" && "matrx-alchemy-sm"
|
|
1691
|
+
),
|
|
1692
|
+
...props.stopPropagation !== void 0 ? { stopPropagation: props.stopPropagation } : {}
|
|
1693
|
+
}
|
|
1694
|
+
),
|
|
1695
|
+
modal?.modal?.({
|
|
1696
|
+
open: true,
|
|
1697
|
+
onOpenChange: (open) => {
|
|
1698
|
+
if (!open) setModal(null);
|
|
1699
|
+
}
|
|
1700
|
+
}),
|
|
1701
|
+
configuration ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1702
|
+
SourceConfiguration,
|
|
1703
|
+
{
|
|
1704
|
+
restoreFocus: () => controller.current?.focusTrigger(),
|
|
1705
|
+
configuration,
|
|
1706
|
+
onClose: () => setConfiguration(null),
|
|
1707
|
+
onPrepare: async (payload, label) => {
|
|
1708
|
+
if (!controller.current)
|
|
1709
|
+
throw new Error("Alchemy is no longer mounted.");
|
|
1710
|
+
await controller.current.prepare(payload, {
|
|
1711
|
+
label,
|
|
1712
|
+
id: `${instance}:configured:${crypto.randomUUID()}`
|
|
1713
|
+
});
|
|
1714
|
+
setConfiguration(null);
|
|
1715
|
+
}
|
|
1716
|
+
},
|
|
1717
|
+
`${instance}:configuration`
|
|
1718
|
+
) : null
|
|
1719
|
+
] });
|
|
1720
|
+
}
|
|
1721
|
+
function SourceConfiguration({
|
|
1722
|
+
restoreFocus,
|
|
1723
|
+
configuration,
|
|
1724
|
+
onClose,
|
|
1725
|
+
onPrepare
|
|
1726
|
+
}) {
|
|
1727
|
+
const custom = configuration.custom;
|
|
1728
|
+
const handingOff = React8.useRef(false);
|
|
1729
|
+
const groomer = configuration.groomer;
|
|
1730
|
+
const [values, setValues] = React8.useState(
|
|
1731
|
+
() => Object.fromEntries(
|
|
1732
|
+
custom?.options.map((option) => [option.key, option.default]) ?? []
|
|
1733
|
+
)
|
|
1734
|
+
);
|
|
1735
|
+
const [sections, setSections] = React8.useState(
|
|
1736
|
+
() => Object.fromEntries(
|
|
1737
|
+
groomer?.sections.map((section) => [
|
|
1738
|
+
section.id,
|
|
1739
|
+
section.defaultSelection ?? "full"
|
|
1740
|
+
]) ?? []
|
|
1741
|
+
)
|
|
1742
|
+
);
|
|
1743
|
+
const [error, setError] = React8.useState(null);
|
|
1744
|
+
const [busy, setBusy] = React8.useState(false);
|
|
1745
|
+
const title = custom?.dialogTitle ?? groomer?.label ?? "Customize source";
|
|
1746
|
+
let prepared = null;
|
|
1747
|
+
let buildError = null;
|
|
667
1748
|
let text = "";
|
|
668
|
-
let error = null;
|
|
669
1749
|
try {
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
1750
|
+
if (custom) {
|
|
1751
|
+
const result = custom.build(values);
|
|
1752
|
+
prepared = custom.wrap(result.text, values, result.meta);
|
|
1753
|
+
} else if (groomer) {
|
|
1754
|
+
const data = {};
|
|
1755
|
+
const omitted = [];
|
|
1756
|
+
for (const section of groomer.sections) {
|
|
1757
|
+
const level = sections[section.id] ?? "full";
|
|
1758
|
+
if (level === "off") omitted.push(section.id);
|
|
1759
|
+
else {
|
|
1760
|
+
const value = section.build(level);
|
|
1761
|
+
if (value !== void 0 && value !== null) data[section.id] = value;
|
|
1762
|
+
}
|
|
1763
|
+
}
|
|
1764
|
+
prepared = {
|
|
1765
|
+
kind: groomer.kind,
|
|
1766
|
+
location: groomer.location,
|
|
1767
|
+
description: groomer.description,
|
|
1768
|
+
data,
|
|
1769
|
+
...groomer.summary ? { summary: groomer.summary } : {},
|
|
1770
|
+
attributes: {
|
|
1771
|
+
...groomer.attributes,
|
|
1772
|
+
dropped_sections: omitted.join(",")
|
|
1773
|
+
},
|
|
1774
|
+
...groomer.context ? { context: groomer.context } : {}
|
|
1775
|
+
};
|
|
1776
|
+
}
|
|
1777
|
+
text = prepared ? (0, import_content_transfer2.buildAgentPayload)(prepared) : "";
|
|
1778
|
+
} catch (cause) {
|
|
1779
|
+
buildError = cause instanceof Error ? cause.message : "Could not prepare this source.";
|
|
674
1780
|
}
|
|
675
|
-
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
1781
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1782
|
+
Dialog,
|
|
1783
|
+
{
|
|
1784
|
+
open: true,
|
|
1785
|
+
onOpenChange: (open) => {
|
|
1786
|
+
if (!open && !busy) onClose();
|
|
1787
|
+
},
|
|
1788
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
1789
|
+
DialogContent,
|
|
1790
|
+
{
|
|
1791
|
+
onCloseAutoFocus: (event) => {
|
|
1792
|
+
event.preventDefault();
|
|
1793
|
+
if (!handingOff.current) restoreFocus();
|
|
1794
|
+
},
|
|
1795
|
+
className: "matrx-alchemy-workspace",
|
|
1796
|
+
children: [
|
|
1797
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(DialogHeader, { children: [
|
|
1798
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(DialogTitle, { children: title }),
|
|
1799
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(DialogDescription, { children: custom?.dialogDescription ?? "Choose the source detail, then prepare, edit, summarize, copy or export it in Alchemy." })
|
|
1800
|
+
] }),
|
|
1801
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "matrx-alchemy-main matrx-alchemy-toolbar", children: [
|
|
1802
|
+
custom?.options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("label", { children: [
|
|
1803
|
+
option.label,
|
|
1804
|
+
"hint" in option && option.hint ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("small", { children: option.hint }) : null,
|
|
1805
|
+
option.kind === "toggle" ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1806
|
+
"input",
|
|
1807
|
+
{
|
|
1808
|
+
type: "checkbox",
|
|
1809
|
+
checked: Boolean(values[option.key]),
|
|
1810
|
+
onChange: (event) => setValues({ ...values, [option.key]: event.target.checked })
|
|
1811
|
+
}
|
|
1812
|
+
) : option.kind === "preset" ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1813
|
+
"select",
|
|
1814
|
+
{
|
|
1815
|
+
value: Number(values[option.key]),
|
|
1816
|
+
onChange: (event) => setValues({
|
|
1817
|
+
...values,
|
|
1818
|
+
[option.key]: Number(event.target.value)
|
|
1819
|
+
}),
|
|
1820
|
+
children: option.options.map((choice) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("option", { value: choice.value, children: choice.label }, choice.value))
|
|
1821
|
+
}
|
|
1822
|
+
) : option.kind === "slider" ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
|
|
1823
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1824
|
+
"input",
|
|
1825
|
+
{
|
|
1826
|
+
type: "range",
|
|
1827
|
+
min: 0,
|
|
1828
|
+
max: Math.max(0, option.stops.length - 1),
|
|
1829
|
+
step: 1,
|
|
1830
|
+
value: option.stops.indexOf(Number(values[option.key])),
|
|
1831
|
+
onChange: (event) => setValues({
|
|
1832
|
+
...values,
|
|
1833
|
+
[option.key]: option.stops[Number(event.target.value)]
|
|
1834
|
+
})
|
|
1835
|
+
}
|
|
1836
|
+
),
|
|
1837
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: option.formatValue(Number(values[option.key])) })
|
|
1838
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
|
|
1839
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1840
|
+
"input",
|
|
1841
|
+
{
|
|
1842
|
+
type: "number",
|
|
1843
|
+
min: option.min,
|
|
1844
|
+
step: option.step,
|
|
1845
|
+
value: Number(values[option.key]),
|
|
1846
|
+
onChange: (event) => setValues({
|
|
1847
|
+
...values,
|
|
1848
|
+
[option.key]: Number(event.target.value)
|
|
1849
|
+
})
|
|
1850
|
+
}
|
|
1851
|
+
),
|
|
1852
|
+
option.presets?.map((preset) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1853
|
+
Button,
|
|
1854
|
+
{
|
|
1855
|
+
type: "button",
|
|
1856
|
+
variant: "ghost",
|
|
1857
|
+
onClick: () => setValues({ ...values, [option.key]: preset.value }),
|
|
1858
|
+
children: preset.label
|
|
1859
|
+
},
|
|
1860
|
+
preset.value
|
|
1861
|
+
))
|
|
1862
|
+
] })
|
|
1863
|
+
] }, option.key)),
|
|
1864
|
+
groomer ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
|
|
1865
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { children: ["full", "compact", "brief"].map((level) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1866
|
+
Button,
|
|
1867
|
+
{
|
|
1868
|
+
type: "button",
|
|
1869
|
+
variant: "ghost",
|
|
1870
|
+
onClick: () => setSections(
|
|
1871
|
+
Object.fromEntries(
|
|
1872
|
+
groomer.sections.map((section) => [
|
|
1873
|
+
section.id,
|
|
1874
|
+
level === "brief" && section.cuttable ? "off" : level
|
|
1875
|
+
])
|
|
1876
|
+
)
|
|
1877
|
+
),
|
|
1878
|
+
children: level
|
|
1879
|
+
},
|
|
1880
|
+
level
|
|
1881
|
+
)) }),
|
|
1882
|
+
groomer.sections.map((section) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("label", { children: [
|
|
1883
|
+
section.title,
|
|
1884
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
1885
|
+
"select",
|
|
1886
|
+
{
|
|
1887
|
+
value: sections[section.id],
|
|
1888
|
+
onChange: (event) => setSections({
|
|
1889
|
+
...sections,
|
|
1890
|
+
[section.id]: event.target.value
|
|
1891
|
+
}),
|
|
1892
|
+
children: [
|
|
1893
|
+
["full", "compact", "brief"].map((level) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("option", { value: level, children: section.levelLabels?.[level] ?? level }, level)),
|
|
1894
|
+
section.cuttable ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("option", { value: "off", children: "Exclude" }) : null
|
|
1895
|
+
]
|
|
1896
|
+
}
|
|
1897
|
+
),
|
|
1898
|
+
section.description ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: section.description }) : null
|
|
1899
|
+
] }, section.id))
|
|
1900
|
+
] }) : null
|
|
1901
|
+
] }),
|
|
1902
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("p", { children: [
|
|
1903
|
+
text.length.toLocaleString(),
|
|
1904
|
+
" characters \xB7 approximately",
|
|
1905
|
+
" ",
|
|
1906
|
+
Math.ceil(text.length / 4).toLocaleString(),
|
|
1907
|
+
" tokens"
|
|
1908
|
+
] }),
|
|
1909
|
+
error || buildError ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { role: "alert", children: error ?? buildError }) : null,
|
|
1910
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(DialogFooter, { children: [
|
|
1911
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1912
|
+
Button,
|
|
1913
|
+
{
|
|
1914
|
+
type: "button",
|
|
1915
|
+
variant: "ghost",
|
|
1916
|
+
disabled: busy,
|
|
1917
|
+
onClick: onClose,
|
|
1918
|
+
children: "Cancel"
|
|
1919
|
+
}
|
|
1920
|
+
),
|
|
1921
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1922
|
+
Button,
|
|
1923
|
+
{
|
|
1924
|
+
type: "button",
|
|
1925
|
+
disabled: busy || !prepared || Boolean(buildError),
|
|
1926
|
+
onClick: async () => {
|
|
1927
|
+
if (!prepared) return;
|
|
1928
|
+
setBusy(true);
|
|
1929
|
+
setError(null);
|
|
1930
|
+
try {
|
|
1931
|
+
handingOff.current = true;
|
|
1932
|
+
await onPrepare(structuredPayload(prepared), title);
|
|
1933
|
+
} catch (cause) {
|
|
1934
|
+
handingOff.current = false;
|
|
1935
|
+
setError(
|
|
1936
|
+
cause instanceof Error ? cause.message : "Could not open Alchemy."
|
|
1937
|
+
);
|
|
1938
|
+
} finally {
|
|
1939
|
+
setBusy(false);
|
|
1940
|
+
}
|
|
1941
|
+
},
|
|
1942
|
+
children: busy ? "Preparing\u2026" : "Prepare in Alchemy"
|
|
1943
|
+
}
|
|
1944
|
+
)
|
|
1945
|
+
] })
|
|
1946
|
+
]
|
|
1947
|
+
}
|
|
1948
|
+
)
|
|
1949
|
+
}
|
|
1950
|
+
);
|
|
1951
|
+
}
|
|
1952
|
+
|
|
1953
|
+
// src/data-table/copy.tsx
|
|
1954
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
1955
|
+
function CopyButtons(props) {
|
|
1956
|
+
const { CopyControls } = useMatrxDataTableHost();
|
|
1957
|
+
if (CopyControls) return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(CopyControls, { ...props });
|
|
1958
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(MatrxCopyMenu, { ...props });
|
|
696
1959
|
}
|
|
697
1960
|
|
|
698
1961
|
// src/data-table/MatrxUuidCell.tsx
|
|
699
|
-
var
|
|
1962
|
+
var import_react3 = require("react");
|
|
1963
|
+
|
|
1964
|
+
// src/data-table/useTableNotice.tsx
|
|
1965
|
+
var import_react2 = require("react");
|
|
1966
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
1967
|
+
function useTableNotice() {
|
|
1968
|
+
const host = useMatrxDataTableHost();
|
|
1969
|
+
const [message, setMessage] = (0, import_react2.useState)(null);
|
|
1970
|
+
const notify = {
|
|
1971
|
+
success(text) {
|
|
1972
|
+
if (host.notify) host.notify.success(text);
|
|
1973
|
+
else setMessage({ text, error: false });
|
|
1974
|
+
},
|
|
1975
|
+
error(text) {
|
|
1976
|
+
if (host.notify) host.notify.error(text);
|
|
1977
|
+
else setMessage({ text, error: true });
|
|
1978
|
+
}
|
|
1979
|
+
};
|
|
1980
|
+
const notice = message ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { role: message.error ? "alert" : "status", className: message.error ? "text-xs text-destructive" : "text-xs text-muted-foreground", children: [
|
|
1981
|
+
message.text,
|
|
1982
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { type: "button", "aria-label": "Dismiss notification", className: "ml-2 underline", onClick: () => setMessage(null), children: "Dismiss" })
|
|
1983
|
+
] }) : null;
|
|
1984
|
+
return { notify, notice };
|
|
1985
|
+
}
|
|
700
1986
|
|
|
701
1987
|
// src/tooltip.tsx
|
|
702
1988
|
var TooltipPrimitive = __toESM(require("@radix-ui/react-tooltip"), 1);
|
|
703
|
-
var
|
|
704
|
-
var
|
|
1989
|
+
var React9 = __toESM(require("react"), 1);
|
|
1990
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
705
1991
|
var TooltipProvider = TooltipPrimitive.Provider;
|
|
706
1992
|
var Tooltip = TooltipPrimitive.Root;
|
|
707
1993
|
var TooltipTrigger = TooltipPrimitive.Trigger;
|
|
708
|
-
var TooltipContent =
|
|
1994
|
+
var TooltipContent = React9.forwardRef(({ className, sideOffset = 4, container, animated = true, ...props }, ref) => {
|
|
709
1995
|
const resolved = usePortalContainer(container);
|
|
710
|
-
return /* @__PURE__ */ (0,
|
|
1996
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(TooltipPrimitive.Portal, { container: resolved ?? null, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
711
1997
|
TooltipPrimitive.Content,
|
|
712
1998
|
{
|
|
713
1999
|
ref,
|
|
@@ -725,7 +2011,7 @@ var TooltipContent = React7.forwardRef(({ className, sideOffset = 4, container,
|
|
|
725
2011
|
TooltipContent.displayName = TooltipPrimitive.Content.displayName;
|
|
726
2012
|
|
|
727
2013
|
// src/data-table/MatrxUuidCell.tsx
|
|
728
|
-
var
|
|
2014
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
729
2015
|
var SHORT_LEN = 8;
|
|
730
2016
|
function shortUuid(id, len = SHORT_LEN) {
|
|
731
2017
|
return id.slice(0, len);
|
|
@@ -764,18 +2050,18 @@ function MatrxUuidCell({
|
|
|
764
2050
|
}) {
|
|
765
2051
|
const { resolveEntityDoors, ResourcePeek } = useMatrxDataTableHost();
|
|
766
2052
|
const { notify, notice } = useTableNotice();
|
|
767
|
-
const [copied, setCopied] = (0,
|
|
768
|
-
const [opening, setOpening] = (0,
|
|
769
|
-
const [peekOpen, setPeekOpen] = (0,
|
|
770
|
-
const timer = (0,
|
|
771
|
-
(0,
|
|
2053
|
+
const [copied, setCopied] = (0, import_react3.useState)(false);
|
|
2054
|
+
const [opening, setOpening] = (0, import_react3.useState)(false);
|
|
2055
|
+
const [peekOpen, setPeekOpen] = (0, import_react3.useState)(false);
|
|
2056
|
+
const timer = (0, import_react3.useRef)(null);
|
|
2057
|
+
(0, import_react3.useEffect)(
|
|
772
2058
|
() => () => {
|
|
773
2059
|
if (timer.current) clearTimeout(timer.current);
|
|
774
2060
|
},
|
|
775
2061
|
[]
|
|
776
2062
|
);
|
|
777
2063
|
if (!value) {
|
|
778
|
-
return /* @__PURE__ */ (0,
|
|
2064
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "text-muted-foreground/40", children: "\u2014" });
|
|
779
2065
|
}
|
|
780
2066
|
const doors = token ? resolveEntityDoors?.(token, value, href) ?? null : null;
|
|
781
2067
|
const resolvedHref = doors?.href ?? href ?? null;
|
|
@@ -818,13 +2104,13 @@ function MatrxUuidCell({
|
|
|
818
2104
|
};
|
|
819
2105
|
const idNode = (() => {
|
|
820
2106
|
if (forbidden) {
|
|
821
|
-
return /* @__PURE__ */ (0,
|
|
822
|
-
/* @__PURE__ */ (0,
|
|
823
|
-
/* @__PURE__ */ (0,
|
|
2107
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { className: "inline-flex min-w-0 items-center gap-1 font-mono text-xs text-muted-foreground/70 tabular-nums", children: [
|
|
2108
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "min-w-0 truncate", children: display }),
|
|
2109
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ShieldOff, { className: "h-3 w-3 shrink-0 opacity-60", "aria-hidden": true })
|
|
824
2110
|
] });
|
|
825
2111
|
}
|
|
826
2112
|
if (onOpen) {
|
|
827
|
-
return /* @__PURE__ */ (0,
|
|
2113
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
828
2114
|
"button",
|
|
829
2115
|
{
|
|
830
2116
|
type: "button",
|
|
@@ -833,14 +2119,14 @@ function MatrxUuidCell({
|
|
|
833
2119
|
disabled: opening,
|
|
834
2120
|
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",
|
|
835
2121
|
children: [
|
|
836
|
-
/* @__PURE__ */ (0,
|
|
837
|
-
/* @__PURE__ */ (0,
|
|
2122
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "min-w-0 truncate tabular-nums", children: display }),
|
|
2123
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(PanelRight, { className: "h-3 w-3 shrink-0 opacity-50" })
|
|
838
2124
|
]
|
|
839
2125
|
}
|
|
840
2126
|
);
|
|
841
2127
|
}
|
|
842
2128
|
if (resolvedHref) {
|
|
843
|
-
return /* @__PURE__ */ (0,
|
|
2129
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
844
2130
|
"a",
|
|
845
2131
|
{
|
|
846
2132
|
href: resolvedHref,
|
|
@@ -850,15 +2136,15 @@ function MatrxUuidCell({
|
|
|
850
2136
|
onClick: stop,
|
|
851
2137
|
className: "inline-flex min-w-0 items-center gap-1 font-mono text-xs text-sky-600 hover:underline dark:text-sky-400",
|
|
852
2138
|
children: [
|
|
853
|
-
/* @__PURE__ */ (0,
|
|
854
|
-
/* @__PURE__ */ (0,
|
|
2139
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "min-w-0 truncate tabular-nums", children: display }),
|
|
2140
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ExternalLink, { className: "h-3 w-3 shrink-0 opacity-50" })
|
|
855
2141
|
]
|
|
856
2142
|
}
|
|
857
2143
|
);
|
|
858
2144
|
}
|
|
859
|
-
return /* @__PURE__ */ (0,
|
|
2145
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "min-w-0 truncate font-mono text-xs text-muted-foreground tabular-nums select-all", children: display });
|
|
860
2146
|
})();
|
|
861
|
-
return /* @__PURE__ */ (0,
|
|
2147
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
862
2148
|
"span",
|
|
863
2149
|
{
|
|
864
2150
|
"data-matrx-cell-control": true,
|
|
@@ -868,11 +2154,11 @@ function MatrxUuidCell({
|
|
|
868
2154
|
),
|
|
869
2155
|
onClick: stop,
|
|
870
2156
|
children: [
|
|
871
|
-
/* @__PURE__ */ (0,
|
|
872
|
-
/* @__PURE__ */ (0,
|
|
873
|
-
/* @__PURE__ */ (0,
|
|
2157
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(TooltipProvider, { delayDuration: 200, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(Tooltip, { children: [
|
|
2158
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "inline-flex min-w-0 max-w-full items-center", children: idNode }) }),
|
|
2159
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(TooltipContent, { side: "top", className: "max-w-sm break-all font-mono", children: forbidden ? `No access \xB7 ${tip}` : tip })
|
|
874
2160
|
] }) }),
|
|
875
|
-
/* @__PURE__ */ (0,
|
|
2161
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
876
2162
|
"button",
|
|
877
2163
|
{
|
|
878
2164
|
type: "button",
|
|
@@ -883,10 +2169,10 @@ function MatrxUuidCell({
|
|
|
883
2169
|
"inline-flex h-4 w-4 shrink-0 items-center justify-center rounded text-muted-foreground transition-colors hover:text-foreground focus:outline-none",
|
|
884
2170
|
copied && "text-primary"
|
|
885
2171
|
),
|
|
886
|
-
children: copied ? /* @__PURE__ */ (0,
|
|
2172
|
+
children: copied ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Check, { className: "h-3 w-3" }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Copy, { className: "h-3 w-3" })
|
|
887
2173
|
}
|
|
888
2174
|
),
|
|
889
|
-
canPeek ? /* @__PURE__ */ (0,
|
|
2175
|
+
canPeek ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
890
2176
|
"button",
|
|
891
2177
|
{
|
|
892
2178
|
type: "button",
|
|
@@ -897,10 +2183,10 @@ function MatrxUuidCell({
|
|
|
897
2183
|
"aria-label": `Quick look at ${label ?? "record"}`,
|
|
898
2184
|
title: `Quick look at ${label ?? "record"}`,
|
|
899
2185
|
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",
|
|
900
|
-
children: /* @__PURE__ */ (0,
|
|
2186
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Lightbulb, { className: "h-3 w-3" })
|
|
901
2187
|
}
|
|
902
2188
|
) : null,
|
|
903
|
-
onOpen && resolvedHref && !forbidden ? /* @__PURE__ */ (0,
|
|
2189
|
+
onOpen && resolvedHref && !forbidden ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
904
2190
|
"a",
|
|
905
2191
|
{
|
|
906
2192
|
href: resolvedHref,
|
|
@@ -910,12 +2196,12 @@ function MatrxUuidCell({
|
|
|
910
2196
|
"aria-label": `Open ${label ?? "record"} in a new tab`,
|
|
911
2197
|
title: `Open ${label ?? "record"} in a new tab`,
|
|
912
2198
|
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",
|
|
913
|
-
children: /* @__PURE__ */ (0,
|
|
2199
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ExternalLink, { className: "h-3 w-3" })
|
|
914
2200
|
}
|
|
915
2201
|
) : null,
|
|
916
2202
|
trailing,
|
|
917
2203
|
notice,
|
|
918
|
-
canPeek && peekOpen && ResourcePeek ? /* @__PURE__ */ (0,
|
|
2204
|
+
canPeek && peekOpen && ResourcePeek ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
919
2205
|
ResourcePeek,
|
|
920
2206
|
{
|
|
921
2207
|
kind: doors?.peekKind ?? token ?? "record",
|
|
@@ -935,7 +2221,7 @@ function isUuidValue(value) {
|
|
|
935
2221
|
}
|
|
936
2222
|
|
|
937
2223
|
// src/data-table/DataRowInspector.tsx
|
|
938
|
-
var
|
|
2224
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
939
2225
|
var noFieldToken = () => null;
|
|
940
2226
|
function formatValue(value) {
|
|
941
2227
|
if (value == null) return "\u2014";
|
|
@@ -964,7 +2250,7 @@ function DataRowInspector({
|
|
|
964
2250
|
tokenForField = noFieldToken
|
|
965
2251
|
}) {
|
|
966
2252
|
const entries = isPlainObject(row) ? Object.entries(row) : [["value", row]];
|
|
967
|
-
const fieldButtons = (key, value) => fieldCopy ? /* @__PURE__ */ (0,
|
|
2253
|
+
const fieldButtons = (key, value) => fieldCopy ? /* @__PURE__ */ (0, import_jsx_runtime16.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_runtime16.jsx)(
|
|
968
2254
|
CopyButtons,
|
|
969
2255
|
{
|
|
970
2256
|
size: "xs",
|
|
@@ -979,21 +2265,21 @@ function DataRowInspector({
|
|
|
979
2265
|
})
|
|
980
2266
|
}
|
|
981
2267
|
) }) : null;
|
|
982
|
-
return /* @__PURE__ */ (0,
|
|
2268
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
983
2269
|
"div",
|
|
984
2270
|
{
|
|
985
2271
|
className: cn("flex h-full min-h-0 flex-col overflow-hidden", className),
|
|
986
2272
|
children: [
|
|
987
|
-
title ? /* @__PURE__ */ (0,
|
|
988
|
-
/* @__PURE__ */ (0,
|
|
2273
|
+
title ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "shrink-0 border-b border-border px-3 py-2 text-sm font-medium", children: title }) : null,
|
|
2274
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "min-h-0 flex-1 overflow-auto p-3", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("dl", { className: "space-y-2", children: entries.map(([key, value]) => {
|
|
989
2275
|
if (isUuidValue(value)) {
|
|
990
|
-
return /* @__PURE__ */ (0,
|
|
2276
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
991
2277
|
"div",
|
|
992
2278
|
{
|
|
993
2279
|
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",
|
|
994
2280
|
children: [
|
|
995
|
-
/* @__PURE__ */ (0,
|
|
996
|
-
/* @__PURE__ */ (0,
|
|
2281
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("dt", { className: "truncate text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: key }),
|
|
2282
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("dd", { className: "min-w-0", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
997
2283
|
MatrxUuidCell,
|
|
998
2284
|
{
|
|
999
2285
|
value,
|
|
@@ -1008,13 +2294,13 @@ function DataRowInspector({
|
|
|
1008
2294
|
}
|
|
1009
2295
|
const formatted = formatValue(value);
|
|
1010
2296
|
const multiline = formatted.includes("\n") || formatted.length > 80;
|
|
1011
|
-
return /* @__PURE__ */ (0,
|
|
2297
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
1012
2298
|
"div",
|
|
1013
2299
|
{
|
|
1014
2300
|
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",
|
|
1015
2301
|
children: [
|
|
1016
|
-
/* @__PURE__ */ (0,
|
|
1017
|
-
/* @__PURE__ */ (0,
|
|
2302
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("dt", { className: "truncate text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: key }),
|
|
2303
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
1018
2304
|
"dd",
|
|
1019
2305
|
{
|
|
1020
2306
|
className: cn(
|
|
@@ -1036,7 +2322,7 @@ function DataRowInspector({
|
|
|
1036
2322
|
}
|
|
1037
2323
|
|
|
1038
2324
|
// src/data-table/DataRowWindow.tsx
|
|
1039
|
-
var
|
|
2325
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
1040
2326
|
function DataRowWindow({
|
|
1041
2327
|
isOpen,
|
|
1042
2328
|
onClose,
|
|
@@ -1056,15 +2342,15 @@ function DataRowWindow({
|
|
|
1056
2342
|
const hasEdit = editContent != null;
|
|
1057
2343
|
const hasTabs = hasEdit && children == null;
|
|
1058
2344
|
const initialTab = defaultTab ?? (hasEdit ? "edit" : "view");
|
|
1059
|
-
const [tab, setTab] = (0,
|
|
1060
|
-
(0,
|
|
2345
|
+
const [tab, setTab] = (0, import_react4.useState)(initialTab);
|
|
2346
|
+
(0, import_react4.useEffect)(() => {
|
|
1061
2347
|
if (!isOpen) return;
|
|
1062
2348
|
setTab(defaultTab ?? (hasEdit ? "edit" : "view"));
|
|
1063
2349
|
}, [isOpen, windowId, hasEdit, defaultTab]);
|
|
1064
2350
|
if (!isOpen) return null;
|
|
1065
|
-
const viewBody = viewContent ?? /* @__PURE__ */ (0,
|
|
1066
|
-
const body = children ?? /* @__PURE__ */ (0,
|
|
1067
|
-
return /* @__PURE__ */ (0,
|
|
2351
|
+
const viewBody = viewContent ?? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(DataRowInspector, { row });
|
|
2352
|
+
const body = children ?? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "flex h-full min-h-0 flex-1 flex-col overflow-hidden", children: hasTabs ? tab === "edit" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "min-h-0 flex-1 overflow-y-auto", children: editContent }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "min-h-0 flex-1 overflow-y-auto", children: viewBody }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "min-h-0 flex-1 overflow-y-auto", children: viewBody }) });
|
|
2353
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
1068
2354
|
WindowPanel,
|
|
1069
2355
|
{
|
|
1070
2356
|
id: windowId,
|
|
@@ -1078,26 +2364,26 @@ function DataRowWindow({
|
|
|
1078
2364
|
bodyClassName: "flex min-h-0 flex-1 flex-col overflow-hidden p-0",
|
|
1079
2365
|
sidebarDefaultSize: 140,
|
|
1080
2366
|
sidebarMinSize: 110,
|
|
1081
|
-
sidebar: hasTabs ? /* @__PURE__ */ (0,
|
|
2367
|
+
sidebar: hasTabs ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
1082
2368
|
"nav",
|
|
1083
2369
|
{
|
|
1084
2370
|
"aria-label": "Row window tabs",
|
|
1085
2371
|
className: "flex h-full flex-col gap-0.5 overflow-y-auto p-1.5",
|
|
1086
2372
|
children: [
|
|
1087
|
-
/* @__PURE__ */ (0,
|
|
2373
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
1088
2374
|
TabButton,
|
|
1089
2375
|
{
|
|
1090
2376
|
active: tab === "view",
|
|
1091
|
-
icon: /* @__PURE__ */ (0,
|
|
2377
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Eye, { className: "h-4 w-4 shrink-0" }),
|
|
1092
2378
|
label: "View",
|
|
1093
2379
|
onClick: () => setTab("view")
|
|
1094
2380
|
}
|
|
1095
2381
|
),
|
|
1096
|
-
/* @__PURE__ */ (0,
|
|
2382
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
1097
2383
|
TabButton,
|
|
1098
2384
|
{
|
|
1099
2385
|
active: tab === "edit",
|
|
1100
|
-
icon: /* @__PURE__ */ (0,
|
|
2386
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Pencil, { className: "h-4 w-4 shrink-0" }),
|
|
1101
2387
|
label: "Edit",
|
|
1102
2388
|
onClick: () => setTab("edit")
|
|
1103
2389
|
}
|
|
@@ -1115,7 +2401,7 @@ function TabButton({
|
|
|
1115
2401
|
label,
|
|
1116
2402
|
onClick
|
|
1117
2403
|
}) {
|
|
1118
|
-
return /* @__PURE__ */ (0,
|
|
2404
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
1119
2405
|
"button",
|
|
1120
2406
|
{
|
|
1121
2407
|
type: "button",
|
|
@@ -1128,7 +2414,7 @@ function TabButton({
|
|
|
1128
2414
|
),
|
|
1129
2415
|
children: [
|
|
1130
2416
|
icon,
|
|
1131
|
-
/* @__PURE__ */ (0,
|
|
2417
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "min-w-0 flex-1 truncate", children: label })
|
|
1132
2418
|
]
|
|
1133
2419
|
}
|
|
1134
2420
|
);
|