mirror of https://github.com/vector-im/riot-web
Move keyboard focus management back to the BaseDialog rather than
leaving it in the Modal manager. We are using Modal manager to load other components not just BaseDialog and its subclasses and they might require different keyboard handling. Also depend on focus-trap-react rather than react-focus-trap for locking keyboard focus inside the dialog. The experience is much nicer and even the FocusTrap element it-self no longer gains the focus. On a side note using the FocusTrap element outside the dialog (on its parent) stops it from working properly.pull/21833/head
parent
5ccbcf02e2
commit
4f83f6cf25
|
@ -65,6 +65,7 @@
|
||||||
"file-saver": "^1.3.3",
|
"file-saver": "^1.3.3",
|
||||||
"filesize": "3.5.6",
|
"filesize": "3.5.6",
|
||||||
"flux": "2.1.1",
|
"flux": "2.1.1",
|
||||||
|
"focus-trap-react": "^3.0.5",
|
||||||
"fuse.js": "^2.2.0",
|
"fuse.js": "^2.2.0",
|
||||||
"glob": "^5.0.14",
|
"glob": "^5.0.14",
|
||||||
"highlight.js": "^8.9.1",
|
"highlight.js": "^8.9.1",
|
||||||
|
@ -78,7 +79,6 @@
|
||||||
"react": "^15.4.0",
|
"react": "^15.4.0",
|
||||||
"react-addons-css-transition-group": "15.3.2",
|
"react-addons-css-transition-group": "15.3.2",
|
||||||
"react-dom": "^15.4.0",
|
"react-dom": "^15.4.0",
|
||||||
"react-focus-trap": "^2.5.0",
|
|
||||||
"react-gemini-scrollbar": "matrix-org/react-gemini-scrollbar#5e97aef",
|
"react-gemini-scrollbar": "matrix-org/react-gemini-scrollbar#5e97aef",
|
||||||
"sanitize-html": "^1.14.1",
|
"sanitize-html": "^1.14.1",
|
||||||
"text-encoding-utf-8": "^1.0.1",
|
"text-encoding-utf-8": "^1.0.1",
|
||||||
|
|
|
@ -19,7 +19,6 @@ limitations under the License.
|
||||||
|
|
||||||
const React = require('react');
|
const React = require('react');
|
||||||
const ReactDOM = require('react-dom');
|
const ReactDOM = require('react-dom');
|
||||||
import FocusTrap from 'react-focus-trap';
|
|
||||||
import Analytics from './Analytics';
|
import Analytics from './Analytics';
|
||||||
import sdk from './index';
|
import sdk from './index';
|
||||||
|
|
||||||
|
@ -165,7 +164,6 @@ class ModalManager {
|
||||||
);
|
);
|
||||||
modal.onFinished = props ? props.onFinished : null;
|
modal.onFinished = props ? props.onFinished : null;
|
||||||
modal.className = className;
|
modal.className = className;
|
||||||
modal.closeDialog = closeDialog;
|
|
||||||
|
|
||||||
this._modals.unshift(modal);
|
this._modals.unshift(modal);
|
||||||
|
|
||||||
|
@ -196,9 +194,9 @@ class ModalManager {
|
||||||
const modal = this._modals[0];
|
const modal = this._modals[0];
|
||||||
const dialog = (
|
const dialog = (
|
||||||
<div className={"mx_Dialog_wrapper " + (modal.className ? modal.className : '')}>
|
<div className={"mx_Dialog_wrapper " + (modal.className ? modal.className : '')}>
|
||||||
<FocusTrap className="mx_Dialog" onExit={modal.closeDialog}>
|
<div className="mx_Dialog">
|
||||||
{ modal.elem }
|
{ modal.elem }
|
||||||
</FocusTrap>
|
</div>
|
||||||
<div className="mx_Dialog_background" onClick={this.closeAll}></div>
|
<div className="mx_Dialog_background" onClick={this.closeAll}></div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import FocusTrap from 'focus-trap-react';
|
||||||
|
|
||||||
import * as KeyCode from '../../../KeyCode';
|
import * as KeyCode from '../../../KeyCode';
|
||||||
import AccessibleButton from '../elements/AccessibleButton';
|
import AccessibleButton from '../elements/AccessibleButton';
|
||||||
|
@ -61,6 +62,14 @@ export default React.createClass({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_onKeyDown: function(e) {
|
||||||
|
if (e.keyCode === KeyCode.ESCAPE) {
|
||||||
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
this.props.onFinished();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
_onCancelClick: function(e) {
|
_onCancelClick: function(e) {
|
||||||
this.props.onFinished();
|
this.props.onFinished();
|
||||||
},
|
},
|
||||||
|
@ -69,7 +78,7 @@ export default React.createClass({
|
||||||
const TintableSvg = sdk.getComponent("elements.TintableSvg");
|
const TintableSvg = sdk.getComponent("elements.TintableSvg");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={this.props.className} role="dialog" aria-labelledby='mx_BaseDialog_title' aria-describedby={this.props.contentId}>
|
<FocusTrap onKeyDown={this._onKeyDown} className={this.props.className} role="dialog" aria-labelledby='mx_BaseDialog_title' aria-describedby={this.props.contentId}>
|
||||||
<AccessibleButton onClick={this._onCancelClick}
|
<AccessibleButton onClick={this._onCancelClick}
|
||||||
className="mx_Dialog_cancelButton"
|
className="mx_Dialog_cancelButton"
|
||||||
>
|
>
|
||||||
|
@ -79,7 +88,7 @@ export default React.createClass({
|
||||||
{ this.props.title }
|
{ this.props.title }
|
||||||
</div>
|
</div>
|
||||||
{ this.props.children }
|
{ this.props.children }
|
||||||
</div>
|
</FocusTrap>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue