@ai-matrx/media 0.2.3 → 0.4.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 +185 -0
- package/README.md +82 -3
- package/dist/core.cjs +177 -39
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +84 -4
- package/dist/core.d.ts +84 -4
- package/dist/core.js +164 -26
- package/dist/core.js.map +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +77 -2
- package/dist/index.d.ts +77 -2
- package/dist/index.js.map +1 -1
- package/dist/next.cjs +92 -0
- package/dist/next.cjs.map +1 -0
- package/dist/next.d.cts +74 -0
- package/dist/next.d.ts +74 -0
- package/dist/next.js +60 -0
- package/dist/next.js.map +1 -0
- package/dist/react.cjs +231 -80
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +10 -1
- package/dist/react.d.ts +10 -1
- package/dist/react.js +209 -57
- package/dist/react.js.map +1 -1
- package/dist/viewers.cjs +1747 -0
- package/dist/viewers.cjs.map +1 -0
- package/dist/viewers.d.cts +289 -0
- package/dist/viewers.d.ts +289 -0
- package/dist/viewers.js +1729 -0
- package/dist/viewers.js.map +1 -0
- package/package.json +32 -5
package/dist/react.cjs
CHANGED
|
@@ -535,7 +535,7 @@ function FileIcon2({
|
|
|
535
535
|
}
|
|
536
536
|
|
|
537
537
|
// src/react/inline-media-ref.tsx
|
|
538
|
-
var
|
|
538
|
+
var import_react6 = require("react");
|
|
539
539
|
|
|
540
540
|
// src/core/context.ts
|
|
541
541
|
var import_react = require("react");
|
|
@@ -565,8 +565,56 @@ function useMediaHostPorts() {
|
|
|
565
565
|
return (0, import_react.useContext)(portsContext());
|
|
566
566
|
}
|
|
567
567
|
|
|
568
|
-
// src/core/
|
|
568
|
+
// src/core/diagnostics.ts
|
|
569
569
|
var import_react2 = require("react");
|
|
570
|
+
var LATCH_SLOT = /* @__PURE__ */ Symbol.for("ai-matrx.media.failure-latch");
|
|
571
|
+
function latch() {
|
|
572
|
+
const host = globalThis;
|
|
573
|
+
host[LATCH_SLOT] ??= /* @__PURE__ */ new Set();
|
|
574
|
+
return host[LATCH_SLOT];
|
|
575
|
+
}
|
|
576
|
+
function failureMediaIdentity(ref, src) {
|
|
577
|
+
if (ref && typeof ref === "object" && ref.file_id) return `file:${ref.file_id}`;
|
|
578
|
+
const raw = typeof ref === "string" ? ref : (ref && typeof ref === "object" ? ref.url ?? null : null) ?? src ?? null;
|
|
579
|
+
if (!raw) return "<unknown-media>";
|
|
580
|
+
if (raw.startsWith("blob:")) return "blob:object-url";
|
|
581
|
+
try {
|
|
582
|
+
const u = new URL(raw);
|
|
583
|
+
return `url:${u.origin}${u.pathname}`;
|
|
584
|
+
} catch {
|
|
585
|
+
const clean = raw.split(/[?#]/, 1)[0] ?? raw;
|
|
586
|
+
return `ref:${clean}`;
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
function emitMediaFailure(capture, info) {
|
|
590
|
+
const key = `${info.terminal ? "terminal" : "warning"}|${info.mediaRef}`;
|
|
591
|
+
const seen = latch();
|
|
592
|
+
if (seen.has(key)) return;
|
|
593
|
+
seen.add(key);
|
|
594
|
+
if (capture) {
|
|
595
|
+
try {
|
|
596
|
+
capture(info);
|
|
597
|
+
return;
|
|
598
|
+
} catch {
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
console.error(
|
|
602
|
+
"[@ai-matrx/media] media failure (no diagnostics sink captured it \u2014 bind MediaHostPorts.diagnostics.capture to your error system)",
|
|
603
|
+
info
|
|
604
|
+
);
|
|
605
|
+
}
|
|
606
|
+
function useMediaFailureCapture() {
|
|
607
|
+
const ports = useMediaHostPorts();
|
|
608
|
+
const capture = ports.diagnostics?.capture;
|
|
609
|
+
const captureRef = (0, import_react2.useRef)(capture);
|
|
610
|
+
captureRef.current = capture;
|
|
611
|
+
return (0, import_react2.useCallback)((info) => {
|
|
612
|
+
emitMediaFailure(captureRef.current, { source: "media", ...info });
|
|
613
|
+
}, []);
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
// src/core/use-media-blob.ts
|
|
617
|
+
var import_react3 = require("react");
|
|
570
618
|
|
|
571
619
|
// src/core/ref-key.ts
|
|
572
620
|
function stableRefKey(ref) {
|
|
@@ -578,12 +626,20 @@ function stableRefKey(ref) {
|
|
|
578
626
|
}
|
|
579
627
|
|
|
580
628
|
// src/core/use-media-blob.ts
|
|
629
|
+
function statusOf(err) {
|
|
630
|
+
if (err && typeof err === "object") {
|
|
631
|
+
const candidate = err.status ?? err.statusCode;
|
|
632
|
+
if (typeof candidate === "number") return candidate;
|
|
633
|
+
}
|
|
634
|
+
return void 0;
|
|
635
|
+
}
|
|
581
636
|
function useMediaBlob(ref) {
|
|
582
637
|
const client = useMediaClient();
|
|
638
|
+
const capture = useMediaFailureCapture();
|
|
583
639
|
const refKey = stableRefKey(ref);
|
|
584
|
-
const [state, setState] = (0,
|
|
585
|
-
const [retryToken, setRetryToken] = (0,
|
|
586
|
-
(0,
|
|
640
|
+
const [state, setState] = (0, import_react3.useState)({ url: null, blob: null, loading: !!ref, error: null });
|
|
641
|
+
const [retryToken, setRetryToken] = (0, import_react3.useState)(0);
|
|
642
|
+
(0, import_react3.useEffect)(() => {
|
|
587
643
|
if (!ref) {
|
|
588
644
|
setState({ url: null, blob: null, loading: false, error: null });
|
|
589
645
|
return void 0;
|
|
@@ -604,6 +660,14 @@ function useMediaBlob(ref) {
|
|
|
604
660
|
if (cancelled) return;
|
|
605
661
|
const message = err instanceof Error ? err.message : String(err ?? "Failed to load file");
|
|
606
662
|
setState({ url: null, blob: null, loading: false, error: message });
|
|
663
|
+
const status = statusOf(err);
|
|
664
|
+
capture({
|
|
665
|
+
phase: "blob",
|
|
666
|
+
mediaRef: failureMediaIdentity(ref),
|
|
667
|
+
terminal: true,
|
|
668
|
+
message: `getBlob() failed: ${message}`,
|
|
669
|
+
...status !== void 0 ? { status } : {}
|
|
670
|
+
});
|
|
607
671
|
}
|
|
608
672
|
);
|
|
609
673
|
return () => {
|
|
@@ -618,7 +682,7 @@ function useMediaBlob(ref) {
|
|
|
618
682
|
}
|
|
619
683
|
|
|
620
684
|
// src/core/use-media-load-recovery.ts
|
|
621
|
-
var
|
|
685
|
+
var import_react4 = require("react");
|
|
622
686
|
|
|
623
687
|
// src/types.ts
|
|
624
688
|
function mintDurableSrc(url) {
|
|
@@ -626,26 +690,51 @@ function mintDurableSrc(url) {
|
|
|
626
690
|
}
|
|
627
691
|
|
|
628
692
|
// src/core/use-media-load-recovery.ts
|
|
693
|
+
function normalizeOutcome(outcome) {
|
|
694
|
+
return typeof outcome === "string" ? { verdict: outcome } : outcome;
|
|
695
|
+
}
|
|
696
|
+
var EPHEMERAL_SECRET_IDENTITY = "server:files-session-secret";
|
|
629
697
|
function useMediaLoadRecovery(src, options) {
|
|
630
698
|
const client = useMediaClient();
|
|
699
|
+
const capture = useMediaFailureCapture();
|
|
631
700
|
const recoverable = options?.recoverable !== false;
|
|
632
701
|
const onTerminal = options?.onTerminal;
|
|
633
|
-
const
|
|
634
|
-
const
|
|
635
|
-
(0,
|
|
702
|
+
const failureRef = options?.failureRef;
|
|
703
|
+
const [result, setResult] = (0, import_react4.useState)({ source: src, retryKey: 0, failed: false });
|
|
704
|
+
const attemptRef = (0, import_react4.useRef)(0);
|
|
705
|
+
(0, import_react4.useEffect)(() => {
|
|
636
706
|
attemptRef.current = 0;
|
|
637
707
|
}, [src]);
|
|
708
|
+
const identity = () => failureMediaIdentity(failureRef ?? null, src);
|
|
638
709
|
const onLoadError = (event) => {
|
|
639
710
|
if (!src || !recoverable) {
|
|
640
711
|
setResult({ source: src, retryKey: 0, failed: true });
|
|
712
|
+
if (src) {
|
|
713
|
+
capture({
|
|
714
|
+
phase: "element-load",
|
|
715
|
+
mediaRef: identity(),
|
|
716
|
+
terminal: true,
|
|
717
|
+
retryOutcome: "not-attempted",
|
|
718
|
+
message: "media element failed to load and the source is unrecoverable (foreign/object URL \u2014 a session refresh cannot fix it)"
|
|
719
|
+
});
|
|
720
|
+
}
|
|
641
721
|
onTerminal?.(event);
|
|
642
722
|
return;
|
|
643
723
|
}
|
|
644
724
|
attemptRef.current += 1;
|
|
645
725
|
const attempt = attemptRef.current;
|
|
646
726
|
client.recoverLoadError(mintDurableSrc(src), attempt).then(
|
|
647
|
-
(
|
|
648
|
-
|
|
727
|
+
(outcome) => {
|
|
728
|
+
const report = normalizeOutcome(outcome);
|
|
729
|
+
if (report.secretSource === "ephemeral") {
|
|
730
|
+
capture({
|
|
731
|
+
phase: "session",
|
|
732
|
+
mediaRef: EPHEMERAL_SECRET_IDENTITY,
|
|
733
|
+
terminal: false,
|
|
734
|
+
message: "server cookie secret is ephemeral \u2014 private renders will break across restarts/instances (set a persistent files-session secret on the server)"
|
|
735
|
+
});
|
|
736
|
+
}
|
|
737
|
+
if (report.verdict === "retry") {
|
|
649
738
|
setResult((current) => ({
|
|
650
739
|
source: src,
|
|
651
740
|
retryKey: current.source === src ? current.retryKey + 1 : 1,
|
|
@@ -653,11 +742,26 @@ function useMediaLoadRecovery(src, options) {
|
|
|
653
742
|
}));
|
|
654
743
|
} else {
|
|
655
744
|
setResult({ source: src, retryKey: 0, failed: true });
|
|
745
|
+
capture({
|
|
746
|
+
phase: attempt > 1 ? "element-load" : "recovery",
|
|
747
|
+
mediaRef: identity(),
|
|
748
|
+
terminal: true,
|
|
749
|
+
retryOutcome: attempt > 1 ? "retried" : "not-attempted",
|
|
750
|
+
message: attempt > 1 ? "media element failed to load after the session-refresh retry" : "media load recovery declined on the first attempt (session refresh did not produce a usable session)",
|
|
751
|
+
...report.status !== void 0 ? { status: report.status } : {}
|
|
752
|
+
});
|
|
656
753
|
onTerminal?.(event);
|
|
657
754
|
}
|
|
658
755
|
},
|
|
659
|
-
() => {
|
|
756
|
+
(err) => {
|
|
660
757
|
setResult({ source: src, retryKey: 0, failed: true });
|
|
758
|
+
capture({
|
|
759
|
+
phase: "session",
|
|
760
|
+
mediaRef: identity(),
|
|
761
|
+
terminal: true,
|
|
762
|
+
retryOutcome: "recovery-failed",
|
|
763
|
+
message: `session recovery failed: ${err instanceof Error ? err.message : String(err ?? "unknown error")}`
|
|
764
|
+
});
|
|
661
765
|
onTerminal?.(event);
|
|
662
766
|
}
|
|
663
767
|
);
|
|
@@ -670,24 +774,51 @@ function useMediaLoadRecovery(src, options) {
|
|
|
670
774
|
}
|
|
671
775
|
|
|
672
776
|
// src/core/use-media-resolution.ts
|
|
673
|
-
var
|
|
777
|
+
var import_react5 = require("react");
|
|
674
778
|
function useMediaResolution(ref) {
|
|
675
779
|
const client = useMediaClient();
|
|
780
|
+
const capture = useMediaFailureCapture();
|
|
676
781
|
const refKey = stableRefKey(ref);
|
|
677
|
-
|
|
678
|
-
if (!ref)
|
|
782
|
+
const { state, failureMessage } = (0, import_react5.useMemo)(() => {
|
|
783
|
+
if (!ref) {
|
|
784
|
+
return {
|
|
785
|
+
state: { resolution: null, status: "empty", reason: null },
|
|
786
|
+
failureMessage: null
|
|
787
|
+
};
|
|
788
|
+
}
|
|
679
789
|
try {
|
|
680
790
|
const resolution = client.resolve(ref);
|
|
681
|
-
if (!resolution)
|
|
682
|
-
|
|
791
|
+
if (!resolution) {
|
|
792
|
+
return {
|
|
793
|
+
state: { resolution: null, status: "empty", reason: null },
|
|
794
|
+
failureMessage: null
|
|
795
|
+
};
|
|
796
|
+
}
|
|
797
|
+
return {
|
|
798
|
+
state: { resolution, status: "ready", reason: null },
|
|
799
|
+
failureMessage: null
|
|
800
|
+
};
|
|
683
801
|
} catch (err) {
|
|
684
802
|
return {
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
803
|
+
state: {
|
|
804
|
+
resolution: null,
|
|
805
|
+
status: "unavailable",
|
|
806
|
+
reason: client.classifyError(err)
|
|
807
|
+
},
|
|
808
|
+
failureMessage: err instanceof Error ? err.message : String(err ?? "resolve() failed")
|
|
688
809
|
};
|
|
689
810
|
}
|
|
690
811
|
}, [client, refKey]);
|
|
812
|
+
(0, import_react5.useEffect)(() => {
|
|
813
|
+
if (state.status !== "unavailable") return;
|
|
814
|
+
capture({
|
|
815
|
+
phase: "resolve",
|
|
816
|
+
mediaRef: failureMediaIdentity(ref ?? null),
|
|
817
|
+
terminal: true,
|
|
818
|
+
message: `resolve() refused (${state.reason ?? "unknown"}): ${failureMessage ?? "no error message"}`
|
|
819
|
+
});
|
|
820
|
+
}, [refKey, state.status]);
|
|
821
|
+
return state;
|
|
691
822
|
}
|
|
692
823
|
|
|
693
824
|
// src/react/inline-media-ref.tsx
|
|
@@ -733,7 +864,7 @@ function prettifyUrl(url) {
|
|
|
733
864
|
}
|
|
734
865
|
var INERT_PLAYBACK = {
|
|
735
866
|
useMediaElementSink(forward) {
|
|
736
|
-
return (0,
|
|
867
|
+
return (0, import_react6.useCallback)(
|
|
737
868
|
(node) => {
|
|
738
869
|
if (!forward) return;
|
|
739
870
|
if (typeof forward === "function") forward(node);
|
|
@@ -777,10 +908,21 @@ function InformativeErrorFallback({
|
|
|
777
908
|
alt,
|
|
778
909
|
elementType,
|
|
779
910
|
mediaRef,
|
|
911
|
+
failurePhase,
|
|
780
912
|
dimensions,
|
|
781
913
|
rounded,
|
|
782
914
|
className
|
|
783
915
|
}) {
|
|
916
|
+
const capture = useMediaFailureCapture();
|
|
917
|
+
const identity = failureMediaIdentity(mediaRef ?? null, url);
|
|
918
|
+
(0, import_react6.useEffect)(() => {
|
|
919
|
+
capture({
|
|
920
|
+
phase: failurePhase,
|
|
921
|
+
mediaRef: identity,
|
|
922
|
+
terminal: true,
|
|
923
|
+
message: `media unavailable panel rendered for ${elementType} (${failurePhase} failure)`
|
|
924
|
+
});
|
|
925
|
+
}, [identity, failurePhase]);
|
|
784
926
|
const shortAxis = dimensions === "fill" ? Number.POSITIVE_INFINITY : Math.min(dimensions.width, dimensions.height);
|
|
785
927
|
const isCompact = dimensions !== "fill" && shortAxis < 64;
|
|
786
928
|
const isMidsize = shortAxis < 140;
|
|
@@ -837,10 +979,10 @@ function InformativeErrorPanel({
|
|
|
837
979
|
icon,
|
|
838
980
|
tooltip
|
|
839
981
|
}) {
|
|
840
|
-
const [copied, setCopied] = (0,
|
|
982
|
+
const [copied, setCopied] = (0, import_react6.useState)(false);
|
|
841
983
|
const isFill = dimensions === "fill";
|
|
842
984
|
const { host, tail } = prettifyUrl(url);
|
|
843
|
-
const handleCopy = (0,
|
|
985
|
+
const handleCopy = (0, import_react6.useCallback)(
|
|
844
986
|
(event) => {
|
|
845
987
|
event.stopPropagation();
|
|
846
988
|
event.preventDefault();
|
|
@@ -959,13 +1101,14 @@ function InlineMediaRef({
|
|
|
959
1101
|
const url = needsBlob ? blob.url : resolution?.src ?? null;
|
|
960
1102
|
const recovery = useMediaLoadRecovery(url, {
|
|
961
1103
|
recoverable: !needsBlob && resolution?.recoverable !== false,
|
|
1104
|
+
failureRef: mediaRef,
|
|
962
1105
|
onTerminal: (event) => onError?.(
|
|
963
1106
|
event
|
|
964
1107
|
)
|
|
965
1108
|
});
|
|
966
1109
|
const playback = ports.playbackSession ?? INERT_PLAYBACK;
|
|
967
|
-
const sessionElRef = (0,
|
|
968
|
-
const [isMediaPlaying, setIsMediaPlaying] = (0,
|
|
1110
|
+
const sessionElRef = (0, import_react6.useRef)(null);
|
|
1111
|
+
const [isMediaPlaying, setIsMediaPlaying] = (0, import_react6.useState)(false);
|
|
969
1112
|
const portSinkRef = playback.useMediaElementSink(
|
|
970
1113
|
mediaElementRef
|
|
971
1114
|
);
|
|
@@ -973,7 +1116,7 @@ function InlineMediaRef({
|
|
|
973
1116
|
sessionElRef.current = node;
|
|
974
1117
|
portSinkRef(node);
|
|
975
1118
|
};
|
|
976
|
-
const trackKey = (0,
|
|
1119
|
+
const trackKey = (0, import_react6.useMemo)(() => {
|
|
977
1120
|
if (mediaRef && typeof mediaRef === "object" && mediaRef.file_id) {
|
|
978
1121
|
return mediaRef.file_id;
|
|
979
1122
|
}
|
|
@@ -1011,6 +1154,7 @@ function InlineMediaRef({
|
|
|
1011
1154
|
alt,
|
|
1012
1155
|
elementType,
|
|
1013
1156
|
mediaRef,
|
|
1157
|
+
failurePhase: status === "unavailable" ? "resolve" : "blob",
|
|
1014
1158
|
dimensions,
|
|
1015
1159
|
rounded,
|
|
1016
1160
|
className
|
|
@@ -1065,6 +1209,7 @@ function InlineMediaRef({
|
|
|
1065
1209
|
alt,
|
|
1066
1210
|
elementType,
|
|
1067
1211
|
mediaRef,
|
|
1212
|
+
failurePhase: "element-load",
|
|
1068
1213
|
dimensions,
|
|
1069
1214
|
rounded,
|
|
1070
1215
|
className
|
|
@@ -1191,15 +1336,15 @@ function InlineMediaRef({
|
|
|
1191
1336
|
}
|
|
1192
1337
|
|
|
1193
1338
|
// src/react/media-thumbnail.tsx
|
|
1194
|
-
var
|
|
1339
|
+
var import_react8 = require("react");
|
|
1195
1340
|
|
|
1196
1341
|
// src/core/use-thumbnail-source.ts
|
|
1197
|
-
var
|
|
1342
|
+
var import_react7 = require("react");
|
|
1198
1343
|
function useThumbnailSource(ref, options = {}) {
|
|
1199
1344
|
const { thumbnailUrl, allowSourceFallback = true } = options;
|
|
1200
1345
|
const client = useMediaClient();
|
|
1201
1346
|
const { resolution } = useMediaResolution(ref);
|
|
1202
|
-
const explicitThumb = (0,
|
|
1347
|
+
const explicitThumb = (0, import_react7.useMemo)(() => {
|
|
1203
1348
|
if (!thumbnailUrl) return null;
|
|
1204
1349
|
try {
|
|
1205
1350
|
return client.resolve(thumbnailUrl);
|
|
@@ -1289,6 +1434,7 @@ function MediaThumbnail({
|
|
|
1289
1434
|
VideoPosterThumb,
|
|
1290
1435
|
{
|
|
1291
1436
|
url: source.src,
|
|
1437
|
+
mediaRef,
|
|
1292
1438
|
recoverable: source.recoverable,
|
|
1293
1439
|
fallback
|
|
1294
1440
|
}
|
|
@@ -1299,6 +1445,7 @@ function MediaThumbnail({
|
|
|
1299
1445
|
{
|
|
1300
1446
|
url: source.src,
|
|
1301
1447
|
alt: fileName,
|
|
1448
|
+
mediaRef,
|
|
1302
1449
|
recoverable: source.recoverable,
|
|
1303
1450
|
fallback
|
|
1304
1451
|
}
|
|
@@ -1316,11 +1463,13 @@ function MediaThumbnail({
|
|
|
1316
1463
|
function ImageThumb({
|
|
1317
1464
|
url,
|
|
1318
1465
|
alt,
|
|
1466
|
+
mediaRef,
|
|
1319
1467
|
recoverable,
|
|
1320
1468
|
fallback
|
|
1321
1469
|
}) {
|
|
1322
1470
|
const { retryKey, onLoadError, failed } = useMediaLoadRecovery(url, {
|
|
1323
|
-
recoverable
|
|
1471
|
+
recoverable,
|
|
1472
|
+
failureRef: mediaRef
|
|
1324
1473
|
});
|
|
1325
1474
|
if (failed) return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children: fallback });
|
|
1326
1475
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
@@ -1337,14 +1486,16 @@ function ImageThumb({
|
|
|
1337
1486
|
}
|
|
1338
1487
|
function VideoPosterThumb({
|
|
1339
1488
|
url,
|
|
1489
|
+
mediaRef,
|
|
1340
1490
|
recoverable,
|
|
1341
1491
|
fallback
|
|
1342
1492
|
}) {
|
|
1343
1493
|
const { retryKey, onLoadError, failed } = useMediaLoadRecovery(url, {
|
|
1344
|
-
recoverable
|
|
1494
|
+
recoverable,
|
|
1495
|
+
failureRef: mediaRef
|
|
1345
1496
|
});
|
|
1346
|
-
const ref = (0,
|
|
1347
|
-
(0,
|
|
1497
|
+
const ref = (0, import_react8.useRef)(null);
|
|
1498
|
+
(0, import_react8.useEffect)(() => {
|
|
1348
1499
|
const v = ref.current;
|
|
1349
1500
|
if (!v) return void 0;
|
|
1350
1501
|
const onMeta = () => {
|
|
@@ -1373,7 +1524,7 @@ function VideoPosterThumb({
|
|
|
1373
1524
|
}
|
|
1374
1525
|
|
|
1375
1526
|
// src/react/use-media-dropzone.ts
|
|
1376
|
-
var
|
|
1527
|
+
var import_react9 = require("react");
|
|
1377
1528
|
function matchesAccept(file, accept) {
|
|
1378
1529
|
if (!accept || accept.length === 0) return true;
|
|
1379
1530
|
const name = file.name.toLowerCase();
|
|
@@ -1397,16 +1548,16 @@ function useMediaDropzone(options) {
|
|
|
1397
1548
|
disabled = false,
|
|
1398
1549
|
multiple = true
|
|
1399
1550
|
} = options;
|
|
1400
|
-
const [isDragActive, setIsDragActive] = (0,
|
|
1401
|
-
const [pasteHighlight, setPasteHighlight] = (0,
|
|
1402
|
-
const dragDepth = (0,
|
|
1403
|
-
const inputRef = (0,
|
|
1404
|
-
const onFilesRef = (0,
|
|
1551
|
+
const [isDragActive, setIsDragActive] = (0, import_react9.useState)(false);
|
|
1552
|
+
const [pasteHighlight, setPasteHighlight] = (0, import_react9.useState)(false);
|
|
1553
|
+
const dragDepth = (0, import_react9.useRef)(0);
|
|
1554
|
+
const inputRef = (0, import_react9.useRef)(null);
|
|
1555
|
+
const onFilesRef = (0, import_react9.useRef)(onFiles);
|
|
1405
1556
|
onFilesRef.current = onFiles;
|
|
1406
|
-
const onRejectedRef = (0,
|
|
1557
|
+
const onRejectedRef = (0, import_react9.useRef)(onRejected);
|
|
1407
1558
|
onRejectedRef.current = onRejected;
|
|
1408
1559
|
const acceptKey = accept?.join(",") ?? "";
|
|
1409
|
-
const filterFiles = (0,
|
|
1560
|
+
const filterFiles = (0, import_react9.useCallback)(
|
|
1410
1561
|
(files) => {
|
|
1411
1562
|
const accepted = [];
|
|
1412
1563
|
const rejected = [];
|
|
@@ -1424,23 +1575,23 @@ function useMediaDropzone(options) {
|
|
|
1424
1575
|
},
|
|
1425
1576
|
[acceptKey, maxSize]
|
|
1426
1577
|
);
|
|
1427
|
-
const emit = (0,
|
|
1578
|
+
const emit = (0, import_react9.useCallback)(
|
|
1428
1579
|
(files) => {
|
|
1429
1580
|
const accepted = filterFiles(files);
|
|
1430
1581
|
if (accepted.length) onFilesRef.current(accepted);
|
|
1431
1582
|
},
|
|
1432
1583
|
[filterFiles]
|
|
1433
1584
|
);
|
|
1434
|
-
const openPicker = (0,
|
|
1585
|
+
const openPicker = (0, import_react9.useCallback)(() => {
|
|
1435
1586
|
if (!disabled) inputRef.current?.click();
|
|
1436
1587
|
}, [disabled]);
|
|
1437
|
-
(0,
|
|
1588
|
+
(0, import_react9.useEffect)(() => {
|
|
1438
1589
|
if (!pickerEventName || typeof window === "undefined") return void 0;
|
|
1439
1590
|
const handler = () => openPicker();
|
|
1440
1591
|
window.addEventListener(pickerEventName, handler);
|
|
1441
1592
|
return () => window.removeEventListener(pickerEventName, handler);
|
|
1442
1593
|
}, [openPicker, pickerEventName]);
|
|
1443
|
-
(0,
|
|
1594
|
+
(0, import_react9.useEffect)(() => {
|
|
1444
1595
|
if (!enablePaste || disabled || typeof window === "undefined") {
|
|
1445
1596
|
return void 0;
|
|
1446
1597
|
}
|
|
@@ -1466,7 +1617,7 @@ function useMediaDropzone(options) {
|
|
|
1466
1617
|
window.addEventListener("paste", handler);
|
|
1467
1618
|
return () => window.removeEventListener("paste", handler);
|
|
1468
1619
|
}, [enablePaste, disabled, emit]);
|
|
1469
|
-
const getRootProps = (0,
|
|
1620
|
+
const getRootProps = (0, import_react9.useCallback)(
|
|
1470
1621
|
() => ({
|
|
1471
1622
|
onDragEnter: (event) => {
|
|
1472
1623
|
if (disabled) return;
|
|
@@ -1495,11 +1646,11 @@ function useMediaDropzone(options) {
|
|
|
1495
1646
|
}),
|
|
1496
1647
|
[disabled, emit, multiple]
|
|
1497
1648
|
);
|
|
1498
|
-
const inputAccept = (0,
|
|
1649
|
+
const inputAccept = (0, import_react9.useMemo)(
|
|
1499
1650
|
() => acceptKey.length ? acceptKey : void 0,
|
|
1500
1651
|
[acceptKey]
|
|
1501
1652
|
);
|
|
1502
|
-
const getInputProps = (0,
|
|
1653
|
+
const getInputProps = (0, import_react9.useCallback)(
|
|
1503
1654
|
() => ({
|
|
1504
1655
|
ref: (node) => {
|
|
1505
1656
|
inputRef.current = node;
|
|
@@ -1521,20 +1672,20 @@ function useMediaDropzone(options) {
|
|
|
1521
1672
|
}
|
|
1522
1673
|
|
|
1523
1674
|
// src/react/file-upload-dropzone.tsx
|
|
1524
|
-
var
|
|
1675
|
+
var import_react12 = require("react");
|
|
1525
1676
|
|
|
1526
1677
|
// src/core/use-media-upload.ts
|
|
1527
|
-
var
|
|
1678
|
+
var import_react10 = require("react");
|
|
1528
1679
|
var entrySeq = 0;
|
|
1529
1680
|
function useMediaUpload() {
|
|
1530
1681
|
const client = useMediaClient();
|
|
1531
|
-
const [uploading, setUploading] = (0,
|
|
1532
|
-
const [progress, setProgress] = (0,
|
|
1533
|
-
const [result, setResult] = (0,
|
|
1534
|
-
const [error, setError] = (0,
|
|
1535
|
-
const [entries, setEntries] = (0,
|
|
1536
|
-
const activeCount = (0,
|
|
1537
|
-
const patchEntry = (0,
|
|
1682
|
+
const [uploading, setUploading] = (0, import_react10.useState)(false);
|
|
1683
|
+
const [progress, setProgress] = (0, import_react10.useState)(null);
|
|
1684
|
+
const [result, setResult] = (0, import_react10.useState)(null);
|
|
1685
|
+
const [error, setError] = (0, import_react10.useState)(null);
|
|
1686
|
+
const [entries, setEntries] = (0, import_react10.useState)([]);
|
|
1687
|
+
const activeCount = (0, import_react10.useRef)(0);
|
|
1688
|
+
const patchEntry = (0, import_react10.useCallback)(
|
|
1538
1689
|
(id, patch) => {
|
|
1539
1690
|
setEntries(
|
|
1540
1691
|
(current) => current.map((e) => e.id === id ? { ...e, ...patch } : e)
|
|
@@ -1542,7 +1693,7 @@ function useMediaUpload() {
|
|
|
1542
1693
|
},
|
|
1543
1694
|
[]
|
|
1544
1695
|
);
|
|
1545
|
-
const upload = (0,
|
|
1696
|
+
const upload = (0, import_react10.useCallback)(
|
|
1546
1697
|
async (file, opts = {}) => {
|
|
1547
1698
|
const id = `up-${++entrySeq}`;
|
|
1548
1699
|
const fileName = opts.fileName ?? (file instanceof File ? file.name : "file");
|
|
@@ -1596,7 +1747,7 @@ function useMediaUpload() {
|
|
|
1596
1747
|
},
|
|
1597
1748
|
[client, patchEntry]
|
|
1598
1749
|
);
|
|
1599
|
-
const uploadMany = (0,
|
|
1750
|
+
const uploadMany = (0, import_react10.useCallback)(
|
|
1600
1751
|
async (files, opts = {}) => {
|
|
1601
1752
|
if (client.uploadMany) {
|
|
1602
1753
|
activeCount.current += 1;
|
|
@@ -1625,10 +1776,10 @@ function useMediaUpload() {
|
|
|
1625
1776
|
},
|
|
1626
1777
|
[client, upload]
|
|
1627
1778
|
);
|
|
1628
|
-
const clearEntry = (0,
|
|
1779
|
+
const clearEntry = (0, import_react10.useCallback)((id) => {
|
|
1629
1780
|
setEntries((current) => current.filter((e) => e.id !== id));
|
|
1630
1781
|
}, []);
|
|
1631
|
-
const reset = (0,
|
|
1782
|
+
const reset = (0, import_react10.useCallback)(() => {
|
|
1632
1783
|
setResult(null);
|
|
1633
1784
|
setError(null);
|
|
1634
1785
|
setProgress(null);
|
|
@@ -1648,11 +1799,11 @@ function useMediaUpload() {
|
|
|
1648
1799
|
}
|
|
1649
1800
|
|
|
1650
1801
|
// src/react/upload-progress-list.tsx
|
|
1651
|
-
var
|
|
1802
|
+
var import_react11 = require("react");
|
|
1652
1803
|
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
1653
1804
|
var AUTO_DISMISS_MS = 1e4;
|
|
1654
1805
|
function formatFileSize(bytes) {
|
|
1655
|
-
if (!Number.isFinite(bytes) || bytes < 0) return "
|
|
1806
|
+
if (bytes == null || !Number.isFinite(bytes) || bytes < 0) return "\u2014";
|
|
1656
1807
|
if (bytes < 1024) return `${bytes} B`;
|
|
1657
1808
|
const units = ["KB", "MB", "GB", "TB"];
|
|
1658
1809
|
let value = bytes;
|
|
@@ -1669,16 +1820,16 @@ function UploadProgressListImpl({
|
|
|
1669
1820
|
onOpenFile,
|
|
1670
1821
|
className
|
|
1671
1822
|
}) {
|
|
1672
|
-
const [hovered, setHovered] = (0,
|
|
1823
|
+
const [hovered, setHovered] = (0, import_react11.useState)(false);
|
|
1673
1824
|
const activeCount = uploads.filter((u) => u.status === "uploading").length;
|
|
1674
1825
|
const successCount = uploads.filter((u) => u.status === "success").length;
|
|
1675
1826
|
const errorCount = uploads.filter((u) => u.status === "error").length;
|
|
1676
|
-
const timersRef = (0,
|
|
1827
|
+
const timersRef = (0, import_react11.useRef)(
|
|
1677
1828
|
/* @__PURE__ */ new Map()
|
|
1678
1829
|
);
|
|
1679
|
-
const onDismissRef = (0,
|
|
1830
|
+
const onDismissRef = (0, import_react11.useRef)(onDismiss);
|
|
1680
1831
|
onDismissRef.current = onDismiss;
|
|
1681
|
-
(0,
|
|
1832
|
+
(0, import_react11.useEffect)(() => {
|
|
1682
1833
|
const timers = timersRef.current;
|
|
1683
1834
|
if (hovered) {
|
|
1684
1835
|
timers.forEach((t) => clearTimeout(t));
|
|
@@ -1706,7 +1857,7 @@ function UploadProgressListImpl({
|
|
|
1706
1857
|
}
|
|
1707
1858
|
}
|
|
1708
1859
|
}, [uploads, hovered]);
|
|
1709
|
-
(0,
|
|
1860
|
+
(0, import_react11.useEffect)(() => {
|
|
1710
1861
|
const timers = timersRef.current;
|
|
1711
1862
|
return () => {
|
|
1712
1863
|
timers.forEach((t) => clearTimeout(t));
|
|
@@ -1818,7 +1969,7 @@ function UploadProgressListImpl({
|
|
|
1818
1969
|
}
|
|
1819
1970
|
);
|
|
1820
1971
|
}
|
|
1821
|
-
var UploadProgressList = (0,
|
|
1972
|
+
var UploadProgressList = (0, import_react11.memo)(UploadProgressListImpl);
|
|
1822
1973
|
|
|
1823
1974
|
// src/react/file-upload-dropzone.tsx
|
|
1824
1975
|
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
@@ -1838,7 +1989,7 @@ function FileUploadDropzone({
|
|
|
1838
1989
|
pickerEventName
|
|
1839
1990
|
}) {
|
|
1840
1991
|
const { uploadMany, entries, clearEntry } = useMediaUpload();
|
|
1841
|
-
const handleUpload = (0,
|
|
1992
|
+
const handleUpload = (0, import_react12.useCallback)(
|
|
1842
1993
|
async (files) => {
|
|
1843
1994
|
if (!files.length) return;
|
|
1844
1995
|
try {
|
|
@@ -1945,22 +2096,22 @@ function FileUploadDropzone({
|
|
|
1945
2096
|
}
|
|
1946
2097
|
|
|
1947
2098
|
// src/react/media-action-toolbar.tsx
|
|
1948
|
-
var
|
|
2099
|
+
var import_react14 = require("react");
|
|
1949
2100
|
|
|
1950
2101
|
// src/core/use-media-actions.ts
|
|
1951
|
-
var
|
|
2102
|
+
var import_react13 = require("react");
|
|
1952
2103
|
function useMediaActions(ref, options = {}) {
|
|
1953
2104
|
const ports = useMediaHostPorts();
|
|
1954
2105
|
const { resolution } = useMediaResolution(ref);
|
|
1955
|
-
const [busy, setBusy] = (0,
|
|
1956
|
-
const [lastError, setLastError] = (0,
|
|
2106
|
+
const [busy, setBusy] = (0, import_react13.useState)(null);
|
|
2107
|
+
const [lastError, setLastError] = (0, import_react13.useState)(null);
|
|
1957
2108
|
const actions = ports.actions;
|
|
1958
2109
|
const { fileName, alt } = options;
|
|
1959
|
-
const context = (0,
|
|
2110
|
+
const context = (0, import_react13.useMemo)(() => {
|
|
1960
2111
|
if (!ref) return null;
|
|
1961
2112
|
return { ref, resolution, fileName, alt };
|
|
1962
2113
|
}, [ref, resolution, fileName, alt]);
|
|
1963
|
-
const isAvailable = (0,
|
|
2114
|
+
const isAvailable = (0, import_react13.useCallback)(
|
|
1964
2115
|
(kind) => {
|
|
1965
2116
|
if (!context || !actions) return false;
|
|
1966
2117
|
if (kind === "share") return Boolean(actions.share || actions.SharePopover);
|
|
@@ -1968,7 +2119,7 @@ function useMediaActions(ref, options = {}) {
|
|
|
1968
2119
|
},
|
|
1969
2120
|
[context, actions]
|
|
1970
2121
|
);
|
|
1971
|
-
const run = (0,
|
|
2122
|
+
const run = (0, import_react13.useCallback)(
|
|
1972
2123
|
async (kind) => {
|
|
1973
2124
|
if (!context || !actions) return;
|
|
1974
2125
|
const handler = actions[kind];
|
|
@@ -2017,7 +2168,7 @@ function MediaActionToolbar({
|
|
|
2017
2168
|
buttonClassName
|
|
2018
2169
|
}) {
|
|
2019
2170
|
const state = useMediaActions(mediaRef, { fileName, alt });
|
|
2020
|
-
const [shareOpen, setShareOpen] = (0,
|
|
2171
|
+
const [shareOpen, setShareOpen] = (0, import_react14.useState)(false);
|
|
2021
2172
|
const SharePopover = state.SharePopover;
|
|
2022
2173
|
const visible = hideUnavailable ? actions.filter((kind) => state.isAvailable(kind)) : actions;
|
|
2023
2174
|
if (visible.length === 0) return null;
|
|
@@ -2074,7 +2225,7 @@ function MediaActionToolbar({
|
|
|
2074
2225
|
}
|
|
2075
2226
|
|
|
2076
2227
|
// src/react/media-lightbox.tsx
|
|
2077
|
-
var
|
|
2228
|
+
var import_react15 = require("react");
|
|
2078
2229
|
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
2079
2230
|
function MediaLightbox({
|
|
2080
2231
|
open,
|
|
@@ -2092,7 +2243,7 @@ function MediaLightbox({
|
|
|
2092
2243
|
headerExtra,
|
|
2093
2244
|
className
|
|
2094
2245
|
}) {
|
|
2095
|
-
(0,
|
|
2246
|
+
(0, import_react15.useEffect)(() => {
|
|
2096
2247
|
if (!open || typeof window === "undefined") return void 0;
|
|
2097
2248
|
const handler = (event) => {
|
|
2098
2249
|
if (event.key === "Escape") {
|