# Conflicts:
#	components/autocomplete/readme.md
#	components/dropdown/readme.md
old
Keren Chandran 2016-04-06 20:50:12 -04:00
commit cdd6ee5f05
44 changed files with 595 additions and 207 deletions

44
CHANGELOG.md Normal file
View File

@ -0,0 +1,44 @@
# Change Log
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
## [Unreleased]
### Changed
- Tabs now only render the contents of the currently active tab.
## [0.15.0] - 2016-03-24
Click on the link above for this release's commit history.
## [0.14.2] - 2016-03-07
Click on the link above for this release's commit history.
## [0.14.1] - 2016-01-26
Click on the link above for this release's commit history.
## [0.14.0] - 2015-12-20
### Added
- A `Ripple` HOC that can be used with your custom components.
### Changed
- Added `className` for the pickers to customize them.
- Animated auto-transition in `DatePicker` component.
- All `Input` components have now an error prop.
- `Dropdown` improvements and normalization with `Input` component.
- More `react-toolbox` attributes to easy customize picker components.
- `btn-colors` mixin extracted to easily define custom `Buttons`.
- New `neutral` boolean property to avoid taking default styles in `Button`.
- Remove hidden scroll from webkit browsers by `commons.scss`.
- Better `Navigation` styles.
- `Overlay` opacity can now be styled from CSS.
**For previous changes, please see the commit messages in
https://github.com/react-toolbox/react-toolbox/releases.**
[Unreleased]: https://github.com/react-toolbox/react-toolbox/compare/0.15.0...dev
[0.15.0]: https://github.com/react-toolbox/react-toolbox/compare/0.14.2...0.15.0
[0.14.2]: https://github.com/react-toolbox/react-toolbox/compare/0.14.1...0.14.2
[0.14.1]: https://github.com/react-toolbox/react-toolbox/compare/0.14.0...0.14.1
[0.14.0]: https://github.com/react-toolbox/react-toolbox/compare/0.13.4...0.14.0

View File

@ -1,6 +1,6 @@
$appbar-color: $color-primary-dark !default;
$appbar-contrast: $color-primary-contrast !default;
$appbar-title-total-distance: 8 * $unit;
$appbar-title-total-distance: 8 * $unit !default;
$appbar-height: 6.4 * $unit !default;
$appbar-h-padding: 2.4 * $unit;
$appbar-title-distance: $appbar-title-total-distance - $appbar-h-padding;
$appbar-h-padding: 2.4 * $unit !default;
$appbar-title-distance: $appbar-title-total-distance - $appbar-h-padding !default;

View File

@ -3,6 +3,7 @@ import ReactDOM from 'react-dom';
import ClassNames from 'classnames';
import Input from '../input';
import events from '../utils/events';
import Chip from '../chip';
import style from './style';
const POSITION = {
@ -11,10 +12,16 @@ const POSITION = {
UP: 'up'
};
const SELECTEDPOSITION = {
ABOVE: 'above',
BELOW: 'below'
};
class Autocomplete extends React.Component {
static propTypes = {
className: React.PropTypes.string,
direction: React.PropTypes.oneOf(['auto', 'up', 'down']),
selectedPosition: React.PropTypes.oneOf(['above', 'below']),
disabled: React.PropTypes.bool,
error: React.PropTypes.string,
label: React.PropTypes.string,
@ -27,6 +34,7 @@ class Autocomplete extends React.Component {
static defaultProps = {
className: '',
direction: 'auto',
selectedPosition: 'above',
multiple: true,
source: {}
};
@ -153,7 +161,16 @@ class Autocomplete extends React.Component {
renderSelected () {
if (this.props.multiple) {
const selectedItems = [...this.values()].map(([key, value]) => {
return <li key={key} className={style.value} onClick={this.unselect.bind(this, key)}>{value}</li>;
return (
<Chip
key={key}
className={style.value}
deletable
onDeleteClick={this.unselect.bind(this, key)}
>
{value}
</Chip>
);
});
return <ul className={style.values}>{selectedItems}</ul>;
@ -187,7 +204,7 @@ class Autocomplete extends React.Component {
return (
<div data-react-toolbox='autocomplete' className={className}>
{this.renderSelected()}
{this.props.selectedPosition === 'above' ? this.renderSelected() : null}
<Input
{...other}
ref='input'
@ -201,6 +218,7 @@ class Autocomplete extends React.Component {
value={this.state.query}
/>
{this.renderSuggestions()}
{this.props.selectedPosition === 'below' ? this.renderSelected() : null}
</div>
);
}

View File

@ -1,9 +1,7 @@
$autocomplete-color-primary-contrast: $color-primary-contrast !default;
$autocomplete-color-primary: $color-primary !default;
$autocomplete-overflow-max-height: 45vh;
$autocomplete-overflow-max-height: 45vh !default;
$autocomplete-suggestion-active-background: $palette-grey-200 !default;
$autocomplete-suggestion-padding: $unit;
$autocomplete-suggestion-padding: $unit !default;
$autocomplete-suggestions-background: $color-white !default;
$autocomplete-value-border-radius: .2 * $unit;
$autocomplete-value-margin: $unit * .25 $unit * .5 $unit * .25 0;
$autocomplete-value-padding: $unit * .5 $unit * .75;
$autocomplete-value-margin: $unit * .25 $unit * .5 $unit * .25 0 !default;

View File

@ -26,6 +26,7 @@ class AutocompleteTest extends React.Component {
return (
<Autocomplete
direction="down"
selectedPosition="above"
label="Choose countries"
onChange={this.handleChange}
source={source}
@ -38,16 +39,17 @@ class AutocompleteTest extends React.Component {
## Properties
| Name | Type | Default | Description|
| Name | Type | Default | Description|
|:-----|:-----|:-----|:-----|
| `className` | `String` | `''` | Sets a class to style of the Component.|
| `direction` | `String` | `auto` | Determines the opening direction. It can be `auto`, `top` or `bottom`.|
| `disabled` | `Bool` | `false` | If true, component will be disabled.|
| `error` | `String` | | Sets the error string for the internal input element.|
| `label` | `String` | | The text string to use for the floating label element.|
| `multiple` | `Bool` | `true` | If true, component can hold multiple values.|
| `onChange` | `Function` | | Callback function that is fired when the components's value changes.|
| `source` | `Object` or `Array` | | Object of key/values or array representing all items suggested. |
| `value` | `String` or `Array` | | Value or array of values currently selected component.|
| `className` | `String` | `''` | Sets a class to style of the Component.|
| `direction` | `String` | `auto` | Determines the opening direction. It can be `auto`, `top` or `bottom`.|
| `disabled` | `Bool` | `false` | If true, component will be disabled.|
| `error` | `String` | | Sets the error string for the internal input element.|
| `label` | `String` | | The text string to use for the floating label element.|
| `multiple` | `Bool` | `true` | If true, component can hold multiple values.|
| `onChange` | `Function` | | Callback function that is fired when the components's value changes.|
| `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` or `below`. |
| `value` | `String` or `Array` | | Value or array of values currently selected component.|
Additional properties will be passed to the Input Component so you can use `hint`, `name` ... etc.

View File

@ -30,14 +30,7 @@
}
.value {
display: inline-block;
padding: $autocomplete-value-padding;
margin: $autocomplete-value-margin;
font-size: $font-size-tiny;
color: $autocomplete-color-primary-contrast;
cursor: pointer;
background-color: $autocomplete-color-primary;
border-radius: $autocomplete-value-border-radius;
}
.suggestions {

View File

@ -14,6 +14,8 @@ class IconButton extends React.Component {
icon: React.PropTypes.any,
inverse: React.PropTypes.bool,
neutral: React.PropTypes.bool,
onMouseLeave: React.PropTypes.func,
onMouseUp: React.PropTypes.func,
primary: React.PropTypes.bool,
type: React.PropTypes.string
};
@ -25,8 +27,14 @@ class IconButton extends React.Component {
primary: false
};
handleMouseUp = () => {
handleMouseUp = (event) => {
this.refs.button.blur();
if (this.props.onMouseUp) this.props.onMouseUp(event);
};
handleMouseLeave = (event) => {
this.refs.button.blur();
if (this.props.onMouseLeave) this.props.onMouseLeave(event);
};
render () {

View File

@ -9,13 +9,13 @@ $button-accent-color-hover: rgba($color-accent, 0.20) !default;
$button-accent-color: $color-accent !default;
$button-disabled-text-color: rgba($color-black, 0.26) !default;
$button-disabled-background-color: rgba($color-black, 0.12) !default;
$button-border-radius: 0.2 * $unit;
$button-floating-font-size: $unit * 2.4;
$button-floating-height: $unit * 5.6;
$button-floating-mini-height: $unit * 4;
$button-floating-mini-font-size: $button-floating-mini-height / 2.25;
$button-height: $unit * 3.6;
$button-squared-icon-margin: $unit * .6;
$button-squared-min-width: 9 * $unit;
$button-squared-padding: 0 $unit * 1.2;
$button-toggle-font-size: $unit * 2;
$button-border-radius: 0.2 * $unit !default;
$button-floating-font-size: $unit * 2.4 !default;
$button-floating-height: $unit * 5.6 !default;
$button-floating-mini-height: $unit * 4 !default;
$button-floating-mini-font-size: $button-floating-mini-height / 2.25 !default;
$button-height: $unit * 3.6 !default;
$button-squared-icon-margin: $unit * .6 !default;
$button-squared-min-width: 9 * $unit !default;
$button-squared-padding: 0 $unit * 1.2 !default;
$button-toggle-font-size: $unit * 2 !default;

View File

@ -1,7 +1,7 @@
$card-color-white: $color-white !default;
$card-text-overlay: rgba($color-black, 0.35) !default;
$card-background-color: $card-color-white !default;
$card-padding-sm: .8 * $unit;
$card-padding: 1.6 * $unit;
$card-padding-lg: 2 * $unit;
$card-font-size: $font-size-small;
$card-padding-sm: .8 * $unit !default;
$card-padding: 1.6 * $unit !default;
$card-padding-lg: 2 * $unit !default;
$card-font-size: $font-size-small !default;

45
components/chip/Chip.jsx Normal file
View File

@ -0,0 +1,45 @@
import React, {PropTypes} from 'react';
import ClassNames from 'classnames';
import style from './style';
const Chip = ({children, className, deletable, onDeleteClick, ...other}) => {
let hasAvatar = false;
if (React.Children.count(children)) {
const firstChild = children[0];
hasAvatar = firstChild && firstChild.type && firstChild.type.name === 'Avatar';
}
const classes = ClassNames(style.chip, {
[style.deletable]: !!deletable,
[style.avatar]: !!hasAvatar
}, className);
return (
<div data-react-toolbox='chip' className={classes} {...other}>
{typeof children === 'string' ? <span>{children}</span> : children}
{
deletable ? (
<span className={style.delete} onClick={onDeleteClick}>
<svg viewBox="0 0 40 40" className={style.deleteIcon}>
<path className={style.deleteX} d="M 12,12 L 28,28 M 28,12 L 12,28" />
</svg>
</span>
) : null
}
</div>
);
};
Chip.propTypes = {
children: PropTypes.node,
className: PropTypes.string,
deletable: PropTypes.bool,
onDeleteClick: PropTypes.func
};
Chip.defaultProps = {
className: '',
deletable: false
};
export default Chip;

View File

@ -0,0 +1,17 @@
$chip-height: 3.2 * $unit !default;
$chip-padding: 1.2 * $unit !default;
$chip-margin-right: 0.25 * $unit !default;
$chip-background: $palette-grey-200 !default;
$chip-icon-font-size: 2.0 * $unit !default;
$chip-icon-margin-right: 0.8 * $unit !default;
$chip-color: $color-text-secondary !default;
$chip-font-size: $font-size-small !default;
$chip-remove-size: 2.4 * $unit !default;
$chip-remove-margin: 0.4 * $unit !default;
$chip-remove-stroke-width: 0.4 * $unit !default;
$chip-remove-background: $palette-grey-400 !default;
$chip-remove-background-hover: $palette-grey-500 !default;
$chip-remove-color: $color-white !default;

3
components/chip/index.js Normal file
View File

@ -0,0 +1,3 @@
import Chip from './Chip';
export { Chip };
export default Chip;

46
components/chip/readme.md Normal file
View File

@ -0,0 +1,46 @@
# Chip
Chips represent complex entities in small blocks, such as a contact. Chips can be used for various types of entities, including free form text, predefined text, rules, or contacts. Chips may also contain icons.
To add an icon or contact image to a chip, include an `Avatar` element as the first child.
<!-- example -->
```jsx
import Avatar from 'react-toolbox/lib/avatar';
import Chip from 'react-toolbox/lib/chip';
const ChipTest = () => (
<div>
<Chip>Example chip</Chip>
<Chip>
<span style={{textDecoration: 'line-through'}}>Standard</span>
<strong>Custom</strong> chip <small>(custom markup)</small>
</Chip>
<Chip deletable>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>
);
```
## Properties
| Name | Type | Default | Description|
|:----------------|:------------|:----------------|:-----------|
| `children` | `Node` | | Child components, usually `Avatar` and inline elements. |
| `className` | `String` | `''` | Additional class name to provide custom styling.|
| `deletable` | `Boolean` | `false` | If true, the chip will be rendered with a delete icon.|
| `onDeleteClick` | `Function` | | Callback to be invoked when the delete icon is clicked. |

View File

@ -0,0 +1,61 @@
@import "../base";
@import "../mixins";
@import "./config";
.chip {
background-color: $chip-background;
border-radius: $chip-height;
color: $chip-color;
display: inline-block;
font-size: $chip-font-size;
line-height: $chip-height;
margin-right: $chip-margin-right;
padding: 0 $chip-padding;
}
.avatar {
padding-left: 0;
> [data-react-toolbox="avatar"] {
height: $chip-height;
margin-right: $chip-icon-margin-right;
vertical-align: middle;
width: $chip-height;
> span {
font-size: $chip-icon-font-size;
line-height: $chip-height;
}
}
}
.deletable {
padding-right: $chip-remove-size + 2 * $chip-remove-margin;
}
.delete {
cursor: pointer;
display: inline-block;
height: $chip-remove-size;
margin: $chip-remove-margin;
padding: $chip-remove-margin;
position: absolute;
vertical-align: middle;
width: $chip-remove-size;
}
.delete:hover .deleteIcon {
background: $chip-remove-background-hover;
}
.deleteIcon {
background: $chip-remove-background;
border-radius: $chip-remove-size;
vertical-align: top;
.deleteX {
fill: transparent;
stroke-width: $chip-remove-stroke-width;
stroke: $chip-remove-color;
}
}

View File

@ -5,14 +5,14 @@ $datepicker-primary-color: $datepicker-primary !default;
$datepicker-primary-hover-color: rgba($datepicker-primary, 0.20) !default;
$datepicker-primary-contrast-color: $datepicker-primary-contrast !default;
$datepicker-primary-dark-color: $datepicker-primary-dark !default;
$datepicker-dialog-width: 33 * $unit;
$datepicker-inactive-opacity: .6;
$datepicker-weekday-line-height: 2 * $unit;
$datepicker-weekday-font-size: $font-size-small;
$datepicker-month-font-size: $font-size-big;
$datepicker-day-font-size: 5 * $unit;
$datepicker-day-line-height: 4 * $unit;
$datepicker-year-font-size: $font-size-small;
$datepicker-dialog-width: 33 * $unit !default;
$datepicker-inactive-opacity: .6 !default;
$datepicker-weekday-line-height: 2 * $unit !default;
$datepicker-weekday-font-size: $font-size-small !default;
$datepicker-month-font-size: $font-size-big !default;
$datepicker-day-font-size: 5 * $unit !default;
$datepicker-day-line-height: 4 * $unit !default;
$datepicker-year-font-size: $font-size-small !default;
$calendar-primary: $color-primary !default;
$calendar-primary-contrast: $color-primary-contrast !default;
@ -20,11 +20,11 @@ $calendar-primary-color: $calendar-primary !default;
$calendar-primary-contrast-color: $calendar-primary-contrast !default;
$calendar-primary-hover-color: rgba($calendar-primary, 0.21) !default;
$calendar-arrows-color: $palette-grey-600 !default;
$calendar-arrows-font-size: 2 * $unit;
$calendar-year-font-size: 2.4;
$calendar-day-font-size: 1.3 * $unit;
$calendar-day-disable-opacity: 0.25;
$calendar-row-height: 3 * $unit;
$calendar-day-padding: .2 * $unit;
$calendar-title-height: 3.6 * $unit;
$calendar-total-height: $calendar-row-height * 7 + $calendar-title-height + $calendar-day-padding * 12;
$calendar-arrows-font-size: 2 * $unit !default;
$calendar-year-font-size: 2.4 !default;
$calendar-day-font-size: 1.3 * $unit !default;
$calendar-day-disable-opacity: 0.25 !default;
$calendar-row-height: 3 * $unit !default;
$calendar-day-padding: .2 * $unit !default;
$calendar-title-height: 3.6 * $unit !default;
$calendar-total-height: $calendar-row-height * 7 + $calendar-title-height + $calendar-day-padding * 12 !default;

View File

@ -2,7 +2,7 @@ import React from 'react';
import ClassNames from 'classnames';
import Button from '../button';
import Overlay from '../overlay';
import style from './style.scss';
import style from './style';
const Dialog = (props) => {
const actions = props.actions.map((action, idx) => {
@ -28,9 +28,12 @@ const Dialog = (props) => {
{props.title ? <h6 className={style.title}>{props.title}</h6> : null}
{props.children}
</section>
<nav role='navigation' className={style.navigation}>
{actions}
</nav>
{actions ?
<nav role='navigation' className={style.navigation}>
{actions}
</nav> :
null
}
</div>
</Overlay>
);

View File

@ -1,6 +1,6 @@
$dialog-border-radius: .2 * $unit;
$dialog-border-radius: .2 * $unit !default;
$dialog-color-title: $color-black !default;
$dialog-color-white: $color-white !default;
$dialog-content-padding: 2.4 * $unit;
$dialog-navigation-padding: .8 * $unit;
$dialog-translate-y: 4 * $unit;
$dialog-content-padding: 2.4 * $unit !default;
$dialog-navigation-padding: .8 * $unit !default;
$dialog-translate-y: 4 * $unit !default;

View File

@ -1,4 +1,4 @@
$drawer-background-color: $palette-grey-50 !default;
$drawer-border-color: $palette-grey-300 !default;
$drawer-text-color: $palette-grey-800 !default;
$drawer-width: 24 * $unit;
$drawer-width: 24 * $unit !default;

View File

@ -7,6 +7,7 @@ import style from './style';
class Dropdown extends React.Component {
static propTypes = {
allowBlank: React.PropTypes.bool,
auto: React.PropTypes.bool,
className: React.PropTypes.string,
disabled: React.PropTypes.bool,
@ -26,6 +27,7 @@ class Dropdown extends React.Component {
static defaultProps = {
auto: true,
className: '',
allowBlank: true,
disabled: false
};
@ -52,11 +54,6 @@ class Dropdown extends React.Component {
}
}
valueIsPresent () {
const value = this.props.value;
return value !== null && value !== undefined && value !== '' && !Number.isNaN(value);
}
close = () => {
if (this.state.active) {
this.setState({active: false});
@ -87,10 +84,11 @@ class Dropdown extends React.Component {
};
getSelectedItem = () => {
if (this.valueIsPresent()) {
for (const item of this.props.source) {
if (item.value === this.props.value) return item;
}
for (const item of this.props.source) {
if (item.value === this.props.value) return item;
}
if (!this.props.allowBlank) {
return this.props.source[0];
}
};

View File

@ -2,5 +2,5 @@ $dropdown-color-white: $color-white !default;
$dropdown-color-primary: $color-primary !default;
$dropdown-color-primary-contrast: $color-primary-contrast !default;
$dropdown-value-hover-background: $palette-grey-200 !default;
$dropdown-overflow-max-height: 45vh;
$dropdown-value-border-radius: .2 * $unit;
$dropdown-overflow-max-height: 45vh !default;
$dropdown-value-border-radius: .2 * $unit !default;

View File

@ -39,7 +39,8 @@ class DropdownTest extends React.Component {
| Name | Type | Default | Description |
|:-----|:-----|:-----|:-----|
| `auto` | `Boolean` | `true` | If true, the dropdown will open up or down depending on the position in the screen .|
| `allowBlank` | `Boolean` | `true` | If true the dropdown will preselect the first item if the supplied value matches none of the options' values.|
| `auto` | `Boolean` | `true` | If true, the dropdown will open up or down depending on the position in the screen.|
| `className` | `String` | `''` | Set the class to give custom styles to the dropdown.|
| `disabled` | `Boolean` | `false` | Set the component as disabled.|
| `error` | `String` | | Give an error string to display under the field.|

View File

@ -1,9 +1,9 @@
$input-padding: 2 * $unit;
$input-field-padding: .8 * $unit;
$input-field-font-size: 1.6 * $unit;
$input-field-height: $input-field-padding * 2 + $input-field-font-size * 1.4;
$input-label-font-size: 1.2 * $unit;
$input-focus-label-top: .6 * $unit;
$input-padding: 2 * $unit !default;
$input-field-padding: .8 * $unit !default;
$input-field-font-size: 1.6 * $unit !default;
$input-field-height: $input-field-padding * 2 + $input-field-font-size * 1.4 !default;
$input-label-font-size: 1.2 * $unit !default;
$input-focus-label-top: .6 * $unit !default;
$input-text-background-color: transparent !default;
$input-text-label-color: rgba($color-black, 0.26) !default;
$input-text-bottom-border-color: rgba($color-black, 0.12) !default;
@ -12,9 +12,9 @@ $input-text-disabled-color: $input-text-bottom-border-color !default;
$input-text-disabled-text-color: $input-text-label-color !default;
$input-text-error-color: rgb(222, 230, 38) !default;
$input-text-required-color: rgb(222, 50, 38) !default;
$input-underline-height: 2 * $unit;
$input-icon-font-size: 2.4 * $unit;
$input-icon-size: 2 * $input-icon-font-size;
$input-icon-offset: 1.6 * $unit;
$input-chevron-offset: .8 * $unit;
$input-underline-height: 2 * $unit !default;
$input-icon-font-size: 2.4 * $unit !default;
$input-icon-size: 2 * $input-icon-font-size !default;
$input-icon-offset: 1.6 * $unit !default;
$input-chevron-offset: .8 * $unit !default;
$input-hint-opacity: 1 !default;

View File

@ -33,7 +33,7 @@ class InputTest extends React.Component {
|:-----|:-----|:-----|:-----|
| `className` | `String` | `''` | Sets a class name to give custom styles.|
| `disabled` | `Boolean` | `false` | If true, component will be disabled.|
| `error` | `Node` | | Give an error node to display under the field.|
| `error` | `String` | | Give an error node to display under the field.|
| `floating` | `Boolean` | `true` | Indicates if the label is floating in the input field or not.|
| `hint` | `String` | `''` | The text string to use for hint text element.|
| `icon` | `Any` | | Name of an icon to use as a label for the input.|

View File

@ -1,18 +1,18 @@
$list-vertical-padding: .8 * $unit;
$list-horizontal-padding: 1.6 * $unit;
$list-content-left-spacing: 7.2 * $unit;
$list-subheader-height: 4.8 * $unit;
$list-subheader-font-size: 1.4 * $unit;
$list-subheader-font-weight: 500;
$list-divider-height: .1 * $unit;
$list-item-min-height: 4.8 * $unit;
$list-item-min-height-legend: 7.2 * $unit;
$list-vertical-padding: .8 * $unit !default;
$list-horizontal-padding: 1.6 * $unit !default;
$list-content-left-spacing: 7.2 * $unit !default;
$list-subheader-height: 4.8 * $unit !default;
$list-subheader-font-size: 1.4 * $unit !default;
$list-subheader-font-weight: 500 !default;
$list-divider-height: .1 * $unit !default;
$list-item-min-height: 4.8 * $unit !default;
$list-item-min-height-legend: 7.2 * $unit !default;
$list-item-hover-color: $palette-grey-200 !default;
$list-item-legend-margin-top: .3 * $unit;
$list-item-icon-font-size: 2.4 * $unit;
$list-item-icon-size: 1.8 * $unit;
$list-item-right-icon-margin: $list-content-left-spacing - 2 * $list-horizontal-padding - $list-item-icon-size;
$list-item-right-checkbox-margin: $list-item-right-icon-margin + $list-horizontal-padding;
$list-item-avatar-height: 4 * $unit;
$list-item-avatar-margin: .8 * $unit;
$list-item-child-margin: .8 * $unit;
$list-item-legend-margin-top: .3 * $unit !default;
$list-item-icon-font-size: 2.4 * $unit !default;
$list-item-icon-size: 1.8 * $unit !default;
$list-item-right-icon-margin: $list-content-left-spacing - 2 * $list-horizontal-padding - $list-item-icon-size !default;
$list-item-right-checkbox-margin: $list-item-right-icon-margin + $list-horizontal-padding !default;
$list-item-avatar-height: 4 * $unit !default;
$list-item-avatar-margin: .8 * $unit !default;
$list-item-child-margin: .8 * $unit !default;

View File

@ -2,15 +2,15 @@ $menu-expand-duration: .3s !default;
$menu-fade-duration: .2s !default;
$menu-ripple-delay: .3s !default;
$menu-background-color: $color-white !default;
$menu-padding: .8 * $unit 0;
$menu-outline-border-radius: .2 * $unit;
$menu-padding: .8 * $unit 0 !default;
$menu-outline-border-radius: .2 * $unit !default;
$menu-item-hover-background: $palette-grey-200 !default;
$menu-item-selected-background: transparent !default;
$menu-item-icon-font-size: 2.4 * $unit;
$menu-item-icon-size: 1.6 * $menu-item-icon-font-size;
$menu-item-height: 4.8 * $unit;
$menu-item-padding: 1.6 * $unit;
$menu-item-font-size: 1.6 * $unit;
$menu-divider-height: (4.8 * $unit) / 4;
$menu-icon-size: 2.3 * $unit;
$menu-icon-ripple-duration: 650ms;
$menu-item-icon-font-size: 2.4 * $unit !default;
$menu-item-icon-size: 1.6 * $menu-item-icon-font-size !default;
$menu-item-height: 4.8 * $unit !default;
$menu-item-padding: 1.6 * $unit !default;
$menu-item-font-size: 1.6 * $unit !default;
$menu-divider-height: (4.8 * $unit) / 4 !default;
$menu-icon-size: 2.3 * $unit !default;
$menu-icon-ripple-duration: 650ms !default;

View File

@ -1,6 +1,6 @@
$progress-height: .4 * $unit;
$progress-height: .4 * $unit !default;
$progress-main-color: $color-primary !default;
$progress-secondary-color: rgba($color-primary-contrast, 0.7) !default;
$circle-wrapper-width: 60;
$circle-radius: 25;
$scale-ratio: $circle-radius / 20;
$circle-wrapper-width: 60 !default;
$circle-radius: 25 !default;
$scale-ratio: $circle-radius / 20 !default;

View File

@ -1,9 +1,9 @@
$radio-field-margin-bottom: 1.5 * $unit;
$radio-field-margin-bottom: 1.5 * $unit !default;
$radio-button-size: 1.6 * $unit !default;
$radio-inner-margin: $radio-button-size / 4;
$radio-inner-margin: $radio-button-size / 4 !default;
$radio-inner-color: $color-primary !default;
$radio-focus-color: rgba($color-black, 0.1) !default;
$radio-checked-focus-color: rgba($color-primary, 0.26) !default;
$radio-text-color: $color-black !default;
$radio-disabled-color: rgba($color-black, 0.26) !default;
$radio-text-font-size: 1.4 * $unit;
$radio-text-font-size: 1.4 * $unit !default;

View File

@ -1,12 +1,12 @@
$slider-main-color: $color-primary !default;
$slider-main-color-contrast: $color-primary-contrast !default;
$slider-snap-color: $color-black !default;
$slider-knob-size: 3.2 * $unit;
$slider-inner-knob-size: 1.2 * $unit;
$slider-snap-size: .2 * $unit;
$slider-input-width: 5 * $unit;
$slider-bar-height: .2 * $unit;
$slider-pin-size: 2.6 * $unit;
$slider-pin-elevation: 1.7 * $unit;
$slider-side-separation: 1 * $unit;
$slider-empty-knob-border: .2 * $unit;
$slider-knob-size: 3.2 * $unit !default;
$slider-inner-knob-size: 1.2 * $unit !default;
$slider-snap-size: .2 * $unit !default;
$slider-input-width: 5 * $unit !default;
$slider-bar-height: .2 * $unit !default;
$slider-pin-size: 2.6 * $unit !default;
$slider-pin-elevation: 1.7 * $unit !default;
$slider-side-separation: 1 * $unit !default;
$slider-empty-knob-border: .2 * $unit !default;

View File

@ -18,11 +18,24 @@ class Snackbar extends React.Component {
type: React.PropTypes.string
};
componentDidUpdate () {
if (this.props.active && this.props.timeout) {
setTimeout(() => {
this.props.onTimeout();
}, this.props.timeout);
state = {
curTimeout: null
};
componentWillReceiveProps (nextProps) {
if (nextProps.active && nextProps.timeout) {
if (this.state.curTimeout) clearTimeout(this.state.curTimeout);
const curTimeout = setTimeout(() => {
nextProps.onTimeout();
this.setState({
curTimeout: null
});
}, nextProps.timeout);
this.setState({
curTimeout
});
}
}

View File

@ -16,7 +16,7 @@ $switch-thumb-size: 2 * $unit !default;
$switch-thumb-on-color: $switch-color !default;
$switch-focus-init-size: .8 * $unit !default;
$switch-focus-size: $switch-total-height * 2 !default;
$switch-focus-diff: ($switch-focus-size - $switch-focus-init-size) / 2;
$switch-focus-diff: ($switch-focus-size - $switch-focus-init-size) / 2 !default;
$switch-ripple-duration: 650ms !default;
$switch-font-size: $font-size-small !default;
$switch-field-margin-bottom: 1.5 * $unit !default;

View File

@ -1,5 +1,5 @@
$table-row-height: 48px;
$table-row-height: 48px !default;
$table-row-divider: solid 1px rgba(0,0,0,.12) !default;
$table-row-offset: 1.8 * $unit;
$table-row-offset: 1.8 * $unit !default;
$table-row-highlight: #eee !default;
$table-text-color: #757575 !default;

View File

@ -82,12 +82,14 @@ class Tabs extends React.Component {
}
renderContents (contents) {
return contents.map((item, idx) => {
return React.cloneElement(item, {
key: idx,
active: this.props.index === idx,
tabIndex: idx
});
const activeIdx = contents.findIndex((item, idx) => {
return this.props.index === idx;
});
return React.cloneElement(contents[activeIdx], {
key: activeIdx,
active: true,
tabIndex: activeIdx
});
}

View File

@ -0,0 +1,51 @@
import expect from 'expect';
import utils from '../../utils/testing';
import ReactTestUtils from 'react-addons-test-utils';
import React, { Component } from 'react';
import Tabs from '../Tabs';
import Tab from '../Tab';
import TabContent from '../TabContent';
describe('Tabs', function () {
let tabContents, composition;
it('only renders the current tab', function () {
class Composition extends Component {
constructor () {
super();
this.state = { index: 0 };
}
render () {
return (
<Tabs index={this.state.index}>
<Tab label="tab1">tab1</Tab>
<Tab label="tab2">tab2</Tab>
</Tabs>
);
}
}
// initial render
composition = utils.renderComponent(Composition);
tabContents = ReactTestUtils
.scryRenderedComponentsWithType(composition, TabContent);
expect(tabContents.length).toEqual(1);
expect(tabContents[0].props.tabIndex).toEqual(0);
// after tab change
composition.setState({ index: 1 });
composition.forceUpdate();
tabContents = ReactTestUtils
.scryRenderedComponentsWithType(composition, TabContent);
expect(tabContents.length).toEqual(1);
expect(tabContents[0].props.tabIndex).toEqual(1);
});
});

View File

@ -1,11 +1,11 @@
$tab-label-disabled-opacity: .2;
$tab-label-h-padding: 1.2 * $unit;
$tab-label-height: 4.8 * $unit;
$tab-text-height: 1.4 * $unit;
$tab-label-v-padding: ($tab-label-height - $tab-text-height) / 2;
$tab-label-disabled-opacity: .2 !default;
$tab-label-h-padding: 1.2 * $unit !default;
$tab-label-height: 4.8 * $unit !default;
$tab-text-height: 1.4 * $unit !default;
$tab-label-v-padding: ($tab-label-height - $tab-text-height) / 2 !default;
$tab-navigation-border-color: $color-divider !default;
$tab-pointer-color: $color-primary !default;
$tab-pointer-height: .2 * $unit;
$tab-pointer-height: .2 * $unit !default;
$tab-text: $color-black !default;
$tab-text-color: $tab-text !default;
$tab-text-inactive-color: rgba($tab-text, 0.70) !default;

View File

@ -1,6 +1,6 @@
# Tabs
[Tabs](https://www.google.com/design/spec/components/tabs.html) make it easy to explore and switch between different views or functional aspects of an app or to browse categorized data sets. For now we are using tabs along with content so it's not possible to render just the tab headers with event listeners. In the future we will add this feature but for now you can compose your tabs with content:
[Tabs](https://www.google.com/design/spec/components/tabs.html) make it easy to explore and switch between different views or functional aspects of an app or to browse categorized data sets. Tabs are composed with their content, but only the active tab's content is rendered. In the future, we may add the ability to render headers only, with event listeners.
<!-- example -->
```jsx

View File

@ -1,6 +1,6 @@
$timepicker-header-font-size: 5.2 * $unit;
$timepicker-header-padding: $unit;
$timepicker-ampm-font-size: 1.6 * $unit;
$timepicker-header-font-size: 5.2 * $unit !default;
$timepicker-header-padding: $unit !default;
$timepicker-ampm-font-size: 1.6 * $unit !default;
$timepicker-primary: $color-primary !default;
$timepicker-primary-contrast: $color-primary-contrast !default;
$timepicker-primary-dark: $color-primary-dark !default;
@ -8,11 +8,11 @@ $timepicker-primary-color: $timepicker-primary !default;
$timepicker-primary-hover-color: rgba($timepicker-primary, 0.20) !default;
$timepicker-primary-contrast-color: $timepicker-primary-contrast !default;
$timepicker-primary-dark-color: $timepicker-primary-dark !default;
$timepicker-ampm-height: 2.2 * $unit;
$timepicker-ampm-width: 4 * $unit;
$timepicker-dialog-width: 30 * $unit;
$timepicker-ampm-height: 2.2 * $unit !default;
$timepicker-ampm-width: 4 * $unit !default;
$timepicker-dialog-width: 30 * $unit !default;
$clock-padding: 1.5 * $unit 2 * $unit;
$clock-padding: 1.5 * $unit 2 * $unit !default;
$clock-primary: $color-primary !default;
$clock-primary-contrast: $color-primary-contrast !default;
$clock-primary-dark: $color-primary-dark !default;
@ -20,8 +20,8 @@ $clock-primary-color: $clock-primary !default;
$clock-primary-hover-color: rgba($clock-primary, 0.20) !default;
$clock-primary-contrast-color: $clock-primary-contrast !default;
$clock-primary-dark-color: $clock-primary-dark !default;
$clock-number-size: 2 * $unit;
$clock-hand-width: .4 * $unit;
$clock-hand-dot-size: 1 * $unit;
$clock-knob-size: 3.4 * $unit;
$clock-knob-small-size: 1.2 * $unit;
$clock-number-size: 2 * $unit !default;
$clock-hand-width: .4 * $unit !default;
$clock-hand-dot-size: 1 * $unit !default;
$clock-knob-size: 3.4 * $unit !default;
$clock-knob-small-size: 1.2 * $unit !default;

View File

@ -1,5 +1,7 @@
@import "../../globals";
$media-min-width: 1440px;
$playground-max-width: $media-min-width / 2;
$playground-width: 50%;
$navigation-width: 22 * $unit;
$navigation-h-padding: 2.4 * $unit;

View File

@ -80,3 +80,20 @@ hr {
.load-button {
display: inline-block;
}
@media(min-width: $media-min-width) {
.root {
.playground {
width: $playground-max-width;
}
&.with-playground {
> .documentation {
padding-right: $playground-max-width;
padding-left: $navigation-width;
}
> .navigation {
transform: translateX(0);
}
}
}
}

View File

@ -9,7 +9,7 @@
"deploy": "gh-pages -d build"
},
"dependencies": {
"babel-standalone": "^1.0.0",
"babel-standalone": "^6.7.4",
"classnames": "^2.2.1",
"codemirror": "^5.10.0",
"history": "^1.17.0",

View File

@ -1,56 +1,43 @@
{
"name": "react-toolbox",
"version": "0.14.1",
"homepage": "http://www.react-toolbox.com",
"description": "A set of React components implementing Google's Material Design specification with the power of CSS Modules.",
"author": "React Toolbox Team (http://github.com/react-toolbox)",
"homepage": "http://www.react-toolbox.com",
"version": "0.15.0",
"main": "./lib",
"author": {
"name": "React Toolbox Team",
"url": "http://github.com/react-toolbox"
},
"contributors": [
{
"name": "Javi Jimenez Villar",
"url": "http://soyjavi.com/",
"email": "javi.jimenez.villar@gmail.com"
"email": "javi.jimenez.villar@gmail.com",
"url": "http://soyjavi.com/"
},
{
"name": "Javi Velasco Arjona",
"url": "http://javivelasco.com/",
"email": "javier.velasco86@gmail.com"
"email": "javier.velasco86@gmail.com",
"url": "http://javivelasco.com/"
}
],
"main": "./lib",
"scripts": {
"start": "cross-env NODE_ENV=development UV_THREADPOOL_SIZE=100 node ./server",
"lint": "eslint ./ --ext .js,.jsx",
"babel": "babel ./components --out-dir ./lib",
"sass": "cpx './components/**/*.scss' ./lib",
"build": "cross-env NODE_ENV=production npm run babel && npm run sass",
"clean": "rimraf ./lib",
"prebuild": "npm run clean",
"prepublish": "npm run build",
"test": "cross-env NODE_ENV=test karma start",
"test:watch": "cross-env NODE_ENV=test karma start --no-single-run",
"release": "bumped release",
"patch": "bumped release patch"
"repository": {
"type": "git",
"url": "git+https://github.com/react-toolbox/react-toolbox.git"
},
"bugs": {
"url": "https://github.com/react-toolbox/react-toolbox/issues",
"email": "issues@react-toolbox.com"
},
"keywords": [
"components",
"material design",
"react",
"react-component",
"material design",
"toolkit",
"components"
"toolkit"
],
"license": "MIT",
"peerDependencies": {
"classnames": "^2.2.0",
"react": "^0.14",
"react-dom": "^0.14.0",
"react-addons-css-transition-group": "^0.14.0",
"normalize.css": "^3.0.3"
"dependencies": {
"classnames": "^2.2.1"
},
"typings": "./react-toolbox.d.ts",
"devDependencies": {
"autoprefixer": "^6.2.1",
"babel-cli": "^6.3.17",
@ -103,8 +90,27 @@
"webpack-dev-middleware": "^1.4.0",
"webpack-hot-middleware": "^2.6.0"
},
"repository": "github:react-toolbox/react-toolbox",
"dependencies": {
"classnames": "^2.2.1"
}
"scripts": {
"babel": "babel ./components --out-dir ./lib",
"build": "cross-env NODE_ENV=production npm run babel && npm run sass",
"clean": "rimraf ./lib",
"lint": "eslint ./ --ext .js,.jsx",
"patch": "bumped release patch",
"prebuild": "npm run clean",
"prepublish": "npm run build",
"release": "bumped release",
"sass": "cpx './components/**/*.scss' ./lib",
"start": "cross-env NODE_ENV=development UV_THREADPOOL_SIZE=100 node ./server",
"test": "cross-env NODE_ENV=test karma start",
"test:watch": "cross-env NODE_ENV=test karma start --no-single-run"
},
"license": "MIT",
"peerDependencies": {
"classnames": "^2.2.0",
"normalize.css": "^3.0.3",
"react": "^0.14",
"react-addons-css-transition-group": "^0.14.0",
"react-dom": "^0.14.0"
},
"typings": "./react-toolbox.d.ts"
}

4
react-toolbox.d.ts vendored
View File

@ -168,7 +168,7 @@ declare namespace __RT {
*/
multiple?: boolean,
/**
* Object of key/values or array representing all items suggested.
* Object of key/values or array representing all items suggested.
*/
source: Object | Array<any>,
/**
@ -177,7 +177,7 @@ declare namespace __RT {
*/
type?: string,
/**
* Value or array of values currently selected component.Current value of the input element.
* Value or array of values currently selected component.Current value of the input element.
*/
value?: string | Array<any>,
}

View File

@ -33,9 +33,9 @@ class AutocompleteTest extends React.Component {
<Autocomplete
label="Choose a country"
hint="Elements up to you..."
multiple={false}
onChange={this.handleSimpleChange}
placeholder="Elements up to you..."
source={countriesArray}
value={this.state.simple}
/>

58
spec/components/chip.jsx Normal file
View File

@ -0,0 +1,58 @@
import React from 'react';
import Avatar from '../../components/avatar';
import Chip from '../../components/chip';
class ChipTest extends React.Component {
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>
</section>
);
}
}
export default ChipTest;

View File

@ -8,6 +8,7 @@ import Autocomplete from './components/autocomplete';
import Button from './components/button';
import Card from './components/card';
import Checkbox from './components/checkbox';
import Chip from './components/chip';
import Dialog from './components/dialog';
import Drawer from './components/drawer';
import Dropdown from './components/dropdown';
@ -48,6 +49,7 @@ const Root = () => (
<Button />
<Card />
<Checkbox />
<Chip />
<Dialog />
<Drawer />
<Dropdown />