Skip to content

Commit 77d7ae0

Browse files
authored
Merge pull request #431 from reactioncommerce/feat-aldeed-latest-reacto-form
feat: update to latest reacto-form and react pkgs
2 parents 3c4214d + e3be63f commit 77d7ae0

File tree

9 files changed

+403
-376
lines changed

9 files changed

+403
-376
lines changed

package.json

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -91,13 +91,13 @@
9191
"dependencies": {
9292
"@babel/polyfill": "~7.2.5",
9393
"@reactioncommerce/components-context": "~1.2.0",
94-
"lodash": "4.17.14",
95-
"prop-types": "~15.6.2",
96-
"react": "~16.4.2",
94+
"lodash": "~4.17.15",
95+
"prop-types": "~15.7.2",
96+
"react": "~16.9.0",
9797
"react-container-query": "~0.11.0",
98-
"react-dom": "~16.4.2",
98+
"react-dom": "~16.9.0",
9999
"react-stripe-elements": "~2.0.1",
100-
"reacto-form": "~0.0.2",
100+
"reacto-form": "~1.4.0",
101101
"styled-components": "~3.3.3"
102102
},
103103
"devDependencies": {
@@ -131,7 +131,7 @@
131131
"case-sensitive-paths-webpack-plugin": "~2.1.2",
132132
"chalk": "~1.1.3",
133133
"check-prop-types": "~1.1.2",
134-
"composable-form-tests": "~1.0.0",
134+
"composable-form-tests": "~1.0.1",
135135
"css-loader": "~0.28.11",
136136
"dotenv": "~4.0.0",
137137
"dotenv-expand": "~4.0.1",
@@ -159,9 +159,9 @@
159159
"postcss-loader": "~2.0.8",
160160
"promise": "~8.0.2",
161161
"raf": "~3.4.1",
162-
"react-dev-utils": "~7.0.1",
163-
"react-styleguidist": "9.1.11",
164-
"react-test-renderer": "~16.7.0",
162+
"react-dev-utils": "~9.0.1",
163+
"react-styleguidist": "~9.1.14",
164+
"react-test-renderer": "~16.9.0",
165165
"replace-in-files": "~1.1.4",
166166
"rimraf": "~2.6.3",
167167
"semantic-release": "~15.13.3",

package/package.json

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
"lodash.isequal": "~4.5.0",
3131
"lodash.uniqueid": "~4.0.1",
3232
"mdi-material-ui": "~5.8.0",
33-
"react-is": "~16.4.1",
33+
"react-is": "~16.9.0",
3434
"react-select": "~2.4.0"
3535
},
3636
"devDependencies": {
@@ -60,7 +60,7 @@
6060
"babel-plugin-styled-components": "~1.10.0",
6161
"chalk": "~1.1.3",
6262
"check-prop-types": "~1.1.2",
63-
"composable-form-tests": "~1.0.0",
63+
"composable-form-tests": "~1.0.1",
6464
"dotenv": "~4.0.0",
6565
"dotenv-expand": "~4.0.1",
6666
"enzyme": "~3.8.0",
@@ -79,9 +79,9 @@
7979
"object-assign": "~4.1.1",
8080
"promise": "~8.0.2",
8181
"raf": "~3.4.1",
82-
"react-dev-utils": "~7.0.1",
82+
"react-dev-utils": "~9.0.1",
8383
"react-styleguidist": "~6.5.3",
84-
"react-test-renderer": "~16.7.0",
84+
"react-test-renderer": "~16.9.0",
8585
"replace-in-files": "~1.1.4",
8686
"rimraf": "~2.6.3",
8787
"semantic-release": "~15.13.3",
@@ -92,11 +92,11 @@
9292
},
9393
"peerDependencies": {
9494
"@reactioncommerce/components-context": "~1.2.0",
95-
"prop-types": "~15.6.2",
96-
"react": "~16.4.2",
95+
"prop-types": "~15.7.2",
96+
"react": "~16.9.0",
9797
"react-container-query": "~0.11.0",
9898
"react-stripe-elements": "~2.0.1",
99-
"reacto-form": "~0.0.2",
99+
"reacto-form": "~1.4.0",
100100
"styled-components": "~3.3.3"
101101
}
102102
}
Lines changed: 133 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import React, { Component } from "react";
1+
import React, { forwardRef, useImperativeHandle, useRef, useState } from "react";
22
import PropTypes from "prop-types";
3-
import { Form } from "reacto-form";
3+
import { useReactoForm } from "reacto-form";
44
import { uniqueId } from "lodash";
55
import { withComponents } from "@reactioncommerce/components-context";
66
import { CustomPropTypes } from "../../../utils";
@@ -11,7 +11,7 @@ import { CustomPropTypes } from "../../../utils";
1111
* @param {Object} Form object
1212
* @returns {Object} Transformed object
1313
*/
14-
function buildResult({ amount, fullName }) {
14+
function buildResult({ amount, fullName = null }) {
1515
let floatAmount = amount ? parseFloat(amount) : null;
1616
if (isNaN(floatAmount)) floatAmount = null;
1717

@@ -22,128 +22,145 @@ function buildResult({ amount, fullName }) {
2222
};
2323
}
2424

25-
class ExampleIOUPaymentForm extends Component {
26-
static propTypes = {
27-
/**
28-
* You can provide a `className` prop that will be applied to the outermost DOM element
29-
* rendered by this component. We do not recommend using this for styling purposes, but
30-
* it can be useful as a selector in some situations.
31-
*/
32-
className: PropTypes.string,
33-
/**
34-
* If you've set up a components context using
35-
* [@reactioncommerce/components-context](https://github.com/reactioncommerce/components-context)
36-
* (recommended), then this prop will come from there automatically. If you have not
37-
* set up a components context or you want to override one of the components in a
38-
* single spot, you can pass in the components prop directly.
39-
*/
40-
components: PropTypes.shape({
41-
/**
42-
* Pass either the Reaction ErrorsBlock component or your own component that
43-
* accepts compatible props.
44-
*/
45-
ErrorsBlock: CustomPropTypes.component.isRequired,
46-
/**
47-
* Pass either the Reaction Field component or your own component that
48-
* accepts compatible props.
49-
*/
50-
Field: CustomPropTypes.component.isRequired,
51-
/**
52-
* Pass either the Reaction TextInput component or your own component that
53-
* accepts compatible props.
54-
*/
55-
TextInput: CustomPropTypes.component.isRequired
56-
}),
57-
/**
58-
* Pass true while the input data is in the process of being saved.
59-
* While true, the form fields are disabled.
60-
*/
61-
isSaving: PropTypes.bool,
62-
/**
63-
* Called as the form fields are changed
64-
*/
65-
onChange: PropTypes.func,
66-
/**
67-
* When this action's input data switches between being
68-
* ready for saving and not ready for saving, this will
69-
* be called with `true` (ready) or `false`
70-
*/
71-
onReadyForSaveChange: PropTypes.func,
72-
/**
73-
* Called with an object value when this component's `submit`
74-
* method is called. The object may have `data`, `displayName`,
75-
* and `amount` properties.
76-
*/
77-
onSubmit: PropTypes.func
78-
}
25+
/**
26+
* @summary ExampleIOUPaymentForm component
27+
* @param {Object} props Props
28+
* @param {Object} ref Ref
29+
* @return {Object} React render
30+
*/
31+
function ExampleIOUPaymentForm(props, ref) {
32+
const lastDocRef = useRef();
33+
const isReadyRef = useRef();
7934

80-
static defaultProps = {
81-
onChange() {},
82-
onReadyForSaveChange() {},
83-
onSubmit() {}
84-
};
35+
const [uniqueInstanceIdentifier, setUniqueInstanceIdentifier] = useState();
36+
if (!uniqueInstanceIdentifier) {
37+
setUniqueInstanceIdentifier(uniqueId("ExampleIOUPaymentForm"));
38+
}
8539

86-
uniqueInstanceIdentifier = uniqueId("ExampleIOUPaymentForm");
40+
const {
41+
className,
42+
components: {
43+
ErrorsBlock,
44+
Field,
45+
TextInput
46+
},
47+
isSaving,
48+
onChange,
49+
onReadyForSaveChange,
50+
onSubmit
51+
} = props;
8752

88-
submit() {
89-
if (this.form) this.form.submit();
90-
}
53+
const {
54+
getErrors,
55+
getInputProps,
56+
submitForm
57+
} = useReactoForm({
58+
isReadOnly: isSaving,
59+
onChange(formData) {
60+
const resultDoc = buildResult(formData);
61+
const stringDoc = JSON.stringify(resultDoc);
62+
if (stringDoc !== lastDocRef.current) {
63+
onChange(resultDoc);
64+
}
65+
lastDocRef.current = stringDoc;
9166

92-
handleChange = (doc) => {
93-
const { onChange, onReadyForSaveChange } = this.props;
67+
const isReady = !!formData.fullName;
68+
if (isReady !== isReadyRef.current) {
69+
onReadyForSaveChange(isReady);
70+
}
71+
isReadyRef.current = isReady;
72+
},
73+
onSubmit: (formData) => onSubmit(buildResult(formData))
74+
});
9475

95-
const resultDoc = buildResult(doc);
96-
const stringDoc = JSON.stringify(resultDoc);
97-
if (stringDoc !== this.lastDoc) {
98-
onChange(resultDoc);
76+
useImperativeHandle(ref, () => ({
77+
submit() {
78+
submitForm();
9979
}
100-
this.lastDoc = stringDoc;
80+
}));
10181

102-
const isReady = !!doc.fullName;
103-
if (isReady !== this.lastIsReady) {
104-
onReadyForSaveChange(isReady);
105-
}
106-
this.lastIsReady = isReady;
107-
}
82+
const fullNameInputId = `fullName_${uniqueInstanceIdentifier}`;
83+
const amountInputId = `amount_${uniqueInstanceIdentifier}`;
10884

109-
handleSubmit = (doc) => {
110-
const { onSubmit } = this.props;
111-
return onSubmit(buildResult(doc));
112-
}
85+
return (
86+
<div className={className}>
87+
<Field name="fullName" errors={getErrors(["fullName"])} label="Full name" labelFor={fullNameInputId}>
88+
<TextInput id={fullNameInputId} {...getInputProps("fullName")} />
89+
<ErrorsBlock errors={getErrors(["fullName"])} />
90+
</Field>
91+
<Field name="amount" errors={getErrors(["amount"])} label="Amount (optional)" labelFor={amountInputId}>
92+
<TextInput id={amountInputId} {...getInputProps("amount")} />
93+
<ErrorsBlock errors={getErrors(["amount"])} />
94+
</Field>
95+
</div>
96+
);
97+
}
11398

114-
render() {
115-
const {
116-
className,
117-
components: {
118-
ErrorsBlock,
119-
Field,
120-
TextInput
121-
},
122-
isSaving
123-
} = this.props;
99+
// There is currently some issue with combining hoist-non-react-statics (used by
100+
// withComponents) with forwardRef. Until that's resolved, reassigning
101+
// ExampleIOUPaymentForm to the wrapped component here, before setting the statics.
102+
/* eslint-disable-next-line no-func-assign */
103+
ExampleIOUPaymentForm = withComponents(forwardRef(ExampleIOUPaymentForm));
124104

125-
const fullNameInputId = `fullName_${this.uniqueInstanceIdentifier}`;
126-
const amountInputId = `amount_${this.uniqueInstanceIdentifier}`;
105+
ExampleIOUPaymentForm.propTypes = {
106+
/**
107+
* You can provide a `className` prop that will be applied to the outermost DOM element
108+
* rendered by this component. We do not recommend using this for styling purposes, but
109+
* it can be useful as a selector in some situations.
110+
*/
111+
className: PropTypes.string,
112+
/**
113+
* If you've set up a components context using
114+
* [@reactioncommerce/components-context](https://github.com/reactioncommerce/components-context)
115+
* (recommended), then this prop will come from there automatically. If you have not
116+
* set up a components context or you want to override one of the components in a
117+
* single spot, you can pass in the components prop directly.
118+
*/
119+
components: PropTypes.shape({
120+
/**
121+
* Pass either the Reaction ErrorsBlock component or your own component that
122+
* accepts compatible props.
123+
*/
124+
ErrorsBlock: CustomPropTypes.component.isRequired,
125+
/**
126+
* Pass either the Reaction Field component or your own component that
127+
* accepts compatible props.
128+
*/
129+
Field: CustomPropTypes.component.isRequired,
130+
/**
131+
* Pass either the Reaction TextInput component or your own component that
132+
* accepts compatible props.
133+
*/
134+
TextInput: CustomPropTypes.component.isRequired
135+
}),
136+
/**
137+
* Pass true while the input data is in the process of being saved.
138+
* While true, the form fields are disabled.
139+
*/
140+
isSaving: PropTypes.bool,
141+
/**
142+
* Called as the form fields are changed
143+
*/
144+
onChange: PropTypes.func,
145+
/**
146+
* When this action's input data switches between being
147+
* ready for saving and not ready for saving, this will
148+
* be called with `true` (ready) or `false`
149+
*/
150+
onReadyForSaveChange: PropTypes.func,
151+
/**
152+
* Called with an object value when this component's `submit`
153+
* method is called. The object may have `data`, `displayName`,
154+
* and `amount` properties.
155+
*/
156+
onSubmit: PropTypes.func
157+
};
127158

128-
return (
129-
<Form
130-
className={className}
131-
isReadOnly={isSaving}
132-
onChange={this.handleChange}
133-
onSubmit={this.handleSubmit}
134-
ref={(formRef) => { this.form = formRef; }}
135-
>
136-
<Field name="fullName" label="Full name" labelFor={fullNameInputId}>
137-
<TextInput id={fullNameInputId} name="fullName" />
138-
<ErrorsBlock names={["fullName"]} />
139-
</Field>
140-
<Field name="amount" label="Amount (optional)" labelFor={amountInputId}>
141-
<TextInput id={amountInputId} name="amount" />
142-
<ErrorsBlock names={["amount"]} />
143-
</Field>
144-
</Form>
145-
);
146-
}
147-
}
159+
ExampleIOUPaymentForm.defaultProps = {
160+
isSaving: false,
161+
onChange() {},
162+
onReadyForSaveChange() {},
163+
onSubmit() {}
164+
};
148165

149-
export default withComponents(ExampleIOUPaymentForm);
166+
export default ExampleIOUPaymentForm;

package/src/components/ExampleIOUPaymentForm/v1/ExampleIOUPaymentForm.test.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,7 @@ test("calls onChange on mount and change", () => {
4242
</ComponentsProvider>
4343
));
4444

45-
expect(onChange).toHaveBeenCalledTimes(1);
46-
expect(onChange).toHaveBeenLastCalledWith({
45+
expect(onChange).toHaveBeenCalledWith({
4746
amount: null,
4847
data: { fullName: null },
4948
displayName: null
Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

33
exports[`basic snapshot 1`] = `
4-
<div
5-
className={null}
6-
style={Object {}}
7-
>
8-
Field({"name":"fullName","label":"Full name","labelFor":"fullName_ExampleIOUPaymentForm1","children":"[Object]"})
9-
Field({"name":"amount","label":"Amount (optional)","labelFor":"amount_ExampleIOUPaymentForm1","children":"[Object]"})
4+
<div>
5+
Field({"name":"fullName","errors":"[Object]","label":"Full name","labelFor":"fullName_ExampleIOUPaymentForm1","children":"[Object]"})
6+
Field({"name":"amount","errors":"[Object]","label":"Amount (optional)","labelFor":"amount_ExampleIOUPaymentForm1","children":"[Object]"})
107
</div>
118
`;

0 commit comments

Comments
 (0)