@ai-matrx/capture 0.1.2 → 0.2.0

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
@@ -38,8 +38,6 @@ interface CaptureCloudPort {
38
38
  recentsThumb: React.ReactNode;
39
39
  /** Opens the host's cloud media library (tiled gallery). */
40
40
  onOpenLibrary: () => void;
41
- /** Persists an edited image produced by the edit sheet. */
42
- onSaveEdited: (blob: Blob, suggestedName: string) => void;
43
41
  }
44
42
  /**
45
43
  * The engine port — everything the chrome needs from the host's camera
@@ -148,6 +146,51 @@ interface CaptureSheetProps {
148
146
  }
149
147
  declare function CaptureSheet({ open, onClose, variant, icon, title, body, actions, busyLabel, }: CaptureSheetProps): React__default.JSX.Element | null;
150
148
 
149
+ /**
150
+ * Package-owned media resolution cache — THE fix for "every page turn feels
151
+ * like a refetch".
152
+ *
153
+ * The host supplies, per media item, either a ready `src` (a local object
154
+ * URL for a fresh capture) or an async `resolve()` (a persisted file that
155
+ * needs an authenticated URL). Everything else — memoization, in-flight
156
+ * dedup, LRU eviction, revocation of URLs the cache itself created — is the
157
+ * package's job. This lives IN the package on the completeness rule: if the
158
+ * host had to rebuild this, most hosts wouldn't, and every viewer would lag.
159
+ *
160
+ * Ownership: URLs returned by `resolve()` are revoked on eviction ONLY when
161
+ * the resolver marks them owned (`{ url, revoke: true }`); a plain string is
162
+ * assumed host-owned and never revoked.
163
+ */
164
+ type ResolvedMedia = string | {
165
+ url: string;
166
+ revoke?: boolean;
167
+ };
168
+ interface CaptureMediaItem {
169
+ /** Stable identity for the item (drives caching + React keys). */
170
+ key: string;
171
+ kind: "photo" | "video" | "audio";
172
+ /** Ready-to-render URL (fresh capture). Host-owned, never revoked here. */
173
+ src?: string | null;
174
+ /** Async URL resolution for persisted items. Called at most once per key
175
+ * while cached; concurrent callers share the in-flight promise. */
176
+ resolve?: () => Promise<ResolvedMedia>;
177
+ /** Upload/processing state — the filmstrip renders it honestly. */
178
+ status?: "ready" | "uploading" | "error";
179
+ /** Accent ring on the filmstrip tile (e.g. a delineator frame). */
180
+ accent?: boolean;
181
+ }
182
+ /**
183
+ * Resolve an item's URL through the cache. Synchronous when already known;
184
+ * kicks off (or joins) the resolution otherwise and notifies subscribers.
185
+ */
186
+ declare function getMediaUrl(item: CaptureMediaItem): string | null;
187
+ /** Drop one item (e.g. after delete). Revokes only cache-owned URLs. */
188
+ declare function invalidateMedia(key: string): void;
189
+ /** React binding: the item's URL, updating when resolution lands. */
190
+ declare function useMediaUrl(item: CaptureMediaItem | null): string | null;
191
+ /** Warm the cache for a set of items (the viewer's neighbor preload). */
192
+ declare function primeMedia(items: (CaptureMediaItem | undefined)[]): void;
193
+
151
194
  /**
152
195
  * CameraCapture — the opinionated iPhone-style camera surface, assembled.
153
196
  *
@@ -170,6 +213,21 @@ declare function CaptureSheet({ open, onClose, variant, icon, title, body, actio
170
213
  * Package source (`@ai-matrx/capture`).
171
214
  */
172
215
 
216
+ /**
217
+ * The session's captured media, handed to the chrome so the WHOLE review
218
+ * loop — filmstrip → swipe viewer → edit → replace — runs inside the
219
+ * package with its tuned gestures, preload and caching. The host only
220
+ * implements the item CRUD.
221
+ */
222
+ interface CaptureMediaSession {
223
+ items: CaptureMediaItem[];
224
+ /** Remove one item (viewer trash button). */
225
+ onDelete?: (key: string) => void;
226
+ /** Replace semantics for the built-in editor: persist the edited JPEG in
227
+ * place of the source item. Edit means edit — after saving, the original
228
+ * must be gone. Omit to hide the edit affordance. */
229
+ onReplacePhoto?: (key: string, blob: Blob) => void;
230
+ }
173
231
  interface CameraCaptureProps {
174
232
  engine: CaptureCameraEngine;
175
233
  /** THE CLOUD LAW: the cloud port is REQUIRED — a camera with no cloud
@@ -177,8 +235,11 @@ interface CameraCaptureProps {
177
235
  cloud: CaptureCloudPort;
178
236
  mode: CaptureCameraMode;
179
237
  onModeChange: (mode: CaptureCameraMode) => void;
180
- /** The live preview element (host wires its runtime's `CameraPreview`). */
238
+ /** The live preview element (`<CameraFeed engine={engine}/>` for the
239
+ * default engine; hosts with their own runtime wire their own). */
181
240
  preview: React__default.ReactNode;
241
+ /** Session media — enables the package-owned filmstrip + viewer + editor. */
242
+ media?: CaptureMediaSession;
182
243
  /** Close affordance top-left; omitted = no close button. */
183
244
  onClose?: () => void;
184
245
  /** Body + actions for the camera-blocked iOS-style sheet. */
@@ -191,7 +252,41 @@ interface CameraCaptureProps {
191
252
  shutterDisabled?: boolean;
192
253
  slots?: CaptureCameraSlots;
193
254
  }
194
- declare function CameraCapture({ engine, cloud, mode, onModeChange, preview, onClose, blockedSheet, controlsHidden, shutterDisabled, slots, }: CameraCaptureProps): React__default.JSX.Element;
255
+ declare function CameraCapture({ engine, cloud, mode, onModeChange, preview, media, onClose, blockedSheet, controlsHidden, shutterDisabled, slots, }: CameraCaptureProps): React__default.JSX.Element;
256
+
257
+ /**
258
+ * CameraFeed — the package's live preview <video> for the default engine
259
+ * (drop-in hosts). Attaches the engine's stream imperatively (srcObject is
260
+ * not a React DOM prop), fills its container with object-cover, and exposes
261
+ * the element through the engine's videoRef so photo capture can read it.
262
+ * Inline styles on purpose: host stylesheets (e.g. mobile `video { height:
263
+ * auto }` resets) must never shrink the live view below the captured frame.
264
+ *
265
+ * Hosts with their own runtime render their own preview component instead —
266
+ * this one is part of the batteries-included path.
267
+ */
268
+
269
+ declare function CameraFeed({ engine, mirror, }: {
270
+ engine: CaptureCameraEngine;
271
+ /** Preview-only CSS mirror (front camera). Output is never mirrored. */
272
+ mirror?: boolean;
273
+ }): React__default.JSX.Element;
274
+
275
+ /**
276
+ * CaptureFilmstrip — the row of session-capture thumbnails floating over the
277
+ * feed. Package-owned so the tile states (uploading spinner, error ring,
278
+ * accent ring) and the tap-to-view wiring are tuned once, everywhere.
279
+ * Thumbnails resolve through the package media cache, so the strip never
280
+ * re-fetches what the viewer already resolved (and vice versa).
281
+ */
282
+
283
+ interface CaptureFilmstripProps {
284
+ items: CaptureMediaItem[];
285
+ onOpen: (item: CaptureMediaItem) => void;
286
+ /** Show at most this many trailing tiles (default 12). */
287
+ limit?: number;
288
+ }
289
+ declare function CaptureFilmstrip({ items, onOpen, limit, }: CaptureFilmstripProps): React__default.JSX.Element | null;
195
290
 
196
291
  /**
197
292
  * CountdownOverlay — the big centered timer digits (iPhone timer capture):
@@ -240,6 +335,41 @@ interface ImageEditSheetProps {
240
335
  }
241
336
  declare function ImageEditSheet({ open, src, onClose, onSave, }: ImageEditSheetProps): React__default.JSX.Element | null;
242
337
 
338
+ /**
339
+ * MediaViewer — the package's full-screen swipe pager (iOS Photos pattern),
340
+ * moved INTO the package after real-phone tuning so every host inherits the
341
+ * tuned gestures, neighbor preload and resolution caching for free.
342
+ *
343
+ * - Pointer-event gestures, zero animation deps: horizontal drag pages
344
+ * (40px travel OR a 0.25px/ms flick), vertical drag ≥110px dismisses,
345
+ * direction locked on first movement.
346
+ * - Neighbors stay MOUNTED and invisible (±2 photos, ±1 video) so a page
347
+ * turn lands on already-resolved, already-decoded pixels — the "revisit
348
+ * lag" fix. URLs come from the package media cache (`media-cache.ts`).
349
+ * - Optional per-item Delete and Edit (edit hands off to the host — the
350
+ * `CameraCapture` orchestration pairs it with `ImageEditSheet` and
351
+ * replace semantics).
352
+ * - Desktop: arrow keys page, Escape closes, chevrons on hover-capable
353
+ * screens.
354
+ */
355
+
356
+ interface MediaViewerProps {
357
+ items: CaptureMediaItem[];
358
+ /** Key of the item to open on. */
359
+ initialKey: string | null;
360
+ onClose: () => void;
361
+ onDelete?: (item: CaptureMediaItem) => void;
362
+ /** Offered on photo items with a renderable URL. */
363
+ onEdit?: (item: CaptureMediaItem) => void;
364
+ /** What deleting costs, stated BEFORE the delete (destructive-actions
365
+ * rule). Override per domain; deletion is never one silent tap. */
366
+ deleteConsequence?: string;
367
+ /** Suppress keyboard handling while another overlay (the editor) is on
368
+ * top — Escape must close the top-most surface, not this one. */
369
+ keysDisabled?: boolean;
370
+ }
371
+ declare function MediaViewer({ items, initialKey, onClose, onDelete, onEdit, deleteConsequence, keysDisabled, }: MediaViewerProps): React__default.JSX.Element | null;
372
+
243
373
  /**
244
374
  * ModeSelector — the CONNECTED capture-mode bar: one compact rounded track
245
375
  * holding VIDEO · PHOTO · UPLOAD (+ injected extras) with a spring-sliding
@@ -347,4 +477,18 @@ interface TrackControls {
347
477
  }
348
478
  declare function useTrackControls(stream: MediaStream | null): TrackControls;
349
479
 
350
- export { CameraCapture, type CameraCaptureProps, type CaptureAspect, type CaptureCameraEngine, type CaptureCameraMode, type CaptureCameraSlots, type CaptureCloudPort, type CaptureOptionTile, CaptureSheet, type CaptureSheetAction, type CaptureSheetProps, type CaptureTimerSetting, CountdownOverlay, GridOverlay, ImageEditSheet, type ImageEditSheetProps, ModeSelector, type ModeSelectorProps, OptionsGridPanel, type OptionsGridPanelProps, ShutterButton, type ShutterButtonProps, type TrackControls, ZoomRow, type ZoomRowProps, useTrackControls };
480
+ interface DefaultEngineOptions {
481
+ /** Receives every captured photo as a JPEG File. */
482
+ onPhoto: (file: File) => void;
483
+ /** Receives the finished recording. */
484
+ onVideo: (file: File, durationMs: number) => void;
485
+ /** Receives files chosen through the Upload lane. */
486
+ onFiles: (files: FileList) => void;
487
+ /** Record microphone audio with video (asks once, at record time). */
488
+ withAudio?: boolean;
489
+ facingMode?: "environment" | "user";
490
+ photoQuality?: number;
491
+ }
492
+ declare function useDefaultCaptureEngine(options: DefaultEngineOptions): CaptureCameraEngine;
493
+
494
+ export { CameraCapture, type CameraCaptureProps, CameraFeed, type CaptureAspect, type CaptureCameraEngine, type CaptureCameraMode, type CaptureCameraSlots, type CaptureCloudPort, CaptureFilmstrip, type CaptureFilmstripProps, type CaptureMediaItem, type CaptureMediaSession, type CaptureOptionTile, CaptureSheet, type CaptureSheetAction, type CaptureSheetProps, type CaptureTimerSetting, CountdownOverlay, type DefaultEngineOptions, GridOverlay, ImageEditSheet, type ImageEditSheetProps, MediaViewer, type MediaViewerProps, ModeSelector, type ModeSelectorProps, OptionsGridPanel, type OptionsGridPanelProps, type ResolvedMedia, ShutterButton, type ShutterButtonProps, type TrackControls, ZoomRow, type ZoomRowProps, getMediaUrl, invalidateMedia, primeMedia, useDefaultCaptureEngine, useMediaUrl, useTrackControls };
package/dist/react.d.ts CHANGED
@@ -38,8 +38,6 @@ interface CaptureCloudPort {
38
38
  recentsThumb: React.ReactNode;
39
39
  /** Opens the host's cloud media library (tiled gallery). */
40
40
  onOpenLibrary: () => void;
41
- /** Persists an edited image produced by the edit sheet. */
42
- onSaveEdited: (blob: Blob, suggestedName: string) => void;
43
41
  }
44
42
  /**
45
43
  * The engine port — everything the chrome needs from the host's camera
@@ -148,6 +146,51 @@ interface CaptureSheetProps {
148
146
  }
149
147
  declare function CaptureSheet({ open, onClose, variant, icon, title, body, actions, busyLabel, }: CaptureSheetProps): React__default.JSX.Element | null;
150
148
 
149
+ /**
150
+ * Package-owned media resolution cache — THE fix for "every page turn feels
151
+ * like a refetch".
152
+ *
153
+ * The host supplies, per media item, either a ready `src` (a local object
154
+ * URL for a fresh capture) or an async `resolve()` (a persisted file that
155
+ * needs an authenticated URL). Everything else — memoization, in-flight
156
+ * dedup, LRU eviction, revocation of URLs the cache itself created — is the
157
+ * package's job. This lives IN the package on the completeness rule: if the
158
+ * host had to rebuild this, most hosts wouldn't, and every viewer would lag.
159
+ *
160
+ * Ownership: URLs returned by `resolve()` are revoked on eviction ONLY when
161
+ * the resolver marks them owned (`{ url, revoke: true }`); a plain string is
162
+ * assumed host-owned and never revoked.
163
+ */
164
+ type ResolvedMedia = string | {
165
+ url: string;
166
+ revoke?: boolean;
167
+ };
168
+ interface CaptureMediaItem {
169
+ /** Stable identity for the item (drives caching + React keys). */
170
+ key: string;
171
+ kind: "photo" | "video" | "audio";
172
+ /** Ready-to-render URL (fresh capture). Host-owned, never revoked here. */
173
+ src?: string | null;
174
+ /** Async URL resolution for persisted items. Called at most once per key
175
+ * while cached; concurrent callers share the in-flight promise. */
176
+ resolve?: () => Promise<ResolvedMedia>;
177
+ /** Upload/processing state — the filmstrip renders it honestly. */
178
+ status?: "ready" | "uploading" | "error";
179
+ /** Accent ring on the filmstrip tile (e.g. a delineator frame). */
180
+ accent?: boolean;
181
+ }
182
+ /**
183
+ * Resolve an item's URL through the cache. Synchronous when already known;
184
+ * kicks off (or joins) the resolution otherwise and notifies subscribers.
185
+ */
186
+ declare function getMediaUrl(item: CaptureMediaItem): string | null;
187
+ /** Drop one item (e.g. after delete). Revokes only cache-owned URLs. */
188
+ declare function invalidateMedia(key: string): void;
189
+ /** React binding: the item's URL, updating when resolution lands. */
190
+ declare function useMediaUrl(item: CaptureMediaItem | null): string | null;
191
+ /** Warm the cache for a set of items (the viewer's neighbor preload). */
192
+ declare function primeMedia(items: (CaptureMediaItem | undefined)[]): void;
193
+
151
194
  /**
152
195
  * CameraCapture — the opinionated iPhone-style camera surface, assembled.
153
196
  *
@@ -170,6 +213,21 @@ declare function CaptureSheet({ open, onClose, variant, icon, title, body, actio
170
213
  * Package source (`@ai-matrx/capture`).
171
214
  */
172
215
 
216
+ /**
217
+ * The session's captured media, handed to the chrome so the WHOLE review
218
+ * loop — filmstrip → swipe viewer → edit → replace — runs inside the
219
+ * package with its tuned gestures, preload and caching. The host only
220
+ * implements the item CRUD.
221
+ */
222
+ interface CaptureMediaSession {
223
+ items: CaptureMediaItem[];
224
+ /** Remove one item (viewer trash button). */
225
+ onDelete?: (key: string) => void;
226
+ /** Replace semantics for the built-in editor: persist the edited JPEG in
227
+ * place of the source item. Edit means edit — after saving, the original
228
+ * must be gone. Omit to hide the edit affordance. */
229
+ onReplacePhoto?: (key: string, blob: Blob) => void;
230
+ }
173
231
  interface CameraCaptureProps {
174
232
  engine: CaptureCameraEngine;
175
233
  /** THE CLOUD LAW: the cloud port is REQUIRED — a camera with no cloud
@@ -177,8 +235,11 @@ interface CameraCaptureProps {
177
235
  cloud: CaptureCloudPort;
178
236
  mode: CaptureCameraMode;
179
237
  onModeChange: (mode: CaptureCameraMode) => void;
180
- /** The live preview element (host wires its runtime's `CameraPreview`). */
238
+ /** The live preview element (`<CameraFeed engine={engine}/>` for the
239
+ * default engine; hosts with their own runtime wire their own). */
181
240
  preview: React__default.ReactNode;
241
+ /** Session media — enables the package-owned filmstrip + viewer + editor. */
242
+ media?: CaptureMediaSession;
182
243
  /** Close affordance top-left; omitted = no close button. */
183
244
  onClose?: () => void;
184
245
  /** Body + actions for the camera-blocked iOS-style sheet. */
@@ -191,7 +252,41 @@ interface CameraCaptureProps {
191
252
  shutterDisabled?: boolean;
192
253
  slots?: CaptureCameraSlots;
193
254
  }
194
- declare function CameraCapture({ engine, cloud, mode, onModeChange, preview, onClose, blockedSheet, controlsHidden, shutterDisabled, slots, }: CameraCaptureProps): React__default.JSX.Element;
255
+ declare function CameraCapture({ engine, cloud, mode, onModeChange, preview, media, onClose, blockedSheet, controlsHidden, shutterDisabled, slots, }: CameraCaptureProps): React__default.JSX.Element;
256
+
257
+ /**
258
+ * CameraFeed — the package's live preview <video> for the default engine
259
+ * (drop-in hosts). Attaches the engine's stream imperatively (srcObject is
260
+ * not a React DOM prop), fills its container with object-cover, and exposes
261
+ * the element through the engine's videoRef so photo capture can read it.
262
+ * Inline styles on purpose: host stylesheets (e.g. mobile `video { height:
263
+ * auto }` resets) must never shrink the live view below the captured frame.
264
+ *
265
+ * Hosts with their own runtime render their own preview component instead —
266
+ * this one is part of the batteries-included path.
267
+ */
268
+
269
+ declare function CameraFeed({ engine, mirror, }: {
270
+ engine: CaptureCameraEngine;
271
+ /** Preview-only CSS mirror (front camera). Output is never mirrored. */
272
+ mirror?: boolean;
273
+ }): React__default.JSX.Element;
274
+
275
+ /**
276
+ * CaptureFilmstrip — the row of session-capture thumbnails floating over the
277
+ * feed. Package-owned so the tile states (uploading spinner, error ring,
278
+ * accent ring) and the tap-to-view wiring are tuned once, everywhere.
279
+ * Thumbnails resolve through the package media cache, so the strip never
280
+ * re-fetches what the viewer already resolved (and vice versa).
281
+ */
282
+
283
+ interface CaptureFilmstripProps {
284
+ items: CaptureMediaItem[];
285
+ onOpen: (item: CaptureMediaItem) => void;
286
+ /** Show at most this many trailing tiles (default 12). */
287
+ limit?: number;
288
+ }
289
+ declare function CaptureFilmstrip({ items, onOpen, limit, }: CaptureFilmstripProps): React__default.JSX.Element | null;
195
290
 
196
291
  /**
197
292
  * CountdownOverlay — the big centered timer digits (iPhone timer capture):
@@ -240,6 +335,41 @@ interface ImageEditSheetProps {
240
335
  }
241
336
  declare function ImageEditSheet({ open, src, onClose, onSave, }: ImageEditSheetProps): React__default.JSX.Element | null;
242
337
 
338
+ /**
339
+ * MediaViewer — the package's full-screen swipe pager (iOS Photos pattern),
340
+ * moved INTO the package after real-phone tuning so every host inherits the
341
+ * tuned gestures, neighbor preload and resolution caching for free.
342
+ *
343
+ * - Pointer-event gestures, zero animation deps: horizontal drag pages
344
+ * (40px travel OR a 0.25px/ms flick), vertical drag ≥110px dismisses,
345
+ * direction locked on first movement.
346
+ * - Neighbors stay MOUNTED and invisible (±2 photos, ±1 video) so a page
347
+ * turn lands on already-resolved, already-decoded pixels — the "revisit
348
+ * lag" fix. URLs come from the package media cache (`media-cache.ts`).
349
+ * - Optional per-item Delete and Edit (edit hands off to the host — the
350
+ * `CameraCapture` orchestration pairs it with `ImageEditSheet` and
351
+ * replace semantics).
352
+ * - Desktop: arrow keys page, Escape closes, chevrons on hover-capable
353
+ * screens.
354
+ */
355
+
356
+ interface MediaViewerProps {
357
+ items: CaptureMediaItem[];
358
+ /** Key of the item to open on. */
359
+ initialKey: string | null;
360
+ onClose: () => void;
361
+ onDelete?: (item: CaptureMediaItem) => void;
362
+ /** Offered on photo items with a renderable URL. */
363
+ onEdit?: (item: CaptureMediaItem) => void;
364
+ /** What deleting costs, stated BEFORE the delete (destructive-actions
365
+ * rule). Override per domain; deletion is never one silent tap. */
366
+ deleteConsequence?: string;
367
+ /** Suppress keyboard handling while another overlay (the editor) is on
368
+ * top — Escape must close the top-most surface, not this one. */
369
+ keysDisabled?: boolean;
370
+ }
371
+ declare function MediaViewer({ items, initialKey, onClose, onDelete, onEdit, deleteConsequence, keysDisabled, }: MediaViewerProps): React__default.JSX.Element | null;
372
+
243
373
  /**
244
374
  * ModeSelector — the CONNECTED capture-mode bar: one compact rounded track
245
375
  * holding VIDEO · PHOTO · UPLOAD (+ injected extras) with a spring-sliding
@@ -347,4 +477,18 @@ interface TrackControls {
347
477
  }
348
478
  declare function useTrackControls(stream: MediaStream | null): TrackControls;
349
479
 
350
- export { CameraCapture, type CameraCaptureProps, type CaptureAspect, type CaptureCameraEngine, type CaptureCameraMode, type CaptureCameraSlots, type CaptureCloudPort, type CaptureOptionTile, CaptureSheet, type CaptureSheetAction, type CaptureSheetProps, type CaptureTimerSetting, CountdownOverlay, GridOverlay, ImageEditSheet, type ImageEditSheetProps, ModeSelector, type ModeSelectorProps, OptionsGridPanel, type OptionsGridPanelProps, ShutterButton, type ShutterButtonProps, type TrackControls, ZoomRow, type ZoomRowProps, useTrackControls };
480
+ interface DefaultEngineOptions {
481
+ /** Receives every captured photo as a JPEG File. */
482
+ onPhoto: (file: File) => void;
483
+ /** Receives the finished recording. */
484
+ onVideo: (file: File, durationMs: number) => void;
485
+ /** Receives files chosen through the Upload lane. */
486
+ onFiles: (files: FileList) => void;
487
+ /** Record microphone audio with video (asks once, at record time). */
488
+ withAudio?: boolean;
489
+ facingMode?: "environment" | "user";
490
+ photoQuality?: number;
491
+ }
492
+ declare function useDefaultCaptureEngine(options: DefaultEngineOptions): CaptureCameraEngine;
493
+
494
+ export { CameraCapture, type CameraCaptureProps, CameraFeed, type CaptureAspect, type CaptureCameraEngine, type CaptureCameraMode, type CaptureCameraSlots, type CaptureCloudPort, CaptureFilmstrip, type CaptureFilmstripProps, type CaptureMediaItem, type CaptureMediaSession, type CaptureOptionTile, CaptureSheet, type CaptureSheetAction, type CaptureSheetProps, type CaptureTimerSetting, CountdownOverlay, type DefaultEngineOptions, GridOverlay, ImageEditSheet, type ImageEditSheetProps, MediaViewer, type MediaViewerProps, ModeSelector, type ModeSelectorProps, OptionsGridPanel, type OptionsGridPanelProps, type ResolvedMedia, ShutterButton, type ShutterButtonProps, type TrackControls, ZoomRow, type ZoomRowProps, getMediaUrl, invalidateMedia, primeMedia, useDefaultCaptureEngine, useMediaUrl, useTrackControls };