Skip to content

Commit 4bb7cf8

Browse files
Merge pull request #27 from iusehooks/ADD_INNER_REF_AND_SETVALUE_CUSTOM_CMP
innerRef - setValue for type='custom'
2 parents e0717d1 + 4b9b826 commit 4bb7cf8

29 files changed

+275
-93
lines changed

__tests__/Form.spec.js

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
import React from "react";
2-
import { render, cleanup, fireEvent, waitFor } from "@testing-library/react";
2+
import {
3+
render,
4+
cleanup,
5+
fireEvent,
6+
waitFor,
7+
act
8+
} from "@testing-library/react";
39

410
import { SimpleFormTestSumbission } from "./helpers/components/SimpleFormTestSumbission";
511
import { CollectionDynamicCart } from "./helpers/components/CollectionDynamicField";
@@ -12,7 +18,7 @@ import {
1218
} from "./helpers/components/ComplexForm";
1319
import { mountForm } from "./helpers/utils/mountForm";
1420

15-
import { Input, Select, Collection, TextArea } from "./../src";
21+
import { Input, Select, Collection, TextArea, Form } from "./../src";
1622

1723
const dataTestid = "email";
1824
const typeInput = "text";
@@ -514,6 +520,18 @@ describe("Component => Form", () => {
514520
);
515521
});
516522

523+
it("should accept an innerRef prop to access to DOM", () => {
524+
const name = "foo";
525+
const ref = React.createRef();
526+
527+
act(() => {
528+
render(<Form innerRef={ref} name={name} />);
529+
});
530+
531+
expect(ref.current).toBeDefined();
532+
expect(ref.current.name).toBe(name);
533+
});
534+
517535
it("should run reducer functions applied to Form on fields removal", () => {
518536
const reducers = jest.fn(value => {
519537
const { cart = {} } = value;

__tests__/Input.spec.js

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,23 @@ describe("Component => Input", () => {
180180
expect(fileInputMultiple.files[1]).toStrictEqual(files[1]);
181181
});
182182

183+
it("should accept an innerRef prop to access to DOM", () => {
184+
const type = "text";
185+
const name = "email";
186+
const ref = React.createRef();
187+
const children = [
188+
<Input key="1" innerRef={ref} type={type} name={name} value="1" />
189+
];
190+
act(() => {
191+
mountForm({ children });
192+
});
193+
194+
expect(ref.current).toBeDefined();
195+
expect(ref.current.type).toBe(type);
196+
expect(ref.current.value).toBe("1");
197+
expect(ref.current.name).toBe(name);
198+
});
199+
183200
it("should trigger onChange event when the Input value changes", () => {
184201
const onChangeInput = jest.fn(value => value);
185202
const children = [
@@ -518,11 +535,7 @@ describe("Component => Input", () => {
518535
expect(checkbox.checked).toBe(true);
519536

520537
onInit.mockClear();
521-
children = [<Input key="1" type="custom" name={name} value={{ a: 1 }} />];
522-
mountForm({ props, children });
523-
expect(onInit).toHaveBeenCalledWith({ [name]: { a: 1 } }, true);
524538

525-
onInit.mockClear();
526539
children = [
527540
<Input
528541
key="1"

__tests__/Select.spec.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,26 @@ describe("Component => Select", () => {
126126
expect(onReset).toHaveBeenCalledWith({ [name]: ["1", "2"] }, true);
127127
});
128128

129+
it("should accept an innerRef prop to access to DOM", () => {
130+
const name = "test";
131+
const value = "1";
132+
const ref = React.createRef();
133+
const children = [
134+
<Select key="1" innerRef={ref} name={name} value={value}>
135+
<option value="" />
136+
<option value={value}>{value}</option>
137+
</Select>
138+
];
139+
140+
act(() => {
141+
mountForm({ children });
142+
});
143+
144+
expect(ref.current).toBeDefined();
145+
expect(ref.current.value).toBe("1");
146+
expect(ref.current.name).toBe(name);
147+
});
148+
129149
it("should use a reducer to reduce the Select value", () => {
130150
const props = { onInit };
131151
const reducer = value => value + 2;

__tests__/TextArea.spec.js

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React from "react";
2-
import { fireEvent, cleanup } from "@testing-library/react";
2+
import { fireEvent, cleanup, act } from "@testing-library/react";
33
import { mountForm } from "./helpers/utils/mountForm";
44
import { TextArea } from "./../src";
55

@@ -29,4 +29,22 @@ describe("Component => TextArea", () => {
2929
expect(onChange).toHaveBeenCalledWith({ [name]: value }, true);
3030
expect(textArea.value).toBe(value);
3131
});
32+
33+
it("should accept an innerRef prop to access to DOM", () => {
34+
const type = "textarea";
35+
const name = "foo";
36+
const ref = React.createRef();
37+
const children = [
38+
<TextArea key="1" innerRef={ref} name={name} value="1" />
39+
];
40+
41+
act(() => {
42+
mountForm({ children });
43+
});
44+
45+
expect(ref.current).toBeDefined();
46+
expect(ref.current.type).toBe(type);
47+
expect(ref.current.value).toBe("1");
48+
expect(ref.current.name).toBe(name);
49+
});
3250
});

__tests__/helpers/components/CustomField.jsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,13 @@ export const CustomField = withIndex(
1010
valueToChange = "5"
1111
}) => {
1212
const props = useField({ type, name, value });
13-
const onChange = () => props.onChange({ target: { value: valueToChange } });
13+
const onChange = () => {
14+
if (type === "custom") {
15+
props.setValue(valueToChange);
16+
} else {
17+
props.onChange({ target: { value: valueToChange } });
18+
}
19+
};
1420
useEffect(() => {
1521
jestFN(props.value);
1622
}, []);

__tests__/hooks/useField.spec.js

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,18 @@ describe("Hooks => useField", () => {
5555
const props = { onInit, onChange };
5656
const initial = { a: "test" };
5757
const jestFN = jest.fn();
58+
const valueToChange = prev => {
59+
return { ...prev, a: "BeBo" };
60+
};
5861

5962
const children = [
60-
<CustomField key="1" name={name} value={initial} jestFN={jestFN} />
63+
<CustomField
64+
key="1"
65+
valueToChange={valueToChange}
66+
name={name}
67+
value={initial}
68+
jestFN={jestFN}
69+
/>
6170
];
6271
const { getByTestId } = mountForm({ children, props });
6372

@@ -70,7 +79,7 @@ describe("Hooks => useField", () => {
7079
fireEvent.click(buttonChange);
7180
});
7281

73-
expect(onChange).toHaveBeenCalledWith({ [name]: "5" }, true);
82+
expect(onChange).toHaveBeenCalledWith({ [name]: { a: "BeBo" } }, true);
7483
});
7584

7685
it("should render a Field of type text with an initial value passed as prop", () => {

docs/Collection.mdx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { Collection, useValidation, Input, useAsyncValidation } from './../src';
1414
It creates a nested piece of state within a Form. <br />
1515
A Collection can be of type: **object** or **array**.
1616

17-
### Props
17+
## Props
1818

1919
**`object`**: boolean
2020

@@ -24,13 +24,15 @@ It creates a collecion of type **object** if "true".
2424

2525
It creates a collecion of type **array** if "true".
2626

27-
**`name`**: string - (except for **Collection** children of Collection of type array)
27+
**`name`**: string
2828

29-
A field's name in Usetheform state.
29+
A field's name in Usetheform state. <br />
30+
If your Collection is rendered within a `<Collection array />`, **name** is not allowed as prop.
3031

31-
**`index`**: string - (only for **Collection** children of Collection of type array)
32+
**`index`**: string
3233

33-
A field's index in array Collection.
34+
A field's index in array Collection. <br />
35+
**index** is only allowed If your Collection is rendered within a `<Collection array /> `.
3436

3537
**`touched`**: boolean
3638

docs/Form.mdx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { Input } from './../src';
1010
# Form
1111
The Form is the most important component in Usetheform. It renders all the Fields and keeps synchronized the entire form state.
1212

13-
### Props
13+
## Props
1414

1515
**`onInit`**: function
1616

@@ -81,6 +81,15 @@ Possible values:
8181
- An absolute URL - points to another web site (like action="http://www.example.com/example.htm")
8282
- A relative URL - points to a file within a web site (like action="example.htm")
8383
84+
**`innerRef`**: object (a mutable ref object)
85+
86+
When you need to access the underlying DOM node created by Form (e.g. to call focus), you can use a ref to store a reference to the form dom node.
87+
88+
```javascript
89+
const ref = useRef(null)
90+
<Form innerRef={ref} name="form">...fields...</Form>
91+
```
92+
8493
## Basic usage
8594
8695
### Example 1

docs/FormContext.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { Input, useForm } from './../src';
1111

1212
It is a react component that provides a context of the "form" at wider level.
1313

14-
### Props
14+
## Props
1515

1616
**`onInit`**: function
1717

docs/Input.mdx

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,21 @@ import { Input, useValidation, useAsyncValidation } from './../src';
1111
# Input
1212
It renders all the inputs of type listed at: [W3schools Input Types](https://www.w3schools.com/html/html_form_input_types.asp) and accepts as props any html attribute listed at: [Html Input Attributes](https://www.w3schools.com/tags/tag_input.asp).
1313

14-
### Props
14+
## Props
1515

1616
**`type`**: string
1717

1818
Type listed at: [W3schools Input Types](https://www.w3schools.com/html/html_form_input_types.asp).
1919

20-
**`name`**: string - (except for **Input** children of Collection of type array)
20+
**`name`**: string
2121

22-
A field's name in Usetheform state.
22+
A field's name in Usetheform state. <br />
23+
If your Input is rendered within a `<Collection array />`, **name** is not allowed as prop.
2324

24-
**`index`**: string - (only for **Input** children of Collection of type array)
25+
**`index`**: string
2526

26-
A field's index in array Collection.
27+
A field's index in array Collection. <br />
28+
**index** is only allowed If your Input is rendered within a `<Collection array /> `.
2729

2830
**`value`**: string | number
2931

@@ -48,6 +50,15 @@ If *true* validation messages (sync and async) will be showing only when the eve
4850
An array whose values correspond to different reducing functions.
4951
Reducers functions specify how the Input's value change.
5052

53+
**`innerRef`**: object (a mutable ref object)
54+
55+
When you need to access the underlying DOM node created by Input (e.g. to call focus), you can use a ref to store a reference to the input dom node.
56+
57+
```javascript
58+
const ref = useRef(null)
59+
<Input innerRef={ref} type="text" name="test" />
60+
```
61+
5162
## Basic usage
5263

5364
```javascript

0 commit comments

Comments
 (0)