diff --git a/src/AsyncWrapper.js b/src/AsyncWrapper.js
new file mode 100644
index 0000000000..63b856a882
--- /dev/null
+++ b/src/AsyncWrapper.js
@@ -0,0 +1,93 @@
+/*
+Copyright 2015, 2016 OpenMarket Ltd
+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 createReactClass from 'create-react-class';
+import Analytics from './Analytics';
+import * as sdk from './index';
+import PropTypes from 'prop-types';
+import { _t } from './languageHandler';
+
+/**
+ * Wrap an asynchronous loader function with a react component which shows a
+ * spinner until the real component loads.
+ */
+export default createReactClass({
+ propTypes: {
+ /** A promise which resolves with the real component
+ */
+ prom: PropTypes.object.isRequired,
+ },
+
+ getInitialState: function() {
+ return {
+ component: null,
+ error: null,
+ };
+ },
+
+ componentWillMount: function() {
+ this._unmounted = false;
+ // XXX: temporary logging to try to diagnose
+ // https://github.com/vector-im/riot-web/issues/3148
+ console.log('Starting load of AsyncWrapper for modal');
+ this.props.prom.then((result) => {
+ if (this._unmounted) {
+ return;
+ }
+ // Take the 'default' member if it's there, then we support
+ // passing in just an import()ed module, since ES6 async import
+ // always returns a module *namespace*.
+ const component = result.default ? result.default : result;
+ this.setState({component});
+ }).catch((e) => {
+ console.warn('AsyncWrapper promise failed', e);
+ this.setState({error: e});
+ });
+ },
+
+ componentWillUnmount: function() {
+ this._unmounted = true;
+ },
+
+ _onWrapperCancelClick: function() {
+ this.props.onFinished(false);
+ },
+
+ render: function() {
+ if (this.state.component) {
+ const Component = this.state.component;
+ return ;
+ } else if (this.state.error) {
+ const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
+ const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
+ return
+ {_t("Unable to load! Check your network connectivity and try again.")}
+
+ ;
+ } else {
+ // show a spinner until the component is loaded.
+ const Spinner = sdk.getComponent("elements.Spinner");
+ return ;
+ }
+ },
+});
+
diff --git a/src/Modal.js b/src/Modal.js
index 29d3af2e74..b6215b2b5a 100644
--- a/src/Modal.js
+++ b/src/Modal.js
@@ -17,87 +17,14 @@ limitations under the License.
import React from 'react';
import ReactDOM from 'react-dom';
-import PropTypes from 'prop-types';
-import createReactClass from 'create-react-class';
import Analytics from './Analytics';
-import * as sdk from './index';
import dis from './dispatcher';
-import { _t } from './languageHandler';
-import {defer} from "./utils/promise";
+import {defer} from './utils/promise';
+import AsyncWrapper from './AsyncWrapper';
const DIALOG_CONTAINER_ID = "mx_Dialog_Container";
const STATIC_DIALOG_CONTAINER_ID = "mx_Dialog_StaticContainer";
-/**
- * Wrap an asynchronous loader function with a react component which shows a
- * spinner until the real component loads.
- */
-const AsyncWrapper = createReactClass({
- propTypes: {
- /** A promise which resolves with the real component
- */
- prom: PropTypes.object.isRequired,
- },
-
- getInitialState: function() {
- return {
- component: null,
- error: null,
- };
- },
-
- componentWillMount: function() {
- this._unmounted = false;
- // XXX: temporary logging to try to diagnose
- // https://github.com/vector-im/riot-web/issues/3148
- console.log('Starting load of AsyncWrapper for modal');
- this.props.prom.then((result) => {
- if (this._unmounted) {
- return;
- }
- // Take the 'default' member if it's there, then we support
- // passing in just an import()ed module, since ES6 async import
- // always returns a module *namespace*.
- const component = result.default ? result.default : result;
- this.setState({component});
- }).catch((e) => {
- console.warn('AsyncWrapper promise failed', e);
- this.setState({error: e});
- });
- },
-
- componentWillUnmount: function() {
- this._unmounted = true;
- },
-
- _onWrapperCancelClick: function() {
- this.props.onFinished(false);
- },
-
- render: function() {
- if (this.state.component) {
- const Component = this.state.component;
- return ;
- } else if (this.state.error) {
- const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
- const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
- return
- {_t("Unable to load! Check your network connectivity and try again.")}
-
- ;
- } else {
- // show a spinner until the component is loaded.
- const Spinner = sdk.getComponent("elements.Spinner");
- return ;
- }
- },
-});
-
class ModalManager {
constructor() {
this._counter = 0;