@ai-matrx/design-system 0.18.2 → 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.
@@ -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" }),