'use client';
import React from 'react';
import { CDNOptions } from '../types';
import NextImage, { ImageProps as NextImageProps } from 'next/image';
import { twMerge } from 'tailwind-merge';
import { ImageLoader } from '../utils/image-loader';
interface ImageProps extends NextImageProps {
/**
* Use fill to make the image responsive.
* You also need to provide sizes and aspectRatio props.
*
* @default false
*/
fill?: boolean;
/**
* Crop option for CDN
*
* Available options:
* - `center`
* - `top`
* - `bottom`
* - `left`
* - `right`
*
* @default 'center'
*/
crop?: CDNOptions['crop'];
/**
* It is used to calculate the height of the image when fill is true.
* It prevents layout shift problems.
*/
aspectRatio?: number;
/**
* Sizes attribute for responsive images
*
* If it is not provided, large images will be downloaded for small screens and it will cause performance issues.
*
* @example
*
* @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attr-sizes
*/
sizes?: string;
imageClassName?: string;
/**
* Swiper removed and we use react-multi-carousel at the moment.
* We need to use this prop to make the image draggable or not.
*/
draggable?: boolean;
}
const DEFAULT_QUALITY = 70;
/**
* Image component for responsive images.
*
* It uses CDN options automatically if the image is hosted on Akinon CDN. You don't need to convert the src prop to CDN url.
*
* ## For responsive images
* You need to provide `fill`, `sizes` and `aspectRatio` props.
* If you are not sure about sizes, you can give `100vw` as a value. But it may cause performance issues.
*
* ## For non-responsive images
* You need to provide `width` and `height` props.
* This way, the browser will know the size of the image before downloading it and it will prevent layout shift problems.
*
* ## CDN options
* You can use `crop` option to crop the image.
*
* Available options:
* - `center`
* - `top`
* - `bottom`
* - `left`
* - `right`
*
* You can also use `quality` option to change the quality of the image.
* Be careful about the file size when you change the quality.
*
* @default 70
*/
export const Image = (props: ImageProps) => {
const {
src,
width,
fill,
sizes,
aspectRatio,
quality = DEFAULT_QUALITY,
crop = 'center',
draggable,
className,
imageClassName,
...restImage
} = props;
const optimizeImageURL = ({ src, width }) => {
return ImageLoader({
src,
width,
quality: parseInt(String(quality), DEFAULT_QUALITY),
crop,
fill,
aspectRatio
});
};
const hasGif = typeof src === 'string' && src.includes('.gif');
if (fill && !aspectRatio) {
throw new Error('aspectRatio is required when fill is true');
}
if (fill && !sizes) {
throw new Error('sizes is required when fill is true');
}
return (
optimizeImageURL({ src, width })}
className={imageClassName}
{...(hasGif && { unoptimized: true })}
{...(draggable !== undefined && { draggable })}
/>
);
};