port notification and split-pane component to ts

This commit is contained in:
Labhansh Agrawal 2020-03-13 20:49:23 +05:30 committed by Benjamin Staneck
parent b0002bbe01
commit 6801460912
5 changed files with 57 additions and 25 deletions

View file

@ -1,8 +1,10 @@
import React from 'react'; import React from 'react';
import {NotificationProps} from '../hyper';
export default class Notification extends React.PureComponent { export default class Notification extends React.PureComponent<NotificationProps, {dismissing: boolean}> {
constructor() { dismissTimer!: NodeJS.Timeout;
super(); constructor(props: NotificationProps) {
super(props);
this.state = { this.state = {
dismissing: false dismissing: false
}; };
@ -14,7 +16,7 @@ export default class Notification extends React.PureComponent {
} }
} }
//TODO: Remove usage of legacy and soon deprecated lifecycle methods //TODO: Remove usage of legacy and soon deprecated lifecycle methods
UNSAFE_componentWillReceiveProps(next) { UNSAFE_componentWillReceiveProps(next: NotificationProps) {
// if we have a timer going and the notification text // if we have a timer going and the notification text
// changed we reset the timer // changed we reset the timer
if (next.text !== this.props.text) { if (next.text !== this.props.text) {
@ -31,7 +33,7 @@ export default class Notification extends React.PureComponent {
this.setState({dismissing: true}); this.setState({dismissing: true});
}; };
onElement = el => { onElement = (el: HTMLDivElement | null) => {
if (el) { if (el) {
el.addEventListener('webkitTransitionEnd', () => { el.addEventListener('webkitTransitionEnd', () => {
if (this.state.dismissing) { if (this.state.dismissing) {
@ -48,7 +50,7 @@ export default class Notification extends React.PureComponent {
setDismissTimer() { setDismissTimer() {
this.dismissTimer = setTimeout(() => { this.dismissTimer = setTimeout(() => {
this.handleDismiss(); this.handleDismiss();
}, this.props.dismissAfter); }, this.props.dismissAfter!);
} }
resetDismissTimer() { resetDismissTimer() {

View file

@ -1,26 +1,36 @@
import React from 'react'; import React from 'react';
import _ from 'lodash'; import _ from 'lodash';
import {SplitPaneProps} from '../hyper';
export default class SplitPane extends React.PureComponent { export default class SplitPane extends React.PureComponent<SplitPaneProps, {dragging: boolean}> {
constructor(props) { dragPanePosition!: number;
dragTarget!: Element;
panes!: Element[];
paneIndex!: number;
d1!: 'height' | 'width';
d2!: 'top' | 'left';
d3!: 'clientX' | 'clientY';
panesSize!: number;
dragging!: boolean;
constructor(props: SplitPaneProps) {
super(props); super(props);
this.state = {dragging: false}; this.state = {dragging: false};
} }
componentDidUpdate(prevProps) { componentDidUpdate(prevProps: SplitPaneProps) {
if (this.state.dragging && prevProps.sizes !== this.props.sizes) { if (this.state.dragging && prevProps.sizes !== this.props.sizes) {
// recompute positions for ongoing dragging // recompute positions for ongoing dragging
this.dragPanePosition = this.dragTarget.getBoundingClientRect()[this.d2]; this.dragPanePosition = this.dragTarget.getBoundingClientRect()[this.d2];
} }
} }
setupPanes(ev) { setupPanes(ev: any) {
this.panes = Array.from(ev.target.parentNode.childNodes); this.panes = Array.from(ev.target.parentNode.childNodes);
this.paneIndex = this.panes.indexOf(ev.target); this.paneIndex = this.panes.indexOf(ev.target);
this.paneIndex -= Math.ceil(this.paneIndex / 2); this.paneIndex -= Math.ceil(this.paneIndex / 2);
} }
handleAutoResize = ev => { handleAutoResize = (ev: React.MouseEvent) => {
ev.preventDefault(); ev.preventDefault();
this.setupPanes(ev); this.setupPanes(ev);
@ -36,7 +46,7 @@ export default class SplitPane extends React.PureComponent {
this.props.onResize(sizes_); this.props.onResize(sizes_);
}; };
handleDragStart = ev => { handleDragStart = (ev: any) => {
ev.preventDefault(); ev.preventDefault();
this.setState({dragging: true}); this.setState({dragging: true});
window.addEventListener('mousemove', this.onDrag); window.addEventListener('mousemove', this.onDrag);
@ -61,20 +71,20 @@ export default class SplitPane extends React.PureComponent {
getSizes() { getSizes() {
const {sizes} = this.props; const {sizes} = this.props;
let sizes_; let sizes_: number[];
if (sizes) { if (sizes) {
sizes_ = [].concat(sizes); sizes_ = [...sizes.asMutable()];
} else { } else {
const total = this.props.children.length; const total = (this.props.children as React.ReactNodeArray).length;
const count = new Array(total).fill(1 / total); const count = new Array<number>(total).fill(1 / total);
sizes_ = count; sizes_ = count;
} }
return sizes_; return sizes_;
} }
onDrag = ev => { onDrag = (ev: MouseEvent) => {
const sizes_ = this.getSizes(); const sizes_ = this.getSizes();
const i = this.paneIndex; const i = this.paneIndex;
@ -99,16 +109,13 @@ export default class SplitPane extends React.PureComponent {
}; };
render() { render() {
const children = this.props.children; const children = this.props.children as React.ReactNodeArray;
const {direction, borderColor} = this.props; const {direction, borderColor} = this.props;
const sizeProperty = direction === 'horizontal' ? 'height' : 'width'; const sizeProperty = direction === 'horizontal' ? 'height' : 'width';
let {sizes} = this.props; // workaround for the fact that if we don't specify
if (!sizes) { // sizes, sometimes flex fails to calculate the
// workaround for the fact that if we don't specify // right height for the horizontal panes
// sizes, sometimes flex fails to calculate the const sizes = this.props.sizes || new Array<number>(children.length).fill(1 / children.length);
// right height for the horizontal panes
sizes = new Array(children.length).fill(1 / children.length);
}
return ( return (
<div className={`splitpane_panes splitpane_panes_${direction}`}> <div className={`splitpane_panes splitpane_panes_${direction}`}>
{React.Children.map(children, (child, i) => { {React.Children.map(children, (child, i) => {

17
lib/hyper.d.ts vendored
View file

@ -241,3 +241,20 @@ export type TabsProps = {
onClose: () => void; onClose: () => void;
fullScreen: boolean; fullScreen: boolean;
} & extensionProps; } & extensionProps;
export type NotificationProps = {
backgroundColor: string;
color?: string;
dismissAfter?: number;
onDismiss: Function;
text?: string | null;
userDismissable?: boolean | null;
userDismissColor?: string;
} & extensionProps;
export type SplitPaneProps = {
borderColor: string;
direction: 'horizontal' | 'vertical';
onResize: Function;
sizes?: Immutable<number[]> | null;
};

View file

@ -74,6 +74,7 @@
"@types/copy-webpack-plugin": "5.0.0", "@types/copy-webpack-plugin": "5.0.0",
"@types/electron-devtools-installer": "2.2.0", "@types/electron-devtools-installer": "2.2.0",
"@types/fs-extra": "8.1.0", "@types/fs-extra": "8.1.0",
"@types/lodash": "^4.14.149",
"@types/mkdirp": "1.0.0", "@types/mkdirp": "1.0.0",
"@types/mousetrap": "^1.6.3", "@types/mousetrap": "^1.6.3",
"@types/ms": "0.7.31", "@types/ms": "0.7.31",

View file

@ -649,6 +649,11 @@
dependencies: dependencies:
"@types/node" "*" "@types/node" "*"
"@types/lodash@^4.14.149":
version "4.14.149"
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.149.tgz#1342d63d948c6062838fbf961012f74d4e638440"
integrity sha512-ijGqzZt/b7BfzcK9vTrS6MFljQRPn5BFWOx8oE0GYxribu6uV+aA9zZuXI1zc/etK9E8nrgdoF2+LgUw7+9tJQ==
"@types/minimatch@*": "@types/minimatch@*":
version "3.0.3" version "3.0.3"
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"