@sesionario/blocks 1.33.2 → 1.34.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/README.md +1 -1
- package/dist/index.cjs +233 -1539
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -246
- package/dist/index.d.ts +1 -246
- package/dist/index.js +41 -1337
- package/dist/index.js.map +1 -1
- package/dist/livo.cjs +220 -0
- package/dist/livo.cjs.map +1 -0
- package/dist/livo.d.cts +34 -0
- package/dist/livo.d.ts +34 -0
- package/dist/livo.js +215 -0
- package/dist/livo.js.map +1 -0
- package/package.json +14 -4
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
var
|
|
4
|
+
var React2 = require('react');
|
|
5
5
|
var lucideReact = require('lucide-react');
|
|
6
6
|
var clsx = require('clsx');
|
|
7
7
|
var tailwindMerge = require('tailwind-merge');
|
|
@@ -44,7 +44,7 @@ function _interopNamespace(e) {
|
|
|
44
44
|
return Object.freeze(n);
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
var
|
|
47
|
+
var React2__namespace = /*#__PURE__*/_interopNamespace(React2);
|
|
48
48
|
var AlertDialogPrimitive__namespace = /*#__PURE__*/_interopNamespace(AlertDialogPrimitive);
|
|
49
49
|
var DialogPrimitive__namespace = /*#__PURE__*/_interopNamespace(DialogPrimitive);
|
|
50
50
|
var DropdownMenuPrimitive__namespace = /*#__PURE__*/_interopNamespace(DropdownMenuPrimitive);
|
|
@@ -55,9 +55,9 @@ var RPNInput__namespace = /*#__PURE__*/_interopNamespace(RPNInput);
|
|
|
55
55
|
var flags__default = /*#__PURE__*/_interopDefault(flags);
|
|
56
56
|
var ScrollAreaPrimitive__namespace = /*#__PURE__*/_interopNamespace(ScrollAreaPrimitive);
|
|
57
57
|
|
|
58
|
-
var LanguageContext =
|
|
58
|
+
var LanguageContext = React2.createContext(null);
|
|
59
59
|
function useLanguageContext() {
|
|
60
|
-
return
|
|
60
|
+
return React2.useContext(LanguageContext);
|
|
61
61
|
}
|
|
62
62
|
function cn(...inputs) {
|
|
63
63
|
return tailwindMerge.twMerge(clsx.clsx(inputs));
|
|
@@ -491,20 +491,20 @@ function useEditableSection({
|
|
|
491
491
|
...DEFAULT_EDITABLE_SECTION_LABELS,
|
|
492
492
|
...labels
|
|
493
493
|
};
|
|
494
|
-
const [mode, setMode] =
|
|
495
|
-
const [status, setStatus] =
|
|
496
|
-
const [confirmOpen, setConfirmOpen] =
|
|
497
|
-
const [minHeightPx, setMinHeightPx] =
|
|
498
|
-
const contentRef =
|
|
499
|
-
const editButtonRef =
|
|
500
|
-
const measuredHeightRef =
|
|
501
|
-
const shouldFocusEditRef =
|
|
502
|
-
const shouldFocusFirstFieldRef =
|
|
503
|
-
const editButtonId =
|
|
504
|
-
const contentFormId =
|
|
494
|
+
const [mode, setMode] = React2.useState("reading");
|
|
495
|
+
const [status, setStatus] = React2.useState(null);
|
|
496
|
+
const [confirmOpen, setConfirmOpen] = React2.useState(false);
|
|
497
|
+
const [minHeightPx, setMinHeightPx] = React2.useState(void 0);
|
|
498
|
+
const contentRef = React2.useRef(null);
|
|
499
|
+
const editButtonRef = React2.useRef(null);
|
|
500
|
+
const measuredHeightRef = React2.useRef(0);
|
|
501
|
+
const shouldFocusEditRef = React2.useRef(false);
|
|
502
|
+
const shouldFocusFirstFieldRef = React2.useRef(false);
|
|
503
|
+
const editButtonId = React2.useId();
|
|
504
|
+
const contentFormId = React2.useId();
|
|
505
505
|
const isEditing = mode === "editing" || mode === "saving";
|
|
506
506
|
const isSaving = mode === "saving";
|
|
507
|
-
|
|
507
|
+
React2.useEffect(() => {
|
|
508
508
|
if (mode === "reading" && shouldFocusEditRef.current) {
|
|
509
509
|
shouldFocusEditRef.current = false;
|
|
510
510
|
editButtonRef.current?.focus();
|
|
@@ -522,18 +522,18 @@ function useEditableSection({
|
|
|
522
522
|
focusFirstField(contentRef.current);
|
|
523
523
|
}
|
|
524
524
|
}, [mode]);
|
|
525
|
-
const exitToReading =
|
|
525
|
+
const exitToReading = React2.useCallback(() => {
|
|
526
526
|
setConfirmOpen(false);
|
|
527
527
|
shouldFocusEditRef.current = true;
|
|
528
528
|
setMode("reading");
|
|
529
529
|
onDiscard?.();
|
|
530
530
|
}, [onDiscard]);
|
|
531
|
-
const startEdit =
|
|
531
|
+
const startEdit = React2.useCallback(() => {
|
|
532
532
|
setStatus(null);
|
|
533
533
|
shouldFocusFirstFieldRef.current = true;
|
|
534
534
|
setMode("editing");
|
|
535
535
|
}, []);
|
|
536
|
-
const requestCancel =
|
|
536
|
+
const requestCancel = React2.useCallback(() => {
|
|
537
537
|
if (isSaving) return;
|
|
538
538
|
if (isDirty) {
|
|
539
539
|
setConfirmOpen(true);
|
|
@@ -541,7 +541,7 @@ function useEditableSection({
|
|
|
541
541
|
}
|
|
542
542
|
exitToReading();
|
|
543
543
|
}, [exitToReading, isDirty, isSaving]);
|
|
544
|
-
const handleSubmit =
|
|
544
|
+
const handleSubmit = React2.useCallback(
|
|
545
545
|
(event) => {
|
|
546
546
|
event.preventDefault();
|
|
547
547
|
if (isSaving) return;
|
|
@@ -561,7 +561,7 @@ function useEditableSection({
|
|
|
561
561
|
},
|
|
562
562
|
[isSaving, onSave, resolvedLabels.saved]
|
|
563
563
|
);
|
|
564
|
-
const handleFormKeyDown =
|
|
564
|
+
const handleFormKeyDown = React2.useCallback(
|
|
565
565
|
(event) => {
|
|
566
566
|
if (event.key !== "Escape") return;
|
|
567
567
|
event.preventDefault();
|
|
@@ -569,7 +569,7 @@ function useEditableSection({
|
|
|
569
569
|
},
|
|
570
570
|
[requestCancel]
|
|
571
571
|
);
|
|
572
|
-
|
|
572
|
+
React2.useEffect(() => {
|
|
573
573
|
if (!stableHeight || !isEditing) return;
|
|
574
574
|
const el = contentRef.current;
|
|
575
575
|
if (!el) return;
|
|
@@ -806,13 +806,13 @@ function ExpandableText({
|
|
|
806
806
|
className,
|
|
807
807
|
textClassName
|
|
808
808
|
}) {
|
|
809
|
-
const [expanded, setExpanded] =
|
|
810
|
-
const [overflowing, setOverflowing] =
|
|
811
|
-
const contentRef =
|
|
812
|
-
|
|
809
|
+
const [expanded, setExpanded] = React2.useState(false);
|
|
810
|
+
const [overflowing, setOverflowing] = React2.useState(false);
|
|
811
|
+
const contentRef = React2.useRef(null);
|
|
812
|
+
React2.useEffect(() => {
|
|
813
813
|
setExpanded(false);
|
|
814
814
|
}, [children]);
|
|
815
|
-
|
|
815
|
+
React2.useLayoutEffect(() => {
|
|
816
816
|
const el = contentRef.current;
|
|
817
817
|
if (!el) return;
|
|
818
818
|
const measure = () => {
|
|
@@ -896,46 +896,46 @@ function useZoomPanGestures(options = {}) {
|
|
|
896
896
|
wheelZoom = true,
|
|
897
897
|
doubleTap = "reset"
|
|
898
898
|
} = options;
|
|
899
|
-
const [transform, setTransform] =
|
|
899
|
+
const [transform, setTransform] = React2.useState({
|
|
900
900
|
...IDENTITY,
|
|
901
901
|
scale: minScale
|
|
902
902
|
});
|
|
903
|
-
const transformRef =
|
|
903
|
+
const transformRef = React2.useRef(transform);
|
|
904
904
|
transformRef.current = transform;
|
|
905
|
-
const [isSwipeDragging, setIsSwipeDragging] =
|
|
906
|
-
const [snapBack, setSnapBack] =
|
|
907
|
-
const stageRef =
|
|
908
|
-
const pointersRef =
|
|
909
|
-
const pinchStartRef =
|
|
910
|
-
const panRef =
|
|
911
|
-
const swipeRef =
|
|
912
|
-
const lastTapRef =
|
|
905
|
+
const [isSwipeDragging, setIsSwipeDragging] = React2.useState(false);
|
|
906
|
+
const [snapBack, setSnapBack] = React2.useState(false);
|
|
907
|
+
const stageRef = React2.useRef(null);
|
|
908
|
+
const pointersRef = React2.useRef(/* @__PURE__ */ new Map());
|
|
909
|
+
const pinchStartRef = React2.useRef(null);
|
|
910
|
+
const panRef = React2.useRef(null);
|
|
911
|
+
const swipeRef = React2.useRef(null);
|
|
912
|
+
const lastTapRef = React2.useRef(
|
|
913
913
|
null
|
|
914
914
|
);
|
|
915
|
-
const onSwipeCommitRef =
|
|
915
|
+
const onSwipeCommitRef = React2.useRef(onSwipeCommit);
|
|
916
916
|
onSwipeCommitRef.current = onSwipeCommit;
|
|
917
|
-
const swipeEnabledRef =
|
|
917
|
+
const swipeEnabledRef = React2.useRef(swipeEnabled);
|
|
918
918
|
swipeEnabledRef.current = swipeEnabled;
|
|
919
|
-
const minScaleRef =
|
|
919
|
+
const minScaleRef = React2.useRef(minScale);
|
|
920
920
|
minScaleRef.current = minScale;
|
|
921
|
-
const maxScaleRef =
|
|
921
|
+
const maxScaleRef = React2.useRef(maxScale);
|
|
922
922
|
maxScaleRef.current = maxScale;
|
|
923
|
-
const doubleTapRef =
|
|
923
|
+
const doubleTapRef = React2.useRef(doubleTap);
|
|
924
924
|
doubleTapRef.current = doubleTap;
|
|
925
|
-
const reset =
|
|
925
|
+
const reset = React2.useCallback(() => {
|
|
926
926
|
setTransform({ ...IDENTITY, scale: minScaleRef.current });
|
|
927
927
|
setIsSwipeDragging(false);
|
|
928
928
|
setSnapBack(false);
|
|
929
929
|
}, []);
|
|
930
|
-
const setScale =
|
|
930
|
+
const setScale = React2.useCallback((next) => {
|
|
931
931
|
setTransform(
|
|
932
932
|
(prev) => zoomToward(prev, next, 0, 0, minScaleRef.current, maxScaleRef.current)
|
|
933
933
|
);
|
|
934
934
|
}, []);
|
|
935
|
-
const clearSnapBack =
|
|
935
|
+
const clearSnapBack = React2.useCallback(() => {
|
|
936
936
|
setSnapBack(false);
|
|
937
937
|
}, []);
|
|
938
|
-
const stageOrigin =
|
|
938
|
+
const stageOrigin = React2.useCallback((clientX, clientY) => {
|
|
939
939
|
const stage = stageRef.current;
|
|
940
940
|
if (!stage) return { x: 0, y: 0 };
|
|
941
941
|
const rect = stage.getBoundingClientRect();
|
|
@@ -944,7 +944,7 @@ function useZoomPanGestures(options = {}) {
|
|
|
944
944
|
y: clientY - rect.top - rect.height / 2
|
|
945
945
|
};
|
|
946
946
|
}, []);
|
|
947
|
-
|
|
947
|
+
React2.useEffect(() => {
|
|
948
948
|
if (!wheelZoom) return;
|
|
949
949
|
const stage = stageRef.current;
|
|
950
950
|
if (!stage) return;
|
|
@@ -1183,13 +1183,13 @@ function SafeImage({
|
|
|
1183
1183
|
onError,
|
|
1184
1184
|
...imgProps
|
|
1185
1185
|
}) {
|
|
1186
|
-
const [failed, setFailed] =
|
|
1187
|
-
const imgRef =
|
|
1186
|
+
const [failed, setFailed] = React2.useState(false);
|
|
1187
|
+
const imgRef = React2.useRef(null);
|
|
1188
1188
|
const resolvedSrc = typeof src === "string" && src.length > 0 ? src : null;
|
|
1189
|
-
|
|
1189
|
+
React2.useLayoutEffect(() => {
|
|
1190
1190
|
setFailed(false);
|
|
1191
1191
|
}, [resolvedSrc]);
|
|
1192
|
-
|
|
1192
|
+
React2.useLayoutEffect(() => {
|
|
1193
1193
|
const img = imgRef.current;
|
|
1194
1194
|
if (img && isBrokenImage(img)) {
|
|
1195
1195
|
setFailed(true);
|
|
@@ -1224,13 +1224,13 @@ function ImageLightbox({
|
|
|
1224
1224
|
const previousLabel = labels?.previous ?? "Anterior";
|
|
1225
1225
|
const nextLabel = labels?.next ?? "Siguiente";
|
|
1226
1226
|
const hasMultiple = images.length > 1;
|
|
1227
|
-
const indexRef =
|
|
1227
|
+
const indexRef = React2.useRef(index);
|
|
1228
1228
|
indexRef.current = index;
|
|
1229
|
-
const imagesLengthRef =
|
|
1229
|
+
const imagesLengthRef = React2.useRef(images.length);
|
|
1230
1230
|
imagesLengthRef.current = images.length;
|
|
1231
|
-
const onIndexChangeRef =
|
|
1231
|
+
const onIndexChangeRef = React2.useRef(onIndexChange);
|
|
1232
1232
|
onIndexChangeRef.current = onIndexChange;
|
|
1233
|
-
const onSwipeCommit =
|
|
1233
|
+
const onSwipeCommit = React2.useCallback((direction) => {
|
|
1234
1234
|
const length = imagesLengthRef.current;
|
|
1235
1235
|
const current = indexRef.current;
|
|
1236
1236
|
if (direction === "next") {
|
|
@@ -1252,7 +1252,7 @@ function ImageLightbox({
|
|
|
1252
1252
|
onSwipeCommit,
|
|
1253
1253
|
doubleTap: "reset"
|
|
1254
1254
|
});
|
|
1255
|
-
|
|
1255
|
+
React2.useEffect(() => {
|
|
1256
1256
|
reset();
|
|
1257
1257
|
}, [index, images[index], reset]);
|
|
1258
1258
|
function goPrev() {
|
|
@@ -1261,7 +1261,7 @@ function ImageLightbox({
|
|
|
1261
1261
|
function goNext() {
|
|
1262
1262
|
onIndexChange((index + 1) % images.length);
|
|
1263
1263
|
}
|
|
1264
|
-
|
|
1264
|
+
React2.useEffect(() => {
|
|
1265
1265
|
function handleKeyDown(e) {
|
|
1266
1266
|
if (e.key === "Escape") {
|
|
1267
1267
|
onClose();
|
|
@@ -1277,7 +1277,7 @@ function ImageLightbox({
|
|
|
1277
1277
|
window.addEventListener("keydown", handleKeyDown);
|
|
1278
1278
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
1279
1279
|
}, [index, images.length, hasMultiple, onClose, onIndexChange]);
|
|
1280
|
-
|
|
1280
|
+
React2.useEffect(() => {
|
|
1281
1281
|
const previousOverflow = document.body.style.overflow;
|
|
1282
1282
|
document.body.style.overflow = "hidden";
|
|
1283
1283
|
return () => {
|
|
@@ -1395,13 +1395,13 @@ function MediaCarousel({
|
|
|
1395
1395
|
const safeIndex = Math.min(Math.max(index, 0), Math.max(items.length - 1, 0));
|
|
1396
1396
|
const item = items[safeIndex];
|
|
1397
1397
|
const hasMultiple = items.length > 1;
|
|
1398
|
-
const indexRef =
|
|
1398
|
+
const indexRef = React2.useRef(safeIndex);
|
|
1399
1399
|
indexRef.current = safeIndex;
|
|
1400
|
-
const lengthRef =
|
|
1400
|
+
const lengthRef = React2.useRef(items.length);
|
|
1401
1401
|
lengthRef.current = items.length;
|
|
1402
|
-
const onIndexChangeRef =
|
|
1402
|
+
const onIndexChangeRef = React2.useRef(onIndexChange);
|
|
1403
1403
|
onIndexChangeRef.current = onIndexChange;
|
|
1404
|
-
const onSwipeCommit =
|
|
1404
|
+
const onSwipeCommit = React2.useCallback((direction) => {
|
|
1405
1405
|
const length = lengthRef.current;
|
|
1406
1406
|
if (length <= 1) return;
|
|
1407
1407
|
const current = indexRef.current;
|
|
@@ -1426,10 +1426,10 @@ function MediaCarousel({
|
|
|
1426
1426
|
doubleTap: "toggle",
|
|
1427
1427
|
wheelZoom: isImage
|
|
1428
1428
|
});
|
|
1429
|
-
|
|
1429
|
+
React2.useEffect(() => {
|
|
1430
1430
|
reset();
|
|
1431
1431
|
}, [safeIndex, item?.kind === "image" ? item.src : null, reset]);
|
|
1432
|
-
|
|
1432
|
+
React2.useEffect(() => {
|
|
1433
1433
|
if (!hasMultiple) return;
|
|
1434
1434
|
function handleKeyDown(e) {
|
|
1435
1435
|
if (e.key === "ArrowLeft") {
|
|
@@ -1936,18 +1936,18 @@ function ThemeSwitcher({
|
|
|
1936
1936
|
labels: userLabels
|
|
1937
1937
|
}) {
|
|
1938
1938
|
const { theme, setTheme } = nextThemes.useTheme();
|
|
1939
|
-
const [mounted, setMounted] =
|
|
1939
|
+
const [mounted, setMounted] = React2.useState(false);
|
|
1940
1940
|
const reduceMotion = framerMotion.useReducedMotion();
|
|
1941
1941
|
const sizes = sizeClasses[size];
|
|
1942
1942
|
const shapeClass = shapeClasses[shape];
|
|
1943
1943
|
const labels = { ...defaultLabels, ...userLabels };
|
|
1944
|
-
const handleThemeClick =
|
|
1944
|
+
const handleThemeClick = React2.useCallback(
|
|
1945
1945
|
(themeKey) => {
|
|
1946
1946
|
setTheme(themeKey);
|
|
1947
1947
|
},
|
|
1948
1948
|
[setTheme]
|
|
1949
1949
|
);
|
|
1950
|
-
|
|
1950
|
+
React2.useEffect(() => {
|
|
1951
1951
|
setMounted(true);
|
|
1952
1952
|
}, []);
|
|
1953
1953
|
if (!mounted) {
|
|
@@ -2501,12 +2501,12 @@ function measureScrollEdges(el) {
|
|
|
2501
2501
|
};
|
|
2502
2502
|
}
|
|
2503
2503
|
function useScrollFadeXEdges(enabled = true) {
|
|
2504
|
-
const scrollerRef =
|
|
2505
|
-
const [edges, setEdges] =
|
|
2504
|
+
const scrollerRef = React2.useRef(null);
|
|
2505
|
+
const [edges, setEdges] = React2.useState({
|
|
2506
2506
|
canScrollLeft: false,
|
|
2507
2507
|
canScrollRight: false
|
|
2508
2508
|
});
|
|
2509
|
-
|
|
2509
|
+
React2.useEffect(() => {
|
|
2510
2510
|
if (!enabled) {
|
|
2511
2511
|
setEdges({ canScrollLeft: false, canScrollRight: false });
|
|
2512
2512
|
return;
|
|
@@ -2758,7 +2758,7 @@ function OrgMenuRows({
|
|
|
2758
2758
|
adminUrl,
|
|
2759
2759
|
labels
|
|
2760
2760
|
}) {
|
|
2761
|
-
const [expanded, setExpanded] =
|
|
2761
|
+
const [expanded, setExpanded] = React2.useState(false);
|
|
2762
2762
|
const collapsible = orgs.length > PLATFORM_ACCOUNT_ORG_COLLAPSE_AT;
|
|
2763
2763
|
const visibleOrgs = collapsible && !expanded ? orgs.slice(0, PLATFORM_ACCOUNT_ORG_COLLAPSE_AT) : orgs;
|
|
2764
2764
|
if (orgs.length === 0) return null;
|
|
@@ -2850,8 +2850,8 @@ function PlatformAccountMenu({
|
|
|
2850
2850
|
className
|
|
2851
2851
|
}) {
|
|
2852
2852
|
const labels = { ...defaultLabels3, ...labelsProp };
|
|
2853
|
-
const [signingOut, setSigningOut] =
|
|
2854
|
-
const mergedOrgs =
|
|
2853
|
+
const [signingOut, setSigningOut] = React2.useState(false);
|
|
2854
|
+
const mergedOrgs = React2.useMemo(
|
|
2855
2855
|
() => mergePlatformAccountOrgs(memberOrgs, manageableOrgs),
|
|
2856
2856
|
[memberOrgs, manageableOrgs]
|
|
2857
2857
|
);
|
|
@@ -3022,7 +3022,7 @@ function Slider({
|
|
|
3022
3022
|
max = 100,
|
|
3023
3023
|
...props
|
|
3024
3024
|
}) {
|
|
3025
|
-
const _values =
|
|
3025
|
+
const _values = React2__namespace.useMemo(
|
|
3026
3026
|
() => Array.isArray(value) ? value : Array.isArray(defaultValue) ? defaultValue : [min, max],
|
|
3027
3027
|
[value, defaultValue, min, max]
|
|
3028
3028
|
);
|
|
@@ -3116,18 +3116,18 @@ function AvatarEditor({
|
|
|
3116
3116
|
className,
|
|
3117
3117
|
controlSize = "default"
|
|
3118
3118
|
}) {
|
|
3119
|
-
const canvasRef =
|
|
3120
|
-
const fileInputRef =
|
|
3121
|
-
const containerRef =
|
|
3122
|
-
const [image, setImage] =
|
|
3123
|
-
const [imageLoaded, setImageLoaded] =
|
|
3124
|
-
const [zoom, setZoom] =
|
|
3125
|
-
const [rotation, setRotation] =
|
|
3126
|
-
const [position, setPosition] =
|
|
3127
|
-
const [isDragging, setIsDragging] =
|
|
3128
|
-
const [dragStart, setDragStart] =
|
|
3129
|
-
const [showGrid, setShowGrid] =
|
|
3130
|
-
const generateOutput =
|
|
3119
|
+
const canvasRef = React2.useRef(null);
|
|
3120
|
+
const fileInputRef = React2.useRef(null);
|
|
3121
|
+
const containerRef = React2.useRef(null);
|
|
3122
|
+
const [image, setImage] = React2.useState(null);
|
|
3123
|
+
const [imageLoaded, setImageLoaded] = React2.useState(false);
|
|
3124
|
+
const [zoom, setZoom] = React2.useState(1);
|
|
3125
|
+
const [rotation, setRotation] = React2.useState(0);
|
|
3126
|
+
const [position, setPosition] = React2.useState({ x: 0, y: 0 });
|
|
3127
|
+
const [isDragging, setIsDragging] = React2.useState(false);
|
|
3128
|
+
const [dragStart, setDragStart] = React2.useState({ x: 0, y: 0 });
|
|
3129
|
+
const [showGrid, setShowGrid] = React2.useState(initialShowGrid);
|
|
3130
|
+
const generateOutput = React2.useCallback(() => {
|
|
3131
3131
|
if (!canvasRef.current || !image) return null;
|
|
3132
3132
|
const outputCanvas = document.createElement("canvas");
|
|
3133
3133
|
outputCanvas.width = outputSize;
|
|
@@ -3138,7 +3138,7 @@ function AvatarEditor({
|
|
|
3138
3138
|
const mimeType = `image/${outputFormat}`;
|
|
3139
3139
|
return outputCanvas.toDataURL(mimeType, outputQuality);
|
|
3140
3140
|
}, [image, outputSize, outputFormat, outputQuality]);
|
|
3141
|
-
|
|
3141
|
+
React2.useEffect(() => {
|
|
3142
3142
|
if (!canvasRef.current || !image || !imageLoaded) return;
|
|
3143
3143
|
const canvas = canvasRef.current;
|
|
3144
3144
|
const ctx = canvas.getContext("2d");
|
|
@@ -3182,12 +3182,12 @@ function AvatarEditor({
|
|
|
3182
3182
|
generateOutput,
|
|
3183
3183
|
onChange
|
|
3184
3184
|
]);
|
|
3185
|
-
const resetTransforms =
|
|
3185
|
+
const resetTransforms = React2.useCallback(() => {
|
|
3186
3186
|
setZoom(1);
|
|
3187
3187
|
setRotation(0);
|
|
3188
3188
|
setPosition({ x: 0, y: 0 });
|
|
3189
3189
|
}, []);
|
|
3190
|
-
const handleFileSelect =
|
|
3190
|
+
const handleFileSelect = React2.useCallback(
|
|
3191
3191
|
(e) => {
|
|
3192
3192
|
const file = e.target.files?.[0];
|
|
3193
3193
|
if (!file) return;
|
|
@@ -3206,7 +3206,7 @@ function AvatarEditor({
|
|
|
3206
3206
|
},
|
|
3207
3207
|
[resetTransforms]
|
|
3208
3208
|
);
|
|
3209
|
-
const handleMouseDown =
|
|
3209
|
+
const handleMouseDown = React2.useCallback(
|
|
3210
3210
|
(e) => {
|
|
3211
3211
|
if (!imageLoaded) return;
|
|
3212
3212
|
setIsDragging(true);
|
|
@@ -3214,7 +3214,7 @@ function AvatarEditor({
|
|
|
3214
3214
|
},
|
|
3215
3215
|
[imageLoaded, position]
|
|
3216
3216
|
);
|
|
3217
|
-
const handleMouseMove =
|
|
3217
|
+
const handleMouseMove = React2.useCallback(
|
|
3218
3218
|
(e) => {
|
|
3219
3219
|
if (!isDragging) return;
|
|
3220
3220
|
setPosition({
|
|
@@ -3224,10 +3224,10 @@ function AvatarEditor({
|
|
|
3224
3224
|
},
|
|
3225
3225
|
[isDragging, dragStart]
|
|
3226
3226
|
);
|
|
3227
|
-
const handleMouseUp =
|
|
3227
|
+
const handleMouseUp = React2.useCallback(() => {
|
|
3228
3228
|
setIsDragging(false);
|
|
3229
3229
|
}, []);
|
|
3230
|
-
const handleTouchStart =
|
|
3230
|
+
const handleTouchStart = React2.useCallback(
|
|
3231
3231
|
(e) => {
|
|
3232
3232
|
if (!imageLoaded) return;
|
|
3233
3233
|
const touch = e.touches[0];
|
|
@@ -3239,7 +3239,7 @@ function AvatarEditor({
|
|
|
3239
3239
|
},
|
|
3240
3240
|
[imageLoaded, position]
|
|
3241
3241
|
);
|
|
3242
|
-
const handleTouchMove =
|
|
3242
|
+
const handleTouchMove = React2.useCallback(
|
|
3243
3243
|
(e) => {
|
|
3244
3244
|
if (!isDragging) return;
|
|
3245
3245
|
const touch = e.touches[0];
|
|
@@ -3250,7 +3250,7 @@ function AvatarEditor({
|
|
|
3250
3250
|
},
|
|
3251
3251
|
[isDragging, dragStart]
|
|
3252
3252
|
);
|
|
3253
|
-
const handleDiscard =
|
|
3253
|
+
const handleDiscard = React2.useCallback(() => {
|
|
3254
3254
|
setImage(null);
|
|
3255
3255
|
setImageLoaded(false);
|
|
3256
3256
|
resetTransforms();
|
|
@@ -3716,8 +3716,8 @@ function DrawerTitle({
|
|
|
3716
3716
|
);
|
|
3717
3717
|
}
|
|
3718
3718
|
function useMediaQuery(query) {
|
|
3719
|
-
const [matches, setMatches] =
|
|
3720
|
-
|
|
3719
|
+
const [matches, setMatches] = React2.useState(false);
|
|
3720
|
+
React2.useEffect(() => {
|
|
3721
3721
|
const media = window.matchMedia(query);
|
|
3722
3722
|
if (media.matches !== matches) {
|
|
3723
3723
|
setMatches(media.matches);
|
|
@@ -3746,13 +3746,13 @@ function AvatarEditorDialog({
|
|
|
3746
3746
|
errorMessage = "Failed to save avatar. Please try again.",
|
|
3747
3747
|
className
|
|
3748
3748
|
}) {
|
|
3749
|
-
const [isOpen, setIsOpen] =
|
|
3750
|
-
const [editedValue, setEditedValue] =
|
|
3751
|
-
const [isSaving, setIsSaving] =
|
|
3752
|
-
const [feedback, setFeedback] =
|
|
3749
|
+
const [isOpen, setIsOpen] = React2.useState(false);
|
|
3750
|
+
const [editedValue, setEditedValue] = React2.useState(value ?? null);
|
|
3751
|
+
const [isSaving, setIsSaving] = React2.useState(false);
|
|
3752
|
+
const [feedback, setFeedback] = React2.useState(null);
|
|
3753
3753
|
const isMobile = useMediaQuery("(max-width: 640px)");
|
|
3754
3754
|
const caption = (placeholder ?? "").trim();
|
|
3755
|
-
const handleOpenChange =
|
|
3755
|
+
const handleOpenChange = React2.useCallback(
|
|
3756
3756
|
(open) => {
|
|
3757
3757
|
if (open) {
|
|
3758
3758
|
setEditedValue(value ?? null);
|
|
@@ -3762,7 +3762,7 @@ function AvatarEditorDialog({
|
|
|
3762
3762
|
},
|
|
3763
3763
|
[value]
|
|
3764
3764
|
);
|
|
3765
|
-
const handleAccept =
|
|
3765
|
+
const handleAccept = React2.useCallback(async () => {
|
|
3766
3766
|
if (!editedValue) return;
|
|
3767
3767
|
setIsSaving(true);
|
|
3768
3768
|
setFeedback(null);
|
|
@@ -4045,22 +4045,22 @@ function EmojiPicker({
|
|
|
4045
4045
|
recentLimit = 24,
|
|
4046
4046
|
storageKey = "blocks-emoji"
|
|
4047
4047
|
}) {
|
|
4048
|
-
const strings =
|
|
4048
|
+
const strings = React2__namespace.useMemo(
|
|
4049
4049
|
() => ({ ...DEFAULT_LABELS[locale], ...labels }),
|
|
4050
4050
|
[locale, labels]
|
|
4051
4051
|
);
|
|
4052
|
-
const titles =
|
|
4052
|
+
const titles = React2__namespace.useMemo(
|
|
4053
4053
|
() => ({ ...DEFAULT_TITLES[locale], ...labels?.categoryTitles }),
|
|
4054
4054
|
[locale, labels]
|
|
4055
4055
|
);
|
|
4056
|
-
const [query, setQuery] =
|
|
4057
|
-
const [skinTone, setSkinTone] =
|
|
4056
|
+
const [query, setQuery] = React2__namespace.useState("");
|
|
4057
|
+
const [skinTone, setSkinTone] = React2__namespace.useState(() => {
|
|
4058
4058
|
const raw = readStored(storageKey, "tone");
|
|
4059
4059
|
const parsed = raw != null ? Number.parseInt(raw, 10) : 0;
|
|
4060
4060
|
return parsed >= 0 && parsed <= 5 ? parsed : 0;
|
|
4061
4061
|
});
|
|
4062
|
-
const [toneOpen, setToneOpen] =
|
|
4063
|
-
const [recents, setRecents] =
|
|
4062
|
+
const [toneOpen, setToneOpen] = React2__namespace.useState(false);
|
|
4063
|
+
const [recents, setRecents] = React2__namespace.useState(() => {
|
|
4064
4064
|
const raw = readStored(storageKey, "recent");
|
|
4065
4065
|
if (!raw) return [];
|
|
4066
4066
|
try {
|
|
@@ -4070,13 +4070,13 @@ function EmojiPicker({
|
|
|
4070
4070
|
return [];
|
|
4071
4071
|
}
|
|
4072
4072
|
});
|
|
4073
|
-
const [focusIndex, setFocusIndex] =
|
|
4074
|
-
const scrollRef =
|
|
4075
|
-
const sectionRefs =
|
|
4073
|
+
const [focusIndex, setFocusIndex] = React2__namespace.useState(-1);
|
|
4074
|
+
const scrollRef = React2__namespace.useRef(null);
|
|
4075
|
+
const sectionRefs = React2__namespace.useRef(
|
|
4076
4076
|
/* @__PURE__ */ new Map()
|
|
4077
4077
|
);
|
|
4078
4078
|
const normalizedQuery = normalizeEmojiQuery(query);
|
|
4079
|
-
const sections =
|
|
4079
|
+
const sections = React2__namespace.useMemo(() => {
|
|
4080
4080
|
if (normalizedQuery) return [];
|
|
4081
4081
|
const result = [];
|
|
4082
4082
|
if (recents.length > 0) {
|
|
@@ -4095,7 +4095,7 @@ function EmojiPicker({
|
|
|
4095
4095
|
}
|
|
4096
4096
|
return result;
|
|
4097
4097
|
}, [normalizedQuery, recents, titles]);
|
|
4098
|
-
const searchResults =
|
|
4098
|
+
const searchResults = React2__namespace.useMemo(() => {
|
|
4099
4099
|
if (!normalizedQuery) return [];
|
|
4100
4100
|
const out = [];
|
|
4101
4101
|
for (const category of EMOJI_CATEGORIES) {
|
|
@@ -4105,21 +4105,21 @@ function EmojiPicker({
|
|
|
4105
4105
|
}
|
|
4106
4106
|
return out;
|
|
4107
4107
|
}, [normalizedQuery]);
|
|
4108
|
-
const flatList =
|
|
4108
|
+
const flatList = React2__namespace.useMemo(() => {
|
|
4109
4109
|
if (normalizedQuery) return searchResults;
|
|
4110
4110
|
return sections.flatMap((s) => s.emojis);
|
|
4111
4111
|
}, [normalizedQuery, searchResults, sections]);
|
|
4112
|
-
|
|
4112
|
+
React2__namespace.useEffect(() => {
|
|
4113
4113
|
setFocusIndex(-1);
|
|
4114
4114
|
}, [normalizedQuery]);
|
|
4115
|
-
|
|
4115
|
+
React2__namespace.useEffect(() => {
|
|
4116
4116
|
if (focusIndex < 0) return;
|
|
4117
4117
|
const el = scrollRef.current?.querySelector(
|
|
4118
4118
|
`[data-emoji-index="${focusIndex}"]`
|
|
4119
4119
|
);
|
|
4120
4120
|
el?.focus();
|
|
4121
4121
|
}, [focusIndex]);
|
|
4122
|
-
const commitRecent =
|
|
4122
|
+
const commitRecent = React2__namespace.useCallback(
|
|
4123
4123
|
(glyph) => {
|
|
4124
4124
|
setRecents((prev) => {
|
|
4125
4125
|
const next = [glyph, ...prev.filter((e) => e !== glyph)].slice(
|
|
@@ -4132,14 +4132,14 @@ function EmojiPicker({
|
|
|
4132
4132
|
},
|
|
4133
4133
|
[recentLimit, storageKey]
|
|
4134
4134
|
);
|
|
4135
|
-
const handleSelect =
|
|
4135
|
+
const handleSelect = React2__namespace.useCallback(
|
|
4136
4136
|
(glyph) => {
|
|
4137
4137
|
commitRecent(glyph);
|
|
4138
4138
|
onSelect(glyph);
|
|
4139
4139
|
},
|
|
4140
4140
|
[commitRecent, onSelect]
|
|
4141
4141
|
);
|
|
4142
|
-
const chooseTone =
|
|
4142
|
+
const chooseTone = React2__namespace.useCallback(
|
|
4143
4143
|
(tone) => {
|
|
4144
4144
|
setSkinTone(tone);
|
|
4145
4145
|
setToneOpen(false);
|
|
@@ -4445,17 +4445,17 @@ function EmojiPickerPopover({
|
|
|
4445
4445
|
locale = "en",
|
|
4446
4446
|
...pickerProps
|
|
4447
4447
|
}) {
|
|
4448
|
-
const [internalOpen, setInternalOpen] =
|
|
4448
|
+
const [internalOpen, setInternalOpen] = React2__namespace.useState(false);
|
|
4449
4449
|
const isControlled = open !== void 0;
|
|
4450
4450
|
const isOpen = isControlled ? open : internalOpen;
|
|
4451
|
-
const setOpen =
|
|
4451
|
+
const setOpen = React2__namespace.useCallback(
|
|
4452
4452
|
(next) => {
|
|
4453
4453
|
if (!isControlled) setInternalOpen(next);
|
|
4454
4454
|
onOpenChange?.(next);
|
|
4455
4455
|
},
|
|
4456
4456
|
[isControlled, onOpenChange]
|
|
4457
4457
|
);
|
|
4458
|
-
const handleSelect =
|
|
4458
|
+
const handleSelect = React2__namespace.useCallback(
|
|
4459
4459
|
(emoji) => {
|
|
4460
4460
|
onSelect(emoji);
|
|
4461
4461
|
if (!keepOpenOnSelect) setOpen(false);
|
|
@@ -4524,7 +4524,7 @@ function emitChange(element, nextValue, onChange) {
|
|
|
4524
4524
|
});
|
|
4525
4525
|
}
|
|
4526
4526
|
function useEmojiInsert(fieldRef, value, onChange) {
|
|
4527
|
-
return
|
|
4527
|
+
return React2__namespace.useCallback(
|
|
4528
4528
|
(emoji) => {
|
|
4529
4529
|
const el = fieldRef.current;
|
|
4530
4530
|
const current = value !== void 0 && value !== null ? String(value) : el?.value ?? "";
|
|
@@ -4545,7 +4545,7 @@ function useEmojiInsert(fieldRef, value, onChange) {
|
|
|
4545
4545
|
[fieldRef, value, onChange]
|
|
4546
4546
|
);
|
|
4547
4547
|
}
|
|
4548
|
-
var EmojiTextarea =
|
|
4548
|
+
var EmojiTextarea = React2__namespace.forwardRef(
|
|
4549
4549
|
function EmojiTextarea2({
|
|
4550
4550
|
className,
|
|
4551
4551
|
locale = "en",
|
|
@@ -4565,7 +4565,7 @@ var EmojiTextarea = React7__namespace.forwardRef(
|
|
|
4565
4565
|
emojiTriggerClassName,
|
|
4566
4566
|
...props
|
|
4567
4567
|
}, ref) {
|
|
4568
|
-
const fieldRef =
|
|
4568
|
+
const fieldRef = React2__namespace.useRef(null);
|
|
4569
4569
|
const handleEmojiSelect = useEmojiInsert(fieldRef, value, onChange);
|
|
4570
4570
|
const pickerDisabled = Boolean(disabled || readOnly);
|
|
4571
4571
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn(emojiFieldWrapperClassName, className), children: [
|
|
@@ -4611,7 +4611,7 @@ var EmojiTextarea = React7__namespace.forwardRef(
|
|
|
4611
4611
|
}
|
|
4612
4612
|
);
|
|
4613
4613
|
EmojiTextarea.displayName = "EmojiTextarea";
|
|
4614
|
-
var EmojiInput =
|
|
4614
|
+
var EmojiInput = React2__namespace.forwardRef(
|
|
4615
4615
|
function EmojiInput2({
|
|
4616
4616
|
className,
|
|
4617
4617
|
locale = "en",
|
|
@@ -4632,7 +4632,7 @@ var EmojiInput = React7__namespace.forwardRef(
|
|
|
4632
4632
|
emojiTriggerClassName,
|
|
4633
4633
|
...props
|
|
4634
4634
|
}, ref) {
|
|
4635
|
-
const fieldRef =
|
|
4635
|
+
const fieldRef = React2__namespace.useRef(null);
|
|
4636
4636
|
const handleEmojiSelect = useEmojiInsert(fieldRef, value, onChange);
|
|
4637
4637
|
const pickerDisabled = Boolean(disabled || readOnly);
|
|
4638
4638
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn(emojiFieldWrapperClassName, className), children: [
|
|
@@ -4679,1313 +4679,17 @@ var EmojiInput = React7__namespace.forwardRef(
|
|
|
4679
4679
|
}
|
|
4680
4680
|
);
|
|
4681
4681
|
EmojiInput.displayName = "EmojiInput";
|
|
4682
|
-
|
|
4683
|
-
// src/components/video/hls-config.ts
|
|
4684
|
-
function shouldRetryLiveEdge404(retryConfig, retryCount, _isTimeout, loaderResponse, defaultRetry) {
|
|
4685
|
-
if (loaderResponse?.code === 404) {
|
|
4686
|
-
return retryConfig != null && retryCount < retryConfig.maxNumRetry;
|
|
4687
|
-
}
|
|
4688
|
-
return defaultRetry;
|
|
4689
|
-
}
|
|
4690
|
-
var liveEdgeErrorRetry = {
|
|
4691
|
-
maxNumRetry: 8,
|
|
4692
|
-
retryDelayMs: 250,
|
|
4693
|
-
maxRetryDelayMs: 4e3,
|
|
4694
|
-
backoff: "exponential",
|
|
4695
|
-
shouldRetry: shouldRetryLiveEdge404
|
|
4696
|
-
};
|
|
4697
|
-
function createLiveHlsConfig() {
|
|
4698
|
-
return {
|
|
4699
|
-
enableWorker: true,
|
|
4700
|
-
// No custom request headers: Cache-Control/Pragma are not
|
|
4701
|
-
// CORS-safelisted and would force an OPTIONS preflight before every
|
|
4702
|
-
// manifest poll and segment fetch. Freshness is controlled by the
|
|
4703
|
-
// origin's response Cache-Control headers instead.
|
|
4704
|
-
liveSyncDurationCount: 4,
|
|
4705
|
-
liveMaxLatencyDurationCount: 12,
|
|
4706
|
-
fragLoadPolicy: {
|
|
4707
|
-
default: {
|
|
4708
|
-
maxTimeToFirstByteMs: 1e4,
|
|
4709
|
-
maxLoadTimeMs: 12e4,
|
|
4710
|
-
timeoutRetry: {
|
|
4711
|
-
maxNumRetry: 4,
|
|
4712
|
-
retryDelayMs: 0,
|
|
4713
|
-
maxRetryDelayMs: 0
|
|
4714
|
-
},
|
|
4715
|
-
errorRetry: liveEdgeErrorRetry
|
|
4716
|
-
}
|
|
4717
|
-
},
|
|
4718
|
-
playlistLoadPolicy: {
|
|
4719
|
-
default: {
|
|
4720
|
-
maxTimeToFirstByteMs: 1e4,
|
|
4721
|
-
maxLoadTimeMs: 3e4,
|
|
4722
|
-
timeoutRetry: {
|
|
4723
|
-
maxNumRetry: 2,
|
|
4724
|
-
retryDelayMs: 0,
|
|
4725
|
-
maxRetryDelayMs: 0
|
|
4726
|
-
},
|
|
4727
|
-
errorRetry: {
|
|
4728
|
-
...liveEdgeErrorRetry,
|
|
4729
|
-
maxNumRetry: 6
|
|
4730
|
-
}
|
|
4731
|
-
}
|
|
4732
|
-
}
|
|
4733
|
-
};
|
|
4734
|
-
}
|
|
4735
|
-
function createVodHlsConfig() {
|
|
4736
|
-
return {
|
|
4737
|
-
enableWorker: true
|
|
4738
|
-
};
|
|
4739
|
-
}
|
|
4740
|
-
|
|
4741
|
-
// src/components/video/hls-errors.ts
|
|
4742
|
-
var MEDIA_ERROR_NAMES = {
|
|
4743
|
-
1: "MEDIA_ERR_ABORTED",
|
|
4744
|
-
2: "MEDIA_ERR_NETWORK",
|
|
4745
|
-
3: "MEDIA_ERR_DECODE",
|
|
4746
|
-
4: "MEDIA_ERR_SRC_NOT_SUPPORTED"
|
|
4747
|
-
};
|
|
4748
|
-
var MEDIA_ERR_NETWORK = 2;
|
|
4749
|
-
var MEDIA_ERR_DECODE = 3;
|
|
4750
|
-
var MEDIA_ERR_SRC_NOT_SUPPORTED = 4;
|
|
4751
|
-
function errorMessageFromUnknown(error) {
|
|
4752
|
-
if (error instanceof Error) return error.message;
|
|
4753
|
-
if (typeof error === "string") return error;
|
|
4754
|
-
return void 0;
|
|
4755
|
-
}
|
|
4756
|
-
function isNotFound(httpStatus, details) {
|
|
4757
|
-
return httpStatus === 404 || details === "manifestLoadError" || details === "levelLoadError" || details === "fragLoadError";
|
|
4758
|
-
}
|
|
4759
|
-
function kindForHls(input) {
|
|
4760
|
-
const httpStatus = input.response?.code;
|
|
4761
|
-
if (input.type === "networkError" && isNotFound(httpStatus, input.details)) {
|
|
4762
|
-
return input.context.mode === "vod" || !input.context.manifestParsed ? "unavailable" : "network";
|
|
4763
|
-
}
|
|
4764
|
-
if (input.type === "mediaError" || input.details === "bufferAppendError" || input.details === "bufferSeekOverHole") {
|
|
4765
|
-
return "media";
|
|
4766
|
-
}
|
|
4767
|
-
return "generic";
|
|
4768
|
-
}
|
|
4769
|
-
function kindForNative(input) {
|
|
4770
|
-
const code = input.mediaError?.code;
|
|
4771
|
-
if (code === MEDIA_ERR_DECODE) return "media";
|
|
4772
|
-
if (code === MEDIA_ERR_SRC_NOT_SUPPORTED) return "unsupported";
|
|
4773
|
-
if (code === MEDIA_ERR_NETWORK) return "unavailable";
|
|
4774
|
-
return "generic";
|
|
4775
|
-
}
|
|
4776
|
-
function describeAvResync(input) {
|
|
4777
|
-
const lag = Number.isFinite(input.lagSeconds) ? input.lagSeconds : 0;
|
|
4778
|
-
return {
|
|
4779
|
-
summary: `av-resync lag=${lag.toFixed(3)}s (non-fatal)`,
|
|
4780
|
-
kind: "resync",
|
|
4781
|
-
detail: {
|
|
4782
|
-
source: input.context.source,
|
|
4783
|
-
kind: "resync",
|
|
4784
|
-
fatal: false,
|
|
4785
|
-
reason: `presented frame lag ${lag.toFixed(3)}s`,
|
|
4786
|
-
context: input.context
|
|
4787
|
-
}
|
|
4788
|
-
};
|
|
4789
|
-
}
|
|
4790
|
-
function describePlaybackError(input) {
|
|
4791
|
-
if (input.source === "unsupported") {
|
|
4792
|
-
return {
|
|
4793
|
-
summary: "playback unsupported (hls.js unavailable, native HLS unsupported)",
|
|
4794
|
-
kind: "unsupported",
|
|
4795
|
-
detail: {
|
|
4796
|
-
source: "unsupported",
|
|
4797
|
-
kind: "unsupported",
|
|
4798
|
-
context: input.context
|
|
4799
|
-
}
|
|
4800
|
-
};
|
|
4801
|
-
}
|
|
4802
|
-
if (input.source === "native") {
|
|
4803
|
-
const code = input.mediaError?.code;
|
|
4804
|
-
const kind2 = kindForNative(input);
|
|
4805
|
-
const detail2 = {
|
|
4806
|
-
source: "native",
|
|
4807
|
-
kind: kind2,
|
|
4808
|
-
mediaErrorCode: code,
|
|
4809
|
-
mediaErrorName: code !== void 0 ? MEDIA_ERROR_NAMES[code] : void 0,
|
|
4810
|
-
errorMessage: input.mediaError?.message,
|
|
4811
|
-
context: input.context
|
|
4812
|
-
};
|
|
4813
|
-
const name = detail2.mediaErrorName ?? "MEDIA_ERR_UNKNOWN";
|
|
4814
|
-
return {
|
|
4815
|
-
summary: `native ${name}${input.mediaError?.message ? `: ${input.mediaError.message}` : ""}`,
|
|
4816
|
-
kind: kind2,
|
|
4817
|
-
detail: detail2
|
|
4818
|
-
};
|
|
4819
|
-
}
|
|
4820
|
-
const httpStatus = input.response?.code;
|
|
4821
|
-
const kind = kindForHls(input);
|
|
4822
|
-
const detail = {
|
|
4823
|
-
source: "hls",
|
|
4824
|
-
kind,
|
|
4825
|
-
type: input.type,
|
|
4826
|
-
details: input.details,
|
|
4827
|
-
fatal: input.fatal,
|
|
4828
|
-
httpStatus,
|
|
4829
|
-
url: input.url,
|
|
4830
|
-
reason: input.reason,
|
|
4831
|
-
errorMessage: errorMessageFromUnknown(input.error),
|
|
4832
|
-
context: input.context
|
|
4833
|
-
};
|
|
4834
|
-
const statusSuffix = httpStatus !== void 0 ? ` ${httpStatus}` : "";
|
|
4835
|
-
const summary = [
|
|
4836
|
-
"hls",
|
|
4837
|
-
input.type ?? "unknown",
|
|
4838
|
-
input.details ?? "unknown",
|
|
4839
|
-
input.fatal ? "(fatal)" : "(non-fatal)",
|
|
4840
|
-
statusSuffix.trim()
|
|
4841
|
-
].filter(Boolean).join(" ");
|
|
4842
|
-
return { summary, kind, detail };
|
|
4843
|
-
}
|
|
4844
|
-
|
|
4845
|
-
// src/components/video/useHlsPlayback.ts
|
|
4846
|
-
var RETRY_INTERVAL_MS = 3e3;
|
|
4847
|
-
var MAX_MEDIA_ERROR_RETRIES = 5;
|
|
4848
|
-
var DRIFT_THRESHOLD_S = 0.4;
|
|
4849
|
-
var DRIFT_CONSECUTIVE_SAMPLES = 3;
|
|
4850
|
-
var RESYNC_COOLDOWN_MS = 1e4;
|
|
4851
|
-
var LIVE_EDGE_RESYNC_THRESHOLD_S = 8;
|
|
4852
|
-
function useHlsPlayback({
|
|
4853
|
-
src,
|
|
4854
|
-
mode,
|
|
4855
|
-
active,
|
|
4856
|
-
autoPlay = false,
|
|
4857
|
-
muted = false,
|
|
4858
|
-
onError,
|
|
4859
|
-
onPlayingChange
|
|
4860
|
-
}) {
|
|
4861
|
-
const videoRef = React7__namespace.useRef(null);
|
|
4862
|
-
const hlsRef = React7__namespace.useRef(null);
|
|
4863
|
-
const [state, setState] = React7__namespace.useState("idle");
|
|
4864
|
-
const [qualities, setQualities] = React7__namespace.useState([]);
|
|
4865
|
-
const [activeLevel, setActiveLevel] = React7__namespace.useState(-1);
|
|
4866
|
-
const [autoplayState, setAutoplayState] = React7__namespace.useState("none");
|
|
4867
|
-
const [error, setError] = React7__namespace.useState(null);
|
|
4868
|
-
const [reloadKey, setReloadKey] = React7__namespace.useState(0);
|
|
4869
|
-
const onErrorRef = React7__namespace.useRef(onError);
|
|
4870
|
-
const onPlayingChangeRef = React7__namespace.useRef(onPlayingChange);
|
|
4871
|
-
React7__namespace.useEffect(() => {
|
|
4872
|
-
onErrorRef.current = onError;
|
|
4873
|
-
onPlayingChangeRef.current = onPlayingChange;
|
|
4874
|
-
}, [onError, onPlayingChange]);
|
|
4875
|
-
const retry = React7__namespace.useCallback(() => {
|
|
4876
|
-
setError(null);
|
|
4877
|
-
setState("loading");
|
|
4878
|
-
setAutoplayState("none");
|
|
4879
|
-
setReloadKey((k) => k + 1);
|
|
4880
|
-
}, []);
|
|
4881
|
-
React7__namespace.useEffect(() => {
|
|
4882
|
-
const media = videoRef.current;
|
|
4883
|
-
if (!media || !src || !active) {
|
|
4884
|
-
setState("idle");
|
|
4885
|
-
return;
|
|
4886
|
-
}
|
|
4887
|
-
let cancelled = false;
|
|
4888
|
-
let retryTimer = null;
|
|
4889
|
-
let manifestParsed = false;
|
|
4890
|
-
let mediaErrorRetries = 0;
|
|
4891
|
-
let playbackSource = "hls";
|
|
4892
|
-
const teardown = [];
|
|
4893
|
-
media.muted = muted;
|
|
4894
|
-
setState("loading");
|
|
4895
|
-
setError(null);
|
|
4896
|
-
setAutoplayState("none");
|
|
4897
|
-
setQualities([]);
|
|
4898
|
-
setActiveLevel(-1);
|
|
4899
|
-
function baseContext() {
|
|
4900
|
-
return {
|
|
4901
|
-
mode,
|
|
4902
|
-
src,
|
|
4903
|
-
manifestParsed,
|
|
4904
|
-
retryCount: mediaErrorRetries,
|
|
4905
|
-
source: playbackSource
|
|
4906
|
-
};
|
|
4907
|
-
}
|
|
4908
|
-
function clearRetryTimer() {
|
|
4909
|
-
if (retryTimer !== null) {
|
|
4910
|
-
clearTimeout(retryTimer);
|
|
4911
|
-
retryTimer = null;
|
|
4912
|
-
}
|
|
4913
|
-
}
|
|
4914
|
-
function destroyHls() {
|
|
4915
|
-
hlsRef.current?.destroy();
|
|
4916
|
-
hlsRef.current = null;
|
|
4917
|
-
}
|
|
4918
|
-
function reportFatal(input) {
|
|
4919
|
-
const described = describePlaybackError(input);
|
|
4920
|
-
onErrorRef.current?.(described);
|
|
4921
|
-
setError(described);
|
|
4922
|
-
setState("error");
|
|
4923
|
-
}
|
|
4924
|
-
function attemptAutoplay(el) {
|
|
4925
|
-
void el.play().then(
|
|
4926
|
-
() => setAutoplayState("playing"),
|
|
4927
|
-
() => {
|
|
4928
|
-
el.muted = true;
|
|
4929
|
-
void el.play().then(
|
|
4930
|
-
() => setAutoplayState("muted"),
|
|
4931
|
-
() => setAutoplayState("blocked")
|
|
4932
|
-
);
|
|
4933
|
-
}
|
|
4934
|
-
);
|
|
4935
|
-
}
|
|
4936
|
-
function scheduleRetry(retryFn) {
|
|
4937
|
-
clearRetryTimer();
|
|
4938
|
-
if (cancelled) return;
|
|
4939
|
-
setState("waiting");
|
|
4940
|
-
retryTimer = setTimeout(() => {
|
|
4941
|
-
retryTimer = null;
|
|
4942
|
-
if (!cancelled) retryFn();
|
|
4943
|
-
}, RETRY_INTERVAL_MS);
|
|
4944
|
-
}
|
|
4945
|
-
function startDriftWatchdog(el) {
|
|
4946
|
-
if (typeof el.requestVideoFrameCallback !== "function") return;
|
|
4947
|
-
let consecutiveLagSamples = 0;
|
|
4948
|
-
let lastResyncAt = 0;
|
|
4949
|
-
let handle = null;
|
|
4950
|
-
const tick = (_now, metadata) => {
|
|
4951
|
-
if (cancelled) return;
|
|
4952
|
-
handle = el.requestVideoFrameCallback(tick);
|
|
4953
|
-
if (el.paused || el.ended) {
|
|
4954
|
-
consecutiveLagSamples = 0;
|
|
4955
|
-
return;
|
|
4956
|
-
}
|
|
4957
|
-
const lag = el.currentTime - metadata.mediaTime;
|
|
4958
|
-
if (!(lag > DRIFT_THRESHOLD_S)) {
|
|
4959
|
-
consecutiveLagSamples = 0;
|
|
4960
|
-
return;
|
|
4961
|
-
}
|
|
4962
|
-
consecutiveLagSamples += 1;
|
|
4963
|
-
if (consecutiveLagSamples < DRIFT_CONSECUTIVE_SAMPLES) return;
|
|
4964
|
-
const nowMs = performance.now();
|
|
4965
|
-
if (nowMs - lastResyncAt < RESYNC_COOLDOWN_MS) return;
|
|
4966
|
-
lastResyncAt = nowMs;
|
|
4967
|
-
consecutiveLagSamples = 0;
|
|
4968
|
-
if (mode === "live" && el.seekable.length > 0) {
|
|
4969
|
-
const edge = el.seekable.end(el.seekable.length - 1);
|
|
4970
|
-
if (edge - el.currentTime > LIVE_EDGE_RESYNC_THRESHOLD_S) {
|
|
4971
|
-
el.currentTime = edge;
|
|
4972
|
-
} else {
|
|
4973
|
-
el.currentTime = el.currentTime + 1e-3;
|
|
4974
|
-
}
|
|
4975
|
-
} else {
|
|
4976
|
-
el.currentTime = el.currentTime + 1e-3;
|
|
4977
|
-
}
|
|
4978
|
-
onErrorRef.current?.(
|
|
4979
|
-
describeAvResync({
|
|
4980
|
-
lagSeconds: lag,
|
|
4981
|
-
context: baseContext()
|
|
4982
|
-
})
|
|
4983
|
-
);
|
|
4984
|
-
};
|
|
4985
|
-
handle = el.requestVideoFrameCallback(tick);
|
|
4986
|
-
teardown.push(() => {
|
|
4987
|
-
if (handle != null && typeof el.cancelVideoFrameCallback === "function") {
|
|
4988
|
-
el.cancelVideoFrameCallback(handle);
|
|
4989
|
-
}
|
|
4990
|
-
});
|
|
4991
|
-
}
|
|
4992
|
-
function onPlaying() {
|
|
4993
|
-
manifestParsed = true;
|
|
4994
|
-
mediaErrorRetries = 0;
|
|
4995
|
-
clearRetryTimer();
|
|
4996
|
-
setState("ready");
|
|
4997
|
-
onPlayingChangeRef.current?.(true);
|
|
4998
|
-
}
|
|
4999
|
-
function onPaused() {
|
|
5000
|
-
onPlayingChangeRef.current?.(false);
|
|
5001
|
-
}
|
|
5002
|
-
media.addEventListener("playing", onPlaying);
|
|
5003
|
-
media.addEventListener("pause", onPaused);
|
|
5004
|
-
media.addEventListener("ended", onPaused);
|
|
5005
|
-
teardown.push(() => {
|
|
5006
|
-
media.removeEventListener("playing", onPlaying);
|
|
5007
|
-
media.removeEventListener("pause", onPaused);
|
|
5008
|
-
media.removeEventListener("ended", onPaused);
|
|
5009
|
-
});
|
|
5010
|
-
startDriftWatchdog(media);
|
|
5011
|
-
function initNative() {
|
|
5012
|
-
playbackSource = "native";
|
|
5013
|
-
manifestParsed = false;
|
|
5014
|
-
media.removeAttribute("src");
|
|
5015
|
-
media.load();
|
|
5016
|
-
media.src = src;
|
|
5017
|
-
const onReady = () => {
|
|
5018
|
-
manifestParsed = true;
|
|
5019
|
-
clearRetryTimer();
|
|
5020
|
-
setState("ready");
|
|
5021
|
-
if (mode === "live" || autoPlay) attemptAutoplay(media);
|
|
5022
|
-
};
|
|
5023
|
-
const onErr = () => {
|
|
5024
|
-
if (manifestParsed) {
|
|
5025
|
-
reportFatal({
|
|
5026
|
-
source: "native",
|
|
5027
|
-
mediaError: media.error,
|
|
5028
|
-
context: baseContext()
|
|
5029
|
-
});
|
|
5030
|
-
return;
|
|
5031
|
-
}
|
|
5032
|
-
onErrorRef.current?.(
|
|
5033
|
-
describePlaybackError({
|
|
5034
|
-
source: "native",
|
|
5035
|
-
mediaError: media.error,
|
|
5036
|
-
context: baseContext()
|
|
5037
|
-
})
|
|
5038
|
-
);
|
|
5039
|
-
scheduleRetry(() => {
|
|
5040
|
-
media.src = src;
|
|
5041
|
-
media.load();
|
|
5042
|
-
});
|
|
5043
|
-
};
|
|
5044
|
-
media.addEventListener("loadedmetadata", onReady);
|
|
5045
|
-
media.addEventListener("error", onErr);
|
|
5046
|
-
teardown.push(() => {
|
|
5047
|
-
media.removeEventListener("loadedmetadata", onReady);
|
|
5048
|
-
media.removeEventListener("error", onErr);
|
|
5049
|
-
});
|
|
5050
|
-
}
|
|
5051
|
-
function initHlsJs(Hls) {
|
|
5052
|
-
playbackSource = "hls";
|
|
5053
|
-
destroyHls();
|
|
5054
|
-
manifestParsed = false;
|
|
5055
|
-
const config = mode === "live" ? createLiveHlsConfig() : createVodHlsConfig();
|
|
5056
|
-
const hls = new Hls(config);
|
|
5057
|
-
hlsRef.current = hls;
|
|
5058
|
-
hls.loadSource(src);
|
|
5059
|
-
hls.attachMedia(media);
|
|
5060
|
-
hls.on(Hls.Events.MANIFEST_PARSED, (_e, data) => {
|
|
5061
|
-
manifestParsed = true;
|
|
5062
|
-
clearRetryTimer();
|
|
5063
|
-
setQualities(
|
|
5064
|
-
data.levels.map((l, index) => ({ index, height: l.height }))
|
|
5065
|
-
);
|
|
5066
|
-
setState("ready");
|
|
5067
|
-
if (mode === "live" || autoPlay) attemptAutoplay(media);
|
|
5068
|
-
});
|
|
5069
|
-
hls.on(Hls.Events.LEVEL_SWITCHED, (_e, data) => {
|
|
5070
|
-
if (hls.autoLevelEnabled) setActiveLevel(-1);
|
|
5071
|
-
else setActiveLevel(data.level);
|
|
5072
|
-
});
|
|
5073
|
-
hls.on(Hls.Events.ERROR, (_e, data) => {
|
|
5074
|
-
onErrorRef.current?.(
|
|
5075
|
-
describePlaybackError({
|
|
5076
|
-
source: "hls",
|
|
5077
|
-
type: data.type,
|
|
5078
|
-
details: data.details,
|
|
5079
|
-
fatal: data.fatal,
|
|
5080
|
-
url: data.url,
|
|
5081
|
-
response: data.response,
|
|
5082
|
-
reason: data.reason,
|
|
5083
|
-
error: data.error,
|
|
5084
|
-
context: baseContext()
|
|
5085
|
-
})
|
|
5086
|
-
);
|
|
5087
|
-
if (!data.fatal) return;
|
|
5088
|
-
if (data.type === Hls.ErrorTypes.NETWORK_ERROR) {
|
|
5089
|
-
if (!manifestParsed) {
|
|
5090
|
-
scheduleRetry(() => initHlsJs(Hls));
|
|
5091
|
-
return;
|
|
5092
|
-
}
|
|
5093
|
-
hls.startLoad();
|
|
5094
|
-
return;
|
|
5095
|
-
}
|
|
5096
|
-
mediaErrorRetries += 1;
|
|
5097
|
-
if (mediaErrorRetries === 1) {
|
|
5098
|
-
hls.recoverMediaError();
|
|
5099
|
-
return;
|
|
5100
|
-
}
|
|
5101
|
-
if (mediaErrorRetries === 2) {
|
|
5102
|
-
hls.swapAudioCodec();
|
|
5103
|
-
hls.recoverMediaError();
|
|
5104
|
-
return;
|
|
5105
|
-
}
|
|
5106
|
-
if (mediaErrorRetries < MAX_MEDIA_ERROR_RETRIES) {
|
|
5107
|
-
scheduleRetry(() => initHlsJs(Hls));
|
|
5108
|
-
return;
|
|
5109
|
-
}
|
|
5110
|
-
reportFatal({
|
|
5111
|
-
source: "hls",
|
|
5112
|
-
type: data.type,
|
|
5113
|
-
details: data.details,
|
|
5114
|
-
fatal: true,
|
|
5115
|
-
url: data.url,
|
|
5116
|
-
response: data.response,
|
|
5117
|
-
reason: data.reason,
|
|
5118
|
-
error: data.error,
|
|
5119
|
-
context: baseContext()
|
|
5120
|
-
});
|
|
5121
|
-
});
|
|
5122
|
-
}
|
|
5123
|
-
async function setup() {
|
|
5124
|
-
let Hls = null;
|
|
5125
|
-
try {
|
|
5126
|
-
Hls = (await import('hls.js')).default;
|
|
5127
|
-
} catch {
|
|
5128
|
-
Hls = null;
|
|
5129
|
-
}
|
|
5130
|
-
if (cancelled) return;
|
|
5131
|
-
if (Hls && Hls.isSupported()) {
|
|
5132
|
-
initHlsJs(Hls);
|
|
5133
|
-
} else if (media.canPlayType("application/vnd.apple.mpegurl")) {
|
|
5134
|
-
initNative();
|
|
5135
|
-
} else {
|
|
5136
|
-
playbackSource = "unsupported";
|
|
5137
|
-
reportFatal({
|
|
5138
|
-
source: "unsupported",
|
|
5139
|
-
context: baseContext()
|
|
5140
|
-
});
|
|
5141
|
-
}
|
|
5142
|
-
}
|
|
5143
|
-
void setup();
|
|
5144
|
-
return () => {
|
|
5145
|
-
cancelled = true;
|
|
5146
|
-
clearRetryTimer();
|
|
5147
|
-
for (const fn of teardown) fn();
|
|
5148
|
-
destroyHls();
|
|
5149
|
-
};
|
|
5150
|
-
}, [src, mode, active, autoPlay, muted, reloadKey]);
|
|
5151
|
-
const setLevel = React7__namespace.useCallback((index) => {
|
|
5152
|
-
const hls = hlsRef.current;
|
|
5153
|
-
if (!hls) return;
|
|
5154
|
-
hls.nextLevel = index;
|
|
5155
|
-
setActiveLevel(index);
|
|
5156
|
-
}, []);
|
|
5157
|
-
return {
|
|
5158
|
-
videoRef,
|
|
5159
|
-
state,
|
|
5160
|
-
qualities,
|
|
5161
|
-
activeLevel,
|
|
5162
|
-
setLevel,
|
|
5163
|
-
autoplayState,
|
|
5164
|
-
error,
|
|
5165
|
-
retry
|
|
5166
|
-
};
|
|
5167
|
-
}
|
|
5168
|
-
var DEFAULT_LABELS2 = {
|
|
5169
|
-
play: "Play",
|
|
5170
|
-
pause: "Pause",
|
|
5171
|
-
mute: "Mute",
|
|
5172
|
-
unmute: "Unmute",
|
|
5173
|
-
enterFullscreen: "Fullscreen",
|
|
5174
|
-
exitFullscreen: "Exit fullscreen",
|
|
5175
|
-
pictureInPicture: "Picture in picture",
|
|
5176
|
-
settings: "Settings",
|
|
5177
|
-
quality: "Quality",
|
|
5178
|
-
auto: "Auto",
|
|
5179
|
-
speed: "Speed",
|
|
5180
|
-
live: "LIVE",
|
|
5181
|
-
goLive: "Go live",
|
|
5182
|
-
tapToUnmute: "Tap to unmute",
|
|
5183
|
-
loading: "Loading\u2026",
|
|
5184
|
-
waiting: "Waiting for stream\u2026",
|
|
5185
|
-
retry: "Retry",
|
|
5186
|
-
errorUnavailable: "This video isn't available yet.",
|
|
5187
|
-
errorNetwork: "We couldn't load the video. Check your connection.",
|
|
5188
|
-
errorMedia: "There was a playback problem.",
|
|
5189
|
-
errorUnsupported: "Your browser can't play this video.",
|
|
5190
|
-
errorGeneric: "We couldn't play this video."
|
|
5191
|
-
};
|
|
5192
|
-
var PLAYBACK_RATES = [0.75, 1, 1.25, 1.5, 2];
|
|
5193
|
-
var CONTROLS_HIDE_MS = 3e3;
|
|
5194
|
-
var LIVE_EDGE_THRESHOLD_S = 8;
|
|
5195
|
-
var SEEK_STEP_S = 5;
|
|
5196
|
-
function asWebkitVideo(video) {
|
|
5197
|
-
return video;
|
|
5198
|
-
}
|
|
5199
|
-
function hasWebkitVideoFullscreen(video) {
|
|
5200
|
-
const webkit = asWebkitVideo(video);
|
|
5201
|
-
return typeof webkit?.webkitEnterFullscreen === "function";
|
|
5202
|
-
}
|
|
5203
|
-
function hasStandardFullscreen() {
|
|
5204
|
-
if (typeof document === "undefined") return false;
|
|
5205
|
-
if (document.fullscreenEnabled) return true;
|
|
5206
|
-
const doc = document;
|
|
5207
|
-
return !!doc.webkitFullscreenEnabled;
|
|
5208
|
-
}
|
|
5209
|
-
function formatTime(seconds) {
|
|
5210
|
-
if (!Number.isFinite(seconds) || seconds < 0) return "0:00";
|
|
5211
|
-
const total = Math.floor(seconds);
|
|
5212
|
-
const h = Math.floor(total / 3600);
|
|
5213
|
-
const m = Math.floor(total % 3600 / 60);
|
|
5214
|
-
const s = total % 60;
|
|
5215
|
-
const mm = h > 0 ? String(m).padStart(2, "0") : String(m);
|
|
5216
|
-
const ss = String(s).padStart(2, "0");
|
|
5217
|
-
return h > 0 ? `${h}:${mm}:${ss}` : `${mm}:${ss}`;
|
|
5218
|
-
}
|
|
5219
|
-
function VideoPlayer({
|
|
5220
|
-
src,
|
|
5221
|
-
mode,
|
|
5222
|
-
poster,
|
|
5223
|
-
autoPlay = false,
|
|
5224
|
-
muted = false,
|
|
5225
|
-
stats,
|
|
5226
|
-
labels,
|
|
5227
|
-
showQualitySelector = true,
|
|
5228
|
-
paused = false,
|
|
5229
|
-
onPlayingChange,
|
|
5230
|
-
onFirstPlay,
|
|
5231
|
-
onError,
|
|
5232
|
-
fit = "aspect-video",
|
|
5233
|
-
className
|
|
5234
|
-
}) {
|
|
5235
|
-
const t = { ...DEFAULT_LABELS2, ...labels };
|
|
5236
|
-
const containerRef = React7__namespace.useRef(null);
|
|
5237
|
-
const firstPlayFiredRef = React7__namespace.useRef(false);
|
|
5238
|
-
const [userStarted, setUserStarted] = React7__namespace.useState(false);
|
|
5239
|
-
const active = autoPlay || !poster || userStarted;
|
|
5240
|
-
const autoplayActive = autoPlay || userStarted;
|
|
5241
|
-
const handlePlayingChange = React7__namespace.useCallback(
|
|
5242
|
-
(playing) => {
|
|
5243
|
-
setIsPlaying(playing);
|
|
5244
|
-
if (playing && !firstPlayFiredRef.current) {
|
|
5245
|
-
firstPlayFiredRef.current = true;
|
|
5246
|
-
onFirstPlay?.();
|
|
5247
|
-
}
|
|
5248
|
-
onPlayingChange?.(playing);
|
|
5249
|
-
},
|
|
5250
|
-
[onFirstPlay, onPlayingChange]
|
|
5251
|
-
);
|
|
5252
|
-
const {
|
|
5253
|
-
videoRef,
|
|
5254
|
-
state,
|
|
5255
|
-
qualities,
|
|
5256
|
-
activeLevel,
|
|
5257
|
-
setLevel,
|
|
5258
|
-
autoplayState,
|
|
5259
|
-
error,
|
|
5260
|
-
retry
|
|
5261
|
-
} = useHlsPlayback({
|
|
5262
|
-
src,
|
|
5263
|
-
mode,
|
|
5264
|
-
active,
|
|
5265
|
-
autoPlay: autoplayActive,
|
|
5266
|
-
muted,
|
|
5267
|
-
onError,
|
|
5268
|
-
onPlayingChange: handlePlayingChange
|
|
5269
|
-
});
|
|
5270
|
-
const [isPlaying, setIsPlaying] = React7__namespace.useState(false);
|
|
5271
|
-
const [isMuted, setIsMuted] = React7__namespace.useState(muted);
|
|
5272
|
-
const [volume, setVolume] = React7__namespace.useState(1);
|
|
5273
|
-
const [currentTime, setCurrentTime] = React7__namespace.useState(0);
|
|
5274
|
-
const [duration, setDuration] = React7__namespace.useState(0);
|
|
5275
|
-
const [buffered, setBuffered] = React7__namespace.useState(0);
|
|
5276
|
-
const [isFullscreen, setIsFullscreen] = React7__namespace.useState(false);
|
|
5277
|
-
const [pipActive, setPipActive] = React7__namespace.useState(false);
|
|
5278
|
-
const [controlsVisible, setControlsVisible] = React7__namespace.useState(true);
|
|
5279
|
-
const [playbackRate, setPlaybackRate] = React7__namespace.useState(1);
|
|
5280
|
-
const [openMenu, setOpenMenu] = React7__namespace.useState(
|
|
5281
|
-
null
|
|
5282
|
-
);
|
|
5283
|
-
const [behindLive, setBehindLive] = React7__namespace.useState(false);
|
|
5284
|
-
const [webkitFullscreenSupported, setWebkitFullscreenSupported] = React7__namespace.useState(false);
|
|
5285
|
-
const hideTimerRef = React7__namespace.useRef(null);
|
|
5286
|
-
const pipSupported = typeof document !== "undefined" && "pictureInPictureEnabled" in document && document.pictureInPictureEnabled;
|
|
5287
|
-
const fullscreenSupported = hasStandardFullscreen() || webkitFullscreenSupported;
|
|
5288
|
-
React7__namespace.useEffect(() => {
|
|
5289
|
-
const video = videoRef.current;
|
|
5290
|
-
if (!video || !active) return;
|
|
5291
|
-
const onTimeUpdate = () => {
|
|
5292
|
-
setCurrentTime(video.currentTime);
|
|
5293
|
-
if (video.buffered.length > 0) {
|
|
5294
|
-
setBuffered(video.buffered.end(video.buffered.length - 1));
|
|
5295
|
-
}
|
|
5296
|
-
if (mode === "live" && video.seekable.length > 0) {
|
|
5297
|
-
const edge = video.seekable.end(video.seekable.length - 1);
|
|
5298
|
-
setBehindLive(edge - video.currentTime > LIVE_EDGE_THRESHOLD_S);
|
|
5299
|
-
}
|
|
5300
|
-
};
|
|
5301
|
-
const onDuration = () => setDuration(video.duration);
|
|
5302
|
-
const onVolume = () => {
|
|
5303
|
-
setIsMuted(video.muted);
|
|
5304
|
-
setVolume(video.volume);
|
|
5305
|
-
};
|
|
5306
|
-
const onRate = () => setPlaybackRate(video.playbackRate);
|
|
5307
|
-
video.addEventListener("timeupdate", onTimeUpdate);
|
|
5308
|
-
video.addEventListener("durationchange", onDuration);
|
|
5309
|
-
video.addEventListener("loadedmetadata", onDuration);
|
|
5310
|
-
video.addEventListener("volumechange", onVolume);
|
|
5311
|
-
video.addEventListener("ratechange", onRate);
|
|
5312
|
-
onVolume();
|
|
5313
|
-
return () => {
|
|
5314
|
-
video.removeEventListener("timeupdate", onTimeUpdate);
|
|
5315
|
-
video.removeEventListener("durationchange", onDuration);
|
|
5316
|
-
video.removeEventListener("loadedmetadata", onDuration);
|
|
5317
|
-
video.removeEventListener("volumechange", onVolume);
|
|
5318
|
-
video.removeEventListener("ratechange", onRate);
|
|
5319
|
-
};
|
|
5320
|
-
}, [videoRef, active, mode]);
|
|
5321
|
-
React7__namespace.useEffect(() => {
|
|
5322
|
-
const video = videoRef.current;
|
|
5323
|
-
if (!paused || !video || !isPlaying) return;
|
|
5324
|
-
video.pause();
|
|
5325
|
-
}, [paused, videoRef, isPlaying]);
|
|
5326
|
-
React7__namespace.useEffect(() => {
|
|
5327
|
-
setWebkitFullscreenSupported(hasWebkitVideoFullscreen(videoRef.current));
|
|
5328
|
-
}, [videoRef, active]);
|
|
5329
|
-
React7__namespace.useEffect(() => {
|
|
5330
|
-
const onFsChange = () => setIsFullscreen(document.fullscreenElement === containerRef.current);
|
|
5331
|
-
document.addEventListener("fullscreenchange", onFsChange);
|
|
5332
|
-
return () => document.removeEventListener("fullscreenchange", onFsChange);
|
|
5333
|
-
}, []);
|
|
5334
|
-
React7__namespace.useEffect(() => {
|
|
5335
|
-
const video = asWebkitVideo(videoRef.current);
|
|
5336
|
-
if (!video) return;
|
|
5337
|
-
const onBegin = () => setIsFullscreen(true);
|
|
5338
|
-
const onEnd = () => setIsFullscreen(false);
|
|
5339
|
-
video.addEventListener("webkitbeginfullscreen", onBegin);
|
|
5340
|
-
video.addEventListener("webkitendfullscreen", onEnd);
|
|
5341
|
-
return () => {
|
|
5342
|
-
video.removeEventListener("webkitbeginfullscreen", onBegin);
|
|
5343
|
-
video.removeEventListener("webkitendfullscreen", onEnd);
|
|
5344
|
-
};
|
|
5345
|
-
}, [videoRef, active]);
|
|
5346
|
-
React7__namespace.useEffect(() => {
|
|
5347
|
-
const video = videoRef.current;
|
|
5348
|
-
if (!video) return;
|
|
5349
|
-
const onEnter = () => setPipActive(true);
|
|
5350
|
-
const onLeave = () => setPipActive(false);
|
|
5351
|
-
video.addEventListener("enterpictureinpicture", onEnter);
|
|
5352
|
-
video.addEventListener("leavepictureinpicture", onLeave);
|
|
5353
|
-
return () => {
|
|
5354
|
-
video.removeEventListener("enterpictureinpicture", onEnter);
|
|
5355
|
-
video.removeEventListener("leavepictureinpicture", onLeave);
|
|
5356
|
-
};
|
|
5357
|
-
}, [videoRef]);
|
|
5358
|
-
const scheduleHide = React7__namespace.useCallback(() => {
|
|
5359
|
-
if (hideTimerRef.current) clearTimeout(hideTimerRef.current);
|
|
5360
|
-
hideTimerRef.current = setTimeout(() => {
|
|
5361
|
-
setControlsVisible(false);
|
|
5362
|
-
setOpenMenu(null);
|
|
5363
|
-
}, CONTROLS_HIDE_MS);
|
|
5364
|
-
}, []);
|
|
5365
|
-
const revealControls = React7__namespace.useCallback(() => {
|
|
5366
|
-
setControlsVisible(true);
|
|
5367
|
-
scheduleHide();
|
|
5368
|
-
}, [scheduleHide]);
|
|
5369
|
-
React7__namespace.useEffect(() => {
|
|
5370
|
-
return () => {
|
|
5371
|
-
if (hideTimerRef.current) clearTimeout(hideTimerRef.current);
|
|
5372
|
-
};
|
|
5373
|
-
}, []);
|
|
5374
|
-
function togglePlay() {
|
|
5375
|
-
const video = videoRef.current;
|
|
5376
|
-
if (!video) return;
|
|
5377
|
-
if (video.paused) void video.play();
|
|
5378
|
-
else video.pause();
|
|
5379
|
-
}
|
|
5380
|
-
function toggleMute() {
|
|
5381
|
-
const video = videoRef.current;
|
|
5382
|
-
if (!video) return;
|
|
5383
|
-
video.muted = !video.muted;
|
|
5384
|
-
}
|
|
5385
|
-
function changeVolume(next) {
|
|
5386
|
-
const video = videoRef.current;
|
|
5387
|
-
if (!video) return;
|
|
5388
|
-
video.volume = next;
|
|
5389
|
-
video.muted = next === 0;
|
|
5390
|
-
}
|
|
5391
|
-
function seekTo(next) {
|
|
5392
|
-
const video = videoRef.current;
|
|
5393
|
-
if (!video) return;
|
|
5394
|
-
video.currentTime = next;
|
|
5395
|
-
setCurrentTime(next);
|
|
5396
|
-
}
|
|
5397
|
-
function seekBy(delta) {
|
|
5398
|
-
const video = videoRef.current;
|
|
5399
|
-
if (!video) return;
|
|
5400
|
-
seekTo(Math.min(Math.max(video.currentTime + delta, 0), duration || 0));
|
|
5401
|
-
}
|
|
5402
|
-
function goToLiveEdge() {
|
|
5403
|
-
const video = videoRef.current;
|
|
5404
|
-
if (!video || video.seekable.length === 0) return;
|
|
5405
|
-
video.currentTime = video.seekable.end(video.seekable.length - 1);
|
|
5406
|
-
if (video.paused) void video.play();
|
|
5407
|
-
}
|
|
5408
|
-
function toggleFullscreen() {
|
|
5409
|
-
const el = containerRef.current;
|
|
5410
|
-
const video = asWebkitVideo(videoRef.current);
|
|
5411
|
-
if (el && document.fullscreenElement === el) {
|
|
5412
|
-
void document.exitFullscreen();
|
|
5413
|
-
return;
|
|
5414
|
-
}
|
|
5415
|
-
if (video?.webkitDisplayingFullscreen && video.webkitExitFullscreen) {
|
|
5416
|
-
video.webkitExitFullscreen();
|
|
5417
|
-
return;
|
|
5418
|
-
}
|
|
5419
|
-
if (el && hasStandardFullscreen() && typeof el.requestFullscreen === "function") {
|
|
5420
|
-
void el.requestFullscreen();
|
|
5421
|
-
return;
|
|
5422
|
-
}
|
|
5423
|
-
if (video && typeof video.webkitEnterFullscreen === "function") {
|
|
5424
|
-
video.webkitEnterFullscreen();
|
|
5425
|
-
}
|
|
5426
|
-
}
|
|
5427
|
-
function togglePip() {
|
|
5428
|
-
const video = videoRef.current;
|
|
5429
|
-
if (!video) return;
|
|
5430
|
-
if (document.pictureInPictureElement === video) {
|
|
5431
|
-
void document.exitPictureInPicture();
|
|
5432
|
-
} else {
|
|
5433
|
-
void video.requestPictureInPicture?.();
|
|
5434
|
-
}
|
|
5435
|
-
}
|
|
5436
|
-
function changeRate(rate) {
|
|
5437
|
-
const video = videoRef.current;
|
|
5438
|
-
if (video) video.playbackRate = rate;
|
|
5439
|
-
setPlaybackRate(rate);
|
|
5440
|
-
setOpenMenu(null);
|
|
5441
|
-
}
|
|
5442
|
-
function chooseLevel(index) {
|
|
5443
|
-
setLevel(index);
|
|
5444
|
-
setOpenMenu(null);
|
|
5445
|
-
}
|
|
5446
|
-
function handleKeyDown(e) {
|
|
5447
|
-
if (!active) return;
|
|
5448
|
-
switch (e.key) {
|
|
5449
|
-
case " ":
|
|
5450
|
-
case "k":
|
|
5451
|
-
e.preventDefault();
|
|
5452
|
-
togglePlay();
|
|
5453
|
-
break;
|
|
5454
|
-
case "m":
|
|
5455
|
-
toggleMute();
|
|
5456
|
-
break;
|
|
5457
|
-
case "f":
|
|
5458
|
-
toggleFullscreen();
|
|
5459
|
-
break;
|
|
5460
|
-
case "ArrowLeft":
|
|
5461
|
-
if (mode === "vod") {
|
|
5462
|
-
e.preventDefault();
|
|
5463
|
-
seekBy(-SEEK_STEP_S);
|
|
5464
|
-
}
|
|
5465
|
-
break;
|
|
5466
|
-
case "ArrowRight":
|
|
5467
|
-
if (mode === "vod") {
|
|
5468
|
-
e.preventDefault();
|
|
5469
|
-
seekBy(SEEK_STEP_S);
|
|
5470
|
-
}
|
|
5471
|
-
break;
|
|
5472
|
-
case "ArrowUp":
|
|
5473
|
-
e.preventDefault();
|
|
5474
|
-
changeVolume(Math.min((videoRef.current?.volume ?? 1) + 0.1, 1));
|
|
5475
|
-
break;
|
|
5476
|
-
case "ArrowDown":
|
|
5477
|
-
e.preventDefault();
|
|
5478
|
-
changeVolume(Math.max((videoRef.current?.volume ?? 0) - 0.1, 0));
|
|
5479
|
-
break;
|
|
5480
|
-
}
|
|
5481
|
-
revealControls();
|
|
5482
|
-
}
|
|
5483
|
-
function errorMessage(err) {
|
|
5484
|
-
switch (err.kind) {
|
|
5485
|
-
case "unavailable":
|
|
5486
|
-
return t.errorUnavailable;
|
|
5487
|
-
case "network":
|
|
5488
|
-
return t.errorNetwork;
|
|
5489
|
-
case "media":
|
|
5490
|
-
return t.errorMedia;
|
|
5491
|
-
case "unsupported":
|
|
5492
|
-
return t.errorUnsupported;
|
|
5493
|
-
case "resync":
|
|
5494
|
-
return t.errorMedia;
|
|
5495
|
-
case "generic":
|
|
5496
|
-
return t.errorGeneric;
|
|
5497
|
-
default: {
|
|
5498
|
-
const _exhaustive = err.kind;
|
|
5499
|
-
return _exhaustive;
|
|
5500
|
-
}
|
|
5501
|
-
}
|
|
5502
|
-
}
|
|
5503
|
-
const VolumeIcon = isMuted || volume === 0 ? lucideReact.VolumeX : volume < 0.5 ? lucideReact.Volume1 : lucideReact.Volume2;
|
|
5504
|
-
const showSpinner = active && (state === "loading" || state === "waiting");
|
|
5505
|
-
const showControls = active && state === "ready" && (controlsVisible || !isPlaying);
|
|
5506
|
-
const showPoster = !active && !!poster;
|
|
5507
|
-
const currentLevelLabel = activeLevel < 0 ? t.auto : `${qualities.find((q) => q.index === activeLevel)?.height ?? ""}p`;
|
|
5508
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5509
|
-
"div",
|
|
5510
|
-
{
|
|
5511
|
-
ref: containerRef,
|
|
5512
|
-
"data-slot": "video-player",
|
|
5513
|
-
"data-mode": mode,
|
|
5514
|
-
"data-fit": fit,
|
|
5515
|
-
className: cn(
|
|
5516
|
-
"group relative w-full overflow-hidden rounded-lg bg-black text-white select-none",
|
|
5517
|
-
fit === "contain" ? "h-full min-h-0 aspect-auto" : "aspect-video",
|
|
5518
|
-
className
|
|
5519
|
-
),
|
|
5520
|
-
onMouseMove: revealControls,
|
|
5521
|
-
onMouseLeave: () => {
|
|
5522
|
-
if (isPlaying) setControlsVisible(false);
|
|
5523
|
-
},
|
|
5524
|
-
onKeyDown: handleKeyDown,
|
|
5525
|
-
tabIndex: 0,
|
|
5526
|
-
role: "region",
|
|
5527
|
-
"aria-label": "Video player",
|
|
5528
|
-
children: [
|
|
5529
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5530
|
-
"video",
|
|
5531
|
-
{
|
|
5532
|
-
ref: videoRef,
|
|
5533
|
-
playsInline: true,
|
|
5534
|
-
className: "h-full w-full bg-black object-contain",
|
|
5535
|
-
onClick: active ? togglePlay : void 0,
|
|
5536
|
-
poster
|
|
5537
|
-
}
|
|
5538
|
-
),
|
|
5539
|
-
showPoster && /* @__PURE__ */ jsxRuntime.jsx(
|
|
5540
|
-
"button",
|
|
5541
|
-
{
|
|
5542
|
-
type: "button",
|
|
5543
|
-
"aria-label": t.play,
|
|
5544
|
-
onClick: () => {
|
|
5545
|
-
setUserStarted(true);
|
|
5546
|
-
revealControls();
|
|
5547
|
-
},
|
|
5548
|
-
className: "absolute inset-0 flex items-center justify-center bg-black bg-contain bg-center bg-no-repeat",
|
|
5549
|
-
style: poster ? { backgroundImage: `url(${poster})` } : void 0,
|
|
5550
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex size-16 items-center justify-center rounded-full bg-black/50 backdrop-blur-sm transition group-hover:bg-black/70", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Play, { className: "size-8 translate-x-0.5", fill: "currentColor" }) })
|
|
5551
|
-
}
|
|
5552
|
-
),
|
|
5553
|
-
showSpinner && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute inset-0 flex flex-col items-center justify-center gap-3 bg-black/50 text-sm", children: [
|
|
5554
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "size-8 animate-spin" }),
|
|
5555
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children: state === "loading" ? t.loading : t.waiting })
|
|
5556
|
-
] }),
|
|
5557
|
-
state === "error" && error && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute inset-0 flex flex-col items-center justify-center gap-4 bg-black/70 px-6 text-center text-sm", children: [
|
|
5558
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertCircle, { className: "text-red-400 size-8" }),
|
|
5559
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-red-200", children: errorMessage(error) }),
|
|
5560
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
5561
|
-
"button",
|
|
5562
|
-
{
|
|
5563
|
-
type: "button",
|
|
5564
|
-
onClick: retry,
|
|
5565
|
-
className: "inline-flex items-center gap-2 rounded-md bg-white/15 px-3 py-1.5 text-sm hover:bg-white/25",
|
|
5566
|
-
children: [
|
|
5567
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.RotateCw, { className: "size-4" }),
|
|
5568
|
-
t.retry
|
|
5569
|
-
]
|
|
5570
|
-
}
|
|
5571
|
-
)
|
|
5572
|
-
] }),
|
|
5573
|
-
state === "ready" && autoplayState === "blocked" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 flex items-center justify-center bg-black/40", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
5574
|
-
"button",
|
|
5575
|
-
{
|
|
5576
|
-
type: "button",
|
|
5577
|
-
"aria-label": t.play,
|
|
5578
|
-
onClick: togglePlay,
|
|
5579
|
-
className: "flex size-16 items-center justify-center rounded-full bg-white/20 backdrop-blur-sm transition hover:bg-white/30",
|
|
5580
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Play, { className: "size-8 translate-x-0.5", fill: "currentColor" })
|
|
5581
|
-
}
|
|
5582
|
-
) }),
|
|
5583
|
-
state === "ready" && autoplayState === "muted" && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5584
|
-
"button",
|
|
5585
|
-
{
|
|
5586
|
-
type: "button",
|
|
5587
|
-
onClick: toggleMute,
|
|
5588
|
-
className: "absolute top-3 right-3 flex items-center gap-1.5 rounded-full bg-black/70 px-3 py-1.5 text-xs backdrop-blur-sm transition hover:bg-black/90",
|
|
5589
|
-
children: [
|
|
5590
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.VolumeX, { className: "size-4" }),
|
|
5591
|
-
t.tapToUnmute
|
|
5592
|
-
]
|
|
5593
|
-
}
|
|
5594
|
-
),
|
|
5595
|
-
mode === "live" && active && state === "ready" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute top-3 left-3 flex items-center gap-2", children: [
|
|
5596
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-1.5 rounded bg-red-600 px-2 py-0.5 text-xs font-semibold tracking-wide", children: [
|
|
5597
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "size-1.5 animate-pulse rounded-full bg-white" }),
|
|
5598
|
-
t.live
|
|
5599
|
-
] }),
|
|
5600
|
-
typeof stats?.viewers === "number" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "rounded bg-black/60 px-2 py-0.5 text-xs", children: t.formatViewers ? t.formatViewers(stats.viewers) : `\u{1F441} ${stats.viewers}` })
|
|
5601
|
-
] }),
|
|
5602
|
-
active && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5603
|
-
"div",
|
|
5604
|
-
{
|
|
5605
|
-
className: cn(
|
|
5606
|
-
"absolute inset-x-0 bottom-0 flex flex-col gap-1 bg-gradient-to-t from-black/80 to-transparent px-3 pt-8 pb-2 transition-opacity",
|
|
5607
|
-
showControls ? "opacity-100" : "pointer-events-none opacity-0"
|
|
5608
|
-
),
|
|
5609
|
-
"data-slot": "video-controls",
|
|
5610
|
-
children: [
|
|
5611
|
-
mode === "vod" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative w-full", children: [
|
|
5612
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5613
|
-
Slider,
|
|
5614
|
-
{
|
|
5615
|
-
"aria-label": "Seek",
|
|
5616
|
-
min: 0,
|
|
5617
|
-
max: duration || 0,
|
|
5618
|
-
step: 0.1,
|
|
5619
|
-
value: [Math.min(currentTime, duration || 0)],
|
|
5620
|
-
onValueChange: (v) => seekTo(v[0] ?? 0),
|
|
5621
|
-
className: "w-full"
|
|
5622
|
-
}
|
|
5623
|
-
),
|
|
5624
|
-
duration > 0 && buffered > currentTime && /* @__PURE__ */ jsxRuntime.jsx(
|
|
5625
|
-
"span",
|
|
5626
|
-
{
|
|
5627
|
-
"aria-hidden": "true",
|
|
5628
|
-
className: "pointer-events-none absolute top-1/2 left-0 h-1.5 -translate-y-1/2 rounded-full bg-white/25",
|
|
5629
|
-
style: {
|
|
5630
|
-
width: `${Math.min(buffered / duration * 100, 100)}%`
|
|
5631
|
-
}
|
|
5632
|
-
}
|
|
5633
|
-
)
|
|
5634
|
-
] }),
|
|
5635
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
5636
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5637
|
-
ControlButton,
|
|
5638
|
-
{
|
|
5639
|
-
label: isPlaying ? t.pause : t.play,
|
|
5640
|
-
onClick: togglePlay,
|
|
5641
|
-
children: isPlaying ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Pause, { className: "size-5", fill: "currentColor" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Play, { className: "size-5", fill: "currentColor" })
|
|
5642
|
-
}
|
|
5643
|
-
),
|
|
5644
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "group/vol flex items-center", children: [
|
|
5645
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5646
|
-
ControlButton,
|
|
5647
|
-
{
|
|
5648
|
-
label: isMuted ? t.unmute : t.mute,
|
|
5649
|
-
onClick: toggleMute,
|
|
5650
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(VolumeIcon, { className: "size-5" })
|
|
5651
|
-
}
|
|
5652
|
-
),
|
|
5653
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-0 overflow-hidden transition-all group-hover/vol:w-20 group-hover/vol:px-1", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
5654
|
-
Slider,
|
|
5655
|
-
{
|
|
5656
|
-
"aria-label": "Volume",
|
|
5657
|
-
min: 0,
|
|
5658
|
-
max: 1,
|
|
5659
|
-
step: 0.05,
|
|
5660
|
-
value: [isMuted ? 0 : volume],
|
|
5661
|
-
onValueChange: (v) => changeVolume(v[0] ?? 0)
|
|
5662
|
-
}
|
|
5663
|
-
) })
|
|
5664
|
-
] }),
|
|
5665
|
-
mode === "vod" && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "ml-1 text-xs tabular-nums", children: [
|
|
5666
|
-
formatTime(currentTime),
|
|
5667
|
-
" / ",
|
|
5668
|
-
formatTime(duration)
|
|
5669
|
-
] }),
|
|
5670
|
-
mode === "live" && behindLive && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5671
|
-
"button",
|
|
5672
|
-
{
|
|
5673
|
-
type: "button",
|
|
5674
|
-
onClick: goToLiveEdge,
|
|
5675
|
-
className: "ml-1 flex items-center gap-1 rounded bg-white/15 px-2 py-0.5 text-xs hover:bg-white/25",
|
|
5676
|
-
children: [
|
|
5677
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "size-1.5 rounded-full bg-red-500" }),
|
|
5678
|
-
t.goLive
|
|
5679
|
-
]
|
|
5680
|
-
}
|
|
5681
|
-
),
|
|
5682
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ml-auto flex items-center gap-1", children: [
|
|
5683
|
-
mode === "vod" && typeof stats?.views === "number" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mr-1 text-xs", children: t.formatViews ? t.formatViews(stats.views) : `${stats.views} views` }),
|
|
5684
|
-
mode === "vod" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
5685
|
-
MenuControl,
|
|
5686
|
-
{
|
|
5687
|
-
label: t.speed,
|
|
5688
|
-
open: openMenu === "speed",
|
|
5689
|
-
onOpenChange: (o) => setOpenMenu(o ? "speed" : null),
|
|
5690
|
-
trigger: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs font-semibold", children: [
|
|
5691
|
-
playbackRate,
|
|
5692
|
-
"\xD7"
|
|
5693
|
-
] }),
|
|
5694
|
-
children: PLAYBACK_RATES.map((rate) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5695
|
-
MenuItem,
|
|
5696
|
-
{
|
|
5697
|
-
selected: rate === playbackRate,
|
|
5698
|
-
onSelect: () => changeRate(rate),
|
|
5699
|
-
children: [
|
|
5700
|
-
rate,
|
|
5701
|
-
"\xD7"
|
|
5702
|
-
]
|
|
5703
|
-
},
|
|
5704
|
-
rate
|
|
5705
|
-
))
|
|
5706
|
-
}
|
|
5707
|
-
),
|
|
5708
|
-
showQualitySelector && qualities.length > 1 && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5709
|
-
MenuControl,
|
|
5710
|
-
{
|
|
5711
|
-
label: t.quality,
|
|
5712
|
-
open: openMenu === "quality",
|
|
5713
|
-
onOpenChange: (o) => setOpenMenu(o ? "quality" : null),
|
|
5714
|
-
trigger: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Settings, { className: "size-5" }),
|
|
5715
|
-
triggerBadge: currentLevelLabel,
|
|
5716
|
-
children: [
|
|
5717
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5718
|
-
MenuItem,
|
|
5719
|
-
{
|
|
5720
|
-
selected: activeLevel < 0,
|
|
5721
|
-
onSelect: () => chooseLevel(-1),
|
|
5722
|
-
children: t.auto
|
|
5723
|
-
}
|
|
5724
|
-
),
|
|
5725
|
-
qualities.map((q) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5726
|
-
MenuItem,
|
|
5727
|
-
{
|
|
5728
|
-
selected: activeLevel === q.index,
|
|
5729
|
-
onSelect: () => chooseLevel(q.index),
|
|
5730
|
-
children: [
|
|
5731
|
-
q.height,
|
|
5732
|
-
"p"
|
|
5733
|
-
]
|
|
5734
|
-
},
|
|
5735
|
-
q.index
|
|
5736
|
-
))
|
|
5737
|
-
]
|
|
5738
|
-
}
|
|
5739
|
-
),
|
|
5740
|
-
pipSupported && /* @__PURE__ */ jsxRuntime.jsx(ControlButton, { label: t.pictureInPicture, onClick: togglePip, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
5741
|
-
lucideReact.PictureInPicture2,
|
|
5742
|
-
{
|
|
5743
|
-
className: cn("size-5", pipActive && "text-primary")
|
|
5744
|
-
}
|
|
5745
|
-
) }),
|
|
5746
|
-
fullscreenSupported && /* @__PURE__ */ jsxRuntime.jsx(
|
|
5747
|
-
ControlButton,
|
|
5748
|
-
{
|
|
5749
|
-
label: isFullscreen ? t.exitFullscreen : t.enterFullscreen,
|
|
5750
|
-
onClick: toggleFullscreen,
|
|
5751
|
-
children: isFullscreen ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Minimize, { className: "size-5" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Maximize, { className: "size-5" })
|
|
5752
|
-
}
|
|
5753
|
-
)
|
|
5754
|
-
] })
|
|
5755
|
-
] })
|
|
5756
|
-
]
|
|
5757
|
-
}
|
|
5758
|
-
)
|
|
5759
|
-
]
|
|
5760
|
-
}
|
|
5761
|
-
);
|
|
5762
|
-
}
|
|
5763
|
-
function ControlButton({
|
|
5764
|
-
label,
|
|
5765
|
-
onClick,
|
|
5766
|
-
children
|
|
5767
|
-
}) {
|
|
5768
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
5769
|
-
"button",
|
|
5770
|
-
{
|
|
5771
|
-
type: "button",
|
|
5772
|
-
"aria-label": label,
|
|
5773
|
-
title: label,
|
|
5774
|
-
onClick,
|
|
5775
|
-
className: "flex size-8 items-center justify-center rounded-md text-white/90 outline-none hover:bg-white/15 hover:text-white focus-visible:ring-2 focus-visible:ring-white/60",
|
|
5776
|
-
children
|
|
5777
|
-
}
|
|
5778
|
-
);
|
|
5779
|
-
}
|
|
5780
|
-
function MenuControl({
|
|
5781
|
-
label,
|
|
5782
|
-
open,
|
|
5783
|
-
onOpenChange,
|
|
5784
|
-
trigger,
|
|
5785
|
-
triggerBadge,
|
|
5786
|
-
children
|
|
5787
|
-
}) {
|
|
5788
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
|
|
5789
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
5790
|
-
"button",
|
|
5791
|
-
{
|
|
5792
|
-
type: "button",
|
|
5793
|
-
"aria-label": label,
|
|
5794
|
-
"aria-haspopup": "menu",
|
|
5795
|
-
"aria-expanded": open,
|
|
5796
|
-
title: label,
|
|
5797
|
-
onClick: () => onOpenChange(!open),
|
|
5798
|
-
className: "flex h-8 items-center gap-1 rounded-md px-1.5 text-white/90 outline-none hover:bg-white/15 hover:text-white focus-visible:ring-2 focus-visible:ring-white/60",
|
|
5799
|
-
children: [
|
|
5800
|
-
trigger,
|
|
5801
|
-
triggerBadge && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-medium", children: triggerBadge })
|
|
5802
|
-
]
|
|
5803
|
-
}
|
|
5804
|
-
),
|
|
5805
|
-
open && /* @__PURE__ */ jsxRuntime.jsx(
|
|
5806
|
-
"div",
|
|
5807
|
-
{
|
|
5808
|
-
role: "menu",
|
|
5809
|
-
className: "absolute right-0 bottom-full z-10 mb-2 min-w-24 rounded-md bg-black/90 p-1 text-sm shadow-lg backdrop-blur-sm",
|
|
5810
|
-
children
|
|
5811
|
-
}
|
|
5812
|
-
)
|
|
5813
|
-
] });
|
|
5814
|
-
}
|
|
5815
|
-
function MenuItem({
|
|
5816
|
-
selected,
|
|
5817
|
-
onSelect,
|
|
5818
|
-
children
|
|
5819
|
-
}) {
|
|
5820
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5821
|
-
"button",
|
|
5822
|
-
{
|
|
5823
|
-
type: "button",
|
|
5824
|
-
role: "menuitemradio",
|
|
5825
|
-
"aria-checked": selected,
|
|
5826
|
-
onClick: onSelect,
|
|
5827
|
-
className: "flex w-full items-center justify-between gap-3 rounded px-2 py-1.5 text-left text-white/90 hover:bg-white/15",
|
|
5828
|
-
children: [
|
|
5829
|
-
children,
|
|
5830
|
-
selected && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "size-4" })
|
|
5831
|
-
]
|
|
5832
|
-
}
|
|
5833
|
-
);
|
|
5834
|
-
}
|
|
5835
|
-
|
|
5836
|
-
// src/components/video/feedPlaybackCoordinator.ts
|
|
5837
|
-
var players = /* @__PURE__ */ new Map();
|
|
5838
|
-
function registerFeedPlayer(id, pause) {
|
|
5839
|
-
players.set(id, pause);
|
|
5840
|
-
return () => {
|
|
5841
|
-
if (players.get(id) === pause) {
|
|
5842
|
-
players.delete(id);
|
|
5843
|
-
}
|
|
5844
|
-
};
|
|
5845
|
-
}
|
|
5846
|
-
function claimFeedPlaying(id) {
|
|
5847
|
-
for (const [otherId, pause] of players) {
|
|
5848
|
-
if (otherId !== id) pause();
|
|
5849
|
-
}
|
|
5850
|
-
}
|
|
5851
|
-
|
|
5852
|
-
// src/components/video/useFeedExclusivePlayback.ts
|
|
5853
|
-
var VISIBILITY_THRESHOLDS = [0, 0.5, 1];
|
|
5854
|
-
var MIN_VISIBLE_RATIO = 0.5;
|
|
5855
|
-
function videoInPictureInPicture(container) {
|
|
5856
|
-
if (typeof document === "undefined" || !container) return false;
|
|
5857
|
-
const pip = document.pictureInPictureElement;
|
|
5858
|
-
if (!pip) return false;
|
|
5859
|
-
return container.contains(pip);
|
|
5860
|
-
}
|
|
5861
|
-
function useFeedExclusivePlayback(playbackId) {
|
|
5862
|
-
const containerRef = React7__namespace.useRef(null);
|
|
5863
|
-
const [forcePaused, setForcePaused] = React7__namespace.useState(false);
|
|
5864
|
-
const requestPause = React7__namespace.useCallback(() => {
|
|
5865
|
-
if (videoInPictureInPicture(containerRef.current)) return;
|
|
5866
|
-
setForcePaused(true);
|
|
5867
|
-
}, []);
|
|
5868
|
-
React7__namespace.useEffect(() => {
|
|
5869
|
-
return registerFeedPlayer(playbackId, requestPause);
|
|
5870
|
-
}, [playbackId, requestPause]);
|
|
5871
|
-
React7__namespace.useEffect(() => {
|
|
5872
|
-
const node = containerRef.current;
|
|
5873
|
-
if (!node || typeof IntersectionObserver === "undefined") return;
|
|
5874
|
-
const observer = new IntersectionObserver(
|
|
5875
|
-
(entries) => {
|
|
5876
|
-
const entry = entries[0];
|
|
5877
|
-
if (!entry) return;
|
|
5878
|
-
if (!entry.isIntersecting || entry.intersectionRatio < MIN_VISIBLE_RATIO) {
|
|
5879
|
-
requestPause();
|
|
5880
|
-
}
|
|
5881
|
-
},
|
|
5882
|
-
{ threshold: [...VISIBILITY_THRESHOLDS] }
|
|
5883
|
-
);
|
|
5884
|
-
observer.observe(node);
|
|
5885
|
-
return () => observer.disconnect();
|
|
5886
|
-
}, [requestPause]);
|
|
5887
|
-
React7__namespace.useEffect(() => {
|
|
5888
|
-
const onVisibility = () => {
|
|
5889
|
-
if (document.hidden) requestPause();
|
|
5890
|
-
};
|
|
5891
|
-
document.addEventListener("visibilitychange", onVisibility);
|
|
5892
|
-
return () => document.removeEventListener("visibilitychange", onVisibility);
|
|
5893
|
-
}, [requestPause]);
|
|
5894
|
-
const onPlayingChange = React7__namespace.useCallback(
|
|
5895
|
-
(playing) => {
|
|
5896
|
-
if (!playing) return;
|
|
5897
|
-
setForcePaused(false);
|
|
5898
|
-
claimFeedPlaying(playbackId);
|
|
5899
|
-
},
|
|
5900
|
-
[playbackId]
|
|
5901
|
-
);
|
|
5902
|
-
return {
|
|
5903
|
-
containerRef,
|
|
5904
|
-
paused: forcePaused,
|
|
5905
|
-
onPlayingChange
|
|
5906
|
-
};
|
|
5907
|
-
}
|
|
5908
|
-
function FeedVideoPlayer({
|
|
5909
|
-
playbackId,
|
|
5910
|
-
onPlayingChange,
|
|
5911
|
-
paused: pausedProp,
|
|
5912
|
-
fit = "aspect-video",
|
|
5913
|
-
className,
|
|
5914
|
-
...playerProps
|
|
5915
|
-
}) {
|
|
5916
|
-
const {
|
|
5917
|
-
containerRef,
|
|
5918
|
-
paused: exclusivePaused,
|
|
5919
|
-
onPlayingChange: onExclusivePlayingChange
|
|
5920
|
-
} = useFeedExclusivePlayback(playbackId);
|
|
5921
|
-
const handlePlayingChange = React7__namespace.useCallback(
|
|
5922
|
-
(playing) => {
|
|
5923
|
-
onExclusivePlayingChange(playing);
|
|
5924
|
-
onPlayingChange?.(playing);
|
|
5925
|
-
},
|
|
5926
|
-
[onExclusivePlayingChange, onPlayingChange]
|
|
5927
|
-
);
|
|
5928
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
5929
|
-
"div",
|
|
5930
|
-
{
|
|
5931
|
-
ref: containerRef,
|
|
5932
|
-
"data-slot": "feed-video-player",
|
|
5933
|
-
className: cn(fit === "contain" && "h-full min-h-0 w-full", className),
|
|
5934
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
5935
|
-
VideoPlayer,
|
|
5936
|
-
{
|
|
5937
|
-
...playerProps,
|
|
5938
|
-
fit,
|
|
5939
|
-
paused: pausedProp || exclusivePaused,
|
|
5940
|
-
onPlayingChange: handlePlayingChange,
|
|
5941
|
-
className: fit === "contain" ? "h-full min-h-0" : void 0
|
|
5942
|
-
}
|
|
5943
|
-
)
|
|
5944
|
-
}
|
|
5945
|
-
);
|
|
5946
|
-
}
|
|
5947
|
-
function usePlaybackStats(statsUrl, { intervalMs = 15e3, enabled = true } = {}) {
|
|
5948
|
-
const [stats, setStats] = React7__namespace.useState({});
|
|
5949
|
-
React7__namespace.useEffect(() => {
|
|
5950
|
-
if (!statsUrl || !enabled) return;
|
|
5951
|
-
let cancelled = false;
|
|
5952
|
-
const controller = new AbortController();
|
|
5953
|
-
async function poll() {
|
|
5954
|
-
try {
|
|
5955
|
-
const res = await fetch(statsUrl, {
|
|
5956
|
-
signal: controller.signal
|
|
5957
|
-
});
|
|
5958
|
-
if (!res.ok) return;
|
|
5959
|
-
const data = await res.json();
|
|
5960
|
-
if (cancelled) return;
|
|
5961
|
-
setStats({
|
|
5962
|
-
viewers: typeof data.viewers === "number" ? data.viewers : void 0,
|
|
5963
|
-
views: typeof data.views === "number" ? data.views : void 0
|
|
5964
|
-
});
|
|
5965
|
-
} catch {
|
|
5966
|
-
}
|
|
5967
|
-
}
|
|
5968
|
-
void poll();
|
|
5969
|
-
const timer = setInterval(() => void poll(), intervalMs);
|
|
5970
|
-
return () => {
|
|
5971
|
-
cancelled = true;
|
|
5972
|
-
controller.abort();
|
|
5973
|
-
clearInterval(timer);
|
|
5974
|
-
};
|
|
5975
|
-
}, [statsUrl, intervalMs, enabled]);
|
|
5976
|
-
return stats;
|
|
5977
|
-
}
|
|
5978
4682
|
function useDebouncedValue(value, delayMs) {
|
|
5979
|
-
const [debounced, setDebounced] =
|
|
5980
|
-
|
|
4683
|
+
const [debounced, setDebounced] = React2.useState(value);
|
|
4684
|
+
React2.useEffect(() => {
|
|
5981
4685
|
const id = window.setTimeout(() => setDebounced(value), delayMs);
|
|
5982
4686
|
return () => window.clearTimeout(id);
|
|
5983
4687
|
}, [value, delayMs]);
|
|
5984
4688
|
return debounced;
|
|
5985
4689
|
}
|
|
5986
4690
|
function useDebouncedValueStrict(value, delayMs) {
|
|
5987
|
-
const [debounced, setDebounced] =
|
|
5988
|
-
|
|
4691
|
+
const [debounced, setDebounced] = React2.useState(void 0);
|
|
4692
|
+
React2.useEffect(() => {
|
|
5989
4693
|
setDebounced(void 0);
|
|
5990
4694
|
const id = window.setTimeout(() => setDebounced(value), delayMs);
|
|
5991
4695
|
return () => window.clearTimeout(id);
|
|
@@ -5993,8 +4697,8 @@ function useDebouncedValueStrict(value, delayMs) {
|
|
|
5993
4697
|
return debounced;
|
|
5994
4698
|
}
|
|
5995
4699
|
function useMediaQuery2(query) {
|
|
5996
|
-
const [matches, setMatches] =
|
|
5997
|
-
|
|
4700
|
+
const [matches, setMatches] = React2.useState(false);
|
|
4701
|
+
React2.useEffect(() => {
|
|
5998
4702
|
if (typeof window === "undefined" || !window.matchMedia) return;
|
|
5999
4703
|
const mql = window.matchMedia(query);
|
|
6000
4704
|
const onChange = () => setMatches(mql.matches);
|
|
@@ -6006,9 +4710,9 @@ function useMediaQuery2(query) {
|
|
|
6006
4710
|
}
|
|
6007
4711
|
function useSearchHotkey(options = {}) {
|
|
6008
4712
|
const { defaultOpen = false, disabled = false } = options;
|
|
6009
|
-
const [open, setOpen] =
|
|
6010
|
-
const toggle =
|
|
6011
|
-
|
|
4713
|
+
const [open, setOpen] = React2.useState(defaultOpen);
|
|
4714
|
+
const toggle = React2.useCallback(() => setOpen((prev) => !prev), []);
|
|
4715
|
+
React2.useEffect(() => {
|
|
6012
4716
|
if (disabled) return;
|
|
6013
4717
|
function handleKeyDown(event) {
|
|
6014
4718
|
if (event.key.toLowerCase() !== "k") return;
|
|
@@ -6202,9 +4906,9 @@ function getScrollHeight(container) {
|
|
|
6202
4906
|
}
|
|
6203
4907
|
var DEFAULT_ANCHOR_ATTRIBUTE = "data-scroll-anchor";
|
|
6204
4908
|
var STABILIZE_MS = 600;
|
|
6205
|
-
var ScrollRestorationContext =
|
|
4909
|
+
var ScrollRestorationContext = React2.createContext(null);
|
|
6206
4910
|
function useScrollRestorationContext() {
|
|
6207
|
-
return
|
|
4911
|
+
return React2.useContext(ScrollRestorationContext);
|
|
6208
4912
|
}
|
|
6209
4913
|
function readContainer(containerRef) {
|
|
6210
4914
|
return containerRef?.current ?? null;
|
|
@@ -6216,7 +4920,7 @@ function ScrollRestorationProvider({
|
|
|
6216
4920
|
children
|
|
6217
4921
|
}) {
|
|
6218
4922
|
ensurePopstateListener();
|
|
6219
|
-
const traversalForRouteRef =
|
|
4923
|
+
const traversalForRouteRef = React2.useRef({ routeKey: "", isTraversal: false });
|
|
6220
4924
|
if (traversalForRouteRef.current.routeKey !== routeKey) {
|
|
6221
4925
|
traversalForRouteRef.current = {
|
|
6222
4926
|
routeKey,
|
|
@@ -6224,7 +4928,7 @@ function ScrollRestorationProvider({
|
|
|
6224
4928
|
};
|
|
6225
4929
|
}
|
|
6226
4930
|
const isTraversal = traversalForRouteRef.current.isTraversal;
|
|
6227
|
-
const value =
|
|
4931
|
+
const value = React2.useMemo(
|
|
6228
4932
|
() => ({
|
|
6229
4933
|
routeKey,
|
|
6230
4934
|
isTraversal,
|
|
@@ -6232,7 +4936,7 @@ function ScrollRestorationProvider({
|
|
|
6232
4936
|
}),
|
|
6233
4937
|
[routeKey, isTraversal, anchorAttribute]
|
|
6234
4938
|
);
|
|
6235
|
-
|
|
4939
|
+
React2.useEffect(() => {
|
|
6236
4940
|
if (typeof window === "undefined" || !("scrollRestoration" in history)) {
|
|
6237
4941
|
return;
|
|
6238
4942
|
}
|
|
@@ -6242,10 +4946,10 @@ function ScrollRestorationProvider({
|
|
|
6242
4946
|
history.scrollRestoration = previous;
|
|
6243
4947
|
};
|
|
6244
4948
|
}, []);
|
|
6245
|
-
const prevRouteKeyRef =
|
|
6246
|
-
const anchorAttributeRef =
|
|
4949
|
+
const prevRouteKeyRef = React2.useRef(routeKey);
|
|
4950
|
+
const anchorAttributeRef = React2.useRef(anchorAttribute);
|
|
6247
4951
|
anchorAttributeRef.current = anchorAttribute;
|
|
6248
|
-
|
|
4952
|
+
React2.useEffect(() => {
|
|
6249
4953
|
const container = readContainer(containerRef);
|
|
6250
4954
|
const target = container ?? window;
|
|
6251
4955
|
let rafId = 0;
|
|
@@ -6265,7 +4969,7 @@ function ScrollRestorationProvider({
|
|
|
6265
4969
|
if (rafId) cancelAnimationFrame(rafId);
|
|
6266
4970
|
};
|
|
6267
4971
|
}, [routeKey, containerRef, anchorAttribute]);
|
|
6268
|
-
|
|
4972
|
+
React2.useLayoutEffect(() => {
|
|
6269
4973
|
const container = readContainer(containerRef);
|
|
6270
4974
|
const prevKey = prevRouteKeyRef.current;
|
|
6271
4975
|
if (prevKey !== routeKey) {
|
|
@@ -6342,14 +5046,14 @@ function startStabilizationLoop(container, mark, attribute) {
|
|
|
6342
5046
|
// src/hooks/useRestorableState.ts
|
|
6343
5047
|
function useRestorableState(subKey, initializer) {
|
|
6344
5048
|
const ctx = useScrollRestorationContext();
|
|
6345
|
-
const [state, setState] =
|
|
5049
|
+
const [state, setState] = React2.useState(() => {
|
|
6346
5050
|
if (!ctx) return initializer();
|
|
6347
5051
|
const traversal = ctx.isTraversal || isPendingTraversal(ctx.routeKey);
|
|
6348
5052
|
if (!traversal) return initializer();
|
|
6349
5053
|
const snap = getSnapshot(ctx.routeKey, subKey);
|
|
6350
5054
|
return snap !== void 0 ? snap : initializer();
|
|
6351
5055
|
});
|
|
6352
|
-
|
|
5056
|
+
React2.useEffect(() => {
|
|
6353
5057
|
if (!ctx) return;
|
|
6354
5058
|
setSnapshot(ctx.routeKey, subKey, state);
|
|
6355
5059
|
}, [ctx, subKey, state]);
|
|
@@ -6757,26 +5461,26 @@ function SearchablePicker(props) {
|
|
|
6757
5461
|
const labels = { ...defaultLabels4, ...userLabels };
|
|
6758
5462
|
const resolvedEmptyLabel = emptyLabel ?? labels.emptyOption;
|
|
6759
5463
|
const isMobile = useMediaQuery2("(max-width: 767px)");
|
|
6760
|
-
const generatedId =
|
|
5464
|
+
const generatedId = React2.useId();
|
|
6761
5465
|
const triggerId = id ?? generatedId;
|
|
6762
|
-
const [uncontrolledOpen, setUncontrolledOpen] =
|
|
5466
|
+
const [uncontrolledOpen, setUncontrolledOpen] = React2.useState(false);
|
|
6763
5467
|
const open = openProp ?? uncontrolledOpen;
|
|
6764
|
-
const setOpen =
|
|
5468
|
+
const setOpen = React2.useCallback(
|
|
6765
5469
|
(next) => {
|
|
6766
5470
|
onOpenChange?.(next);
|
|
6767
5471
|
if (openProp === void 0) setUncontrolledOpen(next);
|
|
6768
5472
|
},
|
|
6769
5473
|
[onOpenChange, openProp]
|
|
6770
5474
|
);
|
|
6771
|
-
const [query, setQuery] =
|
|
6772
|
-
const [remoteItems, setRemoteItems] =
|
|
6773
|
-
const [isLoading, setIsLoading] =
|
|
6774
|
-
const [hasError, setHasError] =
|
|
6775
|
-
const [isLoadingMore, setIsLoadingMore] =
|
|
5475
|
+
const [query, setQuery] = React2.useState("");
|
|
5476
|
+
const [remoteItems, setRemoteItems] = React2.useState([]);
|
|
5477
|
+
const [isLoading, setIsLoading] = React2.useState(false);
|
|
5478
|
+
const [hasError, setHasError] = React2.useState(false);
|
|
5479
|
+
const [isLoadingMore, setIsLoadingMore] = React2.useState(false);
|
|
6776
5480
|
const debouncedQuery = useDebouncedValue(query, debounceMs);
|
|
6777
|
-
const requestIdRef =
|
|
6778
|
-
const knownItemsRef =
|
|
6779
|
-
const rememberItems =
|
|
5481
|
+
const requestIdRef = React2.useRef(0);
|
|
5482
|
+
const knownItemsRef = React2.useRef(/* @__PURE__ */ new Map());
|
|
5483
|
+
const rememberItems = React2.useCallback(
|
|
6780
5484
|
(items) => {
|
|
6781
5485
|
for (const item of items) {
|
|
6782
5486
|
knownItemsRef.current.set(getOptionValue(item), item);
|
|
@@ -6784,12 +5488,12 @@ function SearchablePicker(props) {
|
|
|
6784
5488
|
},
|
|
6785
5489
|
[getOptionValue]
|
|
6786
5490
|
);
|
|
6787
|
-
|
|
5491
|
+
React2.useEffect(() => {
|
|
6788
5492
|
if (options) rememberItems(options);
|
|
6789
5493
|
if (pinned?.recommended) rememberItems(pinned.recommended);
|
|
6790
5494
|
if (pinned?.recent) rememberItems(pinned.recent);
|
|
6791
5495
|
}, [options, pinned, rememberItems]);
|
|
6792
|
-
|
|
5496
|
+
React2.useEffect(() => {
|
|
6793
5497
|
if (!open) {
|
|
6794
5498
|
setQuery("");
|
|
6795
5499
|
setRemoteItems([]);
|
|
@@ -6799,7 +5503,7 @@ function SearchablePicker(props) {
|
|
|
6799
5503
|
}, [open]);
|
|
6800
5504
|
const trimmedDebounced = debouncedQuery.trim();
|
|
6801
5505
|
const shouldFetch = Boolean(fetchOptions) && open && trimmedDebounced.length >= minQueryLength && (trimmedDebounced.length > 0 || !options);
|
|
6802
|
-
|
|
5506
|
+
React2.useEffect(() => {
|
|
6803
5507
|
if (!shouldFetch || !fetchOptions) {
|
|
6804
5508
|
if (!trimmedDebounced) {
|
|
6805
5509
|
setRemoteItems([]);
|
|
@@ -6824,7 +5528,7 @@ function SearchablePicker(props) {
|
|
|
6824
5528
|
setIsLoading(false);
|
|
6825
5529
|
});
|
|
6826
5530
|
}, [shouldFetch, fetchOptions, trimmedDebounced, rememberItems]);
|
|
6827
|
-
const selectedValues =
|
|
5531
|
+
const selectedValues = React2.useMemo(() => {
|
|
6828
5532
|
if (mode === "multiple") {
|
|
6829
5533
|
const multiValue = props.value ?? [];
|
|
6830
5534
|
return new Set(multiValue);
|
|
@@ -6833,12 +5537,12 @@ function SearchablePicker(props) {
|
|
|
6833
5537
|
return singleValue ? /* @__PURE__ */ new Set([singleValue]) : /* @__PURE__ */ new Set();
|
|
6834
5538
|
}, [mode, props]);
|
|
6835
5539
|
const selectedValueKey = mode === "multiple" ? (props.value ?? []).join("\0") : props.value ?? "";
|
|
6836
|
-
const selectedItems =
|
|
5540
|
+
const selectedItems = React2.useMemo(() => {
|
|
6837
5541
|
const values = mode === "multiple" ? selectedValueKey ? selectedValueKey.split("\0") : [] : selectedValueKey ? [selectedValueKey] : [];
|
|
6838
5542
|
return values.map((value) => knownItemsRef.current.get(value)).filter((item) => item !== void 0);
|
|
6839
5543
|
}, [mode, selectedValueKey, options, pinned, remoteItems]);
|
|
6840
5544
|
const queryForFilter = query.trim();
|
|
6841
|
-
const recommended =
|
|
5545
|
+
const recommended = React2.useMemo(() => {
|
|
6842
5546
|
if (queryForFilter) return [];
|
|
6843
5547
|
const pinnedValues = /* @__PURE__ */ new Set();
|
|
6844
5548
|
const items = dedupeByValue(
|
|
@@ -6847,7 +5551,7 @@ function SearchablePicker(props) {
|
|
|
6847
5551
|
for (const entry of items) pinnedValues.add(entry.value);
|
|
6848
5552
|
return items;
|
|
6849
5553
|
}, [queryForFilter, pinned?.recommended, getOptionValue, getOptionLabel]);
|
|
6850
|
-
const recent =
|
|
5554
|
+
const recent = React2.useMemo(() => {
|
|
6851
5555
|
if (queryForFilter) return [];
|
|
6852
5556
|
const exclude = new Set(recommended.map((e) => e.value));
|
|
6853
5557
|
return dedupeByValue(
|
|
@@ -6861,13 +5565,13 @@ function SearchablePicker(props) {
|
|
|
6861
5565
|
getOptionValue,
|
|
6862
5566
|
getOptionLabel
|
|
6863
5567
|
]);
|
|
6864
|
-
const pinnedValueSet =
|
|
5568
|
+
const pinnedValueSet = React2.useMemo(() => {
|
|
6865
5569
|
const set = /* @__PURE__ */ new Set();
|
|
6866
5570
|
for (const entry of recommended) set.add(entry.value);
|
|
6867
5571
|
for (const entry of recent) set.add(entry.value);
|
|
6868
5572
|
return set;
|
|
6869
5573
|
}, [recommended, recent]);
|
|
6870
|
-
const results =
|
|
5574
|
+
const results = React2.useMemo(() => {
|
|
6871
5575
|
const usingRemote = Boolean(fetchOptions) && trimmedDebounced.length >= minQueryLength && (trimmedDebounced.length > 0 || !options);
|
|
6872
5576
|
if (usingRemote) {
|
|
6873
5577
|
return dedupeByValue(
|
|
@@ -6893,7 +5597,7 @@ function SearchablePicker(props) {
|
|
|
6893
5597
|
pinnedValueSet
|
|
6894
5598
|
]);
|
|
6895
5599
|
const closeOnSelect = keepOpenOnSelect !== void 0 ? !keepOpenOnSelect : mode === "single";
|
|
6896
|
-
const handleSelectEmpty =
|
|
5600
|
+
const handleSelectEmpty = React2.useCallback(() => {
|
|
6897
5601
|
if (mode === "single") {
|
|
6898
5602
|
props.onValueChange?.(
|
|
6899
5603
|
null
|
|
@@ -6901,7 +5605,7 @@ function SearchablePicker(props) {
|
|
|
6901
5605
|
}
|
|
6902
5606
|
if (closeOnSelect) setOpen(false);
|
|
6903
5607
|
}, [mode, props, closeOnSelect, setOpen]);
|
|
6904
|
-
const handleSelectItem =
|
|
5608
|
+
const handleSelectItem = React2.useCallback(
|
|
6905
5609
|
(value) => {
|
|
6906
5610
|
if (mode === "multiple") {
|
|
6907
5611
|
const current = props.value ?? [];
|
|
@@ -6924,7 +5628,7 @@ function SearchablePicker(props) {
|
|
|
6924
5628
|
},
|
|
6925
5629
|
[mode, props, maxSelected, closeOnSelect, setOpen]
|
|
6926
5630
|
);
|
|
6927
|
-
const handleClear =
|
|
5631
|
+
const handleClear = React2.useCallback(
|
|
6928
5632
|
(event) => {
|
|
6929
5633
|
event.preventDefault();
|
|
6930
5634
|
event.stopPropagation();
|
|
@@ -6938,7 +5642,7 @@ function SearchablePicker(props) {
|
|
|
6938
5642
|
},
|
|
6939
5643
|
[mode, props]
|
|
6940
5644
|
);
|
|
6941
|
-
const handleLoadMore =
|
|
5645
|
+
const handleLoadMore = React2.useCallback(async () => {
|
|
6942
5646
|
if (!onLoadMore || isLoadingMore) return;
|
|
6943
5647
|
setIsLoadingMore(true);
|
|
6944
5648
|
try {
|
|
@@ -6947,7 +5651,7 @@ function SearchablePicker(props) {
|
|
|
6947
5651
|
setIsLoadingMore(false);
|
|
6948
5652
|
}
|
|
6949
5653
|
}, [onLoadMore, isLoadingMore]);
|
|
6950
|
-
const triggerLabel =
|
|
5654
|
+
const triggerLabel = React2.useMemo(() => {
|
|
6951
5655
|
if (renderValue) {
|
|
6952
5656
|
if (mode === "multiple") {
|
|
6953
5657
|
return renderValue(selectedItems);
|
|
@@ -7129,20 +5833,20 @@ function SearchCommand({
|
|
|
7129
5833
|
className
|
|
7130
5834
|
}) {
|
|
7131
5835
|
const labels = { ...defaultLabels5, ...userLabels };
|
|
7132
|
-
const [query, setQuery] =
|
|
7133
|
-
const [hits, setHits] =
|
|
7134
|
-
const [isLoading, setIsLoading] =
|
|
7135
|
-
const [hasError, setHasError] =
|
|
5836
|
+
const [query, setQuery] = React2.useState("");
|
|
5837
|
+
const [hits, setHits] = React2.useState([]);
|
|
5838
|
+
const [isLoading, setIsLoading] = React2.useState(false);
|
|
5839
|
+
const [hasError, setHasError] = React2.useState(false);
|
|
7136
5840
|
const debouncedQuery = useDebouncedValue(query, debounceMs);
|
|
7137
|
-
const requestIdRef =
|
|
7138
|
-
|
|
5841
|
+
const requestIdRef = React2.useRef(0);
|
|
5842
|
+
React2.useEffect(() => {
|
|
7139
5843
|
if (!open) {
|
|
7140
5844
|
setQuery("");
|
|
7141
5845
|
setHits([]);
|
|
7142
5846
|
setHasError(false);
|
|
7143
5847
|
}
|
|
7144
5848
|
}, [open]);
|
|
7145
|
-
|
|
5849
|
+
React2.useEffect(() => {
|
|
7146
5850
|
const trimmed = debouncedQuery.trim();
|
|
7147
5851
|
if (trimmed.length < minQueryLength) {
|
|
7148
5852
|
setHits([]);
|
|
@@ -7165,13 +5869,13 @@ function SearchCommand({
|
|
|
7165
5869
|
setIsLoading(false);
|
|
7166
5870
|
});
|
|
7167
5871
|
}, [debouncedQuery, minQueryLength, fetchResults]);
|
|
7168
|
-
const filteredFeatures =
|
|
5872
|
+
const filteredFeatures = React2.useMemo(() => {
|
|
7169
5873
|
if (!query.trim()) return features;
|
|
7170
5874
|
return features.filter(
|
|
7171
5875
|
(feature) => fuzzyMatch(query, feature.label) || feature.keywords?.some((keyword) => fuzzyMatch(query, keyword))
|
|
7172
5876
|
);
|
|
7173
5877
|
}, [features, query]);
|
|
7174
|
-
const groupedHits =
|
|
5878
|
+
const groupedHits = React2.useMemo(() => groupHitsByType(hits), [hits]);
|
|
7175
5879
|
function handleSelect(selection) {
|
|
7176
5880
|
onSelect(selection);
|
|
7177
5881
|
onOpenChange(false);
|
|
@@ -7305,7 +6009,7 @@ function ScrollBar({
|
|
|
7305
6009
|
);
|
|
7306
6010
|
}
|
|
7307
6011
|
var phoneInputGroupClass = "flex h-9 w-full gap-0 overflow-hidden rounded-md border border-input bg-transparent shadow-xs transition-[color,box-shadow] [--PhoneInputCountrySelect-marginRight:0] focus-within:border-ring focus-within:ring-[3px] focus-within:ring-ring/50 dark:bg-input/30 [&_.PhoneInputCountry]:mr-0";
|
|
7308
|
-
var PhoneInput =
|
|
6012
|
+
var PhoneInput = React2__namespace.forwardRef(
|
|
7309
6013
|
({ className, onChange, value, defaultCountry = "MX", ...props }, ref) => {
|
|
7310
6014
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
7311
6015
|
RPNInput__namespace.default,
|
|
@@ -7325,7 +6029,7 @@ var PhoneInput = React7__namespace.forwardRef(
|
|
|
7325
6029
|
}
|
|
7326
6030
|
);
|
|
7327
6031
|
PhoneInput.displayName = "PhoneInput";
|
|
7328
|
-
var InputComponent =
|
|
6032
|
+
var InputComponent = React2__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
7329
6033
|
Input,
|
|
7330
6034
|
{
|
|
7331
6035
|
className: cn(
|
|
@@ -7343,9 +6047,9 @@ var CountrySelect = ({
|
|
|
7343
6047
|
options: countryList,
|
|
7344
6048
|
onChange
|
|
7345
6049
|
}) => {
|
|
7346
|
-
const scrollAreaRef =
|
|
7347
|
-
const [searchValue, setSearchValue] =
|
|
7348
|
-
const [isOpen, setIsOpen] =
|
|
6050
|
+
const scrollAreaRef = React2__namespace.useRef(null);
|
|
6051
|
+
const [searchValue, setSearchValue] = React2__namespace.useState("");
|
|
6052
|
+
const [isOpen, setIsOpen] = React2__namespace.useState(false);
|
|
7349
6053
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
7350
6054
|
Popover,
|
|
7351
6055
|
{
|
|
@@ -7526,8 +6230,8 @@ var MEXICO_STATE_PATHS = {
|
|
|
7526
6230
|
};
|
|
7527
6231
|
function MexicoMap({ selected, onToggle, className }) {
|
|
7528
6232
|
const isInteractive = typeof onToggle === "function";
|
|
7529
|
-
const selectedSet =
|
|
7530
|
-
const handleKeyDown =
|
|
6233
|
+
const selectedSet = React2__namespace.useMemo(() => new Set(selected), [selected]);
|
|
6234
|
+
const handleKeyDown = React2__namespace.useCallback(
|
|
7531
6235
|
(event, id) => {
|
|
7532
6236
|
if (!onToggle) return;
|
|
7533
6237
|
if (event.key === "Enter" || event.key === " ") {
|
|
@@ -8049,7 +6753,7 @@ function PaymentIcon({
|
|
|
8049
6753
|
}
|
|
8050
6754
|
);
|
|
8051
6755
|
}
|
|
8052
|
-
var BrandX =
|
|
6756
|
+
var BrandX = React2.forwardRef(function BrandX2({
|
|
8053
6757
|
className,
|
|
8054
6758
|
size = 24,
|
|
8055
6759
|
"aria-label": ariaLabel,
|
|
@@ -8453,7 +7157,7 @@ function ChatMessageList({
|
|
|
8453
7157
|
/* @__PURE__ */ jsxRuntime.jsx(MessageScrollerButton, {})
|
|
8454
7158
|
] }) });
|
|
8455
7159
|
}
|
|
8456
|
-
var MessageComposer =
|
|
7160
|
+
var MessageComposer = React2__namespace.forwardRef(function MessageComposer2({
|
|
8457
7161
|
className,
|
|
8458
7162
|
locale = "en",
|
|
8459
7163
|
disabled,
|
|
@@ -8483,13 +7187,13 @@ var MessageComposer = React7__namespace.forwardRef(function MessageComposer2({
|
|
|
8483
7187
|
rows = 2,
|
|
8484
7188
|
...props
|
|
8485
7189
|
}, ref) {
|
|
8486
|
-
const formRef =
|
|
8487
|
-
const fieldRef =
|
|
7190
|
+
const formRef = React2__namespace.useRef(null);
|
|
7191
|
+
const fieldRef = React2__namespace.useRef(null);
|
|
8488
7192
|
const handleEmojiSelect = useEmojiInsert(fieldRef, value, onChange);
|
|
8489
7193
|
const pickerDisabled = Boolean(disabled || readOnly);
|
|
8490
7194
|
const draft = value !== void 0 && value !== null ? String(value) : "";
|
|
8491
7195
|
const canSubmit = (allowEmptySubmit || Boolean(draft.trim())) && !sendDisabled && !disabled && !readOnly;
|
|
8492
|
-
const handleSubmit =
|
|
7196
|
+
const handleSubmit = React2__namespace.useCallback(
|
|
8493
7197
|
(event) => {
|
|
8494
7198
|
event.preventDefault();
|
|
8495
7199
|
if (!canSubmit) return;
|
|
@@ -8497,7 +7201,7 @@ var MessageComposer = React7__namespace.forwardRef(function MessageComposer2({
|
|
|
8497
7201
|
},
|
|
8498
7202
|
[canSubmit, onSubmit]
|
|
8499
7203
|
);
|
|
8500
|
-
const handleKeyDown =
|
|
7204
|
+
const handleKeyDown = React2__namespace.useCallback(
|
|
8501
7205
|
(event) => {
|
|
8502
7206
|
onKeyDown?.(event);
|
|
8503
7207
|
if (event.defaultPrevented) return;
|
|
@@ -8587,21 +7291,21 @@ function useSupportConversation({
|
|
|
8587
7291
|
onConversationReady,
|
|
8588
7292
|
onIncomingMessage
|
|
8589
7293
|
}) {
|
|
8590
|
-
const [conversationId, setConversationId] =
|
|
7294
|
+
const [conversationId, setConversationId] = React2.useState(
|
|
8591
7295
|
conversationIdProp
|
|
8592
7296
|
);
|
|
8593
|
-
const [messages, setMessages] =
|
|
8594
|
-
const [loading, setLoading] =
|
|
8595
|
-
const [sending, setSending] =
|
|
8596
|
-
const [error, setError] =
|
|
8597
|
-
const socketRef =
|
|
8598
|
-
const reconnectRef =
|
|
8599
|
-
const closedByUser =
|
|
8600
|
-
const onReadyRef =
|
|
8601
|
-
const onIncomingRef =
|
|
7297
|
+
const [messages, setMessages] = React2.useState([]);
|
|
7298
|
+
const [loading, setLoading] = React2.useState(false);
|
|
7299
|
+
const [sending, setSending] = React2.useState(false);
|
|
7300
|
+
const [error, setError] = React2.useState(null);
|
|
7301
|
+
const socketRef = React2.useRef(null);
|
|
7302
|
+
const reconnectRef = React2.useRef(null);
|
|
7303
|
+
const closedByUser = React2.useRef(false);
|
|
7304
|
+
const onReadyRef = React2.useRef(onConversationReady);
|
|
7305
|
+
const onIncomingRef = React2.useRef(onIncomingMessage);
|
|
8602
7306
|
onReadyRef.current = onConversationReady;
|
|
8603
7307
|
onIncomingRef.current = onIncomingMessage;
|
|
8604
|
-
const load =
|
|
7308
|
+
const load = React2.useCallback(async () => {
|
|
8605
7309
|
if (!enabled) return;
|
|
8606
7310
|
setLoading(true);
|
|
8607
7311
|
setError(null);
|
|
@@ -8627,10 +7331,10 @@ function useSupportConversation({
|
|
|
8627
7331
|
setLoading(false);
|
|
8628
7332
|
}
|
|
8629
7333
|
}, [client, conversationIdProp, enabled, open]);
|
|
8630
|
-
|
|
7334
|
+
React2.useEffect(() => {
|
|
8631
7335
|
void load();
|
|
8632
7336
|
}, [load]);
|
|
8633
|
-
|
|
7337
|
+
React2.useEffect(() => {
|
|
8634
7338
|
closedByUser.current = false;
|
|
8635
7339
|
if (!enabled || !conversationId) return;
|
|
8636
7340
|
let cancelled = false;
|
|
@@ -8676,7 +7380,7 @@ function useSupportConversation({
|
|
|
8676
7380
|
socketRef.current = null;
|
|
8677
7381
|
};
|
|
8678
7382
|
}, [conversationId, enabled, getWsUrl]);
|
|
8679
|
-
const send =
|
|
7383
|
+
const send = React2.useCallback(
|
|
8680
7384
|
async (text) => {
|
|
8681
7385
|
const trimmed = text.trim();
|
|
8682
7386
|
if (!conversationId || !trimmed || sending) return;
|
|
@@ -8708,9 +7412,9 @@ function useSupportConversation({
|
|
|
8708
7412
|
reload: load
|
|
8709
7413
|
};
|
|
8710
7414
|
}
|
|
8711
|
-
var SupportMessengerContext =
|
|
7415
|
+
var SupportMessengerContext = React2.createContext(null);
|
|
8712
7416
|
function useSupportMessenger() {
|
|
8713
|
-
const ctx =
|
|
7417
|
+
const ctx = React2.useContext(SupportMessengerContext);
|
|
8714
7418
|
if (!ctx) {
|
|
8715
7419
|
throw new Error(
|
|
8716
7420
|
"useSupportMessenger must be used within SupportMessengerProvider"
|
|
@@ -8719,7 +7423,7 @@ function useSupportMessenger() {
|
|
|
8719
7423
|
return ctx;
|
|
8720
7424
|
}
|
|
8721
7425
|
function useSupportMessengerOptional() {
|
|
8722
|
-
return
|
|
7426
|
+
return React2.useContext(SupportMessengerContext);
|
|
8723
7427
|
}
|
|
8724
7428
|
function ThreadPanel({
|
|
8725
7429
|
thread,
|
|
@@ -8734,7 +7438,7 @@ function ThreadPanel({
|
|
|
8734
7438
|
onConversationReady,
|
|
8735
7439
|
className
|
|
8736
7440
|
}) {
|
|
8737
|
-
const [draft, setDraft] =
|
|
7441
|
+
const [draft, setDraft] = React2.useState("");
|
|
8738
7442
|
const { messages, loading, sending, error, send } = useSupportConversation({
|
|
8739
7443
|
client,
|
|
8740
7444
|
getWsUrl,
|
|
@@ -8828,9 +7532,9 @@ function ListPanel({
|
|
|
8828
7532
|
searchThreshold,
|
|
8829
7533
|
className
|
|
8830
7534
|
}) {
|
|
8831
|
-
const [query, setQuery] =
|
|
7535
|
+
const [query, setQuery] = React2.useState("");
|
|
8832
7536
|
const showSearch = items.length >= searchThreshold;
|
|
8833
|
-
const filtered =
|
|
7537
|
+
const filtered = React2.useMemo(() => {
|
|
8834
7538
|
const q = query.trim().toLowerCase();
|
|
8835
7539
|
if (!q) return items;
|
|
8836
7540
|
return items.filter(
|
|
@@ -8935,34 +7639,34 @@ function SupportMessengerProvider({
|
|
|
8935
7639
|
className
|
|
8936
7640
|
}) {
|
|
8937
7641
|
const isMobile = useMediaQuery2("(max-width: 767px)");
|
|
8938
|
-
const dockRef =
|
|
8939
|
-
const [listOpen, setListOpen] =
|
|
8940
|
-
const [threads, setThreads] =
|
|
8941
|
-
const [mobileThreadKey, setMobileThreadKey] =
|
|
8942
|
-
const totalUnread =
|
|
7642
|
+
const dockRef = React2.useRef(null);
|
|
7643
|
+
const [listOpen, setListOpen] = React2.useState(false);
|
|
7644
|
+
const [threads, setThreads] = React2.useState([]);
|
|
7645
|
+
const [mobileThreadKey, setMobileThreadKey] = React2.useState(null);
|
|
7646
|
+
const totalUnread = React2.useMemo(
|
|
8943
7647
|
() => items.reduce((sum, item) => sum + (item.unreadCount ?? 0), 0),
|
|
8944
7648
|
[items]
|
|
8945
7649
|
);
|
|
8946
7650
|
const isDesktopOpen = !isMobile && (listOpen || threads.length > 0);
|
|
8947
|
-
|
|
7651
|
+
React2.useEffect(() => {
|
|
8948
7652
|
if (!forceMinimized) return;
|
|
8949
7653
|
setListOpen(false);
|
|
8950
7654
|
setThreads([]);
|
|
8951
7655
|
setMobileThreadKey(null);
|
|
8952
7656
|
}, [forceMinimized]);
|
|
8953
|
-
const openList =
|
|
7657
|
+
const openList = React2.useCallback(() => {
|
|
8954
7658
|
setListOpen(true);
|
|
8955
7659
|
void onRefreshItems?.();
|
|
8956
7660
|
}, [onRefreshItems]);
|
|
8957
|
-
const closeList =
|
|
8958
|
-
const toggleList =
|
|
7661
|
+
const closeList = React2.useCallback(() => setListOpen(false), []);
|
|
7662
|
+
const toggleList = React2.useCallback(() => {
|
|
8959
7663
|
setListOpen((prev) => {
|
|
8960
7664
|
const next = !prev;
|
|
8961
7665
|
if (next) void onRefreshItems?.();
|
|
8962
7666
|
return next;
|
|
8963
7667
|
});
|
|
8964
7668
|
}, [onRefreshItems]);
|
|
8965
|
-
const openThread =
|
|
7669
|
+
const openThread = React2.useCallback((req) => {
|
|
8966
7670
|
setListOpen(false);
|
|
8967
7671
|
setThreads((prev) => {
|
|
8968
7672
|
const existing = prev.find((t) => t.key === req.key);
|
|
@@ -8977,16 +7681,16 @@ function SupportMessengerProvider({
|
|
|
8977
7681
|
});
|
|
8978
7682
|
setMobileThreadKey(req.key);
|
|
8979
7683
|
}, []);
|
|
8980
|
-
const closeThread =
|
|
7684
|
+
const closeThread = React2.useCallback((key) => {
|
|
8981
7685
|
setThreads((prev) => prev.filter((t) => t.key !== key));
|
|
8982
7686
|
setMobileThreadKey((prev) => prev === key ? null : prev);
|
|
8983
7687
|
}, []);
|
|
8984
|
-
const closeAll =
|
|
7688
|
+
const closeAll = React2.useCallback(() => {
|
|
8985
7689
|
setListOpen(false);
|
|
8986
7690
|
setThreads([]);
|
|
8987
7691
|
setMobileThreadKey(null);
|
|
8988
7692
|
}, []);
|
|
8989
|
-
|
|
7693
|
+
React2.useEffect(() => {
|
|
8990
7694
|
if (!isDesktopOpen) return;
|
|
8991
7695
|
function onPointerDown(event) {
|
|
8992
7696
|
const target = event.target;
|
|
@@ -9000,7 +7704,7 @@ function SupportMessengerProvider({
|
|
|
9000
7704
|
document.addEventListener("pointerdown", onPointerDown);
|
|
9001
7705
|
return () => document.removeEventListener("pointerdown", onPointerDown);
|
|
9002
7706
|
}, [isDesktopOpen, closeAll]);
|
|
9003
|
-
const ctx =
|
|
7707
|
+
const ctx = React2.useMemo(
|
|
9004
7708
|
() => ({
|
|
9005
7709
|
listOpen,
|
|
9006
7710
|
openList,
|
|
@@ -9025,7 +7729,7 @@ function SupportMessengerProvider({
|
|
|
9025
7729
|
totalUnread
|
|
9026
7730
|
]
|
|
9027
7731
|
);
|
|
9028
|
-
const handleSelectItem =
|
|
7732
|
+
const handleSelectItem = React2.useCallback(
|
|
9029
7733
|
(item) => {
|
|
9030
7734
|
openThread({
|
|
9031
7735
|
key: item.key,
|
|
@@ -9375,11 +8079,11 @@ function useRealtimeChannel({
|
|
|
9375
8079
|
enabled = true,
|
|
9376
8080
|
reconnectDelayMs = DEFAULT_RECONNECT_MS
|
|
9377
8081
|
}) {
|
|
9378
|
-
const onEventRef =
|
|
8082
|
+
const onEventRef = React2.useRef(onEvent);
|
|
9379
8083
|
onEventRef.current = onEvent;
|
|
9380
|
-
const getWsUrlRef =
|
|
8084
|
+
const getWsUrlRef = React2.useRef(getWsUrl);
|
|
9381
8085
|
getWsUrlRef.current = getWsUrl;
|
|
9382
|
-
|
|
8086
|
+
React2.useEffect(() => {
|
|
9383
8087
|
if (!enabled) return;
|
|
9384
8088
|
let cancelled = false;
|
|
9385
8089
|
let joinedKey = null;
|
|
@@ -9446,7 +8150,6 @@ exports.EmptyState = EmptyState;
|
|
|
9446
8150
|
exports.EmptyTitle = EmptyTitle;
|
|
9447
8151
|
exports.ErrorState = ErrorState;
|
|
9448
8152
|
exports.ExpandableText = ExpandableText;
|
|
9449
|
-
exports.FeedVideoPlayer = FeedVideoPlayer;
|
|
9450
8153
|
exports.FieldMessage = FieldMessage;
|
|
9451
8154
|
exports.ImageLightbox = ImageLightbox;
|
|
9452
8155
|
exports.LanguageContext = LanguageContext;
|
|
@@ -9486,7 +8189,6 @@ exports.SearchablePicker = SearchablePicker;
|
|
|
9486
8189
|
exports.SupportMessengerProvider = SupportMessengerProvider;
|
|
9487
8190
|
exports.ThemeSwitcher = ThemeSwitcher;
|
|
9488
8191
|
exports.VerifiedProfessionalBadge = VerifiedProfessionalBadge;
|
|
9489
|
-
exports.VideoPlayer = VideoPlayer;
|
|
9490
8192
|
exports.ZOOM_PAN_MAX_SCALE = ZOOM_PAN_MAX_SCALE;
|
|
9491
8193
|
exports.ZOOM_PAN_MIN_SCALE = ZOOM_PAN_MIN_SCALE;
|
|
9492
8194
|
exports.ZOOM_PAN_SWIPE_COMMIT_PX = ZOOM_PAN_SWIPE_COMMIT_PX;
|
|
@@ -9494,12 +8196,8 @@ exports.ZOOM_PAN_SWIPE_SNAP_MS = ZOOM_PAN_SWIPE_SNAP_MS;
|
|
|
9494
8196
|
exports.avatarFallbackStyle = avatarFallbackStyle;
|
|
9495
8197
|
exports.bubbleVariants = bubbleVariants;
|
|
9496
8198
|
exports.cn = cn;
|
|
9497
|
-
exports.createLiveHlsConfig = createLiveHlsConfig;
|
|
9498
8199
|
exports.createSupportChatClient = createSupportChatClient;
|
|
9499
|
-
exports.createVodHlsConfig = createVodHlsConfig;
|
|
9500
8200
|
exports.defaultLanguages = defaultLanguages;
|
|
9501
|
-
exports.describeAvResync = describeAvResync;
|
|
9502
|
-
exports.describePlaybackError = describePlaybackError;
|
|
9503
8201
|
exports.formatPaymentCardBrand = formatPaymentCardBrand;
|
|
9504
8202
|
exports.fuzzyMatch = fuzzyMatch;
|
|
9505
8203
|
exports.getAvatarColors = getAvatarColors;
|
|
@@ -9512,15 +8210,11 @@ exports.normalizePaymentCardBrand = normalizePaymentCardBrand;
|
|
|
9512
8210
|
exports.paymentIconBrandFromStripe = paymentIconBrandFromStripe;
|
|
9513
8211
|
exports.paymentTypeFromStripeBrand = paymentTypeFromStripeBrand;
|
|
9514
8212
|
exports.prefersReducedMotion = prefersReducedMotion;
|
|
9515
|
-
exports.shouldRetryLiveEdge404 = shouldRetryLiveEdge404;
|
|
9516
8213
|
exports.useDebouncedValue = useDebouncedValue;
|
|
9517
8214
|
exports.useDebouncedValueStrict = useDebouncedValueStrict;
|
|
9518
8215
|
exports.useEditableSection = useEditableSection;
|
|
9519
|
-
exports.useFeedExclusivePlayback = useFeedExclusivePlayback;
|
|
9520
|
-
exports.useHlsPlayback = useHlsPlayback;
|
|
9521
8216
|
exports.useLanguageContext = useLanguageContext;
|
|
9522
8217
|
exports.useMediaQuery = useMediaQuery2;
|
|
9523
|
-
exports.usePlaybackStats = usePlaybackStats;
|
|
9524
8218
|
exports.useRealtimeChannel = useRealtimeChannel;
|
|
9525
8219
|
exports.useRestorableState = useRestorableState;
|
|
9526
8220
|
exports.useScrollFadeXEdges = useScrollFadeXEdges;
|