@qontinui/ui-bridge-native 0.6.4 → 0.6.6

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.
@@ -1,5 +1,5 @@
1
1
  import { createContext, useRef, useState, useCallback, useEffect, useMemo, use } from 'react';
2
- import { StyleSheet, Platform } from 'react-native';
2
+ import { Dimensions, StyleSheet, Platform } from 'react-native';
3
3
  import { jsx, Fragment } from 'react/jsx-runtime';
4
4
 
5
5
  var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
@@ -14,6 +14,10 @@ function extractHandlerNames(props) {
14
14
  if (!props) return [];
15
15
  return Object.keys(props).filter((k) => typeof props[k] === "function");
16
16
  }
17
+ function matchesCurrentRoute(registrationRoute, currentRoute) {
18
+ if (registrationRoute == null || registrationRoute === "") return true;
19
+ return registrationRoute === currentRoute;
20
+ }
17
21
  function inferActions(type) {
18
22
  const baseActions = ["focus", "blur"];
19
23
  switch (type) {
@@ -219,13 +223,20 @@ var NativeUIBridgeRegistry = class {
219
223
  if (this.config.verbose) {
220
224
  console.log(`[ui-bridge-native] Registered element: ${id} (${type})`);
221
225
  }
222
- this.updateElementState(id, {
226
+ const seededState = {
223
227
  mounted: true,
224
228
  visible: true,
225
229
  enabled: true,
226
230
  focused: false,
227
231
  layout: null
228
- });
232
+ };
233
+ if (type === "input" && typeof props?.value === "string") {
234
+ seededState.value = props.value;
235
+ }
236
+ if (type === "text" && typeof label === "string") {
237
+ seededState.value = label;
238
+ }
239
+ this.updateElementState(id, seededState);
229
240
  return registered;
230
241
  }
231
242
  /**
@@ -387,6 +398,9 @@ var NativeUIBridgeRegistry = class {
387
398
  })
388
399
  };
389
400
  this.elements.set(id, updated);
401
+ if (element.type === "text" && labelChanged && typeof nextLabel === "string") {
402
+ this.updateElementState(id, { value: nextLabel });
403
+ }
390
404
  this.emit("element:registered", {
391
405
  id,
392
406
  type: element.type,
@@ -395,7 +409,22 @@ var NativeUIBridgeRegistry = class {
395
409
  return true;
396
410
  }
397
411
  /**
398
- * Update element props (for action execution)
412
+ * Update element props (for action execution).
413
+ *
414
+ * Side effect for `type: 'input'` elements: when `props.value` is a string,
415
+ * mirror it into `state.value` so AI drivers reading the registry don't see
416
+ * `state.value === undefined` until the user types. Before this mirror,
417
+ * controlled-input consumers (`<TextInput value={x} onChangeText={setX} />`
418
+ * with `captureProps({ value: x, onChangeText: setX })`) registered an
419
+ * input whose `state.value` only became defined after the FIRST
420
+ * `onChangeText` call — bridge consumers couldn't read the default value
421
+ * (e.g. a pre-populated API-URL input) until someone typed into it.
422
+ *
423
+ * Re-runs on every `updateElementProps` so a parent passing a fresh
424
+ * `value` prop (controlled re-render) keeps the registry in sync. The
425
+ * mirror is gated on `type === 'input'` to avoid touching non-input
426
+ * elements that may carry an unrelated `value` prop (e.g. a Switch's
427
+ * boolean value, which lives on `state.checked`).
399
428
  */
400
429
  updateElementProps(id, props) {
401
430
  const element = this.elements.get(id);
@@ -405,6 +434,12 @@ var NativeUIBridgeRegistry = class {
405
434
  props: { ...element.props, ...props }
406
435
  };
407
436
  this.elements.set(id, updated);
437
+ if (element.type === "input" && Object.prototype.hasOwnProperty.call(props, "value") && typeof props.value === "string") {
438
+ const currentState = updated.getState();
439
+ if (currentState.value !== props.value) {
440
+ this.updateElementState(id, { value: props.value });
441
+ }
442
+ }
408
443
  }
409
444
  }
410
445
  /**
@@ -615,7 +650,7 @@ var NativeUIBridgeRegistry = class {
615
650
  let elements = options?.visibleOnly ? this.getMountedVisibleElements() : this.getAllElements();
616
651
  if (options?.currentRouteOnly && resolvedRoute.currentRoute) {
617
652
  const currentRoute = resolvedRoute.currentRoute;
618
- elements = elements.filter((e) => e.registrationRoute === currentRoute);
653
+ elements = elements.filter((e) => matchesCurrentRoute(e.registrationRoute, currentRoute));
619
654
  }
620
655
  const snapshot = {
621
656
  timestamp: Date.now(),
@@ -1554,15 +1589,9 @@ function success(data) {
1554
1589
  function error(message, code) {
1555
1590
  return { success: false, error: message, code, timestamp: Date.now() };
1556
1591
  }
1557
- function createDesignHandlers(registry) {
1592
+ function createDesignHandlers(registry, viewportProvider) {
1558
1593
  function getScreenDimensions() {
1559
- try {
1560
- const { Dimensions } = __require("react-native");
1561
- const screen = Dimensions.get("screen");
1562
- return { width: screen.width, height: screen.height };
1563
- } catch {
1564
- return { width: 0, height: 0 };
1565
- }
1594
+ return viewportProvider?.() ?? { width: 0, height: 0 };
1566
1595
  }
1567
1596
  return {
1568
1597
  // 1. GET /design/element/:id/styles
@@ -2192,15 +2221,6 @@ async function executeWorkflowStep(step, registry, executor) {
2192
2221
  };
2193
2222
  }
2194
2223
  }
2195
- function getWindowDimensions() {
2196
- try {
2197
- const { Dimensions } = __require("react-native");
2198
- const win = Dimensions.get("window");
2199
- return { width: win.width, height: win.height };
2200
- } catch {
2201
- return { width: 0, height: 0 };
2202
- }
2203
- }
2204
2224
  function success2(data) {
2205
2225
  return {
2206
2226
  success: true,
@@ -2217,7 +2237,7 @@ function error2(message, code) {
2217
2237
  };
2218
2238
  }
2219
2239
  function createServerHandlers(registry, executor, config) {
2220
- const designHandlers = createDesignHandlers(registry);
2240
+ const designHandlers = createDesignHandlers(registry, config?.viewportProvider);
2221
2241
  return {
2222
2242
  // Elements
2223
2243
  getElements: async (ctx) => {
@@ -2225,7 +2245,7 @@ function createServerHandlers(registry, executor, config) {
2225
2245
  const forRoute = ctx.query?.route || ctx.body?.route;
2226
2246
  let allElements = visibleOnly ? registry.getMountedVisibleElements() : registry.getAllElements();
2227
2247
  if (forRoute) {
2228
- allElements = allElements.filter((e) => e.registrationRoute === forRoute);
2248
+ allElements = allElements.filter((e) => matchesCurrentRoute(e.registrationRoute, forRoute));
2229
2249
  }
2230
2250
  const elements = allElements.map((e) => {
2231
2251
  const handlers = extractHandlerNames(e.props);
@@ -2408,7 +2428,7 @@ function createServerHandlers(registry, executor, config) {
2408
2428
  },
2409
2429
  getPageHealth: async (ctx) => {
2410
2430
  const bodyViewport = ctx.body?.viewport;
2411
- const viewport = bodyViewport ?? getWindowDimensions();
2431
+ const viewport = bodyViewport ?? config?.viewportProvider?.() ?? { width: 0, height: 0 };
2412
2432
  const elements = registry.getAllElements().map((e) => ({
2413
2433
  type: e.type,
2414
2434
  state: e.getState()
@@ -3379,7 +3399,8 @@ var NativeUIBridgeServer = class {
3379
3399
  this.handlers = createServerHandlers(registry, executor, {
3380
3400
  appInfo: this.config.appInfo,
3381
3401
  consoleErrorBuffer: this.consoleErrorBuffer,
3382
- networkRequestBuffer: this.networkRequestBuffer
3402
+ networkRequestBuffer: this.networkRequestBuffer,
3403
+ viewportProvider: this.config.viewportProvider
3383
3404
  });
3384
3405
  this.handlers.getMethods = async () => {
3385
3406
  const testHooks = this.config.testHooks === true;
@@ -5145,7 +5166,17 @@ function UIBridgeNativeProvider({
5145
5166
  serverPort: config.serverPort || 8087,
5146
5167
  cors: true,
5147
5168
  appInfo: config.appInfo,
5148
- testHooks: features.testHooks === true
5169
+ testHooks: features.testHooks === true,
5170
+ // Injected device-viewport getter for POST /control/page-health. The
5171
+ // server doesn't import `react-native` itself — the require/import
5172
+ // pattern there crashed the host RN app in 0.6.3/0.6.4 (Metro/Hermes
5173
+ // raised `unknownModuleError` past every try/catch). This provider
5174
+ // already has a live react-native import, so it's the safe injection
5175
+ // point. See feedback_metro_require_gotcha for the full incident.
5176
+ viewportProvider: () => {
5177
+ const win = Dimensions.get("window");
5178
+ return { width: win.width, height: win.height };
5179
+ }
5149
5180
  });
5150
5181
  server.setAdapter(serverAdapter);
5151
5182
  if (navigationProvider) {
@@ -5240,7 +5271,11 @@ function UIBridgeNativeProvider({
5240
5271
  serverPort: config.serverPort || 8087,
5241
5272
  cors: true,
5242
5273
  appInfo: config.appInfo,
5243
- testHooks: features.testHooks === true
5274
+ testHooks: features.testHooks === true,
5275
+ viewportProvider: () => {
5276
+ const win = Dimensions.get("window");
5277
+ return { width: win.width, height: win.height };
5278
+ }
5244
5279
  });
5245
5280
  if (navigationProvider) bareServer.setNavigationProvider(navigationProvider);
5246
5281
  if (screenshotProvider) bareServer.setScreenshotProvider(screenshotProvider);