Merge pull request #660 from sharetribe/multi-select-component

Field component for multiple checkboxes
This commit is contained in:
Hannu Lyytikäinen 2018-01-22 11:48:12 +02:00 committed by GitHub
commit 24390c3b8d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 350 additions and 11 deletions

View file

@ -0,0 +1,56 @@
@import '../../marketplace.css';
.root {
position: relative;
}
.input {
position: absolute;
opacity: 0;
height: 0;
width: 0;
/* Highlight the borders if the checkbox is hovered, focused or checked */
&:hover + label .box,
&:focus + label .box,
&:checked + label .box {
stroke: var(--marketplaceColor);
}
/* Display the "check" when checked */
&:checked + label .checked {
display: inline;
}
/* Hightlight the text on hover and focus */
&:focus + label .text,
&:hover + label .text {
color: var(--matterColorDark);
}
}
.label {
display: flex;
align-items: center;
padding: 0;
}
.checkbox {
margin-right: 12px;
}
.checked {
display: none;
fill: var(--marketplaceColor);
}
.box {
stroke: var(--matterColorAnti);
}
.text {
@apply --marketplaceListingAttributeFontStyles;
color: var(--matterColor);
margin-top: -1px;
margin-bottom: 1px;
}

View file

@ -0,0 +1,42 @@
import React from 'react';
import { reduxForm, propTypes as formPropTypes } from 'redux-form';
import { Button } from '../../components';
import FieldCheckbox from './FieldCheckbox';
const formName = 'Styleguide.FieldCheckbox.Form';
const FormComponent = props => {
const { form, handleSubmit, invalid, pristine, submitting } = props;
const submitDisabled = invalid || pristine || submitting;
return (
<form onSubmit={handleSubmit}>
<FieldCheckbox
id="field-checkbox-example-id"
name="field-checkbox-example-name"
text="Check here"
/>
<Button style={{ marginTop: 24 }} type="submit" disabled={submitDisabled}>
Submit
</Button>
</form>
);
};
FormComponent.propTypes = formPropTypes;
const Form = reduxForm({
form: formName,
})(FormComponent);
export const Checkbox = {
component: Form,
props: {
onSubmit: values => {
console.log('Submit values of FieldCheckbox: ', values);
},
},
group: 'inputs',
};

View file

@ -0,0 +1,73 @@
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { Field } from 'redux-form';
import css from './FieldCheckbox.css';
const IconCheckbox = props => {
const svgClasses = classNames(props.className, css.checkbox);
return (
<svg className={svgClasses} width="14" height="14" xmlns="http://www.w3.org/2000/svg">
<g fill="none" fillRule="evenodd">
<g transform="translate(2 2)">
<path
className={css.checked}
fill="#C0392B"
d="M9.9992985 1.5048549l-.0194517 6.9993137C9.977549 9.3309651 9.3066522 10 8.4798526 10H1.5001008c-.8284271 0-1.5-.6715729-1.5-1.5l-.000121-7c0-.8284271.6715728-1.5 1.5-1.5h.000121l6.9993246.0006862c.8284272.000067 1.4999458.671694 1.499879 1.5001211a1.5002208 1.5002208 0 0 1-.0000059.0040476z"
/>
<path
className={css.box}
strokeWidth="2"
d="M10.9992947 1.507634l-.0194518 6.9993137C10.9760133 9.8849417 9.8578519 11 8.4798526 11H1.5001008c-1.3807119 0-2.5-1.1192881-2.5-2.4999827L-1.0000202 1.5c0-1.3807119 1.119288-2.5 2.500098-2.5l6.9994284.0006862c1.3807118.0001115 2.4999096 1.11949 2.4997981 2.5002019-.0000018.003373-.0000018.003373-.0000096.0067458z"
/>
</g>
<path
d="M5.636621 10.7824771L3.3573694 8.6447948c-.4764924-.4739011-.4764924-1.2418639 0-1.7181952.4777142-.473901 1.251098-.473901 1.7288122 0l1.260291 1.1254782 2.8256927-4.5462307c.3934117-.5431636 1.1545778-.6695372 1.7055985-.278265.5473554.3912721.6731983 1.150729.2797866 1.6951077l-3.6650524 5.709111c-.2199195.306213-.5803433.5067097-.9920816.5067097-.3225487 0-.6328797-.1263736-.8637952-.3560334z"
fill="#FFF"
/>
</g>
</svg>
);
};
IconCheckbox.defaultProps = { className: null };
const { node, string } = PropTypes;
IconCheckbox.propTypes = { className: string };
const FieldCheckbox = props => {
const { rootClassName, className, svgClassName, id, name, text } = props;
const classes = classNames(rootClassName || css.root, className);
return (
<span className={classes}>
<Field id={id} name={name} className={css.input} type="checkbox" component="input" />
<label htmlFor={id} className={css.label}>
<IconCheckbox className={svgClassName} />
<span className={css.text}>{text}</span>
</label>
</span>
);
};
FieldCheckbox.defaultProps = {
className: null,
rootClassName: null,
svgClassName: null,
text: null,
};
FieldCheckbox.propTypes = {
className: string,
rootClassName: string,
svgClassName: string,
id: string.isRequired,
name: string.isRequired,
text: node,
};
export default FieldCheckbox;

View file

@ -0,0 +1,28 @@
@import '../../marketplace.css';
.root {
margin: 0;
padding: 0;
border: none;
}
.list {
margin: 0;
}
.twoColumns {
@media (--viewportMedium) {
columns: 2;
}
}
.item {
padding: 2px 0;
/* Fix broken multi-column layout in Chrome */
page-break-inside: avoid;
@media (--viewportMedium) {
padding: 4px 0;
}
}

View file

@ -0,0 +1,80 @@
import React from 'react';
import { reduxForm, propTypes as formPropTypes } from 'redux-form';
import { Button } from '../../components';
import FieldGroupCheckbox from './FieldGroupCheckbox';
const formName = 'Styleguide.FieldGroupCheckboxForm';
const legend = <h3>Amenities</h3>;
const componentProps = {
id: `${formName}.amenities`,
legend: legend,
options: [
{
name: 'towels',
text: 'Towels',
},
{
name: 'bathroom',
text: 'Bathfoom',
},
{
name: 'swimming_pool',
text: 'Swimming pool',
},
{
name: 'own_drinks',
text: 'Own drinks allowed',
},
{
name: 'jacuzzi',
text: 'Jacuzzi',
},
{
name: 'audiovisual_entertainment',
text: 'Audiovisual entertainment',
},
{
name: 'barbeque',
text: 'Barbeque',
},
{
name: 'own_food_allowed',
text: 'Own food allowed',
},
],
twoColumns: true,
};
const FormComponent = props => {
const { handleSubmit, invalid, pristine, submitting } = props;
const submitDisabled = invalid || pristine || submitting;
return (
<form onSubmit={handleSubmit}>
<FieldGroupCheckbox {...componentProps} />
<Button style={{ marginTop: 24 }} type="submit" disabled={submitDisabled}>
Submit
</Button>
</form>
);
};
FormComponent.propTypes = formPropTypes;
const Form = reduxForm({
form: formName,
})(FormComponent);
export const WithTwoColumns = {
component: Form,
props: {
onSubmit: values => {
console.log('Submit values: ', values);
},
},
group: 'inputs',
};

View file

@ -0,0 +1,60 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { FieldCheckbox } from '../../components';
import css from './FieldGroupCheckbox.css';
class FieldGroupCheckbox extends Component {
constructor(props) {
super(props);
this.state = { selected: [] };
}
render() {
const { rootClassName, className, id, legend, options, twoColumns } = this.props;
const classes = classNames(rootClassName || css.root, className);
const listClasses = twoColumns ? classNames(css.list, css.twoColumns) : css.list;
return (
<fieldset className={classes}>
{legend ? <legend>{legend}</legend> : null}
<ul className={listClasses}>
{options.map(option => {
const fieldId = `${id}.${option.name}`;
return (
<li key={fieldId} className={css.item}>
<FieldCheckbox id={fieldId} name={option.name} text={option.text} />
</li>
);
})}
</ul>
</fieldset>
);
}
}
FieldGroupCheckbox.defaultProps = {
rootClassName: null,
className: null,
legend: null,
twoColumns: false,
};
const { arrayOf, bool, node, shape, string } = PropTypes;
FieldGroupCheckbox.propTypes = {
rootClassName: string,
className: string,
id: string.isRequired,
legend: node,
options: arrayOf(
shape({
name: string.isRequired,
text: node.isRequired,
})
).isRequired,
twoColumns: bool,
};
export default FieldGroupCheckbox;

View file

@ -75,7 +75,7 @@
}
.menuItem {
@apply --marketplaceSearchFilterOptionFontStyles;
@apply --marketplaceListingAttributeFontStyles;
color: var(--matterColor);
/* Layout */

View file

@ -27,9 +27,11 @@ export { default as EditListingWizard } from './EditListingWizard/EditListingWiz
export { default as ExpandingTextarea } from './ExpandingTextarea/ExpandingTextarea';
export { default as ExternalLink } from './ExternalLink/ExternalLink';
export { default as FilterPanel } from './FilterPanel/FilterPanel';
export { default as FieldCheckbox } from './FieldCheckbox/FieldCheckbox';
export {
default as FieldCustomAttributeSelect,
} from './FieldCustomAttributeSelect/FieldCustomAttributeSelect';
export { default as FieldGroupCheckbox } from './FieldGroupCheckbox/FieldGroupCheckbox';
export { default as FieldReviewRating } from './FieldReviewRating/FieldReviewRating';
export { default as Footer } from './Footer/Footer';
export { default as Form } from './Form/Form';

View file

@ -9,6 +9,8 @@ import * as CurrencyInputField from './components/CurrencyInputField/CurrencyInp
import * as DateRangeInputField from './components/DateRangeInputField/DateRangeInputField.example';
import * as EditListingWizard from './components/EditListingWizard/EditListingWizard.example';
import * as ExpandingTextarea from './components/ExpandingTextarea/ExpandingTextarea.example';
import * as FieldCheckbox from './components/FieldCheckbox/FieldCheckbox.example';
import * as FieldGroupCheckbox from './components/FieldGroupCheckbox/FieldGroupCheckbox.example';
import * as FieldReviewRating from './components/FieldReviewRating/FieldReviewRating.example';
import * as Footer from './components/Footer/Footer.example';
import * as IconBannedUser from './components/IconBannedUser/IconBannedUser.example';
@ -88,6 +90,8 @@ export {
EmailVerificationForm,
EnquiryForm,
ExpandingTextarea,
FieldCheckbox,
FieldGroupCheckbox,
FieldReviewRating,
Footer,
IconBannedUser,

View file

@ -262,17 +262,11 @@
}
}
--marketplaceSearchFilterOptionFontStyles {
--marketplaceListingAttributeFontStyles {
font-family: 'sofiapro', Helvetica, Arial, sans-serif;
font-weight: var(--fontWeightSemiBold);
font-size: 13px;
line-height: 18px;
@media (--viewportMedium) {
font-weight: var(--fontWeightMedium);
font-size: 18px;
line-height: 32px;
}
font-weight: var(--fontWeightMedium);
font-size: 18px;
line-height: 32px;
}
/* ================ Tabbed navigation font styles ================ */