@ttt-productions/file-input 0.11.15 → 0.11.17

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.
Files changed (67) hide show
  1. package/dist/index.d.ts +4 -4
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +4 -4
  4. package/dist/index.js.map +1 -1
  5. package/dist/lib/image-utils.d.ts +3 -4
  6. package/dist/lib/image-utils.d.ts.map +1 -1
  7. package/dist/lib/image-utils.js +11 -12
  8. package/dist/lib/image-utils.js.map +1 -1
  9. package/dist/lib/infer-content-type.d.ts +1 -24
  10. package/dist/lib/infer-content-type.d.ts.map +1 -1
  11. package/dist/lib/infer-content-type.js +31 -85
  12. package/dist/lib/infer-content-type.js.map +1 -1
  13. package/dist/lib/read-media-meta.d.ts +1 -1
  14. package/dist/lib/read-media-meta.d.ts.map +1 -1
  15. package/dist/lib/read-media-meta.js +20 -13
  16. package/dist/lib/read-media-meta.js.map +1 -1
  17. package/dist/lib/validate-media-duration.d.ts.map +1 -1
  18. package/dist/lib/validate-media-duration.js +5 -10
  19. package/dist/lib/validate-media-duration.js.map +1 -1
  20. package/dist/lib/validate-upload-kind.d.ts +0 -34
  21. package/dist/lib/validate-upload-kind.d.ts.map +1 -1
  22. package/dist/lib/validate-upload-kind.js +0 -17
  23. package/dist/lib/validate-upload-kind.js.map +1 -1
  24. package/dist/progress-bar.d.ts +2 -0
  25. package/dist/progress-bar.d.ts.map +1 -0
  26. package/dist/progress-bar.js +2 -0
  27. package/dist/progress-bar.js.map +1 -0
  28. package/dist/react/components/audio-input.d.ts +2 -2
  29. package/dist/react/components/audio-input.js +2 -2
  30. package/dist/react/components/audio-input.js.map +1 -1
  31. package/dist/react/components/file-input.d.ts +1 -1
  32. package/dist/react/components/file-input.d.ts.map +1 -1
  33. package/dist/react/components/file-input.js +59 -44
  34. package/dist/react/components/file-input.js.map +1 -1
  35. package/dist/react/components/image-cropper-modal.d.ts +3 -3
  36. package/dist/react/components/image-cropper-modal.d.ts.map +1 -1
  37. package/dist/react/components/image-cropper-modal.js +6 -8
  38. package/dist/react/components/image-cropper-modal.js.map +1 -1
  39. package/dist/react/components/image-input.d.ts +2 -2
  40. package/dist/react/components/image-input.js +2 -2
  41. package/dist/react/components/image-input.js.map +1 -1
  42. package/dist/react/components/media-constraints-hint.d.ts +1 -1
  43. package/dist/react/components/media-constraints-hint.d.ts.map +1 -1
  44. package/dist/react/components/media-constraints-hint.js +26 -25
  45. package/dist/react/components/media-constraints-hint.js.map +1 -1
  46. package/dist/react/components/media-input.d.ts +2 -2
  47. package/dist/react/components/media-input.d.ts.map +1 -1
  48. package/dist/react/components/media-input.js +111 -158
  49. package/dist/react/components/media-input.js.map +1 -1
  50. package/dist/react/components/photo-capture-modal.d.ts +1 -1
  51. package/dist/react/components/photo-capture-modal.d.ts.map +1 -1
  52. package/dist/react/components/photo-capture-modal.js +16 -20
  53. package/dist/react/components/photo-capture-modal.js.map +1 -1
  54. package/dist/react/components/record-dialog.d.ts +3 -7
  55. package/dist/react/components/record-dialog.d.ts.map +1 -1
  56. package/dist/react/components/record-dialog.js +60 -138
  57. package/dist/react/components/record-dialog.js.map +1 -1
  58. package/dist/react/components/video-input.d.ts +2 -2
  59. package/dist/react/components/video-input.js +2 -2
  60. package/dist/react/components/video-input.js.map +1 -1
  61. package/dist/react/index.d.ts +8 -8
  62. package/dist/react/index.js +8 -8
  63. package/dist/react/index.js.map +1 -1
  64. package/dist/types.d.ts +3 -59
  65. package/dist/types.d.ts.map +1 -1
  66. package/dist/types.js.map +1 -1
  67. package/package.json +4 -4
@@ -1 +1 @@
1
- {"version":3,"file":"record-dialog.js","sourceRoot":"","sources":["../../../src/react/components/record-dialog.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\n\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { Camera, Video, Mic, X, RotateCcw, Check } from \"lucide-react\";\nimport { startWaveformLoop } from \"@ttt-productions/media-viewer\";\nimport { MediaPreview } from \"@ttt-productions/media-viewer/react\";\nimport { ensureFileWithContentType } from \"../../lib/infer-content-type.js\";\nimport {\n Button,\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n Spinner,\n useAsyncAction,\n} from \"@ttt-productions/ui-core/react\";\n\ntype RecorderState = \"idle\" | \"recording\" | \"preview\";\n\n// Explicit MediaRecorder container preferences, probed via isTypeSupported.\n// A no-argument MediaRecorder leaves the container to the browser (Chrome\n// reports \"audio/webm;codecs=opus\" for audio); requesting an explicit\n// supported type keeps the recorded container deterministic. Safari has no\n// webm support and falls through to mp4. When isTypeSupported is unavailable\n// or nothing matches (test environments), we fall back to the no-argument\n// constructor and normalize whatever the recorder produced.\nconst RECORDER_MIME_CANDIDATES: Record<\"audio\" | \"video\", readonly string[]> = {\n audio: [\"audio/webm;codecs=opus\", \"audio/webm\", \"audio/mp4\"],\n video: [\"video/webm;codecs=vp9,opus\", \"video/webm\", \"video/mp4\"],\n};\n\nfunction pickRecorderMimeType(kind: \"audio\" | \"video\"): string | undefined {\n if (\n typeof MediaRecorder === \"undefined\" ||\n typeof MediaRecorder.isTypeSupported !== \"function\"\n ) {\n return undefined;\n }\n for (const candidate of RECORDER_MIME_CANDIDATES[kind]) {\n try {\n if (MediaRecorder.isTypeSupported(candidate)) return candidate;\n } catch {\n // Treat probe errors as \"unsupported\" and keep trying.\n }\n }\n return undefined;\n}\n\n// Name the recording after its actual container so the filename never\n// contradicts the emitted contentType (a webm-named mp4 would mislead any\n// extension-based fallback downstream). The mp4 container holds either audio\n// (.m4a → audio/mp4) or video (.mp4 → video/mp4), and — unlike webm/ogg — mp4\n// is NOT in the extension-inference ambiguous map (a user-picked .mp4 is trusted\n// as video). Here the RecordDialog's selected `kind` IS authoritative: an audio\n// recording uses an audio-only, `video: false` getUserMedia stream, so no video\n// track can exist. A surprising `video/mp4` mimeType on that audio recording is\n// therefore still named `.m4a`; ensureFileWithContentType distrusts the\n// kind-mismatched video/mp4 type and the `.m4a` extension yields audio/mp4.\nfunction recordingFileName(mime: string, kind: \"audio\" | \"video\"): string {\n const base = mime.split(\";\")[0].trim().toLowerCase();\n const ext =\n base === \"audio/mp4\" || base === \"video/mp4\"\n ? kind === \"audio\"\n ? \"m4a\"\n : \"mp4\"\n : base === \"audio/ogg\" || base === \"video/ogg\"\n ? \"ogg\"\n : \"webm\";\n return `recording.${ext}`;\n}\n\n// A MediaRecorder blob is always a little LONGER than the wall-clock window\n// between start() and stop(). Three effects stack, all in the same direction:\n// 1. stop() flushes whatever the encoder/muxer still had buffered, so the\n// last written packet extends past the stop() call (Chromium's webm muxer\n// and Firefox's are both in the tens-to-low-hundreds of ms here; typical\n// observed flush is well under 500ms).\n// 2. The container duration is the END of the final frame/packet, not the\n// moment capture stopped — one video frame is ~33ms at 30fps and one Opus\n// packet is 20ms, and both readers round that way (the client gate's\n// seek-to-end duration and ffprobe on the server agree with the container).\n// 3. setTimeout fires LATE, never early — a busy main thread encoding video\n// routinely adds tens of ms, more under load or in a hidden tab.\n//\n// Both duration gates are exact — the client upload gate (validateMediaDuration:\n// `duration <= maxDurationSec`) and the server processor\n// (media-processing-core validateDuration: `durationSec <= maxDurationSec`) —\n// with no tolerance. So stopping the recorder exactly AT the cap produced blobs\n// the product then rejected as its own \"Media too long. Max N seconds.\" error.\n// Stopping early by 750ms clears all three effects above with headroom for\n// timer jitter, and costs 1.25% of the smallest real cap (60s).\nconst AUTO_STOP_SAFETY_MARGIN_MS = 750;\n\n// The auto-stop delay for a cap. The clamp keeps the margin from swallowing a\n// very short cap (a 1s cap would otherwise stop at 250ms); real caps are >= 60s,\n// where the clamp never applies.\nexport function autoStopDelayMs(maxRecordDurationSec: number): number {\n const capMs = Math.floor(maxRecordDurationSec * 1000);\n return Math.max(capMs - AUTO_STOP_SAFETY_MARGIN_MS, Math.ceil(capMs / 2));\n}\n\ninterface RecordDialogProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n initialKind: \"audio\" | \"video\";\n canPhoto: boolean;\n canRecVideo: boolean;\n canRecAudio: boolean;\n cameraFacingMode?: \"user\" | \"environment\";\n maxRecordDurationSec?: number;\n disabled?: boolean;\n isLoading?: boolean;\n /** `recordedKind` is the kind of the ACTUAL recording session (the dialog's\n * own state at Save time, which tracks the requested MediaStream — audio\n * requests `video:false`). It feeds the STRONG `media-recorder` client\n * claim, so it must never be re-derived from the blob's reported MIME. */\n onRecorded: (file: File, previewUrl: string, recordedKind: \"audio\" | \"video\") => void | Promise<void>;\n onRequestPhoto?: () => void;\n}\n\nfunction formatDuration(ms: number): string {\n const totalSec = Math.max(0, Math.floor(ms / 1000));\n const m = Math.floor(totalSec / 60);\n const s = totalSec % 60;\n return `${m}:${s.toString().padStart(2, \"0\")}`;\n}\n\nexport function RecordDialog({\n open,\n onOpenChange,\n initialKind,\n canPhoto,\n canRecVideo,\n canRecAudio,\n cameraFacingMode,\n maxRecordDurationSec,\n disabled = false,\n isLoading = false,\n onRecorded,\n onRequestPhoto,\n}: RecordDialogProps) {\n const [recordKind, setRecordKind] = useState<\"audio\" | \"video\">(initialKind);\n const [recorderState, setRecorderState] = useState<RecorderState>(\"idle\");\n const [recordPreviewUrl, setRecordPreviewUrl] = useState<string | null>(null);\n const [recordedFile, setRecordedFile] = useState<File | null>(null);\n const [elapsedMs, setElapsedMs] = useState(0);\n const [discardConfirmOpen, setDiscardConfirmOpen] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [acquiring, setAcquiring] = useState(false);\n\n const mediaRecorderRef = useRef<MediaRecorder | null>(null);\n const recordStreamRef = useRef<MediaStream | null>(null);\n const liveStreamKindRef = useRef<\"audio\" | \"video\" | null>(null);\n const recordChunksRef = useRef<BlobPart[]>([]);\n const lastRecordUrlRef = useRef<string | null>(null);\n const livePreviewRef = useRef<HTMLVideoElement | null>(null);\n const autoStopTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n // Bumped by every teardown. An acquisition that resolves after a teardown (dialog\n // closed, kind switched, re-record) belongs to nobody and must not be attached.\n const acquireGenRef = useRef(0);\n const previewReqRef = useRef(0);\n\n const startedAtRef = useRef<number>(0);\n const elapsedIntervalRef = useRef<ReturnType<typeof setInterval> | null>(null);\n\n const audioContextRef = useRef<AudioContext | null>(null);\n const audioAnalyserRef = useRef<AnalyserNode | null>(null);\n const audioSourceRef = useRef<MediaStreamAudioSourceNode | null>(null);\n const waveformStopRef = useRef<(() => void) | null>(null);\n const waveformCanvasRef = useRef<HTMLCanvasElement | null>(null);\n\n // Reset all transient state whenever the dialog opens.\n useEffect(() => {\n if (open) {\n setRecordKind(initialKind);\n setRecorderState(\"idle\");\n setRecordedFile(null);\n setRecordPreviewUrl(null);\n setElapsedMs(0);\n setDiscardConfirmOpen(false);\n setError(null);\n }\n }, [open, initialKind]);\n\n const revokeLastRecordUrl = useCallback(() => {\n if (!lastRecordUrlRef.current) return;\n try {\n URL.revokeObjectURL(lastRecordUrlRef.current);\n } catch {}\n lastRecordUrlRef.current = null;\n }, []);\n\n const makeRecordUrl = useCallback(\n (blob: Blob) => {\n revokeLastRecordUrl();\n const url = URL.createObjectURL(blob);\n lastRecordUrlRef.current = url;\n return url;\n },\n [revokeLastRecordUrl]\n );\n\n const stopElapsedTimer = useCallback(() => {\n if (elapsedIntervalRef.current) {\n clearInterval(elapsedIntervalRef.current);\n elapsedIntervalRef.current = null;\n }\n }, []);\n\n const startElapsedTimer = useCallback(() => {\n stopElapsedTimer();\n startedAtRef.current = Date.now();\n setElapsedMs(0);\n elapsedIntervalRef.current = setInterval(() => {\n setElapsedMs(Date.now() - startedAtRef.current);\n }, 100);\n }, [stopElapsedTimer]);\n\n const stopWaveform = useCallback(() => {\n waveformStopRef.current?.();\n waveformStopRef.current = null;\n try {\n audioSourceRef.current?.disconnect();\n } catch {}\n audioSourceRef.current = null;\n audioAnalyserRef.current = null;\n const ctx = audioContextRef.current;\n audioContextRef.current = null;\n if (ctx && ctx.state !== \"closed\") {\n ctx.close().catch(() => {});\n }\n }, []);\n\n const startWaveform = useCallback(\n (stream: MediaStream) => {\n stopWaveform();\n try {\n const AudioCtx: typeof AudioContext =\n (window as any).AudioContext || (window as any).webkitAudioContext;\n if (!AudioCtx) return;\n\n const ctx = new AudioCtx();\n const source = ctx.createMediaStreamSource(stream);\n const analyser = ctx.createAnalyser();\n analyser.fftSize = 256;\n source.connect(analyser);\n\n audioContextRef.current = ctx;\n audioSourceRef.current = source;\n audioAnalyserRef.current = analyser;\n\n // Draw loop is the shared media-viewer engine (the same one the\n // playback AudioPlayer uses) in oscilloscope mode — one waveform\n // implementation across recording and playback.\n waveformStopRef.current = startWaveformLoop({\n analyser,\n getCanvas: () => waveformCanvasRef.current,\n mode: \"line\",\n });\n } catch {\n // Waveform is best-effort; silent failures are acceptable.\n }\n },\n [stopWaveform]\n );\n\n // Teardown MediaRecorder / MediaStream / auto-stop timeout / timer / waveform.\n // Leaves recorderState alone — callers decide the next state.\n const teardownCapture = useCallback(() => {\n acquireGenRef.current += 1;\n if (autoStopTimeoutRef.current) {\n clearTimeout(autoStopTimeoutRef.current);\n autoStopTimeoutRef.current = null;\n }\n mediaRecorderRef.current = null;\n\n const s = recordStreamRef.current;\n recordStreamRef.current = null;\n liveStreamKindRef.current = null;\n if (s) s.getTracks().forEach((t) => t.stop());\n\n if (livePreviewRef.current) {\n livePreviewRef.current.srcObject = null;\n }\n\n recordChunksRef.current = [];\n\n stopElapsedTimer();\n stopWaveform();\n }, [stopElapsedTimer, stopWaveform]);\n\n // Acquire camera/mic and attach the live preview (video) or waveform (audio)\n // WITHOUT starting the recorder. Returns the live stream for reuse on Start.\n const acquireStream = useCallback(\n async (kind: \"audio\" | \"video\") => {\n const wantVideo = kind === \"video\";\n const facingMode = cameraFacingMode ?? \"user\";\n const gen = acquireGenRef.current;\n const stream = await navigator.mediaDevices.getUserMedia({\n audio: true,\n video: wantVideo ? { facingMode } : false,\n });\n if (gen !== acquireGenRef.current) {\n stream.getTracks().forEach((t) => t.stop());\n return null;\n }\n recordStreamRef.current = stream;\n liveStreamKindRef.current = kind;\n setError(null);\n if (wantVideo && livePreviewRef.current) {\n livePreviewRef.current.srcObject = stream;\n livePreviewRef.current.muted = true;\n try {\n await livePreviewRef.current.play();\n } catch {}\n } else if (!wantVideo) {\n startWaveform(stream);\n }\n return stream;\n },\n [cameraFacingMode, startWaveform]\n );\n\n // Start a live preview for the given kind (used on open and on kind switch),\n // tearing down any existing stream first. Surfaces permission errors inline.\n const startLivePreview = useCallback(\n async (kind: \"audio\" | \"video\") => {\n teardownCapture();\n const req = ++previewReqRef.current;\n setAcquiring(true);\n try {\n await acquireStream(kind);\n } catch (e) {\n setError(e instanceof Error ? e.message : \"Camera/microphone access denied.\");\n } finally {\n if (req === previewReqRef.current) setAcquiring(false);\n }\n },\n [teardownCapture, acquireStream]\n );\n\n // Request camera/mic as soon as the dialog opens (parity with PhotoCaptureModal)\n // so the permission prompt fires on open and the user sees a live preview before\n // pressing Start. Release all devices when the dialog closes or unmounts.\n useEffect(() => {\n if (open) {\n void startLivePreview(initialKind);\n }\n return () => {\n teardownCapture();\n revokeLastRecordUrl();\n };\n }, [open, initialKind, startLivePreview, teardownCapture, revokeLastRecordUrl]);\n\n const startRecording = useCallback(\n async (kind: \"audio\" | \"video\") => {\n // Discard any previous preview before starting fresh.\n revokeLastRecordUrl();\n setRecordPreviewUrl(null);\n setRecordedFile(null);\n setRecordKind(kind);\n\n const wantVideo = kind === \"video\";\n\n // Reuse the live-preview stream when it matches the requested kind;\n // otherwise acquire a fresh one (also (re)triggers the permission prompt).\n let stream = recordStreamRef.current;\n if (!stream || liveStreamKindRef.current !== kind) {\n try {\n stream = await acquireStream(kind);\n } catch (e) {\n setError(e instanceof Error ? e.message : \"Camera/microphone access denied.\");\n return;\n }\n }\n if (!stream) return;\n\n // Request an explicit, supported container so mr.mimeType is\n // deterministic; fall back to the browser default when the explicit\n // request is unavailable or rejected.\n const preferredMimeType = pickRecorderMimeType(kind);\n let mr: MediaRecorder;\n try {\n mr = preferredMimeType\n ? new MediaRecorder(stream, { mimeType: preferredMimeType })\n : new MediaRecorder(stream);\n } catch {\n mr = new MediaRecorder(stream);\n }\n mediaRecorderRef.current = mr;\n recordChunksRef.current = [];\n\n mr.ondataavailable = (e) => {\n if (e.data && e.data.size > 0) recordChunksRef.current.push(e.data);\n };\n\n mr.onstop = () => {\n const blob = new Blob(recordChunksRef.current, {\n type:\n mr.mimeType ||\n preferredMimeType ||\n (wantVideo ? \"video/webm\" : \"audio/webm\"),\n });\n\n const rawFile = new File([blob], recordingFileName(blob.type, kind), { type: blob.type });\n // Normalize to the valid, parameter-less base type\n // (\"audio/webm;codecs=opus\" → \"audio/webm\"). The chosen kind is\n // authoritative: an audio recording must never emit a video/* type\n // even if the recorder reports a surprising container.\n const file = ensureFileWithContentType(rawFile, wantVideo ? \"video\" : \"audio\");\n const url = makeRecordUrl(file);\n\n setRecordedFile(file);\n setRecordPreviewUrl(url);\n setRecorderState(\"preview\");\n\n // Release devices but keep the recorded file/url in state.\n teardownCapture();\n };\n\n mr.start();\n setRecorderState(\"recording\");\n startElapsedTimer();\n\n // Hard cap. Stops with deliberate headroom (autoStopDelayMs) so the blob\n // this produces lands legally UNDER maxRecordDurationSec at both gates.\n if (maxRecordDurationSec && maxRecordDurationSec > 0) {\n autoStopTimeoutRef.current = setTimeout(() => {\n try {\n if (mediaRecorderRef.current && mediaRecorderRef.current.state === \"recording\") {\n mediaRecorderRef.current.stop();\n }\n } catch {}\n }, autoStopDelayMs(maxRecordDurationSec));\n }\n },\n [\n acquireStream,\n maxRecordDurationSec,\n makeRecordUrl,\n revokeLastRecordUrl,\n teardownCapture,\n startElapsedTimer,\n ]\n );\n\n const stopRecording = useCallback(() => {\n const mr = mediaRecorderRef.current;\n if (mr && mr.state === \"recording\") {\n try {\n mr.stop();\n } catch {\n teardownCapture();\n setRecorderState(\"idle\");\n }\n } else {\n teardownCapture();\n setRecorderState(\"idle\");\n }\n }, [teardownCapture]);\n\n const handleReRecord = useCallback(() => {\n revokeLastRecordUrl();\n setRecordPreviewUrl(null);\n setRecordedFile(null);\n setElapsedMs(0);\n setError(null);\n setRecorderState(\"idle\");\n void startLivePreview(recordKind);\n }, [revokeLastRecordUrl, startLivePreview, recordKind]);\n\n // Switching kind in idle restarts the live preview for the new kind so the\n // correct device prompt/preview shows before recording.\n const handleSelectKind = useCallback(\n (kind: \"audio\" | \"video\") => {\n setRecordKind(kind);\n setError(null);\n void startLivePreview(kind);\n },\n [startLivePreview]\n );\n\n const reportError = useCallback((e: unknown) => {\n setError(e instanceof Error ? e.message : \"Something went wrong with the recording.\");\n }, []);\n\n // Start may need to acquire a device first; pending covers that and a repeat click\n // is ignored, so two clicks can never start two recorders.\n const start = useAsyncAction((kind: \"audio\" | \"video\") => startRecording(kind), { onError: reportError });\n\n // Save hands the recording off (the consumer validates and emits it). Pending covers\n // the hand-off and a repeat click is ignored, so a double click can never emit twice.\n const save = useAsyncAction(\n async () => {\n if (!recordedFile || !recordPreviewUrl) return;\n await onRecorded(recordedFile, recordPreviewUrl, recordKind);\n onOpenChange(false);\n },\n { onError: reportError },\n );\n\n // Close the dialog for real (no confirmation). Used for idle/recording\n // states and as the \"Discard\" action in the confirm AlertDialog.\n const closeDialogImmediately = useCallback(() => {\n const mr = mediaRecorderRef.current;\n if (mr && mr.state === \"recording\") {\n try {\n mr.stop();\n } catch {}\n }\n teardownCapture();\n revokeLastRecordUrl();\n setRecordedFile(null);\n setRecordPreviewUrl(null);\n setElapsedMs(0);\n setRecorderState(\"idle\");\n setDiscardConfirmOpen(false);\n onOpenChange(false);\n }, [teardownCapture, revokeLastRecordUrl, onOpenChange]);\n\n // Dialog close requests. In \"preview\" state we ask for confirmation\n // (the user has unsaved work). Other states close immediately.\n const handleDialogOpenChange = useCallback(\n (v: boolean) => {\n if (v) return; // opening is parent-driven via the `open` prop\n if (save.pending) return; // never drop a recording mid-hand-off\n if (recorderState === \"preview\") {\n setDiscardConfirmOpen(true);\n return;\n }\n closeDialogImmediately();\n },\n [recorderState, save.pending, closeDialogImmediately]\n );\n\n const isRecording = recorderState === \"recording\";\n const isPreview = recorderState === \"preview\";\n const isIdle = recorderState === \"idle\";\n\n // The label shows the REAL cap (\"0:42 / 1:00\"), not the earlier auto-stop\n // point — the promise to the user is the cap; the margin is internal.\n const elapsedLabel = maxRecordDurationSec\n ? `${formatDuration(elapsedMs)} / ${formatDuration(maxRecordDurationSec * 1000)}`\n : formatDuration(elapsedMs);\n\n return (\n <>\n <Dialog open={open} onOpenChange={handleDialogOpenChange}>\n <DialogContent className=\"max-w-md\">\n <DialogHeader>\n <DialogTitle>Record</DialogTitle>\n <DialogDescription>\n {isIdle && \"Choose audio or video, then press Start.\"}\n {isRecording && \"Recording…\"}\n {isPreview && \"Review your recording. Save to upload, or Re-record to try again.\"}\n </DialogDescription>\n </DialogHeader>\n\n {/* Kind toggle — only active in idle state */}\n <div className=\"flex flex-wrap gap-2\">\n {canRecVideo && (\n <Button\n type=\"button\"\n variant={recordKind === \"video\" ? \"default\" : \"secondary\"}\n aria-pressed={recordKind === \"video\"}\n onClick={() => handleSelectKind(\"video\")}\n disabled={!isIdle || acquiring}\n icon={<Video className=\"icon-xs\" />}\n >\n Video\n </Button>\n )}\n {canRecAudio && (\n <Button\n type=\"button\"\n variant={recordKind === \"audio\" ? \"default\" : \"secondary\"}\n aria-pressed={recordKind === \"audio\"}\n onClick={() => handleSelectKind(\"audio\")}\n disabled={!isIdle || acquiring}\n icon={<Mic className=\"icon-xs\" />}\n >\n Audio\n </Button>\n )}\n {canPhoto && onRequestPhoto && (\n <Button\n type=\"button\"\n variant=\"secondary\"\n onClick={() => {\n onRequestPhoto();\n onOpenChange(false);\n }}\n disabled={!isIdle}\n icon={<Camera className=\"icon-xs\" />}\n >\n Photo\n </Button>\n )}\n </div>\n\n {/* Live video preview — rendered in idle+recording states for video kind */}\n {recordKind === \"video\" && !isPreview && (\n <div className=\"relative mt-2 rounded-md overflow-hidden bg-[hsl(var(--neutral-black))] aspect-video\">\n <video\n ref={livePreviewRef}\n className=\"w-full h-full object-contain\"\n playsInline\n muted\n />\n {acquiring && (\n <div className=\"absolute inset-0 flex items-center justify-center\">\n <Spinner size=\"lg\" label=\"Starting camera\" />\n </div>\n )}\n </div>\n )}\n\n {/* Audio waveform — live mic level (idle = ready indicator, recording = active) */}\n {recordKind === \"audio\" && !isPreview && (\n <div className=\"relative mt-2 rounded-md bg-muted p-2 text-primary\">\n <canvas\n ref={waveformCanvasRef}\n width={480}\n height={80}\n className=\"w-full h-20\"\n aria-label=\"Audio waveform\"\n />\n {acquiring && (\n <div className=\"absolute inset-0 flex items-center justify-center\">\n <Spinner size=\"lg\" label=\"Starting microphone\" />\n </div>\n )}\n </div>\n )}\n\n {error && (\n <p className=\"text-sm text-destructive\" role=\"alert\">\n {error}\n </p>\n )}\n\n {/* Recording indicator + elapsed timer */}\n {isRecording && (\n <div className=\"flex items-center gap-2 text-sm\" aria-live=\"polite\">\n <span\n className=\"inline-block h-2.5 w-2.5 rounded-full bg-[color:var(--recording-indicator)] animate-pulse\"\n aria-label=\"Recording\"\n />\n <span className=\"tabular-nums\">{elapsedLabel}</span>\n </div>\n )}\n\n {/* Recorded preview — only in preview state */}\n {isPreview && recordPreviewUrl && (\n <div className=\"mt-2\">\n <MediaPreview\n url={recordPreviewUrl}\n type={recordKind}\n controls\n priority\n className=\"w-full rounded-md\"\n />\n </div>\n )}\n\n <DialogFooter className=\"flex-row justify-between gap-2\">\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => handleDialogOpenChange(false)}\n disabled={save.pending}\n icon={<X className=\"icon-xs\" />}\n >\n Close\n </Button>\n\n {isIdle && (\n <Button\n type=\"button\"\n variant=\"default\"\n onClick={() => void start.run(recordKind)}\n disabled={disabled || isLoading || acquiring}\n pending={start.pending}\n icon={recordKind === \"video\" ? <Video className=\"icon-xs\" /> : <Mic className=\"icon-xs\" />}\n >\n Start\n </Button>\n )}\n\n {isRecording && (\n <Button type=\"button\" variant=\"default\" onClick={stopRecording}>\n Stop\n </Button>\n )}\n\n {isPreview && (\n <div className=\"flex gap-2\">\n <Button type=\"button\" variant=\"secondary\" onClick={handleReRecord} disabled={save.pending} icon={<RotateCcw className=\"icon-xs\" />}>\n Re-record\n </Button>\n <Button\n type=\"button\"\n variant=\"default\"\n onClick={() => void save.run()}\n disabled={disabled || isLoading}\n pending={save.pending}\n icon={<Check className=\"icon-xs\" />}\n >\n Save\n </Button>\n </div>\n )}\n </DialogFooter>\n </DialogContent>\n </Dialog>\n\n <AlertDialog open={discardConfirmOpen} onOpenChange={setDiscardConfirmOpen}>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>Discard recording?</AlertDialogTitle>\n <AlertDialogDescription>\n You have a recorded clip that hasn't been saved. Closing now will discard it.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>Keep recording</AlertDialogCancel>\n <AlertDialogAction onClick={closeDialogImmediately}>\n Discard\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n </>\n );\n}\n"]}
1
+ {"version":3,"file":"record-dialog.js","sourceRoot":"","sources":["../../../src/react/components/record-dialog.tsx"],"names":[],"mappings":"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","sourcesContent":["'use client';\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { Camera, Video, Mic, X, RotateCcw, Check } from 'lucide-react';\nimport { startWaveformLoop } from '@ttt-productions/media-viewer';\nimport { MediaPreview } from '@ttt-productions/media-viewer/react';\nimport { ensureFileWithContentType } from '../../lib/infer-content-type.js';\nimport {\n Button,\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n Spinner,\n useAsyncAction,\n} from '@ttt-productions/ui-core/react';\n\ntype RecorderState = 'idle' | 'recording' | 'preview';\n\n// An explicit supported container keeps mr.mimeType deterministic; Safari has no webm and falls\n// through to mp4.\nconst RECORDER_MIME_CANDIDATES: Record<'audio' | 'video', readonly string[]> = {\n audio: ['audio/webm;codecs=opus', 'audio/webm', 'audio/mp4'],\n video: ['video/webm;codecs=vp9,opus', 'video/webm', 'video/mp4'],\n};\n\nfunction pickRecorderMimeType(kind: 'audio' | 'video'): string | undefined {\n if (typeof MediaRecorder === 'undefined' || typeof MediaRecorder.isTypeSupported !== 'function') {\n return undefined;\n }\n for (const candidate of RECORDER_MIME_CANDIDATES[kind]) {\n try {\n if (MediaRecorder.isTypeSupported(candidate)) return candidate;\n } catch {}\n }\n return undefined;\n}\n\n// mp4 is not in the ambiguous-extension map, so an audio recording is named .m4a whatever\n// container type the recorder reports.\nfunction recordingFileName(mime: string, kind: 'audio' | 'video'): string {\n const base = mime.split(';')[0].trim().toLowerCase();\n const ext =\n base === 'audio/mp4' || base === 'video/mp4'\n ? kind === 'audio'\n ? 'm4a'\n : 'mp4'\n : base === 'audio/ogg' || base === 'video/ogg'\n ? 'ogg'\n : 'webm';\n return `recording.${ext}`;\n}\n\n// A MediaRecorder blob runs a little longer than start() to stop() (muxer flush, frame-end\n// duration, late timers) and both duration gates are exact, so recording stops before the cap.\nconst AUTO_STOP_SAFETY_MARGIN_MS = 750;\n\nexport function autoStopDelayMs(maxRecordDurationSec: number): number {\n const capMs = Math.floor(maxRecordDurationSec * 1000);\n return Math.max(capMs - AUTO_STOP_SAFETY_MARGIN_MS, Math.ceil(capMs / 2));\n}\n\ninterface RecordDialogProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n initialKind: 'audio' | 'video';\n canPhoto: boolean;\n canRecVideo: boolean;\n canRecAudio: boolean;\n cameraFacingMode?: 'user' | 'environment';\n maxRecordDurationSec?: number;\n disabled?: boolean;\n isLoading?: boolean;\n onRecorded: (\n file: File,\n previewUrl: string,\n recordedKind: 'audio' | 'video',\n ) => void | Promise<void>;\n onRequestPhoto?: () => void;\n}\n\nfunction formatDuration(ms: number): string {\n const totalSec = Math.max(0, Math.floor(ms / 1000));\n const m = Math.floor(totalSec / 60);\n const s = totalSec % 60;\n return `${m}:${s.toString().padStart(2, '0')}`;\n}\n\nexport function RecordDialog({\n open,\n onOpenChange,\n initialKind,\n canPhoto,\n canRecVideo,\n canRecAudio,\n cameraFacingMode,\n maxRecordDurationSec,\n disabled = false,\n isLoading = false,\n onRecorded,\n onRequestPhoto,\n}: RecordDialogProps) {\n const [recordKind, setRecordKind] = useState<'audio' | 'video'>(initialKind);\n const [recorderState, setRecorderState] = useState<RecorderState>('idle');\n const [recordPreviewUrl, setRecordPreviewUrl] = useState<string | null>(null);\n const [recordedFile, setRecordedFile] = useState<File | null>(null);\n const [elapsedMs, setElapsedMs] = useState(0);\n const [discardConfirmOpen, setDiscardConfirmOpen] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [acquiring, setAcquiring] = useState(false);\n\n const mediaRecorderRef = useRef<MediaRecorder | null>(null);\n const recordStreamRef = useRef<MediaStream | null>(null);\n const liveStreamKindRef = useRef<'audio' | 'video' | null>(null);\n const recordChunksRef = useRef<BlobPart[]>([]);\n const lastRecordUrlRef = useRef<string | null>(null);\n const livePreviewRef = useRef<HTMLVideoElement | null>(null);\n const autoStopTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n // An acquisition that resolves after a teardown belongs to nobody and is never attached.\n const acquireGenRef = useRef(0);\n const previewReqRef = useRef(0);\n\n const startedAtRef = useRef<number>(0);\n const elapsedIntervalRef = useRef<ReturnType<typeof setInterval> | null>(null);\n\n const audioContextRef = useRef<AudioContext | null>(null);\n const audioAnalyserRef = useRef<AnalyserNode | null>(null);\n const audioSourceRef = useRef<MediaStreamAudioSourceNode | null>(null);\n const waveformStopRef = useRef<(() => void) | null>(null);\n const waveformCanvasRef = useRef<HTMLCanvasElement | null>(null);\n\n useEffect(() => {\n if (open) {\n setRecordKind(initialKind);\n setRecorderState('idle');\n setRecordedFile(null);\n setRecordPreviewUrl(null);\n setElapsedMs(0);\n setDiscardConfirmOpen(false);\n setError(null);\n }\n }, [open, initialKind]);\n\n const revokeLastRecordUrl = useCallback(() => {\n if (!lastRecordUrlRef.current) return;\n try {\n URL.revokeObjectURL(lastRecordUrlRef.current);\n } catch {}\n lastRecordUrlRef.current = null;\n }, []);\n\n const makeRecordUrl = useCallback(\n (blob: Blob) => {\n revokeLastRecordUrl();\n const url = URL.createObjectURL(blob);\n lastRecordUrlRef.current = url;\n return url;\n },\n [revokeLastRecordUrl],\n );\n\n const stopElapsedTimer = useCallback(() => {\n if (elapsedIntervalRef.current) {\n clearInterval(elapsedIntervalRef.current);\n elapsedIntervalRef.current = null;\n }\n }, []);\n\n const startElapsedTimer = useCallback(() => {\n stopElapsedTimer();\n startedAtRef.current = Date.now();\n setElapsedMs(0);\n elapsedIntervalRef.current = setInterval(() => {\n setElapsedMs(Date.now() - startedAtRef.current);\n }, 100);\n }, [stopElapsedTimer]);\n\n const stopWaveform = useCallback(() => {\n waveformStopRef.current?.();\n waveformStopRef.current = null;\n try {\n audioSourceRef.current?.disconnect();\n } catch {}\n audioSourceRef.current = null;\n audioAnalyserRef.current = null;\n const ctx = audioContextRef.current;\n audioContextRef.current = null;\n if (ctx && ctx.state !== 'closed') {\n ctx.close().catch(() => {});\n }\n }, []);\n\n const startWaveform = useCallback(\n (stream: MediaStream) => {\n stopWaveform();\n try {\n const AudioCtx: typeof AudioContext =\n (window as any).AudioContext || (window as any).webkitAudioContext;\n if (!AudioCtx) return;\n\n const ctx = new AudioCtx();\n const source = ctx.createMediaStreamSource(stream);\n const analyser = ctx.createAnalyser();\n analyser.fftSize = 256;\n source.connect(analyser);\n\n audioContextRef.current = ctx;\n audioSourceRef.current = source;\n audioAnalyserRef.current = analyser;\n\n waveformStopRef.current = startWaveformLoop({\n analyser,\n getCanvas: () => waveformCanvasRef.current,\n mode: 'line',\n });\n } catch {}\n },\n [stopWaveform],\n );\n\n const teardownCapture = useCallback(() => {\n acquireGenRef.current += 1;\n if (autoStopTimeoutRef.current) {\n clearTimeout(autoStopTimeoutRef.current);\n autoStopTimeoutRef.current = null;\n }\n mediaRecorderRef.current = null;\n\n const s = recordStreamRef.current;\n recordStreamRef.current = null;\n liveStreamKindRef.current = null;\n if (s) s.getTracks().forEach((t) => t.stop());\n\n if (livePreviewRef.current) {\n livePreviewRef.current.srcObject = null;\n }\n\n recordChunksRef.current = [];\n\n stopElapsedTimer();\n stopWaveform();\n }, [stopElapsedTimer, stopWaveform]);\n\n const acquireStream = useCallback(\n async (kind: 'audio' | 'video') => {\n const wantVideo = kind === 'video';\n const facingMode = cameraFacingMode ?? 'user';\n const gen = acquireGenRef.current;\n const stream = await navigator.mediaDevices.getUserMedia({\n audio: true,\n video: wantVideo ? { facingMode } : false,\n });\n if (gen !== acquireGenRef.current) {\n stream.getTracks().forEach((t) => t.stop());\n return null;\n }\n recordStreamRef.current = stream;\n liveStreamKindRef.current = kind;\n setError(null);\n if (wantVideo && livePreviewRef.current) {\n livePreviewRef.current.srcObject = stream;\n livePreviewRef.current.muted = true;\n try {\n await livePreviewRef.current.play();\n } catch {}\n } else if (!wantVideo) {\n startWaveform(stream);\n }\n return stream;\n },\n [cameraFacingMode, startWaveform],\n );\n\n const startLivePreview = useCallback(\n async (kind: 'audio' | 'video') => {\n teardownCapture();\n const req = ++previewReqRef.current;\n setAcquiring(true);\n try {\n await acquireStream(kind);\n } catch (e) {\n setError(e instanceof Error ? e.message : 'Camera/microphone access denied.');\n } finally {\n if (req === previewReqRef.current) setAcquiring(false);\n }\n },\n [teardownCapture, acquireStream],\n );\n\n useEffect(() => {\n if (open) {\n void startLivePreview(initialKind);\n }\n return () => {\n teardownCapture();\n revokeLastRecordUrl();\n };\n }, [open, initialKind, startLivePreview, teardownCapture, revokeLastRecordUrl]);\n\n const startRecording = useCallback(\n async (kind: 'audio' | 'video') => {\n revokeLastRecordUrl();\n setRecordPreviewUrl(null);\n setRecordedFile(null);\n setRecordKind(kind);\n\n const wantVideo = kind === 'video';\n\n let stream = recordStreamRef.current;\n if (!stream || liveStreamKindRef.current !== kind) {\n try {\n stream = await acquireStream(kind);\n } catch (e) {\n setError(e instanceof Error ? e.message : 'Camera/microphone access denied.');\n return;\n }\n }\n if (!stream) return;\n\n const preferredMimeType = pickRecorderMimeType(kind);\n let mr: MediaRecorder;\n try {\n mr = preferredMimeType\n ? new MediaRecorder(stream, { mimeType: preferredMimeType })\n : new MediaRecorder(stream);\n } catch {\n mr = new MediaRecorder(stream);\n }\n mediaRecorderRef.current = mr;\n recordChunksRef.current = [];\n\n mr.ondataavailable = (e) => {\n if (e.data && e.data.size > 0) recordChunksRef.current.push(e.data);\n };\n\n mr.onstop = () => {\n const blob = new Blob(recordChunksRef.current, {\n type: mr.mimeType || preferredMimeType || (wantVideo ? 'video/webm' : 'audio/webm'),\n });\n\n const rawFile = new File([blob], recordingFileName(blob.type, kind), { type: blob.type });\n const file = ensureFileWithContentType(rawFile, wantVideo ? 'video' : 'audio');\n const url = makeRecordUrl(file);\n\n setRecordedFile(file);\n setRecordPreviewUrl(url);\n setRecorderState('preview');\n\n teardownCapture();\n };\n\n mr.start();\n setRecorderState('recording');\n startElapsedTimer();\n\n if (maxRecordDurationSec && maxRecordDurationSec > 0) {\n autoStopTimeoutRef.current = setTimeout(() => {\n try {\n if (mediaRecorderRef.current && mediaRecorderRef.current.state === 'recording') {\n mediaRecorderRef.current.stop();\n }\n } catch {}\n }, autoStopDelayMs(maxRecordDurationSec));\n }\n },\n [\n acquireStream,\n maxRecordDurationSec,\n makeRecordUrl,\n revokeLastRecordUrl,\n teardownCapture,\n startElapsedTimer,\n ],\n );\n\n const stopRecording = useCallback(() => {\n const mr = mediaRecorderRef.current;\n if (mr && mr.state === 'recording') {\n try {\n mr.stop();\n } catch {\n teardownCapture();\n setRecorderState('idle');\n }\n } else {\n teardownCapture();\n setRecorderState('idle');\n }\n }, [teardownCapture]);\n\n const handleReRecord = useCallback(() => {\n revokeLastRecordUrl();\n setRecordPreviewUrl(null);\n setRecordedFile(null);\n setElapsedMs(0);\n setError(null);\n setRecorderState('idle');\n void startLivePreview(recordKind);\n }, [revokeLastRecordUrl, startLivePreview, recordKind]);\n\n const handleSelectKind = useCallback(\n (kind: 'audio' | 'video') => {\n setRecordKind(kind);\n setError(null);\n void startLivePreview(kind);\n },\n [startLivePreview],\n );\n\n const reportError = useCallback((e: unknown) => {\n setError(e instanceof Error ? e.message : 'Something went wrong with the recording.');\n }, []);\n\n const start = useAsyncAction((kind: 'audio' | 'video') => startRecording(kind), {\n onError: reportError,\n });\n\n const save = useAsyncAction(\n async () => {\n if (!recordedFile || !recordPreviewUrl) return;\n await onRecorded(recordedFile, recordPreviewUrl, recordKind);\n onOpenChange(false);\n },\n { onError: reportError },\n );\n\n const closeDialogImmediately = useCallback(() => {\n const mr = mediaRecorderRef.current;\n if (mr && mr.state === 'recording') {\n try {\n mr.stop();\n } catch {}\n }\n teardownCapture();\n revokeLastRecordUrl();\n setRecordedFile(null);\n setRecordPreviewUrl(null);\n setElapsedMs(0);\n setRecorderState('idle');\n setDiscardConfirmOpen(false);\n onOpenChange(false);\n }, [teardownCapture, revokeLastRecordUrl, onOpenChange]);\n\n const handleDialogOpenChange = useCallback(\n (v: boolean) => {\n if (v) return;\n if (save.pending) return;\n if (recorderState === 'preview') {\n setDiscardConfirmOpen(true);\n return;\n }\n closeDialogImmediately();\n },\n [recorderState, save.pending, closeDialogImmediately],\n );\n\n const isRecording = recorderState === 'recording';\n const isPreview = recorderState === 'preview';\n const isIdle = recorderState === 'idle';\n\n const elapsedLabel = maxRecordDurationSec\n ? `${formatDuration(elapsedMs)} / ${formatDuration(maxRecordDurationSec * 1000)}`\n : formatDuration(elapsedMs);\n\n return (\n <>\n <Dialog open={open} onOpenChange={handleDialogOpenChange}>\n <DialogContent className=\"max-w-md\">\n <DialogHeader>\n <DialogTitle>Record</DialogTitle>\n <DialogDescription>\n {isIdle && 'Choose audio or video, then press Start.'}\n {isRecording && 'Recording…'}\n {isPreview && 'Review your recording. Save to upload, or Re-record to try again.'}\n </DialogDescription>\n </DialogHeader>\n\n <div className=\"flex flex-wrap gap-2\">\n {canRecVideo && (\n <Button\n type=\"button\"\n variant={recordKind === 'video' ? 'default' : 'secondary'}\n aria-pressed={recordKind === 'video'}\n onClick={() => handleSelectKind('video')}\n disabled={!isIdle || acquiring}\n icon={<Video className=\"icon-xs\" />}\n >\n Video\n </Button>\n )}\n {canRecAudio && (\n <Button\n type=\"button\"\n variant={recordKind === 'audio' ? 'default' : 'secondary'}\n aria-pressed={recordKind === 'audio'}\n onClick={() => handleSelectKind('audio')}\n disabled={!isIdle || acquiring}\n icon={<Mic className=\"icon-xs\" />}\n >\n Audio\n </Button>\n )}\n {canPhoto && onRequestPhoto && (\n <Button\n type=\"button\"\n variant=\"secondary\"\n onClick={() => {\n onRequestPhoto();\n onOpenChange(false);\n }}\n disabled={!isIdle}\n icon={<Camera className=\"icon-xs\" />}\n >\n Photo\n </Button>\n )}\n </div>\n\n {recordKind === 'video' && !isPreview && (\n <div className=\"relative mt-2 rounded-md overflow-hidden bg-[hsl(var(--neutral-black))] aspect-video\">\n <video\n ref={livePreviewRef}\n className=\"w-full h-full object-contain\"\n playsInline\n muted\n />\n {acquiring && (\n <div className=\"absolute inset-0 flex items-center justify-center\">\n <Spinner size=\"lg\" label=\"Starting camera\" />\n </div>\n )}\n </div>\n )}\n\n {recordKind === 'audio' && !isPreview && (\n <div className=\"relative mt-2 rounded-md bg-muted p-2 text-primary\">\n <canvas\n ref={waveformCanvasRef}\n width={480}\n height={80}\n className=\"w-full h-20\"\n aria-label=\"Audio waveform\"\n />\n {acquiring && (\n <div className=\"absolute inset-0 flex items-center justify-center\">\n <Spinner size=\"lg\" label=\"Starting microphone\" />\n </div>\n )}\n </div>\n )}\n\n {error && (\n <p className=\"text-sm text-destructive\" role=\"alert\">\n {error}\n </p>\n )}\n\n {isRecording && (\n <div className=\"flex items-center gap-2 text-sm\" aria-live=\"polite\">\n <span\n className=\"inline-block h-2.5 w-2.5 rounded-full bg-[color:var(--recording-indicator)] animate-pulse\"\n aria-label=\"Recording\"\n />\n <span className=\"tabular-nums\">{elapsedLabel}</span>\n </div>\n )}\n\n {isPreview && recordPreviewUrl && (\n <div className=\"mt-2\">\n <MediaPreview\n url={recordPreviewUrl}\n type={recordKind}\n controls\n priority\n className=\"w-full rounded-md\"\n />\n </div>\n )}\n\n <DialogFooter className=\"flex-row justify-between gap-2\">\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => handleDialogOpenChange(false)}\n disabled={save.pending}\n icon={<X className=\"icon-xs\" />}\n >\n Close\n </Button>\n\n {isIdle && (\n <Button\n type=\"button\"\n variant=\"default\"\n onClick={() => void start.run(recordKind)}\n disabled={disabled || isLoading || acquiring}\n pending={start.pending}\n icon={\n recordKind === 'video' ? (\n <Video className=\"icon-xs\" />\n ) : (\n <Mic className=\"icon-xs\" />\n )\n }\n >\n Start\n </Button>\n )}\n\n {isRecording && (\n <Button type=\"button\" variant=\"default\" onClick={stopRecording}>\n Stop\n </Button>\n )}\n\n {isPreview && (\n <div className=\"flex gap-2\">\n <Button\n type=\"button\"\n variant=\"secondary\"\n onClick={handleReRecord}\n disabled={save.pending}\n icon={<RotateCcw className=\"icon-xs\" />}\n >\n Re-record\n </Button>\n <Button\n type=\"button\"\n variant=\"default\"\n onClick={() => void save.run()}\n disabled={disabled || isLoading}\n pending={save.pending}\n icon={<Check className=\"icon-xs\" />}\n >\n Save\n </Button>\n </div>\n )}\n </DialogFooter>\n </DialogContent>\n </Dialog>\n\n <AlertDialog open={discardConfirmOpen} onOpenChange={setDiscardConfirmOpen}>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>Discard recording?</AlertDialogTitle>\n <AlertDialogDescription>\n You have a recorded clip that hasn't been saved. Closing now will discard it.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>Keep recording</AlertDialogCancel>\n <AlertDialogAction onClick={closeDialogImmediately}>Discard</AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n </>\n );\n}\n"]}
@@ -1,3 +1,3 @@
1
- import type { FileInputProps } from "../../types.js";
2
- export declare function VideoInput(props: Omit<FileInputProps, "acceptTypes">): import("react").JSX.Element;
1
+ import type { FileInputProps } from '../../types.js';
2
+ export declare function VideoInput(props: Omit<FileInputProps, 'acceptTypes'>): import("react").JSX.Element;
3
3
  //# sourceMappingURL=video-input.d.ts.map
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { FileInput } from "./file-input.js";
2
+ import { FileInput } from './file-input.js';
3
3
  export function VideoInput(props) {
4
- return _jsx(FileInput, { ...props, acceptTypes: ["video"] });
4
+ return _jsx(FileInput, { ...props, acceptTypes: ['video'] });
5
5
  }
6
6
  //# sourceMappingURL=video-input.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"video-input.js","sourceRoot":"","sources":["../../../src/react/components/video-input.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,MAAM,UAAU,UAAU,CAAC,KAA0C;IACnE,OAAO,KAAC,SAAS,OAAK,KAAK,EAAE,WAAW,EAAE,CAAC,OAAO,CAAC,GAAI,CAAC;AAC1D,CAAC","sourcesContent":["import type { FileInputProps } from \"../../types.js\";\nimport { FileInput } from \"./file-input.js\";\n\nexport function VideoInput(props: Omit<FileInputProps, \"acceptTypes\">) {\n return <FileInput {...props} acceptTypes={[\"video\"]} />;\n}\n"]}
1
+ {"version":3,"file":"video-input.js","sourceRoot":"","sources":["../../../src/react/components/video-input.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,MAAM,UAAU,UAAU,CAAC,KAA0C;IACnE,OAAO,KAAC,SAAS,OAAK,KAAK,EAAE,WAAW,EAAE,CAAC,OAAO,CAAC,GAAI,CAAC;AAC1D,CAAC","sourcesContent":["import type { FileInputProps } from '../../types.js';\nimport { FileInput } from './file-input.js';\n\nexport function VideoInput(props: Omit<FileInputProps, 'acceptTypes'>) {\n return <FileInput {...props} acceptTypes={['video']} />;\n}\n"]}
@@ -1,9 +1,9 @@
1
- export { FileInput } from "./components/file-input.js";
2
- export { ImageInput } from "./components/image-input.js";
3
- export { VideoInput } from "./components/video-input.js";
4
- export { AudioInput } from "./components/audio-input.js";
5
- export { MediaInput } from "./components/media-input.js";
6
- export type { PhotoCaptureModalProps } from "./components/photo-capture-modal.js";
7
- export { PhotoCaptureModal } from "./components/photo-capture-modal.js";
8
- export { RecordDialog } from "./components/record-dialog.js";
1
+ export { FileInput } from './components/file-input.js';
2
+ export { ImageInput } from './components/image-input.js';
3
+ export { VideoInput } from './components/video-input.js';
4
+ export { AudioInput } from './components/audio-input.js';
5
+ export { MediaInput } from './components/media-input.js';
6
+ export type { PhotoCaptureModalProps } from './components/photo-capture-modal.js';
7
+ export { PhotoCaptureModal } from './components/photo-capture-modal.js';
8
+ export { RecordDialog } from './components/record-dialog.js';
9
9
  //# sourceMappingURL=index.d.ts.map
@@ -1,9 +1,9 @@
1
- "use client";
2
- export { FileInput } from "./components/file-input.js";
3
- export { ImageInput } from "./components/image-input.js";
4
- export { VideoInput } from "./components/video-input.js";
5
- export { AudioInput } from "./components/audio-input.js";
6
- export { MediaInput } from "./components/media-input.js";
7
- export { PhotoCaptureModal } from "./components/photo-capture-modal.js";
8
- export { RecordDialog } from "./components/record-dialog.js";
1
+ 'use client';
2
+ export { FileInput } from './components/file-input.js';
3
+ export { ImageInput } from './components/image-input.js';
4
+ export { VideoInput } from './components/video-input.js';
5
+ export { AudioInput } from './components/audio-input.js';
6
+ export { MediaInput } from './components/media-input.js';
7
+ export { PhotoCaptureModal } from './components/photo-capture-modal.js';
8
+ export { RecordDialog } from './components/record-dialog.js';
9
9
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAEzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AACxE,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC","sourcesContent":["\"use client\";\n\nexport { FileInput } from \"./components/file-input.js\";\nexport { ImageInput } from \"./components/image-input.js\";\nexport { VideoInput } from \"./components/video-input.js\";\nexport { AudioInput } from \"./components/audio-input.js\";\nexport { MediaInput } from \"./components/media-input.js\";\nexport type { PhotoCaptureModalProps } from \"./components/photo-capture-modal.js\";\nexport { PhotoCaptureModal } from \"./components/photo-capture-modal.js\";\nexport { RecordDialog } from \"./components/record-dialog.js\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAEzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AACxE,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC","sourcesContent":["'use client';\n\nexport { FileInput } from './components/file-input.js';\nexport { ImageInput } from './components/image-input.js';\nexport { VideoInput } from './components/video-input.js';\nexport { AudioInput } from './components/audio-input.js';\nexport { MediaInput } from './components/media-input.js';\nexport type { PhotoCaptureModalProps } from './components/photo-capture-modal.js';\nexport { PhotoCaptureModal } from './components/photo-capture-modal.js';\nexport { RecordDialog } from './components/record-dialog.js';\n"]}
package/dist/types.d.ts CHANGED
@@ -1,14 +1,13 @@
1
- import type { ClientMediaClaim, FileCategory as ContractsFileCategory, MediaKind, MediaProcessingSpec, MediaOriginSpec, SimplifiedMediaType, VideoOrientation, MediaCropSpec, UploadState } from "@ttt-productions/media-schemas";
2
- /** FileCategory is owned by contracts. */
1
+ import type { ClientMediaClaim, FileCategory as ContractsFileCategory, MediaKind, MediaProcessingSpec, MediaOriginSpec, SimplifiedMediaType, VideoOrientation, MediaCropSpec, UploadState } from '@ttt-productions/media-schemas';
3
2
  export type FileCategory = ContractsFileCategory;
4
3
  export interface CropConfig {
5
4
  aspectRatio: number;
6
5
  aspectRatioDisplay?: string;
7
- shape: "rect" | "round";
6
+ shape: 'rect' | 'round';
8
7
  outputWidth: number;
9
8
  outputHeight: number;
10
9
  }
11
- export type FileInputErrorCode = "invalid_type" | "too_large" | "too_long" | "orientation_mismatch" | "aspect_ratio_mismatch" | "dimensions_mismatch" | "read_failed" | "crop_failed" | "unknown";
10
+ export type FileInputErrorCode = 'invalid_type' | 'too_large' | 'too_long' | 'orientation_mismatch' | 'aspect_ratio_mismatch' | 'dimensions_mismatch' | 'read_failed' | 'crop_failed' | 'unknown';
12
11
  export interface FileInputError {
13
12
  code: FileInputErrorCode;
14
13
  message: string;
@@ -31,7 +30,6 @@ export interface FileInputProps {
31
30
  disabled?: boolean;
32
31
  isLoading?: boolean;
33
32
  buttonLabel?: string;
34
- /** Accessible name of the icon-only button that clears the selected file. Default "Clear selected file". */
35
33
  clearLabel?: string;
36
34
  className?: string;
37
35
  variant?: any;
@@ -42,7 +40,6 @@ export interface FileInputProps {
42
40
  cropConfig?: CropConfig;
43
41
  defaultShowDetails?: boolean;
44
42
  }
45
- /** Used by MediaInput (spec-driven selection/capture/record). */
46
43
  export interface SelectedMediaMeta {
47
44
  kind: MediaKind;
48
45
  mime?: string;
@@ -58,15 +55,6 @@ export interface MediaInputChangePayload {
58
55
  file?: File;
59
56
  previewUrl?: string;
60
57
  meta?: SelectedMediaMeta;
61
- /**
62
- * What the user actually DID (canonical-upload-content-classification):
63
- * `media-recorder` / `camera-capture` are STRONG claims (the component itself
64
- * requested that capture kind — an audio recording asked for `video:false`);
65
- * `file-picker` is an ADVISORY inference from browser metadata (`kind:'file'`
66
- * when nothing narrower is known). Crop/normalization preserves the original
67
- * claim. Untrusted context for the server — never classification authority.
68
- * Present on every successful selection; absent only on the error payload.
69
- */
70
58
  claim?: ClientMediaClaim;
71
59
  autoFormat?: boolean;
72
60
  croppedBlob?: Blob;
@@ -79,61 +67,17 @@ export interface MediaInputProps {
79
67
  isLoading?: boolean;
80
68
  className?: string;
81
69
  buttonLabel?: string;
82
- /** Accessible name of the icon-only button that clears the selected file. Default "Clear selected file". */
83
70
  clearLabel?: string;
84
- /**
85
- * Extra advisory notes shown in the "Info" affordance alongside the built-in default
86
- * ("keep your own copy — this isn't a backup/storage service"). Every MediaInput shows that
87
- * default note; pass surface-specific notes here to append to it. The Info button always renders.
88
- */
89
71
  helpNotes?: string[];
90
- /** Phase-aware upload state. When provided, drives the upload/processing UI. */
91
72
  uploadState?: UploadState | null;
92
- /**
93
- * Minimum file size (bytes) before showing a real progress bar.
94
- * Files smaller than this show an indeterminate spinner during upload instead.
95
- * Defaults to `DEFAULT_PROGRESS_BAR_MIN_BYTES` (512 KB) when omitted.
96
- * Pass `Infinity` to always use the spinner. Pass `0` to always use the bar.
97
- */
98
73
  progressBarMinBytes?: number;
99
- /** Currently selected file. Shows a semantic media label + clear button when set. */
100
74
  selectedFile?: File | null;
101
- /** Called when user clears the selected file. */
102
75
  onClear?: () => void;
103
- /**
104
- * Optional cancel callback. When provided AND the upload is in 'preparing' or
105
- * 'uploading' phase AND `isLoading` is true, an inline X button renders next to
106
- * the status text. Click invokes onCancel — the consumer is responsible for
107
- * aborting the underlying upload (e.g. via AbortController.abort()). Never
108
- * renders during 'finalizing'.
109
- */
110
76
  onCancel?: () => void;
111
- /**
112
- * Optional guard fired before opening the OS picker / capture UI for ANY
113
- * action (choose file, take photo, record video, record audio). Return false
114
- * — or a Promise resolving to false — to abort before the picker/capture
115
- * opens. Consumers use this to run a precondition (e.g. an email-verification
116
- * gate) on the click, not after a file has already been selected.
117
- */
118
77
  onBeforeSelect?: () => boolean | Promise<boolean>;
119
78
  onChange: (payload: MediaInputChangePayload) => void;
120
79
  }
121
- /**
122
- * Imperative handle exposed by {@link MediaInput} via `ref`. Additive — existing
123
- * ref-less usage is unaffected.
124
- */
125
80
  export interface MediaInputHandle {
126
- /**
127
- * Programmatically open the canonical selection path, exactly as clicking the
128
- * trigger button does:
129
- * - exactly one enabled action → runs that action directly (choose file / photo
130
- * / record), honoring `onBeforeSelect`, validation, and crop;
131
- * - multiple enabled actions → opens the existing choice dropdown.
132
- *
133
- * No-op while `disabled` or `isLoading`, or when no action is enabled. Must be
134
- * called synchronously from a user gesture so the browser file dialog can open.
135
- * It never bypasses the trigger gates (no hidden-input shortcut).
136
- */
137
81
  openSelection: () => void;
138
82
  }
139
83
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["import type {\n ClientMediaClaim,\n FileCategory as ContractsFileCategory,\n MediaKind,\n MediaProcessingSpec,\n MediaOriginSpec,\n SimplifiedMediaType,\n VideoOrientation,\n MediaCropSpec,\n UploadState,\n} from \"@ttt-productions/media-schemas\";\n\n/** FileCategory is owned by contracts. */\nexport type FileCategory = ContractsFileCategory;\n\n\nexport interface CropConfig {\n aspectRatio: number;\n aspectRatioDisplay?: string;\n shape: \"rect\" | \"round\";\n outputWidth: number;\n outputHeight: number;\n}\n\nexport type FileInputErrorCode =\n | \"invalid_type\"\n | \"too_large\"\n | \"too_long\"\n | \"orientation_mismatch\"\n | \"aspect_ratio_mismatch\"\n | \"dimensions_mismatch\"\n | \"read_failed\"\n | \"crop_failed\"\n | \"unknown\";\n\nexport interface FileInputError {\n code: FileInputErrorCode;\n message: string;\n details?: Record<string, unknown>;\n}\n\nexport interface FileInputChangePayload {\n type: SimplifiedMediaType;\n file?: File;\n blob?: Blob;\n previewUrl?: string;\n revokePreviewUrl?: () => void;\n error?: FileInputError;\n}\n\nexport interface FileInputProps {\n acceptTypes: SimplifiedMediaType[];\n maxSizeMB: Partial<Record<SimplifiedMediaType, number>>;\n selectedFile?: File | null;\n\n onChange: (payload: FileInputChangePayload) => void;\n onError?: (error: FileInputError) => void;\n\n disabled?: boolean;\n isLoading?: boolean;\n buttonLabel?: string;\n /** Accessible name of the icon-only button that clears the selected file. Default \"Clear selected file\". */\n clearLabel?: string;\n className?: string;\n\n variant?: any;\n size?: any;\n\n uploadProgress?: number | null;\n\n videoMaxDurationSec?: number;\n audioMaxDurationSec?: number;\n\n cropConfig?: CropConfig;\n defaultShowDetails?: boolean;\n}\n\n/** Used by MediaInput (spec-driven selection/capture/record). */\nexport interface SelectedMediaMeta {\n kind: MediaKind;\n mime?: string;\n sizeBytes: number;\n width?: number;\n height?: number;\n durationSec?: number;\n orientation?: VideoOrientation;\n aspectRatio?: number;\n}\n\nexport interface MediaInputChangePayload {\n spec: MediaProcessingSpec;\n file?: File;\n previewUrl?: string;\n meta?: SelectedMediaMeta;\n\n /**\n * What the user actually DID (canonical-upload-content-classification):\n * `media-recorder` / `camera-capture` are STRONG claims (the component itself\n * requested that capture kind — an audio recording asked for `video:false`);\n * `file-picker` is an ADVISORY inference from browser metadata (`kind:'file'`\n * when nothing narrower is known). Crop/normalization preserves the original\n * claim. Untrusted context for the server — never classification authority.\n * Present on every successful selection; absent only on the error payload.\n */\n claim?: ClientMediaClaim;\n\n autoFormat?: boolean;\n croppedBlob?: Blob;\n\n error?: FileInputError;\n}\n\nexport interface MediaInputProps {\n spec: MediaOriginSpec;\n cropOverride?: MediaCropSpec;\n\n disabled?: boolean;\n isLoading?: boolean;\n className?: string;\n buttonLabel?: string;\n /** Accessible name of the icon-only button that clears the selected file. Default \"Clear selected file\". */\n clearLabel?: string;\n\n /**\n * Extra advisory notes shown in the \"Info\" affordance alongside the built-in default\n * (\"keep your own copy — this isn't a backup/storage service\"). Every MediaInput shows that\n * default note; pass surface-specific notes here to append to it. The Info button always renders.\n */\n helpNotes?: string[];\n\n /** Phase-aware upload state. When provided, drives the upload/processing UI. */\n uploadState?: UploadState | null;\n /**\n * Minimum file size (bytes) before showing a real progress bar.\n * Files smaller than this show an indeterminate spinner during upload instead.\n * Defaults to `DEFAULT_PROGRESS_BAR_MIN_BYTES` (512 KB) when omitted.\n * Pass `Infinity` to always use the spinner. Pass `0` to always use the bar.\n */\n progressBarMinBytes?: number;\n /** Currently selected file. Shows a semantic media label + clear button when set. */\n selectedFile?: File | null;\n /** Called when user clears the selected file. */\n onClear?: () => void;\n /**\n * Optional cancel callback. When provided AND the upload is in 'preparing' or\n * 'uploading' phase AND `isLoading` is true, an inline X button renders next to\n * the status text. Click invokes onCancel — the consumer is responsible for\n * aborting the underlying upload (e.g. via AbortController.abort()). Never\n * renders during 'finalizing'.\n */\n onCancel?: () => void;\n\n /**\n * Optional guard fired before opening the OS picker / capture UI for ANY\n * action (choose file, take photo, record video, record audio). Return false\n * — or a Promise resolving to false — to abort before the picker/capture\n * opens. Consumers use this to run a precondition (e.g. an email-verification\n * gate) on the click, not after a file has already been selected.\n */\n onBeforeSelect?: () => boolean | Promise<boolean>;\n\n onChange: (payload: MediaInputChangePayload) => void;\n}\n\n/**\n * Imperative handle exposed by {@link MediaInput} via `ref`. Additive — existing\n * ref-less usage is unaffected.\n */\nexport interface MediaInputHandle {\n /**\n * Programmatically open the canonical selection path, exactly as clicking the\n * trigger button does:\n * - exactly one enabled action → runs that action directly (choose file / photo\n * / record), honoring `onBeforeSelect`, validation, and crop;\n * - multiple enabled actions → opens the existing choice dropdown.\n *\n * No-op while `disabled` or `isLoading`, or when no action is enabled. Must be\n * called synchronously from a user gesture so the browser file dialog can open.\n * It never bypasses the trigger gates (no hidden-input shortcut).\n */\n openSelection: () => void;\n}\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["import type {\n ClientMediaClaim,\n FileCategory as ContractsFileCategory,\n MediaKind,\n MediaProcessingSpec,\n MediaOriginSpec,\n SimplifiedMediaType,\n VideoOrientation,\n MediaCropSpec,\n UploadState,\n} from '@ttt-productions/media-schemas';\n\nexport type FileCategory = ContractsFileCategory;\n\nexport interface CropConfig {\n aspectRatio: number;\n aspectRatioDisplay?: string;\n shape: 'rect' | 'round';\n outputWidth: number;\n outputHeight: number;\n}\n\nexport type FileInputErrorCode =\n | 'invalid_type'\n | 'too_large'\n | 'too_long'\n | 'orientation_mismatch'\n | 'aspect_ratio_mismatch'\n | 'dimensions_mismatch'\n | 'read_failed'\n | 'crop_failed'\n | 'unknown';\n\nexport interface FileInputError {\n code: FileInputErrorCode;\n message: string;\n details?: Record<string, unknown>;\n}\n\nexport interface FileInputChangePayload {\n type: SimplifiedMediaType;\n file?: File;\n blob?: Blob;\n previewUrl?: string;\n revokePreviewUrl?: () => void;\n error?: FileInputError;\n}\n\nexport interface FileInputProps {\n acceptTypes: SimplifiedMediaType[];\n maxSizeMB: Partial<Record<SimplifiedMediaType, number>>;\n selectedFile?: File | null;\n\n onChange: (payload: FileInputChangePayload) => void;\n onError?: (error: FileInputError) => void;\n\n disabled?: boolean;\n isLoading?: boolean;\n buttonLabel?: string;\n clearLabel?: string;\n className?: string;\n\n variant?: any;\n size?: any;\n\n uploadProgress?: number | null;\n\n videoMaxDurationSec?: number;\n audioMaxDurationSec?: number;\n\n cropConfig?: CropConfig;\n defaultShowDetails?: boolean;\n}\n\nexport interface SelectedMediaMeta {\n kind: MediaKind;\n mime?: string;\n sizeBytes: number;\n width?: number;\n height?: number;\n durationSec?: number;\n orientation?: VideoOrientation;\n aspectRatio?: number;\n}\n\nexport interface MediaInputChangePayload {\n spec: MediaProcessingSpec;\n file?: File;\n previewUrl?: string;\n meta?: SelectedMediaMeta;\n\n claim?: ClientMediaClaim;\n\n autoFormat?: boolean;\n croppedBlob?: Blob;\n\n error?: FileInputError;\n}\n\nexport interface MediaInputProps {\n spec: MediaOriginSpec;\n cropOverride?: MediaCropSpec;\n\n disabled?: boolean;\n isLoading?: boolean;\n className?: string;\n buttonLabel?: string;\n clearLabel?: string;\n\n helpNotes?: string[];\n\n uploadState?: UploadState | null;\n progressBarMinBytes?: number;\n selectedFile?: File | null;\n onClear?: () => void;\n onCancel?: () => void;\n\n onBeforeSelect?: () => boolean | Promise<boolean>;\n\n onChange: (payload: MediaInputChangePayload) => void;\n}\n\nexport interface MediaInputHandle {\n openSelection: () => void;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ttt-productions/file-input",
3
- "version": "0.11.15",
3
+ "version": "0.11.17",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/ttt-productions/ttt-packages.git",
@@ -31,9 +31,9 @@
31
31
  "prepublishOnly": "npm run clean && npm run build"
32
32
  },
33
33
  "dependencies": {
34
- "@ttt-productions/ui-core": "^0.11.31",
35
- "@ttt-productions/media-schemas": "^0.14.10",
36
- "@ttt-productions/media-viewer": "^0.10.16",
34
+ "@ttt-productions/ui-core": "^0.11.35",
35
+ "@ttt-productions/media-schemas": "^0.14.12",
36
+ "@ttt-productions/media-viewer": "^0.10.19",
37
37
  "react-easy-crop": "^6.2.3"
38
38
  },
39
39
  "peerDependencies": {