You've already forked matrix-react-sdk
							
							
				mirror of
				https://github.com/matrix-org/matrix-react-sdk.git
				synced 2025-11-04 11:51:45 +03:00 
			
		
		
		
	Merge pull request #5138 from matrix-org/t3chguy/dpsah/6785
Allow persistent resizing of the widget app drawer
This commit is contained in:
		@@ -15,18 +15,39 @@ See the License for the specific language governing permissions and
 | 
				
			|||||||
limitations under the License.
 | 
					limitations under the License.
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					$MiniAppTileHeight: 114px;
 | 
				
			||||||
the tile title bar is 5 (top border) + 12 (title, buttons) + 5 (bottom padding) px = 22px
 | 
					 | 
				
			||||||
the body is assumed to be 300px (assumed by at least the sticker pickerm, perhaps elsewhere),
 | 
					 | 
				
			||||||
so the body height would be 300px - 22px (room for title bar) = 278px
 | 
					 | 
				
			||||||
BUT! the sticker picker also assumes it's a little less high than that because the iframe
 | 
					 | 
				
			||||||
for the sticker picker doesn't have any padding or margin on it's bottom.
 | 
					 | 
				
			||||||
so subtracking another 5px, which brings us at 273px.
 | 
					 | 
				
			||||||
*/
 | 
					 | 
				
			||||||
$AppsDrawerBodyHeight: 273px;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
.mx_AppsDrawer {
 | 
					.mx_AppsDrawer {
 | 
				
			||||||
    margin: 5px;
 | 
					    margin: 5px 5px 5px 18px;
 | 
				
			||||||
 | 
					    position: relative;
 | 
				
			||||||
 | 
					    display: flex;
 | 
				
			||||||
 | 
					    flex-direction: column;
 | 
				
			||||||
 | 
					    overflow: hidden;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .mx_AppsContainer_resizerHandle {
 | 
				
			||||||
 | 
					        cursor: ns-resize;
 | 
				
			||||||
 | 
					        border-radius: 3px;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Override styles from library
 | 
				
			||||||
 | 
					        width: unset !important;
 | 
				
			||||||
 | 
					        height: 4px !important;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // This is positioned directly below frame
 | 
				
			||||||
 | 
					        position: absolute;
 | 
				
			||||||
 | 
					        bottom: -8px !important; // override from library
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Together, these make the bar 64px wide
 | 
				
			||||||
 | 
					        // These are also overridden from the library
 | 
				
			||||||
 | 
					        left: calc(50% - 32px) !important;
 | 
				
			||||||
 | 
					        right: calc(50% - 32px) !important;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    &:hover {
 | 
				
			||||||
 | 
					        .mx_AppsContainer_resizerHandle {
 | 
				
			||||||
 | 
					            opacity: 0.8;
 | 
				
			||||||
 | 
					            background: $primary-fg-color;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.mx_AppsDrawer_hidden {
 | 
					.mx_AppsDrawer_hidden {
 | 
				
			||||||
@@ -36,15 +57,23 @@ $AppsDrawerBodyHeight: 273px;
 | 
				
			|||||||
.mx_AppsContainer {
 | 
					.mx_AppsContainer {
 | 
				
			||||||
    display: flex;
 | 
					    display: flex;
 | 
				
			||||||
    flex-direction: row;
 | 
					    flex-direction: row;
 | 
				
			||||||
    align-items: center;
 | 
					    align-items: stretch;
 | 
				
			||||||
    justify-content: center;
 | 
					    justify-content: center;
 | 
				
			||||||
 | 
					    height: 100%;
 | 
				
			||||||
 | 
					    margin-bottom: 8px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.mx_AppsDrawer_minimised .mx_AppsContainer {
 | 
				
			||||||
 | 
					    // override the re-resizable inline styles
 | 
				
			||||||
 | 
					    height: inherit !important;
 | 
				
			||||||
 | 
					    min-height: inherit !important;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.mx_AddWidget_button {
 | 
					.mx_AddWidget_button {
 | 
				
			||||||
    order: 2;
 | 
					    order: 2;
 | 
				
			||||||
    cursor: pointer;
 | 
					    cursor: pointer;
 | 
				
			||||||
    padding: 0;
 | 
					    padding: 0;
 | 
				
			||||||
    margin: 5px auto 5px auto;
 | 
					    margin: -3px auto 5px 0;
 | 
				
			||||||
    color: $accent-color;
 | 
					    color: $accent-color;
 | 
				
			||||||
    font-size: $font-12px;
 | 
					    font-size: $font-12px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -65,40 +94,52 @@ $AppsDrawerBodyHeight: 273px;
 | 
				
			|||||||
.mx_AppTile {
 | 
					.mx_AppTile {
 | 
				
			||||||
    max-width: 960px;
 | 
					    max-width: 960px;
 | 
				
			||||||
    width: 50%;
 | 
					    width: 50%;
 | 
				
			||||||
    margin-right: 5px;
 | 
					 | 
				
			||||||
    border: 5px solid $widget-menu-bar-bg-color;
 | 
					    border: 5px solid $widget-menu-bar-bg-color;
 | 
				
			||||||
    border-radius: 4px;
 | 
					    border-radius: 4px;
 | 
				
			||||||
}
 | 
					    display: flex;
 | 
				
			||||||
 | 
					    flex-direction: column;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.mx_AppTile:last-child {
 | 
					    & + .mx_AppTile {
 | 
				
			||||||
    margin-right: 1px;
 | 
					        margin-left: 5px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.mx_AppTileFullWidth {
 | 
					.mx_AppTileFullWidth {
 | 
				
			||||||
    max-width: 960px;
 | 
					    max-width: 960px;
 | 
				
			||||||
    width: 100%;
 | 
					    width: 100%;
 | 
				
			||||||
    height: 100%;
 | 
					 | 
				
			||||||
    margin: 0;
 | 
					    margin: 0;
 | 
				
			||||||
    padding: 0;
 | 
					    padding: 0;
 | 
				
			||||||
    border: 5px solid $widget-menu-bar-bg-color;
 | 
					    border: 5px solid $widget-menu-bar-bg-color;
 | 
				
			||||||
    border-radius: 8px;
 | 
					    border-radius: 8px;
 | 
				
			||||||
 | 
					    display: flex;
 | 
				
			||||||
 | 
					    flex-direction: column;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.mx_AppTile_mini {
 | 
					.mx_AppTile_mini {
 | 
				
			||||||
    max-width: 960px;
 | 
					    max-width: 960px;
 | 
				
			||||||
    width: 100%;
 | 
					    width: 100%;
 | 
				
			||||||
    height: 100%;
 | 
					 | 
				
			||||||
    margin: 0;
 | 
					    margin: 0;
 | 
				
			||||||
    padding: 0;
 | 
					    padding: 0;
 | 
				
			||||||
 | 
					    display: flex;
 | 
				
			||||||
 | 
					    flex-direction: column;
 | 
				
			||||||
 | 
					    height: $MiniAppTileHeight;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.mx_AppTile_persistedWrapper {
 | 
					.mx_AppTile.mx_AppTile_minimised,
 | 
				
			||||||
    height: $AppsDrawerBodyHeight;
 | 
					.mx_AppTileFullWidth.mx_AppTile_minimised,
 | 
				
			||||||
 | 
					.mx_AppTile_mini.mx_AppTile_minimised {
 | 
				
			||||||
 | 
					    height: 14px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.mx_AppTile .mx_AppTile_persistedWrapper,
 | 
				
			||||||
 | 
					.mx_AppTileFullWidth .mx_AppTile_persistedWrapper,
 | 
				
			||||||
.mx_AppTile_mini .mx_AppTile_persistedWrapper {
 | 
					.mx_AppTile_mini .mx_AppTile_persistedWrapper {
 | 
				
			||||||
    height: 114px;
 | 
					    flex: 1;
 | 
				
			||||||
    min-width: 300px;
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.mx_AppTile_persistedWrapper div {
 | 
				
			||||||
 | 
					    width: 100%;
 | 
				
			||||||
 | 
					    height: 100%;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.mx_AppTileMenuBar {
 | 
					.mx_AppTileMenuBar {
 | 
				
			||||||
@@ -110,6 +151,7 @@ $AppsDrawerBodyHeight: 273px;
 | 
				
			|||||||
    align-items: center;
 | 
					    align-items: center;
 | 
				
			||||||
    justify-content: space-between;
 | 
					    justify-content: space-between;
 | 
				
			||||||
    cursor: pointer;
 | 
					    cursor: pointer;
 | 
				
			||||||
 | 
					    width: 100%;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.mx_AppTileMenuBar_expanded {
 | 
					.mx_AppTileMenuBar_expanded {
 | 
				
			||||||
@@ -172,7 +214,7 @@ $AppsDrawerBodyHeight: 273px;
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.mx_AppTileBody {
 | 
					.mx_AppTileBody {
 | 
				
			||||||
    height: $AppsDrawerBodyHeight;
 | 
					    height: 100%;
 | 
				
			||||||
    width: 100%;
 | 
					    width: 100%;
 | 
				
			||||||
    overflow: hidden;
 | 
					    overflow: hidden;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -183,6 +225,13 @@ $AppsDrawerBodyHeight: 273px;
 | 
				
			|||||||
    overflow: hidden;
 | 
					    overflow: hidden;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.mx_AppTile .mx_AppTileBody,
 | 
				
			||||||
 | 
					.mx_AppTileFullWidth .mx_AppTileBody,
 | 
				
			||||||
 | 
					.mx_AppTile_mini .mx_AppTileBody_mini {
 | 
				
			||||||
 | 
					    height: inherit;
 | 
				
			||||||
 | 
					    flex: 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.mx_AppTileBody_mini iframe {
 | 
					.mx_AppTileBody_mini iframe {
 | 
				
			||||||
    border: none;
 | 
					    border: none;
 | 
				
			||||||
    width: 100%;
 | 
					    width: 100%;
 | 
				
			||||||
@@ -191,7 +240,7 @@ $AppsDrawerBodyHeight: 273px;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
.mx_AppTileBody iframe {
 | 
					.mx_AppTileBody iframe {
 | 
				
			||||||
    width: 100%;
 | 
					    width: 100%;
 | 
				
			||||||
    height: $AppsDrawerBodyHeight;
 | 
					    height: 100%;
 | 
				
			||||||
    overflow: hidden;
 | 
					    overflow: hidden;
 | 
				
			||||||
    border: none;
 | 
					    border: none;
 | 
				
			||||||
    padding: 0;
 | 
					    padding: 0;
 | 
				
			||||||
@@ -331,7 +380,7 @@ form.mx_Custom_Widget_Form div {
 | 
				
			|||||||
    align-items: center;
 | 
					    align-items: center;
 | 
				
			||||||
    font-weight: bold;
 | 
					    font-weight: bold;
 | 
				
			||||||
    position: relative;
 | 
					    position: relative;
 | 
				
			||||||
    height: $AppsDrawerBodyHeight;
 | 
					    height: 100%;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.mx_AppLoading .mx_Spinner {
 | 
					.mx_AppLoading .mx_Spinner {
 | 
				
			||||||
@@ -358,3 +407,16 @@ form.mx_Custom_Widget_Form div {
 | 
				
			|||||||
.mx_AppLoading iframe {
 | 
					.mx_AppLoading iframe {
 | 
				
			||||||
    display: none;
 | 
					    display: none;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.mx_AppsDrawer_minimised .mx_AppsContainer_resizerHandle {
 | 
				
			||||||
 | 
					    display: none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Avoid apptile iframes capturing mouse event focus when resizing */
 | 
				
			||||||
 | 
					.mx_AppsDrawer_resizing iframe {
 | 
				
			||||||
 | 
					    pointer-events: none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.mx_AppsDrawer_resizing .mx_AppTile_persistedWrapper {
 | 
				
			||||||
 | 
					    z-index: 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -36,6 +36,10 @@ limitations under the License.
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .mx_AppTile_persistedWrapper div {
 | 
				
			||||||
 | 
					        min-width: 300px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .mx_IncomingCallBox {
 | 
					    .mx_IncomingCallBox {
 | 
				
			||||||
        min-width: 250px;
 | 
					        min-width: 250px;
 | 
				
			||||||
        background-color: $primary-bg-color;
 | 
					        background-color: $primary-bg-color;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1322,7 +1322,7 @@ export default class GroupView extends React.Component {
 | 
				
			|||||||
                        </div>
 | 
					                        </div>
 | 
				
			||||||
                        <GroupHeaderButtons />
 | 
					                        <GroupHeaderButtons />
 | 
				
			||||||
                    </div>
 | 
					                    </div>
 | 
				
			||||||
                    <MainSplit panel={rightPanel}>
 | 
					                    <MainSplit panel={rightPanel} resizeNotifier={this.props.resizeNotifier}>
 | 
				
			||||||
                        <AutoHideScrollbar className="mx_GroupView_body">
 | 
					                        <AutoHideScrollbar className="mx_GroupView_body">
 | 
				
			||||||
                            { this._getMembershipSection() }
 | 
					                            { this._getMembershipSection() }
 | 
				
			||||||
                            { this._getGroupSection() }
 | 
					                            { this._getGroupSection() }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -257,6 +257,12 @@ class LoggedInView extends React.Component<IProps, IState> {
 | 
				
			|||||||
                window.localStorage.setItem("mx_lhs_size", '' + size);
 | 
					                window.localStorage.setItem("mx_lhs_size", '' + size);
 | 
				
			||||||
                this.props.resizeNotifier.notifyLeftHandleResized();
 | 
					                this.props.resizeNotifier.notifyLeftHandleResized();
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
 | 
					            onResizeStart: () => {
 | 
				
			||||||
 | 
					                this.props.resizeNotifier.startResizing();
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            onResizeStop: () => {
 | 
				
			||||||
 | 
					                this.props.resizeNotifier.stopResizing();
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        const resizer = new Resizer(
 | 
					        const resizer = new Resizer(
 | 
				
			||||||
            this._resizeContainer.current,
 | 
					            this._resizeContainer.current,
 | 
				
			||||||
@@ -650,12 +656,13 @@ class LoggedInView extends React.Component<IProps, IState> {
 | 
				
			|||||||
                break;
 | 
					                break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            case PageTypes.UserView:
 | 
					            case PageTypes.UserView:
 | 
				
			||||||
                pageElement = <UserView userId={this.props.currentUserId} />;
 | 
					                pageElement = <UserView userId={this.props.currentUserId} resizeNotifier={this.props.resizeNotifier} />;
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            case PageTypes.GroupView:
 | 
					            case PageTypes.GroupView:
 | 
				
			||||||
                pageElement = <GroupView
 | 
					                pageElement = <GroupView
 | 
				
			||||||
                    groupId={this.props.currentGroupId}
 | 
					                    groupId={this.props.currentGroupId}
 | 
				
			||||||
                    isNew={this.props.currentGroupIsNew}
 | 
					                    isNew={this.props.currentGroupIsNew}
 | 
				
			||||||
 | 
					                    resizeNotifier={this.props.resizeNotifier}
 | 
				
			||||||
                />;
 | 
					                />;
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,9 +19,18 @@ import React from 'react';
 | 
				
			|||||||
import { Resizable } from 're-resizable';
 | 
					import { Resizable } from 're-resizable';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default class MainSplit extends React.Component {
 | 
					export default class MainSplit extends React.Component {
 | 
				
			||||||
    _onResized = (event, direction, refToElement, delta) => {
 | 
					    _onResizeStart = () => {
 | 
				
			||||||
 | 
					        this.props.resizeNotifier.startResizing();
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _onResize = () => {
 | 
				
			||||||
 | 
					        this.props.resizeNotifier.notifyRightHandleResized();
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _onResizeStop = (event, direction, refToElement, delta) => {
 | 
				
			||||||
 | 
					        this.props.resizeNotifier.stopResizing();
 | 
				
			||||||
        window.localStorage.setItem("mx_rhs_size", this._loadSidePanelSize().width + delta.width);
 | 
					        window.localStorage.setItem("mx_rhs_size", this._loadSidePanelSize().width + delta.width);
 | 
				
			||||||
    }
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _loadSidePanelSize() {
 | 
					    _loadSidePanelSize() {
 | 
				
			||||||
        let rhsSize = parseInt(window.localStorage.getItem("mx_rhs_size"), 10);
 | 
					        let rhsSize = parseInt(window.localStorage.getItem("mx_rhs_size"), 10);
 | 
				
			||||||
@@ -58,7 +67,9 @@ export default class MainSplit extends React.Component {
 | 
				
			|||||||
                    bottomLeft: false,
 | 
					                    bottomLeft: false,
 | 
				
			||||||
                    topLeft: false,
 | 
					                    topLeft: false,
 | 
				
			||||||
                }}
 | 
					                }}
 | 
				
			||||||
                onResizeStop={this._onResized}
 | 
					                onResizeStart={this._onResizeStart}
 | 
				
			||||||
 | 
					                onResize={this._onResize}
 | 
				
			||||||
 | 
					                onResizeStop={this._onResizeStop}
 | 
				
			||||||
                className="mx_RightPanel_ResizeWrapper"
 | 
					                className="mx_RightPanel_ResizeWrapper"
 | 
				
			||||||
                handleClasses={{left: "mx_RightPanel_ResizeHandle"}}
 | 
					                handleClasses={{left: "mx_RightPanel_ResizeHandle"}}
 | 
				
			||||||
            >
 | 
					            >
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1545,9 +1545,9 @@ export default class RoomView extends React.Component {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        // header + footer + status + give us at least 120px of scrollback at all times.
 | 
					        // header + footer + status + give us at least 120px of scrollback at all times.
 | 
				
			||||||
        let auxPanelMaxHeight = window.innerHeight -
 | 
					        let auxPanelMaxHeight = window.innerHeight -
 | 
				
			||||||
                (83 + // height of RoomHeader
 | 
					                (54 + // height of RoomHeader
 | 
				
			||||||
                 36 + // height of the status area
 | 
					                 36 + // height of the status area
 | 
				
			||||||
                 72 + // minimum height of the message compmoser
 | 
					                 51 + // minimum height of the message compmoser
 | 
				
			||||||
                 120); // amount of desired scrollback
 | 
					                 120); // amount of desired scrollback
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // XXX: this is a bit of a hack and might possibly cause the video to push out the page anyway
 | 
					        // XXX: this is a bit of a hack and might possibly cause the video to push out the page anyway
 | 
				
			||||||
@@ -1884,7 +1884,8 @@ export default class RoomView extends React.Component {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const auxPanel = (
 | 
					        const auxPanel = (
 | 
				
			||||||
            <AuxPanel room={this.state.room}
 | 
					            <AuxPanel
 | 
				
			||||||
 | 
					                room={this.state.room}
 | 
				
			||||||
                fullHeight={false}
 | 
					                fullHeight={false}
 | 
				
			||||||
                userId={this.context.credentials.userId}
 | 
					                userId={this.context.credentials.userId}
 | 
				
			||||||
                conferenceHandler={this.props.ConferenceHandler}
 | 
					                conferenceHandler={this.props.ConferenceHandler}
 | 
				
			||||||
@@ -1892,7 +1893,10 @@ export default class RoomView extends React.Component {
 | 
				
			|||||||
                displayConfCallNotification={this.state.displayConfCallNotification}
 | 
					                displayConfCallNotification={this.state.displayConfCallNotification}
 | 
				
			||||||
                maxHeight={this.state.auxPanelMaxHeight}
 | 
					                maxHeight={this.state.auxPanelMaxHeight}
 | 
				
			||||||
                showApps={this.state.showApps}
 | 
					                showApps={this.state.showApps}
 | 
				
			||||||
              hideAppsDrawer={false} >
 | 
					                hideAppsDrawer={false}
 | 
				
			||||||
 | 
					                onResize={this.onResize}
 | 
				
			||||||
 | 
					                resizeNotifier={this.props.resizeNotifier}
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
                { aux }
 | 
					                { aux }
 | 
				
			||||||
            </AuxPanel>
 | 
					            </AuxPanel>
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
@@ -2090,10 +2094,7 @@ export default class RoomView extends React.Component {
 | 
				
			|||||||
                            onLeaveClick={(myMembership === "join") ? this.onLeaveClick : null}
 | 
					                            onLeaveClick={(myMembership === "join") ? this.onLeaveClick : null}
 | 
				
			||||||
                            e2eStatus={this.state.e2eStatus}
 | 
					                            e2eStatus={this.state.e2eStatus}
 | 
				
			||||||
                        />
 | 
					                        />
 | 
				
			||||||
                        <MainSplit
 | 
					                        <MainSplit panel={rightPanel} resizeNotifier={this.props.resizeNotifier}>
 | 
				
			||||||
                            panel={rightPanel}
 | 
					 | 
				
			||||||
                            resizeNotifier={this.props.resizeNotifier}
 | 
					 | 
				
			||||||
                        >
 | 
					 | 
				
			||||||
                            <div className={fadableSectionClasses}>
 | 
					                            <div className={fadableSectionClasses}>
 | 
				
			||||||
                                {auxPanel}
 | 
					                                {auxPanel}
 | 
				
			||||||
                                <div className={timelineClasses}>
 | 
					                                <div className={timelineClasses}>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -163,7 +163,7 @@ export default class ScrollPanel extends React.Component {
 | 
				
			|||||||
        this._pendingFillRequests = {b: null, f: null};
 | 
					        this._pendingFillRequests = {b: null, f: null};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (this.props.resizeNotifier) {
 | 
					        if (this.props.resizeNotifier) {
 | 
				
			||||||
            this.props.resizeNotifier.on("middlePanelResized", this.onResize);
 | 
					            this.props.resizeNotifier.on("middlePanelResizedNoisy", this.onResize);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.resetScrollState();
 | 
					        this.resetScrollState();
 | 
				
			||||||
@@ -193,11 +193,12 @@ export default class ScrollPanel extends React.Component {
 | 
				
			|||||||
        this.unmounted = true;
 | 
					        this.unmounted = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (this.props.resizeNotifier) {
 | 
					        if (this.props.resizeNotifier) {
 | 
				
			||||||
            this.props.resizeNotifier.removeListener("middlePanelResized", this.onResize);
 | 
					            this.props.resizeNotifier.removeListener("middlePanelResizedNoisy", this.onResize);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    onScroll = ev => {
 | 
					    onScroll = ev => {
 | 
				
			||||||
 | 
					        if (this.props.resizeNotifier.isResizing) return; // skip scroll events caused by resizing
 | 
				
			||||||
        debuglog("onScroll", this._getScrollNode().scrollTop);
 | 
					        debuglog("onScroll", this._getScrollNode().scrollTop);
 | 
				
			||||||
        this._scrollTimeout.restart();
 | 
					        this._scrollTimeout.restart();
 | 
				
			||||||
        this._saveScrollState();
 | 
					        this._saveScrollState();
 | 
				
			||||||
@@ -207,6 +208,7 @@ export default class ScrollPanel extends React.Component {
 | 
				
			|||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    onResize = () => {
 | 
					    onResize = () => {
 | 
				
			||||||
 | 
					        debuglog("onResize");
 | 
				
			||||||
        this.checkScroll();
 | 
					        this.checkScroll();
 | 
				
			||||||
        // update preventShrinkingState if present
 | 
					        // update preventShrinkingState if present
 | 
				
			||||||
        if (this.preventShrinkingState) {
 | 
					        if (this.preventShrinkingState) {
 | 
				
			||||||
@@ -236,7 +238,6 @@ export default class ScrollPanel extends React.Component {
 | 
				
			|||||||
        // when scrolled all the way down. E.g. Chrome 72 on debian.
 | 
					        // when scrolled all the way down. E.g. Chrome 72 on debian.
 | 
				
			||||||
        // so check difference <= 1;
 | 
					        // so check difference <= 1;
 | 
				
			||||||
        return Math.abs(sn.scrollHeight - (sn.scrollTop + sn.clientHeight)) <= 1;
 | 
					        return Math.abs(sn.scrollHeight - (sn.scrollTop + sn.clientHeight)) <= 1;
 | 
				
			||||||
 | 
					 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // returns the vertical height in the given direction that can be removed from
 | 
					    // returns the vertical height in the given direction that can be removed from
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -80,7 +80,9 @@ export default class UserView extends React.Component {
 | 
				
			|||||||
            const RightPanel = sdk.getComponent('structures.RightPanel');
 | 
					            const RightPanel = sdk.getComponent('structures.RightPanel');
 | 
				
			||||||
            const MainSplit = sdk.getComponent('structures.MainSplit');
 | 
					            const MainSplit = sdk.getComponent('structures.MainSplit');
 | 
				
			||||||
            const panel = <RightPanel user={this.state.member} />;
 | 
					            const panel = <RightPanel user={this.state.member} />;
 | 
				
			||||||
            return (<MainSplit panel={panel}><HomePage /></MainSplit>);
 | 
					            return (<MainSplit panel={panel} resizeNotifier={this.props.resizeNotifier}>
 | 
				
			||||||
 | 
					                <HomePage />
 | 
				
			||||||
 | 
					            </MainSplit>);
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            return (<div />);
 | 
					            return (<div />);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -804,14 +804,16 @@ export default class AppTile extends React.Component {
 | 
				
			|||||||
        const showMinimiseButton = this.props.showMinimise && this.props.show;
 | 
					        const showMinimiseButton = this.props.showMinimise && this.props.show;
 | 
				
			||||||
        const showMaximiseButton = this.props.showMinimise && !this.props.show;
 | 
					        const showMaximiseButton = this.props.showMinimise && !this.props.show;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let appTileClass;
 | 
					        let appTileClasses;
 | 
				
			||||||
        if (this.props.miniMode) {
 | 
					        if (this.props.miniMode) {
 | 
				
			||||||
            appTileClass = 'mx_AppTile_mini';
 | 
					            appTileClasses = {mx_AppTile_mini: true};
 | 
				
			||||||
        } else if (this.props.fullWidth) {
 | 
					        } else if (this.props.fullWidth) {
 | 
				
			||||||
            appTileClass = 'mx_AppTileFullWidth';
 | 
					            appTileClasses = {mx_AppTileFullWidth: true};
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            appTileClass = 'mx_AppTile';
 | 
					            appTileClasses = {mx_AppTile: true};
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        appTileClasses.mx_AppTile_minimised = !this.props.show;
 | 
				
			||||||
 | 
					        appTileClasses = classNames(appTileClasses);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const menuBarClasses = classNames({
 | 
					        const menuBarClasses = classNames({
 | 
				
			||||||
            mx_AppTileMenuBar: true,
 | 
					            mx_AppTileMenuBar: true,
 | 
				
			||||||
@@ -843,7 +845,7 @@ export default class AppTile extends React.Component {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return <React.Fragment>
 | 
					        return <React.Fragment>
 | 
				
			||||||
            <div className={appTileClass} id={this.props.app.id}>
 | 
					            <div className={appTileClasses} id={this.props.app.id}>
 | 
				
			||||||
                { this.props.showMenubar &&
 | 
					                { this.props.showMenubar &&
 | 
				
			||||||
                <div ref={this._menu_bar} className={menuBarClasses} onClick={this.onClickMenuBar}>
 | 
					                <div ref={this._menu_bar} className={menuBarClasses} onClick={this.onClickMenuBar}>
 | 
				
			||||||
                    <span className="mx_AppTileMenuBarTitle" style={{pointerEvents: (this.props.handleMinimisePointerEvents ? 'all' : false)}}>
 | 
					                    <span className="mx_AppTileMenuBarTitle" style={{pointerEvents: (this.props.handleMinimisePointerEvents ? 'all' : false)}}>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,7 +17,7 @@ limitations under the License.
 | 
				
			|||||||
import React from 'react';
 | 
					import React from 'react';
 | 
				
			||||||
import ReactDOM from 'react-dom';
 | 
					import ReactDOM from 'react-dom';
 | 
				
			||||||
import PropTypes from 'prop-types';
 | 
					import PropTypes from 'prop-types';
 | 
				
			||||||
 | 
					import {throttle} from "lodash";
 | 
				
			||||||
import ResizeObserver from 'resize-observer-polyfill';
 | 
					import ResizeObserver from 'resize-observer-polyfill';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import dis from '../../../dispatcher/dispatcher';
 | 
					import dis from '../../../dispatcher/dispatcher';
 | 
				
			||||||
@@ -156,7 +156,7 @@ export default class PersistedElement extends React.Component {
 | 
				
			|||||||
        child.style.display = visible ? 'block' : 'none';
 | 
					        child.style.display = visible ? 'block' : 'none';
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    updateChildPosition(child, parent) {
 | 
					    updateChildPosition = throttle((child, parent) => {
 | 
				
			||||||
        if (!child || !parent) return;
 | 
					        if (!child || !parent) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const parentRect = parent.getBoundingClientRect();
 | 
					        const parentRect = parent.getBoundingClientRect();
 | 
				
			||||||
@@ -167,9 +167,9 @@ export default class PersistedElement extends React.Component {
 | 
				
			|||||||
            width: parentRect.width + 'px',
 | 
					            width: parentRect.width + 'px',
 | 
				
			||||||
            height: parentRect.height + 'px',
 | 
					            height: parentRect.height + 'px',
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }, 100, {trailing: true, leading: true});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    render() {
 | 
					    render() {
 | 
				
			||||||
        return <div ref={this.collectChildContainer}></div>;
 | 
					        return <div ref={this.collectChildContainer} />;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,7 +15,7 @@ See the License for the specific language governing permissions and
 | 
				
			|||||||
limitations under the License.
 | 
					limitations under the License.
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import React from 'react';
 | 
					import React, {useState} from 'react';
 | 
				
			||||||
import PropTypes from 'prop-types';
 | 
					import PropTypes from 'prop-types';
 | 
				
			||||||
import {MatrixClientPeg} from '../../../MatrixClientPeg';
 | 
					import {MatrixClientPeg} from '../../../MatrixClientPeg';
 | 
				
			||||||
import AppTile from '../elements/AppTile';
 | 
					import AppTile from '../elements/AppTile';
 | 
				
			||||||
@@ -29,6 +29,10 @@ import WidgetEchoStore from "../../../stores/WidgetEchoStore";
 | 
				
			|||||||
import AccessibleButton from '../elements/AccessibleButton';
 | 
					import AccessibleButton from '../elements/AccessibleButton';
 | 
				
			||||||
import {IntegrationManagers} from "../../../integrations/IntegrationManagers";
 | 
					import {IntegrationManagers} from "../../../integrations/IntegrationManagers";
 | 
				
			||||||
import SettingsStore from "../../../settings/SettingsStore";
 | 
					import SettingsStore from "../../../settings/SettingsStore";
 | 
				
			||||||
 | 
					import classNames from 'classnames';
 | 
				
			||||||
 | 
					import {Resizable} from "re-resizable";
 | 
				
			||||||
 | 
					import {useLocalStorageState} from "../../../hooks/useLocalStorageState";
 | 
				
			||||||
 | 
					import ResizeNotifier from "../../../utils/ResizeNotifier";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// The maximum number of widgets that can be added in a room
 | 
					// The maximum number of widgets that can be added in a room
 | 
				
			||||||
const MAX_WIDGETS = 2;
 | 
					const MAX_WIDGETS = 2;
 | 
				
			||||||
@@ -37,6 +41,7 @@ export default class AppsDrawer extends React.Component {
 | 
				
			|||||||
    static propTypes = {
 | 
					    static propTypes = {
 | 
				
			||||||
        userId: PropTypes.string.isRequired,
 | 
					        userId: PropTypes.string.isRequired,
 | 
				
			||||||
        room: PropTypes.object.isRequired,
 | 
					        room: PropTypes.object.isRequired,
 | 
				
			||||||
 | 
					        resizeNotifier: PropTypes.instanceOf(ResizeNotifier).isRequired,
 | 
				
			||||||
        showApps: PropTypes.bool, // Should apps be rendered
 | 
					        showApps: PropTypes.bool, // Should apps be rendered
 | 
				
			||||||
        hide: PropTypes.bool, // If rendered, should apps drawer be visible
 | 
					        hide: PropTypes.bool, // If rendered, should apps drawer be visible
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
@@ -161,7 +166,7 @@ export default class AppsDrawer extends React.Component {
 | 
				
			|||||||
            return (<AppTile
 | 
					            return (<AppTile
 | 
				
			||||||
                key={app.id}
 | 
					                key={app.id}
 | 
				
			||||||
                app={app}
 | 
					                app={app}
 | 
				
			||||||
                fullWidth={arr.length<2 ? true : false}
 | 
					                fullWidth={arr.length < 2}
 | 
				
			||||||
                room={this.props.room}
 | 
					                room={this.props.room}
 | 
				
			||||||
                userId={this.props.userId}
 | 
					                userId={this.props.userId}
 | 
				
			||||||
                show={this.props.showApps}
 | 
					                show={this.props.showApps}
 | 
				
			||||||
@@ -172,8 +177,8 @@ export default class AppsDrawer extends React.Component {
 | 
				
			|||||||
            />);
 | 
					            />);
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (apps.length == 0) {
 | 
					        if (apps.length === 0) {
 | 
				
			||||||
            return <div></div>;
 | 
					            return <div />;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let addWidget;
 | 
					        let addWidget;
 | 
				
			||||||
@@ -202,14 +207,68 @@ export default class AppsDrawer extends React.Component {
 | 
				
			|||||||
            spinner = <Loader />;
 | 
					            spinner = <Loader />;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const classes = classNames({
 | 
				
			||||||
 | 
					            "mx_AppsDrawer": true,
 | 
				
			||||||
 | 
					            "mx_AppsDrawer_hidden": this.props.hide,
 | 
				
			||||||
 | 
					            "mx_AppsDrawer_fullWidth": apps.length < 2,
 | 
				
			||||||
 | 
					            "mx_AppsDrawer_minimised": !this.props.showApps,
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return (
 | 
					        return (
 | 
				
			||||||
            <div className={'mx_AppsDrawer' + (this.props.hide ? ' mx_AppsDrawer_hidden' : '')}>
 | 
					            <div className={classes}>
 | 
				
			||||||
                <div id='apps' className='mx_AppsContainer'>
 | 
					                <PersistentVResizer
 | 
				
			||||||
 | 
					                    id={"apps-drawer_" + this.props.room.roomId}
 | 
				
			||||||
 | 
					                    minHeight={100}
 | 
				
			||||||
 | 
					                    maxHeight={this.props.maxHeight ? this.props.maxHeight - 50 : undefined}
 | 
				
			||||||
 | 
					                    handleClass="mx_AppsContainer_resizerHandle"
 | 
				
			||||||
 | 
					                    className="mx_AppsContainer"
 | 
				
			||||||
 | 
					                    resizeNotifier={this.props.resizeNotifier}
 | 
				
			||||||
 | 
					                >
 | 
				
			||||||
                    { apps }
 | 
					                    { apps }
 | 
				
			||||||
                    { spinner }
 | 
					                    { spinner }
 | 
				
			||||||
                </div>
 | 
					                </PersistentVResizer>
 | 
				
			||||||
                { this._canUserModify() && addWidget }
 | 
					                { this._canUserModify() && addWidget }
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const PersistentVResizer = ({
 | 
				
			||||||
 | 
					    id,
 | 
				
			||||||
 | 
					    minHeight,
 | 
				
			||||||
 | 
					    maxHeight,
 | 
				
			||||||
 | 
					    className,
 | 
				
			||||||
 | 
					    handleWrapperClass,
 | 
				
			||||||
 | 
					    handleClass,
 | 
				
			||||||
 | 
					    resizeNotifier,
 | 
				
			||||||
 | 
					    children,
 | 
				
			||||||
 | 
					}) => {
 | 
				
			||||||
 | 
					    const [height, setHeight] = useLocalStorageState("pvr_" + id, 100);
 | 
				
			||||||
 | 
					    const [resizing, setResizing] = useState(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return <Resizable
 | 
				
			||||||
 | 
					        size={{height: Math.min(height, maxHeight)}}
 | 
				
			||||||
 | 
					        minHeight={minHeight}
 | 
				
			||||||
 | 
					        maxHeight={maxHeight}
 | 
				
			||||||
 | 
					        onResizeStart={() => {
 | 
				
			||||||
 | 
					            if (!resizing) setResizing(true);
 | 
				
			||||||
 | 
					            resizeNotifier.startResizing();
 | 
				
			||||||
 | 
					        }}
 | 
				
			||||||
 | 
					        onResize={() => {
 | 
				
			||||||
 | 
					            resizeNotifier.notifyTimelineHeightChanged();
 | 
				
			||||||
 | 
					        }}
 | 
				
			||||||
 | 
					        onResizeStop={(e, dir, ref, d) => {
 | 
				
			||||||
 | 
					            setHeight(height + d.height);
 | 
				
			||||||
 | 
					            if (resizing) setResizing(false);
 | 
				
			||||||
 | 
					            resizeNotifier.stopResizing();
 | 
				
			||||||
 | 
					        }}
 | 
				
			||||||
 | 
					        handleWrapperClass={handleWrapperClass}
 | 
				
			||||||
 | 
					        handleClasses={{bottom: handleClass}}
 | 
				
			||||||
 | 
					        className={classNames(className, {
 | 
				
			||||||
 | 
					            mx_AppsDrawer_resizing: resizing,
 | 
				
			||||||
 | 
					        })}
 | 
				
			||||||
 | 
					        enable={{bottom: true}}
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					        { children }
 | 
				
			||||||
 | 
					    </Resizable>;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -204,6 +204,7 @@ export default class AuxPanel extends React.Component {
 | 
				
			|||||||
            maxHeight={this.props.maxHeight}
 | 
					            maxHeight={this.props.maxHeight}
 | 
				
			||||||
            showApps={this.props.showApps}
 | 
					            showApps={this.props.showApps}
 | 
				
			||||||
            hide={this.props.hideAppsDrawer}
 | 
					            hide={this.props.hideAppsDrawer}
 | 
				
			||||||
 | 
					            resizeNotifier={this.props.resizeNotifier}
 | 
				
			||||||
        />;
 | 
					        />;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let stateViews = null;
 | 
					        let stateViews = null;
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										44
									
								
								src/hooks/useLocalStorageState.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								src/hooks/useLocalStorageState.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,44 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					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.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import {Dispatch, SetStateAction, useCallback, useEffect, useState} from "react";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const getValue = <T>(key: string, initialValue: T): T => {
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					        const item = window.localStorage.getItem(key);
 | 
				
			||||||
 | 
					        return item ? JSON.parse(item) : initialValue;
 | 
				
			||||||
 | 
					    } catch (error) {
 | 
				
			||||||
 | 
					        return initialValue;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Hook behaving like useState but persisting the value to localStorage. Returns same as useState
 | 
				
			||||||
 | 
					export const useLocalStorageState = <T>(key: string, initialValue: T) => {
 | 
				
			||||||
 | 
					    const lsKey = "mx_" + key;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const [value, setValue] = useState<T>(getValue(lsKey, initialValue));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    useEffect(() => {
 | 
				
			||||||
 | 
					        setValue(getValue(lsKey, initialValue));
 | 
				
			||||||
 | 
					    }, [lsKey, initialValue]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const _setValue: Dispatch<SetStateAction<T>> = useCallback((v: T) => {
 | 
				
			||||||
 | 
					        window.localStorage.setItem(lsKey, JSON.stringify(v));
 | 
				
			||||||
 | 
					        setValue(v);
 | 
				
			||||||
 | 
					    }, [lsKey]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return [value, _setValue];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@@ -105,6 +105,9 @@ export default class Resizer {
 | 
				
			|||||||
        if (this.classNames.resizing) {
 | 
					        if (this.classNames.resizing) {
 | 
				
			||||||
            this.container.classList.add(this.classNames.resizing);
 | 
					            this.container.classList.add(this.classNames.resizing);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        if (this.config.onResizeStart) {
 | 
				
			||||||
 | 
					            this.config.onResizeStart();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const {sizer, distributor} = this._createSizerAndDistributor(resizeHandle);
 | 
					        const {sizer, distributor} = this._createSizerAndDistributor(resizeHandle);
 | 
				
			||||||
        distributor.start();
 | 
					        distributor.start();
 | 
				
			||||||
@@ -119,6 +122,9 @@ export default class Resizer {
 | 
				
			|||||||
            if (this.classNames.resizing) {
 | 
					            if (this.classNames.resizing) {
 | 
				
			||||||
                this.container.classList.remove(this.classNames.resizing);
 | 
					                this.container.classList.remove(this.classNames.resizing);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            if (this.config.onResizeStop) {
 | 
				
			||||||
 | 
					                this.config.onResizeStop();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            distributor.finish();
 | 
					            distributor.finish();
 | 
				
			||||||
            body.removeEventListener("mouseup", finishResize, false);
 | 
					            body.removeEventListener("mouseup", finishResize, false);
 | 
				
			||||||
            document.removeEventListener("mouseleave", finishResize, false);
 | 
					            document.removeEventListener("mouseleave", finishResize, false);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -56,6 +56,18 @@ export default class Sizer {
 | 
				
			|||||||
        return this.vertical ? this.container.offsetTop : this.container.offsetLeft;
 | 
					        return this.vertical ? this.container.offsetTop : this.container.offsetLeft;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** @return {number} container offset to document */
 | 
				
			||||||
 | 
					    _getPageOffset() {
 | 
				
			||||||
 | 
					        let element = this.container;
 | 
				
			||||||
 | 
					        let offset = 0;
 | 
				
			||||||
 | 
					        while (element) {
 | 
				
			||||||
 | 
					            const pos = this.vertical ? element.offsetTop : element.offsetLeft;
 | 
				
			||||||
 | 
					            offset = offset + pos;
 | 
				
			||||||
 | 
					            element = element.offsetParent;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return offset;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    setItemSize(item, size) {
 | 
					    setItemSize(item, size) {
 | 
				
			||||||
        if (this.vertical) {
 | 
					        if (this.vertical) {
 | 
				
			||||||
            item.style.height = `${Math.round(size)}px`;
 | 
					            item.style.height = `${Math.round(size)}px`;
 | 
				
			||||||
@@ -80,9 +92,9 @@ export default class Sizer {
 | 
				
			|||||||
    offsetFromEvent(event) {
 | 
					    offsetFromEvent(event) {
 | 
				
			||||||
        const pos = this.vertical ? event.pageY : event.pageX;
 | 
					        const pos = this.vertical ? event.pageY : event.pageX;
 | 
				
			||||||
        if (this.reverse) {
 | 
					        if (this.reverse) {
 | 
				
			||||||
            return (this._getOffset() + this.getTotalSize()) - pos;
 | 
					            return (this._getPageOffset() + this.getTotalSize()) - pos;
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            return pos - this._getOffset();
 | 
					            return pos - this._getPageOffset();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,6 +31,19 @@ export default class ResizeNotifier extends EventEmitter {
 | 
				
			|||||||
        // with default options, will call fn once at first call, and then every x ms
 | 
					        // with default options, will call fn once at first call, and then every x ms
 | 
				
			||||||
        // if there was another call in that timespan
 | 
					        // if there was another call in that timespan
 | 
				
			||||||
        this._throttledMiddlePanel = throttle(() => this.emit("middlePanelResized"), 200);
 | 
					        this._throttledMiddlePanel = throttle(() => this.emit("middlePanelResized"), 200);
 | 
				
			||||||
 | 
					        this._isResizing = false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    get isResizing() {
 | 
				
			||||||
 | 
					        return this._isResizing;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    startResizing() {
 | 
				
			||||||
 | 
					        this._isResizing = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    stopResizing() {
 | 
				
			||||||
 | 
					        this._isResizing = false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _noisyMiddlePanel() {
 | 
					    _noisyMiddlePanel() {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user