|
1 | 1 | export const INJECTED_HELPERS = ` |
2 | 2 | (function() { |
3 | | - var __HELPERS_VERSION__ = 21; |
| 3 | + var __HELPERS_VERSION__ = 22; |
4 | 4 | if (globalThis.__RN_AGENT && globalThis.__RN_AGENT.__v === __HELPERS_VERSION__) return; |
5 | 5 | if (globalThis.__RN_AGENT) delete globalThis.__RN_AGENT; |
6 | 6 |
|
@@ -1247,6 +1247,87 @@ export const INJECTED_HELPERS = ` |
1247 | 1247 | }); |
1248 | 1248 | } |
1249 | 1249 |
|
| 1250 | + if (action === 'setFieldValue') { |
| 1251 | + // Issue #126 Gap A — explicit React Hook Form fallback. typeText's |
| 1252 | + // handler chain walks DOWN looking for a TextInput descendant with |
| 1253 | + // onChangeText/onChange. That works for wrapper-Pressable patterns |
| 1254 | + // where the inner TextInput is reachable, but fails when the field's |
| 1255 | + // value flows through field.onChange → FormProvider context → |
| 1256 | + // setValue. There's no inner TextInput-shaped fiber to find, because |
| 1257 | + // the design-system field calls field.onChange directly via a |
| 1258 | + // Controller render prop. |
| 1259 | + // |
| 1260 | + // Resolution: walk UP from the matched fiber (the testID anchor) |
| 1261 | + // looking for a Provider fiber whose memoizedProps.value duck-types |
| 1262 | + // as a React Hook Form UseFormReturn. Then call value.setValue( |
| 1263 | + // name, value, options). The closest ancestor wins (natural React |
| 1264 | + // context resolution), so nested forms behave intuitively. |
| 1265 | + var fieldName = opts.name; |
| 1266 | + var fieldValue = opts.value; |
| 1267 | + if (typeof fieldName !== 'string' || fieldName.length === 0) { |
| 1268 | + return JSON.stringify({ |
| 1269 | + error: 'setFieldValue requires opts.name (the RHF field name)', |
| 1270 | + testID: selector, |
| 1271 | + hint: 'Pass the same \`name\` string you used in \`useController({ name })\` or \`<Controller name="..." />\`.' |
| 1272 | + }); |
| 1273 | + } |
| 1274 | + var shouldValidate = opts.shouldValidate !== false; |
| 1275 | + var shouldDirty = opts.shouldDirty !== false; |
| 1276 | +
|
| 1277 | + var ANCESTOR_DEPTH_CAP = 32; |
| 1278 | + var ANCESTOR_VISIT_CAP = 100; |
| 1279 | + function looksLikeUseFormReturn(v) { |
| 1280 | + return ( |
| 1281 | + v && typeof v === 'object' |
| 1282 | + && typeof v.setValue === 'function' |
| 1283 | + && typeof v.getValues === 'function' |
| 1284 | + && v.control && typeof v.control === 'object' |
| 1285 | + ); |
| 1286 | + } |
| 1287 | + var ancestor = found.return; |
| 1288 | + var ancestorDepth = 0; |
| 1289 | + var ancestorVisits = 0; |
| 1290 | + var formReturn = null; |
| 1291 | + while (ancestor && ancestorDepth < ANCESTOR_DEPTH_CAP && ancestorVisits < ANCESTOR_VISIT_CAP) { |
| 1292 | + ancestorVisits++; |
| 1293 | + var aProps = ancestor.memoizedProps; |
| 1294 | + if (aProps && looksLikeUseFormReturn(aProps.value)) { |
| 1295 | + formReturn = aProps.value; |
| 1296 | + break; |
| 1297 | + } |
| 1298 | + ancestor = ancestor.return; |
| 1299 | + ancestorDepth++; |
| 1300 | + } |
| 1301 | + if (!formReturn) { |
| 1302 | + return JSON.stringify({ |
| 1303 | + error: 'setFieldValue: no FormProvider ancestor found', |
| 1304 | + testID: selector, |
| 1305 | + ancestorVisits: ancestorVisits, |
| 1306 | + hint: 'No React Hook Form FormProvider ancestor with setValue+getValues+control was reachable within ' + ANCESTOR_DEPTH_CAP + ' levels. Either the form is not wrapped in <FormProvider {...methods}>, or the testID anchor sits outside the form subtree. If you only need to fire onChangeText/onChange, use action="typeText" instead.' |
| 1307 | + }); |
| 1308 | + } |
| 1309 | + try { |
| 1310 | + formReturn.setValue(fieldName, fieldValue, { shouldValidate: shouldValidate, shouldDirty: shouldDirty }); |
| 1311 | + } catch (e) { |
| 1312 | + return JSON.stringify({ |
| 1313 | + error: 'setFieldValue: setValue threw: ' + (e && e.message ? e.message : String(e)), |
| 1314 | + testID: selector, |
| 1315 | + name: fieldName, |
| 1316 | + hint: 'The form was found but its setValue rejected the call. Common causes: name does not exist on the form, value type mismatch, or the form is in a transitioning state.' |
| 1317 | + }); |
| 1318 | + } |
| 1319 | + return JSON.stringify({ |
| 1320 | + success: true, |
| 1321 | + action: 'setFieldValue', |
| 1322 | + testID: selector, |
| 1323 | + name: fieldName, |
| 1324 | + value: fieldValue, |
| 1325 | + shouldValidate: shouldValidate, |
| 1326 | + shouldDirty: shouldDirty, |
| 1327 | + ancestorVisits: ancestorVisits |
| 1328 | + }); |
| 1329 | + } |
| 1330 | +
|
1250 | 1331 | if (action === 'scroll') { |
1251 | 1332 | var x = opts.scrollX !== undefined ? opts.scrollX : 0; |
1252 | 1333 | var y = opts.scrollY !== undefined ? opts.scrollY : 300; |
|
0 commit comments