@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.
- package/dist/lib/image-utils.d.ts +0 -1
- package/dist/lib/image-utils.d.ts.map +1 -1
- package/dist/lib/image-utils.js +1 -2
- package/dist/lib/image-utils.js.map +1 -1
- package/dist/lib/infer-content-type.d.ts +0 -23
- package/dist/lib/infer-content-type.d.ts.map +1 -1
- package/dist/lib/infer-content-type.js +2 -56
- package/dist/lib/infer-content-type.js.map +1 -1
- package/dist/lib/validate-media-duration.d.ts.map +1 -1
- package/dist/lib/validate-media-duration.js +2 -7
- package/dist/lib/validate-media-duration.js.map +1 -1
- package/dist/lib/validate-upload-kind.d.ts +0 -34
- package/dist/lib/validate-upload-kind.d.ts.map +1 -1
- package/dist/lib/validate-upload-kind.js +0 -17
- package/dist/lib/validate-upload-kind.js.map +1 -1
- package/dist/react/components/file-input.d.ts.map +1 -1
- package/dist/react/components/file-input.js +0 -2
- package/dist/react/components/file-input.js.map +1 -1
- package/dist/react/components/image-cropper-modal.d.ts.map +1 -1
- package/dist/react/components/image-cropper-modal.js +0 -2
- package/dist/react/components/image-cropper-modal.js.map +1 -1
- package/dist/react/components/media-constraints-hint.d.ts.map +1 -1
- package/dist/react/components/media-constraints-hint.js +0 -1
- package/dist/react/components/media-constraints-hint.js.map +1 -1
- package/dist/react/components/media-input.d.ts.map +1 -1
- package/dist/react/components/media-input.js +4 -69
- package/dist/react/components/media-input.js.map +1 -1
- package/dist/react/components/photo-capture-modal.d.ts.map +1 -1
- package/dist/react/components/photo-capture-modal.js +1 -5
- package/dist/react/components/photo-capture-modal.js.map +1 -1
- package/dist/react/components/record-dialog.d.ts +0 -4
- package/dist/react/components/record-dialog.d.ts.map +1 -1
- package/dist/react/components/record-dialog.js +11 -88
- package/dist/react/components/record-dialog.js.map +1 -1
- package/dist/types.d.ts +0 -56
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- 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":"AAAA,YAAY,CAAC;;AAGb,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,gCAAgC,CAAC;AAC7D,OAAO,EAAE,EAAE,EAAE,MAAM,0BAA0B,CAAC;AAQ9C,SAAS,QAAQ,CAAC,KAAc;IAC9B,IAAI,CAAC,KAAK,IAAI,KAAK,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACtC,MAAM,EAAE,GAAG,KAAK,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;IACjC,IAAI,EAAE,GAAG,IAAI;QAAE,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC;IAC5C,MAAM,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;IACrB,OAAO,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;AAC9B,CAAC;AAED,SAAS,SAAS,CAAC,CAAU;IAC3B,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACpB,
|
|
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;
|
|
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;
|
|
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;
|
|
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;
|
|
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
|
|
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,+
|
|
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
|
-
//
|
|
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)
|