yet-another-react-lightbox 1.3.5 → 1.4.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 +67 -5
- package/dist/Lightbox.js +0 -1
- package/dist/core/components/Icons.js +1 -3
- package/dist/core/components/ImageSlide.d.ts +4 -2
- package/dist/core/components/ImageSlide.js +15 -15
- package/dist/core/hooks/useContainerRect.js +11 -8
- package/dist/core/hooks/useEnhancedEffect.js +2 -1
- package/dist/core/modules/Carousel.js +19 -14
- package/dist/core/modules/Controller.d.ts +3 -3
- package/dist/core/modules/Controller.js +16 -17
- package/dist/core/modules/NoScroll.js +0 -1
- package/dist/core/modules/Toolbar.js +8 -1
- package/dist/core/utils.d.ts +2 -0
- package/dist/core/utils.js +2 -0
- package/dist/plugins/Captions.d.ts +26 -0
- package/dist/plugins/Captions.js +54 -0
- package/dist/plugins/Fullscreen.js +3 -5
- package/dist/plugins/Inline.js +0 -3
- package/dist/plugins/Video.js +4 -9
- package/dist/plugins/captions.css +39 -0
- package/dist/plugins/index.d.ts +1 -0
- package/dist/plugins/index.js +1 -0
- package/dist/styles.css +1 -1
- package/dist/types.d.ts +18 -2
- package/dist/types.js +4 -1
- package/package.json +20 -14
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@ Modern React lightbox component. Performant, easy to use, customizable and exten
|
|
|
15
15
|
- **Responsive:** responsive images with automatic resolution switching are supported out of the box
|
|
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
|
-
- **No bloat:** never bundle rarely used features; add optional features via plugins
|
|
18
|
+
- **No bloat:** never bundle rarely used features; add optional features via plugins
|
|
19
19
|
- **TypeScript:** type definitions come built-in in the package
|
|
20
20
|
|
|
21
21
|
## Documentation
|
|
@@ -40,7 +40,7 @@ yarn add yet-another-react-lightbox
|
|
|
40
40
|
|
|
41
41
|
## Minimal Setup Example
|
|
42
42
|
|
|
43
|
-
```
|
|
43
|
+
```jsx
|
|
44
44
|
import * as React from "react";
|
|
45
45
|
import Lightbox from "yet-another-react-lightbox";
|
|
46
46
|
import "yet-another-react-lightbox/styles.css";
|
|
@@ -58,8 +58,8 @@ const App = () => {
|
|
|
58
58
|
open={open}
|
|
59
59
|
close={() => setOpen(false)}
|
|
60
60
|
slides={[
|
|
61
|
-
{ src: "/image1.jpg" },
|
|
62
|
-
{ src: "/image2.jpg" },
|
|
61
|
+
{ src: "/image1.jpg" },
|
|
62
|
+
{ src: "/image2.jpg" },
|
|
63
63
|
{ src: "/image3.jpg" },
|
|
64
64
|
]}
|
|
65
65
|
/>
|
|
@@ -70,6 +70,68 @@ const App = () => {
|
|
|
70
70
|
export default App;
|
|
71
71
|
```
|
|
72
72
|
|
|
73
|
+
## Recommended Setup
|
|
74
|
+
|
|
75
|
+
Unlike many other lightbox libraries, Yet Another React Lightbox doesn't have a concept of "thumbnail" or "original"
|
|
76
|
+
(or "full size") images. We use responsive images instead and recommend you provide multiple files of different
|
|
77
|
+
resolutions for each image. Yet Another React Lightbox automatically populates `srcSet` / `sizes` attributes and lets
|
|
78
|
+
the browser decide which image is more appropriate for its viewport size.
|
|
79
|
+
|
|
80
|
+
```jsx
|
|
81
|
+
import * as React from "react";
|
|
82
|
+
import Lightbox from "yet-another-react-lightbox";
|
|
83
|
+
import "yet-another-react-lightbox/styles.css";
|
|
84
|
+
|
|
85
|
+
const App = () => {
|
|
86
|
+
const [open, setOpen] = React.useState(false);
|
|
87
|
+
|
|
88
|
+
return (
|
|
89
|
+
<>
|
|
90
|
+
<button type="button" onClick={() => setOpen(true)}>
|
|
91
|
+
Open Lightbox
|
|
92
|
+
</button>
|
|
93
|
+
|
|
94
|
+
<Lightbox
|
|
95
|
+
open={open}
|
|
96
|
+
close={() => setOpen(false)}
|
|
97
|
+
slides={[
|
|
98
|
+
{
|
|
99
|
+
src: "/image1x3840.jpg",
|
|
100
|
+
alt: "image 1",
|
|
101
|
+
aspectRatio: 3 / 2,
|
|
102
|
+
srcSet: [
|
|
103
|
+
{ src: "/image1x320.jpg", width: 320 },
|
|
104
|
+
{ src: "/image1x640.jpg", width: 640 },
|
|
105
|
+
{ src: "/image1x1200.jpg", width: 1200 },
|
|
106
|
+
{ src: "/image1x2048.jpg", width: 2048 },
|
|
107
|
+
{ src: "/image1x3840.jpg", width: 3840 },
|
|
108
|
+
]
|
|
109
|
+
},
|
|
110
|
+
// ...
|
|
111
|
+
]}
|
|
112
|
+
/>
|
|
113
|
+
</>
|
|
114
|
+
);
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
export default App;
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
You can also integrate 3rd-party image components (e.g., Next.js Image or Gatsby Image) via a custom render function.
|
|
121
|
+
See [examples](https://yet-another-react-lightbox.vercel.app/examples) on the documentation website.
|
|
122
|
+
|
|
123
|
+
## Plugins
|
|
124
|
+
|
|
125
|
+
Yet Another React Lightbox allows you to add optional features based on your requirements via plugins.
|
|
126
|
+
|
|
127
|
+
The following plugins come bundled in the package:
|
|
128
|
+
|
|
129
|
+
- [Captions](https://yet-another-react-lightbox.vercel.app/plugins/captions) - adds support for slide title and
|
|
130
|
+
description
|
|
131
|
+
- [Fullscreen](https://yet-another-react-lightbox.vercel.app/plugins/fullscreen) - adds support for fullscreen mode
|
|
132
|
+
- [Inline](https://yet-another-react-lightbox.vercel.app/plugins/inline) - adds support for inline rendering mode
|
|
133
|
+
- [Video](https://yet-another-react-lightbox.vercel.app/plugins/video) - adds support for video slides
|
|
134
|
+
|
|
73
135
|
## License
|
|
74
136
|
|
|
75
|
-
MIT © [Igor Danchenko](https://github.com/igordanchenko)
|
|
137
|
+
MIT © 2022 [Igor Danchenko](https://github.com/igordanchenko)
|
package/dist/Lightbox.js
CHANGED
|
@@ -24,7 +24,6 @@ const LightboxComponent = (props) => {
|
|
|
24
24
|
return React.createElement(React.Fragment, null, renderNode(createNode(CoreModule, config), augmentedProps));
|
|
25
25
|
};
|
|
26
26
|
LightboxComponent.propTypes = LightboxPropTypes;
|
|
27
|
-
/** Modern React lightbox component */
|
|
28
27
|
export const Lightbox = (props) => {
|
|
29
28
|
const { carousel, animation, render, toolbar, controller, on, ...restProps } = props;
|
|
30
29
|
const { carousel: defaultCarousel, animation: defaultAnimation, render: defaultRender, toolbar: defaultToolbar, controller: defaultController, on: defaultOn, ...restDefaultProps } = LightboxDefaultProps;
|
|
@@ -10,7 +10,5 @@ export const createIcon = (name, glyph) => {
|
|
|
10
10
|
export const CloseIcon = createIcon("Close", React.createElement("path", { d: "M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" }));
|
|
11
11
|
export const PreviousIcon = createIcon("Previous", React.createElement("path", { d: "M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z" }));
|
|
12
12
|
export const NextIcon = createIcon("Next", React.createElement("path", { d: "M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z" }));
|
|
13
|
-
export const LoadingIcon = createIcon("Loading", React.createElement(React.Fragment, null, Array.from({ length: 8 }).map((_, index, array) => (React.createElement("line", {
|
|
14
|
-
// eslint-disable-next-line react/no-array-index-key
|
|
15
|
-
key: index, x1: "12", y1: "6.5", x2: "12", y2: "1.8", strokeLinecap: "round", strokeWidth: "2.6", stroke: "currentColor", strokeOpacity: (1 / array.length) * (index + 1), transform: `rotate(${(360 / array.length) * index}, 12, 12)` })))));
|
|
13
|
+
export const LoadingIcon = createIcon("Loading", React.createElement(React.Fragment, null, Array.from({ length: 8 }).map((_, index, array) => (React.createElement("line", { key: index, x1: "12", y1: "6.5", x2: "12", y2: "1.8", strokeLinecap: "round", strokeWidth: "2.6", stroke: "currentColor", strokeOpacity: (1 / array.length) * (index + 1), transform: `rotate(${(360 / array.length) * index}, 12, 12)` })))));
|
|
16
14
|
export const ErrorIcon = createIcon("Error", React.createElement("path", { d: "M21.9,21.9l-8.49-8.49l0,0L3.59,3.59l0,0L2.1,2.1L0.69,3.51L3,5.83V19c0,1.1,0.9,2,2,2h13.17l2.31,2.31L21.9,21.9z M5,18 l3.5-4.5l2.5,3.01L12.17,15l3,3H5z M21,18.17L5.83,3H19c1.1,0,2,0.9,2,2V18.17z" }));
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
2
|
import { Render, SlideImage } from "../../types.js";
|
|
3
|
+
import { ContainerRect } from "../hooks/index.js";
|
|
3
4
|
export declare type ImageSlideProps = {
|
|
4
5
|
slide: SlideImage;
|
|
5
|
-
render
|
|
6
|
+
render?: Render;
|
|
7
|
+
rect?: ContainerRect;
|
|
6
8
|
};
|
|
7
|
-
export declare const ImageSlide: ({ slide: image, render }: ImageSlideProps) => JSX.Element;
|
|
9
|
+
export declare const ImageSlide: ({ slide: image, render, rect }: ImageSlideProps) => JSX.Element;
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import { clsx, cssClass } from "../utils.js";
|
|
2
|
+
import { adjustDevicePixelRatio, clsx, cssClass, hasWindow } from "../utils.js";
|
|
3
3
|
import { useLatest } from "../hooks/index.js";
|
|
4
4
|
import { ErrorIcon, LoadingIcon } from "./Icons.js";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
var _a, _b, _c;
|
|
5
|
+
export const ImageSlide = ({ slide: image, render, rect }) => {
|
|
6
|
+
var _a;
|
|
8
7
|
const [state, setState] = React.useState("loading");
|
|
9
8
|
const latestState = useLatest(state);
|
|
10
9
|
const imageRef = React.useRef(null);
|
|
11
|
-
const { containerRect } = useController();
|
|
12
10
|
const handleLoading = React.useCallback((img) => {
|
|
13
11
|
if (latestState.current === "complete") {
|
|
14
12
|
return;
|
|
@@ -37,29 +35,31 @@ export const ImageSlide = ({ slide: image, render }) => {
|
|
|
37
35
|
return (React.createElement(React.Fragment, null,
|
|
38
36
|
React.createElement("img", { ref: setImageRef, onLoad: onLoad, onError: onError, className: clsx(cssClass("slide_image"), state !== "complete" && cssClass("slide_image_loading")), draggable: false, alt: image.alt, ...(image.srcSet
|
|
39
37
|
? {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
38
|
+
...(rect && hasWindow()
|
|
39
|
+
? {
|
|
40
|
+
sizes: `${Math.ceil((Math.min(image.aspectRatio ? rect.height * image.aspectRatio : Number.MAX_VALUE, rect.width) /
|
|
41
|
+
window.innerWidth) *
|
|
42
|
+
100)}vw`,
|
|
43
|
+
}
|
|
44
|
+
: null),
|
|
45
45
|
srcSet: image.srcSet
|
|
46
46
|
.sort((a, b) => a.width - b.width)
|
|
47
47
|
.map((item) => `${item.src} ${item.width}w`)
|
|
48
48
|
.join(", "),
|
|
49
49
|
style: {
|
|
50
|
-
maxWidth: `${Math.max(...image.srcSet.map((x) => x.width))}px`,
|
|
50
|
+
maxWidth: `${adjustDevicePixelRatio(Math.max(...image.srcSet.map((x) => x.width)))}px`,
|
|
51
51
|
},
|
|
52
52
|
}
|
|
53
53
|
: {
|
|
54
|
-
style:
|
|
54
|
+
style: imageRef.current && ((_a = imageRef.current) === null || _a === void 0 ? void 0 : _a.naturalWidth) > 0
|
|
55
55
|
? {
|
|
56
|
-
maxWidth: `${(
|
|
56
|
+
maxWidth: `${adjustDevicePixelRatio(imageRef.current.naturalWidth)}px`,
|
|
57
57
|
}
|
|
58
58
|
: undefined,
|
|
59
59
|
}), src: image.src }),
|
|
60
60
|
state !== "complete" && (React.createElement("div", { className: cssClass("slide_placeholder") },
|
|
61
61
|
state === "loading" &&
|
|
62
|
-
(render.iconLoading ? (render.iconLoading()) : (React.createElement(LoadingIcon, { className: clsx(cssClass("icon"), cssClass("slide_loading")) }))),
|
|
62
|
+
((render === null || render === void 0 ? void 0 : render.iconLoading) ? (render.iconLoading()) : (React.createElement(LoadingIcon, { className: clsx(cssClass("icon"), cssClass("slide_loading")) }))),
|
|
63
63
|
state === "error" &&
|
|
64
|
-
(render.iconError ? (render.iconError()) : (React.createElement(ErrorIcon, { className: clsx(cssClass("icon"), cssClass("slide_error")) })))))));
|
|
64
|
+
((render === null || render === void 0 ? void 0 : render.iconError) ? (render.iconError()) : (React.createElement(ErrorIcon, { className: clsx(cssClass("icon"), cssClass("slide_error")) })))))));
|
|
65
65
|
};
|
|
@@ -10,14 +10,17 @@ export const useContainerRect = () => {
|
|
|
10
10
|
observerRef.current = undefined;
|
|
11
11
|
}
|
|
12
12
|
const updateContainerRect = () => {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
width,
|
|
18
|
-
height,
|
|
19
|
-
}
|
|
20
|
-
|
|
13
|
+
if (node) {
|
|
14
|
+
const styles = window.getComputedStyle(node);
|
|
15
|
+
const parse = (value) => parseFloat(value) || 0;
|
|
16
|
+
setContainerRect({
|
|
17
|
+
width: Math.round(node.clientWidth - parse(styles.paddingLeft) - parse(styles.paddingRight)),
|
|
18
|
+
height: Math.round(node.clientHeight - parse(styles.paddingTop) - parse(styles.paddingBottom)),
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
setContainerRect(undefined);
|
|
23
|
+
}
|
|
21
24
|
};
|
|
22
25
|
updateContainerRect();
|
|
23
26
|
if (node && typeof ResizeObserver !== "undefined") {
|
|
@@ -1,35 +1,40 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { LightboxDefaultProps } from "../../types.js";
|
|
3
|
+
import { useContainerRect } from "../hooks/index.js";
|
|
3
4
|
import { createModule } from "../config.js";
|
|
4
5
|
import { clsx, cssClass, cssVar } from "../utils.js";
|
|
5
6
|
import { ImageSlide } from "../components/index.js";
|
|
6
7
|
import { useController } from "./Controller.js";
|
|
7
|
-
const CarouselSlide = ({ slide, offset
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
const CarouselSlide = ({ slide, offset }) => {
|
|
9
|
+
const { setContainerRef, containerRect } = useContainerRect();
|
|
10
|
+
const { latestProps } = useController();
|
|
11
|
+
const { render } = latestProps.current;
|
|
12
|
+
const renderSlide = (rect) => {
|
|
13
|
+
var _a, _b, _c, _d;
|
|
14
|
+
let rendered = (_a = render.slide) === null || _a === void 0 ? void 0 : _a.call(render, slide, offset, rect);
|
|
15
|
+
if (!rendered && "src" in slide) {
|
|
16
|
+
rendered = React.createElement(ImageSlide, { slide: slide, render: render, rect: rect });
|
|
14
17
|
}
|
|
15
|
-
return
|
|
18
|
+
return rendered ? (React.createElement(React.Fragment, null, (_b = render.slideHeader) === null || _b === void 0 ? void 0 :
|
|
19
|
+
_b.call(render, slide),
|
|
20
|
+
((_c = render.slideContainer) !== null && _c !== void 0 ? _c : ((_, x) => x))(slide, rendered), (_d = render.slideFooter) === null || _d === void 0 ? void 0 :
|
|
21
|
+
_d.call(render, slide))) : null;
|
|
16
22
|
};
|
|
17
|
-
return (React.createElement("div", { className: clsx(cssClass("slide"), cssClass("flex_center")), style: { [cssVar("slide_offset")]: offset } }, renderSlide()));
|
|
23
|
+
return (React.createElement("div", { ref: setContainerRef, className: clsx(cssClass("slide"), cssClass("flex_center")), style: { [cssVar("slide_offset")]: offset } }, containerRect && renderSlide(containerRect)));
|
|
18
24
|
};
|
|
19
|
-
export const Carousel = (
|
|
20
|
-
const { slides, carousel: { finite, preload, padding, spacing }, render, } = props;
|
|
25
|
+
export const Carousel = ({ slides, carousel: { finite, preload, padding, spacing } }) => {
|
|
21
26
|
const { currentIndex, globalIndex } = useController();
|
|
22
27
|
const items = [];
|
|
23
28
|
if ((slides === null || slides === void 0 ? void 0 : slides.length) > 0) {
|
|
24
29
|
for (let i = currentIndex - preload; i < currentIndex; i += 1) {
|
|
25
30
|
if (!finite || i >= 0) {
|
|
26
|
-
items.push(React.createElement(CarouselSlide, { key: globalIndex + i - currentIndex, slide: slides[(i + preload * slides.length) % slides.length], offset: i - currentIndex
|
|
31
|
+
items.push(React.createElement(CarouselSlide, { key: globalIndex + i - currentIndex, slide: slides[(i + preload * slides.length) % slides.length], offset: i - currentIndex }));
|
|
27
32
|
}
|
|
28
33
|
}
|
|
29
|
-
items.push(React.createElement(CarouselSlide, { key: globalIndex, slide: slides[currentIndex], offset: 0
|
|
34
|
+
items.push(React.createElement(CarouselSlide, { key: globalIndex, slide: slides[currentIndex], offset: 0 }));
|
|
30
35
|
for (let i = currentIndex + 1; i <= currentIndex + preload; i += 1) {
|
|
31
36
|
if (!finite || i <= slides.length - 1) {
|
|
32
|
-
items.push(React.createElement(CarouselSlide, { key: globalIndex + i - currentIndex, slide: slides[i % slides.length], offset: i - currentIndex
|
|
37
|
+
items.push(React.createElement(CarouselSlide, { key: globalIndex + i - currentIndex, slide: slides[i % slides.length], offset: i - currentIndex }));
|
|
33
38
|
}
|
|
34
39
|
}
|
|
35
40
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import { Component } from "../../types.js";
|
|
3
|
-
import {
|
|
2
|
+
import { Component, ComponentProps } from "../../types.js";
|
|
3
|
+
import { SubscribeSensors } from "../hooks/index.js";
|
|
4
4
|
export declare type ControllerContextType = {
|
|
5
|
+
latestProps: React.MutableRefObject<ComponentProps>;
|
|
5
6
|
containerRef: React.RefObject<HTMLDivElement>;
|
|
6
|
-
containerRect: ContainerRect;
|
|
7
7
|
currentIndex: number;
|
|
8
8
|
globalIndex: number;
|
|
9
9
|
subscribeSensors: SubscribeSensors<HTMLDivElement>;
|
|
@@ -2,13 +2,13 @@ import * as React from "react";
|
|
|
2
2
|
import { LightboxDefaultProps } from "../../types.js";
|
|
3
3
|
import { cleanup, clsx, cssClass, cssVar, makeUseContext } from "../utils.js";
|
|
4
4
|
import { createModule } from "../config.js";
|
|
5
|
-
import { useContainerRect, useEnhancedEffect, useSensors } from "../hooks/index.js";
|
|
5
|
+
import { useContainerRect, useEnhancedEffect, useLatest, useSensors } from "../hooks/index.js";
|
|
6
6
|
import { useEvents, useTimeouts } from "../contexts/index.js";
|
|
7
7
|
const SWIPE_OFFSET_THRESHOLD = 30;
|
|
8
8
|
const ControllerContext = React.createContext(null);
|
|
9
9
|
export const useController = makeUseContext("useController", "ControllerContext", ControllerContext);
|
|
10
10
|
export const Controller = ({ children, ...props }) => {
|
|
11
|
-
const { containerRef, setContainerRef
|
|
11
|
+
const { containerRef, setContainerRef } = useContainerRect();
|
|
12
12
|
const { registerSensors, subscribeSensors } = useSensors();
|
|
13
13
|
const { subscribe, publish } = useEvents();
|
|
14
14
|
const { setTimeout, clearTimeout } = useTimeouts();
|
|
@@ -16,6 +16,7 @@ export const Controller = ({ children, ...props }) => {
|
|
|
16
16
|
currentIndex: props.index,
|
|
17
17
|
globalIndex: props.index,
|
|
18
18
|
});
|
|
19
|
+
const latestProps = useLatest(props);
|
|
19
20
|
const refs = React.useRef({
|
|
20
21
|
state,
|
|
21
22
|
props,
|
|
@@ -27,9 +28,6 @@ export const Controller = ({ children, ...props }) => {
|
|
|
27
28
|
});
|
|
28
29
|
refs.current.state = state;
|
|
29
30
|
refs.current.props = props;
|
|
30
|
-
refs.current.containerRect = containerRect;
|
|
31
|
-
// prevent browser back/forward navigation on touchpad left/right swipe
|
|
32
|
-
// this has to be done via non-passive native event handler
|
|
33
31
|
useEnhancedEffect(() => {
|
|
34
32
|
const preventDefault = (event) => event.preventDefault();
|
|
35
33
|
const node = containerRef.current;
|
|
@@ -93,7 +91,7 @@ export const Controller = ({ children, ...props }) => {
|
|
|
93
91
|
let newSwipeState = "swipe-animation";
|
|
94
92
|
let newSwipeAnimationDuration = swipeAnimationDuration;
|
|
95
93
|
if (!direction) {
|
|
96
|
-
const containerWidth = (_a = current
|
|
94
|
+
const containerWidth = (_a = containerRef.current) === null || _a === void 0 ? void 0 : _a.clientWidth;
|
|
97
95
|
const elapsedTime = current.swipeStartTime ? Date.now() - current.swipeStartTime : 0;
|
|
98
96
|
const expectedTime = containerWidth
|
|
99
97
|
? (swipeAnimationDuration / containerWidth) * Math.abs(swipeOffset)
|
|
@@ -107,7 +105,6 @@ export const Controller = ({ children, ...props }) => {
|
|
|
107
105
|
newSwipeAnimationDuration =
|
|
108
106
|
(newSwipeAnimationDuration / expectedTime) * Math.max(elapsedTime, expectedTime / 5);
|
|
109
107
|
}
|
|
110
|
-
// eslint-disable-next-line no-param-reassign
|
|
111
108
|
direction = swipeOffset > 0 ? "prev" : "next";
|
|
112
109
|
}
|
|
113
110
|
else {
|
|
@@ -116,7 +113,7 @@ export const Controller = ({ children, ...props }) => {
|
|
|
116
113
|
}
|
|
117
114
|
const newState = {};
|
|
118
115
|
if (direction === "prev") {
|
|
119
|
-
if (isSwipeValid(
|
|
116
|
+
if (isSwipeValid(1)) {
|
|
120
117
|
newState.currentIndex = (currentIndex - 1 + slidesCount) % slidesCount;
|
|
121
118
|
newState.globalIndex = globalIndex - 1;
|
|
122
119
|
}
|
|
@@ -126,7 +123,7 @@ export const Controller = ({ children, ...props }) => {
|
|
|
126
123
|
}
|
|
127
124
|
}
|
|
128
125
|
else if (direction === "next") {
|
|
129
|
-
if (isSwipeValid(
|
|
126
|
+
if (isSwipeValid(-1)) {
|
|
130
127
|
newState.currentIndex = (currentIndex + 1) % slidesCount;
|
|
131
128
|
newState.globalIndex = globalIndex + 1;
|
|
132
129
|
}
|
|
@@ -146,7 +143,7 @@ export const Controller = ({ children, ...props }) => {
|
|
|
146
143
|
}, newSwipeAnimationDuration);
|
|
147
144
|
}
|
|
148
145
|
setState((prev) => ({ ...prev, ...newState }));
|
|
149
|
-
}, [setTimeout, resetSwipe, isSwipeValid, rerender]);
|
|
146
|
+
}, [setTimeout, resetSwipe, isSwipeValid, rerender, containerRef]);
|
|
150
147
|
React.useEffect(() => cleanup(subscribe("prev", () => swipe("prev")), subscribe("next", () => swipe("next"))), [subscribe, swipe]);
|
|
151
148
|
React.useEffect(() => subscribeSensors("onKeyUp", (event) => {
|
|
152
149
|
if (event.code === "Escape") {
|
|
@@ -205,11 +202,9 @@ export const Controller = ({ children, ...props }) => {
|
|
|
205
202
|
const onWheel = React.useCallback((event) => {
|
|
206
203
|
var _a;
|
|
207
204
|
if (event.ctrlKey) {
|
|
208
|
-
// zoom
|
|
209
205
|
return;
|
|
210
206
|
}
|
|
211
207
|
if (Math.abs(event.deltaY) > Math.abs(event.deltaX)) {
|
|
212
|
-
// pan-y
|
|
213
208
|
return;
|
|
214
209
|
}
|
|
215
210
|
const { current } = refs;
|
|
@@ -218,6 +213,9 @@ export const Controller = ({ children, ...props }) => {
|
|
|
218
213
|
current.wheelResidualMomentum = event.deltaX;
|
|
219
214
|
return;
|
|
220
215
|
}
|
|
216
|
+
if (!isSwipeValid(-event.deltaX)) {
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
221
219
|
current.swipeIntent += event.deltaX;
|
|
222
220
|
clearTimeout(current.swipeIntentCleanup);
|
|
223
221
|
if (Math.abs(current.swipeIntent) > SWIPE_OFFSET_THRESHOLD) {
|
|
@@ -235,7 +233,7 @@ export const Controller = ({ children, ...props }) => {
|
|
|
235
233
|
}
|
|
236
234
|
}
|
|
237
235
|
else if (current.swipeState === "swipe") {
|
|
238
|
-
const containerWidth = (_a = current
|
|
236
|
+
const containerWidth = (_a = containerRef.current) === null || _a === void 0 ? void 0 : _a.clientWidth;
|
|
239
237
|
if (containerWidth) {
|
|
240
238
|
current.swipeOffset -= event.deltaX;
|
|
241
239
|
current.swipeOffset =
|
|
@@ -261,19 +259,20 @@ export const Controller = ({ children, ...props }) => {
|
|
|
261
259
|
else {
|
|
262
260
|
current.wheelResidualMomentum = event.deltaX;
|
|
263
261
|
}
|
|
264
|
-
}, [updateSwipeOffset, setTimeout, clearTimeout, swipe, resetSwipe, rerender]);
|
|
262
|
+
}, [updateSwipeOffset, setTimeout, clearTimeout, swipe, resetSwipe, rerender, isSwipeValid, containerRef]);
|
|
265
263
|
React.useEffect(() => subscribeSensors("onWheel", onWheel), [subscribeSensors, onWheel]);
|
|
266
264
|
const context = React.useMemo(() => ({
|
|
265
|
+
latestProps,
|
|
267
266
|
containerRef,
|
|
268
|
-
containerRect,
|
|
269
267
|
currentIndex: state.currentIndex,
|
|
270
268
|
globalIndex: state.globalIndex,
|
|
271
269
|
subscribeSensors,
|
|
272
|
-
}), [
|
|
270
|
+
}), [latestProps, containerRef, state.currentIndex, state.globalIndex, subscribeSensors]);
|
|
273
271
|
return (React.createElement("div", { ref: setContainerRef, className: clsx(cssClass("container"), refs.current.swipeState === "swipe" && cssClass("container_swipe")), style: refs.current.swipeAnimationDuration !== LightboxDefaultProps.animation.swipe
|
|
274
272
|
? {
|
|
275
273
|
[cssVar("swipe_animation_duration")]: `${Math.round(refs.current.swipeAnimationDuration)}ms`,
|
|
276
274
|
}
|
|
277
|
-
: undefined, role: "presentation", "aria-live": "polite", tabIndex: -1, ...registerSensors },
|
|
275
|
+
: undefined, role: "presentation", "aria-live": "polite", tabIndex: -1, ...registerSensors },
|
|
276
|
+
React.createElement(ControllerContext.Provider, { value: context }, children)));
|
|
278
277
|
};
|
|
279
278
|
export const ControllerModule = createModule("controller", Controller);
|
|
@@ -7,7 +7,6 @@ const scrollbarPadding = cssVar("scrollbar_padding");
|
|
|
7
7
|
export const NoScroll = ({ children }) => {
|
|
8
8
|
React.useEffect(() => {
|
|
9
9
|
const scrollbarWidth = Math.round(window.innerWidth - document.documentElement.clientWidth);
|
|
10
|
-
// using an arbitrary threshold to counter the 1px difference in some browsers
|
|
11
10
|
if (scrollbarWidth > 1) {
|
|
12
11
|
document.body.style.setProperty(scrollbarPadding, `${scrollbarWidth}px`);
|
|
13
12
|
document.body.classList.add(padScrollbar);
|
|
@@ -3,9 +3,16 @@ import { createModule } from "../config.js";
|
|
|
3
3
|
import { cssClass, label } from "../utils.js";
|
|
4
4
|
import { useEvents } from "../contexts/index.js";
|
|
5
5
|
import { CloseIcon, IconButton } from "../components/index.js";
|
|
6
|
+
import { useContainerRect } from "../hooks/useContainerRect.js";
|
|
6
7
|
export const Toolbar = ({ toolbar: { buttons }, labels, render: { buttonClose, iconClose } }) => {
|
|
7
8
|
const { publish } = useEvents();
|
|
9
|
+
const { setContainerRef, containerRect } = useContainerRect();
|
|
10
|
+
React.useEffect(() => {
|
|
11
|
+
if (containerRect === null || containerRect === void 0 ? void 0 : containerRect.width) {
|
|
12
|
+
publish("toolbar-width", containerRect.width);
|
|
13
|
+
}
|
|
14
|
+
}, [publish, containerRect === null || containerRect === void 0 ? void 0 : containerRect.width]);
|
|
8
15
|
const renderCloseButton = () => buttonClose ? (buttonClose()) : (React.createElement(IconButton, { key: "close", label: label(labels, "Close"), icon: CloseIcon, renderIcon: iconClose, onClick: () => publish("close") }));
|
|
9
|
-
return (React.createElement("div", { className: cssClass("toolbar") }, buttons === null || buttons === void 0 ? void 0 : buttons.map((button) => (button === "close" ? renderCloseButton() : button))));
|
|
16
|
+
return (React.createElement("div", { ref: setContainerRef, className: cssClass("toolbar") }, buttons === null || buttons === void 0 ? void 0 : buttons.map((button) => (button === "close" ? renderCloseButton() : button))));
|
|
10
17
|
};
|
|
11
18
|
export const ToolbarModule = createModule("toolbar", Toolbar);
|
package/dist/core/utils.d.ts
CHANGED
|
@@ -6,3 +6,5 @@ export declare const cssVar: (name: string) => string;
|
|
|
6
6
|
export declare const label: (labels: Labels | undefined, lbl: string) => string;
|
|
7
7
|
export declare const cleanup: (...cleaners: (() => void)[]) => () => void;
|
|
8
8
|
export declare const makeUseContext: <T>(name: string, contextName: string, context: React.Context<T | null>) => () => T;
|
|
9
|
+
export declare const hasWindow: () => boolean;
|
|
10
|
+
export declare const adjustDevicePixelRatio: (value: number) => number;
|
package/dist/core/utils.js
CHANGED
|
@@ -16,3 +16,5 @@ export const makeUseContext = (name, contextName, context) => () => {
|
|
|
16
16
|
}
|
|
17
17
|
return ctx;
|
|
18
18
|
};
|
|
19
|
+
export const hasWindow = () => typeof window !== "undefined";
|
|
20
|
+
export const adjustDevicePixelRatio = (value) => hasWindow() ? Math.round(value / (window.devicePixelRatio || 1)) : value;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Component, Plugin } from "../types.js";
|
|
2
|
+
declare type TextAlignment = "start" | "end" | "center";
|
|
3
|
+
declare module "../types.js" {
|
|
4
|
+
interface SlideImage {
|
|
5
|
+
/** slide title */
|
|
6
|
+
title?: string;
|
|
7
|
+
/** slide description */
|
|
8
|
+
description?: string;
|
|
9
|
+
}
|
|
10
|
+
interface LightboxProps {
|
|
11
|
+
/** Captions plugin settings */
|
|
12
|
+
captions?: {
|
|
13
|
+
/** description text alignment */
|
|
14
|
+
descriptionTextAlign?: TextAlignment;
|
|
15
|
+
/** maximum number of lines to display in the description section */
|
|
16
|
+
descriptionMaxLines?: number;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/** Captions plugin context holder */
|
|
21
|
+
export declare const CaptionsComponent: Component;
|
|
22
|
+
/** Captions plugin module */
|
|
23
|
+
export declare const CaptionsModule: import("../types.js").Module;
|
|
24
|
+
/** Captions plugin */
|
|
25
|
+
export declare const Captions: Plugin;
|
|
26
|
+
export default Captions;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { cssClass, cssVar, makeUseContext } from "../core/utils.js";
|
|
3
|
+
import { useEvents } from "../core/contexts/Events.js";
|
|
4
|
+
import { createModule } from "../core/index.js";
|
|
5
|
+
const defaultTextAlign = "start";
|
|
6
|
+
const defaultMaxLines = 3;
|
|
7
|
+
const cls = (className) => cssClass(`slide_${className}`);
|
|
8
|
+
const hasTitle = (slide) => "title" in slide ? typeof slide.title === "string" : false;
|
|
9
|
+
const hasDescription = (slide) => "description" in slide ? typeof slide.description === "string" : false;
|
|
10
|
+
const CaptionsContext = React.createContext(null);
|
|
11
|
+
const useCaptions = makeUseContext("useCaptions", "CaptionsContext", CaptionsContext);
|
|
12
|
+
const Title = ({ title }) => {
|
|
13
|
+
const { toolbarWidth } = useCaptions();
|
|
14
|
+
return (React.createElement("div", { className: cls(`title_container`) },
|
|
15
|
+
React.createElement("div", { className: cls("title"), ...(toolbarWidth ? { style: { [cssVar("toolbar_width")]: `${toolbarWidth}px` } } : null) }, title)));
|
|
16
|
+
};
|
|
17
|
+
const Description = ({ description, align, maxLines }) => (React.createElement("div", { className: cls("description_container") },
|
|
18
|
+
React.createElement("div", { className: cls("description"), ...(align !== defaultTextAlign || maxLines !== defaultMaxLines
|
|
19
|
+
? {
|
|
20
|
+
style: {
|
|
21
|
+
[cssVar("slide_description_text_align")]: align,
|
|
22
|
+
[cssVar("slide_description_max_lines")]: maxLines,
|
|
23
|
+
},
|
|
24
|
+
}
|
|
25
|
+
: null) }, description.split("\n").flatMap((line, index) => [...(index > 0 ? [React.createElement("br", { key: index })] : []), line]))));
|
|
26
|
+
export const CaptionsComponent = ({ children }) => {
|
|
27
|
+
const { subscribe } = useEvents();
|
|
28
|
+
const [toolbarWidth, setToolbarWidth] = React.useState();
|
|
29
|
+
React.useEffect(() => subscribe("toolbar-width", (topic, event) => {
|
|
30
|
+
if (typeof event === "undefined" || typeof event === "number") {
|
|
31
|
+
setToolbarWidth(event);
|
|
32
|
+
}
|
|
33
|
+
}), [subscribe]);
|
|
34
|
+
const context = React.useMemo(() => ({ toolbarWidth }), [toolbarWidth]);
|
|
35
|
+
return React.createElement(CaptionsContext.Provider, { value: context }, children);
|
|
36
|
+
};
|
|
37
|
+
export const CaptionsModule = createModule("captions", CaptionsComponent);
|
|
38
|
+
export const Captions = ({ augment, addParent }) => {
|
|
39
|
+
addParent("controller", CaptionsModule);
|
|
40
|
+
augment(({ render: { slideFooter: renderFooter, ...restRender }, captions, ...restProps }) => ({
|
|
41
|
+
render: {
|
|
42
|
+
slideFooter: (slide) => {
|
|
43
|
+
var _a, _b;
|
|
44
|
+
return (React.createElement(React.Fragment, null, renderFooter === null || renderFooter === void 0 ? void 0 :
|
|
45
|
+
renderFooter(slide),
|
|
46
|
+
hasTitle(slide) && React.createElement(Title, { title: slide.title }),
|
|
47
|
+
hasDescription(slide) && (React.createElement(Description, { description: slide.description, align: (_a = captions === null || captions === void 0 ? void 0 : captions.descriptionTextAlign) !== null && _a !== void 0 ? _a : defaultTextAlign, maxLines: (_b = captions === null || captions === void 0 ? void 0 : captions.descriptionMaxLines) !== null && _b !== void 0 ? _b : defaultMaxLines }))));
|
|
48
|
+
},
|
|
49
|
+
...restRender,
|
|
50
|
+
},
|
|
51
|
+
...restProps,
|
|
52
|
+
}));
|
|
53
|
+
};
|
|
54
|
+
export default Captions;
|
|
@@ -2,8 +2,8 @@ import * as React from "react";
|
|
|
2
2
|
import { createIcon, IconButton, label, useController, useLatest } from "../core/index.js";
|
|
3
3
|
const EnterFullscreenIcon = createIcon("EnterFullscreen", React.createElement("path", { d: "M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z" }));
|
|
4
4
|
const ExitFullscreenIcon = createIcon("ExitFullscreen", React.createElement("path", { d: "M5 16h3v3h2v-5H5v2zm3-8H5v2h5V5H8v3zm6 11h2v-3h3v-2h-5v5zm2-11V5h-2v5h5V8h-3z" }));
|
|
5
|
-
/** Fullscreen button */
|
|
6
5
|
export const FullscreenButton = ({ auto, labels, render }) => {
|
|
6
|
+
const [mounted, setMounted] = React.useState(false);
|
|
7
7
|
const [fullscreen, setFullscreen] = React.useState(false);
|
|
8
8
|
const latestAuto = useLatest(auto);
|
|
9
9
|
const { containerRef } = useController();
|
|
@@ -33,7 +33,6 @@ export const FullscreenButton = ({ auto, labels, render }) => {
|
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
35
|
catch (err) {
|
|
36
|
-
//
|
|
37
36
|
}
|
|
38
37
|
}
|
|
39
38
|
}, [containerRef]);
|
|
@@ -54,7 +53,6 @@ export const FullscreenButton = ({ auto, labels, render }) => {
|
|
|
54
53
|
}
|
|
55
54
|
}
|
|
56
55
|
catch (err) {
|
|
57
|
-
//
|
|
58
56
|
}
|
|
59
57
|
}
|
|
60
58
|
}, [getFullscreenElement]);
|
|
@@ -74,6 +72,7 @@ export const FullscreenButton = ({ auto, labels, render }) => {
|
|
|
74
72
|
setFullscreen(false);
|
|
75
73
|
}
|
|
76
74
|
}, [containerRef, getFullscreenElement]);
|
|
75
|
+
React.useEffect(() => setMounted(true), []);
|
|
77
76
|
React.useEffect(() => {
|
|
78
77
|
const events = ["fullscreenchange", "webkitfullscreenchange", "mozfullscreenchange", "MSFullscreenChange"];
|
|
79
78
|
events.forEach((event) => {
|
|
@@ -91,11 +90,10 @@ export const FullscreenButton = ({ auto, labels, render }) => {
|
|
|
91
90
|
requestFullscreen();
|
|
92
91
|
}
|
|
93
92
|
}, [latestAuto, requestFullscreen]);
|
|
94
|
-
if (!isFullscreenEnabled())
|
|
93
|
+
if (!mounted || !isFullscreenEnabled())
|
|
95
94
|
return null;
|
|
96
95
|
return render.buttonFullscreen ? (React.createElement(React.Fragment, null, render.buttonFullscreen({ fullscreen, toggleFullscreen }))) : (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 }));
|
|
97
96
|
};
|
|
98
|
-
/** Fullscreen plugin */
|
|
99
97
|
export const Fullscreen = ({ augment }) => {
|
|
100
98
|
augment(({ toolbar: { buttons, ...restToolbar }, ...restProps }) => ({
|
|
101
99
|
toolbar: {
|
package/dist/plugins/Inline.js
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { createModule } from "../core/index.js";
|
|
3
|
-
/** Inline plugin container */
|
|
4
3
|
export const InlineContainer = ({ inline, children }) => React.createElement("div", { ...inline }, children);
|
|
5
|
-
/** Inline plugin module */
|
|
6
4
|
export const InlineModule = createModule("inline", InlineContainer);
|
|
7
|
-
/** Inline plugin */
|
|
8
5
|
export const Inline = ({ augment, replace, remove }) => {
|
|
9
6
|
augment(({ toolbar: { buttons, ...restToolbar }, open, close, controller: { focus, ...restController }, ...restProps }) => ({
|
|
10
7
|
open: true,
|
package/dist/plugins/Video.js
CHANGED
|
@@ -12,7 +12,6 @@ SlideTypesPropTypes.push(PropTypes.shape({
|
|
|
12
12
|
type: PropTypes.string.isRequired,
|
|
13
13
|
}).isRequired),
|
|
14
14
|
}));
|
|
15
|
-
/** Video slide */
|
|
16
15
|
export const VideoSlide = ({ slide: { sources, poster, width, height } }) => {
|
|
17
16
|
const { setContainerRef, containerRect } = useContainerRect();
|
|
18
17
|
const scaleWidthAndHeight = () => {
|
|
@@ -27,21 +26,17 @@ export const VideoSlide = ({ slide: { sources, poster, width, height } }) => {
|
|
|
27
26
|
return (React.createElement(React.Fragment, null, sources && (React.createElement("div", { ref: setContainerRef, style: {
|
|
28
27
|
width: "100%",
|
|
29
28
|
height: "100%",
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
React.createElement("video", { controls: true, playsInline: true, poster: poster, ...scaleWidthAndHeight() }, sources.map(({ src, type }, index) => (
|
|
33
|
-
// eslint-disable-next-line react/no-array-index-key
|
|
34
|
-
React.createElement("source", { key: index, src: src, type: type })))))))));
|
|
29
|
+
...(width ? { maxWidth: `${width}px` } : null),
|
|
30
|
+
}, className: clsx(cssClass("video_container"), cssClass("flex_center")) }, containerRect && (React.createElement("video", { controls: true, playsInline: true, poster: poster, ...scaleWidthAndHeight() }, sources.map(({ src, type }, index) => (React.createElement("source", { key: index, src: src, type: type })))))))));
|
|
35
31
|
};
|
|
36
|
-
/** Video plugin */
|
|
37
32
|
export const Video = ({ augment }) => {
|
|
38
33
|
augment(({ render: { slide: renderSlide, ...restRender }, ...restProps }) => ({
|
|
39
34
|
render: {
|
|
40
|
-
slide: (slide) => {
|
|
35
|
+
slide: (slide, offset, rect) => {
|
|
41
36
|
if ("type" in slide && slide.type === "video") {
|
|
42
37
|
return React.createElement(VideoSlide, { slide: slide });
|
|
43
38
|
}
|
|
44
|
-
return renderSlide === null || renderSlide === void 0 ? void 0 : renderSlide(slide);
|
|
39
|
+
return renderSlide === null || renderSlide === void 0 ? void 0 : renderSlide(slide, offset, rect);
|
|
45
40
|
},
|
|
46
41
|
...restRender,
|
|
47
42
|
},
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
.yarl__slide_title {
|
|
2
|
+
font-family: Arial, "Helvetica Neue", Helvetica, sans-serif;
|
|
3
|
+
font-size: 1.25rem;
|
|
4
|
+
font-weight: 700;
|
|
5
|
+
max-width: calc(100% - var(--yarl__toolbar_width, 0px));
|
|
6
|
+
overflow: hidden;
|
|
7
|
+
text-overflow: ellipsis;
|
|
8
|
+
white-space: nowrap;
|
|
9
|
+
}
|
|
10
|
+
.yarl__slide_title_container {
|
|
11
|
+
position: absolute;
|
|
12
|
+
left: 0;
|
|
13
|
+
right: 0;
|
|
14
|
+
top: 0;
|
|
15
|
+
padding: 16px;
|
|
16
|
+
background: rgba(0, 0, 0, 0.5);
|
|
17
|
+
}
|
|
18
|
+
.yarl__slide_description {
|
|
19
|
+
font-family: Arial, "Helvetica Neue", Helvetica, sans-serif;
|
|
20
|
+
font-size: 1rem;
|
|
21
|
+
line-height: 1.2;
|
|
22
|
+
font-weight: 500;
|
|
23
|
+
overflow: hidden;
|
|
24
|
+
-webkit-hyphens: auto;
|
|
25
|
+
-ms-hyphens: auto;
|
|
26
|
+
hyphens: auto;
|
|
27
|
+
display: -webkit-box;
|
|
28
|
+
-webkit-box-orient: vertical;
|
|
29
|
+
-webkit-line-clamp: var(--yarl__slide_description_max_lines, 3);
|
|
30
|
+
text-align: var(--yarl__slide_description_text_align, start);
|
|
31
|
+
}
|
|
32
|
+
.yarl__slide_description_container {
|
|
33
|
+
position: absolute;
|
|
34
|
+
left: 0;
|
|
35
|
+
right: 0;
|
|
36
|
+
bottom: 0;
|
|
37
|
+
padding: 16px;
|
|
38
|
+
background: rgba(0, 0, 0, 0.5);
|
|
39
|
+
}
|
package/dist/plugins/index.d.ts
CHANGED
package/dist/plugins/index.js
CHANGED
package/dist/styles.css
CHANGED
package/dist/types.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import PropTypes from "prop-types";
|
|
3
|
+
import { ContainerRect } from "./core/hooks/useContainerRect.js";
|
|
3
4
|
/** Image slide properties */
|
|
4
5
|
export interface SlideImage {
|
|
5
6
|
/** image URL */
|
|
@@ -49,7 +50,19 @@ export interface ControllerSettings {
|
|
|
49
50
|
/** Custom render functions. */
|
|
50
51
|
export interface Render {
|
|
51
52
|
/** render custom slide type, or override the default image slide */
|
|
52
|
-
slide?: (
|
|
53
|
+
slide?: (
|
|
54
|
+
/** slide */
|
|
55
|
+
slide: Slide,
|
|
56
|
+
/** slide offset (`0` - current slide, `1` - next slide, `-1` - previous slide, etc.) */
|
|
57
|
+
offset: number,
|
|
58
|
+
/** container rect */
|
|
59
|
+
rect: ContainerRect) => React.ReactNode;
|
|
60
|
+
/** render custom slide header */
|
|
61
|
+
slideHeader?: (slide: Slide) => React.ReactNode;
|
|
62
|
+
/** render custom slide footer */
|
|
63
|
+
slideFooter?: (slide: Slide) => React.ReactNode;
|
|
64
|
+
/** render custom slide container */
|
|
65
|
+
slideContainer?: (slide: Slide, children: React.ReactNode) => React.ReactNode;
|
|
53
66
|
/** render custom Prev icon */
|
|
54
67
|
iconPrev?: () => React.ReactNode;
|
|
55
68
|
/** render custom Next icon */
|
|
@@ -111,7 +124,7 @@ export interface LightboxProps {
|
|
|
111
124
|
on: Callbacks;
|
|
112
125
|
}
|
|
113
126
|
export declare const ImageSlidePropTypes: PropTypes.Requireable<PropTypes.InferProps<{
|
|
114
|
-
src: PropTypes.
|
|
127
|
+
src: PropTypes.Requireable<string>;
|
|
115
128
|
alt: PropTypes.Requireable<string>;
|
|
116
129
|
aspectRatio: PropTypes.Requireable<number>;
|
|
117
130
|
srcSet: PropTypes.Requireable<PropTypes.InferProps<{
|
|
@@ -127,6 +140,9 @@ export declare const LightboxPropTypes: {
|
|
|
127
140
|
slides: PropTypes.Validator<any[]>;
|
|
128
141
|
render: PropTypes.Validator<PropTypes.InferProps<{
|
|
129
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>;
|
|
130
146
|
iconPrev: PropTypes.Requireable<(...args: any[]) => any>;
|
|
131
147
|
iconNext: PropTypes.Requireable<(...args: any[]) => any>;
|
|
132
148
|
iconClose: PropTypes.Requireable<(...args: any[]) => any>;
|
package/dist/types.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import PropTypes from "prop-types";
|
|
2
2
|
export const ImageSlidePropTypes = PropTypes.shape({
|
|
3
|
-
src: PropTypes.string
|
|
3
|
+
src: PropTypes.string,
|
|
4
4
|
alt: PropTypes.string,
|
|
5
5
|
aspectRatio: PropTypes.number,
|
|
6
6
|
srcSet: PropTypes.arrayOf(PropTypes.shape({
|
|
@@ -16,6 +16,9 @@ export const LightboxPropTypes = {
|
|
|
16
16
|
slides: PropTypes.arrayOf(PropTypes.oneOfType(SlideTypesPropTypes).isRequired).isRequired,
|
|
17
17
|
render: PropTypes.shape({
|
|
18
18
|
slide: PropTypes.func,
|
|
19
|
+
slideHeader: PropTypes.func,
|
|
20
|
+
slideFooter: PropTypes.func,
|
|
21
|
+
slideContainer: PropTypes.func,
|
|
19
22
|
iconPrev: PropTypes.func,
|
|
20
23
|
iconNext: PropTypes.func,
|
|
21
24
|
iconClose: PropTypes.func,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "yet-another-react-lightbox",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.1",
|
|
4
4
|
"description": "Modern React lightbox component",
|
|
5
5
|
"author": "Igor Danchenko",
|
|
6
6
|
"license": "MIT",
|
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
".": "./dist/index.js",
|
|
11
11
|
"./core": "./dist/core/index.js",
|
|
12
12
|
"./plugins": "./dist/plugins/index.js",
|
|
13
|
+
"./plugins/captions": "./dist/plugins/Captions.js",
|
|
14
|
+
"./plugins/captions.css": "./dist/plugins/captions.css",
|
|
13
15
|
"./plugins/fullscreen": "./dist/plugins/Fullscreen.js",
|
|
14
16
|
"./plugins/inline": "./dist/plugins/Inline.js",
|
|
15
17
|
"./plugins/video": "./dist/plugins/Video.js",
|
|
@@ -27,6 +29,9 @@
|
|
|
27
29
|
"plugins": [
|
|
28
30
|
"dist/plugins/index.d.ts"
|
|
29
31
|
],
|
|
32
|
+
"plugins/captions": [
|
|
33
|
+
"dist/plugins/Captions.d.ts"
|
|
34
|
+
],
|
|
30
35
|
"plugins/fullscreen": [
|
|
31
36
|
"dist/plugins/Fullscreen.d.ts"
|
|
32
37
|
],
|
|
@@ -59,8 +64,8 @@
|
|
|
59
64
|
"build": "npm-run-all clean build:scss build:css build:js build:dts",
|
|
60
65
|
"build:js": "tsc -p tsconfig.build.js.json",
|
|
61
66
|
"build:dts": "tsc -p tsconfig.build.dts.json",
|
|
62
|
-
"build:css": "postcss src
|
|
63
|
-
"build:scss": "sass src
|
|
67
|
+
"build:css": "postcss src/*.css src/**/*.css --base src -d dist -u autoprefixer --no-map",
|
|
68
|
+
"build:scss": "sass src --no-source-map",
|
|
64
69
|
"start": "npm-run-all clean --parallel \"build:* -- -w\"",
|
|
65
70
|
"lint": "eslint .",
|
|
66
71
|
"test": "jest"
|
|
@@ -80,13 +85,13 @@
|
|
|
80
85
|
"@testing-library/jest-dom": "^5.16.4",
|
|
81
86
|
"@testing-library/react": "^13.3.0",
|
|
82
87
|
"@testing-library/user-event": "^14.2.0",
|
|
83
|
-
"@types/jest": "^
|
|
84
|
-
"@types/react": "^18.0.
|
|
88
|
+
"@types/jest": "^28.1.1",
|
|
89
|
+
"@types/react": "^18.0.12",
|
|
85
90
|
"@types/react-dom": "^18.0.5",
|
|
86
|
-
"@typescript-eslint/eslint-plugin": "^5.27.
|
|
87
|
-
"@typescript-eslint/parser": "^5.27.
|
|
91
|
+
"@typescript-eslint/eslint-plugin": "^5.27.1",
|
|
92
|
+
"@typescript-eslint/parser": "^5.27.1",
|
|
88
93
|
"autoprefixer": "^10.4.7",
|
|
89
|
-
"eslint": "^8.
|
|
94
|
+
"eslint": "^8.17.0",
|
|
90
95
|
"eslint-config-airbnb": "^19.0.4",
|
|
91
96
|
"eslint-config-airbnb-typescript": "^17.0.0",
|
|
92
97
|
"eslint-config-prettier": "^8.5.0",
|
|
@@ -96,9 +101,9 @@
|
|
|
96
101
|
"eslint-plugin-react": "^7.30.0",
|
|
97
102
|
"eslint-plugin-react-hooks": "^4.5.0",
|
|
98
103
|
"husky": "^8.0.1",
|
|
99
|
-
"jest": "^28.1.
|
|
100
|
-
"jest-environment-jsdom": "^28.1.
|
|
101
|
-
"lint-staged": "^13.0.
|
|
104
|
+
"jest": "^28.1.1",
|
|
105
|
+
"jest-environment-jsdom": "^28.1.1",
|
|
106
|
+
"lint-staged": "^13.0.1",
|
|
102
107
|
"npm-run-all": "^4.1.5",
|
|
103
108
|
"postcss": "^8.4.14",
|
|
104
109
|
"postcss-cli": "^9.1.0",
|
|
@@ -106,12 +111,13 @@
|
|
|
106
111
|
"react": "^18.1.0",
|
|
107
112
|
"react-dom": "^18.1.0",
|
|
108
113
|
"rimraf": "^3.0.2",
|
|
109
|
-
"sass": "^1.52.
|
|
110
|
-
"ts-jest": "^28.0.
|
|
111
|
-
"typescript": "^4.7.
|
|
114
|
+
"sass": "^1.52.3",
|
|
115
|
+
"ts-jest": "^28.0.4",
|
|
116
|
+
"typescript": "^4.7.3"
|
|
112
117
|
},
|
|
113
118
|
"keywords": [
|
|
114
119
|
"react",
|
|
120
|
+
"image",
|
|
115
121
|
"lightbox",
|
|
116
122
|
"react lightbox"
|
|
117
123
|
]
|