yet-another-react-lightbox 1.13.3 → 2.0.0-rc.2
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/Lightbox.js +1 -1
- package/dist/core/components/IconButton.d.ts +1 -1
- package/dist/core/components/IconButton.js +3 -2
- package/dist/core/components/ImageSlide.js +20 -28
- package/dist/core/consts.d.ts +36 -0
- package/dist/core/consts.js +36 -0
- package/dist/core/contexts/Events.d.ts +5 -9
- package/dist/core/contexts/Events.js +23 -25
- package/dist/core/contexts/LightboxState.d.ts +20 -0
- package/dist/core/contexts/LightboxState.js +23 -0
- package/dist/core/contexts/Timeouts.d.ts +1 -2
- package/dist/core/contexts/Timeouts.js +26 -29
- package/dist/core/contexts/index.d.ts +1 -0
- package/dist/core/contexts/index.js +1 -0
- package/dist/core/hooks/index.d.ts +2 -1
- package/dist/core/hooks/index.js +2 -1
- package/dist/core/hooks/useEventCallback.d.ts +1 -0
- package/dist/core/hooks/useEventCallback.js +9 -0
- package/dist/core/hooks/useForkRef.d.ts +3 -0
- package/dist/core/hooks/useForkRef.js +15 -0
- package/dist/core/hooks/useMotionPreference.js +1 -2
- package/dist/core/hooks/useSensors.d.ts +4 -5
- package/dist/core/hooks/useSensors.js +9 -12
- package/dist/core/modules/Carousel.js +29 -31
- package/dist/core/modules/Controller.d.ts +3 -7
- package/dist/core/modules/Controller.js +144 -263
- package/dist/core/modules/Core.js +6 -4
- package/dist/core/modules/Navigation.js +16 -13
- package/dist/core/modules/NoScroll.js +4 -3
- package/dist/core/modules/Portal.js +51 -40
- package/dist/core/modules/Toolbar.js +6 -4
- package/dist/core/modules/controller/index.d.ts +8 -0
- package/dist/core/modules/controller/index.js +9 -0
- package/dist/core/modules/controller/useOffset.d.ts +2 -0
- package/dist/core/modules/controller/useOffset.js +10 -0
- package/dist/core/modules/controller/usePointerSwipe.d.ts +3 -0
- package/dist/core/modules/controller/usePointerSwipe.js +61 -0
- package/dist/core/modules/controller/usePreventSwipeNavigation.d.ts +3 -0
- package/dist/core/modules/controller/usePreventSwipeNavigation.js +20 -0
- package/dist/core/modules/controller/useWheelSwipe.d.ts +3 -0
- package/dist/core/modules/controller/useWheelSwipe.js +94 -0
- package/dist/core/utils.d.ts +12 -1
- package/dist/core/utils.js +14 -0
- package/dist/plugins/captions/Captions.d.ts +7 -0
- package/dist/plugins/captions/Captions.js +23 -0
- package/dist/plugins/captions/CaptionsContext.d.ts +8 -0
- package/dist/plugins/captions/CaptionsContext.js +15 -0
- package/dist/plugins/captions/Description.d.ts +5 -0
- package/dist/plugins/captions/Description.js +17 -0
- package/dist/plugins/captions/Title.d.ts +5 -0
- package/dist/plugins/captions/Title.js +9 -0
- package/dist/plugins/{captions.css → captions/captions.css} +0 -2
- package/dist/plugins/{Captions.d.ts → captions/index.d.ts} +3 -9
- package/dist/plugins/captions/index.js +2 -0
- package/dist/plugins/captions/utils.d.ts +1 -0
- package/dist/plugins/captions/utils.js +2 -0
- package/dist/plugins/fullscreen/Fullscreen.d.ts +3 -0
- package/dist/plugins/fullscreen/Fullscreen.js +17 -0
- package/dist/plugins/fullscreen/FullscreenButton.d.ts +8 -0
- package/dist/plugins/{Fullscreen.js → fullscreen/FullscreenButton.js} +16 -30
- package/dist/plugins/fullscreen/FullscreenContext.d.ts +5 -0
- package/dist/plugins/fullscreen/FullscreenContext.js +9 -0
- package/dist/plugins/{Fullscreen.d.ts → fullscreen/index.d.ts} +2 -11
- package/dist/plugins/fullscreen/index.js +2 -0
- package/dist/plugins/index.d.ts +7 -7
- package/dist/plugins/index.js +7 -7
- package/dist/plugins/inline/Inline.d.ts +3 -0
- package/dist/plugins/{Inline.js → inline/Inline.js} +5 -7
- package/dist/plugins/inline/index.d.ts +9 -0
- package/dist/plugins/inline/index.js +2 -0
- package/dist/plugins/slideshow/Slideshow.d.ts +7 -0
- package/dist/plugins/slideshow/Slideshow.js +20 -0
- package/dist/plugins/slideshow/SlideshowButton.d.ts +2 -0
- package/dist/plugins/{Slideshow.js → slideshow/SlideshowButton.js} +17 -44
- package/dist/plugins/{Slideshow.d.ts → slideshow/index.d.ts} +2 -4
- package/dist/plugins/slideshow/index.js +2 -0
- package/dist/plugins/thumbnails/Thumbnail.d.ts +21 -0
- package/dist/plugins/thumbnails/Thumbnail.js +45 -0
- package/dist/plugins/thumbnails/Thumbnails.d.ts +13 -0
- package/dist/plugins/thumbnails/Thumbnails.js +28 -0
- package/dist/plugins/thumbnails/ThumbnailsContainer.d.ts +3 -0
- package/dist/plugins/thumbnails/ThumbnailsContainer.js +14 -0
- package/dist/plugins/thumbnails/ThumbnailsTrack.d.ts +12 -0
- package/dist/plugins/thumbnails/ThumbnailsTrack.js +148 -0
- package/dist/plugins/{Thumbnails.d.ts → thumbnails/index.d.ts} +4 -16
- package/dist/plugins/thumbnails/index.js +2 -0
- package/dist/plugins/{thumbnails.css → thumbnails/thumbnails.css} +27 -37
- package/dist/plugins/thumbnails/utils.d.ts +2 -0
- package/dist/plugins/thumbnails/utils.js +4 -0
- package/dist/plugins/video/Video.d.ts +7 -0
- package/dist/plugins/video/Video.js +24 -0
- package/dist/plugins/video/VideoSlide.d.ts +9 -0
- package/dist/plugins/{Video.js → video/VideoSlide.js} +14 -39
- package/dist/plugins/{Video.d.ts → video/index.d.ts} +5 -13
- package/dist/plugins/video/index.js +2 -0
- package/dist/plugins/zoom/Zoom.d.ts +14 -0
- package/dist/plugins/zoom/Zoom.js +36 -0
- package/dist/plugins/zoom/ZoomButton.d.ts +7 -0
- package/dist/plugins/zoom/ZoomButton.js +50 -0
- package/dist/plugins/zoom/ZoomButtonsGroup.d.ts +5 -0
- package/dist/plugins/zoom/ZoomButtonsGroup.js +23 -0
- package/dist/plugins/zoom/ZoomContainer.d.ts +9 -0
- package/dist/plugins/zoom/ZoomContainer.js +303 -0
- package/dist/plugins/zoom/ZoomContext.d.ts +12 -0
- package/dist/plugins/zoom/ZoomContext.js +18 -0
- package/dist/plugins/zoom/ZoomWrapper.d.ts +3 -0
- package/dist/plugins/zoom/ZoomWrapper.js +26 -0
- package/dist/plugins/{Zoom.d.ts → zoom/index.d.ts} +5 -5
- package/dist/plugins/zoom/index.js +4 -0
- package/dist/props.d.ts +2 -0
- package/dist/props.js +31 -0
- package/dist/styles.css +32 -29
- package/dist/types.d.ts +8 -22
- package/dist/types.js +1 -30
- package/package.json +17 -17
- package/dist/core/hooks/useLatest.d.ts +0 -3
- package/dist/core/hooks/useLatest.js +0 -6
- package/dist/plugins/Captions.js +0 -58
- package/dist/plugins/Inline.d.ts +0 -15
- package/dist/plugins/Thumbnails.js +0 -243
- package/dist/plugins/Zoom.js +0 -441
|
@@ -2,8 +2,9 @@ import * as React from "react";
|
|
|
2
2
|
import { createModule } from "../config.js";
|
|
3
3
|
import { cssClass } from "../utils.js";
|
|
4
4
|
import { useLayoutEffect, useRTL } from "../hooks/index.js";
|
|
5
|
-
|
|
6
|
-
const
|
|
5
|
+
import { CLASS_NO_SCROLL, CLASS_NO_SCROLL_PADDING, MODULE_NO_SCROLL } from "../consts.js";
|
|
6
|
+
const noScroll = cssClass(CLASS_NO_SCROLL);
|
|
7
|
+
const noScrollPadding = cssClass(CLASS_NO_SCROLL_PADDING);
|
|
7
8
|
const isHTMLElement = (element) => "style" in element;
|
|
8
9
|
const padScrollbar = (element, padding, rtl) => {
|
|
9
10
|
const styles = window.getComputedStyle(element);
|
|
@@ -46,4 +47,4 @@ export const NoScroll = ({ children }) => {
|
|
|
46
47
|
}, [rtl]);
|
|
47
48
|
return React.createElement(React.Fragment, null, children);
|
|
48
49
|
};
|
|
49
|
-
export const NoScrollModule = createModule(
|
|
50
|
+
export const NoScrollModule = createModule(MODULE_NO_SCROLL, NoScroll);
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import * as ReactDOM from "react-dom";
|
|
3
|
-
import { LightboxDefaultProps } from "../../
|
|
3
|
+
import { LightboxDefaultProps } from "../../props.js";
|
|
4
4
|
import { createModule } from "../config.js";
|
|
5
|
-
import { clsx, cssClass, cssVar } from "../utils.js";
|
|
6
|
-
import {
|
|
5
|
+
import { clsx, composePrefix, cssClass, cssVar } from "../utils.js";
|
|
6
|
+
import { useEventCallback, useMotionPreference } from "../hooks/index.js";
|
|
7
7
|
import { useEvents, useTimeouts } from "../contexts/index.js";
|
|
8
|
+
import { ACTION_CLOSE, CLASS_NO_SCROLL_PADDING, MODULE_PORTAL } from "../consts.js";
|
|
9
|
+
const cssPrefix = (value) => composePrefix(MODULE_PORTAL, value);
|
|
8
10
|
const setAttribute = (element, attribute, value) => {
|
|
9
11
|
const previousValue = element.getAttribute(attribute);
|
|
10
12
|
element.setAttribute(attribute, value);
|
|
@@ -17,61 +19,70 @@ const setAttribute = (element, attribute, value) => {
|
|
|
17
19
|
}
|
|
18
20
|
};
|
|
19
21
|
};
|
|
20
|
-
export const Portal = ({ children,
|
|
22
|
+
export const Portal = ({ children, animation, styles, className, on, close }) => {
|
|
21
23
|
const [mounted, setMounted] = React.useState(false);
|
|
22
24
|
const [visible, setVisible] = React.useState(false);
|
|
23
25
|
const cleanup = React.useRef([]);
|
|
24
|
-
const latestProps = useLatest(props);
|
|
25
|
-
const latestAnimationDuration = useLatest(!useMotionPreference() ? props.animation.fade : 0);
|
|
26
26
|
const { setTimeout } = useTimeouts();
|
|
27
27
|
const { subscribe } = useEvents();
|
|
28
|
+
const fadeAnimationDuration = !useMotionPreference() ? animation.fade : 0;
|
|
28
29
|
React.useEffect(() => {
|
|
29
30
|
setMounted(true);
|
|
30
|
-
return () =>
|
|
31
|
+
return () => {
|
|
32
|
+
setMounted(false);
|
|
33
|
+
setVisible(false);
|
|
34
|
+
};
|
|
31
35
|
}, []);
|
|
32
|
-
|
|
33
|
-
var _a
|
|
36
|
+
const handleClose = useEventCallback(() => {
|
|
37
|
+
var _a;
|
|
34
38
|
setVisible(false);
|
|
35
|
-
(
|
|
39
|
+
(_a = on.exiting) === null || _a === void 0 ? void 0 : _a.call(on);
|
|
36
40
|
setTimeout(() => {
|
|
37
|
-
var _a
|
|
38
|
-
(
|
|
39
|
-
|
|
40
|
-
},
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
41
|
+
var _a;
|
|
42
|
+
(_a = on.exited) === null || _a === void 0 ? void 0 : _a.call(on);
|
|
43
|
+
close();
|
|
44
|
+
}, fadeAnimationDuration);
|
|
45
|
+
});
|
|
46
|
+
React.useEffect(() => subscribe(ACTION_CLOSE, handleClose), [subscribe, handleClose]);
|
|
47
|
+
const handleEnter = useEventCallback((node) => {
|
|
48
|
+
var _a, _b, _c;
|
|
49
|
+
node.scrollTop;
|
|
50
|
+
setVisible(true);
|
|
51
|
+
(_a = on.entering) === null || _a === void 0 ? void 0 : _a.call(on);
|
|
52
|
+
const elements = (_c = (_b = node.parentNode) === null || _b === void 0 ? void 0 : _b.children) !== null && _c !== void 0 ? _c : [];
|
|
53
|
+
for (let i = 0; i < elements.length; i += 1) {
|
|
54
|
+
const element = elements[i];
|
|
55
|
+
if (["TEMPLATE", "SCRIPT", "STYLE"].indexOf(element.tagName) === -1 && element !== node) {
|
|
56
|
+
cleanup.current.push(setAttribute(element, "inert", "true"));
|
|
57
|
+
cleanup.current.push(setAttribute(element, "aria-hidden", "true"));
|
|
55
58
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
59
|
+
}
|
|
60
|
+
setTimeout(() => {
|
|
61
|
+
var _a;
|
|
62
|
+
(_a = on.entered) === null || _a === void 0 ? void 0 : _a.call(on);
|
|
63
|
+
}, fadeAnimationDuration);
|
|
64
|
+
});
|
|
65
|
+
const handleExit = useEventCallback(() => {
|
|
66
|
+
cleanup.current.forEach((clean) => clean());
|
|
67
|
+
cleanup.current = [];
|
|
68
|
+
});
|
|
69
|
+
const handleRef = React.useCallback((node) => {
|
|
70
|
+
if (node) {
|
|
71
|
+
handleEnter(node);
|
|
60
72
|
}
|
|
61
73
|
else {
|
|
62
|
-
|
|
63
|
-
cleanup.current = [];
|
|
74
|
+
handleExit();
|
|
64
75
|
}
|
|
65
|
-
}, [
|
|
76
|
+
}, [handleEnter, handleExit]);
|
|
66
77
|
return mounted
|
|
67
|
-
? ReactDOM.createPortal(React.createElement("div", { ref:
|
|
68
|
-
...(
|
|
78
|
+
? ReactDOM.createPortal(React.createElement("div", { ref: handleRef, className: clsx(className, cssClass("root"), cssClass(cssPrefix()), cssClass(CLASS_NO_SCROLL_PADDING), visible && cssClass(cssPrefix("open"))), role: "presentation", "aria-live": "polite", style: {
|
|
79
|
+
...(animation.fade !== LightboxDefaultProps.animation.fade
|
|
69
80
|
? {
|
|
70
|
-
[cssVar("fade_animation_duration")]: `${
|
|
81
|
+
[cssVar("fade_animation_duration")]: `${fadeAnimationDuration}ms`,
|
|
71
82
|
}
|
|
72
83
|
: null),
|
|
73
|
-
...
|
|
84
|
+
...styles.root,
|
|
74
85
|
} }, children), document.body)
|
|
75
86
|
: null;
|
|
76
87
|
};
|
|
77
|
-
export const PortalModule = createModule(
|
|
88
|
+
export const PortalModule = createModule(MODULE_PORTAL, Portal);
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { createModule } from "../config.js";
|
|
3
|
-
import { cssClass, label } from "../utils.js";
|
|
3
|
+
import { composePrefix, cssClass, label } from "../utils.js";
|
|
4
4
|
import { useEvents } from "../contexts/index.js";
|
|
5
5
|
import { CloseIcon, IconButton } from "../components/index.js";
|
|
6
6
|
import { useContainerRect } from "../hooks/useContainerRect.js";
|
|
7
|
+
import { ACTION_CLOSE, MODULE_TOOLBAR } from "../consts.js";
|
|
8
|
+
const cssPrefix = (value) => composePrefix(MODULE_TOOLBAR, value);
|
|
7
9
|
export const Toolbar = ({ toolbar: { buttons }, labels, render: { buttonClose, iconClose } }) => {
|
|
8
10
|
const { publish } = useEvents();
|
|
9
11
|
const { setContainerRef, containerRect } = useContainerRect();
|
|
@@ -12,7 +14,7 @@ export const Toolbar = ({ toolbar: { buttons }, labels, render: { buttonClose, i
|
|
|
12
14
|
publish("toolbar-width", containerRect.width);
|
|
13
15
|
}
|
|
14
16
|
}, [publish, containerRect === null || containerRect === void 0 ? void 0 : containerRect.width]);
|
|
15
|
-
const renderCloseButton = () => buttonClose ? (buttonClose()) : (React.createElement(IconButton, { key:
|
|
16
|
-
return (React.createElement("div", { ref: setContainerRef, className: cssClass(
|
|
17
|
+
const renderCloseButton = () => buttonClose ? (buttonClose()) : (React.createElement(IconButton, { key: ACTION_CLOSE, label: label(labels, "Close"), icon: CloseIcon, renderIcon: iconClose, onClick: () => publish(ACTION_CLOSE) }));
|
|
18
|
+
return (React.createElement("div", { ref: setContainerRef, className: cssClass(cssPrefix()) }, buttons === null || buttons === void 0 ? void 0 : buttons.map((button) => (button === ACTION_CLOSE ? renderCloseButton() : button))));
|
|
17
19
|
};
|
|
18
|
-
export const ToolbarModule = createModule(
|
|
20
|
+
export const ToolbarModule = createModule(MODULE_TOOLBAR, Toolbar);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export var SwipeState;
|
|
2
|
+
(function (SwipeState) {
|
|
3
|
+
SwipeState[SwipeState["NONE"] = 0] = "NONE";
|
|
4
|
+
SwipeState[SwipeState["SWIPE"] = 1] = "SWIPE";
|
|
5
|
+
SwipeState[SwipeState["ANIMATION"] = 2] = "ANIMATION";
|
|
6
|
+
})(SwipeState || (SwipeState = {}));
|
|
7
|
+
export * from "./usePointerSwipe.js";
|
|
8
|
+
export * from "./usePreventSwipeNavigation.js";
|
|
9
|
+
export * from "./useWheelSwipe.js";
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { useEventCallback } from "../../hooks/useEventCallback.js";
|
|
3
|
+
export const useOffset = (onChange) => {
|
|
4
|
+
const [offset, setOffset] = React.useState(0);
|
|
5
|
+
const handleOnChange = useEventCallback(() => {
|
|
6
|
+
onChange(offset);
|
|
7
|
+
});
|
|
8
|
+
React.useEffect(handleOnChange, [offset, handleOnChange]);
|
|
9
|
+
return [offset, setOffset];
|
|
10
|
+
};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { UseSensors } from "../../hooks/useSensors.js";
|
|
2
|
+
import { SwipeState } from "./index.js";
|
|
3
|
+
export declare const usePointerSwipe: <T extends Element = Element>(swipeState: SwipeState, subscribeSensors: import("../../hooks/useSensors.js").SubscribeSensors<T>, isSwipeValid: (offset: number) => boolean, containerWidth: number, swipeAnimationDuration: number, onSwipeStart: () => void, onSwipeFinish: (offset: number, duration: number) => void, onSwipeCancel: (offset: number) => void, onChange: (offset: number) => void) => void;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { cleanup } from "../../utils.js";
|
|
3
|
+
import { useEventCallback } from "../../hooks/useEventCallback.js";
|
|
4
|
+
import { SwipeState } from "./index.js";
|
|
5
|
+
import { useOffset } from "./useOffset.js";
|
|
6
|
+
import { EVENT_ON_POINTER_CANCEL, EVENT_ON_POINTER_DOWN, EVENT_ON_POINTER_LEAVE, EVENT_ON_POINTER_MOVE, EVENT_ON_POINTER_UP, } from "../../consts.js";
|
|
7
|
+
export const usePointerSwipe = (swipeState, subscribeSensors, isSwipeValid, containerWidth, swipeAnimationDuration, onSwipeStart, onSwipeFinish, onSwipeCancel, onChange) => {
|
|
8
|
+
const [offset, setOffset] = useOffset(onChange);
|
|
9
|
+
const pointers = React.useRef([]);
|
|
10
|
+
const activePointer = React.useRef();
|
|
11
|
+
const startTime = React.useRef(0);
|
|
12
|
+
const clearPointer = React.useCallback((event) => {
|
|
13
|
+
if (activePointer.current === event.pointerId) {
|
|
14
|
+
activePointer.current = undefined;
|
|
15
|
+
}
|
|
16
|
+
const currentPointers = pointers.current;
|
|
17
|
+
currentPointers.splice(0, currentPointers.length, ...currentPointers.filter((p) => p.pointerId !== event.pointerId));
|
|
18
|
+
}, []);
|
|
19
|
+
const addPointer = React.useCallback((event) => {
|
|
20
|
+
clearPointer(event);
|
|
21
|
+
pointers.current.push(event);
|
|
22
|
+
}, [clearPointer]);
|
|
23
|
+
const onPointerDown = useEventCallback((event) => {
|
|
24
|
+
addPointer(event);
|
|
25
|
+
});
|
|
26
|
+
const onPointerUp = useEventCallback((event) => {
|
|
27
|
+
if (swipeState === SwipeState.SWIPE &&
|
|
28
|
+
pointers.current.find((x) => x.pointerId === event.pointerId) &&
|
|
29
|
+
activePointer.current === event.pointerId) {
|
|
30
|
+
const duration = Date.now() - startTime.current;
|
|
31
|
+
if (Math.abs(offset) > 0.3 * containerWidth ||
|
|
32
|
+
(Math.abs(offset) > 5 && duration < swipeAnimationDuration)) {
|
|
33
|
+
onSwipeFinish(offset, duration);
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
onSwipeCancel(offset);
|
|
37
|
+
}
|
|
38
|
+
setOffset(0);
|
|
39
|
+
}
|
|
40
|
+
clearPointer(event);
|
|
41
|
+
});
|
|
42
|
+
const onPointerMove = useEventCallback((event) => {
|
|
43
|
+
const pointer = pointers.current.find((p) => p.pointerId === event.pointerId);
|
|
44
|
+
if (pointer) {
|
|
45
|
+
const deltaX = event.clientX - pointer.clientX;
|
|
46
|
+
const deltaY = event.clientY - pointer.clientY;
|
|
47
|
+
if (!swipeState) {
|
|
48
|
+
if (isSwipeValid(deltaX) && Math.abs(deltaX) > Math.abs(deltaY) && Math.abs(deltaX) > 30) {
|
|
49
|
+
addPointer(event);
|
|
50
|
+
activePointer.current = event.pointerId;
|
|
51
|
+
startTime.current = Date.now();
|
|
52
|
+
onSwipeStart();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
else if (activePointer.current === event.pointerId) {
|
|
56
|
+
setOffset(deltaX);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
React.useEffect(() => cleanup(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)), [subscribeSensors, onPointerDown, onPointerMove, onPointerUp]);
|
|
61
|
+
};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
/** prevent browser back/forward navigation on touchpad left/right swipe (especially noticeable in Safari)
|
|
2
|
+
* this has to be done via non-passive native event handler */
|
|
3
|
+
export declare const usePreventSwipeNavigation: <T extends HTMLElement = HTMLElement>() => (node: T | null) => void;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
const WHEEL = "wheel";
|
|
3
|
+
const preventDefault = (event) => {
|
|
4
|
+
if (Math.abs(event.deltaX) > Math.abs(event.deltaY) || event.ctrlKey) {
|
|
5
|
+
event.preventDefault();
|
|
6
|
+
}
|
|
7
|
+
};
|
|
8
|
+
export const usePreventSwipeNavigation = () => {
|
|
9
|
+
const ref = React.useRef(null);
|
|
10
|
+
return React.useCallback((node) => {
|
|
11
|
+
var _a;
|
|
12
|
+
if (node) {
|
|
13
|
+
node.addEventListener(WHEEL, preventDefault, { passive: false });
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
(_a = ref.current) === null || _a === void 0 ? void 0 : _a.removeEventListener(WHEEL, preventDefault);
|
|
17
|
+
}
|
|
18
|
+
ref.current = node;
|
|
19
|
+
}, []);
|
|
20
|
+
};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { UseSensors } from "../../hooks/index.js";
|
|
2
|
+
import { SwipeState } from "./index.js";
|
|
3
|
+
export declare const useWheelSwipe: <T extends Element = Element>(swipeState: SwipeState | undefined, subscribeSensors: import("../../hooks/useSensors.js").SubscribeSensors<T>, isSwipeValid: (offset: number) => boolean, containerWidth: number, swipeAnimationDuration: number, onSwipeStart: () => void, onSwipeFinish: (offset: number, duration: number) => void, onSwipeCancel: (offset: number) => void, onChange: (offset: number) => void) => void;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { useEventCallback } from "../../hooks/index.js";
|
|
3
|
+
import { useTimeouts } from "../../contexts/index.js";
|
|
4
|
+
import { SwipeState } from "./index.js";
|
|
5
|
+
import { useOffset } from "./useOffset.js";
|
|
6
|
+
import { EVENT_ON_WHEEL } from "../../consts.js";
|
|
7
|
+
export const useWheelSwipe = (swipeState, subscribeSensors, isSwipeValid, containerWidth, swipeAnimationDuration, onSwipeStart, onSwipeFinish, onSwipeCancel, onChange) => {
|
|
8
|
+
const [offset, setOffset] = useOffset(onChange);
|
|
9
|
+
const swipeIntent = React.useRef(0);
|
|
10
|
+
const swipeIntentCleanup = React.useRef();
|
|
11
|
+
const swipeResetCleanup = React.useRef();
|
|
12
|
+
const wheelResidualMomentum = React.useRef(0);
|
|
13
|
+
const startTime = React.useRef(0);
|
|
14
|
+
const { setTimeout, clearTimeout } = useTimeouts();
|
|
15
|
+
const cancelSwipeIntentCleanup = React.useCallback(() => {
|
|
16
|
+
if (swipeIntentCleanup.current) {
|
|
17
|
+
clearTimeout(swipeIntentCleanup.current);
|
|
18
|
+
swipeIntentCleanup.current = undefined;
|
|
19
|
+
}
|
|
20
|
+
}, [clearTimeout]);
|
|
21
|
+
const cancelSwipeResetCleanup = React.useCallback(() => {
|
|
22
|
+
if (swipeResetCleanup.current) {
|
|
23
|
+
clearTimeout(swipeResetCleanup.current);
|
|
24
|
+
swipeResetCleanup.current = undefined;
|
|
25
|
+
}
|
|
26
|
+
}, [clearTimeout]);
|
|
27
|
+
const handleCleanup = useEventCallback(() => {
|
|
28
|
+
if (swipeState !== SwipeState.SWIPE) {
|
|
29
|
+
if (offset !== 0) {
|
|
30
|
+
setOffset(0);
|
|
31
|
+
}
|
|
32
|
+
startTime.current = 0;
|
|
33
|
+
cancelSwipeIntentCleanup();
|
|
34
|
+
cancelSwipeResetCleanup();
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
React.useEffect(handleCleanup, [swipeState, handleCleanup]);
|
|
38
|
+
const handleCancelSwipe = useEventCallback((currentSwipeOffset) => {
|
|
39
|
+
swipeResetCleanup.current = undefined;
|
|
40
|
+
if (swipeState === SwipeState.SWIPE && offset === currentSwipeOffset) {
|
|
41
|
+
onSwipeCancel(offset);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
const onWheel = useEventCallback((event) => {
|
|
45
|
+
if (event.ctrlKey) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
if (Math.abs(event.deltaY) > Math.abs(event.deltaX)) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if (!swipeState) {
|
|
52
|
+
if (Math.abs(event.deltaX) <= 1.2 * Math.abs(wheelResidualMomentum.current)) {
|
|
53
|
+
wheelResidualMomentum.current = event.deltaX;
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if (!isSwipeValid(-event.deltaX)) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
swipeIntent.current += event.deltaX;
|
|
60
|
+
cancelSwipeIntentCleanup();
|
|
61
|
+
if (Math.abs(swipeIntent.current) > 30) {
|
|
62
|
+
swipeIntent.current = 0;
|
|
63
|
+
wheelResidualMomentum.current = 0;
|
|
64
|
+
startTime.current = Date.now();
|
|
65
|
+
onSwipeStart();
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
const currentSwipeIntent = swipeIntent.current;
|
|
69
|
+
swipeIntentCleanup.current = setTimeout(() => {
|
|
70
|
+
swipeIntentCleanup.current = undefined;
|
|
71
|
+
if (currentSwipeIntent === swipeIntent.current) {
|
|
72
|
+
swipeIntent.current = 0;
|
|
73
|
+
}
|
|
74
|
+
}, swipeAnimationDuration);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
else if (swipeState === SwipeState.SWIPE) {
|
|
78
|
+
let newSwipeOffset = offset - event.deltaX;
|
|
79
|
+
newSwipeOffset = Math.min(Math.abs(newSwipeOffset), containerWidth) * Math.sign(newSwipeOffset);
|
|
80
|
+
setOffset(newSwipeOffset);
|
|
81
|
+
cancelSwipeResetCleanup();
|
|
82
|
+
if (Math.abs(newSwipeOffset) > 0.2 * containerWidth) {
|
|
83
|
+
wheelResidualMomentum.current = event.deltaX;
|
|
84
|
+
onSwipeFinish(newSwipeOffset, Date.now() - startTime.current);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
swipeResetCleanup.current = setTimeout(() => handleCancelSwipe(newSwipeOffset), 2 * swipeAnimationDuration);
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
wheelResidualMomentum.current = event.deltaX;
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
React.useEffect(() => subscribeSensors(EVENT_ON_WHEEL, onWheel), [subscribeSensors, onWheel]);
|
|
94
|
+
};
|
package/dist/core/utils.d.ts
CHANGED
|
@@ -1,11 +1,22 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import { Labels } from "../types.js";
|
|
2
|
+
import { Labels, Slide, SlideImage } from "../types.js";
|
|
3
3
|
export declare const clsx: (...classes: (string | boolean | undefined)[]) => string;
|
|
4
4
|
export declare const cssClass: (name: string) => string;
|
|
5
5
|
export declare const cssVar: (name: string) => string;
|
|
6
|
+
export declare const composePrefix: (base: string, prefix?: string) => string;
|
|
7
|
+
export declare const makeComposePrefix: (base: string) => (prefix?: string) => string;
|
|
6
8
|
export declare const label: (labels: Labels | undefined, lbl: string) => string;
|
|
7
9
|
export declare const cleanup: (...cleaners: (() => void)[]) => () => void;
|
|
8
10
|
export declare const makeUseContext: <T>(name: string, contextName: string, context: React.Context<T | null>) => () => T;
|
|
9
11
|
export declare const hasWindow: () => boolean;
|
|
10
12
|
export declare const isDefined: <T = any>(x: T | undefined) => x is T;
|
|
13
|
+
export declare const isNumber: (value: any) => value is number;
|
|
11
14
|
export declare const round: (value: number, decimals?: number) => number;
|
|
15
|
+
export declare const isImageSlide: (slide: Slide) => slide is SlideImage;
|
|
16
|
+
export declare const parseLengthPercentage: (input: unknown) => {
|
|
17
|
+
pixel: number;
|
|
18
|
+
percent?: undefined;
|
|
19
|
+
} | {
|
|
20
|
+
percent: number;
|
|
21
|
+
pixel?: undefined;
|
|
22
|
+
};
|
package/dist/core/utils.js
CHANGED
|
@@ -3,6 +3,8 @@ export const clsx = (...classes) => [...classes].filter((cls) => Boolean(cls)).j
|
|
|
3
3
|
const cssPrefix = "yarl__";
|
|
4
4
|
export const cssClass = (name) => `${cssPrefix}${name}`;
|
|
5
5
|
export const cssVar = (name) => `--${cssPrefix}${name}`;
|
|
6
|
+
export const composePrefix = (base, prefix) => `${base}${prefix ? `_${prefix}` : ""}`;
|
|
7
|
+
export const makeComposePrefix = (base) => (prefix) => composePrefix(base, prefix);
|
|
6
8
|
export const label = (labels, lbl) => (labels && labels[lbl] ? labels[lbl] : lbl);
|
|
7
9
|
export const cleanup = (...cleaners) => () => {
|
|
8
10
|
cleaners.forEach((cleaner) => {
|
|
@@ -18,7 +20,19 @@ export const makeUseContext = (name, contextName, context) => () => {
|
|
|
18
20
|
};
|
|
19
21
|
export const hasWindow = () => typeof window !== "undefined";
|
|
20
22
|
export const isDefined = (x) => typeof x !== "undefined";
|
|
23
|
+
export const isNumber = (value) => typeof value === "number";
|
|
21
24
|
export const round = (value, decimals = 0) => {
|
|
22
25
|
const factor = 10 ** decimals;
|
|
23
26
|
return Math.round((value + Number.EPSILON) * factor) / factor;
|
|
24
27
|
};
|
|
28
|
+
export const isImageSlide = (slide) => !isDefined(slide.type) || slide.type === "image";
|
|
29
|
+
export const parseLengthPercentage = (input) => {
|
|
30
|
+
if (typeof input === "number") {
|
|
31
|
+
return { pixel: input };
|
|
32
|
+
}
|
|
33
|
+
if (typeof input === "string") {
|
|
34
|
+
const value = parseInt(input, 10);
|
|
35
|
+
return input.endsWith("%") ? { percent: value } : { pixel: value };
|
|
36
|
+
}
|
|
37
|
+
return { pixel: 0 };
|
|
38
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { createModule, MODULE_CONTROLLER, PLUGIN_CAPTIONS } from "../../core/index.js";
|
|
3
|
+
import { CaptionsContextProvider } from "./CaptionsContext.js";
|
|
4
|
+
import { Description } from "./Description.js";
|
|
5
|
+
import { Title } from "./Title.js";
|
|
6
|
+
export const defaultCaptionsProps = {
|
|
7
|
+
descriptionTextAlign: "start",
|
|
8
|
+
descriptionMaxLines: 3,
|
|
9
|
+
};
|
|
10
|
+
export const Captions = ({ augment, addParent }) => {
|
|
11
|
+
addParent(MODULE_CONTROLLER, createModule(PLUGIN_CAPTIONS, CaptionsContextProvider));
|
|
12
|
+
augment(({ render: { slideFooter: renderFooter, ...restRender }, captions, styles, ...restProps }) => ({
|
|
13
|
+
render: {
|
|
14
|
+
slideFooter: (slide) => (React.createElement(React.Fragment, null, renderFooter === null || renderFooter === void 0 ? void 0 :
|
|
15
|
+
renderFooter(slide),
|
|
16
|
+
slide.title && React.createElement(Title, { styles: styles, title: slide.title }),
|
|
17
|
+
slide.description && (React.createElement(Description, { styles: styles, description: slide.description, ...{ ...defaultCaptionsProps, ...captions } })))),
|
|
18
|
+
...restRender,
|
|
19
|
+
},
|
|
20
|
+
styles,
|
|
21
|
+
...restProps,
|
|
22
|
+
}));
|
|
23
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
declare type CaptionsContextType = {
|
|
3
|
+
toolbarWidth?: number;
|
|
4
|
+
};
|
|
5
|
+
export declare const useCaptions: () => CaptionsContextType;
|
|
6
|
+
/** Captions plugin context holder */
|
|
7
|
+
export declare const CaptionsContextProvider: React.FC<React.PropsWithChildren>;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { isDefined, isNumber, makeUseContext, useEvents } from "../../core/index.js";
|
|
3
|
+
const CaptionsContext = React.createContext(null);
|
|
4
|
+
export const useCaptions = makeUseContext("useCaptions", "CaptionsContext", CaptionsContext);
|
|
5
|
+
export const CaptionsContextProvider = ({ children }) => {
|
|
6
|
+
const { subscribe } = useEvents();
|
|
7
|
+
const [toolbarWidth, setToolbarWidth] = React.useState();
|
|
8
|
+
React.useEffect(() => subscribe("toolbar-width", (event) => {
|
|
9
|
+
if (!isDefined(event) || isNumber(event)) {
|
|
10
|
+
setToolbarWidth(event);
|
|
11
|
+
}
|
|
12
|
+
}), [subscribe]);
|
|
13
|
+
const context = React.useMemo(() => ({ toolbarWidth }), [toolbarWidth]);
|
|
14
|
+
return React.createElement(CaptionsContext.Provider, { value: context }, children);
|
|
15
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { LightboxProps, Slide } from "../../types.js";
|
|
3
|
+
declare type DescriptionProps = Pick<LightboxProps, "styles"> & Required<Pick<Slide, "description">> & Required<LightboxProps["captions"]>;
|
|
4
|
+
export declare const Description: React.FC<DescriptionProps>;
|
|
5
|
+
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { clsx, cssVar } from "../../core/index.js";
|
|
3
|
+
import { defaultCaptionsProps } from "./Captions.js";
|
|
4
|
+
import { cssPrefix } from "./utils.js";
|
|
5
|
+
export const Description = ({ description, descriptionTextAlign, descriptionMaxLines, styles, }) => (React.createElement("div", { style: styles.captionsDescriptionContainer, className: clsx(cssPrefix("captions_container"), cssPrefix("description_container")) },
|
|
6
|
+
React.createElement("div", { className: cssPrefix("description"), style: {
|
|
7
|
+
...(descriptionTextAlign !== defaultCaptionsProps.descriptionTextAlign ||
|
|
8
|
+
descriptionMaxLines !== defaultCaptionsProps.descriptionMaxLines
|
|
9
|
+
? {
|
|
10
|
+
style: {
|
|
11
|
+
[cssVar("slide_description_text_align")]: descriptionTextAlign,
|
|
12
|
+
[cssVar("slide_description_max_lines")]: descriptionMaxLines,
|
|
13
|
+
},
|
|
14
|
+
}
|
|
15
|
+
: null),
|
|
16
|
+
...styles.captionsDescription,
|
|
17
|
+
} }, description.split("\n").flatMap((line, index) => [...(index > 0 ? [React.createElement("br", { key: index })] : []), line]))));
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { clsx, cssVar } from "../../core/index.js";
|
|
3
|
+
import { useCaptions } from "./CaptionsContext.js";
|
|
4
|
+
import { cssPrefix } from "./utils.js";
|
|
5
|
+
export const Title = ({ title, styles }) => {
|
|
6
|
+
const { toolbarWidth } = useCaptions();
|
|
7
|
+
return (React.createElement("div", { style: styles.captionsTitleContainer, className: clsx(cssPrefix("captions_container"), cssPrefix("title_container")) },
|
|
8
|
+
React.createElement("div", { style: styles.captionsTitle, className: cssPrefix("title"), ...(toolbarWidth ? { style: { [cssVar("toolbar_width")]: `${toolbarWidth}px` } } : null) }, title)));
|
|
9
|
+
};
|
|
@@ -4,8 +4,6 @@
|
|
|
4
4
|
right: var(--yarl__slide_captions_container_right, 0);
|
|
5
5
|
padding: var(--yarl__slide_captions_container_padding, 16px);
|
|
6
6
|
background: var(--yarl__slide_captions_container_background, rgba(0, 0, 0, 0.5));
|
|
7
|
-
-webkit-transform: translateZ(0);
|
|
8
|
-
transform: translateZ(0);
|
|
9
7
|
}
|
|
10
8
|
.yarl__slide_title {
|
|
11
9
|
color: var(--yarl__slide_title_color, #fff);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Captions } from "./Captions.js";
|
|
2
2
|
declare type TextAlignment = "start" | "end" | "center";
|
|
3
|
-
declare module "
|
|
4
|
-
interface
|
|
3
|
+
declare module "../../types" {
|
|
4
|
+
interface GenericSlide {
|
|
5
5
|
/** slide title */
|
|
6
6
|
title?: string;
|
|
7
7
|
/** slide description */
|
|
@@ -27,10 +27,4 @@ declare module "../types.js" {
|
|
|
27
27
|
captionsDescriptionContainer: "captionsDescriptionContainer";
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
|
-
/** Captions plugin context holder */
|
|
31
|
-
export declare const CaptionsComponent: Component;
|
|
32
|
-
/** Captions plugin module */
|
|
33
|
-
export declare const CaptionsModule: import("../types.js").Module;
|
|
34
|
-
/** Captions plugin */
|
|
35
|
-
export declare const Captions: Plugin;
|
|
36
30
|
export default Captions;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const cssPrefix: (className: string) => string;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { createModule, MODULE_CONTROLLER, PLUGIN_FULLSCREEN, PLUGIN_THUMBNAILS } from "../../core/index.js";
|
|
3
|
+
import { FullscreenButton } from "./FullscreenButton.js";
|
|
4
|
+
import { FullscreenContextProvider } from "./FullscreenContext.js";
|
|
5
|
+
export const Fullscreen = ({ augment, contains, addParent }) => {
|
|
6
|
+
augment(({ toolbar: { buttons, ...restToolbar }, ...restProps }) => ({
|
|
7
|
+
toolbar: {
|
|
8
|
+
buttons: [
|
|
9
|
+
React.createElement(FullscreenButton, { key: PLUGIN_FULLSCREEN, auto: Boolean(restProps.fullscreen), labels: restProps.labels, render: restProps.render }),
|
|
10
|
+
...buttons,
|
|
11
|
+
],
|
|
12
|
+
...restToolbar,
|
|
13
|
+
},
|
|
14
|
+
...restProps,
|
|
15
|
+
}));
|
|
16
|
+
addParent(contains(PLUGIN_THUMBNAILS) ? PLUGIN_THUMBNAILS : MODULE_CONTROLLER, createModule(PLUGIN_FULLSCREEN, FullscreenContextProvider));
|
|
17
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { LightboxProps } from "../../types.js";
|
|
3
|
+
/** Fullscreen button props */
|
|
4
|
+
export declare type FullscreenButtonProps = Pick<LightboxProps, "labels" | "render"> & {
|
|
5
|
+
auto: boolean;
|
|
6
|
+
};
|
|
7
|
+
/** Fullscreen button */
|
|
8
|
+
export declare const FullscreenButton: React.FC<FullscreenButtonProps>;
|