Merge pull request #847 from MaximKomlev/FileBrowseButton

File browse button
old
Javi Velasco 2016-10-12 16:55:09 +02:00 committed by GitHub
commit c20351f572
5 changed files with 257 additions and 2 deletions

View File

@ -0,0 +1,110 @@
import React, { Component, PropTypes } from 'react';
import classnames from 'classnames';
import { themr } from 'react-css-themr';
import { BUTTON } from '../identifiers.js';
import InjectFontIcon from '../font_icon/FontIcon.js';
import rippleFactory from '../ripple/Ripple.js';
const factory = (ripple, FontIcon) => {
class SimpleBrowseButton extends Component {
static propTypes = {
accent: PropTypes.bool,
children: PropTypes.node,
className: PropTypes.string,
disabled: PropTypes.bool,
flat: PropTypes.bool,
floating: PropTypes.bool,
icon: PropTypes.oneOfType([
PropTypes.string,
PropTypes.element
]),
inverse: PropTypes.bool,
label: PropTypes.string,
mini: PropTypes.bool,
neutral: PropTypes.bool,
onChange: PropTypes.func,
onMouseLeave: PropTypes.func,
onMouseUp: PropTypes.func,
primary: PropTypes.bool,
raised: PropTypes.bool,
theme: PropTypes.shape({
accent: PropTypes.string,
button: PropTypes.string,
flat: PropTypes.string,
floating: PropTypes.string,
icon: PropTypes.string,
inverse: PropTypes.string,
mini: PropTypes.string,
neutral: PropTypes.string,
primary: PropTypes.string,
raised: PropTypes.string,
rippleWrapper: PropTypes.string,
toggle: PropTypes.string
}),
type: PropTypes.string
};
static defaultProps = {
accent: false,
className: '',
flat: false,
floating: false,
mini: false,
neutral: true,
primary: false,
raised: false
};
handleMouseUp = (event) => {
this.refs.label.blur();
if (this.props.onMouseUp) this.props.onMouseUp(event);
};
handleMouseLeave = (event) => {
this.refs.label.blur();
if (this.props.onMouseLeave) this.props.onMouseLeave(event);
};
handleFileChange = (event) => {
if (this.props.onChange) this.props.onChange(event);
};
render () {
const { accent, children, className, flat, floating, icon,
inverse, label, mini, neutral, primary, theme, raised, ...others} = this.props;
const element = 'label';
const level = primary ? 'primary' : accent ? 'accent' : 'neutral';
const shape = flat ? 'flat' : raised ? 'raised' : floating ? 'floating' : 'flat';
const classes = classnames(theme.button, [theme[shape]], {
[theme[level]]: neutral,
[theme.mini]: mini,
[theme.inverse]: inverse
}, className);
const props = {
...others,
ref: 'label',
className: classes,
disabled: this.props.disabled,
onMouseUp: this.handleMouseUp,
onMouseLeave: this.handleMouseLeave,
'data-react-toolbox': 'label'
};
return React.createElement(element, props,
icon ? <FontIcon className={theme.icon} value={icon}/> : null,
<span>{label}</span>,
<input className={classes} type="file" onChange={this.handleFileChange}/>,
children
);
}
}
return ripple(SimpleBrowseButton);
};
const BrowseButton = factory(rippleFactory({ centered: false }), InjectFontIcon);
export default themr(BUTTON)(BrowseButton);
export { factory as browseButtonFactory };
export { BrowseButton };

View File

@ -210,3 +210,128 @@ interface IconButtonProps extends ReactToolbox.Props {
}
export class IconButton extends React.Component<IconButtonProps, {}> { }
export interface BrowseButtonTheme {
/**
* Used for the root in case button is accent.
*/
accent?: string;
/**
* Used for the root element in any button.
*/
button?: string;
/**
* Used when the button is flat for the root element.
*/
flat?: string;
/**
* Used when the button is floating for the root element.
*/
floating?: string;
/**
* For the icon inside a button.
*/
icon?: string;
/**
* Used when colors are inverted.
*/
inverse?: string;
/**
* Used for mini floating buttons.
*/
mini?: string;
/**
* Used for neutral colored buttons.
*/
neutral?: string;
/**
* Used for primary buttons when button is primary.
*/
primary?: string;
/**
* Used when the button is raised for root element.
*/
raised?: string;
/**
* Used for the ripple element.
*/
rippleWrapper?: string;
/**
* Used for toggle buttons in the root element.
*/
toggle?: string;
}
interface BrowseButtonProps extends ReactToolbox.Props {
/**
* Indicates if the button should have accent color.
* @default false
*/
accent?: boolean;
/**
* Children to pass through the component.
*/
children?: React.ReactNode;
/**
* If true, component will be disabled.
* @default false
*/
disabled?: boolean;
/**
* If true, the button will have a flat look.
* @default false
*/
flat?: boolean;
/**
* If true, the button will have a floating look.
* @default false
*/
floating?: boolean;
/**
* Creates a link for the button.
*/
href?: string;
/**
* Value of the icon (See Font Icon Component).
*/
icon?: React.ReactNode | string;
/**
* If true, the neutral colors are inverted. Useful to put a button over a dark background.
*/
inverse?: boolean;
/**
* The text string to use for the name of the button.
*/
label?: string;
/**
* To be used with floating button. If true, the button will be smaller.
* @default false
*/
mini?: boolean;
/**
* Set it to false if you don't want the neutral styles to be included.
* @default true
*/
neutral?: boolean;
/**
* Indicates if the button should have primary color.
* @default false
*/
primary?: boolean;
/**
* If true, the button will have a raised look.
* @default false
*/
raised?: boolean;
/**
* If true, component will have a ripple effect on click.
* @default true
*/
ripple?: boolean;
/**
* Classnames object defining the component style.
*/
theme?: BrowseButtonTheme;
}
export class BrowseButton extends React.Component<BrowseButtonProps, {}> { }

View File

@ -1,6 +1,7 @@
import { BUTTON } from '../identifiers.js';
import { themr } from 'react-css-themr';
import { buttonFactory } from './Button.js';
import { browseButtonFactory } from './BrowseButton.js';
import { iconButtonFactory } from './IconButton.js';
import FontIcon from '../font_icon/FontIcon.js';
import themedRippleFactory from '../ripple';
@ -8,9 +9,12 @@ import theme from './theme.scss';
const Button = buttonFactory(themedRippleFactory({ centered: false }), FontIcon);
const IconButton = iconButtonFactory(themedRippleFactory({centered: true}), FontIcon);
const BrowseButton = browseButtonFactory(themedRippleFactory({ centered: false }), FontIcon);
const ThemedButton = themr(BUTTON, theme)(Button);
const ThemedIconButton = themr(BUTTON, theme)(IconButton);
const ThemedBrowseButton = themr(BUTTON, theme)(BrowseButton);
export default ThemedButton;
export { ThemedButton as Button };
export { ThemedIconButton as IconButton };
export { ThemedBrowseButton as BrowseButton };

View File

@ -6,6 +6,17 @@
.button {
position: relative;
> input {
width: 0.1px !important;
height: 0.1px !important;
opacity: 0;
overflow: hidden;
position: absolute;
z-index: 0 !important;
padding: 0 !important;
margin: 0 !important;
}
}
%button {

View File

@ -1,6 +1,6 @@
import React from 'react';
import GithubIcon from './github_icon';
import { Button, IconButton } from '../../components/button';
import { Button, IconButton, BrowseButton } from '../../components/button';
const ButtonTest = () => (
<section>
@ -35,7 +35,12 @@ const ButtonTest = () => (
<span style={{verticalAlign: 'middle'}}>Menu</span>
<IconButton><GithubIcon /></IconButton>
<span style={{verticalAlign: 'middle'}}>Github</span>
</section>
<h5>Browse Button</h5>
<br/>
<BrowseButton icon='folder_open' label='BROWSE' raised primary />
&nbsp;
<BrowseButton label='BROWSE' raised />
</section>
);
function rippleEnded () {