Skip to content

Commit

Permalink
Add two different abstract components, pure and not (#1896)
Browse files Browse the repository at this point in the history
  • Loading branch information
gscshoyru authored and adidahiya committed Dec 12, 2017
1 parent b728ccb commit b930727
Show file tree
Hide file tree
Showing 32 changed files with 141 additions and 60 deletions.
2 changes: 1 addition & 1 deletion packages/core/src/common/abstractComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { isNodeEnv } from "./utils";
* An abstract component that Blueprint components can extend
* in order to add some common functionality like runtime props validation.
*/
export abstract class AbstractComponent<P, S> extends React.PureComponent<P, S> {
export abstract class AbstractComponent<P, S> extends React.Component<P, S> {
/** Component displayName should be `public static`. This property exists to prevent incorrect usage. */
protected displayName: never;

Expand Down
73 changes: 73 additions & 0 deletions packages/core/src/common/abstractPureComponent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* Copyright 2015 Palantir Technologies, Inc. All rights reserved.
*
* Licensed under the terms of the LICENSE file distributed with this project.
*/

import * as React from "react";
import { isNodeEnv } from "./utils";

/**
* An abstract component that Blueprint components can extend
* in order to add some common functionality like runtime props validation.
*/
export abstract class AbstractPureComponent<P, S> extends React.PureComponent<P, S> {
/** Component displayName should be `public static`. This property exists to prevent incorrect usage. */
protected displayName: never;

// Not bothering to remove entries when their timeouts finish because clearing invalid ID is a no-op
private timeoutIds: number[] = [];

constructor(props?: P, context?: any) {
super(props, context);
if (!isNodeEnv("production")) {
this.validateProps(this.props);
}
}

public componentWillReceiveProps(nextProps: P & { children?: React.ReactNode }) {
if (!isNodeEnv("production")) {
this.validateProps(nextProps);
}
}

public componentWillUnmount() {
this.clearTimeouts();
}

/**
* Set a timeout and remember its ID.
* All stored timeouts will be cleared when component unmounts.
* @returns a "cancel" function that will clear timeout when invoked.
*/
public setTimeout(callback: () => void, timeout?: number) {
const handle = window.setTimeout(callback, timeout);
this.timeoutIds.push(handle);
return () => window.clearTimeout(handle);
}

/**
* Clear all known timeouts.
*/
public clearTimeouts = () => {
if (this.timeoutIds.length > 0) {
for (const timeoutId of this.timeoutIds) {
window.clearTimeout(timeoutId);
}
this.timeoutIds = [];
}
};

/**
* Ensures that the props specified for a component are valid.
* Implementations should check that props are valid and usually throw an Error if they are not.
* Implementations should not duplicate checks that the type system already guarantees.
*
* This method should be used instead of React's
* [propTypes](https://facebook.github.io/react/docs/reusable-components.html#prop-validation) feature.
* In contrast to propTypes, these runtime checks are _always_ run, not just in development mode.
*/
protected validateProps(_: P & { children?: React.ReactNode }) {
// implement in subclass
}
}
1 change: 1 addition & 0 deletions packages/core/src/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*/

export * from "./abstractComponent";
export * from "./abstractPureComponent";
export * from "./colors";
export * from "./intent";
export * from "./position";
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/components/alert/alert.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import * as classNames from "classnames";
import * as React from "react";

import { AbstractComponent, Classes, Intent, IProps } from "../../common";
import { AbstractPureComponent, Classes, Intent, IProps } from "../../common";
import { ALERT_WARN_CANCEL_PROPS } from "../../common/errors";
import { Button } from "../button/buttons";
import { Dialog } from "../dialog/dialog";
Expand Down Expand Up @@ -55,7 +55,7 @@ export interface IAlertProps extends IProps {
onConfirm(e: React.MouseEvent<HTMLButtonElement>): void;
}

export class Alert extends AbstractComponent<IAlertProps, {}> {
export class Alert extends AbstractPureComponent<IAlertProps, {}> {
public static defaultProps: IAlertProps = {
confirmButtonText: "OK",
isOpen: false,
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/components/collapse/collapse.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import * as classNames from "classnames";
import * as React from "react";

import { AbstractComponent } from "../../common/abstractComponent";
import { AbstractPureComponent } from "../../common/abstractPureComponent";
import * as Classes from "../../common/classes";
import { IProps } from "../../common/props";

Expand Down Expand Up @@ -83,7 +83,7 @@ export enum AnimationStates {
* isOpen = false: OPEN -> CLOSING_START -> CLOSING_END -> CLOSED
* These are all animated.
*/
export class Collapse extends AbstractComponent<ICollapseProps, ICollapseState> {
export class Collapse extends AbstractPureComponent<ICollapseProps, ICollapseState> {
public static displayName = "Blueprint.Collapse";

public static defaultProps: ICollapseProps = {
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/components/context-menu/contextMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import * as classNames from "classnames";
import * as React from "react";
import * as ReactDOM from "react-dom";

import { AbstractComponent } from "../../common/abstractComponent";
import { AbstractPureComponent } from "../../common/abstractPureComponent";
import * as Classes from "../../common/classes";
import { Position } from "../../common/position";
import { safeInvoke } from "../../common/utils";
Expand All @@ -33,7 +33,7 @@ const TETHER_OPTIONS = {
const TRANSITION_DURATION = 100;

/* istanbul ignore next */
class ContextMenu extends AbstractComponent<{}, IContextMenuState> {
class ContextMenu extends AbstractPureComponent<{}, IContextMenuState> {
public state: IContextMenuState = {
isOpen: false,
};
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/components/dialog/dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import * as classNames from "classnames";
import * as React from "react";

import { AbstractComponent } from "../../common/abstractComponent";
import { AbstractPureComponent } from "../../common/abstractPureComponent";
import * as Classes from "../../common/classes";
import * as Errors from "../../common/errors";
import { IProps } from "../../common/props";
Expand Down Expand Up @@ -62,7 +62,7 @@ export interface IDialogProps extends IOverlayableProps, IBackdropProps, IProps
transitionName?: string;
}

export class Dialog extends AbstractComponent<IDialogProps, {}> {
export class Dialog extends AbstractPureComponent<IDialogProps, {}> {
public static defaultProps: IDialogProps = {
canOutsideClickClose: true,
isOpen: false,
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/components/editable-text/editableText.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import * as classNames from "classnames";
import * as React from "react";

import { AbstractComponent } from "../../common/abstractComponent";
import { AbstractPureComponent } from "../../common/abstractPureComponent";
import * as Classes from "../../common/classes";
import * as Keys from "../../common/keys";
import { IIntentProps, IProps } from "../../common/props";
Expand Down Expand Up @@ -104,7 +104,7 @@ export interface IEditableTextState {
const BUFFER_WIDTH_EDGE = 5;
const BUFFER_WIDTH_IE = 30;

export class EditableText extends AbstractComponent<IEditableTextProps, IEditableTextState> {
export class EditableText extends AbstractPureComponent<IEditableTextProps, IEditableTextState> {
public static defaultProps: IEditableTextProps = {
confirmOnEnterKey: false,
defaultValue: "",
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/components/forms/numericInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import * as classNames from "classnames";
import * as React from "react";

import {
AbstractComponent,
AbstractPureComponent,
Classes,
HTMLInputProps,
IconName,
Expand Down Expand Up @@ -128,7 +128,7 @@ enum IncrementDirection {
UP = +1,
}

export class NumericInput extends AbstractComponent<HTMLInputProps & INumericInputProps, INumericInputState> {
export class NumericInput extends AbstractPureComponent<HTMLInputProps & INumericInputProps, INumericInputState> {
public static displayName = "Blueprint.NumericInput";

public static VALUE_EMPTY = "";
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/components/forms/radioGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import * as React from "react";

import { AbstractComponent } from "../../common/abstractComponent";
import { AbstractPureComponent } from "../../common/abstractPureComponent";
import * as Classes from "../../common/classes";
import * as Errors from "../../common/errors";
import { IOptionProps, IProps } from "../../common/props";
Expand Down Expand Up @@ -56,7 +56,7 @@ function nextName() {
return `${RadioGroup.displayName}-${counter++}`;
}

export class RadioGroup extends AbstractComponent<IRadioGroupProps, {}> {
export class RadioGroup extends AbstractPureComponent<IRadioGroupProps, {}> {
public static displayName = "Blueprint.RadioGroup";

// a unique name for this group, which can be overridden by `name` prop.
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/components/hotkeys/hotkey.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import * as React from "react";

import { AbstractComponent } from "../../common";
import { AbstractPureComponent } from "../../common";
import { KeyCombo } from "./keyCombo";

export interface IHotkeyProps {
Expand Down Expand Up @@ -72,7 +72,7 @@ export interface IHotkeyProps {
onKeyUp?(e: KeyboardEvent): any;
}

export class Hotkey extends AbstractComponent<IHotkeyProps, {}> {
export class Hotkey extends AbstractPureComponent<IHotkeyProps, {}> {
public static defaultProps = {
allowInInput: false,
disabled: false,
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/components/hotkeys/hotkeys.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import * as React from "react";

import { AbstractComponent, IProps } from "../../common";
import { AbstractPureComponent, IProps } from "../../common";
import { HOTKEYS_HOTKEY_CHILDREN } from "../../common/errors";
import { Hotkey, IHotkeyProps } from "./hotkey";

Expand All @@ -28,7 +28,7 @@ export interface IHotkeysProps extends IProps {
tabIndex?: number;
}

export class Hotkeys extends AbstractComponent<IHotkeysProps, {}> {
export class Hotkeys extends AbstractPureComponent<IHotkeysProps, {}> {
public static defaultProps = {
tabIndex: 0,
};
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/components/menu/menuItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import * as classNames from "classnames";
import * as React from "react";
import * as ReactDOM from "react-dom";

import { AbstractComponent } from "../../common/abstractComponent";
import { AbstractPureComponent } from "../../common/abstractPureComponent";
import * as Classes from "../../common/classes";
import * as Errors from "../../common/errors";
import { Position } from "../../common/position";
Expand Down Expand Up @@ -75,7 +75,7 @@ const REACT_CONTEXT_TYPES: React.ValidationMap<IMenuItemState> = {
},
};

export class MenuItem extends AbstractComponent<IMenuItemProps, IMenuItemState> {
export class MenuItem extends AbstractPureComponent<IMenuItemProps, IMenuItemState> {
public static defaultProps: IMenuItemProps = {
disabled: false,
popoverProps: {},
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/components/popover/popover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import * as React from "react";
import { findDOMNode } from "react-dom";
import * as Tether from "tether";

import { AbstractComponent } from "../../common/abstractComponent";
import { AbstractPureComponent } from "../../common/abstractPureComponent";
import * as Classes from "../../common/classes";
import * as Errors from "../../common/errors";
import * as PosUtils from "../../common/position";
Expand Down Expand Up @@ -216,7 +216,7 @@ export interface IPopoverState {
targetWidth?: number;
}

export class Popover extends AbstractComponent<IPopoverProps, IPopoverState> {
export class Popover extends AbstractPureComponent<IPopoverProps, IPopoverState> {
public static defaultProps: IPopoverProps = {
arrowSize: 30,
className: "",
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/components/popover2/popover2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { Manager, Popper, Target } from "react-popper";
export type PopperModifiers = PopperJS.Modifiers;
export type Placement = PopperJS.Placement;

import { AbstractComponent } from "../../common/abstractComponent";
import { AbstractPureComponent } from "../../common/abstractPureComponent";
import * as Classes from "../../common/classes";
import * as Errors from "../../common/errors";
import { Position } from "../../common/position";
Expand Down Expand Up @@ -202,7 +202,7 @@ export interface IPopover2State {
placement?: Placement;
}

export class Popover2 extends AbstractComponent<IPopover2Props, IPopover2State> {
export class Popover2 extends AbstractPureComponent<IPopover2Props, IPopover2State> {
public static displayName = "Blueprint.Popover2";

public static defaultProps: IPopover2Props = {
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/components/slider/coreSlider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import * as classNames from "classnames";
import * as React from "react";

import { AbstractComponent } from "../../common/abstractComponent";
import { AbstractPureComponent } from "../../common/abstractPureComponent";
import * as Classes from "../../common/classes";
import * as Errors from "../../common/errors";
import { IProps } from "../../common/props";
Expand Down Expand Up @@ -80,7 +80,7 @@ export interface ISliderState {
tickSize?: number;
}

export abstract class CoreSlider<P extends ICoreSliderProps> extends AbstractComponent<P, ISliderState> {
export abstract class CoreSlider<P extends ICoreSliderProps> extends AbstractPureComponent<P, ISliderState> {
public className = Classes.SLIDER;

private trackElement: HTMLElement;
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/components/slider/handle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import * as classNames from "classnames";
import * as React from "react";

import { AbstractComponent } from "../../common/abstractComponent";
import { AbstractPureComponent } from "../../common/abstractPureComponent";
import * as Classes from "../../common/classes";
import * as Keys from "../../common/keys";
import { IProps } from "../../common/props";
Expand Down Expand Up @@ -37,7 +37,7 @@ export interface IHandleState {
// props that require number values, for validation
const NUMBER_PROPS = ["max", "min", "stepSize", "tickSize", "value"];

export class Handle extends AbstractComponent<IHandleProps, IHandleState> {
export class Handle extends AbstractPureComponent<IHandleProps, IHandleState> {
public static displayName = "Blueprint.SliderHandle";

public state = {
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/components/tabs/tabList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import * as classNames from "classnames";
import * as React from "react";

import { AbstractComponent } from "../../common/abstractComponent";
import { AbstractPureComponent } from "../../common/abstractPureComponent";
import * as Classes from "../../common/classes";
import { IProps } from "../../common/props";

Expand All @@ -26,7 +26,7 @@ export interface ITabListState {
shouldAnimate?: boolean;
}

export class TabList extends AbstractComponent<ITabListProps, {}> {
export class TabList extends AbstractPureComponent<ITabListProps, {}> {
public static displayName = "Blueprint.TabList";

public state: ITabListState = {
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/components/tabs/tabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import * as classNames from "classnames";
import * as React from "react";
import { findDOMNode } from "react-dom";

import { AbstractComponent } from "../../common/abstractComponent";
import { AbstractPureComponent } from "../../common/abstractPureComponent";
import * as Classes from "../../common/classes";
import * as Errors from "../../common/errors";
import * as Keys from "../../common/keys";
Expand Down Expand Up @@ -57,7 +57,7 @@ export interface ITabsState {

const TAB_CSS_SELECTOR = "li[role=tab]";

export class Tabs extends AbstractComponent<ITabsProps, ITabsState> {
export class Tabs extends AbstractPureComponent<ITabsProps, ITabsState> {
public static defaultProps: ITabsProps = {
initialSelectedTabIndex: 0,
};
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/components/tabs2/tabs2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import * as classNames from "classnames";
import * as React from "react";

import { AbstractComponent } from "../../common/abstractComponent";
import { AbstractPureComponent } from "../../common/abstractPureComponent";
import * as Classes from "../../common/classes";
import * as Keys from "../../common/keys";
import { IProps } from "../../common/props";
Expand Down Expand Up @@ -83,7 +83,7 @@ export interface ITabs2State {
selectedTabId?: TabId;
}

export class Tabs2 extends AbstractComponent<ITabs2Props, ITabs2State> {
export class Tabs2 extends AbstractPureComponent<ITabs2Props, ITabs2State> {
/** Insert a `Tabs2.Expander` between any two children to right-align all subsequent children. */
public static Expander = Expander;

Expand Down
Loading

0 comments on commit b930727

Please sign in to comment.