yet-another-react-lightbox 2.6.2 → 3.0.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.
Files changed (129) hide show
  1. package/dist/Lightbox.d.ts +1 -1
  2. package/dist/Lightbox.js +17 -13
  3. package/dist/core/components/IconButton.js +2 -2
  4. package/dist/core/components/ImageSlide.js +0 -3
  5. package/dist/core/config.d.ts +3 -3
  6. package/dist/core/config.js +18 -13
  7. package/dist/core/consts.d.ts +2 -4
  8. package/dist/core/consts.js +2 -4
  9. package/dist/core/contexts/Events.d.ts +3 -2
  10. package/dist/core/contexts/Events.js +3 -3
  11. package/dist/core/contexts/LightboxProps.d.ts +6 -0
  12. package/dist/core/contexts/LightboxProps.js +7 -0
  13. package/dist/core/contexts/LightboxState.d.ts +15 -15
  14. package/dist/core/contexts/LightboxState.js +33 -20
  15. package/dist/core/contexts/Timeouts.d.ts +1 -0
  16. package/dist/core/contexts/Timeouts.js +3 -3
  17. package/dist/core/contexts/index.d.ts +1 -0
  18. package/dist/core/contexts/index.js +1 -0
  19. package/dist/core/hooks/useAnimation.d.ts +4 -1
  20. package/dist/core/hooks/useAnimation.js +12 -3
  21. package/dist/core/hooks/useLoseFocus.js +3 -3
  22. package/dist/core/modules/Carousel.d.ts +1 -1
  23. package/dist/core/modules/Carousel.js +19 -24
  24. package/dist/core/modules/Controller.d.ts +15 -16
  25. package/dist/core/modules/Controller.js +68 -34
  26. package/dist/core/modules/Navigation.d.ts +4 -5
  27. package/dist/core/modules/Navigation.js +15 -12
  28. package/dist/core/modules/Portal.js +5 -4
  29. package/dist/core/modules/Root.d.ts +4 -0
  30. package/dist/core/modules/Root.js +7 -0
  31. package/dist/core/modules/Toolbar.d.ts +0 -6
  32. package/dist/core/modules/Toolbar.js +6 -8
  33. package/dist/core/modules/index.d.ts +1 -1
  34. package/dist/core/modules/index.js +1 -1
  35. package/dist/core/utils.d.ts +7 -10
  36. package/dist/core/utils.js +14 -14
  37. package/dist/plugins/captions/Captions.d.ts +2 -6
  38. package/dist/plugins/captions/Captions.js +17 -20
  39. package/dist/plugins/captions/Description.d.ts +2 -2
  40. package/dist/plugins/captions/Description.js +5 -3
  41. package/dist/plugins/captions/Title.js +2 -3
  42. package/dist/plugins/captions/captions.css +1 -0
  43. package/dist/plugins/captions/index.d.ts +2 -2
  44. package/dist/plugins/captions/props.d.ts +9 -0
  45. package/dist/plugins/captions/props.js +8 -0
  46. package/dist/plugins/captions/utils.d.ts +1 -1
  47. package/dist/plugins/captions/utils.js +1 -3
  48. package/dist/plugins/fullscreen/Fullscreen.d.ts +2 -2
  49. package/dist/plugins/fullscreen/Fullscreen.js +5 -3
  50. package/dist/plugins/fullscreen/FullscreenButton.js +8 -5
  51. package/dist/plugins/fullscreen/FullscreenContext.d.ts +5 -9
  52. package/dist/plugins/fullscreen/FullscreenContext.js +16 -26
  53. package/dist/plugins/fullscreen/index.d.ts +21 -10
  54. package/dist/plugins/fullscreen/props.d.ts +10 -0
  55. package/dist/plugins/fullscreen/props.js +8 -0
  56. package/dist/plugins/inline/Inline.d.ts +2 -2
  57. package/dist/plugins/inline/Inline.js +4 -7
  58. package/dist/plugins/inline/InlineContainer.d.ts +4 -0
  59. package/dist/plugins/inline/InlineContainer.js +5 -0
  60. package/dist/plugins/inline/index.d.ts +1 -1
  61. package/dist/plugins/slideshow/Slideshow.d.ts +2 -6
  62. package/dist/plugins/slideshow/Slideshow.js +7 -10
  63. package/dist/plugins/slideshow/SlideshowButton.js +7 -5
  64. package/dist/plugins/slideshow/SlideshowContext.d.ts +5 -9
  65. package/dist/plugins/slideshow/SlideshowContext.js +21 -12
  66. package/dist/plugins/slideshow/index.d.ts +16 -11
  67. package/dist/plugins/slideshow/props.d.ts +12 -0
  68. package/dist/plugins/slideshow/props.js +9 -0
  69. package/dist/plugins/thumbnails/Thumbnail.d.ts +3 -7
  70. package/dist/plugins/thumbnails/Thumbnail.js +7 -3
  71. package/dist/plugins/thumbnails/Thumbnails.d.ts +2 -13
  72. package/dist/plugins/thumbnails/Thumbnails.js +6 -19
  73. package/dist/plugins/thumbnails/ThumbnailsContainer.d.ts +1 -1
  74. package/dist/plugins/thumbnails/ThumbnailsContainer.js +10 -10
  75. package/dist/plugins/thumbnails/ThumbnailsTrack.d.ts +4 -6
  76. package/dist/plugins/thumbnails/ThumbnailsTrack.js +16 -14
  77. package/dist/plugins/thumbnails/index.d.ts +5 -5
  78. package/dist/plugins/thumbnails/props.d.ts +34 -0
  79. package/dist/plugins/thumbnails/props.js +20 -0
  80. package/dist/plugins/video/Video.d.ts +2 -6
  81. package/dist/plugins/video/Video.js +11 -11
  82. package/dist/plugins/video/VideoSlide.d.ts +1 -1
  83. package/dist/plugins/video/VideoSlide.js +3 -3
  84. package/dist/plugins/video/index.d.ts +39 -42
  85. package/dist/plugins/video/props.d.ts +29 -0
  86. package/dist/plugins/video/props.js +13 -0
  87. package/dist/plugins/zoom/ResponsiveImage.js +23 -15
  88. package/dist/plugins/zoom/Zoom.d.ts +0 -11
  89. package/dist/plugins/zoom/Zoom.js +11 -33
  90. package/dist/plugins/zoom/ZoomButton.d.ts +6 -5
  91. package/dist/plugins/zoom/ZoomButton.js +11 -33
  92. package/dist/plugins/zoom/ZoomButtonsGroup.d.ts +1 -4
  93. package/dist/plugins/zoom/ZoomButtonsGroup.js +6 -7
  94. package/dist/plugins/zoom/ZoomController.d.ts +12 -0
  95. package/dist/plugins/zoom/ZoomController.js +17 -0
  96. package/dist/plugins/zoom/ZoomToolbarControl.d.ts +2 -0
  97. package/dist/plugins/zoom/ZoomToolbarControl.js +12 -0
  98. package/dist/plugins/zoom/ZoomWrapper.d.ts +5 -0
  99. package/dist/plugins/zoom/ZoomWrapper.js +36 -0
  100. package/dist/plugins/zoom/hooks/index.d.ts +6 -0
  101. package/dist/plugins/zoom/hooks/index.js +6 -0
  102. package/dist/plugins/zoom/hooks/useZoomAnimation.d.ts +2 -0
  103. package/dist/plugins/zoom/hooks/useZoomAnimation.js +39 -0
  104. package/dist/plugins/zoom/hooks/useZoomCallback.d.ts +1 -0
  105. package/dist/plugins/zoom/hooks/useZoomCallback.js +12 -0
  106. package/dist/plugins/zoom/hooks/useZoomImageRect.d.ts +5 -0
  107. package/dist/plugins/zoom/hooks/useZoomImageRect.js +41 -0
  108. package/dist/plugins/zoom/hooks/useZoomProps.d.ts +13 -0
  109. package/dist/plugins/zoom/hooks/useZoomProps.js +6 -0
  110. package/dist/plugins/zoom/hooks/useZoomSensors.d.ts +3 -0
  111. package/dist/plugins/zoom/hooks/useZoomSensors.js +154 -0
  112. package/dist/plugins/zoom/hooks/useZoomState.d.ts +12 -0
  113. package/dist/plugins/zoom/hooks/useZoomState.js +63 -0
  114. package/dist/plugins/zoom/index.d.ts +37 -24
  115. package/dist/plugins/zoom/index.js +0 -2
  116. package/dist/plugins/zoom/props.d.ts +25 -0
  117. package/dist/plugins/zoom/props.js +15 -0
  118. package/dist/props.d.ts +0 -4
  119. package/dist/props.js +10 -5
  120. package/dist/types.d.ts +173 -117
  121. package/package.json +41 -11
  122. package/dist/core/modules/Core.d.ts +0 -4
  123. package/dist/core/modules/Core.js +0 -10
  124. package/dist/plugins/captions/CaptionsContext.d.ts +0 -7
  125. package/dist/plugins/captions/CaptionsContext.js +0 -11
  126. package/dist/plugins/zoom/ZoomContainer.d.ts +0 -9
  127. package/dist/plugins/zoom/ZoomContainer.js +0 -316
  128. package/dist/plugins/zoom/ZoomContext.d.ts +0 -11
  129. package/dist/plugins/zoom/ZoomContext.js +0 -20
@@ -0,0 +1,17 @@
1
+ import * as React from "react";
2
+ import { makeUseContext, useController } from "../../core/index.js";
3
+ import { useZoomCallback, useZoomImageRect, useZoomProps, useZoomSensors, useZoomState } from "./hooks/index.js";
4
+ export const ZoomControllerContext = React.createContext(null);
5
+ export const useZoom = makeUseContext("useZoom", "ZoomControllerContext", ZoomControllerContext);
6
+ export function ZoomContextProvider({ children }) {
7
+ const [zoomWrapper, setZoomWrapper] = React.useState();
8
+ const { slideRect } = useController();
9
+ const { imageRect, maxZoom } = useZoomImageRect(slideRect, zoomWrapper === null || zoomWrapper === void 0 ? void 0 : zoomWrapper.imageDimensions);
10
+ const { zoom, offsetX, offsetY, disabled, changeZoom, changeOffsets, zoomIn, zoomOut } = useZoomState(imageRect, maxZoom, zoomWrapper === null || zoomWrapper === void 0 ? void 0 : zoomWrapper.zoomWrapperRef);
11
+ useZoomCallback(zoom, disabled);
12
+ useZoomSensors(zoom, maxZoom, disabled, changeZoom, changeOffsets, zoomWrapper === null || zoomWrapper === void 0 ? void 0 : zoomWrapper.zoomWrapperRef);
13
+ const zoomRef = React.useMemo(() => ({ zoom, maxZoom, offsetX, offsetY, disabled, zoomIn, zoomOut }), [zoom, maxZoom, offsetX, offsetY, disabled, zoomIn, zoomOut]);
14
+ React.useImperativeHandle(useZoomProps().ref, () => zoomRef, [zoomRef]);
15
+ const context = React.useMemo(() => ({ ...zoomRef, setZoomWrapper }), [zoomRef, setZoomWrapper]);
16
+ return React.createElement(ZoomControllerContext.Provider, { value: context }, children);
17
+ }
@@ -0,0 +1,2 @@
1
+ /// <reference types="react" />
2
+ export declare function ZoomToolbarControl(): JSX.Element;
@@ -0,0 +1,12 @@
1
+ import * as React from "react";
2
+ import { useLightboxProps } from "../../core/index.js";
3
+ import ZoomButtonsGroup from "./ZoomButtonsGroup.js";
4
+ import { useZoom } from "./ZoomController.js";
5
+ export function ZoomToolbarControl() {
6
+ const { render } = useLightboxProps();
7
+ const zoomRef = useZoom();
8
+ if (render.buttonZoom) {
9
+ return React.createElement(React.Fragment, null, render.buttonZoom(zoomRef));
10
+ }
11
+ return React.createElement(ZoomButtonsGroup, null);
12
+ }
@@ -0,0 +1,5 @@
1
+ /// <reference types="react" />
2
+ import { LightboxProps, RenderSlideProps } from "../../types.js";
3
+ export type ZoomWrapperProps = Pick<LightboxProps, "render"> & RenderSlideProps;
4
+ /** Zoom wrapper */
5
+ export declare function ZoomWrapper({ render, slide, offset, rect }: ZoomWrapperProps): JSX.Element | null;
@@ -0,0 +1,36 @@
1
+ import * as React from "react";
2
+ import { CLASS_FLEX_CENTER, CLASS_FULLSIZE, clsx, cssClass, ImageSlide, isImageSlide, useLayoutEffect, useLightboxProps, useLightboxState, } from "../../core/index.js";
3
+ import { useZoom } from "./ZoomController.js";
4
+ import { isResponsiveImageSlide, ResponsiveImage } from "./ResponsiveImage.js";
5
+ export function ZoomWrapper({ render, slide, offset, rect }) {
6
+ var _a;
7
+ const [imageDimensions, setImageDimensions] = React.useState();
8
+ const zoomWrapperRef = React.useRef(null);
9
+ const { zoom, maxZoom, offsetX, offsetY, setZoomWrapper } = useZoom();
10
+ const { carousel, on } = useLightboxProps();
11
+ const { currentIndex } = useLightboxState().state;
12
+ useLayoutEffect(() => {
13
+ if (offset === 0) {
14
+ setZoomWrapper({ zoomWrapperRef, imageDimensions });
15
+ return () => setZoomWrapper(undefined);
16
+ }
17
+ return () => { };
18
+ }, [offset, imageDimensions, setZoomWrapper]);
19
+ let rendered = (_a = render.slide) === null || _a === void 0 ? void 0 : _a.call(render, { slide, offset, rect, zoom, maxZoom });
20
+ if (!rendered && isImageSlide(slide)) {
21
+ const slideProps = {
22
+ slide,
23
+ offset,
24
+ rect,
25
+ render,
26
+ imageFit: carousel.imageFit,
27
+ onClick: offset === 0 ? () => { var _a; return (_a = on.click) === null || _a === void 0 ? void 0 : _a.call(on, { index: currentIndex }); } : undefined,
28
+ };
29
+ rendered = isResponsiveImageSlide(slide) ? (React.createElement(ResponsiveImage, { key: slide.src, ...slideProps, slide: slide, rect: offset === 0 ? { width: rect.width * zoom, height: rect.height * zoom } : rect })) : (React.createElement(ImageSlide, { key: slide.src, onLoad: (img) => setImageDimensions({ width: img.naturalWidth, height: img.naturalHeight }), ...slideProps }));
30
+ }
31
+ if (!rendered)
32
+ return null;
33
+ return (React.createElement("div", { ref: zoomWrapperRef, className: clsx(cssClass(CLASS_FULLSIZE), cssClass(CLASS_FLEX_CENTER)), style: offset === 0
34
+ ? { transform: `scale(${zoom}) translateX(${offsetX}px) translateY(${offsetY}px)` }
35
+ : undefined }, rendered));
36
+ }
@@ -0,0 +1,6 @@
1
+ export * from "./useZoomAnimation.js";
2
+ export * from "./useZoomCallback.js";
3
+ export * from "./useZoomImageRect.js";
4
+ export * from "./useZoomProps.js";
5
+ export * from "./useZoomSensors.js";
6
+ export * from "./useZoomState.js";
@@ -0,0 +1,6 @@
1
+ export * from "./useZoomAnimation.js";
2
+ export * from "./useZoomCallback.js";
3
+ export * from "./useZoomImageRect.js";
4
+ export * from "./useZoomProps.js";
5
+ export * from "./useZoomSensors.js";
6
+ export * from "./useZoomState.js";
@@ -0,0 +1,2 @@
1
+ import * as React from "react";
2
+ export declare function useZoomAnimation(zoom: number, offsetX: number, offsetY: number, zoomWrapperRef?: React.RefObject<HTMLDivElement>): () => void;
@@ -0,0 +1,39 @@
1
+ import * as React from "react";
2
+ import { useEventCallback, useLayoutEffect, useLightboxProps, useMotionPreference } from "../../../core/index.js";
3
+ export function useZoomAnimation(zoom, offsetX, offsetY, zoomWrapperRef) {
4
+ const zoomAnimation = React.useRef();
5
+ const zoomAnimationStart = React.useRef();
6
+ const { zoom: zoomAnimationDuration } = useLightboxProps().animation;
7
+ const reduceMotion = useMotionPreference();
8
+ const playZoomAnimation = useEventCallback(() => {
9
+ var _a, _b, _c;
10
+ (_a = zoomAnimation.current) === null || _a === void 0 ? void 0 : _a.cancel();
11
+ zoomAnimation.current = undefined;
12
+ if (zoomAnimationStart.current && (zoomWrapperRef === null || zoomWrapperRef === void 0 ? void 0 : zoomWrapperRef.current)) {
13
+ try {
14
+ zoomAnimation.current = (_c = (_b = zoomWrapperRef.current).animate) === null || _c === void 0 ? void 0 : _c.call(_b, [
15
+ { transform: zoomAnimationStart.current },
16
+ { transform: `scale(${zoom}) translateX(${offsetX}px) translateY(${offsetY}px)` },
17
+ ], {
18
+ duration: !reduceMotion ? zoomAnimationDuration !== null && zoomAnimationDuration !== void 0 ? zoomAnimationDuration : 500 : 0,
19
+ easing: zoomAnimation.current ? "ease-out" : "ease-in-out",
20
+ });
21
+ }
22
+ catch (err) {
23
+ console.error(err);
24
+ }
25
+ zoomAnimationStart.current = undefined;
26
+ if (zoomAnimation.current) {
27
+ zoomAnimation.current.onfinish = () => {
28
+ zoomAnimation.current = undefined;
29
+ };
30
+ }
31
+ }
32
+ });
33
+ useLayoutEffect(playZoomAnimation, [zoom, offsetX, offsetY, playZoomAnimation]);
34
+ return React.useCallback(() => {
35
+ zoomAnimationStart.current = (zoomWrapperRef === null || zoomWrapperRef === void 0 ? void 0 : zoomWrapperRef.current)
36
+ ? window.getComputedStyle(zoomWrapperRef.current).transform
37
+ : undefined;
38
+ }, [zoomWrapperRef]);
39
+ }
@@ -0,0 +1 @@
1
+ export declare function useZoomCallback(zoom: number, disabled: boolean): void;
@@ -0,0 +1,12 @@
1
+ import * as React from "react";
2
+ import { useEventCallback, useLightboxProps } from "../../../core/index.js";
3
+ export function useZoomCallback(zoom, disabled) {
4
+ const { on } = useLightboxProps();
5
+ const onZoomCallback = useEventCallback(() => {
6
+ var _a;
7
+ if (!disabled) {
8
+ (_a = on.zoom) === null || _a === void 0 ? void 0 : _a.call(on, { zoom });
9
+ }
10
+ });
11
+ React.useEffect(onZoomCallback, [zoom, onZoomCallback]);
12
+ }
@@ -0,0 +1,5 @@
1
+ import { ContainerRect } from "../../../types.js";
2
+ export declare function useZoomImageRect(slideRect: ContainerRect, imageDimensions?: ContainerRect): {
3
+ imageRect: ContainerRect;
4
+ maxZoom: number;
5
+ };
@@ -0,0 +1,41 @@
1
+ import { isImageFitCover, isImageSlide, round, useLightboxProps, useLightboxState } from "../../../core/index.js";
2
+ import { useZoomProps } from "./useZoomProps.js";
3
+ export function useZoomImageRect(slideRect, imageDimensions) {
4
+ var _a, _b;
5
+ let imageRect = { width: 0, height: 0 };
6
+ let maxImageRect = { width: 0, height: 0 };
7
+ const { slides, currentIndex } = useLightboxState().state;
8
+ const { imageFit } = useLightboxProps().carousel;
9
+ const { maxZoomPixelRatio } = useZoomProps();
10
+ if (slideRect && currentIndex < slides.length) {
11
+ const slide = { ...slides[currentIndex], ...imageDimensions };
12
+ if (isImageSlide(slide)) {
13
+ const cover = isImageFitCover(slide, imageFit);
14
+ const width = Math.max(...(((_a = slide.srcSet) === null || _a === void 0 ? void 0 : _a.map((x) => x.width)) || []).concat(slide.width ? [slide.width] : []));
15
+ const height = Math.max(...(((_b = slide.srcSet) === null || _b === void 0 ? void 0 : _b.map((x) => x.height)) || []).concat(slide.height ? [slide.height] : []));
16
+ if (width > 0 && height > 0 && slideRect.width > 0 && slideRect.height > 0) {
17
+ maxImageRect = cover
18
+ ? {
19
+ width: Math.round(Math.min(width, (slideRect.width / slideRect.height) * height)),
20
+ height: Math.round(Math.min(height, (slideRect.height / slideRect.width) * width)),
21
+ }
22
+ : { width, height };
23
+ maxImageRect = {
24
+ width: maxImageRect.width * maxZoomPixelRatio,
25
+ height: maxImageRect.height * maxZoomPixelRatio,
26
+ };
27
+ imageRect = cover
28
+ ? {
29
+ width: Math.min(slideRect.width, maxImageRect.width, width),
30
+ height: Math.min(slideRect.height, maxImageRect.height, height),
31
+ }
32
+ : {
33
+ width: Math.round(Math.min(slideRect.width, (slideRect.height / height) * width, width)),
34
+ height: Math.round(Math.min(slideRect.height, (slideRect.width / width) * height, height)),
35
+ };
36
+ }
37
+ }
38
+ }
39
+ const maxZoom = imageRect.width ? Math.max(round(maxImageRect.width / imageRect.width, 5), 1) : 1;
40
+ return { imageRect, maxZoom };
41
+ }
@@ -0,0 +1,13 @@
1
+ /// <reference types="react" />
2
+ export declare function useZoomProps(): {
3
+ ref?: import("react").ForwardedRef<import("../../../types.js").ZoomRef> | undefined;
4
+ maxZoomPixelRatio: number;
5
+ zoomInMultiplier: number;
6
+ doubleTapDelay: number;
7
+ doubleClickDelay: number;
8
+ doubleClickMaxStops: number;
9
+ keyboardMoveDistance: number;
10
+ wheelZoomDistanceFactor: number;
11
+ pinchZoomDistanceFactor: number;
12
+ scrollToZoom: boolean;
13
+ };
@@ -0,0 +1,6 @@
1
+ import { useLightboxProps } from "../../../core/index.js";
2
+ import { resolveZoomProps } from "../props.js";
3
+ export function useZoomProps() {
4
+ const { zoom } = useLightboxProps();
5
+ return resolveZoomProps(zoom);
6
+ }
@@ -0,0 +1,3 @@
1
+ import * as React from "react";
2
+ import { useZoomState } from "./useZoomState.js";
3
+ export declare function useZoomSensors(zoom: number, maxZoom: number, disabled: boolean, changeZoom: ReturnType<typeof useZoomState>["changeZoom"], changeOffsets: ReturnType<typeof useZoomState>["changeOffsets"], zoomWrapperRef?: React.RefObject<HTMLDivElement>): void;
@@ -0,0 +1,154 @@
1
+ import * as React from "react";
2
+ import { cleanup, EVENT_ON_KEY_DOWN, EVENT_ON_POINTER_CANCEL, EVENT_ON_POINTER_DOWN, EVENT_ON_POINTER_LEAVE, EVENT_ON_POINTER_MOVE, EVENT_ON_POINTER_UP, EVENT_ON_WHEEL, useController, useEventCallback, useLightboxState, } from "../../../core/index.js";
3
+ import { useZoomProps } from "./useZoomProps.js";
4
+ function distance(pointerA, pointerB) {
5
+ return ((pointerA.clientX - pointerB.clientX) ** 2 + (pointerA.clientY - pointerB.clientY) ** 2) ** 0.5;
6
+ }
7
+ export function useZoomSensors(zoom, maxZoom, disabled, changeZoom, changeOffsets, zoomWrapperRef) {
8
+ const activePointers = React.useRef([]);
9
+ const lastPointerDown = React.useRef(0);
10
+ const pinchZoomDistance = React.useRef();
11
+ const { globalIndex } = useLightboxState().state;
12
+ const { containerRef, subscribeSensors } = useController();
13
+ const { keyboardMoveDistance, zoomInMultiplier, wheelZoomDistanceFactor, scrollToZoom, doubleTapDelay, doubleClickDelay, doubleClickMaxStops, pinchZoomDistanceFactor, } = useZoomProps();
14
+ const translateCoordinates = React.useCallback((event) => {
15
+ if (containerRef.current) {
16
+ const { pageX, pageY } = event;
17
+ const { scrollX, scrollY } = window;
18
+ const { left, top, width, height } = containerRef.current.getBoundingClientRect();
19
+ return [pageX - left - scrollX - width / 2, pageY - top - scrollY - height / 2];
20
+ }
21
+ return [];
22
+ }, [containerRef]);
23
+ const onKeyDown = useEventCallback((event) => {
24
+ const preventDefault = () => {
25
+ event.preventDefault();
26
+ event.stopPropagation();
27
+ };
28
+ if (zoom > 1) {
29
+ const move = (deltaX, deltaY) => {
30
+ preventDefault();
31
+ changeOffsets(deltaX, deltaY);
32
+ };
33
+ if (event.key === "ArrowDown") {
34
+ move(0, keyboardMoveDistance);
35
+ }
36
+ else if (event.key === "ArrowUp") {
37
+ move(0, -keyboardMoveDistance);
38
+ }
39
+ else if (event.key === "ArrowLeft") {
40
+ move(-keyboardMoveDistance, 0);
41
+ }
42
+ else if (event.key === "ArrowRight") {
43
+ move(keyboardMoveDistance, 0);
44
+ }
45
+ }
46
+ const handleChangeZoom = (zoomValue) => {
47
+ preventDefault();
48
+ changeZoom(zoomValue);
49
+ };
50
+ const hasMeta = () => event.getModifierState("Meta");
51
+ if (event.key === "+" || (event.key === "=" && hasMeta())) {
52
+ handleChangeZoom(zoom * zoomInMultiplier);
53
+ }
54
+ else if (event.key === "-" || (event.key === "_" && hasMeta())) {
55
+ handleChangeZoom(zoom / zoomInMultiplier);
56
+ }
57
+ else if (event.key === "0" && hasMeta()) {
58
+ handleChangeZoom(1);
59
+ }
60
+ });
61
+ const onWheel = useEventCallback((event) => {
62
+ if (event.ctrlKey || scrollToZoom) {
63
+ if (Math.abs(event.deltaY) > Math.abs(event.deltaX)) {
64
+ event.stopPropagation();
65
+ changeZoom(zoom * (1 - event.deltaY / wheelZoomDistanceFactor), true, ...translateCoordinates(event));
66
+ return;
67
+ }
68
+ }
69
+ if (zoom > 1) {
70
+ event.stopPropagation();
71
+ if (!scrollToZoom) {
72
+ changeOffsets(event.deltaX, event.deltaY);
73
+ }
74
+ }
75
+ });
76
+ const clearPointer = React.useCallback((event) => {
77
+ const pointers = activePointers.current;
78
+ pointers.splice(0, pointers.length, ...pointers.filter((p) => p.pointerId !== event.pointerId));
79
+ }, []);
80
+ const replacePointer = React.useCallback((event) => {
81
+ clearPointer(event);
82
+ event.persist();
83
+ activePointers.current.push(event);
84
+ }, [clearPointer]);
85
+ const onPointerDown = useEventCallback((event) => {
86
+ var _a;
87
+ const pointers = activePointers.current;
88
+ if (!((_a = zoomWrapperRef === null || zoomWrapperRef === void 0 ? void 0 : zoomWrapperRef.current) === null || _a === void 0 ? void 0 : _a.contains(event.target))) {
89
+ return;
90
+ }
91
+ if (zoom > 1) {
92
+ event.stopPropagation();
93
+ }
94
+ const { timeStamp } = event;
95
+ if (pointers.length === 0 &&
96
+ timeStamp - lastPointerDown.current < (event.pointerType === "touch" ? doubleTapDelay : doubleClickDelay)) {
97
+ lastPointerDown.current = 0;
98
+ changeZoom(zoom !== maxZoom ? zoom * Math.max(maxZoom ** (1 / doubleClickMaxStops), zoomInMultiplier) : 1, false, ...translateCoordinates(event));
99
+ }
100
+ else {
101
+ lastPointerDown.current = timeStamp;
102
+ }
103
+ replacePointer(event);
104
+ if (pointers.length === 2) {
105
+ pinchZoomDistance.current = distance(pointers[0], pointers[1]);
106
+ }
107
+ });
108
+ const onPointerMove = useEventCallback((event) => {
109
+ const pointers = activePointers.current;
110
+ const activePointer = pointers.find((p) => p.pointerId === event.pointerId);
111
+ if (pointers.length === 2 && pinchZoomDistance.current) {
112
+ event.stopPropagation();
113
+ replacePointer(event);
114
+ const currentDistance = distance(pointers[0], pointers[1]);
115
+ const delta = currentDistance - pinchZoomDistance.current;
116
+ if (Math.abs(delta) > 0) {
117
+ changeZoom(zoom * (1 + delta / pinchZoomDistanceFactor), true, ...pointers
118
+ .map((x) => translateCoordinates(x))
119
+ .reduce((acc, coordinate) => coordinate.map((x, i) => acc[i] + x / 2)));
120
+ pinchZoomDistance.current = currentDistance;
121
+ }
122
+ return;
123
+ }
124
+ if (zoom > 1) {
125
+ event.stopPropagation();
126
+ if (activePointer) {
127
+ if (pointers.length === 1) {
128
+ changeOffsets((activePointer.clientX - event.clientX) / zoom, (activePointer.clientY - event.clientY) / zoom);
129
+ }
130
+ replacePointer(event);
131
+ }
132
+ }
133
+ });
134
+ const onPointerUp = React.useCallback((event) => {
135
+ const pointers = activePointers.current;
136
+ if (pointers.length === 2 && pointers.find((p) => p.pointerId === event.pointerId)) {
137
+ pinchZoomDistance.current = undefined;
138
+ }
139
+ clearPointer(event);
140
+ }, [clearPointer]);
141
+ const cleanupSensors = React.useCallback(() => {
142
+ const pointers = activePointers.current;
143
+ pointers.splice(0, pointers.length);
144
+ lastPointerDown.current = 0;
145
+ pinchZoomDistance.current = undefined;
146
+ }, []);
147
+ React.useEffect(cleanupSensors, [globalIndex, cleanupSensors]);
148
+ React.useEffect(() => {
149
+ if (!disabled) {
150
+ return cleanup(cleanupSensors, subscribeSensors(EVENT_ON_KEY_DOWN, onKeyDown), subscribeSensors(EVENT_ON_WHEEL, onWheel), subscribeSensors(EVENT_ON_POINTER_DOWN, onPointerDown), subscribeSensors(EVENT_ON_POINTER_MOVE, onPointerMove), subscribeSensors(EVENT_ON_POINTER_UP, onPointerUp), subscribeSensors(EVENT_ON_POINTER_LEAVE, onPointerUp), subscribeSensors(EVENT_ON_POINTER_CANCEL, onPointerUp));
151
+ }
152
+ return () => { };
153
+ }, [disabled, subscribeSensors, cleanupSensors, onKeyDown, onWheel, onPointerDown, onPointerMove, onPointerUp]);
154
+ }
@@ -0,0 +1,12 @@
1
+ import * as React from "react";
2
+ import { ContainerRect } from "../../../types.js";
3
+ export declare function useZoomState(imageRect: ContainerRect, maxZoom: number, zoomWrapperRef?: React.RefObject<HTMLDivElement>): {
4
+ zoom: number;
5
+ offsetX: number;
6
+ offsetY: number;
7
+ disabled: boolean;
8
+ changeOffsets: (dx?: number, dy?: number, targetZoom?: number) => void;
9
+ changeZoom: (value: number, rapid?: boolean, dx?: number, dy?: number) => void;
10
+ zoomIn: () => void;
11
+ zoomOut: () => void;
12
+ };
@@ -0,0 +1,63 @@
1
+ import * as React from "react";
2
+ import { isImageSlide, round, useController, useEventCallback, useLayoutEffect, useLightboxState, } from "../../../core/index.js";
3
+ import { useZoomProps } from "./useZoomProps.js";
4
+ import { useZoomAnimation } from "./useZoomAnimation.js";
5
+ function getCurrentSource(slides, currentIndex) {
6
+ if (currentIndex < slides.length) {
7
+ const slide = slides[currentIndex];
8
+ if (isImageSlide(slide))
9
+ return slide.src;
10
+ }
11
+ return undefined;
12
+ }
13
+ export function useZoomState(imageRect, maxZoom, zoomWrapperRef) {
14
+ const [zoom, setZoom] = React.useState(1);
15
+ const [offsetX, setOffsetX] = React.useState(0);
16
+ const [offsetY, setOffsetY] = React.useState(0);
17
+ const animate = useZoomAnimation(zoom, offsetX, offsetY, zoomWrapperRef);
18
+ const { slides, currentIndex, globalIndex } = useLightboxState().state;
19
+ const { containerRect, slideRect } = useController();
20
+ const { zoomInMultiplier } = useZoomProps();
21
+ const currentSource = getCurrentSource(slides, currentIndex);
22
+ const disabled = !currentSource || !(zoomWrapperRef === null || zoomWrapperRef === void 0 ? void 0 : zoomWrapperRef.current);
23
+ useLayoutEffect(() => {
24
+ setZoom(1);
25
+ setOffsetX(0);
26
+ setOffsetY(0);
27
+ }, [globalIndex, currentSource]);
28
+ const changeOffsets = React.useCallback((dx, dy, targetZoom) => {
29
+ const newZoom = targetZoom || zoom;
30
+ const newOffsetX = offsetX - (dx || 0);
31
+ const newOffsetY = offsetY - (dy || 0);
32
+ const maxOffsetX = (imageRect.width * newZoom - slideRect.width) / 2 / newZoom;
33
+ const maxOffsetY = (imageRect.height * newZoom - slideRect.height) / 2 / newZoom;
34
+ setOffsetX(Math.min(Math.abs(newOffsetX), Math.max(maxOffsetX, 0)) * Math.sign(newOffsetX));
35
+ setOffsetY(Math.min(Math.abs(newOffsetY), Math.max(maxOffsetY, 0)) * Math.sign(newOffsetY));
36
+ }, [zoom, offsetX, offsetY, slideRect, imageRect.width, imageRect.height]);
37
+ const changeZoom = React.useCallback((value, rapid, dx, dy) => {
38
+ const newZoom = round(Math.min(Math.max(value + 0.001 < maxZoom ? value : maxZoom, 1), maxZoom), 5);
39
+ if (newZoom === zoom)
40
+ return;
41
+ if (!rapid) {
42
+ animate();
43
+ }
44
+ changeOffsets(dx ? dx * (1 / zoom - 1 / newZoom) : 0, dy ? dy * (1 / zoom - 1 / newZoom) : 0, newZoom);
45
+ setZoom(newZoom);
46
+ }, [zoom, maxZoom, changeOffsets, animate]);
47
+ const handleControllerRectChange = useEventCallback(() => {
48
+ if (zoom > 1) {
49
+ if (zoom > maxZoom) {
50
+ changeZoom(maxZoom, true);
51
+ }
52
+ changeOffsets();
53
+ }
54
+ });
55
+ useLayoutEffect(handleControllerRectChange, [
56
+ containerRect.width,
57
+ containerRect.height,
58
+ handleControllerRectChange,
59
+ ]);
60
+ const zoomIn = React.useCallback(() => changeZoom(zoom * zoomInMultiplier), [zoom, zoomInMultiplier, changeZoom]);
61
+ const zoomOut = React.useCallback(() => changeZoom(zoom / zoomInMultiplier), [zoom, zoomInMultiplier, changeZoom]);
62
+ return { zoom, offsetX, offsetY, disabled, changeOffsets, changeZoom, zoomIn, zoomOut };
63
+ }
@@ -1,11 +1,11 @@
1
- import * as React from "react";
1
+ /// <reference types="react" />
2
2
  import { Zoom } from "./Zoom.js";
3
- export declare const ACTION_ZOOM_IN = "zoom-in";
4
- export declare const ACTION_ZOOM_OUT = "zoom-out";
5
- declare module "../../types" {
3
+ declare module "../../types.js" {
6
4
  interface LightboxProps {
7
5
  /** Zoom plugin settings */
8
6
  zoom?: {
7
+ /** Zoom plugin ref */
8
+ ref?: React.ForwardedRef<ZoomRef>;
9
9
  /** ratio of image pixels to physical pixels at maximum zoom level */
10
10
  maxZoomPixelRatio?: number;
11
11
  /** zoom-in multiplier */
@@ -30,32 +30,45 @@ declare module "../../types" {
30
30
  /** zoom animation duration */
31
31
  zoom?: number;
32
32
  }
33
- /** `render.buttonZoomIn` and `render.buttonZoomOut` render function props */
34
- type RenderZoomButtonProps = Pick<LightboxProps, "labels"> & {
35
- ref: React.ForwardedRef<HTMLButtonElement>;
36
- disabled: boolean;
37
- onClick: () => void;
38
- onFocus: () => void;
39
- onBlur: () => void;
40
- };
41
33
  interface Render {
42
- /** render custom Zoom in button */
43
- buttonZoomIn?: RenderFunction<RenderZoomButtonProps>;
44
- /** render custom Zoom in button */
45
- buttonZoomOut?: RenderFunction<RenderZoomButtonProps>;
46
- /** render custom Zoom in icon */
34
+ /** render custom Zoom control in the toolbar */
35
+ buttonZoom?: RenderFunction<ZoomRef>;
36
+ /** render custom Zoom In icon */
47
37
  iconZoomIn?: RenderFunction;
48
- /** render custom Zoom out icon */
38
+ /** render custom Zoom Out icon */
49
39
  iconZoomOut?: RenderFunction;
50
40
  }
41
+ interface RenderSlideProps {
42
+ /** current zoom level */
43
+ zoom?: number;
44
+ /** maximum zoom level */
45
+ maxZoom?: number;
46
+ }
51
47
  interface Callbacks {
52
- zoom?: (level: number) => void;
48
+ /** zoom callback */
49
+ zoom?: Callback<ZoomCallbackProps>;
53
50
  }
54
- }
55
- declare module "../../core" {
56
- interface EventTypes {
57
- [ACTION_ZOOM_IN]: void;
58
- [ACTION_ZOOM_OUT]: void;
51
+ /** Zoom callback props */
52
+ interface ZoomCallbackProps {
53
+ /** current zoom level */
54
+ zoom: number;
55
+ }
56
+ /** Zoom plugin ref */
57
+ interface ZoomRef {
58
+ /** current zoom level */
59
+ zoom: number;
60
+ /** maximum zoom level */
61
+ maxZoom: number;
62
+ /** horizontal offset */
63
+ offsetX: number;
64
+ /** vertical offset */
65
+ offsetY: number;
66
+ /** if `true`, zoom is unavailable for the current slide */
67
+ disabled: boolean;
68
+ /** increase zoom level using `zoomInMultiplier` */
69
+ zoomIn: Callback;
70
+ /** decrease zoom level using `zoomInMultiplier` */
71
+ zoomOut: Callback;
59
72
  }
60
73
  }
61
74
  export default Zoom;
@@ -1,4 +1,2 @@
1
1
  import { Zoom } from "./Zoom.js";
2
- export const ACTION_ZOOM_IN = "zoom-in";
3
- export const ACTION_ZOOM_OUT = "zoom-out";
4
2
  export default Zoom;
@@ -0,0 +1,25 @@
1
+ /// <reference types="react" />
2
+ import { LightboxProps } from "../../types.js";
3
+ export declare const defaultZoomProps: {
4
+ maxZoomPixelRatio: number;
5
+ zoomInMultiplier: number;
6
+ doubleTapDelay: number;
7
+ doubleClickDelay: number;
8
+ doubleClickMaxStops: number;
9
+ keyboardMoveDistance: number;
10
+ wheelZoomDistanceFactor: number;
11
+ pinchZoomDistanceFactor: number;
12
+ scrollToZoom: boolean;
13
+ };
14
+ export declare const resolveZoomProps: (zoom: LightboxProps["zoom"]) => {
15
+ ref?: import("react").ForwardedRef<import("../../types.js").ZoomRef> | undefined;
16
+ maxZoomPixelRatio: number;
17
+ zoomInMultiplier: number;
18
+ doubleTapDelay: number;
19
+ doubleClickDelay: number;
20
+ doubleClickMaxStops: number;
21
+ keyboardMoveDistance: number;
22
+ wheelZoomDistanceFactor: number;
23
+ pinchZoomDistanceFactor: number;
24
+ scrollToZoom: boolean;
25
+ };
@@ -0,0 +1,15 @@
1
+ export const defaultZoomProps = {
2
+ maxZoomPixelRatio: 1,
3
+ zoomInMultiplier: 2,
4
+ doubleTapDelay: 300,
5
+ doubleClickDelay: 500,
6
+ doubleClickMaxStops: 2,
7
+ keyboardMoveDistance: 50,
8
+ wheelZoomDistanceFactor: 100,
9
+ pinchZoomDistanceFactor: 100,
10
+ scrollToZoom: false,
11
+ };
12
+ export const resolveZoomProps = (zoom) => ({
13
+ ...defaultZoomProps,
14
+ ...zoom,
15
+ });
package/dist/props.d.ts CHANGED
@@ -1,6 +1,2 @@
1
1
  import { LightboxProps } from "./types.js";
2
- export declare const AnimationDefaultProps: {
3
- fade: number;
4
- swipe: number;
5
- };
6
2
  export declare const LightboxDefaultProps: LightboxProps;
package/dist/props.js CHANGED
@@ -1,8 +1,4 @@
1
1
  import { ACTION_CLOSE, IMAGE_FIT_CONTAIN } from "./core/consts.js";
2
- export const AnimationDefaultProps = {
3
- fade: 330,
4
- swipe: 500,
5
- };
6
2
  export const LightboxDefaultProps = {
7
3
  open: false,
8
4
  close: () => { },
@@ -12,7 +8,15 @@ export const LightboxDefaultProps = {
12
8
  plugins: [],
13
9
  toolbar: { buttons: [ACTION_CLOSE] },
14
10
  labels: {},
15
- animation: AnimationDefaultProps,
11
+ animation: {
12
+ fade: 250,
13
+ swipe: 500,
14
+ easing: {
15
+ fade: "ease",
16
+ swipe: "ease-out",
17
+ navigation: "ease-in-out",
18
+ },
19
+ },
16
20
  carousel: {
17
21
  finite: false,
18
22
  preload: 2,
@@ -21,6 +25,7 @@ export const LightboxDefaultProps = {
21
25
  imageFit: IMAGE_FIT_CONTAIN,
22
26
  },
23
27
  controller: {
28
+ ref: null,
24
29
  focus: true,
25
30
  aria: false,
26
31
  touchAction: "none",