diff options
author | Sasha Sorokin <dafri.nochiterov8@gmail.com> | 2020-07-09 18:01:30 +0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-07-09 13:01:30 +0200 |
commit | 61c07c37317f01c1ab4981826704750fe9937fe7 (patch) | |
tree | abecace8339a034b8615c4a11eabf541c178bdb5 /app/javascript/mastodon/components/blurhash.js | |
parent | 5b7a93b02cfa4916bd7a99d876b0e6b567e639c3 (diff) |
Replace repetitive blurhash code with component (#14267)
This commit replaces all unnecessarily repeated code for decoding and embedding blurhash canvases with separate component - <Blurhash>. Under the hood Blurhash component will use effect dependent on its props. This gives a few benefits: it will only be re-rendered whenever the hash or width/height/dummy props update, and will not render if canvas won't get to the final DOM, because then effect won't fire, which prevents weird bugs like #14257.
Diffstat (limited to 'app/javascript/mastodon/components/blurhash.js')
-rw-r--r-- | app/javascript/mastodon/components/blurhash.js | 61 |
1 files changed, 61 insertions, 0 deletions
diff --git a/app/javascript/mastodon/components/blurhash.js b/app/javascript/mastodon/components/blurhash.js new file mode 100644 index 000000000..172f8c2f5 --- /dev/null +++ b/app/javascript/mastodon/components/blurhash.js @@ -0,0 +1,61 @@ +// @ts-check + +import { decode } from 'blurhash'; +import React, { useRef, useEffect } from 'react'; +import PropTypes from 'prop-types'; + +/** + * @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<HTMLCanvasElement>} */ (useRef()); + + useEffect(() => { + const { current: canvas } = canvasRef; + canvas.width = canvas.width; // resets canvas + + if (dummy) return; + + const pixels = decode(hash, width, height); + const ctx = canvas.getContext('2d'); + const imageData = new ImageData(pixels, width, height); + + ctx.putImageData(imageData, 0, 0); + }, [dummy, hash, width, height]); + + return ( + <canvas {...canvasProps} ref={canvasRef} width={width} height={height} /> + ); +} + +Blurhash.propTypes = { + hash: PropTypes.string.isRequired, + width: PropTypes.number, + height: PropTypes.number, + dummy: PropTypes.bool, +}; + +export default React.memo(Blurhash); |