From 45358a7d510679366765914f70b94756935def08 Mon Sep 17 00:00:00 2001 From: Hannu Lyytikainen Date: Tue, 30 Jan 2018 18:15:35 +0200 Subject: [PATCH 1/6] Remove FilterPanel as obsolete --- src/components/FilterPanel/FilterPanel.css | 37 ------------------- src/components/FilterPanel/FilterPanel.js | 17 --------- .../FilterPanel/FilterPanel.test.js | 10 ----- .../__snapshots__/FilterPanel.test.js.snap | 19 ---------- src/components/index.js | 1 - 5 files changed, 84 deletions(-) delete mode 100644 src/components/FilterPanel/FilterPanel.css delete mode 100644 src/components/FilterPanel/FilterPanel.js delete mode 100644 src/components/FilterPanel/FilterPanel.test.js delete mode 100644 src/components/FilterPanel/__snapshots__/FilterPanel.test.js.snap diff --git a/src/components/FilterPanel/FilterPanel.css b/src/components/FilterPanel/FilterPanel.css deleted file mode 100644 index c8ac683c..00000000 --- a/src/components/FilterPanel/FilterPanel.css +++ /dev/null @@ -1,37 +0,0 @@ -.filterTitle { - text-align: center; -} - -.toListingsButton { - position: fixed; - bottom: 1rem; - left: 50%; - width: 200px; - margin-left: -100px; - display: block; - text-align: center; - text-decoration: none; - font-size: 1.4rem; - padding: 0.5rem; - color: #fff; - background-color: #9b9b9b; - cursor: pointer; - - &:hover { - background-color: #888; - } -} - -.close { - position: absolute; - top: 0; - left: 0; - height: 3em; - padding: 1em; - color: #999; - text-decoration: none; - - &:hover { - color: #000; - } -} diff --git a/src/components/FilterPanel/FilterPanel.js b/src/components/FilterPanel/FilterPanel.js deleted file mode 100644 index dcc5a762..00000000 --- a/src/components/FilterPanel/FilterPanel.js +++ /dev/null @@ -1,17 +0,0 @@ -import React from 'react'; -import { NamedLink } from '../../components'; -import css from './FilterPanel.css'; - -const FilterPanel = () => ( -
-

Filters

- - See studios - - - X - -
-); - -export default FilterPanel; diff --git a/src/components/FilterPanel/FilterPanel.test.js b/src/components/FilterPanel/FilterPanel.test.js deleted file mode 100644 index 28ada261..00000000 --- a/src/components/FilterPanel/FilterPanel.test.js +++ /dev/null @@ -1,10 +0,0 @@ -import React from 'react'; -import { renderShallow } from '../../util/test-helpers'; -import FilterPanel from './FilterPanel'; - -describe('FilterPanel', () => { - it('matches snapshot', () => { - const tree = renderShallow(); - expect(tree).toMatchSnapshot(); - }); -}); diff --git a/src/components/FilterPanel/__snapshots__/FilterPanel.test.js.snap b/src/components/FilterPanel/__snapshots__/FilterPanel.test.js.snap deleted file mode 100644 index 7ed8959d..00000000 --- a/src/components/FilterPanel/__snapshots__/FilterPanel.test.js.snap +++ /dev/null @@ -1,19 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`FilterPanel matches snapshot 1`] = ` -
-

- Filters -

- - See studios - - - X - -
-`; diff --git a/src/components/index.js b/src/components/index.js index d75ae34e..49a14f0b 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -29,7 +29,6 @@ export { export { default as EditListingWizard } from './EditListingWizard/EditListingWizard'; export { default as ExpandingTextarea } from './ExpandingTextarea/ExpandingTextarea'; export { default as ExternalLink } from './ExternalLink/ExternalLink'; -export { default as FilterPanel } from './FilterPanel/FilterPanel'; export { default as FieldBirthdayInput } from './FieldBirthdayInput/FieldBirthdayInput'; export { default as FieldCheckbox } from './FieldCheckbox/FieldCheckbox'; export { default as FieldCurrencyInput } from './FieldCurrencyInput/FieldCurrencyInput'; From ca410d5c3bc275558d0aed2530b28a25ea68461a Mon Sep 17 00:00:00 2001 From: Hannu Lyytikainen Date: Fri, 2 Feb 2018 11:39:20 +0200 Subject: [PATCH 2/6] Allow ref fucntion to be passed to the form --- src/components/Form/Form.js | 9 +++++++-- .../__snapshots__/BookingDatesForm.test.js.snap | 1 + .../__snapshots__/EditListingLocationForm.test.js.snap | 1 + .../__snapshots__/EditListingPhotosForm.test.js.snap | 1 + .../__snapshots__/EditListingPoliciesForm.test.js.snap | 1 + 5 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/components/Form/Form.js b/src/components/Form/Form.js index 961e205c..07201002 100644 --- a/src/components/Form/Form.js +++ b/src/components/Form/Form.js @@ -2,7 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; const Form = props => { - const { children, ...restProps } = props; + const { children, contentRef, ...restProps } = props; const formProps = { // These are mainly default values for the server @@ -12,6 +12,9 @@ const Form = props => { method: 'post', action: '/', + // allow content ref function to be passed to the form + ref: contentRef, + ...restProps, }; return
{children}
; @@ -19,12 +22,14 @@ const Form = props => { Form.defaultProps = { children: null, + contentRef: null, }; -const { node } = PropTypes; +const { func, node } = PropTypes; Form.propTypes = { children: node, + contentRef: func, }; export default Form; diff --git a/src/containers/BookingDatesForm/__snapshots__/BookingDatesForm.test.js.snap b/src/containers/BookingDatesForm/__snapshots__/BookingDatesForm.test.js.snap index 8ca5cdc2..2164cfc9 100644 --- a/src/containers/BookingDatesForm/__snapshots__/BookingDatesForm.test.js.snap +++ b/src/containers/BookingDatesForm/__snapshots__/BookingDatesForm.test.js.snap @@ -3,6 +3,7 @@ exports[`BookingDatesForm matches snapshot without selected dates 1`] = `
Date: Thu, 1 Feb 2018 15:32:45 +0200 Subject: [PATCH 3/6] Add SelectMultipleFilter component --- .../SelectMultipleFilter.css | 25 +++ .../SelectMultipleFilter.example.js | 67 +++++++ .../SelectMultipleFilter.js | 174 ++++++++++++++++++ .../SelectMultipleFilterForm.css | 102 ++++++++++ .../SelectMultipleFilterForm.js | 98 ++++++++++ src/components/index.js | 1 + src/examples.js | 2 + src/translations/en.json | 4 + 8 files changed, 473 insertions(+) create mode 100644 src/components/SelectMultipleFilter/SelectMultipleFilter.css create mode 100644 src/components/SelectMultipleFilter/SelectMultipleFilter.example.js create mode 100644 src/components/SelectMultipleFilter/SelectMultipleFilter.js create mode 100644 src/components/SelectMultipleFilter/SelectMultipleFilterForm.css create mode 100644 src/components/SelectMultipleFilter/SelectMultipleFilterForm.js diff --git a/src/components/SelectMultipleFilter/SelectMultipleFilter.css b/src/components/SelectMultipleFilter/SelectMultipleFilter.css new file mode 100644 index 00000000..3469efc8 --- /dev/null +++ b/src/components/SelectMultipleFilter/SelectMultipleFilter.css @@ -0,0 +1,25 @@ +@import '../../marketplace.css'; + +.root { + position: relative; + display: inline-block; +} + +.label { + @apply --marketplaceButtonStylesSecondary; + @apply --marketplaceSearchFilterLabelFontStyles; + + padding: 9px 16px 10px 16px; + width: auto; + height: auto; + min-height: 0; + border-radius: 4px; + + &:focus { + outline: none; + background-color: var(--matterColorLight); + border-color: transparent; + text-decoration: none; + box-shadow: var(--boxShadowFilterButton); + } +} diff --git a/src/components/SelectMultipleFilter/SelectMultipleFilter.example.js b/src/components/SelectMultipleFilter/SelectMultipleFilter.example.js new file mode 100644 index 00000000..97ea524f --- /dev/null +++ b/src/components/SelectMultipleFilter/SelectMultipleFilter.example.js @@ -0,0 +1,67 @@ +import React from 'react'; +import { withRouter } from 'react-router-dom'; +import SelectMultipleFilter from './SelectMultipleFilter'; +import { stringify, parse } from '../../util/urlHelpers'; + +const options = [ + { + key: 'towels', + label: 'Towels', + }, + { + key: 'bathroom', + label: 'Bathroom', + }, + { + key: 'swimming_pool', + label: 'Swimming pool', + }, + { + key: 'own_drinks', + label: 'Own drinks allowed', + }, + { + key: 'jacuzzi', + label: 'Jacuzzi', + }, + { + key: 'audiovisual_entertainment', + label: 'Audiovisual entertainment', + }, + { + key: 'barbeque', + label: 'Barbeque', + }, + { + key: 'own_food_allowed', + label: 'Own food allowed', + }, +]; + +const handleSubmit = (values, history) => { + const queryParams = values ? `?${stringify({ pub_amenities: values.join(',') })}` : ''; + history.push(`${window.location.pathname}${queryParams}`); +}; + +const AmenitiesFilterComponent = withRouter(props => { + const { history, location } = props; + + const params = parse(location.search); + const amenities = params.pub_amenities; + const initialValues = !!amenities ? amenities.split(',') : []; + + return ( + handleSubmit(values, history)} + options={options} + initialValues={initialValues} + contentPlacementOffset={-14} + /> + ); +}); + +export const AmenitiesFilter = { + component: AmenitiesFilterComponent, + props: {}, + group: 'misc', +}; diff --git a/src/components/SelectMultipleFilter/SelectMultipleFilter.js b/src/components/SelectMultipleFilter/SelectMultipleFilter.js new file mode 100644 index 00000000..e93d4fad --- /dev/null +++ b/src/components/SelectMultipleFilter/SelectMultipleFilter.js @@ -0,0 +1,174 @@ +import React, { Component } from 'react'; +import { arrayOf, func, node, shape, string } from 'prop-types'; +import classNames from 'classnames'; +import { injectIntl, intlShape } from 'react-intl'; +import { toPairs } from 'lodash'; + +import SelectMultipleFilterForm from './SelectMultipleFilterForm'; +import css from './SelectMultipleFilter.css'; + +const KEY_CODE_ESCAPE = 27; + +/** + * Convert an array of option keys into + * an object that can be passed to a redux + * form as initial values. + */ +const keysToValues = keys => { + return keys.reduce((map, key) => { + map[key] = true; + return map; + }, {}); +}; + +/** + * Convert an object containing values received + * from a redux form into an array of values. + */ +const valuesToKeys = values => { + const entries = toPairs(values); + return entries.filter(entry => entry[1] === true).map(entry => entry[0]); +}; + + +class SelectMultipleFilter extends Component { + constructor(props) { + super(props); + + this.state = { isOpen: false }; + this.filter = null; + this.filterContent = null; + + this.handleSubmit = this.handleSubmit.bind(this); + this.handleClear = this.handleClear.bind(this); + this.handleCancel = this.handleCancel.bind(this); + this.handleBlur = this.handleBlur.bind(this); + this.handleKeyDown = this.handleKeyDown.bind(this); + this.toggleOpen = this.toggleOpen.bind(this); + this.positionStyleForContent = this.positionStyleForContent.bind(this); + } + + handleSubmit(values) { + const selectedKeys = valuesToKeys(values); + this.setState({ isOpen: false }); + this.props.onSubmit(selectedKeys); + } + + handleClear() { + this.setState({ isOpen: false }); + this.props.onSubmit(null); + } + + handleCancel() { + const { onSubmit, initialValues } = this.props; + this.setState({ isOpen: false }); + onSubmit(initialValues); + } + + handleBlur(event) { + // FocusEvent is fired faster than the link elements native click handler + // gets its own event. Therefore, we need to check the origin of this FocusEvent. + if (!this.filter.contains(event.relatedTarget)) { + this.setState({ isOpen: false }); + } + } + + handleKeyDown(e) { + // Gather all escape presses to close menu + if (e.keyCode === KEY_CODE_ESCAPE) { + this.toggleOpen(false); + } + } + + toggleOpen(enforcedState) { + if (enforcedState) { + this.setState({ isOpen: enforcedState }); + } else { + this.setState(prevState => ({ isOpen: !prevState.isOpen })); + } + } + + positionStyleForContent() { + if (this.filter && this.filterContent) { + // Render the filter content to the right from the menu + // unless there's no space in which case it is rendered + // to the left + const distanceToRight = window.innerWidth - this.filter.getBoundingClientRect().right; + const labelWidth = this.filter.offsetWidth; + const contentWidth = this.filterContent.offsetWidth; + const contentWidthBiggerThanLabel = contentWidth - labelWidth; + const renderToRight = distanceToRight > contentWidthBiggerThanLabel; + const contentPlacementOffset = this.props.contentPlacementOffset; + + const offset = renderToRight + ? { left: contentPlacementOffset } + : { right: contentPlacementOffset }; + // set a min-width if the content is narrower than the label + const minWidth = contentWidth < labelWidth ? { minWidth: labelWidth } : null; + + return { ...offset, ...minWidth }; + } + return {}; + } + + render() { + const { rootClassName, className, options, initialValues, intl } = this.props; + const classes = classNames(rootClassName || css.root, className); + + const label = intl.formatMessage({ id: 'SelectMultipleFilterMobile.label' }); + const contentStyle = this.positionStyleForContent(); + + return ( +
{ + this.filter = node; + }} + > + + { + this.filterContent = node; + }} + style={contentStyle} + /> +
+ ); + } +} + +SelectMultipleFilter.defaultProps = { + rootClassName: null, + className: null, + initialValues: [], +}; + +SelectMultipleFilter.propTypes = { + rootClassName: string, + className: string, + onSubmit: func.isRequired, + options: arrayOf( + shape({ + key: string.isRequired, + label: node.isRequired, + }) + ).isRequired, + initialValues: arrayOf(string), + + // form injectIntl + intl: intlShape.isRequired, +}; + +export default injectIntl(SelectMultipleFilter); diff --git a/src/components/SelectMultipleFilter/SelectMultipleFilterForm.css b/src/components/SelectMultipleFilter/SelectMultipleFilterForm.css new file mode 100644 index 00000000..1fa0e41a --- /dev/null +++ b/src/components/SelectMultipleFilter/SelectMultipleFilterForm.css @@ -0,0 +1,102 @@ +@import '../../marketplace.css'; + +.root { + /* By default hide the content */ + visibility: hidden; + opacity: 0; + pointer-events: none; + + /* Position */ + position: absolute; + z-index: var(--zIndexPopup); + + /* Layout */ + margin-top: 7px; + padding: 15px 40px 20px 30px; + + /* Borders */ + background-color: var(--matterColorLight); + border-top: 1px solid var(--matterColorNegative); + box-shadow: var(--boxShadowPopup); + border-radius: 4px; + transition: var(--transitionStyleButton); + outline: none; +} + +.isOpen { + visibility: visible; + opacity: 1; + pointer-events: auto; +} + +.fieldGroup { + margin-bottom: 35px; + white-space: nowrap; +} + +.buttonsWrapper { + display: flex; +} + +.clearButton { + @apply --marketplaceH4FontStyles; + font-weight: var(--fontWeightMedium); + color: var(--matterColorAnti); + + /* Layout */ + margin: 0 auto 0 0; + padding: 0; + + /* Override button styles */ + outline: none; + border: none; + cursor: pointer; + + &:focus, + &:hover { + color: var(--matterColor); + transition: width var(--transitionStyleButton); + } +} + +.cancelButton { + @apply --marketplaceH4FontStyles; + font-weight: var(--fontWeightMedium); + color: var(--matterColorAnti); + + /* Layout */ + margin: 0; + padding: 0; + + /* Override button styles */ + outline: none; + border: none; + cursor: pointer; + + &:focus, + &:hover { + color: var(--matterColor); + transition: width var(--transitionStyleButton); + } +} + +.submitButton { + @apply --marketplaceH4FontStyles; + font-weight: var(--fontWeightMedium); + color: var(--marketplaceColor); + + /* Layout */ + margin: 0 0 0 19px; + padding: 0; + + /* Override button styles */ + outline: none; + border: none; + cursor: pointer; + + &:focus, + &:hover { + color: var(--marketplaceColorDark); + transition: width var(--transitionStyleButton); + } +} diff --git a/src/components/SelectMultipleFilter/SelectMultipleFilterForm.js b/src/components/SelectMultipleFilter/SelectMultipleFilterForm.js new file mode 100644 index 00000000..effcc2d6 --- /dev/null +++ b/src/components/SelectMultipleFilter/SelectMultipleFilterForm.js @@ -0,0 +1,98 @@ +import React from 'react'; +import { arrayOf, bool, func, node, object, shape, string } from 'prop-types'; +import classNames from 'classnames'; +import { compose } from 'redux'; +import { reduxForm, propTypes as formPropTypes } from 'redux-form'; +import { injectIntl, intlShape } from 'react-intl'; + +import { FieldGroupCheckbox, Form } from '../../components'; +import css from './SelectMultipleFilterForm.css'; + +const SelectMultipleFilterFormComponent = props => { + const { + form, + destroy, + reset, + handleSubmit, + onClear, + onCancel, + options, + isOpen, + contentRef, + style, + intl, + } = props; + const classes = classNames(css.root, { [css.isOpen]: isOpen }); + + const handleClear = () => { + // clear the redux form state + destroy(); + onClear(); + }; + + const handleCancel = () => { + // reset the redux form to initialValues + reset(); + onCancel(); + }; + + const clear = intl.formatMessage({ id: 'SelectMultipleFilterMobile.clear' }); + const cancel = intl.formatMessage({ id: 'SelectMultipleFilterMobile.cancel' }); + const submit = intl.formatMessage({ id: 'SelectMultipleFilterMobile.submit' }); + + return ( + + +
+ + + +
+ + ); +}; + +SelectMultipleFilterFormComponent.defaultProps = { + contentRef: null, + style: null, +}; + +SelectMultipleFilterFormComponent.propTypes = { + ...formPropTypes, + onClear: func.isRequired, + onCancel: func.isRequired, + options: arrayOf( + shape({ + key: string.isRequired, + label: node.isRequired, + }) + ).isRequired, + isOpen: bool.isRequired, + contentRef: func, + style: object, + + // form injectIntl + intl: intlShape.isRequired, +}; + +const defaultFormName = 'SelectMultipleFilterForm'; + +export default compose(reduxForm({ form: defaultFormName }), injectIntl)( + SelectMultipleFilterFormComponent +); diff --git a/src/components/index.js b/src/components/index.js index 49a14f0b..b581ac2b 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -107,6 +107,7 @@ export { default as SectionHowItWorks } from './SectionHowItWorks/SectionHowItWo export { default as SectionLocations } from './SectionLocations/SectionLocations'; export { default as SectionThumbnailLinks } from './SectionThumbnailLinks/SectionThumbnailLinks'; export { default as SelectField } from './SelectField/SelectField'; +export { default as SelectMultipleFilter } from './SelectMultipleFilter/SelectMultipleFilter'; export { default as SelectSingleFilter } from './SelectSingleFilter/SelectSingleFilter'; export { default as SelectSingleFilterMobile, diff --git a/src/examples.js b/src/examples.js index 76a51317..b91b8070 100644 --- a/src/examples.js +++ b/src/examples.js @@ -45,6 +45,7 @@ import * as ReviewRating from './components/ReviewRating/ReviewRating.example'; import * as Reviews from './components/Reviews/Reviews.example'; import * as SectionThumbnailLinks from './components/SectionThumbnailLinks/SectionThumbnailLinks.example'; import * as SelectField from './components/SelectField/SelectField.example'; +import * as SelectMultipleFilter from './components/SelectMultipleFilter/SelectMultipleFilter.example'; import * as StripeBankAccountTokenInputField from './components/StripeBankAccountTokenInputField/StripeBankAccountTokenInputField.example'; import * as TabNav from './components/TabNav/TabNav.example'; import * as TabNavHorizontal from './components/TabNavHorizontal/TabNavHorizontal.example'; @@ -136,6 +137,7 @@ export { Reviews, SectionThumbnailLinks, SelectField, + SelectMultipleFilter, SendMessageForm, SignupForm, StripeBankAccountTokenInputField, diff --git a/src/translations/en.json b/src/translations/en.json index 522e9ff3..3f20d517 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -518,6 +518,10 @@ "SectionLocations.listingsInLocation": "Saunas in {location}", "SectionLocations.subtitle": "We have more than 1000 saunas around Finland. Here are some of our most popular locations.", "SectionLocations.title": "We have wooden saunas, electric saunas, and even tent saunas.", + "SelectMultipleFilterMobile.label": "Amenities", + "SelectMultipleFilterMobile.clear": "Clear", + "SelectMultipleFilterMobile.cancel": "Cancel", + "SelectMultipleFilterMobile.submit": "Apply", "SelectSingleFilter.clear": "Clear", "SelectSingleFilterMobile.clear": "Clear", "SendMessageForm.sendFailed": "Failed to send. Please try again.", From a87a83094ab32acb92f41a7648f148dd1b3a738a Mon Sep 17 00:00:00 2001 From: Hannu Lyytikainen Date: Fri, 2 Feb 2018 16:10:14 +0200 Subject: [PATCH 4/6] Change filter lable styles if values are selected --- .../SelectMultipleFilter.css | 18 ++++++++++++++++++ .../SelectMultipleFilter.js | 13 ++++++++++--- src/translations/en.json | 1 + 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/components/SelectMultipleFilter/SelectMultipleFilter.css b/src/components/SelectMultipleFilter/SelectMultipleFilter.css index 3469efc8..67812d59 100644 --- a/src/components/SelectMultipleFilter/SelectMultipleFilter.css +++ b/src/components/SelectMultipleFilter/SelectMultipleFilter.css @@ -23,3 +23,21 @@ box-shadow: var(--boxShadowFilterButton); } } + +.labelSelected { + @apply --marketplaceButtonStyles; + @apply --marketplaceSearchFilterLabelFontStyles; + font-weight: var(--fontWeightSemiBold); + + padding: 9px 16px 10px 16px; + width: auto; + height: auto; + min-height: 0; + border-radius: 4px; + border: 1px solid var(--marketplaceColor); + + &:hover, + &:focus { + border: 1px solid var(--marketplaceColorDark); + } +} diff --git a/src/components/SelectMultipleFilter/SelectMultipleFilter.js b/src/components/SelectMultipleFilter/SelectMultipleFilter.js index e93d4fad..d7d9e656 100644 --- a/src/components/SelectMultipleFilter/SelectMultipleFilter.js +++ b/src/components/SelectMultipleFilter/SelectMultipleFilter.js @@ -30,7 +30,6 @@ const valuesToKeys = values => { return entries.filter(entry => entry[1] === true).map(entry => entry[0]); }; - class SelectMultipleFilter extends Component { constructor(props) { super(props); @@ -115,7 +114,15 @@ class SelectMultipleFilter extends Component { const { rootClassName, className, options, initialValues, intl } = this.props; const classes = classNames(rootClassName || css.root, className); - const label = intl.formatMessage({ id: 'SelectMultipleFilterMobile.label' }); + const hasInitialValues = initialValues.length > 0; + const labelStyles = hasInitialValues ? css.labelSelected : css.label; + const label = hasInitialValues + ? intl.formatMessage( + { id: 'SelectMultipleFilterMobile.labelSelected' }, + { count: initialValues.length } + ) + : intl.formatMessage({ id: 'SelectMultipleFilterMobile.label' }); + const contentStyle = this.positionStyleForContent(); return ( @@ -127,7 +134,7 @@ class SelectMultipleFilter extends Component { this.filter = node; }} > - Date: Fri, 2 Feb 2018 20:07:13 +0200 Subject: [PATCH 5/6] Add prop validation for filter offset --- src/components/SelectMultipleFilter/SelectMultipleFilter.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/SelectMultipleFilter/SelectMultipleFilter.js b/src/components/SelectMultipleFilter/SelectMultipleFilter.js index d7d9e656..a523295d 100644 --- a/src/components/SelectMultipleFilter/SelectMultipleFilter.js +++ b/src/components/SelectMultipleFilter/SelectMultipleFilter.js @@ -1,5 +1,5 @@ import React, { Component } from 'react'; -import { arrayOf, func, node, shape, string } from 'prop-types'; +import { arrayOf, func, node, number, shape, string } from 'prop-types'; import classNames from 'classnames'; import { injectIntl, intlShape } from 'react-intl'; import { toPairs } from 'lodash'; @@ -160,6 +160,7 @@ SelectMultipleFilter.defaultProps = { rootClassName: null, className: null, initialValues: [], + contentPlacementOffset: 0, }; SelectMultipleFilter.propTypes = { @@ -173,6 +174,7 @@ SelectMultipleFilter.propTypes = { }) ).isRequired, initialValues: arrayOf(string), + contentPlacementOffset: number, // form injectIntl intl: intlShape.isRequired, From 078d7700b24d78383ab6d4deb9079ca4d2b8e752 Mon Sep 17 00:00:00 2001 From: Hannu Lyytikainen Date: Mon, 5 Feb 2018 10:52:42 +0200 Subject: [PATCH 6/6] Remove shape validation for options The shape correctness is validated in the child component. --- .../SelectMultipleFilter/SelectMultipleFilter.js | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/components/SelectMultipleFilter/SelectMultipleFilter.js b/src/components/SelectMultipleFilter/SelectMultipleFilter.js index a523295d..627232c2 100644 --- a/src/components/SelectMultipleFilter/SelectMultipleFilter.js +++ b/src/components/SelectMultipleFilter/SelectMultipleFilter.js @@ -1,5 +1,5 @@ import React, { Component } from 'react'; -import { arrayOf, func, node, number, shape, string } from 'prop-types'; +import { array, arrayOf, func, number, string } from 'prop-types'; import classNames from 'classnames'; import { injectIntl, intlShape } from 'react-intl'; import { toPairs } from 'lodash'; @@ -167,12 +167,7 @@ SelectMultipleFilter.propTypes = { rootClassName: string, className: string, onSubmit: func.isRequired, - options: arrayOf( - shape({ - key: string.isRequired, - label: node.isRequired, - }) - ).isRequired, + options: array.isRequired, initialValues: arrayOf(string), contentPlacementOffset: number,