Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support TypeScript for React components #4203

Merged
merged 4 commits into from
Mar 12, 2020
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
"rethemendex": "res/css/rethemendex.sh",
"clean": "rimraf lib",
"build": "yarn clean && git rev-parse HEAD > git-revision.txt && yarn build:compile && yarn build:types",
"build:compile": "yarn reskindex && babel -d lib --verbose --extensions \".ts,.js\" src",
"build:compile": "yarn reskindex && babel -d lib --verbose --extensions \".ts,.js,.tsx\" src",
"build:types": "tsc --emitDeclarationOnly",
"start": "echo THIS IS FOR LEGACY PURPOSES ONLY. && yarn start:all",
"start:all": "concurrently --kill-others-on-fail --prefix \"{time} [{name}]\" -n build,reskindex \"yarn start:build\" \"yarn reskindex:watch\"",
Expand Down Expand Up @@ -118,6 +118,7 @@
"@babel/preset-typescript": "^7.7.4",
"@babel/register": "^7.7.4",
"@peculiar/webcrypto": "^1.0.22",
"@types/react": "16.9",
"babel-eslint": "^10.0.3",
"babel-jest": "^24.9.0",
"chokidar": "^3.3.1",
Expand Down
2 changes: 1 addition & 1 deletion scripts/gen-i18n.js
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ const walkOpts = {
const fullPath = path.join(root, fileStats.name);

let trs;
if (fileStats.name.endsWith('.js')) {
if (fileStats.name.endsWith('.js') || fileStats.name.endsWith('.tsx')) {
trs = getTranslationsJs(fullPath);
} else if (fileStats.name.endsWith('.html')) {
trs = getTranslationsOther(fullPath);
Expand Down
11 changes: 7 additions & 4 deletions scripts/reskindex.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,14 @@ var chokidar = require('chokidar');
var componentIndex = path.join('src', 'component-index.js');
var componentIndexTmp = componentIndex+".tmp";
var componentsDir = path.join('src', 'components');
var componentGlob = '**/*.js';
var componentJsGlob = '**/*.js';
var componentTsGlob = '**/*.tsx';
var prevFiles = [];

function reskindex() {
var files = glob.sync(componentGlob, {cwd: componentsDir}).sort();
var jsFiles = glob.sync(componentJsGlob, {cwd: componentsDir}).sort();
var tsFiles = glob.sync(componentTsGlob, {cwd: componentsDir}).sort();
var files = [...tsFiles, ...jsFiles];
if (!filesHaveChanged(files, prevFiles)) {
return;
}
Expand All @@ -36,7 +39,7 @@ function reskindex() {
strm.write("let components = {};\n");

for (var i = 0; i < files.length; ++i) {
var file = files[i].replace('.js', '');
var file = files[i].replace('.js', '').replace('.tsx', '');

var moduleName = (file.replace(/\//g, '.'));
var importName = moduleName.replace(/\./g, "$");
Expand Down Expand Up @@ -79,7 +82,7 @@ if (!args.w) {
}

var watchDebouncer = null;
chokidar.watch(path.join(componentsDir, componentGlob)).on('all', (event, path) => {
chokidar.watch(path.join(componentsDir, componentJsGlob)).on('all', (event, path) => {
if (path === componentIndex) return;
if (watchDebouncer) clearTimeout(watchDebouncer);
watchDebouncer = setTimeout(reskindex, 1000);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
Copyright 2017 Travis Ralston
Copyright 2019 New Vector Ltd
Copyright 2019 The Matrix.org Foundation C.I.C.
Copyright 2019, 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.
Expand All @@ -18,41 +18,54 @@ limitations under the License.

import * as React from "react";
import {_t} from '../../languageHandler';
import PropTypes from "prop-types";
import * as PropTypes from "prop-types";
import * as sdk from "../../index";
import { ReactNode } from "react";

/**
* Represents a tab for the TabbedView.
*/
export class Tab {
public label: string;
public icon: string;
public body: React.ReactNode;

/**
* Creates a new tab.
* @param {string} tabLabel The untranslated tab label.
* @param {string} tabIconClass The class for the tab icon. This should be a simple mask.
* @param {string} tabJsx The JSX for the tab container.
* @param {React.ReactNode} tabJsx The JSX for the tab container.
*/
constructor(tabLabel, tabIconClass, tabJsx) {
constructor(tabLabel: string, tabIconClass: string, tabJsx: React.ReactNode) {
this.label = tabLabel;
this.icon = tabIconClass;
this.body = tabJsx;
}
}

export default class TabbedView extends React.Component {
interface IProps {
tabs: Tab[];
}

interface IState {
activeTabIndex: number;
}

export default class TabbedView extends React.Component<IProps, IState> {
static propTypes = {
// The tabs to show
tabs: PropTypes.arrayOf(PropTypes.instanceOf(Tab)).isRequired,
};

constructor() {
super();
constructor(props: IProps) {
super(props);

this.state = {
activeTabIndex: 0,
};
}

_getActiveTabIndex() {
private _getActiveTabIndex() {
if (!this.state || !this.state.activeTabIndex) return 0;
return this.state.activeTabIndex;
}
Expand All @@ -62,7 +75,7 @@ export default class TabbedView extends React.Component {
* @param {Tab} tab the tab to show
* @private
*/
_setActiveTab(tab) {
private _setActiveTab(tab: Tab) {
const idx = this.props.tabs.indexOf(tab);
if (idx !== -1) {
this.setState({activeTabIndex: idx});
Expand All @@ -71,7 +84,7 @@ export default class TabbedView extends React.Component {
}
}

_renderTabLabel(tab) {
private _renderTabLabel(tab: Tab) {
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');

let classes = "mx_TabbedView_tabLabel ";
Expand All @@ -97,7 +110,7 @@ export default class TabbedView extends React.Component {
);
}

_renderTabPanel(tab) {
private _renderTabPanel(tab: Tab): React.ReactNode {
return (
<div className="mx_TabbedView_tabPanel" key={"mx_tabpanel_" + tab.label}>
<div className='mx_TabbedView_tabPanelContent'>
Expand All @@ -107,7 +120,7 @@ export default class TabbedView extends React.Component {
);
}

render() {
public render(): React.ReactNode {
const labels = this.props.tabs.map(tab => this._renderTabLabel(tab));
const panel = this._renderTabPanel(this.props.tabs[this._getActiveTabIndex()]);

Expand Down
2 changes: 1 addition & 1 deletion src/utils/replaceableComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

import React from 'react';
import * as React from 'react';
import * as sdk from '../index';

/**
Expand Down
3 changes: 2 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
"outDir": "./lib",
"declaration": true,
"types": [
"node"
"node",
"react"
]
},
"include": [
Expand Down
18 changes: 18 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1217,6 +1217,19 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-13.7.6.tgz#cb734a7c191472ae6a2b3a502b4dfffcea974113"
integrity sha512-eyK7MWD0R1HqVTp+PtwRgFeIsemzuj4gBFSQxfPHY5iMjS7474e5wq+VFgTcdpyHeNxyKSaetYAjdMLJlKoWqA==

"@types/prop-types@*":
version "15.7.3"
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7"
integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==

"@types/react@16.9":
version "16.9.23"
resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.23.tgz#1a66c6d468ba11a8943ad958a8cb3e737568271c"
integrity sha512-SsGVT4E7L2wLN3tPYLiF20hmZTPGuzaayVunfgXzUn1x4uHVsKH6QDJQ/TdpHqwsTLd4CwrmQ2vOgxN7gE24gw==
dependencies:
"@types/prop-types" "*"
csstype "^2.2.0"

"@types/stack-utils@^1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e"
Expand Down Expand Up @@ -2664,6 +2677,11 @@ cssstyle@^1.0.0:
dependencies:
cssom "0.3.x"

csstype@^2.2.0:
version "2.6.9"
resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.9.tgz#05141d0cd557a56b8891394c1911c40c8a98d098"
integrity sha512-xz39Sb4+OaTsULgUERcCk+TJj8ylkL4aSVDQiX/ksxbELSqwkgt4d4RD7fovIdgJGSuNYqwZEiVjYY5l0ask+Q==

currently-unhandled@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea"
Expand Down