@ttt-productions/file-input 0.11.16 → 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 (38) hide show
  1. package/dist/lib/image-utils.d.ts +0 -1
  2. package/dist/lib/image-utils.d.ts.map +1 -1
  3. package/dist/lib/image-utils.js +1 -2
  4. package/dist/lib/image-utils.js.map +1 -1
  5. package/dist/lib/infer-content-type.d.ts +0 -23
  6. package/dist/lib/infer-content-type.d.ts.map +1 -1
  7. package/dist/lib/infer-content-type.js +2 -56
  8. package/dist/lib/infer-content-type.js.map +1 -1
  9. package/dist/lib/validate-media-duration.d.ts.map +1 -1
  10. package/dist/lib/validate-media-duration.js +2 -7
  11. package/dist/lib/validate-media-duration.js.map +1 -1
  12. package/dist/lib/validate-upload-kind.d.ts +0 -34
  13. package/dist/lib/validate-upload-kind.d.ts.map +1 -1
  14. package/dist/lib/validate-upload-kind.js +0 -17
  15. package/dist/lib/validate-upload-kind.js.map +1 -1
  16. package/dist/react/components/file-input.d.ts.map +1 -1
  17. package/dist/react/components/file-input.js +0 -2
  18. package/dist/react/components/file-input.js.map +1 -1
  19. package/dist/react/components/image-cropper-modal.d.ts.map +1 -1
  20. package/dist/react/components/image-cropper-modal.js +0 -2
  21. package/dist/react/components/image-cropper-modal.js.map +1 -1
  22. package/dist/react/components/media-constraints-hint.d.ts.map +1 -1
  23. package/dist/react/components/media-constraints-hint.js +0 -1
  24. package/dist/react/components/media-constraints-hint.js.map +1 -1
  25. package/dist/react/components/media-input.d.ts.map +1 -1
  26. package/dist/react/components/media-input.js +4 -69
  27. package/dist/react/components/media-input.js.map +1 -1
  28. package/dist/react/components/photo-capture-modal.d.ts.map +1 -1
  29. package/dist/react/components/photo-capture-modal.js +1 -5
  30. package/dist/react/components/photo-capture-modal.js.map +1 -1
  31. package/dist/react/components/record-dialog.d.ts +0 -4
  32. package/dist/react/components/record-dialog.d.ts.map +1 -1
  33. package/dist/react/components/record-dialog.js +11 -88
  34. package/dist/react/components/record-dialog.js.map +1 -1
  35. package/dist/types.d.ts +0 -56
  36. package/dist/types.d.ts.map +1 -1
  37. package/dist/types.js.map +1 -1
  38. package/package.json +4 -4
@@ -1 +1 @@
1
- {"version":3,"file":"media-constraints-hint.js","sourceRoot":"","sources":["../../../src/react/components/media-constraints-hint.tsx"],"names":[],"mappings":"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","sourcesContent":["'use client';\n\nimport type { MediaOriginSpec } from '@ttt-productions/media-schemas';\nimport { Badge, Card } from '@ttt-productions/ui-core/react';\nimport { cn } from '@ttt-productions/ui-core';\n\nexport interface MediaConstraintsHintProps {\n spec: MediaOriginSpec;\n className?: string;\n title?: string;\n}\n\nfunction fmtBytes(bytes?: number) {\n if (!bytes || bytes <= 0) return null;\n const mb = bytes / (1024 * 1024);\n if (mb < 1024) return `${Math.round(mb)}MB`;\n const gb = mb / 1024;\n return `${gb.toFixed(1)}GB`;\n}\n\nfunction fmtAspect(x?: number) {\n if (!x) return null;\n // show common approx ratios if close\n const candidates: Array<[string, number]> = [\n ['1:1', 1],\n ['4:5', 4 / 5],\n ['3:4', 3 / 4],\n ['9:16', 9 / 16],\n ['16:9', 16 / 9],\n ];\n for (const [label, v] of candidates) {\n if (Math.abs(x - v) <= 0.02) return label;\n }\n return `${x.toFixed(3)}`;\n}\n\nexport function MediaConstraintsHint(props: MediaConstraintsHintProps) {\n const { spec, className, title = 'Upload requirements' } = props;\n\n const acceptKinds = spec.accept?.kinds?.length ? spec.accept.kinds.join(', ') : 'any';\n const acceptMimes = spec.accept?.mimes?.length ? spec.accept.mimes.join(', ') : 'any';\n\n const maxBytes = fmtBytes(spec.maxBytes);\n const maxDur =\n spec.maxDurationSec ??\n spec.processing?.video?.video?.maxDurationSec ??\n spec.processing?.audio?.audio?.maxDurationSec ??\n undefined;\n\n const requiredAspect = fmtAspect(spec.requiredAspectRatio ?? spec.imageCrop?.aspectRatio);\n const requiredDims = (() => {\n const procVid = spec.processing?.video;\n const w = procVid?.requiredWidth;\n const h = procVid?.requiredHeight;\n return w && h ? `${w}×${h}` : null;\n })();\n\n const videoOri =\n spec.videoOrientation && spec.videoOrientation !== 'any' ? spec.videoOrientation : null;\n\n const cropDims = spec.imageCrop\n ? `${spec.imageCrop.outputWidth}×${spec.imageCrop.outputHeight}`\n : null;\n\n const willAutoFormat = !!spec.processing?.video?.allowAutoFormat;\n\n const items: Array<{ k: string; v: string | null }> = [\n { k: 'Kind', v: acceptKinds },\n { k: 'Types', v: acceptMimes },\n { k: 'Max size', v: maxBytes },\n { k: 'Max length', v: maxDur ? `${maxDur}s` : null },\n { k: 'Orientation', v: videoOri },\n { k: 'Aspect', v: requiredAspect },\n { k: 'Exact size', v: requiredDims },\n { k: 'Crop output', v: cropDims },\n { k: 'Auto-format', v: willAutoFormat ? 'yes' : null },\n ].filter((x) => x.v);\n\n if (!items.length) return null;\n\n return (\n <Card className={cn('p-3', className)}>\n <div className=\"flex items-center justify-between gap-2\">\n <div className=\"text-sm font-medium\">{title}</div>\n {willAutoFormat ? <Badge variant=\"secondary\">Auto-format supported</Badge> : null}\n </div>\n\n <div className=\"mt-2 flex flex-wrap gap-2\">\n {items.map((it) => (\n <Badge key={it.k} variant=\"outline\" className=\"gap-1\">\n <span className=\"text-muted-foreground\">{it.k}:</span>\n <span>{it.v}</span>\n </Badge>\n ))}\n </div>\n\n {spec.imageCrop ? (\n <div className=\"mt-2 text-xs text-muted-foreground\">\n Images will be cropped to {fmtAspect(spec.imageCrop.aspectRatio)} and exported as{' '}\n {(spec.imageCrop.format ?? 'jpeg').toUpperCase()}\n {spec.imageCrop.quality ? ` @ ${spec.imageCrop.quality}%` : ''}.\n </div>\n ) : null}\n\n {willAutoFormat ? (\n <div className=\"mt-2 text-xs text-muted-foreground\">\n If your video doesn't match the format, we'll ask before uploading and then auto-format it\n in processing.\n </div>\n ) : null}\n </Card>\n );\n}\n"]}
1
+ {"version":3,"file":"media-constraints-hint.js","sourceRoot":"","sources":["../../../src/react/components/media-constraints-hint.tsx"],"names":[],"mappings":"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","sourcesContent":["'use client';\n\nimport type { MediaOriginSpec } from '@ttt-productions/media-schemas';\nimport { Badge, Card } from '@ttt-productions/ui-core/react';\nimport { cn } from '@ttt-productions/ui-core';\n\nexport interface MediaConstraintsHintProps {\n spec: MediaOriginSpec;\n className?: string;\n title?: string;\n}\n\nfunction fmtBytes(bytes?: number) {\n if (!bytes || bytes <= 0) return null;\n const mb = bytes / (1024 * 1024);\n if (mb < 1024) return `${Math.round(mb)}MB`;\n const gb = mb / 1024;\n return `${gb.toFixed(1)}GB`;\n}\n\nfunction fmtAspect(x?: number) {\n if (!x) return null;\n const candidates: Array<[string, number]> = [\n ['1:1', 1],\n ['4:5', 4 / 5],\n ['3:4', 3 / 4],\n ['9:16', 9 / 16],\n ['16:9', 16 / 9],\n ];\n for (const [label, v] of candidates) {\n if (Math.abs(x - v) <= 0.02) return label;\n }\n return `${x.toFixed(3)}`;\n}\n\nexport function MediaConstraintsHint(props: MediaConstraintsHintProps) {\n const { spec, className, title = 'Upload requirements' } = props;\n\n const acceptKinds = spec.accept?.kinds?.length ? spec.accept.kinds.join(', ') : 'any';\n const acceptMimes = spec.accept?.mimes?.length ? spec.accept.mimes.join(', ') : 'any';\n\n const maxBytes = fmtBytes(spec.maxBytes);\n const maxDur =\n spec.maxDurationSec ??\n spec.processing?.video?.video?.maxDurationSec ??\n spec.processing?.audio?.audio?.maxDurationSec ??\n undefined;\n\n const requiredAspect = fmtAspect(spec.requiredAspectRatio ?? spec.imageCrop?.aspectRatio);\n const requiredDims = (() => {\n const procVid = spec.processing?.video;\n const w = procVid?.requiredWidth;\n const h = procVid?.requiredHeight;\n return w && h ? `${w}×${h}` : null;\n })();\n\n const videoOri =\n spec.videoOrientation && spec.videoOrientation !== 'any' ? spec.videoOrientation : null;\n\n const cropDims = spec.imageCrop\n ? `${spec.imageCrop.outputWidth}×${spec.imageCrop.outputHeight}`\n : null;\n\n const willAutoFormat = !!spec.processing?.video?.allowAutoFormat;\n\n const items: Array<{ k: string; v: string | null }> = [\n { k: 'Kind', v: acceptKinds },\n { k: 'Types', v: acceptMimes },\n { k: 'Max size', v: maxBytes },\n { k: 'Max length', v: maxDur ? `${maxDur}s` : null },\n { k: 'Orientation', v: videoOri },\n { k: 'Aspect', v: requiredAspect },\n { k: 'Exact size', v: requiredDims },\n { k: 'Crop output', v: cropDims },\n { k: 'Auto-format', v: willAutoFormat ? 'yes' : null },\n ].filter((x) => x.v);\n\n if (!items.length) return null;\n\n return (\n <Card className={cn('p-3', className)}>\n <div className=\"flex items-center justify-between gap-2\">\n <div className=\"text-sm font-medium\">{title}</div>\n {willAutoFormat ? <Badge variant=\"secondary\">Auto-format supported</Badge> : null}\n </div>\n\n <div className=\"mt-2 flex flex-wrap gap-2\">\n {items.map((it) => (\n <Badge key={it.k} variant=\"outline\" className=\"gap-1\">\n <span className=\"text-muted-foreground\">{it.k}:</span>\n <span>{it.v}</span>\n </Badge>\n ))}\n </div>\n\n {spec.imageCrop ? (\n <div className=\"mt-2 text-xs text-muted-foreground\">\n Images will be cropped to {fmtAspect(spec.imageCrop.aspectRatio)} and exported as{' '}\n {(spec.imageCrop.format ?? 'jpeg').toUpperCase()}\n {spec.imageCrop.quality ? ` @ ${spec.imageCrop.quality}%` : ''}.\n </div>\n ) : null}\n\n {willAutoFormat ? (\n <div className=\"mt-2 text-xs text-muted-foreground\">\n If your video doesn't match the format, we'll ask before uploading and then auto-format it\n in processing.\n </div>\n ) : null}\n </Card>\n );\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"media-input.d.ts","sourceRoot":"","sources":["../../../src/react/components/media-input.tsx"],"names":[],"mappings":"AAEA,OAAO,KASN,MAAM,OAAO,CAAC;AA0Bf,OAAO,KAAK,EAEV,gBAAgB,EAChB,eAAe,EAEhB,MAAM,gBAAgB,CAAC;AAgIxB,eAAO,MAAM,UAAU,0FA+rBtB,CAAC"}
1
+ {"version":3,"file":"media-input.d.ts","sourceRoot":"","sources":["../../../src/react/components/media-input.tsx"],"names":[],"mappings":"AAEA,OAAO,KASN,MAAM,OAAO,CAAC;AA0Bf,OAAO,KAAK,EAEV,gBAAgB,EAChB,eAAe,EAEhB,MAAM,gBAAgB,CAAC;AAuHxB,eAAO,MAAM,UAAU,0FA+nBtB,CAAC"}
@@ -15,8 +15,6 @@ import { MediaConstraintsHint } from './media-constraints-hint.js';
15
15
  import { PhotoCaptureModal } from './photo-capture-modal.js';
16
16
  import { readMediaMeta } from '../../lib/read-media-meta.js';
17
17
  import { validateMediaDuration } from '../../lib/validate-media-duration.js';
18
- /** Built-in advisory shown on EVERY MediaInput's Info affordance (overridable via `helpNotes`,
19
- * which appends). Generic + app-agnostic: uploaded files are not a backup/storage service. */
20
18
  const DEFAULT_BACKUP_NOTE = "Keep your own copy of files you upload — this isn't a backup or storage service.";
21
19
  function err(code, message, details) {
22
20
  return { code, message, details };
@@ -55,11 +53,6 @@ function accepts(spec, file) {
55
53
  const accept = spec.accept;
56
54
  if (!accept)
57
55
  return true;
58
- // FAIL-OPEN on unknown browser metadata (canonical-upload-content-
59
- // classification): an empty or neutral type is not evidence of anything —
60
- // rejecting it here used to force MIME fabrication upstream. The file passes
61
- // through and the SERVER's byte inspector decides. Only a DEFINITIVELY known
62
- // wrong kind still rejects fast (better UX than a round trip).
63
56
  if (!file.type || file.type === NEUTRAL_CONTENT_TYPE)
64
57
  return true;
65
58
  const kinds = accept.kinds?.filter(Boolean) ?? [];
@@ -71,7 +64,6 @@ function accepts(spec, file) {
71
64
  const kindOk = kinds.length === 0 ? true : kinds.includes(kind);
72
65
  if (!kindOk)
73
66
  return false;
74
- // If mimes list is empty, accept anything
75
67
  if (mimes.length === 0)
76
68
  return true;
77
69
  return mimes.some((a) => matchMime(a, file.type));
@@ -85,7 +77,7 @@ function orientationOk(required, actual) {
85
77
  if (!required || required === 'any')
86
78
  return true;
87
79
  if (!actual || actual === 'any')
88
- return true; // treat square/unknown as ok
80
+ return true;
89
81
  return required === actual;
90
82
  }
91
83
  function aspectOk(required, actual) {
@@ -93,9 +85,8 @@ function aspectOk(required, actual) {
93
85
  return true;
94
86
  if (!actual)
95
87
  return false;
96
- return Math.abs(actual - required) <= 0.02; // ~2% tolerance
88
+ return Math.abs(actual - required) <= 0.02;
97
89
  }
98
- /** Counts how many input methods are enabled. */
99
90
  function countActions(spec) {
100
91
  const c = spec.client;
101
92
  let n = 0;
@@ -123,27 +114,19 @@ export const MediaInput = forwardRef(function MediaInput(props, ref) {
123
114
  const cropSpec = cropOverride ?? spec.imageCrop;
124
115
  const [localError, setLocalError] = useState(null);
125
116
  const [showInfo, setShowInfo] = useState(false);
126
- // Every MediaInput carries the default backup advisory + any surface-specific notes, so the Info
127
- // affordance always renders (constraints, if any, are shown under the notes).
128
117
  const infoNotes = useMemo(() => [DEFAULT_BACKUP_NOTE, ...(helpNotes ?? [])], [helpNotes]);
129
118
  const specHasConstraints = hasConstraints(spec);
130
119
  const showInfoToggle = specHasConstraints || infoNotes.length > 0;
131
120
  const [cropOpen, setCropOpen] = useState(false);
132
121
  const [cropSrc, setCropSrc] = useState(null);
133
122
  const [pendingCropFile, setPendingCropFile] = useState(null);
134
- // The claim captured when the crop flow started — cropping/normalization
135
- // preserves the ORIGINAL action claim (a captured photo stays camera-capture).
136
123
  const [pendingCropClaim, setPendingCropClaim] = useState(null);
137
124
  const [photoOpen, setPhotoOpen] = useState(false);
138
125
  const [recordOpen, setRecordOpen] = useState(false);
139
126
  const [recordKind, setRecordKind] = useState('video');
140
- // Controlled state for the multi-action choice dropdown. Human clicks toggle it
141
- // via the trigger button; the imperative `openSelection()` handle opens it when
142
- // more than one action is enabled.
143
127
  const [menuOpen, setMenuOpen] = useState(false);
144
128
  const [validating, setValidating] = useState(false);
145
129
  const [emittedSize, setEmittedSize] = useState(null);
146
- // Prevent memory leaks from object URLs
147
130
  const lastObjectUrlRef = useRef(null);
148
131
  const revokeLastObjectUrl = useCallback(() => {
149
132
  if (!lastObjectUrlRef.current)
@@ -166,11 +149,6 @@ export const MediaInput = forwardRef(function MediaInput(props, ref) {
166
149
  };
167
150
  }, [revokeLastObjectUrl]);
168
151
  const acceptAttr = useMemo(() => {
169
- // Explicit enabled-format registry projection FIRST (canonical-upload-
170
- // content-classification): when the origin selects formats, the picker
171
- // advertises exactly those (MIME aliases + extensions, kind-narrowed for
172
- // shared A/V containers) instead of wildcards. Discoverability only — the
173
- // server inspector remains the authority.
174
152
  const formats = spec.accept?.formats?.filter(Boolean) ?? [];
175
153
  if (formats.length) {
176
154
  const tokens = projectAcceptTokens(formats, spec.accept?.kinds ?? undefined);
@@ -187,10 +165,8 @@ export const MediaInput = forwardRef(function MediaInput(props, ref) {
187
165
  return 'video/*';
188
166
  if (k.includes('audio') && k.length === 1)
189
167
  return 'audio/*';
190
- return undefined; // accept anything
168
+ return undefined;
191
169
  }, [spec]);
192
- // Simplified kind of the currently-selected file, used to size and type the
193
- // inline preview. Null when nothing is selected.
194
170
  const previewKind = useMemo(() => (selectedFile ? getSimplifiedMediaType(selectedFile) : null), [selectedFile]);
195
171
  const selectedFileLabel = previewKind === 'image'
196
172
  ? 'Image selected'
@@ -200,7 +176,6 @@ export const MediaInput = forwardRef(function MediaInput(props, ref) {
200
176
  ? 'Audio selected'
201
177
  : 'File selected';
202
178
  const emit = useCallback((payload) => {
203
- // fallback resolution; pre-validation error path when kind is unknown or "file"
204
179
  const rawKind = payload.meta?.kind;
205
180
  const mediaKind = rawKind === 'image' || rawKind === 'video' || rawKind === 'audio' ? rawKind : 'image';
206
181
  const resolvedSpec = resolveActiveSpec(spec, mediaKind);
@@ -214,10 +189,6 @@ export const MediaInput = forwardRef(function MediaInput(props, ref) {
214
189
  }, [emit]);
215
190
  const validateAndEmit = useCallback(async (file, previewUrl, action = undefined) => {
216
191
  setLocalError(null);
217
- // Defense-in-depth: normalize the content type before any downstream
218
- // handling. Recorder/capture files carry their declared kind; a picker
219
- // file with unknown metadata passes through NEUTRALLY (never fabricated —
220
- // the server inspector owns classification).
221
192
  const declaredKind = action?.source === 'media-recorder' || action?.source === 'camera-capture'
222
193
  ? action.kind === 'image' || action.kind === 'video' || action.kind === 'audio'
223
194
  ? action.kind
@@ -229,18 +200,12 @@ export const MediaInput = forwardRef(function MediaInput(props, ref) {
229
200
  return;
230
201
  }
231
202
  const meta = await readMediaMeta(safeFile);
232
- // The CLIENT CLAIM: what the user actually did. Recorder/capture claims
233
- // are strong (the app requested that capture kind); a picker claim is an
234
- // advisory browser-metadata inference — `file` when nothing narrower is
235
- // known. Never derived from the (already-normalized) MIME for strong
236
- // sources; for the picker the meta kind IS the inference.
237
203
  const claim = action ?? {
238
204
  source: 'file-picker',
239
205
  kind: meta.kind === 'image' || meta.kind === 'video' || meta.kind === 'audio'
240
206
  ? meta.kind
241
207
  : 'file',
242
208
  };
243
- // bytes
244
209
  if (spec.maxBytes && safeFile.size > spec.maxBytes) {
245
210
  fail(err('too_large', `File too large. Max ${Math.round(spec.maxBytes / 1024 / 1024)}MB.`, {
246
211
  size: safeFile.size,
@@ -248,7 +213,6 @@ export const MediaInput = forwardRef(function MediaInput(props, ref) {
248
213
  }));
249
214
  return;
250
215
  }
251
- // duration
252
216
  const maxDur = spec.maxDurationSec ??
253
217
  spec.processing?.video?.video?.maxDurationSec ??
254
218
  spec.processing?.audio?.audio?.maxDurationSec;
@@ -259,7 +223,6 @@ export const MediaInput = forwardRef(function MediaInput(props, ref) {
259
223
  return;
260
224
  }
261
225
  }
262
- // image crop enforcement
263
226
  if (meta.kind === 'image' && cropSpec) {
264
227
  const reader = new FileReader();
265
228
  reader.onload = () => {
@@ -272,7 +235,6 @@ export const MediaInput = forwardRef(function MediaInput(props, ref) {
272
235
  reader.readAsDataURL(safeFile);
273
236
  return;
274
237
  }
275
- // video uniform enforcement (orientation/aspect/dimensions)
276
238
  if (meta.kind === 'video') {
277
239
  const procVid = spec.processing?.video;
278
240
  const requiredOri = spec.videoOrientation;
@@ -287,8 +249,6 @@ export const MediaInput = forwardRef(function MediaInput(props, ref) {
287
249
  const okDims = !requiredW || !requiredH ? true : meta.width === requiredW && meta.height === requiredH;
288
250
  if (!okOri || !okAspect || !okDims) {
289
251
  if (allowAutoFormat) {
290
- // Auto-format is always silent — no confirmation prompt. The file is
291
- // emitted with autoFormat:true and reformatted after upload.
292
252
  emit({ file: safeFile, previewUrl, meta, claim, autoFormat: true });
293
253
  return;
294
254
  }
@@ -319,9 +279,6 @@ export const MediaInput = forwardRef(function MediaInput(props, ref) {
319
279
  }
320
280
  emit({ file: safeFile, previewUrl, meta, claim });
321
281
  }, [spec, cropSpec, emit, fail]);
322
- // A picked, captured, or recorded file is validated (type, meta, duration,
323
- // dimensions, crop) before it is emitted. The trigger shows pending for that
324
- // whole window, so a second pick cannot race the first.
325
282
  const handleSelected = useCallback(async (file, previewUrl, action = undefined) => {
326
283
  setValidating(true);
327
284
  try {
@@ -381,8 +338,7 @@ export const MediaInput = forwardRef(function MediaInput(props, ref) {
381
338
  const isPreparing = phase === 'preparing' && isLoading;
382
339
  const isFinalizing = phase === 'finalizing' && isLoading;
383
340
  const sizeThreshold = progressBarMinBytes ?? DEFAULT_PROGRESS_BAR_MIN_BYTES;
384
- // Consumers usually pass selectedFile={null} once the file is handed off, so
385
- // the bar judges the size of the file this input emitted.
341
+ // Consumers usually clear selectedFile once it is handed off, so the bar sizes the file this input emitted.
386
342
  const trackedSize = selectedFile?.size ?? emittedSize;
387
343
  const showRealBar = isUploading &&
388
344
  typeof percent === 'number' &&
@@ -393,14 +349,12 @@ export const MediaInput = forwardRef(function MediaInput(props, ref) {
393
349
  const canRecVideo = spec.client?.allowRecordVideo ?? true;
394
350
  const canRecAudio = spec.client?.allowRecordAudio ?? true;
395
351
  const actionCount = countActions(spec);
396
- // Warn in dev if no actions are enabled
397
352
  useEffect(() => {
398
353
  if (actionCount === 0) {
399
354
  console.warn('[MediaInput] No input methods enabled in spec.client. ' +
400
355
  'At least one of allowPick, allowCapturePhoto, allowRecordVideo, or allowRecordAudio must be true.');
401
356
  }
402
357
  }, [actionCount]);
403
- /** Execute an action directly (used for single-action shortcut). */
404
358
  const executeAction = useCallback((action) => {
405
359
  switch (action) {
406
360
  case 'pick':
@@ -419,12 +373,6 @@ export const MediaInput = forwardRef(function MediaInput(props, ref) {
419
373
  break;
420
374
  }
421
375
  }, []);
422
- /**
423
- * Run the optional pre-select guard, then execute the action. When the guard
424
- * resolves false, the picker/capture never opens. This is the single choke
425
- * point for all four actions, so the gate fires on the click for every entry
426
- * point (single-action button and dropdown items alike).
427
- */
428
376
  const runAction = useCallback(async (action) => {
429
377
  if (onBeforeSelect) {
430
378
  const ok = await onBeforeSelect();
@@ -433,7 +381,6 @@ export const MediaInput = forwardRef(function MediaInput(props, ref) {
433
381
  }
434
382
  executeAction(action);
435
383
  }, [onBeforeSelect, executeAction]);
436
- /** Build the list of enabled actions. */
437
384
  const actions = useMemo(() => {
438
385
  const list = [];
439
386
  if (canPick)
@@ -454,7 +401,6 @@ export const MediaInput = forwardRef(function MediaInput(props, ref) {
454
401
  });
455
402
  return list;
456
403
  }, [canPick, canPhoto, canRecVideo, canRecAudio]);
457
- /** Label & icon for the single trigger button. */
458
404
  const triggerIcon = useMemo(() => {
459
405
  if (actions.length === 1)
460
406
  return actions[0].icon;
@@ -463,28 +409,17 @@ export const MediaInput = forwardRef(function MediaInput(props, ref) {
463
409
  return _jsx(Plus, { className: "icon-xs" });
464
410
  }, [actions, buttonLabel]);
465
411
  const triggerLabel = useMemo(() => {
466
- // If the consumer explicitly set a custom buttonLabel, always respect it.
467
- // Only use the action's built-in label for single-action when using the default.
468
412
  if (buttonLabel !== 'Add media')
469
413
  return buttonLabel;
470
414
  if (actions.length === 1)
471
415
  return actions[0].label;
472
416
  return buttonLabel;
473
417
  }, [actions, buttonLabel]);
474
- /** When there's exactly 1 action, click goes straight to it. Otherwise open menu. */
475
418
  const handleTriggerClick = useCallback(() => {
476
419
  if (actions.length === 1) {
477
420
  void runAction(actions[0].kind);
478
421
  }
479
- // If > 1 action, the DropdownMenuTrigger handles opening the menu.
480
422
  }, [actions, runAction]);
481
- /**
482
- * Imperative entry point: activates the SAME trigger semantics as a human click
483
- * (single action → run it through `runAction`, honoring `onBeforeSelect`/validation/
484
- * crop; multiple actions → open the choice dropdown). Guards on disabled/loading and
485
- * no-enabled-actions exactly as the rendered trigger's `disabled` attribute would.
486
- * Never touches the hidden input directly, so none of the gates are bypassed.
487
- */
488
423
  const openSelection = useCallback(() => {
489
424
  if (disabled || isLoading || validating || actions.length === 0)
490
425
  return;
@@ -1 +1 @@
1
- {"version":3,"file":"media-input.js","sourceRoot":"","sources":["../../../src/react/components/media-input.tsx"],"names":[],"mappings":"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","sourcesContent":["'use client';\n\nimport React, {\n forwardRef,\n useCallback,\n useEffect,\n useId,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport type {\n MediaCropSpec,\n MediaProcessingSpec,\n MediaOriginSpec,\n VideoOrientation,\n} from '@ttt-productions/media-schemas';\nimport { getSimplifiedMediaType } from '@ttt-productions/media-schemas';\nimport { Info, Camera, Mic, Video, Upload, X, Plus } from 'lucide-react';\n\nimport {\n Alert,\n AlertDescription,\n Button,\n Card,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n Input,\n Progress,\n Spinner,\n} from '@ttt-productions/ui-core/react';\nimport { cn } from '@ttt-productions/ui-core';\nimport { MediaPreview } from '@ttt-productions/media-viewer/react';\n\nimport type {\n FileInputError,\n MediaInputHandle,\n MediaInputProps,\n SelectedMediaMeta,\n} from '../../types.js';\nimport { DEFAULT_PROGRESS_BAR_MIN_BYTES } from '../../progress-bar.js';\nimport { RecordDialog } from './record-dialog.js';\nimport { ensureFileWithContentType } from '../../lib/infer-content-type.js';\nimport { NEUTRAL_CONTENT_TYPE, projectAcceptTokens } from '@ttt-productions/media-schemas';\nimport type { ClientMediaClaim } from '@ttt-productions/media-schemas';\nimport { ImageCropperModal } from './image-cropper-modal.js';\nimport { MediaConstraintsHint } from './media-constraints-hint.js';\nimport { PhotoCaptureModal } from './photo-capture-modal.js';\nimport { readMediaMeta } from '../../lib/read-media-meta.js';\nimport { validateMediaDuration } from '../../lib/validate-media-duration.js';\n\n/** Built-in advisory shown on EVERY MediaInput's Info affordance (overridable via `helpNotes`,\n * which appends). Generic + app-agnostic: uploaded files are not a backup/storage service. */\nconst DEFAULT_BACKUP_NOTE =\n \"Keep your own copy of files you upload — this isn't a backup or storage service.\";\n\nfunction err(\n code: FileInputError['code'],\n message: string,\n details?: Record<string, unknown>,\n): FileInputError {\n return { code, message, details };\n}\n\nfunction hasConstraints(spec: MediaOriginSpec): boolean {\n const proc = spec.processing;\n const procImg = proc?.image;\n const procVid = proc?.video;\n const procAud = proc?.audio;\n return Boolean(\n spec.accept?.kinds?.length ||\n spec.accept?.mimes?.length ||\n spec.maxBytes ||\n spec.maxDurationSec ||\n procVid?.video?.maxDurationSec ||\n procAud?.audio?.maxDurationSec ||\n (spec.videoOrientation && spec.videoOrientation !== 'any') ||\n spec.requiredAspectRatio ||\n (procVid?.requiredWidth && procVid?.requiredHeight) ||\n (procImg?.requiredWidth && procImg?.requiredHeight) ||\n spec.imageCrop ||\n procVid?.allowAutoFormat ||\n procImg?.allowAutoFormat,\n );\n}\n\nfunction matchMime(accepted: string, actual: string): boolean {\n const a = accepted.trim().toLowerCase();\n const m = actual.trim().toLowerCase();\n if (!a) return true;\n if (a === '*/*') return true;\n if (a.endsWith('/*')) return m.startsWith(a.slice(0, -1));\n return a === m;\n}\n\nfunction accepts(spec: MediaOriginSpec, file: File): boolean {\n const accept = spec.accept;\n if (!accept) return true;\n\n // FAIL-OPEN on unknown browser metadata (canonical-upload-content-\n // classification): an empty or neutral type is not evidence of anything —\n // rejecting it here used to force MIME fabrication upstream. The file passes\n // through and the SERVER's byte inspector decides. Only a DEFINITIVELY known\n // wrong kind still rejects fast (better UX than a round trip).\n if (!file.type || file.type === NEUTRAL_CONTENT_TYPE) return true;\n\n const kinds = accept.kinds?.filter(Boolean) ?? [];\n const mimes = accept.mimes?.filter(Boolean) ?? [];\n\n const simplified = getSimplifiedMediaType(file);\n const kind: 'image' | 'video' | 'audio' | 'file' =\n simplified === 'image' || simplified === 'video' || simplified === 'audio'\n ? simplified\n : 'file';\n\n const kindOk = kinds.length === 0 ? true : kinds.includes(kind);\n if (!kindOk) return false;\n\n // If mimes list is empty, accept anything\n if (mimes.length === 0) return true;\n\n return mimes.some((a) => matchMime(a, file.type));\n}\n\nfunction computeAspect(width?: number, height?: number): number | undefined {\n if (!width || !height) return undefined;\n return width / height;\n}\n\nfunction orientationOk(\n required: VideoOrientation | undefined,\n actual: VideoOrientation | undefined,\n): boolean {\n if (!required || required === 'any') return true;\n if (!actual || actual === 'any') return true; // treat square/unknown as ok\n return required === actual;\n}\n\nfunction aspectOk(required: number | undefined, actual: number | undefined): boolean {\n if (!required) return true;\n if (!actual) return false;\n return Math.abs(actual - required) <= 0.02; // ~2% tolerance\n}\n\n/** Counts how many input methods are enabled. */\nfunction countActions(spec: MediaOriginSpec): number {\n const c = spec.client;\n let n = 0;\n if (c?.allowPick ?? true) n++;\n if (c?.allowCapturePhoto ?? true) n++;\n if (c?.allowRecordVideo ?? true) n++;\n if (c?.allowRecordAudio ?? true) n++;\n return n;\n}\n\nfunction resolveActiveSpec(\n entry: MediaOriginSpec,\n kind: 'image' | 'video' | 'audio',\n): MediaProcessingSpec {\n const inner = entry.processing?.[kind];\n if (inner) return inner;\n const { processing: _p, ...rest } = entry;\n return rest as MediaProcessingSpec;\n}\n\ntype ActionKind = 'pick' | 'photo' | 'recordVideo' | 'recordAudio';\n\nexport const MediaInput = forwardRef<MediaInputHandle, MediaInputProps>(\n function MediaInput(props, ref) {\n const {\n spec,\n cropOverride,\n disabled = false,\n isLoading = false,\n className,\n buttonLabel = 'Add media',\n clearLabel = 'Clear selected file',\n uploadState,\n progressBarMinBytes,\n selectedFile,\n onClear,\n onCancel,\n onBeforeSelect,\n onChange,\n helpNotes,\n } = props;\n\n const id = useId();\n const pickerRef = useRef<HTMLInputElement>(null);\n\n const cropSpec: MediaCropSpec | undefined = cropOverride ?? spec.imageCrop;\n\n const [localError, setLocalError] = useState<FileInputError | null>(null);\n\n const [showInfo, setShowInfo] = useState(false);\n // Every MediaInput carries the default backup advisory + any surface-specific notes, so the Info\n // affordance always renders (constraints, if any, are shown under the notes).\n const infoNotes = useMemo(() => [DEFAULT_BACKUP_NOTE, ...(helpNotes ?? [])], [helpNotes]);\n const specHasConstraints = hasConstraints(spec);\n const showInfoToggle = specHasConstraints || infoNotes.length > 0;\n\n const [cropOpen, setCropOpen] = useState(false);\n const [cropSrc, setCropSrc] = useState<string | null>(null);\n const [pendingCropFile, setPendingCropFile] = useState<File | null>(null);\n // The claim captured when the crop flow started — cropping/normalization\n // preserves the ORIGINAL action claim (a captured photo stays camera-capture).\n const [pendingCropClaim, setPendingCropClaim] = useState<ClientMediaClaim | null>(null);\n\n const [photoOpen, setPhotoOpen] = useState(false);\n\n const [recordOpen, setRecordOpen] = useState(false);\n const [recordKind, setRecordKind] = useState<'audio' | 'video'>('video');\n\n // Controlled state for the multi-action choice dropdown. Human clicks toggle it\n // via the trigger button; the imperative `openSelection()` handle opens it when\n // more than one action is enabled.\n const [menuOpen, setMenuOpen] = useState(false);\n const [validating, setValidating] = useState(false);\n const [emittedSize, setEmittedSize] = useState<number | null>(null);\n\n // Prevent memory leaks from object URLs\n const lastObjectUrlRef = useRef<string | null>(null);\n\n const revokeLastObjectUrl = useCallback(() => {\n if (!lastObjectUrlRef.current) return;\n try {\n URL.revokeObjectURL(lastObjectUrlRef.current);\n } catch {}\n lastObjectUrlRef.current = null;\n }, []);\n\n const makeObjectUrl = useCallback(\n (blob: Blob) => {\n revokeLastObjectUrl();\n const url = URL.createObjectURL(blob);\n lastObjectUrlRef.current = url;\n return url;\n },\n [revokeLastObjectUrl],\n );\n\n useEffect(() => {\n return () => {\n revokeLastObjectUrl();\n };\n }, [revokeLastObjectUrl]);\n\n const acceptAttr = useMemo(() => {\n // Explicit enabled-format registry projection FIRST (canonical-upload-\n // content-classification): when the origin selects formats, the picker\n // advertises exactly those (MIME aliases + extensions, kind-narrowed for\n // shared A/V containers) instead of wildcards. Discoverability only — the\n // server inspector remains the authority.\n const formats = spec.accept?.formats?.filter(Boolean) ?? [];\n if (formats.length) {\n const tokens = projectAcceptTokens(formats, spec.accept?.kinds ?? undefined);\n if (tokens.length) return tokens.join(', ');\n }\n const m = spec.accept?.mimes?.filter(Boolean) ?? [];\n const k = spec.accept?.kinds?.filter(Boolean) ?? [];\n if (m.length) return m.join(', ');\n if (k.includes('image') && k.length === 1) return 'image/*';\n if (k.includes('video') && k.length === 1) return 'video/*';\n if (k.includes('audio') && k.length === 1) return 'audio/*';\n return undefined; // accept anything\n }, [spec]);\n\n // Simplified kind of the currently-selected file, used to size and type the\n // inline preview. Null when nothing is selected.\n const previewKind = useMemo(\n () => (selectedFile ? getSimplifiedMediaType(selectedFile) : null),\n [selectedFile],\n );\n const selectedFileLabel =\n previewKind === 'image'\n ? 'Image selected'\n : previewKind === 'video'\n ? 'Video selected'\n : previewKind === 'audio'\n ? 'Audio selected'\n : 'File selected';\n\n const emit = useCallback(\n (payload: {\n file?: File;\n previewUrl?: string;\n meta?: SelectedMediaMeta;\n claim?: ClientMediaClaim;\n autoFormat?: boolean;\n croppedBlob?: Blob;\n error?: FileInputError;\n }) => {\n // fallback resolution; pre-validation error path when kind is unknown or \"file\"\n const rawKind = payload.meta?.kind;\n const mediaKind: 'image' | 'video' | 'audio' =\n rawKind === 'image' || rawKind === 'video' || rawKind === 'audio' ? rawKind : 'image';\n const resolvedSpec = resolveActiveSpec(spec, mediaKind);\n if (payload.file) setEmittedSize(payload.file.size);\n onChange({ spec: resolvedSpec, ...payload });\n },\n [onChange, spec],\n );\n\n const fail = useCallback(\n (e: FileInputError) => {\n setLocalError(e);\n emit({ error: e });\n },\n [emit],\n );\n\n const validateAndEmit = useCallback(\n async (file: File, previewUrl?: string, action: ClientMediaClaim | undefined = undefined) => {\n setLocalError(null);\n\n // Defense-in-depth: normalize the content type before any downstream\n // handling. Recorder/capture files carry their declared kind; a picker\n // file with unknown metadata passes through NEUTRALLY (never fabricated —\n // the server inspector owns classification).\n const declaredKind =\n action?.source === 'media-recorder' || action?.source === 'camera-capture'\n ? action.kind === 'image' || action.kind === 'video' || action.kind === 'audio'\n ? action.kind\n : undefined\n : undefined;\n const safeFile = ensureFileWithContentType(file, declaredKind);\n\n if (!accepts(spec, safeFile)) {\n fail(err('invalid_type', 'Invalid file type for this upload.'));\n return;\n }\n\n const meta = await readMediaMeta(safeFile);\n\n // The CLIENT CLAIM: what the user actually did. Recorder/capture claims\n // are strong (the app requested that capture kind); a picker claim is an\n // advisory browser-metadata inference — `file` when nothing narrower is\n // known. Never derived from the (already-normalized) MIME for strong\n // sources; for the picker the meta kind IS the inference.\n const claim: ClientMediaClaim = action ?? {\n source: 'file-picker',\n kind:\n meta.kind === 'image' || meta.kind === 'video' || meta.kind === 'audio'\n ? meta.kind\n : 'file',\n };\n\n // bytes\n if (spec.maxBytes && safeFile.size > spec.maxBytes) {\n fail(\n err('too_large', `File too large. Max ${Math.round(spec.maxBytes / 1024 / 1024)}MB.`, {\n size: safeFile.size,\n maxBytes: spec.maxBytes,\n }),\n );\n return;\n }\n\n // duration\n const maxDur =\n spec.maxDurationSec ??\n spec.processing?.video?.video?.maxDurationSec ??\n spec.processing?.audio?.audio?.maxDurationSec;\n if ((meta.kind === 'video' || meta.kind === 'audio') && maxDur) {\n const ok = await validateMediaDuration(safeFile, maxDur);\n if (!ok) {\n fail(err('too_long', `Media too long. Max ${maxDur} seconds.`));\n return;\n }\n }\n\n // image crop enforcement\n if (meta.kind === 'image' && cropSpec) {\n const reader = new FileReader();\n reader.onload = () => {\n setPendingCropFile(safeFile);\n setPendingCropClaim(claim);\n setCropSrc(reader.result as string);\n setCropOpen(true);\n };\n reader.onerror = () => fail(err('read_failed', 'Failed to read image for cropping.'));\n reader.readAsDataURL(safeFile);\n return;\n }\n\n // video uniform enforcement (orientation/aspect/dimensions)\n if (meta.kind === 'video') {\n const procVid = spec.processing?.video;\n const requiredOri = spec.videoOrientation;\n const requiredAspect = spec.requiredAspectRatio;\n const requiredW = procVid?.requiredWidth;\n const requiredH = procVid?.requiredHeight;\n const allowAutoFormat = procVid?.allowAutoFormat;\n\n const actualOri = meta.orientation;\n const actualAspect = computeAspect(meta.width, meta.height);\n\n const okOri = orientationOk(requiredOri, actualOri);\n const okAspect = aspectOk(requiredAspect, actualAspect);\n const okDims =\n !requiredW || !requiredH ? true : meta.width === requiredW && meta.height === requiredH;\n\n if (!okOri || !okAspect || !okDims) {\n if (allowAutoFormat) {\n // Auto-format is always silent — no confirmation prompt. The file is\n // emitted with autoFormat:true and reformatted after upload.\n emit({ file: safeFile, previewUrl, meta, claim, autoFormat: true });\n return;\n }\n\n if (!okOri) {\n fail(\n err(\n 'orientation_mismatch',\n 'Video orientation does not match the required format.',\n {\n requiredOri,\n actualOri,\n },\n ),\n );\n return;\n }\n if (!okAspect) {\n fail(\n err(\n 'aspect_ratio_mismatch',\n 'Video aspect ratio does not match the required format.',\n {\n requiredAspect,\n actualAspect,\n },\n ),\n );\n return;\n }\n if (!okDims) {\n fail(\n err('dimensions_mismatch', 'Video dimensions do not match the required format.', {\n requiredW,\n requiredH,\n width: meta.width,\n height: meta.height,\n }),\n );\n return;\n }\n }\n }\n\n emit({ file: safeFile, previewUrl, meta, claim });\n },\n [spec, cropSpec, emit, fail],\n );\n\n // A picked, captured, or recorded file is validated (type, meta, duration,\n // dimensions, crop) before it is emitted. The trigger shows pending for that\n // whole window, so a second pick cannot race the first.\n const handleSelected = useCallback(\n async (file: File, previewUrl?: string, action: ClientMediaClaim | undefined = undefined) => {\n setValidating(true);\n try {\n await validateAndEmit(file, previewUrl, action);\n } finally {\n setValidating(false);\n }\n },\n [validateAndEmit],\n );\n\n const onPick = useCallback(\n async (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n e.target.value = '';\n if (!file) return;\n\n const url = makeObjectUrl(file);\n\n await handleSelected(file, url);\n },\n [handleSelected, makeObjectUrl],\n );\n\n const onCropComplete = useCallback(\n (blob: Blob | null) => {\n setCropOpen(false);\n\n const original = pendingCropFile;\n const preservedClaim = pendingCropClaim;\n setPendingCropFile(null);\n setPendingCropClaim(null);\n\n if (!blob || !original) {\n fail(err('crop_failed', 'Cropping failed.'));\n setCropSrc(null);\n return;\n }\n\n const type = blob.type || 'image/jpeg';\n const name = original.name?.replace(/\\.[^/.]+$/, '') || 'image';\n const ext = type.includes('png')\n ? 'png'\n : type.includes('webp')\n ? 'webp'\n : type.includes('avif')\n ? 'avif'\n : 'jpg';\n\n const croppedFile = new File([blob], `${name}.cropped.${ext}`, { type });\n\n const url = makeObjectUrl(croppedFile);\n\n readMediaMeta(croppedFile).then((meta) =>\n emit({\n file: croppedFile,\n previewUrl: url,\n meta,\n claim: preservedClaim ?? undefined,\n croppedBlob: blob,\n }),\n );\n\n setCropSrc(null);\n },\n [emit, fail, pendingCropFile, pendingCropClaim, makeObjectUrl],\n );\n\n const onPhotoCapture = useCallback(\n async (file: File) => {\n setPhotoOpen(false);\n const url = makeObjectUrl(file);\n await handleSelected(file, url, { kind: 'image', source: 'camera-capture' });\n },\n [handleSelected, makeObjectUrl],\n );\n\n const phase = uploadState?.phase ?? null;\n const percent = uploadState?.percent ?? null;\n const isUploading = phase === 'uploading' && isLoading;\n const isPreparing = phase === 'preparing' && isLoading;\n const isFinalizing = phase === 'finalizing' && isLoading;\n\n const sizeThreshold = progressBarMinBytes ?? DEFAULT_PROGRESS_BAR_MIN_BYTES;\n // Consumers usually pass selectedFile={null} once the file is handed off, so\n // the bar judges the size of the file this input emitted.\n const trackedSize = selectedFile?.size ?? emittedSize;\n const showRealBar =\n isUploading &&\n typeof percent === 'number' &&\n trackedSize !== null &&\n trackedSize >= sizeThreshold;\n\n const canPick = spec.client?.allowPick ?? true;\n const canPhoto = spec.client?.allowCapturePhoto ?? true;\n const canRecVideo = spec.client?.allowRecordVideo ?? true;\n const canRecAudio = spec.client?.allowRecordAudio ?? true;\n\n const actionCount = countActions(spec);\n\n // Warn in dev if no actions are enabled\n useEffect(() => {\n if (actionCount === 0) {\n console.warn(\n '[MediaInput] No input methods enabled in spec.client. ' +\n 'At least one of allowPick, allowCapturePhoto, allowRecordVideo, or allowRecordAudio must be true.',\n );\n }\n }, [actionCount]);\n\n /** Execute an action directly (used for single-action shortcut). */\n const executeAction = useCallback((action: ActionKind) => {\n switch (action) {\n case 'pick':\n pickerRef.current?.click();\n break;\n case 'photo':\n setPhotoOpen(true);\n break;\n case 'recordVideo':\n setRecordKind('video');\n setRecordOpen(true);\n break;\n case 'recordAudio':\n setRecordKind('audio');\n setRecordOpen(true);\n break;\n }\n }, []);\n\n /**\n * Run the optional pre-select guard, then execute the action. When the guard\n * resolves false, the picker/capture never opens. This is the single choke\n * point for all four actions, so the gate fires on the click for every entry\n * point (single-action button and dropdown items alike).\n */\n const runAction = useCallback(\n async (action: ActionKind) => {\n if (onBeforeSelect) {\n const ok = await onBeforeSelect();\n if (!ok) return;\n }\n executeAction(action);\n },\n [onBeforeSelect, executeAction],\n );\n\n /** Build the list of enabled actions. */\n const actions = useMemo(() => {\n const list: Array<{ kind: ActionKind; label: string; icon: React.ReactNode }> = [];\n if (canPick)\n list.push({ kind: 'pick', label: 'Choose file', icon: <Upload className=\"icon-xs\" /> });\n if (canPhoto)\n list.push({ kind: 'photo', label: 'Take photo', icon: <Camera className=\"icon-xs\" /> });\n if (canRecVideo)\n list.push({\n kind: 'recordVideo',\n label: 'Record video',\n icon: <Video className=\"icon-xs\" />,\n });\n if (canRecAudio)\n list.push({\n kind: 'recordAudio',\n label: 'Record audio',\n icon: <Mic className=\"icon-xs\" />,\n });\n return list;\n }, [canPick, canPhoto, canRecVideo, canRecAudio]);\n\n /** Label & icon for the single trigger button. */\n const triggerIcon = useMemo(() => {\n if (actions.length === 1) return actions[0].icon;\n if (buttonLabel !== 'Add media') return <Upload className=\"icon-xs\" />;\n return <Plus className=\"icon-xs\" />;\n }, [actions, buttonLabel]);\n\n const triggerLabel = useMemo(() => {\n // If the consumer explicitly set a custom buttonLabel, always respect it.\n // Only use the action's built-in label for single-action when using the default.\n if (buttonLabel !== 'Add media') return buttonLabel;\n if (actions.length === 1) return actions[0].label;\n return buttonLabel;\n }, [actions, buttonLabel]);\n\n /** When there's exactly 1 action, click goes straight to it. Otherwise open menu. */\n const handleTriggerClick = useCallback(() => {\n if (actions.length === 1) {\n void runAction(actions[0].kind);\n }\n // If > 1 action, the DropdownMenuTrigger handles opening the menu.\n }, [actions, runAction]);\n\n /**\n * Imperative entry point: activates the SAME trigger semantics as a human click\n * (single action → run it through `runAction`, honoring `onBeforeSelect`/validation/\n * crop; multiple actions → open the choice dropdown). Guards on disabled/loading and\n * no-enabled-actions exactly as the rendered trigger's `disabled` attribute would.\n * Never touches the hidden input directly, so none of the gates are bypassed.\n */\n const openSelection = useCallback(() => {\n if (disabled || isLoading || validating || actions.length === 0) return;\n if (actions.length === 1) {\n void runAction(actions[0].kind);\n return;\n }\n setMenuOpen(true);\n }, [disabled, isLoading, validating, actions, runAction]);\n\n useImperativeHandle(ref, () => ({ openSelection }), [openSelection]);\n\n return (\n <Card className={cn('p-3', className)}>\n {/* Hidden file picker input */}\n <Input\n id={`media-pick-${id}`}\n ref={pickerRef}\n type=\"file\"\n accept={acceptAttr}\n className=\"hidden\"\n onChange={onPick}\n disabled={disabled || isLoading || validating}\n />\n\n {/* Selected file preview + semantic status (original names stay metadata-only). */}\n {selectedFile && !isLoading ? (\n <div className=\"mb-2 space-y-2\">\n {previewKind === 'image' || previewKind === 'video' || previewKind === 'audio' ? (\n <div\n className={cn(\n 'relative w-full rounded-md bg-muted',\n previewKind === 'audio' ? 'p-2' : 'h-48 overflow-hidden',\n )}\n >\n <MediaPreview\n url={selectedFile}\n type={previewKind}\n mime={selectedFile.type}\n controls\n className={previewKind === 'audio' ? 'w-full' : 'h-full w-full'}\n />\n </div>\n ) : null}\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm truncate flex-1\">{selectedFileLabel}</span>\n {onClear && (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"icon-sm shrink-0\"\n onClick={onClear}\n aria-label={clearLabel}\n >\n <X className=\"icon-xs\" />\n </Button>\n )}\n </div>\n </div>\n ) : null}\n\n {/* Upload / finalizing status */}\n {isLoading ? (\n <div className=\"flex items-center gap-2 mb-2\">\n <Spinner size=\"xs\" />\n <span className=\"text-sm text-muted-foreground\">\n {isPreparing\n ? 'Preparing...'\n : isUploading && showRealBar\n ? `Uploading ${Math.round(percent ?? 0)}%...`\n : isUploading\n ? 'Uploading...'\n : isFinalizing\n ? 'Finalizing...'\n : 'Finalizing...'}\n </span>\n {(isPreparing || isUploading) && onCancel ? (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"icon-sm shrink-0 ml-auto\"\n onClick={onCancel}\n aria-label=\"Cancel upload\"\n >\n <X className=\"icon-xs\" />\n </Button>\n ) : null}\n </div>\n ) : null}\n\n {/* Progress bar — only shown for uploads above the size threshold */}\n {showRealBar ? <Progress value={percent ?? 0} className=\"mb-2 h-1.5\" /> : null}\n\n {/* Action button area */}\n <div className=\"flex flex-wrap gap-2\">\n {actions.length <= 1 ? (\n /* Single action (or none): plain button, no dropdown */\n <Button\n type=\"button\"\n variant=\"default\"\n onClick={handleTriggerClick}\n disabled={disabled || isLoading || actions.length === 0}\n pending={validating}\n icon={triggerIcon}\n >\n {triggerLabel}\n </Button>\n ) : (\n /* Multiple actions: dropdown menu */\n <DropdownMenu open={menuOpen} onOpenChange={setMenuOpen}>\n <DropdownMenuTrigger asChild>\n <Button\n type=\"button\"\n variant=\"default\"\n disabled={disabled || isLoading}\n pending={validating}\n icon={triggerIcon}\n >\n {triggerLabel}\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\">\n {actions.map((a) => (\n <DropdownMenuItem\n key={a.kind}\n onClick={() => void runAction(a.kind)}\n icon={a.icon}\n >\n {a.label}\n </DropdownMenuItem>\n ))}\n </DropdownMenuContent>\n </DropdownMenu>\n )}\n\n {showInfoToggle ? (\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => setShowInfo((v) => !v)}\n disabled={disabled || isLoading}\n >\n <Info className=\"mr-2 icon-xs\" />\n {showInfo ? 'Hide info' : 'Info'}\n </Button>\n ) : null}\n </div>\n\n {showInfo && showInfoToggle ? (\n <div className=\"mt-3 space-y-2\">\n {infoNotes.length > 0 ? (\n <ul className=\"text-xs text-muted-foreground list-disc pl-4 space-y-1\">\n {infoNotes.map((n, i) => (\n <li key={i}>{n}</li>\n ))}\n </ul>\n ) : null}\n {specHasConstraints ? <MediaConstraintsHint spec={spec} /> : null}\n </div>\n ) : null}\n\n {localError && (\n <Alert variant=\"destructive\" className=\"mt-3\">\n <AlertDescription>{localError.message}</AlertDescription>\n </Alert>\n )}\n\n {cropSpec && (\n <ImageCropperModal\n isOpen={cropOpen}\n onClose={() => {\n setCropOpen(false);\n setCropSrc(null);\n }}\n imageSrc={cropSrc}\n aspectRatio={cropSpec.aspectRatio}\n shape={cropSpec.shape ?? 'rect'}\n outputWidth={cropSpec.outputWidth}\n outputHeight={cropSpec.outputHeight}\n encoding={{ format: cropSpec.format, quality: cropSpec.quality }}\n onCropComplete={onCropComplete}\n />\n )}\n\n {/* Photo capture modal (getUserMedia-based, works on desktop + mobile) */}\n <PhotoCaptureModal\n open={photoOpen}\n facingMode={spec.client?.cameraFacingMode ?? 'user'}\n onCapture={onPhotoCapture}\n onClose={() => setPhotoOpen(false)}\n />\n\n <RecordDialog\n open={recordOpen}\n onOpenChange={setRecordOpen}\n initialKind={recordKind}\n canPhoto={canPhoto}\n canRecVideo={canRecVideo}\n canRecAudio={canRecAudio}\n cameraFacingMode={spec.client?.cameraFacingMode}\n maxRecordDurationSec={spec.client?.maxRecordDurationSec}\n disabled={disabled}\n isLoading={isLoading}\n onRecorded={async (file, url, recordedKind) => {\n await handleSelected(file, url, { kind: recordedKind, source: 'media-recorder' });\n }}\n onRequestPhoto={() => setPhotoOpen(true)}\n />\n </Card>\n );\n },\n);\nMediaInput.displayName = 'MediaInput';\n"]}
1
+ {"version":3,"file":"media-input.js","sourceRoot":"","sources":["../../../src/react/components/media-input.tsx"],"names":[],"mappings":"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","sourcesContent":["'use client';\n\nimport React, {\n forwardRef,\n useCallback,\n useEffect,\n useId,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport type {\n MediaCropSpec,\n MediaProcessingSpec,\n MediaOriginSpec,\n VideoOrientation,\n} from '@ttt-productions/media-schemas';\nimport { getSimplifiedMediaType } from '@ttt-productions/media-schemas';\nimport { Info, Camera, Mic, Video, Upload, X, Plus } from 'lucide-react';\n\nimport {\n Alert,\n AlertDescription,\n Button,\n Card,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n Input,\n Progress,\n Spinner,\n} from '@ttt-productions/ui-core/react';\nimport { cn } from '@ttt-productions/ui-core';\nimport { MediaPreview } from '@ttt-productions/media-viewer/react';\n\nimport type {\n FileInputError,\n MediaInputHandle,\n MediaInputProps,\n SelectedMediaMeta,\n} from '../../types.js';\nimport { DEFAULT_PROGRESS_BAR_MIN_BYTES } from '../../progress-bar.js';\nimport { RecordDialog } from './record-dialog.js';\nimport { ensureFileWithContentType } from '../../lib/infer-content-type.js';\nimport { NEUTRAL_CONTENT_TYPE, projectAcceptTokens } from '@ttt-productions/media-schemas';\nimport type { ClientMediaClaim } from '@ttt-productions/media-schemas';\nimport { ImageCropperModal } from './image-cropper-modal.js';\nimport { MediaConstraintsHint } from './media-constraints-hint.js';\nimport { PhotoCaptureModal } from './photo-capture-modal.js';\nimport { readMediaMeta } from '../../lib/read-media-meta.js';\nimport { validateMediaDuration } from '../../lib/validate-media-duration.js';\n\nconst DEFAULT_BACKUP_NOTE =\n \"Keep your own copy of files you upload — this isn't a backup or storage service.\";\n\nfunction err(\n code: FileInputError['code'],\n message: string,\n details?: Record<string, unknown>,\n): FileInputError {\n return { code, message, details };\n}\n\nfunction hasConstraints(spec: MediaOriginSpec): boolean {\n const proc = spec.processing;\n const procImg = proc?.image;\n const procVid = proc?.video;\n const procAud = proc?.audio;\n return Boolean(\n spec.accept?.kinds?.length ||\n spec.accept?.mimes?.length ||\n spec.maxBytes ||\n spec.maxDurationSec ||\n procVid?.video?.maxDurationSec ||\n procAud?.audio?.maxDurationSec ||\n (spec.videoOrientation && spec.videoOrientation !== 'any') ||\n spec.requiredAspectRatio ||\n (procVid?.requiredWidth && procVid?.requiredHeight) ||\n (procImg?.requiredWidth && procImg?.requiredHeight) ||\n spec.imageCrop ||\n procVid?.allowAutoFormat ||\n procImg?.allowAutoFormat,\n );\n}\n\nfunction matchMime(accepted: string, actual: string): boolean {\n const a = accepted.trim().toLowerCase();\n const m = actual.trim().toLowerCase();\n if (!a) return true;\n if (a === '*/*') return true;\n if (a.endsWith('/*')) return m.startsWith(a.slice(0, -1));\n return a === m;\n}\n\nfunction accepts(spec: MediaOriginSpec, file: File): boolean {\n const accept = spec.accept;\n if (!accept) return true;\n\n if (!file.type || file.type === NEUTRAL_CONTENT_TYPE) return true;\n\n const kinds = accept.kinds?.filter(Boolean) ?? [];\n const mimes = accept.mimes?.filter(Boolean) ?? [];\n\n const simplified = getSimplifiedMediaType(file);\n const kind: 'image' | 'video' | 'audio' | 'file' =\n simplified === 'image' || simplified === 'video' || simplified === 'audio'\n ? simplified\n : 'file';\n\n const kindOk = kinds.length === 0 ? true : kinds.includes(kind);\n if (!kindOk) return false;\n\n if (mimes.length === 0) return true;\n\n return mimes.some((a) => matchMime(a, file.type));\n}\n\nfunction computeAspect(width?: number, height?: number): number | undefined {\n if (!width || !height) return undefined;\n return width / height;\n}\n\nfunction orientationOk(\n required: VideoOrientation | undefined,\n actual: VideoOrientation | undefined,\n): boolean {\n if (!required || required === 'any') return true;\n if (!actual || actual === 'any') return true;\n return required === actual;\n}\n\nfunction aspectOk(required: number | undefined, actual: number | undefined): boolean {\n if (!required) return true;\n if (!actual) return false;\n return Math.abs(actual - required) <= 0.02;\n}\n\nfunction countActions(spec: MediaOriginSpec): number {\n const c = spec.client;\n let n = 0;\n if (c?.allowPick ?? true) n++;\n if (c?.allowCapturePhoto ?? true) n++;\n if (c?.allowRecordVideo ?? true) n++;\n if (c?.allowRecordAudio ?? true) n++;\n return n;\n}\n\nfunction resolveActiveSpec(\n entry: MediaOriginSpec,\n kind: 'image' | 'video' | 'audio',\n): MediaProcessingSpec {\n const inner = entry.processing?.[kind];\n if (inner) return inner;\n const { processing: _p, ...rest } = entry;\n return rest as MediaProcessingSpec;\n}\n\ntype ActionKind = 'pick' | 'photo' | 'recordVideo' | 'recordAudio';\n\nexport const MediaInput = forwardRef<MediaInputHandle, MediaInputProps>(\n function MediaInput(props, ref) {\n const {\n spec,\n cropOverride,\n disabled = false,\n isLoading = false,\n className,\n buttonLabel = 'Add media',\n clearLabel = 'Clear selected file',\n uploadState,\n progressBarMinBytes,\n selectedFile,\n onClear,\n onCancel,\n onBeforeSelect,\n onChange,\n helpNotes,\n } = props;\n\n const id = useId();\n const pickerRef = useRef<HTMLInputElement>(null);\n\n const cropSpec: MediaCropSpec | undefined = cropOverride ?? spec.imageCrop;\n\n const [localError, setLocalError] = useState<FileInputError | null>(null);\n\n const [showInfo, setShowInfo] = useState(false);\n const infoNotes = useMemo(() => [DEFAULT_BACKUP_NOTE, ...(helpNotes ?? [])], [helpNotes]);\n const specHasConstraints = hasConstraints(spec);\n const showInfoToggle = specHasConstraints || infoNotes.length > 0;\n\n const [cropOpen, setCropOpen] = useState(false);\n const [cropSrc, setCropSrc] = useState<string | null>(null);\n const [pendingCropFile, setPendingCropFile] = useState<File | null>(null);\n const [pendingCropClaim, setPendingCropClaim] = useState<ClientMediaClaim | null>(null);\n\n const [photoOpen, setPhotoOpen] = useState(false);\n\n const [recordOpen, setRecordOpen] = useState(false);\n const [recordKind, setRecordKind] = useState<'audio' | 'video'>('video');\n\n const [menuOpen, setMenuOpen] = useState(false);\n const [validating, setValidating] = useState(false);\n const [emittedSize, setEmittedSize] = useState<number | null>(null);\n\n const lastObjectUrlRef = useRef<string | null>(null);\n\n const revokeLastObjectUrl = useCallback(() => {\n if (!lastObjectUrlRef.current) return;\n try {\n URL.revokeObjectURL(lastObjectUrlRef.current);\n } catch {}\n lastObjectUrlRef.current = null;\n }, []);\n\n const makeObjectUrl = useCallback(\n (blob: Blob) => {\n revokeLastObjectUrl();\n const url = URL.createObjectURL(blob);\n lastObjectUrlRef.current = url;\n return url;\n },\n [revokeLastObjectUrl],\n );\n\n useEffect(() => {\n return () => {\n revokeLastObjectUrl();\n };\n }, [revokeLastObjectUrl]);\n\n const acceptAttr = useMemo(() => {\n const formats = spec.accept?.formats?.filter(Boolean) ?? [];\n if (formats.length) {\n const tokens = projectAcceptTokens(formats, spec.accept?.kinds ?? undefined);\n if (tokens.length) return tokens.join(', ');\n }\n const m = spec.accept?.mimes?.filter(Boolean) ?? [];\n const k = spec.accept?.kinds?.filter(Boolean) ?? [];\n if (m.length) return m.join(', ');\n if (k.includes('image') && k.length === 1) return 'image/*';\n if (k.includes('video') && k.length === 1) return 'video/*';\n if (k.includes('audio') && k.length === 1) return 'audio/*';\n return undefined;\n }, [spec]);\n\n const previewKind = useMemo(\n () => (selectedFile ? getSimplifiedMediaType(selectedFile) : null),\n [selectedFile],\n );\n const selectedFileLabel =\n previewKind === 'image'\n ? 'Image selected'\n : previewKind === 'video'\n ? 'Video selected'\n : previewKind === 'audio'\n ? 'Audio selected'\n : 'File selected';\n\n const emit = useCallback(\n (payload: {\n file?: File;\n previewUrl?: string;\n meta?: SelectedMediaMeta;\n claim?: ClientMediaClaim;\n autoFormat?: boolean;\n croppedBlob?: Blob;\n error?: FileInputError;\n }) => {\n const rawKind = payload.meta?.kind;\n const mediaKind: 'image' | 'video' | 'audio' =\n rawKind === 'image' || rawKind === 'video' || rawKind === 'audio' ? rawKind : 'image';\n const resolvedSpec = resolveActiveSpec(spec, mediaKind);\n if (payload.file) setEmittedSize(payload.file.size);\n onChange({ spec: resolvedSpec, ...payload });\n },\n [onChange, spec],\n );\n\n const fail = useCallback(\n (e: FileInputError) => {\n setLocalError(e);\n emit({ error: e });\n },\n [emit],\n );\n\n const validateAndEmit = useCallback(\n async (file: File, previewUrl?: string, action: ClientMediaClaim | undefined = undefined) => {\n setLocalError(null);\n\n const declaredKind =\n action?.source === 'media-recorder' || action?.source === 'camera-capture'\n ? action.kind === 'image' || action.kind === 'video' || action.kind === 'audio'\n ? action.kind\n : undefined\n : undefined;\n const safeFile = ensureFileWithContentType(file, declaredKind);\n\n if (!accepts(spec, safeFile)) {\n fail(err('invalid_type', 'Invalid file type for this upload.'));\n return;\n }\n\n const meta = await readMediaMeta(safeFile);\n\n const claim: ClientMediaClaim = action ?? {\n source: 'file-picker',\n kind:\n meta.kind === 'image' || meta.kind === 'video' || meta.kind === 'audio'\n ? meta.kind\n : 'file',\n };\n\n if (spec.maxBytes && safeFile.size > spec.maxBytes) {\n fail(\n err('too_large', `File too large. Max ${Math.round(spec.maxBytes / 1024 / 1024)}MB.`, {\n size: safeFile.size,\n maxBytes: spec.maxBytes,\n }),\n );\n return;\n }\n\n const maxDur =\n spec.maxDurationSec ??\n spec.processing?.video?.video?.maxDurationSec ??\n spec.processing?.audio?.audio?.maxDurationSec;\n if ((meta.kind === 'video' || meta.kind === 'audio') && maxDur) {\n const ok = await validateMediaDuration(safeFile, maxDur);\n if (!ok) {\n fail(err('too_long', `Media too long. Max ${maxDur} seconds.`));\n return;\n }\n }\n\n if (meta.kind === 'image' && cropSpec) {\n const reader = new FileReader();\n reader.onload = () => {\n setPendingCropFile(safeFile);\n setPendingCropClaim(claim);\n setCropSrc(reader.result as string);\n setCropOpen(true);\n };\n reader.onerror = () => fail(err('read_failed', 'Failed to read image for cropping.'));\n reader.readAsDataURL(safeFile);\n return;\n }\n\n if (meta.kind === 'video') {\n const procVid = spec.processing?.video;\n const requiredOri = spec.videoOrientation;\n const requiredAspect = spec.requiredAspectRatio;\n const requiredW = procVid?.requiredWidth;\n const requiredH = procVid?.requiredHeight;\n const allowAutoFormat = procVid?.allowAutoFormat;\n\n const actualOri = meta.orientation;\n const actualAspect = computeAspect(meta.width, meta.height);\n\n const okOri = orientationOk(requiredOri, actualOri);\n const okAspect = aspectOk(requiredAspect, actualAspect);\n const okDims =\n !requiredW || !requiredH ? true : meta.width === requiredW && meta.height === requiredH;\n\n if (!okOri || !okAspect || !okDims) {\n if (allowAutoFormat) {\n emit({ file: safeFile, previewUrl, meta, claim, autoFormat: true });\n return;\n }\n\n if (!okOri) {\n fail(\n err(\n 'orientation_mismatch',\n 'Video orientation does not match the required format.',\n {\n requiredOri,\n actualOri,\n },\n ),\n );\n return;\n }\n if (!okAspect) {\n fail(\n err(\n 'aspect_ratio_mismatch',\n 'Video aspect ratio does not match the required format.',\n {\n requiredAspect,\n actualAspect,\n },\n ),\n );\n return;\n }\n if (!okDims) {\n fail(\n err('dimensions_mismatch', 'Video dimensions do not match the required format.', {\n requiredW,\n requiredH,\n width: meta.width,\n height: meta.height,\n }),\n );\n return;\n }\n }\n }\n\n emit({ file: safeFile, previewUrl, meta, claim });\n },\n [spec, cropSpec, emit, fail],\n );\n\n const handleSelected = useCallback(\n async (file: File, previewUrl?: string, action: ClientMediaClaim | undefined = undefined) => {\n setValidating(true);\n try {\n await validateAndEmit(file, previewUrl, action);\n } finally {\n setValidating(false);\n }\n },\n [validateAndEmit],\n );\n\n const onPick = useCallback(\n async (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n e.target.value = '';\n if (!file) return;\n\n const url = makeObjectUrl(file);\n\n await handleSelected(file, url);\n },\n [handleSelected, makeObjectUrl],\n );\n\n const onCropComplete = useCallback(\n (blob: Blob | null) => {\n setCropOpen(false);\n\n const original = pendingCropFile;\n const preservedClaim = pendingCropClaim;\n setPendingCropFile(null);\n setPendingCropClaim(null);\n\n if (!blob || !original) {\n fail(err('crop_failed', 'Cropping failed.'));\n setCropSrc(null);\n return;\n }\n\n const type = blob.type || 'image/jpeg';\n const name = original.name?.replace(/\\.[^/.]+$/, '') || 'image';\n const ext = type.includes('png')\n ? 'png'\n : type.includes('webp')\n ? 'webp'\n : type.includes('avif')\n ? 'avif'\n : 'jpg';\n\n const croppedFile = new File([blob], `${name}.cropped.${ext}`, { type });\n\n const url = makeObjectUrl(croppedFile);\n\n readMediaMeta(croppedFile).then((meta) =>\n emit({\n file: croppedFile,\n previewUrl: url,\n meta,\n claim: preservedClaim ?? undefined,\n croppedBlob: blob,\n }),\n );\n\n setCropSrc(null);\n },\n [emit, fail, pendingCropFile, pendingCropClaim, makeObjectUrl],\n );\n\n const onPhotoCapture = useCallback(\n async (file: File) => {\n setPhotoOpen(false);\n const url = makeObjectUrl(file);\n await handleSelected(file, url, { kind: 'image', source: 'camera-capture' });\n },\n [handleSelected, makeObjectUrl],\n );\n\n const phase = uploadState?.phase ?? null;\n const percent = uploadState?.percent ?? null;\n const isUploading = phase === 'uploading' && isLoading;\n const isPreparing = phase === 'preparing' && isLoading;\n const isFinalizing = phase === 'finalizing' && isLoading;\n\n const sizeThreshold = progressBarMinBytes ?? DEFAULT_PROGRESS_BAR_MIN_BYTES;\n // Consumers usually clear selectedFile once it is handed off, so the bar sizes the file this input emitted.\n const trackedSize = selectedFile?.size ?? emittedSize;\n const showRealBar =\n isUploading &&\n typeof percent === 'number' &&\n trackedSize !== null &&\n trackedSize >= sizeThreshold;\n\n const canPick = spec.client?.allowPick ?? true;\n const canPhoto = spec.client?.allowCapturePhoto ?? true;\n const canRecVideo = spec.client?.allowRecordVideo ?? true;\n const canRecAudio = spec.client?.allowRecordAudio ?? true;\n\n const actionCount = countActions(spec);\n\n useEffect(() => {\n if (actionCount === 0) {\n console.warn(\n '[MediaInput] No input methods enabled in spec.client. ' +\n 'At least one of allowPick, allowCapturePhoto, allowRecordVideo, or allowRecordAudio must be true.',\n );\n }\n }, [actionCount]);\n\n const executeAction = useCallback((action: ActionKind) => {\n switch (action) {\n case 'pick':\n pickerRef.current?.click();\n break;\n case 'photo':\n setPhotoOpen(true);\n break;\n case 'recordVideo':\n setRecordKind('video');\n setRecordOpen(true);\n break;\n case 'recordAudio':\n setRecordKind('audio');\n setRecordOpen(true);\n break;\n }\n }, []);\n\n const runAction = useCallback(\n async (action: ActionKind) => {\n if (onBeforeSelect) {\n const ok = await onBeforeSelect();\n if (!ok) return;\n }\n executeAction(action);\n },\n [onBeforeSelect, executeAction],\n );\n\n const actions = useMemo(() => {\n const list: Array<{ kind: ActionKind; label: string; icon: React.ReactNode }> = [];\n if (canPick)\n list.push({ kind: 'pick', label: 'Choose file', icon: <Upload className=\"icon-xs\" /> });\n if (canPhoto)\n list.push({ kind: 'photo', label: 'Take photo', icon: <Camera className=\"icon-xs\" /> });\n if (canRecVideo)\n list.push({\n kind: 'recordVideo',\n label: 'Record video',\n icon: <Video className=\"icon-xs\" />,\n });\n if (canRecAudio)\n list.push({\n kind: 'recordAudio',\n label: 'Record audio',\n icon: <Mic className=\"icon-xs\" />,\n });\n return list;\n }, [canPick, canPhoto, canRecVideo, canRecAudio]);\n\n const triggerIcon = useMemo(() => {\n if (actions.length === 1) return actions[0].icon;\n if (buttonLabel !== 'Add media') return <Upload className=\"icon-xs\" />;\n return <Plus className=\"icon-xs\" />;\n }, [actions, buttonLabel]);\n\n const triggerLabel = useMemo(() => {\n if (buttonLabel !== 'Add media') return buttonLabel;\n if (actions.length === 1) return actions[0].label;\n return buttonLabel;\n }, [actions, buttonLabel]);\n\n const handleTriggerClick = useCallback(() => {\n if (actions.length === 1) {\n void runAction(actions[0].kind);\n }\n }, [actions, runAction]);\n\n const openSelection = useCallback(() => {\n if (disabled || isLoading || validating || actions.length === 0) return;\n if (actions.length === 1) {\n void runAction(actions[0].kind);\n return;\n }\n setMenuOpen(true);\n }, [disabled, isLoading, validating, actions, runAction]);\n\n useImperativeHandle(ref, () => ({ openSelection }), [openSelection]);\n\n return (\n <Card className={cn('p-3', className)}>\n <Input\n id={`media-pick-${id}`}\n ref={pickerRef}\n type=\"file\"\n accept={acceptAttr}\n className=\"hidden\"\n onChange={onPick}\n disabled={disabled || isLoading || validating}\n />\n\n {selectedFile && !isLoading ? (\n <div className=\"mb-2 space-y-2\">\n {previewKind === 'image' || previewKind === 'video' || previewKind === 'audio' ? (\n <div\n className={cn(\n 'relative w-full rounded-md bg-muted',\n previewKind === 'audio' ? 'p-2' : 'h-48 overflow-hidden',\n )}\n >\n <MediaPreview\n url={selectedFile}\n type={previewKind}\n mime={selectedFile.type}\n controls\n className={previewKind === 'audio' ? 'w-full' : 'h-full w-full'}\n />\n </div>\n ) : null}\n <div className=\"flex items-center gap-2\">\n <span className=\"text-sm truncate flex-1\">{selectedFileLabel}</span>\n {onClear && (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"icon-sm shrink-0\"\n onClick={onClear}\n aria-label={clearLabel}\n >\n <X className=\"icon-xs\" />\n </Button>\n )}\n </div>\n </div>\n ) : null}\n\n {isLoading ? (\n <div className=\"flex items-center gap-2 mb-2\">\n <Spinner size=\"xs\" />\n <span className=\"text-sm text-muted-foreground\">\n {isPreparing\n ? 'Preparing...'\n : isUploading && showRealBar\n ? `Uploading ${Math.round(percent ?? 0)}%...`\n : isUploading\n ? 'Uploading...'\n : isFinalizing\n ? 'Finalizing...'\n : 'Finalizing...'}\n </span>\n {(isPreparing || isUploading) && onCancel ? (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"icon-sm shrink-0 ml-auto\"\n onClick={onCancel}\n aria-label=\"Cancel upload\"\n >\n <X className=\"icon-xs\" />\n </Button>\n ) : null}\n </div>\n ) : null}\n\n {showRealBar ? <Progress value={percent ?? 0} className=\"mb-2 h-1.5\" /> : null}\n\n <div className=\"flex flex-wrap gap-2\">\n {actions.length <= 1 ? (\n <Button\n type=\"button\"\n variant=\"default\"\n onClick={handleTriggerClick}\n disabled={disabled || isLoading || actions.length === 0}\n pending={validating}\n icon={triggerIcon}\n >\n {triggerLabel}\n </Button>\n ) : (\n <DropdownMenu open={menuOpen} onOpenChange={setMenuOpen}>\n <DropdownMenuTrigger asChild>\n <Button\n type=\"button\"\n variant=\"default\"\n disabled={disabled || isLoading}\n pending={validating}\n icon={triggerIcon}\n >\n {triggerLabel}\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\">\n {actions.map((a) => (\n <DropdownMenuItem\n key={a.kind}\n onClick={() => void runAction(a.kind)}\n icon={a.icon}\n >\n {a.label}\n </DropdownMenuItem>\n ))}\n </DropdownMenuContent>\n </DropdownMenu>\n )}\n\n {showInfoToggle ? (\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={() => setShowInfo((v) => !v)}\n disabled={disabled || isLoading}\n >\n <Info className=\"mr-2 icon-xs\" />\n {showInfo ? 'Hide info' : 'Info'}\n </Button>\n ) : null}\n </div>\n\n {showInfo && showInfoToggle ? (\n <div className=\"mt-3 space-y-2\">\n {infoNotes.length > 0 ? (\n <ul className=\"text-xs text-muted-foreground list-disc pl-4 space-y-1\">\n {infoNotes.map((n, i) => (\n <li key={i}>{n}</li>\n ))}\n </ul>\n ) : null}\n {specHasConstraints ? <MediaConstraintsHint spec={spec} /> : null}\n </div>\n ) : null}\n\n {localError && (\n <Alert variant=\"destructive\" className=\"mt-3\">\n <AlertDescription>{localError.message}</AlertDescription>\n </Alert>\n )}\n\n {cropSpec && (\n <ImageCropperModal\n isOpen={cropOpen}\n onClose={() => {\n setCropOpen(false);\n setCropSrc(null);\n }}\n imageSrc={cropSrc}\n aspectRatio={cropSpec.aspectRatio}\n shape={cropSpec.shape ?? 'rect'}\n outputWidth={cropSpec.outputWidth}\n outputHeight={cropSpec.outputHeight}\n encoding={{ format: cropSpec.format, quality: cropSpec.quality }}\n onCropComplete={onCropComplete}\n />\n )}\n\n <PhotoCaptureModal\n open={photoOpen}\n facingMode={spec.client?.cameraFacingMode ?? 'user'}\n onCapture={onPhotoCapture}\n onClose={() => setPhotoOpen(false)}\n />\n\n <RecordDialog\n open={recordOpen}\n onOpenChange={setRecordOpen}\n initialKind={recordKind}\n canPhoto={canPhoto}\n canRecVideo={canRecVideo}\n canRecAudio={canRecAudio}\n cameraFacingMode={spec.client?.cameraFacingMode}\n maxRecordDurationSec={spec.client?.maxRecordDurationSec}\n disabled={disabled}\n isLoading={isLoading}\n onRecorded={async (file, url, recordedKind) => {\n await handleSelected(file, url, { kind: recordedKind, source: 'media-recorder' });\n }}\n onRequestPhoto={() => setPhotoOpen(true)}\n />\n </Card>\n );\n },\n);\nMediaInput.displayName = 'MediaInput';\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"photo-capture-modal.d.ts","sourceRoot":"","sources":["../../../src/react/components/photo-capture-modal.tsx"],"names":[],"mappings":"AAgBA,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,OAAO,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,GAAG,aAAa,CAAC;IACpC,SAAS,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAChC,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,+BAuL9D"}
1
+ {"version":3,"file":"photo-capture-modal.d.ts","sourceRoot":"","sources":["../../../src/react/components/photo-capture-modal.tsx"],"names":[],"mappings":"AAgBA,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,OAAO,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,GAAG,aAAa,CAAC;IACpC,SAAS,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAChC,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,+BAmL9D"}
@@ -7,9 +7,7 @@ export function PhotoCaptureModal(props) {
7
7
  const { open, facingMode = 'user', onCapture, onClose } = props;
8
8
  const videoRef = useRef(null);
9
9
  const streamRef = useRef(null);
10
- // Bumped by every teardown. A camera that finishes starting after a teardown (dialog closed,
11
- // unmounted, superseded by Flip) belongs to nobody: its tracks are stopped, never attached,
12
- // or the camera would stay on with no dialog left to turn it off.
10
+ // A camera that finishes starting after a teardown is stopped, never attached, or it stays on.
13
11
  const acquireGenRef = useRef(0);
14
12
  const [activeFacing, setActiveFacing] = useState(facingMode);
15
13
  const [ready, setReady] = useState(false);
@@ -68,8 +66,6 @@ export function PhotoCaptureModal(props) {
68
66
  setActiveFacing(next);
69
67
  await startStream(next);
70
68
  }, { onError: reportError });
71
- // Capture is pending until the frame is encoded and handed off, and ignores a repeat
72
- // tap, so a double tap can never emit (and upload) two photos.
73
69
  const capture = useAsyncAction(async () => {
74
70
  const video = videoRef.current;
75
71
  if (!video)