UNPKG

@chakra-ui/image

Version:

React component for progressive image loading

1 lines 4.96 kB
{"version":3,"sources":["../src/use-image.ts"],"sourcesContent":["import { useSafeLayoutEffect } from \"@chakra-ui/react-use-safe-layout-effect\"\nimport { useCallback, useEffect, useRef, useState } from \"react\"\n\ntype NativeImageProps = React.ImgHTMLAttributes<HTMLImageElement>\n\nexport interface UseImageProps {\n /**\n * The image `src` attribute\n */\n src?: string\n /**\n * The image `srcset` attribute\n */\n srcSet?: string\n /**\n * The image `sizes` attribute\n */\n sizes?: string\n /**\n * A callback for when the image `src` has been loaded\n */\n onLoad?: NativeImageProps[\"onLoad\"]\n /**\n * A callback for when there was an error loading the image `src`\n */\n onError?: NativeImageProps[\"onError\"]\n /**\n * If `true`, opt out of the `fallbackSrc` logic and use as `img`\n *\n * @default false\n */\n ignoreFallback?: boolean\n /**\n * The key used to set the crossOrigin on the HTMLImageElement into which the image will be loaded.\n * This tells the browser to request cross-origin access when trying to download the image data.\n */\n crossOrigin?: NativeImageProps[\"crossOrigin\"]\n loading?: NativeImageProps[\"loading\"]\n}\n\ntype Status = \"loading\" | \"failed\" | \"pending\" | \"loaded\"\n\nexport type FallbackStrategy = \"onError\" | \"beforeLoadOrError\"\n\ntype ImageEvent = React.SyntheticEvent<HTMLImageElement, Event>\n\n/**\n * React hook that loads an image in the browser,\n * and lets us know the `status` so we can show image\n * fallback if it is still `pending`\n *\n * @returns the status of the image loading progress\n *\n * @example\n *\n * ```jsx\n * function App(){\n * const status = useImage({ src: \"image.png\" })\n * return status === \"loaded\" ? <img src=\"image.png\" /> : <Placeholder />\n * }\n * ```\n */\nexport function useImage(props: UseImageProps) {\n const {\n loading,\n src,\n srcSet,\n onLoad,\n onError,\n crossOrigin,\n sizes,\n ignoreFallback,\n } = props\n\n const [status, setStatus] = useState<Status>(\"pending\")\n\n useEffect(() => {\n setStatus(src ? \"loading\" : \"pending\")\n }, [src])\n\n const imageRef = useRef<HTMLImageElement | null>()\n\n const load = useCallback(() => {\n if (!src) return\n\n flush()\n\n const img = new Image()\n img.src = src\n if (crossOrigin) img.crossOrigin = crossOrigin\n if (srcSet) img.srcset = srcSet\n if (sizes) img.sizes = sizes\n if (loading) img.loading = loading\n\n img.onload = (event) => {\n flush()\n setStatus(\"loaded\")\n onLoad?.(event as unknown as ImageEvent)\n }\n img.onerror = (error) => {\n flush()\n setStatus(\"failed\")\n onError?.(error as any)\n }\n\n imageRef.current = img\n }, [src, crossOrigin, srcSet, sizes, onLoad, onError, loading])\n\n const flush = () => {\n if (imageRef.current) {\n imageRef.current.onload = null\n imageRef.current.onerror = null\n imageRef.current = null\n }\n }\n\n useSafeLayoutEffect(() => {\n /**\n * If user opts out of the fallback/placeholder\n * logic, let's bail out.\n */\n if (ignoreFallback) return undefined\n\n if (status === \"loading\") {\n load()\n }\n return () => {\n flush()\n }\n }, [status, load, ignoreFallback])\n\n /**\n * If user opts out of the fallback/placeholder\n * logic, let's just return 'loaded'\n */\n return ignoreFallback ? \"loaded\" : status\n}\n\nexport const shouldShowFallbackImage = (\n status: Status,\n fallbackStrategy: FallbackStrategy,\n) =>\n (status !== \"loaded\" && fallbackStrategy === \"beforeLoadOrError\") ||\n (status === \"failed\" && fallbackStrategy === \"onError\")\n\nexport type UseImageReturn = ReturnType<typeof useImage>\n"],"mappings":";;;AAAA,SAAS,2BAA2B;AACpC,SAAS,aAAa,WAAW,QAAQ,gBAAgB;AA6DlD,SAAS,SAAS,OAAsB;AAC7C,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI;AAEJ,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAiB,SAAS;AAEtD,YAAU,MAAM;AACd,cAAU,MAAM,YAAY,SAAS;AAAA,EACvC,GAAG,CAAC,GAAG,CAAC;AAER,QAAM,WAAW,OAAgC;AAEjD,QAAM,OAAO,YAAY,MAAM;AAC7B,QAAI,CAAC;AAAK;AAEV,UAAM;AAEN,UAAM,MAAM,IAAI,MAAM;AACtB,QAAI,MAAM;AACV,QAAI;AAAa,UAAI,cAAc;AACnC,QAAI;AAAQ,UAAI,SAAS;AACzB,QAAI;AAAO,UAAI,QAAQ;AACvB,QAAI;AAAS,UAAI,UAAU;AAE3B,QAAI,SAAS,CAAC,UAAU;AACtB,YAAM;AACN,gBAAU,QAAQ;AAClB,uCAAS;AAAA,IACX;AACA,QAAI,UAAU,CAAC,UAAU;AACvB,YAAM;AACN,gBAAU,QAAQ;AAClB,yCAAU;AAAA,IACZ;AAEA,aAAS,UAAU;AAAA,EACrB,GAAG,CAAC,KAAK,aAAa,QAAQ,OAAO,QAAQ,SAAS,OAAO,CAAC;AAE9D,QAAM,QAAQ,MAAM;AAClB,QAAI,SAAS,SAAS;AACpB,eAAS,QAAQ,SAAS;AAC1B,eAAS,QAAQ,UAAU;AAC3B,eAAS,UAAU;AAAA,IACrB;AAAA,EACF;AAEA,sBAAoB,MAAM;AAKxB,QAAI;AAAgB,aAAO;AAE3B,QAAI,WAAW,WAAW;AACxB,WAAK;AAAA,IACP;AACA,WAAO,MAAM;AACX,YAAM;AAAA,IACR;AAAA,EACF,GAAG,CAAC,QAAQ,MAAM,cAAc,CAAC;AAMjC,SAAO,iBAAiB,WAAW;AACrC;AAEO,IAAM,0BAA0B,CACrC,QACA,qBAEC,WAAW,YAAY,qBAAqB,uBAC5C,WAAW,YAAY,qBAAqB;","names":[]}