@ai-matrx/design-system 0.18.2 → 0.18.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/README.md +22 -0
- package/dist/content-transfer.cjs +127 -30
- package/dist/content-transfer.cjs.map +1 -1
- package/dist/content-transfer.d.cts +2 -0
- package/dist/content-transfer.d.ts +2 -0
- package/dist/content-transfer.js +127 -30
- package/dist/content-transfer.js.map +1 -1
- package/dist/data-table/copy-helpers.d.cts +1 -1
- package/dist/data-table/copy-helpers.d.ts +1 -1
- package/dist/data-table/data-row-inspector.cjs +127 -30
- package/dist/data-table/data-row-inspector.cjs.map +1 -1
- package/dist/data-table/data-row-inspector.js +127 -30
- package/dist/data-table/data-row-inspector.js.map +1 -1
- package/dist/data-table/data-row-window.cjs +127 -30
- package/dist/data-table/data-row-window.cjs.map +1 -1
- package/dist/data-table/data-row-window.js +127 -30
- 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 +1158 -956
- package/dist/data-table/index.cjs.map +1 -1
- package/dist/data-table/index.d.cts +23 -3
- package/dist/data-table/index.d.ts +23 -3
- package/dist/data-table/index.js +1158 -956
- 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/pagination.cjs +2 -2
- package/dist/data-table/pagination.cjs.map +1 -1
- package/dist/data-table/pagination.js +2 -2
- package/dist/data-table/pagination.js.map +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/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/{types-CD4xGL5Z.d.cts → types-Bx9SfdJM.d.cts} +2 -0
- package/dist/{types-BhSkeZQ_.d.ts → types-DyByb6tW.d.ts} +2 -0
- package/package.json +1 -1
|
@@ -95,6 +95,8 @@ interface AlchemyExportItem {
|
|
|
95
95
|
content: BlobPart;
|
|
96
96
|
extension: string;
|
|
97
97
|
mime: string;
|
|
98
|
+
/** Optional exact safe basename captured with bytes; omission derives a default, invalid values error. */
|
|
99
|
+
filename?: string;
|
|
98
100
|
};
|
|
99
101
|
onSelect?: () => void | Promise<void>;
|
|
100
102
|
}
|
|
@@ -95,6 +95,8 @@ interface AlchemyExportItem {
|
|
|
95
95
|
content: BlobPart;
|
|
96
96
|
extension: string;
|
|
97
97
|
mime: string;
|
|
98
|
+
/** Optional exact safe basename captured with bytes; omission derives a default, invalid values error. */
|
|
99
|
+
filename?: string;
|
|
98
100
|
};
|
|
99
101
|
onSelect?: () => void | Promise<void>;
|
|
100
102
|
}
|
package/dist/content-transfer.js
CHANGED
|
@@ -630,6 +630,7 @@ var actionDone = (message) => ({
|
|
|
630
630
|
mimeTypes: [],
|
|
631
631
|
message
|
|
632
632
|
});
|
|
633
|
+
var isSafeFilename = (filename) => filename === filename.trim() && filename.length > 0 && !/^\.+$/.test(filename) && !/[\\/\x00-\x1F\x7F]/.test(filename);
|
|
633
634
|
var sourceFor = (id, label, build) => ({
|
|
634
635
|
id,
|
|
635
636
|
label,
|
|
@@ -778,7 +779,8 @@ function MatrxCopyMenuSession(props) {
|
|
|
778
779
|
value: {
|
|
779
780
|
bytes: Array.from(bytes),
|
|
780
781
|
mime: file.mime,
|
|
781
|
-
extension: file.extension
|
|
782
|
+
extension: file.extension,
|
|
783
|
+
...file.filename !== void 0 ? { filename: file.filename } : {}
|
|
782
784
|
}
|
|
783
785
|
};
|
|
784
786
|
},
|
|
@@ -795,12 +797,16 @@ function MatrxCopyMenuSession(props) {
|
|
|
795
797
|
(byte) => typeof byte !== "number" || !Number.isInteger(byte) || byte < 0 || byte > 255
|
|
796
798
|
))
|
|
797
799
|
throw new Error(`${item.label} did not capture a valid file.`);
|
|
800
|
+
if (value.filename !== void 0 && (typeof value.filename !== "string" || !isSafeFilename(value.filename)))
|
|
801
|
+
throw new Error(
|
|
802
|
+
`${item.label} has an unsafe filename. Use a nonempty basename without leading or trailing whitespace, dots only, path separators, or control characters.`
|
|
803
|
+
);
|
|
798
804
|
if (draft.omissions.some((omission) => omission.reason !== "duplicate"))
|
|
799
805
|
throw new Error(
|
|
800
806
|
"This custom file exceeds the configured export limits or contains excluded content. Use a standard format or revise the source options."
|
|
801
807
|
);
|
|
802
808
|
const bytes = new Uint8Array(value.bytes);
|
|
803
|
-
const filename = `${props.label.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "export"}.${value.extension.replace(/[^a-zA-Z0-9.-]/g, "") || "bin"}`;
|
|
809
|
+
const filename = typeof value.filename === "string" ? value.filename : `${props.label.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "export"}.${value.extension.replace(/[^a-zA-Z0-9.-]/g, "") || "bin"}`;
|
|
804
810
|
return transport.download(
|
|
805
811
|
sealTransferArtifact({
|
|
806
812
|
snapshotId: snapshot.id,
|
|
@@ -1231,6 +1237,10 @@ function materialIdentity(material) {
|
|
|
1231
1237
|
}
|
|
1232
1238
|
return `payload:${id}`;
|
|
1233
1239
|
}
|
|
1240
|
+
function snapshotContent(snapshot) {
|
|
1241
|
+
const { sourceId, label, payload, coverage, unsavedChanges, omissions, sections, limits } = snapshot;
|
|
1242
|
+
return JSON.stringify({ sourceId, label, payload, coverage, unsavedChanges, omissions, sections, limits });
|
|
1243
|
+
}
|
|
1234
1244
|
function useFence() {
|
|
1235
1245
|
const mounted = React8.useRef(true);
|
|
1236
1246
|
const nextId = React8.useRef(0);
|
|
@@ -1333,7 +1343,7 @@ function ContentTransferMenuSession({ source, surface, label, projection, sectio
|
|
|
1333
1343
|
const captured = await material.capture(signal);
|
|
1334
1344
|
sourceMaterial = { id: captured.snapshot.sourceId, label: captured.snapshot.label, capture: async () => captured };
|
|
1335
1345
|
} else if ("kind" in material) {
|
|
1336
|
-
sourceMaterial =
|
|
1346
|
+
sourceMaterial = { id: materialIdentity(material), label: sourceLabel, capture: async () => directSource2(material, { sourceId: materialIdentity(material), label: sourceLabel, ...applyMenuProjection && projection ? { projection } : {}, ...applyMenuProjection && sections ? { sections } : {} }) };
|
|
1337
1347
|
} else if (applyMenuProjection && (projection || sections)) {
|
|
1338
1348
|
sourceMaterial = {
|
|
1339
1349
|
id: material.id,
|
|
@@ -1350,7 +1360,7 @@ function ContentTransferMenuSession({ source, surface, label, projection, sectio
|
|
|
1350
1360
|
} else {
|
|
1351
1361
|
sourceMaterial = material;
|
|
1352
1362
|
}
|
|
1353
|
-
const raw =
|
|
1363
|
+
const raw = await sourceMaterial.capture({ scope, signal });
|
|
1354
1364
|
const constrained = resolveTransferPreferences(providerPreferences, preferences, raw.snapshot.limits);
|
|
1355
1365
|
const result = await capture({ id: raw.snapshot.sourceId, label: raw.snapshot.label, capture: async () => ({ ...raw, snapshot: { ...raw.snapshot, limits: constrained.limits } }) }, signal, scope);
|
|
1356
1366
|
if (scope !== "all-matching" || !collectPages) return result;
|
|
@@ -1410,31 +1420,117 @@ function ContentTransferMenuSession({ source, surface, label, projection, sectio
|
|
|
1410
1420
|
fence.finish(controller);
|
|
1411
1421
|
}
|
|
1412
1422
|
}, [captureOne, capturePrimary, fence, formatSources, initialScope, preferences, providerPreferences, report, transport]);
|
|
1413
|
-
const openWorkspace = React8.useCallback(
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
const
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1423
|
+
const openWorkspace = React8.useCallback(
|
|
1424
|
+
async (key = primaryWorkspaceKey, variant) => {
|
|
1425
|
+
const variantMaterial = variant && "kind" in variant.source ? {
|
|
1426
|
+
id: `variant:${key}`,
|
|
1427
|
+
label: variant.label,
|
|
1428
|
+
capture: async () => directSource2(variant.source, {
|
|
1429
|
+
sourceId: `variant:${key}`,
|
|
1430
|
+
label: variant.label
|
|
1431
|
+
})
|
|
1432
|
+
} : variant?.source;
|
|
1433
|
+
const captureWorkspace = (scope, signal, collectPages = true) => captureOne(variantMaterial ?? primary, scope, signal, true, collectPages);
|
|
1434
|
+
workspaceCaptures.current.set(key, captureWorkspace);
|
|
1435
|
+
const existing = workspaces[key];
|
|
1436
|
+
const { controller, id } = fence.begin();
|
|
1437
|
+
if (existing) {
|
|
1438
|
+
try {
|
|
1439
|
+
const allMatching = existing.scope === "all-matching";
|
|
1440
|
+
const fresh = await captureWorkspace(
|
|
1441
|
+
existing.scope,
|
|
1442
|
+
controller.signal,
|
|
1443
|
+
!allMatching
|
|
1444
|
+
);
|
|
1445
|
+
if (!fence.valid(id, controller) || !workspaceCaptures.current.has(key))
|
|
1446
|
+
return;
|
|
1447
|
+
if (allMatching && (!existing.allMatching || !fresh.allMatching))
|
|
1448
|
+
throw new Error(
|
|
1449
|
+
"This source can no longer provide an all-matching snapshot."
|
|
1450
|
+
);
|
|
1451
|
+
const collectionIdentity = (value) => value && {
|
|
1452
|
+
query: value.source.query,
|
|
1453
|
+
projection: value.projection,
|
|
1454
|
+
columns: value.columns,
|
|
1455
|
+
limits: value.limits
|
|
1456
|
+
};
|
|
1457
|
+
const changed = allMatching ? JSON.stringify(collectionIdentity(existing.allMatching)) !== JSON.stringify(collectionIdentity(fresh.allMatching)) : snapshotContent(existing.snapshot) !== snapshotContent(fresh.snapshot);
|
|
1458
|
+
setWorkspaces((current) => {
|
|
1459
|
+
const retained = current[key];
|
|
1460
|
+
if (!retained) return current;
|
|
1461
|
+
return {
|
|
1462
|
+
...current,
|
|
1463
|
+
[key]: {
|
|
1464
|
+
...retained,
|
|
1465
|
+
error: fresh.collectionError,
|
|
1466
|
+
...allMatching ? { sourceStale: changed } : changed ? { pending: { ...fresh, scope: retained.scope } } : { pending: void 0 }
|
|
1467
|
+
}
|
|
1468
|
+
};
|
|
1469
|
+
});
|
|
1470
|
+
setWorkspaceKey(key);
|
|
1471
|
+
setWorkspaceOpen(true);
|
|
1472
|
+
} catch (error) {
|
|
1473
|
+
if (fence.valid(id, controller) && workspaceCaptures.current.has(key)) {
|
|
1474
|
+
setWorkspaces(
|
|
1475
|
+
(current) => current[key] ? {
|
|
1476
|
+
...current,
|
|
1477
|
+
[key]: {
|
|
1478
|
+
...current[key],
|
|
1479
|
+
error: errorMessage(error, "Could not refresh source")
|
|
1480
|
+
}
|
|
1481
|
+
} : current
|
|
1482
|
+
);
|
|
1483
|
+
setWorkspaceKey(key);
|
|
1484
|
+
setWorkspaceOpen(true);
|
|
1485
|
+
}
|
|
1486
|
+
} finally {
|
|
1487
|
+
fence.finish(controller);
|
|
1488
|
+
}
|
|
1489
|
+
return;
|
|
1490
|
+
}
|
|
1491
|
+
try {
|
|
1492
|
+
const result = await captureWorkspace(initialScope, controller.signal);
|
|
1493
|
+
if (!fence.valid(id, controller)) return;
|
|
1494
|
+
const resolved = resolveTransferPreferences(
|
|
1495
|
+
providerPreferences,
|
|
1496
|
+
preferences,
|
|
1497
|
+
result.snapshot.limits
|
|
1498
|
+
);
|
|
1499
|
+
const original = createDraft(result.snapshot);
|
|
1500
|
+
const base = {
|
|
1501
|
+
...result,
|
|
1502
|
+
key,
|
|
1503
|
+
original,
|
|
1504
|
+
draft: original,
|
|
1505
|
+
scope: initialScope,
|
|
1506
|
+
preferences: resolved,
|
|
1507
|
+
...result.collectionError ? { error: result.collectionError } : {}
|
|
1508
|
+
};
|
|
1509
|
+
setWorkspaces((current) => ({
|
|
1510
|
+
...current,
|
|
1511
|
+
[key]: { ...base, draft: rebuild(base, initialControls(base)) }
|
|
1512
|
+
}));
|
|
1513
|
+
setWorkspaceKey(key);
|
|
1514
|
+
setWorkspaceOpen(true);
|
|
1515
|
+
} catch (error) {
|
|
1516
|
+
if (fence.valid(id, controller))
|
|
1517
|
+
setNotice(errorMessage(error, "Could not capture content"));
|
|
1518
|
+
} finally {
|
|
1519
|
+
fence.finish(controller);
|
|
1520
|
+
}
|
|
1521
|
+
},
|
|
1522
|
+
[
|
|
1523
|
+
captureOne,
|
|
1524
|
+
capturePrimary,
|
|
1525
|
+
fence,
|
|
1526
|
+
initialScope,
|
|
1527
|
+
preferences,
|
|
1528
|
+
primaryWorkspaceKey,
|
|
1529
|
+
primary,
|
|
1530
|
+
providerPreferences,
|
|
1531
|
+
workspaces
|
|
1532
|
+
]
|
|
1533
|
+
);
|
|
1438
1534
|
React8.useImperativeHandle(controllerRef, () => ({
|
|
1439
1535
|
focusTrigger: () => triggerRef.current?.focus(),
|
|
1440
1536
|
prepare: async (requestedSource, options) => {
|
|
@@ -1657,7 +1753,7 @@ function PreparationWorkspace({ restoreFocus, open, state, scopes, onClose, onCh
|
|
|
1657
1753
|
setBusy("capture");
|
|
1658
1754
|
try {
|
|
1659
1755
|
const result = await captureScope(scope, controller.signal);
|
|
1660
|
-
if (fence.valid(id, controller) && latest.current.draft.revision === revision) onChange({ ...latest.current, pending: { ...result, scope }, error: result.collectionError });
|
|
1756
|
+
if (fence.valid(id, controller) && latest.current.draft.revision === revision) onChange({ ...latest.current, pending: { ...result, scope }, sourceStale: false, error: result.collectionError });
|
|
1661
1757
|
} catch (error) {
|
|
1662
1758
|
if (fence.valid(id, controller)) onChange({ ...latest.current, error: errorMessage(error, "Refresh failed") });
|
|
1663
1759
|
} finally {
|
|
@@ -1900,6 +1996,7 @@ function PreparationWorkspace({ restoreFocus, open, state, scopes, onClose, onCh
|
|
|
1900
1996
|
/* @__PURE__ */ jsx8(Button, { type: "button", variant: "outline", onClick: () => setPendingControls(null), children: "Keep edited draft" }),
|
|
1901
1997
|
/* @__PURE__ */ jsx8(Button, { type: "button", onClick: applyPendingControls, children: "Rebuild from source" })
|
|
1902
1998
|
] }) : null,
|
|
1999
|
+
state.sourceStale ? /* @__PURE__ */ jsx8("p", { role: "alert", className: "matrx-alchemy-decision", children: "The source changed since this draft. Use Refresh source to review the latest data." }) : null,
|
|
1903
2000
|
state.pending ? /* @__PURE__ */ jsxs5("div", { className: "matrx-alchemy-decision", role: "alert", children: [
|
|
1904
2001
|
/* @__PURE__ */ jsx8("p", { children: "A fresh source snapshot is ready." }),
|
|
1905
2002
|
/* @__PURE__ */ jsx8(Button, { type: "button", variant: "outline", onClick: () => resolveCapture("keep"), children: "Keep current snapshot and draft" }),
|