yet-another-react-lightbox 1.13.2 → 2.0.0-rc.1

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 (121) hide show
  1. package/dist/Lightbox.js +1 -1
  2. package/dist/core/components/IconButton.d.ts +1 -1
  3. package/dist/core/components/IconButton.js +3 -2
  4. package/dist/core/components/ImageSlide.js +20 -28
  5. package/dist/core/consts.d.ts +36 -0
  6. package/dist/core/consts.js +36 -0
  7. package/dist/core/contexts/Events.d.ts +5 -9
  8. package/dist/core/contexts/Events.js +23 -25
  9. package/dist/core/contexts/LightboxState.d.ts +20 -0
  10. package/dist/core/contexts/LightboxState.js +23 -0
  11. package/dist/core/contexts/Timeouts.d.ts +1 -2
  12. package/dist/core/contexts/Timeouts.js +26 -29
  13. package/dist/core/contexts/index.d.ts +1 -0
  14. package/dist/core/contexts/index.js +1 -0
  15. package/dist/core/hooks/index.d.ts +2 -1
  16. package/dist/core/hooks/index.js +2 -1
  17. package/dist/core/hooks/useEventCallback.d.ts +1 -0
  18. package/dist/core/hooks/useEventCallback.js +9 -0
  19. package/dist/core/hooks/useForkRef.d.ts +3 -0
  20. package/dist/core/hooks/useForkRef.js +15 -0
  21. package/dist/core/hooks/useMotionPreference.js +1 -2
  22. package/dist/core/hooks/useSensors.d.ts +4 -5
  23. package/dist/core/hooks/useSensors.js +9 -12
  24. package/dist/core/modules/Carousel.js +29 -29
  25. package/dist/core/modules/Controller.d.ts +3 -7
  26. package/dist/core/modules/Controller.js +144 -263
  27. package/dist/core/modules/Core.js +6 -4
  28. package/dist/core/modules/Navigation.js +16 -13
  29. package/dist/core/modules/NoScroll.js +4 -3
  30. package/dist/core/modules/Portal.js +51 -40
  31. package/dist/core/modules/Toolbar.js +6 -4
  32. package/dist/core/modules/controller/index.d.ts +8 -0
  33. package/dist/core/modules/controller/index.js +9 -0
  34. package/dist/core/modules/controller/useOffset.d.ts +2 -0
  35. package/dist/core/modules/controller/useOffset.js +10 -0
  36. package/dist/core/modules/controller/usePointerSwipe.d.ts +3 -0
  37. package/dist/core/modules/controller/usePointerSwipe.js +61 -0
  38. package/dist/core/modules/controller/usePreventSwipeNavigation.d.ts +3 -0
  39. package/dist/core/modules/controller/usePreventSwipeNavigation.js +20 -0
  40. package/dist/core/modules/controller/useWheelSwipe.d.ts +3 -0
  41. package/dist/core/modules/controller/useWheelSwipe.js +94 -0
  42. package/dist/core/utils.d.ts +12 -1
  43. package/dist/core/utils.js +14 -0
  44. package/dist/plugins/captions/Captions.d.ts +7 -0
  45. package/dist/plugins/captions/Captions.js +23 -0
  46. package/dist/plugins/captions/CaptionsContext.d.ts +8 -0
  47. package/dist/plugins/captions/CaptionsContext.js +15 -0
  48. package/dist/plugins/captions/Description.d.ts +5 -0
  49. package/dist/plugins/captions/Description.js +17 -0
  50. package/dist/plugins/captions/Title.d.ts +5 -0
  51. package/dist/plugins/captions/Title.js +9 -0
  52. package/dist/plugins/{captions.css → captions/captions.css} +0 -2
  53. package/dist/plugins/{Captions.d.ts → captions/index.d.ts} +3 -9
  54. package/dist/plugins/captions/index.js +2 -0
  55. package/dist/plugins/captions/utils.d.ts +1 -0
  56. package/dist/plugins/captions/utils.js +2 -0
  57. package/dist/plugins/fullscreen/Fullscreen.d.ts +3 -0
  58. package/dist/plugins/fullscreen/Fullscreen.js +17 -0
  59. package/dist/plugins/fullscreen/FullscreenButton.d.ts +8 -0
  60. package/dist/plugins/{Fullscreen.js → fullscreen/FullscreenButton.js} +16 -30
  61. package/dist/plugins/fullscreen/FullscreenContext.d.ts +5 -0
  62. package/dist/plugins/fullscreen/FullscreenContext.js +9 -0
  63. package/dist/plugins/{Fullscreen.d.ts → fullscreen/index.d.ts} +2 -11
  64. package/dist/plugins/fullscreen/index.js +2 -0
  65. package/dist/plugins/index.d.ts +7 -7
  66. package/dist/plugins/index.js +7 -7
  67. package/dist/plugins/inline/Inline.d.ts +3 -0
  68. package/dist/plugins/{Inline.js → inline/Inline.js} +5 -7
  69. package/dist/plugins/inline/index.d.ts +9 -0
  70. package/dist/plugins/inline/index.js +2 -0
  71. package/dist/plugins/slideshow/Slideshow.d.ts +7 -0
  72. package/dist/plugins/slideshow/Slideshow.js +20 -0
  73. package/dist/plugins/slideshow/SlideshowButton.d.ts +2 -0
  74. package/dist/plugins/{Slideshow.js → slideshow/SlideshowButton.js} +17 -44
  75. package/dist/plugins/{Slideshow.d.ts → slideshow/index.d.ts} +2 -4
  76. package/dist/plugins/slideshow/index.js +2 -0
  77. package/dist/plugins/thumbnails/Thumbnail.d.ts +21 -0
  78. package/dist/plugins/thumbnails/Thumbnail.js +45 -0
  79. package/dist/plugins/thumbnails/Thumbnails.d.ts +13 -0
  80. package/dist/plugins/thumbnails/Thumbnails.js +28 -0
  81. package/dist/plugins/thumbnails/ThumbnailsContainer.d.ts +3 -0
  82. package/dist/plugins/thumbnails/ThumbnailsContainer.js +14 -0
  83. package/dist/plugins/thumbnails/ThumbnailsTrack.d.ts +12 -0
  84. package/dist/plugins/thumbnails/ThumbnailsTrack.js +148 -0
  85. package/dist/plugins/{Thumbnails.d.ts → thumbnails/index.d.ts} +4 -16
  86. package/dist/plugins/thumbnails/index.js +2 -0
  87. package/dist/plugins/{thumbnails.css → thumbnails/thumbnails.css} +27 -37
  88. package/dist/plugins/thumbnails/utils.d.ts +2 -0
  89. package/dist/plugins/thumbnails/utils.js +4 -0
  90. package/dist/plugins/video/Video.d.ts +7 -0
  91. package/dist/plugins/video/Video.js +24 -0
  92. package/dist/plugins/video/VideoSlide.d.ts +9 -0
  93. package/dist/plugins/{Video.js → video/VideoSlide.js} +14 -39
  94. package/dist/plugins/{Video.d.ts → video/index.d.ts} +5 -13
  95. package/dist/plugins/video/index.js +2 -0
  96. package/dist/plugins/zoom/Zoom.d.ts +14 -0
  97. package/dist/plugins/zoom/Zoom.js +36 -0
  98. package/dist/plugins/zoom/ZoomButton.d.ts +7 -0
  99. package/dist/plugins/zoom/ZoomButton.js +50 -0
  100. package/dist/plugins/zoom/ZoomButtonsGroup.d.ts +5 -0
  101. package/dist/plugins/zoom/ZoomButtonsGroup.js +23 -0
  102. package/dist/plugins/zoom/ZoomContainer.d.ts +9 -0
  103. package/dist/plugins/zoom/ZoomContainer.js +303 -0
  104. package/dist/plugins/zoom/ZoomContext.d.ts +12 -0
  105. package/dist/plugins/zoom/ZoomContext.js +18 -0
  106. package/dist/plugins/zoom/ZoomWrapper.d.ts +3 -0
  107. package/dist/plugins/zoom/ZoomWrapper.js +26 -0
  108. package/dist/plugins/{Zoom.d.ts → zoom/index.d.ts} +5 -5
  109. package/dist/plugins/zoom/index.js +4 -0
  110. package/dist/props.d.ts +2 -0
  111. package/dist/props.js +31 -0
  112. package/dist/styles.css +30 -27
  113. package/dist/types.d.ts +8 -22
  114. package/dist/types.js +1 -30
  115. package/package.json +17 -17
  116. package/dist/core/hooks/useLatest.d.ts +0 -3
  117. package/dist/core/hooks/useLatest.js +0 -6
  118. package/dist/plugins/Captions.js +0 -58
  119. package/dist/plugins/Inline.d.ts +0 -15
  120. package/dist/plugins/Thumbnails.js +0 -243
  121. package/dist/plugins/Zoom.js +0 -441
@@ -1,27 +1,27 @@
1
1
  import * as React from "react";
2
- import { YARL_EVENT_BACKDROP_CLICK } from "../consts.js";
3
- import { LightboxDefaultProps } from "../../types.js";
4
- import { useContainerRect } from "../hooks/index.js";
5
2
  import { createModule } from "../config.js";
6
- import { clsx, cssClass, cssVar } from "../utils.js";
3
+ import { LightboxDefaultProps } from "../../props.js";
4
+ import { useContainerRect } from "../hooks/index.js";
5
+ import { clsx, composePrefix, cssClass, cssVar, isImageSlide, parseSpacing } from "../utils.js";
7
6
  import { ImageSlide } from "../components/index.js";
8
7
  import { useController } from "./Controller.js";
9
8
  import { useEvents } from "../contexts/Events.js";
9
+ import { useLightboxState } from "../contexts/LightboxState.js";
10
+ import { CLASS_FLEX_CENTER, CLASS_FULLSIZE, MODULE_CAROUSEL, YARL_EVENT_BACKDROP_CLICK } from "../consts.js";
11
+ const cssPrefix = (value) => composePrefix(MODULE_CAROUSEL, value);
12
+ const cssSlidePrefix = (value) => composePrefix("slide", value);
13
+ const sanitize = (value) => (value === 0 || value === "0" ? "0px" : value);
10
14
  const CarouselSlide = ({ slide, offset }) => {
11
15
  const { setContainerRef, containerRect, containerRef } = useContainerRect();
12
16
  const { publish } = useEvents();
13
- const { latestProps, currentIndex } = useController();
14
- const { render } = latestProps.current;
17
+ const { state: { currentIndex }, } = useLightboxState();
18
+ const { getLightboxProps } = useController();
19
+ const { render, carousel: { imageFit }, on: { click: onClick }, } = getLightboxProps();
15
20
  const renderSlide = (rect) => {
16
21
  var _a, _b, _c, _d;
17
22
  let rendered = (_a = render.slide) === null || _a === void 0 ? void 0 : _a.call(render, slide, offset, rect);
18
- if (!rendered && "src" in slide) {
19
- rendered = (React.createElement(ImageSlide, { slide: slide, offset: offset, render: render, rect: rect, imageFit: latestProps.current.carousel.imageFit, onClick: latestProps.current.on.click && offset === 0
20
- ? () => {
21
- var _a, _b;
22
- (_b = (_a = latestProps.current.on).click) === null || _b === void 0 ? void 0 : _b.call(_a, currentIndex);
23
- }
24
- : undefined }));
23
+ if (!rendered && isImageSlide(slide)) {
24
+ rendered = (React.createElement(ImageSlide, { slide: slide, offset: offset, render: render, rect: rect, imageFit: imageFit, onClick: offset === 0 ? () => onClick === null || onClick === void 0 ? void 0 : onClick(currentIndex) : undefined }));
25
25
  }
26
26
  return rendered ? (React.createElement(React.Fragment, null, (_b = render.slideHeader) === null || _b === void 0 ? void 0 :
27
27
  _b.call(render, slide),
@@ -35,36 +35,36 @@ const CarouselSlide = ({ slide, offset }) => {
35
35
  container &&
36
36
  (target === container ||
37
37
  (Array.from(container.children).find((x) => x === target) &&
38
- target.classList.contains(cssClass("fullsize"))))) {
38
+ target.classList.contains(cssClass(CLASS_FULLSIZE))))) {
39
39
  publish(YARL_EVENT_BACKDROP_CLICK);
40
40
  }
41
41
  };
42
- return (React.createElement("div", { ref: setContainerRef, className: clsx(cssClass("slide"), cssClass("flex_center")), style: { [cssVar("slide_offset")]: offset }, onClick: handleBackdropClick }, containerRect && renderSlide(containerRect)));
42
+ return (React.createElement("div", { ref: setContainerRef, className: clsx(cssClass(cssSlidePrefix()), offset === 0 && cssClass(cssSlidePrefix("current")), cssClass(CLASS_FLEX_CENTER)), onClick: handleBackdropClick }, containerRect && renderSlide(containerRect)));
43
43
  };
44
+ const Placeholder = () => React.createElement("div", { className: cssClass("slide") });
44
45
  export const Carousel = ({ slides, carousel: { finite, preload, padding, spacing } }) => {
45
- const { currentIndex, globalIndex } = useController();
46
+ const { state: { currentIndex, globalIndex }, } = useLightboxState();
47
+ const { setCarouselRef } = useController();
48
+ const spacingValue = parseSpacing(spacing);
46
49
  const items = [];
47
50
  if ((slides === null || slides === void 0 ? void 0 : slides.length) > 0) {
48
51
  for (let i = currentIndex - preload; i < currentIndex; i += 1) {
49
- if (!finite || i >= 0) {
50
- items.push(React.createElement(CarouselSlide, { key: globalIndex + i - currentIndex, slide: slides[(i + preload * slides.length) % slides.length], offset: i - currentIndex }));
51
- }
52
+ const key = globalIndex + i - currentIndex;
53
+ items.push(!finite || i >= 0 ? (React.createElement(CarouselSlide, { key: key, slide: slides[(i + preload * slides.length) % slides.length], offset: i - currentIndex })) : (React.createElement(Placeholder, { key: key })));
52
54
  }
53
55
  items.push(React.createElement(CarouselSlide, { key: globalIndex, slide: slides[currentIndex], offset: 0 }));
54
56
  for (let i = currentIndex + 1; i <= currentIndex + preload; i += 1) {
55
- if (!finite || i <= slides.length - 1) {
56
- items.push(React.createElement(CarouselSlide, { key: globalIndex + i - currentIndex, slide: slides[i % slides.length], offset: i - currentIndex }));
57
- }
57
+ const key = globalIndex + i - currentIndex;
58
+ items.push(!finite || i <= slides.length - 1 ? (React.createElement(CarouselSlide, { key: key, slide: slides[i % slides.length], offset: i - currentIndex })) : (React.createElement(Placeholder, { key: key })));
58
59
  }
59
60
  }
60
- const sanitize = (value) => value === 0 || value.trim() === "" || value.trim() === "0" ? "0px" : value;
61
- return (React.createElement("div", { className: cssClass("carousel"), style: {
61
+ return (React.createElement("div", { ref: setCarouselRef, className: cssClass(cssPrefix()), style: {
62
+ [`${cssVar(cssPrefix("slides_count"))}`]: items.length,
63
+ [`${cssVar(cssPrefix("spacing_px"))}`]: spacingValue.pixel || 0,
64
+ [`${cssVar(cssPrefix("spacing_percent"))}`]: spacingValue.percent || 0,
62
65
  ...(padding !== LightboxDefaultProps.carousel.padding
63
- ? { [cssVar("carousel_padding")]: sanitize(padding) }
64
- : null),
65
- ...(spacing !== LightboxDefaultProps.carousel.spacing
66
- ? { [cssVar("carousel_spacing")]: sanitize(spacing) }
66
+ ? { [cssVar(cssPrefix("padding"))]: sanitize(padding) }
67
67
  : null),
68
68
  } }, items));
69
69
  };
70
- export const CarouselModule = createModule("carousel", Carousel);
70
+ export const CarouselModule = createModule(MODULE_CAROUSEL, Carousel);
@@ -1,18 +1,14 @@
1
1
  import * as React from "react";
2
2
  import { Component, ComponentProps } from "../../types.js";
3
3
  import { ContainerRect, SubscribeSensors } from "../hooks/index.js";
4
- declare type ControllerState = {
5
- currentIndex: number;
6
- globalIndex: number;
7
- };
8
- export declare type ControllerContextType = ControllerState & {
9
- latestProps: React.MutableRefObject<ComponentProps>;
4
+ export declare type ControllerContextType = {
5
+ getLightboxProps: () => ComponentProps;
10
6
  subscribeSensors: SubscribeSensors<HTMLDivElement>;
11
7
  transferFocus: () => void;
12
8
  containerRect: ContainerRect;
13
9
  containerRef: React.RefObject<HTMLDivElement>;
10
+ setCarouselRef: React.Ref<HTMLDivElement>;
14
11
  };
15
12
  export declare const useController: () => ControllerContextType;
16
13
  export declare const Controller: Component;
17
14
  export declare const ControllerModule: import("../../types.js").Module;
18
- export {};
@@ -1,308 +1,189 @@
1
1
  import * as React from "react";
2
- import { YARL_EVENT_BACKDROP_CLICK } from "../consts.js";
3
- import { LightboxDefaultProps } from "../../types.js";
4
- import { cleanup, clsx, cssClass, cssVar, makeUseContext } from "../utils.js";
5
2
  import { createModule } from "../config.js";
6
- import { useContainerRect, useLatest, useLayoutEffect, useRTL, useSensors, } from "../hooks/index.js";
7
- import { useEvents, useTimeouts } from "../contexts/index.js";
8
- const SWIPE_OFFSET_THRESHOLD = 30;
3
+ import { cleanup, clsx, cssClass, cssVar, isNumber, makeComposePrefix, makeUseContext, parseSpacing, } from "../utils.js";
4
+ import { useContainerRect, useEventCallback, useForkRef, useLayoutEffect, useMotionPreference, useRTL, useSensors, } from "../hooks/index.js";
5
+ import { useEvents, useLightboxState, useTimeouts } from "../contexts/index.js";
6
+ import { SwipeState, usePointerSwipe, usePreventSwipeNavigation, useWheelSwipe } from "./controller/index.js";
7
+ import { ACTION_CLOSE, ACTION_NEXT, ACTION_PREV, CLASS_FLEX_CENTER, EVENT_ON_KEY_UP, MODULE_CONTROLLER, VK_ESCAPE, YARL_EVENT_BACKDROP_CLICK, } from "../consts.js";
8
+ const cssContainerPrefix = makeComposePrefix("container");
9
9
  const ControllerContext = React.createContext(null);
10
10
  export const useController = makeUseContext("useController", "ControllerContext", ControllerContext);
11
11
  export const Controller = ({ children, ...props }) => {
12
- const { containerRef, setContainerRef, containerRect } = useContainerRect();
12
+ const { carousel, slides, animation, controller, on, styles } = props;
13
+ const { state, dispatch } = useLightboxState();
14
+ const [swipeState, setSwipeState] = React.useState(SwipeState.NONE);
15
+ const [swipeOffset, setSwipeOffset] = React.useState(0);
16
+ const swipeAnimationReset = React.useRef();
13
17
  const { registerSensors, subscribeSensors } = useSensors();
14
18
  const { subscribe, publish } = useEvents();
15
19
  const { setTimeout, clearTimeout } = useTimeouts();
16
- const isRTL = useLatest(useRTL());
17
- const [state, setState] = React.useState({
18
- currentIndex: props.index,
19
- globalIndex: props.index,
20
- });
21
- const latestProps = useLatest(props);
22
- const refs = React.useRef({
23
- state,
24
- props,
25
- swipeOffset: 0,
26
- swipeIntent: 0,
27
- swipeAnimationDuration: props.animation.swipe,
28
- wheelResidualMomentum: 0,
29
- pointers: [],
30
- });
31
- refs.current.state = state;
32
- refs.current.props = props;
33
- useLayoutEffect(() => {
34
- const preventDefault = (event) => {
35
- if (Math.abs(event.deltaX) > Math.abs(event.deltaY) || event.ctrlKey) {
36
- event.preventDefault();
37
- }
38
- };
39
- const node = containerRef.current;
40
- if (node) {
41
- node.addEventListener("wheel", preventDefault, { passive: false });
42
- }
43
- return () => {
44
- if (node) {
45
- node.removeEventListener("wheel", preventDefault);
46
- }
47
- };
48
- }, [containerRef]);
49
- React.useEffect(() => {
50
- var _a;
51
- if (refs.current.props.controller.focus) {
52
- (_a = containerRef.current) === null || _a === void 0 ? void 0 : _a.focus();
53
- }
54
- }, [containerRef, refs]);
55
- React.useEffect(() => {
56
- var _a, _b;
57
- (_b = (_a = refs.current.props.on).view) === null || _b === void 0 ? void 0 : _b.call(_a, state.currentIndex);
58
- }, [state.currentIndex]);
59
- const updateSwipeOffset = React.useCallback(() => {
60
- var _a, _b;
61
- const offsetVar = cssVar("swipe_offset");
62
- if (refs.current.swipeOffset !== 0) {
63
- (_a = containerRef.current) === null || _a === void 0 ? void 0 : _a.style.setProperty(offsetVar, `${Math.round(refs.current.swipeOffset)}px`);
64
- }
65
- else {
66
- (_b = containerRef.current) === null || _b === void 0 ? void 0 : _b.style.removeProperty(offsetVar);
67
- }
68
- }, [containerRef]);
69
- useLayoutEffect(() => {
70
- updateSwipeOffset();
71
- });
72
- const rerender = React.useCallback(() => {
73
- setState((prev) => ({ ...prev }));
74
- }, []);
75
- const resetSwipe = React.useCallback(() => {
76
- const { current } = refs;
77
- current.swipeOffset = 0;
78
- current.swipeIntent = 0;
79
- current.swipeStartTime = undefined;
80
- clearTimeout(current.swipeResetCleanup);
81
- current.swipeResetCleanup = undefined;
82
- clearTimeout(current.swipeIntentCleanup);
83
- current.swipeIntentCleanup = undefined;
84
- }, [clearTimeout]);
85
- const rtl = React.useCallback((value) => (isRTL.current ? -1 : 1) * (typeof value === "number" ? value : 1), [isRTL]);
86
- const isSwipeValid = React.useCallback((offset) => {
87
- const { state: { currentIndex }, props: { carousel, slides }, } = refs.current;
88
- return !(carousel.finite &&
89
- ((rtl(offset) > 0 && currentIndex === 0) || (rtl(offset) < 0 && currentIndex === slides.length - 1)));
90
- }, [rtl]);
91
- const swipe = React.useCallback((direction, count = 1) => {
20
+ const { containerRef, setContainerRef, containerRect } = useContainerRect();
21
+ const handleContainerRef = useForkRef(usePreventSwipeNavigation(), setContainerRef);
22
+ const carouselRef = React.useRef(null);
23
+ const setCarouselRef = useForkRef(carouselRef, undefined);
24
+ const carouselAnimation = React.useRef();
25
+ const carouselSwipeAnimation = React.useRef();
26
+ const reduceMotion = useMotionPreference();
27
+ const isRTL = useRTL();
28
+ const rtl = useEventCallback((value) => (isRTL ? -1 : 1) * (isNumber(value) ? value : 1));
29
+ const isSwipeValid = useEventCallback((offset) => !(carousel.finite &&
30
+ ((rtl(offset) > 0 && state.currentIndex === 0) ||
31
+ (rtl(offset) < 0 && state.currentIndex === slides.length - 1))));
32
+ const swipe = useEventCallback((action) => {
92
33
  var _a;
93
- const { current } = refs;
94
- const slidesCount = current.props.slides.length;
95
- const swipeAnimationDuration = current.props.animation.swipe;
96
- const { currentIndex, globalIndex } = current.state;
97
- const { swipeOffset } = current;
98
- let newSwipeState = "swipe-animation";
99
- let newSwipeAnimationDuration = swipeAnimationDuration * count;
34
+ const swipeDuration = animation.swipe;
35
+ const currentSwipeOffset = action.offset || 0;
36
+ let { direction } = action;
37
+ const count = (_a = action.count) !== null && _a !== void 0 ? _a : 1;
38
+ let newSwipeState = SwipeState.ANIMATION;
39
+ let newSwipeAnimationDuration = swipeDuration * count;
100
40
  if (!direction) {
101
- const containerWidth = (_a = containerRef.current) === null || _a === void 0 ? void 0 : _a.clientWidth;
102
- const elapsedTime = current.swipeStartTime ? Date.now() - current.swipeStartTime : 0;
41
+ const containerWidth = containerRect === null || containerRect === void 0 ? void 0 : containerRect.width;
42
+ const elapsedTime = action.duration || 0;
103
43
  const expectedTime = containerWidth
104
- ? (swipeAnimationDuration / containerWidth) * Math.abs(swipeOffset)
105
- : swipeAnimationDuration;
106
- if (containerWidth &&
107
- ((swipeOffset !== 0 && elapsedTime < swipeAnimationDuration) ||
108
- Math.abs(swipeOffset) > 0.5 * containerWidth)) {
109
- newSwipeAnimationDuration =
110
- (swipeAnimationDuration / containerWidth) * (containerWidth - Math.abs(swipeOffset));
44
+ ? (swipeDuration / containerWidth) * Math.abs(currentSwipeOffset)
45
+ : swipeDuration;
46
+ if (count !== 0) {
111
47
  if (elapsedTime < expectedTime) {
112
48
  newSwipeAnimationDuration =
113
49
  (newSwipeAnimationDuration / expectedTime) * Math.max(elapsedTime, expectedTime / 5);
114
50
  }
115
- direction = rtl(swipeOffset) > 0 ? "prev" : "next";
51
+ else if (containerWidth) {
52
+ newSwipeAnimationDuration =
53
+ (swipeDuration / containerWidth) * (containerWidth - Math.abs(currentSwipeOffset));
54
+ }
116
55
  }
117
56
  else {
118
- newSwipeAnimationDuration = swipeAnimationDuration / 2;
57
+ newSwipeAnimationDuration = swipeDuration / 2;
58
+ }
59
+ if (count !== 0) {
60
+ direction = rtl(currentSwipeOffset) > 0 ? ACTION_PREV : ACTION_NEXT;
119
61
  }
120
62
  }
121
- const newState = {};
122
- if (direction === "prev") {
63
+ let increment;
64
+ if (direction === ACTION_PREV) {
123
65
  if (isSwipeValid(rtl(1))) {
124
- newState.currentIndex = (currentIndex - count + slidesCount) % slidesCount;
125
- newState.globalIndex = globalIndex - count;
66
+ increment = -count;
126
67
  }
127
68
  else {
128
- newSwipeState = undefined;
129
- newSwipeAnimationDuration = swipeAnimationDuration;
69
+ newSwipeState = SwipeState.NONE;
70
+ newSwipeAnimationDuration = swipeDuration;
130
71
  }
131
72
  }
132
- else if (direction === "next") {
73
+ else if (direction === ACTION_NEXT) {
133
74
  if (isSwipeValid(rtl(-1))) {
134
- newState.currentIndex = (currentIndex + count) % slidesCount;
135
- newState.globalIndex = globalIndex + count;
75
+ increment = count;
136
76
  }
137
77
  else {
138
- newSwipeState = undefined;
139
- newSwipeAnimationDuration = swipeAnimationDuration;
78
+ newSwipeState = SwipeState.NONE;
79
+ newSwipeAnimationDuration = swipeDuration;
140
80
  }
141
81
  }
142
82
  newSwipeAnimationDuration = Math.round(newSwipeAnimationDuration);
143
- resetSwipe();
144
- current.swipeState = newSwipeState;
145
- current.swipeAnimationDuration = newSwipeAnimationDuration;
83
+ clearTimeout(swipeAnimationReset.current);
146
84
  if (newSwipeState) {
147
- setTimeout(() => {
148
- current.swipeState = undefined;
149
- current.swipeAnimationDuration = current.props.animation.swipe;
150
- rerender();
151
- }, newSwipeAnimationDuration);
152
- }
153
- publish("controller-swipe", { ...newState, animationDuration: current.swipeAnimationDuration });
154
- setState((prev) => ({ ...prev, ...newState }));
155
- }, [setTimeout, resetSwipe, isSwipeValid, rerender, containerRef, rtl, publish]);
156
- React.useEffect(() => cleanup(subscribe("prev", (_, count) => swipe("prev", typeof count === "number" ? count : undefined)), subscribe("next", (_, count) => swipe("next", typeof count === "number" ? count : undefined))), [subscribe, swipe]);
157
- React.useEffect(() => subscribeSensors("onKeyUp", (event) => {
158
- if (event.code === "Escape") {
159
- publish("close");
160
- }
161
- }), [subscribeSensors, publish]);
162
- React.useEffect(() => props.controller.closeOnBackdropClick
163
- ? subscribe(YARL_EVENT_BACKDROP_CLICK, () => publish("close"))
164
- : () => { }, [props.controller.closeOnBackdropClick, publish, subscribe]);
165
- const clearPointer = React.useCallback((event) => {
166
- const { current } = refs;
167
- if (current.activePointer === event.pointerId) {
168
- current.activePointer = undefined;
169
- }
170
- current.pointers.splice(0, current.pointers.length, ...current.pointers.filter((p) => p.pointerId !== event.pointerId));
171
- }, []);
172
- const addPointer = React.useCallback((event) => {
173
- clearPointer(event);
174
- refs.current.pointers.push(event);
175
- }, [clearPointer]);
176
- const onPointerDown = React.useCallback((event) => {
177
- addPointer(event);
178
- }, [addPointer]);
179
- const onPointerMove = React.useCallback((event) => {
180
- const { current } = refs;
181
- const original = current.pointers.find((p) => p.pointerId === event.pointerId);
182
- if (original) {
183
- const deltaX = event.clientX - original.clientX;
184
- const deltaY = event.clientY - original.clientY;
185
- if (!current.swipeState) {
186
- if (isSwipeValid(deltaX) &&
187
- Math.abs(deltaX) > Math.abs(deltaY) &&
188
- Math.abs(deltaX) > SWIPE_OFFSET_THRESHOLD) {
189
- addPointer(event);
190
- current.activePointer = event.pointerId;
191
- current.swipeStartTime = Date.now();
192
- current.swipeState = "swipe";
193
- rerender();
85
+ const timeoutId = setTimeout(() => {
86
+ if (swipeAnimationReset.current === timeoutId) {
87
+ setSwipeOffset(0);
88
+ setSwipeState(SwipeState.NONE);
194
89
  }
195
- }
196
- else if (current.swipeState === "swipe") {
197
- if (event.pointerId === current.activePointer) {
198
- current.swipeOffset = deltaX;
199
- updateSwipeOffset();
200
- }
201
- }
202
- }
203
- }, [addPointer, updateSwipeOffset, isSwipeValid, rerender]);
204
- const onPointerUp = React.useCallback((event) => {
205
- const { current } = refs;
206
- if (current.pointers.find((p) => p.pointerId === event.pointerId) &&
207
- current.swipeState === "swipe" &&
208
- current.activePointer === event.pointerId) {
209
- swipe();
210
- }
211
- clearPointer(event);
212
- }, [clearPointer, swipe]);
213
- React.useEffect(() => cleanup(subscribeSensors("onPointerDown", onPointerDown), subscribeSensors("onPointerMove", onPointerMove), subscribeSensors("onPointerUp", onPointerUp), subscribeSensors("onPointerLeave", onPointerUp), subscribeSensors("onPointerCancel", onPointerUp)), [subscribeSensors, onPointerDown, onPointerMove, onPointerUp]);
214
- const onWheel = React.useCallback((event) => {
215
- var _a;
216
- if (event.ctrlKey) {
217
- return;
90
+ }, newSwipeAnimationDuration);
91
+ swipeAnimationReset.current = timeoutId;
218
92
  }
219
- if (Math.abs(event.deltaY) > Math.abs(event.deltaX)) {
220
- return;
93
+ if (carouselRef.current) {
94
+ carouselSwipeAnimation.current = {
95
+ rect: carouselRef.current.getBoundingClientRect(),
96
+ index: state.globalIndex,
97
+ };
221
98
  }
222
- const { current } = refs;
223
- if (!current.swipeState) {
224
- if (Math.abs(event.deltaX) <= 1.2 * Math.abs(current.wheelResidualMomentum)) {
225
- current.wheelResidualMomentum = event.deltaX;
226
- return;
227
- }
228
- if (!isSwipeValid(-event.deltaX)) {
229
- return;
230
- }
231
- current.swipeIntent += event.deltaX;
232
- clearTimeout(current.swipeIntentCleanup);
233
- if (Math.abs(current.swipeIntent) > SWIPE_OFFSET_THRESHOLD) {
234
- current.swipeStartTime = Date.now();
235
- current.swipeIntent = 0;
236
- current.wheelResidualMomentum = 0;
237
- current.swipeState = "swipe";
238
- rerender();
239
- }
240
- else {
241
- current.swipeIntentCleanup = setTimeout(() => {
242
- current.swipeIntent = 0;
243
- current.swipeIntentCleanup = undefined;
244
- }, current.props.animation.swipe);
99
+ setSwipeState(newSwipeState);
100
+ dispatch({ increment, animationDuration: newSwipeAnimationDuration });
101
+ });
102
+ const animateCarouselSwipe = useEventCallback(() => {
103
+ var _a, _b, _c;
104
+ const swipeAnimation = carouselSwipeAnimation.current;
105
+ carouselSwipeAnimation.current = undefined;
106
+ if (swipeAnimation && carouselRef.current && containerRect) {
107
+ const parsedSpacing = parseSpacing(carousel.spacing);
108
+ const spacingValue = (parsedSpacing.percent ? (parsedSpacing.percent * containerRect.width) / 100 : parsedSpacing.pixel) ||
109
+ 0;
110
+ (_a = carouselAnimation.current) === null || _a === void 0 ? void 0 : _a.cancel();
111
+ carouselAnimation.current = (_c = (_b = carouselRef.current).animate) === null || _c === void 0 ? void 0 : _c.call(_b, [
112
+ {
113
+ transform: `translateX(${rtl(state.globalIndex - swipeAnimation.index) * (containerRect.width + spacingValue) +
114
+ swipeAnimation.rect.x -
115
+ carouselRef.current.getBoundingClientRect().x}px)`,
116
+ },
117
+ { transform: "translateX(0)" },
118
+ ], !reduceMotion ? state.animationDuration : 0);
119
+ if (carouselAnimation.current) {
120
+ carouselAnimation.current.onfinish = () => {
121
+ carouselAnimation.current = undefined;
122
+ };
245
123
  }
246
124
  }
247
- else if (current.swipeState === "swipe") {
248
- const containerWidth = (_a = containerRef.current) === null || _a === void 0 ? void 0 : _a.clientWidth;
249
- if (containerWidth) {
250
- current.swipeOffset -= event.deltaX;
251
- current.swipeOffset =
252
- Math.min(Math.abs(current.swipeOffset), containerWidth) * Math.sign(current.swipeOffset);
253
- updateSwipeOffset();
254
- clearTimeout(current.swipeResetCleanup);
255
- if (Math.abs(current.swipeOffset) > 0.2 * containerWidth) {
256
- current.wheelResidualMomentum = event.deltaX;
257
- swipe();
258
- return;
259
- }
260
- const currentSwipeOffset = current.swipeOffset;
261
- current.swipeResetCleanup = setTimeout(() => {
262
- current.swipeResetCleanup = undefined;
263
- if (current.swipeState === "swipe" && current.swipeOffset === currentSwipeOffset) {
264
- resetSwipe();
265
- current.swipeState = undefined;
266
- rerender();
267
- }
268
- }, 2 * current.props.animation.swipe);
125
+ });
126
+ useLayoutEffect(animateCarouselSwipe);
127
+ const swipeParams = [
128
+ swipeState,
129
+ subscribeSensors,
130
+ isSwipeValid,
131
+ (containerRect === null || containerRect === void 0 ? void 0 : containerRect.width) || 0,
132
+ animation.swipe,
133
+ () => setSwipeState(SwipeState.SWIPE),
134
+ (offset, duration) => swipe({ offset, duration, count: 1 }),
135
+ (offset) => swipe({ offset, count: 0 }),
136
+ (offset) => {
137
+ if (swipeState === SwipeState.SWIPE) {
138
+ setSwipeOffset(offset);
269
139
  }
140
+ },
141
+ ];
142
+ usePointerSwipe(...swipeParams);
143
+ useWheelSwipe(...swipeParams);
144
+ const focusOnMount = useEventCallback(() => {
145
+ var _a;
146
+ if (controller.focus) {
147
+ (_a = containerRef.current) === null || _a === void 0 ? void 0 : _a.focus();
270
148
  }
271
- else {
272
- current.wheelResidualMomentum = event.deltaX;
149
+ });
150
+ React.useEffect(focusOnMount, [focusOnMount]);
151
+ const handleIndexChange = useEventCallback(() => {
152
+ var _a;
153
+ (_a = on.view) === null || _a === void 0 ? void 0 : _a.call(on, state.currentIndex);
154
+ });
155
+ React.useEffect(handleIndexChange, [state.currentIndex, handleIndexChange]);
156
+ React.useEffect(() => cleanup(subscribe(ACTION_PREV, (count) => swipe({
157
+ direction: ACTION_PREV,
158
+ count: isNumber(count) ? count : undefined,
159
+ })), subscribe(ACTION_NEXT, (count) => swipe({
160
+ direction: ACTION_NEXT,
161
+ count: isNumber(count) ? count : undefined,
162
+ }))), [subscribe, swipe]);
163
+ React.useEffect(() => subscribeSensors(EVENT_ON_KEY_UP, (event) => {
164
+ if (event.code === VK_ESCAPE) {
165
+ publish(ACTION_CLOSE);
273
166
  }
274
- }, [updateSwipeOffset, setTimeout, clearTimeout, swipe, resetSwipe, rerender, isSwipeValid, containerRef]);
275
- React.useEffect(() => subscribeSensors("onWheel", onWheel), [subscribeSensors, onWheel]);
276
- const transferFocus = React.useCallback(() => { var _a; return (_a = containerRef.current) === null || _a === void 0 ? void 0 : _a.focus(); }, [containerRef]);
167
+ }), [subscribeSensors, publish]);
168
+ React.useEffect(() => controller.closeOnBackdropClick
169
+ ? subscribe(YARL_EVENT_BACKDROP_CLICK, () => publish(ACTION_CLOSE))
170
+ : () => { }, [controller.closeOnBackdropClick, publish, subscribe]);
171
+ const transferFocus = useEventCallback(() => { var _a; return (_a = containerRef.current) === null || _a === void 0 ? void 0 : _a.focus(); });
172
+ const getLightboxProps = useEventCallback(() => props);
277
173
  const context = React.useMemo(() => ({
278
- latestProps,
279
- currentIndex: state.currentIndex,
280
- globalIndex: state.globalIndex,
174
+ getLightboxProps,
281
175
  subscribeSensors,
282
176
  transferFocus,
283
- containerRect,
177
+ containerRect: containerRect || { width: 0, height: 0 },
284
178
  containerRef,
285
- }), [
286
- latestProps,
287
- state.currentIndex,
288
- state.globalIndex,
289
- subscribeSensors,
290
- transferFocus,
291
- containerRect,
292
- containerRef,
293
- ]);
294
- return (React.createElement("div", { ref: setContainerRef, className: clsx(cssClass("container"), cssClass("fullsize"), refs.current.swipeState === "swipe" && cssClass("container_swipe")), style: {
295
- ...(refs.current.swipeAnimationDuration !== LightboxDefaultProps.animation.swipe
296
- ? {
297
- [cssVar("swipe_animation_duration")]: `${Math.round(refs.current.swipeAnimationDuration)}ms`,
298
- }
299
- : null),
300
- ...(props.controller.touchAction !== "none"
301
- ? {
302
- [cssVar("controller_touch_action")]: props.controller.touchAction,
303
- }
179
+ setCarouselRef,
180
+ }), [getLightboxProps, subscribeSensors, transferFocus, containerRect, containerRef, setCarouselRef]);
181
+ return (React.createElement("div", { ref: handleContainerRef, className: clsx(cssClass(cssContainerPrefix()), cssClass(CLASS_FLEX_CENTER)), style: {
182
+ ...(swipeState === SwipeState.SWIPE
183
+ ? { [cssVar("swipe_offset")]: `${Math.round(swipeOffset)}px` }
304
184
  : null),
305
- ...props.styles.container,
306
- }, ...(props.controller.aria ? { role: "presentation", "aria-live": "polite" } : null), tabIndex: -1, ...registerSensors }, containerRect && (React.createElement(ControllerContext.Provider, { value: context }, children))));
185
+ ...(controller.touchAction !== "none" ? {} : null),
186
+ ...styles.container,
187
+ }, ...(controller.aria ? { role: "presentation", "aria-live": "polite" } : null), tabIndex: -1, ...registerSensors }, containerRect && React.createElement(ControllerContext.Provider, { value: context }, children)));
307
188
  };
308
- export const ControllerModule = createModule("controller", Controller);
189
+ export const ControllerModule = createModule(MODULE_CONTROLLER, Controller);
@@ -1,6 +1,8 @@
1
1
  import * as React from "react";
2
2
  import { createModule } from "../config.js";
3
- import { EventsProvider, TimeoutsProvider } from "../contexts/index.js";
4
- export const Core = ({ children }) => (React.createElement(TimeoutsProvider, null,
5
- React.createElement(EventsProvider, null, children)));
6
- export const CoreModule = createModule("core", Core);
3
+ import { EventsProvider, LightboxStateProvider, TimeoutsProvider } from "../contexts/index.js";
4
+ import { MODULE_CORE } from "../consts.js";
5
+ export const Core = ({ slides, index, children }) => (React.createElement(TimeoutsProvider, null,
6
+ React.createElement(EventsProvider, null,
7
+ React.createElement(LightboxStateProvider, { slidesCount: slides.length, initialIndex: index }, children))));
8
+ export const CoreModule = createModule(MODULE_CORE, Core);
@@ -1,27 +1,30 @@
1
1
  import * as React from "react";
2
2
  import { createModule } from "../config.js";
3
+ import { useEventCallback, useRTL } from "../hooks/index.js";
3
4
  import { cssClass, label as translateLabel } from "../utils.js";
4
5
  import { IconButton, NextIcon, PreviousIcon } from "../components/index.js";
5
- import { useEvents } from "../contexts/index.js";
6
+ import { useEvents, useLightboxState } from "../contexts/index.js";
6
7
  import { useController } from "./Controller.js";
7
- import { useLatest, useRTL } from "../hooks/index.js";
8
+ import { ACTION_NEXT, ACTION_PREV, EVENT_ON_KEY_DOWN, MODULE_NAVIGATION, VK_ARROW_LEFT, VK_ARROW_RIGHT, } from "../consts.js";
8
9
  export const NavigationButton = ({ publish, labels, label, icon, renderIcon, action, disabled, }) => (React.createElement(IconButton, { label: translateLabel(labels, label), icon: icon, renderIcon: renderIcon, className: cssClass(`navigation_${action}`), disabled: disabled, "aria-disabled": disabled, onClick: () => {
9
10
  publish(action);
10
11
  } }));
11
12
  export const Navigation = ({ slides, carousel: { finite }, labels, render: { buttonPrev, buttonNext, iconPrev, iconNext }, }) => {
12
- const { currentIndex, subscribeSensors } = useController();
13
+ const { state: { currentIndex }, } = useLightboxState();
14
+ const { subscribeSensors } = useController();
13
15
  const { publish } = useEvents();
14
- const isRTL = useLatest(useRTL());
15
- React.useEffect(() => subscribeSensors("onKeyDown", (event) => {
16
- if (event.key === "ArrowLeft") {
17
- publish(isRTL.current ? "next" : "prev");
16
+ const isRTL = useRTL();
17
+ const handleKeyDown = useEventCallback((event) => {
18
+ if (event.key === VK_ARROW_LEFT) {
19
+ publish(isRTL ? ACTION_NEXT : ACTION_PREV);
18
20
  }
19
- else if (event.key === "ArrowRight") {
20
- publish(isRTL.current ? "prev" : "next");
21
+ else if (event.key === VK_ARROW_RIGHT) {
22
+ publish(isRTL ? ACTION_PREV : ACTION_NEXT);
21
23
  }
22
- }), [subscribeSensors, publish, isRTL]);
24
+ });
25
+ React.useEffect(() => subscribeSensors(EVENT_ON_KEY_DOWN, handleKeyDown), [subscribeSensors, handleKeyDown]);
23
26
  return (React.createElement(React.Fragment, null,
24
- buttonPrev ? (buttonPrev()) : (React.createElement(NavigationButton, { label: "Previous", action: "prev", icon: PreviousIcon, renderIcon: iconPrev, disabled: finite && currentIndex === 0, labels: labels, publish: publish })),
25
- buttonNext ? (buttonNext()) : (React.createElement(NavigationButton, { label: "Next", action: "next", icon: NextIcon, renderIcon: iconNext, disabled: finite && currentIndex === slides.length - 1, labels: labels, publish: publish }))));
27
+ buttonPrev ? (buttonPrev()) : (React.createElement(NavigationButton, { label: "Previous", action: ACTION_PREV, icon: PreviousIcon, renderIcon: iconPrev, disabled: finite && currentIndex === 0, labels: labels, publish: publish })),
28
+ buttonNext ? (buttonNext()) : (React.createElement(NavigationButton, { label: "Next", action: ACTION_NEXT, icon: NextIcon, renderIcon: iconNext, disabled: finite && currentIndex === slides.length - 1, labels: labels, publish: publish }))));
26
29
  };
27
- export const NavigationModule = createModule("navigation", Navigation);
30
+ export const NavigationModule = createModule(MODULE_NAVIGATION, Navigation);