@react-native-ama/forms 1.2.0 → 2.0.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/dist/components/Form.d.ts +5 -2
  2. package/dist/components/Form.js +14 -31
  3. package/dist/components/FormSubmit.d.ts +7 -9
  4. package/dist/components/FormSubmit.js +2 -14
  5. package/dist/components/TextInput.d.ts +36 -4
  6. package/dist/components/TextInput.js +20 -73
  7. package/dist/hooks/useFocus.d.ts +4 -0
  8. package/dist/hooks/useFocus.js +69 -0
  9. package/dist/hooks/useFormField.d.ts +1 -7
  10. package/dist/hooks/useFormField.js +32 -25
  11. package/dist/hooks/useFormSubmit.d.ts +4 -0
  12. package/dist/hooks/useFormSubmit.js +14 -0
  13. package/dist/hooks/useTextInput.d.ts +59 -231
  14. package/dist/hooks/useTextInput.js +2 -37
  15. package/dist/index.d.ts +10 -13
  16. package/dist/index.js +3 -8
  17. package/dist/utils/checkFocusTrap.d.ts +8 -0
  18. package/dist/utils/checkFocusTrap.js +30 -0
  19. package/package.json +59 -18
  20. package/src/components/Form.test.tsx +63 -70
  21. package/src/components/Form.tsx +28 -52
  22. package/src/components/FormField.test.tsx +32 -16
  23. package/src/components/FormField.tsx +0 -1
  24. package/src/components/FormSubmit.test.tsx +17 -55
  25. package/src/components/FormSubmit.tsx +9 -36
  26. package/src/components/TextInput.test.tsx +83 -397
  27. package/src/components/TextInput.tsx +41 -109
  28. package/src/hooks/useFocus.test.ts +130 -0
  29. package/src/hooks/useFocus.ts +62 -0
  30. package/src/hooks/useFormField.test.tsx +183 -78
  31. package/src/hooks/useFormField.ts +36 -28
  32. package/src/hooks/useFormSubmit.test.tsx +18 -0
  33. package/src/hooks/useFormSubmit.ts +17 -0
  34. package/src/hooks/useTextInput.ts +10 -55
  35. package/src/index.ts +15 -20
  36. package/src/utils/checkFocusTrap.test.ts +80 -0
  37. package/src/utils/checkFocusTrap.ts +40 -0
  38. package/dist/components/FormSwitch.d.ts +0 -4
  39. package/dist/components/FormSwitch.js +0 -15
  40. package/src/components/FormSwitch.tsx +0 -17
package/package.json CHANGED
@@ -1,17 +1,41 @@
1
1
  {
2
2
  "name": "@react-native-ama/forms",
3
- "version": "1.2.0",
4
- "react-native": "src/index",
5
- "types": "dist/index.d.ts",
6
- "main": "dist/index.js",
3
+ "version": "2.0.0-beta.0",
4
+ "sideEffects": false,
7
5
  "exports": {
8
- ".": [
9
- {
10
- "imports": "./dist/index.js",
11
- "types": "./dist/index.d.ts"
12
- },
13
- "./dist/index.js"
14
- ]
6
+ ".": {
7
+ "types": "./dist/index.d.ts",
8
+ "react-native": "./src/index.ts",
9
+ "default": "./dist/index.js"
10
+ },
11
+ "./Form": {
12
+ "types": "./dist/components/Form.d.ts",
13
+ "default": "./dist/components/Form.js"
14
+ },
15
+ "./FormField": {
16
+ "types": "./dist/components/FormField.d.ts",
17
+ "default": "./dist/components/FormField.js"
18
+ },
19
+ "./FormSubmit": {
20
+ "types": "./dist/components/FormSubmit.d.ts",
21
+ "default": "./dist/components/FormSubmit.js"
22
+ },
23
+ "./TextInput": {
24
+ "types": "./dist/components/TextInput.d.ts",
25
+ "default": "./dist/components/TextInput.js"
26
+ },
27
+ "./useFormField": {
28
+ "types": "./dist/hooks/useFormField.d.ts",
29
+ "default": "./dist/hooks/useFormField.js"
30
+ },
31
+ "./useFormSubmit": {
32
+ "types": "./dist/hooks/useFormSubmit.d.ts",
33
+ "default": "./dist/hooks/useFormSubmit.js"
34
+ },
35
+ "./useTextInput": {
36
+ "types": "./dist/hooks/useTextInput.d.ts",
37
+ "default": "./dist/hooks/useTextInput.js"
38
+ }
15
39
  },
16
40
  "files": [
17
41
  "src",
@@ -22,15 +46,16 @@
22
46
  "typecheck": "tsc --noEmit",
23
47
  "test": "jest"
24
48
  },
25
- "dependencies": {
26
- "@react-native-ama/core": "~1.2.0",
27
- "@react-native-ama/internal": "~1.2.0",
28
- "@react-native-ama/react-native": "~1.2.0"
29
- },
30
49
  "peerDependencies": {
50
+ "@react-native-ama/core": "~2.0.0-beta.0",
31
51
  "react": "*",
32
52
  "react-native": "*"
33
53
  },
54
+ "peerDependenciesMeta": {
55
+ "@react-native-ama/core": {
56
+ "optional": true
57
+ }
58
+ },
34
59
  "keywords": [
35
60
  "react-native",
36
61
  "a11y",
@@ -51,7 +76,10 @@
51
76
  "author": "",
52
77
  "license": "MIT",
53
78
  "jest": {
54
- "preset": "jest-expo",
79
+ "preset": "react-native",
80
+ "setupFilesAfterEnv": [
81
+ "<rootDir>/jest.setup.js"
82
+ ],
55
83
  "modulePathIgnorePatterns": [
56
84
  "<rootDir>/node_modules",
57
85
  "<rootDir>/dist/"
@@ -68,11 +96,24 @@
68
96
  }
69
97
  },
70
98
  "transformIgnorePatterns": [
71
- "node_modules/(?!(@react-native|react-native|react-native-reanimated/))"
99
+ "node_modules/(?!(react-native|react-native-reanimated|expo|@expo)/)"
72
100
  ],
73
101
  "transform": {
74
102
  "\\.[jt]sx?$": "babel-jest"
75
103
  },
104
+ "moduleDirectories": [
105
+ "node_modules",
106
+ "../../playground/node_modules"
107
+ ],
108
+ "moduleNameMapper": {
109
+ "@react-native/js-polyfills/error-guard": "<rootDir>/../../jest-mocks/error-guard.js",
110
+ "^(\\.{1,2}/)*ama\\.config\\.json$": "<rootDir>/../../jest-mocks/ama-config.js",
111
+ "^(\\.{1,2}/)*ReactNativeAmaModule$": "<rootDir>/../../jest-mocks/ReactNativeAmaModule.js",
112
+ "^@react-native-ama/core$": "<rootDir>/../../packages/core/src/index.ts",
113
+ "^@react-native-ama/core/(.*)$": "<rootDir>/../../packages/core/$1",
114
+ "^react-native$": "<rootDir>/../../node_modules/react-native",
115
+ "^react-native/(.*)$": "<rootDir>/../../node_modules/react-native/$1"
116
+ },
76
117
  "verbose": true
77
118
  },
78
119
  "devDependencies": {
@@ -1,7 +1,5 @@
1
- import * as UseChecks from '@react-native-ama/core/src/hooks/useChecks';
2
1
  import { render, waitFor } from '@testing-library/react-native';
3
2
  import * as React from 'react';
4
-
5
3
  import { Form, FormContext } from './Form';
6
4
 
7
5
  beforeEach(() => {
@@ -9,56 +7,6 @@ beforeEach(() => {
9
7
  });
10
8
 
11
9
  describe('Form', () => {
12
- let checkFocusTrap: jest.Mock;
13
-
14
- beforeEach(function () {
15
- checkFocusTrap = jest.fn().mockResolvedValue(null);
16
-
17
- // @ts-ignore
18
- jest.spyOn(UseChecks, 'useChecks').mockReturnValue({
19
- checkFocusTrap,
20
- hasErrors: true,
21
- } as any);
22
- });
23
-
24
- it('checks that next field has the focus if it has the focus callback', async () => {
25
- const focus = jest.fn();
26
- const ref = { current: { focus, isFocused: jest.fn() } };
27
- const secondField = {
28
- ref,
29
- hasFocusCallback: true,
30
- hasValidation: false,
31
- isEditable: true,
32
- id: 'second',
33
- };
34
-
35
- let providerValues = customRender();
36
-
37
- providerValues.refs?.push({
38
- ref: { current: 'random ref' },
39
- hasFocusCallback: false,
40
- hasValidation: false,
41
- id: 'first',
42
- });
43
-
44
- // next field
45
- providerValues.refs?.push(secondField);
46
-
47
- providerValues.focusField?.(secondField);
48
-
49
- await waitFor(() =>
50
- expect(checkFocusTrap).toHaveBeenCalledWith({
51
- ref: {
52
- current: {
53
- focus: expect.any(Function),
54
- isFocused: expect.any(Function),
55
- },
56
- },
57
- shouldHaveFocus: true,
58
- }),
59
- );
60
- });
61
-
62
10
  it('calls setFocus if the next field has no .focus callback', () => {
63
11
  const ref = { current: 'whatever' };
64
12
  const secondField = {
@@ -141,24 +89,11 @@ describe('Form', () => {
141
89
  providerValues.focusField?.(secondField);
142
90
 
143
91
  expect(focus).not.toHaveBeenCalled();
144
- expect(checkFocusTrap).not.toHaveBeenCalled();
145
92
 
146
93
  jest.advanceTimersByTime(51);
147
94
 
148
95
  expect(focus).toHaveBeenCalledWith();
149
96
 
150
- await waitFor(() =>
151
- expect(checkFocusTrap).toHaveBeenCalledWith({
152
- ref: {
153
- current: {
154
- focus: expect.any(Function),
155
- isFocused: expect.any(Function),
156
- },
157
- },
158
- shouldHaveFocus: true,
159
- }),
160
- );
161
-
162
97
  jest.useRealTimers();
163
98
  });
164
99
 
@@ -190,6 +125,35 @@ describe('Form', () => {
190
125
  expect(setFocus).toHaveBeenCalledWith(ref.current);
191
126
  });
192
127
 
128
+ it('focusFieldAt focuses the field at the given index', async () => {
129
+ const focus = jest.fn();
130
+ const ref = React.createRef<any>();
131
+ (ref as any).current = { focus, isFocused: jest.fn().mockReturnValue(false) };
132
+
133
+ let formRef = React.createRef<any>();
134
+
135
+ render(
136
+ <Form ref={formRef} onSubmit={jest.fn()}>
137
+ <FormContext.Consumer>
138
+ {value => {
139
+ value?.refs?.push({
140
+ ref: { current: ref } as any,
141
+ hasFocusCallback: true,
142
+ hasValidation: false,
143
+ isEditable: true,
144
+ id: 'field0',
145
+ });
146
+ return null;
147
+ }}
148
+ </FormContext.Consumer>
149
+ </Form>,
150
+ );
151
+
152
+ formRef.current?.focusFieldAt(0);
153
+
154
+ await waitFor(() => expect(focus).toHaveBeenCalled());
155
+ });
156
+
193
157
  it('focuses the first failed component when submitForm fails', async () => {
194
158
  const onSubmit = jest.fn().mockReturnValue(false);
195
159
 
@@ -222,7 +186,7 @@ describe('Form', () => {
222
186
  });
223
187
  });
224
188
 
225
- let setFocus: jest.Mock;
189
+ var setFocus: jest.Mock;
226
190
 
227
191
  function mockUseFocus() {
228
192
  setFocus = jest.fn();
@@ -255,8 +219,37 @@ function customRender(onSubmit = jest.fn()) {
255
219
  }
256
220
 
257
221
  jest.mock('../hooks/useFocus', () => mockUseFocus());
258
- jest.mock('../internal/checks/checkFocusTrap', () => {
259
- return {
260
- checkFocusTrap: jest.fn().mockResolvedValue(null),
261
- };
222
+
223
+ describe('useForm', () => {
224
+ it('returns default context value when suppressError is true and no Form wrapper', () => {
225
+ const { useForm } = require('./Form');
226
+ const { renderHook } = require('@testing-library/react-native');
227
+
228
+ const { result } = renderHook(() => useForm({ suppressError: true }));
229
+ expect(result.current.refs).toEqual([]);
230
+ expect(typeof result.current.submitForm).toBe('function');
231
+ });
232
+
233
+ it('throws when called outside Form and suppressError is false', () => {
234
+ const { useForm } = require('./Form');
235
+ const { renderHook } = require('@testing-library/react-native');
236
+
237
+ expect(() => renderHook(() => useForm())).toThrow(
238
+ 'useForm must be used within a FormContextProvider',
239
+ );
240
+ });
241
+
242
+ it('logs a console.error in __DEV__ when called outside Form', () => {
243
+ const { useForm } = require('./Form');
244
+ const { renderHook } = require('@testing-library/react-native');
245
+ const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
246
+ // @ts-ignore
247
+ global.__DEV__ = true;
248
+
249
+ expect(() => renderHook(() => useForm())).toThrow();
250
+ expect(errorSpy).toHaveBeenCalled();
251
+ errorSpy.mockRestore();
252
+ // @ts-ignore
253
+ global.__DEV__ = true;
254
+ });
262
255
  });
@@ -1,11 +1,9 @@
1
- import { useChecks, useFocus } from '@react-native-ama/core';
2
- import { isFocused } from '@react-native-ama/internal';
3
1
  import * as React from 'react';
4
- import { InteractionManager } from 'react-native';
2
+ import { InteractionManager, TextInput } from 'react-native';
3
+ import { useFocus } from '../hooks/useFocus';
5
4
 
6
5
  export type FormProps = React.PropsWithChildren<{
7
6
  onSubmit: () => boolean | Promise<boolean>;
8
- ref?: React.RefObject<FormActions>; // need to explicitly type for inference in <Form /> component
9
7
  }>;
10
8
 
11
9
  export type FormActions = {
@@ -18,8 +16,6 @@ export const Form = React.forwardRef<FormActions, FormProps>(
18
16
  const refs = React.useRef<FormRef[]>([]);
19
17
  const { setFocus } = useFocus();
20
18
 
21
- const checks = __DEV__ ? useChecks?.() : undefined;
22
-
23
19
  const focusField = React.useCallback(
24
20
  (nextField?: Partial<FormRef> | undefined) => {
25
21
  /**
@@ -35,14 +31,6 @@ export const Form = React.forwardRef<FormActions, FormProps>(
35
31
  nextField?.hasFocusCallback &&
36
32
  nextField?.isEditable;
37
33
 
38
- __DEV__ &&
39
- nextRefElement == null &&
40
- checks?.logResult('nextRefElement', {
41
- message:
42
- 'No next field found. Make sure you wrapped your form inside the <Form /> component',
43
- rule: 'NO_UNDEFINED',
44
- });
45
-
46
34
  if (callFocus) {
47
35
  /**
48
36
  * On some apps, if we call focus immediately and the field is already focused we lose the focus.
@@ -52,51 +40,33 @@ export const Form = React.forwardRef<FormActions, FormProps>(
52
40
 
53
41
  setTimeout(() => {
54
42
  nextRefElement?.current?.focus();
55
-
56
- __DEV__ &&
57
- nextRefElement &&
58
- checks?.checkFocusTrap({
59
- ref: nextRefElement,
60
- shouldHaveFocus: true,
61
- });
62
43
  }, timeoutValue);
63
44
  } else if (nextRefElement?.current) {
64
45
  setFocus(nextRefElement?.current);
65
46
  }
66
47
  },
67
- [checks, setFocus],
48
+ [setFocus]
68
49
  );
69
50
 
70
- const focusFieldAt = React.useCallback(
71
- (position: number) => {
72
- InteractionManager.runAfterInteractions(() => {
73
- setTimeout(() => {
74
- const fieldWithError = refs.current[position];
51
+ const focusFieldAt = (position: number) => {
52
+ InteractionManager.runAfterInteractions(() => {
53
+ setTimeout(() => {
54
+ const fieldWithError = refs.current[position];
75
55
 
76
- focusField(fieldWithError);
77
- }, 0);
78
- });
79
- },
80
- [focusField],
81
- );
56
+ focusField(fieldWithError);
57
+ }, 0);
58
+ });
59
+ };
82
60
 
83
- const focusFirstInvalidField = React.useCallback(() => {
61
+ const focusFirstInvalidField = () => {
84
62
  const fieldWithError = (refs.current || []).findIndex(
85
- fieldRef => fieldRef.hasValidation && fieldRef.hasError,
63
+ (fieldRef) => fieldRef.hasValidation && fieldRef.hasError
86
64
  );
87
65
 
88
- __DEV__ &&
89
- fieldWithError == null &&
90
- checks?.logResult('Form', {
91
- message:
92
- 'The form validation has failed, but no component with error was found',
93
- rule: 'NO_UNDEFINED',
94
- });
95
-
96
66
  focusFieldAt(fieldWithError);
97
- }, [focusFieldAt, checks]);
67
+ };
98
68
 
99
- const submitForm = React.useCallback(async () => {
69
+ const submitForm = async () => {
100
70
  const isValid = await onSubmit();
101
71
 
102
72
  if (isValid) {
@@ -104,7 +74,7 @@ export const Form = React.forwardRef<FormActions, FormProps>(
104
74
  }
105
75
 
106
76
  focusFirstInvalidField();
107
- }, [focusFirstInvalidField, onSubmit]);
77
+ };
108
78
 
109
79
  React.useImperativeHandle(ref, () => ({
110
80
  focusFirstInvalidField,
@@ -113,11 +83,12 @@ export const Form = React.forwardRef<FormActions, FormProps>(
113
83
 
114
84
  return (
115
85
  <FormContext.Provider
116
- value={{ refs: refs.current, submitForm, focusField }}>
86
+ value={{ refs: refs.current, submitForm, focusField }}
87
+ >
117
88
  {children}
118
89
  </FormContext.Provider>
119
90
  );
120
- },
91
+ }
121
92
  );
122
93
 
123
94
  export type FormContextValue = {
@@ -140,11 +111,11 @@ export const FormContext = React.createContext<FormContextValue | null>(null);
140
111
  const DEFAULT_CONTEXT_VALUE: FormContextValue = {
141
112
  refs: [],
142
113
  submitForm: () => Promise.resolve(),
143
- focusField: () => {},
114
+ focusField: () => { },
144
115
  };
145
116
 
146
117
  export const useForm = (
147
- { suppressError }: { suppressError?: boolean } = { suppressError: false },
118
+ { suppressError }: { suppressError?: boolean } = { suppressError: false }
148
119
  ) => {
149
120
  const context = React.useContext(FormContext);
150
121
 
@@ -155,12 +126,17 @@ export const useForm = (
155
126
  if (!context) {
156
127
  __DEV__ &&
157
128
  console.error(
158
- 'Please wrap your form field inside the <Form /> component',
129
+ 'Please wrap your form field inside the <Form /> component'
159
130
  );
160
131
  throw new Error(
161
- 'useForm must be used within a FormContextProvider, please wrap your form field inside the <Form /> component',
132
+ 'useForm must be used within a FormContextProvider, please wrap your form field inside the <Form /> component'
162
133
  );
163
134
  }
164
135
 
165
136
  return context;
166
137
  };
138
+
139
+
140
+ const isFocused = (input: TextInput | undefined | null) => {
141
+ return input?.isFocused();
142
+ };
@@ -1,12 +1,16 @@
1
1
  import { render } from '@testing-library/react-native';
2
2
  import * as React from 'react';
3
3
  import { Text } from 'react-native';
4
-
5
4
  import * as UseFormField from '../hooks/useFormField';
6
5
  import { FormField } from './FormField';
7
6
 
7
+ jest.mock('../hooks/useFormField', () => ({
8
+ useFormField: jest.fn(() => ({})),
9
+ }));
10
+
8
11
  beforeEach(() => {
9
12
  jest.clearAllMocks();
13
+ (UseFormField.useFormField as jest.Mock).mockReturnValue({});
10
14
  });
11
15
 
12
16
  describe('FormField', () => {
@@ -25,6 +29,18 @@ describe('FormField', () => {
25
29
  });
26
30
  });
27
31
 
32
+ it('renders children without accessible View when wrapInsideAccessibleView is false', () => {
33
+ const { toJSON } = render(
34
+ <FormField hasValidation={false} wrapInsideAccessibleView={false}>
35
+ <Text>Test</Text>
36
+ </FormField>,
37
+ );
38
+
39
+ const json = toJSON() as any;
40
+ expect(json.type).toBe('TouchableWithoutFeedback');
41
+ expect(json.children[0].type).not.toBe('View');
42
+ });
43
+
28
44
  it('wraps the children in a focusable View', () => {
29
45
  const { toJSON } = render(
30
46
  <FormField hasValidation={false}>
@@ -33,22 +49,22 @@ describe('FormField', () => {
33
49
  );
34
50
 
35
51
  expect(toJSON()).toMatchInlineSnapshot(`
36
- <View
37
- accessibilityHint=""
38
- accessible={true}
39
- focusable={false}
40
- onClick={[Function]}
41
- onResponderGrant={[Function]}
42
- onResponderMove={[Function]}
43
- onResponderRelease={[Function]}
44
- onResponderTerminate={[Function]}
45
- onResponderTerminationRequest={[Function]}
46
- onStartShouldSetResponder={[Function]}
52
+ <TouchableWithoutFeedback
53
+ hasValidation={false}
54
+ ref={
55
+ {
56
+ "current": null,
57
+ }
58
+ }
47
59
  >
48
- <Text>
49
- Test
50
- </Text>
51
- </View>
60
+ <View
61
+ accessible={true}
62
+ >
63
+ <Text>
64
+ Test
65
+ </Text>
66
+ </View>
67
+ </TouchableWithoutFeedback>
52
68
  `);
53
69
  });
54
70
  });
@@ -4,7 +4,6 @@ import {
4
4
  TouchableWithoutFeedbackProps,
5
5
  View,
6
6
  } from 'react-native';
7
-
8
7
  import { UseFormField, useFormField } from '../hooks/useFormField';
9
8
 
10
9
  export type FormFieldProps = React.PropsWithChildren<
@@ -1,71 +1,33 @@
1
- import { render } from '@testing-library/react-native';
1
+ import { fireEvent, render } from '@testing-library/react-native';
2
2
  import * as React from 'react';
3
- import { Pressable, View } from 'react-native';
4
-
3
+ import { Pressable } from 'react-native';
5
4
  import { FormSubmit } from './FormSubmit';
5
+ import * as Form from './Form';
6
6
 
7
7
  beforeEach(() => {
8
8
  jest.clearAllMocks();
9
9
  });
10
10
 
11
11
  describe('FormSubmit', () => {
12
- it('wraps the children inside a Pressable component with the correct accessibility role and label', () => {
13
- const { getByTestId, UNSAFE_getByType } = render(
14
- <FormSubmit
15
- accessibilityLabel="This is the label"
16
- busy={false}
17
- testID="test-me"
18
- />,
12
+ it('provides onPress to its children render function', () => {
13
+ const submitForm = jest.fn().mockResolvedValue(undefined);
14
+ jest.spyOn(Form, 'useForm').mockImplementation(
15
+ () => ({ submitForm }) as any,
19
16
  );
20
17
 
21
- expect(UNSAFE_getByType(Pressable)).toBeTruthy();
22
- expect(getByTestId('test-me').props).toEqual(
23
- expect.objectContaining({
24
- accessibilityRole: 'button',
25
- accessibilityLabel: 'This is the label',
26
- accessibilityState: {
27
- busy: false,
28
- },
29
- busy: false,
30
- accessible: true,
31
- }),
32
- );
33
- });
18
+ const renderChildren = jest.fn(({ onPress }) => (
19
+ <Pressable testID="submit" onPress={onPress} />
20
+ ));
34
21
 
35
- it('hides the children from the accessibility tree', () => {
36
- const { getByTestId } = render(
37
- <FormSubmit
38
- accessibilityLabel="This is the label"
39
- busy={false}
40
- testID="test-me">
41
- <View testID="child" />
42
- </FormSubmit>,
22
+ const { getByTestId, UNSAFE_getAllByType } = render(
23
+ <FormSubmit>{renderChildren}</FormSubmit>,
43
24
  );
44
25
 
45
- expect(getByTestId('child').props).toEqual({
46
- accessibilityElementsHidden: true,
47
- children: null,
48
- importantForAccessibility: 'no',
49
- testID: 'child',
50
- });
51
- });
52
- });
53
-
54
- jest.mock('../hooks/useFormField', () => {
55
- return {
56
- useFormField: jest.fn().mockReturnValue({}),
57
- };
58
- });
26
+ expect(renderChildren).toHaveBeenCalledTimes(1);
27
+ expect(UNSAFE_getAllByType(Pressable)).toHaveLength(1);
59
28
 
60
- jest.mock('@react-native-ama/core', () => {
61
- const originalModule = jest.requireActual('@react-native-ama/core');
29
+ fireEvent.press(getByTestId('submit'));
62
30
 
63
- return {
64
- ...originalModule,
65
- useAMAContext: () => {
66
- return {
67
- isScreenReaderEnabled: true,
68
- };
69
- },
70
- };
31
+ expect(submitForm).toHaveBeenCalledTimes(1);
32
+ });
71
33
  });
@@ -1,43 +1,16 @@
1
- import { useAMAContext } from '@react-native-ama/core';
2
- import { HideChildrenFromAccessibilityTree } from '@react-native-ama/core';
3
1
  import React from 'react';
4
- import { Pressable, PressableProps } from 'react-native';
5
-
6
2
  import { useForm } from '../components/Form';
7
3
 
8
- export type FormSubmitProps = React.PropsWithChildren<{
9
- accessibilityLabel: string;
10
- accessibilityHint?: string;
11
- busy: boolean;
12
- style?: PressableProps['style'];
13
- testID?: string;
14
- }>;
15
-
16
- export const FormSubmit = (props: FormSubmitProps) => {
17
- const { submitForm } = useForm();
18
- const { isScreenReaderEnabled } = useAMAContext();
4
+ export type FormSubmitRenderProps = {
5
+ onPress: () => Promise<void>;
6
+ };
19
7
 
20
- return (
21
- <Pressable
22
- accessibilityRole="button"
23
- pointerEvents="box-only" // prevent event propagation to children eg Pressable
24
- {...props}
25
- onPress={submitForm}>
26
- {isScreenReaderEnabled ? (
27
- <FormSubmitForScreenReader children={props.children} />
28
- ) : (
29
- props.children
30
- )}
31
- </Pressable>
32
- );
8
+ export type FormSubmitProps = {
9
+ children: (props: FormSubmitRenderProps) => React.ReactNode;
33
10
  };
34
11
 
35
- const FormSubmitForScreenReader = ({
36
- children,
37
- }: React.PropsWithChildren<{}>) => {
38
- return (
39
- <HideChildrenFromAccessibilityTree>
40
- {children}
41
- </HideChildrenFromAccessibilityTree>
42
- );
12
+ export const FormSubmit = ({ children }: FormSubmitProps) => {
13
+ const { submitForm } = useForm();
14
+
15
+ return <>{children({ onPress: submitForm })}</>;
43
16
  };