yet-another-react-lightbox 3.24.0 → 3.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10,6 +10,8 @@ declare module "yet-another-react-lightbox" {
10
10
  zoom?: {
11
11
  /** Zoom plugin ref */
12
12
  ref?: React.ForwardedRef<ZoomRef>;
13
+ /** override minimum zoom level (default: 1.0) */
14
+ minZoom?: number;
13
15
  /** ratio of image pixels to physical pixels at maximum zoom level */
14
16
  maxZoomPixelRatio?: number;
15
17
  /** zoom-in multiplier */
@@ -70,6 +72,8 @@ declare module "yet-another-react-lightbox" {
70
72
  interface ZoomRef {
71
73
  /** current zoom level */
72
74
  zoom: number;
75
+ /** minimum zoom level */
76
+ minZoom: number;
73
77
  /** maximum zoom level */
74
78
  maxZoom: number;
75
79
  /** horizontal offset */
@@ -3,6 +3,7 @@ import { useLightboxProps, useMotionPreference, useEventCallback, useLayoutEffec
3
3
  import { EVENT_ON_KEY_DOWN, EVENT_ON_WHEEL, UNKNOWN_ACTION_TYPE, CLASS_FULLSIZE, CLASS_FLEX_CENTER, CLASS_SLIDE_WRAPPER, CLASS_SLIDE_WRAPPER_INTERACTIVE, PLUGIN_ZOOM } from '../../types.js';
4
4
 
5
5
  const defaultZoomProps = {
6
+ minZoom: 1,
6
7
  maxZoomPixelRatio: 1,
7
8
  zoomInMultiplier: 2,
8
9
  doubleTapDelay: 300,
@@ -13,10 +14,13 @@ const defaultZoomProps = {
13
14
  pinchZoomDistanceFactor: 100,
14
15
  scrollToZoom: false,
15
16
  };
16
- const resolveZoomProps = (zoom) => ({
17
- ...defaultZoomProps,
18
- ...zoom,
19
- });
17
+ function validateMinZoom(minZoom) {
18
+ return Math.min(Math.max(minZoom, Number.EPSILON), 1);
19
+ }
20
+ function resolveZoomProps(zoom) {
21
+ const { minZoom, ...rest } = { ...defaultZoomProps, ...zoom };
22
+ return { minZoom: validateMinZoom(minZoom), ...rest };
23
+ }
20
24
 
21
25
  function useZoomAnimation(zoom, offsetX, offsetY, zoomWrapperRef) {
22
26
  const zoomAnimation = React.useRef(undefined);
@@ -118,7 +122,7 @@ function distance(pointerA, pointerB) {
118
122
  function scaleZoom(value, delta, factor = 100, clamp = 2) {
119
123
  return value * Math.min(1 + Math.abs(delta / factor), clamp) ** Math.sign(delta);
120
124
  }
121
- function useZoomSensors(zoom, maxZoom, disabled, changeZoom, changeOffsets, zoomWrapperRef) {
125
+ function useZoomSensors(zoom, minZoom, maxZoom, disabled, zoomIn, zoomOut, changeZoom, changeOffsets, zoomWrapperRef) {
122
126
  const activePointers = React.useRef([]);
123
127
  const lastPointerDown = React.useRef(0);
124
128
  const pinchZoomDistance = React.useRef(undefined);
@@ -160,18 +164,17 @@ function useZoomSensors(zoom, maxZoom, disabled, changeZoom, changeOffsets, zoom
160
164
  move(keyboardMoveDistance, 0);
161
165
  }
162
166
  }
163
- const handleChangeZoom = (zoomValue) => {
164
- preventDefault();
165
- changeZoom(zoomValue);
166
- };
167
167
  if (key === "+" || (meta && key === "=")) {
168
- handleChangeZoom(zoom * zoomInMultiplier);
168
+ preventDefault();
169
+ zoomIn();
169
170
  }
170
171
  else if (key === "-" || (meta && key === "_")) {
171
- handleChangeZoom(zoom / zoomInMultiplier);
172
+ preventDefault();
173
+ zoomOut();
172
174
  }
173
175
  else if (meta && key === "0") {
174
- handleChangeZoom(1);
176
+ preventDefault();
177
+ changeZoom(1);
175
178
  }
176
179
  });
177
180
  const onWheel = useEventCallback((event) => {
@@ -212,7 +215,14 @@ function useZoomSensors(zoom, maxZoom, disabled, changeZoom, changeOffsets, zoom
212
215
  if (pointers.length === 0 &&
213
216
  timeStamp - lastPointerDown.current < (event.pointerType === "touch" ? doubleTapDelay : doubleClickDelay)) {
214
217
  lastPointerDown.current = 0;
215
- changeZoom(zoom !== maxZoom ? zoom * Math.max(maxZoom ** (1 / doubleClickMaxStops), zoomInMultiplier) : 1, false, ...translateCoordinates(event));
218
+ const targetZoom = zoom >= 1
219
+ ? zoom !== maxZoom
220
+ ? zoom * Math.max(maxZoom ** (1 / doubleClickMaxStops), zoomInMultiplier)
221
+ : 1
222
+ : zoom !== minZoom
223
+ ? zoom / Math.max(minZoom ** (-1 / doubleClickMaxStops), zoomInMultiplier)
224
+ : 1;
225
+ changeZoom(targetZoom, false, ...translateCoordinates(event));
216
226
  }
217
227
  else {
218
228
  lastPointerDown.current = timeStamp;
@@ -278,7 +288,7 @@ function useZoomState(imageRect, maxZoom, zoomWrapperRef) {
278
288
  const animate = useZoomAnimation(zoom, offsetX, offsetY, zoomWrapperRef);
279
289
  const { currentSlide, globalIndex } = useLightboxState();
280
290
  const { containerRect, slideRect } = useController();
281
- const { zoomInMultiplier } = useZoomProps();
291
+ const { minZoom, zoomInMultiplier } = useZoomProps();
282
292
  const currentSource = currentSlide && isImageSlide(currentSlide) ? currentSlide.src : undefined;
283
293
  const disabled = !currentSource || !(zoomWrapperRef === null || zoomWrapperRef === void 0 ? void 0 : zoomWrapperRef.current);
284
294
  useLayoutEffect(() => {
@@ -296,7 +306,7 @@ function useZoomState(imageRect, maxZoom, zoomWrapperRef) {
296
306
  setOffsetY(Math.min(Math.abs(newOffsetY), Math.max(maxOffsetY, 0)) * Math.sign(newOffsetY));
297
307
  }, [zoom, offsetX, offsetY, slideRect, imageRect.width, imageRect.height]);
298
308
  const changeZoom = React.useCallback((targetZoom, rapid, dx, dy) => {
299
- const newZoom = round(Math.min(Math.max(targetZoom + 0.001 < maxZoom ? targetZoom : maxZoom, 1), maxZoom), 5);
309
+ const newZoom = round(Math.min(Math.max(targetZoom + 0.001 < maxZoom ? targetZoom : maxZoom, minZoom), maxZoom), 5);
300
310
  if (newZoom === zoom)
301
311
  return;
302
312
  if (!rapid) {
@@ -304,7 +314,7 @@ function useZoomState(imageRect, maxZoom, zoomWrapperRef) {
304
314
  }
305
315
  changeOffsets(dx ? dx * (1 / zoom - 1 / newZoom) : 0, dy ? dy * (1 / zoom - 1 / newZoom) : 0, newZoom);
306
316
  setZoom(newZoom);
307
- }, [zoom, maxZoom, changeOffsets, animate]);
317
+ }, [zoom, minZoom, maxZoom, changeOffsets, animate]);
308
318
  const handleControllerRectChange = useEventCallback(() => {
309
319
  if (zoom > 1) {
310
320
  if (zoom > maxZoom) {
@@ -314,8 +324,14 @@ function useZoomState(imageRect, maxZoom, zoomWrapperRef) {
314
324
  }
315
325
  });
316
326
  useLayoutEffect(handleControllerRectChange, [containerRect.width, containerRect.height, handleControllerRectChange]);
317
- const zoomIn = React.useCallback(() => changeZoom(zoom * zoomInMultiplier), [zoom, zoomInMultiplier, changeZoom]);
318
- const zoomOut = React.useCallback(() => changeZoom(zoom / zoomInMultiplier), [zoom, zoomInMultiplier, changeZoom]);
327
+ const zoomIn = React.useCallback(() => {
328
+ const targetZoom = zoom * zoomInMultiplier;
329
+ changeZoom(zoom < 1 && targetZoom > 1 ? 1 : targetZoom);
330
+ }, [zoom, zoomInMultiplier, changeZoom]);
331
+ const zoomOut = React.useCallback(() => {
332
+ const targetZoom = zoom / zoomInMultiplier;
333
+ changeZoom(zoom > 1 && targetZoom < 1 ? 1 : targetZoom);
334
+ }, [zoom, zoomInMultiplier, changeZoom]);
319
335
  return { zoom, offsetX, offsetY, disabled, changeOffsets, changeZoom, zoomIn, zoomOut };
320
336
  }
321
337
 
@@ -324,12 +340,13 @@ const useZoom = makeUseContext("useZoom", "ZoomControllerContext", ZoomControlle
324
340
  function ZoomContextProvider({ children }) {
325
341
  const [zoomWrapper, setZoomWrapper] = React.useState();
326
342
  const { slideRect } = useController();
343
+ const { ref, minZoom } = useZoomProps();
327
344
  const { imageRect, maxZoom } = useZoomImageRect(slideRect, zoomWrapper === null || zoomWrapper === void 0 ? void 0 : zoomWrapper.imageDimensions);
328
345
  const { zoom, offsetX, offsetY, disabled, changeZoom, changeOffsets, zoomIn, zoomOut } = useZoomState(imageRect, maxZoom, zoomWrapper === null || zoomWrapper === void 0 ? void 0 : zoomWrapper.zoomWrapperRef);
329
346
  useZoomCallback(zoom, disabled);
330
- useZoomSensors(zoom, maxZoom, disabled, changeZoom, changeOffsets, zoomWrapper === null || zoomWrapper === void 0 ? void 0 : zoomWrapper.zoomWrapperRef);
331
- const zoomRef = React.useMemo(() => ({ zoom, maxZoom, offsetX, offsetY, disabled, zoomIn, zoomOut, changeZoom }), [zoom, maxZoom, offsetX, offsetY, disabled, zoomIn, zoomOut, changeZoom]);
332
- React.useImperativeHandle(useZoomProps().ref, () => zoomRef, [zoomRef]);
347
+ useZoomSensors(zoom, minZoom, maxZoom, disabled, zoomIn, zoomOut, changeZoom, changeOffsets, zoomWrapper === null || zoomWrapper === void 0 ? void 0 : zoomWrapper.zoomWrapperRef);
348
+ const zoomRef = React.useMemo(() => ({ zoom, minZoom, maxZoom, offsetX, offsetY, disabled, zoomIn, zoomOut, changeZoom }), [zoom, minZoom, maxZoom, offsetX, offsetY, disabled, zoomIn, zoomOut, changeZoom]);
349
+ React.useImperativeHandle(ref, () => zoomRef, [zoomRef]);
333
350
  const context = React.useMemo(() => ({ ...zoomRef, setZoomWrapper }), [zoomRef, setZoomWrapper]);
334
351
  return React.createElement(ZoomControllerContext.Provider, { value: context }, children);
335
352
  }
@@ -341,9 +358,9 @@ const ZoomOutIcon = createIcon("ZoomOut", React.createElement("path", { d: "M15.
341
358
  const ZoomButton = React.forwardRef(function ZoomButton({ zoomIn, onLoseFocus }, ref) {
342
359
  const wasEnabled = React.useRef(false);
343
360
  const wasFocused = React.useRef(false);
344
- const { zoom, maxZoom, zoomIn: zoomInCallback, zoomOut: zoomOutCallback, disabled: zoomDisabled } = useZoom();
361
+ const { zoom, minZoom, maxZoom, zoomIn: zoomInCallback, zoomOut: zoomOutCallback, disabled: zoomDisabled, } = useZoom();
345
362
  const { render } = useLightboxProps();
346
- const disabled = zoomDisabled || (zoomIn ? zoom >= maxZoom : zoom <= 1);
363
+ const disabled = zoomDisabled || (zoomIn ? zoom >= maxZoom : zoom <= minZoom);
347
364
  React.useEffect(() => {
348
365
  if (disabled && wasEnabled.current && wasFocused.current) {
349
366
  onLoseFocus();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yet-another-react-lightbox",
3
- "version": "3.24.0",
3
+ "version": "3.25.0",
4
4
  "description": "Modern React lightbox component",
5
5
  "author": "Igor Danchenko",
6
6
  "license": "MIT",