Skip to content

Commit

Permalink
Start adding type annotations for React lib code
Browse files Browse the repository at this point in the history
  • Loading branch information
thibaudcolas committed Jan 26, 2019
1 parent f3bbaed commit 0f701ea
Show file tree
Hide file tree
Showing 11 changed files with 74 additions and 57 deletions.
8 changes: 8 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ module.exports = {
plugins: ["flowtype"],
rules: {
"flowtype/space-after-type-colon": [0],
"@thibaudcolas/cookbook/react/require-default-props": [
"error",
{ forbidDefaultForRequired: false },
],
"@thibaudcolas/cookbook/react/default-props-match-prop-types": [
"error",
{ allowRequiredDefaults: true },
],
},
settings: {
polyfills: ["promises"],
Expand Down
1 change: 0 additions & 1 deletion examples/blocks/ImageBlock.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import type { ContentBlock } from "draft-js";

import MediaBlock from "./MediaBlock";
import type { BlockProps } from "./MediaBlock";
// $FlowFixMe
import { DraftUtils } from "../../lib/index";

type Props = {|
Expand Down
1 change: 0 additions & 1 deletion examples/blocks/MediaBlock.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import type { Node } from "react";
import { EditorState } from "draft-js";
import type { EntityInstance } from "draft-js";

// $FlowFixMe
import { Icon } from "../../lib";

import Tooltip from "../components/Tooltip";
Expand Down
1 change: 0 additions & 1 deletion examples/components/PrismDecorator.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import type { Node } from "react";
import Prism from "prismjs";
import type { ContentBlock } from "draft-js";

// $FlowFixMe
import { BLOCK_TYPE } from "../../lib";

type Options = {|
Expand Down
1 change: 0 additions & 1 deletion examples/components/ReadingTime.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import React from "react";
import readingTime from "reading-time";
import { EditorState } from "draft-js";

// $FlowFixMe
import { ToolbarButton } from "../../lib";

const CLOCK_ICON =
Expand Down
1 change: 0 additions & 1 deletion examples/entities/TooltipEntity.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import React, { Component } from "react";
import type { Node } from "react";
import { ContentState } from "draft-js";

// $FlowFixMe
import { Icon } from "../../lib";

import Tooltip from "../components/Tooltip";
Expand Down
30 changes: 12 additions & 18 deletions lib/components/Icon.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
import PropTypes from "prop-types";
// @flow
import React from "react";
import type { Node } from "react";

export type IconProp = string | string[] | Node;

type Props = {|
icon: IconProp,
title: ?string,
className: ?string,
|};

/**
* Icon as SVG element. Can optionally render a React element instead.
*/
const Icon = ({ icon, title, className }) => {
const isPathOrRef = typeof icon === "string";
const Icon = ({ icon, title, className }: Props) => {
let children;

if (isPathOrRef) {
if (typeof icon === "string") {
if (icon.includes("#")) {
children = <use xlinkHref={icon} />;
} else {
Expand Down Expand Up @@ -36,20 +44,6 @@ const Icon = ({ icon, title, className }) => {
);
};

Icon.propTypes = {
// The icon definition is very flexible.
icon: PropTypes.oneOfType([
// String icon = SVG path or symbol reference.
PropTypes.string,
// List of SVG paths.
PropTypes.arrayOf(PropTypes.string),
// Arbitrary React element.
PropTypes.node,
]).isRequired,
title: PropTypes.string,
className: PropTypes.string,
};

Icon.defaultProps = {
title: null,
className: null,
Expand Down
24 changes: 16 additions & 8 deletions lib/components/Toolbar.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,24 @@
import PropTypes from "prop-types";
// @flow
import React from "react";
import type { ComponentType } from "react";
import { EditorState } from "draft-js";

// $FlowFixMe
import ToolbarDefaults from "./ToolbarDefaults";
import ToolbarGroup from "./ToolbarGroup";

const Toolbar = (props) => {
type ControlProps = {|
getEditorState: () => EditorState,
onChange: (EditorState) => void,
|};

type Props = {|
controls: $ReadOnlyArray<ComponentType<ControlProps>>,
getEditorState: () => EditorState,
onChange: (EditorState) => void,
|};

const Toolbar = (props: Props) => {
const { controls, getEditorState, onChange } = props;
return (
<div className="Draftail-Toolbar" role="toolbar">
Expand All @@ -24,10 +38,4 @@ const Toolbar = (props) => {
);
};

Toolbar.propTypes = {
controls: PropTypes.array.isRequired,
getEditorState: PropTypes.func.isRequired,
onChange: PropTypes.func.isRequired,
};

export default Toolbar;
49 changes: 29 additions & 20 deletions lib/components/ToolbarButton.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,30 @@
import PropTypes from "prop-types";
// @flow
import React, { PureComponent } from "react";

import Icon from "./Icon";
import type { IconProp } from "./Icon";

type Props = {|
name: ?string,
active: boolean,
label: ?string,
title: ?string,
icon: ?IconProp,
onClick: ?(?string) => void,
|};

type State = {|
showTooltipOnHover: boolean,
|};

/**
* Displays a basic button, with optional active variant,
* enriched with a tooltip. The tooltip stops showing on click.
*/
class ToolbarButton extends PureComponent {
constructor(props) {
class ToolbarButton extends PureComponent<Props, State> {
static defaultProps: Props;

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

this.state = {
Expand All @@ -19,7 +35,8 @@ class ToolbarButton extends PureComponent {
this.onMouseLeave = this.onMouseLeave.bind(this);
}

onMouseDown(e) {
/* :: onMouseDown: (e: Event) => void; */
onMouseDown(e: Event) {
const { name, onClick } = this.props;

e.preventDefault();
Expand All @@ -28,9 +45,12 @@ class ToolbarButton extends PureComponent {
showTooltipOnHover: false,
});

onClick(name);
if (onClick) {
onClick(name);
}
}

/* :: onMouseLeave: () => void; */
onMouseLeave() {
this.setState({
showTooltipOnHover: true,
Expand All @@ -54,7 +74,9 @@ class ToolbarButton extends PureComponent {
onMouseDown={this.onMouseDown}
onMouseLeave={this.onMouseLeave}
>
{icon ? <Icon icon={icon} /> : null}
{typeof icon !== "undefined" && icon !== null ? (
<Icon icon={icon} />
) : null}
{label ? (
<span className="Draftail-ToolbarButton__label">{label}</span>
) : null}
Expand All @@ -63,26 +85,13 @@ class ToolbarButton extends PureComponent {
}
}

ToolbarButton.propTypes = {
name: PropTypes.string,
active: PropTypes.bool,
label: PropTypes.string,
title: PropTypes.string,
icon: PropTypes.oneOfType([
PropTypes.string,
PropTypes.arrayOf(PropTypes.string),
PropTypes.node,
]),
onClick: PropTypes.func,
};

ToolbarButton.defaultProps = {
name: null,
active: false,
label: null,
title: null,
icon: null,
onClick: () => {},
onClick: null,
};

export default ToolbarButton;
13 changes: 7 additions & 6 deletions lib/components/ToolbarGroup.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import PropTypes from "prop-types";
// @flow
import React from "react";
import type { Node } from "react";

const ToolbarGroup = ({ children }) => {
type Props = {|
children?: Node,
|};

const ToolbarGroup = ({ children }: Props) => {
const hasChildren = React.Children.toArray(children).some((c) => c !== null);
return hasChildren ? (
<div className="Draftail-ToolbarGroup">{children}</div>
) : null;
};

ToolbarGroup.propTypes = {
children: PropTypes.node,
};

ToolbarGroup.defaultProps = {
children: null,
};
Expand Down
2 changes: 2 additions & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// @flow
/**
* Draftail's main API entry point. Exposes all of the modules people
* will need to create their own editor instances from Draftail.
*/
// $FlowFixMe
export { default as DraftailEditor } from "./components/DraftailEditor";
export { default as Icon } from "./components/Icon";
export { default as ToolbarButton } from "./components/ToolbarButton";
Expand Down

0 comments on commit 0f701ea

Please sign in to comment.