diff --git a/.babelrc b/.babelrc
index 3710e20a37..29cd99f8c4 100644
--- a/.babelrc
+++ b/.babelrc
@@ -15,6 +15,7 @@
"@babel/preset-react"
],
"plugins": [
+ ["@babel/plugin-proposal-decorators", { "legacy": true }],
"@babel/plugin-proposal-numeric-separator",
"@babel/plugin-proposal-class-properties",
"@babel/plugin-proposal-object-rest-spread",
diff --git a/.eslintrc.js b/.eslintrc.js
index 81c3752301..0721c1c8d2 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -25,6 +25,7 @@ module.exports = {
parserOptions: {
ecmaFeatures: {
jsx: true,
+ legacyDecorators: true,
}
},
rules: {
diff --git a/package.json b/package.json
index 3b6e571d0c..99e4983d60 100644
--- a/package.json
+++ b/package.json
@@ -113,6 +113,7 @@
"@babel/cli": "^7.7.5",
"@babel/core": "^7.7.5",
"@babel/plugin-proposal-class-properties": "^7.7.4",
+ "@babel/plugin-proposal-decorators": "^7.7.4",
"@babel/plugin-proposal-numeric-separator": "^7.7.4",
"@babel/plugin-proposal-object-rest-spread": "^7.7.4",
"@babel/plugin-transform-flow-comments": "^7.7.4",
diff --git a/scripts/reskindex.js b/scripts/reskindex.js
index 833151a298..3919295078 100755
--- a/scripts/reskindex.js
+++ b/scripts/reskindex.js
@@ -19,7 +19,6 @@ function reskindex() {
prevFiles = files;
var header = args.h || args.header;
- var packageJson = JSON.parse(fs.readFileSync('./package.json'));
var strm = fs.createWriteStream(componentIndexTmp);
@@ -34,19 +33,7 @@ function reskindex() {
strm.write(" * so you'd just be trying to swim upstream like a salmon.\n");
strm.write(" * You are not a salmon.\n");
strm.write(" */\n\n");
-
- if (packageJson['matrix-react-parent']) {
- const parentIndex = packageJson['matrix-react-parent'] +
- '/lib/component-index';
- strm.write(
-`let components = require('${parentIndex}').components;
-if (!components) {
- throw new Error("'${parentIndex}' didn't export components");
-}
-`);
- } else {
- strm.write("let components = {};\n");
- }
+ strm.write("let components = {};\n");
for (var i = 0; i < files.length; ++i) {
var file = files[i].replace('.js', '');
diff --git a/src/Skinner.js b/src/Skinner.js
index 1fe12f85ab..7235d55937 100644
--- a/src/Skinner.js
+++ b/src/Skinner.js
@@ -28,15 +28,31 @@ class Skinner {
" b) A component has called getComponent at the root level",
);
}
- let comp = this.components[name];
- // XXX: Temporarily also try 'views.' as we're currently
- // leaving the 'views.' off views.
+
+ const doLookup = (components) => {
+ if (!components) return null;
+ let comp = components[name];
+ // XXX: Temporarily also try 'views.' as we're currently
+ // leaving the 'views.' off views.
+ if (!comp) {
+ comp = components['views.' + name];
+ }
+ return comp;
+ };
+
+ // Check the skin first
+ let comp = doLookup(this.components);
+
+ // If that failed, check against our own components
if (!comp) {
- comp = this.components['views.'+name];
+ // Lazily load our own components because they might end up calling .getComponent()
+ comp = doLookup(require("./component-index").components);
}
+ // Just return nothing instead of erroring - the consumer should be smart enough to
+ // handle this at this point.
if (!comp) {
- throw new Error("No such component: "+name);
+ return null;
}
// components have to be functions.
diff --git a/src/components/structures/auth/ForgotPassword.js b/src/components/structures/auth/ForgotPassword.js
index 6f68293caa..ada7d4449b 100644
--- a/src/components/structures/auth/ForgotPassword.js
+++ b/src/components/structures/auth/ForgotPassword.js
@@ -26,6 +26,7 @@ import SdkConfig from "../../../SdkConfig";
import PasswordReset from "../../../PasswordReset";
import AutoDiscoveryUtils, {ValidatedServerConfig} from "../../../utils/AutoDiscoveryUtils";
import classNames from 'classnames';
+import AuthPage from "../../views/auth/AuthPage";
// Phases
// Show controls to configure server details
@@ -367,7 +368,6 @@ module.exports = createReactClass({
},
render: function() {
- const AuthPage = sdk.getComponent("auth.AuthPage");
const AuthHeader = sdk.getComponent("auth.AuthHeader");
const AuthBody = sdk.getComponent("auth.AuthBody");
diff --git a/src/components/structures/auth/Login.js b/src/components/structures/auth/Login.js
index b2e9d3e7cd..ade417d156 100644
--- a/src/components/structures/auth/Login.js
+++ b/src/components/structures/auth/Login.js
@@ -26,6 +26,7 @@ import SdkConfig from '../../../SdkConfig';
import { messageForResourceLimitError } from '../../../utils/ErrorUtils';
import AutoDiscoveryUtils, {ValidatedServerConfig} from "../../../utils/AutoDiscoveryUtils";
import classNames from "classnames";
+import AuthPage from "../../views/auth/AuthPage";
// For validating phone numbers without country codes
const PHONE_NUMBER_REGEX = /^[0-9()\-\s]*$/;
@@ -608,7 +609,6 @@ module.exports = createReactClass({
render: function() {
const Loader = sdk.getComponent("elements.Spinner");
- const AuthPage = sdk.getComponent("auth.AuthPage");
const AuthHeader = sdk.getComponent("auth.AuthHeader");
const AuthBody = sdk.getComponent("auth.AuthBody");
const loader = this.isBusy() ?
: null;
diff --git a/src/components/structures/auth/PostRegistration.js b/src/components/structures/auth/PostRegistration.js
index 760163585d..a77b4d0d56 100644
--- a/src/components/structures/auth/PostRegistration.js
+++ b/src/components/structures/auth/PostRegistration.js
@@ -20,6 +20,7 @@ import PropTypes from 'prop-types';
import sdk from '../../../index';
import MatrixClientPeg from '../../../MatrixClientPeg';
import { _t } from '../../../languageHandler';
+import AuthPage from "../../views/auth/AuthPage";
module.exports = createReactClass({
displayName: 'PostRegistration',
@@ -59,7 +60,6 @@ module.exports = createReactClass({
render: function() {
const ChangeDisplayName = sdk.getComponent('settings.ChangeDisplayName');
const ChangeAvatar = sdk.getComponent('settings.ChangeAvatar');
- const AuthPage = sdk.getComponent('auth.AuthPage');
const AuthHeader = sdk.getComponent('auth.AuthHeader');
const AuthBody = sdk.getComponent("auth.AuthBody");
return (
diff --git a/src/components/structures/auth/Registration.js b/src/components/structures/auth/Registration.js
index 3578d745f5..69f34f764a 100644
--- a/src/components/structures/auth/Registration.js
+++ b/src/components/structures/auth/Registration.js
@@ -30,6 +30,7 @@ import AutoDiscoveryUtils, {ValidatedServerConfig} from "../../../utils/AutoDisc
import classNames from "classnames";
import * as Lifecycle from '../../../Lifecycle';
import MatrixClientPeg from "../../../MatrixClientPeg";
+import AuthPage from "../../views/auth/AuthPage";
// Phases
// Show controls to configure server details
@@ -576,7 +577,6 @@ module.exports = createReactClass({
render: function() {
const AuthHeader = sdk.getComponent('auth.AuthHeader');
const AuthBody = sdk.getComponent("auth.AuthBody");
- const AuthPage = sdk.getComponent('auth.AuthPage');
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
let errorText;
diff --git a/src/components/structures/auth/SoftLogout.js b/src/components/structures/auth/SoftLogout.js
index 585b4bfe67..da19a852f6 100644
--- a/src/components/structures/auth/SoftLogout.js
+++ b/src/components/structures/auth/SoftLogout.js
@@ -24,6 +24,7 @@ import Modal from '../../../Modal';
import MatrixClientPeg from "../../../MatrixClientPeg";
import {sendLoginRequest} from "../../../Login";
import url from 'url';
+import AuthPage from "../../views/auth/AuthPage";
const LOGIN_VIEW = {
LOADING: 1,
@@ -284,7 +285,6 @@ export default class SoftLogout extends React.Component {
}
render() {
- const AuthPage = sdk.getComponent("auth.AuthPage");
const AuthHeader = sdk.getComponent("auth.AuthHeader");
const AuthBody = sdk.getComponent("auth.AuthBody");
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
diff --git a/src/components/views/auth/AuthPage.js b/src/components/views/auth/AuthPage.js
index 41098c9d6c..8448df9ac8 100644
--- a/src/components/views/auth/AuthPage.js
+++ b/src/components/views/auth/AuthPage.js
@@ -1,6 +1,7 @@
/*
Copyright 2015, 2016 OpenMarket Ltd
Copyright 2019 New Vector Ltd
+Copyright 2019 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.
@@ -16,22 +17,21 @@ limitations under the License.
*/
import React from 'react';
-import createReactClass from 'create-react-class';
import sdk from '../../../index';
+import {replaceComponent} from "../../../utils/replaceComponent";
-module.exports = createReactClass({
- displayName: 'AuthPage',
-
- render: function() {
+@replaceComponent("views.auth.AuthPage")
+export default class AuthPage extends React.PureComponent {
+ render() {
const AuthFooter = sdk.getComponent('auth.AuthFooter');
return (
- { this.props.children }
+ {this.props.children}
);
- },
-});
+ }
+}
diff --git a/src/components/views/auth/Welcome.js b/src/components/views/auth/Welcome.js
index 9cc398329d..a110631033 100644
--- a/src/components/views/auth/Welcome.js
+++ b/src/components/views/auth/Welcome.js
@@ -17,10 +17,10 @@ limitations under the License.
import React from 'react';
import sdk from '../../../index';
import SdkConfig from '../../../SdkConfig';
+import AuthPage from "./AuthPage";
export default class Welcome extends React.PureComponent {
render() {
- const AuthPage = sdk.getComponent("auth.AuthPage");
const EmbeddedPage = sdk.getComponent('structures.EmbeddedPage');
const LanguageSelector = sdk.getComponent('auth.LanguageSelector');
diff --git a/src/utils/replaceComponent.ts b/src/utils/replaceComponent.ts
new file mode 100644
index 0000000000..1775c42294
--- /dev/null
+++ b/src/utils/replaceComponent.ts
@@ -0,0 +1,22 @@
+/*
+Copyright 2019 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 React from 'react';
+import sdk from '../index';
+
+export function replaceComponent(name: string, origComponent: React.Component) {
+ return () => sdk.getComponent(name) || origComponent;
+}
diff --git a/yarn.lock b/yarn.lock
index 6c05ab5933..4e1be061bc 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -303,6 +303,15 @@
"@babel/helper-create-class-features-plugin" "^7.7.4"
"@babel/helper-plugin-utils" "^7.0.0"
+"@babel/plugin-proposal-decorators@^7.7.4":
+ version "7.7.4"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.7.4.tgz#58c1e21d21ea12f9f5f0a757e46e687b94a7ab2b"
+ integrity sha512-GftcVDcLCwVdzKmwOBDjATd548+IE+mBo7ttgatqNDR7VG7GqIuZPtRWlMLHbhTXhcnFZiGER8iIYl1n/imtsg==
+ dependencies:
+ "@babel/helper-create-class-features-plugin" "^7.7.4"
+ "@babel/helper-plugin-utils" "^7.0.0"
+ "@babel/plugin-syntax-decorators" "^7.7.4"
+
"@babel/plugin-proposal-dynamic-import@^7.7.4":
version "7.7.4"
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.7.4.tgz#dde64a7f127691758cbfed6cf70de0fa5879d52d"
@@ -358,6 +367,13 @@
dependencies:
"@babel/helper-plugin-utils" "^7.0.0"
+"@babel/plugin-syntax-decorators@^7.7.4":
+ version "7.7.4"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.7.4.tgz#3c91cfee2a111663ff3ac21b851140f5a52a4e0b"
+ integrity sha512-0oNLWNH4k5ZbBVfAwiTU53rKFWIeTh6ZlaWOXWJc4ywxs0tjz5fc3uZ6jKAnZSxN98eXVgg7bJIuzjX+3SXY+A==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.0.0"
+
"@babel/plugin-syntax-dynamic-import@^7.7.4":
version "7.7.4"
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.7.4.tgz#29ca3b4415abfe4a5ec381e903862ad1a54c3aec"