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"