@ai-matrx/capture 0.5.3 → 0.5.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/dist/react.d.cts CHANGED
@@ -231,6 +231,9 @@ interface CaptureMediaItem {
231
231
  /** Async URL resolution for persisted items. Called at most once per key
232
232
  * while cached; concurrent callers share the in-flight promise. */
233
233
  resolve?: () => Promise<ResolvedMedia>;
234
+ /** Fresh bytes for pixel editing. Persisted hosts should provide this
235
+ * instead of asking the editor to borrow a cache-owned viewer URL. */
236
+ resolveEditBlob?: () => Promise<Blob>;
234
237
  /** Upload/processing state — the filmstrip renders it honestly. */
235
238
  status?: "ready" | "uploading" | "error";
236
239
  /** Accent ring on the filmstrip tile (e.g. a delineator frame). */
package/dist/react.d.ts CHANGED
@@ -231,6 +231,9 @@ interface CaptureMediaItem {
231
231
  /** Async URL resolution for persisted items. Called at most once per key
232
232
  * while cached; concurrent callers share the in-flight promise. */
233
233
  resolve?: () => Promise<ResolvedMedia>;
234
+ /** Fresh bytes for pixel editing. Persisted hosts should provide this
235
+ * instead of asking the editor to borrow a cache-owned viewer URL. */
236
+ resolveEditBlob?: () => Promise<Blob>;
234
237
  /** Upload/processing state — the filmstrip renders it honestly. */
235
238
  status?: "ready" | "uploading" | "error";
236
239
  /** Accent ring on the filmstrip tile (e.g. a delineator frame). */
package/dist/react.js CHANGED
@@ -661,6 +661,16 @@ function invalidateMedia(key) {
661
661
  if (entry?.revoke && entry.url) URL.revokeObjectURL(entry.url);
662
662
  notify(key);
663
663
  }
664
+ async function prepareMediaForEdit(item) {
665
+ if (item.resolveEditBlob) {
666
+ const blob = await item.resolveEditBlob();
667
+ if (blob.size === 0) throw new Error("media snapshot was empty");
668
+ return { url: URL.createObjectURL(blob), revoke: true };
669
+ }
670
+ const url = item.src ?? getMediaUrl(item);
671
+ if (!url) throw new Error("media item has no editable source");
672
+ return { url, revoke: false };
673
+ }
664
674
  function useMediaUrl(item) {
665
675
  const [, bump] = useState2(0);
666
676
  const key = item?.key ?? null;
@@ -1549,6 +1559,10 @@ function CameraCapture({
1549
1559
  const [optionsOpen, setOptionsOpen] = useState5(false);
1550
1560
  const [viewerKey, setViewerKey] = useState5(null);
1551
1561
  const [editTarget, setEditTarget] = useState5(null);
1562
+ const [editPreparing, setEditPreparing] = useState5(false);
1563
+ const [editPreparationError, setEditPreparationError] = useState5(
1564
+ null
1565
+ );
1552
1566
  const [gridOn, setGridOn] = useState5(false);
1553
1567
  const [timerSetting, setTimerSetting] = useState5(0);
1554
1568
  const [aspect, setAspect] = useState5("full");
@@ -1573,6 +1587,12 @@ function CameraCapture({
1573
1587
  useEffect5(() => {
1574
1588
  onReviewOpenChange?.(reviewOpen);
1575
1589
  }, [reviewOpen, onReviewOpenChange]);
1590
+ useEffect5(
1591
+ () => () => {
1592
+ if (editTarget?.revoke) URL.revokeObjectURL(editTarget.url);
1593
+ },
1594
+ [editTarget]
1595
+ );
1576
1596
  const clearCountdown = useCallback4(() => {
1577
1597
  if (countdownRef.current) clearInterval(countdownRef.current);
1578
1598
  countdownRef.current = null;
@@ -1886,8 +1906,16 @@ function CameraCapture({
1886
1906
  invalidateMedia(item.key);
1887
1907
  } : void 0,
1888
1908
  onEdit: media.onReplacePhoto ? (item) => {
1889
- const url = getMediaUrl(item);
1890
- if (url) setEditTarget({ key: item.key, url });
1909
+ if (editPreparing) return;
1910
+ setEditPreparing(true);
1911
+ setEditPreparationError(null);
1912
+ void prepareMediaForEdit(item).then(
1913
+ (prepared) => setEditTarget({ key: item.key, ...prepared })
1914
+ ).catch(
1915
+ () => setEditPreparationError(
1916
+ "This photo could not be prepared for editing. Try again."
1917
+ )
1918
+ ).finally(() => setEditPreparing(false));
1891
1919
  } : void 0
1892
1920
  }
1893
1921
  ),
@@ -1908,6 +1936,14 @@ function CameraCapture({
1908
1936
  }
1909
1937
  }
1910
1938
  ),
1939
+ editPreparationError && /* @__PURE__ */ jsx12(
1940
+ "p",
1941
+ {
1942
+ role: "alert",
1943
+ className: "fixed inset-x-4 bottom-24 z-[70] rounded-xl bg-black/85 px-4 py-3 text-center text-sm text-[#FF6961]",
1944
+ children: editPreparationError
1945
+ }
1946
+ ),
1911
1947
  slots.overlays
1912
1948
  ] });
1913
1949
  }
@@ -2206,7 +2242,9 @@ function CameraCaptureV3({
2206
2242
  slots = {}
2207
2243
  }) {
2208
2244
  const [viewerKey, setViewerKey] = useState8(null);
2209
- const [editTarget, setEditTarget] = useState8(
2245
+ const [editTarget, setEditTarget] = useState8(null);
2246
+ const [editPreparing, setEditPreparing] = useState8(false);
2247
+ const [editPreparationError, setEditPreparationError] = useState8(
2210
2248
  null
2211
2249
  );
2212
2250
  const [gridOn, setGridOn] = useState8(false);
@@ -2220,6 +2258,12 @@ function CameraCaptureV3({
2220
2258
  useEffect7(() => {
2221
2259
  onReviewOpenChange?.(reviewOpen);
2222
2260
  }, [reviewOpen, onReviewOpenChange]);
2261
+ useEffect7(
2262
+ () => () => {
2263
+ if (editTarget?.revoke) URL.revokeObjectURL(editTarget.url);
2264
+ },
2265
+ [editTarget]
2266
+ );
2223
2267
  const clearCountdown = useCallback6(() => {
2224
2268
  if (countdownRef.current) clearInterval(countdownRef.current);
2225
2269
  countdownRef.current = null;
@@ -2438,8 +2482,16 @@ function CameraCaptureV3({
2438
2482
  invalidateMedia(item.key);
2439
2483
  } : void 0,
2440
2484
  onEdit: media.onReplacePhoto ? (item) => {
2441
- const url = getMediaUrl(item);
2442
- if (url) setEditTarget({ key: item.key, url });
2485
+ if (editPreparing) return;
2486
+ setEditPreparing(true);
2487
+ setEditPreparationError(null);
2488
+ void prepareMediaForEdit(item).then(
2489
+ (prepared) => setEditTarget({ key: item.key, ...prepared })
2490
+ ).catch(
2491
+ () => setEditPreparationError(
2492
+ "This photo could not be prepared for editing. Try again."
2493
+ )
2494
+ ).finally(() => setEditPreparing(false));
2443
2495
  } : void 0
2444
2496
  }
2445
2497
  ),
@@ -2460,6 +2512,14 @@ function CameraCaptureV3({
2460
2512
  }
2461
2513
  }
2462
2514
  ),
2515
+ editPreparationError && /* @__PURE__ */ jsx15(
2516
+ "p",
2517
+ {
2518
+ role: "alert",
2519
+ className: "fixed inset-x-4 bottom-24 z-[70] rounded-xl bg-black/85 px-4 py-3 text-center text-sm text-[#FF6961]",
2520
+ children: editPreparationError
2521
+ }
2522
+ ),
2463
2523
  slots.overlays
2464
2524
  ] });
2465
2525
  }