or
.
2 | export default function isValidTriggerElement(element) {
3 | return element && (element.nodeType === 1 || element === window);
4 | }
5 |
--------------------------------------------------------------------------------
/docs/src/vendor/react-over/overlay.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { warning } from './warning';
3 |
4 | const defaultColor = 'rgba(0, 0, 0, 0.7)';
5 | const transition = 'opacity 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275)';
6 |
7 | // Overlays are optional backgrounds to the over.
8 | // By default, overs do not have an overlay. There are
9 | // three ways to configure one, all involving the value that you
10 | // pass as the `overlay` option:
11 | //
12 | // 1. Pass a React Element to use that Element for the Overlay
13 | // 2. Pass a string to set the background color for the overlay.
14 | // 3. Pass a truthy value to use the default color
15 | //
16 |
17 | // TODO: Possibly allow the user to customize the transition for the default
18 | // overlay. Maybe something like:
19 | //
20 | // {
21 | // overlay: {
22 | // color: '#000',
23 | // transitionDuration: '450ms'
24 | // }
25 | // }
26 | export default class Overlay extends Component {
27 | render() {
28 | const { config } = this.props;
29 |
30 | if (React.isValidElement(config)) {
31 | return config;
32 | } else if (!config) {
33 | return null;
34 | }
35 |
36 | let color;
37 | if (typeof config !== 'string') {
38 | if (process.env.NODE_ENV !== 'production') {
39 | warning(
40 | `You passed an invalid value as overlay when configuring a React Over element.` +
41 | ` The overlay option must be a React Element or a string.`,
42 | 'MISSING_CONFIG'
43 | );
44 | }
45 |
46 | color = defaultColor;
47 | } else {
48 | color = config || defaultColor;
49 | }
50 |
51 | return (
52 |
63 | );
64 | }
65 |
66 | componentWillEnter(cb) {
67 | if (!this.el) {
68 | return;
69 | }
70 |
71 | this.el.style.opacity = 0;
72 |
73 | requestAnimationFrame(() => {
74 | requestAnimationFrame(() => {
75 | if (!this.el) {
76 | cb();
77 | return;
78 | }
79 |
80 | this.el.style.transition = transition;
81 | this.el.style.opacity = 1;
82 | cb();
83 | });
84 | });
85 | }
86 |
87 | componentWillLeave(cb) {
88 | if (!this.el) {
89 | cb();
90 | return;
91 | }
92 |
93 | this.el.style.transition = transition;
94 | this.el.style.opacity = 0;
95 |
96 | setTimeout(cb, 300);
97 | }
98 |
99 | getRef = ref => {
100 | this.el = ref;
101 | };
102 | }
103 |
--------------------------------------------------------------------------------
/docs/src/vendor/react-over/simple-shallow-equals.js:
--------------------------------------------------------------------------------
1 | export default function simpleShallowEquals(a, b) {
2 | // Handle exact object matches and primitives
3 | if (a === b) {
4 | return true;
5 | }
6 |
7 | // When either value are null, then a strict equals comparison will return
8 | // the expected value.
9 | if (a === null || b === null) {
10 | return a === b;
11 | }
12 |
13 | const aKeys = Object.keys(a);
14 | const bKeys = Object.keys(b);
15 |
16 | // If they are both objects, then they must have the same
17 | // number of keys. Otherwise, they can't be shallowly equal!
18 | if (aKeys.length !== bKeys.length) {
19 | return false;
20 | }
21 |
22 | for (var prop in b) {
23 | if (a[prop] !== b[prop]) {
24 | return false;
25 | }
26 | }
27 |
28 | return true;
29 | }
30 |
--------------------------------------------------------------------------------
/docs/src/vendor/react-over/validate-over-config.js:
--------------------------------------------------------------------------------
1 | import { warning } from './warning';
2 |
3 | export default function validateOverConfig(config) {
4 | // The config object itself is required.
5 | if (!config) {
6 | if (process.env.NODE_ENV !== 'production') {
7 | warning(
8 | `You attempted to open an Over Element without passing a config.` +
9 | ` The config argument is required.`,
10 | 'MISSING_CONFIG'
11 | );
12 | }
13 |
14 | return false;
15 | }
16 |
17 | // Configs must have an ID.
18 | if (typeof config.id !== 'string' && typeof config.id !== 'number') {
19 | if (process.env.NODE_ENV !== 'production') {
20 | warning(
21 | `You attempted to open an Over Element with an invalid config.id.` +
22 | ` The ID must be a string or a number.`,
23 | 'INVALID_CONFIG_ID'
24 | );
25 | }
26 |
27 | return false;
28 | }
29 |
30 | return true;
31 | }
32 |
--------------------------------------------------------------------------------
/docs/src/vendor/react-over/warning.js:
--------------------------------------------------------------------------------
1 | let codeCache = {};
2 |
3 | export function warning(message, code) {
4 | // This ensures that each warning type is only logged out one time
5 | if (code) {
6 | if (codeCache[code]) {
7 | return;
8 | }
9 |
10 | codeCache[code] = true;
11 | }
12 |
13 | if (console && typeof console.error === 'function') {
14 | console.error(`Warning: ${message}`);
15 | }
16 |
17 | try {
18 | // This error was thrown as a convenience so that if you enable
19 | // "break on all exceptions" in your console,
20 | // it would pause the execution at this line.
21 | throw new Error(message);
22 | } catch (e) {
23 | // Intentionally blank
24 | }
25 | }
26 |
27 | export function resetCodeCache() {
28 | codeCache = {};
29 | }
30 |
--------------------------------------------------------------------------------
/src/action-chip/action-chip.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import PropTypes from 'prop-types';
3 | import Ripple from '../ripple/ripple';
4 |
5 | class ActionChip extends Component {
6 | render() {
7 | const {
8 | className = '',
9 | ripple = true,
10 | children,
11 | icon,
12 | nodeRef,
13 | ...props
14 | } = this.props;
15 |
16 | return (
17 |
24 | {icon &&
25 | React.cloneElement(icon, {
26 | className: `mt-chip_icon ${icon.props.className}`,
27 | })}
28 | {children}
29 | {ripple && props.onClick && }
30 |
31 | );
32 | }
33 |
34 | getRippleRef = component => {
35 | this.rippleComponent = component;
36 | };
37 |
38 | onClick = e => {
39 | const { onClick } = this.props;
40 |
41 | if (this.rippleComponent) {
42 | this.rippleComponent.onClick(e);
43 | }
44 |
45 | if (onClick) {
46 | onClick(e);
47 | }
48 | };
49 | }
50 |
51 | ActionChip.propTypes = {
52 | className: PropTypes.string,
53 | ripple: PropTypes.bool,
54 | onClick: PropTypes.func,
55 | };
56 |
57 | export default ActionChip;
58 |
--------------------------------------------------------------------------------
/src/avatar/avatar.css:
--------------------------------------------------------------------------------
1 | .mt-avatar {
2 | /*
3 | This (ugly) set of variables defines the variable fallback implementation.
4 |
5 | 1. If `mt-avatar-backgroundColor` is set, then that will be applied
6 | 2. Otherwise, `#ccc` will be applied
7 | */
8 | --_mt-avatar-backgroundColor: var(--mt-avatar-backgroundColor, #ccc);
9 | --_mt-avatar-color: var(--mt-avatar-color, #333);
10 | --_mt-avatar-bg-image: var(--mt-avatar-bg-image, 'none');
11 |
12 | font-size: var(--mt-baseFontSize, 1rem);
13 | font-family: var(--mt-fontFamily, 'Roboto');
14 | width: 2.5em;
15 | height: 2.5em;
16 | overflow: hidden;
17 | border-radius: 50%;
18 | display: inline-flex;
19 | align-items: center;
20 | justify-content: center;
21 | background-color: var(--_mt-avatar-backgroundColor);
22 | background-image: var(--_mt-avatar-bg-image);
23 | background-size: cover;
24 | background-position: center;
25 | color: var(--_mt-avatar-color);
26 | vertical-align: middle;
27 | }
28 |
29 | .mt-avatar_initials {
30 | font-size: 1.2em;
31 | width: 100%;
32 | text-align: center;
33 | }
34 |
--------------------------------------------------------------------------------
/src/avatar/avatar.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | class Avatar extends Component {
5 | render() {
6 | const {
7 | className = '',
8 | image,
9 | initials = '',
10 | style,
11 | nodeRef,
12 | ...props
13 | } = this.props;
14 |
15 | return (
16 |
24 | {!image &&
{initials}
}
25 |
26 | );
27 | }
28 | }
29 |
30 | Avatar.propTypes = {
31 | className: PropTypes.string,
32 | image: PropTypes.string,
33 | initials: PropTypes.string,
34 | };
35 |
36 | export default Avatar;
37 |
--------------------------------------------------------------------------------
/src/button/button.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import PropTypes from 'prop-types';
3 | import classnames from 'classnames';
4 | import Ripple from '../ripple/ripple';
5 |
6 | class Button extends Component {
7 | render() {
8 | const {
9 | children,
10 | className = '',
11 | raised = false,
12 | flat = false,
13 | stroked = false,
14 | compact = flat,
15 | ripple = true,
16 | nodeRef,
17 | ...otherProps
18 | } = this.props;
19 |
20 | const componentClassNames = classnames('mt-button', className, {
21 | 'mt-button-raised': raised,
22 | 'mt-button-flat': flat,
23 | 'mt-button-stroked': stroked,
24 | 'mt-button-compact': compact,
25 | });
26 |
27 | return (
28 |
33 | {ripple && }
34 | {children}
35 |
36 | );
37 | }
38 |
39 | getRippleRef = component => {
40 | this.rippleComponent = component;
41 | };
42 |
43 | onClick = e => {
44 | const { onClick } = this.props;
45 |
46 | if (this.rippleComponent) {
47 | this.rippleComponent.onClick(e);
48 | }
49 |
50 | if (onClick) {
51 | onClick(e);
52 | }
53 | };
54 | }
55 |
56 | Button.propTypes = {
57 | className: PropTypes.string,
58 | raised: PropTypes.bool,
59 | flat: PropTypes.bool,
60 | stroked: PropTypes.bool,
61 | compact: PropTypes.bool,
62 | ripple: PropTypes.bool,
63 | onClick: PropTypes.func,
64 | };
65 |
66 | export default Button;
67 |
--------------------------------------------------------------------------------
/src/checkbox/checkbox.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | class Checkbox extends Component {
5 | render() {
6 | const { className = '', style, nodeRef, ...props } = this.props;
7 | return (
8 |
18 | );
19 | }
20 | }
21 |
22 | Checkbox.propTypes = {
23 | className: PropTypes.string,
24 | style: PropTypes.object,
25 | };
26 |
27 | export default Checkbox;
28 |
--------------------------------------------------------------------------------
/src/choice-chip/choice-chip.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import PropTypes from 'prop-types';
3 | import Ripple from '../ripple/ripple';
4 |
5 | class ChoiceChip extends Component {
6 | render() {
7 | const {
8 | className = '',
9 | ripple = true,
10 | children,
11 | icon,
12 | nodeRef,
13 | ...props
14 | } = this.props;
15 |
16 | return (
17 |
18 |
24 | {icon &&
25 | React.cloneElement(icon, {
26 | className: `mt-chip_choiceIcon ${icon.props.className}`,
27 | })}
28 |
{children}
29 | {ripple &&
}
30 |
31 | );
32 | }
33 |
34 | getRippleRef = component => {
35 | this.rippleComponent = component;
36 | };
37 |
38 | onClick = e => {
39 | const { onClick } = this.props;
40 |
41 | if (this.rippleComponent) {
42 | this.rippleComponent.onClick(e);
43 | }
44 |
45 | if (onClick) {
46 | onClick(e);
47 | }
48 | };
49 | }
50 |
51 | ChoiceChip.propTypes = {
52 | className: PropTypes.string,
53 | ripple: PropTypes.bool,
54 | onClick: PropTypes.func,
55 | };
56 |
57 | export default ChoiceChip;
58 |
--------------------------------------------------------------------------------
/src/dialog/dialog.css:
--------------------------------------------------------------------------------
1 | .mt-dialog {
2 | font-family: var(--mt-fontFamily, 'Roboto');
3 | font-size: var(--mt-baseFontSize, 1rem);
4 | background-color: #fff;
5 | text-align: left;
6 | box-shadow: 0 11px 15px -7px rgba(0, 0, 0, 0.2), 0 24px 38px 3px rgba(0, 0, 0, 0.14), 0 9px 46px 8px rgba(0, 0, 0, 0.12);
7 | border-radius: 0.125em;
8 | }
9 |
10 | .mt-dialog_title {
11 | color: #212121;
12 | font-size: 1.25em;
13 | padding: 1.2em 1.2em 0;
14 | font-weight: 500;
15 | }
16 |
17 | .mt-dialog_content {
18 | color: #757575;
19 | margin: 1.25em 1.5em 1.5em;
20 | }
21 |
22 | .mt-dialog_actions {
23 | padding: 0.5em;
24 | display: flex;
25 | justify-content: flex-end;
26 | }
27 |
28 | .mt-dialog_actions .mt-button+.mt-button {
29 | margin-left: 0.43em;
30 | }
31 |
--------------------------------------------------------------------------------
/src/dialog/dialog.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | class Dialog extends Component {
5 | static Title = ({ className = '', nodeRef, ...props }) => (
6 |
7 | );
8 | static Body = ({ className = '', nodeRef, ...props }) => (
9 |
14 | );
15 |
16 | static Actions = ({ className = '', nodeRef, ...props }) => (
17 |
22 | );
23 |
24 | render() {
25 | const { className = '', nodeRef, ...props } = this.props;
26 | return (
27 |
28 | );
29 | }
30 | }
31 |
32 | Dialog.propTypes = {
33 | className: PropTypes.string,
34 | };
35 |
36 | export default Dialog;
37 |
--------------------------------------------------------------------------------
/src/elevation/elevation.css:
--------------------------------------------------------------------------------
1 | .mt-elevation {
2 | font-size: var(--mt-baseFontSize, 1rem);
3 | font-family: var(--mt-fontFamily, 'Roboto');
4 | background: #fff;
5 | border-radius: 0.125em;
6 | display: inline-block;
7 | position: relative;
8 | transition: box-shadow 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
9 | }
10 |
11 | mt-elevation-0 {
12 | box-shadow: none;
13 | }
14 |
15 | .mt-elevation-1 {
16 | box-shadow: 0 3px 1px -2px rgba(0, 0, 0, .2), 0 2px 2px 0 rgba(0, 0, 0, .14), 0 1px 5px 0 rgba(0, 0, 0, .12);
17 | }
18 |
19 | .mt-elevation-2 {
20 | box-shadow: 0 4px 5px -2px rgba(0, 0, 0, .2), 0 7px 10px 1px rgba(0, 0, 0, .14), 0 2px 16px 1px rgba(0, 0, 0, .12);
21 | }
22 |
23 | .mt-elevation-3 {
24 | box-shadow: 0 7px 8px -4px rgba(0, 0, 0, .2), 0 12px 17px 2px rgba(0, 0, 0, .14), 0 5px 22px 4px rgba(0, 0, 0, .12);
25 | }
26 |
27 | .mt-elevation-4 {
28 | box-shadow: 0 9px 11px -5px rgba(0, 0, 0, .2), 0 18px 28px 2px rgba(0, 0, 0, .14), 0 7px 34px 6px rgba(0, 0, 0, .12);
29 | }
30 |
31 | .mt-elevation-5 {
32 | box-shadow: 0 11px 15px -7px rgba(0, 0, 0, .2), 0 24px 38px 3px rgba(0, 0, 0, .14), 0 9px 46px 8px rgba(0, 0, 0, .12);
33 | }
34 |
--------------------------------------------------------------------------------
/src/elevation/elevation.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | function clamp(min, val, max) {
5 | return Math.min(Math.max(min, val), max);
6 | }
7 |
8 | class Elevation extends Component {
9 | render() {
10 | const { className = '', depth = 1, nodeRef, ...props } = this.props;
11 |
12 | const depthToUse = Number.isNaN(depth) ? 1 : depth;
13 | const clampedDepth = clamp(0, depthToUse, 5);
14 |
15 | return (
16 |
21 | );
22 | }
23 | }
24 |
25 | Elevation.propTypes = {
26 | className: PropTypes.string,
27 | depth: PropTypes.oneOf([0, 1, 2, 3, 4, 5]),
28 | };
29 |
30 | export default Elevation;
31 |
--------------------------------------------------------------------------------
/src/expandable/expandable.css:
--------------------------------------------------------------------------------
1 | .mt-expandable {
2 | height: 0;
3 | overflow: hidden;
4 | }
5 |
6 | .mt-expandable-open {
7 | height: auto;
8 | }
9 |
--------------------------------------------------------------------------------
/src/expansion-panel/expansion-panel.css:
--------------------------------------------------------------------------------
1 | .mt-expansionPanel {
2 | font-size: var(--mt-baseFontSize, 1rem);
3 | font-family: var(--mt-fontFamily, 'Roboto');
4 | display: block;
5 | box-shadow: 0 -1px 0 #e5e5e5, 0 0 2px rgba(0, 0, 0, 0.12),
6 | 0 2px 4px rgba(0, 0, 0, 0.24);
7 | background-color: #fff;
8 | transition: margin 0.2s ease-out;
9 | }
10 |
11 | .mt-expansionPanel-open {
12 | margin: 0 0 1em 0;
13 | }
14 |
15 | .mt-expansionPanel + .mt-expansionPanel-open {
16 | margin: 1em 0;
17 | }
18 |
19 | .mt-expansionPanel_header {
20 | padding: 0.75em 3em 0.75em 1.5em;
21 | position: relative;
22 | }
23 |
24 | .mt-expansionPanel_icon {
25 | width: 1.5em;
26 | height: 1.5em;
27 | fill: #666;
28 | position: absolute;
29 | right: 1em;
30 | top: calc(50% - 0.75em);
31 | will-change: transform;
32 | transition: transform 0.2s ease-out;
33 | }
34 |
35 | .mt-expansionPanel-open .mt-expansionPanel_icon {
36 | transform: rotate(180deg);
37 | }
38 |
39 | .mt-expansionPanel_bodyWrapper {
40 | padding: 0.5em 1.5em 1.5em;
41 | }
42 |
--------------------------------------------------------------------------------
/src/expansion-panel/expansion-panel.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import Expandable from '../expandable/expandable';
3 | import IconKeyboardArrowDown from '../icons/icon-keyboard-arrow-down';
4 |
5 | export default class ExpansionPanel extends Component {
6 | static Header = ({ className = '', children, nodeRef, ...props }) => {
7 | return (
8 |
12 | {children}
13 |
17 |
18 | );
19 | };
20 |
21 | static Body = ({
22 | className = '',
23 | children,
24 | open = false,
25 | nodeRef,
26 | ...props
27 | }) => {
28 | return (
29 |
33 |
34 | {children}
35 |
36 |
37 | );
38 | };
39 |
40 | render() {
41 | const {
42 | className = '',
43 | children,
44 | open = false,
45 | nodeRef,
46 | ...props
47 | } = this.props;
48 |
49 | return (
50 |
56 | {React.Children.map(children, child =>
57 | React.cloneElement(child, { open })
58 | )}
59 |
60 | );
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/field/field.css:
--------------------------------------------------------------------------------
1 | .mt-field {
2 | --_mt-field-labelColor: var(--mt-field-labelColor, #757575);
3 | --_mt-field-labelErrorColor: var(--mt-field-labelErrorColor, #f34335);
4 |
5 | font-size: var(--mt-baseFontSize, 1rem);
6 | font-family: var(--mt-fontFamily, 'Roboto');
7 | display: inline-block;
8 | vertical-align: text-top;
9 | }
10 |
11 | .mt-field_label {
12 | font-size: 0.875em;
13 | padding: 0 0 0.7em;
14 | color: var(--_mt-field-labelColor);
15 | display: inline-flex;
16 | align-items: center;
17 | position: relative;
18 | }
19 |
20 | .mt-field_label > svg {
21 | fill: var(--_mt-field-labelColor);
22 | margin: 0 0.2em;
23 | }
24 |
25 | .mt-field_errorMessage {
26 | font-size: 0.875em;
27 | padding: 0.7em 0;
28 | color: var(--_mt-field-labelErrorColor);
29 | display: flex;
30 | align-items: center;
31 | margin-top: -2.6em;
32 | }
33 |
34 | .mt-field_errorMessage > svg {
35 | fill: var(--_mt-field-labelErrorColor);
36 | margin: 0 0.2em;
37 | }
38 |
39 | .mt-field_errorMessage > svg:first-child,
40 | .mt-field_label > svg:first-child {
41 | margin: 0 0.2em 0 0;
42 | }
43 |
44 | .mt-field-required > .mt-field_label:after {
45 | content: '*';
46 | font-size: 1.3em;
47 | color: var(--_mt-field-labelErrorColor);
48 | position: absolute;
49 | right: -0.6em;
50 | }
51 |
52 | .mt-field > .mt-input_container,
53 | .mt-field > .mt-input,
54 | .mt-field > .mt-textarea {
55 | display: block;
56 | margin-bottom: 2.5em;
57 | }
58 |
--------------------------------------------------------------------------------
/src/field/field.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import PropTypes from 'prop-types';
3 | import InputComponent from '../input/input';
4 | import TextAreaComponent from '../text-area/text-area';
5 |
6 | export default class Field extends Component {
7 | static Input = InputComponent;
8 | static TextArea = TextAreaComponent;
9 |
10 | static Label = ({ className = '', children, nodeRef, ...props }) => (
11 |
12 | {children}
13 |
14 | );
15 |
16 | static ErrorMessage = ({ className = '', nodeRef, ...props }) => (
17 |
22 | );
23 |
24 | render() {
25 | const { className = '', required = false, nodeRef, ...props } = this.props;
26 |
27 | return (
28 |
35 | );
36 | }
37 | }
38 |
39 | Field.Label.propTypes = {
40 | className: PropTypes.string,
41 | };
42 |
43 | Field.ErrorMessage.propTypes = {
44 | className: PropTypes.string,
45 | };
46 |
47 | Field.propTypes = {
48 | className: PropTypes.string,
49 | required: PropTypes.bool,
50 | };
51 |
--------------------------------------------------------------------------------
/src/filter-chip/filter-chip.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import PropTypes from 'prop-types';
3 | import Ripple from '../ripple/ripple';
4 |
5 | class FilterChip extends Component {
6 | render() {
7 | const {
8 | className = '',
9 | ripple = true,
10 | icon,
11 | children,
12 | nodeRef,
13 | ...props
14 | } = this.props;
15 |
16 | return (
17 |
18 |
24 | {icon &&
25 | React.cloneElement(icon, {
26 | className: `mt-chip_icon ${icon.props.className}`,
27 | })}
28 |
29 |
35 |
36 |
{children}
37 | {ripple &&
}
38 |
39 | );
40 | }
41 |
42 | getRippleRef = component => {
43 | this.rippleComponent = component;
44 | };
45 |
46 | onClick = e => {
47 | const { onClick } = this.props;
48 |
49 | if (this.rippleComponent) {
50 | this.rippleComponent.onClick(e);
51 | }
52 |
53 | if (onClick) {
54 | onClick(e);
55 | }
56 | };
57 | }
58 |
59 | FilterChip.propTypes = {
60 | className: PropTypes.string,
61 | ripple: PropTypes.bool,
62 | icon: PropTypes.element,
63 | onClick: PropTypes.func,
64 | };
65 |
66 | export default FilterChip;
67 |
--------------------------------------------------------------------------------
/src/icon-button/icon-button.css:
--------------------------------------------------------------------------------
1 | .mt-iconButton {
2 | --_mt-iconButton-color: var(--mt-iconButton-color, #6d6c6c);
3 | --_mt-iconButton-disabledColor: var(
4 | --mt-iconButton-disabledColor,
5 | rgba(0, 0, 0, 0.38)
6 | );
7 |
8 | all: initial;
9 | font-size: calc(1.5 * var(--mt-baseFontSize, 1rem));
10 | border: none;
11 | position: relative;
12 | width: 2em;
13 | height: 2em;
14 | border-radius: 2em;
15 | cursor: pointer;
16 | outline: none;
17 | background-color: transparent;
18 | -webkit-mask-image: -webkit-radial-gradient(white, black);
19 | touch-action: manipulation;
20 | z-index: 0;
21 |
22 | --mt-ripple-color: var(--_mt-iconButton-color);
23 | --mt-ripple-spread: 1.2;
24 | }
25 |
26 | .mt-iconButton:after {
27 | content: '';
28 | position: absolute;
29 | top: 0;
30 | left: 0;
31 | right: 0;
32 | bottom: 0;
33 | background-color: var(--_mt-iconButton-color);
34 | opacity: 0;
35 | border-radius: 2em;
36 | z-index: -1;
37 | }
38 |
39 | .mt-iconButton:hover:after,
40 | .mt-iconButton:focus:after {
41 | opacity: 0.1;
42 | }
43 |
44 | .mt-iconButton > svg {
45 | position: absolute;
46 | top: 50%;
47 | left: 50%;
48 | transform: translate3d(-50%, -50%, 0);
49 | fill: var(--_mt-iconButton-color);
50 | pointer-events: none;
51 | }
52 |
53 | .mt-iconButton:disabled {
54 | cursor: default;
55 | }
56 |
57 | .mt-iconButton:disabled > svg {
58 | fill: var(--_mt-iconButton-disabledColor);
59 | }
60 |
61 | .mt-iconButton:disabled:hover:after,
62 | .mt-iconButton:disabled:focus:after {
63 | opacity: 0;
64 | }
65 |
--------------------------------------------------------------------------------
/src/icon-button/icon-button.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import Ripple from '../ripple/ripple';
3 | import PropTypes from 'prop-types';
4 |
5 | export default class IconButton extends Component {
6 | render() {
7 | const {
8 | className = '',
9 | ripple = true,
10 | children,
11 | nodeRef,
12 | ...props
13 | } = this.props;
14 |
15 | return (
16 |
21 | {children}
22 | {ripple && }
23 |
24 | );
25 | }
26 |
27 | getRippleRef = component => {
28 | this.rippleComponent = component;
29 | };
30 |
31 | onClick = e => {
32 | const { onClick } = this.props;
33 |
34 | if (this.rippleComponent) {
35 | this.rippleComponent.onClick(e);
36 | }
37 |
38 | if (onClick) {
39 | onClick(e);
40 | }
41 | };
42 | }
43 |
44 | IconButton.propTypes = {
45 | ripple: PropTypes.bool,
46 | className: PropTypes.string,
47 | };
48 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import Ripple from './ripple/ripple';
2 | import Button from './button/button';
3 | import Checkbox from './checkbox/checkbox';
4 | import Switch from './switch/switch';
5 | import Avatar from './avatar/avatar';
6 | import Spinner from './spinner/spinner';
7 | import LoadingDots from './loading-dots/loading-dots';
8 | import Radio from './radio/radio';
9 | import Dialog from './dialog/dialog';
10 | import Elevation from './elevation/elevation';
11 | import InputChip from './input-chip/input-chip';
12 | import ActionChip from './action-chip/action-chip';
13 | import ChoiceChip from './choice-chip/choice-chip';
14 | import FilterChip from './filter-chip/filter-chip';
15 | import Menu from './menu/menu';
16 | import Snackbar from './snackbar/snackbar';
17 | import Table from './table/table';
18 | import Input from './input/input';
19 | import TextArea from './text-area/text-area';
20 | import IconButton from './icon-button/icon-button';
21 | import Field from './field/field';
22 | import Expandable from './expandable/expandable';
23 | import ExpansionPanel from './expansion-panel/expansion-panel';
24 | import ProgressBar from './progress-bar/progress-bar';
25 | import Navigation from './navigation/navigation';
26 |
27 | export {
28 | Avatar,
29 | Button,
30 | Checkbox,
31 | Ripple,
32 | Spinner,
33 | LoadingDots,
34 | Switch,
35 | Radio,
36 | Dialog,
37 | Elevation,
38 | InputChip,
39 | ActionChip,
40 | ChoiceChip,
41 | FilterChip,
42 | Menu,
43 | Snackbar,
44 | Table,
45 | Input,
46 | TextArea,
47 | IconButton,
48 | Field,
49 | Expandable,
50 | ExpansionPanel,
51 | ProgressBar,
52 | Navigation,
53 | };
54 |
--------------------------------------------------------------------------------
/src/input-chip/input-chip.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import PropTypes from 'prop-types';
3 | import Ripple from '../ripple/ripple';
4 |
5 | export default class InputChip extends Component {
6 | render() {
7 | const {
8 | className = '',
9 | onClose,
10 | icon,
11 | ripple = true,
12 | children,
13 | nodeRef,
14 | ...props
15 | } = this.props;
16 |
17 | return (
18 |
24 | {icon &&
25 | React.cloneElement(icon, {
26 | className: `mt-chip_icon ${icon.props.className}`,
27 | })}
28 |
{children}
29 | {onClose && (
30 |
37 |
38 |
39 | )}
40 | {ripple && props.onClick &&
}
41 |
42 | );
43 | }
44 |
45 | getRippleRef = component => {
46 | this.rippleComponent = component;
47 | };
48 |
49 | onClose = e => {
50 | const { onClose } = this.props;
51 | e.stopPropagation();
52 | onClose(e);
53 | };
54 |
55 | onClick = e => {
56 | const { onClick } = this.props;
57 |
58 | if (this.rippleComponent) {
59 | this.rippleComponent.onClick(e);
60 | }
61 |
62 | if (onClick) {
63 | onClick(e);
64 | }
65 | };
66 | }
67 |
68 | InputChip.propTypes = {
69 | className: PropTypes.string,
70 | icon: PropTypes.element,
71 | ripple: PropTypes.bool,
72 | onClose: PropTypes.func,
73 | onClick: PropTypes.func,
74 | };
75 |
--------------------------------------------------------------------------------
/src/input/input.css:
--------------------------------------------------------------------------------
1 | .mt-input_container,
2 | .mt-textarea {
3 | --_mt-input-focusBorderColor: var(
4 | --mt-input-focusBorderColor,
5 | var(--mt-mainColor, #4a8fe2)
6 | );
7 |
8 | font-size: calc(var(--mt-baseFontSize) * 0.875);
9 | font-family: var(--mt-fontFamily, 'Roboto');
10 | }
11 |
12 | .mt-input_container {
13 | position: relative;
14 | display: inline-block;
15 | }
16 |
17 | .mt-input {
18 | font-size: 1em;
19 | }
20 |
21 | .mt-input,
22 | .mt-textarea {
23 | border: 1px solid #e1e0e0;
24 | padding: 0.85em 0.8em;
25 | border-radius: 0.1875em;
26 | min-width: 18.75em;
27 | outline: none;
28 | background-color: #fff;
29 | /* Removes the box-shadow from iOS */
30 | -webkit-appearance: none;
31 | resize: none;
32 | }
33 |
34 | .mt-input-clearable {
35 | padding-right: 2.6em;
36 | }
37 |
38 | .mt-input-withIcon {
39 | padding-left: 2.6em;
40 | }
41 |
42 | .mt-input::placeholder,
43 | .mt-textarea::placeholder {
44 | color: #9e9d9d;
45 | }
46 |
47 | .mt-input:focus,
48 | .mt-textarea:focus {
49 | box-shadow: 0 0 0 1px var(--_mt-input-focusBorderColor);
50 | border: 1px solid var(--_mt-input-focusBorderColor);
51 | caret-color: var(--_mt-input-focusBorderColor);
52 | }
53 |
54 | .mt-input-error,
55 | .mt-textarea-error {
56 | border: 1px solid #e69c96;
57 | }
58 |
59 | .mt-input-error:focus,
60 | .mt-textarea-error:focus {
61 | box-shadow: 0 0 0 1px #f34335;
62 | border: 1px solid #f34335;
63 | caret-color: #f34335;
64 | }
65 |
66 | .mt-input:disabled,
67 | .mt-textarea:disabled {
68 | border-color: #e1e0e0;
69 | background-color: #f9f9f9f9;
70 | color: #9e9d9d;
71 | }
72 |
73 | .mt-input:read-only,
74 | .mt-input:read-only:focus,
75 | .mt-textarea:read-only,
76 | .mt-textarea:read-only:focus {
77 | cursor: default;
78 | box-shadow: none;
79 | border-color: #e1e0e0;
80 | }
81 |
82 | .mt-input_closeBtn {
83 | position: absolute;
84 | top: 50%;
85 | right: 0.625em;
86 | fill: #999;
87 | transform: translateY(-50%);
88 | cursor: pointer;
89 | outline: none;
90 | border: 2px solid transparent;
91 | border-radius: 3px;
92 | box-sizing: border-box;
93 | opacity: 0;
94 | will-change: opacity;
95 | transition: opacity 300ms ease-in-out;
96 | pointer-events: none;
97 | }
98 |
99 | .mt-input_closeBtn:focus {
100 | border-color: var(--_mt-input-focusBorderColor);
101 | }
102 |
103 | .mt-input_closeBtn-visible {
104 | opacity: 1;
105 | pointer-events: all;
106 | }
107 |
108 | .mt-input:disabled + .mt-input_closeBtn-visible {
109 | opacity: 0;
110 | pointer-events: none;
111 | }
112 |
113 | .mt-input-icon {
114 | position: absolute;
115 | left: 0.625em;
116 | top: 50%;
117 | transform: translateY(-50%);
118 | fill: #999;
119 | pointer-events: none;
120 | }
121 |
122 | .mt-input_container-disabled .mt-input-icon {
123 | opacity: 0.75;
124 | }
125 |
--------------------------------------------------------------------------------
/src/loading-dots/loading-dots.css:
--------------------------------------------------------------------------------
1 | .mt-loadingDots_circle {
2 | fill: var(--mt-loadingDots-fill, #000);
3 | animation: mt-loadingDots-jump var(--mt-loadingDots-animationDuration, 300ms)
4 | cubic-bezier(0.68, 0.06, 0.68, 0.42) infinite alternate;
5 | transform-origin: center;
6 | animation-delay: var(--mt-loadingDots-delay, 0);
7 | will-change: transform;
8 | }
9 |
10 | .mt-loadingDots_two {
11 | --mt-loadingDots-delay: 0.1s;
12 | }
13 |
14 | .mt-loadingDots_three {
15 | --mt-loadingDots-delay: 0.2s;
16 | }
17 |
18 | @keyframes mt-loadingDots-jump {
19 | 0%,
20 | 10% {
21 | transform: translate3d(0, 0, 0);
22 | }
23 | 100% {
24 | transform: translate3d(0, 15px, 0);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/loading-dots/loading-dots.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | export default class LoadingDots extends Component {
5 | render() {
6 | const {
7 | size = 'calc(var(--mt-baseFontSize, 1rem) * 1.125)',
8 | style,
9 | nodeRef,
10 | ...rest
11 | } = this.props;
12 |
13 | return (
14 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | );
34 | }
35 | }
36 |
37 | LoadingDots.propTypes = {
38 | size: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
39 | };
40 |
--------------------------------------------------------------------------------
/src/menu/menu.css:
--------------------------------------------------------------------------------
1 | .mt-menu {
2 | --mt-ripple-color: #666;
3 | all: initial;
4 | font-size: calc(var(--mt-baseFontSize, 1rem) * 0.875);
5 | font-family: var(--mt-fontFamily, 'Roboto');
6 | position: relative;
7 | box-sizing: border-box;
8 | border-radius: 2px;
9 | text-align: left;
10 | margin: 0;
11 | padding: 0.55em 0;
12 | display: inline-block;
13 | background-color: #fff;
14 | min-width: 10em;
15 | overflow: hidden;
16 | }
17 |
18 | .mt-menu_item {
19 | position: relative;
20 | box-sizing: border-box;
21 | display: block;
22 | min-height: var(--mt-menuItemMinHeight);
23 | margin: 0;
24 | padding: 1.1em 1.7em;
25 | z-index: 0;
26 | cursor: pointer;
27 | }
28 |
29 | .mt-menu_item:after {
30 | content: '';
31 | display: block;
32 | position: absolute;
33 | top: 0;
34 | left: 0;
35 | right: 0;
36 | bottom: 0;
37 | background-color: #eee;
38 | z-index: -1;
39 | opacity: 0;
40 | will-change: opacity;
41 | transition: opacity 0.1s ease-in-out;
42 | }
43 |
44 | .mt-menu_item:hover:after {
45 | opacity: 1;
46 | }
47 |
48 | .mt-menu_separator {
49 | height: 0px;
50 | border-bottom: 1px solid #e3e2e2;
51 | }
52 |
53 | .mt-menu_item-selected:after {
54 | background-color: #e1e0e0;
55 | opacity: 1;
56 | }
57 |
--------------------------------------------------------------------------------
/src/menu/menu.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import PropTypes from 'prop-types';
3 | import Ripple from '../ripple/ripple';
4 | import Elevation from '../elevation/elevation';
5 |
6 | export default class Menu extends Component {
7 | render() {
8 | const { className = '', nodeRef, ...props } = this.props;
9 | return (
10 |
11 |
12 |
13 | );
14 | }
15 | }
16 |
17 | Menu.propTypes = {
18 | className: PropTypes.string,
19 | };
20 |
21 | class Item extends Component {
22 | render() {
23 | const {
24 | className = '',
25 | selected = false,
26 | ripple = true,
27 | children,
28 | nodeRef,
29 | ...props
30 | } = this.props;
31 |
32 | return (
33 |
40 | {children}
41 | {ripple && }
42 |
43 | );
44 | }
45 |
46 | getRippleRef = component => {
47 | this.rippleComponent = component;
48 | };
49 |
50 | onClick = e => {
51 | const { onClick } = this.props;
52 |
53 | if (this.rippleComponent) {
54 | this.rippleComponent.onClick(e);
55 | }
56 |
57 | if (onClick) {
58 | onClick(e);
59 | }
60 | };
61 | }
62 |
63 | Item.propTypes = {
64 | className: PropTypes.string,
65 | selected: PropTypes.bool,
66 | ripple: PropTypes.bool,
67 | };
68 |
69 | function Separator(props) {
70 | const { className, nodeRef, ...rest } = props;
71 |
72 | return (
73 |
74 | );
75 | }
76 |
77 | Separator.propTypes = {
78 | className: PropTypes.string,
79 | };
80 |
81 | Menu.Item = Item;
82 | Menu.Separator = Separator;
83 |
--------------------------------------------------------------------------------
/src/navigation/navigation.css:
--------------------------------------------------------------------------------
1 | .mt-navigation {
2 | --_mt-navigation-color: var(
3 | --mt-navigation-color,
4 | var(--mt-mainColor, #2196f3)
5 | );
6 |
7 | width: 100%;
8 | font-size: calc(0.875 * var(--mt-baseFontSize, 1rem));
9 | font-family: var(--mt-fontFamily, 'Roboto');
10 | background-color: #fff;
11 | display: flex;
12 | color: #757575;
13 | list-style: none;
14 | box-sizing: border-box;
15 | -webkit-font-smoothing: antialiased;
16 | font-weight: 500;
17 | position: relative;
18 | align-items: stretch;
19 |
20 | --mt-ripple-color: var(--_mt-navigation-color);
21 | }
22 |
23 | .mt-navigation-vertical {
24 | display: inline-flex;
25 | flex-direction: column;
26 | width: auto;
27 | }
28 |
29 | .mt-navigation-centered {
30 | justify-content: center;
31 | }
32 |
33 | .mt-navigation-fullWidth .mt-navigation_item {
34 | flex: 1;
35 | }
36 |
37 | .mt-navigation_item {
38 | font-size: 1em;
39 | font-family: inherit;
40 | min-width: 6.5em;
41 | text-align: center;
42 | text-transform: uppercase;
43 | overflow: hidden;
44 | position: relative;
45 | z-index: 0;
46 | padding: 1.15em 1em;
47 | display: flex;
48 | flex-direction: column;
49 | justify-content: center;
50 | align-items: center;
51 | cursor: pointer;
52 | text-decoration: none;
53 | color: inherit;
54 | border: none;
55 | outline: none;
56 | background-color: transparent;
57 | }
58 |
59 | .mt-navigation_item:after {
60 | content: '';
61 | display: block;
62 | position: absolute;
63 | top: 0;
64 | left: 0;
65 | right: 0;
66 | bottom: 0;
67 | background-color: #000;
68 | opacity: 0;
69 | z-index: -1;
70 | }
71 |
72 | .mt-navigation_item:hover:after,
73 | .mt-navigation_item:focus:after {
74 | opacity: 0.03;
75 | }
76 |
77 | .mt-navigation_item > svg {
78 | --_mt-iconSize: 1.7em;
79 | fill: #757575;
80 | }
81 |
82 | .mt-navigation_item-active {
83 | color: var(--_mt-navigation-color);
84 | }
85 |
86 | .mt-navigation_item-active > svg {
87 | fill: var(--_mt-navigation-color);
88 | }
89 |
90 | .mt-navigation-vertical .mt-navigation_item {
91 | text-align: left;
92 | justify-content: flex-start;
93 | flex-direction: row;
94 | min-width: auto;
95 | }
96 |
97 | .mt-navigation_tracker {
98 | position: absolute;
99 | left: var(--mt-tracker-left, 0);
100 | bottom: 0;
101 | width: var(--mt-tracker-width, 8.5em);
102 | height: 3px;
103 | background-color: var(--_mt-navigation-color);
104 | transform: translateX(0);
105 | transform-origin: top left;
106 | transition: transform 0.2s ease-out;
107 | }
108 |
109 | .mt-navigation-vertical .mt-navigation_tracker {
110 | width: 3px;
111 | height: var(--mt-tracker-height);
112 | top: var(--mt-tracker-top, 0);
113 | bottom: initial;
114 | left: 0;
115 | }
116 |
--------------------------------------------------------------------------------
/src/progress-bar/progress-bar.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | export default class ProgressBar extends Component {
5 | render() {
6 | const {
7 | className = '',
8 | style = {},
9 | loaded = 0,
10 | buffered = 100,
11 | indeterminate = false,
12 | nodeRef,
13 | } = this.props;
14 |
15 | return (
16 |
30 | );
31 | }
32 | }
33 |
34 | ProgressBar.propTypes = {
35 | className: PropTypes.string,
36 | style: PropTypes.object,
37 | loaded: PropTypes.number,
38 | buffered: PropTypes.number,
39 | indeterminate: PropTypes.bool,
40 | };
41 |
--------------------------------------------------------------------------------
/src/radio/radio.css:
--------------------------------------------------------------------------------
1 | .mt-radio {
2 | --_mt-radio-checkedColor: var(
3 | --mt-radio-checkedColor,
4 | var(--mt-mainColor, #2196f3)
5 | );
6 | --_mt-radio-focusColor: var(--mt-radio-focusColor, #e8e8e8);
7 |
8 | font-size: var(--mt-baseFontSize, 1rem);
9 | position: relative;
10 | height: 1.25em;
11 | width: 1.25em;
12 | z-index: 0;
13 | display: inline-block;
14 | }
15 |
16 | .mt-radio_input {
17 | width: 100%;
18 | height: 100%;
19 | border: none;
20 | border-radius: 0;
21 | display: inline-block;
22 | position: absolute;
23 | top: 0;
24 | left: 0;
25 | right: 0;
26 | bottom: 0;
27 | opacity: 0;
28 | display: block;
29 | cursor: pointer;
30 | z-index: 20;
31 | transform: translateZ(0);
32 | margin: 0;
33 | padding: 0;
34 | }
35 |
36 | .mt-radio_radio {
37 | width: 100%;
38 | height: 100%;
39 | border-radius: 50%;
40 | border: 2px solid #6f6e6e;
41 | box-sizing: border-box;
42 | position: relative;
43 | }
44 |
45 | .mt-radio_radio:before,
46 | .mt-radio_radio:after {
47 | content: '';
48 | position: absolute;
49 | height: 0.75em;
50 | width: 0.75em;
51 | top: calc(50% - 0.375em);
52 | left: calc(50% - 0.375em);
53 | background-color: var(--_mt-radio-checkedColor);
54 | border-radius: 50%;
55 | transform: scale(0);
56 | transition: transform 0.2s cubic-bezier(0, 0, 0.2, 1);
57 | will-change: transform;
58 | }
59 |
60 | .mt-radio_input:checked + .mt-radio_radio {
61 | border-color: var(--_mt-radio-checkedColor);
62 | }
63 |
64 | .mt-radio_input:disabled + .mt-radio_radio {
65 | border-color: #b3b2b2;
66 | }
67 |
68 | .mt-radio_input:checked:disabled + .mt-radio_radio:before {
69 | background-color: #b3b2b2;
70 | }
71 |
72 | .mt-radio_input:checked + .mt-radio_radio:before {
73 | transform: scale(1);
74 | }
75 |
76 | .mt-radio_focus {
77 | position: absolute;
78 | top: -0.4em;
79 | bottom: -0.4em;
80 | left: -0.4em;
81 | right: -0.4em;
82 | opacity: 0;
83 | z-index: -1;
84 | transition: opacity 0.2s ease-out;
85 | will-change: opacity;
86 | }
87 |
88 | .mt-radio_focus:before {
89 | position: absolute;
90 | top: 1px;
91 | left: 1px;
92 | right: 1px;
93 | bottom: 1px;
94 | content: '';
95 | background-color: var(--_mt-radio-focusColor);
96 | border-radius: 50%;
97 | }
98 |
99 | .mt-radio_input:focus + .mt-radio_radio + .mt-radio_focus {
100 | opacity: 1;
101 | }
102 |
103 | .mt-radio_input:checked:focus + .mt-radio_radio + .mt-radio_focus:before {
104 | background-color: var(--_mt-radio-checkedColor);
105 | opacity: 0.3;
106 | }
107 |
--------------------------------------------------------------------------------
/src/radio/radio.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | class Radio extends Component {
5 | render() {
6 | const { className = '', style, nodeRef, ...props } = this.props;
7 |
8 | return (
9 |
19 | );
20 | }
21 | }
22 |
23 | Radio.propTypes = {
24 | className: PropTypes.string,
25 | style: PropTypes.object,
26 | };
27 |
28 | export default Radio;
29 |
--------------------------------------------------------------------------------
/src/ripple/ripple.css:
--------------------------------------------------------------------------------
1 | .mt-ripple {
2 | --_mt-ripple-spread: var(--mt-ripple-spread, 4);
3 | --_mt-ripple-color: var(--mt-ripple-color, #fff);
4 | --_mt-ripple-top: var(--mt-ripple-top, 50%);
5 | --_mt-ripple-left: var(--mt-ripple-left, 50%);
6 |
7 | all: initial;
8 | font-size: inherit;
9 |
10 | position: absolute;
11 | display: block;
12 | top: 0;
13 | bottom: 0;
14 | left: 0;
15 | right: 0;
16 | overflow: hidden;
17 | pointer-events: none;
18 | }
19 |
20 | .mt-ripple::after {
21 | content: '';
22 | position: absolute;
23 | top: var(--_mt-ripple-top);
24 | left: var(--_mt-ripple-left);
25 | margin-top: calc(-0.625 * 1em);
26 | margin-left: calc(-0.625 * 1em);
27 | width: 1.25em;
28 | height: 1.25em;
29 | border-radius: 200%;
30 | background-color: var(--_mt-ripple-color);
31 | will-change: transform;
32 | opacity: 0;
33 | pointer-events: none;
34 | }
35 |
36 | .mt-ripple-active::after {
37 | animation: ripple 0.6s;
38 | }
39 |
40 | @keyframes ripple {
41 | from {
42 | opacity: 0.3;
43 | transform: scale(var(--_mt-ripple-spread));
44 | }
45 |
46 | to {
47 | transform: scale(calc(4 * var(--_mt-ripple-spread)));
48 | opacity: 0;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/ripple/ripple.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import classnames from 'classnames';
3 |
4 | class Ripple extends Component {
5 | render() {
6 | const { active, top, left } = this.state;
7 |
8 | const classname = classnames('mt-ripple', {
9 | 'mt-ripple-active': active,
10 | });
11 | const styles = {
12 | '--mt-ripple-top': top,
13 | '--mt-ripple-left': left,
14 | };
15 |
16 | return
;
17 | }
18 |
19 | state = {
20 | active: false,
21 | top: 0,
22 | left: 0,
23 | };
24 |
25 | componentWillUnmount() {
26 | clearTimeout(this.activeTimeout);
27 | }
28 |
29 | onClick = e => {
30 | const wasMouseClick = e.nativeEvent.x && e.nativeEvent.y;
31 | const left = wasMouseClick ? `${e.nativeEvent.layerX}px` : '50%';
32 | const top = wasMouseClick ? `${e.nativeEvent.layerY}px` : '50%';
33 |
34 | this.setState({
35 | active: false,
36 | top,
37 | left,
38 | });
39 |
40 | this.activeTimeout = setTimeout(() => {
41 | this.setState({
42 | active: true,
43 | });
44 | }, 25);
45 | };
46 | }
47 |
48 | export default Ripple;
49 |
--------------------------------------------------------------------------------
/src/snackbar/snackbar.css:
--------------------------------------------------------------------------------
1 | .mt-snackbar {
2 | all: initial;
3 | background-color: #323232;
4 | color: #fff;
5 | font-size: calc(var(--mt-baseFontSize, 1rem) * 0.875);
6 | font-family: var(--mt-fontFamily, 'Roboto');
7 | padding: 0 1.5em;
8 | display: inline-block;
9 | border-radius: 0.125em;
10 | box-sizing: border-box;
11 | align-items: center;
12 | height: 3em;
13 | line-height: 3em;
14 | -webkit-font-smoothing: antialiased;
15 | }
16 |
17 | .mt-snackbar>.mt-button {
18 | font-size: 1em;
19 | margin-right: -1.3em;
20 | margin-left: 0.3em;
21 | }
22 |
--------------------------------------------------------------------------------
/src/snackbar/snackbar.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | export default class Snackbar extends Component {
5 | render() {
6 | const { className = '', nodeRef, ...props } = this.props;
7 |
8 | return (
9 |
10 | );
11 | }
12 | }
13 |
14 | Snackbar.propTypes = {
15 | className: PropTypes.string,
16 | };
17 |
--------------------------------------------------------------------------------
/src/spinner/spinner.css:
--------------------------------------------------------------------------------
1 | .mt-spinner {
2 | --duration: 2s;
3 |
4 | animation: mt-spinner-rotator var(--duration) ease-in infinite;
5 | }
6 |
7 | .mt-spinner_path {
8 | stroke-dasharray: 187;
9 | stroke-dashoffset: 0;
10 | transform-origin: center;
11 | animation: mt-spinner-dash var(--duration) ease-in-out infinite,
12 | mt-spinner-colors calc(var(--duration) * 4) ease-in-out infinite;
13 | }
14 |
15 | @keyframes mt-spinner-rotator {
16 | 0% {
17 | transform: rotate(0deg);
18 | }
19 | 100% {
20 | transform: rotate(360deg);
21 | }
22 | }
23 |
24 | @keyframes mt-spinner-colors {
25 | 0% {
26 | stroke: var(--mt-spinnerColor, #4285f4);
27 | }
28 | 25% {
29 | stroke: var(--mt-spinnerColor, #de3e35);
30 | }
31 | 50% {
32 | stroke: var(--mt-spinnerColor, #f7c223);
33 | }
34 | 75% {
35 | stroke: var(--mt-spinnerColor, #1b9a59);
36 | }
37 | 100% {
38 | stroke: var(--mt-spinnerColor, #4285f4);
39 | }
40 | }
41 |
42 | @keyframes mt-spinner-dash {
43 | 0% {
44 | stroke-dashoffset: 187;
45 | }
46 | 50% {
47 | stroke-dashoffset: 46;
48 | transform: rotate(90deg);
49 | }
50 | 100% {
51 | stroke-dashoffset: 187;
52 | transform: rotate(355deg);
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/spinner/spinner.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | class Spinner extends Component {
5 | render() {
6 | const {
7 | size = 'calc(var(--mt-baseFontSize, 1rem) * 1.5)',
8 | className = '',
9 | style,
10 | nodeRef,
11 | ...props
12 | } = this.props;
13 |
14 | return (
15 |
26 |
35 |
36 | );
37 | }
38 | }
39 |
40 | Spinner.propTypes = {
41 | size: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
42 | className: PropTypes.string,
43 | };
44 |
45 | export default Spinner;
46 |
--------------------------------------------------------------------------------
/src/switch/switch.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | class Switch extends Component {
5 | render() {
6 | const { className = '', style, nodeRef, ...props } = this.props;
7 | return (
8 |
18 | );
19 | }
20 | }
21 |
22 | Switch.propTypes = {
23 | className: PropTypes.string,
24 | style: PropTypes.object,
25 | };
26 |
27 | export default Switch;
28 |
--------------------------------------------------------------------------------
/src/table/table.css:
--------------------------------------------------------------------------------
1 | .mt-table {
2 | display: flex;
3 | flex-direction: column;
4 | width: 100%;
5 | border: 1px solid #d5d5d5;
6 | border-bottom: none;
7 | font-family: var(--mt-fontFamily, 'Roboto');
8 | font-size: calc(0.875 * var(--mt-baseFontSize, 1rem));
9 | box-sizing: border-box;
10 | will-change: transform;
11 | color: #000;
12 | }
13 |
14 | .mt-table-clickableElement {
15 | cursor: pointer;
16 | }
17 |
18 | .mt-table_header {
19 | color: #757575;
20 | background-color: #fff;
21 | box-sizing: border-box;
22 | }
23 |
24 | .mt-table_row {
25 | display: flex;
26 | border-bottom: 1px solid #d5d5d5;
27 | position: relative;
28 | z-index: 0;
29 | flex-wrap: wrap;
30 | box-sizing: border-box;
31 | background-color: #fff;
32 | }
33 |
34 | .mt-table_expandedRowContent {
35 | flex-basis: 100%;
36 | overflow: hidden;
37 | box-sizing: border-box;
38 | height: 0;
39 | }
40 |
41 | .mt-table_expandedRowContent-open {
42 | height: auto;
43 | }
44 |
45 | .mt-table_row:after {
46 | content: '';
47 | box-sizing: border-box;
48 | position: absolute;
49 | top: 0;
50 | left: 0;
51 | right: 0;
52 | bottom: 0;
53 | background-color: #eee;
54 | z-index: -1;
55 | pointer-events: none;
56 | opacity: 0;
57 | will-change: opacity;
58 | }
59 |
60 | .mt-table_headerRow:after {
61 | content: none;
62 | }
63 |
64 | .mt-table_row:hover:after {
65 | opacity: 1;
66 | }
67 |
68 | .mt-table_row-highlighted {
69 | background-color: #e3f2fd;
70 | }
71 |
72 | .mt-table_row-highlighted:after {
73 | background-color: #dceefe;
74 | }
75 |
76 | .mt-table_cell {
77 | flex-grow: 1;
78 | flex-shrink: 1;
79 | flex-basis: 0;
80 | display: flex;
81 | align-items: center;
82 | padding: 1em;
83 | box-sizing: border-box;
84 | overflow: hidden;
85 | text-align: left;
86 | }
87 |
88 | .mt-table_headerCell {
89 | padding: 1.2em 1em;
90 | }
91 |
92 | .mt-table_cell-rightBorder {
93 | border-right: 1px solid #d5d5d5;
94 | }
95 |
96 | .mt-table_headerCellContent {
97 | font-size: 0.9em;
98 | box-sizing: border-box;
99 | }
100 |
--------------------------------------------------------------------------------
/src/text-area/text-area.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | export default class TextArea extends Component {
5 | render() {
6 | const { className = '', error = false, nodeRef, ...props } = this.props;
7 | return (
8 |
15 | );
16 | }
17 | }
18 |
19 | TextArea.propTypes = {
20 | className: PropTypes.string,
21 | error: PropTypes.bool,
22 | };
23 |
--------------------------------------------------------------------------------
/src/utils/warning.js:
--------------------------------------------------------------------------------
1 | /* eslint no-console:off */
2 |
3 | let codeCache = {};
4 |
5 | export default function warning(message, code) {
6 | // This ensures that each warning type is only logged out one time
7 | if (code) {
8 | if (codeCache[code]) {
9 | return;
10 | }
11 |
12 | codeCache[code] = true;
13 | }
14 |
15 | if (typeof console !== 'undefined' && typeof console.error === 'function') {
16 | console.error(message);
17 | }
18 |
19 | try {
20 | // This error was thrown as a convenience so that if you enable
21 | // "break on all exceptions" in your console,
22 | // it would pause the execution at this line.
23 | throw new Error(message);
24 | } catch (e) {
25 | // Intentionally blank
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/stories/avatar.stories.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { storiesOf } from '@storybook/react';
3 | import { action } from '@storybook/addon-actions';
4 | import { setOptions } from '@storybook/addon-options';
5 | import '../src/avatar/avatar.css';
6 | import { Avatar } from '../src/index';
7 |
8 | setOptions({
9 | name: 'Materialish',
10 | addonPanelInRight: true,
11 | });
12 |
13 | storiesOf('Avatar', module)
14 | .add('Regular', () => (
15 |
19 | ))
20 | .add('With Initials', () => (
21 |
22 | ));
23 |
--------------------------------------------------------------------------------
/stories/button.stories.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { storiesOf } from '@storybook/react';
3 | import { withKnobs, text, boolean } from '@storybook/addon-knobs/react';
4 | import { action } from '@storybook/addon-actions';
5 | import { setOptions } from '@storybook/addon-options';
6 | import '../src/button/button.css';
7 | import '../src/ripple/ripple.css';
8 | import { Button } from '../src/index';
9 |
10 | setOptions({
11 | name: 'Materialish',
12 | addonPanelInRight: true,
13 | });
14 |
15 | storiesOf('Button', module)
16 | .addDecorator(withKnobs)
17 | .add('Regular', () => (
18 |
26 | {text('Text', 'Hello Button')}
27 |
28 | ));
29 |
--------------------------------------------------------------------------------
/stories/checkbox.stories.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { storiesOf } from '@storybook/react';
3 | import { withKnobs, boolean } from '@storybook/addon-knobs/react';
4 | import { action } from '@storybook/addon-actions';
5 | import { setOptions } from '@storybook/addon-options';
6 | import '../src/checkbox/checkbox.css';
7 | import { Checkbox } from '../src/index';
8 |
9 | setOptions({
10 | name: 'Materialish',
11 | addonPanelInRight: true,
12 | });
13 |
14 | storiesOf('Checkbox', module)
15 | .addDecorator(withKnobs)
16 | .add('Regular', () => (
17 |
22 | ))
23 | .add('With Label', () => (
24 |
26 | Click Me
27 |
33 |
34 | ));
35 |
--------------------------------------------------------------------------------
/stories/chips.stories.js:
--------------------------------------------------------------------------------
1 | import React, { Fragment } from 'react';
2 | import { storiesOf } from '@storybook/react';
3 | import { withKnobs } from '@storybook/addon-knobs/react';
4 | import { action } from '@storybook/addon-actions';
5 | import { setOptions } from '@storybook/addon-options';
6 | import '../src/action-chip/chip.css';
7 | import '../src/ripple/ripple.css';
8 | import { ActionChip, ChoiceChip, FilterChip, InputChip } from '../src/index';
9 |
10 | setOptions({
11 | name: 'Materialish',
12 | addonPanelInRight: true,
13 | });
14 |
15 | storiesOf('Chip', module)
16 | .addDecorator(withKnobs)
17 | .add('Action Chip', () => (
18 |
I am a chip
19 | ))
20 | .add('Choice Chip', () => (
21 |
22 |
23 | One
24 |
25 |
26 | Two
27 |
28 |
29 | Three
30 |
31 |
32 | ))
33 | .add('Filter Chip', () => (
34 |
35 |
36 | One
37 |
38 |
39 | Two
40 |
41 |
42 | Three
43 |
44 |
45 | ))
46 | .add('Input Chip', () => (
47 |
48 | I am a chip
49 |
50 | ));
51 |
--------------------------------------------------------------------------------
/stories/dialog.stories.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { storiesOf } from '@storybook/react';
3 | import { setOptions } from '@storybook/addon-options';
4 | import '../src/dialog/dialog.css';
5 | import { Dialog } from '../src/index';
6 | import { Button } from '../src/index';
7 |
8 | setOptions({
9 | name: 'Materialish',
10 | addonPanelInRight: true,
11 | });
12 |
13 | storiesOf('Dialog', module).add('Regular', () => (
14 |
15 | I am a modal
16 |
17 |
18 | Lorem ipsum dolor sit amet consectetur adipisicing elit. Numquam
19 | consequatur enim voluptates nobis perferendis voluptatibus alias modi
20 | voluptate dolorum ipsa amet, aliquam similique blanditiis iusto ipsam,
21 | atque beatae aliquid sit! Lorem ipsum dolor sit amet consectetur
22 | adipisicing elit.
23 |
24 |
25 |
26 | Nevermind
27 | Accept
28 |
29 |
30 | ));
31 |
--------------------------------------------------------------------------------
/stories/elevation.stories.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { storiesOf } from '@storybook/react';
3 | import { setOptions } from '@storybook/addon-options';
4 | import '../src/elevation/elevation.css';
5 | import { Elevation } from '../src/index';
6 |
7 | setOptions({
8 | name: 'Materialish',
9 | addonPanelInRight: true,
10 | });
11 |
12 | storiesOf('Elevation', module)
13 | .add('Depth - 0', () => (
14 |
17 | This is an elevation with some content
18 |
19 | ))
20 | .add('Depth - 1', () => (
21 |
24 | This is an elevation with some content
25 |
26 | ))
27 | .add('Depth - 2', () => (
28 |
31 | This is an elevation with some content
32 |
33 | ))
34 | .add('Depth - 3', () => (
35 |
38 | This is an elevation with some content
39 |
40 | ))
41 | .add('Depth - 4', () => (
42 |
45 | This is an elevation with some content
46 |
47 | ))
48 | .add('Depth - 5', () => (
49 |
52 | This is an elevation with some content
53 |
54 | ));
55 |
--------------------------------------------------------------------------------
/stories/expansion-panel.stories.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { storiesOf } from '@storybook/react';
3 | import { withKnobs, boolean } from '@storybook/addon-knobs/react';
4 | import { setOptions } from '@storybook/addon-options';
5 | import '../src/expansion-panel/expansion-panel.css';
6 | import '../src/expandable/expandable.css';
7 | import { ExpansionPanel } from '../src/index';
8 |
9 | setOptions({
10 | name: 'Materialish',
11 | addonPanelInRight: true,
12 | });
13 |
14 | storiesOf('ExpansionPanel', module)
15 | .addDecorator(withKnobs)
16 | .add('Regular', () => (
17 |
18 |
19 | Expansion Panel One
20 |
21 |
22 | Lorem ipsum dolor sit amet, consectetur adipiscing elit.
23 | Pellentesque fermentum sed magna quis interdum. Suspendisse vitae
24 | lobortis odio, a accumsan purus. Vivamus suscipit magna et nisl
25 | mattis vestibulum. Donec interdum leo elementum eros fringilla, ut
26 | varius velit volutpat. In porttitor tempus purus id lacinia.
27 | Phasellus vitae blandit tellus, fermentum dictum libero.
28 |
29 |
30 |
31 |
32 | Expansion Panel Two
33 |
34 |
35 | Lorem ipsum dolor sit amet, consectetur adipiscing elit.
36 | Pellentesque fermentum sed magna quis interdum. Suspendisse vitae
37 | lobortis odio, a accumsan purus. Vivamus suscipit magna et nisl
38 | mattis vestibulum. Donec interdum leo elementum eros fringilla, ut
39 | varius velit volutpat. In porttitor tempus purus id lacinia.
40 | Phasellus vitae blandit tellus, fermentum dictum libero. Nullam
41 | lacus leo, convallis ut mattis non, luctus eu tellus.
42 |
43 |
44 |
45 |
46 | Expansion Panel Three
47 |
48 |
49 | Lorem ipsum dolor sit amet, consectetur adipiscing elit.
50 | Pellentesque fermentum sed magna quis interdum. Suspendisse vitae
51 | lobortis odio, a accumsan purus.
52 |
53 |
54 |
55 |
56 | ));
57 |
--------------------------------------------------------------------------------
/stories/field.stories.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { storiesOf } from '@storybook/react';
3 | import { withKnobs, text, boolean } from '@storybook/addon-knobs/react';
4 | import { setOptions } from '@storybook/addon-options';
5 | import '../src/input/input.css';
6 | import '../src/field/field.css';
7 | import { Field } from '../src/index';
8 |
9 | setOptions({
10 | name: 'Materialish',
11 | addonPanelInRight: true,
12 | });
13 |
14 | storiesOf('Field', module)
15 | .addDecorator(withKnobs)
16 | .add('Regular', () => (
17 |
18 | Place of Residence
19 |
25 |
26 | ))
27 | .add('Required', () => (
28 |
29 | Place of Residence
30 |
36 |
37 | ))
38 | .add('With error', () => (
39 |
40 | Place of Residence
41 |
47 | There was an error.
48 |
49 | ));
50 |
--------------------------------------------------------------------------------
/stories/icon-button.stories.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { storiesOf } from '@storybook/react';
3 | import { withKnobs, boolean } from '@storybook/addon-knobs/react';
4 | import { action } from '@storybook/addon-actions';
5 | import { setOptions } from '@storybook/addon-options';
6 | import '../src/icon-button/icon-button.css';
7 | import '../src/ripple/ripple.css';
8 | import { IconButton } from '../src/index';
9 |
10 | setOptions({
11 | name: 'Materialish',
12 | addonPanelInRight: true,
13 | });
14 |
15 | storiesOf('Icon Button', module)
16 | .addDecorator(withKnobs)
17 | .add('Regular', () => (
18 |
21 |
26 |
27 |
28 |
29 | ));
30 |
--------------------------------------------------------------------------------
/stories/input.stories.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { storiesOf } from '@storybook/react';
3 | import { withKnobs, text, boolean } from '@storybook/addon-knobs/react';
4 | import { setOptions } from '@storybook/addon-options';
5 | import '../src/input/input.css';
6 | import { Input } from '../src/index';
7 | import IconSearch from '../src/icons/icon-search';
8 |
9 | setOptions({
10 | name: 'Materialish',
11 | addonPanelInRight: true,
12 | });
13 |
14 | storiesOf('Input', module)
15 | .addDecorator(withKnobs)
16 |
17 | .add('Regular', () => (
18 |
25 | ))
26 | .add('Clearable', () => (
27 |
}
29 | clearable
30 | disabled={boolean('Disabled', false, 'PROPS')}
31 | error={boolean('Error', false, 'PROPS')}
32 | value={text('Value', 'Paris, France')}
33 | placeholder={text('Placeholder', 'Please enter a value')}
34 | />
35 | ));
36 |
--------------------------------------------------------------------------------
/stories/loading-dots.stories.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { storiesOf } from '@storybook/react';
3 | import { setOptions } from '@storybook/addon-options';
4 | import '../src/loading-dots/loading-dots.css';
5 | import { LoadingDots } from '../src/index';
6 |
7 | setOptions({
8 | name: 'Materialish',
9 | addonPanelInRight: true,
10 | });
11 |
12 | storiesOf('LoadingDots', module).add('Regular', () =>
);
13 |
--------------------------------------------------------------------------------
/stories/menu.stories.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { storiesOf } from '@storybook/react';
3 | import { setOptions } from '@storybook/addon-options';
4 | import '../src/menu/menu.css';
5 | import { Menu } from '../src/index';
6 |
7 | setOptions({
8 | name: 'Materialish',
9 | addonPanelInRight: true,
10 | });
11 |
12 | storiesOf('Menu', module).add('Regular', () => (
13 |
14 | Option one
15 | Option two
16 | Option three
17 |
18 | Option four
19 | Option five
20 | Option six
21 |
22 | ));
23 |
--------------------------------------------------------------------------------
/stories/navigation.stories.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { storiesOf } from '@storybook/react';
3 | import { withKnobs, boolean } from '@storybook/addon-knobs/react';
4 | import { setOptions } from '@storybook/addon-options';
5 | import '../src/navigation/navigation.css';
6 | import { Navigation } from '../src/index';
7 | import IconAlarmOn from '../icon-alarm-on';
8 | import IconBugReport from '../icon-bug-report';
9 | import IconFace from '../icon-face';
10 |
11 | setOptions({
12 | name: 'Materialish',
13 | addonPanelInRight: true,
14 | });
15 |
16 | storiesOf('Navigation', module)
17 | .addDecorator(withKnobs)
18 | .add('Regular', () => (
19 |
22 | One
23 | Item Two Hundred and a half
24 | Three
25 |
26 | ))
27 | .add('With Icons', () => (
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | ));
40 |
--------------------------------------------------------------------------------
/stories/progress-bar.stories.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { storiesOf } from '@storybook/react';
3 | import { withKnobs, number, boolean } from '@storybook/addon-knobs/react';
4 | import { setOptions } from '@storybook/addon-options';
5 | import '../src/progress-bar/progress-bar.css';
6 | import { ProgressBar } from '../src/index';
7 |
8 | setOptions({
9 | name: 'Materialish',
10 | addonPanelInRight: true,
11 | });
12 |
13 | storiesOf('ProgressBar', module)
14 | .addDecorator(withKnobs)
15 | .add('Regular', () => (
16 |
21 | ));
22 |
--------------------------------------------------------------------------------
/stories/radio.stories.js:
--------------------------------------------------------------------------------
1 | import React, { Fragment } from 'react';
2 | import { storiesOf } from '@storybook/react';
3 | import { withKnobs, boolean } from '@storybook/addon-knobs/react';
4 | import { action } from '@storybook/addon-actions';
5 | import { setOptions } from '@storybook/addon-options';
6 | import '../src/radio/radio.css';
7 | import { Radio } from '../src/index';
8 |
9 | setOptions({
10 | name: 'Materialish',
11 | addonPanelInRight: true,
12 | });
13 |
14 | storiesOf('Radio', module)
15 | .addDecorator(withKnobs)
16 | .add('Regular', () => (
17 |
22 | ))
23 | .add('With Label', () => (
24 |
25 |
27 | One
28 |
36 |
37 |
39 | Two
40 |
48 |
49 |
51 | Two
52 |
60 |
61 |
62 | ));
63 |
--------------------------------------------------------------------------------
/stories/snackbar.stories.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { storiesOf } from '@storybook/react';
3 | import { setOptions } from '@storybook/addon-options';
4 | import '../src/snackbar/snackbar.css';
5 | import { Snackbar, Button } from '../src/index';
6 |
7 | setOptions({
8 | name: 'Materialish',
9 | addonPanelInRight: true,
10 | });
11 |
12 | storiesOf('Snackbar', module)
13 | .add('Regular', () => (
14 |
15 | There was an error.
16 |
17 | Retry
18 |
19 |
20 | ))
21 | .add('Without button', () =>
There was an error. );
22 |
--------------------------------------------------------------------------------
/stories/spinner.stories.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { storiesOf } from '@storybook/react';
3 | import { setOptions } from '@storybook/addon-options';
4 | import '../src/spinner/spinner.css';
5 | import { Spinner } from '../src/index';
6 |
7 | setOptions({
8 | name: 'Materialish',
9 | addonPanelInRight: true,
10 | });
11 |
12 | storiesOf('Spinner', module)
13 | .add('Regular', () =>
)
14 | .add('Monochromatic', () => (
15 |
16 | ));
17 |
--------------------------------------------------------------------------------
/stories/switch.stories.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { storiesOf } from '@storybook/react';
3 | import { withKnobs, boolean } from '@storybook/addon-knobs/react';
4 | import { action } from '@storybook/addon-actions';
5 | import { setOptions } from '@storybook/addon-options';
6 | import '../src/switch/switch.css';
7 | import { Switch } from '../src/index';
8 |
9 | setOptions({
10 | name: 'Materialish',
11 | addonPanelInRight: true,
12 | });
13 |
14 | storiesOf('Switch', module)
15 | .addDecorator(withKnobs)
16 | .add('Regular', () => (
17 |
22 | ))
23 | .add('With Label', () => (
24 |
26 | Click Me
27 |
33 |
34 | ));
35 |
--------------------------------------------------------------------------------
/stories/text-area.stories.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { storiesOf } from '@storybook/react';
3 | import { withKnobs, text, boolean } from '@storybook/addon-knobs/react';
4 | import { setOptions } from '@storybook/addon-options';
5 | import '../src/input/input.css';
6 | import { TextArea } from '../src/index';
7 |
8 | setOptions({
9 | name: 'Materialish',
10 | addonPanelInRight: true,
11 | });
12 |
13 | storiesOf('TextArea', module)
14 | .addDecorator(withKnobs)
15 | .add('Regular', () => (
16 |
25 | ));
26 |
--------------------------------------------------------------------------------