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