Skip to content

Commit

Permalink
feat: export experimental useZoom hook
Browse files Browse the repository at this point in the history
  • Loading branch information
igordanchenko committed Aug 16, 2024
1 parent 529c7bb commit fe46a89
Show file tree
Hide file tree
Showing 7 changed files with 72 additions and 14 deletions.
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,31 @@ fixed-positioned element container should not have its own border or padding
styles. If that's the case, you can always add an extra wrapper that just
defines the fixed position without visual styles.

## Hooks (experimental)

The library exports the following experimental hooks that you may find helpful
in customizing lightbox functionality. All experimental hooks are currently
exported with the `unstable_` prefix.

### useZoom

You can use the `useZoom` hook to build your custom zoom controls.

```tsx
import { unstable_useZoom as useZoom } from "yet-another-react-lightbox-lite";
```

The hook provides an object with the following props:

- `rect` - slide rect
- `zoom` - current zoom level (numeric value between `1` and `8`)
- `maxZoom` - maximum zoom level (`1` if zoom is not supported on the current
slide)
- `offsetX` - horizontal slide position offset
- `offsetY` - vertical slide position offset
- `changeZoom` - change zoom level
- `changeOffsets` - change position offsets

## License

MIT © 2024 [Igor Danchenko](https://github.com/igordanchenko)
5 changes: 3 additions & 2 deletions src/components/Carousel.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { useZoom } from "./Zoom";
import { useZoom, useZoomInternal } from "./Zoom";
import { useLightboxContext } from "./LightboxContext";
import ImageSlide from "./ImageSlide";
import { cssClass, isImageSlide, round } from "../utils";
import { SlideImage } from "../types";

export default function Carousel() {
const { slides, index, styles, render: { slide: renderSlide, slideHeader, slideFooter } = {} } = useLightboxContext();
const { rect, zoom, offsetX, offsetY, setCarouselRef } = useZoom();
const { rect, zoom, offsetX, offsetY } = useZoom();
const { setCarouselRef } = useZoomInternal();

return (
<div ref={setCarouselRef} style={styles?.carousel} className={cssClass("carousel")}>
Expand Down
43 changes: 35 additions & 8 deletions src/components/Zoom.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,43 @@ import { useLightboxContext } from "./LightboxContext";
import { isImageSlide, makeUseContext } from "../utils";
import { Rect } from "../types";

/** Zoom context */
type ZoomContextType = {
/** slide rect */
rect?: Rect;
/** zoom level */
zoom: number;
/** maximum zoom level */
maxZoom: number;
/** horizontal slide position offset */
offsetX: number;
/** vertical slide position offset */
offsetY: number;
changeZoom: (newZoom: number, event?: Pick<MouseEvent, "clientX" | "clientY">) => void;
/** change zoom level */
changeZoom: (
/** new zoom value */
newZoom: number,
/** pointer/mouse/wheel event that determines zoom-in point */
event?: Pick<MouseEvent, "clientX" | "clientY">,
) => void;
/** change position offsets */
changeOffsets: (dx: number, dy: number) => void;
carouselRef: RefObject<HTMLDivElement>;
setCarouselRef: RefCallback<HTMLDivElement>;
};

const ZoomContext = createContext<ZoomContextType | null>(null);

/** `useZoom` hook */
export const useZoom = makeUseContext(ZoomContext);

type ZoomInternalContextType = {
carouselRef: RefObject<HTMLDivElement>;
setCarouselRef: RefCallback<HTMLDivElement>;
};

const ZoomInternalContext = createContext<ZoomInternalContextType | null>(null);

export const useZoomInternal = makeUseContext(ZoomInternalContext);

export default function Zoom({ children }: PropsWithChildren) {
const [zoom, setZoom] = useState(1);
const [offsetX, setOffsetX] = useState(0);
Expand Down Expand Up @@ -120,10 +141,16 @@ export default function Zoom({ children }: PropsWithChildren) {
[zoom, maxZoom, offsetX, offsetY, changeOffsets],
);

const context = useMemo(
() => ({ rect, zoom, maxZoom, offsetX, offsetY, changeZoom, changeOffsets, carouselRef, setCarouselRef }),
[rect, zoom, maxZoom, offsetX, offsetY, changeZoom, changeOffsets, setCarouselRef],
return (
<ZoomContext.Provider
value={useMemo(
() => ({ rect, zoom, maxZoom, offsetX, offsetY, changeZoom, changeOffsets }),
[rect, zoom, maxZoom, offsetX, offsetY, changeZoom, changeOffsets],
)}
>
<ZoomInternalContext.Provider value={useMemo(() => ({ carouselRef, setCarouselRef }), [setCarouselRef])}>
{children}
</ZoomInternalContext.Provider>
</ZoomContext.Provider>
);

return <ZoomContext.Provider value={context}>{children}</ZoomContext.Provider>;
}
2 changes: 1 addition & 1 deletion src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ export { default as LightboxContext } from "./LightboxContext";
export { default as Navigation } from "./Navigation";
export { default as Portal } from "./Portal";
export { default as Toolbar } from "./Toolbar";
export { default as Zoom } from "./Zoom";
export { default as Zoom, useZoom } from "./Zoom";
5 changes: 3 additions & 2 deletions src/components/useSensors.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { KeyboardEvent, MouseEvent, PointerEvent, useMemo, useRef, WheelEvent } from "react";

import { useZoom } from "./Zoom";
import { useZoom, useZoomInternal } from "./Zoom";
import { useController } from "./Controller";
import { useLightboxContext } from "./LightboxContext";
import { cssClass, scaleZoom } from "../utils";
Expand All @@ -26,7 +26,8 @@ export default function useSensors() {
const activePointers = useRef<PointerEvent[]>([]);
const pinchZoomDistance = useRef<number>();

const { zoom, changeZoom, changeOffsets, carouselRef } = useZoom();
const { zoom, changeZoom, changeOffsets } = useZoom();
const { carouselRef } = useZoomInternal();
const { prev, next, close } = useController();

const { closeOnPullUp, closeOnPullDown, closeOnBackdropClick } = {
Expand Down
3 changes: 3 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
export * from "./types";
export { default } from "./Lightbox";

// experimental exports
export { useZoom as unstable_useZoom } from "./components";
3 changes: 2 additions & 1 deletion test/Lightbox.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,15 @@ import {
wheelZoom,
withFakeTimers,
} from "./test-utils";
import { useZoom } from "../src/components";
import { makeUseContext } from "../src/utils";
import { useZoom } from "../src/components/Zoom";

declare module "../src/types" {
interface CustomSlide extends GenericSlide {
type: "custom-slide";
}

// noinspection JSUnusedGlobalSymbols
interface SlideTypes {
"custom-slide": CustomSlide;
}
Expand Down

0 comments on commit fe46a89

Please sign in to comment.