diff --git a/app/soapbox/components/blurhash.js b/app/soapbox/components/blurhash.js deleted file mode 100644 index 7a7620699..000000000 --- a/app/soapbox/components/blurhash.js +++ /dev/null @@ -1,68 +0,0 @@ -// @ts-check - -import { decode } from 'blurhash'; -import PropTypes from 'prop-types'; -import React, { useRef, useEffect } from 'react'; - -/** - * @typedef BlurhashPropsBase - * @property {string?} hash Hash to render - * @property {number} width - * Width of the blurred region in pixels. Defaults to 32 - * @property {number} [height] - * Height of the blurred region in pixels. Defaults to width - * @property {boolean} [dummy] - * Whether dummy mode is enabled. If enabled, nothing is rendered - * and canvas left untouched - */ - -/** @typedef {JSX.IntrinsicElements['canvas'] & BlurhashPropsBase} BlurhashProps */ - -/** - * Component that is used to render blurred of blurhash string - * - * @param {BlurhashProps} param1 Props of the component - * @returns Canvas which will render blurred region element to embed - */ -function Blurhash({ - hash, - width = 32, - height = width, - dummy = false, - ...canvasProps -}) { - const canvasRef = /** @type {import('react').MutableRefObject} */ (useRef()); - - useEffect(() => { - const { current: canvas } = canvasRef; - - // resets canvas - canvas.width = canvas.width; // eslint-disable-line no-self-assign - - if (dummy || !hash) return; - - try { - const pixels = decode(hash, width, height); - const ctx = canvas.getContext('2d'); - const imageData = new ImageData(pixels, width, height); - - // @ts-ignore - ctx.putImageData(imageData, 0, 0); - } catch (err) { - console.error('Blurhash decoding failure', { err, hash }); - } - }, [dummy, hash, width, height]); - - return ( - - ); -} - -Blurhash.propTypes = { - hash: PropTypes.string, - width: PropTypes.number, - height: PropTypes.number, - dummy: PropTypes.bool, -}; - -export default React.memo(Blurhash); diff --git a/app/soapbox/components/blurhash.tsx b/app/soapbox/components/blurhash.tsx new file mode 100644 index 000000000..cdf5cbf9e --- /dev/null +++ b/app/soapbox/components/blurhash.tsx @@ -0,0 +1,59 @@ +import { decode } from 'blurhash'; +import React, { useRef, useEffect } from 'react'; + +interface IBlurhash { + /** Hash to render */ + hash: string | null | undefined, + /** Width of the blurred region in pixels. Defaults to 32. */ + width?: number, + /** Height of the blurred region in pixels. Defaults to width. */ + height?: number, + /** + * Whether dummy mode is enabled. If enabled, nothing is rendered + * and canvas left untouched. + */ + dummy?: boolean, + /** className of the canvas element. */ + className?: string, +} + +/** + * Renders a blurhash in a canvas element. + * @see {@link https://blurha.sh/} + */ +const Blurhash: React.FC = ({ + hash, + width = 32, + height = width, + dummy = false, + ...canvasProps +}) => { + const canvasRef = useRef(null); + + useEffect(() => { + const { current: canvas } = canvasRef; + if (!canvas) return; + + // resets canvas + canvas.width = canvas.width; // eslint-disable-line no-self-assign + + if (dummy || !hash) return; + + try { + const pixels = decode(hash, width, height); + const ctx = canvas.getContext('2d'); + const imageData = new ImageData(pixels, width, height); + + if (!ctx) return; + ctx.putImageData(imageData, 0, 0); + } catch (err) { + console.error('Blurhash decoding failure', { err, hash }); + } + }, [dummy, hash, width, height]); + + return ( + + ); +}; + +export default React.memo(Blurhash);