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 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
@@ -1,8 +1,4 @@
1
- /// <reference types="react" />
2
- import { LightboxProps } from "./types.js";
3
- declare type DeepPartial<T, K extends keyof T> = Omit<T, K> & {
4
- [P in keyof Pick<T, K>]?: Partial<Pick<T, K>[P]>;
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, LightboxPropTypes } from "./types.js";
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 LightboxComponent = (props) => {
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(props);
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
- export const ImageSlide = ({ slide: image, render, rect }) => {
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 [state, setState] = React.useState("loading");
8
- const latestState = useLatest(state);
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 (latestState.current === "complete") {
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
- setState("complete");
30
+ setStatus(SLIDE_STATUS_COMPLETE);
21
31
  });
22
- }, [latestState]);
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
- setState("error");
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"), state !== "complete" && cssClass("slide_image_loading")), draggable: false, alt: image.alt, ...(image.srcSet
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
- state !== "complete" && (React.createElement("div", { className: cssClass("slide_placeholder") },
61
- state === "loading" &&
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
- state === "error" &&
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);
@@ -1,3 +1,4 @@
1
+ export * from "./consts.js";
1
2
  export * from "./utils.js";
2
3
  export * from "./config.js";
3
4
  export * from "./hooks/index.js";
@@ -1,3 +1,4 @@
1
+ export * from "./consts.js";
1
2
  export * from "./utils.js";
2
3
  export * from "./config.js";
3
4
  export * from "./hooks/index.js";
@@ -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 !== 0 ? spacing : "0px" }
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
- export declare type ControllerContextType = {
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) => event.preventDefault();
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: refs.current.swipeAnimationDuration !== LightboxDefaultProps.animation.swipe
272
- ? {
273
- [cssVar("swipe_animation_duration")]: `${Math.round(refs.current.swipeAnimationDuration)}ms`,
274
- }
275
- : undefined, role: "presentation", "aria-live": "polite", tabIndex: -1, ...registerSensors },
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 }))));
@@ -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;
@@ -1,5 +1,5 @@
1
1
  import * as React from "react";
2
- import { LightboxProps, Plugin } from "../types.js";
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 = Required<Pick<LightboxProps, "video">> & {
51
+ declare type VideoSlideProps = {
52
52
  slide: SlideVideo;
53
53
  offset: number;
54
54
  };
@@ -1,30 +1,16 @@
1
1
  import * as React from "react";
2
- import PropTypes from "prop-types";
3
- import { SlideTypesPropTypes } from "../types.js";
4
- import { clsx, cssClass, useContainerRect, useLatest } from "../core/index.js";
5
- SlideTypesPropTypes.push(PropTypes.shape({
6
- type: PropTypes.oneOf(["video"]).isRequired,
7
- poster: PropTypes.string,
8
- width: PropTypes.number,
9
- height: PropTypes.number,
10
- autoPlay: PropTypes.bool,
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") }, sources.map(({ src, type }, index) => (React.createElement("source", { key: index, src: src, type: type })))))))));
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
- const video = {
86
- controls: true,
87
- playsInline: true,
88
- ...originalVideo,
89
- };
90
- return {
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
- video,
101
- ...restProps,
102
- };
103
- });
83
+ ...restRender,
84
+ },
85
+ video: {
86
+ ...defaultVideoProps,
87
+ ...originalVideo,
88
+ },
89
+ ...restProps,
90
+ }));
104
91
  };
105
92
  export default Video;
@@ -1,4 +1,5 @@
1
1
  export * from "./Captions.js";
2
2
  export * from "./Fullscreen.js";
3
3
  export * from "./Inline.js";
4
+ export * from "./Slideshow.js";
4
5
  export * from "./Video.js";
@@ -1,4 +1,5 @@
1
1
  export * from "./Captions.js";
2
2
  export * from "./Fullscreen.js";
3
3
  export * from "./Inline.js";
4
+ export * from "./Slideshow.js";
4
5
  export * from "./Video.js";
package/dist/styles.css CHANGED
@@ -9,12 +9,12 @@
9
9
  .yarl__portal_open {
10
10
  opacity: 1;
11
11
  }
12
- .yarl__container, .yarl__carousel, .yarl__slide {
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 | number;
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 | number;
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 v */
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.5.0",
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.12",
90
+ "@types/react": "^18.0.13",
90
91
  "@types/react-dom": "^18.0.5",
91
- "@typescript-eslint/eslint-plugin": "^5.27.1",
92
- "@typescript-eslint/parser": "^5.27.1",
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.5.0",
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.1",
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.6.2",
111
- "react": "^18.1.0",
112
- "react-dom": "^18.1.0",
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.4",
116
+ "ts-jest": "^28.0.5",
116
117
  "typescript": "^4.7.3"
117
118
  },
118
119
  "keywords": [