From 934e0fa415b06611cbaa742e86921c560a58b7cd Mon Sep 17 00:00:00 2001 From: Evan Hahn <69474926+EvanHahn-Signal@users.noreply.github.com> Date: Mon, 8 Mar 2021 14:07:37 -0600 Subject: [PATCH] In , use new "scrollToBottom" helper --- ts/components/ContactPills.tsx | 7 ++-- ts/test-electron/scrollToBottom_test.ts | 47 +++++++++++++++++++++++++ ts/util/lint/exceptions.json | 6 ++-- ts/util/scrollToBottom.ts | 8 +++++ 4 files changed, 62 insertions(+), 6 deletions(-) create mode 100644 ts/test-electron/scrollToBottom_test.ts create mode 100644 ts/util/scrollToBottom.ts diff --git a/ts/components/ContactPills.tsx b/ts/components/ContactPills.tsx index eda64626eb09..ed3789c78ec0 100644 --- a/ts/components/ContactPills.tsx +++ b/ts/components/ContactPills.tsx @@ -9,6 +9,8 @@ import React, { ReactNode, } from 'react'; +import { scrollToBottom } from '../util/scrollToBottom'; + type PropsType = { children?: ReactNode; }; @@ -24,10 +26,9 @@ export const ContactPills: FunctionComponent = ({ children }) => { useEffect(() => { const hasAddedNewChild = childCount > previousChildCount; const el = elRef.current; - if (!hasAddedNewChild || !el) { - return; + if (hasAddedNewChild && el) { + scrollToBottom(el); } - el.scrollTop = el.scrollHeight; }, [childCount, previousChildCount]); return ( diff --git a/ts/test-electron/scrollToBottom_test.ts b/ts/test-electron/scrollToBottom_test.ts new file mode 100644 index 000000000000..4b81d854da91 --- /dev/null +++ b/ts/test-electron/scrollToBottom_test.ts @@ -0,0 +1,47 @@ +// Copyright 2021 Signal Messenger, LLC +// SPDX-License-Identifier: AGPL-3.0-only + +import { assert } from 'chai'; + +import { scrollToBottom } from '../util/scrollToBottom'; + +describe('scrollToBottom', () => { + let sandbox: HTMLDivElement; + + beforeEach(() => { + sandbox = document.createElement('div'); + document.body.appendChild(sandbox); + }); + + afterEach(() => { + sandbox.remove(); + }); + + it("sets the element's scrollTop to the element's scrollHeight", () => { + const el = document.createElement('div'); + el.innerText = 'a'.repeat(50000); + Object.assign(el.style, { + height: '50px', + overflow: 'scroll', + whiteSpace: 'wrap', + width: '100px', + wordBreak: 'break-word', + }); + sandbox.appendChild(el); + + assert.strictEqual( + el.scrollTop, + 0, + 'Test is not set up correctly. Element is already scrolled' + ); + assert.isAtLeast( + el.scrollHeight, + 50, + 'Test is not set up correctly. scrollHeight is too low' + ); + + scrollToBottom(el); + + assert.isAtLeast(el.scrollTop, el.scrollHeight - 50); + }); +}); diff --git a/ts/util/lint/exceptions.json b/ts/util/lint/exceptions.json index 9ca326dd0b15..dcabd4d5cb8b 100644 --- a/ts/util/lint/exceptions.json +++ b/ts/util/lint/exceptions.json @@ -14671,7 +14671,7 @@ "rule": "React-useRef", "path": "ts/components/ContactPills.js", "line": " const elRef = react_1.useRef(null);", - "lineNumber": 27, + "lineNumber": 28, "reasonCategory": "usageTrusted", "updated": "2021-03-01T18:34:36.638Z", "reasonDetail": "Used for scrolling. Doesn't otherwise manipulate the DOM" @@ -14680,7 +14680,7 @@ "rule": "React-useRef", "path": "ts/components/ContactPills.js", "line": " const previousChildCountRef = react_1.useRef(childCount);", - "lineNumber": 29, + "lineNumber": 30, "reasonCategory": "usageTrusted", "updated": "2021-03-01T18:34:36.638Z", "reasonDetail": "Doesn't reference the DOM. Refers to a number" @@ -15394,4 +15394,4 @@ "updated": "2021-01-08T15:46:32.143Z", "reasonDetail": "Doesn't manipulate the DOM. This is just a function." } -] +] \ No newline at end of file diff --git a/ts/util/scrollToBottom.ts b/ts/util/scrollToBottom.ts new file mode 100644 index 000000000000..0ac3b55f2c16 --- /dev/null +++ b/ts/util/scrollToBottom.ts @@ -0,0 +1,8 @@ +// Copyright 2021 Signal Messenger, LLC +// SPDX-License-Identifier: AGPL-3.0-only + +export function scrollToBottom(el: HTMLElement): void { + // We want to mutate the parameter here. + // eslint-disable-next-line no-param-reassign + el.scrollTop = el.scrollHeight; +}