Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
import { useRef, CSSProperties } from 'react';
import withSpacing, { WithSpacingProps } from '~/lib/hocs/withSpacing';
import useTestIdAttr from '~/lib/hooks/useTestIdAttr';
import { getAspect } from './utils';
import { ImageProps } from '.';
interface BackgroundImageProps extends ImageProps, WithSpacingProps {
gradient?: string;
borderRadius?: number | string;
}
export const BackgroundImage: React.FC<BackgroundImageProps> = ({
src,
alt,
size,
className,
style,
objectPosition = '50% 50%',
fadeInDuration = 1000,
borderRadius,
gradient,
testId,
}) => {
const dynamicStyleRef = useRef<CSSProperties>({ opacity: 0 });
const testIdAttrs = useTestIdAttr(testId);
const aspect = getAspect(size);
const rootStyle: React.CSSProperties = {
...style,
};
const innerStyle: React.CSSProperties = {
position: 'relative',
width: '100%',
height: '100%',
paddingBottom: aspect ? `${aspect * 100}%` : '',
backgroundPosition: objectPosition,
backgroundSize: 'cover',
backgroundColor: '#000',
transitionProperty: 'opacity',
transitionDuration: `${fadeInDuration}ms`,
borderRadius,
...dynamicStyleRef.current,
};
return (
<div className={className} style={rootStyle} title={alt} {...testIdAttrs}>
<div
style={{
...innerStyle,
backgroundImage: toBackgroundImage({ src, gradient }),
}}
/>
<img
{...{
src,
'aria-hidden': 'true',
width: 0,
height: 0,
Onload: 'this.previousElementSibling.style.opacity = 1',
}}
/>
</div>
);
};
const toBackgroundImage = ({ src, gradient }) => {
if (gradient) return `${gradient}, url(${src})`;
return `url(${src}), linear-gradient(0deg,rgba(0,0,0,.01) 0%,rgba(0,0,0,.01) 100%)`;
};
export default (BackgroundImage) as React.FC<BackgroundImageProps>;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment