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