import React, { CSSProperties, SyntheticEvent, useEffect, Ref } from 'react'; import { ImageContentPositionObject, ImageContentPositionValue, ImageNativeProps, ImageSource, } from '../Image.types'; import { useBlurhash } from '../utils/blurhash/useBlurhash'; import { isBlurhashString } from '../utils/resolveSources'; function ensureUnit(value: string | number) { const trimmedValue = String(value).trim(); if (trimmedValue.endsWith('%')) { return trimmedValue; } return `${trimmedValue}px`; } type KeysOfUnion = T extends T ? keyof T : never; function getObjectPositionFromContentPositionObject( contentPosition?: ImageContentPositionObject ): string { const resolvedPosition = { ...contentPosition } as Record< KeysOfUnion, ImageContentPositionValue >; if (!resolvedPosition) { return '50% 50%'; } if (resolvedPosition.top == null && resolvedPosition.bottom == null) { resolvedPosition.top = '50%'; } if (resolvedPosition.left == null && resolvedPosition.right == null) { resolvedPosition.left = '50%'; } return ( ['top', 'bottom', 'left', 'right'] .map((key) => { if (key in resolvedPosition) { return `${key} ${ensureUnit(resolvedPosition[key])}`; } return ''; }) .join(' ') || '50% 50%' ); } function getFetchPriorityFromImagePriority(priority: ImageNativeProps['priority'] = 'normal') { return priority && ['low', 'high'].includes(priority) ? priority : 'auto'; } const ImageWrapper = React.forwardRef( ( { source, events, contentPosition, blurhashContentPosition, priority, style, blurhashStyle, className, accessibilityLabel, }: { source?: ImageSource | null; events?: { onLoad?: (((event: SyntheticEvent) => void) | undefined | null)[]; onError?: ((({ source }: { source: ImageSource | null }) => void) | undefined | null)[]; onTransitionEnd?: ((() => void) | undefined | null)[]; onMount?: ((() => void) | undefined | null)[]; }; contentPosition?: ImageContentPositionObject; blurhashContentPosition?: ImageContentPositionObject; priority?: string | null; style: CSSProperties; blurhashStyle?: CSSProperties; className?: string; accessibilityLabel?: string; }, ref: Ref ) => { useEffect(() => { events?.onMount?.forEach((e) => e?.()); }, []); const isBlurhash = isBlurhashString(source?.uri || ''); const blurhashUri = useBlurhash(isBlurhash ? source?.uri : null, source?.width, source?.height); const objectPosition = getObjectPositionFromContentPositionObject( isBlurhash ? blurhashContentPosition : contentPosition ); const uri = isBlurhash ? blurhashUri : source?.uri; if (!uri) return null; return ( {accessibilityLabel} { events?.onLoad?.forEach((e) => e?.(event)); }} onTransitionEnd={() => events?.onTransitionEnd?.forEach((e) => e?.())} onError={() => events?.onError?.forEach((e) => e?.({ source: source || null }))} /> ); } ); export default ImageWrapper;