@mobileai/react-native 0.9.4 → 0.9.5

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.
@@ -3,64 +3,41 @@
3
3
  /**
4
4
  * Type Tool — Reliable multi-strategy text input.
5
5
  *
6
- * Strategy chain (tried in order, first success wins):
6
+ * For uncontrolled TextInputs (defaultValue, no onChangeText):
7
+ * 1. Walk fiber subtree (BFS) to find the native host view whose
8
+ * memoizedProps has `onChange` — this is RN's internal `_onChange`.
9
+ * 2. ALSO walk to find the native stateNode with `setNativeProps` to
10
+ * update the VISUAL text in the native view.
7
11
  *
8
- * 1. onChangeText developer's controlled component wired React state.
9
- * calls element.props.onChangeText(text) directly.
12
+ * Both steps are needed:
13
+ * - `onChange` updates React's internal lastNativeText state
14
+ * - `setNativeProps` → updates what the user sees on screen
10
15
  *
11
- * 2. Fiber subtree walk for uncontrolled TextInputs (defaultValue only).
12
- * React Native's TextInput.js always creates an internal `_onChange` handler
13
- * and passes it as `onChange` to the native host view (RCTTextInputView /
14
- * AndroidTextInput). That `_onChange` internally calls `props.onChangeText`
15
- * and updates native text state.
16
- *
17
- * We walk the fiber subtree (behavior-based, no tag numbers) to find any
18
- * descendant node whose memoizedProps.onChange is a function. Then we call
19
- * it with a synthetic TextInputChangeEvent. This triggers RN's internal
20
- * `_onChange` which calls `setLastNativeText` and updates the native view.
21
- *
22
- * Why this is robust:
23
- * - No hardcoded fiber tag numbers (host component tags can change across versions)
24
- * - No dependency on setNativeProps (deprecated in New Architecture / Fabric)
25
- * - Uses the same code path as a real user typing — RN's own _onChange handler
16
+ * No hardcoded fiber tag numbers. Detection is purely behavior-based.
26
17
  */
27
18
 
28
19
  import { walkFiberTree } from "../core/FiberTreeWalker.js";
29
- /**
30
- * Walk a fiber subtree to find the first descendant whose memoizedProps
31
- * has an `onChange` function. This is behavior-based — we don't check
32
- * fiber tags, component names, or any React internal that could change.
33
- * We just look for the prop that RN's TextInput always wires.
34
- */
35
- function findNativeOnChange(fiber, maxDepth = 8) {
36
- if (!fiber) return null;
37
- let current = fiber.child;
38
-
39
- // BFS-style walk through the fiber children
40
- const queue = [];
41
- if (current) queue.push({
42
- node: current,
20
+ /** BFS through fiber children. Returns first node where predicate matches. */
21
+ function findFiberNode(rootFiber, predicate, maxDepth = 10) {
22
+ if (!rootFiber?.child) return null;
23
+ const queue = [{
24
+ node: rootFiber.child,
43
25
  depth: 0
44
- });
26
+ }];
45
27
  while (queue.length > 0) {
46
28
  const {
47
29
  node,
48
- depth: d
30
+ depth
49
31
  } = queue.shift();
50
- if (d > maxDepth) continue;
51
- const props = node.memoizedProps;
52
- if (props && typeof props.onChange === 'function') {
53
- return props.onChange;
54
- }
55
-
56
- // Add child and sibling
32
+ if (!node || depth > maxDepth) continue;
33
+ if (predicate(node)) return node;
57
34
  if (node.child) queue.push({
58
35
  node: node.child,
59
- depth: d + 1
36
+ depth: depth + 1
60
37
  });
61
38
  if (node.sibling) queue.push({
62
39
  node: node.sibling,
63
- depth: d + 1
40
+ depth: depth + 1
64
41
  });
65
42
  }
66
43
  return null;
@@ -91,9 +68,9 @@ export function createTypeTool(context) {
91
68
  }
92
69
  const props = element.props;
93
70
  const label = element.label || `[${element.type}]`;
71
+ const fiberNode = element.fiberNode;
94
72
 
95
73
  // ── Strategy 1: controlled via onChangeText ───────────────────────────
96
- // App developer wired onChangeText={setText} — most reliable.
97
74
  if (typeof props.onChangeText === 'function') {
98
75
  try {
99
76
  props.onChangeText(args.text);
@@ -104,33 +81,46 @@ export function createTypeTool(context) {
104
81
  }
105
82
  }
106
83
 
107
- // ── Strategy 2: fiber subtree walk for native onChange ─────────────────
108
- // For uncontrolled TextInputs (defaultValue only, no onChangeText).
109
- // RN's TextInput.js creates _onChange internally and passes it as
110
- // onChange to the native host view. We find that handler and call it
111
- // with a synthetic TextInputChangeEvent.
112
- const fiberNode = element.fiberNode;
84
+ // ── Strategy 2: uncontrolled find native onChange + setNativeProps ──
85
+ // For TextInputs with defaultValue only.
86
+ // We need BOTH:
87
+ // a) find the onChange handler (RN's internal _onChange) to update React state
88
+ // b) find the native stateNode to call setNativeProps to update visual display
113
89
  if (fiberNode) {
114
- // First check the matched fiber itself
115
- const directOnChange = fiberNode.memoizedProps?.onChange;
116
- const onChange = typeof directOnChange === 'function' ? directOnChange : findNativeOnChange(fiberNode);
117
- if (onChange) {
90
+ // Find native onChange handler (behavior-based, no tag numbers)
91
+ const nativeOnChangeFiber = fiberNode.memoizedProps?.onChange ? fiberNode : findFiberNode(fiberNode, n => typeof n.memoizedProps?.onChange === 'function');
92
+
93
+ // Find native stateNode (host component with setNativeProps)
94
+ const nativeStateFiber = fiberNode.stateNode?.setNativeProps ? fiberNode : findFiberNode(fiberNode, n => n.stateNode && typeof n.stateNode.setNativeProps === 'function');
95
+ const onChange = nativeOnChangeFiber?.memoizedProps?.onChange;
96
+ const nativeInstance = nativeStateFiber?.stateNode;
97
+ if (onChange || nativeInstance) {
118
98
  try {
119
- onChange({
120
- nativeEvent: {
121
- text: args.text,
122
- eventCount: 0,
123
- target: 0
124
- }
125
- });
99
+ // Step 1: Update visual text in native view
100
+ if (nativeInstance && typeof nativeInstance.setNativeProps === 'function') {
101
+ nativeInstance.setNativeProps({
102
+ text: args.text
103
+ });
104
+ }
105
+
106
+ // Step 2: Notify React's internal onChange so lastNativeText stays in sync
107
+ if (typeof onChange === 'function') {
108
+ onChange({
109
+ nativeEvent: {
110
+ text: args.text,
111
+ eventCount: 1,
112
+ target: 0
113
+ }
114
+ });
115
+ }
126
116
  await new Promise(resolve => setTimeout(resolve, 300));
127
117
  return `✅ Typed "${args.text}" into [${args.index}] "${label}"`;
128
118
  } catch (err) {
129
- return `❌ onChange failed: ${err.message}`;
119
+ return `❌ Type failed: ${err.message}`;
130
120
  }
131
121
  }
132
122
  }
133
- return `❌ Element [${args.index}] "${label}" is not a typeable text input. No onChangeText or onChange handler found in fiber tree.`;
123
+ return `❌ Element [${args.index}] "${label}" is not a typeable text input. No onChange or native stateNode found in fiber tree.`;
134
124
  }
135
125
  };
136
126
  }
@@ -1 +1 @@
1
- {"version":3,"names":["walkFiberTree","findNativeOnChange","fiber","maxDepth","current","child","queue","push","node","depth","length","d","shift","props","memoizedProps","onChange","sibling","createTypeTool","context","name","description","parameters","index","type","required","text","execute","args","interactives","elements","getRootRef","getWalkConfig","element","find","el","label","onChangeText","Promise","resolve","setTimeout","err","message","fiberNode","directOnChange","nativeEvent","eventCount","target"],"sourceRoot":"../../../src","sources":["tools/typeTool.ts"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["walkFiberTree","findFiberNode","rootFiber","predicate","maxDepth","child","queue","node","depth","length","shift","push","sibling","createTypeTool","context","name","description","parameters","index","type","required","text","execute","args","interactives","elements","getRootRef","getWalkConfig","element","find","el","props","label","fiberNode","onChangeText","Promise","resolve","setTimeout","err","message","nativeOnChangeFiber","memoizedProps","onChange","n","nativeStateFiber","stateNode","setNativeProps","nativeInstance","nativeEvent","eventCount","target"],"sourceRoot":"../../../src","sources":["tools/typeTool.ts"],"mappings":"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","ignoreList":[]}
@@ -1,26 +1,17 @@
1
1
  /**
2
2
  * Type Tool — Reliable multi-strategy text input.
3
3
  *
4
- * Strategy chain (tried in order, first success wins):
4
+ * For uncontrolled TextInputs (defaultValue, no onChangeText):
5
+ * 1. Walk fiber subtree (BFS) to find the native host view whose
6
+ * memoizedProps has `onChange` — this is RN's internal `_onChange`.
7
+ * 2. ALSO walk to find the native stateNode with `setNativeProps` to
8
+ * update the VISUAL text in the native view.
5
9
  *
6
- * 1. onChangeText developer's controlled component wired React state.
7
- * calls element.props.onChangeText(text) directly.
10
+ * Both steps are needed:
11
+ * - `onChange` updates React's internal lastNativeText state
12
+ * - `setNativeProps` → updates what the user sees on screen
8
13
  *
9
- * 2. Fiber subtree walk for uncontrolled TextInputs (defaultValue only).
10
- * React Native's TextInput.js always creates an internal `_onChange` handler
11
- * and passes it as `onChange` to the native host view (RCTTextInputView /
12
- * AndroidTextInput). That `_onChange` internally calls `props.onChangeText`
13
- * and updates native text state.
14
- *
15
- * We walk the fiber subtree (behavior-based, no tag numbers) to find any
16
- * descendant node whose memoizedProps.onChange is a function. Then we call
17
- * it with a synthetic TextInputChangeEvent. This triggers RN's internal
18
- * `_onChange` which calls `setLastNativeText` and updates the native view.
19
- *
20
- * Why this is robust:
21
- * - No hardcoded fiber tag numbers (host component tags can change across versions)
22
- * - No dependency on setNativeProps (deprecated in New Architecture / Fabric)
23
- * - Uses the same code path as a real user typing — RN's own _onChange handler
14
+ * No hardcoded fiber tag numbers. Detection is purely behavior-based.
24
15
  */
25
16
  import type { AgentTool, ToolContext } from './types';
26
17
  export declare function createTypeTool(context: ToolContext): AgentTool;
@@ -1 +1 @@
1
- {"version":3,"file":"typeTool.d.ts","sourceRoot":"","sources":["../../../../src/tools/typeTool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAkCtD,wBAAgB,cAAc,CAAC,OAAO,EAAE,WAAW,GAAG,SAAS,CAgE9D"}
1
+ {"version":3,"file":"typeTool.d.ts","sourceRoot":"","sources":["../../../../src/tools/typeTool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAgBtD,wBAAgB,cAAc,CAAC,OAAO,EAAE,WAAW,GAAG,SAAS,CA+E9D"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mobileai/react-native",
3
- "version": "0.9.4",
3
+ "version": "0.9.5",
4
4
  "description": "Build autonomous AI agents for React Native and Expo apps. Provides AI-native UI traversal, tool calling, and structured reasoning.",
5
5
  "main": "./lib/module/index.js",
6
6
  "source": "./src/index.ts",
@@ -1,60 +1,33 @@
1
1
  /**
2
2
  * Type Tool — Reliable multi-strategy text input.
3
3
  *
4
- * Strategy chain (tried in order, first success wins):
4
+ * For uncontrolled TextInputs (defaultValue, no onChangeText):
5
+ * 1. Walk fiber subtree (BFS) to find the native host view whose
6
+ * memoizedProps has `onChange` — this is RN's internal `_onChange`.
7
+ * 2. ALSO walk to find the native stateNode with `setNativeProps` to
8
+ * update the VISUAL text in the native view.
5
9
  *
6
- * 1. onChangeText developer's controlled component wired React state.
7
- * calls element.props.onChangeText(text) directly.
10
+ * Both steps are needed:
11
+ * - `onChange` updates React's internal lastNativeText state
12
+ * - `setNativeProps` → updates what the user sees on screen
8
13
  *
9
- * 2. Fiber subtree walk for uncontrolled TextInputs (defaultValue only).
10
- * React Native's TextInput.js always creates an internal `_onChange` handler
11
- * and passes it as `onChange` to the native host view (RCTTextInputView /
12
- * AndroidTextInput). That `_onChange` internally calls `props.onChangeText`
13
- * and updates native text state.
14
- *
15
- * We walk the fiber subtree (behavior-based, no tag numbers) to find any
16
- * descendant node whose memoizedProps.onChange is a function. Then we call
17
- * it with a synthetic TextInputChangeEvent. This triggers RN's internal
18
- * `_onChange` which calls `setLastNativeText` and updates the native view.
19
- *
20
- * Why this is robust:
21
- * - No hardcoded fiber tag numbers (host component tags can change across versions)
22
- * - No dependency on setNativeProps (deprecated in New Architecture / Fabric)
23
- * - Uses the same code path as a real user typing — RN's own _onChange handler
14
+ * No hardcoded fiber tag numbers. Detection is purely behavior-based.
24
15
  */
25
16
 
26
17
  import { walkFiberTree } from '../core/FiberTreeWalker';
27
18
  import type { AgentTool, ToolContext } from './types';
28
19
 
29
- /**
30
- * Walk a fiber subtree to find the first descendant whose memoizedProps
31
- * has an `onChange` function. This is behavior-based — we don't check
32
- * fiber tags, component names, or any React internal that could change.
33
- * We just look for the prop that RN's TextInput always wires.
34
- */
35
- function findNativeOnChange(fiber: any, maxDepth = 8): ((event: any) => void) | null {
36
- if (!fiber) return null;
37
-
38
- let current: any = fiber.child;
39
-
40
- // BFS-style walk through the fiber children
41
- const queue: { node: any; depth: number }[] = [];
42
- if (current) queue.push({ node: current, depth: 0 });
43
-
20
+ /** BFS through fiber children. Returns first node where predicate matches. */
21
+ function findFiberNode(rootFiber: any, predicate: (node: any) => boolean, maxDepth = 10): any | null {
22
+ if (!rootFiber?.child) return null;
23
+ const queue: { node: any; depth: number }[] = [{ node: rootFiber.child, depth: 0 }];
44
24
  while (queue.length > 0) {
45
- const { node, depth: d } = queue.shift()!;
46
- if (d > maxDepth) continue;
47
-
48
- const props = node.memoizedProps;
49
- if (props && typeof props.onChange === 'function') {
50
- return props.onChange;
51
- }
52
-
53
- // Add child and sibling
54
- if (node.child) queue.push({ node: node.child, depth: d + 1 });
55
- if (node.sibling) queue.push({ node: node.sibling, depth: d + 1 });
25
+ const { node, depth } = queue.shift()!;
26
+ if (!node || depth > maxDepth) continue;
27
+ if (predicate(node)) return node;
28
+ if (node.child) queue.push({ node: node.child, depth: depth + 1 });
29
+ if (node.sibling) queue.push({ node: node.sibling, depth: depth + 1 });
56
30
  }
57
-
58
31
  return null;
59
32
  }
60
33
 
@@ -76,9 +49,9 @@ export function createTypeTool(context: ToolContext): AgentTool {
76
49
 
77
50
  const props = element.props;
78
51
  const label = element.label || `[${element.type}]`;
52
+ const fiberNode = element.fiberNode;
79
53
 
80
54
  // ── Strategy 1: controlled via onChangeText ───────────────────────────
81
- // App developer wired onChangeText={setText} — most reliable.
82
55
  if (typeof props.onChangeText === 'function') {
83
56
  try {
84
57
  props.onChangeText(args.text);
@@ -89,37 +62,52 @@ export function createTypeTool(context: ToolContext): AgentTool {
89
62
  }
90
63
  }
91
64
 
92
- // ── Strategy 2: fiber subtree walk for native onChange ─────────────────
93
- // For uncontrolled TextInputs (defaultValue only, no onChangeText).
94
- // RN's TextInput.js creates _onChange internally and passes it as
95
- // onChange to the native host view. We find that handler and call it
96
- // with a synthetic TextInputChangeEvent.
97
- const fiberNode = element.fiberNode;
65
+ // ── Strategy 2: uncontrolled find native onChange + setNativeProps ──
66
+ // For TextInputs with defaultValue only.
67
+ // We need BOTH:
68
+ // a) find the onChange handler (RN's internal _onChange) to update React state
69
+ // b) find the native stateNode to call setNativeProps to update visual display
98
70
  if (fiberNode) {
99
- // First check the matched fiber itself
100
- const directOnChange = fiberNode.memoizedProps?.onChange;
101
- const onChange = typeof directOnChange === 'function'
102
- ? directOnChange
103
- : findNativeOnChange(fiberNode);
71
+ // Find native onChange handler (behavior-based, no tag numbers)
72
+ const nativeOnChangeFiber = fiberNode.memoizedProps?.onChange
73
+ ? fiberNode
74
+ : findFiberNode(fiberNode, n => typeof n.memoizedProps?.onChange === 'function');
104
75
 
105
- if (onChange) {
76
+ // Find native stateNode (host component with setNativeProps)
77
+ const nativeStateFiber = fiberNode.stateNode?.setNativeProps
78
+ ? fiberNode
79
+ : findFiberNode(fiberNode, n => n.stateNode && typeof n.stateNode.setNativeProps === 'function');
80
+
81
+ const onChange = nativeOnChangeFiber?.memoizedProps?.onChange;
82
+ const nativeInstance = nativeStateFiber?.stateNode;
83
+
84
+ if (onChange || nativeInstance) {
106
85
  try {
107
- onChange({
108
- nativeEvent: {
109
- text: args.text,
110
- eventCount: 0,
111
- target: 0,
112
- },
113
- });
86
+ // Step 1: Update visual text in native view
87
+ if (nativeInstance && typeof nativeInstance.setNativeProps === 'function') {
88
+ nativeInstance.setNativeProps({ text: args.text });
89
+ }
90
+
91
+ // Step 2: Notify React's internal onChange so lastNativeText stays in sync
92
+ if (typeof onChange === 'function') {
93
+ onChange({
94
+ nativeEvent: {
95
+ text: args.text,
96
+ eventCount: 1,
97
+ target: 0,
98
+ },
99
+ });
100
+ }
101
+
114
102
  await new Promise(resolve => setTimeout(resolve, 300));
115
103
  return `✅ Typed "${args.text}" into [${args.index}] "${label}"`;
116
104
  } catch (err: any) {
117
- return `❌ onChange failed: ${err.message}`;
105
+ return `❌ Type failed: ${err.message}`;
118
106
  }
119
107
  }
120
108
  }
121
109
 
122
- return `❌ Element [${args.index}] "${label}" is not a typeable text input. No onChangeText or onChange handler found in fiber tree.`;
110
+ return `❌ Element [${args.index}] "${label}" is not a typeable text input. No onChange or native stateNode found in fiber tree.`;
123
111
  },
124
112
  };
125
113
  }