Skip to content

Commit

Permalink
Add buttons
Browse files Browse the repository at this point in the history
  • Loading branch information
adlk committed Jan 14, 2019
1 parent b8990f4 commit 8b4231e
Show file tree
Hide file tree
Showing 20 changed files with 426 additions and 281 deletions.
7 changes: 1 addition & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

309 changes: 92 additions & 217 deletions packages/forms/package-lock.json

Large diffs are not rendered by default.

8 changes: 6 additions & 2 deletions packages/forms/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,16 @@
"@mdi/js": "^3.3.92",
"@mdi/react": "^1.1.0",
"@meetfranz/theme": "file:../theme",
"react-html-attributes": "^1.4.3",
"react-loader": "^2.4.5"
},
"peerDependencies": {
"classnames": "^2.2.6",
"lodash": "^4.17.11",
"react": "^16.7.0",
"mobx": "^5.8.0",
"mobx-react": "^5.4.3",
"react": "^16.7.0",
"react-html-attributes": "^1.4.3",
"react-dom": "16.7.0",
"react-jss": "^8.6.1"
},
"gitHead": "e9a48f96f8659dcd6ac07a8445f60f27d6ae698a"
Expand Down
172 changes: 172 additions & 0 deletions packages/forms/src/button/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
import { Theme } from '@meetfranz/theme';
import classnames from 'classnames';
import CSS from 'csstype';
import { observer } from 'mobx-react';
import React, { Component } from 'react';
import injectStyle from 'react-jss';
import Loader from 'react-loader';

import { IFormField, IWithStyle } from '../typings/generic';

type ButtonType = 'primary' | 'secondary' | 'danger' | 'warning' | 'inverted';

interface IProps extends React.InputHTMLAttributes<HTMLButtonElement>, IFormField, IWithStyle {
buttonType?: ButtonType;
stretch?: boolean;
loaded?: boolean;
busy?: boolean;
}

interface IState {
busy: boolean;
}

const styles = (theme: Theme) => ({
button: {
borderRadius: theme.borderRadiusSmall,
border: 'none',
display: 'flex',
position: 'relative' as CSS.PositionProperty,
transition: 'background .5s',
textAlign: 'center' as CSS.TextAlignProperty,
outline: 'none',
alignItems: 'center',
padding: 0,
width: (props: IProps) => (props.stretch ? '100%' : 'auto') as CSS.WidthProperty<string>,
fontSize: theme.uiFontSize,
},
label: {
margin: '10px 20px',
width: '100%',
},
primary: {
background: theme.buttonPrimaryBackground,
color: theme.buttonPrimaryTextColor,
},
secondary: {
background: theme.buttonSecondaryBackground,
color: theme.buttonSecondaryTextColor,
},
danger: {
background: theme.buttonDangerBackground,
color: theme.buttonDangerTextColor,
},
warning: {
background: theme.buttonWarningBackground,
color: theme.buttonWarningTextColor,
},
inverted: {
background: theme.buttonInvertedBackground,
color: theme.buttonInvertedTextColor,
border: theme.buttonInvertedBorder,
},
disabled: {
opacity: theme.inputDisabledOpacity,
},
loader: {
position: 'relative' as CSS.PositionProperty,
width: 20,
height: 18,
zIndex: 9999,
},
loaderContainer: {
width: (props: IProps): string => (!props.busy ? '0' : '40px'),
height: 20,
overflow: 'hidden',
transition: 'all 0.3s',
marginLeft: (props: IProps): number => !props.busy ? 10 : 20,
marginRight: (props: IProps): number => !props.busy ? -10 : -20,
position: (props: IProps): CSS.PositionProperty => props.stretch ? 'absolute' : 'inherit',
},
});

@observer
class ButtonComponent extends Component<IProps> {
public static defaultProps = {
type: 'button',
disabled: false,
onClick: () => null,
buttonType: 'primary' as ButtonType,
stretch: false,
busy: false,
};

state = {
busy: false,
};

componentWillMount() {
this.setState({ busy: this.props.busy });
}

componentWillReceiveProps(nextProps: IProps) {
if (nextProps.busy !== this.props.busy) {
if (this.props.busy) {
setTimeout(() => {
this.setState({ busy: nextProps.busy });
}, 300);
} else {
this.setState({ busy: nextProps.busy });
}
}
}

render() {
const {
classes,
theme,
disabled,
id,
label,
type,
onClick,
buttonType,
loaded,
busy: busyProp,
} = this.props;

const {
busy,
} = this.state;

let showLoader = false;
if (loaded) {
showLoader = !loaded;
console.warn('Franz Button prop `loaded` will be deprecated in the future. Please use `busy` instead');
}
if (busy) {
showLoader = busy;
}

return (
<button
id={id}
type={type}
onClick={onClick}
className={classnames({
[`${classes.button}`]: true,
[`${classes[buttonType as ButtonType]}`]: true,
[`${classes.disabled}`]: disabled,
})}
disabled={disabled}
>
<div className={classes.loaderContainer}>
{showLoader && (
<Loader
loaded={false}
width={4}
scale={0.45}
color={theme.buttonLoaderColor[buttonType!]}
parentClassName={classes.loader}
/>
)}
</div>
<div className={classes.label}>
{label}
</div>
</button>
);
}
}

export const Button = injectStyle(styles)(ButtonComponent);
1 change: 1 addition & 0 deletions packages/forms/src/error/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ export default (theme: Theme) => ({
message: {
color: theme.brandDanger,
margin: '5px 0 0',
fontSize: theme.uiFontSize,
},
});
1 change: 1 addition & 0 deletions packages/forms/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export { Input } from './input';
export { Toggle } from './toggle';
export { Button } from './button';
34 changes: 19 additions & 15 deletions packages/forms/src/input/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class InputComponent extends Component<IProps, IState> {
public static defaultProps = {
focus: false,
onChange: () => {},
onBlur: () => {},
scorePassword: false,
showLabel: true,
showPasswordToggle: false,
Expand Down Expand Up @@ -74,6 +75,7 @@ class InputComponent extends Component<IProps, IState> {
render() {
const {
classes,
className,
disabled,
error,
id,
Expand All @@ -84,36 +86,31 @@ class InputComponent extends Component<IProps, IState> {
showLabel,
showPasswordToggle,
type,
value,
name,
placeholder,
spellCheck,
onBlur,
} = this.props;

const {
showPassword,
passwordScore,
} = this.state;

const inputProps = pick(this.props, htmlElementAttributes['input']);

if (type === 'password' && showPassword) {
inputProps.type = 'text';
}

inputProps.onChange = this.onChange.bind(this);

const cssClasses = classnames({
[`${inputProps.className}`]: inputProps.className,
[`${classes.input}`]: true,
});
const inputType = type === 'password' && showPassword ? 'text' : type;

return (
<Wrapper>
<Label
title={label}
showLabel={showLabel}
htmlFor={id}
className={className}
>
<div
className={classnames({
[`${classes.hasPasswordScore}`]: showPasswordToggle,
[`${classes.hasPasswordScore}`]: scorePassword,
[`${classes.wrapper}`]: true,
[`${classes.disabled}`]: disabled,
[`${classes.hasError}`]: error,
Expand All @@ -124,9 +121,16 @@ class InputComponent extends Component<IProps, IState> {
</span>
)}
<input
{...inputProps}
className={cssClasses}
id={id}
type={inputType}
name={name}
value={value}
placeholder={placeholder}
spellCheck={spellCheck}
className={classes.input}
ref={this.inputRef}
onChange={this.onChange.bind(this)}
onBlur={onBlur}
/>
{suffix && (
<span className={classes.suffix}>
Expand Down
6 changes: 2 additions & 4 deletions packages/forms/src/input/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,10 @@ const prefixStyles = (theme: Theme) => ({
color: theme.inputPrefixColor,
lineHeight: theme.inputHeight,
padding: '0 10px',
fontSize: theme.uiFontSize,
});

export default (theme: Theme) => ({
container: {
// display: 'flex',
},
disabled: {
opacity: theme.inputDisabledOpacity,
},
Expand All @@ -33,7 +31,7 @@ export default (theme: Theme) => ({
input: {
background: 'none',
border: 0,
fontSize: theme.inputFontSize,
fontSize: theme.uiFontSize,
outline: 'none',
padding: 8,
width: '100%',
Expand Down
1 change: 1 addition & 0 deletions packages/forms/src/label/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export default (theme: Theme) => ({
},
label: {
color: theme.labelColor,
fontSize: theme.uiFontSize,
},
hasError: {
color: theme.brandDanger,
Expand Down
8 changes: 2 additions & 6 deletions packages/forms/src/toggle/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@ import Error from '../error';
import Label from '../label';
import Wrapper from '../wrapper';

interface IProps extends React.InputHTMLAttributes<HTMLInputElement>, IFormField, IWithStyle {
// field: any;
}
interface IProps extends React.InputHTMLAttributes<HTMLInputElement>, IFormField, IWithStyle {}

const styles = (theme: Theme) => ({
toggle: {
Expand Down Expand Up @@ -42,7 +40,7 @@ const styles = (theme: Theme) => ({
visibility: 'hidden' as any,
},
disabled: {
opacity: 0.5,
opacity: theme.inputDisabledOpacity,
},
toggleLabel: {
display: 'flex',
Expand Down Expand Up @@ -77,8 +75,6 @@ class ToggleComponent extends Component<IProps> {
onChange,
} = this.props;

console.log('props', this.props);

return (
<Wrapper>
<Label
Expand Down
2 changes: 2 additions & 0 deletions packages/forms/src/typings/generic.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Theme } from '@meetfranz/theme/lib';
import { Classes } from 'jss';

export interface IFormField {
Expand All @@ -8,6 +9,7 @@ export interface IFormField {

export interface IWithStyle {
classes: Classes;
theme: Theme;
}

export type Merge<M, N> = Omit<M, Extract<keyof M, keyof N>> & N;
Expand Down
2 changes: 1 addition & 1 deletion packages/forms/src/wrapper/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class Wrapper extends Component<IProps> {
} = this.props;

return (
<div className={classes.container}>
<div className={classes.container}>
{children}
</div>
);
Expand Down
1 change: 0 additions & 1 deletion packages/forms/typings/react-html-attributes.d.ts

This file was deleted.

9 changes: 9 additions & 0 deletions packages/forms/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,13 @@ module.exports = Object.assign({}, baseConfig, {
path: path.join(__dirname, 'lib'),
libraryTarget: 'commonjs2',
},
externals: {
react: 'react',
reactDom: 'react-dom',
classnames: 'classnames',
lodash: 'lodash',
mobx: 'mobx',
mobxReact: 'mobx-react',
reactJss: 'react-jss',
},
});
Loading

0 comments on commit 8b4231e

Please sign in to comment.