Skip to content
This repository has been archived by the owner on Nov 2, 2019. It is now read-only.

Adding IconButton Component and Story #171

Merged
merged 3 commits into from
Jun 23, 2018
Merged
Show file tree
Hide file tree
Changes from all 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
10 changes: 10 additions & 0 deletions docs/components.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,16 @@ export default [
materialDocsLink:
'https://material.io/guidelines/components/buttons.html',
},
{
name: 'Icon Button',
url: 'icon-button',
componentKey: 'icon-button',
description:
'An icon button represents that an action will occur when the user clicks or touches it.',
component: 'src/components/component-doc',
materialDocsLink:
'https://material.io/guidelines/components/buttons.html',
},
],
},
{
Expand Down
11 changes: 11 additions & 0 deletions docs/examples/icon-button.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
class IconButtonsExample extends Component {
render() {
return (
<IconButton>
<IconAlarmOn />
</IconButton>
);
}
}

return <IconButtonsExample />;
24 changes: 24 additions & 0 deletions docs/readmes/icon-button.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
## Usage

```jsx
import { IconButton } from 'materialish';
import 'materialish/icon-button.css';
import 'materialish/ripple.css';
```

## Props

| Prop Name | Default Value | Required | Description |
| --------- | ------------- | -------- | --------------------------------------------------------- |
| children | | No | The contents that are rendered |
| className | | No | Additional class name(s) to add to the Button |
| ripple | true | No | Whether or not to display the "ripple" effect |
| ...rest | | No | Other props are placed on the underlying `button` element |

## CSS Variables

| Variable | Default Value | Description |
| ----------------------------- | ------------------- | -------------------------------------------------------- |
| --mt-baseFontSize | 1rem | The dimensions of the button are based off of this value |
| --mt-iconButton-color | #6d6c6c | The color to use for the icon and ripple |
| --mt-iconButton-disabledColor | rgba(0, 0, 0, 0.38) | The color to use when the button is disabled |
2 changes: 2 additions & 0 deletions docs/static.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const homeMarkdown = fs.readFileSync('./src/home/index.md', fsOptions);
const readmes = {
avatar: fs.readFileSync('./readmes/avatar.md', fsOptions),
button: fs.readFileSync('./readmes/button.md', fsOptions),
'icon-button': fs.readFileSync('./readmes/icon-button.md', fsOptions),
checkbox: fs.readFileSync('./readmes/checkbox.md', fsOptions),
switch: fs.readFileSync('./readmes/switch.md', fsOptions),
icons: fs.readFileSync('./readmes/icons.md', fsOptions),
Expand All @@ -32,6 +33,7 @@ const readmes = {
const examples = {
avatar: fs.readFileSync('./examples/avatar.js', fsOptions),
button: fs.readFileSync('./examples/button.js', fsOptions),
'icon-button': fs.readFileSync('./examples/icon-button.js', fsOptions),
checkbox: fs.readFileSync('./examples/checkbox.js', fsOptions),
switch: fs.readFileSync('./examples/switch.js', fsOptions),
icons: fs.readFileSync('./examples/icons.js', fsOptions),
Expand Down
64 changes: 64 additions & 0 deletions src/icon-button/icon-button.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
.mt-iconButton {
--_mt-iconButton-color: var(--mt-iconButton-color, #6d6c6c);
--_mt-iconButton-disabledColor: var(
--mt-iconButton-disabledColor,
rgba(0, 0, 0, 0.38)
);

all: initial;
font-size: calc(1.5 * var(--mt-baseFontSize, 1rem));
border: none;
position: relative;
width: 2em;
height: 2em;
border-radius: 2em;
cursor: pointer;
outline: none;
background-color: transparent;
-webkit-mask-image: -webkit-radial-gradient(white, black);
touch-action: manipulation;
z-index: 0;

--mt-ripple-color: var(--_mt-iconButton-color);
--mt-ripple-spread: 1.2;
}

.mt-iconButton:after {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: var(--_mt-iconButton-color);
opacity: 0;
border-radius: 2em;
z-index: -1;
}

.mt-iconButton:hover:after,
.mt-iconButton:focus:after {
opacity: 0.1;
}

.mt-iconButton > svg {
position: absolute;
top: 50%;
left: 50%;
transform: translate3d(-50%, -50%, 0);
fill: var(--_mt-iconButton-color);
pointer-events: none;
}

.mt-iconButton:disabled {
cursor: default;
}

.mt-iconButton:disabled > svg {
fill: var(--_mt-iconButton-disabledColor);
}

.mt-iconButton:disabled:hover:after,
.mt-iconButton:disabled:focus:after {
opacity: 0;
}
40 changes: 40 additions & 0 deletions src/icon-button/icon-button.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React, { Component } from 'react';
import Ripple from '../ripple/ripple';
import PropTypes from 'prop-types';

export default class IconButton extends Component {
render() {
const { className = '', ripple = true, children, ...props } = this.props;

return (
<button
className={`mt-iconButton ${className}`}
{...props}
onClick={this.onClick}>
{children}
{ripple && <Ripple ref={this.getRippleRef} />}
</button>
);
}

getRippleRef = component => {
this.rippleComponent = component;
};

onClick = e => {
const { onClick } = this.props;

if (this.rippleComponent) {
this.rippleComponent.onClick(e);
}

if (onClick) {
onClick(e);
}
};
}

IconButton.propTypes = {
ripple: PropTypes.bool,
className: PropTypes.string,
};
2 changes: 2 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import Menu from './menu/menu';
import Snackbar from './snackbar/snackbar';
import Table from './table/table';
import Input from './input/input';
import IconButton from './icon-button/icon-button';

export {
Avatar,
Expand All @@ -36,4 +37,5 @@ export {
Snackbar,
Table,
Input,
IconButton,
};
29 changes: 29 additions & 0 deletions stories/icon-button.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from 'react';
import { storiesOf } from '@storybook/react';
import { withKnobs, boolean } from '@storybook/addon-knobs/react';
import { action } from '@storybook/addon-actions';
import { setOptions } from '@storybook/addon-options';
import '../src/icon-button/icon-button.css';
import '../src/ripple/ripple.css';
import { IconButton } from '../src/index';

setOptions({
name: 'Materialish',
addonPanelInRight: true,
});

storiesOf('Icon Button', module)
.addDecorator(withKnobs)
.add('Regular', () => (
<IconButton
onClick={action('clicked')}
disabled={boolean('Disabled', false, 'PROPS')}>
<svg
xmlns="http://www.w3.org/2000/svg"
width="1em"
height="1em"
viewBox="0 0 48 48">
<path d="M44 11.44l-9.19-7.71-2.57 3.06 9.19 7.71L44 11.44zM15.76 6.78l-2.57-3.06L4 11.43l2.57 3.06 9.19-7.71zM23.99 8C14.04 8 6 16.06 6 26s8.04 18 17.99 18S42 35.94 42 26 33.94 8 23.99 8zM24 40c-7.73 0-14-6.27-14-14s6.27-14 14-14 14 6.27 14 14-6.26 14-14 14zm-2.93-10.95l-4.24-4.24-2.12 2.12 6.36 6.36 12.01-12.01-2.12-2.12-9.89 9.89z" />
</svg>
</IconButton>
));