@ttt-productions/file-input 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/dist/components/audio-input.d.ts +3 -0
  2. package/dist/components/audio-input.d.ts.map +1 -0
  3. package/dist/components/audio-input.js +6 -0
  4. package/dist/components/audio-input.js.map +1 -0
  5. package/dist/components/auto-format-modal.d.ts +11 -0
  6. package/dist/components/auto-format-modal.d.ts.map +1 -0
  7. package/dist/components/auto-format-modal.js +8 -0
  8. package/dist/components/auto-format-modal.js.map +1 -0
  9. package/dist/components/file-input.d.ts +3 -0
  10. package/dist/components/file-input.d.ts.map +1 -0
  11. package/dist/components/file-input.js +168 -0
  12. package/dist/components/file-input.js.map +1 -0
  13. package/dist/components/image-cropper-modal.d.ts +12 -0
  14. package/dist/components/image-cropper-modal.d.ts.map +1 -0
  15. package/dist/components/image-cropper-modal.js +31 -0
  16. package/dist/components/image-cropper-modal.js.map +1 -0
  17. package/dist/components/image-input.d.ts +3 -0
  18. package/dist/components/image-input.d.ts.map +1 -0
  19. package/dist/components/image-input.js +6 -0
  20. package/dist/components/image-input.js.map +1 -0
  21. package/dist/components/media-constraints-hint.d.ts +8 -0
  22. package/dist/components/media-constraints-hint.d.ts.map +1 -0
  23. package/dist/components/media-constraints-hint.js +56 -0
  24. package/dist/components/media-constraints-hint.js.map +1 -0
  25. package/dist/components/media-input.d.ts +3 -0
  26. package/dist/components/media-input.d.ts.map +1 -0
  27. package/dist/components/media-input.js +358 -0
  28. package/dist/components/media-input.js.map +1 -0
  29. package/dist/components/video-input.d.ts +3 -0
  30. package/dist/components/video-input.d.ts.map +1 -0
  31. package/dist/components/video-input.js +6 -0
  32. package/dist/components/video-input.js.map +1 -0
  33. package/dist/index.d.ts +7 -0
  34. package/dist/index.d.ts.map +1 -0
  35. package/dist/index.js +7 -0
  36. package/dist/index.js.map +1 -0
  37. package/dist/lib/image-utils.d.ts +6 -0
  38. package/dist/lib/image-utils.d.ts.map +1 -0
  39. package/dist/lib/image-utils.js +44 -0
  40. package/dist/lib/image-utils.js.map +1 -0
  41. package/dist/lib/read-media-meta.d.ts +13 -0
  42. package/dist/lib/read-media-meta.d.ts.map +1 -0
  43. package/dist/lib/read-media-meta.js +100 -0
  44. package/dist/lib/read-media-meta.js.map +1 -0
  45. package/dist/lib/validate-media-duration.d.ts +2 -0
  46. package/dist/lib/validate-media-duration.d.ts.map +1 -0
  47. package/dist/lib/validate-media-duration.js +20 -0
  48. package/dist/lib/validate-media-duration.js.map +1 -0
  49. package/dist/types.d.ts +72 -0
  50. package/dist/types.d.ts.map +1 -0
  51. package/dist/types.js +2 -0
  52. package/dist/types.js.map +1 -0
  53. package/package.json +44 -0
@@ -0,0 +1,3 @@
1
+ import type { FileInputProps } from "../types";
2
+ export declare function AudioInput(props: Omit<FileInputProps, "acceptTypes">): import("react/jsx-runtime").JSX.Element;
3
+ //# sourceMappingURL=audio-input.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audio-input.d.ts","sourceRoot":"","sources":["../../src/components/audio-input.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAG/C,wBAAgB,UAAU,CAAC,KAAK,EAAE,IAAI,CAAC,cAAc,EAAE,aAAa,CAAC,2CAEpE"}
@@ -0,0 +1,6 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { FileInput } from "./file-input";
3
+ export function AudioInput(props) {
4
+ return _jsx(FileInput, { ...props, acceptTypes: ["audio"] });
5
+ }
6
+ //# sourceMappingURL=audio-input.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audio-input.js","sourceRoot":"","sources":["../../src/components/audio-input.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,MAAM,UAAU,UAAU,CAAC,KAA0C;IACnE,OAAO,KAAC,SAAS,OAAK,KAAK,EAAE,WAAW,EAAE,CAAC,OAAO,CAAC,GAAI,CAAC;AAC1D,CAAC"}
@@ -0,0 +1,11 @@
1
+ export interface AutoFormatModalProps {
2
+ open: boolean;
3
+ title?: string;
4
+ description?: string;
5
+ proceedLabel?: string;
6
+ cancelLabel?: string;
7
+ onProceed: () => void;
8
+ onCancel: () => void;
9
+ }
10
+ export declare function AutoFormatModal(props: AutoFormatModalProps): import("react/jsx-runtime").JSX.Element;
11
+ //# sourceMappingURL=auto-format-modal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auto-format-modal.d.ts","sourceRoot":"","sources":["../../src/components/auto-format-modal.tsx"],"names":[],"mappings":"AAYA,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,oBAAoB,2CA8B1D"}
@@ -0,0 +1,8 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Button, Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@ttt-productions/ui-core";
4
+ export function AutoFormatModal(props) {
5
+ const { open, title = "We’ll auto-format this video", description = "This video doesn’t match the required format. We can auto-crop/resize/transcode after upload. This may take longer.", proceedLabel = "Proceed (Auto-format)", cancelLabel = "Cancel", onProceed, onCancel, } = props;
6
+ return (_jsx(Dialog, { open: open, onOpenChange: (v) => !v && onCancel(), children: _jsxs(DialogContent, { className: "max-w-md", children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: title }), _jsx(DialogDescription, { children: description })] }), _jsxs(DialogFooter, { className: "flex-row justify-end gap-2", children: [_jsx(Button, { variant: "destructive", onClick: onCancel, children: cancelLabel }), _jsx(Button, { variant: "default", onClick: onProceed, children: proceedLabel })] })] }) }));
7
+ }
8
+ //# sourceMappingURL=auto-format-modal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auto-format-modal.js","sourceRoot":"","sources":["../../src/components/auto-format-modal.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EACL,MAAM,EACN,MAAM,EACN,aAAa,EACb,iBAAiB,EACjB,YAAY,EACZ,YAAY,EACZ,WAAW,GACZ,MAAM,0BAA0B,CAAC;AAYlC,MAAM,UAAU,eAAe,CAAC,KAA2B;IACzD,MAAM,EACJ,IAAI,EACJ,KAAK,GAAG,8BAA8B,EACtC,WAAW,GAAG,qHAAqH,EACnI,YAAY,GAAG,uBAAuB,EACtC,WAAW,GAAG,QAAQ,EACtB,SAAS,EACT,QAAQ,GACT,GAAG,KAAK,CAAC;IAEV,OAAO,CACL,KAAC,MAAM,IAAC,IAAI,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,QAAQ,EAAE,YACvD,MAAC,aAAa,IAAC,SAAS,EAAC,UAAU,aACjC,MAAC,YAAY,eACX,KAAC,WAAW,cAAE,KAAK,GAAe,EAClC,KAAC,iBAAiB,cAAE,WAAW,GAAqB,IACvC,EAEf,MAAC,YAAY,IAAC,SAAS,EAAC,4BAA4B,aAClD,KAAC,MAAM,IAAC,OAAO,EAAC,aAAa,EAAC,OAAO,EAAE,QAAQ,YAC5C,WAAW,GACL,EACT,KAAC,MAAM,IAAC,OAAO,EAAC,SAAS,EAAC,OAAO,EAAE,SAAS,YACzC,YAAY,GACN,IACI,IACD,GACT,CACV,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { FileInputProps } from "../types";
2
+ export declare function FileInput(props: FileInputProps): import("react/jsx-runtime").JSX.Element;
3
+ //# sourceMappingURL=file-input.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-input.d.ts","sourceRoot":"","sources":["../../src/components/file-input.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAkB,cAAc,EAAE,MAAM,UAAU,CAAC;AAe/D,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,2CA2R9C"}
@@ -0,0 +1,168 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { useCallback, useEffect, useMemo, useRef, useState, useId } from "react";
4
+ import { getSimplifiedMediaType } from "@ttt-productions/media-contracts";
5
+ import { Alert, AlertDescription, Button, Card, Input, Progress, cn } from "@ttt-productions/ui-core";
6
+ import { Info, X, Upload, Film, Music, Paperclip, AlertTriangle, Loader2 } from "lucide-react";
7
+ import { validateMediaDuration } from "../lib/validate-media-duration";
8
+ import { ImageCropperModal } from "./image-cropper-modal";
9
+ const MIME_MAP = {
10
+ image: "image/jpeg, image/png, image/gif, image/webp, image/svg+xml, image/bmp, image/avif",
11
+ video: "video/*, .mkv",
12
+ audio: "audio/*",
13
+ other: ".pdf, .doc, .docx"
14
+ };
15
+ function err(code, message, details) {
16
+ return { code, message, details };
17
+ }
18
+ export function FileInput(props) {
19
+ const { acceptTypes, maxSizeMB, selectedFile, onChange, onError, isLoading = false, disabled = false, buttonLabel = "Upload File", className, uploadProgress = null, variant = "default", size = "default", cropConfig, videoMaxDurationSec, audioMaxDurationSec, defaultShowDetails = false, } = props;
20
+ const fileInputRef = useRef(null);
21
+ const lastPreviewUrlRef = useRef(null);
22
+ const revokeLastPreviewUrl = useCallback(() => {
23
+ if (!lastPreviewUrlRef.current)
24
+ return;
25
+ try {
26
+ URL.revokeObjectURL(lastPreviewUrlRef.current);
27
+ }
28
+ catch { }
29
+ lastPreviewUrlRef.current = null;
30
+ }, []);
31
+ const makePreviewUrl = useCallback((blob) => {
32
+ revokeLastPreviewUrl();
33
+ const url = URL.createObjectURL(blob);
34
+ lastPreviewUrlRef.current = url;
35
+ return url;
36
+ }, [revokeLastPreviewUrl]);
37
+ useEffect(() => {
38
+ return () => revokeLastPreviewUrl();
39
+ }, [revokeLastPreviewUrl]);
40
+ const uniqueId = useId();
41
+ const inputId = `file-input-${uniqueId}`;
42
+ const [internalSelected, setInternalSelected] = useState(null);
43
+ const fileValue = selectedFile !== undefined ? selectedFile : internalSelected;
44
+ const [localError, setLocalError] = useState(null);
45
+ const [isCropperOpen, setIsCropperOpen] = useState(false);
46
+ const [imageToCrop, setImageToCrop] = useState(null);
47
+ const [showDetails, setShowDetails] = useState(defaultShowDetails);
48
+ const acceptString = useMemo(() => (acceptTypes.length ? acceptTypes.map((t) => MIME_MAP[t]).join(", ") : undefined), [acceptTypes]);
49
+ const detailsDescriptionParts = useMemo(() => {
50
+ const parts = [];
51
+ if (cropConfig) {
52
+ const ratioDisplay = cropConfig.aspectRatioDisplay || `${cropConfig.aspectRatio.toFixed(2)}:1`;
53
+ parts.push(`Image will be cropped to a ${ratioDisplay} rect (${cropConfig.outputWidth}x${cropConfig.outputHeight}px).`);
54
+ }
55
+ const sizeParts = acceptTypes
56
+ .map((t) => (maxSizeMB[t] ? `${t.charAt(0).toUpperCase() + t.slice(1)} (${maxSizeMB[t]}MB)` : null))
57
+ .filter(Boolean);
58
+ if (sizeParts.length)
59
+ parts.push(`Max sizes: ${sizeParts.join(", ")}.`);
60
+ if (videoMaxDurationSec)
61
+ parts.push(`Max video duration: ${videoMaxDurationSec}s.`);
62
+ if (audioMaxDurationSec)
63
+ parts.push(`Max audio duration: ${audioMaxDurationSec}s.`);
64
+ return parts;
65
+ }, [acceptTypes, maxSizeMB, cropConfig, videoMaxDurationSec, audioMaxDurationSec]);
66
+ const getUploadIcon = () => {
67
+ if (acceptTypes.includes("image"))
68
+ return _jsx(Upload, { className: "mr-2 icon-xs" });
69
+ if (acceptTypes.includes("video"))
70
+ return _jsx(Film, { className: "mr-2 icon-xs" });
71
+ if (acceptTypes.includes("audio"))
72
+ return _jsx(Music, { className: "mr-2 icon-xs" });
73
+ return _jsx(Upload, { className: "mr-2 icon-xs" });
74
+ };
75
+ const clearNative = () => {
76
+ if (fileInputRef.current)
77
+ fileInputRef.current.value = "";
78
+ };
79
+ const emitError = (e, type = "other") => {
80
+ setLocalError(e);
81
+ onError?.(e);
82
+ onChange({ type, error: e });
83
+ };
84
+ const handleClear = (e) => {
85
+ e.stopPropagation();
86
+ e.preventDefault();
87
+ setLocalError(null);
88
+ setInternalSelected(null);
89
+ clearNative();
90
+ onChange({ type: "other" });
91
+ };
92
+ const handleFileChange = useCallback(async (event) => {
93
+ const file = event.target.files?.[0];
94
+ clearNative();
95
+ setLocalError(null);
96
+ if (!file) {
97
+ setInternalSelected(null);
98
+ onChange({ type: "other" });
99
+ return;
100
+ }
101
+ const fileType = getSimplifiedMediaType(file);
102
+ if (acceptTypes.length && !acceptTypes.includes(fileType)) {
103
+ emitError(err("invalid_type", `Invalid file type. Allowed: ${acceptTypes.join(", ")}.`), fileType);
104
+ return;
105
+ }
106
+ const maxBytes = (maxSizeMB[fileType] ?? Infinity) * 1024 * 1024;
107
+ if (file.size > maxBytes) {
108
+ emitError(err("too_large", `File too large. Max ${maxSizeMB[fileType]}MB for ${fileType}.`, { size: file.size, maxBytes }), fileType);
109
+ return;
110
+ }
111
+ if (fileType === "video" && videoMaxDurationSec) {
112
+ const ok = await validateMediaDuration(file, videoMaxDurationSec);
113
+ if (!ok) {
114
+ emitError(err("too_long", `Video too long. Max ${videoMaxDurationSec} seconds.`), fileType);
115
+ return;
116
+ }
117
+ }
118
+ if (fileType === "audio" && audioMaxDurationSec) {
119
+ const ok = await validateMediaDuration(file, audioMaxDurationSec);
120
+ if (!ok) {
121
+ emitError(err("too_long", `Audio too long. Max ${audioMaxDurationSec} seconds.`), fileType);
122
+ return;
123
+ }
124
+ }
125
+ // cropping path
126
+ if (cropConfig && fileType === "image") {
127
+ const reader = new FileReader();
128
+ reader.onload = () => {
129
+ setImageToCrop(reader.result);
130
+ setIsCropperOpen(true);
131
+ };
132
+ reader.onerror = () => {
133
+ emitError(err("read_failed", "Failed to read image for cropping."));
134
+ };
135
+ reader.readAsDataURL(file);
136
+ setInternalSelected(file);
137
+ return;
138
+ }
139
+ // normal selection
140
+ setInternalSelected(file);
141
+ const previewUrl = makePreviewUrl(file);
142
+ onChange({ type: fileType, file, previewUrl, revokePreviewUrl: revokeLastPreviewUrl });
143
+ }, [acceptTypes, maxSizeMB, cropConfig, videoMaxDurationSec, audioMaxDurationSec]);
144
+ const handleCropComplete = (blob) => {
145
+ setIsCropperOpen(false);
146
+ const original = internalSelected;
147
+ setImageToCrop(null);
148
+ if (!blob) {
149
+ emitError(err("crop_failed", "Cropping failed."), "image");
150
+ return;
151
+ }
152
+ onChange({
153
+ type: "image",
154
+ file: original ?? undefined,
155
+ blob,
156
+ previewUrl: makePreviewUrl(blob),
157
+ revokePreviewUrl: revokeLastPreviewUrl,
158
+ });
159
+ };
160
+ const isUploading = typeof uploadProgress === "number" && isLoading;
161
+ return (_jsxs("div", { className: cn("relative w-full", className), children: [localError && (_jsxs(Alert, { variant: "destructive", className: "mb-2", children: [_jsx(AlertTriangle, { className: "icon-xs" }), _jsx(AlertDescription, { children: localError.message })] })), _jsx(Input, { id: inputId, type: "file", accept: acceptString, onChange: handleFileChange, className: "hidden", disabled: disabled || isLoading, ref: fileInputRef }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("label", { htmlFor: inputId, className: "w-full flex-grow", children: _jsx(Button, { asChild: true, disabled: disabled || isLoading, variant: variant, size: size, className: cn("w-full relative overflow-hidden cursor-pointer", { "icon-xl p-0": size === "icon" }), children: _jsxs("span", { className: "relative w-full h-full center-row", children: [isUploading && (_jsx(Progress, { value: uploadProgress ?? 0, className: "absolute left-0 top-0 h-full w-full z-0 bg-accent" })), _jsx("span", { className: "z-10 center-row w-full", children: isLoading ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { className: "mr-2 spinner-xs" }), " ", isUploading ? `${(uploadProgress ?? 0).toFixed(0)}%` : "Processing..."] })) : fileValue ? (_jsxs("span", { className: "flex items-center justify-between w-full", children: [_jsx("span", { className: "truncate pr-2", children: fileValue.name }), _jsx(Button, { variant: "ghost", size: "icon", className: "icon-sm hover:bg-destructive/20 shrink-0", onClick: handleClear, children: _jsx(X, { className: "icon-xs" }) })] })) : (_jsx(_Fragment, { children: buttonLabel === "Attach"
162
+ ? _jsxs(_Fragment, { children: [_jsx(Paperclip, { className: "mr-2 icon-xs" }), " ", buttonLabel] })
163
+ : _jsxs(_Fragment, { children: [getUploadIcon(), " ", buttonLabel] }) })) })] }) }) }), detailsDescriptionParts.length > 0 && size !== "icon" && (_jsx(Button, { type: "button", variant: "default", size: "icon", onClick: () => setShowDetails((p) => !p), "aria-label": "Show file processing details", className: "flex-shrink-0 icon-xl", children: _jsx(Info, { className: "icon-sm" }) }))] }), showDetails && detailsDescriptionParts.length > 0 && size !== "icon" && (_jsx(Card, { className: "page-card w-full mt-2", children: _jsx("div", { className: "text-center p-2 space-y-0.5", children: detailsDescriptionParts.map((part, i) => (_jsx("p", { className: "text-small font-bold", children: part }, i))) }) })), cropConfig && imageToCrop && (_jsx(ImageCropperModal, { isOpen: isCropperOpen, onClose: () => {
164
+ setIsCropperOpen(false);
165
+ setImageToCrop(null);
166
+ }, imageSrc: imageToCrop, aspectRatio: cropConfig.aspectRatio, shape: cropConfig.shape, outputWidth: cropConfig.outputWidth, outputHeight: cropConfig.outputHeight, onCropComplete: handleCropComplete }))] }));
167
+ }
168
+ //# sourceMappingURL=file-input.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-input.js","sourceRoot":"","sources":["../../src/components/file-input.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ export interface ImageCropperModalProps {
2
+ isOpen: boolean;
3
+ onClose: () => void;
4
+ imageSrc: string | null;
5
+ aspectRatio: number;
6
+ shape: "rect" | "round";
7
+ outputWidth: number;
8
+ outputHeight: number;
9
+ onCropComplete: (croppedBlob: Blob | null) => void;
10
+ }
11
+ export declare function ImageCropperModal(props: ImageCropperModalProps): import("react/jsx-runtime").JSX.Element | null;
12
+ //# sourceMappingURL=image-cropper-modal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-cropper-modal.d.ts","sourceRoot":"","sources":["../../src/components/image-cropper-modal.tsx"],"names":[],"mappings":"AAOA,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,CAAC,WAAW,EAAE,IAAI,GAAG,IAAI,KAAK,IAAI,CAAC;CACpD;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,kDA0D9D"}
@@ -0,0 +1,31 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useState, useCallback } from "react";
4
+ import Cropper from "react-easy-crop";
5
+ import { Button, Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, DialogDescription, Slider } from "@ttt-productions/ui-core";
6
+ import { getCroppedImg } from "../lib/image-utils";
7
+ export function ImageCropperModal(props) {
8
+ const { isOpen, onClose, imageSrc, aspectRatio, shape, outputWidth, outputHeight, onCropComplete } = props;
9
+ const [crop, setCrop] = useState({ x: 0, y: 0 });
10
+ const [zoom, setZoom] = useState(1);
11
+ const [croppedAreaPixels, setCroppedAreaPixels] = useState(null);
12
+ const handleCropComplete = useCallback((_a, pixels) => {
13
+ setCroppedAreaPixels(pixels);
14
+ }, []);
15
+ const handleConfirm = useCallback(async () => {
16
+ if (!imageSrc || !croppedAreaPixels)
17
+ return;
18
+ try {
19
+ const blob = await getCroppedImg(imageSrc, croppedAreaPixels, 0, { horizontal: false, vertical: false }, outputWidth, outputHeight);
20
+ onCropComplete(blob);
21
+ onClose();
22
+ }
23
+ catch {
24
+ onCropComplete(null);
25
+ }
26
+ }, [imageSrc, croppedAreaPixels, onCropComplete, onClose, outputWidth, outputHeight]);
27
+ if (!imageSrc)
28
+ return null;
29
+ return (_jsx(Dialog, { open: isOpen, onOpenChange: (open) => !open && onClose(), children: _jsxs(DialogContent, { className: "max-w-md", children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: "Crop Image" }), _jsx(DialogDescription, { children: "Adjust the crop area and zoom level to select the desired portion of your image." })] }), _jsx("div", { className: "relative h-64 w-full bg-muted", children: _jsx(Cropper, { image: imageSrc, crop: crop, zoom: zoom, aspect: aspectRatio, cropShape: shape, showGrid: false, onCropChange: setCrop, onZoomChange: setZoom, onCropComplete: handleCropComplete }) }), _jsxs("div", { className: "stack-2", children: [_jsx("label", { htmlFor: "zoom", className: "text-small", children: "Zoom" }), _jsx(Slider, { id: "zoom", min: 1, max: 3, step: 0.1, value: [zoom], onValueChange: (v) => setZoom(v[0]) })] }), _jsxs(DialogFooter, { className: "flex-row justify-end gap-2", children: [_jsx(Button, { variant: "destructive", onClick: onClose, children: "Cancel" }), _jsx(Button, { variant: "default", onClick: handleConfirm, children: "Confirm" })] })] }) }));
30
+ }
31
+ //# sourceMappingURL=image-cropper-modal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-cropper-modal.js","sourceRoot":"","sources":["../../src/components/image-cropper-modal.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { FileInputProps } from "../types";
2
+ export declare function ImageInput(props: Omit<FileInputProps, "acceptTypes">): import("react/jsx-runtime").JSX.Element;
3
+ //# sourceMappingURL=image-input.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-input.d.ts","sourceRoot":"","sources":["../../src/components/image-input.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAG/C,wBAAgB,UAAU,CAAC,KAAK,EAAE,IAAI,CAAC,cAAc,EAAE,aAAa,CAAC,2CAEpE"}
@@ -0,0 +1,6 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { FileInput } from "./file-input";
3
+ export function ImageInput(props) {
4
+ return _jsx(FileInput, { ...props, acceptTypes: ["image"] });
5
+ }
6
+ //# sourceMappingURL=image-input.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-input.js","sourceRoot":"","sources":["../../src/components/image-input.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,MAAM,UAAU,UAAU,CAAC,KAA0C;IACnE,OAAO,KAAC,SAAS,OAAK,KAAK,EAAE,WAAW,EAAE,CAAC,OAAO,CAAC,GAAI,CAAC;AAC1D,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { MediaProcessingSpec } from "@ttt-productions/media-contracts";
2
+ export interface MediaConstraintsHintProps {
3
+ spec: MediaProcessingSpec;
4
+ className?: string;
5
+ title?: string;
6
+ }
7
+ export declare function MediaConstraintsHint(props: MediaConstraintsHintProps): import("react/jsx-runtime").JSX.Element | null;
8
+ //# sourceMappingURL=media-constraints-hint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"media-constraints-hint.d.ts","sourceRoot":"","sources":["../../src/components/media-constraints-hint.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAG5E,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,mBAAmB,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA0BD,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,yBAAyB,kDAkEpE"}
@@ -0,0 +1,56 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Badge, Card, cn } from "@ttt-productions/ui-core";
4
+ function fmtBytes(bytes) {
5
+ if (!bytes || bytes <= 0)
6
+ return null;
7
+ const mb = bytes / (1024 * 1024);
8
+ if (mb < 1024)
9
+ return `${Math.round(mb)}MB`;
10
+ const gb = mb / 1024;
11
+ return `${gb.toFixed(1)}GB`;
12
+ }
13
+ function fmtAspect(x) {
14
+ if (!x)
15
+ return null;
16
+ // show common approx ratios if close
17
+ const candidates = [
18
+ ["1:1", 1],
19
+ ["4:5", 4 / 5],
20
+ ["3:4", 3 / 4],
21
+ ["9:16", 9 / 16],
22
+ ["16:9", 16 / 9],
23
+ ];
24
+ for (const [label, v] of candidates) {
25
+ if (Math.abs(x - v) <= 0.02)
26
+ return label;
27
+ }
28
+ return `${x.toFixed(3)}`;
29
+ }
30
+ export function MediaConstraintsHint(props) {
31
+ const { spec, className, title = "Upload requirements" } = props;
32
+ const acceptKinds = spec.accept?.kinds?.length ? spec.accept.kinds.join(", ") : "any";
33
+ const acceptMimes = spec.accept?.mimes?.length ? spec.accept.mimes.join(", ") : "any";
34
+ const maxBytes = fmtBytes(spec.maxBytes);
35
+ const maxDur = spec.maxDurationSec ?? spec.video?.maxDurationSec ?? spec.audio?.maxDurationSec ?? undefined;
36
+ const requiredAspect = fmtAspect(spec.requiredAspectRatio ?? spec.imageCrop?.aspectRatio);
37
+ const requiredDims = spec.requiredWidth && spec.requiredHeight ? `${spec.requiredWidth}×${spec.requiredHeight}` : null;
38
+ const videoOri = spec.videoOrientation && spec.videoOrientation !== "any" ? spec.videoOrientation : null;
39
+ const cropDims = spec.imageCrop ? `${spec.imageCrop.outputWidth}×${spec.imageCrop.outputHeight}` : null;
40
+ const willAutoFormat = !!spec.allowAutoFormat;
41
+ const items = [
42
+ { k: "Kind", v: acceptKinds },
43
+ { k: "Types", v: acceptMimes },
44
+ { k: "Max size", v: maxBytes },
45
+ { k: "Max length", v: maxDur ? `${maxDur}s` : null },
46
+ { k: "Orientation", v: videoOri },
47
+ { k: "Aspect", v: requiredAspect },
48
+ { k: "Exact size", v: requiredDims },
49
+ { k: "Crop output", v: cropDims },
50
+ { k: "Auto-format", v: willAutoFormat ? "yes" : null },
51
+ ].filter((x) => x.v);
52
+ if (!items.length)
53
+ return null;
54
+ return (_jsxs(Card, { className: cn("p-3", className), children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsx("div", { className: "text-sm font-medium", children: title }), willAutoFormat ? _jsx(Badge, { variant: "secondary", children: "Auto-format supported" }) : null] }), _jsx("div", { className: "mt-2 flex flex-wrap gap-2", children: items.map((it) => (_jsxs(Badge, { variant: "outline", className: "gap-1", children: [_jsxs("span", { className: "text-muted-foreground", children: [it.k, ":"] }), _jsx("span", { children: it.v })] }, it.k))) }), spec.imageCrop ? (_jsxs("div", { className: "mt-2 text-xs text-muted-foreground", children: ["Images will be cropped to ", fmtAspect(spec.imageCrop.aspectRatio), " and exported as", " ", (spec.imageCrop.format ?? "jpeg").toUpperCase(), spec.imageCrop.quality ? ` @ ${spec.imageCrop.quality}%` : "", "."] })) : null, spec.allowAutoFormat ? (_jsx("div", { className: "mt-2 text-xs text-muted-foreground", children: "If your video doesn\u2019t match the format, we\u2019ll ask before uploading and then auto-format it in processing." })) : null] }));
55
+ }
56
+ //# sourceMappingURL=media-constraints-hint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"media-constraints-hint.js","sourceRoot":"","sources":["../../src/components/media-constraints-hint.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { MediaInputProps } from "../types";
2
+ export declare function MediaInput(props: MediaInputProps): import("react/jsx-runtime").JSX.Element;
3
+ //# sourceMappingURL=media-input.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"media-input.d.ts","sourceRoot":"","sources":["../../src/components/media-input.tsx"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAkB,eAAe,EAAqB,MAAM,UAAU,CAAC;AA4EnF,wBAAgB,UAAU,CAAC,KAAK,EAAE,eAAe,2CA+fhD"}