yet-another-react-lightbox 2.3.1 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/components/IconButton.d.ts +1 -1
- package/dist/core/components/ImageSlide.js +5 -2
- package/dist/core/consts.d.ts +7 -5
- package/dist/core/consts.js +2 -0
- package/dist/core/contexts/Events.d.ts +8 -4
- package/dist/core/contexts/Events.js +2 -3
- package/dist/core/contexts/LightboxState.d.ts +6 -4
- package/dist/core/contexts/LightboxState.js +13 -10
- package/dist/core/hooks/index.d.ts +4 -0
- package/dist/core/hooks/index.js +4 -0
- package/dist/core/hooks/useAnimation.d.ts +10 -0
- package/dist/core/hooks/useAnimation.js +48 -0
- package/dist/core/hooks/useDelay.d.ts +1 -0
- package/dist/core/hooks/useDelay.js +10 -0
- package/dist/core/hooks/useLoseFocus.d.ts +4 -0
- package/dist/core/hooks/useLoseFocus.js +19 -0
- package/dist/core/hooks/useThrottle.d.ts +1 -0
- package/dist/core/hooks/useThrottle.js +16 -0
- package/dist/core/modules/Carousel.js +3 -4
- package/dist/core/modules/Controller.d.ts +11 -0
- package/dist/core/modules/Controller.js +46 -59
- package/dist/core/modules/Navigation.js +13 -12
- package/dist/core/modules/Toolbar.d.ts +6 -0
- package/dist/core/modules/Toolbar.js +2 -2
- package/dist/core/utils.d.ts +2 -0
- package/dist/core/utils.js +2 -0
- package/dist/plugins/captions/CaptionsContext.js +2 -6
- package/dist/plugins/fullscreen/Fullscreen.js +1 -7
- package/dist/plugins/fullscreen/FullscreenButton.d.ts +1 -6
- package/dist/plugins/fullscreen/FullscreenButton.js +6 -99
- package/dist/plugins/fullscreen/FullscreenContext.d.ts +7 -3
- package/dist/plugins/fullscreen/FullscreenContext.js +97 -3
- package/dist/plugins/fullscreen/index.d.ts +2 -1
- package/dist/plugins/slideshow/Slideshow.js +7 -11
- package/dist/plugins/slideshow/SlideshowButton.js +6 -55
- package/dist/plugins/slideshow/SlideshowContext.d.ts +9 -0
- package/dist/plugins/slideshow/SlideshowContext.js +58 -0
- package/dist/plugins/thumbnails/ThumbnailsContainer.js +2 -2
- package/dist/plugins/thumbnails/ThumbnailsTrack.d.ts +0 -1
- package/dist/plugins/thumbnails/ThumbnailsTrack.js +28 -46
- package/dist/plugins/video/Video.js +2 -5
- package/dist/plugins/video/index.d.ts +9 -0
- package/dist/plugins/video/index.js +1 -0
- package/dist/plugins/zoom/ZoomContainer.js +1 -1
- package/dist/plugins/zoom/ZoomContext.js +1 -1
- package/dist/plugins/zoom/index.d.ts +6 -0
- package/package.json +1 -1
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import {
|
|
2
|
+
import { makeUseContext, useEvents, YARL_EVENT_TOOLBAR_WIDTH } from "../../core/index.js";
|
|
3
3
|
const CaptionsContext = React.createContext(null);
|
|
4
4
|
export const useCaptions = makeUseContext("useCaptions", "CaptionsContext", CaptionsContext);
|
|
5
5
|
export const CaptionsContextProvider = ({ children }) => {
|
|
6
6
|
const { subscribe } = useEvents();
|
|
7
7
|
const [toolbarWidth, setToolbarWidth] = React.useState();
|
|
8
|
-
React.useEffect(() => subscribe(
|
|
9
|
-
if (!isDefined(event) || isNumber(event)) {
|
|
10
|
-
setToolbarWidth(event);
|
|
11
|
-
}
|
|
12
|
-
}), [subscribe]);
|
|
8
|
+
React.useEffect(() => subscribe(YARL_EVENT_TOOLBAR_WIDTH, (event) => setToolbarWidth(event)), [subscribe]);
|
|
13
9
|
const context = React.useMemo(() => ({ toolbarWidth }), [toolbarWidth]);
|
|
14
10
|
return React.createElement(CaptionsContext.Provider, { value: context }, children);
|
|
15
11
|
};
|
|
@@ -4,13 +4,7 @@ import { FullscreenButton } from "./FullscreenButton.js";
|
|
|
4
4
|
import { FullscreenContextProvider } from "./FullscreenContext.js";
|
|
5
5
|
export const Fullscreen = ({ augment, contains, addParent }) => {
|
|
6
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
|
-
},
|
|
7
|
+
toolbar: { buttons: [React.createElement(FullscreenButton, { key: PLUGIN_FULLSCREEN }), ...buttons], ...restToolbar },
|
|
14
8
|
...restProps,
|
|
15
9
|
}));
|
|
16
10
|
addParent(contains(PLUGIN_THUMBNAILS) ? PLUGIN_THUMBNAILS : MODULE_CONTROLLER, createModule(PLUGIN_FULLSCREEN, FullscreenContextProvider));
|
|
@@ -1,8 +1,3 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import { LightboxProps } from "../../types.js";
|
|
3
|
-
/** Fullscreen button props */
|
|
4
|
-
export type FullscreenButtonProps = Pick<LightboxProps, "labels" | "render"> & {
|
|
5
|
-
auto: boolean;
|
|
6
|
-
};
|
|
7
2
|
/** Fullscreen button */
|
|
8
|
-
export declare const FullscreenButton: React.FC
|
|
3
|
+
export declare const FullscreenButton: React.FC;
|
|
@@ -1,106 +1,13 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import { createIcon, IconButton, label,
|
|
2
|
+
import { createIcon, IconButton, label, useController } from "../../core/index.js";
|
|
3
3
|
import { useFullscreen } from "./FullscreenContext.js";
|
|
4
4
|
const EnterFullscreenIcon = createIcon("EnterFullscreen", React.createElement("path", { d: "M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z" }));
|
|
5
5
|
const ExitFullscreenIcon = createIcon("ExitFullscreen", React.createElement("path", { d: "M5 16h3v3h2v-5H5v2zm3-8H5v2h5V5H8v3zm6 11h2v-3h3v-2h-5v5zm2-11V5h-2v5h5V8h-3z" }));
|
|
6
|
-
export const FullscreenButton = (
|
|
6
|
+
export const FullscreenButton = () => {
|
|
7
7
|
var _a;
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
const isFullscreenEnabled = () => {
|
|
12
|
-
var _a, _b, _c, _d;
|
|
13
|
-
return (_d = (_c = (_b = (_a = document.fullscreenEnabled) !== null && _a !== void 0 ? _a : document.webkitFullscreenEnabled) !== null && _b !== void 0 ? _b : document.mozFullScreenEnabled) !== null && _c !== void 0 ? _c : document.msFullscreenEnabled) !== null && _d !== void 0 ? _d : false;
|
|
14
|
-
};
|
|
15
|
-
const getFullscreenElement = React.useCallback(() => {
|
|
16
|
-
var _a, _b, _c;
|
|
17
|
-
return (_c = (_b = (_a = document.fullscreenElement) !== null && _a !== void 0 ? _a : document.webkitFullscreenElement) !== null && _b !== void 0 ? _b : document.mozFullScreenElement) !== null && _c !== void 0 ? _c : document.msFullscreenElement;
|
|
18
|
-
}, []);
|
|
19
|
-
const requestFullscreen = React.useCallback(() => {
|
|
20
|
-
const container = containerRef.current;
|
|
21
|
-
if (container) {
|
|
22
|
-
try {
|
|
23
|
-
if (container.requestFullscreen) {
|
|
24
|
-
container.requestFullscreen().catch(() => { });
|
|
25
|
-
}
|
|
26
|
-
else if (container.webkitRequestFullscreen) {
|
|
27
|
-
container.webkitRequestFullscreen();
|
|
28
|
-
}
|
|
29
|
-
else if (container.mozRequestFullScreen) {
|
|
30
|
-
container.mozRequestFullScreen();
|
|
31
|
-
}
|
|
32
|
-
else if (container.msRequestFullscreen) {
|
|
33
|
-
container.msRequestFullscreen();
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
catch (err) {
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
}, [containerRef]);
|
|
40
|
-
const exitFullscreen = React.useCallback(() => {
|
|
41
|
-
if (getFullscreenElement()) {
|
|
42
|
-
try {
|
|
43
|
-
if (document.exitFullscreen) {
|
|
44
|
-
document.exitFullscreen().catch(() => { });
|
|
45
|
-
}
|
|
46
|
-
else if (document.webkitExitFullscreen) {
|
|
47
|
-
document.webkitExitFullscreen();
|
|
48
|
-
}
|
|
49
|
-
else if (document.mozCancelFullScreen) {
|
|
50
|
-
document.mozCancelFullScreen();
|
|
51
|
-
}
|
|
52
|
-
else if (document.msExitFullscreen) {
|
|
53
|
-
document.msExitFullscreen();
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
catch (err) {
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}, [getFullscreenElement]);
|
|
60
|
-
const toggleFullscreen = React.useCallback(() => {
|
|
61
|
-
if (fullscreen) {
|
|
62
|
-
exitFullscreen();
|
|
63
|
-
}
|
|
64
|
-
else {
|
|
65
|
-
requestFullscreen();
|
|
66
|
-
}
|
|
67
|
-
}, [fullscreen, requestFullscreen, exitFullscreen]);
|
|
68
|
-
const fullscreenChangeListener = React.useCallback(() => {
|
|
69
|
-
if (getFullscreenElement() === containerRef.current) {
|
|
70
|
-
setFullscreen(true);
|
|
71
|
-
}
|
|
72
|
-
else {
|
|
73
|
-
setFullscreen(false);
|
|
74
|
-
}
|
|
75
|
-
}, [containerRef, getFullscreenElement]);
|
|
76
|
-
React.useEffect(() => {
|
|
77
|
-
setMounted(true);
|
|
78
|
-
return () => setMounted(false);
|
|
79
|
-
}, []);
|
|
80
|
-
React.useEffect(() => {
|
|
81
|
-
const events = ["fullscreenchange", "webkitfullscreenchange", "mozfullscreenchange", "MSFullscreenChange"];
|
|
82
|
-
events.forEach((event) => {
|
|
83
|
-
document.addEventListener(event, fullscreenChangeListener);
|
|
84
|
-
});
|
|
85
|
-
return () => {
|
|
86
|
-
events.forEach((event) => {
|
|
87
|
-
document.removeEventListener(event, fullscreenChangeListener);
|
|
88
|
-
});
|
|
89
|
-
};
|
|
90
|
-
}, [fullscreenChangeListener]);
|
|
91
|
-
const handleAutoFullscreen = useEventCallback(() => {
|
|
92
|
-
if (auto) {
|
|
93
|
-
requestFullscreen();
|
|
94
|
-
}
|
|
95
|
-
});
|
|
96
|
-
React.useEffect(() => {
|
|
97
|
-
handleAutoFullscreen();
|
|
98
|
-
return () => {
|
|
99
|
-
exitFullscreen();
|
|
100
|
-
};
|
|
101
|
-
}, [handleAutoFullscreen, exitFullscreen]);
|
|
102
|
-
if (!mounted || !isFullscreenEnabled())
|
|
8
|
+
const { labels, render } = useController().getLightboxProps();
|
|
9
|
+
const { fullscreen, fullscreenEnabled, toggleFullscreen } = useFullscreen();
|
|
10
|
+
if (!fullscreenEnabled)
|
|
103
11
|
return null;
|
|
104
|
-
|
|
105
|
-
return customButton === undefined ? (React.createElement(IconButton, { label: fullscreen ? label(labels, "Exit Fullscreen") : label(labels, "Enter Fullscreen"), icon: fullscreen ? ExitFullscreenIcon : EnterFullscreenIcon, renderIcon: fullscreen ? render.iconExitFullscreen : render.iconEnterFullscreen, onClick: toggleFullscreen })) : (React.createElement(React.Fragment, null, customButton));
|
|
12
|
+
return render.buttonFullscreen ? (React.createElement(React.Fragment, null, (_a = render.buttonFullscreen) === null || _a === void 0 ? void 0 : _a.call(render, { fullscreen, fullscreenEnabled, toggleFullscreen }))) : (React.createElement(IconButton, { disabled: !fullscreenEnabled, label: fullscreen ? label(labels, "Exit Fullscreen") : label(labels, "Enter Fullscreen"), icon: fullscreen ? ExitFullscreenIcon : EnterFullscreenIcon, renderIcon: fullscreen ? render.iconExitFullscreen : render.iconEnterFullscreen, onClick: toggleFullscreen }));
|
|
106
13
|
};
|
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
import
|
|
2
|
-
type FullscreenContextType =
|
|
1
|
+
import { Component } from "../../types.js";
|
|
2
|
+
type FullscreenContextType = {
|
|
3
|
+
fullscreen: boolean;
|
|
4
|
+
fullscreenEnabled?: boolean;
|
|
5
|
+
toggleFullscreen: () => void;
|
|
6
|
+
};
|
|
3
7
|
export declare const useFullscreen: () => FullscreenContextType;
|
|
4
|
-
export declare const FullscreenContextProvider:
|
|
8
|
+
export declare const FullscreenContextProvider: Component;
|
|
5
9
|
export {};
|
|
@@ -1,9 +1,103 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import { CLASS_FULLSIZE, clsx, cssClass, makeUseContext, PLUGIN_FULLSCREEN } from "../../core/index.js";
|
|
2
|
+
import { CLASS_FULLSIZE, clsx, cssClass, makeUseContext, PLUGIN_FULLSCREEN, useEventCallback, useLayoutEffect, } from "../../core/index.js";
|
|
3
3
|
const FullscreenContext = React.createContext(null);
|
|
4
4
|
export const useFullscreen = makeUseContext("useFullscreen", "FullscreenContext", FullscreenContext);
|
|
5
|
-
export const FullscreenContextProvider = ({ children }) => {
|
|
5
|
+
export const FullscreenContextProvider = ({ fullscreen: auto, children }) => {
|
|
6
6
|
const containerRef = React.useRef(null);
|
|
7
|
+
const [fullscreen, setFullscreen] = React.useState(false);
|
|
8
|
+
const [fullscreenEnabled, setFullscreenEnabled] = React.useState();
|
|
9
|
+
useLayoutEffect(() => {
|
|
10
|
+
var _a, _b, _c, _d;
|
|
11
|
+
setFullscreenEnabled((_d = (_c = (_b = (_a = document.fullscreenEnabled) !== null && _a !== void 0 ? _a : document.webkitFullscreenEnabled) !== null && _b !== void 0 ? _b : document.mozFullScreenEnabled) !== null && _c !== void 0 ? _c : document.msFullscreenEnabled) !== null && _d !== void 0 ? _d : false);
|
|
12
|
+
}, []);
|
|
13
|
+
const getFullscreenElement = React.useCallback(() => {
|
|
14
|
+
var _a, _b, _c;
|
|
15
|
+
return (_c = (_b = (_a = document.fullscreenElement) !== null && _a !== void 0 ? _a : document.webkitFullscreenElement) !== null && _b !== void 0 ? _b : document.mozFullScreenElement) !== null && _c !== void 0 ? _c : document.msFullscreenElement;
|
|
16
|
+
}, []);
|
|
17
|
+
const requestFullscreen = React.useCallback(() => {
|
|
18
|
+
const container = containerRef.current;
|
|
19
|
+
if (container) {
|
|
20
|
+
try {
|
|
21
|
+
if (container.requestFullscreen) {
|
|
22
|
+
container.requestFullscreen().catch(() => { });
|
|
23
|
+
}
|
|
24
|
+
else if (container.webkitRequestFullscreen) {
|
|
25
|
+
container.webkitRequestFullscreen();
|
|
26
|
+
}
|
|
27
|
+
else if (container.mozRequestFullScreen) {
|
|
28
|
+
container.mozRequestFullScreen();
|
|
29
|
+
}
|
|
30
|
+
else if (container.msRequestFullscreen) {
|
|
31
|
+
container.msRequestFullscreen();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
catch (err) {
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}, []);
|
|
38
|
+
const exitFullscreen = React.useCallback(() => {
|
|
39
|
+
if (getFullscreenElement()) {
|
|
40
|
+
try {
|
|
41
|
+
if (document.exitFullscreen) {
|
|
42
|
+
document.exitFullscreen().catch(() => { });
|
|
43
|
+
}
|
|
44
|
+
else if (document.webkitExitFullscreen) {
|
|
45
|
+
document.webkitExitFullscreen();
|
|
46
|
+
}
|
|
47
|
+
else if (document.mozCancelFullScreen) {
|
|
48
|
+
document.mozCancelFullScreen();
|
|
49
|
+
}
|
|
50
|
+
else if (document.msExitFullscreen) {
|
|
51
|
+
document.msExitFullscreen();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}, [getFullscreenElement]);
|
|
58
|
+
const toggleFullscreen = React.useCallback(() => {
|
|
59
|
+
if (fullscreen) {
|
|
60
|
+
exitFullscreen();
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
requestFullscreen();
|
|
64
|
+
}
|
|
65
|
+
}, [fullscreen, requestFullscreen, exitFullscreen]);
|
|
66
|
+
const fullscreenChangeListener = React.useCallback(() => {
|
|
67
|
+
if (getFullscreenElement() === containerRef.current) {
|
|
68
|
+
setFullscreen(true);
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
setFullscreen(false);
|
|
72
|
+
}
|
|
73
|
+
}, [getFullscreenElement]);
|
|
74
|
+
React.useEffect(() => {
|
|
75
|
+
const events = ["fullscreenchange", "webkitfullscreenchange", "mozfullscreenchange", "MSFullscreenChange"];
|
|
76
|
+
events.forEach((event) => {
|
|
77
|
+
document.addEventListener(event, fullscreenChangeListener);
|
|
78
|
+
});
|
|
79
|
+
return () => {
|
|
80
|
+
events.forEach((event) => {
|
|
81
|
+
document.removeEventListener(event, fullscreenChangeListener);
|
|
82
|
+
});
|
|
83
|
+
};
|
|
84
|
+
}, [fullscreenChangeListener]);
|
|
85
|
+
const handleAutoFullscreen = useEventCallback(() => {
|
|
86
|
+
if (auto) {
|
|
87
|
+
requestFullscreen();
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
React.useEffect(() => {
|
|
91
|
+
handleAutoFullscreen();
|
|
92
|
+
return () => {
|
|
93
|
+
exitFullscreen();
|
|
94
|
+
};
|
|
95
|
+
}, [handleAutoFullscreen, exitFullscreen]);
|
|
96
|
+
const context = React.useMemo(() => ({
|
|
97
|
+
fullscreen,
|
|
98
|
+
fullscreenEnabled,
|
|
99
|
+
toggleFullscreen,
|
|
100
|
+
}), [fullscreen, fullscreenEnabled, toggleFullscreen]);
|
|
7
101
|
return (React.createElement("div", { ref: containerRef, className: clsx(cssClass(PLUGIN_FULLSCREEN), cssClass(CLASS_FULLSIZE)) },
|
|
8
|
-
React.createElement(FullscreenContext.Provider, { value:
|
|
102
|
+
React.createElement(FullscreenContext.Provider, { value: context }, children)));
|
|
9
103
|
};
|
|
@@ -7,8 +7,9 @@ declare module "../../types" {
|
|
|
7
7
|
}
|
|
8
8
|
interface Render {
|
|
9
9
|
/** render custom Enter/Exit Fullscreen button */
|
|
10
|
-
buttonFullscreen?: ({ fullscreen, toggleFullscreen, }: {
|
|
10
|
+
buttonFullscreen?: ({ fullscreen, fullscreenEnabled, toggleFullscreen, }: {
|
|
11
11
|
fullscreen: boolean;
|
|
12
|
+
fullscreenEnabled: boolean | undefined;
|
|
12
13
|
toggleFullscreen: () => void;
|
|
13
14
|
}) => React.ReactNode;
|
|
14
15
|
/** render custom Enter Fullscreen icon */
|
|
@@ -1,20 +1,16 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
+
import { createModule, MODULE_CONTROLLER, PLUGIN_SLIDESHOW } from "../../core/index.js";
|
|
3
|
+
import { SlideshowContextProvider } from "./SlideshowContext.js";
|
|
2
4
|
import { SlideshowButton } from "./SlideshowButton.js";
|
|
3
|
-
import { PLUGIN_SLIDESHOW } from "../../core/index.js";
|
|
4
5
|
export const defaultSlideshowProps = {
|
|
5
6
|
autoplay: false,
|
|
6
7
|
delay: 3000,
|
|
7
8
|
};
|
|
8
|
-
export const Slideshow = ({ augment }) => {
|
|
9
|
-
augment(({ slideshow:
|
|
10
|
-
toolbar: {
|
|
11
|
-
|
|
12
|
-
...restToolbar,
|
|
13
|
-
},
|
|
14
|
-
slideshow: {
|
|
15
|
-
...defaultSlideshowProps,
|
|
16
|
-
...originalSlideshow,
|
|
17
|
-
},
|
|
9
|
+
export const Slideshow = ({ augment, append }) => {
|
|
10
|
+
augment(({ slideshow: slideshowProps, toolbar: { buttons, ...restToolbar }, ...restProps }) => ({
|
|
11
|
+
toolbar: { buttons: [React.createElement(SlideshowButton, { key: PLUGIN_SLIDESHOW }), ...buttons], ...restToolbar },
|
|
12
|
+
slideshow: { ...defaultSlideshowProps, ...slideshowProps },
|
|
18
13
|
...restProps,
|
|
19
14
|
}));
|
|
15
|
+
append(MODULE_CONTROLLER, createModule(PLUGIN_SLIDESHOW, SlideshowContextProvider));
|
|
20
16
|
};
|
|
@@ -1,61 +1,12 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { createIcon, IconButton, label, useController, useLoseFocus } from "../../core/index.js";
|
|
3
|
+
import { useSlideshow } from "./SlideshowContext.js";
|
|
4
4
|
const PlayIcon = createIcon("Play", React.createElement("path", { d: "M8 5v14l11-7z" }));
|
|
5
5
|
const PauseIcon = createIcon("Pause", React.createElement("path", { d: "M6 19h4V5H6v14zm8-14v14h4V5h-4z" }));
|
|
6
6
|
export const SlideshowButton = () => {
|
|
7
|
-
const {
|
|
7
|
+
const { playing, disabled, togglePlaying } = useSlideshow();
|
|
8
8
|
const { getLightboxProps } = useController();
|
|
9
|
-
const {
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
const slidesCount = slides.length;
|
|
13
|
-
const slideshow = { ...defaultSlideshowProps, ...slideshowProps };
|
|
14
|
-
const [playing, setPlaying] = React.useState(slideshow.autoplay);
|
|
15
|
-
const scheduler = React.useRef();
|
|
16
|
-
const slideStatus = React.useRef();
|
|
17
|
-
const cancelScheduler = React.useCallback(() => {
|
|
18
|
-
clearTimeout(scheduler.current);
|
|
19
|
-
scheduler.current = undefined;
|
|
20
|
-
}, [clearTimeout]);
|
|
21
|
-
const reachedLastSlide = useEventCallback(() => slides.length === 0 || (finite && currentIndex === slidesCount - 1));
|
|
22
|
-
const scheduleNextSlide = useEventCallback(() => {
|
|
23
|
-
cancelScheduler();
|
|
24
|
-
if (!playing ||
|
|
25
|
-
reachedLastSlide() ||
|
|
26
|
-
slideStatus.current === SLIDE_STATUS_LOADING ||
|
|
27
|
-
slideStatus.current === SLIDE_STATUS_PLAYING) {
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
scheduler.current = setTimeout(() => {
|
|
31
|
-
if (playing) {
|
|
32
|
-
slideStatus.current = undefined;
|
|
33
|
-
publish(ACTION_NEXT);
|
|
34
|
-
}
|
|
35
|
-
}, slideshow.delay);
|
|
36
|
-
});
|
|
37
|
-
const togglePlaying = React.useCallback(() => {
|
|
38
|
-
setPlaying((prev) => !prev);
|
|
39
|
-
}, []);
|
|
40
|
-
React.useEffect(scheduleNextSlide, [currentIndex, playing, scheduleNextSlide]);
|
|
41
|
-
React.useEffect(() => {
|
|
42
|
-
if (playing && reachedLastSlide()) {
|
|
43
|
-
setPlaying(false);
|
|
44
|
-
}
|
|
45
|
-
}, [currentIndex, playing, reachedLastSlide]);
|
|
46
|
-
React.useEffect(() => cleanup(subscribe(ACTIVE_SLIDE_LOADING, () => {
|
|
47
|
-
slideStatus.current = SLIDE_STATUS_LOADING;
|
|
48
|
-
cancelScheduler();
|
|
49
|
-
}), subscribe(ACTIVE_SLIDE_PLAYING, () => {
|
|
50
|
-
slideStatus.current = SLIDE_STATUS_PLAYING;
|
|
51
|
-
cancelScheduler();
|
|
52
|
-
}), subscribe(ACTIVE_SLIDE_ERROR, () => {
|
|
53
|
-
slideStatus.current = SLIDE_STATUS_ERROR;
|
|
54
|
-
scheduleNextSlide();
|
|
55
|
-
}), subscribe(ACTIVE_SLIDE_COMPLETE, () => {
|
|
56
|
-
slideStatus.current = SLIDE_STATUS_COMPLETE;
|
|
57
|
-
scheduleNextSlide();
|
|
58
|
-
}), cancelScheduler), [subscribe, cancelScheduler, scheduleNextSlide]);
|
|
59
|
-
const disabled = reachedLastSlide();
|
|
60
|
-
return render.buttonSlideshow ? (React.createElement(React.Fragment, null, render.buttonSlideshow({ playing, togglePlaying, disabled }))) : (React.createElement(IconButton, { label: playing ? label(labels, "Pause") : label(labels, "Play"), icon: playing ? PauseIcon : PlayIcon, renderIcon: playing ? render.iconSlideshowPause : render.iconSlideshowPlay, onClick: togglePlaying, disabled: disabled, "aria-disabled": disabled }));
|
|
9
|
+
const { render, labels } = getLightboxProps();
|
|
10
|
+
const focusListeners = useLoseFocus(disabled);
|
|
11
|
+
return render.buttonSlideshow ? (React.createElement(React.Fragment, null, render.buttonSlideshow({ playing, togglePlaying, disabled }))) : (React.createElement(IconButton, { label: playing ? label(labels, "Pause") : label(labels, "Play"), icon: playing ? PauseIcon : PlayIcon, renderIcon: playing ? render.iconSlideshowPause : render.iconSlideshowPlay, onClick: togglePlaying, disabled: disabled, ...focusListeners }));
|
|
61
12
|
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Component } from "../../types.js";
|
|
2
|
+
type SlideshowContextType = {
|
|
3
|
+
playing: boolean;
|
|
4
|
+
disabled: boolean;
|
|
5
|
+
togglePlaying: () => void;
|
|
6
|
+
};
|
|
7
|
+
export declare const useSlideshow: () => SlideshowContextType;
|
|
8
|
+
export declare const SlideshowContextProvider: Component;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { ACTION_NEXT, ACTIVE_SLIDE_COMPLETE, ACTIVE_SLIDE_ERROR, ACTIVE_SLIDE_LOADING, ACTIVE_SLIDE_PLAYING, cleanup, makeUseContext, SLIDE_STATUS_COMPLETE, SLIDE_STATUS_ERROR, SLIDE_STATUS_LOADING, SLIDE_STATUS_PLAYING, useEventCallback, useEvents, useLightboxState, useTimeouts, } from "../../core/index.js";
|
|
3
|
+
import { defaultSlideshowProps } from "./Slideshow.js";
|
|
4
|
+
const SlideshowContext = React.createContext(null);
|
|
5
|
+
export const useSlideshow = makeUseContext("useSlideshow", "SlideshowContext", SlideshowContext);
|
|
6
|
+
export const SlideshowContextProvider = ({ slides, slideshow, carousel: { finite }, children }) => {
|
|
7
|
+
const { autoplay, delay } = { ...defaultSlideshowProps, ...slideshow };
|
|
8
|
+
const [playing, setPlaying] = React.useState(autoplay);
|
|
9
|
+
const scheduler = React.useRef();
|
|
10
|
+
const slideStatus = React.useRef();
|
|
11
|
+
const { currentIndex } = useLightboxState().state;
|
|
12
|
+
const { setTimeout, clearTimeout } = useTimeouts();
|
|
13
|
+
const { publish, subscribe } = useEvents();
|
|
14
|
+
const disabled = slides.length === 0 || (finite && currentIndex === slides.length - 1);
|
|
15
|
+
const togglePlaying = React.useCallback(() => {
|
|
16
|
+
setPlaying((prev) => !prev);
|
|
17
|
+
}, []);
|
|
18
|
+
const cancelScheduler = React.useCallback(() => {
|
|
19
|
+
clearTimeout(scheduler.current);
|
|
20
|
+
scheduler.current = undefined;
|
|
21
|
+
}, [clearTimeout]);
|
|
22
|
+
const scheduleNextSlide = useEventCallback(() => {
|
|
23
|
+
cancelScheduler();
|
|
24
|
+
if (!playing ||
|
|
25
|
+
disabled ||
|
|
26
|
+
slideStatus.current === SLIDE_STATUS_LOADING ||
|
|
27
|
+
slideStatus.current === SLIDE_STATUS_PLAYING) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
scheduler.current = setTimeout(() => {
|
|
31
|
+
if (playing) {
|
|
32
|
+
slideStatus.current = undefined;
|
|
33
|
+
publish(ACTION_NEXT);
|
|
34
|
+
}
|
|
35
|
+
}, delay);
|
|
36
|
+
});
|
|
37
|
+
React.useEffect(scheduleNextSlide, [currentIndex, playing, scheduleNextSlide]);
|
|
38
|
+
React.useEffect(() => {
|
|
39
|
+
if (playing && disabled) {
|
|
40
|
+
setPlaying(false);
|
|
41
|
+
}
|
|
42
|
+
}, [currentIndex, playing, disabled]);
|
|
43
|
+
React.useEffect(() => cleanup(cancelScheduler, subscribe(ACTIVE_SLIDE_LOADING, () => {
|
|
44
|
+
slideStatus.current = SLIDE_STATUS_LOADING;
|
|
45
|
+
cancelScheduler();
|
|
46
|
+
}), subscribe(ACTIVE_SLIDE_PLAYING, () => {
|
|
47
|
+
slideStatus.current = SLIDE_STATUS_PLAYING;
|
|
48
|
+
cancelScheduler();
|
|
49
|
+
}), subscribe(ACTIVE_SLIDE_ERROR, () => {
|
|
50
|
+
slideStatus.current = SLIDE_STATUS_ERROR;
|
|
51
|
+
scheduleNextSlide();
|
|
52
|
+
}), subscribe(ACTIVE_SLIDE_COMPLETE, () => {
|
|
53
|
+
slideStatus.current = SLIDE_STATUS_COMPLETE;
|
|
54
|
+
scheduleNextSlide();
|
|
55
|
+
})), [subscribe, cancelScheduler, scheduleNextSlide]);
|
|
56
|
+
const context = React.useMemo(() => ({ playing, disabled, togglePlaying }), [playing, disabled, togglePlaying]);
|
|
57
|
+
return React.createElement(SlideshowContext.Provider, { value: context }, children);
|
|
58
|
+
};
|
|
@@ -3,10 +3,10 @@ import { clsx, cssClass } from "../../core/index.js";
|
|
|
3
3
|
import { cssPrefix } from "./utils.js";
|
|
4
4
|
import { ThumbnailsTrack } from "./ThumbnailsTrack.js";
|
|
5
5
|
import { defaultThumbnailsProps } from "./Thumbnails.js";
|
|
6
|
-
export const ThumbnailsComponent = ({ thumbnails: thumbnailsProps, slides,
|
|
6
|
+
export const ThumbnailsComponent = ({ thumbnails: thumbnailsProps, slides, carousel, animation, render, styles, children, }) => {
|
|
7
7
|
const thumbnails = { ...defaultThumbnailsProps, ...thumbnailsProps };
|
|
8
8
|
const ref = React.useRef(null);
|
|
9
|
-
const track = (React.createElement(ThumbnailsTrack, { container: ref, slides: slides, thumbnails: thumbnails, carousel: carousel, animation: animation, render: render,
|
|
9
|
+
const track = (React.createElement(ThumbnailsTrack, { container: ref, slides: slides, thumbnails: thumbnails, carousel: carousel, animation: animation, render: render, thumbnailRect: { width: thumbnails.width, height: thumbnails.height }, styles: styles }));
|
|
10
10
|
return (React.createElement("div", { ref: ref, className: clsx(cssClass(cssPrefix()), cssClass(cssPrefix(`${thumbnails.position}`))) },
|
|
11
11
|
(thumbnails.position === "start" || thumbnails.position === "top") && track,
|
|
12
12
|
React.createElement("div", { className: cssClass(cssPrefix("wrapper")) }, children),
|
|
@@ -4,7 +4,6 @@ type ThumbnailsInternal = DeepNonNullable<LightboxProps["thumbnails"]>;
|
|
|
4
4
|
type ThumbnailsTrackProps = Pick<LightboxProps, "slides" | "carousel" | "animation" | "render" | "styles"> & {
|
|
5
5
|
container: React.RefObject<HTMLDivElement>;
|
|
6
6
|
thumbnails: ThumbnailsInternal;
|
|
7
|
-
startingIndex: number;
|
|
8
7
|
thumbnailRect: ContainerRect;
|
|
9
8
|
};
|
|
10
9
|
export declare const ThumbnailsTrack: React.FC<ThumbnailsTrackProps>;
|
|
@@ -1,67 +1,49 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import { ACTION_NEXT, ACTION_PREV, CLASS_FLEX_CENTER, clsx, cssClass, cssVar,
|
|
2
|
+
import { ACTION_NEXT, ACTION_PREV, ACTION_SWIPE, CLASS_FLEX_CENTER, cleanup, clsx, cssClass, cssVar, getSlide, useAnimation, useEventCallback, useEvents, useLightboxState, useRTL, } from "../../core/index.js";
|
|
3
3
|
import { cssPrefix, cssThumbnailPrefix } from "./utils.js";
|
|
4
4
|
import { Thumbnail } from "./Thumbnail.js";
|
|
5
5
|
import { defaultThumbnailsProps } from "./Thumbnails.js";
|
|
6
6
|
const isHorizontal = (position) => ["top", "bottom"].includes(position);
|
|
7
7
|
const boxSize = (thumbnails, dimension, includeGap) => dimension + 2 * (thumbnails.border + thumbnails.padding) + (includeGap ? thumbnails.gap : 0);
|
|
8
|
-
const
|
|
9
|
-
export const ThumbnailsTrack = ({ container, startingIndex, slides, carousel, render, thumbnails, thumbnailRect, styles, }) => {
|
|
10
|
-
const [index, setIndex] = React.useState(startingIndex);
|
|
11
|
-
const [offset, setOffset] = React.useState(0);
|
|
8
|
+
export const ThumbnailsTrack = ({ container, slides, carousel, render, thumbnails, thumbnailRect, styles, }) => {
|
|
12
9
|
const track = React.useRef(null);
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
const { state: { globalIndex, animationDuration }, } = useLightboxState();
|
|
16
|
-
const { publish } = useEvents();
|
|
17
|
-
const reduceMotion = useMotionPreference();
|
|
10
|
+
const { globalIndex, animation } = useLightboxState().state;
|
|
11
|
+
const { publish, subscribe } = useEvents();
|
|
18
12
|
const isRTL = useRTL();
|
|
13
|
+
const index = globalIndex;
|
|
14
|
+
const offset = (animation === null || animation === void 0 ? void 0 : animation.increment) || 0;
|
|
15
|
+
const animationDuration = (animation === null || animation === void 0 ? void 0 : animation.duration) || 0;
|
|
16
|
+
const animate = useAnimation(track, (snapshot) => ({
|
|
17
|
+
keyframes: isHorizontal(thumbnails.position)
|
|
18
|
+
? [
|
|
19
|
+
{
|
|
20
|
+
transform: `translateX(${(isRTL ? -1 : 1) * boxSize(thumbnails, thumbnails.width, true) * offset + snapshot}px)`,
|
|
21
|
+
},
|
|
22
|
+
{ transform: "translateX(0)" },
|
|
23
|
+
]
|
|
24
|
+
: [
|
|
25
|
+
{
|
|
26
|
+
transform: `translateY(${boxSize(thumbnails, thumbnails.height, true) * offset + snapshot}px)`,
|
|
27
|
+
},
|
|
28
|
+
{ transform: "translateY(0)" },
|
|
29
|
+
],
|
|
30
|
+
duration: animationDuration,
|
|
31
|
+
}));
|
|
19
32
|
const handleControllerSwipe = useEventCallback(() => {
|
|
33
|
+
let animationOffset;
|
|
20
34
|
if (container.current && track.current) {
|
|
21
35
|
const containerRect = container.current.getBoundingClientRect();
|
|
22
36
|
const trackRect = track.current.getBoundingClientRect();
|
|
23
|
-
animationOffset
|
|
37
|
+
animationOffset = isHorizontal(thumbnails.position)
|
|
24
38
|
? trackRect.left - containerRect.left - (containerRect.width - trackRect.width) / 2
|
|
25
39
|
: trackRect.top - containerRect.top - (containerRect.height - trackRect.height) / 2;
|
|
26
40
|
}
|
|
27
41
|
else {
|
|
28
|
-
animationOffset
|
|
42
|
+
animationOffset = 0;
|
|
29
43
|
}
|
|
30
|
-
|
|
31
|
-
setOffset(globalIndex - index);
|
|
44
|
+
animate(animationOffset);
|
|
32
45
|
});
|
|
33
|
-
React.useEffect(handleControllerSwipe, [
|
|
34
|
-
const getCurrentIndex = useEventCallback(() => index);
|
|
35
|
-
const handleIndexOffsetChange = useEventCallback(() => {
|
|
36
|
-
var _a, _b, _c;
|
|
37
|
-
if (track.current && offset) {
|
|
38
|
-
(_a = animationRef.current) === null || _a === void 0 ? void 0 : _a.cancel();
|
|
39
|
-
animationRef.current = (_c = (_b = track.current).animate) === null || _c === void 0 ? void 0 : _c.call(_b, isHorizontal(thumbnails.position)
|
|
40
|
-
? [
|
|
41
|
-
{
|
|
42
|
-
transform: `translateX(${(isRTL ? -1 : 1) * boxSize(thumbnails, thumbnails.width, true) * offset +
|
|
43
|
-
animationOffset.current}px)`,
|
|
44
|
-
},
|
|
45
|
-
{ transform: "translateX(0)" },
|
|
46
|
-
]
|
|
47
|
-
: [
|
|
48
|
-
{
|
|
49
|
-
transform: `translateY(${boxSize(thumbnails, thumbnails.height, true) * offset + animationOffset.current}px)`,
|
|
50
|
-
},
|
|
51
|
-
{ transform: "translateY(0)" },
|
|
52
|
-
], !reduceMotion ? animationDuration : 0);
|
|
53
|
-
if (animationRef.current) {
|
|
54
|
-
animationRef.current.onfinish = () => {
|
|
55
|
-
animationRef.current = undefined;
|
|
56
|
-
if (getCurrentIndex() === index) {
|
|
57
|
-
setOffset(0);
|
|
58
|
-
}
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
animationOffset.current = 0;
|
|
62
|
-
}
|
|
63
|
-
});
|
|
64
|
-
useLayoutEffect(handleIndexOffsetChange, [index, offset, handleIndexOffsetChange]);
|
|
46
|
+
React.useEffect(() => cleanup(subscribe(ACTION_SWIPE, handleControllerSwipe)), [subscribe, handleControllerSwipe]);
|
|
65
47
|
const { finite } = carousel;
|
|
66
48
|
const preload = Math.max(Math.min(carousel.preload, slides.length - 1), 0);
|
|
67
49
|
const items = [];
|
|
@@ -5,7 +5,7 @@ export const defaultVideoProps = {
|
|
|
5
5
|
playsInline: true,
|
|
6
6
|
};
|
|
7
7
|
export const Video = ({ augment }) => {
|
|
8
|
-
augment(({ render: { slide: renderSlide, ...restRender }, video:
|
|
8
|
+
augment(({ render: { slide: renderSlide, ...restRender }, video: videoProps, ...restProps }) => ({
|
|
9
9
|
render: {
|
|
10
10
|
slide: (slide, offset, rect) => {
|
|
11
11
|
if (slide.type === "video") {
|
|
@@ -15,10 +15,7 @@ export const Video = ({ augment }) => {
|
|
|
15
15
|
},
|
|
16
16
|
...restRender,
|
|
17
17
|
},
|
|
18
|
-
video: {
|
|
19
|
-
...defaultVideoProps,
|
|
20
|
-
...originalVideo,
|
|
21
|
-
},
|
|
18
|
+
video: { ...defaultVideoProps, ...videoProps },
|
|
22
19
|
...restProps,
|
|
23
20
|
}));
|
|
24
21
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { GenericSlide } from "../../types.js";
|
|
2
2
|
import { Video } from "./Video.js";
|
|
3
|
+
import { ACTIVE_SLIDE_COMPLETE, ACTIVE_SLIDE_ERROR, ACTIVE_SLIDE_LOADING, ACTIVE_SLIDE_PLAYING } from "../../core/consts.js";
|
|
3
4
|
/** Video slide attributes */
|
|
4
5
|
export interface SlideVideo extends GenericSlide {
|
|
5
6
|
/** video slide type marker */
|
|
@@ -48,4 +49,12 @@ declare module "../../types" {
|
|
|
48
49
|
video?: Pick<SlideVideo, "autoPlay" | "controls" | "controlsList" | "crossOrigin" | "preload" | "loop" | "muted" | "playsInline" | "disablePictureInPicture" | "disableRemotePlayback">;
|
|
49
50
|
}
|
|
50
51
|
}
|
|
52
|
+
declare module "../../core" {
|
|
53
|
+
interface EventTypes {
|
|
54
|
+
[ACTIVE_SLIDE_LOADING]: void;
|
|
55
|
+
[ACTIVE_SLIDE_PLAYING]: void;
|
|
56
|
+
[ACTIVE_SLIDE_COMPLETE]: void;
|
|
57
|
+
[ACTIVE_SLIDE_ERROR]: void;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
51
60
|
export default Video;
|
|
@@ -39,7 +39,7 @@ const distance = (pointerA, pointerB) => ((pointerA.clientX - pointerB.clientX)
|
|
|
39
39
|
export const ZoomContainer = ({ slide, offset, rect, render, carousel, animation, zoom: originalZoomProps, on }) => {
|
|
40
40
|
var _a;
|
|
41
41
|
const zoomProps = { ...defaultZoomProps, ...originalZoomProps };
|
|
42
|
-
const {
|
|
42
|
+
const { currentIndex } = useLightboxState().state;
|
|
43
43
|
const [zoom, setZoom] = React.useState(1);
|
|
44
44
|
const [offsetX, setOffsetX] = React.useState(0);
|
|
45
45
|
const [offsetY, setOffsetY] = React.useState(0);
|
|
@@ -6,7 +6,7 @@ export const ZoomContextProvider = ({ slides, children }) => {
|
|
|
6
6
|
const [isMinZoom, setIsMinZoom] = React.useState(false);
|
|
7
7
|
const [isMaxZoom, setIsMaxZoom] = React.useState(false);
|
|
8
8
|
const [isZoomSupported, setIsZoomSupported] = React.useState(false);
|
|
9
|
-
const {
|
|
9
|
+
const { currentIndex } = useLightboxState().state;
|
|
10
10
|
const updateZoomSupported = useEventCallback(() => setIsZoomSupported(slides.length > currentIndex && isImageSlide(slides[currentIndex])));
|
|
11
11
|
useLayoutEffect(updateZoomSupported, [currentIndex, updateZoomSupported]);
|
|
12
12
|
const context = React.useMemo(() => ({
|