Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(regioninput): add RegionInput component, use in AddressForm #354

Merged
merged 8 commits into from Nov 2, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
45 changes: 19 additions & 26 deletions package/src/components/AddressForm/v1/AddressForm.js
Expand Up @@ -74,7 +74,12 @@ class AddressForm extends Component {
* Pass either the Reaction PhoneNumberInput component or your own component that is
* compatible with ReactoForm.
*/
PhoneNumberInput: CustomPropTypes.component.isRequired
PhoneNumberInput: CustomPropTypes.component.isRequired,
/**
* Pass either the Reaction RegionInput component or your own component that is
* compatible with ReactoForm.
*/
RegionInput: CustomPropTypes.component.isRequired
}).isRequired,
/**
* Errors array
Expand Down Expand Up @@ -107,7 +112,7 @@ class AddressForm extends Component {
continent: PropTypes.string,
capital: PropTypes.string,
currency: PropTypes.string,
languges: PropTypes.string,
languages: PropTypes.string,
states: PropTypes.objectOf(PropTypes.shape({ name: PropTypes.string }))
})),
/**
Expand Down Expand Up @@ -151,9 +156,9 @@ class AddressForm extends Component {
isOnDarkBackground: false,
isSaving: false,
name: "address",
onCancel() {},
onChange() {},
onSubmit() {},
onCancel() { },
onChange() { },
onSubmit() { },
shouldShowAddressNameField: false,
shouldShowIsCommercialField: false,
validator: getRequiredValidator(
Expand Down Expand Up @@ -258,7 +263,7 @@ class AddressForm extends Component {
addressNamePlaceholder,
value,
className,
components: { Checkbox, ErrorsBlock, Field, TextInput, Select, PhoneNumberInput },
components: { Checkbox, ErrorsBlock, Field, TextInput, Select, PhoneNumberInput, RegionInput },
errors,
isOnDarkBackground,
isSaving,
Expand Down Expand Up @@ -389,26 +394,14 @@ class AddressForm extends Component {

<ColHalf>
<Field name="region" label="Region" labelFor={regionInputId} isRequired>
{this.regionOptions && this.regionOptions.length > 1 ? (
<Select
id={regionInputId}
alphabetize
isSearchable
name="region"
options={this.regionOptions}
placeholder="Region"
isOnDarkBackground={isOnDarkBackground}
isReadOnly={isSaving}
/>
) : (
<TextInput
id={regionInputId}
name="region"
placeholder="Region"
isOnDarkBackground={isOnDarkBackground}
isReadOnly={isSaving}
/>
)}
<RegionInput
id={regionInputId}
options={this.regionOptions}
isOnDarkBackground={isOnDarkBackground}
isReadOnly={isSaving}
name="region"
placeholder="Region"
/>
<ErrorsBlock names={["region"]} />
</Field>
</ColHalf>
Expand Down
81 changes: 81 additions & 0 deletions package/src/components/RegionInput/v1/RegionInput.js
@@ -0,0 +1,81 @@
import React, { Component, Fragment } from "react";
import PropTypes from "prop-types";
import { withComponents } from "@reactioncommerce/components-context";
import { CustomPropTypes } from "../../../utils";

class RegionInput extends Component {
static propTypes = {
/**
* You can provide a `className` prop that will be applied to the outermost DOM element
* rendered by this component. We do not recommend using this for styling purposes, but
* it can be useful as a selector in some situations.
*/
className: PropTypes.string,
/**
* If you've set up a components context using
* [@reactioncommerce/components-context](https://github.com/reactioncommerce/components-context)
* (recommended), then this prop will come from there automatically. If you have not
* set up a components context or you want to override one of the components in a
* single spot, you can pass in the components prop directly.
*/
components: PropTypes.shape({
/**
* Pass either the Reaction TextInput component or your own component that is
* compatible with ReactoForm.
*/
TextInput: CustomPropTypes.component.isRequired,
/**
* Pass either the Reaction Select component or your own component that is
* compatible with ReactoForm.
*/
Select: CustomPropTypes.component.isRequired
}).isRequired,
/**
* Name of input
*/
name: PropTypes.string.isRequired,
/**
* Region options to populate the form's region fields
*/
options: PropTypes.array,
/**
* Prepopulate the input's value
*/
value: PropTypes.string
aldeed marked this conversation as resolved.
Show resolved Hide resolved
};

render() {
const {
className,
components: { Select, TextInput },
options,
value,
...props
} = this.props;

return (
<Fragment>
{
options && options.length > 1 ? (
<Select
className={className}
alphabetize
isSearchable
options={options}
value={value}
{...props}
/>
) : (
<TextInput
className={className}
value={value}
{...props}
/>
)
}
</Fragment>
);
}
}

export default withComponents(RegionInput);
86 changes: 86 additions & 0 deletions package/src/components/RegionInput/v1/RegionInput.md
@@ -0,0 +1,86 @@
### Overview

The `RegionInput` component renders either a `Select` or `TextInput`, based on the number of region options.

### Usage

Use the `RegionInput` in a form with country and region locales. In the `AddressForm` component, for example, the form's `activeCountry` state, set by the country select, will trigger the `RegionInput` to appear as a plain text input or a dropdown of regions specified in a locale object or file.

Pass any related form input props, like `isReadOnly`, `placeholder`, `maxLength`, `name`, `id` and more through from the parent component into `RegionInput`. See [Select](./#!/Select) and [TextInput](./#!/TextInput) for more props.

#### With a value in a TextInput

```jsx
<RegionInput name="region" isOnDarkBackground isReadOnly value="California" />
```

#### With a value in a Select

```jsx
const options = [
{
"value": "AA",
"label": "A State"
},
{
"value": "BB",
"label": "B State"
}
];

<RegionInput name="region" options={options} value="BB" />
```

#### Implemented in an AddressForm

```jsx
const locales = {
"NR": {
"name": "Country Without Regions",
},
"WR": {
"name": "Country With Regions",
"states": {
"AA": {
"name": "A State"
},
"BB": {
"name": "B State"
}
}
}
};

class AddressExample extends React.Component {
constructor(props) {
super(props);
this._addressForm;
this.bindForm.bind(this);
}

bindForm(formEl) {
if (formEl) {
this._addressForm = formEl;
}
}

render() {
return (
<div>
<AddressForm
locales={locales}
ref={(formEl) => { this.bindForm(formEl) }}
onSubmit={(address) => console.log("Address submitted", address)}
/>
<Button onClick={() => this._addressForm.submit()}>Submit</Button>
</div>
);
}
}

<AddressExample />
```

### Theme

Refer to [Select](./#!/Select), [TextInput](./#!/TextInput) and [AddressForm](./#!/AddressForm) themes.
61 changes: 61 additions & 0 deletions package/src/components/RegionInput/v1/RegionInput.test.js
@@ -0,0 +1,61 @@
import React from "react";
import renderer from "react-test-renderer";
import mockComponents from "../../../tests/mockComponents";
import RegionInput from "./RegionInput";

test("basic snapshot with only the components and required props should render a TextInput", () => {
const component = renderer.create(<RegionInput name="region" components={mockComponents} />);

const tree = component.toJSON();
expect(tree).toMatchSnapshot();
});

test("basic snapshot with other form props", () => {
const component = renderer.create(<RegionInput components={mockComponents} value="California" name="region" isReadOnly />);

const tree = component.toJSON();
expect(tree).toMatchSnapshot();
});

test("basic snapshot with pre-filled value in TextInput", () => {
const component = renderer.create(<RegionInput name="region" components={mockComponents} value="California"/>);

const tree = component.toJSON();
expect(tree).toMatchSnapshot();
});

test("basic snapshot with pre-filled value in Select", () => {
const options = [
{
value: "AA",
label: "A State"
},
{
value: "BB",
label: "B State"
}
];

const component = renderer.create(<RegionInput name="region" components={mockComponents} options={options} value="BB"/>);

const tree = component.toJSON();
expect(tree).toMatchSnapshot();
});

test("basic snapshot with options should render a Select", () => {
const options = [
{
value: "AA",
label: "A State"
},
{
value: "BB",
label: "B State"
}
];

const component = renderer.create(<RegionInput name="region" components={mockComponents} options={options}/>);

const tree = component.toJSON();
expect(tree).toMatchSnapshot();
});
@@ -0,0 +1,11 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`basic snapshot with only the components and required props should render a TextInput 1`] = `"TextInput(undefined)"`;

exports[`basic snapshot with options should render a Select 1`] = `"Select(undefined)"`;

exports[`basic snapshot with other form props 1`] = `"TextInput(undefined)"`;

exports[`basic snapshot with pre-filled value in Select 1`] = `"Select(undefined)"`;

exports[`basic snapshot with pre-filled value in TextInput 1`] = `"TextInput(undefined)"`;
1 change: 1 addition & 0 deletions package/src/components/RegionInput/v1/index.js
@@ -0,0 +1 @@
export { default } from "./RegionInput";
1 change: 1 addition & 0 deletions package/src/tests/mockComponents.js
Expand Up @@ -60,6 +60,7 @@ function stringifyJSONCircularSafe(obj) {
"ProgressiveImage",
"ProfileImage",
"QuantityInput",
"RegionInput",
"Select",
"StockWarning",
"TextInput",
Expand Down
1 change: 1 addition & 0 deletions styleguide.config.js
Expand Up @@ -421,6 +421,7 @@ module.exports = {
"ErrorsBlock",
"Field",
"PhoneNumberInput",
"RegionInput",
"QuantityInput",
"Select",
"SelectableItem",
Expand Down
2 changes: 2 additions & 0 deletions styleguide/src/appComponents.js
Expand Up @@ -38,6 +38,7 @@ import Price from "../../package/src/components/Price/v1";
import ProfileImage from "../../package/src/components/ProfileImage/v1";
import ProgressiveImage from "../../package/src/components/ProgressiveImage/v1";
import QuantityInput from "../../package/src/components/QuantityInput/v1";
import RegionInput from "../../package/src/components/RegionInput/v1";
import Select from "../../package/src/components/Select/v1";
import StockWarning from "../../package/src/components/StockWarning/v1";
import StripeForm from "../../package/src/components/StripeForm/v1";
Expand Down Expand Up @@ -91,6 +92,7 @@ export default {
ProfileImage,
ProgressiveImage,
QuantityInput,
RegionInput,
Select,
spinner,
StockWarning,
Expand Down
4 changes: 4 additions & 0 deletions styleguide/src/sections/InstallingandImporting.md
Expand Up @@ -57,6 +57,7 @@ import CheckoutActionComplete from "@reactioncommerce/components/CheckoutActionC
import CheckoutActionIncomplete from "@reactioncommerce/components/CheckoutActionIncomplete/v1";
import ErrorsBlock from "@reactioncommerce/components/ErrorsBlock/v1";
import Field from "@reactioncommerce/components/Field/v1";
import InlineAlert from "@reactioncommerce/components/InlineAlert/v1";
import InPageMenuItem from "@reactioncommerce/components/InPageMenuItem/v1";
import Link from "@reactioncommerce/components/Link/v1";
import MiniCartSummary from "@reactioncommerce/components/MiniCartSummary/v1";
Expand All @@ -65,6 +66,7 @@ import Price from "@reactioncommerce/components/Price/v1";
import ProfileImage from "@reactioncommerce/components/ProfileImage/v1";
import ProgressiveImage from "@reactioncommerce/components/ProgressiveImage/v1";
import QuantityInput from "@reactioncommerce/components/QuantityInput/v1";
import RegionInput from "@reactioncommerce/components/RegionInput/v1";
import Select from "@reactioncommerce/components/Select/v1";
import StockWarning from "@reactioncommerce/components/StockWarning/v1";
import StripeForm from "@reactioncommerce/components/StripeForm/v1";
Expand Down Expand Up @@ -103,6 +105,7 @@ export default {
iconLock,
iconMastercard,
iconVisa,
InlineAlert,
InPageMenuItem,
Link,
MiniCartSummary,
Expand All @@ -111,6 +114,7 @@ export default {
ProfileImage,
ProgressiveImage,
QuantityInput,
RegionInput,
Select,
spinner,
StockWarning,
Expand Down