Skip to content

Commit

Permalink
feat(atoms): change Form component api
Browse files Browse the repository at this point in the history
  • Loading branch information
ej9x committed Jun 15, 2018
1 parent 1b15e8c commit 18122a4
Show file tree
Hide file tree
Showing 20 changed files with 727 additions and 438 deletions.
7 changes: 4 additions & 3 deletions src/atoms/FlexLayout/FlexLayout.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,20 +38,21 @@ type FlexLayoutProps = {
}

const defaultProps = {
gap: 'md',
gap: 'sm',
};

/** component provides interface to render flex layout */
const FlexLayout = (props: FlexLayoutProps) => {
return <FlexLayoutTag { ...props } tagName="div" />;
};

FlexLayout.defaultProps = defaultProps;

/** component provides interface to render flex row */
const Row = (props: FlexLayoutCommonProps) => <FlexLayout { ...props } direction="row" />;
Row.defaultProps = defaultProps;

/** component provides interface to render flex column */
const Column = (props: FlexLayoutCommonProps) => <FlexLayout { ...props } direction="column" />;
Column.defaultProps = defaultProps;

export { Row, Column, FlexLayout };
export type { FlexLayoutProps };
1 change: 0 additions & 1 deletion src/atoms/atoms.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ export { Dialog } from './Dialog';
export { Divider } from './Divider';
export { Dropdown } from './Dropdown';
export { Form } from './dataEntry/Form';
export { FormSubTitle } from './dataEntry/FormSubTitle';
export { Grid } from './Grid';
export { Heading } from './typography/Heading';
export { Icon } from './typography/Icon';
Expand Down
2 changes: 1 addition & 1 deletion src/atoms/dataEntry/CheckboxField/CheckboxField.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import React from 'react';

import type { InputType, MetaType } from '../formTypes';
import { Checkbox } from '../Checkbox';
import { FormField } from '../FormField';
import { FormField } from '../Form/FormField';

type CheckboxFieldProps = {|
/** field label */
Expand Down
17 changes: 0 additions & 17 deletions src/atoms/dataEntry/Form/Form.js

This file was deleted.

51 changes: 25 additions & 26 deletions src/atoms/dataEntry/Form/Form.stories.js
Original file line number Diff line number Diff line change
@@ -1,36 +1,35 @@
import React from 'react';

const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));

const onSubmit = async values => {
await sleep(300);
// eslint-disable-next-line no-alert
alert(JSON.stringify(values, 0, 2));
};
const FieldMock = ({ component: Component, label, name }) => (
<Component label={ label } input={{ name }} />
);

export default (asStory) => {
asStory('ATOMS/DATA ENTRY/Form', module, (story, { Form, InputField, Button }) => {
asStory('ATOMS/DATA ENTRY/Form', module, (story, { Form, InputField }) => {
story
.add('without groups', () => (
<Form.Plate onSubmit={ onSubmit } initialValues={{
curple: 'Breakthrough',
provect: 'Yearock',
inlaying: 'Lombard',
saccharifier: 'Cyanoacetic',
inertance: 'Unfluent',
}}>
{ ({ submitting }) => (
<React.Fragment>
<Form.Field component={ InputField } name="curple" label="Jobs" />
<Form.Field component={ InputField } name="provect" label="Posted" />
<Form.Field component={ InputField } name="inlaying" label="My Active Jobs" />
<Form.Field component={ InputField } name="saccharifier" label="Active Requests" />
<Form.Field component={ InputField } name="inertance" label="Applied" />
<Button text="Submit" type="submit" loading={ submitting } />
</React.Fragment>
) }
<Form.Plate>
<FieldMock component={ InputField } name="curple" label="Jobs" />
<FieldMock component={ InputField } name="provect" label="Posted" />
<FieldMock component={ InputField } name="inlaying" label="My Active Jobs" />
<FieldMock component={ InputField } name="saccharifier" label="Active Requests" />
<FieldMock component={ InputField } name="inertance" label="Applied" />
</Form.Plate>
))
.add('with groups', () => (
<Form.Plate>
<Form.Section>
<Form.SectionTitle>Some section 1</Form.SectionTitle>
<FieldMock component={ InputField } name="curple" label="Jobs" />
<FieldMock component={ InputField } name="provect" label="Posted" />
<FieldMock component={ InputField } name="inlaying" label="My Active Jobs" />
</Form.Section>
<Form.Section>
<Form.SectionTitle>Some section 2</Form.SectionTitle>
<FieldMock component={ InputField } name="saccharifier" label="Active Requests" />
<FieldMock component={ InputField } name="inertance" label="Applied" />
</Form.Section>
</Form.Plate>
));
});
};

92 changes: 73 additions & 19 deletions src/atoms/dataEntry/Form/FormField.js
Original file line number Diff line number Diff line change
@@ -1,35 +1,89 @@
// @flow

import React from 'react';
import { Field } from 'react-final-form';

import { createStyledTag, createTheme } from 'utils';
import type { InputType, MetaType } from '../formTypes';

type FormFieldProps = {|
children?: React.Node,
|};
type FormFieldProps = {
children?: React$Node,
label?: string,
stretch?: boolean,
hideErrorLabel?: boolean,
direction?: 'row' | 'column',
input: InputType,
meta: MetaType,
};

const name = 'formField';

const theme = createTheme(name, {
modifiers: {
},
defaults: {
},
modifiers: {},
defaults: {},
});

const FormFieldTag = createStyledTag(name, props => ({
position: 'relative',
display: 'inline-flex',
flexDirection: props.direction === 'row' ? 'row-reverse' : 'column',
alignItems: props.direction === 'row' ? 'center' : 'flex-start',
width: props.stretch ? '100%' : 'auto',
}));

const ControlErrorWrapperTag = createStyledTag(name, {
display: 'block',
position: 'absolute',
bottom: 0,
height: 0,
lineHeight: 1,
});

const StyledTag = createStyledTag(name, {});
const ControlErrorTag = createStyledTag(name, props => ({
fontSize: '1rem',
color: props.theme.COLORS.DANGER,
lineHeight: 1,
}));

function FormField({
name,
component,
const ControlLabelTag = createStyledTag(name, props => ({
marginLeft: props.direction === 'row' ? '1rem' : 0,
fontSize: props.direction === 'row' ? '1.4rem' : '1.2rem',
color: props.theme.COLORS.SECONDARY_TEXT_COLOR,
lineHeight: 2,
}));

const FormField = ({
meta,
label,
children,
direction,
hideErrorLabel,
...rest
}: FormFieldProps) {
}: FormFieldProps) => {
const { error, touched } = meta;
const hasError = !!error && !!touched;
const hasLabel = !!label;

return (
<Field name={ name }>
{ ({ input }) => (
<StyledTag { ...rest } { ...input } tagName={ component } />
) }
</Field>
<FormFieldTag { ...rest } direction={ direction } tagName="div">
<If condition={ hasLabel }>
<ControlLabelTag direction={ direction } tagName="div">
{ label }
</ControlLabelTag>
</If>
{ children }
<If condition={ hasError && !hideErrorLabel }>
<ControlErrorWrapperTag tagName="div">
<ControlErrorTag tagName="span">{ error }</ControlErrorTag>
</ControlErrorWrapperTag>
</If>
</FormFieldTag>
);
}
};

FormField.defaultProps = {
hideErrorLabel: false,
stretch: true,
direction: 'column',
};

export { FormField, theme };
38 changes: 29 additions & 9 deletions src/atoms/dataEntry/Form/FormPlate.js
Original file line number Diff line number Diff line change
@@ -1,35 +1,55 @@
import React from 'react';
import { Form } from 'react-final-form';

import { createStyledTag, createTheme } from 'utils';
import { FlexLayout } from '../../FlexLayout/FlexLayout';

type FormPlateProps = {|
children?: Function,
|};
/** callback called on form submit */
onSubmit?: Function,
/** when true then stretch form by the parent */
stretch?: boolean,
/** form content */
children?: React$Node,
|}

const name = 'formPlate';

const theme = createTheme(name, {
modifiers: {
stretch: {
height: '100%',
width: '100%',
},
},
defaults: {
stretch: false,
},
});

const StyledTag = createStyledTag(name, {
const FormStyledTag = createStyledTag(name, {
flex: 1,
height: '100%',
});

function FormPlate({
children,
onSubmit,
initialValues,
component,
...rest
}: FormPlateProps) {
return (<Form onSubmit={ onSubmit } initialValues={ initialValues } render={ ({ handleSubmit, reset, submitting, pristine, values }) => (
<StyledTag tagName="form" onSubmit={ handleSubmit } { ...rest }>{ children({ reset, submitting, pristine, values }) }</StyledTag>
) } />);
return (
<FormStyledTag
tagName={ component }
onSubmit={ onSubmit }
>
<FlexLayout { ...rest }>{ children }</FlexLayout>
</FormStyledTag>
);
}

FormPlate.defaultProps = {
...theme[name].defaults,
component: 'form',
direction: 'column',
};

export { FormPlate, theme };
25 changes: 25 additions & 0 deletions src/atoms/dataEntry/Form/FormSection.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// @flow

import React from 'react';

import { FlexLayout } from '../../FlexLayout/FlexLayout';

type FormSectionProps = {
direction?: 'column' | 'row',
stretch?: boolean,
children: React$Node,
};

const FormSection = ({ ...rest }: FormSectionProps) => {
return (
<FlexLayout { ...rest } />
);
};

FormSection.defaultProps = {
direction: 'column',
stretch: true,
};

export { FormSection };

46 changes: 46 additions & 0 deletions src/atoms/dataEntry/Form/FormSectionTitle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// @flow

import React from 'react';
import { createStyledTag, createTheme } from 'utils';

type FormSectionTitleProps = {|
children?: string,
text?: string,
size?: PropSizes,
|}

const name = 'formSectionTitle';

const theme = createTheme(name, {
modifiers: {
size: {
xs: {
fontSize: '1rem',
},
sm: {
fontSize: '1.2rem',
},
md: {
fontSize: '1.4rem',
},
lg: {
fontSize: '1.6rem',
},
xl: {
fontSize: '1.8rem',
},
},
},
defaults: {
},
});

const FormSectionTitleTag = createStyledTag(name, {
fontWeight: 600,
});

const FormSectionTitle = ({ children, text, ...rest }: FormSectionTitleProps) => (
<FormSectionTitleTag { ...rest } tagName="span">{ children || text }</FormSectionTitleTag>
);

export { FormSectionTitle, theme };
23 changes: 22 additions & 1 deletion src/atoms/dataEntry/Form/index.js
Original file line number Diff line number Diff line change
@@ -1 +1,22 @@
export { Form, theme } from './Form';
import { FormField as Field, theme as formFieldTheme } from './FormField';
import { FormPlate as Plate, theme as formPlateTheme } from './FormPlate';
import { FormSection as Section } from './FormSection';
import { FormSectionTitle as SectionTitle, theme as formSectionTitleTheme } from './FormSectionTitle';

const Form = {
Field,
Plate,
Section,
SectionTitle,
};

const theme = {
...formFieldTheme,
...formPlateTheme,
...formSectionTitleTheme,
};

export {
Form,
theme,
};
Loading

0 comments on commit 18122a4

Please sign in to comment.