@ai-matrx/design-system 0.18.1 → 0.18.3
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 +25 -0
- package/dist/content-transfer.cjs +143 -34
- package/dist/content-transfer.cjs.map +1 -1
- package/dist/content-transfer.d.cts +5 -1
- package/dist/content-transfer.d.ts +5 -1
- package/dist/content-transfer.js +143 -34
- package/dist/content-transfer.js.map +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 +146 -36
- package/dist/data-table/data-row-inspector.cjs.map +1 -1
- package/dist/data-table/data-row-inspector.js +146 -36
- package/dist/data-table/data-row-inspector.js.map +1 -1
- package/dist/data-table/data-row-window.cjs +146 -36
- package/dist/data-table/data-row-window.cjs.map +1 -1
- package/dist/data-table/data-row-window.js +146 -36
- package/dist/data-table/data-row-window.js.map +1 -1
- package/dist/data-table/index.cjs +146 -36
- package/dist/data-table/index.cjs.map +1 -1
- package/dist/data-table/index.js +146 -36
- package/dist/data-table/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.18.3 — 2026-09-12
|
|
4
|
+
|
|
5
|
+
Reopening an Alchemy preparation now checks the current source while retaining
|
|
6
|
+
manual drafts. Changed direct sources offer an explicit keep-or-regenerate
|
|
7
|
+
choice, all-matching sources detect identity changes without eagerly fetching
|
|
8
|
+
pages, and failed refreshes remain visible instead of silently reusing stale
|
|
9
|
+
content.
|
|
10
|
+
|
|
11
|
+
### Consumer action
|
|
12
|
+
|
|
13
|
+
Update to 0.18.3. No host configuration changes are required.
|
|
14
|
+
|
|
15
|
+
## 0.18.2 — 2026-09-12
|
|
16
|
+
|
|
17
|
+
Alchemy copy sessions now reset only when their explicit identity changes,
|
|
18
|
+
preventing organization or authentication transitions from leaking prepared
|
|
19
|
+
state across sessions. Data-table copy sources explicitly identify the table as
|
|
20
|
+
their primary source while preserving raw JSON and hidden-export preparation.
|
|
21
|
+
Failed-run recovery remains limited to valid recoverable runs.
|
|
22
|
+
|
|
23
|
+
### Consumer action
|
|
24
|
+
|
|
25
|
+
Update to 0.18.2 and provide a stable `identityKey` wherever authentication or
|
|
26
|
+
organization identity can change during a mounted Alchemy session.
|
|
27
|
+
|
|
3
28
|
## 0.18.1 — 2026-09-12
|
|
4
29
|
|
|
5
30
|
Reorderable table columns now drag from the visible header label instead of a
|
|
@@ -660,7 +660,17 @@ var sourceFor = (id, label, build) => ({
|
|
|
660
660
|
}
|
|
661
661
|
});
|
|
662
662
|
function MatrxCopyMenu(props) {
|
|
663
|
-
|
|
663
|
+
const inherited = useContentTransferCapabilities();
|
|
664
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
665
|
+
MatrxCopyMenuSession,
|
|
666
|
+
{
|
|
667
|
+
...props
|
|
668
|
+
},
|
|
669
|
+
JSON.stringify([
|
|
670
|
+
inherited.identityKey ?? null,
|
|
671
|
+
props.sourceId ?? props.label
|
|
672
|
+
])
|
|
673
|
+
);
|
|
664
674
|
}
|
|
665
675
|
function MatrxCopyMenuSession(props) {
|
|
666
676
|
const instance = React7.useId();
|
|
@@ -688,7 +698,7 @@ function MatrxCopyMenuSession(props) {
|
|
|
688
698
|
})) : void 0;
|
|
689
699
|
const agent = aiVisible && props.agent !== void 0 ? make("agent", () => asPayload(resolve(props.agent))) : void 0;
|
|
690
700
|
const structuredAgent = aiVisible && props.agent !== void 0 ? make("structured-agent", () => structuredPayload(resolve(props.agent))) : void 0;
|
|
691
|
-
const table = exportVisible && props.export?.sheetRows ? make("rows", () => {
|
|
701
|
+
const table = (exportVisible || props.primarySource === "table") && props.export?.sheetRows ? make("rows", () => {
|
|
692
702
|
const value = (0, import_content_transfer.normalizeTransferJson)(props.export.sheetRows());
|
|
693
703
|
if (!Array.isArray(value) || value.some(
|
|
694
704
|
(row) => row === null || typeof row !== "object" || Array.isArray(row)
|
|
@@ -835,7 +845,7 @@ function MatrxCopyMenuSession(props) {
|
|
|
835
845
|
return props.sendToSheet(draft.payload.rows, props.label);
|
|
836
846
|
}
|
|
837
847
|
});
|
|
838
|
-
const source = json ?? table ?? structuredAgent ?? human ?? builderVariants[0]?.source;
|
|
848
|
+
const source = (props.primarySource === "table" ? table : void 0) ?? json ?? table ?? structuredAgent ?? human ?? builderVariants[0]?.source;
|
|
839
849
|
if (!source && !actions.length) return null;
|
|
840
850
|
const target = source ?? make("actions", () => ({ kind: "text", text: props.label }));
|
|
841
851
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
@@ -855,7 +865,7 @@ function MatrxCopyMenuSession(props) {
|
|
|
855
865
|
formatSources: {
|
|
856
866
|
...human ? { plain: human, markdown: humanMarkdown, html: humanMarkdown } : {},
|
|
857
867
|
...json ? { json, "compact-json": json } : {},
|
|
858
|
-
...table ? { csv: table, tsv: table } : {}
|
|
868
|
+
...table && exportVisible ? { csv: table, tsv: table } : {}
|
|
859
869
|
},
|
|
860
870
|
...props.disabled !== void 0 ? { disabled: props.disabled } : {},
|
|
861
871
|
className: cn(
|
|
@@ -1240,6 +1250,10 @@ function materialIdentity(material) {
|
|
|
1240
1250
|
}
|
|
1241
1251
|
return `payload:${id}`;
|
|
1242
1252
|
}
|
|
1253
|
+
function snapshotContent(snapshot) {
|
|
1254
|
+
const { sourceId, label, payload, coverage, unsavedChanges, omissions, sections, limits } = snapshot;
|
|
1255
|
+
return JSON.stringify({ sourceId, label, payload, coverage, unsavedChanges, omissions, sections, limits });
|
|
1256
|
+
}
|
|
1243
1257
|
function useFence() {
|
|
1244
1258
|
const mounted = React8.useRef(true);
|
|
1245
1259
|
const nextId = React8.useRef(0);
|
|
@@ -1288,7 +1302,12 @@ async function buildArtifact(draft, format, label) {
|
|
|
1288
1302
|
const extension = format === "plain" ? "txt" : format === "compact-json" ? "json" : format;
|
|
1289
1303
|
return (0, import_content_transfer2.serialize)(draft, format, { spreadsheetSafe: format === "csv" || format === "tsv", filename: `${filenameFor(label)}.${extension}` });
|
|
1290
1304
|
}
|
|
1291
|
-
function ContentTransferMenu(
|
|
1305
|
+
function ContentTransferMenu(props) {
|
|
1306
|
+
const inherited = React8.useContext(CapabilityContext);
|
|
1307
|
+
const identityKey = props.capabilities?.identityKey ?? inherited.identityKey;
|
|
1308
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ContentTransferMenuSession, { ...props }, identityKey ?? "anonymous");
|
|
1309
|
+
}
|
|
1310
|
+
function ContentTransferMenuSession({ source, surface, label, projection, sections, preferences, table, formatSources, variants = EMPTY_VARIANTS, actions = [], capabilities: local, disabled, enabled = true, className, stopPropagation = true, hide = [], controllerRef }) {
|
|
1292
1311
|
const triggerRef = React8.useRef(null);
|
|
1293
1312
|
const inherited = React8.useContext(CapabilityContext);
|
|
1294
1313
|
const nearestSurface = React8.useContext(SurfaceContext);
|
|
@@ -1337,7 +1356,7 @@ function ContentTransferMenu({ source, surface, label, projection, sections, pre
|
|
|
1337
1356
|
const captured = await material.capture(signal);
|
|
1338
1357
|
sourceMaterial = { id: captured.snapshot.sourceId, label: captured.snapshot.label, capture: async () => captured };
|
|
1339
1358
|
} else if ("kind" in material) {
|
|
1340
|
-
sourceMaterial =
|
|
1359
|
+
sourceMaterial = { id: materialIdentity(material), label: sourceLabel, capture: async () => (0, import_content_transfer2.directSource)(material, { sourceId: materialIdentity(material), label: sourceLabel, ...applyMenuProjection && projection ? { projection } : {}, ...applyMenuProjection && sections ? { sections } : {} }) };
|
|
1341
1360
|
} else if (applyMenuProjection && (projection || sections)) {
|
|
1342
1361
|
sourceMaterial = {
|
|
1343
1362
|
id: material.id,
|
|
@@ -1354,7 +1373,7 @@ function ContentTransferMenu({ source, surface, label, projection, sections, pre
|
|
|
1354
1373
|
} else {
|
|
1355
1374
|
sourceMaterial = material;
|
|
1356
1375
|
}
|
|
1357
|
-
const raw =
|
|
1376
|
+
const raw = await sourceMaterial.capture({ scope, signal });
|
|
1358
1377
|
const constrained = (0, import_content_transfer2.resolveTransferPreferences)(providerPreferences, preferences, raw.snapshot.limits);
|
|
1359
1378
|
const result = await (0, import_content_transfer2.capture)({ id: raw.snapshot.sourceId, label: raw.snapshot.label, capture: async () => ({ ...raw, snapshot: { ...raw.snapshot, limits: constrained.limits } }) }, signal, scope);
|
|
1360
1379
|
if (scope !== "all-matching" || !collectPages) return result;
|
|
@@ -1414,31 +1433,117 @@ function ContentTransferMenu({ source, surface, label, projection, sections, pre
|
|
|
1414
1433
|
fence.finish(controller);
|
|
1415
1434
|
}
|
|
1416
1435
|
}, [captureOne, capturePrimary, fence, formatSources, initialScope, preferences, providerPreferences, report, transport]);
|
|
1417
|
-
const openWorkspace = React8.useCallback(
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
const
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1436
|
+
const openWorkspace = React8.useCallback(
|
|
1437
|
+
async (key = primaryWorkspaceKey, variant) => {
|
|
1438
|
+
const variantMaterial = variant && "kind" in variant.source ? {
|
|
1439
|
+
id: `variant:${key}`,
|
|
1440
|
+
label: variant.label,
|
|
1441
|
+
capture: async () => (0, import_content_transfer2.directSource)(variant.source, {
|
|
1442
|
+
sourceId: `variant:${key}`,
|
|
1443
|
+
label: variant.label
|
|
1444
|
+
})
|
|
1445
|
+
} : variant?.source;
|
|
1446
|
+
const captureWorkspace = (scope, signal, collectPages = true) => captureOne(variantMaterial ?? primary, scope, signal, true, collectPages);
|
|
1447
|
+
workspaceCaptures.current.set(key, captureWorkspace);
|
|
1448
|
+
const existing = workspaces[key];
|
|
1449
|
+
const { controller, id } = fence.begin();
|
|
1450
|
+
if (existing) {
|
|
1451
|
+
try {
|
|
1452
|
+
const allMatching = existing.scope === "all-matching";
|
|
1453
|
+
const fresh = await captureWorkspace(
|
|
1454
|
+
existing.scope,
|
|
1455
|
+
controller.signal,
|
|
1456
|
+
!allMatching
|
|
1457
|
+
);
|
|
1458
|
+
if (!fence.valid(id, controller) || !workspaceCaptures.current.has(key))
|
|
1459
|
+
return;
|
|
1460
|
+
if (allMatching && (!existing.allMatching || !fresh.allMatching))
|
|
1461
|
+
throw new Error(
|
|
1462
|
+
"This source can no longer provide an all-matching snapshot."
|
|
1463
|
+
);
|
|
1464
|
+
const collectionIdentity = (value) => value && {
|
|
1465
|
+
query: value.source.query,
|
|
1466
|
+
projection: value.projection,
|
|
1467
|
+
columns: value.columns,
|
|
1468
|
+
limits: value.limits
|
|
1469
|
+
};
|
|
1470
|
+
const changed = allMatching ? JSON.stringify(collectionIdentity(existing.allMatching)) !== JSON.stringify(collectionIdentity(fresh.allMatching)) : snapshotContent(existing.snapshot) !== snapshotContent(fresh.snapshot);
|
|
1471
|
+
setWorkspaces((current) => {
|
|
1472
|
+
const retained = current[key];
|
|
1473
|
+
if (!retained) return current;
|
|
1474
|
+
return {
|
|
1475
|
+
...current,
|
|
1476
|
+
[key]: {
|
|
1477
|
+
...retained,
|
|
1478
|
+
error: fresh.collectionError,
|
|
1479
|
+
...allMatching ? { sourceStale: changed } : changed ? { pending: { ...fresh, scope: retained.scope } } : { pending: void 0 }
|
|
1480
|
+
}
|
|
1481
|
+
};
|
|
1482
|
+
});
|
|
1483
|
+
setWorkspaceKey(key);
|
|
1484
|
+
setWorkspaceOpen(true);
|
|
1485
|
+
} catch (error) {
|
|
1486
|
+
if (fence.valid(id, controller) && workspaceCaptures.current.has(key)) {
|
|
1487
|
+
setWorkspaces(
|
|
1488
|
+
(current) => current[key] ? {
|
|
1489
|
+
...current,
|
|
1490
|
+
[key]: {
|
|
1491
|
+
...current[key],
|
|
1492
|
+
error: errorMessage(error, "Could not refresh source")
|
|
1493
|
+
}
|
|
1494
|
+
} : current
|
|
1495
|
+
);
|
|
1496
|
+
setWorkspaceKey(key);
|
|
1497
|
+
setWorkspaceOpen(true);
|
|
1498
|
+
}
|
|
1499
|
+
} finally {
|
|
1500
|
+
fence.finish(controller);
|
|
1501
|
+
}
|
|
1502
|
+
return;
|
|
1503
|
+
}
|
|
1504
|
+
try {
|
|
1505
|
+
const result = await captureWorkspace(initialScope, controller.signal);
|
|
1506
|
+
if (!fence.valid(id, controller)) return;
|
|
1507
|
+
const resolved = (0, import_content_transfer2.resolveTransferPreferences)(
|
|
1508
|
+
providerPreferences,
|
|
1509
|
+
preferences,
|
|
1510
|
+
result.snapshot.limits
|
|
1511
|
+
);
|
|
1512
|
+
const original = (0, import_content_transfer2.createDraft)(result.snapshot);
|
|
1513
|
+
const base = {
|
|
1514
|
+
...result,
|
|
1515
|
+
key,
|
|
1516
|
+
original,
|
|
1517
|
+
draft: original,
|
|
1518
|
+
scope: initialScope,
|
|
1519
|
+
preferences: resolved,
|
|
1520
|
+
...result.collectionError ? { error: result.collectionError } : {}
|
|
1521
|
+
};
|
|
1522
|
+
setWorkspaces((current) => ({
|
|
1523
|
+
...current,
|
|
1524
|
+
[key]: { ...base, draft: rebuild(base, initialControls(base)) }
|
|
1525
|
+
}));
|
|
1526
|
+
setWorkspaceKey(key);
|
|
1527
|
+
setWorkspaceOpen(true);
|
|
1528
|
+
} catch (error) {
|
|
1529
|
+
if (fence.valid(id, controller))
|
|
1530
|
+
setNotice(errorMessage(error, "Could not capture content"));
|
|
1531
|
+
} finally {
|
|
1532
|
+
fence.finish(controller);
|
|
1533
|
+
}
|
|
1534
|
+
},
|
|
1535
|
+
[
|
|
1536
|
+
captureOne,
|
|
1537
|
+
capturePrimary,
|
|
1538
|
+
fence,
|
|
1539
|
+
initialScope,
|
|
1540
|
+
preferences,
|
|
1541
|
+
primaryWorkspaceKey,
|
|
1542
|
+
primary,
|
|
1543
|
+
providerPreferences,
|
|
1544
|
+
workspaces
|
|
1545
|
+
]
|
|
1546
|
+
);
|
|
1442
1547
|
React8.useImperativeHandle(controllerRef, () => ({
|
|
1443
1548
|
focusTrigger: () => triggerRef.current?.focus(),
|
|
1444
1549
|
prepare: async (requestedSource, options) => {
|
|
@@ -1581,6 +1686,9 @@ function PreparationWorkspace({ restoreFocus, open, state, scopes, onClose, onCh
|
|
|
1581
1686
|
const [instruction, setInstruction] = React8.useState("");
|
|
1582
1687
|
const [busy, setBusy] = React8.useState(null);
|
|
1583
1688
|
const [aiFailed, setAiFailed] = React8.useState(false);
|
|
1689
|
+
React8.useEffect(() => {
|
|
1690
|
+
setAiFailed(false);
|
|
1691
|
+
}, [state.snapshot.id, state.draft.revision]);
|
|
1584
1692
|
const activeAi = React8.useRef(null);
|
|
1585
1693
|
const activeCapture = React8.useRef(null);
|
|
1586
1694
|
React8.useEffect(() => {
|
|
@@ -1658,7 +1766,7 @@ function PreparationWorkspace({ restoreFocus, open, state, scopes, onClose, onCh
|
|
|
1658
1766
|
setBusy("capture");
|
|
1659
1767
|
try {
|
|
1660
1768
|
const result = await captureScope(scope, controller.signal);
|
|
1661
|
-
if (fence.valid(id, controller) && latest.current.draft.revision === revision) onChange({ ...latest.current, pending: { ...result, scope }, error: result.collectionError });
|
|
1769
|
+
if (fence.valid(id, controller) && latest.current.draft.revision === revision) onChange({ ...latest.current, pending: { ...result, scope }, sourceStale: false, error: result.collectionError });
|
|
1662
1770
|
} catch (error) {
|
|
1663
1771
|
if (fence.valid(id, controller)) onChange({ ...latest.current, error: errorMessage(error, "Refresh failed") });
|
|
1664
1772
|
} finally {
|
|
@@ -1891,7 +1999,7 @@ function PreparationWorkspace({ restoreFocus, open, state, scopes, onClose, onCh
|
|
|
1891
1999
|
activeCapture.current = null;
|
|
1892
2000
|
setBusy(null);
|
|
1893
2001
|
}, children: "Stop loading rows" }) : null,
|
|
1894
|
-
ai && aiSession.current?.recover && busy !== "ai" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Button, { type: "button", variant: "outline", onClick: () => void runAi(true), children: aiFailed ? "Retry or rejoin AI run" : "Rejoin AI run" }) : null,
|
|
2002
|
+
ai && aiFailed && aiSession.current?.recover && busy !== "ai" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Button, { type: "button", variant: "outline", onClick: () => void runAi(true), children: aiFailed ? "Retry or rejoin AI run" : "Rejoin AI run" }) : null,
|
|
1895
2003
|
ai ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "matrx-alchemy-meta", children: "AI creates a preview. It never copies automatically. Closing detaches this view without cancelling server work." }) : null,
|
|
1896
2004
|
state.error ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { role: "alert", className: "matrx-alchemy-error", children: state.error }) : null
|
|
1897
2005
|
] }) : null
|
|
@@ -1901,6 +2009,7 @@ function PreparationWorkspace({ restoreFocus, open, state, scopes, onClose, onCh
|
|
|
1901
2009
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Button, { type: "button", variant: "outline", onClick: () => setPendingControls(null), children: "Keep edited draft" }),
|
|
1902
2010
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Button, { type: "button", onClick: applyPendingControls, children: "Rebuild from source" })
|
|
1903
2011
|
] }) : null,
|
|
2012
|
+
state.sourceStale ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { role: "alert", className: "matrx-alchemy-decision", children: "The source changed since this draft. Use Refresh source to review the latest data." }) : null,
|
|
1904
2013
|
state.pending ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "matrx-alchemy-decision", role: "alert", children: [
|
|
1905
2014
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { children: "A fresh source snapshot is ready." }),
|
|
1906
2015
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Button, { type: "button", variant: "outline", onClick: () => resolveCapture("keep"), children: "Keep current snapshot and draft" }),
|