From f80aef0ba46d577e701f64014c172617e0f2088b Mon Sep 17 00:00:00 2001 From: Fedor Indutny <79877362+indutny-signal@users.noreply.github.com> Date: Tue, 5 Aug 2025 11:13:10 -0700 Subject: [PATCH] Fix aspect ratio of ImageOrBlurhash --- ts/components/ImageOrBlurhash.tsx | 22 +++++++++- ts/components/conversation/Image.tsx | 2 +- ts/util/lint/exceptions.json | 63 +++++++++++++++------------- 3 files changed, 56 insertions(+), 31 deletions(-) diff --git a/ts/components/ImageOrBlurhash.tsx b/ts/components/ImageOrBlurhash.tsx index 179fbcf133..8dc5a45432 100644 --- a/ts/components/ImageOrBlurhash.tsx +++ b/ts/components/ImageOrBlurhash.tsx @@ -1,7 +1,7 @@ // Copyright 2025 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import React, { useMemo } from 'react'; +import React, { useMemo, useCallback, useState, useRef } from 'react'; import { computeBlurHashUrl } from '../util/computeBlurHashUrl'; @@ -21,25 +21,43 @@ export function ImageOrBlurhash({ intrinsicHeight, ...rest }: Props): JSX.Element { + const ref = useRef(null); + const [isLoaded, setIsLoaded] = useState(false); + const blurHashUrl = useMemo(() => { return blurHash ? computeBlurHashUrl(blurHash, intrinsicWidth, intrinsicHeight) : undefined; }, [blurHash, intrinsicWidth, intrinsicHeight]); + const onLoad = useCallback(() => { + // Don't let background blurhash be visible at the same time as the image + // while React propagates the `isLoaded` change. + if (ref.current) { + ref.current.style.backgroundImage = 'none'; + } + setIsLoaded(true); + }, [ref]); + const src = imageSrc ?? blurHashUrl; return ( {alt} ); diff --git a/ts/util/lint/exceptions.json b/ts/util/lint/exceptions.json index 777eea4714..c2326746e1 100644 --- a/ts/util/lint/exceptions.json +++ b/ts/util/lint/exceptions.json @@ -1319,6 +1319,13 @@ "updated": "2021-12-10T23:24:31.237Z", "reasonDetail": "Doesn't touch the DOM." }, + { + "rule": "React-useRef", + "path": "ts/components/ImageOrBlurhash.tsx", + "line": " const ref = useRef(null);", + "reasonCategory": "usageTrusted", + "updated": "2025-08-05T17:07:11.678Z" + }, { "rule": "React-useRef", "path": "ts/components/IncomingCallBar.tsx", @@ -1486,34 +1493,6 @@ "updated": "2025-06-26T23:23:57.292Z", "reasonDetail": "Holding on to a close function" }, - { - "rule": "React-useRef", - "path": "ts/components/preferences/donations/DonateInputAmount.tsx", - "line": " const inputRef = useRef(null);", - "reasonCategory": "usageTrusted", - "updated": "2025-08-01T20:31:42.993Z" - }, - { - "rule": "React-useRef", - "path": "ts/components/preferences/donations/DonateInputCardCvc.tsx", - "line": " const inputRef = useRef(null);", - "reasonCategory": "usageTrusted", - "updated": "2025-07-17T19:33:27.401Z" - }, - { - "rule": "React-useRef", - "path": "ts/components/preferences/donations/DonateInputCardExp.tsx", - "line": " const inputRef = useRef(null);", - "reasonCategory": "usageTrusted", - "updated": "2025-07-17T19:33:27.401Z" - }, - { - "rule": "React-useRef", - "path": "ts/components/preferences/donations/DonateInputCardNumber.tsx", - "line": " const inputRef = useRef(null);", - "reasonCategory": "usageTrusted", - "updated": "2025-07-17T19:33:27.401Z" - }, { "rule": "React-useRef", "path": "ts/components/PreferencesLocalBackups.tsx", @@ -2090,6 +2069,34 @@ "reasonCategory": "usageTrusted", "updated": "2025-02-19T20:14:46.879Z" }, + { + "rule": "React-useRef", + "path": "ts/components/preferences/donations/DonateInputAmount.tsx", + "line": " const inputRef = useRef(null);", + "reasonCategory": "usageTrusted", + "updated": "2025-08-01T20:31:42.993Z" + }, + { + "rule": "React-useRef", + "path": "ts/components/preferences/donations/DonateInputCardCvc.tsx", + "line": " const inputRef = useRef(null);", + "reasonCategory": "usageTrusted", + "updated": "2025-07-17T19:33:27.401Z" + }, + { + "rule": "React-useRef", + "path": "ts/components/preferences/donations/DonateInputCardExp.tsx", + "line": " const inputRef = useRef(null);", + "reasonCategory": "usageTrusted", + "updated": "2025-07-17T19:33:27.401Z" + }, + { + "rule": "React-useRef", + "path": "ts/components/preferences/donations/DonateInputCardNumber.tsx", + "line": " const inputRef = useRef(null);", + "reasonCategory": "usageTrusted", + "updated": "2025-07-17T19:33:27.401Z" + }, { "rule": "React-useRef", "path": "ts/components/stickers/StickerButton.tsx",