@ai-matrx/capture 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/react.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/CameraCapture.tsx","../src/cn.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/components/ImageEditSheet.tsx"],"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 Grip,\n Grid3x3,\n Proportions,\n SunMedium,\n Timer,\n X,\n Zap,\n ZapOff,\n RefreshCw,\n} from \"lucide-react\";\nimport { cn } from \"../cn\";\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\";\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 (host wires its runtime's `CameraPreview`). */\n preview: React.ReactNode;\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 onClose,\n blockedSheet,\n controlsHidden = false,\n shutterDisabled = false,\n slots = {},\n}: CameraCaptureProps) {\n const [optionsOpen, setOptionsOpen] = useState(false);\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 clearCountdown = useCallback(() => {\n if (countdownRef.current) clearInterval(countdownRef.current);\n countdownRef.current = null;\n setCountdown(null);\n }, []);\n useEffect(() => clearCountdown, [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 <Zap className=\"h-6 w-6\" fill=\"currentColor\" />\n ) : (\n <ZapOff 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: <Timer 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: <Grid3x3 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: <Proportions 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: <SunMedium 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 — semi-transparent near-black, feed visible through it. */}\n {!controlsHidden && (\n <div className=\"absolute inset-x-0 top-0 z-20 bg-black/65 pt-safe backdrop-blur-[2px]\">\n <div className=\"flex h-16 items-center gap-1 px-3\">\n {onClose ? (\n <button\n type=\"button\"\n onClick={onClose}\n aria-label=\"Close camera\"\n className=\"flex h-11 w-11 shrink-0 touch-manipulation items-center justify-center rounded-full text-white transition-colors hover:bg-white/10\"\n >\n <X className=\"h-6 w-6\" />\n </button>\n ) : (\n <span className=\"w-11 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-11 w-11 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 <Zap\n className=\"h-[22px] w-[22px]\"\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-11 w-11 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 <Grip className=\"h-[22px] w-[22px]\" />\n </button>\n </div>\n </div>\n )}\n\n {/* Honesty chips — visible even with controls hidden. */}\n <div className=\"pointer-events-none absolute inset-x-0 top-20 z-20 mt-safe flex flex-col items-center gap-2\">\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-3\">\n <ZoomRow\n options={controls.zoomOptions}\n value={controls.zoom}\n onSelect={controls.setZoom}\n />\n </div>\n )}\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 <SunMedium 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 className=\"bg-black/65 px-3 pb-safe backdrop-blur-[2px]\">\n {slots.aboveModeSelector}\n {/* The domain action (Next/Break) gets its own right-aligned row —\n overlaying it on the mode labels collides on narrow phones. */}\n {slots.modeRowTrailing && (\n <div className=\"flex justify-end pb-1 pt-1.5\">\n {slots.modeRowTrailing}\n </div>\n )}\n <div className=\"flex items-center justify-center py-2.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 </div>\n <div className=\"flex items-center justify-between px-2 pb-4 pt-1\">\n <div className=\"flex w-16 justify-start\">\n <button\n type=\"button\"\n onClick={cloud.onOpenLibrary}\n aria-label=\"Open your media library\"\n className=\"h-12 w-12 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-16 justify-end\">\n {engine.onFlipCamera ? (\n <button\n type=\"button\"\n onClick={engine.onFlipCamera}\n aria-label=\"Switch camera\"\n className=\"flex h-12 w-12 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 <RefreshCw className=\"h-5 w-5\" />\n </button>\n ) : (\n <span className=\"h-12 w-12\" />\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 {slots.overlays}\n </div>\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","\"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 const read = () => {\n try {\n setCaps(track.getCapabilities() as ExtendedCapabilities);\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 } catch {\n setCaps(null);\n }\n };\n read();\n const timer = window.setTimeout(read, 750);\n return () => window.clearTimeout(timer);\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 iPhone mode row: uppercase, letter-spaced labels in a\n * horizontal band; the ACTIVE mode sits in a dark pill with the iOS camera\n * yellow. VIDEO and PHOTO are persistent modes; UPLOAD is an immediate\n * action (opens the host's picker) and never takes the active state — it is\n * our third lane in the slot the iPhone layout leaves open next to PHOTO.\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 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 }[];\n}\n\nconst LABEL_BASE =\n \"touch-manipulation rounded-full px-4 py-1.5 text-[13px] font-semibold uppercase tracking-[0.12em] transition-colors duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/70 disabled:opacity-40\";\n\nexport function ModeSelector({\n mode,\n onModeChange,\n onUpload,\n modeDisabled = false,\n uploadDisabled = false,\n extraModes = [],\n}: ModeSelectorProps) {\n return (\n <div\n role=\"tablist\"\n aria-label=\"Capture mode\"\n className=\"flex items-center justify-center gap-1\"\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\" ? \"bg-white/15 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\" ? \"bg-white/15 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 className=\"absolute inset-x-3 bottom-3 mb-safe rounded-[2.5rem] bg-[#3a3a3c]/95 px-6 py-8 shadow-2xl\">\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 { Loader2, X } from \"lucide-react\";\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 className=\"relative mx-2 mb-2 mb-safe rounded-[2rem] bg-[#f2f2f7] px-6 pb-6 pt-5 text-black shadow-2xl\">\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 <X 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 <Loader2 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","\"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 { Check, FlipHorizontal2, RotateCcw, X } from \"lucide-react\";\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 const [rotation, setRotation] = useState(0); // 0|90|180|270, CCW steps\n const [flipped, setFlipped] = useState(false);\n const [aspect, setAspect] = useState<AspectPreset>(\"free\");\n const [crop, setCrop] = useState<CropRect>(FULL_CROP);\n const [saving, setSaving] = useState(false);\n const stageRef = useRef<HTMLDivElement | null>(null);\n const imgRef = useRef<HTMLImageElement | null>(null);\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 useEffect(() => {\n if (open) {\n setRotation(0);\n setFlipped(false);\n setAspect(\"free\");\n setCrop(FULL_CROP);\n setSaving(false);\n }\n }, [open, src]);\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 (needs the element's real aspect).\n const img = imgRef.current;\n if (!img || img.naturalWidth === 0) return;\n const rotated = rotationSwapsAxes();\n const iw = rotated ? img.naturalHeight : img.naturalWidth;\n const ih = rotated ? img.naturalWidth : img.naturalHeight;\n const imageRatio = iw / ih;\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 function rotationSwapsAxes() {\n return rotation % 180 !== 0;\n }\n }, [rotation]);\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 try {\n const swap = rotation % 180 !== 0;\n const outW = Math.round((swap ? img.naturalHeight : img.naturalWidth) * crop.w);\n const outH = Math.round((swap ? img.naturalWidth : img.naturalHeight) * crop.h);\n const canvas = document.createElement(\"canvas\");\n canvas.width = Math.max(1, outW);\n canvas.height = Math.max(1, outH);\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) throw new Error(\"no 2d context\");\n // Move into crop space, then apply rotation/flip about the image center.\n const rw = swap ? img.naturalHeight : img.naturalWidth;\n const rh = swap ? img.naturalWidth : img.naturalHeight;\n ctx.translate(-crop.x * rw, -crop.y * rh);\n ctx.translate(rw / 2, rh / 2);\n ctx.rotate((rotation * Math.PI) / 180);\n if (flipped) ctx.scale(-1, 1);\n ctx.drawImage(img, -img.naturalWidth / 2, -img.naturalHeight / 2);\n canvas.toBlob(\n (blob) => {\n setSaving(false);\n if (blob) {\n onSave(blob);\n onClose();\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 }\n }, [rotation, flipped, 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 className=\"flex shrink-0 items-center justify-between px-4 pt-safe\">\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 <X 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 <Check 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={src}\n alt=\"Image being edited\"\n draggable={false}\n className=\"max-h-[62dvh] max-w-full select-none object-contain\"\n style={{\n transform: `rotate(${rotation}deg) ${flipped ? \"scaleX(-1)\" : \"\"}`,\n }}\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 pb-safe\">\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={() => {\n setRotation((r) => (r + 270) % 360);\n setCrop(FULL_CROP);\n setAspect(\"free\");\n }}\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 <RotateCcw className=\"h-5 w-5\" />\n </button>\n <button\n type=\"button\"\n onClick={() => setFlipped((f) => !f)}\n aria-label=\"Flip horizontally\"\n aria-pressed={flipped}\n className={cn(\n \"flex h-12 w-12 touch-manipulation items-center justify-center rounded-full bg-white/10\",\n flipped ? \"text-[#FFCC00]\" : \"text-white\",\n )}\n >\n <FlipHorizontal2 className=\"h-5 w-5\" />\n </button>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["useCallback","useEffect","useState","X","jsx","jsx","jsxs","jsx","jsxs","jsx","jsxs","jsx","jsxs","jsx","jsx","jsxs","useState","useCallback","useEffect","X","useCallback","useEffect","useRef","useState","X","jsx","jsxs","useState","useRef","useEffect","useCallback","X"]}
1
+ {"version":3,"sources":["../src/components/CameraCapture.tsx","../src/cn.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/components/ImageEditSheet.tsx"],"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 Grip,\n Grid3x3,\n Proportions,\n SunMedium,\n Timer,\n X,\n Zap,\n ZapOff,\n RefreshCw,\n} from \"lucide-react\";\nimport { cn } from \"../cn\";\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\";\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 (host wires its runtime's `CameraPreview`). */\n preview: React.ReactNode;\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 onClose,\n blockedSheet,\n controlsHidden = false,\n shutterDisabled = false,\n slots = {},\n}: CameraCaptureProps) {\n const [optionsOpen, setOptionsOpen] = useState(false);\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 clearCountdown = useCallback(() => {\n if (countdownRef.current) clearInterval(countdownRef.current);\n countdownRef.current = null;\n setCountdown(null);\n }, []);\n useEffect(() => clearCountdown, [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 <Zap className=\"h-6 w-6\" fill=\"currentColor\" />\n ) : (\n <ZapOff 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: <Timer 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: <Grid3x3 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: <Proportions 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: <SunMedium 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 className=\"absolute inset-x-0 top-0 z-20 bg-black/65 pt-safe backdrop-blur-[2px]\">\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 <X 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 <Zap\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 <Grip className=\"h-5 w-5\" />\n </button>\n </div>\n </div>\n )}\n\n {/* Honesty chips — visible even with controls hidden. */}\n <div className=\"pointer-events-none absolute inset-x-0 top-[50px] z-20 mt-safe flex flex-col items-center gap-1.5\">\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 {/* Host content OVER the feed (filmstrip etc.) — zero bar height. */}\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 <SunMedium 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 className=\"bg-black/65 px-3 pb-safe backdrop-blur-[2px]\">\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 <RefreshCw 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 {slots.overlays}\n </div>\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","\"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 const read = () => {\n try {\n setCaps(track.getCapabilities() as ExtendedCapabilities);\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 } catch {\n setCaps(null);\n }\n };\n read();\n const timer = window.setTimeout(read, 750);\n return () => window.clearTimeout(timer);\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 }[];\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 className=\"absolute inset-x-3 bottom-3 mb-safe rounded-[2.5rem] bg-[#3a3a3c]/95 px-6 py-8 shadow-2xl\">\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 { Loader2, X } from \"lucide-react\";\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 className=\"relative mx-2 mb-2 mb-safe rounded-[2rem] bg-[#f2f2f7] px-6 pb-6 pt-5 text-black shadow-2xl\">\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 <X 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 <Loader2 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","\"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 { Check, FlipHorizontal2, RotateCcw, X } from \"lucide-react\";\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 const [rotation, setRotation] = useState(0); // 0|90|180|270, CCW steps\n const [flipped, setFlipped] = useState(false);\n const [aspect, setAspect] = useState<AspectPreset>(\"free\");\n const [crop, setCrop] = useState<CropRect>(FULL_CROP);\n const [saving, setSaving] = useState(false);\n const stageRef = useRef<HTMLDivElement | null>(null);\n const imgRef = useRef<HTMLImageElement | null>(null);\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 useEffect(() => {\n if (open) {\n setRotation(0);\n setFlipped(false);\n setAspect(\"free\");\n setCrop(FULL_CROP);\n setSaving(false);\n }\n }, [open, src]);\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 (needs the element's real aspect).\n const img = imgRef.current;\n if (!img || img.naturalWidth === 0) return;\n const rotated = rotationSwapsAxes();\n const iw = rotated ? img.naturalHeight : img.naturalWidth;\n const ih = rotated ? img.naturalWidth : img.naturalHeight;\n const imageRatio = iw / ih;\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 function rotationSwapsAxes() {\n return rotation % 180 !== 0;\n }\n }, [rotation]);\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 try {\n const swap = rotation % 180 !== 0;\n const outW = Math.round((swap ? img.naturalHeight : img.naturalWidth) * crop.w);\n const outH = Math.round((swap ? img.naturalWidth : img.naturalHeight) * crop.h);\n const canvas = document.createElement(\"canvas\");\n canvas.width = Math.max(1, outW);\n canvas.height = Math.max(1, outH);\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) throw new Error(\"no 2d context\");\n // Move into crop space, then apply rotation/flip about the image center.\n const rw = swap ? img.naturalHeight : img.naturalWidth;\n const rh = swap ? img.naturalWidth : img.naturalHeight;\n ctx.translate(-crop.x * rw, -crop.y * rh);\n ctx.translate(rw / 2, rh / 2);\n ctx.rotate((rotation * Math.PI) / 180);\n if (flipped) ctx.scale(-1, 1);\n ctx.drawImage(img, -img.naturalWidth / 2, -img.naturalHeight / 2);\n canvas.toBlob(\n (blob) => {\n setSaving(false);\n if (blob) {\n onSave(blob);\n onClose();\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 }\n }, [rotation, flipped, 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 className=\"flex shrink-0 items-center justify-between px-4 pt-safe\">\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 <X 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 <Check 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={src}\n alt=\"Image being edited\"\n draggable={false}\n className=\"max-h-[62dvh] max-w-full select-none object-contain\"\n style={{\n transform: `rotate(${rotation}deg) ${flipped ? \"scaleX(-1)\" : \"\"}`,\n }}\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 pb-safe\">\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={() => {\n setRotation((r) => (r + 270) % 360);\n setCrop(FULL_CROP);\n setAspect(\"free\");\n }}\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 <RotateCcw className=\"h-5 w-5\" />\n </button>\n <button\n type=\"button\"\n onClick={() => setFlipped((f) => !f)}\n aria-label=\"Flip horizontally\"\n aria-pressed={flipped}\n className={cn(\n \"flex h-12 w-12 touch-manipulation items-center justify-center rounded-full bg-white/10\",\n flipped ? \"text-[#FFCC00]\" : \"text-white\",\n )}\n >\n <FlipHorizontal2 className=\"h-5 w-5\" />\n </button>\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["useCallback","useEffect","useState","X","jsx","jsx","jsxs","jsx","jsxs","jsx","jsxs","jsx","jsxs","jsx","jsx","jsxs","useState","useCallback","useEffect","X","useCallback","useEffect","useRef","useState","X","jsx","jsxs","useState","useRef","useEffect","useCallback","X"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-matrx/capture",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "The AI Matrx capture kit: the opinionated iPhone-style camera chrome — translucent viewfinder bars, two-tap options grid, zoom pills, shutter, VIDEO·PHOTO·UPLOAD mode row, iOS-style sheets, instant in-browser crop/rotate editing — cloud-first by law (the cloud port is required), engine-injected (the host owns getUserMedia), and slot-extensible for domain add-ons.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",