diff --git a/ts/components/LeftPane.tsx b/ts/components/LeftPane.tsx index 10609ebbd5d..a261b7d1223 100644 --- a/ts/components/LeftPane.tsx +++ b/ts/components/LeftPane.tsx @@ -40,6 +40,8 @@ import * as OS from '../OS'; import { LocalizerType, ScrollBehavior } from '../types/Util'; import { usePrevious } from '../hooks/usePrevious'; import { missingCaseError } from '../util/missingCaseError'; +import { strictAssert } from '../util/assert'; +import { isSorted } from '../util/isSorted'; import { getConversationListWidthBreakpoint, WidthBreakpoint } from './_util'; import { ConversationList } from './ConversationList'; @@ -52,9 +54,13 @@ import { } from '../types/Avatar'; const MIN_WIDTH = 109; -const MIN_SNAP_WIDTH = 280; -const MIN_FULL_WIDTH = 320; +const SNAP_WIDTH = 200; +const MIN_FULL_WIDTH = 280; const MAX_WIDTH = 380; +strictAssert( + isSorted([MIN_WIDTH, SNAP_WIDTH, MIN_FULL_WIDTH, MAX_WIDTH]), + 'Expected widths to be in the right order' +); export enum LeftPaneMode { Inbox, @@ -387,10 +393,10 @@ export const LeftPane: React.FC = ({ let width: number; if (requiresFullWidth) { width = Math.max(event.clientX, MIN_FULL_WIDTH); - } else if (event.clientX < MIN_SNAP_WIDTH) { + } else if (event.clientX < SNAP_WIDTH) { width = MIN_WIDTH; } else { - width = Math.max(event.clientX, MIN_WIDTH); + width = clamp(event.clientX, MIN_FULL_WIDTH, MAX_WIDTH); } setPreferredWidth(Math.min(width, MAX_WIDTH)); @@ -484,12 +490,10 @@ export const LeftPane: React.FC = ({ ); let width: number; - if (requiresFullWidth) { + if (requiresFullWidth || preferredWidth >= SNAP_WIDTH) { width = Math.max(preferredWidth, MIN_FULL_WIDTH); - } else if (preferredWidth < MIN_SNAP_WIDTH) { - width = MIN_WIDTH; } else { - width = preferredWidth; + width = MIN_WIDTH; } const isScrollable = helper.isScrollable(); diff --git a/ts/test-both/util/isSorted_test.ts b/ts/test-both/util/isSorted_test.ts new file mode 100644 index 00000000000..da3129e6d3b --- /dev/null +++ b/ts/test-both/util/isSorted_test.ts @@ -0,0 +1,26 @@ +// Copyright 2021 Signal Messenger, LLC +// SPDX-License-Identifier: AGPL-3.0-only + +import { assert } from 'chai'; + +import { isSorted } from '../../util/isSorted'; + +describe('isSorted', () => { + it('returns true for empty lists', () => { + assert.isTrue(isSorted([])); + }); + + it('returns true for one-element lists', () => { + assert.isTrue(isSorted([5])); + }); + + it('returns true for sorted lists', () => { + assert.isTrue(isSorted([1, 2])); + assert.isTrue(isSorted([1, 2, 2, 3])); + }); + + it('returns false for out-of-order lists', () => { + assert.isFalse(isSorted([2, 1])); + assert.isFalse(isSorted([1, 2, 2, 3, 0])); + }); +}); diff --git a/ts/util/isSorted.ts b/ts/util/isSorted.ts new file mode 100644 index 00000000000..7630e6e7f21 --- /dev/null +++ b/ts/util/isSorted.ts @@ -0,0 +1,13 @@ +// Copyright 2021 Signal Messenger, LLC +// SPDX-License-Identifier: AGPL-3.0-only + +export function isSorted(list: Iterable): boolean { + let previousItem: undefined | number; + for (const item of list) { + if (previousItem !== undefined && item < previousItem) { + return false; + } + previousItem = item; + } + return true; +}