Skip to content

Commit 81a38fa

Browse files
committed
Adds Button component
1 parent 0636054 commit 81a38fa

File tree

6 files changed

+234
-44
lines changed

6 files changed

+234
-44
lines changed

README.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ $ npm install -g install-peerdeps
1717
$ install-peerdeps topcoder-react-utils
1818
```
1919

20-
Peer dependencies will be also stored into `package.json` of your project, thus future invokations of `npm install` will automatically install them, and you won't need to use `install-peerdeps` as long as you don't update `topcoder-react-utils` version.
20+
Peer dependencies will be also stored into `package.json` of your project, thus
21+
future invokations of `npm install` will automatically install them, and you
22+
won't need to use `install-peerdeps` as long as you don't update
23+
`topcoder-react-utils` version.
2124

2225
### Configurations
2326
- [**Babel Configurations**](docs/babel-config.md) — Standard configurations
@@ -26,7 +29,13 @@ for [Babel](https://babeljs.io/);
2629
configurations for [ESLint](https://eslint.org/).
2730

2831
### Components
29-
- [**Link and NavLink**](docs/link-and-navlink.md) &mdash; Auxiliary wrappers around [React Router](https://github.com/ReactTraining/react-router)'s `<Link>` and `<NavLink>` components; they help to handle external and internal links in a single uniform manner;
32+
- [**Button**](docs/button.md) &mdash; Handles buttons and button-like links
33+
(components that look like regular buttons, but behave as links) in the same
34+
uniform manner;
35+
- [**Link and NavLink**](docs/link-and-navlink.md) &mdash; Auxiliary wrappers
36+
around [React Router](https://github.com/ReactTraining/react-router)'s `<Link>`
37+
and `<NavLink>` components; they help to handle external and internal links in
38+
the same uniform manner.
3039

3140
### Utilities
3241
*To be added*

docs/button.md

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# Button
2+
Handles buttons and button-like links (components that look like buttons, but
3+
behave as links) in the same uniform manner.
4+
5+
[Examples](#examples)
6+
7+
**Why?** &mdash; Some buttons in our applications, although they look like
8+
regular buttons, should behave as external (to different apps/webpages) or
9+
internal (to different routes inside the app) links. Often, there is a need to
10+
switch between this link-like and the true button behavior as the development
11+
goes. The `<Button>` button component separates button styling from its logic,
12+
helping to switch these behaviors without caring about styling, and update the
13+
styling without caring about functionality.
14+
15+
Under the hood, a `<Button>` is rendered in one of the three ways:
16+
1. When the `<Button>` is disabled it is rendered as `<div>` element with
17+
button content, which allows to style disabled buttons the same way, whether
18+
they are true or buttons or button-like links;
19+
2. Otherwise, if the `<Button>` has `to` property set it is rendered as
20+
[`<Link>`](link-and-navlink.md) (in this case it accepts all other props a
21+
`<Link>` can accept). It helps to properly handle transitions both to external
22+
URLs, and to other routes within the app (these are handled via the React
23+
Router's mechanics, without reloading the app);
24+
3. Otherwise the `<Button>` is rendered as a regular HTML `<button>` (we could
25+
just use the `<Link>` in this case as well, but rendering and handling the
26+
`<button>` is a bit more efficient.
27+
28+
### Button Properties
29+
- **`active`** &mdash; *Boolean* &mdash; Optional. When *true* the button is
30+
rendered in active state, even if it is not active otherwise;
31+
- **`disabled`** &mdash; *Boolean* &mdash; Optional. When *true* the button is
32+
disabled;
33+
- **`enforceA`** &mdash; *Boolean* &mdash; Optional. When the button is rendered
34+
as `<Link>` this prop enforces it to be rendered as a simple `<a>` element (thus
35+
being treated as an external link);
36+
- **`onClick`** &mdash; *Function* &mdash; Optional. *onClick* event handler;
37+
- **`onMouseDown`** &mdash; *Function* &mdash; Optional. *onMouseDown* event
38+
handler;
39+
- **`opneNewTab`** &mdash; *Boolean* &mdash; Optional. When the button is
40+
rendered as `<Link>` this property tells to open the link in a new tab;
41+
- **`replace`** &mdash; *Boolean* &mdash; Optional. When the button is rendered
42+
as `<Link>`, and the URL is internal, this property tells that the new route
43+
should replace the last record in the browser's history, rather than be pushed
44+
as a new entry into the history stack;
45+
- **`size`** &mdash; *String* &mdash; Optional. Button size. If specified, and
46+
`theme[size]` is defined, `theme[size]` class is added to the root element of
47+
the button. It is supposed to control button size, and although any values can
48+
be used, it is recommended to stick with `xs`, `sm`, `md`, `lg`, and `xl` size
49+
labels, with `md` size being the default, when no `size` property is passed in;
50+
- **`theme`** &mdash; *Object* &mdash; Button theme (we use
51+
[react-css-super-themr](https://www.npmjs.com/package/react-css-super-themr)
52+
to manage default / context / ad-hoc theming of components). This object is
53+
supposed to have the following fields:
54+
- **`button`** &mdash; *String* &mdash; The class to apply to the root element
55+
of the button in all cases;
56+
- **`disabled`** &mdash; *String* &mdash; The class to additionally apply to
57+
the root element of the button, when it is disabled;
58+
- **`link`** &mdash; *String* &mdash; Optional. The class to additionally
59+
apply to the root element of the button, when the button is rendered as
60+
`<Link>`;
61+
- **`regular`** &mdash; *String* &mdash; Optinal. The class to additionally
62+
apply to the root element of the button, when the button is rendered as
63+
`<button>`;
64+
- Other fields matching acceptable values of the `size` prop. Each of them
65+
will hold the class to additionally apply to the root element of the button,
66+
when the `<size>` value matches;
67+
- **`to`** &mdash; *Object* or *String* &mdash; When specified the button will
68+
be rendered as `<Link>` (if non-disabled), and it will point to the specified
69+
URL/location.
70+
71+
### <a name="examples">Examples</a>
72+
Simple button:
73+
```js
74+
import { Button } from 'topcoder-react-utils';
75+
76+
export default function Example() {
77+
return <Button onClick={() => console.log('Clicked!')}>Click Me!</Button>;
78+
}
79+
```

docs/link-and-navlink.md

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
Auxiliary wrappers around [React Router](https://github.com/ReactTraining/react-router)'s
44
`<Link>` and `<NavLink>` components; they help to handle external and internal
5-
links in a single uniform manner;
5+
links in a single uniform manner.
6+
7+
[Examples](#examples)
68

79
**Why?** &mdash; We use React Router to handle routing of our applications.
810
React Router's `<Link>` and `<NavLink>` components work only with the
@@ -30,7 +32,7 @@ use `enforceA` property to handle such case.
3032
Both `<Link>` and `<NavLink>` support all properties of the underlying React
3133
Router's components, along with some additional props:
3234

33-
### `<Link>` properties
35+
### Link properties
3436
- **`children`** &mdash; *Node* &mdash; Optional. Child ReactJS node to render
3537
inside the link;
3638
- **`className`** &mdash; *String* &mdash; Optional. Class(es) to apply to the
@@ -49,12 +51,12 @@ one;
4951
- **`to`** &mdash; *String* &mdash; Optional. Link URL. Defaults to empty
5052
string.
5153

52-
### `<NavLink>` properties
54+
### NavLink properties
5355
`<NavLink>` supports all properties of `<Link>`, listed above, and the following
5456
additional ones, coming from React Router:
5557
- **`activeClassName`** &mdash; *String* &mdash; Optional. Class(es) to apply to
5658
the rendered link when it is active;
57-
- **`activeStyle`** &mdash; *String* &mash; Optional. Styles to apply to the
59+
- **`activeStyle`** &mdash; *String* &mdash; Optional. Styles to apply to the
5860
rendered link when it is active;
5961
- **`exact`** &mdash; *Boolean* &mdash; Optional. When *true*, the active
6062
class/style will only be applied if the location is matched exactly;
@@ -69,3 +71,14 @@ different location, a `location` can be passed.
6971
slash on a location’s pathname will be taken into consideration when determining
7072
if the location matches the current URL. See the <Route strict> documentation
7173
for more information.
74+
75+
### <a name="examples">Examples</a>
76+
77+
Minimal `<Link>` example:
78+
```js
79+
import { Link } from 'topcoder-react-utils';
80+
81+
export default function LinksExample() {
82+
return <Link to="some/url">Link to Some URL</a>;
83+
}
84+
```

package.json

Lines changed: 39 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,17 @@
11
{
2-
"name": "topcoder-react-utils",
3-
"version": "0.0.21",
4-
"description": "Topcoder collection of generic ReactJS components and utils",
5-
"main": "dist/index.js",
6-
"engines": {
7-
"node": "~8.9.4",
8-
"npm": "~5.6.0"
9-
},
10-
"scripts": {
11-
"build": "babel src --out-dir dist",
12-
"lint": "npm run lint:js",
13-
"lint:js": "eslint --ext .js,.jsx .",
14-
"prepublishOnly": "npm run build",
15-
"test": "npm run lint"
16-
},
17-
"repository": {
18-
"type": "git",
19-
"url": "git+https://github.com/topcoder-platform/topcoder-react-utils.git"
20-
},
21-
"keywords": [
22-
"Topcoder",
23-
"React"
24-
],
25-
"license": "MIT",
262
"bugs": {
273
"url": "https://github.com/topcoder-platform/topcoder-react-utils/issues"
284
},
29-
"homepage": "https://github.com/topcoder-platform/topcoder-react-utils#readme",
30-
"peerDependencies": {
5+
"dependencies": {
6+
"lodash": "^4.17.4",
7+
"prop-types": "^15.6.0",
8+
"react": "^16.1.1",
9+
"react-dom": "^16.1.1",
10+
"react-router-dom": "^4.2.2",
11+
"url-parse": "^1.2.0"
12+
},
13+
"description": "Topcoder collection of generic ReactJS components and utils",
14+
"devDependencies": {
3115
"babel-cli": "^6.26.0",
3216
"babel-eslint": "^7.2.3",
3317
"babel-plugin-css-modules-transform": "^1.4.0",
@@ -46,18 +30,21 @@
4630
"eslint-plugin-import": "^2.7.0",
4731
"eslint-plugin-jest": "^21.0.2",
4832
"eslint-plugin-jsx-a11y": "^5.1.1",
49-
"eslint-plugin-react": "^7.3.0",
50-
"react-hot-loader": "^3.1.3"
33+
"eslint-plugin-react": "^7.3.0"
5134
},
52-
"dependencies": {
53-
"lodash": "^4.17.4",
54-
"prop-types": "^15.6.0",
55-
"react": "^16.1.1",
56-
"react-dom": "^16.1.1",
57-
"react-router-dom": "^4.2.2",
58-
"url-parse": "^1.2.0"
35+
"engines": {
36+
"node": "~8.9.4",
37+
"npm": "~5.6.0"
5938
},
60-
"devDependencies": {
39+
"homepage": "https://github.com/topcoder-platform/topcoder-react-utils#readme",
40+
"keywords": [
41+
"Topcoder",
42+
"React"
43+
],
44+
"license": "MIT",
45+
"main": "dist/index.js",
46+
"name": "topcoder-react-utils",
47+
"peerDependencies": {
6148
"babel-cli": "^6.26.0",
6249
"babel-eslint": "^7.2.3",
6350
"babel-plugin-css-modules-transform": "^1.4.0",
@@ -76,6 +63,20 @@
7663
"eslint-plugin-import": "^2.7.0",
7764
"eslint-plugin-jest": "^21.0.2",
7865
"eslint-plugin-jsx-a11y": "^5.1.1",
79-
"eslint-plugin-react": "^7.3.0"
80-
}
66+
"eslint-plugin-react": "^7.3.0",
67+
"react-hot-loader": "^3.1.3"
68+
},
69+
"repository": {
70+
"type": "git",
71+
"url": "git+https://github.com/topcoder-platform/topcoder-react-utils.git"
72+
},
73+
"scripts": {
74+
"build": "babel src --out-dir dist",
75+
"build:dev": "babel --watch src --out-dir dist",
76+
"lint": "npm run lint:js",
77+
"lint:js": "eslint --ext .js,.jsx .",
78+
"prepublishOnly": "npm run build",
79+
"test": "npm run lint"
80+
},
81+
"version": "0.0.22"
8182
}

src/Button.jsx

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/**
2+
* The Button component provide a standard button / button-like link:
3+
* - When disabled, it renders as <div>;
4+
* - When no "to" prop is passed in, it renders as <button>;
5+
* - Otherwise, it renders as <Link>.
6+
*/
7+
8+
import PT from 'prop-types';
9+
import React from 'react';
10+
11+
import Link from './Link';
12+
13+
export default function Button({
14+
active,
15+
children,
16+
disabled,
17+
enforceA,
18+
onClick,
19+
onMouseDown,
20+
openNewTab,
21+
replace,
22+
size,
23+
theme,
24+
to,
25+
}) {
26+
let className = theme.button;
27+
if (theme[size]) className += ` ${theme[size]}`;
28+
if (active && theme.active) className += ` ${theme.active}`;
29+
if (disabled) {
30+
if (theme.disabled) className += ` ${theme.disabled}`;
31+
return <div className={className}>{children}</div>;
32+
} else if (to) {
33+
if (theme.link) className += ` ${theme.link}`;
34+
return (
35+
<Link
36+
className={className}
37+
enforceA={enforceA}
38+
onClick={onClick}
39+
onMouseDown={onMouseDown}
40+
openNewTab={openNewTab}
41+
replace={replace}
42+
to={to}
43+
>{children}</Link>
44+
);
45+
}
46+
if (theme.regular) className += ` ${theme.regular}`;
47+
return (
48+
<button
49+
className={className}
50+
onClick={onClick}
51+
onMouseDown={onMouseDown}
52+
>{children}</button>
53+
);
54+
}
55+
56+
Button.defaultProps = {
57+
active: false,
58+
children: null,
59+
disabled: false,
60+
enforceA: false,
61+
onClick: null,
62+
onMouseDown: null,
63+
openNewTab: false,
64+
replace: false,
65+
size: null,
66+
to: null,
67+
};
68+
69+
Button.propTypes = {
70+
active: PT.bool,
71+
children: PT.node,
72+
disabled: PT.bool,
73+
enforceA: PT.bool,
74+
onClick: PT.func,
75+
onMouseDown: PT.func,
76+
openNewTab: PT.bool,
77+
replace: PT.bool,
78+
size: PT.string,
79+
theme: PT.shape({
80+
button: PT.string.isRequired,
81+
disabled: PT.string.isRequired,
82+
link: PT.string,
83+
regular: PT.string,
84+
}).isRequired,
85+
to: PT.oneOfType([PT.object, PT.string]),
86+
};

src/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
import Button from './Button';
12
import Link from './Link';
23
import NavLink from './NavLink';
34

45
export {
6+
Button,
57
Link,
68
NavLink,
79
};

0 commit comments

Comments
 (0)