yet-another-react-lightbox 1.5.0 → 1.7.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.
- package/README.md +2 -0
- package/dist/Lightbox.d.ts +4 -8
- package/dist/Lightbox.js +14 -10
- package/dist/core/components/ImageSlide.d.ts +2 -1
- package/dist/core/components/ImageSlide.js +23 -11
- package/dist/core/consts.d.ts +10 -0
- package/dist/core/consts.js +9 -0
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.js +1 -0
- package/dist/core/modules/Carousel.js +4 -3
- package/dist/core/modules/Controller.d.ts +7 -3
- package/dist/core/modules/Controller.js +33 -13
- package/dist/core/modules/Navigation.js +4 -4
- package/dist/plugins/Inline.js +2 -2
- package/dist/plugins/Slideshow.d.ts +31 -0
- package/dist/plugins/Slideshow.js +88 -0
- package/dist/plugins/Video.d.ts +3 -3
- package/dist/plugins/Video.js +32 -45
- package/dist/plugins/index.d.ts +1 -0
- package/dist/plugins/index.js +1 -0
- package/dist/styles.css +34 -6
- package/dist/types.d.ts +18 -60
- package/dist/types.js +2 -56
- package/package.json +14 -13
package/README.md
CHANGED
|
@@ -16,6 +16,7 @@ Modern React lightbox component. Performant, easy to use, customizable and exten
|
|
|
16
16
|
- **Video:** video slides are supported via an optional plugin
|
|
17
17
|
- **Customization:** customize any UI element or add your own custom slides
|
|
18
18
|
- **No bloat:** never bundle rarely used features; add optional features via plugins
|
|
19
|
+
- **RTL:** compatible with RTL layout
|
|
19
20
|
- **TypeScript:** type definitions come built-in in the package
|
|
20
21
|
|
|
21
22
|
## Documentation
|
|
@@ -130,6 +131,7 @@ The following plugins come bundled in the package:
|
|
|
130
131
|
description
|
|
131
132
|
- [Fullscreen](https://yet-another-react-lightbox.vercel.app/plugins/fullscreen) - adds support for fullscreen mode
|
|
132
133
|
- [Inline](https://yet-another-react-lightbox.vercel.app/plugins/inline) - adds support for inline rendering mode
|
|
134
|
+
- [Slideshow](https://yet-another-react-lightbox.vercel.app/plugins/slideshow) - adds slideshow autoplay feature
|
|
133
135
|
- [Video](https://yet-another-react-lightbox.vercel.app/plugins/video) - adds support for video slides
|
|
134
136
|
|
|
135
137
|
## License
|
package/dist/Lightbox.d.ts
CHANGED
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
};
|
|
6
|
-
/** Modern React lightbox component */
|
|
7
|
-
export declare const Lightbox: (props: DeepPartial<Partial<LightboxProps>, "carousel" | "animation" | "render" | "toolbar" | "controller" | "on">) => JSX.Element;
|
|
8
|
-
export {};
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { LightboxExternalProps } from "./types.js";
|
|
3
|
+
/** Lightbox component */
|
|
4
|
+
export declare const Lightbox: React.FC<LightboxExternalProps>;
|
package/dist/Lightbox.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import { LightboxDefaultProps
|
|
2
|
+
import { LightboxDefaultProps } from "./types.js";
|
|
3
3
|
import { CarouselModule, ControllerModule, CoreModule, createNode, NavigationModule, NoScrollModule, PortalModule, ToolbarModule, withPlugins, } from "./core/index.js";
|
|
4
4
|
const renderNode = (node, props) => {
|
|
5
5
|
var _a;
|
|
6
6
|
return React.createElement(node.module.component, { key: node.module.name, ...props }, (_a = node.children) === null || _a === void 0 ? void 0 : _a.map((child) => renderNode(child, props)));
|
|
7
7
|
};
|
|
8
|
-
const
|
|
9
|
-
const { plugins } = props;
|
|
8
|
+
export const Lightbox = (props) => {
|
|
9
|
+
const { carousel, animation, render, toolbar, controller, on, plugins, ...restProps } = props;
|
|
10
|
+
const { carousel: defaultCarousel, animation: defaultAnimation, render: defaultRender, toolbar: defaultToolbar, controller: defaultController, on: defaultOn, ...restDefaultProps } = LightboxDefaultProps;
|
|
10
11
|
const { config, augmentation } = withPlugins([
|
|
11
12
|
createNode(PortalModule, [
|
|
12
13
|
createNode(NoScrollModule, [
|
|
@@ -18,14 +19,17 @@ const LightboxComponent = (props) => {
|
|
|
18
19
|
]),
|
|
19
20
|
]),
|
|
20
21
|
], plugins);
|
|
21
|
-
const augmentedProps = augmentation(
|
|
22
|
+
const augmentedProps = augmentation({
|
|
23
|
+
carousel: { ...defaultCarousel, ...carousel },
|
|
24
|
+
animation: { ...defaultAnimation, ...animation },
|
|
25
|
+
render: { ...defaultRender, ...render },
|
|
26
|
+
toolbar: { ...defaultToolbar, ...toolbar },
|
|
27
|
+
controller: { ...defaultController, ...controller },
|
|
28
|
+
on: { ...defaultOn, ...on },
|
|
29
|
+
...restDefaultProps,
|
|
30
|
+
...restProps,
|
|
31
|
+
});
|
|
22
32
|
if (!augmentedProps.open)
|
|
23
33
|
return null;
|
|
24
34
|
return React.createElement(React.Fragment, null, renderNode(createNode(CoreModule, config), augmentedProps));
|
|
25
35
|
};
|
|
26
|
-
LightboxComponent.propTypes = LightboxPropTypes;
|
|
27
|
-
export const Lightbox = (props) => {
|
|
28
|
-
const { carousel, animation, render, toolbar, controller, on, ...restProps } = props;
|
|
29
|
-
const { carousel: defaultCarousel, animation: defaultAnimation, render: defaultRender, toolbar: defaultToolbar, controller: defaultController, on: defaultOn, ...restDefaultProps } = LightboxDefaultProps;
|
|
30
|
-
return (React.createElement(LightboxComponent, { carousel: { ...defaultCarousel, ...carousel }, animation: { ...defaultAnimation, ...animation }, render: { ...defaultRender, ...render }, toolbar: { ...defaultToolbar, ...toolbar }, controller: { ...defaultController, ...controller }, on: { ...defaultOn, ...on }, ...restDefaultProps, ...restProps }));
|
|
31
|
-
};
|
|
@@ -3,7 +3,8 @@ import { Render, SlideImage } from "../../types.js";
|
|
|
3
3
|
import { ContainerRect } from "../hooks/index.js";
|
|
4
4
|
export declare type ImageSlideProps = {
|
|
5
5
|
slide: SlideImage;
|
|
6
|
+
offset: number;
|
|
6
7
|
render?: Render;
|
|
7
8
|
rect?: ContainerRect;
|
|
8
9
|
};
|
|
9
|
-
export declare const ImageSlide: ({ slide: image, render, rect }: ImageSlideProps) => JSX.Element;
|
|
10
|
+
export declare const ImageSlide: ({ slide: image, offset, render, rect }: ImageSlideProps) => JSX.Element;
|
|
@@ -1,14 +1,24 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { adjustDevicePixelRatio, clsx, cssClass, hasWindow } from "../utils.js";
|
|
3
3
|
import { useLatest } from "../hooks/index.js";
|
|
4
|
+
import { useEvents } from "../contexts/index.js";
|
|
4
5
|
import { ErrorIcon, LoadingIcon } from "./Icons.js";
|
|
5
|
-
|
|
6
|
+
import { activeSlideStatus, SLIDE_STATUS_COMPLETE, SLIDE_STATUS_ERROR, SLIDE_STATUS_LOADING } from "../consts.js";
|
|
7
|
+
import { useController } from "../modules/Controller.js";
|
|
8
|
+
export const ImageSlide = ({ slide: image, offset, render, rect }) => {
|
|
6
9
|
var _a;
|
|
7
|
-
const [
|
|
8
|
-
const
|
|
10
|
+
const [status, setStatus] = React.useState(SLIDE_STATUS_LOADING);
|
|
11
|
+
const latestStatus = useLatest(status);
|
|
12
|
+
const { latestProps } = useController();
|
|
13
|
+
const { publish } = useEvents();
|
|
9
14
|
const imageRef = React.useRef(null);
|
|
15
|
+
React.useEffect(() => {
|
|
16
|
+
if (offset === 0) {
|
|
17
|
+
publish(activeSlideStatus(status));
|
|
18
|
+
}
|
|
19
|
+
}, [offset, status, publish]);
|
|
10
20
|
const handleLoading = React.useCallback((img) => {
|
|
11
|
-
if (
|
|
21
|
+
if (latestStatus.current === SLIDE_STATUS_COMPLETE) {
|
|
12
22
|
return;
|
|
13
23
|
}
|
|
14
24
|
("decode" in img ? img.decode() : Promise.resolve())
|
|
@@ -17,9 +27,9 @@ export const ImageSlide = ({ slide: image, render, rect }) => {
|
|
|
17
27
|
if (!img.parentNode) {
|
|
18
28
|
return;
|
|
19
29
|
}
|
|
20
|
-
|
|
30
|
+
setStatus(SLIDE_STATUS_COMPLETE);
|
|
21
31
|
});
|
|
22
|
-
}, [
|
|
32
|
+
}, [latestStatus]);
|
|
23
33
|
const setImageRef = React.useCallback((img) => {
|
|
24
34
|
imageRef.current = img;
|
|
25
35
|
if (img === null || img === void 0 ? void 0 : img.complete) {
|
|
@@ -30,10 +40,12 @@ export const ImageSlide = ({ slide: image, render, rect }) => {
|
|
|
30
40
|
handleLoading(event.currentTarget);
|
|
31
41
|
}, [handleLoading]);
|
|
32
42
|
const onError = React.useCallback(() => {
|
|
33
|
-
|
|
43
|
+
setStatus(SLIDE_STATUS_ERROR);
|
|
34
44
|
}, []);
|
|
35
45
|
return (React.createElement(React.Fragment, null,
|
|
36
|
-
React.createElement("img", { ref: setImageRef, onLoad: onLoad, onError: onError, className: clsx(cssClass("slide_image"),
|
|
46
|
+
React.createElement("img", { ref: setImageRef, onLoad: onLoad, onError: onError, className: clsx(cssClass("slide_image"), (image.imageFit === "cover" ||
|
|
47
|
+
(image.imageFit !== "contain" && latestProps.current.carousel.imageFit === "cover")) &&
|
|
48
|
+
cssClass("slide_image_cover"), status !== SLIDE_STATUS_COMPLETE && cssClass("slide_image_loading")), draggable: false, alt: image.alt, ...(image.srcSet
|
|
37
49
|
? {
|
|
38
50
|
...(rect && hasWindow()
|
|
39
51
|
? {
|
|
@@ -57,9 +69,9 @@ export const ImageSlide = ({ slide: image, render, rect }) => {
|
|
|
57
69
|
}
|
|
58
70
|
: undefined,
|
|
59
71
|
}), src: image.src }),
|
|
60
|
-
|
|
61
|
-
|
|
72
|
+
status !== SLIDE_STATUS_COMPLETE && (React.createElement("div", { className: cssClass("slide_placeholder") },
|
|
73
|
+
status === SLIDE_STATUS_LOADING &&
|
|
62
74
|
((render === null || render === void 0 ? void 0 : render.iconLoading) ? (render.iconLoading()) : (React.createElement(LoadingIcon, { className: clsx(cssClass("icon"), cssClass("slide_loading")) }))),
|
|
63
|
-
|
|
75
|
+
status === SLIDE_STATUS_ERROR &&
|
|
64
76
|
((render === null || render === void 0 ? void 0 : render.iconError) ? (render.iconError()) : (React.createElement(ErrorIcon, { className: clsx(cssClass("icon"), cssClass("slide_error")) })))))));
|
|
65
77
|
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare const SLIDE_STATUS_LOADING = "loading";
|
|
2
|
+
export declare const SLIDE_STATUS_PLAYING = "playing";
|
|
3
|
+
export declare const SLIDE_STATUS_ERROR = "error";
|
|
4
|
+
export declare const SLIDE_STATUS_COMPLETE = "complete";
|
|
5
|
+
export declare type SlideStatus = typeof SLIDE_STATUS_LOADING | typeof SLIDE_STATUS_PLAYING | typeof SLIDE_STATUS_ERROR | typeof SLIDE_STATUS_COMPLETE;
|
|
6
|
+
export declare const activeSlideStatus: (status: SlideStatus) => string;
|
|
7
|
+
export declare const ACTIVE_SLIDE_LOADING: string;
|
|
8
|
+
export declare const ACTIVE_SLIDE_PLAYING: string;
|
|
9
|
+
export declare const ACTIVE_SLIDE_ERROR: string;
|
|
10
|
+
export declare const ACTIVE_SLIDE_COMPLETE: string;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export const SLIDE_STATUS_LOADING = "loading";
|
|
2
|
+
export const SLIDE_STATUS_PLAYING = "playing";
|
|
3
|
+
export const SLIDE_STATUS_ERROR = "error";
|
|
4
|
+
export const SLIDE_STATUS_COMPLETE = "complete";
|
|
5
|
+
export const activeSlideStatus = (status) => `active-slide-${status}`;
|
|
6
|
+
export const ACTIVE_SLIDE_LOADING = activeSlideStatus(SLIDE_STATUS_LOADING);
|
|
7
|
+
export const ACTIVE_SLIDE_PLAYING = activeSlideStatus(SLIDE_STATUS_PLAYING);
|
|
8
|
+
export const ACTIVE_SLIDE_ERROR = activeSlideStatus(SLIDE_STATUS_ERROR);
|
|
9
|
+
export const ACTIVE_SLIDE_COMPLETE = activeSlideStatus(SLIDE_STATUS_COMPLETE);
|
package/dist/core/index.d.ts
CHANGED
package/dist/core/index.js
CHANGED
|
@@ -13,7 +13,7 @@ const CarouselSlide = ({ slide, offset }) => {
|
|
|
13
13
|
var _a, _b, _c, _d;
|
|
14
14
|
let rendered = (_a = render.slide) === null || _a === void 0 ? void 0 : _a.call(render, slide, offset, rect);
|
|
15
15
|
if (!rendered && "src" in slide) {
|
|
16
|
-
rendered = React.createElement(ImageSlide, { slide: slide, render: render, rect: rect });
|
|
16
|
+
rendered = React.createElement(ImageSlide, { slide: slide, offset: offset, render: render, rect: rect });
|
|
17
17
|
}
|
|
18
18
|
return rendered ? (React.createElement(React.Fragment, null, (_b = render.slideHeader) === null || _b === void 0 ? void 0 :
|
|
19
19
|
_b.call(render, slide),
|
|
@@ -38,12 +38,13 @@ export const Carousel = ({ slides, carousel: { finite, preload, padding, spacing
|
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
|
+
const sanitize = (value) => value === 0 || value.trim() === "" || value.trim() === "0" ? "0px" : value;
|
|
41
42
|
return (React.createElement("div", { className: cssClass("carousel"), style: {
|
|
42
43
|
...(padding !== LightboxDefaultProps.carousel.padding
|
|
43
|
-
? { [cssVar("carousel_padding")]: padding }
|
|
44
|
+
? { [cssVar("carousel_padding")]: sanitize(padding) }
|
|
44
45
|
: null),
|
|
45
46
|
...(spacing !== LightboxDefaultProps.carousel.spacing
|
|
46
|
-
? { [cssVar("carousel_spacing")]: spacing
|
|
47
|
+
? { [cssVar("carousel_spacing")]: sanitize(spacing) }
|
|
47
48
|
: null),
|
|
48
49
|
} }, items));
|
|
49
50
|
};
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { Component, ComponentProps } from "../../types.js";
|
|
3
3
|
import { SubscribeSensors } from "../hooks/index.js";
|
|
4
|
-
|
|
5
|
-
latestProps: React.MutableRefObject<ComponentProps>;
|
|
6
|
-
containerRef: React.RefObject<HTMLDivElement>;
|
|
4
|
+
declare type ControllerState = {
|
|
7
5
|
currentIndex: number;
|
|
8
6
|
globalIndex: number;
|
|
7
|
+
isRTL: boolean;
|
|
8
|
+
};
|
|
9
|
+
export declare type ControllerContextType = ControllerState & {
|
|
10
|
+
latestProps: React.MutableRefObject<ComponentProps>;
|
|
11
|
+
containerRef: React.RefObject<HTMLDivElement>;
|
|
9
12
|
subscribeSensors: SubscribeSensors<HTMLDivElement>;
|
|
10
13
|
};
|
|
11
14
|
export declare const useController: () => ControllerContextType;
|
|
12
15
|
export declare const Controller: Component;
|
|
13
16
|
export declare const ControllerModule: import("../../types.js").Module;
|
|
17
|
+
export {};
|
|
@@ -15,6 +15,7 @@ export const Controller = ({ children, ...props }) => {
|
|
|
15
15
|
const [state, setState] = React.useState({
|
|
16
16
|
currentIndex: props.index,
|
|
17
17
|
globalIndex: props.index,
|
|
18
|
+
isRTL: false,
|
|
18
19
|
});
|
|
19
20
|
const latestProps = useLatest(props);
|
|
20
21
|
const refs = React.useRef({
|
|
@@ -29,7 +30,11 @@ export const Controller = ({ children, ...props }) => {
|
|
|
29
30
|
refs.current.state = state;
|
|
30
31
|
refs.current.props = props;
|
|
31
32
|
useEnhancedEffect(() => {
|
|
32
|
-
const preventDefault = (event) =>
|
|
33
|
+
const preventDefault = (event) => {
|
|
34
|
+
if (Math.abs(event.deltaX) > Math.abs(event.deltaY)) {
|
|
35
|
+
event.preventDefault();
|
|
36
|
+
}
|
|
37
|
+
};
|
|
33
38
|
const node = containerRef.current;
|
|
34
39
|
if (node) {
|
|
35
40
|
node.addEventListener("wheel", preventDefault, { passive: false });
|
|
@@ -40,6 +45,12 @@ export const Controller = ({ children, ...props }) => {
|
|
|
40
45
|
}
|
|
41
46
|
};
|
|
42
47
|
}, [containerRef]);
|
|
48
|
+
useEnhancedEffect(() => {
|
|
49
|
+
const node = containerRef.current;
|
|
50
|
+
if (node) {
|
|
51
|
+
setState((prev) => ({ ...prev, isRTL: window.getComputedStyle(node).direction === "rtl" }));
|
|
52
|
+
}
|
|
53
|
+
}, [containerRef]);
|
|
43
54
|
React.useEffect(() => {
|
|
44
55
|
var _a;
|
|
45
56
|
if (refs.current.props.controller.focus) {
|
|
@@ -76,11 +87,12 @@ export const Controller = ({ children, ...props }) => {
|
|
|
76
87
|
clearTimeout(current.swipeIntentCleanup);
|
|
77
88
|
current.swipeIntentCleanup = undefined;
|
|
78
89
|
}, [clearTimeout]);
|
|
90
|
+
const rtl = React.useCallback((value) => (refs.current.state.isRTL ? -1 : 1) * (typeof value === "number" ? value : 1), [refs]);
|
|
79
91
|
const isSwipeValid = React.useCallback((offset) => {
|
|
80
92
|
const { state: { currentIndex }, props: { carousel, slides }, } = refs.current;
|
|
81
93
|
return !(carousel.finite &&
|
|
82
|
-
((offset > 0 && currentIndex === 0) || (offset < 0 && currentIndex === slides.length - 1)));
|
|
83
|
-
}, []);
|
|
94
|
+
((rtl(offset) > 0 && currentIndex === 0) || (rtl(offset) < 0 && currentIndex === slides.length - 1)));
|
|
95
|
+
}, [rtl]);
|
|
84
96
|
const swipe = React.useCallback((direction) => {
|
|
85
97
|
var _a;
|
|
86
98
|
const { current } = refs;
|
|
@@ -105,7 +117,7 @@ export const Controller = ({ children, ...props }) => {
|
|
|
105
117
|
newSwipeAnimationDuration =
|
|
106
118
|
(newSwipeAnimationDuration / expectedTime) * Math.max(elapsedTime, expectedTime / 5);
|
|
107
119
|
}
|
|
108
|
-
direction = swipeOffset > 0 ? "prev" : "next";
|
|
120
|
+
direction = rtl(swipeOffset) > 0 ? "prev" : "next";
|
|
109
121
|
}
|
|
110
122
|
else {
|
|
111
123
|
newSwipeAnimationDuration = swipeAnimationDuration / 2;
|
|
@@ -113,7 +125,7 @@ export const Controller = ({ children, ...props }) => {
|
|
|
113
125
|
}
|
|
114
126
|
const newState = {};
|
|
115
127
|
if (direction === "prev") {
|
|
116
|
-
if (isSwipeValid(1)) {
|
|
128
|
+
if (isSwipeValid(rtl(1))) {
|
|
117
129
|
newState.currentIndex = (currentIndex - 1 + slidesCount) % slidesCount;
|
|
118
130
|
newState.globalIndex = globalIndex - 1;
|
|
119
131
|
}
|
|
@@ -123,7 +135,7 @@ export const Controller = ({ children, ...props }) => {
|
|
|
123
135
|
}
|
|
124
136
|
}
|
|
125
137
|
else if (direction === "next") {
|
|
126
|
-
if (isSwipeValid(-1)) {
|
|
138
|
+
if (isSwipeValid(rtl(-1))) {
|
|
127
139
|
newState.currentIndex = (currentIndex + 1) % slidesCount;
|
|
128
140
|
newState.globalIndex = globalIndex + 1;
|
|
129
141
|
}
|
|
@@ -143,7 +155,7 @@ export const Controller = ({ children, ...props }) => {
|
|
|
143
155
|
}, newSwipeAnimationDuration);
|
|
144
156
|
}
|
|
145
157
|
setState((prev) => ({ ...prev, ...newState }));
|
|
146
|
-
}, [setTimeout, resetSwipe, isSwipeValid, rerender, containerRef]);
|
|
158
|
+
}, [setTimeout, resetSwipe, isSwipeValid, rerender, containerRef, rtl]);
|
|
147
159
|
React.useEffect(() => cleanup(subscribe("prev", () => swipe("prev")), subscribe("next", () => swipe("next"))), [subscribe, swipe]);
|
|
148
160
|
React.useEffect(() => subscribeSensors("onKeyUp", (event) => {
|
|
149
161
|
if (event.code === "Escape") {
|
|
@@ -266,13 +278,21 @@ export const Controller = ({ children, ...props }) => {
|
|
|
266
278
|
containerRef,
|
|
267
279
|
currentIndex: state.currentIndex,
|
|
268
280
|
globalIndex: state.globalIndex,
|
|
281
|
+
isRTL: state.isRTL,
|
|
269
282
|
subscribeSensors,
|
|
270
|
-
}), [latestProps, containerRef, state.currentIndex, state.globalIndex, subscribeSensors]);
|
|
271
|
-
return (React.createElement("div", { ref: setContainerRef, className: clsx(cssClass("container"), refs.current.swipeState === "swipe" && cssClass("container_swipe")), style:
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
283
|
+
}), [latestProps, containerRef, state.currentIndex, state.globalIndex, state.isRTL, subscribeSensors]);
|
|
284
|
+
return (React.createElement("div", { ref: setContainerRef, className: clsx(cssClass("container"), refs.current.swipeState === "swipe" && cssClass("container_swipe")), style: {
|
|
285
|
+
...(refs.current.swipeAnimationDuration !== LightboxDefaultProps.animation.swipe
|
|
286
|
+
? {
|
|
287
|
+
[cssVar("swipe_animation_duration")]: `${Math.round(refs.current.swipeAnimationDuration)}ms`,
|
|
288
|
+
}
|
|
289
|
+
: null),
|
|
290
|
+
...(props.controller.touchAction !== "none"
|
|
291
|
+
? {
|
|
292
|
+
[cssVar("controller_touch_action")]: props.controller.touchAction,
|
|
293
|
+
}
|
|
294
|
+
: null),
|
|
295
|
+
}, role: "presentation", "aria-live": "polite", tabIndex: -1, ...registerSensors },
|
|
276
296
|
React.createElement(ControllerContext.Provider, { value: context }, children)));
|
|
277
297
|
};
|
|
278
298
|
export const ControllerModule = createModule("controller", Controller);
|
|
@@ -8,16 +8,16 @@ export const NavigationButton = ({ publish, labels, label, icon, renderIcon, act
|
|
|
8
8
|
publish(action);
|
|
9
9
|
} }));
|
|
10
10
|
export const Navigation = ({ slides, carousel: { finite }, labels, render: { buttonPrev, buttonNext, iconPrev, iconNext }, }) => {
|
|
11
|
-
const { currentIndex, subscribeSensors } = useController();
|
|
11
|
+
const { currentIndex, subscribeSensors, isRTL } = useController();
|
|
12
12
|
const { publish } = useEvents();
|
|
13
13
|
React.useEffect(() => subscribeSensors("onKeyUp", (event) => {
|
|
14
14
|
if (event.code === "ArrowLeft") {
|
|
15
|
-
publish("prev");
|
|
15
|
+
publish(isRTL ? "next" : "prev");
|
|
16
16
|
}
|
|
17
17
|
else if (event.code === "ArrowRight") {
|
|
18
|
-
publish("next");
|
|
18
|
+
publish(isRTL ? "prev" : "next");
|
|
19
19
|
}
|
|
20
|
-
}), [subscribeSensors, publish]);
|
|
20
|
+
}), [subscribeSensors, publish, isRTL]);
|
|
21
21
|
return (React.createElement(React.Fragment, null,
|
|
22
22
|
buttonPrev ? (buttonPrev()) : (React.createElement(NavigationButton, { label: "Previous", action: "prev", icon: PreviousIcon, renderIcon: iconPrev, disabled: finite && currentIndex === 0, labels: labels, publish: publish })),
|
|
23
23
|
buttonNext ? (buttonNext()) : (React.createElement(NavigationButton, { label: "Next", action: "next", icon: NextIcon, renderIcon: iconNext, disabled: finite && currentIndex === slides.length - 1, labels: labels, publish: publish }))));
|
package/dist/plugins/Inline.js
CHANGED
|
@@ -3,7 +3,7 @@ import { createModule } from "../core/index.js";
|
|
|
3
3
|
export const InlineContainer = ({ inline, children }) => React.createElement("div", { ...inline }, children);
|
|
4
4
|
export const InlineModule = createModule("inline", InlineContainer);
|
|
5
5
|
export const Inline = ({ augment, replace, remove }) => {
|
|
6
|
-
augment(({ toolbar: { buttons, ...restToolbar }, open, close, controller: { focus, ...restController }, ...restProps }) => ({
|
|
6
|
+
augment(({ toolbar: { buttons, ...restToolbar }, open, close, controller: { focus, touchAction, ...restController }, ...restProps }) => ({
|
|
7
7
|
open: true,
|
|
8
8
|
close: () => { },
|
|
9
9
|
toolbar: {
|
|
@@ -11,7 +11,7 @@ export const Inline = ({ augment, replace, remove }) => {
|
|
|
11
11
|
...restToolbar,
|
|
12
12
|
},
|
|
13
13
|
inline: { style: { width: "100%", height: "100%" } },
|
|
14
|
-
controller: { focus: false, ...restController },
|
|
14
|
+
controller: { focus: false, touchAction: "pan-y", ...restController },
|
|
15
15
|
...restProps,
|
|
16
16
|
}));
|
|
17
17
|
remove("no-scroll");
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { Plugin } from "../types.js";
|
|
3
|
+
declare module "../types.js" {
|
|
4
|
+
interface LightboxProps {
|
|
5
|
+
/** Slideshow plugin settings */
|
|
6
|
+
slideshow?: {
|
|
7
|
+
/** if `true`, slideshow is turned on automatically when the lightbox opens */
|
|
8
|
+
autoplay?: boolean;
|
|
9
|
+
/** slideshow delay in milliseconds */
|
|
10
|
+
delay?: number;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
interface Render {
|
|
14
|
+
/** render custom Slideshow Play icon */
|
|
15
|
+
iconSlideshowPlay?: () => React.ReactNode;
|
|
16
|
+
/** render custom Slideshow Pause icon */
|
|
17
|
+
iconSlideshowPause?: () => React.ReactNode;
|
|
18
|
+
/** render custom Slideshow button */
|
|
19
|
+
buttonSlideshow?: ({ playing, togglePlaying, disabled, }: {
|
|
20
|
+
/** current slideshow autoplay status */
|
|
21
|
+
playing: boolean;
|
|
22
|
+
/** toggle slideshow autoplay status */
|
|
23
|
+
togglePlaying: () => void;
|
|
24
|
+
/** if `true`, the button is disabled */
|
|
25
|
+
disabled: boolean;
|
|
26
|
+
}) => React.ReactNode;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/** Slideshow plugin */
|
|
30
|
+
export declare const Slideshow: Plugin;
|
|
31
|
+
export default Slideshow;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { ACTIVE_SLIDE_COMPLETE, ACTIVE_SLIDE_ERROR, ACTIVE_SLIDE_LOADING, ACTIVE_SLIDE_PLAYING, cleanup, createIcon, IconButton, label, SLIDE_STATUS_COMPLETE, SLIDE_STATUS_ERROR, SLIDE_STATUS_LOADING, SLIDE_STATUS_PLAYING, useController, useEvents, useLatest, useTimeouts, } from "../core/index.js";
|
|
3
|
+
const defaultSlideshowProps = {
|
|
4
|
+
autoplay: false,
|
|
5
|
+
delay: 3000,
|
|
6
|
+
};
|
|
7
|
+
const PlayIcon = createIcon("Play", React.createElement("path", { d: "M8 5v14l11-7z" }));
|
|
8
|
+
const PauseIcon = createIcon("Pause", React.createElement("path", { d: "M6 19h4V5H6v14zm8-14v14h4V5h-4z" }));
|
|
9
|
+
const SlideshowButton = () => {
|
|
10
|
+
const { currentIndex, latestProps } = useController();
|
|
11
|
+
const { setTimeout, clearTimeout } = useTimeouts();
|
|
12
|
+
const { publish, subscribe } = useEvents();
|
|
13
|
+
const slideshow = {
|
|
14
|
+
...defaultSlideshowProps,
|
|
15
|
+
...latestProps.current.slideshow,
|
|
16
|
+
};
|
|
17
|
+
const [playing, setPlaying] = React.useState(slideshow.autoplay);
|
|
18
|
+
const scheduler = React.useRef();
|
|
19
|
+
const refs = useLatest({
|
|
20
|
+
playing,
|
|
21
|
+
delay: slideshow.delay,
|
|
22
|
+
currentIndex,
|
|
23
|
+
finite: latestProps.current.carousel.finite,
|
|
24
|
+
slidesCount: latestProps.current.slides.length,
|
|
25
|
+
});
|
|
26
|
+
const slideStatus = React.useRef();
|
|
27
|
+
const cancelScheduler = React.useCallback(() => {
|
|
28
|
+
clearTimeout(scheduler.current);
|
|
29
|
+
scheduler.current = undefined;
|
|
30
|
+
}, [clearTimeout]);
|
|
31
|
+
const reachedLastSlide = React.useCallback(() => refs.current.finite && refs.current.currentIndex === refs.current.slidesCount - 1, [refs]);
|
|
32
|
+
const scheduleNextSlide = React.useCallback(() => {
|
|
33
|
+
cancelScheduler();
|
|
34
|
+
if (!refs.current.playing ||
|
|
35
|
+
reachedLastSlide() ||
|
|
36
|
+
slideStatus.current === SLIDE_STATUS_LOADING ||
|
|
37
|
+
slideStatus.current === SLIDE_STATUS_PLAYING) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
scheduler.current = setTimeout(() => {
|
|
41
|
+
if (refs.current.playing) {
|
|
42
|
+
slideStatus.current = undefined;
|
|
43
|
+
publish("next");
|
|
44
|
+
}
|
|
45
|
+
}, refs.current.delay);
|
|
46
|
+
}, [publish, setTimeout, cancelScheduler, refs, reachedLastSlide]);
|
|
47
|
+
const togglePlaying = React.useCallback(() => {
|
|
48
|
+
setPlaying((prev) => !prev);
|
|
49
|
+
}, []);
|
|
50
|
+
React.useEffect(() => {
|
|
51
|
+
scheduleNextSlide();
|
|
52
|
+
}, [currentIndex, playing, scheduleNextSlide]);
|
|
53
|
+
React.useEffect(() => {
|
|
54
|
+
if (playing && reachedLastSlide()) {
|
|
55
|
+
setPlaying(false);
|
|
56
|
+
}
|
|
57
|
+
}, [currentIndex, playing, reachedLastSlide]);
|
|
58
|
+
React.useEffect(() => cleanup(subscribe(ACTIVE_SLIDE_LOADING, () => {
|
|
59
|
+
slideStatus.current = SLIDE_STATUS_LOADING;
|
|
60
|
+
cancelScheduler();
|
|
61
|
+
}), subscribe(ACTIVE_SLIDE_PLAYING, () => {
|
|
62
|
+
slideStatus.current = SLIDE_STATUS_PLAYING;
|
|
63
|
+
cancelScheduler();
|
|
64
|
+
}), subscribe(ACTIVE_SLIDE_ERROR, () => {
|
|
65
|
+
slideStatus.current = SLIDE_STATUS_ERROR;
|
|
66
|
+
scheduleNextSlide();
|
|
67
|
+
}), subscribe(ACTIVE_SLIDE_COMPLETE, () => {
|
|
68
|
+
slideStatus.current = SLIDE_STATUS_COMPLETE;
|
|
69
|
+
scheduleNextSlide();
|
|
70
|
+
})), [subscribe, cancelScheduler, scheduleNextSlide]);
|
|
71
|
+
const { render, labels } = latestProps.current;
|
|
72
|
+
const disabled = reachedLastSlide();
|
|
73
|
+
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 }));
|
|
74
|
+
};
|
|
75
|
+
export const Slideshow = ({ augment }) => {
|
|
76
|
+
augment(({ slideshow: originalSlideshow, toolbar: { buttons, ...restToolbar }, ...restProps }) => ({
|
|
77
|
+
toolbar: {
|
|
78
|
+
buttons: [React.createElement(SlideshowButton, { key: "slideshow" }), ...buttons],
|
|
79
|
+
...restToolbar,
|
|
80
|
+
},
|
|
81
|
+
slideshow: {
|
|
82
|
+
...defaultSlideshowProps,
|
|
83
|
+
...originalSlideshow,
|
|
84
|
+
},
|
|
85
|
+
...restProps,
|
|
86
|
+
}));
|
|
87
|
+
};
|
|
88
|
+
export default Slideshow;
|
package/dist/plugins/Video.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import {
|
|
2
|
+
import { Plugin } from "../types.js";
|
|
3
3
|
/** Video slide attributes */
|
|
4
4
|
export interface SlideVideo {
|
|
5
5
|
/** video slide type marker */
|
|
@@ -24,7 +24,7 @@ export interface SlideVideo {
|
|
|
24
24
|
loop?: boolean;
|
|
25
25
|
/** the default setting of the audio contained in the video */
|
|
26
26
|
muted?: boolean;
|
|
27
|
-
/** if `true`, the video is to be played "inline", that is within the element's playback area
|
|
27
|
+
/** if `true`, the video is to be played "inline", that is within the element's playback area */
|
|
28
28
|
playsInline?: boolean;
|
|
29
29
|
/** prevents the browser from suggesting a Picture-in-Picture context menu */
|
|
30
30
|
disablePictureInPicture?: boolean;
|
|
@@ -48,7 +48,7 @@ declare module "../types.js" {
|
|
|
48
48
|
video?: Pick<SlideVideo, "autoPlay" | "controls" | "controlsList" | "crossOrigin" | "preload" | "loop" | "muted" | "playsInline" | "disablePictureInPicture" | "disableRemotePlayback">;
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
|
-
declare type VideoSlideProps =
|
|
51
|
+
declare type VideoSlideProps = {
|
|
52
52
|
slide: SlideVideo;
|
|
53
53
|
offset: number;
|
|
54
54
|
};
|
package/dist/plugins/Video.js
CHANGED
|
@@ -1,30 +1,16 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
controls: PropTypes.bool,
|
|
12
|
-
controlsList: PropTypes.string,
|
|
13
|
-
crossOrigin: PropTypes.string,
|
|
14
|
-
preload: PropTypes.string,
|
|
15
|
-
loop: PropTypes.bool,
|
|
16
|
-
muted: PropTypes.bool,
|
|
17
|
-
playsInline: PropTypes.bool,
|
|
18
|
-
disablePictureInPicture: PropTypes.bool,
|
|
19
|
-
disableRemotePlayback: PropTypes.bool,
|
|
20
|
-
sources: PropTypes.arrayOf(PropTypes.shape({
|
|
21
|
-
src: PropTypes.string.isRequired,
|
|
22
|
-
type: PropTypes.string.isRequired,
|
|
23
|
-
}).isRequired),
|
|
24
|
-
}));
|
|
25
|
-
export const VideoSlide = ({ slide, video, offset }) => {
|
|
2
|
+
import { ACTIVE_SLIDE_COMPLETE, ACTIVE_SLIDE_LOADING, ACTIVE_SLIDE_PLAYING, clsx, cssClass, useContainerRect, useController, useEvents, useLatest, } from "../core/index.js";
|
|
3
|
+
const defaultVideoProps = {
|
|
4
|
+
controls: true,
|
|
5
|
+
playsInline: true,
|
|
6
|
+
};
|
|
7
|
+
export const VideoSlide = ({ slide, offset }) => {
|
|
8
|
+
var _a;
|
|
9
|
+
const { latestProps } = useController();
|
|
10
|
+
const { publish } = useEvents();
|
|
26
11
|
const { setContainerRef, containerRect } = useContainerRect();
|
|
27
12
|
const videoRef = React.useRef(null);
|
|
13
|
+
const video = (_a = latestProps.current.video) !== null && _a !== void 0 ? _a : defaultVideoProps;
|
|
28
14
|
React.useEffect(() => {
|
|
29
15
|
if (offset !== 0 && videoRef.current && !videoRef.current.paused) {
|
|
30
16
|
videoRef.current.pause();
|
|
@@ -32,9 +18,10 @@ export const VideoSlide = ({ slide, video, offset }) => {
|
|
|
32
18
|
}, [offset]);
|
|
33
19
|
React.useEffect(() => {
|
|
34
20
|
if (offset === 0 && videoRef.current && (slide.autoPlay || video.autoPlay)) {
|
|
21
|
+
publish(ACTIVE_SLIDE_LOADING);
|
|
35
22
|
videoRef.current.play().catch(() => { });
|
|
36
23
|
}
|
|
37
|
-
}, [offset, video.autoPlay, slide.autoPlay]);
|
|
24
|
+
}, [offset, video.autoPlay, slide.autoPlay, publish]);
|
|
38
25
|
const latestOffset = useLatest(offset);
|
|
39
26
|
const latestVideoAutoPlay = useLatest(video.autoPlay);
|
|
40
27
|
const latestSlideAutoPlay = useLatest(slide.autoPlay);
|
|
@@ -78,28 +65,28 @@ export const VideoSlide = ({ slide, video, offset }) => {
|
|
|
78
65
|
width: "100%",
|
|
79
66
|
height: "100%",
|
|
80
67
|
...(width ? { maxWidth: `${width}px` } : null),
|
|
81
|
-
}, className: clsx(cssClass("video_container"), cssClass("flex_center")) }, containerRect && (React.createElement("video", { ref: setVideoRef, poster: poster, ...scaleWidthAndHeight(), ...resolveBoolean("controls"), ...resolveBoolean("playsInline"), ...resolveBoolean("loop"), ...resolveBoolean("muted"), ...resolveBoolean("playsInline"), ...resolveBoolean("disablePictureInPicture"), ...resolveBoolean("disableRemotePlayback"), ...resolveString("controlsList"), ...resolveString("crossOrigin"), ...resolveString("preload")
|
|
68
|
+
}, className: clsx(cssClass("video_container"), cssClass("flex_center")) }, containerRect && (React.createElement("video", { ref: setVideoRef, poster: poster, ...scaleWidthAndHeight(), ...resolveBoolean("controls"), ...resolveBoolean("playsInline"), ...resolveBoolean("loop"), ...resolveBoolean("muted"), ...resolveBoolean("playsInline"), ...resolveBoolean("disablePictureInPicture"), ...resolveBoolean("disableRemotePlayback"), ...resolveString("controlsList"), ...resolveString("crossOrigin"), ...resolveString("preload"), onPlay: () => {
|
|
69
|
+
publish(ACTIVE_SLIDE_PLAYING);
|
|
70
|
+
}, onEnded: () => {
|
|
71
|
+
publish(ACTIVE_SLIDE_COMPLETE);
|
|
72
|
+
} }, sources.map(({ src, type }, index) => (React.createElement("source", { key: index, src: src, type: type })))))))));
|
|
82
73
|
};
|
|
83
74
|
export const Video = ({ augment }) => {
|
|
84
|
-
augment(({ render: { slide: renderSlide, ...restRender }, video: originalVideo, ...restProps }) => {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
render: {
|
|
92
|
-
slide: (slide, offset, rect) => {
|
|
93
|
-
if ("type" in slide && slide.type === "video") {
|
|
94
|
-
return React.createElement(VideoSlide, { slide: slide, video: video, offset: offset });
|
|
95
|
-
}
|
|
96
|
-
return renderSlide === null || renderSlide === void 0 ? void 0 : renderSlide(slide, offset, rect);
|
|
97
|
-
},
|
|
98
|
-
...restRender,
|
|
75
|
+
augment(({ render: { slide: renderSlide, ...restRender }, video: originalVideo, ...restProps }) => ({
|
|
76
|
+
render: {
|
|
77
|
+
slide: (slide, offset, rect) => {
|
|
78
|
+
if ("type" in slide && slide.type === "video") {
|
|
79
|
+
return React.createElement(VideoSlide, { slide: slide, offset: offset });
|
|
80
|
+
}
|
|
81
|
+
return renderSlide === null || renderSlide === void 0 ? void 0 : renderSlide(slide, offset, rect);
|
|
99
82
|
},
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
83
|
+
...restRender,
|
|
84
|
+
},
|
|
85
|
+
video: {
|
|
86
|
+
...defaultVideoProps,
|
|
87
|
+
...originalVideo,
|
|
88
|
+
},
|
|
89
|
+
...restProps,
|
|
90
|
+
}));
|
|
104
91
|
};
|
|
105
92
|
export default Video;
|
package/dist/plugins/index.d.ts
CHANGED
package/dist/plugins/index.js
CHANGED
package/dist/styles.css
CHANGED
|
@@ -9,12 +9,12 @@
|
|
|
9
9
|
.yarl__portal_open {
|
|
10
10
|
opacity: 1;
|
|
11
11
|
}
|
|
12
|
-
.yarl__container
|
|
12
|
+
.yarl__container {
|
|
13
13
|
-webkit-user-select: none;
|
|
14
14
|
-moz-user-select: none;
|
|
15
15
|
-ms-user-select: none;
|
|
16
16
|
user-select: none;
|
|
17
|
-
touch-action: none;
|
|
17
|
+
touch-action: var(--yarl__controller_touch_action, none);
|
|
18
18
|
}
|
|
19
19
|
.yarl__container {
|
|
20
20
|
width: 100%;
|
|
@@ -41,15 +41,18 @@
|
|
|
41
41
|
overflow: hidden;
|
|
42
42
|
inset: 0;
|
|
43
43
|
padding: var(--yarl__carousel_padding, 16px);
|
|
44
|
-
-webkit-transform: translate3d(calc(var(--yarl__slide_offset, 0) * (100% + var(--yarl__carousel_spacing, 30%))), 0, 0);
|
|
45
|
-
transform: translate3d(calc(var(--yarl__slide_offset, 0) * (100% + var(--yarl__carousel_spacing, 30%))), 0, 0);
|
|
44
|
+
-webkit-transform: translate3d(calc(var(--yarl__slide_offset, 0) * (100% + var(--yarl__carousel_spacing, 30%)) * var(--yarl__direction, 1)), 0, 0);
|
|
45
|
+
transform: translate3d(calc(var(--yarl__slide_offset, 0) * (100% + var(--yarl__carousel_spacing, 30%)) * var(--yarl__direction, 1)), 0, 0);
|
|
46
46
|
transition: -webkit-transform var(--yarl__swipe_animation_duration, 500ms) ease-out;
|
|
47
47
|
transition: transform var(--yarl__swipe_animation_duration, 500ms) ease-out;
|
|
48
48
|
transition: transform var(--yarl__swipe_animation_duration, 500ms) ease-out, -webkit-transform var(--yarl__swipe_animation_duration, 500ms) ease-out;
|
|
49
49
|
}
|
|
50
|
+
[dir=rtl] .yarl__slide {
|
|
51
|
+
--yarl__direction: -1;
|
|
52
|
+
}
|
|
50
53
|
.yarl__container_swipe .yarl__slide {
|
|
51
|
-
-webkit-transform: translate3d(calc(var(--yarl__slide_offset, 0) * (100% + var(--yarl__carousel_spacing, 30%))), 0, 0) translate3d(var(--yarl__swipe_offset, 0px), 0, 0);
|
|
52
|
-
transform: translate3d(calc(var(--yarl__slide_offset, 0) * (100% + var(--yarl__carousel_spacing, 30%))), 0, 0) translate3d(var(--yarl__swipe_offset, 0px), 0, 0);
|
|
54
|
+
-webkit-transform: translate3d(calc(var(--yarl__slide_offset, 0) * (100% + var(--yarl__carousel_spacing, 30%)) * var(--yarl__direction, 1)), 0, 0) translate3d(var(--yarl__swipe_offset, 0px), 0, 0);
|
|
55
|
+
transform: translate3d(calc(var(--yarl__slide_offset, 0) * (100% + var(--yarl__carousel_spacing, 30%)) * var(--yarl__direction, 1)), 0, 0) translate3d(var(--yarl__swipe_offset, 0px), 0, 0);
|
|
53
56
|
transition: unset;
|
|
54
57
|
}
|
|
55
58
|
.yarl__slide_image {
|
|
@@ -62,6 +65,12 @@
|
|
|
62
65
|
user-select: none;
|
|
63
66
|
-webkit-user-select: none;
|
|
64
67
|
-webkit-touch-callout: none;
|
|
68
|
+
-webkit-transform: translate3d(0, 0, 0);
|
|
69
|
+
transform: translate3d(0, 0, 0);
|
|
70
|
+
}
|
|
71
|
+
.yarl__slide_image_cover {
|
|
72
|
+
-o-object-fit: cover;
|
|
73
|
+
object-fit: cover;
|
|
65
74
|
}
|
|
66
75
|
.yarl__slide_image_loading {
|
|
67
76
|
opacity: 0;
|
|
@@ -137,6 +146,9 @@
|
|
|
137
146
|
padding: 8px;
|
|
138
147
|
gap: 8px;
|
|
139
148
|
}
|
|
149
|
+
[dir=rtl] .yarl__toolbar {
|
|
150
|
+
inset: 0 auto auto 0;
|
|
151
|
+
}
|
|
140
152
|
.yarl__icon {
|
|
141
153
|
width: 32px;
|
|
142
154
|
height: 32px;
|
|
@@ -185,9 +197,21 @@
|
|
|
185
197
|
.yarl__navigation_prev {
|
|
186
198
|
left: 0;
|
|
187
199
|
}
|
|
200
|
+
[dir=rtl] .yarl__navigation_prev {
|
|
201
|
+
left: unset;
|
|
202
|
+
right: 0;
|
|
203
|
+
-webkit-transform: translateY(-50%) rotate(180deg);
|
|
204
|
+
transform: translateY(-50%) rotate(180deg);
|
|
205
|
+
}
|
|
188
206
|
.yarl__navigation_next {
|
|
189
207
|
right: 0;
|
|
190
208
|
}
|
|
209
|
+
[dir=rtl] .yarl__navigation_next {
|
|
210
|
+
left: 0;
|
|
211
|
+
right: unset;
|
|
212
|
+
-webkit-transform: translateY(-50%) rotate(180deg);
|
|
213
|
+
transform: translateY(-50%) rotate(180deg);
|
|
214
|
+
}
|
|
191
215
|
.yarl__no_scroll {
|
|
192
216
|
height: 100%;
|
|
193
217
|
overflow: hidden;
|
|
@@ -195,6 +219,10 @@
|
|
|
195
219
|
.yarl__pad_scrollbar {
|
|
196
220
|
padding-right: var(--yarl__scrollbar_padding, 17px);
|
|
197
221
|
}
|
|
222
|
+
[dir=rtl] .yarl__pad_scrollbar {
|
|
223
|
+
padding-right: unset;
|
|
224
|
+
padding-left: var(--yarl__scrollbar_padding, 17px);
|
|
225
|
+
}
|
|
198
226
|
|
|
199
227
|
@-webkit-keyframes yarl__delayed_fadein {
|
|
200
228
|
0% {
|
package/dist/types.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import PropTypes from "prop-types";
|
|
3
2
|
import { ContainerRect } from "./core/hooks/useContainerRect.js";
|
|
3
|
+
/** Image fit setting */
|
|
4
|
+
export declare type ImageFit = "contain" | "cover";
|
|
4
5
|
/** Image slide properties */
|
|
5
6
|
export interface SlideImage {
|
|
6
7
|
/** image URL */
|
|
@@ -9,6 +10,8 @@ export interface SlideImage {
|
|
|
9
10
|
alt?: string;
|
|
10
11
|
/** image aspect ratio */
|
|
11
12
|
aspectRatio?: number;
|
|
13
|
+
/** `object-fit` setting */
|
|
14
|
+
imageFit?: ImageFit;
|
|
12
15
|
/** alternative images to be passed to the 'srcSet' */
|
|
13
16
|
srcSet?: {
|
|
14
17
|
/** image URL */
|
|
@@ -30,10 +33,12 @@ export interface CarouselSettings {
|
|
|
30
33
|
finite: boolean;
|
|
31
34
|
/** the lightbox preloads (2 * preload + 1) slides */
|
|
32
35
|
preload: number;
|
|
33
|
-
/** padding around each slide */
|
|
34
|
-
padding: string |
|
|
36
|
+
/** padding around each slide (e.g., "16px", "10px 20px" or 0) */
|
|
37
|
+
padding: string | 0;
|
|
35
38
|
/** spacing between slides (e.g., "100px", "50%" or 0) */
|
|
36
|
-
spacing: string |
|
|
39
|
+
spacing: string | 0;
|
|
40
|
+
/** `object-fit` setting for image slides */
|
|
41
|
+
imageFit: ImageFit;
|
|
37
42
|
}
|
|
38
43
|
/** Animation settings */
|
|
39
44
|
export interface AnimationSettings {
|
|
@@ -44,8 +49,10 @@ export interface AnimationSettings {
|
|
|
44
49
|
}
|
|
45
50
|
/** Controller settings */
|
|
46
51
|
export interface ControllerSettings {
|
|
47
|
-
/** if true, the lightbox captures focus when it opens
|
|
52
|
+
/** if true, the lightbox captures focus when it opens */
|
|
48
53
|
focus: boolean;
|
|
54
|
+
/** controller `touch-action` */
|
|
55
|
+
touchAction: "none" | "pan-y";
|
|
49
56
|
}
|
|
50
57
|
/** Custom render functions. */
|
|
51
58
|
export interface Render {
|
|
@@ -123,61 +130,6 @@ export interface LightboxProps {
|
|
|
123
130
|
/** lifecycle callbacks */
|
|
124
131
|
on: Callbacks;
|
|
125
132
|
}
|
|
126
|
-
export declare const ImageSlidePropTypes: PropTypes.Requireable<PropTypes.InferProps<{
|
|
127
|
-
src: PropTypes.Requireable<string>;
|
|
128
|
-
alt: PropTypes.Requireable<string>;
|
|
129
|
-
aspectRatio: PropTypes.Requireable<number>;
|
|
130
|
-
srcSet: PropTypes.Requireable<PropTypes.InferProps<{
|
|
131
|
-
src: PropTypes.Validator<string>;
|
|
132
|
-
width: PropTypes.Validator<number>;
|
|
133
|
-
}>[]>;
|
|
134
|
-
}>>;
|
|
135
|
-
export declare const SlideTypesPropTypes: PropTypes.Validator<any>[];
|
|
136
|
-
export declare const LightboxPropTypes: {
|
|
137
|
-
open: PropTypes.Validator<boolean>;
|
|
138
|
-
close: PropTypes.Validator<(...args: any[]) => any>;
|
|
139
|
-
index: PropTypes.Validator<number>;
|
|
140
|
-
slides: PropTypes.Validator<any[]>;
|
|
141
|
-
render: PropTypes.Validator<PropTypes.InferProps<{
|
|
142
|
-
slide: PropTypes.Requireable<(...args: any[]) => any>;
|
|
143
|
-
slideHeader: PropTypes.Requireable<(...args: any[]) => any>;
|
|
144
|
-
slideFooter: PropTypes.Requireable<(...args: any[]) => any>;
|
|
145
|
-
slideContainer: PropTypes.Requireable<(...args: any[]) => any>;
|
|
146
|
-
iconPrev: PropTypes.Requireable<(...args: any[]) => any>;
|
|
147
|
-
iconNext: PropTypes.Requireable<(...args: any[]) => any>;
|
|
148
|
-
iconClose: PropTypes.Requireable<(...args: any[]) => any>;
|
|
149
|
-
iconLoading: PropTypes.Requireable<(...args: any[]) => any>;
|
|
150
|
-
iconError: PropTypes.Requireable<(...args: any[]) => any>;
|
|
151
|
-
buttonPrev: PropTypes.Requireable<(...args: any[]) => any>;
|
|
152
|
-
buttonNext: PropTypes.Requireable<(...args: any[]) => any>;
|
|
153
|
-
buttonClose: PropTypes.Requireable<(...args: any[]) => any>;
|
|
154
|
-
}>>;
|
|
155
|
-
plugins: PropTypes.Validator<((...args: any[]) => any)[]>;
|
|
156
|
-
toolbar: PropTypes.Validator<PropTypes.InferProps<{
|
|
157
|
-
buttons: PropTypes.Validator<(string | number | boolean | PropTypes.ReactElementLike | PropTypes.ReactNodeArray | null | undefined)[]>;
|
|
158
|
-
}>>;
|
|
159
|
-
labels: PropTypes.Validator<PropTypes.InferProps<{}>>;
|
|
160
|
-
carousel: PropTypes.Validator<PropTypes.InferProps<{
|
|
161
|
-
finite: PropTypes.Validator<boolean>;
|
|
162
|
-
preload: PropTypes.Validator<number>;
|
|
163
|
-
padding: PropTypes.Validator<string | number>;
|
|
164
|
-
spacing: PropTypes.Validator<string | number>;
|
|
165
|
-
}>>;
|
|
166
|
-
animation: PropTypes.Validator<PropTypes.InferProps<{
|
|
167
|
-
fade: PropTypes.Validator<number>;
|
|
168
|
-
swipe: PropTypes.Validator<number>;
|
|
169
|
-
}>>;
|
|
170
|
-
controller: PropTypes.Validator<PropTypes.InferProps<{
|
|
171
|
-
focus: PropTypes.Validator<boolean>;
|
|
172
|
-
}>>;
|
|
173
|
-
on: PropTypes.Validator<PropTypes.InferProps<{
|
|
174
|
-
view: PropTypes.Requireable<(...args: any[]) => any>;
|
|
175
|
-
entering: PropTypes.Requireable<(...args: any[]) => any>;
|
|
176
|
-
entered: PropTypes.Requireable<(...args: any[]) => any>;
|
|
177
|
-
exiting: PropTypes.Requireable<(...args: any[]) => any>;
|
|
178
|
-
exited: PropTypes.Requireable<(...args: any[]) => any>;
|
|
179
|
-
}>>;
|
|
180
|
-
};
|
|
181
133
|
export declare const LightboxDefaultProps: {
|
|
182
134
|
open: boolean;
|
|
183
135
|
close: () => void;
|
|
@@ -238,3 +190,9 @@ export declare type PluginMethods = {
|
|
|
238
190
|
};
|
|
239
191
|
/** Lightbox plugin */
|
|
240
192
|
export declare type Plugin = ({ addParent, addChild, addSibling, replace, remove, augment }: PluginMethods) => void;
|
|
193
|
+
/** Deep partial utility type */
|
|
194
|
+
export declare type DeepPartial<T, K extends keyof T> = Omit<T, K> & {
|
|
195
|
+
[P in keyof Pick<T, K>]?: Partial<Pick<T, K>[P]>;
|
|
196
|
+
};
|
|
197
|
+
/** Lightbox external props */
|
|
198
|
+
export declare type LightboxExternalProps = DeepPartial<Partial<LightboxProps>, "carousel" | "animation" | "render" | "toolbar" | "controller" | "on">;
|
package/dist/types.js
CHANGED
|
@@ -1,59 +1,3 @@
|
|
|
1
|
-
import PropTypes from "prop-types";
|
|
2
|
-
export const ImageSlidePropTypes = PropTypes.shape({
|
|
3
|
-
src: PropTypes.string,
|
|
4
|
-
alt: PropTypes.string,
|
|
5
|
-
aspectRatio: PropTypes.number,
|
|
6
|
-
srcSet: PropTypes.arrayOf(PropTypes.shape({
|
|
7
|
-
src: PropTypes.string.isRequired,
|
|
8
|
-
width: PropTypes.number.isRequired,
|
|
9
|
-
}).isRequired),
|
|
10
|
-
});
|
|
11
|
-
export const SlideTypesPropTypes = [ImageSlidePropTypes];
|
|
12
|
-
export const LightboxPropTypes = {
|
|
13
|
-
open: PropTypes.bool.isRequired,
|
|
14
|
-
close: PropTypes.func.isRequired,
|
|
15
|
-
index: PropTypes.number.isRequired,
|
|
16
|
-
slides: PropTypes.arrayOf(PropTypes.oneOfType(SlideTypesPropTypes).isRequired).isRequired,
|
|
17
|
-
render: PropTypes.shape({
|
|
18
|
-
slide: PropTypes.func,
|
|
19
|
-
slideHeader: PropTypes.func,
|
|
20
|
-
slideFooter: PropTypes.func,
|
|
21
|
-
slideContainer: PropTypes.func,
|
|
22
|
-
iconPrev: PropTypes.func,
|
|
23
|
-
iconNext: PropTypes.func,
|
|
24
|
-
iconClose: PropTypes.func,
|
|
25
|
-
iconLoading: PropTypes.func,
|
|
26
|
-
iconError: PropTypes.func,
|
|
27
|
-
buttonPrev: PropTypes.func,
|
|
28
|
-
buttonNext: PropTypes.func,
|
|
29
|
-
buttonClose: PropTypes.func,
|
|
30
|
-
}).isRequired,
|
|
31
|
-
plugins: PropTypes.arrayOf(PropTypes.func.isRequired).isRequired,
|
|
32
|
-
toolbar: PropTypes.shape({
|
|
33
|
-
buttons: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.oneOf(["close"]), PropTypes.node])).isRequired,
|
|
34
|
-
}).isRequired,
|
|
35
|
-
labels: PropTypes.shape({}).isRequired,
|
|
36
|
-
carousel: PropTypes.shape({
|
|
37
|
-
finite: PropTypes.bool.isRequired,
|
|
38
|
-
preload: PropTypes.number.isRequired,
|
|
39
|
-
padding: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,
|
|
40
|
-
spacing: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,
|
|
41
|
-
}).isRequired,
|
|
42
|
-
animation: PropTypes.shape({
|
|
43
|
-
fade: PropTypes.number.isRequired,
|
|
44
|
-
swipe: PropTypes.number.isRequired,
|
|
45
|
-
}).isRequired,
|
|
46
|
-
controller: PropTypes.shape({
|
|
47
|
-
focus: PropTypes.bool.isRequired,
|
|
48
|
-
}).isRequired,
|
|
49
|
-
on: PropTypes.shape({
|
|
50
|
-
view: PropTypes.func,
|
|
51
|
-
entering: PropTypes.func,
|
|
52
|
-
entered: PropTypes.func,
|
|
53
|
-
exiting: PropTypes.func,
|
|
54
|
-
exited: PropTypes.func,
|
|
55
|
-
}).isRequired,
|
|
56
|
-
};
|
|
57
1
|
export const LightboxDefaultProps = {
|
|
58
2
|
open: false,
|
|
59
3
|
close: () => { },
|
|
@@ -72,9 +16,11 @@ export const LightboxDefaultProps = {
|
|
|
72
16
|
preload: 2,
|
|
73
17
|
padding: "16px",
|
|
74
18
|
spacing: "30%",
|
|
19
|
+
imageFit: "contain",
|
|
75
20
|
},
|
|
76
21
|
controller: {
|
|
77
22
|
focus: true,
|
|
23
|
+
touchAction: "none",
|
|
78
24
|
},
|
|
79
25
|
on: {},
|
|
80
26
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "yet-another-react-lightbox",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.1",
|
|
4
4
|
"description": "Modern React lightbox component",
|
|
5
5
|
"author": "Igor Danchenko",
|
|
6
6
|
"license": "MIT",
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"./plugins/captions.css": "./dist/plugins/captions.css",
|
|
15
15
|
"./plugins/fullscreen": "./dist/plugins/Fullscreen.js",
|
|
16
16
|
"./plugins/inline": "./dist/plugins/Inline.js",
|
|
17
|
+
"./plugins/slideshow": "./dist/plugins/Slideshow.js",
|
|
17
18
|
"./plugins/video": "./dist/plugins/Video.js",
|
|
18
19
|
"./styles.css": "./dist/styles.css"
|
|
19
20
|
},
|
|
@@ -38,6 +39,9 @@
|
|
|
38
39
|
"plugins/inline": [
|
|
39
40
|
"dist/plugins/Inline.d.ts"
|
|
40
41
|
],
|
|
42
|
+
"plugins/slideshow": [
|
|
43
|
+
"dist/plugins/Slideshow.d.ts"
|
|
44
|
+
],
|
|
41
45
|
"plugins/video": [
|
|
42
46
|
"dist/plugins/Video.d.ts"
|
|
43
47
|
]
|
|
@@ -70,9 +74,6 @@
|
|
|
70
74
|
"lint": "eslint .",
|
|
71
75
|
"test": "jest"
|
|
72
76
|
},
|
|
73
|
-
"dependencies": {
|
|
74
|
-
"prop-types": "^15.5.7"
|
|
75
|
-
},
|
|
76
77
|
"peerDependencies": {
|
|
77
78
|
"react": ">=16.8.0",
|
|
78
79
|
"react-dom": ">=16.8.0"
|
|
@@ -86,10 +87,10 @@
|
|
|
86
87
|
"@testing-library/react": "^13.3.0",
|
|
87
88
|
"@testing-library/user-event": "^14.2.0",
|
|
88
89
|
"@types/jest": "^28.1.1",
|
|
89
|
-
"@types/react": "^18.0.
|
|
90
|
+
"@types/react": "^18.0.13",
|
|
90
91
|
"@types/react-dom": "^18.0.5",
|
|
91
|
-
"@typescript-eslint/eslint-plugin": "^5.
|
|
92
|
-
"@typescript-eslint/parser": "^5.
|
|
92
|
+
"@typescript-eslint/eslint-plugin": "^5.28.0",
|
|
93
|
+
"@typescript-eslint/parser": "^5.28.0",
|
|
93
94
|
"autoprefixer": "^10.4.7",
|
|
94
95
|
"eslint": "^8.17.0",
|
|
95
96
|
"eslint-config-airbnb": "^19.0.4",
|
|
@@ -99,20 +100,20 @@
|
|
|
99
100
|
"eslint-plugin-jsx-a11y": "^6.5.1",
|
|
100
101
|
"eslint-plugin-prettier": "^4.0.0",
|
|
101
102
|
"eslint-plugin-react": "^7.30.0",
|
|
102
|
-
"eslint-plugin-react-hooks": "^4.
|
|
103
|
+
"eslint-plugin-react-hooks": "^4.6.0",
|
|
103
104
|
"husky": "^8.0.1",
|
|
104
105
|
"jest": "^28.1.1",
|
|
105
106
|
"jest-environment-jsdom": "^28.1.1",
|
|
106
|
-
"lint-staged": "^13.0.
|
|
107
|
+
"lint-staged": "^13.0.2",
|
|
107
108
|
"npm-run-all": "^4.1.5",
|
|
108
109
|
"postcss": "^8.4.14",
|
|
109
110
|
"postcss-cli": "^9.1.0",
|
|
110
|
-
"prettier": "^2.
|
|
111
|
-
"react": "^18.
|
|
112
|
-
"react-dom": "^18.
|
|
111
|
+
"prettier": "^2.7.1",
|
|
112
|
+
"react": "^18.2.0",
|
|
113
|
+
"react-dom": "^18.2.0",
|
|
113
114
|
"rimraf": "^3.0.2",
|
|
114
115
|
"sass": "^1.52.3",
|
|
115
|
-
"ts-jest": "^28.0.
|
|
116
|
+
"ts-jest": "^28.0.5",
|
|
116
117
|
"typescript": "^4.7.3"
|
|
117
118
|
},
|
|
118
119
|
"keywords": [
|