@ai-matrx/capture 0.4.2 → 0.4.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.
- package/CHANGELOG.md +4 -0
- package/dist/react.cjs +1 -1
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +1 -1
- package/dist/react.js.map +1 -1
- package/package.json +1 -1
package/dist/react.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/CameraCapture.tsx","../src/components/icons.tsx","../src/cn.ts","../src/safe-area.ts","../src/hooks/useTrackControls.ts","../src/components/ShutterButton.tsx","../src/components/ModeSelector.tsx","../src/components/ZoomRow.tsx","../src/components/OptionsGridPanel.tsx","../src/components/CaptureSheet.tsx","../src/components/GridOverlay.tsx","../src/components/CountdownOverlay.tsx","../src/media/media-cache.ts","../src/components/CaptureFilmstrip.tsx","../src/components/MediaViewer.tsx","../src/components/ImageEditSheet.tsx","../src/components/CameraCaptureV3.tsx","../src/components/CaptureRail.tsx","../src/components/HoldShutter.tsx","../src/components/CaptureExpandingField.tsx","../src/components/CameraFeed.tsx","../src/engine/useDefaultEngine.ts"],"sourcesContent":["\"use client\";\n\n/**\n * CameraCapture — the opinionated iPhone-style camera surface, assembled.\n *\n * Layout (matching the iOS Camera app):\n * - Full-bleed live feed with a semi-transparent near-black bar across the\n * top and bottom — controls read clearly while the feed shows through.\n * - Top bar: close (host-provided), center slot, torch, host extras, and the\n * grid button revealing the two-tap OptionsGridPanel.\n * - Over the feed's bottom edge: real zoom pills (only when the track\n * reports a zoom range).\n * - Bottom bar: injected rows → VIDEO·PHOTO·UPLOAD mode selector → recents\n * thumb · shutter · flip.\n * - Overlays: rule-of-thirds grid, timer countdown, recording chip, blocked\n * sheet (iOS system-sheet presentation).\n *\n * The chrome owns UI state only (options panel, grid, timer, countdown).\n * Capture behavior, streams and persistence come from the injected\n * `CaptureCameraEngine`; domain features attach through `CaptureCameraSlots`.\n *\n * Package source (`@ai-matrx/capture`).\n */\n\nimport React, { useCallback, useEffect, useRef, useState } from \"react\";\nimport {\n Grid3x3Icon,\n GripIcon,\n ProportionsIcon,\n RefreshCwIcon,\n SunMediumIcon,\n TimerIcon,\n XIcon,\n ZapIcon,\n ZapOffIcon,\n} from \"./icons\";\nimport { cn } from \"../cn\";\nimport { safeTop, safeBottom, safeMarginTop } from \"../safe-area\";\n\nimport type {\n CaptureAspect,\n CaptureCameraEngine,\n CaptureCameraMode,\n CaptureCameraSlots,\n CaptureCloudPort,\n CaptureOptionTile,\n CaptureTimerSetting,\n} from \"../types\";\nimport { useTrackControls } from \"../hooks/useTrackControls\";\nimport { ShutterButton } from \"./ShutterButton\";\nimport { ModeSelector } from \"./ModeSelector\";\nimport { ZoomRow } from \"./ZoomRow\";\nimport { OptionsGridPanel } from \"./OptionsGridPanel\";\nimport { CaptureSheet, type CaptureSheetAction } from \"./CaptureSheet\";\nimport { GridOverlay } from \"./GridOverlay\";\nimport { CountdownOverlay } from \"./CountdownOverlay\";\nimport { CaptureFilmstrip } from \"./CaptureFilmstrip\";\nimport { MediaViewer } from \"./MediaViewer\";\nimport { ImageEditSheet } from \"./ImageEditSheet\";\nimport {\n getMediaUrl,\n invalidateMedia,\n type CaptureMediaItem,\n} from \"../media/media-cache\";\n\n/**\n * The session's captured media, handed to the chrome so the WHOLE review\n * loop — filmstrip → swipe viewer → edit → replace — runs inside the\n * package with its tuned gestures, preload and caching. The host only\n * implements the item CRUD.\n */\nexport interface CaptureMediaSession {\n items: CaptureMediaItem[];\n /** Remove one item (viewer trash button). */\n onDelete?: (key: string) => void;\n /** Replace semantics for the built-in editor: persist the edited JPEG in\n * place of the source item. Edit means edit — after saving, the original\n * must be gone. Omit to hide the edit affordance. */\n onReplacePhoto?: (key: string, blob: Blob) => void;\n}\n\nexport interface CameraCaptureProps {\n engine: CaptureCameraEngine;\n /** THE CLOUD LAW: the cloud port is REQUIRED — a camera with no cloud\n * library/persistence is not a valid instance of this system. */\n cloud: CaptureCloudPort;\n mode: CaptureCameraMode;\n onModeChange: (mode: CaptureCameraMode) => void;\n /** The live preview element (`<CameraFeed engine={engine}/>` for the\n * default engine; hosts with their own runtime wire their own). */\n preview: React.ReactNode;\n /** Session media — enables the package-owned filmstrip + viewer + editor. */\n media?: CaptureMediaSession;\n /** Fires when the package review loop (viewer or editor) opens/closes over\n * the live feed — hosts pause things that watch the feed (QR scanning). */\n onReviewOpenChange?: (open: boolean) => void;\n /** Close affordance top-left; omitted = no close button. */\n onClose?: () => void;\n /** Body + actions for the camera-blocked iOS-style sheet. */\n blockedSheet?: { body: React.ReactNode; actions: CaptureSheetAction[] };\n /** Hide all chrome except honesty chips (host renders its own toggle). */\n controlsHidden?: boolean;\n shutterDisabled?: boolean;\n slots?: CaptureCameraSlots;\n}\n\nfunction formatElapsed(totalSeconds: number): string {\n const m = Math.floor(totalSeconds / 60);\n const s = String(totalSeconds % 60).padStart(2, \"0\");\n return `${m}:${s}`;\n}\n\nconst ASPECT_CYCLE: CaptureAspect[] = [\"full\", \"4:3\", \"1:1\", \"16:9\"];\n\nexport function CameraCapture({\n engine,\n cloud,\n mode,\n onModeChange,\n preview,\n media,\n onReviewOpenChange,\n onClose,\n blockedSheet,\n controlsHidden = false,\n shutterDisabled = false,\n slots = {},\n}: CameraCaptureProps) {\n const [optionsOpen, setOptionsOpen] = useState(false);\n // The package-owned review loop: which item the viewer is open on, and\n // which photo the editor is replacing.\n const [viewerKey, setViewerKey] = useState<string | null>(null);\n const [editTarget, setEditTarget] = useState<{\n key: string;\n url: string;\n } | null>(null);\n const [gridOn, setGridOn] = useState(false);\n const [timerSetting, setTimerSetting] = useState<CaptureTimerSetting>(0);\n const [aspect, setAspect] = useState<CaptureAspect>(\"full\");\n const [exposureOpen, setExposureOpen] = useState(false);\n const [countdown, setCountdown] = useState<number | null>(null);\n // The blocked sheet is dismissible — uploads and the system camera keep\n // working, so closing it reveals the chrome rather than leaving the page.\n const [blockedDismissed, setBlockedDismissed] = useState(false);\n const countdownRef = useRef<ReturnType<typeof setInterval> | null>(null);\n\n const controls = useTrackControls(engine.stream);\n\n const reviewOpen = viewerKey !== null || editTarget !== null;\n useEffect(() => {\n onReviewOpenChange?.(reviewOpen);\n }, [reviewOpen, onReviewOpenChange]);\n\n const clearCountdown = useCallback(() => {\n if (countdownRef.current) clearInterval(countdownRef.current);\n countdownRef.current = null;\n setCountdown(null);\n }, []);\n useEffect(() => clearCountdown, [clearCountdown]);\n // A photo countdown must not survive a mode switch — it would fire a\n // photo capture while in video mode (possibly mid-recording).\n useEffect(() => {\n if (mode !== \"photo\") clearCountdown();\n }, [mode, clearCountdown]);\n\n const onShutter = useCallback(() => {\n if (mode === \"video\") {\n if (engine.recording) engine.onStopRecording();\n else engine.onStartRecording();\n return;\n }\n if (countdown !== null) {\n // Tapping mid-countdown cancels — matching iOS.\n clearCountdown();\n return;\n }\n if (timerSetting === 0) {\n engine.onCapturePhoto({ aspect });\n return;\n }\n let remaining = timerSetting;\n setCountdown(remaining);\n countdownRef.current = setInterval(() => {\n remaining -= 1;\n if (remaining <= 0) {\n clearCountdown();\n engine.onCapturePhoto({ aspect });\n } else {\n setCountdown(remaining);\n }\n }, 1000);\n }, [mode, engine, countdown, timerSetting, aspect, clearCountdown]);\n\n const cycleTimer = useCallback(() => {\n setTimerSetting((t) => (t === 0 ? 3 : t === 3 ? 10 : 0));\n }, []);\n\n const coreTiles: CaptureOptionTile[] = [\n ...(controls.torchSupported\n ? [\n {\n id: \"flash\",\n label: \"Flash\",\n icon: controls.torchOn ? (\n <ZapIcon className=\"h-6 w-6\" fill=\"currentColor\" />\n ) : (\n <ZapOffIcon className=\"h-6 w-6\" />\n ),\n active: controls.torchOn,\n onPress: controls.toggleTorch,\n },\n ]\n : []),\n {\n id: \"timer\",\n label: \"Timer\",\n icon: <TimerIcon className=\"h-6 w-6\" />,\n active: timerSetting !== 0,\n valueLabel: timerSetting === 0 ? undefined : `${timerSetting}s`,\n onPress: cycleTimer,\n },\n {\n id: \"grid\",\n label: \"Grid\",\n icon: <Grid3x3Icon className=\"h-6 w-6\" />,\n active: gridOn,\n onPress: () => setGridOn((g) => !g),\n },\n // Aspect applies to PHOTO output (center-cropped from the full sensor).\n {\n id: \"aspect\",\n label: \"Aspect\",\n icon: <ProportionsIcon className=\"h-6 w-6\" />,\n active: aspect !== \"full\",\n valueLabel: aspect === \"full\" ? undefined : aspect,\n onPress: () =>\n setAspect(\n (a) =>\n ASPECT_CYCLE[\n (ASPECT_CYCLE.indexOf(a) + 1) % ASPECT_CYCLE.length\n ] ?? \"full\",\n ),\n },\n ...(controls.exposureSupported\n ? [\n {\n id: \"exposure\",\n label: \"Exposure\",\n icon: <SunMediumIcon className=\"h-6 w-6\" />,\n active: controls.exposure !== 0 || exposureOpen,\n valueLabel:\n controls.exposure === 0\n ? undefined\n : `${controls.exposure > 0 ? \"+\" : \"\"}${controls.exposure}`,\n onPress: () => setExposureOpen((o) => !o),\n },\n ]\n : []),\n ];\n const tiles = [...coreTiles, ...(slots.optionTiles ?? [])];\n\n const blocked = engine.blocked !== null;\n\n return (\n <div className=\"absolute inset-0 select-none overflow-hidden bg-black\">\n {/* Full-bleed feed */}\n <div className=\"absolute inset-0\">{preview}</div>\n <GridOverlay visible={gridOn && !blocked} />\n {/* Aspect framing hint — the photo output is center-cropped to the\n selected ratio; the dimmed bands approximate the discarded region\n of the VISIBLE frame (the capture itself crops the full sensor). */}\n {mode === \"photo\" && aspect !== \"full\" && !blocked && (\n <div\n aria-hidden\n className=\"pointer-events-none absolute inset-0 z-10 flex items-center justify-center\"\n >\n <div\n className=\"shadow-[0_0_0_9999px_rgba(0,0,0,0.45)]\"\n style={{\n aspectRatio:\n aspect === \"1:1\" ? \"1 / 1\" : aspect === \"4:3\" ? \"3 / 4\" : \"9 / 16\",\n width: aspect === \"16:9\" ? \"100%\" : undefined,\n height: aspect === \"16:9\" ? undefined : \"70%\",\n maxWidth: \"100%\",\n maxHeight: \"100%\",\n }}\n />\n </div>\n )}\n <CountdownOverlay seconds={countdown} />\n\n {/* Top bar — ONE compact row; every pixel here is stolen from the\n feed, and a phone browser already spends chrome above us. */}\n {!controlsHidden && (\n <div\n className=\"absolute inset-x-0 top-0 z-20 bg-black/65 backdrop-blur-[2px]\"\n style={safeTop}\n >\n <div className=\"flex h-11 items-center gap-0.5 px-1.5\">\n {onClose ? (\n <button\n type=\"button\"\n onClick={onClose}\n aria-label=\"Close camera\"\n className=\"flex h-10 w-10 shrink-0 touch-manipulation items-center justify-center rounded-full text-white transition-colors hover:bg-white/10\"\n >\n <XIcon className=\"h-5 w-5\" />\n </button>\n ) : (\n <span className=\"w-10 shrink-0\" />\n )}\n <div className=\"min-w-0 flex-1\">{slots.topBarCenter}</div>\n {controls.torchSupported && (\n <button\n type=\"button\"\n onClick={controls.toggleTorch}\n aria-label={\n controls.torchOn ? \"Turn flash off\" : \"Turn flash on\"\n }\n aria-pressed={controls.torchOn}\n className={cn(\n \"flex h-10 w-10 shrink-0 touch-manipulation items-center justify-center rounded-full transition-colors\",\n controls.torchOn\n ? \"text-[#FFCC00]\"\n : \"text-white hover:bg-white/10\",\n )}\n >\n <ZapIcon\n className=\"h-5 w-5\"\n fill={controls.torchOn ? \"currentColor\" : \"none\"}\n />\n </button>\n )}\n {slots.topBarTrailing}\n <button\n type=\"button\"\n onClick={() => setOptionsOpen((o) => !o)}\n aria-label=\"More camera options\"\n aria-expanded={optionsOpen}\n className={cn(\n \"flex h-10 w-10 shrink-0 touch-manipulation items-center justify-center rounded-full transition-colors\",\n optionsOpen ? \"bg-white/20 text-white\" : \"text-white hover:bg-white/10\",\n )}\n >\n <GripIcon className=\"h-5 w-5\" />\n </button>\n </div>\n </div>\n )}\n\n {/* Honesty chips — visible even with controls hidden. */}\n <div\n className=\"pointer-events-none absolute inset-x-0 top-[50px] z-20 flex flex-col items-center gap-1.5\"\n style={safeMarginTop}\n >\n {engine.recording && (\n <span className=\"flex items-center gap-2 rounded-full bg-black/60 px-3 py-1.5 text-sm font-medium text-white\">\n <span className=\"h-2.5 w-2.5 animate-pulse rounded-full bg-[#FF3B30]\" />\n {formatElapsed(engine.recordElapsedSeconds)}\n </span>\n )}\n {slots.statusChips}\n </div>\n\n {/* Bottom stack */}\n {!controlsHidden && (\n <div className=\"absolute inset-x-0 bottom-0 z-20\">\n {/* Zoom pills float on the FEED, just above the bottom bar. */}\n {!blocked && controls.zoomOptions.length >= 2 && (\n <div className=\"mb-2\">\n <ZoomRow\n options={controls.zoomOptions}\n value={controls.zoom}\n onSelect={controls.setZoom}\n />\n </div>\n )}\n {/* The package filmstrip + host content OVER the feed — zero bar\n height. Tapping a tile opens the package viewer. */}\n {media && media.items.length > 0 && (\n <div className=\"mb-1.5 px-2\">\n <CaptureFilmstrip\n items={media.items}\n onOpen={(item) => setViewerKey(item.key)}\n />\n </div>\n )}\n {slots.aboveBar && <div className=\"mb-1.5 px-2\">{slots.aboveBar}</div>}\n {/* Exposure slider — revealed by the EXPOSURE tile, floats above\n the bottom bar like the iOS exposure control. */}\n {exposureOpen && controls.exposureSupported && controls.exposureRange && (\n <div className=\"mx-auto mb-3 flex w-64 items-center gap-3 rounded-full bg-black/55 px-4 py-2\">\n <SunMediumIcon className=\"h-4 w-4 shrink-0 text-[#FFCC00]\" />\n <input\n type=\"range\"\n min={controls.exposureRange.min}\n max={controls.exposureRange.max}\n step={controls.exposureRange.step}\n value={controls.exposure}\n onChange={(e) => controls.setExposure(Number(e.target.value))}\n aria-label=\"Exposure compensation\"\n className=\"w-full accent-[#FFCC00]\"\n />\n <span className=\"w-8 shrink-0 text-right text-xs tabular-nums text-white\">\n {controls.exposure > 0 ? \"+\" : \"\"}\n {controls.exposure}\n </span>\n </div>\n )}\n <div\n className=\"bg-black/65 px-3 backdrop-blur-[2px]\"\n style={safeBottom}\n >\n {slots.aboveModeSelector}\n {/* Connected mode bar + the domain action share ONE row as flex\n siblings — absolute positioning collided with the labels on\n narrow phones, twice. Never reintroduce it. */}\n <div className=\"flex items-center justify-center gap-2 py-1.5\">\n <ModeSelector\n mode={mode}\n onModeChange={onModeChange}\n onUpload={engine.onUpload}\n modeDisabled={engine.recording}\n uploadDisabled={shutterDisabled && !blocked}\n extraModes={slots.extraModes}\n />\n {slots.modeRowTrailing && (\n <div className=\"shrink-0\">{slots.modeRowTrailing}</div>\n )}\n </div>\n <div className=\"flex items-center justify-between px-2 pb-1.5 pt-0.5\">\n <div className=\"flex w-14 justify-start\">\n <button\n type=\"button\"\n onClick={cloud.onOpenLibrary}\n aria-label=\"Open your media library\"\n className=\"h-11 w-11 touch-manipulation overflow-hidden rounded-xl bg-white/10 ring-1 ring-white/25 transition-transform active:scale-95\"\n >\n {cloud.recentsThumb ?? (\n <span className=\"block h-full w-full bg-white/5\" />\n )}\n </button>\n </div>\n <ShutterButton\n mode={mode}\n recording={engine.recording}\n disabled={shutterDisabled || blocked}\n onPress={onShutter}\n />\n <div className=\"flex w-14 justify-end\">\n {engine.onFlipCamera ? (\n <button\n type=\"button\"\n onClick={engine.onFlipCamera}\n aria-label=\"Switch camera\"\n className=\"flex h-11 w-11 touch-manipulation items-center justify-center rounded-full bg-white/15 text-white transition-transform active:rotate-180 active:scale-95 duration-300\"\n >\n <RefreshCwIcon className=\"h-5 w-5\" />\n </button>\n ) : (\n <span className=\"h-11 w-11\" />\n )}\n </div>\n </div>\n </div>\n </div>\n )}\n\n <OptionsGridPanel\n open={optionsOpen && !controlsHidden}\n onClose={() => setOptionsOpen(false)}\n tiles={tiles}\n />\n\n {blocked && blockedSheet && !blockedDismissed && (\n <CaptureSheet\n open\n onClose={() => setBlockedDismissed(true)}\n body={blockedSheet.body}\n title=\"Camera unavailable\"\n actions={blockedSheet.actions}\n />\n )}\n\n {/* Package review loop: viewer over the camera, editor over the\n viewer. Replace semantics — saving an edit persists the new frame,\n removes the source item and drops its cached URL, then closes back\n to the camera. */}\n {media && viewerKey !== null && (\n <MediaViewer\n items={media.items}\n initialKey={viewerKey}\n keysDisabled={editTarget !== null}\n onClose={() => setViewerKey(null)}\n onDelete={\n media.onDelete\n ? (item) => {\n media.onDelete?.(item.key);\n invalidateMedia(item.key);\n }\n : undefined\n }\n onEdit={\n media.onReplacePhoto\n ? (item) => {\n const url = getMediaUrl(item);\n if (url) setEditTarget({ key: item.key, url });\n }\n : undefined\n }\n />\n )}\n {media?.onReplacePhoto && (\n <ImageEditSheet\n open={editTarget !== null}\n src={editTarget?.url ?? null}\n onClose={() => setEditTarget(null)}\n onSave={(blob) => {\n const target = editTarget;\n setEditTarget(null);\n setViewerKey(null);\n if (target) {\n media.onReplacePhoto?.(target.key, blob);\n invalidateMedia(target.key);\n }\n }}\n />\n )}\n\n {slots.overlays}\n </div>\n );\n}\n","/**\n * src/components/icons.tsx — the package's OWN inlined SVG icons.\n *\n * Per campaign ruling C19 (2026-08-29): no icon-library dependency, ever.\n * Every glyph below is copied from lucide-react v0.545.0 (ISC license)\n * exactly — the version this package shipped with before the swap, so\n * pixels don't change — following the @ai-matrx/media precedent\n * (`media/src/react/icons.tsx`). Add a new icon by copying the lucide\n * `__iconNode` data from the version noted here — never by adding a\n * lucide dep back.\n *\n * Internal module: icons are exported for the package's own components\n * only; they are not part of the public entry surface.\n */\n\nimport type { SVGProps } from \"react\";\n\nexport type CaptureIconProps = SVGProps<SVGSVGElement>;\n\nfunction svgProps(props: CaptureIconProps): CaptureIconProps {\n return {\n xmlns: \"http://www.w3.org/2000/svg\",\n viewBox: \"0 0 24 24\",\n width: 24,\n height: 24,\n fill: \"none\",\n stroke: \"currentColor\",\n strokeWidth: 2,\n strokeLinecap: \"round\",\n strokeLinejoin: \"round\",\n \"aria-hidden\": true,\n ...props,\n };\n}\n\n// lucide: check\nexport function CheckIcon(props: CaptureIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M20 6 9 17l-5-5\" />\n </svg>\n );\n}\n\n// lucide: chevron-left\nexport function ChevronLeftIcon(props: CaptureIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"m15 18-6-6 6-6\" />\n </svg>\n );\n}\n\n// lucide: chevron-right\nexport function ChevronRightIcon(props: CaptureIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n );\n}\n\n// lucide: flip-horizontal-2\nexport function FlipHorizontal2Icon(props: CaptureIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"m3 7 5 5-5 5V7\" />\n <path d=\"m21 7-5 5 5 5V7\" />\n <path d=\"M12 20v2\" />\n <path d=\"M12 14v2\" />\n <path d=\"M12 8v2\" />\n <path d=\"M12 2v2\" />\n </svg>\n );\n}\n\n// lucide: grid-3x3\nexport function Grid3x3Icon(props: CaptureIconProps) {\n return (\n <svg {...svgProps(props)}>\n <rect width=\"18\" height=\"18\" x=\"3\" y=\"3\" rx=\"2\" />\n <path d=\"M3 9h18\" />\n <path d=\"M3 15h18\" />\n <path d=\"M9 3v18\" />\n <path d=\"M15 3v18\" />\n </svg>\n );\n}\n\n// lucide: grip\nexport function GripIcon(props: CaptureIconProps) {\n return (\n <svg {...svgProps(props)}>\n <circle cx=\"12\" cy=\"5\" r=\"1\" />\n <circle cx=\"19\" cy=\"5\" r=\"1\" />\n <circle cx=\"5\" cy=\"5\" r=\"1\" />\n <circle cx=\"12\" cy=\"12\" r=\"1\" />\n <circle cx=\"19\" cy=\"12\" r=\"1\" />\n <circle cx=\"5\" cy=\"12\" r=\"1\" />\n <circle cx=\"12\" cy=\"19\" r=\"1\" />\n <circle cx=\"19\" cy=\"19\" r=\"1\" />\n <circle cx=\"5\" cy=\"19\" r=\"1\" />\n </svg>\n );\n}\n\n// lucide: images\nexport function ImagesIcon(props: CaptureIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"m22 11-1.296-1.296a2.4 2.4 0 0 0-3.408 0L11 16\" />\n <path d=\"M4 8a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2\" />\n <circle cx=\"13\" cy=\"7\" r=\"1\" fill=\"currentColor\" />\n <rect x=\"8\" y=\"2\" width=\"14\" height=\"14\" rx=\"2\" />\n </svg>\n );\n}\n\n// lucide: loader-circle (a.k.a. Loader2)\nexport function Loader2Icon(props: CaptureIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M21 12a9 9 0 1 1-6.219-8.56\" />\n </svg>\n );\n}\n\n// lucide: lock\nexport function LockIcon(props: CaptureIconProps) {\n return (\n <svg {...svgProps(props)}>\n <rect width=\"18\" height=\"11\" x=\"3\" y=\"11\" rx=\"2\" ry=\"2\" />\n <path d=\"M7 11V7a5 5 0 0 1 10 0v4\" />\n </svg>\n );\n}\n\n// lucide: pencil\nexport function PencilIcon(props: CaptureIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z\" />\n <path d=\"m15 5 4 4\" />\n </svg>\n );\n}\n\n// lucide: play\nexport function PlayIcon(props: CaptureIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z\" />\n </svg>\n );\n}\n\n// lucide: proportions\nexport function ProportionsIcon(props: CaptureIconProps) {\n return (\n <svg {...svgProps(props)}>\n <rect width=\"20\" height=\"16\" x=\"2\" y=\"4\" rx=\"2\" />\n <path d=\"M12 9v11\" />\n <path d=\"M2 9h13a2 2 0 0 1 2 2v9\" />\n </svg>\n );\n}\n\n// lucide: refresh-cw\nexport function RefreshCwIcon(props: CaptureIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8\" />\n <path d=\"M21 3v5h-5\" />\n <path d=\"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16\" />\n <path d=\"M8 16H3v5\" />\n </svg>\n );\n}\n\n// lucide: rotate-ccw\nexport function RotateCcwIcon(props: CaptureIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8\" />\n <path d=\"M3 3v5h5\" />\n </svg>\n );\n}\n\n// lucide: sun-medium\nexport function SunMediumIcon(props: CaptureIconProps) {\n return (\n <svg {...svgProps(props)}>\n <circle cx=\"12\" cy=\"12\" r=\"4\" />\n <path d=\"M12 3v1\" />\n <path d=\"M12 20v1\" />\n <path d=\"M3 12h1\" />\n <path d=\"M20 12h1\" />\n <path d=\"m18.364 5.636-.707.707\" />\n <path d=\"m6.343 17.657-.707.707\" />\n <path d=\"m5.636 5.636.707.707\" />\n <path d=\"m17.657 17.657.707.707\" />\n </svg>\n );\n}\n\n// lucide: timer\nexport function TimerIcon(props: CaptureIconProps) {\n return (\n <svg {...svgProps(props)}>\n <line x1=\"10\" x2=\"14\" y1=\"2\" y2=\"2\" />\n <line x1=\"12\" x2=\"15\" y1=\"14\" y2=\"11\" />\n <circle cx=\"12\" cy=\"14\" r=\"8\" />\n </svg>\n );\n}\n\n// lucide: trash-2\nexport function Trash2Icon(props: CaptureIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M10 11v6\" />\n <path d=\"M14 11v6\" />\n <path d=\"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6\" />\n <path d=\"M3 6h18\" />\n <path d=\"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\" />\n </svg>\n );\n}\n\n// lucide: x\nexport function XIcon(props: CaptureIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </svg>\n );\n}\n\n// lucide: zap\nexport function ZapIcon(props: CaptureIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z\" />\n </svg>\n );\n}\n\n// lucide: zap-off\nexport function ZapOffIcon(props: CaptureIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M10.513 4.856 13.12 2.17a.5.5 0 0 1 .86.46l-1.377 4.317\" />\n <path d=\"M15.656 10H20a1 1 0 0 1 .78 1.63l-1.72 1.773\" />\n <path d=\"M16.273 16.273 10.88 21.83a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14H4a1 1 0 0 1-.78-1.63l4.507-4.643\" />\n <path d=\"m2 2 20 20\" />\n </svg>\n );\n}\n","/**\n * The package-local `cn` — the documented substitution point for the app's\n * `@/lib/utils` cn during extraction (same pattern as `@ai-matrx/media`).\n */\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(\n ...inputs: Array<string | false | null | undefined>\n): string {\n return twMerge(inputs.filter(Boolean).join(\" \"));\n}\n","/**\n * Safe-area insets as INLINE STYLES — deliberately not utility classes.\n *\n * v0.1.x used the host app's `pt-safe` / `pb-safe` / `mb-safe` Tailwind\n * utilities, which exist only in AI Matrx's globals.css: in any other host\n * (the Vite drop-in test) they silently resolved to nothing and the chrome\n * collided with the notch and home indicator. Inline `env()` styles work in\n * every host with zero setup — the package-completeness rule: if it breaks\n * when the host forgets something, the package must not let the host forget.\n */\n\nimport type { CSSProperties } from \"react\";\n\nexport const safeTop: CSSProperties = {\n paddingTop: \"env(safe-area-inset-top, 0px)\",\n};\n\nexport const safeBottom: CSSProperties = {\n paddingBottom: \"env(safe-area-inset-bottom, 0px)\",\n};\n\nexport const safeMarginTop: CSSProperties = {\n marginTop: \"env(safe-area-inset-top, 0px)\",\n};\n\nexport const safeMarginBottom: CSSProperties = {\n marginBottom: \"env(safe-area-inset-bottom, 0px)\",\n};\n","\"use client\";\n\n/**\n * useTrackControls — HONEST torch + zoom over a live video track's real\n * capabilities (`MediaTrackCapabilities`). If the hardware doesn't report\n * torch or a zoom range, the corresponding control simply doesn't exist —\n * we never render a fake toggle.\n *\n * Zoom pill options are derived from the reported [min, max] range using the\n * familiar phone ladder (.5 / 1 / 2 / 4 / 8) clipped to what the device can\n * actually do. Applied via `track.applyConstraints({ advanced: [...] })`.\n *\n * Package source (`@ai-matrx/capture`) — browser media APIs only, no app\n * imports.\n */\n\nimport { useCallback, useEffect, useMemo, useState } from \"react\";\n\n// torch/zoom are spec'd in mediacapture-image but absent from lib.dom.\ninterface ExtendedCapabilities extends MediaTrackCapabilities {\n torch?: boolean;\n zoom?: { min: number; max: number; step?: number };\n exposureCompensation?: { min: number; max: number; step?: number };\n}\ninterface ExtendedSettings extends MediaTrackSettings {\n torch?: boolean;\n zoom?: number;\n exposureCompensation?: number;\n}\n\nconst ZOOM_LADDER = [0.5, 1, 2, 4, 8];\n\nexport interface TrackControls {\n torchSupported: boolean;\n torchOn: boolean;\n toggleTorch: () => void;\n /** ≥2 entries when the track reports a usable zoom range, else []. */\n zoomOptions: number[];\n zoom: number;\n setZoom: (factor: number) => void;\n /** Exposure compensation — only when the hardware reports a range. */\n exposureSupported: boolean;\n exposure: number;\n exposureRange: { min: number; max: number; step: number } | null;\n setExposure: (value: number) => void;\n}\n\nexport function useTrackControls(stream: MediaStream | null): TrackControls {\n const [torchOn, setTorchOn] = useState(false);\n const [zoom, setZoomState] = useState(1);\n const [exposure, setExposureState] = useState(0);\n // Capabilities can be empty until the track is fully live; re-read once on\n // stream change and again on a short delayed tick (iOS reports late).\n const [caps, setCaps] = useState<ExtendedCapabilities | null>(null);\n\n const track = stream?.getVideoTracks()[0] ?? null;\n\n useEffect(() => {\n setTorchOn(false);\n if (!track || typeof track.getCapabilities !== \"function\") {\n setCaps(null);\n return;\n }\n // iOS can report an EMPTY capability set for seconds after the track\n // goes live — a single delayed re-read missed it and the zoom pills /\n // torch never appeared. Poll on a widening ladder and stop as soon as\n // a usable capability shows up (or the ladder runs out).\n const timers: number[] = [];\n const read = (): boolean => {\n try {\n const next = track.getCapabilities() as ExtendedCapabilities;\n setCaps(next);\n const settings = track.getSettings() as ExtendedSettings;\n if (typeof settings.zoom === \"number\") setZoomState(settings.zoom);\n if (typeof settings.exposureCompensation === \"number\")\n setExposureState(settings.exposureCompensation);\n return (\n next.torch === true ||\n next.zoom !== undefined ||\n next.exposureCompensation !== undefined\n );\n } catch {\n setCaps(null);\n return false;\n }\n };\n if (!read()) {\n for (const delay of [500, 1200, 2500, 5000]) {\n timers.push(\n window.setTimeout(() => {\n if (read()) timers.forEach((t) => window.clearTimeout(t));\n }, delay),\n );\n }\n }\n return () => timers.forEach((t) => window.clearTimeout(t));\n }, [track]);\n\n const torchSupported = caps?.torch === true;\n\n const toggleTorch = useCallback(() => {\n if (!track || !torchSupported) return;\n const next = !torchOn;\n track\n .applyConstraints({ advanced: [{ torch: next } as MediaTrackConstraintSet] })\n .then(() => setTorchOn(next))\n .catch((err: unknown) => {\n console.error(\"[capture-camera] torch toggle failed\", err);\n });\n }, [track, torchSupported, torchOn]);\n\n const zoomOptions = useMemo(() => {\n const range = caps?.zoom;\n if (!range || !(range.max > range.min)) return [];\n const options = ZOOM_LADDER.filter(\n (f) => f >= range.min && f <= range.max,\n );\n if (!options.includes(1) && 1 >= range.min && 1 <= range.max) {\n options.push(1);\n options.sort((a, b) => a - b);\n }\n return options.length >= 2 ? options : [];\n }, [caps]);\n\n const setZoom = useCallback(\n (factor: number) => {\n if (!track || !caps?.zoom) return;\n const clamped = Math.min(caps.zoom.max, Math.max(caps.zoom.min, factor));\n track\n .applyConstraints({\n advanced: [{ zoom: clamped } as MediaTrackConstraintSet],\n })\n .then(() => setZoomState(clamped))\n .catch((err: unknown) => {\n console.error(\"[capture-camera] zoom failed\", err);\n });\n },\n [track, caps],\n );\n\n const exposureCaps = caps?.exposureCompensation;\n const exposureRange =\n exposureCaps && exposureCaps.max > exposureCaps.min\n ? {\n min: exposureCaps.min,\n max: exposureCaps.max,\n step: exposureCaps.step && exposureCaps.step > 0 ? exposureCaps.step : 0.5,\n }\n : null;\n\n const setExposure = useCallback(\n (value: number) => {\n if (!track || !exposureRange) return;\n const clamped = Math.min(\n exposureRange.max,\n Math.max(exposureRange.min, value),\n );\n track\n .applyConstraints({\n advanced: [\n { exposureCompensation: clamped } as MediaTrackConstraintSet,\n ],\n })\n .then(() => setExposureState(clamped))\n .catch((err: unknown) => {\n console.error(\"[capture-camera] exposure failed\", err);\n });\n },\n [track, exposureRange],\n );\n\n return {\n torchSupported,\n torchOn,\n toggleTorch,\n zoomOptions,\n zoom,\n setZoom,\n exposureSupported: exposureRange !== null,\n exposure,\n exposureRange,\n setExposure,\n };\n}\n","\"use client\";\n\n/**\n * ShutterButton — the iPhone shutter: a thin white ring with a filled inner\n * circle. Photo = white fill; video idle = red circle; video recording = the\n * inner shape morphs to a small red rounded square (the iOS stop affordance).\n * Press feedback is a scale-down of the INNER fill only, like iOS.\n *\n * Package source (`@ai-matrx/capture`) — presentational only.\n */\n\nimport React from \"react\";\nimport { cn } from \"../cn\";\nimport type { CaptureCameraMode } from \"../types\";\n\nexport interface ShutterButtonProps {\n mode: CaptureCameraMode;\n recording: boolean;\n disabled?: boolean;\n onPress: () => void;\n}\n\nexport function ShutterButton({\n mode,\n recording,\n disabled = false,\n onPress,\n}: ShutterButtonProps) {\n return (\n <button\n type=\"button\"\n onClick={onPress}\n disabled={disabled}\n aria-label={\n mode === \"photo\"\n ? \"Take photo\"\n : recording\n ? \"Stop recording\"\n : \"Start recording\"\n }\n className={cn(\n \"group flex h-[74px] w-[74px] shrink-0 items-center justify-center rounded-full\",\n \"border-[3.5px] border-white transition-opacity\",\n disabled && \"opacity-30\",\n )}\n >\n <span\n className={cn(\n \"block transition-all duration-200 ease-out group-active:scale-90\",\n mode === \"photo\"\n ? \"h-[62px] w-[62px] rounded-full bg-white\"\n : recording\n ? \"h-8 w-8 rounded-md bg-[#FF3B30]\"\n : \"h-[62px] w-[62px] rounded-full bg-[#FF3B30]\",\n )}\n />\n </button>\n );\n}\n","\"use client\";\n\n/**\n * ModeSelector — the CONNECTED capture-mode bar: one compact rounded track\n * holding VIDEO · PHOTO · UPLOAD (+ injected extras) with a spring-sliding\n * thumb under the active mode (the proven CaptureModeBar interaction, in\n * iPhone dress: uppercase letter-spaced labels, active in iOS camera\n * yellow). Deliberately narrow — the row keeps usable space on BOTH sides\n * for host affordances; screen height is the scarcest resource on a phone\n * browser, so the bar is one short row, never a spread of pills.\n *\n * VIDEO and PHOTO are persistent modes; UPLOAD and extras are immediate\n * actions and never take the thumb.\n *\n * Package source (`@ai-matrx/capture`) — presentational only.\n */\n\nimport React from \"react\";\nimport { cn } from \"../cn\";\n\nimport type { CaptureCameraMode } from \"../types\";\n\n/** Spring curve with a small overshoot (CSS linear() approximation);\n * class-level overshooting cubic-bezier is the fallback. */\nconst SPRING_EASING =\n \"linear(0, 0.0047 0.71%, 0.0189 1.44%, 0.0755 2.93%, 0.1692 4.49%, \" +\n \"0.3921 7.55%, 0.8121 12.94%, 0.9804 15.49%, 1.0946 18.14%, 1.1423 20.16%, \" +\n \"1.1568 21.62%, 1.1541 23.03%, 1.1113 26.4%, 1.0322 31.83%, 0.9902 36.25%, \" +\n \"0.9769 40.24%, 0.9844 45.87%, 1.0028 55.35%, 1.0075 63.42%, 1.0006 85.48%, 1)\";\n\nconst LABEL_BASE =\n \"relative z-10 flex h-8 min-w-0 touch-manipulation items-center justify-center rounded-full px-3 \" +\n \"text-[11px] font-semibold uppercase tracking-[0.12em] transition-colors duration-200 \" +\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/70 disabled:opacity-40\";\n\nexport interface ModeSelectorProps {\n mode: CaptureCameraMode;\n onModeChange: (mode: CaptureCameraMode) => void;\n onUpload: () => void;\n /** Locks mode switching (while recording). */\n modeDisabled?: boolean;\n uploadDisabled?: boolean;\n /** Host-injected extra entries after UPLOAD (e.g. SCAN) — immediate\n * actions, never the active mode. */\n extraModes?: { id: string; label: string; onSelect: () => void }[] | undefined;\n}\n\nexport function ModeSelector({\n mode,\n onModeChange,\n onUpload,\n modeDisabled = false,\n uploadDisabled = false,\n extraModes = [],\n}: ModeSelectorProps) {\n const segments = 3 + extraModes.length;\n const activeIndex = mode === \"video\" ? 0 : 1;\n\n return (\n <div\n role=\"tablist\"\n aria-label=\"Capture mode\"\n className=\"relative inline-grid rounded-full bg-white/10 p-1\"\n style={{ gridTemplateColumns: `repeat(${segments}, minmax(0, 1fr))` }}\n >\n {/* Sliding thumb — transform-only, springs with overshoot, instant\n under prefers-reduced-motion. */}\n <div\n aria-hidden\n className=\"pointer-events-none absolute bottom-1 top-1 left-1 rounded-full bg-white/20 transition-transform duration-500 ease-[cubic-bezier(0.34,1.56,0.64,1)] will-change-transform motion-reduce:transition-none\"\n style={{\n width: `calc((100% - 0.5rem) / ${segments})`,\n transform: `translateX(${activeIndex * 100}%)`,\n transitionTimingFunction: SPRING_EASING,\n }}\n />\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={mode === \"video\"}\n disabled={modeDisabled}\n onClick={() => onModeChange(\"video\")}\n className={cn(\n LABEL_BASE,\n mode === \"video\" ? \"text-[#FFCC00]\" : \"text-white\",\n )}\n >\n Video\n </button>\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={mode === \"photo\"}\n disabled={modeDisabled}\n onClick={() => onModeChange(\"photo\")}\n className={cn(\n LABEL_BASE,\n mode === \"photo\" ? \"text-[#FFCC00]\" : \"text-white\",\n )}\n >\n Photo\n </button>\n <button\n type=\"button\"\n aria-label=\"Upload photos or videos from this device\"\n disabled={modeDisabled || uploadDisabled}\n onClick={onUpload}\n className={cn(LABEL_BASE, \"text-white active:text-[#FFCC00]\")}\n >\n Upload\n </button>\n {extraModes.map((extra) => (\n <button\n key={extra.id}\n type=\"button\"\n aria-label={extra.label}\n disabled={modeDisabled}\n onClick={extra.onSelect}\n className={cn(LABEL_BASE, \"text-white active:text-[#FFCC00]\")}\n >\n {extra.label}\n </button>\n ))}\n </div>\n );\n}\n","\"use client\";\n\n/**\n * ZoomRow — the iPhone zoom pills floating over the bottom of the feed:\n * small translucent circles, the active factor in a slightly larger circle\n * with yellow text and an \"×\" suffix. Rendered ONLY when the host reports a\n * real zoom range (track capabilities) — we never fake unsupported zoom.\n *\n * Package source (`@ai-matrx/capture`) — presentational only.\n */\n\nimport React from \"react\";\nimport { cn } from \"../cn\";\n\nexport interface ZoomRowProps {\n /** Available zoom factors in ascending order (e.g. [1, 2, 4]). */\n options: number[];\n /** The currently applied factor (nearest option is highlighted). */\n value: number;\n onSelect: (factor: number) => void;\n}\n\nfunction formatFactor(factor: number): string {\n return factor < 1\n ? `.${String(Math.round(factor * 10))}`\n : String(Math.round(factor * 10) / 10);\n}\n\nexport function ZoomRow({ options, value, onSelect }: ZoomRowProps) {\n if (options.length < 2) return null;\n const active = options.reduce((best, opt) =>\n Math.abs(opt - value) < Math.abs(best - value) ? opt : best,\n );\n return (\n <div className=\"flex items-center justify-center gap-3\">\n {options.map((opt) => {\n const isActive = opt === active;\n return (\n <button\n key={opt}\n type=\"button\"\n onClick={() => onSelect(opt)}\n aria-label={`Zoom ${formatFactor(opt)}x`}\n aria-pressed={isActive}\n className={cn(\n \"flex touch-manipulation items-center justify-center rounded-full font-semibold transition-all duration-200\",\n isActive\n ? \"h-10 w-10 bg-black/45 text-[13px] text-[#FFCC00]\"\n : \"h-8 w-8 bg-black/35 text-[12px] text-white\",\n )}\n >\n {formatFactor(opt)}\n {isActive && <span className=\"text-[10px]\">×</span>}\n </button>\n );\n })}\n </div>\n );\n}\n","\"use client\";\n\n/**\n * OptionsGridPanel — the iPhone two-tap options surface: tapping the grid\n * button dims the viewfinder and reveals a rounded dark panel pinned to the\n * bottom holding a grid of circular toggle buttons with uppercase labels\n * (one tap to reveal, one tap to act). This is NOT a drawer — no drag\n * handle, no route; tapping the scrim or the grid button again closes it.\n *\n * Tiles are injected (`CaptureOptionTile[]`) so hosts and domain extensions\n * add their own toggles without touching the panel.\n *\n * Package source (`@ai-matrx/capture`) — presentational only.\n */\n\nimport React from \"react\";\nimport { cn } from \"../cn\";\nimport type { CaptureOptionTile } from \"../types\";\n\nexport interface OptionsGridPanelProps {\n open: boolean;\n onClose: () => void;\n tiles: CaptureOptionTile[];\n}\n\nexport function OptionsGridPanel({\n open,\n onClose,\n tiles,\n}: OptionsGridPanelProps) {\n if (!open) return null;\n return (\n <div className=\"absolute inset-0 z-40\">\n {/* Dimming scrim — the viewfinder darkens like iOS; tap to dismiss. */}\n <button\n type=\"button\"\n aria-label=\"Close camera options\"\n onClick={onClose}\n className=\"absolute inset-0 bg-black/70\"\n />\n <div\n className=\"absolute inset-x-3 bottom-3 rounded-[2.5rem] bg-[#3a3a3c]/95 px-6 py-8 shadow-2xl\"\n style={{ marginBottom: \"env(safe-area-inset-bottom, 0px)\" }}\n >\n <div className=\"grid grid-cols-3 gap-x-4 gap-y-7\">\n {tiles.map((tile) => (\n <div key={tile.id} className=\"flex flex-col items-center gap-2.5\">\n <button\n type=\"button\"\n onClick={tile.onPress}\n disabled={tile.disabled}\n aria-label={tile.label}\n aria-pressed={tile.active === true}\n className={cn(\n \"flex h-16 w-16 touch-manipulation items-center justify-center rounded-full bg-[#2c2c2e] transition-colors\",\n tile.active ? \"text-[#FFCC00]\" : \"text-white\",\n tile.disabled && \"opacity-40\",\n )}\n >\n {tile.icon}\n </button>\n <span className=\"text-[13px] font-semibold uppercase tracking-[0.14em] text-white\">\n {tile.valueLabel ? `${tile.label} ${tile.valueLabel}` : tile.label}\n </span>\n </div>\n ))}\n </div>\n </div>\n </div>\n );\n}\n","\"use client\";\n\n/**\n * CaptureSheet — the iOS-style system sheet used over the camera: a light,\n * heavily-rounded card sliding over the lower portion of the screen with a\n * circular ✕ close top-right; content is an icon + bold title + body text\n * with a filled primary action and a tinted secondary one. `variant=\"busy\"`\n * is the transient state (small spinner + label, like the OS \"Connecting…\"\n * sheet). Deliberately light-on-dark regardless of app theme — it mirrors\n * the OS presentation over camera chrome.\n *\n * Package source (`@ai-matrx/capture`) — presentational only.\n */\n\nimport React from \"react\";\nimport {\n Loader2Icon,\n XIcon,\n} from \"./icons\";\nimport { cn } from \"../cn\";\n\nexport interface CaptureSheetAction {\n label: string;\n onPress: () => void;\n kind?: \"primary\" | \"secondary\";\n}\n\nexport interface CaptureSheetProps {\n open: boolean;\n onClose: () => void;\n /** Standard content sheet by default; \"busy\" renders spinner + label. */\n variant?: \"content\" | \"busy\";\n icon?: React.ReactNode;\n title?: string;\n body?: React.ReactNode;\n actions?: CaptureSheetAction[];\n /** The busy variant's label (\"Connecting…\"). */\n busyLabel?: string;\n}\n\nexport function CaptureSheet({\n open,\n onClose,\n variant = \"content\",\n icon,\n title,\n body,\n actions = [],\n busyLabel = \"Working…\",\n}: CaptureSheetProps) {\n if (!open) return null;\n return (\n <div className=\"absolute inset-0 z-50 flex flex-col justify-end\">\n <button\n type=\"button\"\n aria-label=\"Dismiss\"\n onClick={onClose}\n className=\"absolute inset-0 bg-black/30\"\n />\n <div\n className=\"relative mx-2 mb-2 rounded-[2rem] bg-[#f2f2f7] px-6 pb-6 pt-5 text-black shadow-2xl\"\n style={{ marginBottom: \"calc(0.5rem + env(safe-area-inset-bottom, 0px))\" }}\n >\n <button\n type=\"button\"\n onClick={onClose}\n aria-label=\"Close\"\n className=\"absolute right-4 top-4 flex h-9 w-9 items-center justify-center rounded-full bg-black/5 text-black/70 transition-colors hover:bg-black/10\"\n >\n <XIcon className=\"h-5 w-5\" strokeWidth={2.5} />\n </button>\n {variant === \"busy\" ? (\n <div className=\"flex min-h-[220px] items-center justify-center gap-2.5\">\n <Loader2Icon className=\"h-5 w-5 animate-spin text-black/50\" />\n <span className=\"text-[17px] font-medium text-black/80\">\n {busyLabel}\n </span>\n </div>\n ) : (\n <div className=\"pt-4\">\n {icon && <div className=\"mb-5 text-[#0a84ff]\">{icon}</div>}\n {title && (\n <h2 className=\"mb-2 text-[26px] font-bold leading-tight\">\n {title}\n </h2>\n )}\n {body && (\n <div className=\"text-[17px] leading-snug text-black/85\">\n {body}\n </div>\n )}\n {actions.length > 0 && (\n <div className=\"mt-7 flex flex-col gap-3\">\n {actions.map((action) => (\n <button\n key={action.label}\n type=\"button\"\n onClick={action.onPress}\n className={cn(\n \"h-[50px] w-full touch-manipulation rounded-full text-[17px] font-semibold transition-transform active:scale-[0.98]\",\n (action.kind ?? \"primary\") === \"primary\"\n ? \"bg-[#0a84ff] text-white\"\n : \"bg-black/[0.06] text-[#0a84ff]\",\n )}\n >\n {action.label}\n </button>\n ))}\n </div>\n )}\n </div>\n )}\n </div>\n </div>\n );\n}\n","\"use client\";\n\n/**\n * GridOverlay — the rule-of-thirds composition grid over the viewfinder.\n * Genuinely supported (pure CSS), toggled from the options grid.\n *\n * Package source (`@ai-matrx/capture`) — presentational only.\n */\n\nimport React from \"react\";\n\nexport function GridOverlay({ visible }: { visible: boolean }) {\n if (!visible) return null;\n return (\n <div aria-hidden className=\"pointer-events-none absolute inset-0 z-10\">\n <div className=\"absolute inset-y-0 left-1/3 w-px bg-white/40\" />\n <div className=\"absolute inset-y-0 left-2/3 w-px bg-white/40\" />\n <div className=\"absolute inset-x-0 top-1/3 h-px bg-white/40\" />\n <div className=\"absolute inset-x-0 top-2/3 h-px bg-white/40\" />\n </div>\n );\n}\n","\"use client\";\n\n/**\n * CountdownOverlay — the big centered timer digits (iPhone timer capture):\n * one large white numeral per second, scaling in as it changes.\n *\n * Package source (`@ai-matrx/capture`) — presentational only.\n */\n\nimport React from \"react\";\n\nexport function CountdownOverlay({ seconds }: { seconds: number | null }) {\n if (seconds === null || seconds <= 0) return null;\n return (\n <div className=\"pointer-events-none absolute inset-0 z-30 flex items-center justify-center\">\n <span\n key={seconds}\n className=\"text-[120px] font-light text-white drop-shadow-lg [@starting-style]:scale-125 [@starting-style]:opacity-0 transition-all duration-300\"\n >\n {seconds}\n </span>\n </div>\n );\n}\n","/**\n * Package-owned media resolution cache — THE fix for \"every page turn feels\n * like a refetch\".\n *\n * The host supplies, per media item, either a ready `src` (a local object\n * URL for a fresh capture) or an async `resolve()` (a persisted file that\n * needs an authenticated URL). Everything else — memoization, in-flight\n * dedup, LRU eviction, revocation of URLs the cache itself created — is the\n * package's job. This lives IN the package on the completeness rule: if the\n * host had to rebuild this, most hosts wouldn't, and every viewer would lag.\n *\n * Ownership: URLs returned by `resolve()` are revoked on eviction ONLY when\n * the resolver marks them owned (`{ url, revoke: true }`); a plain string is\n * assumed host-owned and never revoked.\n */\n\nimport { useEffect, useState } from \"react\";\n\nexport type ResolvedMedia = string | { url: string; revoke?: boolean };\n\nexport interface CaptureMediaItem {\n /** Stable identity for the item (drives caching + React keys). */\n key: string;\n kind: \"photo\" | \"video\" | \"audio\";\n /** Ready-to-render URL (fresh capture). Host-owned, never revoked here. */\n src?: string | null;\n /** Async URL resolution for persisted items. Called at most once per key\n * while cached; concurrent callers share the in-flight promise. */\n resolve?: () => Promise<ResolvedMedia>;\n /** Upload/processing state — the filmstrip renders it honestly. */\n status?: \"ready\" | \"uploading\" | \"error\";\n /** Accent ring on the filmstrip tile (e.g. a delineator frame). */\n accent?: boolean;\n}\n\ninterface CacheEntry {\n url: string | null;\n revoke: boolean;\n promise: Promise<string | null> | null;\n error: boolean;\n}\n\nconst MAX_ENTRIES = 80;\n\ninterface MediaCacheState {\n cache: Map<string, CacheEntry>;\n listeners: Map<string, Set<() => void>>;\n}\n\n// The LRU survives viewer/filmstrip mount cycles by design — but it must\n// NOT live in module-level variables: this package builds `splitting: false`\n// in dual ESM/CJS format, so a host whose loaders pull both graphs (Next.js\n// RSC + Jest, for example) would instantiate TWO caches and silently split\n// resolutions from subscribers. State lives on `globalThis` under a\n// `Symbol.for` slot instead (the kit `confirm/opener.ts` exemplar). Behavior\n// is unchanged; never \"clean this up\" into module locals.\nconst STATE_SLOT = Symbol.for(\"ai-matrx.capture.media-cache-state\");\n\nfunction getState(): MediaCacheState {\n const holder = globalThis as Record<symbol, MediaCacheState | undefined>;\n let state = holder[STATE_SLOT];\n if (!state) {\n state = { cache: new Map(), listeners: new Map() };\n holder[STATE_SLOT] = state;\n }\n return state;\n}\n\nfunction notify(key: string): void {\n getState().listeners.get(key)?.forEach((fn) => fn());\n}\n\nfunction evictIfNeeded(): void {\n while (getState().cache.size > MAX_ENTRIES) {\n const oldest = getState().cache.keys().next().value;\n if (oldest === undefined) return;\n const entry = getState().cache.get(oldest);\n getState().cache.delete(oldest);\n if (entry?.revoke && entry.url) URL.revokeObjectURL(entry.url);\n }\n}\n\nfunction touch(key: string, entry: CacheEntry): void {\n // Map iteration order = insertion order; re-insert on hit = LRU for free.\n getState().cache.delete(key);\n getState().cache.set(key, entry);\n}\n\n/**\n * Resolve an item's URL through the cache. Synchronous when already known;\n * kicks off (or joins) the resolution otherwise and notifies subscribers.\n */\nexport function getMediaUrl(item: CaptureMediaItem): string | null {\n if (item.src) return item.src;\n if (!item.resolve) return null;\n\n const existing = getState().cache.get(item.key);\n if (existing) {\n touch(item.key, existing);\n if (existing.url || existing.error) return existing.url;\n return null; // in flight\n }\n\n const entry: CacheEntry = { url: null, revoke: false, promise: null, error: false };\n getState().cache.set(item.key, entry);\n evictIfNeeded();\n entry.promise = item\n .resolve()\n .then((resolved) => {\n const url = typeof resolved === \"string\" ? resolved : resolved.url;\n entry.revoke = typeof resolved === \"object\" && resolved.revoke === true;\n entry.url = url;\n entry.promise = null;\n notify(item.key);\n return url;\n })\n .catch(() => {\n entry.error = true;\n entry.promise = null;\n notify(item.key);\n return null;\n });\n return null;\n}\n\n/** Drop one item (e.g. after delete). Revokes only cache-owned URLs. */\nexport function invalidateMedia(key: string): void {\n const entry = getState().cache.get(key);\n getState().cache.delete(key);\n if (entry?.revoke && entry.url) URL.revokeObjectURL(entry.url);\n notify(key);\n}\n\n/** React binding: the item's URL, updating when resolution lands. */\nexport function useMediaUrl(item: CaptureMediaItem | null): string | null {\n const [, bump] = useState(0);\n const key = item?.key ?? null;\n useEffect(() => {\n if (!key) return;\n const set = getState().listeners.get(key) ?? new Set();\n const fn = () => bump((n) => n + 1);\n set.add(fn);\n getState().listeners.set(key, set);\n return () => {\n set.delete(fn);\n if (set.size === 0) getState().listeners.delete(key);\n };\n }, [key]);\n if (!item) return null;\n return getMediaUrl(item);\n}\n\n/** Warm the cache for a set of items (the viewer's neighbor preload). */\nexport function primeMedia(items: (CaptureMediaItem | undefined)[]): void {\n for (const item of items) {\n if (item) void getMediaUrl(item);\n }\n}\n","\"use client\";\n\n/**\n * CaptureFilmstrip — the row of session-capture thumbnails floating over the\n * feed. Package-owned so the tile states (uploading spinner, error ring,\n * accent ring) and the tap-to-view wiring are tuned once, everywhere.\n * Thumbnails resolve through the package media cache, so the strip never\n * re-fetches what the viewer already resolved (and vice versa).\n */\n\nimport React from \"react\";\nimport { cn } from \"../cn\";\nimport { useMediaUrl, type CaptureMediaItem } from \"../media/media-cache\";\n\nexport interface CaptureFilmstripProps {\n items: CaptureMediaItem[];\n onOpen: (item: CaptureMediaItem) => void;\n /** Show at most this many trailing tiles (default 12). */\n limit?: number;\n}\n\nexport function CaptureFilmstrip({\n items,\n onOpen,\n limit = 12,\n}: CaptureFilmstripProps) {\n if (items.length === 0) return null;\n return (\n <div className=\"flex items-center gap-1.5 overflow-x-auto py-1\">\n {items.slice(-limit).map((item) => (\n <button\n key={item.key}\n type=\"button\"\n onClick={() => onOpen(item)}\n aria-label=\"View capture\"\n className={cn(\n \"relative h-12 w-9 shrink-0 touch-manipulation overflow-hidden rounded bg-white/10\",\n item.accent && \"ring-2 ring-inset ring-amber-400\",\n )}\n >\n <FilmstripThumb item={item} />\n {item.status === \"uploading\" && (\n <span className=\"absolute inset-0 flex items-center justify-center bg-black/40\">\n <span className=\"h-3.5 w-3.5 animate-spin rounded-full border-2 border-white/40 border-t-white\" />\n </span>\n )}\n {item.status === \"error\" && (\n <span className=\"absolute inset-0 rounded ring-2 ring-inset ring-red-500\" />\n )}\n </button>\n ))}\n </div>\n );\n}\n\nfunction FilmstripThumb({ item }: { item: CaptureMediaItem }) {\n const url = useMediaUrl(item);\n if (item.kind === \"audio\") {\n return (\n <span className=\"flex h-full w-full items-center justify-center\">\n <svg\n viewBox=\"0 0 24 24\"\n className=\"h-4 w-4 stroke-white/80\"\n fill=\"none\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n aria-hidden\n >\n <path d=\"M12 3v10\" />\n <path d=\"M8 7v4M16 7v4M4 9v1M20 9v1\" />\n <circle cx=\"12\" cy=\"17\" r=\"3\" />\n </svg>\n </span>\n );\n }\n if (!url) return <span className=\"block h-full w-full bg-white/5\" />;\n if (item.kind === \"video\") {\n return (\n <span className=\"relative block h-full w-full\">\n <video\n src={url}\n muted\n playsInline\n preload=\"metadata\"\n className=\"h-full w-full object-cover\"\n />\n <svg\n viewBox=\"0 0 24 24\"\n className=\"absolute inset-0 m-auto h-4 w-4 fill-white drop-shadow\"\n aria-hidden\n >\n <path d=\"M8 5v14l11-7z\" />\n </svg>\n </span>\n );\n }\n return <img src={url} alt=\"\" className=\"h-full w-full object-cover\" />;\n}\n","\"use client\";\n\n/**\n * MediaViewer — the package's full-screen swipe pager (iOS Photos pattern),\n * moved INTO the package after real-phone tuning so every host inherits the\n * tuned gestures, neighbor preload and resolution caching for free.\n *\n * - Pointer-event gestures, zero animation deps: horizontal drag pages\n * (40px travel OR a 0.25px/ms flick), vertical drag ≥110px dismisses,\n * direction locked on first movement.\n * - Neighbors stay MOUNTED and invisible (±2 photos, ±1 video) so a page\n * turn lands on already-resolved, already-decoded pixels — the \"revisit\n * lag\" fix. URLs come from the package media cache (`media-cache.ts`).\n * - Optional per-item Delete and Edit (edit hands off to the host — the\n * `CameraCapture` orchestration pairs it with `ImageEditSheet` and\n * replace semantics).\n * - Desktop: arrow keys page, Escape closes, chevrons on hover-capable\n * screens.\n */\n\nimport React, {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport {\n ChevronLeftIcon,\n ChevronRightIcon,\n PencilIcon,\n PlayIcon,\n Trash2Icon,\n XIcon,\n} from \"./icons\";\nimport { cn } from \"../cn\";\nimport { safeTop, safeMarginBottom } from \"../safe-area\";\nimport {\n primeMedia,\n useMediaUrl,\n type CaptureMediaItem,\n} from \"../media/media-cache\";\n\n// Tuned on a real phone (2026-08-29): distance OR a modest flick must page.\nconst SWIPE_TRIGGER_PX = 40;\nconst SWIPE_TRIGGER_VELOCITY = 0.25; // px per ms\nconst DISMISS_TRIGGER_PX = 110;\nconst DIRECTION_LOCK_PX = 8;\n\nexport interface MediaViewerProps {\n items: CaptureMediaItem[];\n /** Key of the item to open on. */\n initialKey: string | null;\n onClose: () => void;\n onDelete?: ((item: CaptureMediaItem) => void) | undefined;\n /** Offered on photo items with a renderable URL. */\n onEdit?: ((item: CaptureMediaItem) => void) | undefined;\n /** What deleting costs, stated BEFORE the delete (destructive-actions\n * rule). Override per domain; deletion is never one silent tap. */\n deleteConsequence?: string;\n /** Suppress keyboard handling while another overlay (the editor) is on\n * top — Escape must close the top-most surface, not this one. */\n keysDisabled?: boolean;\n}\n\nexport function MediaViewer({\n items,\n initialKey,\n onClose,\n onDelete,\n onEdit,\n deleteConsequence = \"It is removed from this capture for everyone.\",\n keysDisabled = false,\n}: MediaViewerProps) {\n const count = items.length;\n const [index, setIndex] = useState(() => {\n const i = items.findIndex((m) => m.key === initialKey);\n return i >= 0 ? i : 0;\n });\n const clamped = Math.min(index, count - 1);\n const current = count > 0 ? items[clamped] : undefined;\n\n // Drag state lives in refs; only the applied transform is React state.\n // Delete states its consequence before acting — never a one-tap delete.\n const [confirmingDelete, setConfirmingDelete] = useState(false);\n // The ACTIVE slide's <video> element (tap-to-play toggle target).\n const activeVideoRef = useRef<HTMLVideoElement | null>(null);\n const dragRef = useRef<{\n x0: number;\n y0: number;\n t0: number;\n axis: \"x\" | \"y\" | null;\n pointerId: number;\n } | null>(null);\n const [drag, setDrag] = useState<{ dx: number; dy: number } | null>(null);\n const [settling, setSettling] = useState(false);\n\n const go = useCallback(\n (dir: 1 | -1) => {\n setIndex((i) => Math.max(0, Math.min(count - 1, i + dir)));\n setDrag(null);\n setSettling(true);\n },\n [count],\n );\n\n // The list can shrink underneath us (a delete) — clamp, close on empty.\n useEffect(() => {\n if (count === 0) {\n const t = setTimeout(onClose, 0);\n return () => clearTimeout(t);\n }\n if (index >= count) setIndex(count - 1);\n }, [count, index, onClose]);\n\n // Paging away drops a pending delete confirmation — it must always refer\n // to the slide on screen.\n useEffect(() => {\n setConfirmingDelete(false);\n }, [clamped]);\n\n // Neighbor warm-up: resolve upcoming URLs before the swipe lands.\n useEffect(() => {\n primeMedia([\n items[clamped - 2],\n items[clamped - 1],\n items[clamped + 1],\n items[clamped + 2],\n ]);\n }, [items, clamped]);\n\n useEffect(() => {\n if (keysDisabled) return;\n const onKey = (e: KeyboardEvent) => {\n if (e.key === \"ArrowRight\") go(1);\n else if (e.key === \"ArrowLeft\") go(-1);\n else if (e.key === \"Escape\") onClose();\n };\n window.addEventListener(\"keydown\", onKey);\n return () => window.removeEventListener(\"keydown\", onKey);\n }, [go, onClose, keysDisabled]);\n\n const onPointerDown = useCallback((e: React.PointerEvent) => {\n // Audio keeps native controls, so it keeps its pointer events. Video does\n // NOT: the slide is a control-less tap-to-play surface precisely so the\n // stage owns every gesture and a video swipes exactly like a photo.\n if ((e.target as HTMLElement).closest(\"audio\")) return;\n dragRef.current = {\n x0: e.clientX,\n y0: e.clientY,\n t0: performance.now(),\n axis: null,\n pointerId: e.pointerId,\n };\n (e.currentTarget as HTMLElement).setPointerCapture(e.pointerId);\n setSettling(false);\n }, []);\n\n const onPointerMove = useCallback((e: React.PointerEvent) => {\n const d = dragRef.current;\n if (!d || e.pointerId !== d.pointerId) return;\n const dx = e.clientX - d.x0;\n const dy = e.clientY - d.y0;\n if (d.axis === null) {\n if (Math.abs(dx) < DIRECTION_LOCK_PX && Math.abs(dy) < DIRECTION_LOCK_PX)\n return;\n d.axis = Math.abs(dx) >= Math.abs(dy) ? \"x\" : \"y\";\n }\n setDrag(d.axis === \"x\" ? { dx, dy: 0 } : { dx: 0, dy });\n }, []);\n\n const endDrag = useCallback(\n (e: React.PointerEvent) => {\n const d = dragRef.current;\n if (!d || e.pointerId !== d.pointerId) return;\n dragRef.current = null;\n const dx = e.clientX - d.x0;\n const dy = e.clientY - d.y0;\n const dt = Math.max(1, performance.now() - d.t0);\n const vx = dx / dt;\n\n if (d.axis === \"y\" && Math.abs(dy) > DISMISS_TRIGGER_PX) {\n onClose();\n return;\n }\n if (d.axis === \"x\") {\n const flick =\n Math.abs(dx) > 10 && Math.abs(vx) > SWIPE_TRIGGER_VELOCITY;\n if ((dx < -SWIPE_TRIGGER_PX || (flick && dx < 0)) && clamped < count - 1) {\n go(1);\n return;\n }\n if ((dx > SWIPE_TRIGGER_PX || (flick && dx > 0)) && clamped > 0) {\n go(-1);\n return;\n }\n }\n // No direction ever locked = a TAP. On a video slide that toggles\n // playback (the control-less player's one control).\n if (d.axis === null) {\n const video = activeVideoRef.current;\n if (video) {\n if (video.paused) void video.play().catch(() => {});\n else video.pause();\n }\n }\n setDrag(null);\n setSettling(true);\n },\n [clamped, count, go, onClose],\n );\n\n // Mount only ±1 (a 12MP decoded frame is ~48MB — ±2 mounted flirted with\n // iOS jetsam); ±2 still get their URLs primed above, which is the cheap\n // half of the work.\n const neighborKeys = useMemo(() => {\n const wanted: CaptureMediaItem[] = [];\n for (const i of [clamped - 1, clamped + 1]) {\n const m = items[i];\n if (m) wanted.push(m);\n }\n return wanted;\n }, [items, clamped]);\n\n if (!current) return null;\n const canEdit = onEdit && current.kind === \"photo\";\n\n return (\n <div className=\"absolute inset-0 z-40 flex flex-col bg-black\">\n {/* Top bar */}\n <div\n className=\"absolute inset-x-0 top-0 z-20 flex items-center justify-between bg-gradient-to-b from-black/70 to-transparent p-3\"\n style={safeTop}\n >\n <button\n type=\"button\"\n onClick={onClose}\n aria-label=\"Close viewer\"\n className=\"flex h-10 w-10 touch-manipulation items-center justify-center rounded-full text-white transition-colors hover:bg-white/10\"\n >\n <XIcon className=\"h-5 w-5\" />\n </button>\n <span className=\"rounded-full bg-black/50 px-3 py-1 text-sm tabular-nums text-white/90\">\n {clamped + 1} / {count}\n </span>\n <span className=\"flex items-center gap-1\">\n {canEdit ? (\n <button\n type=\"button\"\n onClick={() => onEdit(current)}\n aria-label=\"Edit this photo\"\n className=\"flex h-10 w-10 touch-manipulation items-center justify-center rounded-full text-white transition-colors hover:bg-white/10\"\n >\n <PencilIcon className=\"h-5 w-5\" />\n </button>\n ) : null}\n {onDelete ? (\n <button\n type=\"button\"\n onClick={() => setConfirmingDelete(true)}\n aria-label=\"Delete this file\"\n className=\"flex h-10 w-10 touch-manipulation items-center justify-center rounded-full text-white transition-colors hover:bg-white/10\"\n >\n <Trash2Icon className=\"h-5 w-5\" />\n </button>\n ) : (\n <span className=\"h-10 w-10\" aria-hidden />\n )}\n </span>\n </div>\n\n {/* Stage */}\n <div className=\"relative min-h-0 flex-1 overflow-hidden\">\n <div\n className=\"absolute inset-0 touch-none\"\n style={{\n transform: drag\n ? `translate(${drag.dx}px, ${drag.dy}px)`\n : \"translate(0px, 0px)\",\n transition: settling\n ? \"transform 220ms cubic-bezier(0.2, 0.8, 0.3, 1)\"\n : \"none\",\n opacity: drag?.dy\n ? Math.max(0.4, 1 - Math.abs(drag.dy) / 400)\n : 1,\n }}\n onPointerDown={onPointerDown}\n onPointerMove={onPointerMove}\n onPointerUp={endDrag}\n onPointerCancel={endDrag}\n >\n <ViewerSlide\n key={current.key}\n item={current}\n active\n videoRef={activeVideoRef}\n />\n </div>\n\n {/* Neighbor preload — mounted, invisible, decoded before the swipe. */}\n <div\n aria-hidden\n className=\"pointer-events-none absolute inset-0 opacity-0\"\n >\n {neighborKeys.map((m) => (\n <div key={m.key} className=\"absolute inset-0\">\n <ViewerSlide item={m} active={false} />\n </div>\n ))}\n </div>\n\n {/* Desktop chevrons */}\n {clamped > 0 && (\n <button\n type=\"button\"\n onClick={() => go(-1)}\n aria-label=\"Previous file\"\n className=\"absolute left-2 top-1/2 z-20 hidden h-11 w-11 -translate-y-1/2 items-center justify-center rounded-full bg-black/40 text-white hover:bg-black/60 sm:flex\"\n >\n <ChevronLeftIcon className=\"h-6 w-6\" />\n </button>\n )}\n {clamped < count - 1 && (\n <button\n type=\"button\"\n onClick={() => go(1)}\n aria-label=\"Next file\"\n className=\"absolute right-2 top-1/2 z-20 hidden h-11 w-11 -translate-y-1/2 items-center justify-center rounded-full bg-black/40 text-white hover:bg-black/60 sm:flex\"\n >\n <ChevronRightIcon className=\"h-6 w-6\" />\n </button>\n )}\n </div>\n\n {/* Delete confirmation — names the consequence first. */}\n {confirmingDelete && onDelete && (\n <div\n className=\"absolute inset-x-0 bottom-0 z-30 bg-black/85 px-4 pt-4 backdrop-blur-sm\"\n style={{\n paddingBottom: \"calc(1rem + env(safe-area-inset-bottom, 0px))\",\n }}\n >\n <p className=\"pb-3 text-center text-sm text-white/85\">\n Delete this {current.kind === \"video\" ? \"video\" : current.kind === \"audio\" ? \"voice note\" : \"photo\"}? {deleteConsequence}\n </p>\n <div className=\"flex items-center justify-center gap-3\">\n <button\n type=\"button\"\n onClick={() => setConfirmingDelete(false)}\n className=\"h-11 touch-manipulation rounded-full bg-white/15 px-6 text-sm font-medium text-white\"\n >\n Keep it\n </button>\n <button\n type=\"button\"\n onClick={() => {\n setConfirmingDelete(false);\n onDelete(current);\n }}\n className=\"h-11 touch-manipulation rounded-full bg-[#FF3B30] px-6 text-sm font-semibold text-white\"\n >\n Delete\n </button>\n </div>\n </div>\n )}\n\n {/* Position dots (small counts only) */}\n {count > 1 && count <= 12 && (\n <div\n className=\"pointer-events-none absolute inset-x-0 bottom-4 z-20 flex justify-center gap-1.5\"\n style={safeMarginBottom}\n >\n {items.map((m, i) => (\n <span\n key={m.key}\n className={cn(\n \"h-1.5 w-1.5 rounded-full transition-colors\",\n i === clamped ? \"bg-white\" : \"bg-white/35\",\n )}\n />\n ))}\n </div>\n )}\n </div>\n );\n}\n\nfunction ViewerSlide({\n item,\n active,\n videoRef,\n}: {\n item: CaptureMediaItem;\n active: boolean;\n /** Receives the ACTIVE slide's video element (the tap-to-play target). */\n videoRef?: React.MutableRefObject<HTMLVideoElement | null> | undefined;\n}) {\n const url = useMediaUrl(item);\n if (!url) {\n return active ? (\n <div className=\"absolute inset-0 flex items-center justify-center\">\n <span className=\"h-8 w-8 animate-spin rounded-full border-2 border-white/30 border-t-white\" />\n </div>\n ) : null;\n }\n if (item.kind === \"audio\") {\n if (!active) return null;\n return (\n <div className=\"absolute inset-0 flex flex-col items-center justify-center gap-6 px-8\">\n <svg\n viewBox=\"0 0 24 24\"\n className=\"h-12 w-12 stroke-white/80\"\n fill=\"none\"\n strokeWidth={1.5}\n strokeLinecap=\"round\"\n aria-hidden\n >\n <path d=\"M12 2v12\" />\n <path d=\"M7 6v6M17 6v6M2 9v2M22 9v2\" />\n <circle cx=\"12\" cy=\"19\" r=\"3\" />\n </svg>\n {/* eslint-disable-next-line jsx-a11y/media-has-caption -- a just-recorded voice note has no caption track */}\n <audio src={url} controls className=\"w-full max-w-sm\" />\n </div>\n );\n }\n if (item.kind === \"video\") {\n return <VideoSlide url={url} active={active} videoRef={videoRef} />;\n }\n return (\n <img\n src={url}\n alt=\"\"\n draggable={false}\n decoding={active ? \"auto\" : \"async\"}\n className=\"absolute inset-0 h-full w-full select-none object-contain\"\n />\n );\n}\n\n/**\n * The control-less video slide. Native `controls` made the whole slide a\n * pointer sink — a video could not be swiped like a photo, which is the one\n * behavior a pager must keep uniform. Instead: the STAGE owns every gesture\n * (this element is pointer-events-none), a tap toggles playback, a centre\n * glyph shows the paused state, and a thin bottom bar shows progress.\n */\nfunction VideoSlide({\n url,\n active,\n videoRef,\n}: {\n url: string;\n active: boolean;\n videoRef?: React.MutableRefObject<HTMLVideoElement | null> | undefined;\n}) {\n const [paused, setPaused] = useState(true);\n const [progress, setProgress] = useState(0);\n const localRef = useRef<HTMLVideoElement | null>(null);\n\n // Hand the ACTIVE element to the stage's tap handler; clear on unmount so\n // a swiped-away slide can never receive the next tap.\n useEffect(() => {\n if (!active || !videoRef) return;\n videoRef.current = localRef.current;\n return () => {\n if (videoRef.current === localRef.current) videoRef.current = null;\n };\n }, [active, videoRef]);\n\n return (\n <div className=\"pointer-events-none absolute inset-0\">\n <video\n ref={localRef}\n src={url}\n playsInline\n // Hidden neighbors buffer METADATA only — never whole videos.\n preload={active ? \"auto\" : \"metadata\"}\n muted={!active}\n loop={false}\n onPlay={() => setPaused(false)}\n onPause={() => setPaused(true)}\n onEnded={() => setPaused(true)}\n onTimeUpdate={(e) => {\n const v = e.currentTarget;\n setProgress(v.duration > 0 ? v.currentTime / v.duration : 0);\n }}\n className=\"absolute inset-0 h-full w-full object-contain\"\n />\n {active && paused && (\n <span className=\"absolute inset-0 flex items-center justify-center\">\n <span className=\"flex h-16 w-16 items-center justify-center rounded-full bg-black/45\">\n <PlayIcon className=\"ml-1 h-8 w-8 fill-white text-white\" />\n </span>\n </span>\n )}\n {active && !paused && (\n <span className=\"absolute inset-x-4 bottom-2 h-0.5 overflow-hidden rounded-full bg-white/25\">\n <span\n className=\"block h-full rounded-full bg-white\"\n style={{ width: `${Math.round(progress * 100)}%` }}\n />\n </span>\n )}\n </div>\n );\n}\n","\"use client\";\n\n/**\n * ImageEditSheet — instant in-browser image editing, core to the package\n * (THE CLOUD LAW's sibling: capture without instant edit is half a system).\n * v1 covers the basics that belong in the browser — crop (free + 1:1, 4:3,\n * 16:9 presets), rotate 90°, flip — full-screen dark chrome in the iOS\n * editing style: Cancel/Save top bar, the image letterboxed center, a\n * draggable/resizable crop frame with corner handles, tool row bottom.\n * Heavier AI edits ride host-injected actions, not this sheet.\n *\n * Output is a JPEG re-encode of the ORIGINAL pixels (rotation/flip/crop\n * applied on canvas) — never a screenshot of the preview.\n *\n * Package source (`@ai-matrx/capture`) — browser canvas only, no app deps.\n */\n\nimport React, {\n useCallback,\n useEffect,\n useRef,\n useState,\n} from \"react\";\nimport {\n CheckIcon,\n FlipHorizontal2Icon,\n RotateCcwIcon,\n XIcon,\n} from \"./icons\";\nimport { cn } from \"../cn\";\n\ntype AspectPreset = \"free\" | \"1:1\" | \"4:3\" | \"16:9\";\nconst ASPECTS: { id: AspectPreset; label: string; ratio: number | null }[] = [\n { id: \"free\", label: \"Free\", ratio: null },\n { id: \"1:1\", label: \"Square\", ratio: 1 },\n { id: \"4:3\", label: \"4:3\", ratio: 4 / 3 },\n { id: \"16:9\", label: \"16:9\", ratio: 16 / 9 },\n];\n\n/** Normalized crop rect (0..1) relative to the ROTATED/FLIPPED image. */\ninterface CropRect {\n x: number;\n y: number;\n w: number;\n h: number;\n}\n\nexport interface ImageEditSheetProps {\n open: boolean;\n /** Source image URL (object URL or resolvable src). */\n src: string | null;\n onClose: () => void;\n /** Receives the edited JPEG. The host persists it (cloud port). */\n onSave: (blob: Blob) => void;\n}\n\nconst FULL_CROP: CropRect = { x: 0, y: 0, w: 1, h: 1 };\nconst MIN_CROP = 0.08;\n\nexport function ImageEditSheet({\n open,\n src,\n onClose,\n onSave,\n}: ImageEditSheetProps) {\n // Rotation/flip are BAKED into a working bitmap the moment they are\n // applied (full-res canvas re-encode → object URL). The displayed <img>\n // is therefore always untransformed, so the percentage-positioned crop\n // frame measures exactly the pixels on screen — the earlier CSS\n // `transform: rotate()` approach left the layout box unrotated and the\n // crop frame visibly divergent from the image at 90°/270°.\n const [workingSrc, setWorkingSrc] = useState<string | null>(null);\n const [aspect, setAspect] = useState<AspectPreset>(\"free\");\n const [crop, setCrop] = useState<CropRect>(FULL_CROP);\n const [saving, setSaving] = useState(false);\n const [editError, setEditError] = useState<string | null>(null);\n const stageRef = useRef<HTMLDivElement | null>(null);\n const imgRef = useRef<HTMLImageElement | null>(null);\n // Object URLs THIS sheet minted for baked bitmaps — revoked on replace\n // and on close. The host's `src` is never revoked here.\n const ownedUrlsRef = useRef<string[]>([]);\n const dragRef = useRef<{\n kind: \"move\" | \"nw\" | \"ne\" | \"sw\" | \"se\";\n startX: number;\n startY: number;\n startCrop: CropRect;\n } | null>(null);\n\n const revokeOwned = useCallback(() => {\n for (const url of ownedUrlsRef.current) URL.revokeObjectURL(url);\n ownedUrlsRef.current = [];\n }, []);\n\n useEffect(() => {\n if (open) {\n setWorkingSrc(null);\n setAspect(\"free\");\n setCrop(FULL_CROP);\n setSaving(false);\n setEditError(null);\n }\n return revokeOwned;\n }, [open, src, revokeOwned]);\n\n /** Apply rotate/flip by re-encoding the CURRENT working bitmap. */\n const bake = useCallback(\n (op: \"rotate-left\" | \"flip\") => {\n const img = imgRef.current;\n if (!img || img.naturalWidth === 0 || saving) return;\n try {\n const swap = op === \"rotate-left\";\n const canvas = document.createElement(\"canvas\");\n canvas.width = swap ? img.naturalHeight : img.naturalWidth;\n canvas.height = swap ? img.naturalWidth : img.naturalHeight;\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) throw new Error(\"no 2d context\");\n ctx.translate(canvas.width / 2, canvas.height / 2);\n if (swap) ctx.rotate(-Math.PI / 2);\n else ctx.scale(-1, 1);\n ctx.drawImage(img, -img.naturalWidth / 2, -img.naturalHeight / 2);\n canvas.toBlob(\n (blob) => {\n if (!blob) {\n setEditError(\n \"This image is too large to process on this device.\",\n );\n return;\n }\n revokeOwned();\n const url = URL.createObjectURL(blob);\n ownedUrlsRef.current.push(url);\n setWorkingSrc(url);\n setCrop(FULL_CROP);\n setAspect(\"free\");\n setEditError(null);\n },\n \"image/jpeg\",\n 0.95,\n );\n } catch {\n setEditError(\"This image could not be edited on this device.\");\n }\n },\n [saving, revokeOwned],\n );\n\n const applyAspect = useCallback((preset: AspectPreset) => {\n setAspect(preset);\n const ratio = ASPECTS.find((a) => a.id === preset)?.ratio ?? null;\n if (ratio === null) return;\n // Fit the largest centered rect of the target ratio inside the frame,\n // in DISPLAYED-image normalized space. The working bitmap is always\n // untransformed, so natural dimensions ARE the displayed geometry.\n const img = imgRef.current;\n if (!img || img.naturalWidth === 0) return;\n const imageRatio = img.naturalWidth / img.naturalHeight;\n let w = 1;\n let h = 1;\n if (ratio > imageRatio) h = imageRatio / ratio;\n else w = ratio / imageRatio;\n setCrop({ x: (1 - w) / 2, y: (1 - h) / 2, w, h });\n }, []);\n\n const onPointerDown = useCallback(\n (kind: \"move\" | \"nw\" | \"ne\" | \"sw\" | \"se\") =>\n (e: React.PointerEvent) => {\n e.preventDefault();\n e.stopPropagation();\n (e.target as HTMLElement).setPointerCapture(e.pointerId);\n dragRef.current = {\n kind,\n startX: e.clientX,\n startY: e.clientY,\n startCrop: crop,\n };\n },\n [crop],\n );\n\n const onPointerMove = useCallback(\n (e: React.PointerEvent) => {\n const drag = dragRef.current;\n const img = imgRef.current;\n if (!drag || !img) return;\n const rect = img.getBoundingClientRect();\n if (rect.width === 0 || rect.height === 0) return;\n const dx = (e.clientX - drag.startX) / rect.width;\n const dy = (e.clientY - drag.startY) / rect.height;\n const c = { ...drag.startCrop };\n const ratio = ASPECTS.find((a) => a.id === aspect)?.ratio ?? null;\n const frameRatio = rect.width / rect.height;\n\n if (drag.kind === \"move\") {\n c.x = Math.min(1 - c.w, Math.max(0, c.x + dx));\n c.y = Math.min(1 - c.h, Math.max(0, c.y + dy));\n } else {\n const left = drag.kind === \"nw\" || drag.kind === \"sw\";\n const top = drag.kind === \"nw\" || drag.kind === \"ne\";\n let x2 = c.x + c.w;\n let y2 = c.y + c.h;\n if (left) c.x = Math.min(x2 - MIN_CROP, Math.max(0, c.x + dx));\n else x2 = Math.max(c.x + MIN_CROP, Math.min(1, x2 + dx));\n if (top) c.y = Math.min(y2 - MIN_CROP, Math.max(0, c.y + dy));\n else y2 = Math.max(c.y + MIN_CROP, Math.min(1, y2 + dy));\n c.w = x2 - c.x;\n c.h = y2 - c.y;\n if (ratio !== null) {\n // Lock the ratio by deriving height from width in SCREEN space.\n const targetH = (c.w * frameRatio) / ratio;\n if (top) c.y = y2 - Math.min(targetH, y2);\n c.h = Math.min(targetH, top ? y2 - c.y : 1 - c.y);\n c.w = (c.h * ratio) / frameRatio;\n if (left) c.x = x2 - c.w;\n }\n }\n setCrop(c);\n },\n [aspect],\n );\n\n const onPointerUp = useCallback(() => {\n dragRef.current = null;\n }, []);\n\n const save = useCallback(() => {\n const img = imgRef.current;\n if (!img || img.naturalWidth === 0) return;\n setSaving(true);\n setEditError(null);\n try {\n // Rotation/flip are already baked into the working bitmap — save is\n // a pure crop of what the user sees.\n const canvas = document.createElement(\"canvas\");\n canvas.width = Math.max(1, Math.round(img.naturalWidth * crop.w));\n canvas.height = Math.max(1, Math.round(img.naturalHeight * crop.h));\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) throw new Error(\"no 2d context\");\n ctx.drawImage(img, -crop.x * img.naturalWidth, -crop.y * img.naturalHeight);\n canvas.toBlob(\n (blob) => {\n setSaving(false);\n if (blob) {\n onSave(blob);\n onClose();\n } else {\n // iOS canvas memory limits can yield null on huge frames —\n // Save must never silently do nothing.\n setEditError(\n \"Saving failed on this device — try a smaller crop.\",\n );\n }\n },\n \"image/jpeg\",\n 0.92,\n );\n } catch (err) {\n console.error(\"[capture-camera] edit save failed\", err);\n setSaving(false);\n setEditError(\"Saving failed on this device — try again.\");\n }\n }, [crop, onSave, onClose]);\n\n if (!open || !src) return null;\n\n return (\n <div className=\"absolute inset-0 z-50 flex flex-col bg-black\">\n {/* Top bar */}\n <div\n className=\"flex shrink-0 items-center justify-between px-4\"\n style={{ paddingTop: \"env(safe-area-inset-top, 0px)\" }}\n >\n <button\n type=\"button\"\n onClick={onClose}\n aria-label=\"Cancel editing\"\n className=\"flex h-11 items-center gap-1.5 rounded-full px-3 text-[15px] font-medium text-white\"\n >\n <XIcon className=\"h-5 w-5\" />\n Cancel\n </button>\n <span className=\"text-[15px] font-semibold text-white/90\">Edit</span>\n <button\n type=\"button\"\n onClick={save}\n disabled={saving}\n aria-label=\"Save edited image\"\n className=\"flex h-11 items-center gap-1.5 rounded-full px-3 text-[15px] font-semibold text-[#FFCC00] disabled:opacity-50\"\n >\n <CheckIcon className=\"h-5 w-5\" />\n Save\n </button>\n </div>\n\n {/* Stage */}\n <div\n ref={stageRef}\n className=\"relative flex min-h-0 flex-1 items-center justify-center overflow-hidden p-4\"\n onPointerMove={onPointerMove}\n onPointerUp={onPointerUp}\n onPointerCancel={onPointerUp}\n >\n <div className=\"relative max-h-full max-w-full\">\n {/* eslint-disable-next-line @next/next/no-img-element -- local object URL being edited */}\n <img\n ref={imgRef}\n src={workingSrc ?? src}\n alt=\"Image being edited\"\n draggable={false}\n className=\"max-h-[62dvh] max-w-full select-none object-contain\"\n />\n {/* Crop frame in displayed-image space */}\n <div\n role=\"presentation\"\n onPointerDown={onPointerDown(\"move\")}\n className=\"absolute cursor-move touch-none border-2 border-white shadow-[0_0_0_9999px_rgba(0,0,0,0.55)]\"\n style={{\n left: `${crop.x * 100}%`,\n top: `${crop.y * 100}%`,\n width: `${crop.w * 100}%`,\n height: `${crop.h * 100}%`,\n }}\n >\n {([\"nw\", \"ne\", \"sw\", \"se\"] as const).map((corner) => (\n <span\n key={corner}\n role=\"presentation\"\n onPointerDown={onPointerDown(corner)}\n className={cn(\n \"absolute h-6 w-6 touch-none\",\n corner === \"nw\" &&\n \"-left-1.5 -top-1.5 border-l-4 border-t-4 cursor-nwse-resize\",\n corner === \"ne\" &&\n \"-right-1.5 -top-1.5 border-r-4 border-t-4 cursor-nesw-resize\",\n corner === \"sw\" &&\n \"-bottom-1.5 -left-1.5 border-b-4 border-l-4 cursor-nesw-resize\",\n corner === \"se\" &&\n \"-bottom-1.5 -right-1.5 border-b-4 border-r-4 cursor-nwse-resize\",\n \"border-white\",\n )}\n />\n ))}\n </div>\n </div>\n </div>\n\n {/* Tool row */}\n <div className=\"shrink-0\" style={{ paddingBottom: \"env(safe-area-inset-bottom, 0px)\" }}>\n {editError && (\n <p className=\"px-6 pb-2 text-center text-sm text-[#FF6961]\">\n {editError}\n </p>\n )}\n <div className=\"flex items-center justify-center gap-2 pb-2\">\n {ASPECTS.map((a) => (\n <button\n key={a.id}\n type=\"button\"\n onClick={() => applyAspect(a.id)}\n aria-pressed={aspect === a.id}\n className={cn(\n \"touch-manipulation rounded-full px-3.5 py-1.5 text-[12px] font-semibold uppercase tracking-wide transition-colors\",\n aspect === a.id\n ? \"bg-white/20 text-[#FFCC00]\"\n : \"text-white/80\",\n )}\n >\n {a.label}\n </button>\n ))}\n </div>\n <div className=\"flex items-center justify-center gap-6 pb-4\">\n <button\n type=\"button\"\n onClick={() => bake(\"rotate-left\")}\n aria-label=\"Rotate left\"\n className=\"flex h-12 w-12 touch-manipulation items-center justify-center rounded-full bg-white/10 text-white\"\n >\n <RotateCcwIcon className=\"h-5 w-5\" />\n </button>\n <button\n type=\"button\"\n onClick={() => bake(\"flip\")}\n aria-label=\"Flip horizontally\"\n className=\"flex h-12 w-12 touch-manipulation items-center justify-center rounded-full bg-white/10 text-white\"\n >\n <FlipHorizontal2Icon className=\"h-5 w-5\" />\n </button>\n </div>\n </div>\n </div>\n );\n}\n","\"use client\";\n\n/**\n * CameraCaptureV3 — the vertical-rail camera chrome.\n *\n * A SECOND chrome over the same ports as `CameraCapture`, not a replacement.\n * Same engine, same cloud port, same package-owned review loop (filmstrip →\n * viewer → editor). What differs is the layout and the input model, and every\n * difference answers something the v2 chrome got wrong on a real phone\n * (Arman, 2026-08-30):\n *\n * ONE SHUTTER. Tap = photo, press-and-hold = video. v2 spent a whole\n * row on a mode selector, so the user paid bar height AND\n * a decision before the moment they were trying to catch.\n * THE RIGHT EDGE. Options live on a rail over the feed instead of a\n * two-tap grid behind a button. No layout cost, one tap\n * to anything, and the viewfinder stays whole.\n * IT COLLAPSES. Extras hide behind a chevron so the idle rail is short.\n * TEXT IS A BUTTON. Entry expands from a pill (see CaptureExpandingField) —\n * no permanent field, no keyboard-bait over the frame.\n * ONE MEDIA DOOR. There is no UPLOAD mode. The library button is the only\n * way to existing media, and picking files is an option\n * INSIDE that drawer — the host renders it there.\n *\n * Deliberately NOT copied from the app this borrows its shape from: fixed\n * duration choices (they belong to that product's format, not to a camera),\n * and the oversized promo pill for a new feature (chrome is not a billboard).\n *\n * Package source (`@ai-matrx/capture`). UI state only — capture, streams and\n * persistence come from the injected engine.\n */\n\nimport React, { useCallback, useEffect, useRef, useState } from \"react\";\nimport {\n Grid3x3Icon,\n ImagesIcon,\n ProportionsIcon,\n RefreshCwIcon,\n SunMediumIcon,\n TimerIcon,\n XIcon,\n ZapIcon,\n ZapOffIcon,\n} from \"./icons\";\nimport { cn } from \"../cn\";\nimport { safeTop, safeBottom } from \"../safe-area\";\n\nimport type {\n CaptureAspect,\n CaptureCameraEngine,\n CaptureCameraV3Slots,\n CaptureCloudPort,\n CaptureRailAction,\n CaptureTimerSetting,\n} from \"../types\";\nimport { CaptureRail } from \"./CaptureRail\";\nimport { CaptureSheet, type CaptureSheetAction } from \"./CaptureSheet\";\nimport { CaptureFilmstrip } from \"./CaptureFilmstrip\";\nimport { CountdownOverlay } from \"./CountdownOverlay\";\nimport { GridOverlay } from \"./GridOverlay\";\nimport { HoldShutter } from \"./HoldShutter\";\nimport { ImageEditSheet } from \"./ImageEditSheet\";\nimport { MediaViewer } from \"./MediaViewer\";\nimport { getMediaUrl, invalidateMedia } from \"../media/media-cache\";\nimport { useTrackControls } from \"../hooks/useTrackControls\";\nimport type { CaptureMediaSession } from \"./CameraCapture\";\n\nconst ASPECT_CYCLE: CaptureAspect[] = [\"full\", \"4:3\", \"1:1\", \"16:9\"];\n\nexport interface CameraCaptureV3Props {\n engine: CaptureCameraEngine;\n /** THE CLOUD LAW: still required. v3 changes where the door is, not whether\n * there is one — and in v3 it is the ONLY door to existing media. */\n cloud: CaptureCloudPort;\n preview: React.ReactNode;\n media?: CaptureMediaSession;\n /**\n * Fired on pointer-DOWN, before the hold threshold decides photo vs video.\n *\n * 🚨 THIS EXISTS FOR iOS. Hosts warm the microphone when they believe a\n * recording is coming (one permission prompt per medium). With a mode row\n * that signal arrived when the user chose VIDEO — early. With a hold\n * shutter there is no such moment, so waiting for the recording to actually\n * start means warming DURING the take, which on iOS Safari costs the first\n * second of audio or throws a prompt over the viewfinder mid-recording.\n *\n * The host is expected to make this idempotent: it fires on every press,\n * including the taps that turn out to be photos.\n */\n onRecordIntent?: () => void;\n /** Ring completes here; presentational only — it never stops the recorder. */\n maxRecordSeconds?: number;\n onReviewOpenChange?: (open: boolean) => void;\n onClose?: () => void;\n blockedSheet?: { body: React.ReactNode; actions: CaptureSheetAction[] };\n /** Hide all chrome except status chips (host renders its own toggle). */\n controlsHidden?: boolean;\n shutterDisabled?: boolean;\n slots?: CaptureCameraV3Slots;\n}\n\nexport function CameraCaptureV3({\n engine,\n cloud,\n preview,\n media,\n onRecordIntent,\n maxRecordSeconds,\n onReviewOpenChange,\n onClose,\n blockedSheet,\n controlsHidden = false,\n shutterDisabled = false,\n slots = {},\n}: CameraCaptureV3Props) {\n const [viewerKey, setViewerKey] = useState<string | null>(null);\n const [editTarget, setEditTarget] = useState<{ key: string; url: string } | null>(\n null,\n );\n const [gridOn, setGridOn] = useState(false);\n const [timerSetting, setTimerSetting] = useState<CaptureTimerSetting>(0);\n const [aspect, setAspect] = useState<CaptureAspect>(\"full\");\n const [countdown, setCountdown] = useState<number | null>(null);\n const [blockedDismissed, setBlockedDismissed] = useState(false);\n const countdownRef = useRef<ReturnType<typeof setInterval> | null>(null);\n\n const controls = useTrackControls(engine.stream);\n\n const reviewOpen = viewerKey !== null || editTarget !== null;\n useEffect(() => {\n onReviewOpenChange?.(reviewOpen);\n }, [reviewOpen, onReviewOpenChange]);\n\n const clearCountdown = useCallback(() => {\n if (countdownRef.current) clearInterval(countdownRef.current);\n countdownRef.current = null;\n setCountdown(null);\n }, []);\n useEffect(() => clearCountdown, [clearCountdown]);\n // A countdown must never survive into a recording — it would fire a photo\n // capture mid-take (the v2 bug, kept fixed here).\n useEffect(() => {\n if (engine.recording) clearCountdown();\n }, [engine.recording, clearCountdown]);\n\n const onPhoto = useCallback(() => {\n if (countdown !== null) {\n clearCountdown(); // tapping mid-countdown cancels\n return;\n }\n if (timerSetting === 0) {\n engine.onCapturePhoto({ aspect });\n return;\n }\n let remaining = timerSetting;\n setCountdown(remaining);\n countdownRef.current = setInterval(() => {\n remaining -= 1;\n if (remaining <= 0) {\n clearCountdown();\n engine.onCapturePhoto({ aspect });\n } else {\n setCountdown(remaining);\n }\n }, 1000);\n }, [aspect, clearCountdown, countdown, engine, timerSetting]);\n\n const blocked = engine.blocked !== null;\n\n // ── The rail ───────────────────────────────────────────────────────────\n // Primary (always visible): flip and flash — the two a user reaches for\n // without thinking. Everything else collapses.\n const coreRail: CaptureRailAction[] = [\n ...(engine.onFlipCamera\n ? [\n {\n id: \"flip\",\n label: \"Switch camera\",\n icon: <RefreshCwIcon className=\"h-[22px] w-[22px]\" />,\n primary: true,\n onPress: engine.onFlipCamera,\n },\n ]\n : []),\n ...(controls.torchSupported\n ? [\n {\n id: \"flash\",\n label: \"Flash\",\n icon: controls.torchOn ? (\n <ZapIcon className=\"h-[22px] w-[22px]\" fill=\"currentColor\" />\n ) : (\n <ZapOffIcon className=\"h-[22px] w-[22px]\" />\n ),\n active: controls.torchOn,\n primary: true,\n onPress: controls.toggleTorch,\n },\n ]\n : []),\n {\n id: \"timer\",\n label: \"Timer\",\n icon: <TimerIcon className=\"h-[22px] w-[22px]\" />,\n active: timerSetting !== 0,\n valueLabel: timerSetting === 0 ? undefined : `${timerSetting}s`,\n onPress: () => setTimerSetting((t) => (t === 0 ? 3 : t === 3 ? 10 : 0)),\n },\n {\n id: \"grid\",\n label: \"Grid\",\n icon: <Grid3x3Icon className=\"h-[22px] w-[22px]\" />,\n active: gridOn,\n onPress: () => setGridOn((g) => !g),\n },\n {\n id: \"aspect\",\n label: \"Aspect\",\n icon: <ProportionsIcon className=\"h-[22px] w-[22px]\" />,\n active: aspect !== \"full\",\n valueLabel: aspect === \"full\" ? undefined : aspect,\n onPress: () =>\n setAspect(\n (a) =>\n ASPECT_CYCLE[(ASPECT_CYCLE.indexOf(a) + 1) % ASPECT_CYCLE.length] ??\n \"full\",\n ),\n },\n ...(controls.exposureSupported\n ? [\n {\n id: \"exposure\",\n label: \"Exposure\",\n icon: <SunMediumIcon className=\"h-[22px] w-[22px]\" />,\n active: controls.exposure !== 0,\n valueLabel:\n controls.exposure === 0\n ? undefined\n : `${controls.exposure > 0 ? \"+\" : \"\"}${controls.exposure}`,\n onPress: () => controls.setExposure(controls.exposure === 0 ? 1 : 0),\n },\n ]\n : []),\n ];\n // A blocked camera disables the CORE actions (they steer hardware that is\n // not there) but the rail itself stays: host actions keep working through\n // the upload lane.\n const railActions = [\n ...coreRail.map((a) => (blocked ? { ...a, disabled: true } : a)),\n ...(slots.railActions ?? []),\n ];\n\n return (\n <div className=\"absolute inset-0 select-none overflow-hidden bg-black\">\n <div className=\"absolute inset-0\">{preview}</div>\n <GridOverlay visible={gridOn && !blocked} />\n\n {/* Aspect framing hint — the dimmed bands approximate the region the\n photo will discard. Never shown while recording: video is not\n cropped, so the bands would be a lie about the take in progress. */}\n {aspect !== \"full\" && !blocked && !engine.recording && (\n <div\n aria-hidden\n className=\"pointer-events-none absolute inset-0 z-10 flex items-center justify-center\"\n >\n <div\n className=\"shadow-[0_0_0_9999px_rgba(0,0,0,0.45)]\"\n style={{\n aspectRatio:\n aspect === \"1:1\" ? \"1 / 1\" : aspect === \"4:3\" ? \"3 / 4\" : \"9 / 16\",\n width: aspect === \"16:9\" ? \"100%\" : undefined,\n height: aspect === \"16:9\" ? undefined : \"70%\",\n maxWidth: \"100%\",\n maxHeight: \"100%\",\n }}\n />\n </div>\n )}\n <CountdownOverlay seconds={countdown} />\n\n {/* ── Top row: no bar. Controls float over the feed so the viewfinder\n keeps its full height — the single biggest v2 complaint. ── */}\n {!controlsHidden && (\n <div\n className=\"pointer-events-none absolute inset-x-0 top-0 z-20 px-2\"\n style={safeTop}\n >\n <div className=\"flex min-h-[44px] items-center gap-2 py-1.5\">\n {onClose ? (\n <button\n type=\"button\"\n onClick={onClose}\n aria-label=\"Close camera\"\n className=\"pointer-events-auto flex h-10 w-10 shrink-0 touch-manipulation items-center justify-center rounded-full text-white drop-shadow-[0_1px_3px_rgba(0,0,0,0.6)] transition-colors hover:bg-white/10\"\n >\n <XIcon className=\"h-6 w-6\" />\n </button>\n ) : (\n <span className=\"h-10 w-10 shrink-0\" />\n )}\n\n {/* The expanding entry sits centre-top, where the eye already is\n and where a keyboard rising will not cover it. */}\n <div className=\"pointer-events-auto flex min-w-0 flex-1 justify-center\">\n {slots.topEntry}\n </div>\n\n <span className=\"h-10 w-10 shrink-0\" />\n </div>\n\n {slots.topCenter ? (\n <div className=\"pointer-events-none pb-1 text-center\">\n {slots.topCenter}\n </div>\n ) : null}\n </div>\n )}\n\n {/* Honesty chips stay visible even with controls hidden — they are the\n camera telling the truth, not chrome. */}\n {slots.statusChips ? (\n <div\n className=\"pointer-events-none absolute inset-x-0 z-20 flex flex-col items-center gap-1.5 px-3\"\n style={{\n // Clears the top row AND the topCenter line beneath it — chips\n // rendered at the label's own height read as a collision.\n top: `calc(env(safe-area-inset-top, 0px) + ${\n controlsHidden ? 12 : slots.topCenter ? 92 : 64\n }px)`,\n }}\n >\n {slots.statusChips}\n </div>\n ) : null}\n\n {/* ── The right rail. Rendered even when the camera is BLOCKED: host\n actions (notes, QR, process) are not camera controls and keep\n working through the upload lane — only the core camera actions\n disable (they are built with `disabled: blocked` above). ── */}\n {!controlsHidden && (\n <div\n className=\"pointer-events-none absolute right-1 z-20 flex justify-end\"\n style={{ top: `calc(env(safe-area-inset-top, 0px) + 64px)` }}\n >\n <CaptureRail actions={railActions} />\n </div>\n )}\n\n {/* ── Bottom: filmstrip over the feed, then the shutter row ── */}\n {!controlsHidden && (\n <div className=\"absolute inset-x-0 bottom-0 z-20\" style={safeBottom}>\n {/* The session's captures, over the feed — same package-owned strip\n v2 renders, so the review loop is identical across chromes. */}\n {media && media.items.length > 0 ? (\n <div className=\"px-2 pb-1.5\">\n <CaptureFilmstrip\n items={media.items}\n onOpen={(item) => setViewerKey(item.key)}\n />\n </div>\n ) : null}\n {slots.aboveShutter ? (\n <div className=\"px-2 pb-1.5\">{slots.aboveShutter}</div>\n ) : null}\n\n <div className=\"flex items-center justify-between px-3 pb-2\">\n {/* ONE door to existing media. There is no upload lane here by\n design — the host's library drawer carries the \"pick files\"\n option, so a user has one place to look instead of two\n controls that both mean \"media I already have\". */}\n <div className=\"flex w-[86px] justify-start\">\n <button\n type=\"button\"\n onClick={cloud.onOpenLibrary}\n aria-label=\"Your media — library and upload\"\n className=\"relative h-12 w-12 touch-manipulation overflow-hidden rounded-xl bg-black/40 ring-1 ring-white/30 backdrop-blur-md transition-transform active:scale-95\"\n >\n {cloud.recentsThumb ?? (\n <span className=\"flex h-full w-full items-center justify-center\">\n <ImagesIcon className=\"h-5 w-5 text-white/80\" />\n </span>\n )}\n </button>\n </div>\n\n <HoldShutter\n recording={engine.recording}\n elapsedSeconds={engine.recordElapsedSeconds}\n {...(maxRecordSeconds !== undefined\n ? { maxSeconds: maxRecordSeconds }\n : {})}\n disabled={shutterDisabled || blocked}\n {...(onRecordIntent ? { onPressStart: onRecordIntent } : {})}\n onPhoto={onPhoto}\n onStartRecording={engine.onStartRecording}\n onStopRecording={engine.onStopRecording}\n />\n\n <div className=\"flex w-[86px] justify-end\">\n {slots.shutterTrailing}\n </div>\n </div>\n\n {/* The gesture, stated once. A single-button camera is only obvious\n to the person who built it. */}\n {!engine.recording && !blocked ? (\n <p className=\"pb-1.5 text-center text-[11px] text-white/60 drop-shadow-[0_1px_2px_rgba(0,0,0,0.8)]\">\n Tap for a photo · hold to record\n </p>\n ) : null}\n </div>\n )}\n\n {blocked && blockedSheet && !blockedDismissed && (\n <CaptureSheet\n open\n onClose={() => setBlockedDismissed(true)}\n body={blockedSheet.body}\n title=\"Camera unavailable\"\n actions={blockedSheet.actions}\n />\n )}\n\n {media && viewerKey !== null && (\n <MediaViewer\n items={media.items}\n initialKey={viewerKey}\n keysDisabled={editTarget !== null}\n onClose={() => setViewerKey(null)}\n onDelete={\n media.onDelete\n ? (item) => {\n media.onDelete?.(item.key);\n invalidateMedia(item.key);\n }\n : undefined\n }\n onEdit={\n media.onReplacePhoto\n ? (item) => {\n const url = getMediaUrl(item);\n if (url) setEditTarget({ key: item.key, url });\n }\n : undefined\n }\n />\n )}\n {media?.onReplacePhoto && (\n <ImageEditSheet\n open={editTarget !== null}\n src={editTarget?.url ?? null}\n onClose={() => setEditTarget(null)}\n onSave={(blob) => {\n const target = editTarget;\n setEditTarget(null);\n setViewerKey(null);\n if (target) {\n media.onReplacePhoto?.(target.key, blob);\n invalidateMedia(target.key);\n }\n }}\n />\n )}\n\n {slots.overlays}\n </div>\n );\n}\n","\"use client\";\n\n/**\n * CaptureRail — the vertical action rail down the RIGHT edge of the frame.\n *\n * Why the edge and not a bar: a bottom bar steals height from the viewfinder\n * on every phone, and the options grid it fed cost two taps to reach anything.\n * A rail sits over the feed, costs no layout, and puts every option one tap\n * away under the thumb that is already holding the phone.\n *\n * Why it collapses: a complete rail is a long rail, and a long rail is a wall\n * of icons nobody reads. Actions marked `primary` stay; the rest hide behind a\n * chevron. The chevron is only rendered when there is something to hide —\n * a control that toggles nothing is a lie about the interface.\n *\n * Presentational only.\n */\n\nimport React, { useState } from \"react\";\nimport { cn } from \"../cn\";\nimport type { CaptureRailAction } from \"../types\";\n\nexport interface CaptureRailProps {\n actions: CaptureRailAction[];\n /** Start expanded. Default false — an idle camera shows the short rail. */\n defaultExpanded?: boolean;\n className?: string;\n}\n\nexport function CaptureRail({\n actions,\n defaultExpanded = false,\n className,\n}: CaptureRailProps) {\n const [expanded, setExpanded] = useState(defaultExpanded);\n\n const primary = actions.filter((a) => a.primary);\n const extra = actions.filter((a) => !a.primary);\n // With nothing marked primary, the whole rail is always-on rather than\n // collapsing to nothing — a rail that can hide everything reads as broken.\n const shown = primary.length === 0 ? actions : expanded ? actions : primary;\n const collapsible = primary.length > 0 && extra.length > 0;\n\n if (actions.length === 0) return null;\n\n return (\n <div\n className={cn(\n \"pointer-events-auto flex flex-col items-center gap-1\",\n className,\n )}\n >\n {shown.map((action) => (\n <RailButton key={action.id} action={action} />\n ))}\n\n {collapsible ? (\n <button\n type=\"button\"\n onClick={() => setExpanded((open) => !open)}\n aria-expanded={expanded}\n aria-label={expanded ? \"Fewer options\" : \"More options\"}\n className={cn(\n \"mt-0.5 flex h-9 w-9 touch-manipulation items-center justify-center\",\n \"rounded-full text-white/90 transition-colors hover:bg-white/10\",\n )}\n >\n <Chevron\n className={cn(\n \"h-5 w-5 transition-transform duration-200\",\n expanded && \"rotate-180\",\n )}\n />\n </button>\n ) : null}\n </div>\n );\n}\n\nfunction RailButton({ action }: { action: CaptureRailAction }) {\n return (\n <button\n type=\"button\"\n onClick={action.onPress}\n disabled={action.disabled}\n aria-label={action.label}\n aria-pressed={action.active ?? undefined}\n className={cn(\n \"flex w-12 shrink-0 touch-manipulation flex-col items-center justify-center gap-0.5\",\n \"rounded-2xl py-1.5 transition-colors\",\n action.active ? \"text-[#FFCC00]\" : \"text-white\",\n action.disabled ? \"opacity-40\" : \"hover:bg-white/10 active:bg-white/15\",\n )}\n >\n {/* The icon carries a shadow rather than a plate: a chip per action turns\n the rail into a stack of boxes over the picture the user is framing. */}\n <span className=\"drop-shadow-[0_1px_3px_rgba(0,0,0,0.6)]\">\n {action.icon}\n </span>\n {action.valueLabel ? (\n <span className=\"text-[10px] font-semibold leading-none tabular-nums drop-shadow-[0_1px_2px_rgba(0,0,0,0.7)]\">\n {action.valueLabel}\n </span>\n ) : null}\n </button>\n );\n}\n\n/** Inlined so the package keeps zero icon dependencies. */\nfunction Chevron({ className }: { className?: string }) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={className}\n aria-hidden=\"true\"\n >\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n );\n}\n","\"use client\";\n\n/**\n * HoldShutter — ONE button for photo and video.\n *\n * Tap takes a photo. Press and hold records, and releasing stops. The mode is\n * therefore a gesture, not a control you must set before the moment you are\n * trying to catch — which is the whole reason the v2 mode row was wrong on a\n * phone: it cost bar height AND a decision, and the decision was usually made\n * after the thing had happened.\n *\n * The interaction, precisely:\n *\n * pointerdown → arm a hold timer (HOLD_MS)\n * timer fires → start recording, ring begins filling\n * pointerup < HOLD_MS → cancel the timer, take a photo\n * pointerup >= HOLD_MS → stop recording (recording follows the finger)\n * slide up ≥ LOCK_DRAG_PX while holding → LOCK: release keeps recording,\n * the next tap stops\n * pointercancel / leave → same as pointerup (a drag off the button must not\n * leave the camera recording with nothing to stop it)\n *\n * A LOCK is a GESTURE, never a timer (Arman, 2026-08-30: recording follows\n * the finger — releasing stops, full stop — unless the user deliberately\n * locks): while holding a recording, slide UP to the lock target that\n * appears above the button. Locked, release keeps recording and the next\n * tap stops. An automatic time-based latch shipped first and was wrong —\n * it silently converted \"I let go\" into \"still recording\".\n *\n * Presentational only — the host owns the recorder.\n */\n\nimport React, { useCallback, useEffect, useRef, useState } from \"react\";\nimport {\n LockIcon,\n} from \"./icons\";\nimport { cn } from \"../cn\";\n\n/** Hold this long before a press becomes a recording. */\nconst HOLD_MS = 320;\n/** Slide the held finger this far UP to lock the recording. */\nconst LOCK_DRAG_PX = 64;\n\nexport interface HoldShutterProps {\n recording: boolean;\n /** Elapsed recording seconds, for the ring + read-out. */\n elapsedSeconds: number;\n /**\n * Ring completes at this many seconds. Presentational only — it does not\n * stop the recorder, because a chrome that silently ends a take is worse\n * than one that shows a full ring. Omit for no progress arc.\n */\n maxSeconds?: number;\n disabled?: boolean;\n /**\n * Fired on pointer-DOWN, before the hold threshold decides photo vs video.\n * Hosts use it to warm the microphone — see `CameraCaptureV3Props`.\n */\n onPressStart?: () => void;\n onPhoto: () => void;\n onStartRecording: () => void;\n onStopRecording: () => void;\n}\n\nexport function HoldShutter({\n recording,\n elapsedSeconds,\n maxSeconds,\n disabled = false,\n onPressStart,\n onPhoto,\n onStartRecording,\n onStopRecording,\n}: HoldShutterProps) {\n const holdTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n const startedRecording = useRef(false);\n const pressOriginY = useRef(0);\n const [pressed, setPressed] = useState(false);\n const [locked, setLocked] = useState(false);\n\n const clearHold = useCallback(() => {\n if (holdTimer.current !== null) {\n clearTimeout(holdTimer.current);\n holdTimer.current = null;\n }\n }, []);\n\n // An externally-stopped recording (mode change, error, host abort) must\n // always unlatch.\n useEffect(() => {\n if (!recording) setLocked(false);\n }, [recording]);\n\n useEffect(() => clearHold, [clearHold]);\n\n const onPointerDown = useCallback(\n (event: React.PointerEvent<HTMLButtonElement>) => {\n if (disabled) return;\n // Keep receiving move/up even if the finger slides off the button.\n event.currentTarget.setPointerCapture?.(event.pointerId);\n pressOriginY.current = event.clientY;\n setPressed(true);\n onPressStart?.();\n\n // Locked: this press is a STOP, decided on release so a tap-and-hold\n // does not stop and immediately restart.\n if (recording && locked) return;\n\n startedRecording.current = false;\n holdTimer.current = setTimeout(() => {\n holdTimer.current = null;\n startedRecording.current = true;\n onStartRecording();\n }, HOLD_MS);\n },\n [disabled, locked, onPressStart, onStartRecording, recording],\n );\n\n // Slide-to-lock: while THIS press is recording, dragging up past the lock\n // target latches the take.\n const onPointerMove = useCallback(\n (event: React.PointerEvent<HTMLButtonElement>) => {\n if (!pressed || locked || !startedRecording.current) return;\n if (pressOriginY.current - event.clientY >= LOCK_DRAG_PX) {\n setLocked(true);\n navigator.vibrate?.(30);\n }\n },\n [pressed, locked],\n );\n\n const endPress = useCallback(() => {\n if (!pressed) return;\n setPressed(false);\n const wasHold = startedRecording.current;\n clearHold();\n startedRecording.current = false;\n\n if (recording && locked && !wasHold) {\n onStopRecording();\n return;\n }\n if (wasHold) {\n // Recording follows the finger: release stops — unless the user slid\n // up to the lock during this press.\n if (!locked) onStopRecording();\n return;\n }\n if (!recording) onPhoto();\n }, [clearHold, locked, onPhoto, onStopRecording, pressed, recording]);\n\n const progress =\n maxSeconds && maxSeconds > 0\n ? Math.min(1, elapsedSeconds / maxSeconds)\n : 0;\n\n // 74px button, 3.5px ring — the arc rides just outside the border.\n const R = 39;\n const C = 2 * Math.PI * R;\n\n return (\n <div className=\"relative flex h-[86px] w-[86px] shrink-0 items-center justify-center\">\n {recording && maxSeconds ? (\n <svg\n className=\"pointer-events-none absolute inset-0 -rotate-90\"\n viewBox=\"0 0 86 86\"\n aria-hidden=\"true\"\n >\n <circle\n cx=\"43\"\n cy=\"43\"\n r={R}\n fill=\"none\"\n stroke=\"rgba(255,255,255,0.25)\"\n strokeWidth=\"4\"\n />\n <circle\n cx=\"43\"\n cy=\"43\"\n r={R}\n fill=\"none\"\n stroke=\"#FF3B30\"\n strokeWidth=\"4\"\n strokeLinecap=\"round\"\n strokeDasharray={C}\n strokeDashoffset={C * (1 - progress)}\n />\n </svg>\n ) : null}\n\n {/* The lock target — appears above the button while an UNLOCKED\n recording is held; sliding the finger up to it latches the take. */}\n {recording && pressed && !locked && (\n <span\n className=\"pointer-events-none absolute left-1/2 flex -translate-x-1/2 flex-col items-center gap-0.5\"\n style={{ top: -LOCK_DRAG_PX - 22 }}\n aria-hidden\n >\n <span className=\"flex h-9 w-9 items-center justify-center rounded-full bg-black/60 ring-1 ring-white/30\">\n <LockIcon className=\"h-4 w-4 text-white/90\" />\n </span>\n <span className=\"text-[10px] font-medium text-white/80 drop-shadow\">\n Slide up to lock\n </span>\n </span>\n )}\n {recording && locked && (\n <span\n className=\"pointer-events-none absolute left-1/2 flex h-9 w-9 -translate-x-1/2 items-center justify-center rounded-full bg-[#FF3B30]\"\n style={{ top: -LOCK_DRAG_PX - 22 }}\n aria-hidden\n >\n <LockIcon className=\"h-4 w-4 text-white\" fill=\"currentColor\" />\n </span>\n )}\n\n <button\n type=\"button\"\n disabled={disabled}\n onPointerDown={onPointerDown}\n onPointerMove={onPointerMove}\n onPointerUp={endPress}\n onPointerCancel={endPress}\n onLostPointerCapture={endPress}\n // The press IS the gesture; a click would fire a second photo after\n // pointerup on desktop.\n onContextMenu={(e) => e.preventDefault()}\n aria-label={\n recording\n ? locked\n ? \"Stop recording\"\n : \"Recording — release to stop\"\n : \"Tap for a photo, hold to record\"\n }\n className={cn(\n \"group flex h-[74px] w-[74px] shrink-0 touch-none select-none items-center justify-center\",\n \"rounded-full border-[3.5px] border-white transition-opacity\",\n disabled && \"opacity-30\",\n )}\n >\n <span\n className={cn(\n \"block transition-all duration-200 ease-out\",\n recording\n ? \"h-7 w-7 rounded-[6px] bg-[#FF3B30]\"\n : cn(\n \"h-[62px] w-[62px] rounded-full bg-white\",\n pressed && \"scale-90\",\n ),\n )}\n />\n </button>\n\n {recording ? (\n <span\n className={cn(\n \"pointer-events-none absolute -bottom-1 left-1/2 -translate-x-1/2 translate-y-full\",\n \"rounded-full bg-black/60 px-2 py-0.5 text-[11px] font-medium tabular-nums text-white\",\n )}\n >\n {formatElapsed(elapsedSeconds)}\n {locked ? \" · tap to stop\" : \"\"}\n </span>\n ) : null}\n </div>\n );\n}\n\nfunction formatElapsed(totalSeconds: number): string {\n const m = Math.floor(totalSeconds / 60);\n const s = String(Math.floor(totalSeconds % 60)).padStart(2, \"0\");\n return `${m}:${s}`;\n}\n","\"use client\";\n\n/**\n * CaptureExpandingField — a pill BUTTON that becomes a text field on press,\n * and goes back to being a button when it is done.\n *\n * 🚨 WHY IT IS NOT AN INPUT (Arman, 2026-08-30). v2 pinned a live `<input>` in\n * the bottom bar. On a camera that is wrong three ways: it occupies a row\n * permanently for something used occasionally, it invites the keyboard over\n * the viewfinder on an accidental tap, and it makes an idle camera look like a\n * form. The pattern that fits is the one Apple uses for search — a compact\n * control that admits it is a control, and grows only when you mean it.\n *\n * COMMIT ON UNMOUNT, always. The v2 input already learned this the hard way:\n * hiding the controls or switching item remounts the field, `onBlur` never\n * fires, and a typed value evaporates. Anything typed is committed on the way\n * out, whatever caused the exit.\n *\n * Presentational + local draft state only; the host owns what a value means.\n */\n\nimport React, { useCallback, useEffect, useRef, useState } from \"react\";\nimport { cn } from \"../cn\";\n\nexport interface CaptureExpandingFieldProps {\n /** Collapsed label, e.g. \"Serial / tag\". Also the accessible name. */\n label: string;\n /** Placeholder once expanded. Defaults to `label`. */\n placeholder?: string;\n /** Icon shown in the collapsed pill and at the field's leading edge. */\n icon?: React.ReactNode;\n /** Commit a non-empty trimmed value. Called on Enter, blur, and unmount. */\n onCommit: (value: string) => void;\n /** Start expanded (a host that knows entry is imminent). */\n defaultExpanded?: boolean;\n disabled?: boolean;\n /** Shown in the collapsed pill instead of `label` — e.g. the current tag. */\n currentValue?: string | null;\n className?: string;\n}\n\nexport function CaptureExpandingField({\n label,\n placeholder,\n icon,\n onCommit,\n defaultExpanded = false,\n disabled = false,\n currentValue = null,\n className,\n}: CaptureExpandingFieldProps) {\n const [expanded, setExpanded] = useState(defaultExpanded);\n const [draft, setDraft] = useState(\"\");\n const inputRef = useRef<HTMLInputElement | null>(null);\n\n // Refs so the unmount commit reads the LATEST draft without re-running the\n // effect (which would fire the cleanup on every keystroke).\n const draftRef = useRef(draft);\n draftRef.current = draft;\n const onCommitRef = useRef(onCommit);\n onCommitRef.current = onCommit;\n\n useEffect(() => {\n return () => {\n const trimmed = draftRef.current.trim();\n if (trimmed) onCommitRef.current(trimmed);\n };\n }, []);\n\n const commit = useCallback(() => {\n const trimmed = draftRef.current.trim();\n if (trimmed) onCommitRef.current(trimmed);\n setDraft(\"\");\n }, []);\n\n const open = useCallback(() => {\n setExpanded(true);\n // Focus after paint so the keyboard rises with the field, not before it.\n requestAnimationFrame(() => inputRef.current?.focus());\n }, []);\n\n const close = useCallback(() => {\n commit();\n setExpanded(false);\n }, [commit]);\n\n if (!expanded) {\n return (\n <button\n type=\"button\"\n onClick={open}\n disabled={disabled}\n aria-label={label}\n aria-expanded={false}\n className={cn(\n \"flex h-9 max-w-[62vw] items-center gap-1.5 rounded-full px-3.5\",\n \"bg-black/45 text-[13px] font-semibold text-white backdrop-blur-md\",\n \"transition-colors hover:bg-black/60 active:bg-black/70\",\n disabled && \"opacity-40\",\n className,\n )}\n >\n {icon ? <span className=\"shrink-0\">{icon}</span> : null}\n <span className=\"truncate\">{currentValue?.trim() || label}</span>\n </button>\n );\n }\n\n return (\n <div\n className={cn(\n \"flex h-9 w-[min(78vw,320px)] items-center gap-1.5 rounded-full px-3\",\n \"bg-black/60 backdrop-blur-md\",\n className,\n )}\n >\n {icon ? <span className=\"shrink-0 text-white/70\">{icon}</span> : null}\n <input\n ref={inputRef}\n value={draft}\n onChange={(e) => setDraft(e.target.value)}\n onBlur={close}\n onKeyDown={(e) => {\n if (e.key === \"Enter\") {\n commit();\n (e.target as HTMLInputElement).blur();\n }\n if (e.key === \"Escape\") {\n setDraft(\"\");\n setExpanded(false);\n }\n }}\n placeholder={placeholder ?? label}\n aria-label={label}\n enterKeyHint=\"done\"\n autoCapitalize=\"characters\"\n autoCorrect=\"off\"\n spellCheck={false}\n // 16px floor: anything smaller makes iOS zoom the whole page on focus\n // and it never zooms back out.\n className={cn(\n \"min-w-0 flex-1 bg-transparent text-base text-white\",\n \"placeholder:text-white/40 focus:outline-none\",\n )}\n />\n <button\n type=\"button\"\n // onMouseDown, not onClick: the input's blur would otherwise fire\n // first, collapse the field, and unmount this button mid-click.\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => {\n setDraft(\"\");\n setExpanded(false);\n }}\n aria-label={`Close ${label}`}\n className=\"flex h-6 w-6 shrink-0 items-center justify-center rounded-full text-white/70 hover:bg-white/10 hover:text-white\"\n >\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2.5\"\n strokeLinecap=\"round\"\n className=\"h-3.5 w-3.5\"\n aria-hidden=\"true\"\n >\n <path d=\"M18 6 6 18M6 6l12 12\" />\n </svg>\n </button>\n </div>\n );\n}\n","\"use client\";\n\n/**\n * CameraFeed — the package's live preview <video> for the default engine\n * (drop-in hosts). Attaches the engine's stream imperatively (srcObject is\n * not a React DOM prop), fills its container with object-cover, and exposes\n * the element through the engine's videoRef so photo capture can read it.\n * Inline styles on purpose: host stylesheets (e.g. mobile `video { height:\n * auto }` resets) must never shrink the live view below the captured frame.\n *\n * Hosts with their own runtime render their own preview component instead —\n * this one is part of the batteries-included path.\n */\n\nimport React, { useEffect } from \"react\";\nimport type { CaptureCameraEngine } from \"../types\";\n\nexport function CameraFeed({\n engine,\n mirror = false,\n}: {\n engine: CaptureCameraEngine;\n /** Preview-only CSS mirror (front camera). Output is never mirrored. */\n mirror?: boolean;\n}) {\n const { stream, videoRef } = engine;\n\n useEffect(() => {\n const video = videoRef.current;\n if (!video) return;\n if (video.srcObject !== stream) video.srcObject = stream;\n return () => {\n video.srcObject = null;\n };\n }, [stream, videoRef]);\n\n return (\n <video\n ref={videoRef}\n style={{\n width: \"100%\",\n height: \"100%\",\n objectFit: \"cover\",\n ...(mirror ? { transform: \"scaleX(-1)\" } : {}),\n }}\n muted\n autoPlay\n playsInline\n />\n );\n}\n","\"use client\";\n\n/**\n * useDefaultCaptureEngine — the package's OWN working camera engine, so a\n * host with no media runtime (the Vite drop-in test) gets a fully wired\n * camera from a few lines:\n *\n * const engine = useDefaultCaptureEngine({ onPhoto, onVideo, onFiles });\n * <CameraCapture engine={engine} preview={<CameraFeed engine={engine} />} … />\n *\n * Sophisticated hosts (AI Matrx injects its lease-managed runtime) may pass\n * their own `CaptureCameraEngine` instead — this default is the floor, not\n * the ceiling.\n *\n * THE ONE getUserMedia SITE of the package lives here (`src/engine/` — the\n * laws test bans it everywhere else). Behavior:\n * - Environment-facing by default; flip toggles facingMode and reacquires.\n * - Photo: full-sensor canvas capture (JPEG q0.92), optional center-crop to\n * the chrome's aspect setting. Never a screenshot of the cropped preview.\n * - Video: MediaRecorder over the live stream plus (when granted) audio,\n * with a concrete-MIME ladder and a monotonic elapsed clock.\n * - Upload: a package-created hidden <input type=\"file\"> (no `capture`\n * attribute — that is what opens the OS gallery, not the camera).\n * - Tracks stop on unmount and on flip; permission denial reports\n * `blocked: \"permission-denied\"`, everything else \"not-supported\".\n */\n\nimport {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport type { CaptureAspect, CaptureCameraEngine } from \"../types\";\n\nconst RECORDING_MIME_LADDER = [\n 'video/mp4;codecs=\"avc1.42E01E,mp4a.40.2\"',\n \"video/mp4\",\n 'video/webm;codecs=\"vp9,opus\"',\n 'video/webm;codecs=\"vp8,opus\"',\n \"video/webm\",\n];\n\nexport interface DefaultEngineOptions {\n /** Receives every captured photo as a JPEG File. */\n onPhoto: (file: File) => void;\n /** Receives the finished recording. */\n onVideo: (file: File, durationMs: number) => void;\n /** Receives files chosen through the Upload lane. */\n onFiles: (files: FileList) => void;\n /** Record microphone audio with video (asks once, at record time). */\n withAudio?: boolean;\n facingMode?: \"environment\" | \"user\";\n photoQuality?: number;\n}\n\nfunction cropRect(\n w: number,\n h: number,\n aspect: CaptureAspect,\n): { x: number; y: number; w: number; h: number } {\n if (aspect === \"full\") return { x: 0, y: 0, w, h };\n const [aw, ah] =\n aspect === \"1:1\" ? [1, 1] : aspect === \"4:3\" ? [3, 4] : [9, 16];\n // Portrait ratios above; swap for landscape sensors.\n const [rw, rh] = w >= h ? [ah, aw] : [aw, ah];\n const target = rw / rh;\n let cw = w;\n let ch = w / target;\n if (ch > h) {\n ch = h;\n cw = h * target;\n }\n return { x: (w - cw) / 2, y: (h - ch) / 2, w: cw, h: ch };\n}\n\nexport function useDefaultCaptureEngine(\n options: DefaultEngineOptions,\n): CaptureCameraEngine {\n const {\n onPhoto,\n onVideo,\n onFiles,\n withAudio = true,\n facingMode: initialFacing = \"environment\",\n photoQuality = 0.92,\n } = options;\n\n const [stream, setStream] = useState<MediaStream | null>(null);\n const [blocked, setBlocked] = useState<CaptureCameraEngine[\"blocked\"]>(null);\n const [facing, setFacing] = useState(initialFacing);\n const [multipleCameras, setMultipleCameras] = useState(false);\n const [recording, setRecording] = useState(false);\n const [recordElapsedSeconds, setRecordElapsedSeconds] = useState(0);\n\n const videoRef = useRef<HTMLVideoElement | null>(null);\n const streamRef = useRef<MediaStream | null>(null);\n const recorderRef = useRef<{\n recorder: MediaRecorder;\n chunks: Blob[];\n startedAt: number;\n micTracks: MediaStreamTrack[];\n timer: ReturnType<typeof setInterval>;\n } | null>(null);\n const callbacksRef = useRef({ onPhoto, onVideo, onFiles });\n callbacksRef.current = { onPhoto, onVideo, onFiles };\n\n // ── Stream lifecycle ─────────────────────────────────────────────────────\n useEffect(() => {\n let cancelled = false;\n let acquired: MediaStream | null = null;\n if (typeof navigator === \"undefined\" || !navigator.mediaDevices) {\n setBlocked({ reason: \"not-supported\" });\n return;\n }\n navigator.mediaDevices\n .getUserMedia({\n video: {\n facingMode: facing,\n width: { ideal: 4096 },\n height: { ideal: 4096 },\n },\n audio: false,\n })\n .then((s) => {\n if (cancelled) {\n s.getTracks().forEach((t) => t.stop());\n return;\n }\n acquired = s;\n streamRef.current = s;\n setStream(s);\n setBlocked(null);\n return navigator.mediaDevices.enumerateDevices().then((devices) => {\n if (!cancelled)\n setMultipleCameras(\n devices.filter((d) => d.kind === \"videoinput\").length > 1,\n );\n });\n })\n .catch((err: unknown) => {\n if (cancelled) return;\n const name =\n err && typeof err === \"object\" && \"name\" in err\n ? String((err as { name: unknown }).name)\n : \"\";\n setBlocked({\n reason:\n name === \"NotAllowedError\" || name === \"SecurityError\"\n ? \"permission-denied\"\n : \"not-supported\",\n });\n });\n return () => {\n cancelled = true;\n acquired?.getTracks().forEach((t) => t.stop());\n if (streamRef.current === acquired) streamRef.current = null;\n setStream(null);\n };\n }, [facing]);\n\n // Never leave a recorder running past unmount.\n useEffect(() => {\n return () => {\n const r = recorderRef.current;\n if (r) {\n clearInterval(r.timer);\n if (r.recorder.state !== \"inactive\") r.recorder.stop();\n r.micTracks.forEach((t) => t.stop());\n }\n };\n }, []);\n\n // ── Photo ────────────────────────────────────────────────────────────────\n const onCapturePhoto = useCallback(\n (opts?: { aspect?: CaptureAspect }) => {\n const video = videoRef.current;\n if (!video || video.videoWidth === 0) return;\n const rect = cropRect(\n video.videoWidth,\n video.videoHeight,\n opts?.aspect ?? \"full\",\n );\n const canvas = document.createElement(\"canvas\");\n canvas.width = Math.round(rect.w);\n canvas.height = Math.round(rect.h);\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) return;\n ctx.drawImage(\n video,\n rect.x,\n rect.y,\n rect.w,\n rect.h,\n 0,\n 0,\n canvas.width,\n canvas.height,\n );\n canvas.toBlob(\n (blob) => {\n if (!blob) return;\n callbacksRef.current.onPhoto(\n new File([blob], `capture-${new Date().toISOString()}.jpg`, {\n type: \"image/jpeg\",\n }),\n );\n },\n \"image/jpeg\",\n photoQuality,\n );\n },\n [photoQuality],\n );\n\n // ── Video ────────────────────────────────────────────────────────────────\n const onStartRecording = useCallback(() => {\n const base = streamRef.current;\n if (!base || recorderRef.current) return;\n void (async () => {\n let micTracks: MediaStreamTrack[] = [];\n if (withAudio) {\n try {\n const mic = await navigator.mediaDevices.getUserMedia({\n audio: true,\n });\n micTracks = mic.getAudioTracks();\n } catch {\n // Mic denied — record video-only rather than failing the capture.\n }\n }\n const composed = new MediaStream([\n ...base.getVideoTracks(),\n ...micTracks,\n ]);\n const mime = RECORDING_MIME_LADDER.find((m) =>\n typeof MediaRecorder !== \"undefined\" &&\n MediaRecorder.isTypeSupported(m),\n );\n let recorder: MediaRecorder;\n try {\n recorder = new MediaRecorder(\n composed,\n mime ? { mimeType: mime } : undefined,\n );\n } catch {\n micTracks.forEach((t) => t.stop());\n return;\n }\n const entry = {\n recorder,\n chunks: [] as Blob[],\n startedAt: performance.now(),\n micTracks,\n timer: setInterval(() => {\n setRecordElapsedSeconds(\n Math.floor((performance.now() - entry.startedAt) / 1000),\n );\n }, 250),\n };\n recorderRef.current = entry;\n recorder.ondataavailable = (e) => {\n if (e.data.size > 0) entry.chunks.push(e.data);\n };\n recorder.onstop = () => {\n clearInterval(entry.timer);\n entry.micTracks.forEach((t) => t.stop());\n recorderRef.current = null;\n setRecording(false);\n const durationMs = Math.round(performance.now() - entry.startedAt);\n const type = recorder.mimeType || entry.chunks[0]?.type || \"video/webm\";\n const blob = new Blob(entry.chunks, { type });\n const ext = type.includes(\"mp4\") ? \"mp4\" : \"webm\";\n callbacksRef.current.onVideo(\n new File([blob], `capture-${new Date().toISOString()}.${ext}`, {\n type,\n }),\n durationMs,\n );\n };\n recorder.start(1000);\n setRecordElapsedSeconds(0);\n setRecording(true);\n })();\n }, [withAudio]);\n\n const onStopRecording = useCallback(() => {\n const r = recorderRef.current;\n if (r && r.recorder.state !== \"inactive\") r.recorder.stop();\n }, []);\n\n // ── Upload lane ──────────────────────────────────────────────────────────\n const onUpload = useCallback(() => {\n const input = document.createElement(\"input\");\n input.type = \"file\";\n input.accept = \"image/*,video/*\";\n input.multiple = true;\n input.onchange = () => {\n if (input.files && input.files.length > 0)\n callbacksRef.current.onFiles(input.files);\n };\n input.click();\n }, []);\n\n const onFlipCamera = useCallback(() => {\n setFacing((f) => (f === \"environment\" ? \"user\" : \"environment\"));\n }, []);\n\n return useMemo(\n () => ({\n stream,\n videoRef,\n blocked,\n onCapturePhoto,\n onStartRecording,\n onStopRecording,\n recording,\n recordElapsedSeconds,\n onUpload,\n onFlipCamera: multipleCameras ? onFlipCamera : null,\n }),\n [\n stream,\n blocked,\n onCapturePhoto,\n onStartRecording,\n onStopRecording,\n recording,\n recordElapsedSeconds,\n onUpload,\n onFlipCamera,\n multipleCameras,\n ],\n );\n}\n"],"mappings":"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","names":["useCallback","useEffect","useRef","useState","jsx","jsx","jsxs","jsx","jsxs","jsx","jsxs","jsx","jsxs","jsx","jsxs","jsx","useEffect","useState","jsx","jsxs","useCallback","useEffect","useMemo","useState","jsx","jsxs","useState","useCallback","useEffect","useMemo","useCallback","useEffect","useRef","useState","jsx","jsxs","useState","useRef","useCallback","useEffect","jsx","jsxs","useState","useRef","useEffect","useCallback","useCallback","useEffect","useRef","useState","useState","jsx","jsxs","useState","useCallback","useEffect","useRef","useState","jsx","jsxs","useRef","useState","useCallback","useEffect","formatElapsed","jsx","jsxs","ASPECT_CYCLE","useState","useRef","useEffect","useCallback","useCallback","useEffect","useRef","useState","jsx","jsxs","useState","useRef","useEffect","useCallback","useEffect","jsx","useCallback","useEffect","useMemo","useRef","useState"]}
|
|
1
|
+
{"version":3,"sources":["../src/components/CameraCapture.tsx","../src/components/icons.tsx","../src/cn.ts","../src/safe-area.ts","../src/hooks/useTrackControls.ts","../src/components/ShutterButton.tsx","../src/components/ModeSelector.tsx","../src/components/ZoomRow.tsx","../src/components/OptionsGridPanel.tsx","../src/components/CaptureSheet.tsx","../src/components/GridOverlay.tsx","../src/components/CountdownOverlay.tsx","../src/media/media-cache.ts","../src/components/CaptureFilmstrip.tsx","../src/components/MediaViewer.tsx","../src/components/ImageEditSheet.tsx","../src/components/CameraCaptureV3.tsx","../src/components/CaptureRail.tsx","../src/components/HoldShutter.tsx","../src/components/CaptureExpandingField.tsx","../src/components/CameraFeed.tsx","../src/engine/useDefaultEngine.ts"],"sourcesContent":["\"use client\";\n\n/**\n * CameraCapture — the opinionated iPhone-style camera surface, assembled.\n *\n * Layout (matching the iOS Camera app):\n * - Full-bleed live feed with a semi-transparent near-black bar across the\n * top and bottom — controls read clearly while the feed shows through.\n * - Top bar: close (host-provided), center slot, torch, host extras, and the\n * grid button revealing the two-tap OptionsGridPanel.\n * - Over the feed's bottom edge: real zoom pills (only when the track\n * reports a zoom range).\n * - Bottom bar: injected rows → VIDEO·PHOTO·UPLOAD mode selector → recents\n * thumb · shutter · flip.\n * - Overlays: rule-of-thirds grid, timer countdown, recording chip, blocked\n * sheet (iOS system-sheet presentation).\n *\n * The chrome owns UI state only (options panel, grid, timer, countdown).\n * Capture behavior, streams and persistence come from the injected\n * `CaptureCameraEngine`; domain features attach through `CaptureCameraSlots`.\n *\n * Package source (`@ai-matrx/capture`).\n */\n\nimport React, { useCallback, useEffect, useRef, useState } from \"react\";\nimport {\n Grid3x3Icon,\n GripIcon,\n ProportionsIcon,\n RefreshCwIcon,\n SunMediumIcon,\n TimerIcon,\n XIcon,\n ZapIcon,\n ZapOffIcon,\n} from \"./icons\";\nimport { cn } from \"../cn\";\nimport { safeTop, safeBottom, safeMarginTop } from \"../safe-area\";\n\nimport type {\n CaptureAspect,\n CaptureCameraEngine,\n CaptureCameraMode,\n CaptureCameraSlots,\n CaptureCloudPort,\n CaptureOptionTile,\n CaptureTimerSetting,\n} from \"../types\";\nimport { useTrackControls } from \"../hooks/useTrackControls\";\nimport { ShutterButton } from \"./ShutterButton\";\nimport { ModeSelector } from \"./ModeSelector\";\nimport { ZoomRow } from \"./ZoomRow\";\nimport { OptionsGridPanel } from \"./OptionsGridPanel\";\nimport { CaptureSheet, type CaptureSheetAction } from \"./CaptureSheet\";\nimport { GridOverlay } from \"./GridOverlay\";\nimport { CountdownOverlay } from \"./CountdownOverlay\";\nimport { CaptureFilmstrip } from \"./CaptureFilmstrip\";\nimport { MediaViewer } from \"./MediaViewer\";\nimport { ImageEditSheet } from \"./ImageEditSheet\";\nimport {\n getMediaUrl,\n invalidateMedia,\n type CaptureMediaItem,\n} from \"../media/media-cache\";\n\n/**\n * The session's captured media, handed to the chrome so the WHOLE review\n * loop — filmstrip → swipe viewer → edit → replace — runs inside the\n * package with its tuned gestures, preload and caching. The host only\n * implements the item CRUD.\n */\nexport interface CaptureMediaSession {\n items: CaptureMediaItem[];\n /** Remove one item (viewer trash button). */\n onDelete?: (key: string) => void;\n /** Replace semantics for the built-in editor: persist the edited JPEG in\n * place of the source item. Edit means edit — after saving, the original\n * must be gone. Omit to hide the edit affordance. */\n onReplacePhoto?: (key: string, blob: Blob) => void;\n}\n\nexport interface CameraCaptureProps {\n engine: CaptureCameraEngine;\n /** THE CLOUD LAW: the cloud port is REQUIRED — a camera with no cloud\n * library/persistence is not a valid instance of this system. */\n cloud: CaptureCloudPort;\n mode: CaptureCameraMode;\n onModeChange: (mode: CaptureCameraMode) => void;\n /** The live preview element (`<CameraFeed engine={engine}/>` for the\n * default engine; hosts with their own runtime wire their own). */\n preview: React.ReactNode;\n /** Session media — enables the package-owned filmstrip + viewer + editor. */\n media?: CaptureMediaSession;\n /** Fires when the package review loop (viewer or editor) opens/closes over\n * the live feed — hosts pause things that watch the feed (QR scanning). */\n onReviewOpenChange?: (open: boolean) => void;\n /** Close affordance top-left; omitted = no close button. */\n onClose?: () => void;\n /** Body + actions for the camera-blocked iOS-style sheet. */\n blockedSheet?: { body: React.ReactNode; actions: CaptureSheetAction[] };\n /** Hide all chrome except honesty chips (host renders its own toggle). */\n controlsHidden?: boolean;\n shutterDisabled?: boolean;\n slots?: CaptureCameraSlots;\n}\n\nfunction formatElapsed(totalSeconds: number): string {\n const m = Math.floor(totalSeconds / 60);\n const s = String(totalSeconds % 60).padStart(2, \"0\");\n return `${m}:${s}`;\n}\n\nconst ASPECT_CYCLE: CaptureAspect[] = [\"full\", \"4:3\", \"1:1\", \"16:9\"];\n\nexport function CameraCapture({\n engine,\n cloud,\n mode,\n onModeChange,\n preview,\n media,\n onReviewOpenChange,\n onClose,\n blockedSheet,\n controlsHidden = false,\n shutterDisabled = false,\n slots = {},\n}: CameraCaptureProps) {\n const [optionsOpen, setOptionsOpen] = useState(false);\n // The package-owned review loop: which item the viewer is open on, and\n // which photo the editor is replacing.\n const [viewerKey, setViewerKey] = useState<string | null>(null);\n const [editTarget, setEditTarget] = useState<{\n key: string;\n url: string;\n } | null>(null);\n const [gridOn, setGridOn] = useState(false);\n const [timerSetting, setTimerSetting] = useState<CaptureTimerSetting>(0);\n const [aspect, setAspect] = useState<CaptureAspect>(\"full\");\n const [exposureOpen, setExposureOpen] = useState(false);\n const [countdown, setCountdown] = useState<number | null>(null);\n // The blocked sheet is dismissible — uploads and the system camera keep\n // working, so closing it reveals the chrome rather than leaving the page.\n const [blockedDismissed, setBlockedDismissed] = useState(false);\n const countdownRef = useRef<ReturnType<typeof setInterval> | null>(null);\n\n const controls = useTrackControls(engine.stream);\n\n const reviewOpen = viewerKey !== null || editTarget !== null;\n useEffect(() => {\n onReviewOpenChange?.(reviewOpen);\n }, [reviewOpen, onReviewOpenChange]);\n\n const clearCountdown = useCallback(() => {\n if (countdownRef.current) clearInterval(countdownRef.current);\n countdownRef.current = null;\n setCountdown(null);\n }, []);\n useEffect(() => clearCountdown, [clearCountdown]);\n // A photo countdown must not survive a mode switch — it would fire a\n // photo capture while in video mode (possibly mid-recording).\n useEffect(() => {\n if (mode !== \"photo\") clearCountdown();\n }, [mode, clearCountdown]);\n\n const onShutter = useCallback(() => {\n if (mode === \"video\") {\n if (engine.recording) engine.onStopRecording();\n else engine.onStartRecording();\n return;\n }\n if (countdown !== null) {\n // Tapping mid-countdown cancels — matching iOS.\n clearCountdown();\n return;\n }\n if (timerSetting === 0) {\n engine.onCapturePhoto({ aspect });\n return;\n }\n let remaining = timerSetting;\n setCountdown(remaining);\n countdownRef.current = setInterval(() => {\n remaining -= 1;\n if (remaining <= 0) {\n clearCountdown();\n engine.onCapturePhoto({ aspect });\n } else {\n setCountdown(remaining);\n }\n }, 1000);\n }, [mode, engine, countdown, timerSetting, aspect, clearCountdown]);\n\n const cycleTimer = useCallback(() => {\n setTimerSetting((t) => (t === 0 ? 3 : t === 3 ? 10 : 0));\n }, []);\n\n const coreTiles: CaptureOptionTile[] = [\n ...(controls.torchSupported\n ? [\n {\n id: \"flash\",\n label: \"Flash\",\n icon: controls.torchOn ? (\n <ZapIcon className=\"h-6 w-6\" fill=\"currentColor\" />\n ) : (\n <ZapOffIcon className=\"h-6 w-6\" />\n ),\n active: controls.torchOn,\n onPress: controls.toggleTorch,\n },\n ]\n : []),\n {\n id: \"timer\",\n label: \"Timer\",\n icon: <TimerIcon className=\"h-6 w-6\" />,\n active: timerSetting !== 0,\n valueLabel: timerSetting === 0 ? undefined : `${timerSetting}s`,\n onPress: cycleTimer,\n },\n {\n id: \"grid\",\n label: \"Grid\",\n icon: <Grid3x3Icon className=\"h-6 w-6\" />,\n active: gridOn,\n onPress: () => setGridOn((g) => !g),\n },\n // Aspect applies to PHOTO output (center-cropped from the full sensor).\n {\n id: \"aspect\",\n label: \"Aspect\",\n icon: <ProportionsIcon className=\"h-6 w-6\" />,\n active: aspect !== \"full\",\n valueLabel: aspect === \"full\" ? undefined : aspect,\n onPress: () =>\n setAspect(\n (a) =>\n ASPECT_CYCLE[\n (ASPECT_CYCLE.indexOf(a) + 1) % ASPECT_CYCLE.length\n ] ?? \"full\",\n ),\n },\n ...(controls.exposureSupported\n ? [\n {\n id: \"exposure\",\n label: \"Exposure\",\n icon: <SunMediumIcon className=\"h-6 w-6\" />,\n active: controls.exposure !== 0 || exposureOpen,\n valueLabel:\n controls.exposure === 0\n ? undefined\n : `${controls.exposure > 0 ? \"+\" : \"\"}${controls.exposure}`,\n onPress: () => setExposureOpen((o) => !o),\n },\n ]\n : []),\n ];\n const tiles = [...coreTiles, ...(slots.optionTiles ?? [])];\n\n const blocked = engine.blocked !== null;\n\n return (\n <div className=\"absolute inset-0 select-none overflow-hidden bg-black\">\n {/* Full-bleed feed */}\n <div className=\"absolute inset-0\">{preview}</div>\n <GridOverlay visible={gridOn && !blocked} />\n {/* Aspect framing hint — the photo output is center-cropped to the\n selected ratio; the dimmed bands approximate the discarded region\n of the VISIBLE frame (the capture itself crops the full sensor). */}\n {mode === \"photo\" && aspect !== \"full\" && !blocked && (\n <div\n aria-hidden\n className=\"pointer-events-none absolute inset-0 z-10 flex items-center justify-center\"\n >\n <div\n className=\"shadow-[0_0_0_9999px_rgba(0,0,0,0.45)]\"\n style={{\n aspectRatio:\n aspect === \"1:1\" ? \"1 / 1\" : aspect === \"4:3\" ? \"3 / 4\" : \"9 / 16\",\n width: aspect === \"16:9\" ? \"100%\" : undefined,\n height: aspect === \"16:9\" ? undefined : \"70%\",\n maxWidth: \"100%\",\n maxHeight: \"100%\",\n }}\n />\n </div>\n )}\n <CountdownOverlay seconds={countdown} />\n\n {/* Top bar — ONE compact row; every pixel here is stolen from the\n feed, and a phone browser already spends chrome above us. */}\n {!controlsHidden && (\n <div\n className=\"absolute inset-x-0 top-0 z-20 bg-black/65 backdrop-blur-[2px]\"\n style={safeTop}\n >\n <div className=\"flex h-11 items-center gap-0.5 px-1.5\">\n {onClose ? (\n <button\n type=\"button\"\n onClick={onClose}\n aria-label=\"Close camera\"\n className=\"flex h-10 w-10 shrink-0 touch-manipulation items-center justify-center rounded-full text-white transition-colors hover:bg-white/10\"\n >\n <XIcon className=\"h-5 w-5\" />\n </button>\n ) : (\n <span className=\"w-10 shrink-0\" />\n )}\n <div className=\"min-w-0 flex-1\">{slots.topBarCenter}</div>\n {controls.torchSupported && (\n <button\n type=\"button\"\n onClick={controls.toggleTorch}\n aria-label={\n controls.torchOn ? \"Turn flash off\" : \"Turn flash on\"\n }\n aria-pressed={controls.torchOn}\n className={cn(\n \"flex h-10 w-10 shrink-0 touch-manipulation items-center justify-center rounded-full transition-colors\",\n controls.torchOn\n ? \"text-[#FFCC00]\"\n : \"text-white hover:bg-white/10\",\n )}\n >\n <ZapIcon\n className=\"h-5 w-5\"\n fill={controls.torchOn ? \"currentColor\" : \"none\"}\n />\n </button>\n )}\n {slots.topBarTrailing}\n <button\n type=\"button\"\n onClick={() => setOptionsOpen((o) => !o)}\n aria-label=\"More camera options\"\n aria-expanded={optionsOpen}\n className={cn(\n \"flex h-10 w-10 shrink-0 touch-manipulation items-center justify-center rounded-full transition-colors\",\n optionsOpen ? \"bg-white/20 text-white\" : \"text-white hover:bg-white/10\",\n )}\n >\n <GripIcon className=\"h-5 w-5\" />\n </button>\n </div>\n </div>\n )}\n\n {/* Honesty chips — visible even with controls hidden. */}\n <div\n className=\"pointer-events-none absolute inset-x-0 top-[50px] z-20 flex flex-col items-center gap-1.5\"\n style={safeMarginTop}\n >\n {engine.recording && (\n <span className=\"flex items-center gap-2 rounded-full bg-black/60 px-3 py-1.5 text-sm font-medium text-white\">\n <span className=\"h-2.5 w-2.5 animate-pulse rounded-full bg-[#FF3B30]\" />\n {formatElapsed(engine.recordElapsedSeconds)}\n </span>\n )}\n {slots.statusChips}\n </div>\n\n {/* Bottom stack */}\n {!controlsHidden && (\n <div className=\"absolute inset-x-0 bottom-0 z-20\">\n {/* Zoom pills float on the FEED, just above the bottom bar. */}\n {!blocked && controls.zoomOptions.length >= 2 && (\n <div className=\"mb-2\">\n <ZoomRow\n options={controls.zoomOptions}\n value={controls.zoom}\n onSelect={controls.setZoom}\n />\n </div>\n )}\n {/* The package filmstrip + host content OVER the feed — zero bar\n height. Tapping a tile opens the package viewer. */}\n {media && media.items.length > 0 && (\n <div className=\"mb-1.5 px-2\">\n <CaptureFilmstrip\n items={media.items}\n onOpen={(item) => setViewerKey(item.key)}\n />\n </div>\n )}\n {slots.aboveBar && <div className=\"mb-1.5 px-2\">{slots.aboveBar}</div>}\n {/* Exposure slider — revealed by the EXPOSURE tile, floats above\n the bottom bar like the iOS exposure control. */}\n {exposureOpen && controls.exposureSupported && controls.exposureRange && (\n <div className=\"mx-auto mb-3 flex w-64 items-center gap-3 rounded-full bg-black/55 px-4 py-2\">\n <SunMediumIcon className=\"h-4 w-4 shrink-0 text-[#FFCC00]\" />\n <input\n type=\"range\"\n min={controls.exposureRange.min}\n max={controls.exposureRange.max}\n step={controls.exposureRange.step}\n value={controls.exposure}\n onChange={(e) => controls.setExposure(Number(e.target.value))}\n aria-label=\"Exposure compensation\"\n className=\"w-full accent-[#FFCC00]\"\n />\n <span className=\"w-8 shrink-0 text-right text-xs tabular-nums text-white\">\n {controls.exposure > 0 ? \"+\" : \"\"}\n {controls.exposure}\n </span>\n </div>\n )}\n <div\n className=\"bg-black/65 px-3 backdrop-blur-[2px]\"\n style={safeBottom}\n >\n {slots.aboveModeSelector}\n {/* Connected mode bar + the domain action share ONE row as flex\n siblings — absolute positioning collided with the labels on\n narrow phones, twice. Never reintroduce it. */}\n <div className=\"flex items-center justify-center gap-2 py-1.5\">\n <ModeSelector\n mode={mode}\n onModeChange={onModeChange}\n onUpload={engine.onUpload}\n modeDisabled={engine.recording}\n uploadDisabled={shutterDisabled && !blocked}\n extraModes={slots.extraModes}\n />\n {slots.modeRowTrailing && (\n <div className=\"shrink-0\">{slots.modeRowTrailing}</div>\n )}\n </div>\n <div className=\"flex items-center justify-between px-2 pb-1.5 pt-0.5\">\n <div className=\"flex w-14 justify-start\">\n <button\n type=\"button\"\n onClick={cloud.onOpenLibrary}\n aria-label=\"Open your media library\"\n className=\"h-11 w-11 touch-manipulation overflow-hidden rounded-xl bg-white/10 ring-1 ring-white/25 transition-transform active:scale-95\"\n >\n {cloud.recentsThumb ?? (\n <span className=\"block h-full w-full bg-white/5\" />\n )}\n </button>\n </div>\n <ShutterButton\n mode={mode}\n recording={engine.recording}\n disabled={shutterDisabled || blocked}\n onPress={onShutter}\n />\n <div className=\"flex w-14 justify-end\">\n {engine.onFlipCamera ? (\n <button\n type=\"button\"\n onClick={engine.onFlipCamera}\n aria-label=\"Switch camera\"\n className=\"flex h-11 w-11 touch-manipulation items-center justify-center rounded-full bg-white/15 text-white transition-transform active:rotate-180 active:scale-95 duration-300\"\n >\n <RefreshCwIcon className=\"h-5 w-5\" />\n </button>\n ) : (\n <span className=\"h-11 w-11\" />\n )}\n </div>\n </div>\n </div>\n </div>\n )}\n\n <OptionsGridPanel\n open={optionsOpen && !controlsHidden}\n onClose={() => setOptionsOpen(false)}\n tiles={tiles}\n />\n\n {blocked && blockedSheet && !blockedDismissed && (\n <CaptureSheet\n open\n onClose={() => setBlockedDismissed(true)}\n body={blockedSheet.body}\n title=\"Camera unavailable\"\n actions={blockedSheet.actions}\n />\n )}\n\n {/* Package review loop: viewer over the camera, editor over the\n viewer. Replace semantics — saving an edit persists the new frame,\n removes the source item and drops its cached URL, then closes back\n to the camera. */}\n {media && viewerKey !== null && (\n <MediaViewer\n items={media.items}\n initialKey={viewerKey}\n keysDisabled={editTarget !== null}\n onClose={() => setViewerKey(null)}\n onDelete={\n media.onDelete\n ? (item) => {\n media.onDelete?.(item.key);\n invalidateMedia(item.key);\n }\n : undefined\n }\n onEdit={\n media.onReplacePhoto\n ? (item) => {\n const url = getMediaUrl(item);\n if (url) setEditTarget({ key: item.key, url });\n }\n : undefined\n }\n />\n )}\n {media?.onReplacePhoto && (\n <ImageEditSheet\n open={editTarget !== null}\n src={editTarget?.url ?? null}\n onClose={() => setEditTarget(null)}\n onSave={(blob) => {\n const target = editTarget;\n setEditTarget(null);\n setViewerKey(null);\n if (target) {\n media.onReplacePhoto?.(target.key, blob);\n invalidateMedia(target.key);\n }\n }}\n />\n )}\n\n {slots.overlays}\n </div>\n );\n}\n","/**\n * src/components/icons.tsx — the package's OWN inlined SVG icons.\n *\n * Per campaign ruling C19 (2026-08-29): no icon-library dependency, ever.\n * Every glyph below is copied from lucide-react v0.545.0 (ISC license)\n * exactly — the version this package shipped with before the swap, so\n * pixels don't change — following the @ai-matrx/media precedent\n * (`media/src/react/icons.tsx`). Add a new icon by copying the lucide\n * `__iconNode` data from the version noted here — never by adding a\n * lucide dep back.\n *\n * Internal module: icons are exported for the package's own components\n * only; they are not part of the public entry surface.\n */\n\nimport type { SVGProps } from \"react\";\n\nexport type CaptureIconProps = SVGProps<SVGSVGElement>;\n\nfunction svgProps(props: CaptureIconProps): CaptureIconProps {\n return {\n xmlns: \"http://www.w3.org/2000/svg\",\n viewBox: \"0 0 24 24\",\n width: 24,\n height: 24,\n fill: \"none\",\n stroke: \"currentColor\",\n strokeWidth: 2,\n strokeLinecap: \"round\",\n strokeLinejoin: \"round\",\n \"aria-hidden\": true,\n ...props,\n };\n}\n\n// lucide: check\nexport function CheckIcon(props: CaptureIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M20 6 9 17l-5-5\" />\n </svg>\n );\n}\n\n// lucide: chevron-left\nexport function ChevronLeftIcon(props: CaptureIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"m15 18-6-6 6-6\" />\n </svg>\n );\n}\n\n// lucide: chevron-right\nexport function ChevronRightIcon(props: CaptureIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n );\n}\n\n// lucide: flip-horizontal-2\nexport function FlipHorizontal2Icon(props: CaptureIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"m3 7 5 5-5 5V7\" />\n <path d=\"m21 7-5 5 5 5V7\" />\n <path d=\"M12 20v2\" />\n <path d=\"M12 14v2\" />\n <path d=\"M12 8v2\" />\n <path d=\"M12 2v2\" />\n </svg>\n );\n}\n\n// lucide: grid-3x3\nexport function Grid3x3Icon(props: CaptureIconProps) {\n return (\n <svg {...svgProps(props)}>\n <rect width=\"18\" height=\"18\" x=\"3\" y=\"3\" rx=\"2\" />\n <path d=\"M3 9h18\" />\n <path d=\"M3 15h18\" />\n <path d=\"M9 3v18\" />\n <path d=\"M15 3v18\" />\n </svg>\n );\n}\n\n// lucide: grip\nexport function GripIcon(props: CaptureIconProps) {\n return (\n <svg {...svgProps(props)}>\n <circle cx=\"12\" cy=\"5\" r=\"1\" />\n <circle cx=\"19\" cy=\"5\" r=\"1\" />\n <circle cx=\"5\" cy=\"5\" r=\"1\" />\n <circle cx=\"12\" cy=\"12\" r=\"1\" />\n <circle cx=\"19\" cy=\"12\" r=\"1\" />\n <circle cx=\"5\" cy=\"12\" r=\"1\" />\n <circle cx=\"12\" cy=\"19\" r=\"1\" />\n <circle cx=\"19\" cy=\"19\" r=\"1\" />\n <circle cx=\"5\" cy=\"19\" r=\"1\" />\n </svg>\n );\n}\n\n// lucide: images\nexport function ImagesIcon(props: CaptureIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"m22 11-1.296-1.296a2.4 2.4 0 0 0-3.408 0L11 16\" />\n <path d=\"M4 8a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2\" />\n <circle cx=\"13\" cy=\"7\" r=\"1\" fill=\"currentColor\" />\n <rect x=\"8\" y=\"2\" width=\"14\" height=\"14\" rx=\"2\" />\n </svg>\n );\n}\n\n// lucide: loader-circle (a.k.a. Loader2)\nexport function Loader2Icon(props: CaptureIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M21 12a9 9 0 1 1-6.219-8.56\" />\n </svg>\n );\n}\n\n// lucide: lock\nexport function LockIcon(props: CaptureIconProps) {\n return (\n <svg {...svgProps(props)}>\n <rect width=\"18\" height=\"11\" x=\"3\" y=\"11\" rx=\"2\" ry=\"2\" />\n <path d=\"M7 11V7a5 5 0 0 1 10 0v4\" />\n </svg>\n );\n}\n\n// lucide: pencil\nexport function PencilIcon(props: CaptureIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z\" />\n <path d=\"m15 5 4 4\" />\n </svg>\n );\n}\n\n// lucide: play\nexport function PlayIcon(props: CaptureIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z\" />\n </svg>\n );\n}\n\n// lucide: proportions\nexport function ProportionsIcon(props: CaptureIconProps) {\n return (\n <svg {...svgProps(props)}>\n <rect width=\"20\" height=\"16\" x=\"2\" y=\"4\" rx=\"2\" />\n <path d=\"M12 9v11\" />\n <path d=\"M2 9h13a2 2 0 0 1 2 2v9\" />\n </svg>\n );\n}\n\n// lucide: refresh-cw\nexport function RefreshCwIcon(props: CaptureIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8\" />\n <path d=\"M21 3v5h-5\" />\n <path d=\"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16\" />\n <path d=\"M8 16H3v5\" />\n </svg>\n );\n}\n\n// lucide: rotate-ccw\nexport function RotateCcwIcon(props: CaptureIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8\" />\n <path d=\"M3 3v5h5\" />\n </svg>\n );\n}\n\n// lucide: sun-medium\nexport function SunMediumIcon(props: CaptureIconProps) {\n return (\n <svg {...svgProps(props)}>\n <circle cx=\"12\" cy=\"12\" r=\"4\" />\n <path d=\"M12 3v1\" />\n <path d=\"M12 20v1\" />\n <path d=\"M3 12h1\" />\n <path d=\"M20 12h1\" />\n <path d=\"m18.364 5.636-.707.707\" />\n <path d=\"m6.343 17.657-.707.707\" />\n <path d=\"m5.636 5.636.707.707\" />\n <path d=\"m17.657 17.657.707.707\" />\n </svg>\n );\n}\n\n// lucide: timer\nexport function TimerIcon(props: CaptureIconProps) {\n return (\n <svg {...svgProps(props)}>\n <line x1=\"10\" x2=\"14\" y1=\"2\" y2=\"2\" />\n <line x1=\"12\" x2=\"15\" y1=\"14\" y2=\"11\" />\n <circle cx=\"12\" cy=\"14\" r=\"8\" />\n </svg>\n );\n}\n\n// lucide: trash-2\nexport function Trash2Icon(props: CaptureIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M10 11v6\" />\n <path d=\"M14 11v6\" />\n <path d=\"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6\" />\n <path d=\"M3 6h18\" />\n <path d=\"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\" />\n </svg>\n );\n}\n\n// lucide: x\nexport function XIcon(props: CaptureIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </svg>\n );\n}\n\n// lucide: zap\nexport function ZapIcon(props: CaptureIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z\" />\n </svg>\n );\n}\n\n// lucide: zap-off\nexport function ZapOffIcon(props: CaptureIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M10.513 4.856 13.12 2.17a.5.5 0 0 1 .86.46l-1.377 4.317\" />\n <path d=\"M15.656 10H20a1 1 0 0 1 .78 1.63l-1.72 1.773\" />\n <path d=\"M16.273 16.273 10.88 21.83a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14H4a1 1 0 0 1-.78-1.63l4.507-4.643\" />\n <path d=\"m2 2 20 20\" />\n </svg>\n );\n}\n","/**\n * The package-local `cn` — the documented substitution point for the app's\n * `@/lib/utils` cn during extraction (same pattern as `@ai-matrx/media`).\n */\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(\n ...inputs: Array<string | false | null | undefined>\n): string {\n return twMerge(inputs.filter(Boolean).join(\" \"));\n}\n","/**\n * Safe-area insets as INLINE STYLES — deliberately not utility classes.\n *\n * v0.1.x used the host app's `pt-safe` / `pb-safe` / `mb-safe` Tailwind\n * utilities, which exist only in AI Matrx's globals.css: in any other host\n * (the Vite drop-in test) they silently resolved to nothing and the chrome\n * collided with the notch and home indicator. Inline `env()` styles work in\n * every host with zero setup — the package-completeness rule: if it breaks\n * when the host forgets something, the package must not let the host forget.\n */\n\nimport type { CSSProperties } from \"react\";\n\nexport const safeTop: CSSProperties = {\n paddingTop: \"env(safe-area-inset-top, 0px)\",\n};\n\nexport const safeBottom: CSSProperties = {\n paddingBottom: \"env(safe-area-inset-bottom, 0px)\",\n};\n\nexport const safeMarginTop: CSSProperties = {\n marginTop: \"env(safe-area-inset-top, 0px)\",\n};\n\nexport const safeMarginBottom: CSSProperties = {\n marginBottom: \"env(safe-area-inset-bottom, 0px)\",\n};\n","\"use client\";\n\n/**\n * useTrackControls — HONEST torch + zoom over a live video track's real\n * capabilities (`MediaTrackCapabilities`). If the hardware doesn't report\n * torch or a zoom range, the corresponding control simply doesn't exist —\n * we never render a fake toggle.\n *\n * Zoom pill options are derived from the reported [min, max] range using the\n * familiar phone ladder (.5 / 1 / 2 / 4 / 8) clipped to what the device can\n * actually do. Applied via `track.applyConstraints({ advanced: [...] })`.\n *\n * Package source (`@ai-matrx/capture`) — browser media APIs only, no app\n * imports.\n */\n\nimport { useCallback, useEffect, useMemo, useState } from \"react\";\n\n// torch/zoom are spec'd in mediacapture-image but absent from lib.dom.\ninterface ExtendedCapabilities extends MediaTrackCapabilities {\n torch?: boolean;\n zoom?: { min: number; max: number; step?: number };\n exposureCompensation?: { min: number; max: number; step?: number };\n}\ninterface ExtendedSettings extends MediaTrackSettings {\n torch?: boolean;\n zoom?: number;\n exposureCompensation?: number;\n}\n\nconst ZOOM_LADDER = [0.5, 1, 2, 4, 8];\n\nexport interface TrackControls {\n torchSupported: boolean;\n torchOn: boolean;\n toggleTorch: () => void;\n /** ≥2 entries when the track reports a usable zoom range, else []. */\n zoomOptions: number[];\n zoom: number;\n setZoom: (factor: number) => void;\n /** Exposure compensation — only when the hardware reports a range. */\n exposureSupported: boolean;\n exposure: number;\n exposureRange: { min: number; max: number; step: number } | null;\n setExposure: (value: number) => void;\n}\n\nexport function useTrackControls(stream: MediaStream | null): TrackControls {\n const [torchOn, setTorchOn] = useState(false);\n const [zoom, setZoomState] = useState(1);\n const [exposure, setExposureState] = useState(0);\n // Capabilities can be empty until the track is fully live; re-read once on\n // stream change and again on a short delayed tick (iOS reports late).\n const [caps, setCaps] = useState<ExtendedCapabilities | null>(null);\n\n const track = stream?.getVideoTracks()[0] ?? null;\n\n useEffect(() => {\n setTorchOn(false);\n if (!track || typeof track.getCapabilities !== \"function\") {\n setCaps(null);\n return;\n }\n // iOS can report an EMPTY capability set for seconds after the track\n // goes live — a single delayed re-read missed it and the zoom pills /\n // torch never appeared. Poll on a widening ladder and stop as soon as\n // a usable capability shows up (or the ladder runs out).\n const timers: number[] = [];\n const read = (): boolean => {\n try {\n const next = track.getCapabilities() as ExtendedCapabilities;\n setCaps(next);\n const settings = track.getSettings() as ExtendedSettings;\n if (typeof settings.zoom === \"number\") setZoomState(settings.zoom);\n if (typeof settings.exposureCompensation === \"number\")\n setExposureState(settings.exposureCompensation);\n return (\n next.torch === true ||\n next.zoom !== undefined ||\n next.exposureCompensation !== undefined\n );\n } catch {\n setCaps(null);\n return false;\n }\n };\n if (!read()) {\n for (const delay of [500, 1200, 2500, 5000]) {\n timers.push(\n window.setTimeout(() => {\n if (read()) timers.forEach((t) => window.clearTimeout(t));\n }, delay),\n );\n }\n }\n return () => timers.forEach((t) => window.clearTimeout(t));\n }, [track]);\n\n const torchSupported = caps?.torch === true;\n\n const toggleTorch = useCallback(() => {\n if (!track || !torchSupported) return;\n const next = !torchOn;\n track\n .applyConstraints({ advanced: [{ torch: next } as MediaTrackConstraintSet] })\n .then(() => setTorchOn(next))\n .catch((err: unknown) => {\n console.error(\"[capture-camera] torch toggle failed\", err);\n });\n }, [track, torchSupported, torchOn]);\n\n const zoomOptions = useMemo(() => {\n const range = caps?.zoom;\n if (!range || !(range.max > range.min)) return [];\n const options = ZOOM_LADDER.filter(\n (f) => f >= range.min && f <= range.max,\n );\n if (!options.includes(1) && 1 >= range.min && 1 <= range.max) {\n options.push(1);\n options.sort((a, b) => a - b);\n }\n return options.length >= 2 ? options : [];\n }, [caps]);\n\n const setZoom = useCallback(\n (factor: number) => {\n if (!track || !caps?.zoom) return;\n const clamped = Math.min(caps.zoom.max, Math.max(caps.zoom.min, factor));\n track\n .applyConstraints({\n advanced: [{ zoom: clamped } as MediaTrackConstraintSet],\n })\n .then(() => setZoomState(clamped))\n .catch((err: unknown) => {\n console.error(\"[capture-camera] zoom failed\", err);\n });\n },\n [track, caps],\n );\n\n const exposureCaps = caps?.exposureCompensation;\n const exposureRange =\n exposureCaps && exposureCaps.max > exposureCaps.min\n ? {\n min: exposureCaps.min,\n max: exposureCaps.max,\n step: exposureCaps.step && exposureCaps.step > 0 ? exposureCaps.step : 0.5,\n }\n : null;\n\n const setExposure = useCallback(\n (value: number) => {\n if (!track || !exposureRange) return;\n const clamped = Math.min(\n exposureRange.max,\n Math.max(exposureRange.min, value),\n );\n track\n .applyConstraints({\n advanced: [\n { exposureCompensation: clamped } as MediaTrackConstraintSet,\n ],\n })\n .then(() => setExposureState(clamped))\n .catch((err: unknown) => {\n console.error(\"[capture-camera] exposure failed\", err);\n });\n },\n [track, exposureRange],\n );\n\n return {\n torchSupported,\n torchOn,\n toggleTorch,\n zoomOptions,\n zoom,\n setZoom,\n exposureSupported: exposureRange !== null,\n exposure,\n exposureRange,\n setExposure,\n };\n}\n","\"use client\";\n\n/**\n * ShutterButton — the iPhone shutter: a thin white ring with a filled inner\n * circle. Photo = white fill; video idle = red circle; video recording = the\n * inner shape morphs to a small red rounded square (the iOS stop affordance).\n * Press feedback is a scale-down of the INNER fill only, like iOS.\n *\n * Package source (`@ai-matrx/capture`) — presentational only.\n */\n\nimport React from \"react\";\nimport { cn } from \"../cn\";\nimport type { CaptureCameraMode } from \"../types\";\n\nexport interface ShutterButtonProps {\n mode: CaptureCameraMode;\n recording: boolean;\n disabled?: boolean;\n onPress: () => void;\n}\n\nexport function ShutterButton({\n mode,\n recording,\n disabled = false,\n onPress,\n}: ShutterButtonProps) {\n return (\n <button\n type=\"button\"\n onClick={onPress}\n disabled={disabled}\n aria-label={\n mode === \"photo\"\n ? \"Take photo\"\n : recording\n ? \"Stop recording\"\n : \"Start recording\"\n }\n className={cn(\n \"group flex h-[74px] w-[74px] shrink-0 items-center justify-center rounded-full\",\n \"border-[3.5px] border-white transition-opacity\",\n disabled && \"opacity-30\",\n )}\n >\n <span\n className={cn(\n \"block transition-all duration-200 ease-out group-active:scale-90\",\n mode === \"photo\"\n ? \"h-[62px] w-[62px] rounded-full bg-white\"\n : recording\n ? \"h-8 w-8 rounded-md bg-[#FF3B30]\"\n : \"h-[62px] w-[62px] rounded-full bg-[#FF3B30]\",\n )}\n />\n </button>\n );\n}\n","\"use client\";\n\n/**\n * ModeSelector — the CONNECTED capture-mode bar: one compact rounded track\n * holding VIDEO · PHOTO · UPLOAD (+ injected extras) with a spring-sliding\n * thumb under the active mode (the proven CaptureModeBar interaction, in\n * iPhone dress: uppercase letter-spaced labels, active in iOS camera\n * yellow). Deliberately narrow — the row keeps usable space on BOTH sides\n * for host affordances; screen height is the scarcest resource on a phone\n * browser, so the bar is one short row, never a spread of pills.\n *\n * VIDEO and PHOTO are persistent modes; UPLOAD and extras are immediate\n * actions and never take the thumb.\n *\n * Package source (`@ai-matrx/capture`) — presentational only.\n */\n\nimport React from \"react\";\nimport { cn } from \"../cn\";\n\nimport type { CaptureCameraMode } from \"../types\";\n\n/** Spring curve with a small overshoot (CSS linear() approximation);\n * class-level overshooting cubic-bezier is the fallback. */\nconst SPRING_EASING =\n \"linear(0, 0.0047 0.71%, 0.0189 1.44%, 0.0755 2.93%, 0.1692 4.49%, \" +\n \"0.3921 7.55%, 0.8121 12.94%, 0.9804 15.49%, 1.0946 18.14%, 1.1423 20.16%, \" +\n \"1.1568 21.62%, 1.1541 23.03%, 1.1113 26.4%, 1.0322 31.83%, 0.9902 36.25%, \" +\n \"0.9769 40.24%, 0.9844 45.87%, 1.0028 55.35%, 1.0075 63.42%, 1.0006 85.48%, 1)\";\n\nconst LABEL_BASE =\n \"relative z-10 flex h-8 min-w-0 touch-manipulation items-center justify-center rounded-full px-3 \" +\n \"text-[11px] font-semibold uppercase tracking-[0.12em] transition-colors duration-200 \" +\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/70 disabled:opacity-40\";\n\nexport interface ModeSelectorProps {\n mode: CaptureCameraMode;\n onModeChange: (mode: CaptureCameraMode) => void;\n onUpload: () => void;\n /** Locks mode switching (while recording). */\n modeDisabled?: boolean;\n uploadDisabled?: boolean;\n /** Host-injected extra entries after UPLOAD (e.g. SCAN) — immediate\n * actions, never the active mode. */\n extraModes?: { id: string; label: string; onSelect: () => void }[] | undefined;\n}\n\nexport function ModeSelector({\n mode,\n onModeChange,\n onUpload,\n modeDisabled = false,\n uploadDisabled = false,\n extraModes = [],\n}: ModeSelectorProps) {\n const segments = 3 + extraModes.length;\n const activeIndex = mode === \"video\" ? 0 : 1;\n\n return (\n <div\n role=\"tablist\"\n aria-label=\"Capture mode\"\n className=\"relative inline-grid rounded-full bg-white/10 p-1\"\n style={{ gridTemplateColumns: `repeat(${segments}, minmax(0, 1fr))` }}\n >\n {/* Sliding thumb — transform-only, springs with overshoot, instant\n under prefers-reduced-motion. */}\n <div\n aria-hidden\n className=\"pointer-events-none absolute bottom-1 top-1 left-1 rounded-full bg-white/20 transition-transform duration-500 ease-[cubic-bezier(0.34,1.56,0.64,1)] will-change-transform motion-reduce:transition-none\"\n style={{\n width: `calc((100% - 0.5rem) / ${segments})`,\n transform: `translateX(${activeIndex * 100}%)`,\n transitionTimingFunction: SPRING_EASING,\n }}\n />\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={mode === \"video\"}\n disabled={modeDisabled}\n onClick={() => onModeChange(\"video\")}\n className={cn(\n LABEL_BASE,\n mode === \"video\" ? \"text-[#FFCC00]\" : \"text-white\",\n )}\n >\n Video\n </button>\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={mode === \"photo\"}\n disabled={modeDisabled}\n onClick={() => onModeChange(\"photo\")}\n className={cn(\n LABEL_BASE,\n mode === \"photo\" ? \"text-[#FFCC00]\" : \"text-white\",\n )}\n >\n Photo\n </button>\n <button\n type=\"button\"\n aria-label=\"Upload photos or videos from this device\"\n disabled={modeDisabled || uploadDisabled}\n onClick={onUpload}\n className={cn(LABEL_BASE, \"text-white active:text-[#FFCC00]\")}\n >\n Upload\n </button>\n {extraModes.map((extra) => (\n <button\n key={extra.id}\n type=\"button\"\n aria-label={extra.label}\n disabled={modeDisabled}\n onClick={extra.onSelect}\n className={cn(LABEL_BASE, \"text-white active:text-[#FFCC00]\")}\n >\n {extra.label}\n </button>\n ))}\n </div>\n );\n}\n","\"use client\";\n\n/**\n * ZoomRow — the iPhone zoom pills floating over the bottom of the feed:\n * small translucent circles, the active factor in a slightly larger circle\n * with yellow text and an \"×\" suffix. Rendered ONLY when the host reports a\n * real zoom range (track capabilities) — we never fake unsupported zoom.\n *\n * Package source (`@ai-matrx/capture`) — presentational only.\n */\n\nimport React from \"react\";\nimport { cn } from \"../cn\";\n\nexport interface ZoomRowProps {\n /** Available zoom factors in ascending order (e.g. [1, 2, 4]). */\n options: number[];\n /** The currently applied factor (nearest option is highlighted). */\n value: number;\n onSelect: (factor: number) => void;\n}\n\nfunction formatFactor(factor: number): string {\n return factor < 1\n ? `.${String(Math.round(factor * 10))}`\n : String(Math.round(factor * 10) / 10);\n}\n\nexport function ZoomRow({ options, value, onSelect }: ZoomRowProps) {\n if (options.length < 2) return null;\n const active = options.reduce((best, opt) =>\n Math.abs(opt - value) < Math.abs(best - value) ? opt : best,\n );\n return (\n <div className=\"flex items-center justify-center gap-3\">\n {options.map((opt) => {\n const isActive = opt === active;\n return (\n <button\n key={opt}\n type=\"button\"\n onClick={() => onSelect(opt)}\n aria-label={`Zoom ${formatFactor(opt)}x`}\n aria-pressed={isActive}\n className={cn(\n \"flex touch-manipulation items-center justify-center rounded-full font-semibold transition-all duration-200\",\n isActive\n ? \"h-10 w-10 bg-black/45 text-[13px] text-[#FFCC00]\"\n : \"h-8 w-8 bg-black/35 text-[12px] text-white\",\n )}\n >\n {formatFactor(opt)}\n {isActive && <span className=\"text-[10px]\">×</span>}\n </button>\n );\n })}\n </div>\n );\n}\n","\"use client\";\n\n/**\n * OptionsGridPanel — the iPhone two-tap options surface: tapping the grid\n * button dims the viewfinder and reveals a rounded dark panel pinned to the\n * bottom holding a grid of circular toggle buttons with uppercase labels\n * (one tap to reveal, one tap to act). This is NOT a drawer — no drag\n * handle, no route; tapping the scrim or the grid button again closes it.\n *\n * Tiles are injected (`CaptureOptionTile[]`) so hosts and domain extensions\n * add their own toggles without touching the panel.\n *\n * Package source (`@ai-matrx/capture`) — presentational only.\n */\n\nimport React from \"react\";\nimport { cn } from \"../cn\";\nimport type { CaptureOptionTile } from \"../types\";\n\nexport interface OptionsGridPanelProps {\n open: boolean;\n onClose: () => void;\n tiles: CaptureOptionTile[];\n}\n\nexport function OptionsGridPanel({\n open,\n onClose,\n tiles,\n}: OptionsGridPanelProps) {\n if (!open) return null;\n return (\n <div className=\"absolute inset-0 z-40\">\n {/* Dimming scrim — the viewfinder darkens like iOS; tap to dismiss. */}\n <button\n type=\"button\"\n aria-label=\"Close camera options\"\n onClick={onClose}\n className=\"absolute inset-0 bg-black/70\"\n />\n <div\n className=\"absolute inset-x-3 bottom-3 rounded-[2.5rem] bg-[#3a3a3c]/95 px-6 py-8 shadow-2xl\"\n style={{ marginBottom: \"env(safe-area-inset-bottom, 0px)\" }}\n >\n <div className=\"grid grid-cols-3 gap-x-4 gap-y-7\">\n {tiles.map((tile) => (\n <div key={tile.id} className=\"flex flex-col items-center gap-2.5\">\n <button\n type=\"button\"\n onClick={tile.onPress}\n disabled={tile.disabled}\n aria-label={tile.label}\n aria-pressed={tile.active === true}\n className={cn(\n \"flex h-16 w-16 touch-manipulation items-center justify-center rounded-full bg-[#2c2c2e] transition-colors\",\n tile.active ? \"text-[#FFCC00]\" : \"text-white\",\n tile.disabled && \"opacity-40\",\n )}\n >\n {tile.icon}\n </button>\n <span className=\"text-[13px] font-semibold uppercase tracking-[0.14em] text-white\">\n {tile.valueLabel ? `${tile.label} ${tile.valueLabel}` : tile.label}\n </span>\n </div>\n ))}\n </div>\n </div>\n </div>\n );\n}\n","\"use client\";\n\n/**\n * CaptureSheet — the iOS-style system sheet used over the camera: a light,\n * heavily-rounded card sliding over the lower portion of the screen with a\n * circular ✕ close top-right; content is an icon + bold title + body text\n * with a filled primary action and a tinted secondary one. `variant=\"busy\"`\n * is the transient state (small spinner + label, like the OS \"Connecting…\"\n * sheet). Deliberately light-on-dark regardless of app theme — it mirrors\n * the OS presentation over camera chrome.\n *\n * Package source (`@ai-matrx/capture`) — presentational only.\n */\n\nimport React from \"react\";\nimport {\n Loader2Icon,\n XIcon,\n} from \"./icons\";\nimport { cn } from \"../cn\";\n\nexport interface CaptureSheetAction {\n label: string;\n onPress: () => void;\n kind?: \"primary\" | \"secondary\";\n}\n\nexport interface CaptureSheetProps {\n open: boolean;\n onClose: () => void;\n /** Standard content sheet by default; \"busy\" renders spinner + label. */\n variant?: \"content\" | \"busy\";\n icon?: React.ReactNode;\n title?: string;\n body?: React.ReactNode;\n actions?: CaptureSheetAction[];\n /** The busy variant's label (\"Connecting…\"). */\n busyLabel?: string;\n}\n\nexport function CaptureSheet({\n open,\n onClose,\n variant = \"content\",\n icon,\n title,\n body,\n actions = [],\n busyLabel = \"Working…\",\n}: CaptureSheetProps) {\n if (!open) return null;\n return (\n <div className=\"absolute inset-0 z-50 flex flex-col justify-end\">\n <button\n type=\"button\"\n aria-label=\"Dismiss\"\n onClick={onClose}\n className=\"absolute inset-0 bg-black/30\"\n />\n <div\n className=\"relative mx-2 mb-2 rounded-[2rem] bg-[#f2f2f7] px-6 pb-6 pt-5 text-black shadow-2xl\"\n style={{ marginBottom: \"calc(0.5rem + env(safe-area-inset-bottom, 0px))\" }}\n >\n <button\n type=\"button\"\n onClick={onClose}\n aria-label=\"Close\"\n className=\"absolute right-4 top-4 flex h-9 w-9 items-center justify-center rounded-full bg-black/5 text-black/70 transition-colors hover:bg-black/10\"\n >\n <XIcon className=\"h-5 w-5\" strokeWidth={2.5} />\n </button>\n {variant === \"busy\" ? (\n <div className=\"flex min-h-[220px] items-center justify-center gap-2.5\">\n <Loader2Icon className=\"h-5 w-5 animate-spin text-black/50\" />\n <span className=\"text-[17px] font-medium text-black/80\">\n {busyLabel}\n </span>\n </div>\n ) : (\n <div className=\"pt-4\">\n {icon && <div className=\"mb-5 text-[#0a84ff]\">{icon}</div>}\n {title && (\n <h2 className=\"mb-2 text-[26px] font-bold leading-tight\">\n {title}\n </h2>\n )}\n {body && (\n <div className=\"text-[17px] leading-snug text-black/85\">\n {body}\n </div>\n )}\n {actions.length > 0 && (\n <div className=\"mt-7 flex flex-col gap-3\">\n {actions.map((action) => (\n <button\n key={action.label}\n type=\"button\"\n onClick={action.onPress}\n className={cn(\n \"h-[50px] w-full touch-manipulation rounded-full text-[17px] font-semibold transition-transform active:scale-[0.98]\",\n (action.kind ?? \"primary\") === \"primary\"\n ? \"bg-[#0a84ff] text-white\"\n : \"bg-black/[0.06] text-[#0a84ff]\",\n )}\n >\n {action.label}\n </button>\n ))}\n </div>\n )}\n </div>\n )}\n </div>\n </div>\n );\n}\n","\"use client\";\n\n/**\n * GridOverlay — the rule-of-thirds composition grid over the viewfinder.\n * Genuinely supported (pure CSS), toggled from the options grid.\n *\n * Package source (`@ai-matrx/capture`) — presentational only.\n */\n\nimport React from \"react\";\n\nexport function GridOverlay({ visible }: { visible: boolean }) {\n if (!visible) return null;\n return (\n <div aria-hidden className=\"pointer-events-none absolute inset-0 z-10\">\n <div className=\"absolute inset-y-0 left-1/3 w-px bg-white/40\" />\n <div className=\"absolute inset-y-0 left-2/3 w-px bg-white/40\" />\n <div className=\"absolute inset-x-0 top-1/3 h-px bg-white/40\" />\n <div className=\"absolute inset-x-0 top-2/3 h-px bg-white/40\" />\n </div>\n );\n}\n","\"use client\";\n\n/**\n * CountdownOverlay — the big centered timer digits (iPhone timer capture):\n * one large white numeral per second, scaling in as it changes.\n *\n * Package source (`@ai-matrx/capture`) — presentational only.\n */\n\nimport React from \"react\";\n\nexport function CountdownOverlay({ seconds }: { seconds: number | null }) {\n if (seconds === null || seconds <= 0) return null;\n return (\n <div className=\"pointer-events-none absolute inset-0 z-30 flex items-center justify-center\">\n <span\n key={seconds}\n className=\"text-[120px] font-light text-white drop-shadow-lg [@starting-style]:scale-125 [@starting-style]:opacity-0 transition-all duration-300\"\n >\n {seconds}\n </span>\n </div>\n );\n}\n","/**\n * Package-owned media resolution cache — THE fix for \"every page turn feels\n * like a refetch\".\n *\n * The host supplies, per media item, either a ready `src` (a local object\n * URL for a fresh capture) or an async `resolve()` (a persisted file that\n * needs an authenticated URL). Everything else — memoization, in-flight\n * dedup, LRU eviction, revocation of URLs the cache itself created — is the\n * package's job. This lives IN the package on the completeness rule: if the\n * host had to rebuild this, most hosts wouldn't, and every viewer would lag.\n *\n * Ownership: URLs returned by `resolve()` are revoked on eviction ONLY when\n * the resolver marks them owned (`{ url, revoke: true }`); a plain string is\n * assumed host-owned and never revoked.\n */\n\nimport { useEffect, useState } from \"react\";\n\nexport type ResolvedMedia = string | { url: string; revoke?: boolean };\n\nexport interface CaptureMediaItem {\n /** Stable identity for the item (drives caching + React keys). */\n key: string;\n kind: \"photo\" | \"video\" | \"audio\";\n /** Ready-to-render URL (fresh capture). Host-owned, never revoked here. */\n src?: string | null;\n /** Async URL resolution for persisted items. Called at most once per key\n * while cached; concurrent callers share the in-flight promise. */\n resolve?: () => Promise<ResolvedMedia>;\n /** Upload/processing state — the filmstrip renders it honestly. */\n status?: \"ready\" | \"uploading\" | \"error\";\n /** Accent ring on the filmstrip tile (e.g. a delineator frame). */\n accent?: boolean;\n}\n\ninterface CacheEntry {\n url: string | null;\n revoke: boolean;\n promise: Promise<string | null> | null;\n error: boolean;\n}\n\nconst MAX_ENTRIES = 80;\n\ninterface MediaCacheState {\n cache: Map<string, CacheEntry>;\n listeners: Map<string, Set<() => void>>;\n}\n\n// The LRU survives viewer/filmstrip mount cycles by design — but it must\n// NOT live in module-level variables: this package builds `splitting: false`\n// in dual ESM/CJS format, so a host whose loaders pull both graphs (Next.js\n// RSC + Jest, for example) would instantiate TWO caches and silently split\n// resolutions from subscribers. State lives on `globalThis` under a\n// `Symbol.for` slot instead (the kit `confirm/opener.ts` exemplar). Behavior\n// is unchanged; never \"clean this up\" into module locals.\nconst STATE_SLOT = Symbol.for(\"ai-matrx.capture.media-cache-state\");\n\nfunction getState(): MediaCacheState {\n const holder = globalThis as Record<symbol, MediaCacheState | undefined>;\n let state = holder[STATE_SLOT];\n if (!state) {\n state = { cache: new Map(), listeners: new Map() };\n holder[STATE_SLOT] = state;\n }\n return state;\n}\n\nfunction notify(key: string): void {\n getState().listeners.get(key)?.forEach((fn) => fn());\n}\n\nfunction evictIfNeeded(): void {\n while (getState().cache.size > MAX_ENTRIES) {\n const oldest = getState().cache.keys().next().value;\n if (oldest === undefined) return;\n const entry = getState().cache.get(oldest);\n getState().cache.delete(oldest);\n if (entry?.revoke && entry.url) URL.revokeObjectURL(entry.url);\n }\n}\n\nfunction touch(key: string, entry: CacheEntry): void {\n // Map iteration order = insertion order; re-insert on hit = LRU for free.\n getState().cache.delete(key);\n getState().cache.set(key, entry);\n}\n\n/**\n * Resolve an item's URL through the cache. Synchronous when already known;\n * kicks off (or joins) the resolution otherwise and notifies subscribers.\n */\nexport function getMediaUrl(item: CaptureMediaItem): string | null {\n if (item.src) return item.src;\n if (!item.resolve) return null;\n\n const existing = getState().cache.get(item.key);\n if (existing) {\n touch(item.key, existing);\n if (existing.url || existing.error) return existing.url;\n return null; // in flight\n }\n\n const entry: CacheEntry = { url: null, revoke: false, promise: null, error: false };\n getState().cache.set(item.key, entry);\n evictIfNeeded();\n entry.promise = item\n .resolve()\n .then((resolved) => {\n const url = typeof resolved === \"string\" ? resolved : resolved.url;\n entry.revoke = typeof resolved === \"object\" && resolved.revoke === true;\n entry.url = url;\n entry.promise = null;\n notify(item.key);\n return url;\n })\n .catch(() => {\n entry.error = true;\n entry.promise = null;\n notify(item.key);\n return null;\n });\n return null;\n}\n\n/** Drop one item (e.g. after delete). Revokes only cache-owned URLs. */\nexport function invalidateMedia(key: string): void {\n const entry = getState().cache.get(key);\n getState().cache.delete(key);\n if (entry?.revoke && entry.url) URL.revokeObjectURL(entry.url);\n notify(key);\n}\n\n/** React binding: the item's URL, updating when resolution lands. */\nexport function useMediaUrl(item: CaptureMediaItem | null): string | null {\n const [, bump] = useState(0);\n const key = item?.key ?? null;\n useEffect(() => {\n if (!key) return;\n const set = getState().listeners.get(key) ?? new Set();\n const fn = () => bump((n) => n + 1);\n set.add(fn);\n getState().listeners.set(key, set);\n return () => {\n set.delete(fn);\n if (set.size === 0) getState().listeners.delete(key);\n };\n }, [key]);\n if (!item) return null;\n return getMediaUrl(item);\n}\n\n/** Warm the cache for a set of items (the viewer's neighbor preload). */\nexport function primeMedia(items: (CaptureMediaItem | undefined)[]): void {\n for (const item of items) {\n if (item) void getMediaUrl(item);\n }\n}\n","\"use client\";\n\n/**\n * CaptureFilmstrip — the row of session-capture thumbnails floating over the\n * feed. Package-owned so the tile states (uploading spinner, error ring,\n * accent ring) and the tap-to-view wiring are tuned once, everywhere.\n * Thumbnails resolve through the package media cache, so the strip never\n * re-fetches what the viewer already resolved (and vice versa).\n */\n\nimport React from \"react\";\nimport { cn } from \"../cn\";\nimport { useMediaUrl, type CaptureMediaItem } from \"../media/media-cache\";\n\nexport interface CaptureFilmstripProps {\n items: CaptureMediaItem[];\n onOpen: (item: CaptureMediaItem) => void;\n /** Show at most this many trailing tiles (default 12). */\n limit?: number;\n}\n\nexport function CaptureFilmstrip({\n items,\n onOpen,\n limit = 12,\n}: CaptureFilmstripProps) {\n if (items.length === 0) return null;\n return (\n <div className=\"flex items-center gap-1.5 overflow-x-auto py-1\">\n {items.slice(-limit).map((item) => (\n <button\n key={item.key}\n type=\"button\"\n onClick={() => onOpen(item)}\n aria-label=\"View capture\"\n className={cn(\n \"relative h-12 w-9 shrink-0 touch-manipulation overflow-hidden rounded bg-white/10\",\n item.accent && \"ring-2 ring-inset ring-amber-400\",\n )}\n >\n <FilmstripThumb item={item} />\n {item.status === \"uploading\" && (\n <span className=\"absolute inset-0 flex items-center justify-center bg-black/40\">\n <span className=\"h-3.5 w-3.5 animate-spin rounded-full border-2 border-white/40 border-t-white\" />\n </span>\n )}\n {item.status === \"error\" && (\n <span className=\"absolute inset-0 rounded ring-2 ring-inset ring-red-500\" />\n )}\n </button>\n ))}\n </div>\n );\n}\n\nfunction FilmstripThumb({ item }: { item: CaptureMediaItem }) {\n const url = useMediaUrl(item);\n if (item.kind === \"audio\") {\n return (\n <span className=\"flex h-full w-full items-center justify-center\">\n <svg\n viewBox=\"0 0 24 24\"\n className=\"h-4 w-4 stroke-white/80\"\n fill=\"none\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n aria-hidden\n >\n <path d=\"M12 3v10\" />\n <path d=\"M8 7v4M16 7v4M4 9v1M20 9v1\" />\n <circle cx=\"12\" cy=\"17\" r=\"3\" />\n </svg>\n </span>\n );\n }\n if (!url) return <span className=\"block h-full w-full bg-white/5\" />;\n if (item.kind === \"video\") {\n return (\n <span className=\"relative block h-full w-full\">\n <video\n // The #t media fragment forces iOS Safari to decode and PAINT the\n // first frame — without it a preload=\"metadata\" video tile renders\n // black (\"videos don't show a thumbnail\", real-phone 2026-08-30).\n src={`${url}#t=0.01`}\n muted\n playsInline\n preload=\"metadata\"\n className=\"h-full w-full object-cover\"\n />\n <svg\n viewBox=\"0 0 24 24\"\n className=\"absolute inset-0 m-auto h-4 w-4 fill-white drop-shadow\"\n aria-hidden\n >\n <path d=\"M8 5v14l11-7z\" />\n </svg>\n </span>\n );\n }\n return <img src={url} alt=\"\" className=\"h-full w-full object-cover\" />;\n}\n","\"use client\";\n\n/**\n * MediaViewer — the package's full-screen swipe pager (iOS Photos pattern),\n * moved INTO the package after real-phone tuning so every host inherits the\n * tuned gestures, neighbor preload and resolution caching for free.\n *\n * - Pointer-event gestures, zero animation deps: horizontal drag pages\n * (40px travel OR a 0.25px/ms flick), vertical drag ≥110px dismisses,\n * direction locked on first movement.\n * - Neighbors stay MOUNTED and invisible (±2 photos, ±1 video) so a page\n * turn lands on already-resolved, already-decoded pixels — the \"revisit\n * lag\" fix. URLs come from the package media cache (`media-cache.ts`).\n * - Optional per-item Delete and Edit (edit hands off to the host — the\n * `CameraCapture` orchestration pairs it with `ImageEditSheet` and\n * replace semantics).\n * - Desktop: arrow keys page, Escape closes, chevrons on hover-capable\n * screens.\n */\n\nimport React, {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport {\n ChevronLeftIcon,\n ChevronRightIcon,\n PencilIcon,\n PlayIcon,\n Trash2Icon,\n XIcon,\n} from \"./icons\";\nimport { cn } from \"../cn\";\nimport { safeTop, safeMarginBottom } from \"../safe-area\";\nimport {\n primeMedia,\n useMediaUrl,\n type CaptureMediaItem,\n} from \"../media/media-cache\";\n\n// Tuned on a real phone (2026-08-29): distance OR a modest flick must page.\nconst SWIPE_TRIGGER_PX = 40;\nconst SWIPE_TRIGGER_VELOCITY = 0.25; // px per ms\nconst DISMISS_TRIGGER_PX = 110;\nconst DIRECTION_LOCK_PX = 8;\n\nexport interface MediaViewerProps {\n items: CaptureMediaItem[];\n /** Key of the item to open on. */\n initialKey: string | null;\n onClose: () => void;\n onDelete?: ((item: CaptureMediaItem) => void) | undefined;\n /** Offered on photo items with a renderable URL. */\n onEdit?: ((item: CaptureMediaItem) => void) | undefined;\n /** What deleting costs, stated BEFORE the delete (destructive-actions\n * rule). Override per domain; deletion is never one silent tap. */\n deleteConsequence?: string;\n /** Suppress keyboard handling while another overlay (the editor) is on\n * top — Escape must close the top-most surface, not this one. */\n keysDisabled?: boolean;\n}\n\nexport function MediaViewer({\n items,\n initialKey,\n onClose,\n onDelete,\n onEdit,\n deleteConsequence = \"It is removed from this capture for everyone.\",\n keysDisabled = false,\n}: MediaViewerProps) {\n const count = items.length;\n const [index, setIndex] = useState(() => {\n const i = items.findIndex((m) => m.key === initialKey);\n return i >= 0 ? i : 0;\n });\n const clamped = Math.min(index, count - 1);\n const current = count > 0 ? items[clamped] : undefined;\n\n // Drag state lives in refs; only the applied transform is React state.\n // Delete states its consequence before acting — never a one-tap delete.\n const [confirmingDelete, setConfirmingDelete] = useState(false);\n // The ACTIVE slide's <video> element (tap-to-play toggle target).\n const activeVideoRef = useRef<HTMLVideoElement | null>(null);\n const dragRef = useRef<{\n x0: number;\n y0: number;\n t0: number;\n axis: \"x\" | \"y\" | null;\n pointerId: number;\n } | null>(null);\n const [drag, setDrag] = useState<{ dx: number; dy: number } | null>(null);\n const [settling, setSettling] = useState(false);\n\n const go = useCallback(\n (dir: 1 | -1) => {\n setIndex((i) => Math.max(0, Math.min(count - 1, i + dir)));\n setDrag(null);\n setSettling(true);\n },\n [count],\n );\n\n // The list can shrink underneath us (a delete) — clamp, close on empty.\n useEffect(() => {\n if (count === 0) {\n const t = setTimeout(onClose, 0);\n return () => clearTimeout(t);\n }\n if (index >= count) setIndex(count - 1);\n }, [count, index, onClose]);\n\n // Paging away drops a pending delete confirmation — it must always refer\n // to the slide on screen.\n useEffect(() => {\n setConfirmingDelete(false);\n }, [clamped]);\n\n // Neighbor warm-up: resolve upcoming URLs before the swipe lands.\n useEffect(() => {\n primeMedia([\n items[clamped - 2],\n items[clamped - 1],\n items[clamped + 1],\n items[clamped + 2],\n ]);\n }, [items, clamped]);\n\n useEffect(() => {\n if (keysDisabled) return;\n const onKey = (e: KeyboardEvent) => {\n if (e.key === \"ArrowRight\") go(1);\n else if (e.key === \"ArrowLeft\") go(-1);\n else if (e.key === \"Escape\") onClose();\n };\n window.addEventListener(\"keydown\", onKey);\n return () => window.removeEventListener(\"keydown\", onKey);\n }, [go, onClose, keysDisabled]);\n\n const onPointerDown = useCallback((e: React.PointerEvent) => {\n // Audio keeps native controls, so it keeps its pointer events. Video does\n // NOT: the slide is a control-less tap-to-play surface precisely so the\n // stage owns every gesture and a video swipes exactly like a photo.\n if ((e.target as HTMLElement).closest(\"audio\")) return;\n dragRef.current = {\n x0: e.clientX,\n y0: e.clientY,\n t0: performance.now(),\n axis: null,\n pointerId: e.pointerId,\n };\n (e.currentTarget as HTMLElement).setPointerCapture(e.pointerId);\n setSettling(false);\n }, []);\n\n const onPointerMove = useCallback((e: React.PointerEvent) => {\n const d = dragRef.current;\n if (!d || e.pointerId !== d.pointerId) return;\n const dx = e.clientX - d.x0;\n const dy = e.clientY - d.y0;\n if (d.axis === null) {\n if (Math.abs(dx) < DIRECTION_LOCK_PX && Math.abs(dy) < DIRECTION_LOCK_PX)\n return;\n d.axis = Math.abs(dx) >= Math.abs(dy) ? \"x\" : \"y\";\n }\n setDrag(d.axis === \"x\" ? { dx, dy: 0 } : { dx: 0, dy });\n }, []);\n\n const endDrag = useCallback(\n (e: React.PointerEvent) => {\n const d = dragRef.current;\n if (!d || e.pointerId !== d.pointerId) return;\n dragRef.current = null;\n const dx = e.clientX - d.x0;\n const dy = e.clientY - d.y0;\n const dt = Math.max(1, performance.now() - d.t0);\n const vx = dx / dt;\n\n if (d.axis === \"y\" && Math.abs(dy) > DISMISS_TRIGGER_PX) {\n onClose();\n return;\n }\n if (d.axis === \"x\") {\n const flick =\n Math.abs(dx) > 10 && Math.abs(vx) > SWIPE_TRIGGER_VELOCITY;\n if ((dx < -SWIPE_TRIGGER_PX || (flick && dx < 0)) && clamped < count - 1) {\n go(1);\n return;\n }\n if ((dx > SWIPE_TRIGGER_PX || (flick && dx > 0)) && clamped > 0) {\n go(-1);\n return;\n }\n }\n // No direction ever locked = a TAP. On a video slide that toggles\n // playback (the control-less player's one control).\n if (d.axis === null) {\n const video = activeVideoRef.current;\n if (video) {\n if (video.paused) void video.play().catch(() => {});\n else video.pause();\n }\n }\n setDrag(null);\n setSettling(true);\n },\n [clamped, count, go, onClose],\n );\n\n // Mount only ±1 (a 12MP decoded frame is ~48MB — ±2 mounted flirted with\n // iOS jetsam); ±2 still get their URLs primed above, which is the cheap\n // half of the work.\n const neighborKeys = useMemo(() => {\n const wanted: CaptureMediaItem[] = [];\n for (const i of [clamped - 1, clamped + 1]) {\n const m = items[i];\n if (m) wanted.push(m);\n }\n return wanted;\n }, [items, clamped]);\n\n if (!current) return null;\n const canEdit = onEdit && current.kind === \"photo\";\n\n return (\n <div className=\"absolute inset-0 z-40 flex flex-col bg-black\">\n {/* Top bar */}\n <div\n className=\"absolute inset-x-0 top-0 z-20 flex items-center justify-between bg-gradient-to-b from-black/70 to-transparent p-3\"\n style={safeTop}\n >\n <button\n type=\"button\"\n onClick={onClose}\n aria-label=\"Close viewer\"\n className=\"flex h-10 w-10 touch-manipulation items-center justify-center rounded-full text-white transition-colors hover:bg-white/10\"\n >\n <XIcon className=\"h-5 w-5\" />\n </button>\n <span className=\"rounded-full bg-black/50 px-3 py-1 text-sm tabular-nums text-white/90\">\n {clamped + 1} / {count}\n </span>\n <span className=\"flex items-center gap-1\">\n {canEdit ? (\n <button\n type=\"button\"\n onClick={() => onEdit(current)}\n aria-label=\"Edit this photo\"\n className=\"flex h-10 w-10 touch-manipulation items-center justify-center rounded-full text-white transition-colors hover:bg-white/10\"\n >\n <PencilIcon className=\"h-5 w-5\" />\n </button>\n ) : null}\n {onDelete ? (\n <button\n type=\"button\"\n onClick={() => setConfirmingDelete(true)}\n aria-label=\"Delete this file\"\n className=\"flex h-10 w-10 touch-manipulation items-center justify-center rounded-full text-white transition-colors hover:bg-white/10\"\n >\n <Trash2Icon className=\"h-5 w-5\" />\n </button>\n ) : (\n <span className=\"h-10 w-10\" aria-hidden />\n )}\n </span>\n </div>\n\n {/* Stage */}\n <div className=\"relative min-h-0 flex-1 overflow-hidden\">\n <div\n className=\"absolute inset-0 touch-none\"\n style={{\n transform: drag\n ? `translate(${drag.dx}px, ${drag.dy}px)`\n : \"translate(0px, 0px)\",\n transition: settling\n ? \"transform 220ms cubic-bezier(0.2, 0.8, 0.3, 1)\"\n : \"none\",\n opacity: drag?.dy\n ? Math.max(0.4, 1 - Math.abs(drag.dy) / 400)\n : 1,\n }}\n onPointerDown={onPointerDown}\n onPointerMove={onPointerMove}\n onPointerUp={endDrag}\n onPointerCancel={endDrag}\n >\n <ViewerSlide\n key={current.key}\n item={current}\n active\n videoRef={activeVideoRef}\n />\n </div>\n\n {/* Neighbor preload — mounted, invisible, decoded before the swipe. */}\n <div\n aria-hidden\n className=\"pointer-events-none absolute inset-0 opacity-0\"\n >\n {neighborKeys.map((m) => (\n <div key={m.key} className=\"absolute inset-0\">\n <ViewerSlide item={m} active={false} />\n </div>\n ))}\n </div>\n\n {/* Desktop chevrons */}\n {clamped > 0 && (\n <button\n type=\"button\"\n onClick={() => go(-1)}\n aria-label=\"Previous file\"\n className=\"absolute left-2 top-1/2 z-20 hidden h-11 w-11 -translate-y-1/2 items-center justify-center rounded-full bg-black/40 text-white hover:bg-black/60 sm:flex\"\n >\n <ChevronLeftIcon className=\"h-6 w-6\" />\n </button>\n )}\n {clamped < count - 1 && (\n <button\n type=\"button\"\n onClick={() => go(1)}\n aria-label=\"Next file\"\n className=\"absolute right-2 top-1/2 z-20 hidden h-11 w-11 -translate-y-1/2 items-center justify-center rounded-full bg-black/40 text-white hover:bg-black/60 sm:flex\"\n >\n <ChevronRightIcon className=\"h-6 w-6\" />\n </button>\n )}\n </div>\n\n {/* Delete confirmation — names the consequence first. */}\n {confirmingDelete && onDelete && (\n <div\n className=\"absolute inset-x-0 bottom-0 z-30 bg-black/85 px-4 pt-4 backdrop-blur-sm\"\n style={{\n paddingBottom: \"calc(1rem + env(safe-area-inset-bottom, 0px))\",\n }}\n >\n <p className=\"pb-3 text-center text-sm text-white/85\">\n Delete this {current.kind === \"video\" ? \"video\" : current.kind === \"audio\" ? \"voice note\" : \"photo\"}? {deleteConsequence}\n </p>\n <div className=\"flex items-center justify-center gap-3\">\n <button\n type=\"button\"\n onClick={() => setConfirmingDelete(false)}\n className=\"h-11 touch-manipulation rounded-full bg-white/15 px-6 text-sm font-medium text-white\"\n >\n Keep it\n </button>\n <button\n type=\"button\"\n onClick={() => {\n setConfirmingDelete(false);\n onDelete(current);\n }}\n className=\"h-11 touch-manipulation rounded-full bg-[#FF3B30] px-6 text-sm font-semibold text-white\"\n >\n Delete\n </button>\n </div>\n </div>\n )}\n\n {/* Position dots (small counts only) */}\n {count > 1 && count <= 12 && (\n <div\n className=\"pointer-events-none absolute inset-x-0 bottom-4 z-20 flex justify-center gap-1.5\"\n style={safeMarginBottom}\n >\n {items.map((m, i) => (\n <span\n key={m.key}\n className={cn(\n \"h-1.5 w-1.5 rounded-full transition-colors\",\n i === clamped ? \"bg-white\" : \"bg-white/35\",\n )}\n />\n ))}\n </div>\n )}\n </div>\n );\n}\n\nfunction ViewerSlide({\n item,\n active,\n videoRef,\n}: {\n item: CaptureMediaItem;\n active: boolean;\n /** Receives the ACTIVE slide's video element (the tap-to-play target). */\n videoRef?: React.MutableRefObject<HTMLVideoElement | null> | undefined;\n}) {\n const url = useMediaUrl(item);\n if (!url) {\n return active ? (\n <div className=\"absolute inset-0 flex items-center justify-center\">\n <span className=\"h-8 w-8 animate-spin rounded-full border-2 border-white/30 border-t-white\" />\n </div>\n ) : null;\n }\n if (item.kind === \"audio\") {\n if (!active) return null;\n return (\n <div className=\"absolute inset-0 flex flex-col items-center justify-center gap-6 px-8\">\n <svg\n viewBox=\"0 0 24 24\"\n className=\"h-12 w-12 stroke-white/80\"\n fill=\"none\"\n strokeWidth={1.5}\n strokeLinecap=\"round\"\n aria-hidden\n >\n <path d=\"M12 2v12\" />\n <path d=\"M7 6v6M17 6v6M2 9v2M22 9v2\" />\n <circle cx=\"12\" cy=\"19\" r=\"3\" />\n </svg>\n {/* eslint-disable-next-line jsx-a11y/media-has-caption -- a just-recorded voice note has no caption track */}\n <audio src={url} controls className=\"w-full max-w-sm\" />\n </div>\n );\n }\n if (item.kind === \"video\") {\n return <VideoSlide url={url} active={active} videoRef={videoRef} />;\n }\n return (\n <img\n src={url}\n alt=\"\"\n draggable={false}\n decoding={active ? \"auto\" : \"async\"}\n className=\"absolute inset-0 h-full w-full select-none object-contain\"\n />\n );\n}\n\n/**\n * The control-less video slide. Native `controls` made the whole slide a\n * pointer sink — a video could not be swiped like a photo, which is the one\n * behavior a pager must keep uniform. Instead: the STAGE owns every gesture\n * (this element is pointer-events-none), a tap toggles playback, a centre\n * glyph shows the paused state, and a thin bottom bar shows progress.\n */\nfunction VideoSlide({\n url,\n active,\n videoRef,\n}: {\n url: string;\n active: boolean;\n videoRef?: React.MutableRefObject<HTMLVideoElement | null> | undefined;\n}) {\n const [paused, setPaused] = useState(true);\n const [progress, setProgress] = useState(0);\n const localRef = useRef<HTMLVideoElement | null>(null);\n\n // Hand the ACTIVE element to the stage's tap handler; clear on unmount so\n // a swiped-away slide can never receive the next tap.\n useEffect(() => {\n if (!active || !videoRef) return;\n videoRef.current = localRef.current;\n return () => {\n if (videoRef.current === localRef.current) videoRef.current = null;\n };\n }, [active, videoRef]);\n\n return (\n <div className=\"pointer-events-none absolute inset-0\">\n <video\n ref={localRef}\n src={url}\n playsInline\n // Hidden neighbors buffer METADATA only — never whole videos.\n preload={active ? \"auto\" : \"metadata\"}\n muted={!active}\n loop={false}\n onPlay={() => setPaused(false)}\n onPause={() => setPaused(true)}\n onEnded={() => setPaused(true)}\n onTimeUpdate={(e) => {\n const v = e.currentTarget;\n setProgress(v.duration > 0 ? v.currentTime / v.duration : 0);\n }}\n className=\"absolute inset-0 h-full w-full object-contain\"\n />\n {active && paused && (\n <span className=\"absolute inset-0 flex items-center justify-center\">\n <span className=\"flex h-16 w-16 items-center justify-center rounded-full bg-black/45\">\n <PlayIcon className=\"ml-1 h-8 w-8 fill-white text-white\" />\n </span>\n </span>\n )}\n {active && !paused && (\n <span className=\"absolute inset-x-4 bottom-2 h-0.5 overflow-hidden rounded-full bg-white/25\">\n <span\n className=\"block h-full rounded-full bg-white\"\n style={{ width: `${Math.round(progress * 100)}%` }}\n />\n </span>\n )}\n </div>\n );\n}\n","\"use client\";\n\n/**\n * ImageEditSheet — instant in-browser image editing, core to the package\n * (THE CLOUD LAW's sibling: capture without instant edit is half a system).\n * v1 covers the basics that belong in the browser — crop (free + 1:1, 4:3,\n * 16:9 presets), rotate 90°, flip — full-screen dark chrome in the iOS\n * editing style: Cancel/Save top bar, the image letterboxed center, a\n * draggable/resizable crop frame with corner handles, tool row bottom.\n * Heavier AI edits ride host-injected actions, not this sheet.\n *\n * Output is a JPEG re-encode of the ORIGINAL pixels (rotation/flip/crop\n * applied on canvas) — never a screenshot of the preview.\n *\n * Package source (`@ai-matrx/capture`) — browser canvas only, no app deps.\n */\n\nimport React, {\n useCallback,\n useEffect,\n useRef,\n useState,\n} from \"react\";\nimport {\n CheckIcon,\n FlipHorizontal2Icon,\n RotateCcwIcon,\n XIcon,\n} from \"./icons\";\nimport { cn } from \"../cn\";\n\ntype AspectPreset = \"free\" | \"1:1\" | \"4:3\" | \"16:9\";\nconst ASPECTS: { id: AspectPreset; label: string; ratio: number | null }[] = [\n { id: \"free\", label: \"Free\", ratio: null },\n { id: \"1:1\", label: \"Square\", ratio: 1 },\n { id: \"4:3\", label: \"4:3\", ratio: 4 / 3 },\n { id: \"16:9\", label: \"16:9\", ratio: 16 / 9 },\n];\n\n/** Normalized crop rect (0..1) relative to the ROTATED/FLIPPED image. */\ninterface CropRect {\n x: number;\n y: number;\n w: number;\n h: number;\n}\n\nexport interface ImageEditSheetProps {\n open: boolean;\n /** Source image URL (object URL or resolvable src). */\n src: string | null;\n onClose: () => void;\n /** Receives the edited JPEG. The host persists it (cloud port). */\n onSave: (blob: Blob) => void;\n}\n\nconst FULL_CROP: CropRect = { x: 0, y: 0, w: 1, h: 1 };\nconst MIN_CROP = 0.08;\n\nexport function ImageEditSheet({\n open,\n src,\n onClose,\n onSave,\n}: ImageEditSheetProps) {\n // Rotation/flip are BAKED into a working bitmap the moment they are\n // applied (full-res canvas re-encode → object URL). The displayed <img>\n // is therefore always untransformed, so the percentage-positioned crop\n // frame measures exactly the pixels on screen — the earlier CSS\n // `transform: rotate()` approach left the layout box unrotated and the\n // crop frame visibly divergent from the image at 90°/270°.\n const [workingSrc, setWorkingSrc] = useState<string | null>(null);\n const [aspect, setAspect] = useState<AspectPreset>(\"free\");\n const [crop, setCrop] = useState<CropRect>(FULL_CROP);\n const [saving, setSaving] = useState(false);\n const [editError, setEditError] = useState<string | null>(null);\n const stageRef = useRef<HTMLDivElement | null>(null);\n const imgRef = useRef<HTMLImageElement | null>(null);\n // Object URLs THIS sheet minted for baked bitmaps — revoked on replace\n // and on close. The host's `src` is never revoked here.\n const ownedUrlsRef = useRef<string[]>([]);\n const dragRef = useRef<{\n kind: \"move\" | \"nw\" | \"ne\" | \"sw\" | \"se\";\n startX: number;\n startY: number;\n startCrop: CropRect;\n } | null>(null);\n\n const revokeOwned = useCallback(() => {\n for (const url of ownedUrlsRef.current) URL.revokeObjectURL(url);\n ownedUrlsRef.current = [];\n }, []);\n\n useEffect(() => {\n if (open) {\n setWorkingSrc(null);\n setAspect(\"free\");\n setCrop(FULL_CROP);\n setSaving(false);\n setEditError(null);\n }\n return revokeOwned;\n }, [open, src, revokeOwned]);\n\n /** Apply rotate/flip by re-encoding the CURRENT working bitmap. */\n const bake = useCallback(\n (op: \"rotate-left\" | \"flip\") => {\n const img = imgRef.current;\n if (!img || img.naturalWidth === 0 || saving) return;\n try {\n const swap = op === \"rotate-left\";\n const canvas = document.createElement(\"canvas\");\n canvas.width = swap ? img.naturalHeight : img.naturalWidth;\n canvas.height = swap ? img.naturalWidth : img.naturalHeight;\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) throw new Error(\"no 2d context\");\n ctx.translate(canvas.width / 2, canvas.height / 2);\n if (swap) ctx.rotate(-Math.PI / 2);\n else ctx.scale(-1, 1);\n ctx.drawImage(img, -img.naturalWidth / 2, -img.naturalHeight / 2);\n canvas.toBlob(\n (blob) => {\n if (!blob) {\n setEditError(\n \"This image is too large to process on this device.\",\n );\n return;\n }\n revokeOwned();\n const url = URL.createObjectURL(blob);\n ownedUrlsRef.current.push(url);\n setWorkingSrc(url);\n setCrop(FULL_CROP);\n setAspect(\"free\");\n setEditError(null);\n },\n \"image/jpeg\",\n 0.95,\n );\n } catch {\n setEditError(\"This image could not be edited on this device.\");\n }\n },\n [saving, revokeOwned],\n );\n\n const applyAspect = useCallback((preset: AspectPreset) => {\n setAspect(preset);\n const ratio = ASPECTS.find((a) => a.id === preset)?.ratio ?? null;\n if (ratio === null) return;\n // Fit the largest centered rect of the target ratio inside the frame,\n // in DISPLAYED-image normalized space. The working bitmap is always\n // untransformed, so natural dimensions ARE the displayed geometry.\n const img = imgRef.current;\n if (!img || img.naturalWidth === 0) return;\n const imageRatio = img.naturalWidth / img.naturalHeight;\n let w = 1;\n let h = 1;\n if (ratio > imageRatio) h = imageRatio / ratio;\n else w = ratio / imageRatio;\n setCrop({ x: (1 - w) / 2, y: (1 - h) / 2, w, h });\n }, []);\n\n const onPointerDown = useCallback(\n (kind: \"move\" | \"nw\" | \"ne\" | \"sw\" | \"se\") =>\n (e: React.PointerEvent) => {\n e.preventDefault();\n e.stopPropagation();\n (e.target as HTMLElement).setPointerCapture(e.pointerId);\n dragRef.current = {\n kind,\n startX: e.clientX,\n startY: e.clientY,\n startCrop: crop,\n };\n },\n [crop],\n );\n\n const onPointerMove = useCallback(\n (e: React.PointerEvent) => {\n const drag = dragRef.current;\n const img = imgRef.current;\n if (!drag || !img) return;\n const rect = img.getBoundingClientRect();\n if (rect.width === 0 || rect.height === 0) return;\n const dx = (e.clientX - drag.startX) / rect.width;\n const dy = (e.clientY - drag.startY) / rect.height;\n const c = { ...drag.startCrop };\n const ratio = ASPECTS.find((a) => a.id === aspect)?.ratio ?? null;\n const frameRatio = rect.width / rect.height;\n\n if (drag.kind === \"move\") {\n c.x = Math.min(1 - c.w, Math.max(0, c.x + dx));\n c.y = Math.min(1 - c.h, Math.max(0, c.y + dy));\n } else {\n const left = drag.kind === \"nw\" || drag.kind === \"sw\";\n const top = drag.kind === \"nw\" || drag.kind === \"ne\";\n let x2 = c.x + c.w;\n let y2 = c.y + c.h;\n if (left) c.x = Math.min(x2 - MIN_CROP, Math.max(0, c.x + dx));\n else x2 = Math.max(c.x + MIN_CROP, Math.min(1, x2 + dx));\n if (top) c.y = Math.min(y2 - MIN_CROP, Math.max(0, c.y + dy));\n else y2 = Math.max(c.y + MIN_CROP, Math.min(1, y2 + dy));\n c.w = x2 - c.x;\n c.h = y2 - c.y;\n if (ratio !== null) {\n // Lock the ratio by deriving height from width in SCREEN space.\n const targetH = (c.w * frameRatio) / ratio;\n if (top) c.y = y2 - Math.min(targetH, y2);\n c.h = Math.min(targetH, top ? y2 - c.y : 1 - c.y);\n c.w = (c.h * ratio) / frameRatio;\n if (left) c.x = x2 - c.w;\n }\n }\n setCrop(c);\n },\n [aspect],\n );\n\n const onPointerUp = useCallback(() => {\n dragRef.current = null;\n }, []);\n\n const save = useCallback(() => {\n const img = imgRef.current;\n if (!img || img.naturalWidth === 0) return;\n setSaving(true);\n setEditError(null);\n try {\n // Rotation/flip are already baked into the working bitmap — save is\n // a pure crop of what the user sees.\n const canvas = document.createElement(\"canvas\");\n canvas.width = Math.max(1, Math.round(img.naturalWidth * crop.w));\n canvas.height = Math.max(1, Math.round(img.naturalHeight * crop.h));\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) throw new Error(\"no 2d context\");\n ctx.drawImage(img, -crop.x * img.naturalWidth, -crop.y * img.naturalHeight);\n canvas.toBlob(\n (blob) => {\n setSaving(false);\n if (blob) {\n onSave(blob);\n onClose();\n } else {\n // iOS canvas memory limits can yield null on huge frames —\n // Save must never silently do nothing.\n setEditError(\n \"Saving failed on this device — try a smaller crop.\",\n );\n }\n },\n \"image/jpeg\",\n 0.92,\n );\n } catch (err) {\n console.error(\"[capture-camera] edit save failed\", err);\n setSaving(false);\n setEditError(\"Saving failed on this device — try again.\");\n }\n }, [crop, onSave, onClose]);\n\n if (!open || !src) return null;\n\n return (\n <div className=\"absolute inset-0 z-50 flex flex-col bg-black\">\n {/* Top bar */}\n <div\n className=\"flex shrink-0 items-center justify-between px-4\"\n style={{ paddingTop: \"env(safe-area-inset-top, 0px)\" }}\n >\n <button\n type=\"button\"\n onClick={onClose}\n aria-label=\"Cancel editing\"\n className=\"flex h-11 items-center gap-1.5 rounded-full px-3 text-[15px] font-medium text-white\"\n >\n <XIcon className=\"h-5 w-5\" />\n Cancel\n </button>\n <span className=\"text-[15px] font-semibold text-white/90\">Edit</span>\n <button\n type=\"button\"\n onClick={save}\n disabled={saving}\n aria-label=\"Save edited image\"\n className=\"flex h-11 items-center gap-1.5 rounded-full px-3 text-[15px] font-semibold text-[#FFCC00] disabled:opacity-50\"\n >\n <CheckIcon className=\"h-5 w-5\" />\n Save\n </button>\n </div>\n\n {/* Stage */}\n <div\n ref={stageRef}\n className=\"relative flex min-h-0 flex-1 items-center justify-center overflow-hidden p-4\"\n onPointerMove={onPointerMove}\n onPointerUp={onPointerUp}\n onPointerCancel={onPointerUp}\n >\n <div className=\"relative max-h-full max-w-full\">\n {/* eslint-disable-next-line @next/next/no-img-element -- local object URL being edited */}\n <img\n ref={imgRef}\n src={workingSrc ?? src}\n alt=\"Image being edited\"\n draggable={false}\n className=\"max-h-[62dvh] max-w-full select-none object-contain\"\n />\n {/* Crop frame in displayed-image space */}\n <div\n role=\"presentation\"\n onPointerDown={onPointerDown(\"move\")}\n className=\"absolute cursor-move touch-none border-2 border-white shadow-[0_0_0_9999px_rgba(0,0,0,0.55)]\"\n style={{\n left: `${crop.x * 100}%`,\n top: `${crop.y * 100}%`,\n width: `${crop.w * 100}%`,\n height: `${crop.h * 100}%`,\n }}\n >\n {([\"nw\", \"ne\", \"sw\", \"se\"] as const).map((corner) => (\n <span\n key={corner}\n role=\"presentation\"\n onPointerDown={onPointerDown(corner)}\n className={cn(\n \"absolute h-6 w-6 touch-none\",\n corner === \"nw\" &&\n \"-left-1.5 -top-1.5 border-l-4 border-t-4 cursor-nwse-resize\",\n corner === \"ne\" &&\n \"-right-1.5 -top-1.5 border-r-4 border-t-4 cursor-nesw-resize\",\n corner === \"sw\" &&\n \"-bottom-1.5 -left-1.5 border-b-4 border-l-4 cursor-nesw-resize\",\n corner === \"se\" &&\n \"-bottom-1.5 -right-1.5 border-b-4 border-r-4 cursor-nwse-resize\",\n \"border-white\",\n )}\n />\n ))}\n </div>\n </div>\n </div>\n\n {/* Tool row */}\n <div className=\"shrink-0\" style={{ paddingBottom: \"env(safe-area-inset-bottom, 0px)\" }}>\n {editError && (\n <p className=\"px-6 pb-2 text-center text-sm text-[#FF6961]\">\n {editError}\n </p>\n )}\n <div className=\"flex items-center justify-center gap-2 pb-2\">\n {ASPECTS.map((a) => (\n <button\n key={a.id}\n type=\"button\"\n onClick={() => applyAspect(a.id)}\n aria-pressed={aspect === a.id}\n className={cn(\n \"touch-manipulation rounded-full px-3.5 py-1.5 text-[12px] font-semibold uppercase tracking-wide transition-colors\",\n aspect === a.id\n ? \"bg-white/20 text-[#FFCC00]\"\n : \"text-white/80\",\n )}\n >\n {a.label}\n </button>\n ))}\n </div>\n <div className=\"flex items-center justify-center gap-6 pb-4\">\n <button\n type=\"button\"\n onClick={() => bake(\"rotate-left\")}\n aria-label=\"Rotate left\"\n className=\"flex h-12 w-12 touch-manipulation items-center justify-center rounded-full bg-white/10 text-white\"\n >\n <RotateCcwIcon className=\"h-5 w-5\" />\n </button>\n <button\n type=\"button\"\n onClick={() => bake(\"flip\")}\n aria-label=\"Flip horizontally\"\n className=\"flex h-12 w-12 touch-manipulation items-center justify-center rounded-full bg-white/10 text-white\"\n >\n <FlipHorizontal2Icon className=\"h-5 w-5\" />\n </button>\n </div>\n </div>\n </div>\n );\n}\n","\"use client\";\n\n/**\n * CameraCaptureV3 — the vertical-rail camera chrome.\n *\n * A SECOND chrome over the same ports as `CameraCapture`, not a replacement.\n * Same engine, same cloud port, same package-owned review loop (filmstrip →\n * viewer → editor). What differs is the layout and the input model, and every\n * difference answers something the v2 chrome got wrong on a real phone\n * (Arman, 2026-08-30):\n *\n * ONE SHUTTER. Tap = photo, press-and-hold = video. v2 spent a whole\n * row on a mode selector, so the user paid bar height AND\n * a decision before the moment they were trying to catch.\n * THE RIGHT EDGE. Options live on a rail over the feed instead of a\n * two-tap grid behind a button. No layout cost, one tap\n * to anything, and the viewfinder stays whole.\n * IT COLLAPSES. Extras hide behind a chevron so the idle rail is short.\n * TEXT IS A BUTTON. Entry expands from a pill (see CaptureExpandingField) —\n * no permanent field, no keyboard-bait over the frame.\n * ONE MEDIA DOOR. There is no UPLOAD mode. The library button is the only\n * way to existing media, and picking files is an option\n * INSIDE that drawer — the host renders it there.\n *\n * Deliberately NOT copied from the app this borrows its shape from: fixed\n * duration choices (they belong to that product's format, not to a camera),\n * and the oversized promo pill for a new feature (chrome is not a billboard).\n *\n * Package source (`@ai-matrx/capture`). UI state only — capture, streams and\n * persistence come from the injected engine.\n */\n\nimport React, { useCallback, useEffect, useRef, useState } from \"react\";\nimport {\n Grid3x3Icon,\n ImagesIcon,\n ProportionsIcon,\n RefreshCwIcon,\n SunMediumIcon,\n TimerIcon,\n XIcon,\n ZapIcon,\n ZapOffIcon,\n} from \"./icons\";\nimport { cn } from \"../cn\";\nimport { safeTop, safeBottom } from \"../safe-area\";\n\nimport type {\n CaptureAspect,\n CaptureCameraEngine,\n CaptureCameraV3Slots,\n CaptureCloudPort,\n CaptureRailAction,\n CaptureTimerSetting,\n} from \"../types\";\nimport { CaptureRail } from \"./CaptureRail\";\nimport { CaptureSheet, type CaptureSheetAction } from \"./CaptureSheet\";\nimport { CaptureFilmstrip } from \"./CaptureFilmstrip\";\nimport { CountdownOverlay } from \"./CountdownOverlay\";\nimport { GridOverlay } from \"./GridOverlay\";\nimport { HoldShutter } from \"./HoldShutter\";\nimport { ImageEditSheet } from \"./ImageEditSheet\";\nimport { MediaViewer } from \"./MediaViewer\";\nimport { getMediaUrl, invalidateMedia } from \"../media/media-cache\";\nimport { useTrackControls } from \"../hooks/useTrackControls\";\nimport type { CaptureMediaSession } from \"./CameraCapture\";\n\nconst ASPECT_CYCLE: CaptureAspect[] = [\"full\", \"4:3\", \"1:1\", \"16:9\"];\n\nexport interface CameraCaptureV3Props {\n engine: CaptureCameraEngine;\n /** THE CLOUD LAW: still required. v3 changes where the door is, not whether\n * there is one — and in v3 it is the ONLY door to existing media. */\n cloud: CaptureCloudPort;\n preview: React.ReactNode;\n media?: CaptureMediaSession;\n /**\n * Fired on pointer-DOWN, before the hold threshold decides photo vs video.\n *\n * 🚨 THIS EXISTS FOR iOS. Hosts warm the microphone when they believe a\n * recording is coming (one permission prompt per medium). With a mode row\n * that signal arrived when the user chose VIDEO — early. With a hold\n * shutter there is no such moment, so waiting for the recording to actually\n * start means warming DURING the take, which on iOS Safari costs the first\n * second of audio or throws a prompt over the viewfinder mid-recording.\n *\n * The host is expected to make this idempotent: it fires on every press,\n * including the taps that turn out to be photos.\n */\n onRecordIntent?: () => void;\n /** Ring completes here; presentational only — it never stops the recorder. */\n maxRecordSeconds?: number;\n onReviewOpenChange?: (open: boolean) => void;\n onClose?: () => void;\n blockedSheet?: { body: React.ReactNode; actions: CaptureSheetAction[] };\n /** Hide all chrome except status chips (host renders its own toggle). */\n controlsHidden?: boolean;\n shutterDisabled?: boolean;\n slots?: CaptureCameraV3Slots;\n}\n\nexport function CameraCaptureV3({\n engine,\n cloud,\n preview,\n media,\n onRecordIntent,\n maxRecordSeconds,\n onReviewOpenChange,\n onClose,\n blockedSheet,\n controlsHidden = false,\n shutterDisabled = false,\n slots = {},\n}: CameraCaptureV3Props) {\n const [viewerKey, setViewerKey] = useState<string | null>(null);\n const [editTarget, setEditTarget] = useState<{ key: string; url: string } | null>(\n null,\n );\n const [gridOn, setGridOn] = useState(false);\n const [timerSetting, setTimerSetting] = useState<CaptureTimerSetting>(0);\n const [aspect, setAspect] = useState<CaptureAspect>(\"full\");\n const [countdown, setCountdown] = useState<number | null>(null);\n const [blockedDismissed, setBlockedDismissed] = useState(false);\n const countdownRef = useRef<ReturnType<typeof setInterval> | null>(null);\n\n const controls = useTrackControls(engine.stream);\n\n const reviewOpen = viewerKey !== null || editTarget !== null;\n useEffect(() => {\n onReviewOpenChange?.(reviewOpen);\n }, [reviewOpen, onReviewOpenChange]);\n\n const clearCountdown = useCallback(() => {\n if (countdownRef.current) clearInterval(countdownRef.current);\n countdownRef.current = null;\n setCountdown(null);\n }, []);\n useEffect(() => clearCountdown, [clearCountdown]);\n // A countdown must never survive into a recording — it would fire a photo\n // capture mid-take (the v2 bug, kept fixed here).\n useEffect(() => {\n if (engine.recording) clearCountdown();\n }, [engine.recording, clearCountdown]);\n\n const onPhoto = useCallback(() => {\n if (countdown !== null) {\n clearCountdown(); // tapping mid-countdown cancels\n return;\n }\n if (timerSetting === 0) {\n engine.onCapturePhoto({ aspect });\n return;\n }\n let remaining = timerSetting;\n setCountdown(remaining);\n countdownRef.current = setInterval(() => {\n remaining -= 1;\n if (remaining <= 0) {\n clearCountdown();\n engine.onCapturePhoto({ aspect });\n } else {\n setCountdown(remaining);\n }\n }, 1000);\n }, [aspect, clearCountdown, countdown, engine, timerSetting]);\n\n const blocked = engine.blocked !== null;\n\n // ── The rail ───────────────────────────────────────────────────────────\n // Primary (always visible): flip and flash — the two a user reaches for\n // without thinking. Everything else collapses.\n const coreRail: CaptureRailAction[] = [\n ...(engine.onFlipCamera\n ? [\n {\n id: \"flip\",\n label: \"Switch camera\",\n icon: <RefreshCwIcon className=\"h-[22px] w-[22px]\" />,\n primary: true,\n onPress: engine.onFlipCamera,\n },\n ]\n : []),\n ...(controls.torchSupported\n ? [\n {\n id: \"flash\",\n label: \"Flash\",\n icon: controls.torchOn ? (\n <ZapIcon className=\"h-[22px] w-[22px]\" fill=\"currentColor\" />\n ) : (\n <ZapOffIcon className=\"h-[22px] w-[22px]\" />\n ),\n active: controls.torchOn,\n primary: true,\n onPress: controls.toggleTorch,\n },\n ]\n : []),\n {\n id: \"timer\",\n label: \"Timer\",\n icon: <TimerIcon className=\"h-[22px] w-[22px]\" />,\n active: timerSetting !== 0,\n valueLabel: timerSetting === 0 ? undefined : `${timerSetting}s`,\n onPress: () => setTimerSetting((t) => (t === 0 ? 3 : t === 3 ? 10 : 0)),\n },\n {\n id: \"grid\",\n label: \"Grid\",\n icon: <Grid3x3Icon className=\"h-[22px] w-[22px]\" />,\n active: gridOn,\n onPress: () => setGridOn((g) => !g),\n },\n {\n id: \"aspect\",\n label: \"Aspect\",\n icon: <ProportionsIcon className=\"h-[22px] w-[22px]\" />,\n active: aspect !== \"full\",\n valueLabel: aspect === \"full\" ? undefined : aspect,\n onPress: () =>\n setAspect(\n (a) =>\n ASPECT_CYCLE[(ASPECT_CYCLE.indexOf(a) + 1) % ASPECT_CYCLE.length] ??\n \"full\",\n ),\n },\n ...(controls.exposureSupported\n ? [\n {\n id: \"exposure\",\n label: \"Exposure\",\n icon: <SunMediumIcon className=\"h-[22px] w-[22px]\" />,\n active: controls.exposure !== 0,\n valueLabel:\n controls.exposure === 0\n ? undefined\n : `${controls.exposure > 0 ? \"+\" : \"\"}${controls.exposure}`,\n onPress: () => controls.setExposure(controls.exposure === 0 ? 1 : 0),\n },\n ]\n : []),\n ];\n // A blocked camera disables the CORE actions (they steer hardware that is\n // not there) but the rail itself stays: host actions keep working through\n // the upload lane.\n const railActions = [\n ...coreRail.map((a) => (blocked ? { ...a, disabled: true } : a)),\n ...(slots.railActions ?? []),\n ];\n\n return (\n <div className=\"absolute inset-0 select-none overflow-hidden bg-black\">\n <div className=\"absolute inset-0\">{preview}</div>\n <GridOverlay visible={gridOn && !blocked} />\n\n {/* Aspect framing hint — the dimmed bands approximate the region the\n photo will discard. Never shown while recording: video is not\n cropped, so the bands would be a lie about the take in progress. */}\n {aspect !== \"full\" && !blocked && !engine.recording && (\n <div\n aria-hidden\n className=\"pointer-events-none absolute inset-0 z-10 flex items-center justify-center\"\n >\n <div\n className=\"shadow-[0_0_0_9999px_rgba(0,0,0,0.45)]\"\n style={{\n aspectRatio:\n aspect === \"1:1\" ? \"1 / 1\" : aspect === \"4:3\" ? \"3 / 4\" : \"9 / 16\",\n width: aspect === \"16:9\" ? \"100%\" : undefined,\n height: aspect === \"16:9\" ? undefined : \"70%\",\n maxWidth: \"100%\",\n maxHeight: \"100%\",\n }}\n />\n </div>\n )}\n <CountdownOverlay seconds={countdown} />\n\n {/* ── Top row: no bar. Controls float over the feed so the viewfinder\n keeps its full height — the single biggest v2 complaint. ── */}\n {!controlsHidden && (\n <div\n className=\"pointer-events-none absolute inset-x-0 top-0 z-20 px-2\"\n style={safeTop}\n >\n <div className=\"flex min-h-[44px] items-center gap-2 py-1.5\">\n {onClose ? (\n <button\n type=\"button\"\n onClick={onClose}\n aria-label=\"Close camera\"\n className=\"pointer-events-auto flex h-10 w-10 shrink-0 touch-manipulation items-center justify-center rounded-full text-white drop-shadow-[0_1px_3px_rgba(0,0,0,0.6)] transition-colors hover:bg-white/10\"\n >\n <XIcon className=\"h-6 w-6\" />\n </button>\n ) : (\n <span className=\"h-10 w-10 shrink-0\" />\n )}\n\n {/* The expanding entry sits centre-top, where the eye already is\n and where a keyboard rising will not cover it. */}\n <div className=\"pointer-events-auto flex min-w-0 flex-1 justify-center\">\n {slots.topEntry}\n </div>\n\n <span className=\"h-10 w-10 shrink-0\" />\n </div>\n\n {slots.topCenter ? (\n <div className=\"pointer-events-none pb-1 text-center\">\n {slots.topCenter}\n </div>\n ) : null}\n </div>\n )}\n\n {/* Honesty chips stay visible even with controls hidden — they are the\n camera telling the truth, not chrome. */}\n {slots.statusChips ? (\n <div\n className=\"pointer-events-none absolute inset-x-0 z-20 flex flex-col items-center gap-1.5 px-3\"\n style={{\n // Clears the top row AND the topCenter line beneath it — chips\n // rendered at the label's own height read as a collision.\n top: `calc(env(safe-area-inset-top, 0px) + ${\n controlsHidden ? 12 : slots.topCenter ? 92 : 64\n }px)`,\n }}\n >\n {slots.statusChips}\n </div>\n ) : null}\n\n {/* ── The right rail. Rendered even when the camera is BLOCKED: host\n actions (notes, QR, process) are not camera controls and keep\n working through the upload lane — only the core camera actions\n disable (they are built with `disabled: blocked` above). ── */}\n {!controlsHidden && (\n <div\n className=\"pointer-events-none absolute right-1 z-20 flex justify-end\"\n style={{ top: `calc(env(safe-area-inset-top, 0px) + 64px)` }}\n >\n <CaptureRail actions={railActions} />\n </div>\n )}\n\n {/* ── Bottom: filmstrip over the feed, then the shutter row ── */}\n {!controlsHidden && (\n <div className=\"absolute inset-x-0 bottom-0 z-20\" style={safeBottom}>\n {/* The session's captures, over the feed — same package-owned strip\n v2 renders, so the review loop is identical across chromes. */}\n {media && media.items.length > 0 ? (\n <div className=\"px-2 pb-1.5\">\n <CaptureFilmstrip\n items={media.items}\n onOpen={(item) => setViewerKey(item.key)}\n />\n </div>\n ) : null}\n {slots.aboveShutter ? (\n <div className=\"px-2 pb-1.5\">{slots.aboveShutter}</div>\n ) : null}\n\n <div className=\"flex items-center justify-between px-3 pb-2\">\n {/* ONE door to existing media. There is no upload lane here by\n design — the host's library drawer carries the \"pick files\"\n option, so a user has one place to look instead of two\n controls that both mean \"media I already have\". */}\n <div className=\"flex w-[86px] justify-start\">\n <button\n type=\"button\"\n onClick={cloud.onOpenLibrary}\n aria-label=\"Your media — library and upload\"\n className=\"relative h-12 w-12 touch-manipulation overflow-hidden rounded-xl bg-black/40 ring-1 ring-white/30 backdrop-blur-md transition-transform active:scale-95\"\n >\n {cloud.recentsThumb ?? (\n <span className=\"flex h-full w-full items-center justify-center\">\n <ImagesIcon className=\"h-5 w-5 text-white/80\" />\n </span>\n )}\n </button>\n </div>\n\n <HoldShutter\n recording={engine.recording}\n elapsedSeconds={engine.recordElapsedSeconds}\n {...(maxRecordSeconds !== undefined\n ? { maxSeconds: maxRecordSeconds }\n : {})}\n disabled={shutterDisabled || blocked}\n {...(onRecordIntent ? { onPressStart: onRecordIntent } : {})}\n onPhoto={onPhoto}\n onStartRecording={engine.onStartRecording}\n onStopRecording={engine.onStopRecording}\n />\n\n <div className=\"flex w-[86px] justify-end\">\n {slots.shutterTrailing}\n </div>\n </div>\n\n {/* The gesture, stated once. A single-button camera is only obvious\n to the person who built it. */}\n {!engine.recording && !blocked ? (\n <p className=\"pb-1.5 text-center text-[11px] text-white/60 drop-shadow-[0_1px_2px_rgba(0,0,0,0.8)]\">\n Tap for a photo · hold to record\n </p>\n ) : null}\n </div>\n )}\n\n {blocked && blockedSheet && !blockedDismissed && (\n <CaptureSheet\n open\n onClose={() => setBlockedDismissed(true)}\n body={blockedSheet.body}\n title=\"Camera unavailable\"\n actions={blockedSheet.actions}\n />\n )}\n\n {media && viewerKey !== null && (\n <MediaViewer\n items={media.items}\n initialKey={viewerKey}\n keysDisabled={editTarget !== null}\n onClose={() => setViewerKey(null)}\n onDelete={\n media.onDelete\n ? (item) => {\n media.onDelete?.(item.key);\n invalidateMedia(item.key);\n }\n : undefined\n }\n onEdit={\n media.onReplacePhoto\n ? (item) => {\n const url = getMediaUrl(item);\n if (url) setEditTarget({ key: item.key, url });\n }\n : undefined\n }\n />\n )}\n {media?.onReplacePhoto && (\n <ImageEditSheet\n open={editTarget !== null}\n src={editTarget?.url ?? null}\n onClose={() => setEditTarget(null)}\n onSave={(blob) => {\n const target = editTarget;\n setEditTarget(null);\n setViewerKey(null);\n if (target) {\n media.onReplacePhoto?.(target.key, blob);\n invalidateMedia(target.key);\n }\n }}\n />\n )}\n\n {slots.overlays}\n </div>\n );\n}\n","\"use client\";\n\n/**\n * CaptureRail — the vertical action rail down the RIGHT edge of the frame.\n *\n * Why the edge and not a bar: a bottom bar steals height from the viewfinder\n * on every phone, and the options grid it fed cost two taps to reach anything.\n * A rail sits over the feed, costs no layout, and puts every option one tap\n * away under the thumb that is already holding the phone.\n *\n * Why it collapses: a complete rail is a long rail, and a long rail is a wall\n * of icons nobody reads. Actions marked `primary` stay; the rest hide behind a\n * chevron. The chevron is only rendered when there is something to hide —\n * a control that toggles nothing is a lie about the interface.\n *\n * Presentational only.\n */\n\nimport React, { useState } from \"react\";\nimport { cn } from \"../cn\";\nimport type { CaptureRailAction } from \"../types\";\n\nexport interface CaptureRailProps {\n actions: CaptureRailAction[];\n /** Start expanded. Default false — an idle camera shows the short rail. */\n defaultExpanded?: boolean;\n className?: string;\n}\n\nexport function CaptureRail({\n actions,\n defaultExpanded = false,\n className,\n}: CaptureRailProps) {\n const [expanded, setExpanded] = useState(defaultExpanded);\n\n const primary = actions.filter((a) => a.primary);\n const extra = actions.filter((a) => !a.primary);\n // With nothing marked primary, the whole rail is always-on rather than\n // collapsing to nothing — a rail that can hide everything reads as broken.\n const shown = primary.length === 0 ? actions : expanded ? actions : primary;\n const collapsible = primary.length > 0 && extra.length > 0;\n\n if (actions.length === 0) return null;\n\n return (\n <div\n className={cn(\n \"pointer-events-auto flex flex-col items-center gap-1\",\n className,\n )}\n >\n {shown.map((action) => (\n <RailButton key={action.id} action={action} />\n ))}\n\n {collapsible ? (\n <button\n type=\"button\"\n onClick={() => setExpanded((open) => !open)}\n aria-expanded={expanded}\n aria-label={expanded ? \"Fewer options\" : \"More options\"}\n className={cn(\n \"mt-0.5 flex h-9 w-9 touch-manipulation items-center justify-center\",\n \"rounded-full text-white/90 transition-colors hover:bg-white/10\",\n )}\n >\n <Chevron\n className={cn(\n \"h-5 w-5 transition-transform duration-200\",\n expanded && \"rotate-180\",\n )}\n />\n </button>\n ) : null}\n </div>\n );\n}\n\nfunction RailButton({ action }: { action: CaptureRailAction }) {\n return (\n <button\n type=\"button\"\n onClick={action.onPress}\n disabled={action.disabled}\n aria-label={action.label}\n aria-pressed={action.active ?? undefined}\n className={cn(\n \"flex w-12 shrink-0 touch-manipulation flex-col items-center justify-center gap-0.5\",\n \"rounded-2xl py-1.5 transition-colors\",\n action.active ? \"text-[#FFCC00]\" : \"text-white\",\n action.disabled ? \"opacity-40\" : \"hover:bg-white/10 active:bg-white/15\",\n )}\n >\n {/* The icon carries a shadow rather than a plate: a chip per action turns\n the rail into a stack of boxes over the picture the user is framing. */}\n <span className=\"drop-shadow-[0_1px_3px_rgba(0,0,0,0.6)]\">\n {action.icon}\n </span>\n {action.valueLabel ? (\n <span className=\"text-[10px] font-semibold leading-none tabular-nums drop-shadow-[0_1px_2px_rgba(0,0,0,0.7)]\">\n {action.valueLabel}\n </span>\n ) : null}\n </button>\n );\n}\n\n/** Inlined so the package keeps zero icon dependencies. */\nfunction Chevron({ className }: { className?: string }) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={className}\n aria-hidden=\"true\"\n >\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n );\n}\n","\"use client\";\n\n/**\n * HoldShutter — ONE button for photo and video.\n *\n * Tap takes a photo. Press and hold records, and releasing stops. The mode is\n * therefore a gesture, not a control you must set before the moment you are\n * trying to catch — which is the whole reason the v2 mode row was wrong on a\n * phone: it cost bar height AND a decision, and the decision was usually made\n * after the thing had happened.\n *\n * The interaction, precisely:\n *\n * pointerdown → arm a hold timer (HOLD_MS)\n * timer fires → start recording, ring begins filling\n * pointerup < HOLD_MS → cancel the timer, take a photo\n * pointerup >= HOLD_MS → stop recording (recording follows the finger)\n * slide up ≥ LOCK_DRAG_PX while holding → LOCK: release keeps recording,\n * the next tap stops\n * pointercancel / leave → same as pointerup (a drag off the button must not\n * leave the camera recording with nothing to stop it)\n *\n * A LOCK is a GESTURE, never a timer (Arman, 2026-08-30: recording follows\n * the finger — releasing stops, full stop — unless the user deliberately\n * locks): while holding a recording, slide UP to the lock target that\n * appears above the button. Locked, release keeps recording and the next\n * tap stops. An automatic time-based latch shipped first and was wrong —\n * it silently converted \"I let go\" into \"still recording\".\n *\n * Presentational only — the host owns the recorder.\n */\n\nimport React, { useCallback, useEffect, useRef, useState } from \"react\";\nimport {\n LockIcon,\n} from \"./icons\";\nimport { cn } from \"../cn\";\n\n/** Hold this long before a press becomes a recording. */\nconst HOLD_MS = 320;\n/** Slide the held finger this far UP to lock the recording. */\nconst LOCK_DRAG_PX = 64;\n\nexport interface HoldShutterProps {\n recording: boolean;\n /** Elapsed recording seconds, for the ring + read-out. */\n elapsedSeconds: number;\n /**\n * Ring completes at this many seconds. Presentational only — it does not\n * stop the recorder, because a chrome that silently ends a take is worse\n * than one that shows a full ring. Omit for no progress arc.\n */\n maxSeconds?: number;\n disabled?: boolean;\n /**\n * Fired on pointer-DOWN, before the hold threshold decides photo vs video.\n * Hosts use it to warm the microphone — see `CameraCaptureV3Props`.\n */\n onPressStart?: () => void;\n onPhoto: () => void;\n onStartRecording: () => void;\n onStopRecording: () => void;\n}\n\nexport function HoldShutter({\n recording,\n elapsedSeconds,\n maxSeconds,\n disabled = false,\n onPressStart,\n onPhoto,\n onStartRecording,\n onStopRecording,\n}: HoldShutterProps) {\n const holdTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n const startedRecording = useRef(false);\n const pressOriginY = useRef(0);\n const [pressed, setPressed] = useState(false);\n const [locked, setLocked] = useState(false);\n\n const clearHold = useCallback(() => {\n if (holdTimer.current !== null) {\n clearTimeout(holdTimer.current);\n holdTimer.current = null;\n }\n }, []);\n\n // An externally-stopped recording (mode change, error, host abort) must\n // always unlatch.\n useEffect(() => {\n if (!recording) setLocked(false);\n }, [recording]);\n\n useEffect(() => clearHold, [clearHold]);\n\n const onPointerDown = useCallback(\n (event: React.PointerEvent<HTMLButtonElement>) => {\n if (disabled) return;\n // Keep receiving move/up even if the finger slides off the button.\n event.currentTarget.setPointerCapture?.(event.pointerId);\n pressOriginY.current = event.clientY;\n setPressed(true);\n onPressStart?.();\n\n // Locked: this press is a STOP, decided on release so a tap-and-hold\n // does not stop and immediately restart.\n if (recording && locked) return;\n\n startedRecording.current = false;\n holdTimer.current = setTimeout(() => {\n holdTimer.current = null;\n startedRecording.current = true;\n onStartRecording();\n }, HOLD_MS);\n },\n [disabled, locked, onPressStart, onStartRecording, recording],\n );\n\n // Slide-to-lock: while THIS press is recording, dragging up past the lock\n // target latches the take.\n const onPointerMove = useCallback(\n (event: React.PointerEvent<HTMLButtonElement>) => {\n if (!pressed || locked || !startedRecording.current) return;\n if (pressOriginY.current - event.clientY >= LOCK_DRAG_PX) {\n setLocked(true);\n navigator.vibrate?.(30);\n }\n },\n [pressed, locked],\n );\n\n const endPress = useCallback(() => {\n if (!pressed) return;\n setPressed(false);\n const wasHold = startedRecording.current;\n clearHold();\n startedRecording.current = false;\n\n if (recording && locked && !wasHold) {\n onStopRecording();\n return;\n }\n if (wasHold) {\n // Recording follows the finger: release stops — unless the user slid\n // up to the lock during this press.\n if (!locked) onStopRecording();\n return;\n }\n if (!recording) onPhoto();\n }, [clearHold, locked, onPhoto, onStopRecording, pressed, recording]);\n\n const progress =\n maxSeconds && maxSeconds > 0\n ? Math.min(1, elapsedSeconds / maxSeconds)\n : 0;\n\n // 74px button, 3.5px ring — the arc rides just outside the border.\n const R = 39;\n const C = 2 * Math.PI * R;\n\n return (\n <div className=\"relative flex h-[86px] w-[86px] shrink-0 items-center justify-center\">\n {recording && maxSeconds ? (\n <svg\n className=\"pointer-events-none absolute inset-0 -rotate-90\"\n viewBox=\"0 0 86 86\"\n aria-hidden=\"true\"\n >\n <circle\n cx=\"43\"\n cy=\"43\"\n r={R}\n fill=\"none\"\n stroke=\"rgba(255,255,255,0.25)\"\n strokeWidth=\"4\"\n />\n <circle\n cx=\"43\"\n cy=\"43\"\n r={R}\n fill=\"none\"\n stroke=\"#FF3B30\"\n strokeWidth=\"4\"\n strokeLinecap=\"round\"\n strokeDasharray={C}\n strokeDashoffset={C * (1 - progress)}\n />\n </svg>\n ) : null}\n\n {/* The lock target — appears above the button while an UNLOCKED\n recording is held; sliding the finger up to it latches the take. */}\n {recording && pressed && !locked && (\n <span\n className=\"pointer-events-none absolute left-1/2 flex -translate-x-1/2 flex-col items-center gap-0.5\"\n style={{ top: -LOCK_DRAG_PX - 22 }}\n aria-hidden\n >\n <span className=\"flex h-9 w-9 items-center justify-center rounded-full bg-black/60 ring-1 ring-white/30\">\n <LockIcon className=\"h-4 w-4 text-white/90\" />\n </span>\n <span className=\"text-[10px] font-medium text-white/80 drop-shadow\">\n Slide up to lock\n </span>\n </span>\n )}\n {recording && locked && (\n <span\n className=\"pointer-events-none absolute left-1/2 flex h-9 w-9 -translate-x-1/2 items-center justify-center rounded-full bg-[#FF3B30]\"\n style={{ top: -LOCK_DRAG_PX - 22 }}\n aria-hidden\n >\n <LockIcon className=\"h-4 w-4 text-white\" fill=\"currentColor\" />\n </span>\n )}\n\n <button\n type=\"button\"\n disabled={disabled}\n onPointerDown={onPointerDown}\n onPointerMove={onPointerMove}\n onPointerUp={endPress}\n onPointerCancel={endPress}\n onLostPointerCapture={endPress}\n // The press IS the gesture; a click would fire a second photo after\n // pointerup on desktop.\n onContextMenu={(e) => e.preventDefault()}\n aria-label={\n recording\n ? locked\n ? \"Stop recording\"\n : \"Recording — release to stop\"\n : \"Tap for a photo, hold to record\"\n }\n className={cn(\n \"group flex h-[74px] w-[74px] shrink-0 touch-none select-none items-center justify-center\",\n \"rounded-full border-[3.5px] border-white transition-opacity\",\n disabled && \"opacity-30\",\n )}\n >\n <span\n className={cn(\n \"block transition-all duration-200 ease-out\",\n recording\n ? \"h-7 w-7 rounded-[6px] bg-[#FF3B30]\"\n : cn(\n \"h-[62px] w-[62px] rounded-full bg-white\",\n pressed && \"scale-90\",\n ),\n )}\n />\n </button>\n\n {recording ? (\n <span\n className={cn(\n \"pointer-events-none absolute -bottom-1 left-1/2 -translate-x-1/2 translate-y-full\",\n \"rounded-full bg-black/60 px-2 py-0.5 text-[11px] font-medium tabular-nums text-white\",\n )}\n >\n {formatElapsed(elapsedSeconds)}\n {locked ? \" · tap to stop\" : \"\"}\n </span>\n ) : null}\n </div>\n );\n}\n\nfunction formatElapsed(totalSeconds: number): string {\n const m = Math.floor(totalSeconds / 60);\n const s = String(Math.floor(totalSeconds % 60)).padStart(2, \"0\");\n return `${m}:${s}`;\n}\n","\"use client\";\n\n/**\n * CaptureExpandingField — a pill BUTTON that becomes a text field on press,\n * and goes back to being a button when it is done.\n *\n * 🚨 WHY IT IS NOT AN INPUT (Arman, 2026-08-30). v2 pinned a live `<input>` in\n * the bottom bar. On a camera that is wrong three ways: it occupies a row\n * permanently for something used occasionally, it invites the keyboard over\n * the viewfinder on an accidental tap, and it makes an idle camera look like a\n * form. The pattern that fits is the one Apple uses for search — a compact\n * control that admits it is a control, and grows only when you mean it.\n *\n * COMMIT ON UNMOUNT, always. The v2 input already learned this the hard way:\n * hiding the controls or switching item remounts the field, `onBlur` never\n * fires, and a typed value evaporates. Anything typed is committed on the way\n * out, whatever caused the exit.\n *\n * Presentational + local draft state only; the host owns what a value means.\n */\n\nimport React, { useCallback, useEffect, useRef, useState } from \"react\";\nimport { cn } from \"../cn\";\n\nexport interface CaptureExpandingFieldProps {\n /** Collapsed label, e.g. \"Serial / tag\". Also the accessible name. */\n label: string;\n /** Placeholder once expanded. Defaults to `label`. */\n placeholder?: string;\n /** Icon shown in the collapsed pill and at the field's leading edge. */\n icon?: React.ReactNode;\n /** Commit a non-empty trimmed value. Called on Enter, blur, and unmount. */\n onCommit: (value: string) => void;\n /** Start expanded (a host that knows entry is imminent). */\n defaultExpanded?: boolean;\n disabled?: boolean;\n /** Shown in the collapsed pill instead of `label` — e.g. the current tag. */\n currentValue?: string | null;\n className?: string;\n}\n\nexport function CaptureExpandingField({\n label,\n placeholder,\n icon,\n onCommit,\n defaultExpanded = false,\n disabled = false,\n currentValue = null,\n className,\n}: CaptureExpandingFieldProps) {\n const [expanded, setExpanded] = useState(defaultExpanded);\n const [draft, setDraft] = useState(\"\");\n const inputRef = useRef<HTMLInputElement | null>(null);\n\n // Refs so the unmount commit reads the LATEST draft without re-running the\n // effect (which would fire the cleanup on every keystroke).\n const draftRef = useRef(draft);\n draftRef.current = draft;\n const onCommitRef = useRef(onCommit);\n onCommitRef.current = onCommit;\n\n useEffect(() => {\n return () => {\n const trimmed = draftRef.current.trim();\n if (trimmed) onCommitRef.current(trimmed);\n };\n }, []);\n\n const commit = useCallback(() => {\n const trimmed = draftRef.current.trim();\n if (trimmed) onCommitRef.current(trimmed);\n setDraft(\"\");\n }, []);\n\n const open = useCallback(() => {\n setExpanded(true);\n // Focus after paint so the keyboard rises with the field, not before it.\n requestAnimationFrame(() => inputRef.current?.focus());\n }, []);\n\n const close = useCallback(() => {\n commit();\n setExpanded(false);\n }, [commit]);\n\n if (!expanded) {\n return (\n <button\n type=\"button\"\n onClick={open}\n disabled={disabled}\n aria-label={label}\n aria-expanded={false}\n className={cn(\n \"flex h-9 max-w-[62vw] items-center gap-1.5 rounded-full px-3.5\",\n \"bg-black/45 text-[13px] font-semibold text-white backdrop-blur-md\",\n \"transition-colors hover:bg-black/60 active:bg-black/70\",\n disabled && \"opacity-40\",\n className,\n )}\n >\n {icon ? <span className=\"shrink-0\">{icon}</span> : null}\n <span className=\"truncate\">{currentValue?.trim() || label}</span>\n </button>\n );\n }\n\n return (\n <div\n className={cn(\n \"flex h-9 w-[min(78vw,320px)] items-center gap-1.5 rounded-full px-3\",\n \"bg-black/60 backdrop-blur-md\",\n className,\n )}\n >\n {icon ? <span className=\"shrink-0 text-white/70\">{icon}</span> : null}\n <input\n ref={inputRef}\n value={draft}\n onChange={(e) => setDraft(e.target.value)}\n onBlur={close}\n onKeyDown={(e) => {\n if (e.key === \"Enter\") {\n commit();\n (e.target as HTMLInputElement).blur();\n }\n if (e.key === \"Escape\") {\n setDraft(\"\");\n setExpanded(false);\n }\n }}\n placeholder={placeholder ?? label}\n aria-label={label}\n enterKeyHint=\"done\"\n autoCapitalize=\"characters\"\n autoCorrect=\"off\"\n spellCheck={false}\n // 16px floor: anything smaller makes iOS zoom the whole page on focus\n // and it never zooms back out.\n className={cn(\n \"min-w-0 flex-1 bg-transparent text-base text-white\",\n \"placeholder:text-white/40 focus:outline-none\",\n )}\n />\n <button\n type=\"button\"\n // onMouseDown, not onClick: the input's blur would otherwise fire\n // first, collapse the field, and unmount this button mid-click.\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => {\n setDraft(\"\");\n setExpanded(false);\n }}\n aria-label={`Close ${label}`}\n className=\"flex h-6 w-6 shrink-0 items-center justify-center rounded-full text-white/70 hover:bg-white/10 hover:text-white\"\n >\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2.5\"\n strokeLinecap=\"round\"\n className=\"h-3.5 w-3.5\"\n aria-hidden=\"true\"\n >\n <path d=\"M18 6 6 18M6 6l12 12\" />\n </svg>\n </button>\n </div>\n );\n}\n","\"use client\";\n\n/**\n * CameraFeed — the package's live preview <video> for the default engine\n * (drop-in hosts). Attaches the engine's stream imperatively (srcObject is\n * not a React DOM prop), fills its container with object-cover, and exposes\n * the element through the engine's videoRef so photo capture can read it.\n * Inline styles on purpose: host stylesheets (e.g. mobile `video { height:\n * auto }` resets) must never shrink the live view below the captured frame.\n *\n * Hosts with their own runtime render their own preview component instead —\n * this one is part of the batteries-included path.\n */\n\nimport React, { useEffect } from \"react\";\nimport type { CaptureCameraEngine } from \"../types\";\n\nexport function CameraFeed({\n engine,\n mirror = false,\n}: {\n engine: CaptureCameraEngine;\n /** Preview-only CSS mirror (front camera). Output is never mirrored. */\n mirror?: boolean;\n}) {\n const { stream, videoRef } = engine;\n\n useEffect(() => {\n const video = videoRef.current;\n if (!video) return;\n if (video.srcObject !== stream) video.srcObject = stream;\n return () => {\n video.srcObject = null;\n };\n }, [stream, videoRef]);\n\n return (\n <video\n ref={videoRef}\n style={{\n width: \"100%\",\n height: \"100%\",\n objectFit: \"cover\",\n ...(mirror ? { transform: \"scaleX(-1)\" } : {}),\n }}\n muted\n autoPlay\n playsInline\n />\n );\n}\n","\"use client\";\n\n/**\n * useDefaultCaptureEngine — the package's OWN working camera engine, so a\n * host with no media runtime (the Vite drop-in test) gets a fully wired\n * camera from a few lines:\n *\n * const engine = useDefaultCaptureEngine({ onPhoto, onVideo, onFiles });\n * <CameraCapture engine={engine} preview={<CameraFeed engine={engine} />} … />\n *\n * Sophisticated hosts (AI Matrx injects its lease-managed runtime) may pass\n * their own `CaptureCameraEngine` instead — this default is the floor, not\n * the ceiling.\n *\n * THE ONE getUserMedia SITE of the package lives here (`src/engine/` — the\n * laws test bans it everywhere else). Behavior:\n * - Environment-facing by default; flip toggles facingMode and reacquires.\n * - Photo: full-sensor canvas capture (JPEG q0.92), optional center-crop to\n * the chrome's aspect setting. Never a screenshot of the cropped preview.\n * - Video: MediaRecorder over the live stream plus (when granted) audio,\n * with a concrete-MIME ladder and a monotonic elapsed clock.\n * - Upload: a package-created hidden <input type=\"file\"> (no `capture`\n * attribute — that is what opens the OS gallery, not the camera).\n * - Tracks stop on unmount and on flip; permission denial reports\n * `blocked: \"permission-denied\"`, everything else \"not-supported\".\n */\n\nimport {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport type { CaptureAspect, CaptureCameraEngine } from \"../types\";\n\nconst RECORDING_MIME_LADDER = [\n 'video/mp4;codecs=\"avc1.42E01E,mp4a.40.2\"',\n \"video/mp4\",\n 'video/webm;codecs=\"vp9,opus\"',\n 'video/webm;codecs=\"vp8,opus\"',\n \"video/webm\",\n];\n\nexport interface DefaultEngineOptions {\n /** Receives every captured photo as a JPEG File. */\n onPhoto: (file: File) => void;\n /** Receives the finished recording. */\n onVideo: (file: File, durationMs: number) => void;\n /** Receives files chosen through the Upload lane. */\n onFiles: (files: FileList) => void;\n /** Record microphone audio with video (asks once, at record time). */\n withAudio?: boolean;\n facingMode?: \"environment\" | \"user\";\n photoQuality?: number;\n}\n\nfunction cropRect(\n w: number,\n h: number,\n aspect: CaptureAspect,\n): { x: number; y: number; w: number; h: number } {\n if (aspect === \"full\") return { x: 0, y: 0, w, h };\n const [aw, ah] =\n aspect === \"1:1\" ? [1, 1] : aspect === \"4:3\" ? [3, 4] : [9, 16];\n // Portrait ratios above; swap for landscape sensors.\n const [rw, rh] = w >= h ? [ah, aw] : [aw, ah];\n const target = rw / rh;\n let cw = w;\n let ch = w / target;\n if (ch > h) {\n ch = h;\n cw = h * target;\n }\n return { x: (w - cw) / 2, y: (h - ch) / 2, w: cw, h: ch };\n}\n\nexport function useDefaultCaptureEngine(\n options: DefaultEngineOptions,\n): CaptureCameraEngine {\n const {\n onPhoto,\n onVideo,\n onFiles,\n withAudio = true,\n facingMode: initialFacing = \"environment\",\n photoQuality = 0.92,\n } = options;\n\n const [stream, setStream] = useState<MediaStream | null>(null);\n const [blocked, setBlocked] = useState<CaptureCameraEngine[\"blocked\"]>(null);\n const [facing, setFacing] = useState(initialFacing);\n const [multipleCameras, setMultipleCameras] = useState(false);\n const [recording, setRecording] = useState(false);\n const [recordElapsedSeconds, setRecordElapsedSeconds] = useState(0);\n\n const videoRef = useRef<HTMLVideoElement | null>(null);\n const streamRef = useRef<MediaStream | null>(null);\n const recorderRef = useRef<{\n recorder: MediaRecorder;\n chunks: Blob[];\n startedAt: number;\n micTracks: MediaStreamTrack[];\n timer: ReturnType<typeof setInterval>;\n } | null>(null);\n const callbacksRef = useRef({ onPhoto, onVideo, onFiles });\n callbacksRef.current = { onPhoto, onVideo, onFiles };\n\n // ── Stream lifecycle ─────────────────────────────────────────────────────\n useEffect(() => {\n let cancelled = false;\n let acquired: MediaStream | null = null;\n if (typeof navigator === \"undefined\" || !navigator.mediaDevices) {\n setBlocked({ reason: \"not-supported\" });\n return;\n }\n navigator.mediaDevices\n .getUserMedia({\n video: {\n facingMode: facing,\n width: { ideal: 4096 },\n height: { ideal: 4096 },\n },\n audio: false,\n })\n .then((s) => {\n if (cancelled) {\n s.getTracks().forEach((t) => t.stop());\n return;\n }\n acquired = s;\n streamRef.current = s;\n setStream(s);\n setBlocked(null);\n return navigator.mediaDevices.enumerateDevices().then((devices) => {\n if (!cancelled)\n setMultipleCameras(\n devices.filter((d) => d.kind === \"videoinput\").length > 1,\n );\n });\n })\n .catch((err: unknown) => {\n if (cancelled) return;\n const name =\n err && typeof err === \"object\" && \"name\" in err\n ? String((err as { name: unknown }).name)\n : \"\";\n setBlocked({\n reason:\n name === \"NotAllowedError\" || name === \"SecurityError\"\n ? \"permission-denied\"\n : \"not-supported\",\n });\n });\n return () => {\n cancelled = true;\n acquired?.getTracks().forEach((t) => t.stop());\n if (streamRef.current === acquired) streamRef.current = null;\n setStream(null);\n };\n }, [facing]);\n\n // Never leave a recorder running past unmount.\n useEffect(() => {\n return () => {\n const r = recorderRef.current;\n if (r) {\n clearInterval(r.timer);\n if (r.recorder.state !== \"inactive\") r.recorder.stop();\n r.micTracks.forEach((t) => t.stop());\n }\n };\n }, []);\n\n // ── Photo ────────────────────────────────────────────────────────────────\n const onCapturePhoto = useCallback(\n (opts?: { aspect?: CaptureAspect }) => {\n const video = videoRef.current;\n if (!video || video.videoWidth === 0) return;\n const rect = cropRect(\n video.videoWidth,\n video.videoHeight,\n opts?.aspect ?? \"full\",\n );\n const canvas = document.createElement(\"canvas\");\n canvas.width = Math.round(rect.w);\n canvas.height = Math.round(rect.h);\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) return;\n ctx.drawImage(\n video,\n rect.x,\n rect.y,\n rect.w,\n rect.h,\n 0,\n 0,\n canvas.width,\n canvas.height,\n );\n canvas.toBlob(\n (blob) => {\n if (!blob) return;\n callbacksRef.current.onPhoto(\n new File([blob], `capture-${new Date().toISOString()}.jpg`, {\n type: \"image/jpeg\",\n }),\n );\n },\n \"image/jpeg\",\n photoQuality,\n );\n },\n [photoQuality],\n );\n\n // ── Video ────────────────────────────────────────────────────────────────\n const onStartRecording = useCallback(() => {\n const base = streamRef.current;\n if (!base || recorderRef.current) return;\n void (async () => {\n let micTracks: MediaStreamTrack[] = [];\n if (withAudio) {\n try {\n const mic = await navigator.mediaDevices.getUserMedia({\n audio: true,\n });\n micTracks = mic.getAudioTracks();\n } catch {\n // Mic denied — record video-only rather than failing the capture.\n }\n }\n const composed = new MediaStream([\n ...base.getVideoTracks(),\n ...micTracks,\n ]);\n const mime = RECORDING_MIME_LADDER.find((m) =>\n typeof MediaRecorder !== \"undefined\" &&\n MediaRecorder.isTypeSupported(m),\n );\n let recorder: MediaRecorder;\n try {\n recorder = new MediaRecorder(\n composed,\n mime ? { mimeType: mime } : undefined,\n );\n } catch {\n micTracks.forEach((t) => t.stop());\n return;\n }\n const entry = {\n recorder,\n chunks: [] as Blob[],\n startedAt: performance.now(),\n micTracks,\n timer: setInterval(() => {\n setRecordElapsedSeconds(\n Math.floor((performance.now() - entry.startedAt) / 1000),\n );\n }, 250),\n };\n recorderRef.current = entry;\n recorder.ondataavailable = (e) => {\n if (e.data.size > 0) entry.chunks.push(e.data);\n };\n recorder.onstop = () => {\n clearInterval(entry.timer);\n entry.micTracks.forEach((t) => t.stop());\n recorderRef.current = null;\n setRecording(false);\n const durationMs = Math.round(performance.now() - entry.startedAt);\n const type = recorder.mimeType || entry.chunks[0]?.type || \"video/webm\";\n const blob = new Blob(entry.chunks, { type });\n const ext = type.includes(\"mp4\") ? \"mp4\" : \"webm\";\n callbacksRef.current.onVideo(\n new File([blob], `capture-${new Date().toISOString()}.${ext}`, {\n type,\n }),\n durationMs,\n );\n };\n recorder.start(1000);\n setRecordElapsedSeconds(0);\n setRecording(true);\n })();\n }, [withAudio]);\n\n const onStopRecording = useCallback(() => {\n const r = recorderRef.current;\n if (r && r.recorder.state !== \"inactive\") r.recorder.stop();\n }, []);\n\n // ── Upload lane ──────────────────────────────────────────────────────────\n const onUpload = useCallback(() => {\n const input = document.createElement(\"input\");\n input.type = \"file\";\n input.accept = \"image/*,video/*\";\n input.multiple = true;\n input.onchange = () => {\n if (input.files && input.files.length > 0)\n callbacksRef.current.onFiles(input.files);\n };\n input.click();\n }, []);\n\n const onFlipCamera = useCallback(() => {\n setFacing((f) => (f === \"environment\" ? \"user\" : \"environment\"));\n }, []);\n\n return useMemo(\n () => ({\n stream,\n videoRef,\n blocked,\n onCapturePhoto,\n onStartRecording,\n onStopRecording,\n recording,\n recordElapsedSeconds,\n onUpload,\n onFlipCamera: multipleCameras ? onFlipCamera : null,\n }),\n [\n stream,\n blocked,\n onCapturePhoto,\n onStartRecording,\n onStopRecording,\n recording,\n recordElapsedSeconds,\n onUpload,\n onFlipCamera,\n multipleCameras,\n ],\n );\n}\n"],"mappings":"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","names":["useCallback","useEffect","useRef","useState","jsx","jsx","jsxs","jsx","jsxs","jsx","jsxs","jsx","jsxs","jsx","jsxs","jsx","useEffect","useState","jsx","jsxs","useCallback","useEffect","useMemo","useState","jsx","jsxs","useState","useCallback","useEffect","useMemo","useCallback","useEffect","useRef","useState","jsx","jsxs","useState","useRef","useCallback","useEffect","jsx","jsxs","useState","useRef","useEffect","useCallback","useCallback","useEffect","useRef","useState","useState","jsx","jsxs","useState","useCallback","useEffect","useRef","useState","jsx","jsxs","useRef","useState","useCallback","useEffect","formatElapsed","jsx","jsxs","ASPECT_CYCLE","useState","useRef","useEffect","useCallback","useCallback","useEffect","useRef","useState","jsx","jsxs","useState","useRef","useEffect","useCallback","useEffect","jsx","useCallback","useEffect","useMemo","useRef","useState"]}
|