@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.
Files changed (50) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +22 -0
  3. package/dist/content-transfer.cjs +127 -30
  4. package/dist/content-transfer.cjs.map +1 -1
  5. package/dist/content-transfer.d.cts +2 -0
  6. package/dist/content-transfer.d.ts +2 -0
  7. package/dist/content-transfer.js +127 -30
  8. package/dist/content-transfer.js.map +1 -1
  9. package/dist/data-table/copy-helpers.d.cts +1 -1
  10. package/dist/data-table/copy-helpers.d.ts +1 -1
  11. package/dist/data-table/data-row-inspector.cjs +127 -30
  12. package/dist/data-table/data-row-inspector.cjs.map +1 -1
  13. package/dist/data-table/data-row-inspector.js +127 -30
  14. package/dist/data-table/data-row-inspector.js.map +1 -1
  15. package/dist/data-table/data-row-window.cjs +127 -30
  16. package/dist/data-table/data-row-window.cjs.map +1 -1
  17. package/dist/data-table/data-row-window.js +127 -30
  18. package/dist/data-table/data-row-window.js.map +1 -1
  19. package/dist/data-table/filter-engine.d.cts +1 -1
  20. package/dist/data-table/filter-engine.d.ts +1 -1
  21. package/dist/data-table/index.cjs +1158 -956
  22. package/dist/data-table/index.cjs.map +1 -1
  23. package/dist/data-table/index.d.cts +23 -3
  24. package/dist/data-table/index.d.ts +23 -3
  25. package/dist/data-table/index.js +1158 -956
  26. package/dist/data-table/index.js.map +1 -1
  27. package/dist/data-table/infer-filter.d.cts +1 -1
  28. package/dist/data-table/infer-filter.d.ts +1 -1
  29. package/dist/data-table/layered-filters.d.cts +1 -1
  30. package/dist/data-table/layered-filters.d.ts +1 -1
  31. package/dist/data-table/pagination.cjs +2 -2
  32. package/dist/data-table/pagination.cjs.map +1 -1
  33. package/dist/data-table/pagination.js +2 -2
  34. package/dist/data-table/pagination.js.map +1 -1
  35. package/dist/data-table/query-control.d.cts +1 -1
  36. package/dist/data-table/query-control.d.ts +1 -1
  37. package/dist/data-table/types.cjs.map +1 -1
  38. package/dist/data-table/types.d.cts +1 -1
  39. package/dist/data-table/types.d.ts +1 -1
  40. package/dist/data-table/url-state.d.cts +1 -1
  41. package/dist/data-table/url-state.d.ts +1 -1
  42. package/dist/data-table/xlsx.d.cts +1 -1
  43. package/dist/data-table/xlsx.d.ts +1 -1
  44. package/dist/index.cjs +2 -2
  45. package/dist/index.cjs.map +1 -1
  46. package/dist/index.js +2 -2
  47. package/dist/index.js.map +1 -1
  48. package/dist/{types-CD4xGL5Z.d.cts → types-Bx9SfdJM.d.cts} +2 -0
  49. package/dist/{types-BhSkeZQ_.d.ts → types-DyByb6tW.d.ts} +2 -0
  50. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  import { AgentPayloadInput } from './copy-types.cjs';
2
- import { f as MatrxDataTableCopyConfig, M as MatrxColumnDef } from '../types-CD4xGL5Z.cjs';
2
+ import { f as MatrxDataTableCopyConfig, M as MatrxColumnDef } from '../types-Bx9SfdJM.cjs';
3
3
  import 'react';
4
4
 
5
5
  /** Human markdown table of the current view (visible columns × rows). */
@@ -1,5 +1,5 @@
1
1
  import { AgentPayloadInput } from './copy-types.js';
2
- import { f as MatrxDataTableCopyConfig, M as MatrxColumnDef } from '../types-BhSkeZQ_.js';
2
+ import { f as MatrxDataTableCopyConfig, M as MatrxColumnDef } from '../types-DyByb6tW.js';
3
3
  import 'react';
4
4
 
5
5
  /** Human markdown table of the current view (visible columns × rows). */
@@ -657,6 +657,10 @@ function materialIdentity(material) {
657
657
  }
658
658
  return `payload:${id}`;
659
659
  }
660
+ function snapshotContent(snapshot) {
661
+ const { sourceId, label, payload, coverage, unsavedChanges, omissions, sections, limits } = snapshot;
662
+ return JSON.stringify({ sourceId, label, payload, coverage, unsavedChanges, omissions, sections, limits });
663
+ }
660
664
  function useFence() {
661
665
  const mounted = React7.useRef(true);
662
666
  const nextId = React7.useRef(0);
@@ -759,7 +763,7 @@ function ContentTransferMenuSession({ source, surface, label, projection, sectio
759
763
  const captured = await material.capture(signal);
760
764
  sourceMaterial = { id: captured.snapshot.sourceId, label: captured.snapshot.label, capture: async () => captured };
761
765
  } else if ("kind" in material) {
762
- sourceMaterial = applyMenuProjection ? { id: "direct", label: sourceLabel, capture: async () => (0, import_content_transfer.directSource)(material, { label: sourceLabel, ...projection ? { projection } : {}, ...sections ? { sections } : {} }) } : material;
766
+ sourceMaterial = { id: materialIdentity(material), label: sourceLabel, capture: async () => (0, import_content_transfer.directSource)(material, { sourceId: materialIdentity(material), label: sourceLabel, ...applyMenuProjection && projection ? { projection } : {}, ...applyMenuProjection && sections ? { sections } : {} }) };
763
767
  } else if (applyMenuProjection && (projection || sections)) {
764
768
  sourceMaterial = {
765
769
  id: material.id,
@@ -776,7 +780,7 @@ function ContentTransferMenuSession({ source, surface, label, projection, sectio
776
780
  } else {
777
781
  sourceMaterial = material;
778
782
  }
779
- const raw = "kind" in sourceMaterial ? (0, import_content_transfer.directSource)(sourceMaterial) : await sourceMaterial.capture({ scope, signal });
783
+ const raw = await sourceMaterial.capture({ scope, signal });
780
784
  const constrained = (0, import_content_transfer.resolveTransferPreferences)(providerPreferences, preferences, raw.snapshot.limits);
781
785
  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);
782
786
  if (scope !== "all-matching" || !collectPages) return result;
@@ -836,31 +840,117 @@ function ContentTransferMenuSession({ source, surface, label, projection, sectio
836
840
  fence.finish(controller);
837
841
  }
838
842
  }, [captureOne, capturePrimary, fence, formatSources, initialScope, preferences, providerPreferences, report, transport]);
839
- const openWorkspace = React7.useCallback(async (key = primaryWorkspaceKey, variant) => {
840
- 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;
841
- const captureWorkspace = variantMaterial ? (scope, signal) => captureOne(variantMaterial, scope, signal, true) : capturePrimary;
842
- workspaceCaptures.current.set(key, captureWorkspace);
843
- if (workspaces[key]) {
844
- setWorkspaceKey(key);
845
- setWorkspaceOpen(true);
846
- return;
847
- }
848
- const { controller, id } = fence.begin();
849
- try {
850
- const result = await captureWorkspace(initialScope, controller.signal);
851
- if (!fence.valid(id, controller)) return;
852
- const resolved = (0, import_content_transfer.resolveTransferPreferences)(providerPreferences, preferences, result.snapshot.limits);
853
- const original = (0, import_content_transfer.createDraft)(result.snapshot);
854
- const base = { ...result, key, original, draft: original, scope: initialScope, preferences: resolved, ...result.collectionError ? { error: result.collectionError } : {} };
855
- setWorkspaces((current) => ({ ...current, [key]: { ...base, draft: rebuild(base, initialControls(base)) } }));
856
- setWorkspaceKey(key);
857
- setWorkspaceOpen(true);
858
- } catch (error) {
859
- if (fence.valid(id, controller)) setNotice(errorMessage(error, "Could not capture content"));
860
- } finally {
861
- fence.finish(controller);
862
- }
863
- }, [captureOne, capturePrimary, fence, initialScope, preferences, primaryWorkspaceKey, providerPreferences, workspaces]);
843
+ const openWorkspace = React7.useCallback(
844
+ async (key = primaryWorkspaceKey, variant) => {
845
+ const variantMaterial = variant && "kind" in variant.source ? {
846
+ id: `variant:${key}`,
847
+ label: variant.label,
848
+ capture: async () => (0, import_content_transfer.directSource)(variant.source, {
849
+ sourceId: `variant:${key}`,
850
+ label: variant.label
851
+ })
852
+ } : variant?.source;
853
+ const captureWorkspace = (scope, signal, collectPages = true) => captureOne(variantMaterial ?? primary, scope, signal, true, collectPages);
854
+ workspaceCaptures.current.set(key, captureWorkspace);
855
+ const existing = workspaces[key];
856
+ const { controller, id } = fence.begin();
857
+ if (existing) {
858
+ try {
859
+ const allMatching = existing.scope === "all-matching";
860
+ const fresh = await captureWorkspace(
861
+ existing.scope,
862
+ controller.signal,
863
+ !allMatching
864
+ );
865
+ if (!fence.valid(id, controller) || !workspaceCaptures.current.has(key))
866
+ return;
867
+ if (allMatching && (!existing.allMatching || !fresh.allMatching))
868
+ throw new Error(
869
+ "This source can no longer provide an all-matching snapshot."
870
+ );
871
+ const collectionIdentity = (value) => value && {
872
+ query: value.source.query,
873
+ projection: value.projection,
874
+ columns: value.columns,
875
+ limits: value.limits
876
+ };
877
+ const changed = allMatching ? JSON.stringify(collectionIdentity(existing.allMatching)) !== JSON.stringify(collectionIdentity(fresh.allMatching)) : snapshotContent(existing.snapshot) !== snapshotContent(fresh.snapshot);
878
+ setWorkspaces((current) => {
879
+ const retained = current[key];
880
+ if (!retained) return current;
881
+ return {
882
+ ...current,
883
+ [key]: {
884
+ ...retained,
885
+ error: fresh.collectionError,
886
+ ...allMatching ? { sourceStale: changed } : changed ? { pending: { ...fresh, scope: retained.scope } } : { pending: void 0 }
887
+ }
888
+ };
889
+ });
890
+ setWorkspaceKey(key);
891
+ setWorkspaceOpen(true);
892
+ } catch (error) {
893
+ if (fence.valid(id, controller) && workspaceCaptures.current.has(key)) {
894
+ setWorkspaces(
895
+ (current) => current[key] ? {
896
+ ...current,
897
+ [key]: {
898
+ ...current[key],
899
+ error: errorMessage(error, "Could not refresh source")
900
+ }
901
+ } : current
902
+ );
903
+ setWorkspaceKey(key);
904
+ setWorkspaceOpen(true);
905
+ }
906
+ } finally {
907
+ fence.finish(controller);
908
+ }
909
+ return;
910
+ }
911
+ try {
912
+ const result = await captureWorkspace(initialScope, controller.signal);
913
+ if (!fence.valid(id, controller)) return;
914
+ const resolved = (0, import_content_transfer.resolveTransferPreferences)(
915
+ providerPreferences,
916
+ preferences,
917
+ result.snapshot.limits
918
+ );
919
+ const original = (0, import_content_transfer.createDraft)(result.snapshot);
920
+ const base = {
921
+ ...result,
922
+ key,
923
+ original,
924
+ draft: original,
925
+ scope: initialScope,
926
+ preferences: resolved,
927
+ ...result.collectionError ? { error: result.collectionError } : {}
928
+ };
929
+ setWorkspaces((current) => ({
930
+ ...current,
931
+ [key]: { ...base, draft: rebuild(base, initialControls(base)) }
932
+ }));
933
+ setWorkspaceKey(key);
934
+ setWorkspaceOpen(true);
935
+ } catch (error) {
936
+ if (fence.valid(id, controller))
937
+ setNotice(errorMessage(error, "Could not capture content"));
938
+ } finally {
939
+ fence.finish(controller);
940
+ }
941
+ },
942
+ [
943
+ captureOne,
944
+ capturePrimary,
945
+ fence,
946
+ initialScope,
947
+ preferences,
948
+ primaryWorkspaceKey,
949
+ primary,
950
+ providerPreferences,
951
+ workspaces
952
+ ]
953
+ );
864
954
  React7.useImperativeHandle(controllerRef, () => ({
865
955
  focusTrigger: () => triggerRef.current?.focus(),
866
956
  prepare: async (requestedSource, options) => {
@@ -1083,7 +1173,7 @@ function PreparationWorkspace({ restoreFocus, open, state, scopes, onClose, onCh
1083
1173
  setBusy("capture");
1084
1174
  try {
1085
1175
  const result = await captureScope(scope, controller.signal);
1086
- if (fence.valid(id, controller) && latest.current.draft.revision === revision) onChange({ ...latest.current, pending: { ...result, scope }, error: result.collectionError });
1176
+ if (fence.valid(id, controller) && latest.current.draft.revision === revision) onChange({ ...latest.current, pending: { ...result, scope }, sourceStale: false, error: result.collectionError });
1087
1177
  } catch (error) {
1088
1178
  if (fence.valid(id, controller)) onChange({ ...latest.current, error: errorMessage(error, "Refresh failed") });
1089
1179
  } finally {
@@ -1326,6 +1416,7 @@ function PreparationWorkspace({ restoreFocus, open, state, scopes, onClose, onCh
1326
1416
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Button, { type: "button", variant: "outline", onClick: () => setPendingControls(null), children: "Keep edited draft" }),
1327
1417
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Button, { type: "button", onClick: applyPendingControls, children: "Rebuild from source" })
1328
1418
  ] }) : null,
1419
+ state.sourceStale ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { role: "alert", className: "matrx-alchemy-decision", children: "The source changed since this draft. Use Refresh source to review the latest data." }) : null,
1329
1420
  state.pending ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "matrx-alchemy-decision", role: "alert", children: [
1330
1421
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { children: "A fresh source snapshot is ready." }),
1331
1422
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Button, { type: "button", variant: "outline", onClick: () => resolveCapture("keep"), children: "Keep current snapshot and draft" }),
@@ -1432,6 +1523,7 @@ var actionDone = (message) => ({
1432
1523
  mimeTypes: [],
1433
1524
  message
1434
1525
  });
1526
+ var isSafeFilename = (filename) => filename === filename.trim() && filename.length > 0 && !/^\.+$/.test(filename) && !/[\\/\x00-\x1F\x7F]/.test(filename);
1435
1527
  var sourceFor = (id, label, build) => ({
1436
1528
  id,
1437
1529
  label,
@@ -1580,7 +1672,8 @@ function MatrxCopyMenuSession(props) {
1580
1672
  value: {
1581
1673
  bytes: Array.from(bytes),
1582
1674
  mime: file.mime,
1583
- extension: file.extension
1675
+ extension: file.extension,
1676
+ ...file.filename !== void 0 ? { filename: file.filename } : {}
1584
1677
  }
1585
1678
  };
1586
1679
  },
@@ -1597,12 +1690,16 @@ function MatrxCopyMenuSession(props) {
1597
1690
  (byte) => typeof byte !== "number" || !Number.isInteger(byte) || byte < 0 || byte > 255
1598
1691
  ))
1599
1692
  throw new Error(`${item.label} did not capture a valid file.`);
1693
+ if (value.filename !== void 0 && (typeof value.filename !== "string" || !isSafeFilename(value.filename)))
1694
+ throw new Error(
1695
+ `${item.label} has an unsafe filename. Use a nonempty basename without leading or trailing whitespace, dots only, path separators, or control characters.`
1696
+ );
1600
1697
  if (draft.omissions.some((omission) => omission.reason !== "duplicate"))
1601
1698
  throw new Error(
1602
1699
  "This custom file exceeds the configured export limits or contains excluded content. Use a standard format or revise the source options."
1603
1700
  );
1604
1701
  const bytes = new Uint8Array(value.bytes);
1605
- const filename = `${props.label.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "export"}.${value.extension.replace(/[^a-zA-Z0-9.-]/g, "") || "bin"}`;
1702
+ 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"}`;
1606
1703
  return transport.download(
1607
1704
  (0, import_content_transfer2.sealTransferArtifact)({
1608
1705
  snapshotId: snapshot.id,