Skip to content

Commit

Permalink
feat: add carousel.imageProps configuration option (close #131)
Browse files Browse the repository at this point in the history
  • Loading branch information
igordanchenko committed May 25, 2023
1 parent 5ffd036 commit c693e71
Show file tree
Hide file tree
Showing 8 changed files with 57 additions and 32 deletions.
32 changes: 16 additions & 16 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^14.0.0",
"@testing-library/user-event": "^14.4.3",
"@types/react": "^18.2.6",
"@types/react": "^18.2.7",
"@types/react-dom": "^18.2.4",
"@typescript-eslint/eslint-plugin": "^5.59.7",
"@typescript-eslint/parser": "^5.59.7",
Expand Down
4 changes: 2 additions & 2 deletions src/Lightbox.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as React from "react";

import { AnimationSettings, ComponentProps, DeepPartialValue, LightboxExternalProps, Node } from "./types.js";
import { AnimationSettings, ComponentProps, LightboxExternalProps, Node } from "./types.js";
import { LightboxDefaultProps } from "./props.js";
import { createNode, withPlugins } from "./config.js";
import { EventsProvider, LightboxPropsProvider, LightboxStateProvider, TimeoutsProvider } from "./contexts/index.js";
Expand All @@ -22,7 +22,7 @@ function renderNode(node: Node, props: ComponentProps): React.ReactElement {
);
}

function mergeAnimation(defaultAnimation: AnimationSettings, animation: DeepPartialValue<AnimationSettings> = {}) {
function mergeAnimation(defaultAnimation: AnimationSettings, animation: LightboxExternalProps["animation"] = {}) {
const { easing: defaultAnimationEasing, ...restDefaultAnimation } = defaultAnimation;
const { easing, ...restAnimation } = animation;
return {
Expand Down
27 changes: 20 additions & 7 deletions src/components/ImageSlide.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as React from "react";

import { ContainerRect, ImageFit, Render, SlideImage } from "../types.js";
import { CarouselSettings, ContainerRect, Render, SlideImage } from "../types.js";
import { clsx, cssClass, hasWindow, isImageFitCover, makeComposePrefix } from "../utils.js";
import { useEventCallback } from "../hooks/index.js";
import { useEvents, useTimeouts } from "../contexts/index.js";
Expand All @@ -18,18 +18,27 @@ import {
const slidePrefix = makeComposePrefix("slide");
const slideImagePrefix = makeComposePrefix("slide_image");

export type ImageSlideProps = {
export type ImageSlideProps = Partial<Pick<CarouselSettings, "imageFit" | "imageProps">> & {
slide: SlideImage;
offset?: number;
render?: Render;
rect?: ContainerRect;
imageFit?: ImageFit;
onClick?: () => void;
onLoad?: (image: HTMLImageElement) => void;
style?: React.CSSProperties;
};

export function ImageSlide({ slide: image, offset, render, rect, imageFit, onClick, onLoad, style }: ImageSlideProps) {
export function ImageSlide({
slide: image,
offset,
render,
rect,
imageFit,
imageProps,
onClick,
onLoad,
style,
}: ImageSlideProps) {
const [status, setStatus] = React.useState<SlideStatus>(SLIDE_STATUS_LOADING);

const { publish } = useEvents();
Expand Down Expand Up @@ -118,6 +127,8 @@ export function ImageSlide({ slide: image, offset, render, rect, imageFit, onCli
const sizes =
srcSet && rect && hasWindow() ? `${Math.round(Math.min(estimateActualWidth(), rect.width))}px` : undefined;

const { style: imagePropsStyle, className: imagePropsClassName, ...restImageProps } = imageProps || {};

return (
<>
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-noninteractive-element-interactions */}
Expand All @@ -126,14 +137,16 @@ export function ImageSlide({ slide: image, offset, render, rect, imageFit, onCli
onLoad={handleOnLoad}
onError={onError}
onClick={onClick}
draggable={false}
className={clsx(
cssClass(slideImagePrefix()),
cover && cssClass(slideImagePrefix("cover")),
status !== SLIDE_STATUS_COMPLETE && cssClass(slideImagePrefix("loading"))
status !== SLIDE_STATUS_COMPLETE && cssClass(slideImagePrefix("loading")),
imagePropsClassName
)}
draggable={false}
style={{ ...defaultStyle, ...style, ...imagePropsStyle }}
{...restImageProps}
alt={image.alt}
style={{ ...defaultStyle, ...style }}
sizes={sizes}
srcSet={srcSet}
src={image.src}
Expand Down
3 changes: 2 additions & 1 deletion src/modules/Carousel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ function CarouselSlide({ slide, offset }: CarouselSlideProps) {
const { slideRect, close } = useController();
const {
render,
carousel: { imageFit },
carousel: { imageFit, imageProps },
on: { click: onClick },
controller: { closeOnBackdropClick },
} = useLightboxProps();
Expand All @@ -44,6 +44,7 @@ function CarouselSlide({ slide, offset }: CarouselSlideProps) {
render={render}
rect={slideRect}
imageFit={imageFit}
imageProps={imageProps}
onClick={offset === 0 ? () => onClick?.({ index: currentIndex }) : undefined}
/>
);
Expand Down
1 change: 1 addition & 0 deletions src/plugins/zoom/ZoomWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export function ZoomWrapper({ render, slide, offset, rect }: ZoomWrapperProps) {
rect,
render,
imageFit: carousel.imageFit,
imageProps: carousel.imageProps,
onClick: offset === 0 ? () => on.click?.({ index: currentIndex }) : undefined,
};

Expand Down
1 change: 1 addition & 0 deletions src/props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export const LightboxDefaultProps: LightboxProps = {
padding: "16px",
spacing: "30%",
imageFit: IMAGE_FIT_CONTAIN,
imageProps: {},
},
controller: {
ref: null,
Expand Down
19 changes: 14 additions & 5 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ import {
} from "./consts.js";

/** Lightbox external props */
export type LightboxExternalProps = DeepPartial<LightboxProps, "carousel" | "animation" | "controller" | "toolbar">;
export type LightboxExternalProps = DeepPartial<
DeepPartial<DeepPartial<LightboxProps, "animation" | "toolbar">, "carousel", "imageProps">,
"controller",
"ref"
>;

/** Lightbox properties */
export interface LightboxProps {
Expand Down Expand Up @@ -162,6 +166,11 @@ export interface CarouselSettings {
spacing: LengthOrPercentage;
/** `object-fit` setting for image slides */
imageFit: ImageFit;
/** custom image attributes */
imageProps: Omit<
React.ImgHTMLAttributes<HTMLImageElement>,
"src" | "alt" | "sizes" | "srcSet" | "onLoad" | "onError" | "onClick"
>;
}

export type LengthOrPercentage = `${number}px` | `${number}%` | number;
Expand Down Expand Up @@ -397,16 +406,16 @@ export interface PluginProps {
export type Plugin = (props: PluginProps) => void;

/** Deep partial utility type */
export type DeepPartial<T extends {}, K extends keyof T> = Omit<Partial<T>, K> & {
[P in K]?: DeepPartialValue<T[P]>;
export type DeepPartial<T extends {}, K extends keyof T = keyof T, E extends string = never> = Omit<Partial<T>, K> & {
[P in K]?: DeepPartialValue<T[P], E>;
};

export type DeepPartialValue<T> = T extends any[]
export type DeepPartialValue<T, E extends string = never> = T extends any[]
? T
: T extends (...props: any[]) => any
? T
: T extends {}
? {
[P in keyof T]?: P extends "ref" ? T[P] : DeepPartialValue<T[P]>;
[P in keyof T]?: P extends E ? T[P] : DeepPartialValue<T[P], E>;
}
: T;

0 comments on commit c693e71

Please sign in to comment.