Fix widget resizing

There was a line of CSS that set pointer-events: none on widget
iframes whilst they were being resized to stop iframes swallowing
the mousemove/up events while dragging the resize handle, but a)
all widgets are now in a persisted element wrapper and therefore
not in the right place in the DOM to get that CSS and b) that only
got set when resizing the whole aps drawer vertically, not dragging
the handle between apps to change the width distribution.

Add a pointer events prop to AppTile to allow the pointer-events
style to be set by the parent, and set it when dragging either
resize handle.

Fixes https://github.com/vector-im/element-web/issues/16473
This commit is contained in:
David Baker 2021-03-05 17:52:51 +00:00
parent 06ad9f0fb8
commit e5b03488d8
3 changed files with 23 additions and 10 deletions

View file

@ -370,11 +370,6 @@ $MinWidth: 240px;
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;
}

View file

@ -328,6 +328,10 @@ export default class AppTile extends React.Component {
const iframeFeatures = "microphone; camera; encrypted-media; autoplay; display-capture;";
const appTileBodyClass = 'mx_AppTileBody' + (this.props.miniMode ? '_mini ' : ' ');
const appTileBodyStyles = {};
if (this.props.pointerEvents) {
appTileBodyStyles['pointer-events'] = this.props.pointerEvents;
}
const loadingElement = (
<div className="mx_AppLoading_spinner_fadeIn">
@ -338,7 +342,7 @@ export default class AppTile extends React.Component {
// only possible for room widgets, can assert this.props.room here
const isEncrypted = MatrixClientPeg.get().isRoomEncrypted(this.props.room.roomId);
appTileBody = (
<div className={appTileBodyClass}>
<div className={appTileBodyClass} style={appTileBodyStyles}>
<AppPermission
roomId={this.props.room.roomId}
creatorUserId={this.props.creatorUserId}
@ -350,20 +354,20 @@ export default class AppTile extends React.Component {
);
} else if (this.state.initialising) {
appTileBody = (
<div className={appTileBodyClass + (this.state.loading ? 'mx_AppLoading' : '')}>
<div className={appTileBodyClass + (this.state.loading ? 'mx_AppLoading' : '')} style={appTileBodyStyles}>
{ loadingElement }
</div>
);
} else {
if (this.isMixedContent()) {
appTileBody = (
<div className={appTileBodyClass}>
<div className={appTileBodyClass} style={appTileBodyStyles}>
<AppWarning errorMsg="Error - Mixed content" />
</div>
);
} else {
appTileBody = (
<div className={appTileBodyClass + (this.state.loading ? 'mx_AppLoading' : '')}>
<div className={appTileBodyClass + (this.state.loading ? 'mx_AppLoading' : '')} style={appTileBodyStyles}>
{ this.state.loading && loadingElement }
<iframe
allow={iframeFeatures}
@ -477,6 +481,8 @@ AppTile.propTypes = {
showPopout: PropTypes.bool,
// Is this an instance of a user widget
userWidget: PropTypes.bool,
// sets the pointer-events property on the iframe
pointerEvents: PropTypes.string,
};
AppTile.defaultProps = {

View file

@ -53,6 +53,8 @@ export default class AppsDrawer extends React.Component {
this.state = {
apps: this._getApps(),
resizingVertical: false, // true when changing the height of the apps drawer
resizingHorizontal: false, // true when chagning the distribution of the width between widgets
};
this._resizeContainer = null;
@ -85,13 +87,16 @@ export default class AppsDrawer extends React.Component {
}
onIsResizing = (resizing) => {
this.setState({ resizing });
// This one is the vertical, ie. change height of apps drawer
this.setState({ resizingVertical: resizing });
if (!resizing) {
this._relaxResizer();
}
};
_createResizer() {
// This is the horizontal one, changing the distribution of the width between the app tiles
// (ie. a vertical resize handle because, the handle itself is vertical...)
const classNames = {
handle: "mx_ResizeHandle",
vertical: "mx_ResizeHandle_vertical",
@ -100,6 +105,7 @@ export default class AppsDrawer extends React.Component {
const collapseConfig = {
onResizeStart: () => {
this._resizeContainer.classList.add("mx_AppsDrawer_resizing");
this.setState({ resizingHorizontal: true });
},
onResizeStop: () => {
this._resizeContainer.classList.remove("mx_AppsDrawer_resizing");
@ -107,6 +113,7 @@ export default class AppsDrawer extends React.Component {
this.props.room, Container.Top,
this.state.apps.slice(1).map((_, i) => this.resizer.forHandleAt(i).size),
);
this.setState({ resizingHorizontal: false });
},
};
// pass a truthy container for now, we won't call attach until we update it
@ -162,6 +169,10 @@ export default class AppsDrawer extends React.Component {
}
};
isResizing() {
return this.state.resizingVertical || this.state.resizingHorizontal;
}
onAction = (action) => {
const hideWidgetKey = this.props.room.roomId + '_hide_widget_drawer';
switch (action.action) {
@ -209,6 +220,7 @@ export default class AppsDrawer extends React.Component {
creatorUserId={app.creatorUserId}
widgetPageTitle={WidgetUtils.getWidgetDataTitle(app)}
waitForIframeLoad={app.waitForIframeLoad}
pointerEvents={this.isResizing() ? 'none' : undefined}
/>);
});