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