Swap out the resizer lib for something more stable
react-resizer appears to be okay at tracking state, but it often desyncs from reality. re-resizer is more maintained and more broadly used (160k downloads vs 110k), and appears to generally do a better job of tracking the cursor. The new library has some oddities though, such as deltas, touch support (hence the polyfill), and calling handles "Enable". For https://github.com/vector-im/riot-web/issues/14022pull/21833/head
							parent
							
								
									7f757cd0f3
								
							
						
					
					
						commit
						15b6a273c9
					
				| 
						 | 
				
			
			@ -89,11 +89,11 @@
 | 
			
		|||
    "prop-types": "^15.5.8",
 | 
			
		||||
    "qrcode": "^1.4.4",
 | 
			
		||||
    "qs": "^6.6.0",
 | 
			
		||||
    "re-resizable": "^6.5.2",
 | 
			
		||||
    "react": "^16.9.0",
 | 
			
		||||
    "react-beautiful-dnd": "^4.0.1",
 | 
			
		||||
    "react-dom": "^16.9.0",
 | 
			
		||||
    "react-focus-lock": "^2.2.1",
 | 
			
		||||
    "react-resizable": "^1.10.1",
 | 
			
		||||
    "react-transition-group": "^4.4.1",
 | 
			
		||||
    "resize-observer-polyfill": "^1.5.0",
 | 
			
		||||
    "sanitize-html": "^1.18.4",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -254,24 +254,26 @@ limitations under the License.
 | 
			
		|||
        // Class name comes from the ResizableBox component
 | 
			
		||||
        // The hover state needs to use the whole sublist, not just the resizable box,
 | 
			
		||||
        // so that selector is below and one level higher.
 | 
			
		||||
        .react-resizable-handle {
 | 
			
		||||
        .mx_RoomSublist2_resizerHandle {
 | 
			
		||||
            cursor: ns-resize;
 | 
			
		||||
            border-radius: 3px;
 | 
			
		||||
 | 
			
		||||
            // Update RESIZE_HANDLE_HEIGHT if this changes
 | 
			
		||||
            height: 4px;
 | 
			
		||||
            // Override styles from library
 | 
			
		||||
            width: unset !important;
 | 
			
		||||
            height: 4px !important; // Update RESIZE_HANDLE_HEIGHT if this changes
 | 
			
		||||
 | 
			
		||||
            // This is positioned directly below the 'show more' button.
 | 
			
		||||
            position: absolute;
 | 
			
		||||
            bottom: 0;
 | 
			
		||||
            bottom: 0 !important; // override from library
 | 
			
		||||
 | 
			
		||||
            // Together, these make the bar 64px wide
 | 
			
		||||
            left: calc(50% - 32px);
 | 
			
		||||
            right: calc(50% - 32px);
 | 
			
		||||
            // These are also overridden from the library
 | 
			
		||||
            left: calc(50% - 32px) !important;
 | 
			
		||||
            right: calc(50% - 32px) !important;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        &:hover, &.mx_RoomSublist2_hasMenuOpen {
 | 
			
		||||
            .react-resizable-handle {
 | 
			
		||||
            .mx_RoomSublist2_resizerHandle {
 | 
			
		||||
                opacity: 0.8;
 | 
			
		||||
                background-color: $primary-fg-color;
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,36 @@
 | 
			
		|||
/*
 | 
			
		||||
Copyright 2020 The Matrix.org Foundation C.I.C.
 | 
			
		||||
 | 
			
		||||
Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
you may not use this file except in compliance with the License.
 | 
			
		||||
You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
    http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
See the License for the specific language governing permissions and
 | 
			
		||||
limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
export function polyfillTouchEvent() {
 | 
			
		||||
    // Firefox doesn't have touch events, so create a fake one we can rely on lying about.
 | 
			
		||||
    if (!window.TouchEvent) {
 | 
			
		||||
        // We have no intention of actually using this, so just lie.
 | 
			
		||||
        window.TouchEvent = class TouchEvent extends UIEvent {
 | 
			
		||||
            public get altKey(): boolean { return false; }
 | 
			
		||||
            public get changedTouches(): any { return []; }
 | 
			
		||||
            public get ctrlKey(): boolean { return false; }
 | 
			
		||||
            public get metaKey(): boolean { return false; }
 | 
			
		||||
            public get shiftKey(): boolean { return false; }
 | 
			
		||||
            public get targetTouches(): any { return []; }
 | 
			
		||||
            public get touches(): any { return []; }
 | 
			
		||||
            public get rotation(): number { return 0.0; }
 | 
			
		||||
            public get scale(): number { return 0.0; }
 | 
			
		||||
            constructor(eventType: string, params?: any) {
 | 
			
		||||
                super(eventType, params);
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -24,7 +24,6 @@ import {RovingAccessibleButton, RovingTabIndexWrapper} from "../../../accessibil
 | 
			
		|||
import { _t } from "../../../languageHandler";
 | 
			
		||||
import AccessibleButton from "../../views/elements/AccessibleButton";
 | 
			
		||||
import RoomTile2 from "./RoomTile2";
 | 
			
		||||
import { ResizableBox, ResizeCallbackData } from "react-resizable";
 | 
			
		||||
import { ListLayout } from "../../../stores/room-list/ListLayout";
 | 
			
		||||
import {
 | 
			
		||||
    ContextMenu,
 | 
			
		||||
| 
						 | 
				
			
			@ -40,7 +39,9 @@ import NotificationBadge from "./NotificationBadge";
 | 
			
		|||
import { ListNotificationState } from "../../../stores/notifications/ListNotificationState";
 | 
			
		||||
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
 | 
			
		||||
import { Key } from "../../../Keyboard";
 | 
			
		||||
import StyledCheckbox from "../elements/StyledCheckbox";
 | 
			
		||||
import { Enable, Resizable } from "re-resizable";
 | 
			
		||||
import { Direction } from "re-resizable/lib/resizer";
 | 
			
		||||
import { polyfillTouchEvent } from "../../../@types/polyfill";
 | 
			
		||||
 | 
			
		||||
// TODO: Remove banner on launch: https://github.com/vector-im/riot-web/issues/14231
 | 
			
		||||
// TODO: Rename on launch: https://github.com/vector-im/riot-web/issues/14231
 | 
			
		||||
| 
						 | 
				
			
			@ -58,6 +59,9 @@ const RESIZE_HANDLE_HEIGHT = 4; // As defined by CSS
 | 
			
		|||
 | 
			
		||||
const MAX_PADDING_HEIGHT = SHOW_N_BUTTON_HEIGHT + RESIZE_HANDLE_HEIGHT;
 | 
			
		||||
 | 
			
		||||
// HACK: We really shouldn't have to do this.
 | 
			
		||||
polyfillTouchEvent();
 | 
			
		||||
 | 
			
		||||
interface IProps {
 | 
			
		||||
    forRooms: boolean;
 | 
			
		||||
    rooms?: Room[];
 | 
			
		||||
| 
						 | 
				
			
			@ -124,10 +128,25 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
 | 
			
		|||
        if (this.props.onAddRoom) this.props.onAddRoom();
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    private onResize = (e: React.MouseEvent, data: ResizeCallbackData) => {
 | 
			
		||||
        const direction = e.movementY < 0 ? -1 : +1;
 | 
			
		||||
        const tileDiff = this.props.layout.pixelsToTiles(Math.abs(e.movementY)) * direction;
 | 
			
		||||
        this.props.layout.setVisibleTilesWithin(tileDiff, this.numTiles);
 | 
			
		||||
    private onResize = (
 | 
			
		||||
        e: MouseEvent | TouchEvent,
 | 
			
		||||
        travelDirection: Direction,
 | 
			
		||||
        refToElement: HTMLDivElement,
 | 
			
		||||
        delta: { width: number, height: number }, // TODO: Use NumberSize from re-resizer when it is exposed
 | 
			
		||||
    ) => {
 | 
			
		||||
        // Do some sanity checks, but in reality we shouldn't need these.
 | 
			
		||||
        if (travelDirection !== "bottom") return;
 | 
			
		||||
        if (delta.height === 0) return; // something went wrong, so just ignore it.
 | 
			
		||||
 | 
			
		||||
        // NOTE: the movement in the MouseEvent (not present on a TouchEvent) is inaccurate
 | 
			
		||||
        // for our purposes. The delta provided by the library is also a change *from when
 | 
			
		||||
        // resizing started*, meaning it is fairly useless for us. This is why we just use
 | 
			
		||||
        // the client height and run with it.
 | 
			
		||||
 | 
			
		||||
        const heightBefore = this.props.layout.visibleTiles;
 | 
			
		||||
        const heightInTiles = this.props.layout.pixelsToTiles(refToElement.clientHeight);
 | 
			
		||||
        this.props.layout.setVisibleTilesWithin(heightInTiles, this.numTiles);
 | 
			
		||||
        if (heightBefore === this.props.layout.visibleTiles) return; // no-op
 | 
			
		||||
        this.forceUpdate(); // because the layout doesn't trigger a re-render
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -556,9 +575,19 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
 | 
			
		|||
            }
 | 
			
		||||
 | 
			
		||||
            // Figure out if we need a handle
 | 
			
		||||
            let handles = ['s'];
 | 
			
		||||
            const handles: Enable = {
 | 
			
		||||
                bottom: true, // the only one we need, but the others must be explicitly false
 | 
			
		||||
                bottomLeft: false,
 | 
			
		||||
                bottomRight: false,
 | 
			
		||||
                left: false,
 | 
			
		||||
                right: false,
 | 
			
		||||
                top: false,
 | 
			
		||||
                topLeft: false,
 | 
			
		||||
                topRight: false,
 | 
			
		||||
            };
 | 
			
		||||
            if (layout.visibleTiles >= this.numTiles && this.numTiles <= layout.minVisibleTiles) {
 | 
			
		||||
                handles = []; // no handles, we're at a minimum
 | 
			
		||||
                // we're at a minimum, don't have a bottom handle
 | 
			
		||||
                handles.bottom = false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // We have to account for padding so we can accommodate a 'show more' button and
 | 
			
		||||
| 
						 | 
				
			
			@ -582,22 +611,25 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
 | 
			
		|||
            const tilesWithoutPadding = Math.min(relativeTiles, layout.visibleTiles);
 | 
			
		||||
            const tilesPx = layout.calculateTilesToPixelsMin(relativeTiles, tilesWithoutPadding, padding);
 | 
			
		||||
 | 
			
		||||
            const dimensions = {
 | 
			
		||||
                height: tilesPx,
 | 
			
		||||
            };
 | 
			
		||||
            content = (
 | 
			
		||||
                <ResizableBox
 | 
			
		||||
                    width={-1}
 | 
			
		||||
                    height={tilesPx}
 | 
			
		||||
                    axis="y"
 | 
			
		||||
                    minConstraints={[-1, minTilesPx]}
 | 
			
		||||
                    maxConstraints={[-1, maxTilesPx]}
 | 
			
		||||
                    resizeHandles={handles}
 | 
			
		||||
                    onResize={this.onResize}
 | 
			
		||||
                    className="mx_RoomSublist2_resizeBox"
 | 
			
		||||
                <Resizable
 | 
			
		||||
                    size={dimensions as any}
 | 
			
		||||
                    minHeight={minTilesPx}
 | 
			
		||||
                    maxHeight={maxTilesPx}
 | 
			
		||||
                    onResizeStart={this.onResizeStart}
 | 
			
		||||
                    onResizeStop={this.onResizeStop}
 | 
			
		||||
                    onResize={this.onResize}
 | 
			
		||||
                    handleWrapperClass="mx_RoomSublist2_resizerHandles"
 | 
			
		||||
                    handleClasses={{bottom: "mx_RoomSublist2_resizerHandle"}}
 | 
			
		||||
                    className="mx_RoomSublist2_resizeBox"
 | 
			
		||||
                    enable={handles}
 | 
			
		||||
                >
 | 
			
		||||
                    {visibleTiles}
 | 
			
		||||
                    {showNButton}
 | 
			
		||||
                </ResizableBox>
 | 
			
		||||
                </Resizable>
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -89,11 +89,12 @@ export class ListLayout {
 | 
			
		|||
        return 5 + RESIZER_BOX_FACTOR;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public setVisibleTilesWithin(diff: number, maxPossible: number) {
 | 
			
		||||
    public setVisibleTilesWithin(newVal: number, maxPossible: number) {
 | 
			
		||||
        maxPossible = maxPossible + RESIZER_BOX_FACTOR;
 | 
			
		||||
        if (this.visibleTiles > maxPossible) {
 | 
			
		||||
            this.visibleTiles = maxPossible + diff;
 | 
			
		||||
            this.visibleTiles = maxPossible;
 | 
			
		||||
        } else {
 | 
			
		||||
            this.visibleTiles += diff;
 | 
			
		||||
            this.visibleTiles = newVal;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										32
									
								
								yarn.lock
								
								
								
								
							
							
						
						
									
										32
									
								
								yarn.lock
								
								
								
								
							| 
						 | 
				
			
			@ -2499,7 +2499,7 @@ class-utils@^0.3.5:
 | 
			
		|||
    isobject "^3.0.0"
 | 
			
		||||
    static-extend "^0.1.1"
 | 
			
		||||
 | 
			
		||||
classnames@^2.1.2, classnames@^2.2.5:
 | 
			
		||||
classnames@^2.1.2:
 | 
			
		||||
  version "2.2.6"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce"
 | 
			
		||||
  integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==
 | 
			
		||||
| 
						 | 
				
			
			@ -3779,6 +3779,11 @@ fast-levenshtein@~2.0.6:
 | 
			
		|||
  resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
 | 
			
		||||
  integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
 | 
			
		||||
 | 
			
		||||
fast-memoize@^2.5.1:
 | 
			
		||||
  version "2.5.2"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/fast-memoize/-/fast-memoize-2.5.2.tgz#79e3bb6a4ec867ea40ba0e7146816f6cdce9b57e"
 | 
			
		||||
  integrity sha512-Ue0LwpDYErFbmNnZSF0UH6eImUwDmogUO1jyE+JbN2gsQz/jICm1Ve7t9QT0rNSsfJt+Hs4/S3GnsDVjL4HVrw==
 | 
			
		||||
 | 
			
		||||
fb-watchman@^2.0.0:
 | 
			
		||||
  version "2.0.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.1.tgz#fc84fb39d2709cf3ff6d743706157bb5708a8a85"
 | 
			
		||||
| 
						 | 
				
			
			@ -6882,7 +6887,7 @@ prop-types-exact@^1.2.0:
 | 
			
		|||
    object.assign "^4.1.0"
 | 
			
		||||
    reflect.ownkeys "^0.2.0"
 | 
			
		||||
 | 
			
		||||
prop-types@15.x, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2:
 | 
			
		||||
prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2:
 | 
			
		||||
  version "15.7.2"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
 | 
			
		||||
  integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
 | 
			
		||||
| 
						 | 
				
			
			@ -7053,6 +7058,13 @@ rc@1.2.8, rc@^1.2.8:
 | 
			
		|||
    minimist "^1.2.0"
 | 
			
		||||
    strip-json-comments "~2.0.1"
 | 
			
		||||
 | 
			
		||||
re-resizable@^6.5.2:
 | 
			
		||||
  version "6.5.2"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/re-resizable/-/re-resizable-6.5.2.tgz#7eb1928c673285d4dcf654211e47acb9a3801c3e"
 | 
			
		||||
  integrity sha512-Pjo3ydkr/meTr6j3YZqyv+9fRS5UNOj5SaAI06gHFQ35BnpsZKmwNvupCnbo11gjQ1I62Uy+UzlHLO9xPQEuWQ==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    fast-memoize "^2.5.1"
 | 
			
		||||
 | 
			
		||||
react-beautiful-dnd@^4.0.1:
 | 
			
		||||
  version "4.0.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/react-beautiful-dnd/-/react-beautiful-dnd-4.0.1.tgz#3b0a49bf6be75af351176c904f012611dd292b81"
 | 
			
		||||
| 
						 | 
				
			
			@ -7086,14 +7098,6 @@ react-dom@^16.9.0:
 | 
			
		|||
    prop-types "^15.6.2"
 | 
			
		||||
    scheduler "^0.19.1"
 | 
			
		||||
 | 
			
		||||
react-draggable@^4.0.3:
 | 
			
		||||
  version "4.4.2"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/react-draggable/-/react-draggable-4.4.2.tgz#f3cefecee25f467f865144cda0d066e5f05f94a0"
 | 
			
		||||
  integrity sha512-zLQs4R4bnBCGnCVTZiD8hPsHtkiJxgMpGDlRESM+EHQo8ysXhKJ2GKdJ8UxxLJdRVceX1j19jy+hQS2wHislPQ==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    classnames "^2.2.5"
 | 
			
		||||
    prop-types "^15.6.0"
 | 
			
		||||
 | 
			
		||||
react-focus-lock@^2.2.1:
 | 
			
		||||
  version "2.3.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/react-focus-lock/-/react-focus-lock-2.3.1.tgz#9d5d85899773609c7eefa4fc54fff6a0f5f2fc47"
 | 
			
		||||
| 
						 | 
				
			
			@ -7138,14 +7142,6 @@ react-redux@^5.0.6:
 | 
			
		|||
    react-is "^16.6.0"
 | 
			
		||||
    react-lifecycles-compat "^3.0.0"
 | 
			
		||||
 | 
			
		||||
react-resizable@^1.10.1:
 | 
			
		||||
  version "1.10.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/react-resizable/-/react-resizable-1.10.1.tgz#f0c2cf1d83b3470b87676ce6d6b02bbe3f4d8cd4"
 | 
			
		||||
  integrity sha512-Jd/bKOKx6+19NwC4/aMLRu/J9/krfxlDnElP41Oc+oLiUWs/zwV1S9yBfBZRnqAwQb6vQ/HRSk3bsSWGSgVbpw==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    prop-types "15.x"
 | 
			
		||||
    react-draggable "^4.0.3"
 | 
			
		||||
 | 
			
		||||
react-test-renderer@^16.0.0-0, react-test-renderer@^16.9.0:
 | 
			
		||||
  version "16.13.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.13.1.tgz#de25ea358d9012606de51e012d9742e7f0deabc1"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue