Created
December 5, 2020 18:37
-
-
Save gaurangrshah/0d2a71f3f4ec8914063440f9954fe5db to your computer and use it in GitHub Desktop.
Integrate NextJs `next/image` with Chakra-UI styling
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { chakra, ThemingProps, useStyleConfig } from '@chakra-ui/react' | |
import NextImage, { ImageProps as NextImageProps } from 'next/image' | |
import { ReactElement } from 'react' | |
/** | |
* ? Because NextJs typing is preventing auto-suggest for layout, width and height | |
* ? we declare the styles differently in this component and will manage the switch | |
* ? to NextJs typings when calling NextJs Image component | |
*/ | |
type LayoutValue = 'fixed' | 'intrinsic' | 'responsive' | undefined | |
type LayoutAndSize = | |
| { | |
layout: 'fill' | |
} | |
| { | |
layout: LayoutValue | |
height: number | |
width: number | |
} | |
/** | |
* Types for the Image component | |
* Picking only the props I want to allow, you can adjust to your liking | |
*/ | |
type ImageProps = Pick< | |
NextImageProps, | |
'className' | 'loading' | 'objectFit' | 'objectPosition' | 'priority' | 'quality' | 'src' | 'unoptimized' | |
> & | |
Pick<Required<NextImageProps>, 'alt'> & | |
Pick<ThemingProps, 'variant'> & { | |
dimensions?: [number, number] | |
layout?: 'fill' | LayoutValue | |
} | |
/** | |
* Wrap NextJs Image component in Chakra's factory function | |
* This is what will allow to use the theme and the styling properties on the component | |
*/ | |
const ImageWithChakra = chakra( | |
({ | |
className, | |
dimensions = [0, 0], | |
layout = 'fill', | |
loading, | |
objectFit, | |
objectPosition, | |
priority, | |
quality, | |
src, | |
unoptimized, | |
...nextjsInternals | |
}: ImageProps): ReactElement => { | |
/** | |
* As explained earlier, NextJs typing is preventing auto-suggest for layout, width and height | |
* Here we actual convert our component typing to NextJs typing | |
*/ | |
const [width, height] = dimensions | |
const layoutAndSize: LayoutAndSize = | |
height > 0 || width > 0 | |
? { | |
height, | |
layout: layout === 'fill' ? 'intrinsic' : layout, | |
width | |
} | |
: { | |
layout: 'fill' | |
} | |
/** | |
* The actual NextImage component | |
*/ | |
return ( | |
<NextImage | |
className={className} | |
loading={loading} | |
objectFit={objectFit} | |
objectPosition={objectPosition} | |
priority={priority} | |
quality={quality} | |
src={src} | |
unoptimized={unoptimized} | |
{...layoutAndSize} | |
{...nextjsInternals} | |
/> | |
) | |
} | |
) | |
export const Image = ({ variant, ...props }: ImageProps): ReactElement => { | |
/** | |
* This components serves as an interface to pass Chakra's styles | |
* You can use the theme and/or styling properties (eg. backgroundColor='red.200') | |
*/ | |
const styles = useStyleConfig('Image', { variant }) | |
return <ImageWithChakra sx={styles} {...props} /> | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment