Merge branch 'upstream-dev' into iconmenu-active-prop

old
Adam Henson 2018-02-10 12:17:50 -05:00
commit c6a730112c
73 changed files with 1915 additions and 73 deletions

1
.gitignore vendored
View File

@ -4,3 +4,4 @@ node_modules
npm-debug.log
.idea
.DS_Store
.vscode

View File

@ -8,4 +8,5 @@ node_js:
script:
- npm run lint
- npm run ts
- npm test

View File

@ -1,4 +1,4 @@
# <a href='http://react-toolbox.com'><img src='http://i.imgur.com/VCSElQX.png' height='50'></a>
# <a href='http://react-toolbox.io'><img src='http://i.imgur.com/VCSElQX.png' height='50'></a>
[![npm version](https://img.shields.io/npm/v/react-toolbox.svg?style=flat-square)](https://www.npmjs.com/package/react-toolbox) [![Build Status](http://img.shields.io/travis/react-toolbox/react-toolbox/master.svg?style=flat-square)](https://travis-ci.org/react-toolbox/react-toolbox) [![NPM Status](http://img.shields.io/npm/dm/react-toolbox.svg?style=flat-square)](https://www.npmjs.org/package/react-toolbox) [![Donate](https://img.shields.io/badge/donate-paypal-blue.svg?style=flat-square)](https://paypal.me/javivelasco) [![OpenCollective](https://opencollective.com/react-toolbox/backers/badge.svg)](#backers)
[![OpenCollective](https://opencollective.com/react-toolbox/sponsors/badge.svg)](#sponsors)

View File

@ -1,4 +1,4 @@
This document defines a manifesto and the main Roadmap 🚵 ideas for [React Toolbox](www.react-toolbox.com). It's not a fixed document and of course it's open to change. You can leave your feedback in [this gist](https://gist.github.com/javivelasco/259d2087c2a8c3e8f2c5c720d1fd3f2e) or you can also do it [through an issue](https://github.com/react-toolbox/react-toolbox/issues/new).
This document defines a manifesto and the main Roadmap 🚵 ideas for [React Toolbox](www.react-toolbox.io). It's not a fixed document and of course it's open to change. You can leave your feedback in [this gist](https://gist.github.com/javivelasco/259d2087c2a8c3e8f2c5c720d1fd3f2e) or you can also do it [through an issue](https://github.com/react-toolbox/react-toolbox/issues/new).
## The Manifesto

View File

@ -88,6 +88,14 @@ export interface AutocompleteProps extends InputProps {
* Callback function that is fired when component is focused.
*/
onFocus?: Function;
/**
* Callback function that is fired when a key is pressed down.
*/
onKeyDown?: Function;
/**
* Callback function that is fired when a key is lifted up.
*/
onKeyUp?: Function;
/**
* Callback function that is fired when the components's query value changes.
*/

View File

@ -35,6 +35,8 @@ const factory = (Chip, Input) => {
onBlur: PropTypes.func,
onChange: PropTypes.func,
onFocus: PropTypes.func,
onKeyDown: PropTypes.func,
onKeyUp: PropTypes.func,
onQueryChange: PropTypes.func,
query: PropTypes.string,
selectedPosition: PropTypes.oneOf(['above', 'below', 'none']),
@ -132,7 +134,7 @@ const factory = (Chip, Input) => {
};
handleQueryFocus = (event) => {
this.suggestionsNode.scrollTop = 0;
event.target.scrollTop = 0;
this.setState({ active: '', focus: true });
if (this.props.onFocus) this.props.onFocus(event);
};
@ -148,6 +150,8 @@ const factory = (Chip, Input) => {
if (event.which === 13) {
this.selectOrCreateActiveItem(event);
}
if(this.props.onKeyDown) this.props.onKeyDown(event);
};
handleQueryKeyUp = (event) => {
@ -160,6 +164,8 @@ const factory = (Chip, Input) => {
if (index >= suggestionsKeys.length) index = 0;
this.setState({ active: suggestionsKeys[index] });
}
if(this.props.onKeyUp) this.props.onKeyUp(event);
};
handleSuggestionHover = (event) => {
@ -375,7 +381,6 @@ const factory = (Chip, Input) => {
return (
<ul
className={classnames(theme.suggestions, { [theme.up]: this.state.direction === 'up' })}
ref={(node) => { this.suggestionsNode = node; }}
>
{suggestions}
</ul>

View File

@ -45,7 +45,7 @@ If you want to provide a theme via context, the component key is `RTAutocomplete
|:-----|:-----|:-----|:-----|
| `allowCreate` | `Bool` | `false` | Determines if user can create a new option with the current typed value |
| `className` | `String` | `''` | Sets a class to style of the Component.|
| `direction` | `String` | `auto` | Determines the opening direction. It can be `auto`, `top` or `down`. |
| `direction` | `String` | `auto` | Determines the opening direction. It can be `auto`, `up` or `down`. |
| `disabled` | `Bool` | `false` | If true, component will be disabled. |
| `error` | `String` or `Node` | | Sets the error string for the internal input element. |
| `keepFocusOnChange` | `Bool` | `false` | Whether component should keep focus after value change. |
@ -53,8 +53,10 @@ If you want to provide a theme via context, the component key is `RTAutocomplete
| `multiple` | `Bool` | `true` | If true, component can hold multiple values. |
| `onBlur` | `Function` | | Callback function that is fired when component is blurred. |
| `onChange` | `Function` | | Callback function that is fired when the components's value changes. |
| `onQueryChange` | `Function` | | Callback function that is fired when the components's query input value changes. |
| `onFocus` | `Function` | | Callback function that is fired when component is focused. |
| `onKeyDown` | `Function` | | Callback function that is fired when a key is pressed down. |
| `onKeyUp` | `Function` | | Callback function that is fired when a key is lifted up. |
| `onQueryChange` | `Function` | | Callback function that is fired when the components's query input value changes. |
| `query` | `String` | | This property has to be used in case the `source` is not static and will be changing during search for `multiple={false}` autocomplete, content of the `query` has to be managed by the `onQueryChange` callback. |
| `source` | `Object` or `Array` | | Object of key/values or array representing all items suggested. |
| `selectedPosition` | `String` | `above` | Determines if the selected list is shown above or below input. It can be `above`, `below` or `none`. |

View File

@ -13,8 +13,8 @@
& .suggestions {
box-shadow: var(--zdepth-shadow-1);
max-height: var(--autocomplete-overflow-max-height);
-ms-overflow-style: none;
visibility: visible;
-ms-overflow-style:none;
}
}
}

View File

@ -10,7 +10,7 @@ const factory = (FontIcon) => {
<div data-react-toolbox="avatar" className={classnames(theme.avatar, className)} {...other}>
{children}
{cover && typeof image === 'string' && <span aria-label={alt} className={theme.image} style={{ backgroundImage: `url(${image})` }} />}
{!cover && (typeof image === 'string' ? <img alt={alt} className={theme.image} src={image} /> : image)}
{!cover && (typeof image === 'string' ? <img alt={alt} className={theme.image} src={image} title={title} /> : image)}
{typeof icon === 'string' ? <FontIcon className={theme.letter} value={icon} alt={alt} /> : icon}
{title ? <span className={theme.letter}>{title[0]}</span> : null}
</div>

View File

@ -37,6 +37,8 @@ export interface BrowseButtonProps extends ButtonBaseProps {
* Classnames object defining the component style.
*/
theme?: BrowseButtonTheme;
onChange?: Function;
}
export class BrowseButton extends React.Component<BrowseButtonProps, {}> { }

View File

@ -23,6 +23,7 @@ const factory = (ripple, FontIcon) => {
inverse: PropTypes.bool,
label: PropTypes.string,
mini: PropTypes.bool,
multiple: PropTypes.bool,
neutral: PropTypes.bool,
onChange: PropTypes.func,
onMouseLeave: PropTypes.func,
@ -53,6 +54,7 @@ const factory = (ripple, FontIcon) => {
flat: false,
floating: false,
mini: false,
multiple: false,
neutral: true,
primary: false,
raised: false,
@ -96,6 +98,7 @@ const factory = (ripple, FontIcon) => {
inverse,
label,
mini,
multiple,
neutral,
primary, // eslint-disable-line
raised, // eslint-disable-line
@ -130,6 +133,7 @@ const factory = (ripple, FontIcon) => {
className={classes}
type="file"
accept={accept}
multiple={multiple}
onChange={this.handleFileChange}
/>,
children,

View File

@ -1,8 +1,9 @@
import * as React from "react";
import ReactToolbox from "../index";
import { RippleProps } from '../ripple/index';
import { ButtonBaseProps, ButtonTheme } from './base';
export interface ButtonProps extends ButtonBaseProps {
export interface ButtonProps extends ButtonBaseProps, RippleProps {
/**
* If true, the button will have a flat look.
* @default false
@ -31,6 +32,10 @@ export interface ButtonProps extends ButtonBaseProps {
* @default false
*/
raised?: boolean;
/**
* Passed down to the root element
*/
target?: string;
/**
* Classnames object defining the component style.
*/

View File

@ -101,6 +101,10 @@ const factory = (ripple, FontIcon) => {
const element = href ? 'a' : 'button';
const level = this.getLevel();
const shape = this.getShape();
const mouseEvents = {
onMouseUp: this.handleMouseUp,
onMouseLeave: this.handleMouseLeave,
};
const classes = classnames(theme.button, [theme[shape]], {
[theme[level]]: neutral,
@ -110,21 +114,24 @@ const factory = (ripple, FontIcon) => {
const props = {
...others,
...mouseEvents,
href,
ref: (node) => { this.buttonNode = node; },
className: classes,
disabled: this.props.disabled,
onMouseUp: this.handleMouseUp,
onMouseLeave: this.handleMouseLeave,
type: !href ? type : null,
'data-react-toolbox': 'button',
};
return React.createElement(element, props,
const buttonElement = React.createElement(element, props,
icon ? <FontIcon className={theme.icon} value={icon} /> : null,
label,
children,
);
return others.onMouseEnter && this.props.disabled
? <span {...mouseEvents}>{buttonElement}</span>
: buttonElement;
}
}

View File

@ -8,6 +8,7 @@
--checkbox-focus-color: color(var(--color-black) a(1%));
--checkbox-focus-size: calc(var(--checkbox-size) * 2.3);
--checkbox-text-color: var(--color-black);
--checkbox-border-color: var(--palette-grey-600);
--checkbox-text-font-size: var(--font-size-small);
--checkbox-total-height: calc(1.8 * var(--unit));
--checkbox-transition-duration: 0.2s;

View File

@ -47,7 +47,7 @@ If you want to provide a theme via context, the component key is `RTCheckbox`.
| `children` | `String`, `Element` or `Array` | | Children to pass through the component. |
| `className` | `String` | `''` | Sets a class to give customized styles to the checkbox field.|
| `disabled` | `Boolean` | `false` | If true, the checkbox shown as disabled and cannot be modified.|
| `label` | `String` of `node` | | Text label to attach next to the checkbox element.|
| `label` | `String` or `node` | | Text label to attach next to the checkbox element.|
| `name` | `String` | `false` | The name of the field to set in the input checkbox.|
| `onBlur` | `Function` | | Callback called when the checkbox is blurred.|
| `onChange` | `Function` | | Callback called when the checkbox value is changed.|

View File

@ -57,7 +57,7 @@
}
.check {
border-color: var(--checkbox-text-color);
border-color: var(--checkbox-border-color);
border-radius: 2px;
border-style: solid;
border-width: 2px;

View File

@ -28,7 +28,7 @@ export interface DrawerTheme {
wrapper?: string;
}
export interface DrawerProps extends ReactToolbox.Props {
export interface DrawerCommonProps {
/**
* If true, the drawer will be visible.
* @default false
@ -47,10 +47,6 @@ export interface DrawerProps extends ReactToolbox.Props {
* Callback function to be invoked when the overlay is clicked.
*/
onOverlayClick?: Function;
/**
* Classnames object defining the component style.
*/
theme?: DrawerTheme;
/**
* Type of drawer. It can be left or right to display the drawer on the left or right side of the screen.
* @default left
@ -63,6 +59,13 @@ export interface DrawerProps extends ReactToolbox.Props {
withOverlay?: boolean;
}
export interface DrawerProps extends ReactToolbox.Props, DrawerCommonProps {
/**
* Classnames object defining the component style.
*/
theme?: DrawerTheme;
}
export class Drawer extends React.Component<DrawerProps, {}> { }
export default Drawer;

View File

@ -30,10 +30,6 @@ export interface DropdownTheme {
* Used for the the label element.
*/
label?: string;
/**
* Used for setting the label from source
*/
labelKey?: string;
/**
* Used when dropdown has required attribute.
*/
@ -58,10 +54,6 @@ export interface DropdownTheme {
* Used for the list of values.
*/
values?: string;
/**
* Used for setting the value from source
*/
valueKey: string;
}
export interface DropdownProps extends ReactToolbox.Props {
@ -88,6 +80,10 @@ export interface DropdownProps extends ReactToolbox.Props {
* The text string to use for the floating label element.
*/
label?: string;
/**
* Used for setting the label from source
*/
labelKey?: string;
/**
* Name for the input field.
*/
@ -104,6 +100,11 @@ export interface DropdownProps extends ReactToolbox.Props {
* Callback function that is fired when the component is focused.
*/
onFocus?: Function;
/**
* If true, the dropdown has a required attribute.
* @default false
*/
required?: boolean;
/**
* Array of data objects with the data to represent in the dropdown.
*/
@ -121,10 +122,9 @@ export interface DropdownProps extends ReactToolbox.Props {
*/
value?: string | number;
/**
* If true, the dropdown has a required attribute.
* @default false
* Used for setting the value from source
*/
required?: boolean;
valueKey?: string;
}
export class Dropdown extends React.Component<DropdownProps, {}> { }

View File

@ -1,13 +1,14 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import ReactDOM from 'react-dom';
import styleShape from 'react-style-proptype';
class Portal extends Component {
static propTypes = {
children: PropTypes.node,
className: PropTypes.string,
container: PropTypes.node,
style: PropTypes.style,
style: styleShape,
}
static defaultProps = {

View File

@ -132,7 +132,7 @@ export interface InputProps extends ReactToolbox.Props {
/**
* The number of rows the multiline input field has.
*/
rows?:number;
rows?: number;
/**
* Classnames object defining the component style.
*/

View File

@ -6,8 +6,9 @@
--input-label-font-size: calc(1.2 * var(--unit));
--input-focus-label-top: calc(0.6 * var(--unit));
--input-text-background-color: transparent;
--input-text-label-color: color(var(--color-black) a(26%));
--input-text-bottom-border-color: color(var(--color-black) a(12%));
--input-text-label-color: color(var(--color-text) a(26%));
--input-text-input-element-color: var(--color-text);
--input-text-bottom-border-color: color(var(--color-text) a(12%));
--input-text-highlight-color: var(--color-primary);
--input-text-disabled-color: var(--input-text-bottom-border-color);
--input-text-disabled-text-color: var(--input-text-label-color);

View File

@ -71,7 +71,7 @@ If you want to provide a theme via context, the component key is `RTInput`.
## Methods
The `Input` component has some imperative methods that are used as a bypass to the native rendered DOM element. To call this methods you will need to retrieve the instance of the component. Check the [Install](http://react-toolbox.com/#/install) section for details on how to do this. The methods included for the `Input` are:
The `Input` component has some imperative methods that are used as a bypass to the native rendered DOM element. To call this methods you will need to retrieve the instance of the component. Check the [Install](http://react-toolbox.io/#/install) section for details on how to do this. The methods included for the `Input` are:
- `blur` used to blur the `input` element.
- `focus` used to focus the `input` element.

View File

@ -34,13 +34,17 @@
border-radius: 0;
border-right: 0;
border-top: 0;
color: var(--color-text);
color: var(--input-text-input-element-color);
display: block;
font-size: var(--input-field-font-size);
outline: none;
padding: var(--input-field-padding) 0;
width: 100%;
&:required {
box-shadow: none;
}
&:focus:not([disabled]):not([readonly]) {
& ~ .bar::before,
& ~ .bar::after {
@ -158,7 +162,7 @@
}
.disabled > .inputElement {
border-bottom-style: dotted;
border-bottom-style: dashed;
color: var(--input-text-disabled-text-color);
}

View File

@ -1,8 +1,5 @@
import * as React from "react";
import ReactToolbox from "../index";
import { NavDrawer } from './NavDrawer';
import { Panel } from './Panel';
import { Sidebar } from './Sidebar';
export interface LayoutTheme {
appbarFixed?: string;
@ -54,7 +51,7 @@ export interface LayoutProps extends ReactToolbox.Props {
/**
* Children to pass through the component.
*/
children?: [NavDrawer | Panel | Sidebar];
children?: JSX.Element | JSX.Element[];
/**
* Classnames object defining the component style.
*/

View File

@ -1,5 +1,5 @@
import * as React from "react";
import { DrawerProps } from '../drawer/Drawer';
import { DrawerCommonProps } from '../drawer/Drawer';
export interface NavDrawerTheme {
/**
@ -12,7 +12,7 @@ export interface NavDrawerTheme {
clipped?: string;
}
export interface NavDrawerProps extends DrawerProps {
export interface NavDrawerProps extends DrawerCommonProps {
/**
* If true, the drawer will be shown as an overlay.
* @default false

View File

@ -1,5 +1,5 @@
import * as React from "react";
import { DrawerProps } from '../drawer/Drawer';
import { DrawerCommonProps } from '../drawer/Drawer';
export interface SidebarTheme {
/**
@ -12,7 +12,7 @@ export interface SidebarTheme {
pinned?: string;
}
export interface SidebarProps extends DrawerProps {
export interface SidebarProps extends DrawerCommonProps {
/**
* If true, when the `AppBar` gets pinned, it will stand over the `Drawer`.
* @default false

View File

@ -3,6 +3,7 @@ import ReactToolbox from '../index';
import { ListItemContentTheme } from './ListItemContent';
import { ListItemActionsTheme } from './ListItemActions';
import { ListItemLayoutProps, ListItemLayoutTheme } from './ListItemLayout';
import { ListItemTextTheme } from './ListItemText';
export interface ListItemTheme {
/**
@ -29,7 +30,7 @@ export interface ListItemProps extends ReactToolbox.Props {
* Classnames object defining the component style.
* @default false
*/
theme?: ListItemTheme & ListItemActionsTheme & ListItemContentTheme & ListItemLayoutTheme;
theme?: ListItemTheme & ListItemActionsTheme & ListItemContentTheme & ListItemLayoutTheme & ListItemTextTheme;
/**
* In case you want to provide the item as a link, you can pass this property to specify the href.
*/

View File

@ -71,7 +71,7 @@ Represents a list item that can have avatar, icons, title, subtitle, etc. Note:
| `leftActions` | `Array of Elements` | | A list of elements that are placed on the left side of the item and after the avatar attribute.|
| `leftIcon` | `String` or `Element` | | A string key of a font icon or element to display an icon in the left side of the item. |
| `legend` | `String` or `Element` | | Secondary text to display under the caption.|
| `onClick` | `Function` | | Callback the is invoked when the item is clicked if it's not disabled. |
| `onClick` | `Function` | | Callback that is invoked when the item is clicked if it's not disabled. |
| `rightIcon` | `String` or `Element` | | The same as the `leftIcon` but in this case the icon is displayed in the right side.|
| `rightActions` | `Array of Elements` | | A list of elements that are placed on the right side of the item and after the rightIcon attribute.|
| `ripple` | `Boolean` | `false` | If true, the item displays a ripple effect on click. By default it's inherited from the parent element.|

View File

@ -64,6 +64,9 @@
min-height: var(--list-item-min-height);
padding: 0 var(--list-horizontal-padding);
position: relative;
transition-duration: 0.28s;
transition-property: background-color;
transition-timing-function: var(--animation-curve-default);
&.selectable:not(.disabled):hover {
background-color: var(--list-item-hover-color);

View File

@ -59,6 +59,10 @@ export interface MenuItemProps extends ReactToolbox.Props {
* Classnames object defining the component style.
*/
theme?: MenuItemTheme;
/**
* Passed down to the root element
*/
value?: any;
}
export class MenuItem extends React.Component<MenuItemProps, {}> { }

View File

@ -56,7 +56,7 @@ The inner component to compose radio selectors. They will be rendered as radio i
| `checked` | `Boolean` | `false` | If true, the input element will be selected by default. Transferred from the parent. |
| `className` | `String` | `''` | Set a class to give custom styles to the radio button.|
| `disabled` | `Boolean` | `false` | If true, the item will be displayed as disabled.|
| `label` | `String` of `node` | `''` | Label for the radio button.|
| `label` | `String` or `node` | `''` | Label for the radio button.|
| `name` | `String` | | Name for the input element. |
| `onBlur` | `Function` | | Callback function that will be invoked when the input is blurred. |
| `onChange` | `Function` | | Callback function that will be invoked when the value changes. |

View File

@ -49,7 +49,7 @@ export interface SnackbarProps extends ReactToolbox.Props {
/**
* Text to display in the content.
*/
label?: string;
label?: string | JSX.Element;
/**
* Callback function that will be called when the button action is clicked.
*/

View File

@ -40,7 +40,8 @@
transition-property: background-color;
transition-timing-function: var(--animation-curve-default);
&:hover { background-color: var(--table-hover-color); }
&:hover,
&.selected:hover { background-color: var(--table-hover-color); }
&.selected { background-color: var(--table-selection-color); }
}

View File

@ -52,9 +52,9 @@ export interface TabProps extends ReactToolbox.Props {
*/
icon?: React.ReactNode;
/**
* Label text for navigation header. Required.
* Label text for navigation header.
*/
label: string;
label?: string;
/**
* Callback function that is fired when the tab is activated.
*/

View File

@ -59,6 +59,8 @@ const factory = (Tab, TabContent, FontIcon) => {
if (index !== prevIndex || children !== prevChildren) {
this.updatePointer(index);
}
this.updateArrows();
}
componentWillUnmount() {
@ -83,7 +85,7 @@ const factory = (Tab, TabContent, FontIcon) => {
updatePointer = (idx) => {
if (this.navigationNode && this.navigationNode.children[idx]) {
this.updatePointerAnimationFrame = requestAnimationFrame(() => {
this.updatePointerAnimationFrame = window.requestAnimationFrame(() => {
const nav = this.navigationNode.getBoundingClientRect();
const label = this.navigationNode.children[idx].getBoundingClientRect();
const scrollLeft = this.navigationNode.scrollLeft;
@ -105,13 +107,18 @@ const factory = (Tab, TabContent, FontIcon) => {
const scrollLeft = this.navigationNode.scrollLeft;
const nav = this.navigationNode.getBoundingClientRect();
const lastLabel = this.navigationNode.children[idx].getBoundingClientRect();
const left = scrollLeft > 0;
const right = nav.right < (lastLabel.right - 5);
const { left: prevLeft, right: prevRight } = this.state.arrows;
this.setState({
arrows: {
left: scrollLeft > 0,
right: nav.right < (lastLabel.right - 5),
},
});
if (left !== prevLeft || right !== prevRight) {
this.setState({
arrows: {
left,
right,
},
});
}
}
}

View File

@ -70,10 +70,21 @@ declare class TooltipComponent<P, S> extends React.Component<P, S> {
props: P & TooltipProps;
}
interface TooltippedComponentClass<P> extends TooltipProps {
declare interface TooltippedComponentClass<P> extends TooltipProps {
new (props?: P, context?: any): TooltipComponent<P, any>;
}
export function Tooltip<P>(componentClass: React.ComponentClass<P>): TooltippedComponentClass<P>;
declare interface TooltipOptions {
className?: string;
delay?: number;
hideOnClick?: boolean;
passthrough?: boolean;
showOnClick?: boolean;
position?: 'bottom' | 'horizontal' | 'left' | 'right' | 'top' | 'vertical'
}
export default Tooltip;
declare type tooltipHOC<P> = (componentClass: React.ComponentClass<P>) => TooltippedComponentClass<P>
export function tooltipFactory<P>(options?: TooltipOptions): tooltipHOC<P>;
export default function Tooltip<P>(component: React.ReactType): TooltippedComponentClass<P>;

View File

@ -5,8 +5,9 @@ A Tooltip is useful to show information on hover in any kind of component. We ha
<!-- example -->
```jsx
import Button from 'react-toolbox/lib/button';
import Tooltip from 'react-toolbox/lib/tooltip';
import Input from 'react-toolbox/lib/input';
import Link from 'react-toolbox/lib/link';
import Tooltip from 'react-toolbox/lib/tooltip';
const TooltipButton = Tooltip(Button);
const TooltipInput = Tooltip(Input);

View File

@ -1,5 +1,5 @@
class InputTest extends React.Component {
state = { name: '', phone: '', multiline: '', email: '', hint: '', label: '' };
state = { name: '', phone: '', multiline: '', email: '', hint: '', label: '', error: '' };
handleChange = (value, ev) => {
this.setState({[ev.target.name]: value});
@ -16,7 +16,7 @@ class InputTest extends React.Component {
<Input type='tel' label='Phone' name='phone' icon='phone' value={this.state.phone} onChange={this.handleChange} />
<Input type='text' name='hint' value={this.state.hint} label='Required Field' hint='With Hint' required onChange={this.handleChange} icon='share' />
{/* Just an example. Defining functions in a property, such as onClick, is a bad idea: */}
<Input type='text' label='error' error={<span>Error!! <a href="#!" onClick={e => { e.preventDefault(); console.log('some help'); }}>?</a></span>} />
<Input type='text' value={this.state.error} name="error" onChange={this.handleChange.bind(this, 'error')} label='error' error={<span>Error!! <a href="#!" onClick={e => { e.preventDefault(); console.log('some help'); }}>?</a></span>} />
</section>
);
}

View File

@ -15,18 +15,18 @@
<meta http-equiv="cleartype" content="on">
<meta name="twitter:card" content="summary">
<meta name="twitter:site" content="www.react-toolbox.com">
<meta name="twitter:site" content="www.react-toolbox.io">
<meta name="twitter:title" content="React Toolbox">
<meta name="twitter:description" content="React Toolbox is a set of React components that implement Google's Material Design specification. It's powered by CSS Modules and harmoniously integrates with your Webpack workflow. You can take a tour through our documentation website and try the components live!.">
<meta name="twitter:image" content="images/logo.png">
<meta name="og:title" content="React Toolbox">
<meta name="og:description" content="React Toolbox is a set of React components that implement Google's Material Design specification. It's powered by CSS Modules and harmoniously integrates with your Webpack workflow. You can take a tour through our documentation website and try the components live!.">
<meta name="og:url" content="www.react-toolbox.com">
<meta name="og:url" content="www.react-toolbox.io">
<meta name="og:image" content="images/logo.png">
<meta name="og:type" content="app">
<link rel="canonical" href="http://www.react-toolbox.com/">
<link rel="canonical" href="http://www.react-toolbox.io/">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700" rel="stylesheet">
<link rel="stylesheet" href="docs.css">

View File

@ -1 +1 @@
react-toolbox.com
react-toolbox.io

View File

@ -1,7 +1,7 @@
{
"name": "react-toolbox",
"description": "A set of React components implementing Google's Material Design specification with the power of CSS Modules.",
"homepage": "http://www.react-toolbox.com",
"homepage": "http://www.react-toolbox.io",
"version": "2.0.0-beta.11",
"main": "./lib",
"module": "./components",
@ -15,7 +15,7 @@
"url": "git+https://github.com/react-toolbox/react-toolbox.git"
},
"bugs": {
"email": "issues@react-toolbox.com",
"email": "issues@react-toolbox.io",
"url": "https://github.com/react-toolbox/react-toolbox/issues"
},
"keywords": [
@ -34,6 +34,8 @@
"react-transition-group": "^1.1.3"
},
"devDependencies": {
"@types/node": "^7.0.4",
"@types/react": "^15.0.0",
"babel-cli": "^6.24.1",
"babel-core": "^6.24.1",
"babel-eslint": "^7.2.3",
@ -86,10 +88,12 @@
"react-transform-hmr": "^1.0.4",
"redbox-react": "^1.3.6",
"rimraf": "^2.6.1",
"sinon": "^2.0.0-pre.2",
"style-loader": "^0.18.1",
"stylelint": "^7.10.1",
"stylelint-config-standard": "^16.0.0",
"stylelint-order": "^0.4.4",
"typescript": "^2.1.5",
"webpack": "^2.6.0",
"webpack-dev-middleware": "^1.10.2",
"webpack-hot-middleware": "^2.18.0"
@ -111,6 +115,8 @@
"prepublish": "npm run build",
"release": "bumped release",
"start": "cross-env NODE_ENV=development UV_THREADPOOL_SIZE=100 node ./server",
"ts": "tsc",
"tsd": "cpx \"./components/**/*.d.ts\" ./lib",
"test": "jest",
"test:watch": "jest --watch --no-watchman"
},

View File

@ -30,7 +30,7 @@ class InputTest extends React.Component {
/>
<Input type="email" name="fixedLabel" value={this.state.fixedLabel} label="Label fixed" floating={false} onChange={this.handleChange} />
<Input type="text" value="Read only" readOnly label="Phone Number" />
<Input type="email" name="multilineHint" multilineHint value={this.state.multilineHint} label="Description" hint="Enter Description" multiline onChange={this.handleChange} />
<Input type="email" name="multilineHint" value={this.state.multilineHint} label="Description" hint="Enter Description" multiline onChange={this.handleChange} />
<Input type="text" name="multilineRows" value={this.state.multilineRows} label="Row Limited Description" hint="Enter Description" multiline rows={4} onChange={this.handleChange} />
<Input type="text" label="Disabled field" disabled />
<Input type="tel" name="withIcon" value={this.state.withIcon} required label="With icon" onChange={this.handleChange} icon="phone" />

View File

@ -20,6 +20,7 @@ const TooltipTest = () => (
<section>
<h5>Tooltip</h5>
<p>Give information on :hover</p>
<TooltipButton label="Bookmark" icon="bookmark" raised primary disabled={true} tooltip="Bookmark Tooltip" tooltipDelay={1000} />
<TooltipButton label="Bookmark" icon="bookmark" raised primary tooltip="Bookmark Tooltip" tooltipDelay={1000} />
<TooltipButton icon="add" floating accent tooltip="Floating Tooltip" />
<TooltipButton icon="add" floating disabled tooltip="Floating can not be shown" />

View File

@ -52,7 +52,7 @@ class Root extends Component {
>
<ButtonToolbox
className={style.github}
href="http://react-toolbox.com/#/"
href="http://react-toolbox.io/#/"
target="_blank"
icon="web"
floating

22
spec/ts/app_bar.tsx Normal file
View File

@ -0,0 +1,22 @@
import * as React from 'react';
import AppBar, {AppBar as NamedAppBar} from 'components/app_bar';
const AppBarTest: React.SFC<any> = () => (
<section>
<h5>AppBar</h5>
<br />
<AppBar title='Title' />
<br />
<AppBar leftIcon='menu' title='Title' />
<br />
<AppBar leftIcon='arrow_back' title='Title' rightIcon='close' />
<br />
<AppBar>
Custom content
</AppBar>
<br/>
<NamedAppBar title='NamedAppBar' />
</section>
)
export default AppBarTest;

96
spec/ts/autocomplete.tsx Normal file
View File

@ -0,0 +1,96 @@
import * as React from 'react';
import Autocomplete from 'components/autocomplete';
class AutocompleteTest extends React.Component<any, any> {
state: any = {
simple: 'Spain',
simpleShowAll: 'England',
multipleArray: ['ES-es', 'TH-th'],
multipleObject: {'ES-es': 'Spain', 'TH-th': 'Thailand'},
countriesArray: ['Spain', 'England', 'USA', 'Thailand', 'Tongo', 'Slovenia'],
countriesObject: {
'EN-gb': 'England',
'EN-en': 'United States of America', 'EN-nz': 'New Zealand'
}
};
handleFocus = (event: React.MouseEvent<any>) => {
console.log('This is focused');
console.log(event);
};
handleMultipleArrayChange = (value: any) => {
this.setState({
multipleArray: value,
countriesObject: {
...this.state.countriesObject,
...(value[0] && !this.state.countriesObject[value[0]]) ? {[value[0]]: value[0]} : {}
}
});
};
handleMultipleObjectChange = (value: any) => {
this.setState({
multipleObject: value
});
};
handleSimpleChange = (value: any) => {
this.setState({simple: value});
};
handleSimpleShowAllChange = (value: any) => {
this.setState({simpleShowAll: value});
};
render () {
return (
<section>
<h5>Autocomplete</h5>
<p>You can have a multiple or simple autocomplete.</p>
<Autocomplete
allowCreate
keepFocusOnChange
label="Pick multiple elements..."
onFocus={this.handleFocus}
onChange={this.handleMultipleArrayChange}
source={this.state.countriesObject}
suggestionMatch="anywhere"
value={this.state.multipleArray}
/>
<Autocomplete
allowCreate
label="Pick multiple elements with object value..."
onChange={this.handleMultipleObjectChange}
showSelectedWhenNotInSource
source={this.state.countriesObject}
suggestionMatch="anywhere"
value={this.state.multipleObject}
/>
<Autocomplete
hint="Elements up to you..."
label="Choose a country"
multiple={false}
onChange={this.handleSimpleChange}
source={this.state.countriesArray}
value={this.state.simple}
/>
<Autocomplete
hint="Elements up to you..."
label="Choose a country (showing all suggestions)"
multiple={false}
onChange={this.handleSimpleShowAllChange}
showSuggestionsWhenValueIsSet
source={this.state.countriesArray}
value={this.state.simpleShowAll}
/>
</section>
);
}
}
export default AutocompleteTest;

22
spec/ts/avatar.tsx Normal file
View File

@ -0,0 +1,22 @@
import * as React from 'react';
import Avatar from '../../components/avatar';
import GithubIcon from './github_icon';
const AvatarTest = () => (
<section>
<h5>Avatars</h5>
<p>Provide an image source or object, a font icon, children or a title to use its first letter.</p>
<Avatar style={{ backgroundColor: 'deepskyblue' }} icon="folder" alt="icon folder" />
<Avatar icon={<GithubIcon />} />
<Avatar><img src="https://placeimg.com/80/80/animals" alt="foobar" /></Avatar>
<Avatar image="https://placeimg.com/80/80/animals" alt="foobar" />
<Avatar
alt="foobar"
image="http://www.thewrap.com/wp-content/uploads/2015/08/margot-robbie-harley-quinn_main.jpg" cover
/>
<Avatar title="Javier" />
<Avatar style={{ backgroundColor: 'yellowgreen' }}><GithubIcon /></Avatar>
</section>
);
export default AvatarTest;

51
spec/ts/button.tsx Normal file
View File

@ -0,0 +1,51 @@
import * as React from 'react';
import GithubIcon from './github_icon';
import { Button, IconButton, BrowseButton } from '../../components/button';
const ButtonTest = () => (
<section>
<h5>Buttons</h5>
<p>lorem ipsum...</p>
<Button href="http://github.com/javivelasco" target="_blank" raised>
<GithubIcon /> Github
</Button>
<Button icon="bookmark" label="Bookmark" accent onRippleEnded={rippleEnded} />
<Button icon="bookmark" label="Bookmark" raised primary rippleMultiple={false} onRippleEnded={rippleEnded} />
<Button icon="inbox" label="Inbox" flat />
<Button icon="add" floating />
<Button icon="add" floating primary />
<Button href="http://github.com/javivelasco" target="_blank" icon="link" floating accent />
<Button icon="add" floating primary disabled />
<Button icon="add" floating accent mini />
<IconButton icon="favorite" accent />
<IconButton icon="favorite" inverse />
<IconButton icon="favorite" />
<IconButton icon="favorite" disabled />
<IconButton primary><GithubIcon /></IconButton>
<Button icon="add" label="Add this" flat primary />
<Button icon="add" label="Add this" flat disabled />
<h5>Icon Button Alignment</h5>
<p>
Icon Buttons should align in the vertical center, to see this we need to
put them next to text or highlight thier background color.
</p>
<IconButton icon="menu" style={{ backgroundColor: 'red' }} inverse />
<span style={{ verticalAlign: 'middle' }}>Menu</span>
<IconButton icon="menu" />
<span style={{ verticalAlign: 'middle' }}>Menu</span>
<IconButton><GithubIcon /></IconButton>
<span style={{ verticalAlign: 'middle' }}>Github</span>
<h5>Browse Button</h5>
<br />
<BrowseButton icon="folder_open" label="BROWSE" raised primary />
&nbsp;
<BrowseButton label="BROWSE" raised />
</section>
);
function rippleEnded() {
console.log('Ripple animation ended!');
}
export default ButtonTest;

247
spec/ts/card.tsx Normal file
View File

@ -0,0 +1,247 @@
/* eslint-disable react/prop-types */
import * as React from 'react';
import Button, { IconButton } from '../../components/button';
import Card, { CardActions, CardMedia, CardText, CardTitle } from '../../components/card';
const style = require('../style.css');
const dummyText = 'Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry\'s standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.';
const Spacer: React.SFC<any> = () => <div style={{ display: 'flex', flex: '1 1 auto' }} />;
const CardList: React.SFC<any> = ({ children }) => <ul className={style.cardsGroup}>{children}</ul>;
const CardListItem: React.SFC<any> = ({ component, name }) => (
<li className={style.cardItem}>
<div className={style.cardItemContent}>{component}</div>
<div className={style.cardItemName}>{name}</div>
</li>
);
const cards: any = {
basic: [{
name: 'Basic Card',
component: (
<Card className={style.card}>
<CardTitle
title="Title goes here"
subtitle="Subtitle here"
/>
<CardText>{dummyText}</CardText>
<CardActions>
<Button label="Action 1" />
<Button label="Action 2" />
</CardActions>
</Card>
),
}, {
name: 'Raised Card',
component: (
<Card raised className={style.card}>
<CardTitle
title="Title goes here"
subtitle="Subtitle here"
/>
<CardText>{dummyText}</CardText>
<CardActions>
<Button label="Action 1" />
<Button label="Action 2" />
</CardActions>
</Card>
),
}, {
name: 'Customized header',
component: (
<Card className={style.card}>
<CardTitle
title={<u>Title component</u>}
subtitle={<u>Subtitle component</u>}
/>
<CardText>{dummyText}</CardText>
<CardActions>
<Button label="Action 1" />
<Button label="Action 2" />
</CardActions>
</Card>
),
}],
media: [{
name: '16:9 Card Media Area',
component: (
<Card className={style.card}>
<CardMedia
aspectRatio="wide"
className={style.primary}
>
<CardTitle>Basic Card</CardTitle>
</CardMedia>
<CardTitle subtitle="You can also use a subtitle like this" />
<CardText>{dummyText}</CardText>
</Card>
),
}, {
name: '16:9 Card Media Image',
component: (
<Card className={style.card}>
<CardMedia
aspectRatio="wide"
image="https://placeimg.com/800/450/nature"
/>
<CardTitle
title="Title goes here"
subtitle="Subtitle here"
/>
<CardText>{dummyText}</CardText>
</Card>
),
}, {
name: 'Square Media Card',
component: (
<Card className={style.card}>
<CardMedia
contentOverlay
aspectRatio="square"
image="https://placeimg.com/700/700/nature"
>
<CardTitle
title="Title goes here"
subtitle="Subtitle here"
/>
<CardActions>
<Button inverse label="Action 1" />
<Button inverse label="Action 2" />
</CardActions>
</CardMedia>
</Card>
),
}],
avatar: [{
name: 'Avatar Card Title',
component: (
<Card className={style.card}>
<CardTitle
avatar="https://placeimg.com/80/80/animals"
title="Avatar Card"
subtitle="An awesome basic card"
/>
<CardMedia
aspectRatio="wide"
image="https://placeimg.com/800/450/nature"
/>
<CardActions style={{ justifyContent: 'flex-end' }}>
<IconButton icon="share" />
<IconButton icon="favorite" />
</CardActions>
</Card>
),
}, {
name: 'Video in a card',
component: (
<Card className={style.card}>
<CardTitle
avatar="https://placeimg.com/80/80/animals"
title="Avatar Card"
subtitle="An awesome basic card"
/>
<CardMedia
aspectRatio="wide"
>
<iframe width="1280" height="720" src="https://www.youtube.com/embed/sGbxmsDFVnE?rel=0&amp;showinfo=0" frameBorder="0" allowFullScreen />
</CardMedia>
<CardActions style={{ justifyContent: 'flex-end' }}>
<IconButton icon="report_problem" />
<Spacer />
<IconButton icon="share" />
<IconButton icon="favorite" />
</CardActions>
</Card>
),
}],
horizontal: [{
name: 'Alternative Layout Example',
component: (
<Card className={style.card}>
<div className={style.cardRow}>
<CardTitle
title="Title goes here"
subtitle="Subtitle here"
/>
<CardMedia
className={style.media}
image="https://placeimg.com/400/400/nature"
/>
</div>
<CardActions>
<Button label="Action 1" />
<Button label="Action 2" />
</CardActions>
</Card>
),
}, {
name: 'Another Variation',
component: (
<Card>
<div className={style.cardRow}>
<CardTitle
title="Title goes here"
subtitle="Subtitle here"
/>
<CardMedia
className={style.mediaLarge}
image="https://placeimg.com/400/400/nature"
/>
</div>
</Card>
),
}],
small: [{
name: 'Small Media Card',
component: (
<Card>
<CardMedia
aspectRatio="square"
image="https://placeimg.com/400/400/nature"
>
<CardTitle>Test</CardTitle>
</CardMedia>
<CardActions style={{ justifyContent: 'center' }}>
<IconButton icon="thumb_down" />
<IconButton icon="thumb_up" />
<IconButton icon="turned_in_not" />
</CardActions>
</Card>
),
}, {
name: 'Small Media Controls',
component: (
<Card style={{ width: '140px' }}>
<CardMedia
contentOverlay
aspectRatio="square"
image="https://placeimg.com/280/280/people"
>
<CardActions style={{ justifyContent: 'center' }}>
<IconButton inverse icon="fast_rewind" />
<IconButton inverse icon="play_arrow" />
<IconButton inverse icon="fast_forward" />
</CardActions>
</CardMedia>
</Card>
),
}],
};
const CardTest = () => (
<section>
<h5>Cards</h5>
<p>You have multiple options for cards. Combine different subcomponents to create your own:</p>
<div className={style.cards}>
{Object.keys(cards).map(key => (
<CardList key={key}>
{cards[key].map((demo: any, i: any) => <CardListItem key={key + i} {...demo} />)}
</CardList>
))}
</div>
</section>
);
export default CardTest;

56
spec/ts/checkbox.tsx Normal file
View File

@ -0,0 +1,56 @@
import * as React from 'react';
import Checkbox from '../../components/checkbox';
class CheckboxTest extends React.Component<any, any> {
state = {
checkbox_1: true,
checkbox_2: false,
checkbox_3: true,
};
handleChange = (field: any, value: any) => {
this.setState({ ...this.state, [field]: value });
};
handleFocus = () => {
console.log('Focused');
};
handleBlur = () => {
console.log('Blur');
};
render() {
return (
<section>
<h5>Checkbox</h5>
<p style={{ marginBottom: '10px' }}>Lorem ipsum...</p>
<Checkbox
checked={this.state.checkbox_1}
label="Checked checkbox"
onChange={this.handleChange.bind(this, 'checkbox_1')}
onFocus={this.handleFocus}
onBlur={this.handleBlur}
/>
<Checkbox
checked={this.state.checkbox_2}
label="Not checked checkbox"
onChange={this.handleChange.bind(this, 'checkbox_2')}
onFocus={this.handleFocus}
onBlur={this.handleBlur}
/>
<Checkbox
checked={this.state.checkbox_3}
label="Disabled checkbox"
disabled
onChange={this.handleChange.bind(this, 'checkbox_3')}
onFocus={this.handleFocus}
onBlur={this.handleBlur}
/>
</section>
);
}
}
export default CheckboxTest;

67
spec/ts/chip.tsx Normal file
View File

@ -0,0 +1,67 @@
import * as React from 'react';
import Avatar from '../../components/avatar';
import Chip from '../../components/chip';
const style = require('../style.css');
class ChipTest extends React.Component<any, any> {
state = {
deleted: false,
};
handleDeleteClick = () => {
this.setState({
deleted: true,
});
};
render() {
return (
<section>
<h5>Chips</h5>
<p>Chips can be deletable and have an avatar.</p>
<Chip>Example chip</Chip>
<Chip>
<span style={{ textDecoration: 'line-through' }}>Standard</span>
<strong>Custom</strong> chip <small>(custom markup)</small>
</Chip>
{
this.state.deleted ? null : (
<Chip
deletable
onDeleteClick={this.handleDeleteClick}
>
Deletable Chip
</Chip>
)
}
<Chip>
<Avatar style={{ backgroundColor: 'deepskyblue' }} icon="folder" />
<span>Avatar Chip</span>
</Chip>
<Chip>
<Avatar title="A" /><span>Initial chip</span>
</Chip>
<Chip>
<Avatar><img src="https://placeimg.com/80/80/animals" /></Avatar>
<span>Image contact chip</span>
</Chip>
<div className={style.chipTruncateWrapper}>
<Chip deletable>
Truncated chip with long label. Lorem ipsum Amet quis mollit Excepteur id dolore.
</Chip>
</div>
</section>
);
}
}
export default ChipTest;

95
spec/ts/dialog.tsx Normal file
View File

@ -0,0 +1,95 @@
import * as React from 'react';
import Button from '../../components/button';
import Dialog from '../../components/dialog';
import Dropdown from '../../components/dropdown';
const dialogTypes = [
{ value: 'small', label: 'small' },
{ value: 'normal', label: 'normal' },
{ value: 'large', label: 'large' },
{ value: 'fullscreen', label: 'fullscreen' },
];
class DialogTest extends React.Component<any, any> {
state = {
active: false,
type: 'normal',
};
handleToggle = () => {
this.setState({
active: !this.state.active,
});
};
changeDialogType = (value: any) => {
this.setState({ type: value });
};
actions = [
{ label: 'Disagree', primary: true, onClick: this.handleToggle },
{ label: 'Agree', primary: true, onClick: this.handleToggle },
];
render() {
return (
<section>
<h5>Dialog</h5>
<p>lorem ipsum...</p>
<Dropdown
label="Dialog Type"
auto
onChange={this.changeDialogType}
source={dialogTypes}
value={this.state.type}
/>
<Button label="Show Dialog" raised primary onClick={this.handleToggle} />
<ContextComponent>
<Dialog
actions={this.actions}
active={this.state.active}
type={this.state.type}
title="Use Google's location service?"
onOverlayClick={this.handleToggle}
onEscKeyDown={this.handleToggle}
>
<p>Let Google help apps <strong>determine location</strong>. This means sending anonymous location data to Google, even when no apps are running.</p>
<DialogChild />
</Dialog>
</ContextComponent>
</section>
);
}
}
class ContextComponent extends React.Component<any, any> {
static propTypes = {
children: React.PropTypes.any,
};
static childContextTypes = {
message: React.PropTypes.string,
}
getChildContext() {
return {
message: 'Hi, I\'m the top container',
};
}
render() {
return this.props.children;
}
}
class DialogChild extends React.Component<any, any> {
static contextTypes = {
message: React.PropTypes.string,
}
render() {
return <p>This message comes from a parent: <strong>{this.context.message}</strong></p>;
}
}
export default DialogTest;

50
spec/ts/drawer.tsx Normal file
View File

@ -0,0 +1,50 @@
import * as React from 'react';
import Button from '../../components/button';
import Drawer from '../../components/drawer';
const style = require('../style.css');
class DrawerTest extends React.Component<any, any> {
state = {
leftActive: false,
rightActive: false,
};
handleToggleLeft = () => {
this.setState({ leftActive: !this.state.leftActive });
};
handleToggleRight = () => {
this.setState({ rightActive: !this.state.rightActive });
};
render() {
return (
<section>
<h5>Drawer</h5>
<p>You can navigate using a drawer to the left or right.</p>
<Drawer
active={this.state.leftActive}
className={style.drawer}
onOverlayClick={this.handleToggleLeft}
>
<h5>Officia deserunt mollit.</h5>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</Drawer>
<Drawer active={this.state.rightActive} type="right">
<Button primary label="Close" onClick={this.handleToggleRight} />
</Drawer>
<nav>
<Button label="Drawer left" raised primary onClick={this.handleToggleLeft} />
<Button label="Drawer right" raised accent onClick={this.handleToggleRight} />
</nav>
</section>
);
}
}
export default DrawerTest;

82
spec/ts/dropdown.tsx Normal file
View File

@ -0,0 +1,82 @@
import * as React from 'react';
import Dropdown from '../../components/dropdown';
const style = require('../style.css');
const countries = [
{ value: 'EN-gb', label: 'England', img: 'http://' },
{ value: 'ES-es', label: 'Spain', img: 'http://' },
{ value: 'TH-th', label: 'Thailand', img: 'http://' },
{ value: 'EN-en', label: 'USA', img: 'http://' },
{ value: 'FR-fr', label: 'France', img: 'http://' },
];
class DropdownTest extends React.Component<any, any> {
state: any = {
dropdown4: 'TH-th',
};
handleChange = (dropdown: any, value: any) => {
console.log('selected', value);
const newState: any = {};
newState[dropdown] = value;
this.setState(newState);
};
customDropdownItem(data: any) {
return (
<div className={style.dropdownTemplate}>
<img className={style.dropdownTemplateImage} src={data.img} />
<div className={style.dropdownTemplateContent}>
<strong>{data.label}</strong>
<small>{data.value}</small>
</div>
</div>
);
}
render() {
return (
<section>
<h5>Dropdown</h5>
<p>lorem ipsum...</p>
<Dropdown
label="Country"
ref="dropdown1"
onChange={this.handleChange.bind(this, 'dropdown1')}
source={countries}
template={this.customDropdownItem}
value={this.state.dropdown1}
/>
<Dropdown
label="Country"
ref="dropdown4"
onChange={this.handleChange.bind(this, 'dropdown4')}
source={countries}
value={this.state.dropdown4}
/>
<Dropdown
disabled
ref="dropdown3"
label="Country"
onChange={this.handleChange.bind(this, 'dropdown3')}
source={countries}
/>
<Dropdown
label="Country"
ref="dropdown5"
onChange={this.handleChange.bind(this, 'dropdown5')}
source={countries}
value={this.state.dropdown5}
required
/>
</section>
);
}
}
export default DropdownTest;

17
spec/ts/font_icon.tsx Normal file
View File

@ -0,0 +1,17 @@
import * as React from 'react';
import FontIcon from '../../components/font_icon';
const FontIconTest = () => (
<section>
<h5>Font Icons</h5>
<p>lorem ipsum...</p>
<FontIcon value="add" alt="add icon" />
<FontIcon value="access_alarm" />
<FontIcon value="explore" alt="explore icon" />
<FontIcon value="zoom_in" alt="zoom icon" />
<FontIcon alt="input icon">input</FontIcon>
</section>
);
export default FontIconTest;

10
spec/ts/github_icon.tsx Normal file
View File

@ -0,0 +1,10 @@
import * as React from 'react';
const GithubIcon = () => (
<svg viewBox="0 0 284 277" aria-labelledby="title">
<title id="title">GitHub Icon</title>
<g><path d="M141.888675,0.0234927555 C63.5359948,0.0234927555 0,63.5477395 0,141.912168 C0,204.6023 40.6554239,257.788232 97.0321356,276.549924 C104.12328,277.86336 106.726656,273.471926 106.726656,269.724287 C106.726656,266.340838 106.595077,255.16371 106.533987,243.307542 C67.0604204,251.890693 58.7310279,226.56652 58.7310279,226.56652 C52.2766299,210.166193 42.9768456,205.805304 42.9768456,205.805304 C30.1032937,196.998939 43.9472374,197.17986 43.9472374,197.17986 C58.1953153,198.180797 65.6976425,211.801527 65.6976425,211.801527 C78.35268,233.493192 98.8906827,227.222064 106.987463,223.596605 C108.260955,214.426049 111.938106,208.166669 115.995895,204.623447 C84.4804813,201.035582 51.3508808,188.869264 51.3508808,134.501475 C51.3508808,119.01045 56.8936274,106.353063 65.9701981,96.4165325 C64.4969882,92.842765 59.6403297,78.411417 67.3447241,58.8673023 C67.3447241,58.8673023 79.2596322,55.0538738 106.374213,73.4114319 C117.692318,70.2676443 129.83044,68.6910512 141.888675,68.63701 C153.94691,68.6910512 166.09443,70.2676443 177.433682,73.4114319 C204.515368,55.0538738 216.413829,58.8673023 216.413829,58.8673023 C224.13702,78.411417 219.278012,92.842765 217.804802,96.4165325 C226.902519,106.353063 232.407672,119.01045 232.407672,134.501475 C232.407672,188.998493 199.214632,200.997988 167.619331,204.510665 C172.708602,208.913848 177.243363,217.54869 177.243363,230.786433 C177.243363,249.771339 177.078889,265.050898 177.078889,269.724287 C177.078889,273.500121 179.632923,277.92445 186.825101,276.531127 C243.171268,257.748288 283.775,204.581154 283.775,141.912168 C283.775,63.5477395 220.248404,0.0234927555 141.888675,0.0234927555" /></g>
</svg>
);
export default GithubIcon;

53
spec/ts/icon_menu.tsx Normal file
View File

@ -0,0 +1,53 @@
import * as React from 'react';
import { MenuItem, IconMenu, MenuDivider } from '../../components/menu';
class IconMenuTest extends React.Component<any, any> {
state: any = {
selected: undefined,
};
handleShow = () => {
console.log('Showing menu...');
};
handleHide = () => {
console.log('Hiding menu...');
};
handleSelect = (value: any) => {
console.log('Option selected', value);
this.setState({ selected: value });
};
handleItem = () => {
console.log('Refresh clicked');
};
render() {
return (
<section>
<h5>Icon Menus</h5>
<p>Although a menu can be used indepently with any component, we are providing a common use case with the icon menu.</p>
<IconMenu
icon="more_vert"
position="auto"
iconRipple
menuRipple
onShow={this.handleShow}
onHide={this.handleHide}
onSelect={this.handleSelect}
selectable
selected={this.state.selected}
>
<MenuItem onClick={this.handleItem} value="refresh" caption="Refresh" />
<MenuItem value="help" caption="Help & Feedback" />
<MenuItem value="settings" caption="Settings" />
<MenuDivider />
<MenuItem value="signout" caption="Sign out" disabled />
</IconMenu>
</section>
);
}
}
export default IconMenuTest;

43
spec/ts/input.tsx Normal file
View File

@ -0,0 +1,43 @@
import * as React from 'react';
import Input from '../../components/input';
class InputTest extends React.Component<any, any> {
state = {
normal: 'Tony Stark',
fixedLabel: '',
withIcon: '',
withCustomIcon: '',
withHintCustomIcon: '',
multilineHint: 'Long Description here',
multilineRows: 'A\n\B\nC\nD\nE\nF',
};
handleChange = (name: any, value: any) => {
this.setState({ ...this.state, [name]: value });
};
render() {
return (
<section>
<h5>Inputs</h5>
<p>lorem ipsum...</p>
<Input
type="text"
value={this.state.normal}
label="First Name" onChange={this.handleChange.bind(this, 'normal')}
maxLength={12}
/>
<Input type="email" value={this.state.fixedLabel} label="Label fixed" floating={false} onChange={this.handleChange.bind(this, 'fixedLabel')} />
<Input type="text" value="Read only" rows={1} label="Phone Number" />
<Input type="email" value={this.state.multilineHint} label="Description" hint="Enter Description" multiline onChange={this.handleChange.bind(this, 'multilineHint')} />
<Input type="text" value={this.state.multilineRows} label="Row Limited Description" hint="Enter Description" multiline rows={4} onChange={this.handleChange.bind(this, 'multilineRows')} />
<Input type="text" label="Disabled field" disabled />
<Input type="tel" value={this.state.withIcon} required label="With icon" onChange={this.handleChange.bind(this, 'withIcon')} icon="phone" />
<Input type="tel" value={this.state.withCustomIcon} label="With custom icon" onChange={this.handleChange.bind(this, 'withCustomIcon')} icon="favorite" />
<Input type="text" value={this.state.withHintCustomIcon} label="With Hint Text Icon" hint="Hint Text" onChange={this.handleChange.bind(this, 'withHintCustomIcon')} icon="share" />
</section>
);
}
}
export default InputTest;

13
spec/ts/link.tsx Normal file
View File

@ -0,0 +1,13 @@
import * as React from 'react';
import Link from '../../components/link';
const LinkTest = () => (
<section>
<h5>Links</h5>
<p>lorem ipsum...</p>
<Link label="Github" route="http://www.github.com" icon="bookmark" />
<Link label="Inbox" route="http://mail.google.com" icon="inbox" />
</section>
);
export default LinkTest;

190
spec/ts/list.tsx Normal file
View File

@ -0,0 +1,190 @@
import * as React from 'react';
import { ListCheckbox, ListSubHeader, List, ListItem, ListDivider, ListItemText, ListItemContent } from '../../components/list';
import { Button } from '../../components/button';
import Avatar from '../../components/avatar';
import FontIcon from '../../components/font_icon';
const listStyle = {
border: '1px solid #EEE',
display: 'inline-block',
minWidth: 340,
};
class ListTest extends React.Component<any, any> {
state: any = {
checkbox1: false,
checkbox2: true,
checkbox3: true,
};
handleCheckboxChange = (field: any) => {
const newState: any = {};
newState[field] = !this.state[field];
this.setState(newState);
};
render() {
return (
<section>
<h5>With simple text and icons</h5>
<p>This list can be used inside a Drawer for a list of options or as navigation.</p>
<div style={listStyle}>
<List selectable ripple>
<ListSubHeader caption="Contacts" />
<ListItem caption="Inbox" leftIcon="inbox" />
<ListItem caption="Outbox" selectable={false} ripple={false} leftIcon="send" />
<ListItem caption="Trash" leftIcon="delete" />
<ListItem caption="Spam" leftIcon="report" />
</List>
</div>
<h5>Two text lines, avatar and right icon</h5>
<p>Useful for a list of contacts or similar.</p>
<div style={listStyle}>
<List selectable ripple>
<ListSubHeader caption="Contacts" />
<ListItem
avatar="https://pbs.twimg.com/profile_images/614407428/s6pTalMzZs-nusCGWqoV.0_400x400.jpeg"
caption="Alfonso Rocha"
legend="Product Manager at Fon"
rightIcon="star"
/>
<ListItem
avatar="https://pbs.twimg.com/profile_images/693578804808278017/a5y4h8MN_400x400.png"
caption="Javi Velasco"
legend="Frontend engineer at Audiense"
rightIcon="star"
/>
<ListItem
avatar="https://avatars2.githubusercontent.com/u/559654?v=3&s=460"
caption="Javi Jiménez"
legend="Frontend engineer at MediaSmart"
rightIcon="star"
/>
<ListItem
avatar="https://pbs.twimg.com/profile_images/755797598565531649/Whsf9259.jpg"
caption="Tobias Van Schneider"
legend="Designer at Spotify"
rightIcon="star"
/>
</List>
</div>
<h5>Two line options and checkbox items</h5>
<p>It can be used to embed little checkboxes in the list. These behave as checkboxes.</p>
<div style={listStyle}>
<List>
<ListSubHeader caption="General" />
<ListItem caption="Profile Photo" legend="Change your Google+ profile photo" />
<ListItem disabled caption="Show your status" legend="Your status is visible to everyone you use with" />
</List>
<ListDivider />
<List>
<ListSubHeader caption="Hangout notifications" />
<ListCheckbox
caption="Notifications"
checked={this.state.checkbox1}
legend="Allow notifications"
onChange={this.handleCheckboxChange.bind(this, 'checkbox1')}
/>
<ListCheckbox
caption="Sound"
checked={this.state.checkbox2}
legend="Hangouts message"
onChange={this.handleCheckboxChange.bind(this, 'checkbox2')}
/>
<ListCheckbox
caption="Video sounds"
checked
disabled
legend="Hangouts video call"
/>
</List>
</div>
<h5>Avatar, single text and icon</h5>
<p>Similar to a previous one but only with one text line</p>
<div style={listStyle}>
<List>
<ListItem
avatar="https://pbs.twimg.com/profile_images/614407428/s6pTalMzZs-nusCGWqoV.0_400x400.jpeg"
caption="Alfonso Rocha"
rightIcon="mail"
/>
<ListItem
avatar="https://pbs.twimg.com/profile_images/693578804808278017/a5y4h8MN_400x400.png"
caption="Javi Velasco"
rightIcon="mail"
/>
<ListItem
avatar="https://avatars2.githubusercontent.com/u/559654?v=3&s=460"
caption="Javi Jiménez"
rightIcon="mail"
/>
<ListItem
avatar="https://pbs.twimg.com/profile_images/755797598565531649/Whsf9259.jpg"
caption="Tobias Van Schneider"
rightIcon="mail"
/>
</List>
</div>
<h5>Simple with just one text line</h5>
<p>The most simple list.</p>
<div style={listStyle}>
<List>
<ListItem caption="Alfonso Rocha" />
<ListItem caption="Javi Velasco" />
<ListItem caption="Javi Jiménez" />
<ListItem caption="Tobias Van Schneider" />
<ListDivider />
<ListItem caption="Other people" />
</List>
</div>
<h5> List with custom components </h5>
<p> Using custom components in list item </p>
<div style={listStyle}>
<List ripple selectable>
<ListItem leftIcon="send" rightIcon="done" caption="Reference item" />
<ListItem rightIcon="done" caption="Item with custom left icons">
<FontIcon value="send" />
<Avatar image="https://pbs.twimg.com/profile_images/693578804808278017/a5y4h8MN_400x400.png" />
</ListItem>
<ListItem leftIcon="send">
<ListItemContent caption="custom right icons" legend="ListItemContent acts as a divider" />
<FontIcon value="done" />
<FontIcon value="undo" />
</ListItem>
<ListItem leftIcon="mail" rightIcon="create">
<ListItemContent>
<ListItemText primary> Custom Caption </ListItemText>
</ListItemContent>
</ListItem>
<ListItem leftIcon="save" rightIcon="delete">
<ListItemContent>
<ListItemText primary onClick={() => { console.log('clicked caption'); }}>
Custom caption with events
</ListItemText>
<ListItemText> Custom legend with correct height </ListItemText>
</ListItemContent>
</ListItem>
<ListItem caption="Item with a button">
<Button icon="save" label="save" onClick={() => console.log('clicked button')} />
</ListItem>
<ListItem caption="Item with overlayed click events" onClick={() => console.log('clicked row')}>
<FontIcon value="send" onClick={() => console.log('clicked icon')} />
<Avatar
image="https://pbs.twimg.com/profile_images/693578804808278017/a5y4h8MN_400x400.png"
onMouseDown={() => console.log('avatar mouse down, should see ripple')}
onClick={() => console.log('clicked avatar')}
/>
</ListItem>
</List>
</div>
</section>
);
}
}
export default ListTest;

38
spec/ts/menu.tsx Normal file
View File

@ -0,0 +1,38 @@
import * as React from 'react';
import { Menu, MenuItem, MenuDivider } from '../../components/menu';
class MenuTest extends React.Component<any, any> {
state: any = {
value: undefined,
};
handleSelect = (item: any) => {
console.log('Menu selection changed!!, now its', item);
this.setState({ value: item });
};
handleItemClick = () => {
console.log('This item is so special that has a special handler');
};
render() {
return (
<section>
<h5>Menus</h5>
<p>This tabs can be disabled or hidden</p>
<Menu onSelect={this.handleSelect} selectable={false} selected={this.state.value}>
<MenuItem value="foo" caption="Caption" />
<MenuItem onClick={this.handleItemClick} value="bar" caption="Caption & Shortcut" shortcut="Ctrl + P" />
<MenuItem caption="Disabled ..." disabled shortcut="Ctrl + P" />
<MenuDivider />
<MenuItem caption="Caption & Icon" icon="phone" />
<MenuItem caption="Caption, Icon & Shortcut" icon="phone" shortcut="Ctrl + P" />
<MenuItem caption="Disabled ..." icon="phone" shortcut="Ctrl + P" disabled />
</Menu>
</section>
);
}
}
export default MenuTest;

22
spec/ts/navigation.tsx Normal file
View File

@ -0,0 +1,22 @@
import * as React from 'react';
import Navigation from '../../components/navigation';
import Link from '../../components/link';
const actions = [
{ label: 'Alarm', raised: true, icon: 'access_alarm' },
{ label: 'Location', raised: true, accent: true, icon: 'room' },
];
const NavigationTest = () => (
<section>
<h5>Navigation</h5>
<p>lorem ipsum...</p>
<Navigation type="horizontal" actions={actions} />
<Navigation type="vertical">
<Link href="http://" label="Inbox" icon="inbox" />
<Link href="http://" active label="Profile" icon="person" />
</Navigation>
</section>
);
export default NavigationTest;

131
spec/ts/pickers.tsx Normal file
View File

@ -0,0 +1,131 @@
import * as React from 'react';
import DatePicker from '../../components/date_picker';
import TimePicker from '../../components/time_picker';
const datetime = new Date(2015, 10, 16);
const min_datetime = new Date(new Date(datetime).setDate(8));
const max_datetime = new Date(new Date(datetime).setDate(24));
datetime.setHours(17);
datetime.setMinutes(28);
const today = new Date();
today.setHours(0, 0, 0, 0);
const enabledDisabledDates = [new Date(today.getTime()), new Date(today.setDate(today.getDate() - 1))];
class PickersTest extends React.Component<any, any> {
state: any = {
date2: datetime,
firstActive: false,
time2: datetime,
};
handleChange = (item: any, value: any) => {
const newState: any = {};
newState.firstActive = false;
newState[item] = value;
this.setState(newState);
};
makeFirstUnactive = () => {
this.setState({ firstActive: false });
};
localeExample = {
months: 'urtarrila_otsaila_martxoa_apirila_maiatza_ekaina_uztaila_abuztua_iraila_urria_azaroa_abendua'.split('_'),
monthsShort: 'urt._ots._mar._api._mai._eka._uzt._abu._ira._urr._aza._abe.'.split('_'),
weekdays: 'igandea_astelehena_asteartea_asteazkena_osteguna_ostirala_larunbata'.split('_'),
weekdaysShort: 'ig._al._ar._az._og._ol._lr.'.split('_'),
weekdaysLetter: 'ig_al_ar_az_og_ol_lr'.split('_'),
}
render() {
return (
<section>
<h5>Pickers</h5>
<p>Date pickers and time pickers with Material flavour.</p>
<DatePicker
active={this.state.firstActive}
label="Birthdate"
onChange={this.handleChange.bind(this, 'date1')}
onEscKeyDown={this.makeFirstUnactive}
onOverlayClick={this.makeFirstUnactive}
value={this.state.date1}
sundayFirstDayOfWeek
/>
<DatePicker
label="With locale (string) - Spanish (string: en|es|af|ar|be|bg|bn|bo|br|bs|ca|gl|eu|pt|it|fr)"
locale="es"
onChange={this.handleChange.bind(this, 'date2')}
value={this.state.date2}
/>
<DatePicker
label="With locale (object) - Basque"
locale={this.localeExample}
onChange={this.handleChange.bind(this, 'date2')}
value={this.state.date2}
/>
<DatePicker
label="Expiration date (Read Only)"
maxDate={max_datetime}
minDate={min_datetime}
onChange={this.handleChange.bind(this, 'date2')}
readonly
value={this.state.date2}
sundayFirstDayOfWeek
/>
<DatePicker
label="Formatted Date"
inputFormat={(value: any) => `${value.getDate()}/${value.getMonth() + 1}/${value.getFullYear()}`}
onChange={this.handleChange.bind(this, 'date3')}
value={this.state.date3}
sundayFirstDayOfWeek
/>
<DatePicker
label="Auto Picker"
autoOk
sundayFirstDayOfWeek
onChange={this.handleChange.bind(this, 'date4')}
value={this.state.date4}
/>
<DatePicker
label="Date picker with enabled dates"
onChange={this.handleChange.bind(this, 'date5')}
enabledDates={enabledDisabledDates}
value={this.state.date5}
/>
<DatePicker
label="Date picker with disabled dates"
onChange={this.handleChange.bind(this, 'date6')}
disabledDates={enabledDisabledDates}
value={this.state.date6}
/>
<TimePicker
format="ampm"
label="Start time"
onChange={this.handleChange.bind(this, 'time1')}
onEscKeyDown={() => console.log('esc key down')}
onOverlayClick={() => console.log('overlay click')}
value={this.state.time1}
/>
<TimePicker
format="ampm"
label="Finishing time (Read Only)"
readonly
onChange={this.handleChange.bind(this, 'time2')}
value={this.state.time2}
/>
</section>
);
}
}
export default PickersTest;

59
spec/ts/progress.tsx Normal file
View File

@ -0,0 +1,59 @@
import * as React from 'react';
import ProgressBar from '../../components/progress_bar';
const style = require('../style.css');
const initialState = {
progress: 0,
buffer: 10,
};
class ProgressBarTest extends React.Component<any, any> {
state = initialState;
componentWillMount() {
this.simulateProgress();
}
simulateProgress() {
setTimeout(() => {
if (this.state.progress < 100) {
this.increaseProgress();
if (this.state.progress > this.state.buffer) this.increaseBuffer();
} else {
this.setState(initialState);
}
this.simulateProgress();
}, (Math.random() * 1 + 1) * 1000);
}
increaseProgress() {
this.setState({
progress: Math.random() * 30 + this.state.progress,
});
}
increaseBuffer() {
this.setState({
buffer: Math.random() * (100 - this.state.progress) + this.state.progress,
});
}
render() {
return (
<section>
<h5>Progress bars</h5>
<p style={{ margin: '10px auto' }}>Determinate</p>
<ProgressBar mode="determinate" value={this.state.progress} buffer={this.state.buffer} />
<p style={{ margin: '10px auto' }}>Indeterminate...</p>
<ProgressBar mode="indeterminate" />
<p style={{ margin: '10px auto' }}>Circular</p>
<ProgressBar type="circular" mode="indeterminate" />
<p style={{ margin: '10px auto' }}>Circular with custom size</p>
<ProgressBar className={style.customSizedProgress} type="circular" mode="indeterminate" theme={style} />
</section>
);
}
}
export default ProgressBarTest;

39
spec/ts/radio.tsx Normal file
View File

@ -0,0 +1,39 @@
import * as React from 'react';
import { RadioGroup, RadioButton } from '../../components/radio';
class RadioGroupTest extends React.Component<any, any> {
state = {
value: 'vvendetta',
};
handleChange = (value: any) => {
console.log('Changed!', { comic: value });
this.setState({ value });
};
handleFocus = () => {
console.log('Focused V for a Vendetta');
};
handleBlur = () => {
console.log('Blurred Watchmen');
};
render() {
return (
<section>
<h5>Radio Button</h5>
<p style={{ marginBottom: '10px' }}>Lorem ipsum...</p>
<RadioGroup name="comic" value={this.state.value} onChange={this.handleChange}>
<RadioButton label="The Walking Dead" value="thewalkingdead" />
<RadioButton label="From Hell" value="fromhell" disabled />
<RadioButton label="V for a Vendetta" value="vvendetta" onFocus={this.handleFocus} />
<RadioButton label="Watchmen" value="watchmen" onBlur={this.handleBlur} />
</RadioGroup>
</section>
);
}
}
export default RadioGroupTest;

31
spec/ts/slider.tsx Normal file
View File

@ -0,0 +1,31 @@
import * as React from 'react';
import Slider from '../../components/slider';
class SliderTest extends React.Component<any, any> {
state: any = {
slider2: 5,
slider3: 1,
};
handleChange = (slider: any, value: any) => {
this.setState({ ...this.state, [slider]: value });
};
render() {
return (
<section>
<h5>Sliders</h5>
<p>Normal slider</p>
<Slider value={this.state.slider1} onChange={this.handleChange.bind(this, 'slider1')} />
<p>With steps, initial value and editable</p>
<Slider min={0} max={10} editable value={this.state.slider2} onChange={this.handleChange.bind(this, 'slider2')} />
<p>Pinned and with snaps</p>
<Slider pinned snaps min={0} max={10} step={2} editable value={this.state.slider3} onChange={this.handleChange.bind(this, 'slider3')} />
<p>Disabled status</p>
<Slider disabled pinned snaps min={0} max={10} step={2} editable value={this.state.slider3} onChange={this.handleChange.bind(this, 'slider3')} />
</section>
);
}
}
export default SliderTest;

43
spec/ts/snackbar.tsx Normal file
View File

@ -0,0 +1,43 @@
import * as React from 'react';
import Button from '../../components/button';
import Snackbar from '../../components/snackbar';
class SnackbarTest extends React.Component<any, any> {
state = {
active: false,
};
handleSnackbarClick = () => {
this.setState({ active: false });
};
handleSnackbarTimeout = () => {
this.setState({ active: false });
};
handleClick = () => {
this.setState({ active: true });
};
render() {
return (
<section>
<h5>Snackbars & Toasts</h5>
<p>lorem ipsum...</p>
<Button label="Show snackbar" primary raised onClick={this.handleClick} />
<Snackbar
action="Hide"
active={this.state.active}
timeout={2000}
onClick={this.handleSnackbarClick}
onTimeout={this.handleSnackbarTimeout}
type="warning"
>
Snackbar action <strong>cancel</strong>
</Snackbar>
</section>
);
}
}
export default SnackbarTest;

41
spec/ts/switch.tsx Normal file
View File

@ -0,0 +1,41 @@
import * as React from 'react';
import Switch from '../../components/switch';
class SwitchTest extends React.Component<any, any> {
state = {
switch_1: true,
switch_2: false,
switch_3: true,
};
handleChange = (field: any, value: any) => {
this.setState({ ...this.state, [field]: value });
};
render() {
return (
<section>
<h5>Switches</h5>
<p style={{ marginBottom: '10px' }}>This is more beautiful than the old fashion checkboxes...</p>
<Switch
checked={this.state.switch_1}
label="Push notifications"
onChange={this.handleChange.bind(this, 'switch_1')}
/>
<Switch
checked={this.state.switch_2}
label="Mail notifications"
onChange={this.handleChange.bind(this, 'switch_2')}
/>
<Switch
checked={this.state.switch_3}
disabled
label="Nothing, thanks"
onChange={this.handleChange.bind(this, 'switch_3')}
/>
</section>
);
}
}
export default SwitchTest;

91
spec/ts/table.tsx Normal file
View File

@ -0,0 +1,91 @@
import * as React from 'react';
import { Table, TableHead, TableRow, TableCell } from '../../components/table';
import Tooltip from '../../components/tooltip';
const data = [
{ name: 'Cupcake', calories: 305, fat: 3.7, carbs: 67, protein: 4.3, sodium: 413, calcium: '3%', iron: '8%' },
{ name: 'Donut', calories: 452, fat: 25.0, carbs: 51, protein: 4.9, sodium: 326, calcium: '2%', iron: '22%' },
{ name: 'Eclair', calories: 262, fat: 16.0, carbs: 24, protein: 6.0, sodium: 337, calcium: '6%', iron: '7%' },
{ name: 'Frozen yogurt', calories: 159, fat: 6.0, carbs: 24, protein: 4.0, sodium: 87, calcium: '14%', iron: '1%' },
{ name: 'Gingerbread', calories: 356, fat: 16.0, carbs: 49, protein: 3.9, sodium: 327, calcium: '7%', iron: '16%' },
{ name: 'Ice cream sandwich', calories: 237, fat: 9.0, carbs: 37, protein: 4.3, sodium: 129, calcium: '8%', iron: '1%' },
{ name: 'Jelly bean', calories: 375, fat: 0.0, carbs: 94, protein: 0.0, sodium: 50, calcium: '0%', iron: '0%' },
{ name: 'KitKat', calories: 518, fat: 26.0, carbs: 65, protein: 7, sodium: 54, calcium: '12%', iron: '6%' },
];
const TooltippedCell = Tooltip(TableCell);
const sortByCaloriesAsc = (a: any, b: any) => {
if (a.calories < b.calories) return -1;
if (a.calories > b.calories) return 1;
return 0;
};
const sortByCaloriesDesc = (a: any, b: any) => {
if (a.calories > b.calories) return -1;
if (a.calories < b.calories) return 1;
return 0;
};
class TableTest extends React.Component<any, any> {
state: any = {
selected: ['Donut'],
sorted: 'asc',
};
getSortedData = () => {
const compare = this.state.sorted === 'asc' ? sortByCaloriesAsc : sortByCaloriesDesc;
return data.sort(compare);
}
handleRowSelect = (selected: any) => {
const sortedData = this.getSortedData();
this.setState({ selected: selected.map((item: any) => sortedData[item].name) });
};
handleSortClick = () => {
const { sorted } = this.state;
const nextSorting = sorted === 'asc' ? 'desc' : 'asc';
this.setState({ sorted: nextSorting });
};
render() {
const { sorted } = this.state;
const sortedData = this.getSortedData();
return (
<section>
<h5>Table</h5>
<p>Organized data.</p>
<Table multiSelectable onRowSelect={this.handleRowSelect} style={{ marginTop: 10 }}>
<TableHead>
<TooltippedCell tooltip="The total amount of food energy in the given serving size">
Dessert (100g serving)
</TooltippedCell>
<TableCell onClick={this.handleSortClick} numeric sorted={sorted}>Calories</TableCell>
<TableCell numeric>Fat (g)</TableCell>
<TableCell numeric>Carbs (g)</TableCell>
<TableCell numeric>Protein (g)</TableCell>
<TableCell numeric>Sodium (mg)</TableCell>
<TableCell numeric>Calcium (%)</TableCell>
<TableCell numeric>Iron (%)</TableCell>
</TableHead>
{sortedData.map((item, idx) => (
<TableRow key={idx} selected={this.state.selected.indexOf(item.name) !== -1}>
<TableCell>{item.name}</TableCell>
<TableCell numeric>{item.calories}</TableCell>
<TableCell numeric>{item.fat}</TableCell>
<TableCell numeric>{item.carbs}</TableCell>
<TableCell numeric>{item.protein}</TableCell>
<TableCell numeric>{item.sodium}</TableCell>
<TableCell numeric>{item.calcium}</TableCell>
<TableCell numeric>{item.iron}</TableCell>
</TableRow>
))}
</Table>
</section>
);
}
}
export default TableTest;

73
spec/ts/tabs.tsx Normal file
View File

@ -0,0 +1,73 @@
import * as React from 'react';
import { Tabs, Tab } from '../../components/tabs';
class TabsTest extends React.Component<any, any> {
state = {
index: 1,
fixedIndex: 1,
inverseIndex: 1,
};
handleTabChange = (index: any) => {
this.setState({ index });
};
handleFixedTabChange = (index: any) => {
this.setState({ fixedIndex: index });
};
handleInverseTabChange = (index: any) => {
this.setState({ inverseIndex: index });
};
handleActive = () => {
console.log('Special one activated');
};
render() {
return (
<section>
<h5>Tabs</h5>
<p>This tabs can be disabled or hidden</p>
<Tabs disableAnimatedBottomBorder index={this.state.index} onChange={this.handleTabChange}>
<Tab ripple={false} label="Primary"><small>Primary content (no ripple)</small></Tab>
<Tab label="Secondary" onActive={this.handleActive}><small>Secondary content</small></Tab>
<Tab label="Third" disabled><small>Disabled content</small></Tab>
<Tab label="Fourth" hidden><small>Fourth content hidden</small></Tab>
<Tab label="Fifth"><small>Fifth content</small></Tab>
</Tabs>
<h5>Fixed Tabs</h5>
<p>These tabs fill the given space.</p>
<Tabs index={this.state.fixedIndex} onChange={this.handleFixedTabChange} fixed>
<Tab label="First"><small>First Content</small></Tab>
<Tab label="Second"><small>Second Content</small></Tab>
<Tab label="Third"><small>Third Content</small></Tab>
<Tab label="Fourth"><small>Fourth Content</small></Tab>
<Tab label="Fifth"><small>Fifth Content</small></Tab>
</Tabs>
<h5>Inverse Tabs</h5>
<p>These tabs have an inverted theme.</p>
<Tabs index={this.state.inverseIndex} onChange={this.handleInverseTabChange} inverse>
<Tab label="First"><small>First Content</small></Tab>
<Tab label="Second"><small>Second Content</small></Tab>
<Tab label="Third"><small>Third Content</small></Tab>
<Tab label="Disabled" disabled><small>Disabled Content</small></Tab>
</Tabs>
<h5>Inverse Tabs with labels and icons</h5>
<Tabs index={this.state.inverseIndex} onChange={this.handleInverseTabChange} inverse>
<Tab label="Home" icon="home"><small>First Content</small></Tab>
<Tab label="Favorite" icon="favorite"><small>Second Content</small></Tab>
<Tab label="Call" icon="call"><small>Third Content</small></Tab>
</Tabs>
<h5>Inverse Tabs with icons</h5>
<Tabs index={this.state.inverseIndex} onChange={this.handleInverseTabChange} inverse>
<Tab icon="home"><small>First Content</small></Tab>
<Tab icon="favorite"><small>Second Content</small></Tab>
<Tab icon="call"><small>Third Content</small></Tab>
</Tabs>
</section>
);
}
}
export default TabsTest;

49
spec/ts/tooltip.tsx Normal file
View File

@ -0,0 +1,49 @@
import * as React from 'react';
import Button from '../../components/button';
import Input from '../../components/input';
import FontIcon from '../../components/font_icon';
import Tooltip, { tooltipFactory } from '../../components/tooltip';
import Chip from '../../components/chip';
import Avatar from '../../components/avatar';
const TooltipFontIcon = tooltipFactory({ passthrough: false })(FontIcon);
const TooltipButton = Tooltip(Button);
const TooltipInput = Tooltip(Input);
const TooltipStrong = Tooltip(({ children, ...other }) => {
delete other.theme;
return <strong {...other}>{children}</strong>;
});
const TooltipStrongDirect = Tooltip('strong');
const ChipTooltip = Tooltip(Chip);
const TooltipTest = () => (
<section>
<h5>Tooltip</h5>
<p>Give information on :hover</p>
<TooltipButton label="Bookmark" icon="bookmark" raised primary tooltip="Bookmark Tooltip" tooltipDelay={1000} />
<TooltipButton icon="add" floating accent tooltip="Floating Tooltip" />
<TooltipButton icon="add" floating disabled tooltip="Floating can not be shown" />
<TooltipButton
icon="add"
floating
tooltip={<div><p>An example with</p><p>Multiline!</p></div>}
/>
<ChipTooltip tooltip="Dolor sit amet" tooltipPosition="top">
<Avatar icon="home" />
<span>Tooltip in a chip</span>
</ChipTooltip>
<TooltipInput tooltip="lorem ipsum..." />
<p>Lorem ipsum dolor sit amet, <TooltipStrong tooltip="This is a auto show tooltip">consectetur</TooltipStrong> adipiscing elit.</p>
<p>
Click this next word to show and hide on click:
{' '}
<TooltipStrongDirect tooltip="This is a auto show tooltip" tooltipShowOnClick>
oh hai
</TooltipStrongDirect>
{' '}. This is useful for mobile!
</p>
<TooltipFontIcon value="code" tooltip="This is a test with FontIcon" />
</section>
);
export default TooltipTest;

22
tsconfig.json Normal file
View File

@ -0,0 +1,22 @@
{
"compilerOptions": {
"target": "es5",
"moduleResolution": "node",
"jsx": "react",
"noEmit": true,
"noImplicitAny": true,
"noUnusedLocals": true,
"baseUrl": ".",
"paths": {
"components/*": [
"./components/*"
]
}
},
"exclude": [
"./index.d.ts",
"node_modules",
"docs/node_modules",
"lib"
]
}

View File

@ -2,6 +2,14 @@
# yarn lockfile v1
"@types/node@^7.0.4":
version "7.0.4"
resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.4.tgz#9aabc135979ded383325749f508894c662948c8b"
"@types/react@^15.0.0":
version "15.0.0"
resolved "https://registry.yarnpkg.com/@types/react/-/react-15.0.0.tgz#33eb3438130614f25c07c09e46ebec5a8d45b3b0"
JSONStream@^0.8.4:
version "0.8.4"
resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-0.8.4.tgz#91657dfe6ff857483066132b4618b62e8f4887bd"
@ -6999,6 +7007,10 @@ typedarray@^0.0.6:
version "0.0.6"
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
typescript@^2.1.5:
version "2.1.5"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.1.5.tgz#6fe9479e00e01855247cea216e7561bafcdbcd4a"
ua-parser-js@^0.7.9:
version "0.7.12"
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.12.tgz#04c81a99bdd5dc52263ea29d24c6bf8d4818a4bb"