@sesionario/blocks 1.9.0 → 1.10.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/dist/index.cjs +137 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +137 -14
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -119,8 +119,8 @@ type ImageLightboxProps = {
|
|
|
119
119
|
};
|
|
120
120
|
/**
|
|
121
121
|
* Fullscreen image gallery viewer. Portal overlay with Esc/click-to-close,
|
|
122
|
-
* arrow-key navigation, wheel/pinch zoom, and pan when zoomed. Locks
|
|
123
|
-
* scroll while mounted.
|
|
122
|
+
* arrow-key / swipe navigation, wheel/pinch zoom, and pan when zoomed. Locks
|
|
123
|
+
* page scroll while mounted.
|
|
124
124
|
*/
|
|
125
125
|
declare function ImageLightbox({ images, index, onIndexChange, onClose, labels, }: ImageLightboxProps): React.ReactPortal;
|
|
126
126
|
|
package/dist/index.d.ts
CHANGED
|
@@ -119,8 +119,8 @@ type ImageLightboxProps = {
|
|
|
119
119
|
};
|
|
120
120
|
/**
|
|
121
121
|
* Fullscreen image gallery viewer. Portal overlay with Esc/click-to-close,
|
|
122
|
-
* arrow-key navigation, wheel/pinch zoom, and pan when zoomed. Locks
|
|
123
|
-
* scroll while mounted.
|
|
122
|
+
* arrow-key / swipe navigation, wheel/pinch zoom, and pan when zoomed. Locks
|
|
123
|
+
* page scroll while mounted.
|
|
124
124
|
*/
|
|
125
125
|
declare function ImageLightbox({ images, index, onIndexChange, onClose, labels, }: ImageLightboxProps): React.ReactPortal;
|
|
126
126
|
|
package/dist/index.js
CHANGED
|
@@ -490,6 +490,9 @@ function ExpandableText({
|
|
|
490
490
|
var MIN_SCALE = 1;
|
|
491
491
|
var MAX_SCALE = 4;
|
|
492
492
|
var DOUBLE_TAP_MS = 300;
|
|
493
|
+
var SWIPE_LOCK_PX = 8;
|
|
494
|
+
var SWIPE_COMMIT_PX = 56;
|
|
495
|
+
var SWIPE_SNAP_MS = 180;
|
|
493
496
|
var IDENTITY = { scale: 1, tx: 0, ty: 0 };
|
|
494
497
|
function clamp(value, min, max) {
|
|
495
498
|
return Math.min(max, Math.max(min, value));
|
|
@@ -507,6 +510,10 @@ function zoomToward(prev, nextScale, originX, originY) {
|
|
|
507
510
|
function pointerDistance(a, b) {
|
|
508
511
|
return Math.hypot(b.x - a.x, b.y - a.y);
|
|
509
512
|
}
|
|
513
|
+
function prefersReducedMotion() {
|
|
514
|
+
if (typeof window === "undefined" || !window.matchMedia) return false;
|
|
515
|
+
return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
516
|
+
}
|
|
510
517
|
function ImageLightbox({
|
|
511
518
|
images,
|
|
512
519
|
index,
|
|
@@ -522,15 +529,24 @@ function ImageLightbox({
|
|
|
522
529
|
const [transform, setTransform] = useState(IDENTITY);
|
|
523
530
|
const transformRef = useRef(transform);
|
|
524
531
|
transformRef.current = transform;
|
|
532
|
+
const [isSwipeDragging, setIsSwipeDragging] = useState(false);
|
|
533
|
+
const [snapBack, setSnapBack] = useState(false);
|
|
525
534
|
const stageRef = useRef(null);
|
|
526
535
|
const pointersRef = useRef(/* @__PURE__ */ new Map());
|
|
527
536
|
const pinchStartRef = useRef(null);
|
|
528
537
|
const panRef = useRef(null);
|
|
538
|
+
const swipeRef = useRef(null);
|
|
529
539
|
const lastTapRef = useRef(
|
|
530
540
|
null
|
|
531
541
|
);
|
|
542
|
+
const indexRef = useRef(index);
|
|
543
|
+
indexRef.current = index;
|
|
544
|
+
const imagesLengthRef = useRef(images.length);
|
|
545
|
+
imagesLengthRef.current = images.length;
|
|
532
546
|
const resetZoom = useCallback(() => {
|
|
533
547
|
setTransform(IDENTITY);
|
|
548
|
+
setIsSwipeDragging(false);
|
|
549
|
+
setSnapBack(false);
|
|
534
550
|
}, []);
|
|
535
551
|
useEffect(() => {
|
|
536
552
|
resetZoom();
|
|
@@ -587,6 +603,10 @@ function ImageLightbox({
|
|
|
587
603
|
stage.addEventListener("wheel", handleWheel, { passive: false });
|
|
588
604
|
return () => stage.removeEventListener("wheel", handleWheel);
|
|
589
605
|
}, [stageOrigin]);
|
|
606
|
+
function clearSwipe() {
|
|
607
|
+
swipeRef.current = null;
|
|
608
|
+
setIsSwipeDragging(false);
|
|
609
|
+
}
|
|
590
610
|
function beginPinch() {
|
|
591
611
|
const pts = [...pointersRef.current.values()];
|
|
592
612
|
const [a, b] = pts;
|
|
@@ -601,13 +621,18 @@ function ImageLightbox({
|
|
|
601
621
|
transform: { ...transformRef.current }
|
|
602
622
|
};
|
|
603
623
|
panRef.current = null;
|
|
624
|
+
clearSwipe();
|
|
625
|
+
setSnapBack(false);
|
|
604
626
|
}
|
|
605
627
|
function onPointerDown(e) {
|
|
606
628
|
e.stopPropagation();
|
|
607
629
|
const stage = stageRef.current;
|
|
608
630
|
if (!stage) return;
|
|
609
|
-
stage.setPointerCapture
|
|
631
|
+
if (typeof stage.setPointerCapture === "function") {
|
|
632
|
+
stage.setPointerCapture(e.pointerId);
|
|
633
|
+
}
|
|
610
634
|
pointersRef.current.set(e.pointerId, { x: e.clientX, y: e.clientY });
|
|
635
|
+
setSnapBack(false);
|
|
611
636
|
if (pointersRef.current.size === 2) {
|
|
612
637
|
beginPinch();
|
|
613
638
|
return;
|
|
@@ -621,6 +646,17 @@ function ImageLightbox({
|
|
|
621
646
|
originTy: transformRef.current.ty,
|
|
622
647
|
moved: false
|
|
623
648
|
};
|
|
649
|
+
return;
|
|
650
|
+
}
|
|
651
|
+
if (hasMultiple) {
|
|
652
|
+
swipeRef.current = {
|
|
653
|
+
pointerId: e.pointerId,
|
|
654
|
+
startX: e.clientX,
|
|
655
|
+
startY: e.clientY,
|
|
656
|
+
moved: false,
|
|
657
|
+
axis: null
|
|
658
|
+
};
|
|
659
|
+
setIsSwipeDragging(true);
|
|
624
660
|
}
|
|
625
661
|
}
|
|
626
662
|
function onPointerMove(e) {
|
|
@@ -645,19 +681,62 @@ function ImageLightbox({
|
|
|
645
681
|
}
|
|
646
682
|
const pan = panRef.current;
|
|
647
683
|
if (pan && pan.pointerId === e.pointerId) {
|
|
648
|
-
const
|
|
649
|
-
const
|
|
650
|
-
if (Math.abs(
|
|
684
|
+
const dx2 = e.clientX - pan.startX;
|
|
685
|
+
const dy2 = e.clientY - pan.startY;
|
|
686
|
+
if (Math.abs(dx2) > 2 || Math.abs(dy2) > 2) pan.moved = true;
|
|
651
687
|
setTransform((prev) => ({
|
|
652
688
|
...prev,
|
|
653
|
-
tx: pan.originTx +
|
|
654
|
-
ty: pan.originTy +
|
|
689
|
+
tx: pan.originTx + dx2,
|
|
690
|
+
ty: pan.originTy + dy2
|
|
655
691
|
}));
|
|
692
|
+
return;
|
|
693
|
+
}
|
|
694
|
+
const swipe = swipeRef.current;
|
|
695
|
+
if (!swipe || swipe.pointerId !== e.pointerId) return;
|
|
696
|
+
const dx = e.clientX - swipe.startX;
|
|
697
|
+
const dy = e.clientY - swipe.startY;
|
|
698
|
+
if (Math.abs(dx) > 2 || Math.abs(dy) > 2) swipe.moved = true;
|
|
699
|
+
if (swipe.axis === null) {
|
|
700
|
+
const absX = Math.abs(dx);
|
|
701
|
+
const absY = Math.abs(dy);
|
|
702
|
+
if (absX < SWIPE_LOCK_PX && absY < SWIPE_LOCK_PX) return;
|
|
703
|
+
swipe.axis = absX >= absY ? "x" : "y";
|
|
704
|
+
if (swipe.axis === "y") {
|
|
705
|
+
clearSwipe();
|
|
706
|
+
setTransform(IDENTITY);
|
|
707
|
+
return;
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
if (swipe.axis === "x") {
|
|
711
|
+
setTransform({ scale: MIN_SCALE, tx: dx, ty: 0 });
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
function finishSwipe(e) {
|
|
715
|
+
const swipe = swipeRef.current;
|
|
716
|
+
if (!swipe || swipe.pointerId !== e.pointerId) return false;
|
|
717
|
+
const dx = e.clientX - swipe.startX;
|
|
718
|
+
const wasMoved = swipe.moved;
|
|
719
|
+
const axis = swipe.axis;
|
|
720
|
+
clearSwipe();
|
|
721
|
+
if (axis === "x" && Math.abs(dx) >= SWIPE_COMMIT_PX) {
|
|
722
|
+
const length = imagesLengthRef.current;
|
|
723
|
+
const current = indexRef.current;
|
|
724
|
+
if (dx < 0) {
|
|
725
|
+
onIndexChange((current + 1) % length);
|
|
726
|
+
} else {
|
|
727
|
+
onIndexChange((current - 1 + length) % length);
|
|
728
|
+
}
|
|
729
|
+
return true;
|
|
730
|
+
}
|
|
731
|
+
if (wasMoved || transformRef.current.tx !== 0) {
|
|
732
|
+
if (!prefersReducedMotion()) setSnapBack(true);
|
|
733
|
+
setTransform(IDENTITY);
|
|
656
734
|
}
|
|
735
|
+
return wasMoved;
|
|
657
736
|
}
|
|
658
737
|
function onPointerUp(e) {
|
|
659
738
|
const stage = stageRef.current;
|
|
660
|
-
if (stage
|
|
739
|
+
if (stage && typeof stage.hasPointerCapture === "function" && stage.hasPointerCapture(e.pointerId) && typeof stage.releasePointerCapture === "function") {
|
|
661
740
|
stage.releasePointerCapture(e.pointerId);
|
|
662
741
|
}
|
|
663
742
|
pointersRef.current.delete(e.pointerId);
|
|
@@ -678,6 +757,8 @@ function ImageLightbox({
|
|
|
678
757
|
};
|
|
679
758
|
}
|
|
680
759
|
}
|
|
760
|
+
const swipeHandled = finishSwipe(e);
|
|
761
|
+
if (swipeHandled) return;
|
|
681
762
|
const pan = panRef.current;
|
|
682
763
|
if (pan && pan.pointerId === e.pointerId) {
|
|
683
764
|
const wasMoved = pan.moved;
|
|
@@ -699,6 +780,7 @@ function ImageLightbox({
|
|
|
699
780
|
e.stopPropagation();
|
|
700
781
|
}
|
|
701
782
|
const { scale, tx, ty } = transform;
|
|
783
|
+
const transition = snapBack && !isSwipeDragging && !prefersReducedMotion() ? `transform ${SWIPE_SNAP_MS}ms ease-out` : void 0;
|
|
702
784
|
return createPortal(
|
|
703
785
|
/* @__PURE__ */ jsxs(
|
|
704
786
|
"div",
|
|
@@ -738,6 +820,7 @@ function ImageLightbox({
|
|
|
738
820
|
ref: stageRef,
|
|
739
821
|
className: "relative flex max-h-full max-w-full touch-none items-center justify-center",
|
|
740
822
|
"data-scale": scale,
|
|
823
|
+
"data-swipe-dragging": isSwipeDragging ? "true" : "false",
|
|
741
824
|
onClick: stopDialogClose,
|
|
742
825
|
onPointerDown,
|
|
743
826
|
onPointerMove,
|
|
@@ -752,8 +835,10 @@ function ImageLightbox({
|
|
|
752
835
|
className: "max-h-[calc(100dvh-2rem)] max-w-full select-none rounded-lg object-contain",
|
|
753
836
|
style: {
|
|
754
837
|
transform: `translate(${tx}px, ${ty}px) scale(${scale})`,
|
|
838
|
+
transition,
|
|
755
839
|
cursor: scale > MIN_SCALE ? "grab" : "default"
|
|
756
|
-
}
|
|
840
|
+
},
|
|
841
|
+
onTransitionEnd: () => setSnapBack(false)
|
|
757
842
|
}
|
|
758
843
|
)
|
|
759
844
|
}
|
|
@@ -3679,6 +3764,19 @@ var PLAYBACK_RATES = [0.75, 1, 1.25, 1.5, 2];
|
|
|
3679
3764
|
var CONTROLS_HIDE_MS = 3e3;
|
|
3680
3765
|
var LIVE_EDGE_THRESHOLD_S = 8;
|
|
3681
3766
|
var SEEK_STEP_S = 5;
|
|
3767
|
+
function asWebkitVideo(video) {
|
|
3768
|
+
return video;
|
|
3769
|
+
}
|
|
3770
|
+
function hasWebkitVideoFullscreen(video) {
|
|
3771
|
+
const webkit = asWebkitVideo(video);
|
|
3772
|
+
return typeof webkit?.webkitEnterFullscreen === "function";
|
|
3773
|
+
}
|
|
3774
|
+
function hasStandardFullscreen() {
|
|
3775
|
+
if (typeof document === "undefined") return false;
|
|
3776
|
+
if (document.fullscreenEnabled) return true;
|
|
3777
|
+
const doc = document;
|
|
3778
|
+
return !!doc.webkitFullscreenEnabled;
|
|
3779
|
+
}
|
|
3682
3780
|
function formatTime(seconds) {
|
|
3683
3781
|
if (!Number.isFinite(seconds) || seconds < 0) return "0:00";
|
|
3684
3782
|
const total = Math.floor(seconds);
|
|
@@ -3752,10 +3850,10 @@ function VideoPlayer({
|
|
|
3752
3850
|
null
|
|
3753
3851
|
);
|
|
3754
3852
|
const [behindLive, setBehindLive] = React6.useState(false);
|
|
3853
|
+
const [webkitFullscreenSupported, setWebkitFullscreenSupported] = React6.useState(false);
|
|
3755
3854
|
const hideTimerRef = React6.useRef(null);
|
|
3756
3855
|
const pipSupported = typeof document !== "undefined" && "pictureInPictureEnabled" in document && document.pictureInPictureEnabled;
|
|
3757
|
-
const fullscreenSupported =
|
|
3758
|
-
"webkitFullscreenEnabled" in document);
|
|
3856
|
+
const fullscreenSupported = hasStandardFullscreen() || webkitFullscreenSupported;
|
|
3759
3857
|
React6.useEffect(() => {
|
|
3760
3858
|
const video = videoRef.current;
|
|
3761
3859
|
if (!video || !active) return;
|
|
@@ -3789,11 +3887,26 @@ function VideoPlayer({
|
|
|
3789
3887
|
video.removeEventListener("ratechange", onRate);
|
|
3790
3888
|
};
|
|
3791
3889
|
}, [videoRef, active, mode]);
|
|
3890
|
+
React6.useEffect(() => {
|
|
3891
|
+
setWebkitFullscreenSupported(hasWebkitVideoFullscreen(videoRef.current));
|
|
3892
|
+
}, [videoRef, active]);
|
|
3792
3893
|
React6.useEffect(() => {
|
|
3793
3894
|
const onFsChange = () => setIsFullscreen(document.fullscreenElement === containerRef.current);
|
|
3794
3895
|
document.addEventListener("fullscreenchange", onFsChange);
|
|
3795
3896
|
return () => document.removeEventListener("fullscreenchange", onFsChange);
|
|
3796
3897
|
}, []);
|
|
3898
|
+
React6.useEffect(() => {
|
|
3899
|
+
const video = asWebkitVideo(videoRef.current);
|
|
3900
|
+
if (!video) return;
|
|
3901
|
+
const onBegin = () => setIsFullscreen(true);
|
|
3902
|
+
const onEnd = () => setIsFullscreen(false);
|
|
3903
|
+
video.addEventListener("webkitbeginfullscreen", onBegin);
|
|
3904
|
+
video.addEventListener("webkitendfullscreen", onEnd);
|
|
3905
|
+
return () => {
|
|
3906
|
+
video.removeEventListener("webkitbeginfullscreen", onBegin);
|
|
3907
|
+
video.removeEventListener("webkitendfullscreen", onEnd);
|
|
3908
|
+
};
|
|
3909
|
+
}, [videoRef, active]);
|
|
3797
3910
|
React6.useEffect(() => {
|
|
3798
3911
|
const video = videoRef.current;
|
|
3799
3912
|
if (!video) return;
|
|
@@ -3858,11 +3971,21 @@ function VideoPlayer({
|
|
|
3858
3971
|
}
|
|
3859
3972
|
function toggleFullscreen() {
|
|
3860
3973
|
const el = containerRef.current;
|
|
3861
|
-
|
|
3862
|
-
if (document.fullscreenElement === el) {
|
|
3974
|
+
const video = asWebkitVideo(videoRef.current);
|
|
3975
|
+
if (el && document.fullscreenElement === el) {
|
|
3863
3976
|
void document.exitFullscreen();
|
|
3864
|
-
|
|
3865
|
-
|
|
3977
|
+
return;
|
|
3978
|
+
}
|
|
3979
|
+
if (video?.webkitDisplayingFullscreen && video.webkitExitFullscreen) {
|
|
3980
|
+
video.webkitExitFullscreen();
|
|
3981
|
+
return;
|
|
3982
|
+
}
|
|
3983
|
+
if (el && hasStandardFullscreen() && typeof el.requestFullscreen === "function") {
|
|
3984
|
+
void el.requestFullscreen();
|
|
3985
|
+
return;
|
|
3986
|
+
}
|
|
3987
|
+
if (video && typeof video.webkitEnterFullscreen === "function") {
|
|
3988
|
+
video.webkitEnterFullscreen();
|
|
3866
3989
|
}
|
|
3867
3990
|
}
|
|
3868
3991
|
function togglePip() {
|