@react-native-ama/core 1.2.1 → 2.0.0-beta.1

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 (179) hide show
  1. package/dist/ReactNativeAma.types.d.ts +66 -0
  2. package/dist/ReactNativeAma.types.js +2 -0
  3. package/dist/ReactNativeAmaModule.d.ts +11 -0
  4. package/dist/ReactNativeAmaModule.js +5 -0
  5. package/dist/ReactNativeAmaModule.web.d.ts +9 -0
  6. package/dist/ReactNativeAmaModule.web.js +27 -0
  7. package/dist/ReactNativeAmaView.d.ts +3 -0
  8. package/dist/ReactNativeAmaView.js +32 -0
  9. package/dist/ReactNativeAmaView.web.d.ts +3 -0
  10. package/dist/ReactNativeAmaView.web.js +34 -0
  11. package/dist/{src/components → components}/AMAProvider.d.ts +4 -2
  12. package/dist/{src/components → components}/AMAProvider.js +19 -45
  13. package/dist/{src/components → components}/AutofocusContainer.d.ts +2 -1
  14. package/dist/{src/components → components}/HideChildrenFromAccessibilityTree.d.ts +1 -1
  15. package/dist/{src/components → components}/HideChildrenFromAccessibilityTree.js +7 -5
  16. package/dist/{src/hooks → hooks}/useFocus.js +10 -3
  17. package/dist/{src/index.d.ts → index.d.ts} +3 -2
  18. package/dist/index.js +38 -0
  19. package/dist/internals/checks/checkAriaLabel.d.ts +3 -0
  20. package/dist/internals/checks/checkAriaLabel.js +15 -0
  21. package/dist/internals/checks/checkAriaRole.d.ts +3 -0
  22. package/dist/internals/checks/checkAriaRole.js +48 -0
  23. package/dist/internals/checks/checkContrast.d.ts +3 -0
  24. package/dist/internals/checks/checkContrast.js +84 -0
  25. package/dist/internals/checks/checkImageAlt.d.ts +3 -0
  26. package/dist/internals/checks/checkImageAlt.js +20 -0
  27. package/dist/internals/checks/checkIsUppercase.d.ts +8 -0
  28. package/dist/internals/checks/checkIsUppercase.js +30 -0
  29. package/dist/internals/checks/checkLongNumber.d.ts +3 -0
  30. package/dist/internals/checks/checkLongNumber.js +31 -0
  31. package/dist/internals/checks/checkMinimumSize.d.ts +3 -0
  32. package/dist/internals/checks/checkMinimumSize.js +22 -0
  33. package/dist/internals/checks/checkTextInput.d.ts +3 -0
  34. package/dist/internals/checks/checkTextInput.js +51 -0
  35. package/dist/internals/checks/performChecks.d.ts +3 -0
  36. package/dist/internals/checks/performChecks.js +23 -0
  37. package/dist/internals/components/AMAErrorOverlay.d.ts +5 -0
  38. package/dist/internals/components/AMAErrorOverlay.js +334 -0
  39. package/dist/internals/components/AMARuleError.d.ts +7 -0
  40. package/dist/internals/components/AMARuleError.js +161 -0
  41. package/dist/internals/config.d.ts +23 -0
  42. package/dist/internals/config.js +33 -0
  43. package/dist/internals/types.d.ts +9 -0
  44. package/dist/internals/types.js +2 -0
  45. package/dist/internals/useAMADev.d.ts +8 -0
  46. package/dist/internals/useAMADev.dev.d.ts +2 -0
  47. package/dist/internals/useAMADev.dev.js +110 -0
  48. package/dist/internals/useAMADev.js +6 -0
  49. package/dist/internals/useAMADevNodeChecks.dev.d.ts +16 -0
  50. package/dist/internals/useAMADevNodeChecks.dev.js +115 -0
  51. package/dist/internals/useAMADevUiInteraction.dev.d.ts +7 -0
  52. package/dist/internals/useAMADevUiInteraction.dev.js +100 -0
  53. package/dist/internals/utils/amaClearHighlight.d.ts +2 -0
  54. package/dist/internals/utils/amaClearHighlight.js +12 -0
  55. package/dist/internals/utils/amaHighlightComponent.d.ts +3 -0
  56. package/dist/internals/utils/amaHighlightComponent.js +51 -0
  57. package/dist/internals/utils/constants.d.ts +3 -0
  58. package/dist/internals/utils/constants.js +32 -0
  59. package/dist/internals/utils/getErrorColor.d.ts +2 -0
  60. package/dist/internals/utils/getErrorColor.js +10 -0
  61. package/dist/internals/utils/getRuleAction.d.ts +2 -0
  62. package/dist/internals/utils/getRuleAction.js +40 -0
  63. package/dist/internals/utils/getRuleErrorInfo.d.ts +7 -0
  64. package/dist/internals/utils/getRuleErrorInfo.js +19 -0
  65. package/dist/internals/utils/ignoreContrastCheck.d.ts +1 -0
  66. package/dist/internals/utils/ignoreContrastCheck.js +15 -0
  67. package/dist/internals/utils/interpolateAnimationStates.d.ts +2 -0
  68. package/dist/internals/utils/interpolateAnimationStates.js +43 -0
  69. package/dist/internals/utils/isA11yLabelAllowed.d.ts +1 -0
  70. package/dist/internals/utils/isA11yLabelAllowed.js +14 -0
  71. package/dist/internals/utils/isRuleDisabled.d.ts +2 -0
  72. package/dist/internals/utils/isRuleDisabled.js +10 -0
  73. package/dist/internals/utils/logError.d.ts +2 -0
  74. package/dist/internals/utils/logError.js +36 -0
  75. package/dist/internals/utils/logFoundIssues.d.ts +2 -0
  76. package/dist/internals/utils/logFoundIssues.js +23 -0
  77. package/dist/internals/utils/logger.d.ts +6 -0
  78. package/dist/internals/utils/logger.js +15 -0
  79. package/dist/internals/utils/minimumTouchableSize.d.ts +1 -0
  80. package/dist/internals/utils/minimumTouchableSize.js +9 -0
  81. package/dist/internals/utils/platformHelpers.d.ts +2 -0
  82. package/dist/internals/utils/platformHelpers.js +6 -0
  83. package/dist/internals/utils/rules.d.ts +22 -0
  84. package/dist/internals/utils/rules.js +253 -0
  85. package/dist/scripts/create-config.js +4 -3
  86. package/package.json +62 -20
  87. package/src/ReactNativeAma.types.ts +70 -0
  88. package/src/ReactNativeAmaModule.ts +18 -0
  89. package/src/ReactNativeAmaModule.web.ts +14 -0
  90. package/src/ReactNativeAmaView.tsx +9 -0
  91. package/src/ReactNativeAmaView.web.tsx +15 -0
  92. package/src/__mocks__/ReactNativeAmaModule.ts +9 -0
  93. package/src/components/AMAProvider.integration.test.tsx +3 -96
  94. package/src/components/AMAProvider.test.tsx +9 -4
  95. package/src/components/AMAProvider.tsx +40 -76
  96. package/src/components/AutofocusContainer.test.tsx +4 -5
  97. package/src/components/AutofocusContainer.tsx +20 -5
  98. package/src/components/HideChildrenFromAccessibilityTree.test.tsx +23 -39
  99. package/src/components/HideChildrenFromAccessibilityTree.tsx +12 -11
  100. package/src/hooks/useFocus.test.ts +20 -20
  101. package/src/hooks/useFocus.ts +14 -6
  102. package/src/hooks/useTimedAction.android.test.ts +0 -1
  103. package/src/hooks/useTimedAction.ios.test.ts +0 -1
  104. package/src/hooks/useTimedAction.ts +0 -1
  105. package/src/index.ts +4 -2
  106. package/src/internals/checks/checkAriaLabel.test.ts +165 -0
  107. package/src/internals/checks/checkAriaLabel.ts +16 -0
  108. package/src/internals/checks/checkAriaRole.test.ts +429 -0
  109. package/src/internals/checks/checkAriaRole.ts +60 -0
  110. package/src/internals/checks/checkContrast.test.ts +278 -0
  111. package/src/internals/checks/checkContrast.ts +109 -0
  112. package/src/internals/checks/checkImageAlt.test.ts +125 -0
  113. package/src/internals/checks/checkImageAlt.ts +23 -0
  114. package/src/internals/checks/checkIsUppercase.test.ts +399 -0
  115. package/src/internals/checks/checkIsUppercase.ts +46 -0
  116. package/src/internals/checks/checkLongNumber.test.ts +111 -0
  117. package/src/internals/checks/checkLongNumber.ts +34 -0
  118. package/src/internals/checks/checkMinimumSize.test.ts +67 -0
  119. package/src/internals/checks/checkMinimumSize.ts +25 -0
  120. package/src/internals/checks/checkTextInput.ts +65 -0
  121. package/src/internals/checks/performChecks.test.ts +171 -0
  122. package/src/internals/checks/performChecks.ts +24 -0
  123. package/src/internals/components/AMAErrorOverlay.test.tsx +139 -0
  124. package/src/internals/components/AMAErrorOverlay.tsx +451 -0
  125. package/src/internals/components/AMARuleError.test.tsx +93 -0
  126. package/src/internals/components/AMARuleError.tsx +225 -0
  127. package/src/internals/config.ts +58 -0
  128. package/src/internals/types.ts +11 -0
  129. package/src/internals/useAMADev.dev.ts +153 -0
  130. package/src/internals/useAMADev.test.ts +260 -0
  131. package/src/internals/useAMADev.ts +17 -0
  132. package/src/internals/useAMADevNodeChecks.dev.ts +178 -0
  133. package/src/internals/useAMADevUiInteraction.dev.ts +164 -0
  134. package/src/internals/utils/amaClearHighlight.test.ts +21 -0
  135. package/src/internals/utils/amaClearHighlight.ts +8 -0
  136. package/src/internals/utils/amaHighlightComponent.test.ts +74 -0
  137. package/src/internals/utils/amaHighlightComponent.ts +46 -0
  138. package/src/internals/utils/constants.ts +33 -0
  139. package/src/internals/utils/devMode.test.ts +99 -0
  140. package/src/internals/utils/getErrorColor.test.ts +18 -0
  141. package/src/internals/utils/getErrorColor.ts +8 -0
  142. package/src/internals/utils/getRuleAction.ts +13 -0
  143. package/src/internals/utils/getRuleErrorInfo.test.ts +59 -0
  144. package/src/internals/utils/getRuleErrorInfo.ts +26 -0
  145. package/src/internals/utils/ignoreContrastCheck.test.ts +34 -0
  146. package/src/internals/utils/ignoreContrastCheck.ts +11 -0
  147. package/src/internals/utils/interpolateAnimation.test.ts +176 -0
  148. package/src/internals/utils/interpolateAnimationStates.ts +55 -0
  149. package/src/internals/utils/isA11yLabelAllowed.test.ts +39 -0
  150. package/src/internals/utils/isA11yLabelAllowed.ts +10 -0
  151. package/src/internals/utils/isRuleDisabled.test.ts +35 -0
  152. package/src/internals/utils/isRuleDisabled.ts +10 -0
  153. package/src/internals/utils/logError.test.ts +148 -0
  154. package/src/internals/utils/logError.ts +41 -0
  155. package/src/internals/utils/logFoundIssues.test.ts +98 -0
  156. package/src/internals/utils/logFoundIssues.ts +22 -0
  157. package/src/internals/utils/logger.test.ts +26 -0
  158. package/src/internals/utils/logger.ts +15 -0
  159. package/src/internals/utils/loggerMethods.test.ts +38 -0
  160. package/src/internals/utils/minimumTouchableSize.test.ts +28 -0
  161. package/src/internals/utils/minimumTouchableSize.tsx +9 -0
  162. package/src/internals/utils/platformHelpers.test.ts +11 -0
  163. package/src/internals/utils/platformHelpers.ts +4 -0
  164. package/src/internals/utils/rules.ts +363 -0
  165. package/src/scripts/create-config.ts +21 -0
  166. package/dist/src/hooks/useButtonChecks.d.ts +0 -6
  167. package/dist/src/hooks/useButtonChecks.js +0 -51
  168. package/dist/src/hooks/useChecks.d.ts +0 -15
  169. package/dist/src/hooks/useChecks.js +0 -152
  170. package/dist/src/index.js +0 -20
  171. package/src/hooks/useButtonChecks.ts +0 -73
  172. package/src/hooks/useChecks.test.ts +0 -214
  173. package/src/hooks/useChecks.ts +0 -207
  174. /package/dist/{src/components → components}/AutofocusContainer.js +0 -0
  175. /package/dist/{src/hooks → hooks}/useFocus.d.ts +0 -0
  176. /package/dist/{src/hooks → hooks}/useTimedAction.d.ts +0 -0
  177. /package/dist/{src/hooks → hooks}/useTimedAction.js +0 -0
  178. /package/dist/{src/utils → utils}/numerify.d.ts +0 -0
  179. /package/dist/{src/utils → utils}/numerify.js +0 -0
@@ -2,13 +2,15 @@ import { act, render } from '@testing-library/react-native';
2
2
  import { flushMicroTasks } from '@testing-library/react-native/build/flush-micro-tasks';
3
3
  import * as React from 'react';
4
4
  import { AccessibilityInfo } from 'react-native';
5
-
6
5
  import { AMAContextValue, AMAProvider } from './AMAProvider';
7
6
 
8
7
  var mockProvider: jest.Mock;
9
8
 
10
9
  beforeEach(() => {
11
10
  jest.clearAllMocks();
11
+ if (mockProvider) {
12
+ mockProvider.mockReturnValue(null);
13
+ }
12
14
  });
13
15
 
14
16
  describe('AMAProvider', () => {
@@ -103,9 +105,10 @@ describe('AMAProvider', () => {
103
105
  expect.objectContaining({
104
106
  value: expect.objectContaining(state),
105
107
  }),
106
- {},
108
+ undefined,
107
109
  );
108
110
 
111
+
109
112
  jest.clearAllMocks();
110
113
 
111
114
  act(() => {
@@ -117,9 +120,10 @@ describe('AMAProvider', () => {
117
120
  expect.objectContaining({
118
121
  value: expect.objectContaining(state),
119
122
  }),
120
- {},
123
+ undefined,
121
124
  );
122
125
 
126
+
123
127
  jest.clearAllMocks();
124
128
 
125
129
  act(() => {
@@ -131,8 +135,9 @@ describe('AMAProvider', () => {
131
135
  expect.objectContaining({
132
136
  value: expect.objectContaining(state),
133
137
  }),
134
- {},
138
+ undefined,
135
139
  );
140
+
136
141
  },
137
142
  );
138
143
 
@@ -1,14 +1,13 @@
1
1
  /* eslint-disable react-native/no-inline-styles */
2
-
3
- import { RED } from '@react-native-ama/internal';
4
2
  import * as React from 'react';
5
3
  import {
6
4
  AccessibilityChangeEventName,
7
5
  AccessibilityInfo,
8
6
  NativeEventSubscription,
9
- Text,
10
7
  View,
11
8
  } from 'react-native';
9
+ import type { AmaRule } from '../internals/types';
10
+ import type { UseAMADev } from '../internals/useAMADev';
12
11
 
13
12
  type AMAProviderProps = {
14
13
  children: React.ReactNode;
@@ -21,14 +20,16 @@ type SharedContextValue = {
21
20
  isInvertColorsEnabled: boolean;
22
21
  isReduceMotionEnabled: boolean;
23
22
  isReduceTransparencyEnabled: boolean;
23
+ isHighTextContrastEnabled: boolean;
24
+ isDarkerSystemColorsEnabled: boolean;
24
25
  reactNavigationScreenOptions: {
25
26
  animationEnabled: boolean;
26
27
  animation: 'default' | 'fade';
27
28
  };
28
29
  };
30
+
29
31
  export type AMADevContextValue = SharedContextValue & {
30
- trackError: (id: string) => void;
31
- removeError: (id: string) => void;
32
+ trackError: (rule: AmaRule, ref?: React.RefObject<any>) => void;
32
33
  };
33
34
 
34
35
  export type AMAProdContextValue = SharedContextValue & {};
@@ -39,7 +40,7 @@ type AccessibilityEvents = Exclude<AccessibilityChangeEventName, 'change'>;
39
40
 
40
41
  type AccessibilityInfoKey = Exclude<
41
42
  keyof AMAContextValue,
42
- 'reactNavigationScreenOptions' | 'trackError' | 'removeError'
43
+ 'reactNavigationScreenOptions' | 'trackError'
43
44
  >;
44
45
 
45
46
  type Extractor<S extends AccessibilityEvents> = S extends `${infer R}Changed`
@@ -57,10 +58,12 @@ const eventsMapping: AccessibilityInfoEvents = {
57
58
  boldTextChanged: 'isBoldTextEnabled',
58
59
  invertColorsChanged: 'isInvertColorsEnabled',
59
60
  screenReaderChanged: 'isScreenReaderEnabled',
61
+ highTextContrastChanged: 'isHighTextContrastEnabled',
62
+ darkerSystemColorsChanged: 'isDarkerSystemColorsEnabled',
60
63
  };
61
64
 
62
65
  export const isDevContextValue = (
63
- value: AMAContextValue,
66
+ value: AMAContextValue
64
67
  ): value is AMADevContextValue =>
65
68
  (value as AMADevContextValue).trackError !== undefined;
66
69
 
@@ -71,6 +74,8 @@ const DEFAULT_VALUES = {
71
74
  isInvertColorsEnabled: false,
72
75
  isReduceMotionEnabled: false,
73
76
  isScreenReaderEnabled: false,
77
+ isHighTextContrastEnabled: false,
78
+ isDarkerSystemColorsEnabled: false,
74
79
  reactNavigationScreenOptions: {
75
80
  animationEnabled: true,
76
81
  animation: 'default',
@@ -79,12 +84,28 @@ const DEFAULT_VALUES = {
79
84
 
80
85
  const AMAContext = React.createContext<AMAContextValue | null>(null);
81
86
 
87
+ type AMAErrorOverlayModule = typeof import('../internals/components/AMAErrorOverlay');
88
+ type UseAMADevModule = {
89
+ useAMADev: UseAMADev | null;
90
+ };
91
+
92
+ const AMAErrorOverlay = __DEV__
93
+ ? (require('../internals/components/AMAErrorOverlay') as AMAErrorOverlayModule)
94
+ .AMAErrorOverlay
95
+ : null;
96
+
97
+ const useAMADev = __DEV__
98
+ ? (require('../internals/useAMADev') as UseAMADevModule).useAMADev
99
+ : null;
100
+
82
101
  export const AMAProvider: React.FC<AMAProviderProps> = ({ children }) => {
83
102
  const [values, setValues] = React.useState<AMAContextValue>(DEFAULT_VALUES);
84
103
 
104
+ const { issues, trackError } = (__DEV__ && useAMADev?.()) || {};
105
+
85
106
  const handleAccessibilityInfoChanged = (key: AccessibilityInfoKey) => {
86
107
  return (newValue: boolean) => {
87
- setValues(oldValues => {
108
+ setValues((oldValues) => {
88
109
  const newValues = { ...oldValues };
89
110
  newValues[key] = newValue;
90
111
 
@@ -107,27 +128,27 @@ export const AMAProvider: React.FC<AMAProviderProps> = ({ children }) => {
107
128
  const allInitPromises: Promise<boolean>[] = [];
108
129
 
109
130
  const subscriptions: NativeEventSubscription[] = Object.entries(
110
- eventsMapping,
131
+ eventsMapping
111
132
  ).map(([eventName, contextKey]) => {
112
133
  allInitPromises.push(AccessibilityInfo[contextKey]());
113
134
 
114
135
  return AccessibilityInfo.addEventListener(
115
136
  eventName as AccessibilityEvents,
116
- handleAccessibilityInfoChanged(contextKey),
137
+ handleAccessibilityInfoChanged(contextKey)
117
138
  );
118
139
  });
119
140
 
120
- Promise.all(allInitPromises).then(promisesValues => {
141
+ Promise.all(allInitPromises).then((promisesValues) => {
121
142
  const newValues = Object.values(eventsMapping).reduce(
122
143
  (list, key, index) => {
123
144
  list[key] = promisesValues[index] as boolean;
124
145
 
125
146
  return list;
126
147
  },
127
- {} as AMAContextValue,
148
+ {} as AMAContextValue
128
149
  );
129
150
 
130
- setValues(oldValues => {
151
+ setValues((oldValues) => {
131
152
  return {
132
153
  ...oldValues,
133
154
  ...newValues,
@@ -136,52 +157,22 @@ export const AMAProvider: React.FC<AMAProviderProps> = ({ children }) => {
136
157
  });
137
158
 
138
159
  return () => {
139
- subscriptions.forEach(subscription => subscription?.remove());
160
+ subscriptions.forEach((subscription) => subscription?.remove());
140
161
  };
141
162
  }, []);
142
163
 
143
- const [failedItems, setFailedItems] = React.useState<string[]>([]);
144
-
145
164
  if (__DEV__) {
146
- const trackError = (id: string) => {
147
- if (failedItems.includes(id)) {
148
- return;
149
- }
150
-
151
- setFailedItems(items => [...items, id]);
152
-
153
- AccessibilityInfo.announceForAccessibility(
154
- "One or more component didn't pass the accessibility check, please check the console for more info",
155
- );
156
- };
157
-
158
- const removeError = (id: string) => {
159
- setFailedItems(items => {
160
- const index = items.indexOf(id);
161
-
162
- if (index >= 0) {
163
- items.splice(index);
164
-
165
- return [...items];
166
- }
167
-
168
- return items;
169
- });
170
- };
171
-
172
165
  return (
173
166
  <AMAContext.Provider
174
167
  value={{
175
168
  ...values,
176
- trackError,
177
- removeError,
178
- }}>
169
+ trackError: trackError || (() => { }),
170
+ }}
171
+ >
179
172
  <View style={{ flex: 1 }}>
180
173
  <>
181
174
  {children}
182
- {failedItems.length > 0 ? (
183
- <AMAError count={failedItems.length} />
184
- ) : null}
175
+ {AMAErrorOverlay && <AMAErrorOverlay issues={issues} />}
185
176
  </>
186
177
  </View>
187
178
  </AMAContext.Provider>
@@ -191,36 +182,9 @@ export const AMAProvider: React.FC<AMAProviderProps> = ({ children }) => {
191
182
  return <AMAContext.Provider value={values}>{children}</AMAContext.Provider>;
192
183
  };
193
184
 
194
- const AMAError = ({ count }: { count: number }) => {
195
- const error = `${count} component(s) didn't pass the accessibility check(s)`;
196
-
197
- return (
198
- <View
199
- accessibilityLabel={error}
200
- accessibilityHint="Please check the console for more info..."
201
- style={{
202
- paddingHorizontal: 24,
203
- paddingTop: 24,
204
- paddingBottom: 48,
205
- backgroundColor: RED,
206
- }}
207
- testID="amaError">
208
- <View accessible={true}>
209
- <Text
210
- style={{ color: 'white', fontSize: 16, lineHeight: 26 }}
211
- testID="amaError.message">
212
- {error}
213
- </Text>
214
- <Text style={{ color: 'white', fontSize: 16, lineHeight: 24 }}>
215
- Please check the console for more info...
216
- </Text>
217
- </View>
218
- </View>
219
- );
220
- };
221
-
222
185
  export const useAMAContext = () => {
223
186
  const context = React.useContext(AMAContext);
187
+
224
188
  if (!context) {
225
189
  throw new Error('Please wrap your app with <AMAProvider />');
226
190
  }
@@ -1,6 +1,5 @@
1
1
  import { render, waitFor } from '@testing-library/react-native';
2
2
  import * as React from 'react';
3
-
4
3
  import * as UseFocus from '../hooks/useFocus';
5
4
  import { AutofocusContainer } from './AutofocusContainer';
6
5
 
@@ -9,7 +8,7 @@ beforeEach(() => {
9
8
  });
10
9
 
11
10
  describe('AutofocusContainer', () => {
12
- it('it call setFocus when gets rendered', async () => {
11
+ it('call setFocus when gets rendered', async () => {
13
12
  const setFocus = jest.fn();
14
13
  jest.spyOn(UseFocus, 'useFocus').mockReturnValue({
15
14
  setFocus,
@@ -21,7 +20,7 @@ describe('AutofocusContainer', () => {
21
20
  </AutofocusContainer>,
22
21
  );
23
22
 
24
- await waitFor(() => expect(setFocus).toBeCalled());
23
+ await waitFor(() => expect(setFocus).toHaveBeenCalled());
25
24
  });
26
25
 
27
26
  it.each([undefined, true])(
@@ -38,7 +37,7 @@ describe('AutofocusContainer', () => {
38
37
  </AutofocusContainer>,
39
38
  );
40
39
 
41
- await waitFor(() => expect(setFocus).toBeCalled());
40
+ await waitFor(() => expect(setFocus).toHaveBeenCalled());
42
41
 
43
42
  expect(
44
43
  renderAPI.getByTestId('autofocusContainer.accessibleView'),
@@ -58,7 +57,7 @@ describe('AutofocusContainer', () => {
58
57
  </AutofocusContainer>,
59
58
  );
60
59
 
61
- await waitFor(() => expect(setFocus).toBeCalled());
60
+ await waitFor(() => expect(setFocus).toHaveBeenCalled());
62
61
 
63
62
  expect(
64
63
  renderAPI.queryByTestId('autofocusContainer.accessibleView'),
@@ -5,9 +5,21 @@ import {
5
5
  View,
6
6
  ViewProps,
7
7
  } from 'react-native';
8
-
9
8
  import { useFocus } from '../hooks/useFocus';
10
- import { PickAccessibleProps } from '@react-native-ama/internal';
9
+
10
+ type AccessibilityPropKeys =
11
+ | 'accessibilityActions'
12
+ | 'accessibilityElementsHidden'
13
+ | 'accessibilityHint'
14
+ | 'accessibilityLabel'
15
+ | 'accessibilityLiveRegion'
16
+ | 'accessibilityRole'
17
+ | 'accessibilityState'
18
+ | 'accessibilityViewIsModal'
19
+ | 'onAccessibilityAction'
20
+ | 'testID';
21
+
22
+ type PickAccessibleProps<T> = Pick<T, Extract<keyof T, AccessibilityPropKeys>>;
11
23
 
12
24
  type TouchableAccessibleProps =
13
25
  PickAccessibleProps<TouchableWithoutFeedbackProps>;
@@ -46,18 +58,21 @@ export const AutofocusContainer = ({
46
58
  return wrapChildrenInAccessibleView ? (
47
59
  <TouchableWithoutFeedback
48
60
  ref={containerRef}
49
- {...touchableContainerAccessibilityProps}>
61
+ {...touchableContainerAccessibilityProps}
62
+ >
50
63
  <View
51
64
  accessible={true}
52
65
  testID="autofocusContainer.accessibleView"
53
- {...viewProps}>
66
+ {...viewProps}
67
+ >
54
68
  {children}
55
69
  </View>
56
70
  </TouchableWithoutFeedback>
57
71
  ) : (
58
72
  <TouchableWithoutFeedback
59
73
  ref={containerRef}
60
- {...touchableContainerAccessibilityProps}>
74
+ {...touchableContainerAccessibilityProps}
75
+ >
61
76
  {children}
62
77
  </TouchableWithoutFeedback>
63
78
  );
@@ -1,33 +1,39 @@
1
- /* eslint-disable jest/no-disabled-tests */
2
1
  import { act, render } from '@testing-library/react-native';
3
2
  import { flushMicroTasks } from '@testing-library/react-native/build/flush-micro-tasks';
4
3
  import * as React from 'react';
5
4
  import { Pressable, Text } from 'react-native';
6
-
7
5
  import { AMAProvider } from './AMAProvider';
8
6
  import { HideChildrenFromAccessibilityTree } from './HideChildrenFromAccessibilityTree';
9
7
 
8
+ jest.mock('./AMAProvider', () => {
9
+ const originalModule = jest.requireActual('./AMAProvider');
10
+ return {
11
+ ...originalModule,
12
+ useAMAContext: jest.fn().mockReturnValue({ isScreenReaderEnabled: true }),
13
+ };
14
+ });
15
+
16
+ let useAMAContext: jest.Mock;
17
+
10
18
  beforeEach(() => {
11
19
  jest.clearAllMocks();
20
+ useAMAContext = jest.requireMock('./AMAProvider').useAMAContext;
21
+ useAMAContext.mockReturnValue({ isScreenReaderEnabled: true });
12
22
  });
13
23
 
14
- describe.skip('HideChildrenFromAccessibilityTree', () => {
24
+ describe('HideChildrenFromAccessibilityTree', () => {
15
25
  describe('iOS', () => {
16
26
  beforeEach(() => {
17
- const Platform = jest.requireActual(
18
- 'react-native/Libraries/Utilities/Platform',
19
- );
20
-
21
- Platform.select = (params: any) => {
22
- return params.ios;
23
- };
27
+ const rn = jest.requireMock('react-native');
28
+ rn.Platform.OS = 'ios';
29
+ rn.Platform.select = (params: any) => params.ios ?? params.default;
24
30
  });
25
31
 
26
32
  it('hides all the children from the accessibility tree when the screen reader is enabled', async () => {
27
33
  const { getByTestId } = await renderHideChildrenFromAccessibilityTree();
28
34
 
29
35
  ['test-text', 'test-button', 'nested-text'].forEach(testID => {
30
- expect(getByTestId(testID).props).toEqual(
36
+ expect(getByTestId(testID, { includeHiddenElements: true }).props).toEqual(
31
37
  expect.objectContaining({
32
38
  importantForAccessibility: 'no',
33
39
  accessibilityElementsHidden: true,
@@ -36,7 +42,7 @@ describe.skip('HideChildrenFromAccessibilityTree', () => {
36
42
  });
37
43
  });
38
44
 
39
- it('does nothing if the SR is turned off %s', async () => {
45
+ it('does nothing if the SR is turned off', async () => {
40
46
  const { getByTestId } = await renderHideChildrenFromAccessibilityTree({
41
47
  isScreenReaderEnabled: false,
42
48
  });
@@ -45,7 +51,6 @@ describe.skip('HideChildrenFromAccessibilityTree', () => {
45
51
  expect(getByTestId(testID).props).not.toHaveProperty(
46
52
  'importantForAccessibility',
47
53
  );
48
-
49
54
  expect(getByTestId(testID).props).not.toHaveProperty(
50
55
  'accessibilityElementsHidden',
51
56
  );
@@ -55,26 +60,22 @@ describe.skip('HideChildrenFromAccessibilityTree', () => {
55
60
 
56
61
  describe('Android', () => {
57
62
  beforeEach(() => {
58
- const Platform = jest.requireActual(
59
- 'react-native/Libraries/Utilities/Platform',
60
- );
61
-
62
- Platform.select = (params: any) => {
63
- return params.default;
64
- };
63
+ const rn = jest.requireMock('react-native');
64
+ rn.Platform.OS = 'android';
65
+ rn.Platform.select = (params: any) => params.default ?? params.android;
65
66
  });
66
67
 
67
68
  it('hides all the children from the accessibility tree when the screen reader is enabled', async () => {
68
69
  const { getByTestId } = await renderHideChildrenFromAccessibilityTree();
69
70
 
70
- expect(getByTestId('test-wrapper').props).toEqual(
71
+ expect(getByTestId('test-wrapper', { includeHiddenElements: true }).props).toEqual(
71
72
  expect.objectContaining({
72
73
  importantForAccessibility: 'no-hide-descendants',
73
74
  }),
74
75
  );
75
76
  });
76
77
 
77
- it('does nothing if the SR is turned off %s', async () => {
78
+ it('does nothing if the SR is turned off', async () => {
78
79
  const { queryByTestId } = await renderHideChildrenFromAccessibilityTree({
79
80
  isScreenReaderEnabled: false,
80
81
  });
@@ -110,20 +111,3 @@ const renderHideChildrenFromAccessibilityTree = async (params?: {
110
111
 
111
112
  return renderAPI;
112
113
  };
113
-
114
- let useAMAContext: jest.Mock;
115
-
116
- function mockAMAProvider() {
117
- const originalModule = jest.requireActual('./AMAProvider');
118
-
119
- useAMAContext = jest.fn().mockReturnValue({
120
- isScreenReaderEnabled: true,
121
- });
122
-
123
- return {
124
- ...originalModule,
125
- useAMAContext,
126
- };
127
- }
128
-
129
- jest.mock('./AMAProvider', () => mockAMAProvider());
@@ -1,6 +1,5 @@
1
- import React, { PropsWithChildren } from 'react';
1
+ import React, { PropsWithChildren, type JSX } from 'react';
2
2
  import { Platform, View } from 'react-native';
3
-
4
3
  import { useAMAContext } from './AMAProvider';
5
4
 
6
5
  type HideChildrenFromAccessibilityTreeProps = {
@@ -39,17 +38,19 @@ const HideChildrenFromAccessibilityTreeIOS = ({
39
38
  return hideChildrenFromAccessibilityTree(children);
40
39
  };
41
40
 
42
- const hideChildrenFromAccessibilityTree = (component: React.ReactNode): any => {
41
+ const hideChildrenFromAccessibilityTree = (component: React.ReactNode): React.ReactNode => {
43
42
  return (
44
43
  React.Children.map(component, child => {
45
- return React.isValidElement(child)
46
- ? React.cloneElement(child, {
47
- // @ts-ignore
48
- importantForAccessibility: 'no',
49
- accessibilityElementsHidden: true,
50
- children: hideChildrenFromAccessibilityTree(child.props.children),
51
- })
52
- : child;
44
+ if (React.isValidElement(child)) {
45
+ const element = child as React.ReactElement<{ children?: React.ReactNode }>;
46
+ return React.cloneElement(element, {
47
+ // @ts-ignore
48
+ importantForAccessibility: 'no',
49
+ accessibilityElementsHidden: true,
50
+ children: hideChildrenFromAccessibilityTree(element.props.children),
51
+ });
52
+ }
53
+ return child;
53
54
  }) || null
54
55
  );
55
56
  };
@@ -1,16 +1,29 @@
1
- import { SHELL_COLORS } from '@react-native-ama/internal';
2
1
  import { renderHook } from '@testing-library/react-native';
3
-
4
2
  import { useFocus } from './useFocus';
5
3
 
4
+ const SHELL_COLORS = {
5
+ BG_RED: '\x1b[41m',
6
+ RESET: '\x1b[0m',
7
+ BLUE: '\x1b[34m',
8
+ YELLOW: '\x1b[33m',
9
+ };
10
+
11
+ let findNodeHandleMock: jest.Mock;
12
+ let setAccessibilityFocusMock: jest.Mock;
13
+
6
14
  beforeEach(() => {
15
+ jest.useFakeTimers();
7
16
  jest.clearAllMocks();
8
-
9
17
  jest.spyOn(console, 'warn').mockImplementation();
18
+
19
+ const rn = jest.requireMock('react-native');
20
+ findNodeHandleMock = rn.findNodeHandle;
21
+ setAccessibilityFocusMock = rn.AccessibilityInfo.setAccessibilityFocus;
10
22
  });
11
23
 
12
- let findNodeHandleMock: jest.Mock;
13
- let setAccessibilityFocusMock: jest.Mock;
24
+ afterEach(() => {
25
+ jest.useRealTimers();
26
+ });
14
27
 
15
28
  describe('useFocus', () => {
16
29
  it.each([null, undefined])('does nothing if the Ref is %s', refElement => {
@@ -24,6 +37,7 @@ describe('useFocus', () => {
24
37
  findNodeHandleMock.mockReturnValue('element-id');
25
38
 
26
39
  renderHook(() => useFocus({ current: 'test-element' }));
40
+ jest.runAllTimers();
27
41
 
28
42
  expect(findNodeHandleMock).toHaveBeenCalledWith('test-element');
29
43
  expect(setAccessibilityFocusMock).toHaveBeenNthCalledWith(1, 'element-id');
@@ -70,6 +84,7 @@ describe('useFocus', () => {
70
84
  const { result } = renderHook(() => useFocus());
71
85
 
72
86
  result.current.setFocus('component' as any);
87
+ jest.runAllTimers();
73
88
 
74
89
  expect(findNodeHandleMock).toHaveBeenCalledWith('component');
75
90
  expect(setAccessibilityFocusMock).toHaveBeenNthCalledWith(
@@ -82,18 +97,3 @@ describe('useFocus', () => {
82
97
  );
83
98
  });
84
99
  });
85
-
86
- function mockReactNative() {
87
- findNodeHandleMock = jest.fn();
88
- setAccessibilityFocusMock = jest.fn();
89
-
90
- return {
91
- findNodeHandle: findNodeHandleMock,
92
- AccessibilityInfo: {
93
- setAccessibilityFocus: setAccessibilityFocusMock,
94
- },
95
- Platform: {},
96
- };
97
- }
98
-
99
- jest.mock('react-native', () => mockReactNative());
@@ -1,11 +1,19 @@
1
- import { SHELL_COLORS } from '@react-native-ama/internal';
2
1
  import * as React from 'react';
3
2
  import {
4
3
  AccessibilityInfo,
5
- InteractionManager,
6
4
  findNodeHandle,
5
+ InteractionManager,
7
6
  } from 'react-native';
8
7
 
8
+ const SHELL_COLORS = __DEV__
9
+ ? {
10
+ BG_RED: '\x1b[41m',
11
+ RESET: '\x1b[0m',
12
+ BLUE: '\x1b[34m',
13
+ YELLOW: '\x1b[33m',
14
+ }
15
+ : null;
16
+
9
17
  export const useFocus = (refComponent?: React.RefObject<any>) => {
10
18
  const setFocus = React.useCallback(
11
19
  (
@@ -13,7 +21,7 @@ export const useFocus = (refComponent?: React.RefObject<any>) => {
13
21
  | null
14
22
  | number
15
23
  | React.Component<any, any>
16
- | React.ComponentClass<any>,
24
+ | React.ComponentClass<any>
17
25
  ) => {
18
26
  if (!component) {
19
27
  return;
@@ -31,7 +39,7 @@ export const useFocus = (refComponent?: React.RefObject<any>) => {
31
39
  } else if (__DEV__) {
32
40
  console.warn(
33
41
  // @ts-ignore
34
- `${SHELL_COLORS.BG_RED}AMA.${SHELL_COLORS.RESET} ${SHELL_COLORS.BLUE}useFocus${SHELL_COLORS.RESET}: ${SHELL_COLORS.YELLOW}Ref element not found${SHELL_COLORS.RESET}`,
42
+ `${SHELL_COLORS.BG_RED}AMA.${SHELL_COLORS.RESET} ${SHELL_COLORS.BLUE}useFocus${SHELL_COLORS.RESET}: ${SHELL_COLORS.YELLOW}Ref element not found${SHELL_COLORS.RESET}`
35
43
  );
36
44
  }
37
45
  } catch (error) {
@@ -39,13 +47,13 @@ export const useFocus = (refComponent?: React.RefObject<any>) => {
39
47
  console.warn(
40
48
  // @ts-ignore
41
49
  `${SHELL_COLORS.BG_RED}AMA.${SHELL_COLORS.RESET} ${SHELL_COLORS.BLUE}useFocus${SHELL_COLORS.RESET}: ${SHELL_COLORS.YELLOW}Error finding node handle${SHELL_COLORS.RESET} \n`,
42
- error,
50
+ error
43
51
  );
44
52
  }
45
53
  }
46
54
  });
47
55
  },
48
- [],
56
+ []
49
57
  );
50
58
 
51
59
  React.useEffect(() => {
@@ -1,6 +1,5 @@
1
1
  import { renderHook } from '@testing-library/react-native';
2
2
  import { AccessibilityInfo, Platform } from 'react-native';
3
-
4
3
  import * as AMAProvider from '../components/AMAProvider';
5
4
  import { useTimedAction } from './useTimedAction';
6
5
 
@@ -1,6 +1,5 @@
1
1
  import { renderHook } from '@testing-library/react-native';
2
2
  import { Platform } from 'react-native';
3
-
4
3
  import * as AMAProvider from '../components/AMAProvider';
5
4
  import { useTimedAction } from './useTimedAction';
6
5
 
@@ -1,6 +1,5 @@
1
1
  import * as React from 'react';
2
2
  import { AccessibilityInfo, Platform } from 'react-native';
3
-
4
3
  import { useAMAContext } from '../components/AMAProvider';
5
4
 
6
5
  export const useTimedAction = () => {
package/src/index.ts CHANGED
@@ -13,7 +13,9 @@ export {
13
13
  export { HideChildrenFromAccessibilityTree } from './components/HideChildrenFromAccessibilityTree';
14
14
 
15
15
  // Hooks
16
- export { useButtonChecks } from './hooks/useButtonChecks';
17
- export { useChecks } from './hooks/useChecks';
18
16
  export { useFocus } from './hooks/useFocus';
19
17
  export { useTimedAction } from './hooks/useTimedAction';
18
+
19
+ export { default } from './ReactNativeAmaModule';
20
+ export { default as ReactNativeAmaView } from './ReactNativeAmaView';
21
+ export * from './ReactNativeAma.types';