Skip to content

Instantly share code, notes, and snippets.

@TomasSestak
Last active September 20, 2024 13:02
Show Gist options
  • Save TomasSestak/91ca8edf14fd1ea6dbd470da6d163390 to your computer and use it in GitHub Desktop.
Save TomasSestak/91ca8edf14fd1ea6dbd470da6d163390 to your computer and use it in GitHub Desktop.
NextPicture - Picture Component that uses native picture element while keeping NextImageProps
import { getImageProps, ImageProps } from "next/image";
import { StaticImport } from "next/dist/shared/lib/get-img-props";
export type NextPictureSetWithMedia = {
src: StaticImport;
media: number;
};
export type NextPictureSetWithoutMedia = {
src: StaticImport;
media?: never; // Ensures that the last set can have no media
};
export type NextPictureSets = [...NextPictureSetWithMedia[], NextPictureSetWithoutMedia]; // Forces all but the last to have media
interface NextPictureProps extends Omit<ImageProps, "alt" | "src"> {
alt?: string;
sets: NextPictureSets;
}
export const NextPicture = ({ sets, alt = "", ...rest }: NextPictureProps) => {
return (
<picture>
{sets.map((item, index) => {
return <Source {...item} alt={alt} {...rest} key={index} />;
})}
</picture>
);
};
const Source = ({
src,
media,
alt,
...rest
}: (NextPictureSetWithMedia | NextPictureSetWithoutMedia) & { alt: string } & Omit<ImageProps, "alt" | "src">) => {
const {
props: { srcSet, ...imageRest },
} = getImageProps({ alt, src, ...rest });
return (
<>
{/* eslint-disable-next-line @next/next/no-img-element */}
{!media ? <img {...imageRest} alt={alt} /> : <source media={`(min-width: ${media}px)`} srcSet={srcSet} />}
</>
);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment