@ai-matrx/media 0.4.4 → 0.5.0
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/CHANGELOG.md +40 -0
- package/dist/core.cjs.map +1 -1
- package/dist/core.js.map +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +167 -93
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +1 -11
- package/dist/react.d.ts +1 -11
- package/dist/react.js +163 -89
- package/dist/react.js.map +1 -1
- package/dist/viewers.cjs +75 -266
- package/dist/viewers.cjs.map +1 -1
- package/dist/viewers.js +73 -264
- package/dist/viewers.js.map +1 -1
- package/package.json +3 -2
package/dist/react.d.cts
CHANGED
|
@@ -280,16 +280,6 @@ interface FileUploadDropzoneProps {
|
|
|
280
280
|
}
|
|
281
281
|
declare function FileUploadDropzone({ uploadOptions, accept, maxSize, enablePaste, mode, children, className, actions, onUploadStart, onUploaded, onError, onOpenFile, pickerEventName, }: FileUploadDropzoneProps): react.JSX.Element;
|
|
282
282
|
|
|
283
|
-
/**
|
|
284
|
-
* Human file size.
|
|
285
|
-
*
|
|
286
|
-
* `null` / `undefined` / NaN / negative collapse to an em-dash, NOT to
|
|
287
|
-
* "0 B" (fixed at 0.4.0 while absorbing the viewer bodies — matrx-frontend's
|
|
288
|
-
* `formatFileSize` already had this guard and the package's did not, so a
|
|
289
|
-
* corrupt or mid-upload `size` row rendered as a confident, wrong "0 B"
|
|
290
|
-
* instead of an honest "size unknown").
|
|
291
|
-
*/
|
|
292
|
-
declare function formatFileSize(bytes: number | null | undefined): string;
|
|
293
283
|
interface UploadProgressListProps {
|
|
294
284
|
uploads: MediaUploadEntry[];
|
|
295
285
|
/** Remove an entry from the tray (wire to `useMediaUpload().clearEntry`). */
|
|
@@ -350,4 +340,4 @@ interface MediaLightboxProps {
|
|
|
350
340
|
}
|
|
351
341
|
declare function MediaLightbox({ open, onClose, mediaRef, fileName, alt, as, autoPlay, playsInline, poster, playbackLabel, actions, hideUnavailableActions, headerExtra, className, }: MediaLightboxProps): react.JSX.Element | null;
|
|
352
342
|
|
|
353
|
-
export { AlertCircleIcon, ArchiveIcon, BracesIcon, CheckCircle2Icon, CheckIcon, CodeIcon, CopyIcon, DatabaseIcon, DownloadIcon, ExternalLinkIcon, FileAudioIcon, FileCodeIcon, FileIcon, type FileIconProps, FileJsonIcon, FileSpreadsheetIcon, FileTextIcon, FileTypeIcon, FileUploadDropzone, type FileUploadDropzoneActions, type FileUploadDropzoneProps, FileVideoIcon, FolderIcon, FolderOpenIcon, GlobeIcon, ImageIcon, ImageOffIcon, InlineMediaRef, type InlineMediaRefFit, type InlineMediaRefProps, type InlineMediaRefSize, Link2Icon, MediaActionToolbar, type MediaActionToolbarProps, type MediaDropzoneOptions, type MediaDropzoneState, type MediaIconProps, MediaLightbox, type MediaLightboxProps, MediaThumbnail, type MediaThumbnailProps, MusicIcon, PackageBoxIcon, PenToolIcon, PlusIcon, SearchIcon, Settings2Icon, Share2Icon, SpinnerIcon, SubtitlesIcon, UploadIcon, UploadProgressList, type UploadProgressListProps, VideoIcon, VideoOffIcon, VolumeXIcon, XIcon, cn,
|
|
343
|
+
export { AlertCircleIcon, ArchiveIcon, BracesIcon, CheckCircle2Icon, CheckIcon, CodeIcon, CopyIcon, DatabaseIcon, DownloadIcon, ExternalLinkIcon, FileAudioIcon, FileCodeIcon, FileIcon, type FileIconProps, FileJsonIcon, FileSpreadsheetIcon, FileTextIcon, FileTypeIcon, FileUploadDropzone, type FileUploadDropzoneActions, type FileUploadDropzoneProps, FileVideoIcon, FolderIcon, FolderOpenIcon, GlobeIcon, ImageIcon, ImageOffIcon, InlineMediaRef, type InlineMediaRefFit, type InlineMediaRefProps, type InlineMediaRefSize, Link2Icon, MediaActionToolbar, type MediaActionToolbarProps, type MediaDropzoneOptions, type MediaDropzoneState, type MediaIconProps, MediaLightbox, type MediaLightboxProps, MediaThumbnail, type MediaThumbnailProps, MusicIcon, PackageBoxIcon, PenToolIcon, PlusIcon, SearchIcon, Settings2Icon, Share2Icon, SpinnerIcon, SubtitlesIcon, UploadIcon, UploadProgressList, type UploadProgressListProps, VideoIcon, VideoOffIcon, VolumeXIcon, XIcon, cn, useMediaDropzone };
|
package/dist/react.d.ts
CHANGED
|
@@ -280,16 +280,6 @@ interface FileUploadDropzoneProps {
|
|
|
280
280
|
}
|
|
281
281
|
declare function FileUploadDropzone({ uploadOptions, accept, maxSize, enablePaste, mode, children, className, actions, onUploadStart, onUploaded, onError, onOpenFile, pickerEventName, }: FileUploadDropzoneProps): react.JSX.Element;
|
|
282
282
|
|
|
283
|
-
/**
|
|
284
|
-
* Human file size.
|
|
285
|
-
*
|
|
286
|
-
* `null` / `undefined` / NaN / negative collapse to an em-dash, NOT to
|
|
287
|
-
* "0 B" (fixed at 0.4.0 while absorbing the viewer bodies — matrx-frontend's
|
|
288
|
-
* `formatFileSize` already had this guard and the package's did not, so a
|
|
289
|
-
* corrupt or mid-upload `size` row rendered as a confident, wrong "0 B"
|
|
290
|
-
* instead of an honest "size unknown").
|
|
291
|
-
*/
|
|
292
|
-
declare function formatFileSize(bytes: number | null | undefined): string;
|
|
293
283
|
interface UploadProgressListProps {
|
|
294
284
|
uploads: MediaUploadEntry[];
|
|
295
285
|
/** Remove an entry from the tray (wire to `useMediaUpload().clearEntry`). */
|
|
@@ -350,4 +340,4 @@ interface MediaLightboxProps {
|
|
|
350
340
|
}
|
|
351
341
|
declare function MediaLightbox({ open, onClose, mediaRef, fileName, alt, as, autoPlay, playsInline, poster, playbackLabel, actions, hideUnavailableActions, headerExtra, className, }: MediaLightboxProps): react.JSX.Element | null;
|
|
352
342
|
|
|
353
|
-
export { AlertCircleIcon, ArchiveIcon, BracesIcon, CheckCircle2Icon, CheckIcon, CodeIcon, CopyIcon, DatabaseIcon, DownloadIcon, ExternalLinkIcon, FileAudioIcon, FileCodeIcon, FileIcon, type FileIconProps, FileJsonIcon, FileSpreadsheetIcon, FileTextIcon, FileTypeIcon, FileUploadDropzone, type FileUploadDropzoneActions, type FileUploadDropzoneProps, FileVideoIcon, FolderIcon, FolderOpenIcon, GlobeIcon, ImageIcon, ImageOffIcon, InlineMediaRef, type InlineMediaRefFit, type InlineMediaRefProps, type InlineMediaRefSize, Link2Icon, MediaActionToolbar, type MediaActionToolbarProps, type MediaDropzoneOptions, type MediaDropzoneState, type MediaIconProps, MediaLightbox, type MediaLightboxProps, MediaThumbnail, type MediaThumbnailProps, MusicIcon, PackageBoxIcon, PenToolIcon, PlusIcon, SearchIcon, Settings2Icon, Share2Icon, SpinnerIcon, SubtitlesIcon, UploadIcon, UploadProgressList, type UploadProgressListProps, VideoIcon, VideoOffIcon, VolumeXIcon, XIcon, cn,
|
|
343
|
+
export { AlertCircleIcon, ArchiveIcon, BracesIcon, CheckCircle2Icon, CheckIcon, CodeIcon, CopyIcon, DatabaseIcon, DownloadIcon, ExternalLinkIcon, FileAudioIcon, FileCodeIcon, FileIcon, type FileIconProps, FileJsonIcon, FileSpreadsheetIcon, FileTextIcon, FileTypeIcon, FileUploadDropzone, type FileUploadDropzoneActions, type FileUploadDropzoneProps, FileVideoIcon, FolderIcon, FolderOpenIcon, GlobeIcon, ImageIcon, ImageOffIcon, InlineMediaRef, type InlineMediaRefFit, type InlineMediaRefProps, type InlineMediaRefSize, Link2Icon, MediaActionToolbar, type MediaActionToolbarProps, type MediaDropzoneOptions, type MediaDropzoneState, type MediaIconProps, MediaLightbox, type MediaLightboxProps, MediaThumbnail, type MediaThumbnailProps, MusicIcon, PackageBoxIcon, PenToolIcon, PlusIcon, SearchIcon, Settings2Icon, Share2Icon, SpinnerIcon, SubtitlesIcon, UploadIcon, UploadProgressList, type UploadProgressListProps, VideoIcon, VideoOffIcon, VolumeXIcon, XIcon, cn, useMediaDropzone };
|
package/dist/react.js
CHANGED
|
@@ -465,11 +465,11 @@ function FileIcon2({
|
|
|
465
465
|
|
|
466
466
|
// src/react/inline-media-ref.tsx
|
|
467
467
|
import {
|
|
468
|
-
useCallback as
|
|
469
|
-
useEffect as
|
|
468
|
+
useCallback as useCallback3,
|
|
469
|
+
useEffect as useEffect5,
|
|
470
470
|
useMemo as useMemo2,
|
|
471
|
-
useRef as
|
|
472
|
-
useState as
|
|
471
|
+
useRef as useRef4,
|
|
472
|
+
useState as useState4
|
|
473
473
|
} from "react";
|
|
474
474
|
|
|
475
475
|
// src/core/context.ts
|
|
@@ -620,8 +620,83 @@ function useMediaBlob(ref) {
|
|
|
620
620
|
};
|
|
621
621
|
}
|
|
622
622
|
|
|
623
|
+
// src/core/use-media-blob-load-recovery.ts
|
|
624
|
+
import { useCallback as useCallback2, useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
|
|
625
|
+
function useMediaBlobLoadRecovery(ref, source, options) {
|
|
626
|
+
const client = useMediaClient();
|
|
627
|
+
const capture = useMediaFailureCapture();
|
|
628
|
+
const refKey = stableRefKey(ref);
|
|
629
|
+
const [failed, setFailed] = useState2(false);
|
|
630
|
+
const attemptRef = useRef2(0);
|
|
631
|
+
const recoveryInFlightRef = useRef2(false);
|
|
632
|
+
const onRetry = options.onRetry;
|
|
633
|
+
const onTerminal = options.onTerminal;
|
|
634
|
+
useEffect2(() => {
|
|
635
|
+
attemptRef.current = 0;
|
|
636
|
+
recoveryInFlightRef.current = false;
|
|
637
|
+
setFailed(false);
|
|
638
|
+
}, [refKey]);
|
|
639
|
+
useEffect2(() => {
|
|
640
|
+
recoveryInFlightRef.current = false;
|
|
641
|
+
}, [source]);
|
|
642
|
+
const finishTerminal = useCallback2(
|
|
643
|
+
(event, attempt, message) => {
|
|
644
|
+
setFailed(true);
|
|
645
|
+
capture({
|
|
646
|
+
phase: "element-load",
|
|
647
|
+
mediaRef: failureMediaIdentity(ref ?? null, source),
|
|
648
|
+
terminal: true,
|
|
649
|
+
retryOutcome: attempt > 1 ? "retried" : "not-attempted",
|
|
650
|
+
message
|
|
651
|
+
});
|
|
652
|
+
onTerminal?.(event);
|
|
653
|
+
},
|
|
654
|
+
[capture, onTerminal, ref, source]
|
|
655
|
+
);
|
|
656
|
+
const onLoadError = useCallback2(
|
|
657
|
+
(event) => {
|
|
658
|
+
if (recoveryInFlightRef.current || !source) return;
|
|
659
|
+
recoveryInFlightRef.current = true;
|
|
660
|
+
attemptRef.current += 1;
|
|
661
|
+
const attempt = attemptRef.current;
|
|
662
|
+
const recover = client.recoverBlobLoadError;
|
|
663
|
+
if (!ref || !recover) {
|
|
664
|
+
finishTerminal(
|
|
665
|
+
event,
|
|
666
|
+
attempt,
|
|
667
|
+
"blob-backed media element failed to load and the client exposes no object-URL recovery policy"
|
|
668
|
+
);
|
|
669
|
+
return;
|
|
670
|
+
}
|
|
671
|
+
recover(ref, attempt).then(
|
|
672
|
+
(verdict) => {
|
|
673
|
+
if (verdict === "retry") {
|
|
674
|
+
setFailed(false);
|
|
675
|
+
onRetry();
|
|
676
|
+
return;
|
|
677
|
+
}
|
|
678
|
+
finishTerminal(
|
|
679
|
+
event,
|
|
680
|
+
attempt,
|
|
681
|
+
attempt > 1 ? "blob-backed media element failed after the client-approved re-read" : "blob-backed media recovery was declined on the first attempt"
|
|
682
|
+
);
|
|
683
|
+
},
|
|
684
|
+
(err) => {
|
|
685
|
+
finishTerminal(
|
|
686
|
+
event,
|
|
687
|
+
attempt,
|
|
688
|
+
`blob-backed media recovery failed: ${err instanceof Error ? err.message : String(err ?? "unknown error")}`
|
|
689
|
+
);
|
|
690
|
+
}
|
|
691
|
+
);
|
|
692
|
+
},
|
|
693
|
+
[client, finishTerminal, onRetry, ref, source]
|
|
694
|
+
);
|
|
695
|
+
return { onLoadError, failed };
|
|
696
|
+
}
|
|
697
|
+
|
|
623
698
|
// src/core/use-media-load-recovery.ts
|
|
624
|
-
import { useEffect as
|
|
699
|
+
import { useEffect as useEffect3, useLayoutEffect, useRef as useRef3, useState as useState3 } from "react";
|
|
625
700
|
|
|
626
701
|
// src/types.ts
|
|
627
702
|
function mintDurableSrc(url) {
|
|
@@ -639,10 +714,10 @@ function useMediaLoadRecovery(src, options) {
|
|
|
639
714
|
const recoverable = options?.recoverable !== false;
|
|
640
715
|
const onTerminal = options?.onTerminal;
|
|
641
716
|
const failureRef = options?.failureRef;
|
|
642
|
-
const [result, setResult] =
|
|
643
|
-
const attemptRef =
|
|
644
|
-
const recoveryInFlightRef =
|
|
645
|
-
|
|
717
|
+
const [result, setResult] = useState3({ source: src, retryKey: 0, failed: false });
|
|
718
|
+
const attemptRef = useRef3(0);
|
|
719
|
+
const recoveryInFlightRef = useRef3(false);
|
|
720
|
+
useEffect3(() => {
|
|
646
721
|
attemptRef.current = 0;
|
|
647
722
|
recoveryInFlightRef.current = false;
|
|
648
723
|
}, [src]);
|
|
@@ -720,7 +795,7 @@ function useMediaLoadRecovery(src, options) {
|
|
|
720
795
|
}
|
|
721
796
|
|
|
722
797
|
// src/core/use-media-resolution.ts
|
|
723
|
-
import { useEffect as
|
|
798
|
+
import { useEffect as useEffect4, useMemo } from "react";
|
|
724
799
|
function useMediaResolution(ref) {
|
|
725
800
|
const client = useMediaClient();
|
|
726
801
|
const capture = useMediaFailureCapture();
|
|
@@ -755,7 +830,7 @@ function useMediaResolution(ref) {
|
|
|
755
830
|
};
|
|
756
831
|
}
|
|
757
832
|
}, [client, refKey]);
|
|
758
|
-
|
|
833
|
+
useEffect4(() => {
|
|
759
834
|
if (state.status !== "unavailable") return;
|
|
760
835
|
capture({
|
|
761
836
|
phase: "resolve",
|
|
@@ -810,7 +885,7 @@ function prettifyUrl(url) {
|
|
|
810
885
|
}
|
|
811
886
|
var INERT_PLAYBACK = {
|
|
812
887
|
useMediaElementSink(forward) {
|
|
813
|
-
return
|
|
888
|
+
return useCallback3(
|
|
814
889
|
(node) => {
|
|
815
890
|
if (!forward) return;
|
|
816
891
|
if (typeof forward === "function") forward(node);
|
|
@@ -861,7 +936,7 @@ function InformativeErrorFallback({
|
|
|
861
936
|
}) {
|
|
862
937
|
const capture = useMediaFailureCapture();
|
|
863
938
|
const identity = failureMediaIdentity(mediaRef ?? null, url);
|
|
864
|
-
|
|
939
|
+
useEffect5(() => {
|
|
865
940
|
capture({
|
|
866
941
|
phase: failurePhase,
|
|
867
942
|
mediaRef: identity,
|
|
@@ -925,10 +1000,10 @@ function InformativeErrorPanel({
|
|
|
925
1000
|
icon,
|
|
926
1001
|
tooltip
|
|
927
1002
|
}) {
|
|
928
|
-
const [copied, setCopied] =
|
|
1003
|
+
const [copied, setCopied] = useState4(false);
|
|
929
1004
|
const isFill = dimensions === "fill";
|
|
930
1005
|
const { host, tail } = prettifyUrl(url);
|
|
931
|
-
const handleCopy =
|
|
1006
|
+
const handleCopy = useCallback3(
|
|
932
1007
|
(event) => {
|
|
933
1008
|
event.stopPropagation();
|
|
934
1009
|
event.preventDefault();
|
|
@@ -1045,16 +1120,25 @@ function InlineMediaRef({
|
|
|
1045
1120
|
);
|
|
1046
1121
|
const blob = useMediaBlob(needsBlob ? mediaRef : null);
|
|
1047
1122
|
const url = needsBlob ? blob.url : resolution?.src ?? null;
|
|
1123
|
+
const terminalCallback = (event) => onError?.(
|
|
1124
|
+
event
|
|
1125
|
+
);
|
|
1048
1126
|
const recovery = useMediaLoadRecovery(url, {
|
|
1049
|
-
recoverable:
|
|
1127
|
+
recoverable: resolution?.recoverable !== false,
|
|
1050
1128
|
failureRef: mediaRef,
|
|
1051
|
-
onTerminal:
|
|
1052
|
-
event
|
|
1053
|
-
)
|
|
1129
|
+
onTerminal: terminalCallback
|
|
1054
1130
|
});
|
|
1131
|
+
const blobRecovery = useMediaBlobLoadRecovery(
|
|
1132
|
+
needsBlob ? mediaRef : null,
|
|
1133
|
+
needsBlob ? url : null,
|
|
1134
|
+
{
|
|
1135
|
+
onRetry: blob.retry,
|
|
1136
|
+
onTerminal: terminalCallback
|
|
1137
|
+
}
|
|
1138
|
+
);
|
|
1055
1139
|
const playback = ports.playbackSession ?? INERT_PLAYBACK;
|
|
1056
|
-
const sessionElRef =
|
|
1057
|
-
const [isMediaPlaying, setIsMediaPlaying] =
|
|
1140
|
+
const sessionElRef = useRef4(null);
|
|
1141
|
+
const [isMediaPlaying, setIsMediaPlaying] = useState4(false);
|
|
1058
1142
|
const portSinkRef = playback.useMediaElementSink(
|
|
1059
1143
|
mediaElementRef
|
|
1060
1144
|
);
|
|
@@ -1085,8 +1169,10 @@ function InlineMediaRef({
|
|
|
1085
1169
|
const mediaResolutionError = status === "unavailable" ? reason ?? "unknown" : blob.error ?? null;
|
|
1086
1170
|
const dimensions = resolveDimensions(size);
|
|
1087
1171
|
const isFill = dimensions === "fill";
|
|
1088
|
-
const
|
|
1089
|
-
const
|
|
1172
|
+
const activeRecovery = needsBlob ? blobRecovery : recovery;
|
|
1173
|
+
const retryKey = needsBlob ? 0 : recovery.retryKey;
|
|
1174
|
+
const hasLoadError = activeRecovery.failed;
|
|
1175
|
+
const handleLoadError = activeRecovery.onLoadError;
|
|
1090
1176
|
const defaultIcon = elementType === "video" ? /* @__PURE__ */ jsx3(FileVideoIcon, { className: "h-1/2 w-1/2" }) : elementType === "audio" ? /* @__PURE__ */ jsx3(FileAudioIcon, { className: "h-1/2 w-1/2" }) : mediaRef ? /* @__PURE__ */ jsx3(ImageIcon, { className: "h-1/2 w-1/2" }) : /* @__PURE__ */ jsx3(FileIcon, { className: "h-1/2 w-1/2" });
|
|
1091
1177
|
const unresolvedDisplayUrl = mediaRef && typeof mediaRef === "object" && mediaRef.file_id ? `file:${mediaRef.file_id}` : "unresolved-media";
|
|
1092
1178
|
if (!url) {
|
|
@@ -1222,7 +1308,7 @@ function InlineMediaRef({
|
|
|
1222
1308
|
...mediaSessionEvents,
|
|
1223
1309
|
...interactiveProps
|
|
1224
1310
|
},
|
|
1225
|
-
|
|
1311
|
+
retryKey
|
|
1226
1312
|
);
|
|
1227
1313
|
}
|
|
1228
1314
|
if (elementType === "audio") {
|
|
@@ -1243,7 +1329,7 @@ function InlineMediaRef({
|
|
|
1243
1329
|
crossOrigin,
|
|
1244
1330
|
...interactiveProps
|
|
1245
1331
|
},
|
|
1246
|
-
|
|
1332
|
+
retryKey
|
|
1247
1333
|
);
|
|
1248
1334
|
}
|
|
1249
1335
|
const needsPlainImg = !!onLoad || !!mediaElementRef || !!crossOrigin;
|
|
@@ -1261,7 +1347,7 @@ function InlineMediaRef({
|
|
|
1261
1347
|
onError: handleLoadError,
|
|
1262
1348
|
...interactiveProps
|
|
1263
1349
|
},
|
|
1264
|
-
|
|
1350
|
+
retryKey
|
|
1265
1351
|
);
|
|
1266
1352
|
}
|
|
1267
1353
|
return /* @__PURE__ */ jsx3(
|
|
@@ -1277,12 +1363,12 @@ function InlineMediaRef({
|
|
|
1277
1363
|
crossOrigin,
|
|
1278
1364
|
...interactiveProps
|
|
1279
1365
|
},
|
|
1280
|
-
|
|
1366
|
+
retryKey
|
|
1281
1367
|
);
|
|
1282
1368
|
}
|
|
1283
1369
|
|
|
1284
1370
|
// src/react/media-thumbnail.tsx
|
|
1285
|
-
import { useEffect as
|
|
1371
|
+
import { useEffect as useEffect6, useRef as useRef5 } from "react";
|
|
1286
1372
|
|
|
1287
1373
|
// src/core/use-thumbnail-source.ts
|
|
1288
1374
|
import { useMemo as useMemo3 } from "react";
|
|
@@ -1440,8 +1526,8 @@ function VideoPosterThumb({
|
|
|
1440
1526
|
recoverable,
|
|
1441
1527
|
failureRef: mediaRef
|
|
1442
1528
|
});
|
|
1443
|
-
const ref =
|
|
1444
|
-
|
|
1529
|
+
const ref = useRef5(null);
|
|
1530
|
+
useEffect6(() => {
|
|
1445
1531
|
const v = ref.current;
|
|
1446
1532
|
if (!v) return void 0;
|
|
1447
1533
|
const onMeta = () => {
|
|
@@ -1471,11 +1557,11 @@ function VideoPosterThumb({
|
|
|
1471
1557
|
|
|
1472
1558
|
// src/react/use-media-dropzone.ts
|
|
1473
1559
|
import {
|
|
1474
|
-
useCallback as
|
|
1475
|
-
useEffect as
|
|
1560
|
+
useCallback as useCallback4,
|
|
1561
|
+
useEffect as useEffect7,
|
|
1476
1562
|
useMemo as useMemo4,
|
|
1477
|
-
useRef as
|
|
1478
|
-
useState as
|
|
1563
|
+
useRef as useRef6,
|
|
1564
|
+
useState as useState5
|
|
1479
1565
|
} from "react";
|
|
1480
1566
|
function matchesAccept(file, accept) {
|
|
1481
1567
|
if (!accept || accept.length === 0) return true;
|
|
@@ -1500,16 +1586,16 @@ function useMediaDropzone(options) {
|
|
|
1500
1586
|
disabled = false,
|
|
1501
1587
|
multiple = true
|
|
1502
1588
|
} = options;
|
|
1503
|
-
const [isDragActive, setIsDragActive] =
|
|
1504
|
-
const [pasteHighlight, setPasteHighlight] =
|
|
1505
|
-
const dragDepth =
|
|
1506
|
-
const inputRef =
|
|
1507
|
-
const onFilesRef =
|
|
1589
|
+
const [isDragActive, setIsDragActive] = useState5(false);
|
|
1590
|
+
const [pasteHighlight, setPasteHighlight] = useState5(false);
|
|
1591
|
+
const dragDepth = useRef6(0);
|
|
1592
|
+
const inputRef = useRef6(null);
|
|
1593
|
+
const onFilesRef = useRef6(onFiles);
|
|
1508
1594
|
onFilesRef.current = onFiles;
|
|
1509
|
-
const onRejectedRef =
|
|
1595
|
+
const onRejectedRef = useRef6(onRejected);
|
|
1510
1596
|
onRejectedRef.current = onRejected;
|
|
1511
1597
|
const acceptKey = accept?.join(",") ?? "";
|
|
1512
|
-
const filterFiles =
|
|
1598
|
+
const filterFiles = useCallback4(
|
|
1513
1599
|
(files) => {
|
|
1514
1600
|
const accepted = [];
|
|
1515
1601
|
const rejected = [];
|
|
@@ -1527,23 +1613,23 @@ function useMediaDropzone(options) {
|
|
|
1527
1613
|
},
|
|
1528
1614
|
[acceptKey, maxSize]
|
|
1529
1615
|
);
|
|
1530
|
-
const emit =
|
|
1616
|
+
const emit = useCallback4(
|
|
1531
1617
|
(files) => {
|
|
1532
1618
|
const accepted = filterFiles(files);
|
|
1533
1619
|
if (accepted.length) onFilesRef.current(accepted);
|
|
1534
1620
|
},
|
|
1535
1621
|
[filterFiles]
|
|
1536
1622
|
);
|
|
1537
|
-
const openPicker =
|
|
1623
|
+
const openPicker = useCallback4(() => {
|
|
1538
1624
|
if (!disabled) inputRef.current?.click();
|
|
1539
1625
|
}, [disabled]);
|
|
1540
|
-
|
|
1626
|
+
useEffect7(() => {
|
|
1541
1627
|
if (!pickerEventName || typeof window === "undefined") return void 0;
|
|
1542
1628
|
const handler = () => openPicker();
|
|
1543
1629
|
window.addEventListener(pickerEventName, handler);
|
|
1544
1630
|
return () => window.removeEventListener(pickerEventName, handler);
|
|
1545
1631
|
}, [openPicker, pickerEventName]);
|
|
1546
|
-
|
|
1632
|
+
useEffect7(() => {
|
|
1547
1633
|
if (!enablePaste || disabled || typeof window === "undefined") {
|
|
1548
1634
|
return void 0;
|
|
1549
1635
|
}
|
|
@@ -1569,7 +1655,7 @@ function useMediaDropzone(options) {
|
|
|
1569
1655
|
window.addEventListener("paste", handler);
|
|
1570
1656
|
return () => window.removeEventListener("paste", handler);
|
|
1571
1657
|
}, [enablePaste, disabled, emit]);
|
|
1572
|
-
const getRootProps =
|
|
1658
|
+
const getRootProps = useCallback4(
|
|
1573
1659
|
() => ({
|
|
1574
1660
|
onDragEnter: (event) => {
|
|
1575
1661
|
if (disabled) return;
|
|
@@ -1602,7 +1688,7 @@ function useMediaDropzone(options) {
|
|
|
1602
1688
|
() => acceptKey.length ? acceptKey : void 0,
|
|
1603
1689
|
[acceptKey]
|
|
1604
1690
|
);
|
|
1605
|
-
const getInputProps =
|
|
1691
|
+
const getInputProps = useCallback4(
|
|
1606
1692
|
() => ({
|
|
1607
1693
|
ref: (node) => {
|
|
1608
1694
|
inputRef.current = node;
|
|
@@ -1624,20 +1710,20 @@ function useMediaDropzone(options) {
|
|
|
1624
1710
|
}
|
|
1625
1711
|
|
|
1626
1712
|
// src/react/file-upload-dropzone.tsx
|
|
1627
|
-
import { useCallback as
|
|
1713
|
+
import { useCallback as useCallback6 } from "react";
|
|
1628
1714
|
|
|
1629
1715
|
// src/core/use-media-upload.ts
|
|
1630
|
-
import { useCallback as
|
|
1716
|
+
import { useCallback as useCallback5, useRef as useRef7, useState as useState6 } from "react";
|
|
1631
1717
|
var entrySeq = 0;
|
|
1632
1718
|
function useMediaUpload() {
|
|
1633
1719
|
const client = useMediaClient();
|
|
1634
|
-
const [uploading, setUploading] =
|
|
1635
|
-
const [progress, setProgress] =
|
|
1636
|
-
const [result, setResult] =
|
|
1637
|
-
const [error, setError] =
|
|
1638
|
-
const [entries, setEntries] =
|
|
1639
|
-
const activeCount =
|
|
1640
|
-
const patchEntry =
|
|
1720
|
+
const [uploading, setUploading] = useState6(false);
|
|
1721
|
+
const [progress, setProgress] = useState6(null);
|
|
1722
|
+
const [result, setResult] = useState6(null);
|
|
1723
|
+
const [error, setError] = useState6(null);
|
|
1724
|
+
const [entries, setEntries] = useState6([]);
|
|
1725
|
+
const activeCount = useRef7(0);
|
|
1726
|
+
const patchEntry = useCallback5(
|
|
1641
1727
|
(id, patch) => {
|
|
1642
1728
|
setEntries(
|
|
1643
1729
|
(current) => current.map((e) => e.id === id ? { ...e, ...patch } : e)
|
|
@@ -1645,7 +1731,7 @@ function useMediaUpload() {
|
|
|
1645
1731
|
},
|
|
1646
1732
|
[]
|
|
1647
1733
|
);
|
|
1648
|
-
const upload =
|
|
1734
|
+
const upload = useCallback5(
|
|
1649
1735
|
async (file, opts = {}) => {
|
|
1650
1736
|
const id = `up-${++entrySeq}`;
|
|
1651
1737
|
const fileName = opts.fileName ?? (file instanceof File ? file.name : "file");
|
|
@@ -1699,7 +1785,7 @@ function useMediaUpload() {
|
|
|
1699
1785
|
},
|
|
1700
1786
|
[client, patchEntry]
|
|
1701
1787
|
);
|
|
1702
|
-
const uploadMany =
|
|
1788
|
+
const uploadMany = useCallback5(
|
|
1703
1789
|
async (files, opts = {}) => {
|
|
1704
1790
|
if (client.uploadMany) {
|
|
1705
1791
|
activeCount.current += 1;
|
|
@@ -1728,10 +1814,10 @@ function useMediaUpload() {
|
|
|
1728
1814
|
},
|
|
1729
1815
|
[client, upload]
|
|
1730
1816
|
);
|
|
1731
|
-
const clearEntry =
|
|
1817
|
+
const clearEntry = useCallback5((id) => {
|
|
1732
1818
|
setEntries((current) => current.filter((e) => e.id !== id));
|
|
1733
1819
|
}, []);
|
|
1734
|
-
const reset =
|
|
1820
|
+
const reset = useCallback5(() => {
|
|
1735
1821
|
setResult(null);
|
|
1736
1822
|
setError(null);
|
|
1737
1823
|
setProgress(null);
|
|
@@ -1751,37 +1837,26 @@ function useMediaUpload() {
|
|
|
1751
1837
|
}
|
|
1752
1838
|
|
|
1753
1839
|
// src/react/upload-progress-list.tsx
|
|
1754
|
-
import { memo, useEffect as
|
|
1840
|
+
import { memo, useEffect as useEffect8, useRef as useRef8, useState as useState7 } from "react";
|
|
1841
|
+
import { formatFileSize } from "@ai-matrx/kit/format";
|
|
1755
1842
|
import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1756
1843
|
var AUTO_DISMISS_MS = 1e4;
|
|
1757
|
-
function formatFileSize(bytes) {
|
|
1758
|
-
if (bytes == null || !Number.isFinite(bytes) || bytes < 0) return "\u2014";
|
|
1759
|
-
if (bytes < 1024) return `${bytes} B`;
|
|
1760
|
-
const units = ["KB", "MB", "GB", "TB"];
|
|
1761
|
-
let value = bytes;
|
|
1762
|
-
let unit = -1;
|
|
1763
|
-
do {
|
|
1764
|
-
value /= 1024;
|
|
1765
|
-
unit += 1;
|
|
1766
|
-
} while (value >= 1024 && unit < units.length - 1);
|
|
1767
|
-
return `${value >= 10 ? Math.round(value) : value.toFixed(1)} ${units[unit] ?? "TB"}`;
|
|
1768
|
-
}
|
|
1769
1844
|
function UploadProgressListImpl({
|
|
1770
1845
|
uploads,
|
|
1771
1846
|
onDismiss,
|
|
1772
1847
|
onOpenFile,
|
|
1773
1848
|
className
|
|
1774
1849
|
}) {
|
|
1775
|
-
const [hovered, setHovered] =
|
|
1850
|
+
const [hovered, setHovered] = useState7(false);
|
|
1776
1851
|
const activeCount = uploads.filter((u) => u.status === "uploading").length;
|
|
1777
1852
|
const successCount = uploads.filter((u) => u.status === "success").length;
|
|
1778
1853
|
const errorCount = uploads.filter((u) => u.status === "error").length;
|
|
1779
|
-
const timersRef =
|
|
1854
|
+
const timersRef = useRef8(
|
|
1780
1855
|
/* @__PURE__ */ new Map()
|
|
1781
1856
|
);
|
|
1782
|
-
const onDismissRef =
|
|
1857
|
+
const onDismissRef = useRef8(onDismiss);
|
|
1783
1858
|
onDismissRef.current = onDismiss;
|
|
1784
|
-
|
|
1859
|
+
useEffect8(() => {
|
|
1785
1860
|
const timers = timersRef.current;
|
|
1786
1861
|
if (hovered) {
|
|
1787
1862
|
timers.forEach((t) => clearTimeout(t));
|
|
@@ -1809,7 +1884,7 @@ function UploadProgressListImpl({
|
|
|
1809
1884
|
}
|
|
1810
1885
|
}
|
|
1811
1886
|
}, [uploads, hovered]);
|
|
1812
|
-
|
|
1887
|
+
useEffect8(() => {
|
|
1813
1888
|
const timers = timersRef.current;
|
|
1814
1889
|
return () => {
|
|
1815
1890
|
timers.forEach((t) => clearTimeout(t));
|
|
@@ -1941,7 +2016,7 @@ function FileUploadDropzone({
|
|
|
1941
2016
|
pickerEventName
|
|
1942
2017
|
}) {
|
|
1943
2018
|
const { uploadMany, entries, clearEntry } = useMediaUpload();
|
|
1944
|
-
const handleUpload =
|
|
2019
|
+
const handleUpload = useCallback6(
|
|
1945
2020
|
async (files) => {
|
|
1946
2021
|
if (!files.length) return;
|
|
1947
2022
|
try {
|
|
@@ -2048,22 +2123,22 @@ function FileUploadDropzone({
|
|
|
2048
2123
|
}
|
|
2049
2124
|
|
|
2050
2125
|
// src/react/media-action-toolbar.tsx
|
|
2051
|
-
import { useState as
|
|
2126
|
+
import { useState as useState9 } from "react";
|
|
2052
2127
|
|
|
2053
2128
|
// src/core/use-media-actions.ts
|
|
2054
|
-
import { useCallback as
|
|
2129
|
+
import { useCallback as useCallback7, useMemo as useMemo5, useState as useState8 } from "react";
|
|
2055
2130
|
function useMediaActions(ref, options = {}) {
|
|
2056
2131
|
const ports = useMediaHostPorts();
|
|
2057
2132
|
const { resolution } = useMediaResolution(ref);
|
|
2058
|
-
const [busy, setBusy] =
|
|
2059
|
-
const [lastError, setLastError] =
|
|
2133
|
+
const [busy, setBusy] = useState8(null);
|
|
2134
|
+
const [lastError, setLastError] = useState8(null);
|
|
2060
2135
|
const actions = ports.actions;
|
|
2061
2136
|
const { fileName, alt } = options;
|
|
2062
2137
|
const context = useMemo5(() => {
|
|
2063
2138
|
if (!ref) return null;
|
|
2064
2139
|
return { ref, resolution, fileName, alt };
|
|
2065
2140
|
}, [ref, resolution, fileName, alt]);
|
|
2066
|
-
const isAvailable =
|
|
2141
|
+
const isAvailable = useCallback7(
|
|
2067
2142
|
(kind) => {
|
|
2068
2143
|
if (!context || !actions) return false;
|
|
2069
2144
|
if (kind === "share") return Boolean(actions.share || actions.SharePopover);
|
|
@@ -2071,7 +2146,7 @@ function useMediaActions(ref, options = {}) {
|
|
|
2071
2146
|
},
|
|
2072
2147
|
[context, actions]
|
|
2073
2148
|
);
|
|
2074
|
-
const run =
|
|
2149
|
+
const run = useCallback7(
|
|
2075
2150
|
async (kind) => {
|
|
2076
2151
|
if (!context || !actions) return;
|
|
2077
2152
|
const handler = actions[kind];
|
|
@@ -2120,7 +2195,7 @@ function MediaActionToolbar({
|
|
|
2120
2195
|
buttonClassName
|
|
2121
2196
|
}) {
|
|
2122
2197
|
const state = useMediaActions(mediaRef, { fileName, alt });
|
|
2123
|
-
const [shareOpen, setShareOpen] =
|
|
2198
|
+
const [shareOpen, setShareOpen] = useState9(false);
|
|
2124
2199
|
const SharePopover = state.SharePopover;
|
|
2125
2200
|
const visible = hideUnavailable ? actions.filter((kind) => state.isAvailable(kind)) : actions;
|
|
2126
2201
|
if (visible.length === 0) return null;
|
|
@@ -2177,7 +2252,7 @@ function MediaActionToolbar({
|
|
|
2177
2252
|
}
|
|
2178
2253
|
|
|
2179
2254
|
// src/react/media-lightbox.tsx
|
|
2180
|
-
import { useEffect as
|
|
2255
|
+
import { useEffect as useEffect9 } from "react";
|
|
2181
2256
|
import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
2182
2257
|
function MediaLightbox({
|
|
2183
2258
|
open,
|
|
@@ -2195,7 +2270,7 @@ function MediaLightbox({
|
|
|
2195
2270
|
headerExtra,
|
|
2196
2271
|
className
|
|
2197
2272
|
}) {
|
|
2198
|
-
|
|
2273
|
+
useEffect9(() => {
|
|
2199
2274
|
if (!open || typeof window === "undefined") return void 0;
|
|
2200
2275
|
const handler = (event) => {
|
|
2201
2276
|
if (event.key === "Escape") {
|
|
@@ -2327,7 +2402,6 @@ export {
|
|
|
2327
2402
|
VolumeXIcon,
|
|
2328
2403
|
XIcon,
|
|
2329
2404
|
cn,
|
|
2330
|
-
formatFileSize,
|
|
2331
2405
|
useMediaDropzone
|
|
2332
2406
|
};
|
|
2333
2407
|
//# sourceMappingURL=react.js.map
|