@qontinui/ui-bridge-native 0.6.9 → 0.6.11

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 (45) hide show
  1. package/dist/control/action-executor.d.ts.map +1 -1
  2. package/dist/control/index.js +2 -1
  3. package/dist/control/index.js.map +1 -1
  4. package/dist/control/index.mjs +2 -1
  5. package/dist/control/index.mjs.map +1 -1
  6. package/dist/core/index.js +232 -1
  7. package/dist/core/index.js.map +1 -1
  8. package/dist/core/index.mjs +232 -2
  9. package/dist/core/index.mjs.map +1 -1
  10. package/dist/core/registry.d.ts +46 -1
  11. package/dist/core/registry.d.ts.map +1 -1
  12. package/dist/core/types.d.ts +114 -0
  13. package/dist/core/types.d.ts.map +1 -1
  14. package/dist/core/vision-fields.d.ts +142 -0
  15. package/dist/core/vision-fields.d.ts.map +1 -0
  16. package/dist/debug/index.js.map +1 -1
  17. package/dist/debug/index.mjs.map +1 -1
  18. package/dist/index.d.ts +3 -0
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +371 -20
  21. package/dist/index.js.map +1 -1
  22. package/dist/index.mjs +365 -22
  23. package/dist/index.mjs.map +1 -1
  24. package/dist/react/UIBridgeNativeProvider.d.ts.map +1 -1
  25. package/dist/react/index.js +323 -20
  26. package/dist/react/index.js.map +1 -1
  27. package/dist/react/index.mjs +324 -21
  28. package/dist/react/index.mjs.map +1 -1
  29. package/dist/react/useUIElement.d.ts.map +1 -1
  30. package/dist/server/bind-retry.d.ts +64 -0
  31. package/dist/server/bind-retry.d.ts.map +1 -0
  32. package/dist/server/handlers.d.ts.map +1 -1
  33. package/dist/server/http-server.d.ts +9 -1
  34. package/dist/server/http-server.d.ts.map +1 -1
  35. package/dist/server/index.d.ts +2 -0
  36. package/dist/server/index.d.ts.map +1 -1
  37. package/dist/server/index.js +275 -13
  38. package/dist/server/index.js.map +1 -1
  39. package/dist/server/index.mjs +274 -14
  40. package/dist/server/index.mjs.map +1 -1
  41. package/dist/server/observability.d.ts +4 -3
  42. package/dist/server/observability.d.ts.map +1 -1
  43. package/dist/server/types.d.ts +10 -0
  44. package/dist/server/types.d.ts.map +1 -1
  45. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"UIBridgeNativeProvider.d.ts","sourceRoot":"","sources":["../../src/react/UIBridgeNativeProvider.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"UIBridgeNativeProvider.d.ts","sourceRoot":"","sources":["../../src/react/UIBridgeNativeProvider.tsx"],"names":[],"mappings":"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"}
@@ -11,6 +11,179 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
11
11
  throw Error('Dynamic require of "' + x + '" is not supported');
12
12
  });
13
13
 
14
+ // src/core/vision-fields.ts
15
+ var INTERACTIVE_HANDLER_NAMES = /* @__PURE__ */ new Set([
16
+ "onPress",
17
+ "onPressIn",
18
+ "onPressOut",
19
+ "onLongPress",
20
+ "onChangeText",
21
+ "onValueChange",
22
+ "onChange",
23
+ "onSubmitEditing",
24
+ "onClick",
25
+ "onTouchStart",
26
+ "onTouchEnd"
27
+ ]);
28
+ var INTERACTIVE_TYPES = /* @__PURE__ */ new Set([
29
+ "button",
30
+ "input",
31
+ "switch",
32
+ "checkbox",
33
+ "radio",
34
+ "touchable",
35
+ "pressable",
36
+ "listItem"
37
+ ]);
38
+ function roleForType(type) {
39
+ switch (type) {
40
+ case "button":
41
+ case "touchable":
42
+ case "pressable":
43
+ return "button";
44
+ case "input":
45
+ return "textbox";
46
+ case "text":
47
+ return "text";
48
+ case "switch":
49
+ return "switch";
50
+ case "checkbox":
51
+ return "checkbox";
52
+ case "radio":
53
+ return "radio";
54
+ case "image":
55
+ return "img";
56
+ case "list":
57
+ return "list";
58
+ case "listItem":
59
+ return "listitem";
60
+ case "modal":
61
+ return "dialog";
62
+ case "scroll":
63
+ case "view":
64
+ case "custom":
65
+ default:
66
+ return void 0;
67
+ }
68
+ }
69
+ function deriveInteractable(type, handlerNames) {
70
+ if (INTERACTIVE_TYPES.has(type)) return true;
71
+ if (handlerNames) {
72
+ for (const name of handlerNames) {
73
+ if (INTERACTIVE_HANDLER_NAMES.has(name)) return true;
74
+ }
75
+ }
76
+ return false;
77
+ }
78
+ function deriveText(state, label) {
79
+ const candidates = [state.value, state.textContent, label];
80
+ for (const c of candidates) {
81
+ if (typeof c === "string") {
82
+ const trimmed = c.trim();
83
+ if (trimmed.length > 0) return trimmed;
84
+ }
85
+ }
86
+ return void 0;
87
+ }
88
+ var NAMED_COLORS = {
89
+ black: { r: 0, g: 0, b: 0 },
90
+ white: { r: 255, g: 255, b: 255 },
91
+ red: { r: 255, g: 0, b: 0 },
92
+ green: { r: 0, g: 128, b: 0 },
93
+ blue: { r: 0, g: 0, b: 255 },
94
+ gray: { r: 128, g: 128, b: 128 },
95
+ grey: { r: 128, g: 128, b: 128 },
96
+ silver: { r: 192, g: 192, b: 192 },
97
+ transparent: { r: 0, g: 0, b: 0 },
98
+ orange: { r: 255, g: 165, b: 0 },
99
+ yellow: { r: 255, g: 255, b: 0 },
100
+ purple: { r: 128, g: 0, b: 128 },
101
+ navy: { r: 0, g: 0, b: 128 }
102
+ };
103
+ var clamp255 = (n) => Math.max(0, Math.min(255, Math.round(n)));
104
+ function parseColorToRgb(input) {
105
+ if (typeof input !== "string") return void 0;
106
+ const raw = input.trim().toLowerCase();
107
+ if (raw.length === 0) return void 0;
108
+ if (Object.prototype.hasOwnProperty.call(NAMED_COLORS, raw)) {
109
+ return NAMED_COLORS[raw];
110
+ }
111
+ if (raw.startsWith("#")) {
112
+ const hex = raw.slice(1);
113
+ if (hex.length === 3 || hex.length === 4) {
114
+ const r = parseInt(hex[0] + hex[0], 16);
115
+ const g = parseInt(hex[1] + hex[1], 16);
116
+ const b = parseInt(hex[2] + hex[2], 16);
117
+ if ([r, g, b].every((v) => Number.isFinite(v))) return { r, g, b };
118
+ return void 0;
119
+ }
120
+ if (hex.length === 6 || hex.length === 8) {
121
+ const r = parseInt(hex.slice(0, 2), 16);
122
+ const g = parseInt(hex.slice(2, 4), 16);
123
+ const b = parseInt(hex.slice(4, 6), 16);
124
+ if ([r, g, b].every((v) => Number.isFinite(v))) return { r, g, b };
125
+ return void 0;
126
+ }
127
+ return void 0;
128
+ }
129
+ const rgbMatch = raw.match(/^rgba?\(([^)]+)\)$/);
130
+ if (rgbMatch) {
131
+ const parts = rgbMatch[1].split(",").map((p) => p.trim());
132
+ if (parts.length < 3) return void 0;
133
+ const channel = (p) => {
134
+ if (p.endsWith("%")) {
135
+ const pct = parseFloat(p.slice(0, -1));
136
+ if (!Number.isFinite(pct)) return void 0;
137
+ return clamp255(pct / 100 * 255);
138
+ }
139
+ const n = parseFloat(p);
140
+ if (!Number.isFinite(n)) return void 0;
141
+ return clamp255(n);
142
+ };
143
+ const r = channel(parts[0]);
144
+ const g = channel(parts[1]);
145
+ const b = channel(parts[2]);
146
+ if (r === void 0 || g === void 0 || b === void 0) return void 0;
147
+ return { r, g, b };
148
+ }
149
+ return void 0;
150
+ }
151
+ function parseFontSizePx(input) {
152
+ if (typeof input === "number") {
153
+ return Number.isFinite(input) && input > 0 ? input : void 0;
154
+ }
155
+ if (typeof input === "string") {
156
+ const m = input.trim().match(/^(-?\d*\.?\d+)/);
157
+ if (m) {
158
+ const n = parseFloat(m[1]);
159
+ return Number.isFinite(n) && n > 0 ? n : void 0;
160
+ }
161
+ }
162
+ return void 0;
163
+ }
164
+ function projectVisionFields(args) {
165
+ const { type, label, handlerNames, state, flatStyle } = args;
166
+ const fields = {
167
+ interactable: deriveInteractable(type, handlerNames)
168
+ };
169
+ const text = deriveText(state, label);
170
+ if (text !== void 0) fields.text = text;
171
+ const role = roleForType(type);
172
+ if (role !== void 0) fields.role = role;
173
+ if (flatStyle) {
174
+ const fg = parseColorToRgb(flatStyle.color);
175
+ if (fg !== void 0) fields.fg_color = fg;
176
+ const bg = parseColorToRgb(flatStyle.backgroundColor);
177
+ if (bg !== void 0) fields.bg_color = bg;
178
+ const size = parseFontSizePx(flatStyle.fontSize);
179
+ if (size !== void 0) fields.font_size_px = size;
180
+ if (typeof flatStyle.fontFamily === "string" && flatStyle.fontFamily.trim().length > 0) {
181
+ fields.font_family = flatStyle.fontFamily;
182
+ }
183
+ }
184
+ return fields;
185
+ }
186
+
14
187
  // src/core/registry.ts
15
188
  function extractHandlerNames(props) {
16
189
  if (!props) return [];
@@ -20,6 +193,25 @@ function matchesCurrentRoute(registrationRoute, currentRoute) {
20
193
  if (registrationRoute == null || registrationRoute === "") return true;
21
194
  return registrationRoute === currentRoute;
22
195
  }
196
+ function projectBbox(state, visibility, pixelRatio = 1) {
197
+ if (visibility !== "visible") return void 0;
198
+ const layout = state.layout;
199
+ if (!layout) return void 0;
200
+ const ratio = pixelRatio > 0 && Number.isFinite(pixelRatio) ? pixelRatio : 1;
201
+ const toPx = (v) => Math.max(0, Math.round(v * ratio));
202
+ const hasPage = typeof layout.pageX === "number" && typeof layout.pageY === "number" && Number.isFinite(layout.pageX) && Number.isFinite(layout.pageY);
203
+ const originX = hasPage ? layout.pageX : layout.x;
204
+ const originY = hasPage ? layout.pageY : layout.y;
205
+ if (typeof originX !== "number" || typeof originY !== "number" || typeof layout.width !== "number" || typeof layout.height !== "number" || !Number.isFinite(originX) || !Number.isFinite(originY) || !Number.isFinite(layout.width) || !Number.isFinite(layout.height)) {
206
+ return void 0;
207
+ }
208
+ return {
209
+ x: toPx(originX),
210
+ y: toPx(originY),
211
+ w: toPx(layout.width),
212
+ h: toPx(layout.height)
213
+ };
214
+ }
23
215
  function inferActions(type) {
24
216
  const baseActions = ["focus", "blur"];
25
217
  switch (type) {
@@ -84,6 +276,15 @@ var NativeUIBridgeRegistry = class {
84
276
  * already installs.
85
277
  */
86
278
  this.routeProvider = null;
279
+ /**
280
+ * Device pixel ratio used to project `state.layout` (logical dp) into the
281
+ * physical-pixel `bbox` emitted on each snapshot element. Defaults to `1`
282
+ * (dp ≈ px) so callers/tests that never inject a ratio still get a usable
283
+ * box; the React provider wires the real `PixelRatio.get()` via
284
+ * {@link setPixelRatio}. Read from a non-React core module on purpose — see
285
+ * the `projectBbox` doc comment for why we don't import `react-native` here.
286
+ */
287
+ this.pixelRatio = 1;
87
288
  /**
88
289
  * Sticky flag: flips `true` the first time any element is registered and
89
290
  * stays `true` even after elements are unregistered. Lets agents distinguish
@@ -121,6 +322,21 @@ var NativeUIBridgeRegistry = class {
121
322
  getRouteProvider() {
122
323
  return this.routeProvider;
123
324
  }
325
+ /**
326
+ * Set the device pixel ratio used to project per-element `bbox` geometry
327
+ * into physical pixels. The React provider passes `PixelRatio.get()` here
328
+ * once at startup. Ignores non-finite / non-positive values (keeps the
329
+ * previous ratio) so a bad call can't zero out every bbox.
330
+ */
331
+ setPixelRatio(ratio) {
332
+ if (typeof ratio === "number" && Number.isFinite(ratio) && ratio > 0) {
333
+ this.pixelRatio = ratio;
334
+ }
335
+ }
336
+ /** Read-only accessor for the device pixel ratio used for bbox projection. */
337
+ getPixelRatio() {
338
+ return this.pixelRatio;
339
+ }
124
340
  // ============================================================================
125
341
  // Snapshot Enricher Slots
126
342
  // ============================================================================
@@ -660,6 +876,18 @@ var NativeUIBridgeRegistry = class {
660
876
  const handlers = extractHandlerNames(e.props);
661
877
  const state = e.getState();
662
878
  const visibility = !state.visible ? "hidden" : state.layout !== null ? "visible" : "likely-visible";
879
+ const bbox = projectBbox(state, visibility, this.pixelRatio);
880
+ const vision = projectVisionFields({
881
+ type: e.type,
882
+ label: e.label,
883
+ // Real interactivity signal: the names of props that are actually
884
+ // functions (onPress/onChangeText/...). NOT `e.actions`, which
885
+ // `inferActions` synthesizes press/click onto for every element —
886
+ // using it would mark plain text/view nodes interactable.
887
+ handlerNames: handlers,
888
+ state,
889
+ flatStyle: e.flatStyle
890
+ });
663
891
  return {
664
892
  id: e.id,
665
893
  type: e.type,
@@ -670,7 +898,9 @@ var NativeUIBridgeRegistry = class {
670
898
  customActions: e.customActions ? Object.keys(e.customActions) : void 0,
671
899
  registeredHandlers: handlers.length > 0 ? handlers : void 0,
672
900
  registrationRoute: e.registrationRoute,
673
- visibility
901
+ visibility,
902
+ ...bbox ? { bbox } : {},
903
+ ...vision
674
904
  };
675
905
  }),
676
906
  components: this.getAllComponents().map((c) => ({
@@ -935,9 +1165,10 @@ var DefaultNativeActionExecutor = class {
935
1165
  requestId: request.requestId,
936
1166
  durationMs: successTime - startTime
937
1167
  });
1168
+ const fresh = this.registry.getElement(registered.id) ?? registered;
938
1169
  return {
939
1170
  success: true,
940
- elementState: registered.getState(),
1171
+ elementState: fresh.getState(),
941
1172
  result,
942
1173
  durationMs: successTime - startTime,
943
1174
  timestamp: successTime,
@@ -1843,7 +2074,7 @@ function createDesignHandlers(registry, viewportProvider) {
1843
2074
  var GRID_SIZE = 20;
1844
2075
  var NAV_TYPES = /* @__PURE__ */ new Set(["button", "heading", "badge", "status-message"]);
1845
2076
  var SKIP_TEXT_TYPES = /* @__PURE__ */ new Set(["button", "link", "tab", "menuitem"]);
1846
- var INTERACTIVE_TYPES = /* @__PURE__ */ new Set([
2077
+ var INTERACTIVE_TYPES2 = /* @__PURE__ */ new Set([
1847
2078
  "button",
1848
2079
  "input",
1849
2080
  "switch",
@@ -2040,7 +2271,7 @@ function diagnosePageHealth(elements, viewport) {
2040
2271
  let interactiveTotal = 0;
2041
2272
  let interactiveDisabled = 0;
2042
2273
  for (const el of elements) {
2043
- if (!INTERACTIVE_TYPES.has(el.type)) continue;
2274
+ if (!INTERACTIVE_TYPES2.has(el.type)) continue;
2044
2275
  interactiveTotal++;
2045
2276
  if (el.state.enabled === false) interactiveDisabled++;
2046
2277
  }
@@ -2108,6 +2339,13 @@ function matchElementsByText(registry, text, opts) {
2108
2339
  scored.sort((a, b) => a.rank - b.rank);
2109
2340
  return scored.map((s) => s.element);
2110
2341
  }
2342
+ function resolveElementState(element) {
2343
+ const state = element.getState();
2344
+ if (element.type === "input" && state.value === void 0 && typeof element.props?.value === "string") {
2345
+ return { ...state, value: element.props.value };
2346
+ }
2347
+ return state;
2348
+ }
2111
2349
  async function executeWorkflowStep(step, registry, executor) {
2112
2350
  const startTime = Date.now();
2113
2351
  try {
@@ -2316,6 +2554,16 @@ function createServerHandlers(registry, executor, config) {
2316
2554
  const handlers = extractHandlerNames(e.props);
2317
2555
  const state = e.getState();
2318
2556
  const visibility = !state.visible ? "hidden" : state.layout !== null ? "visible" : "likely-visible";
2557
+ const bbox = projectBbox(state, visibility, registry.getPixelRatio());
2558
+ const vision = projectVisionFields({
2559
+ type: e.type,
2560
+ label: e.label,
2561
+ // Real handler names (onPress/...), NOT inferred actions which
2562
+ // synthesize press/click onto every element. See projectVisionFields.
2563
+ handlerNames: handlers,
2564
+ state,
2565
+ flatStyle: e.flatStyle
2566
+ });
2319
2567
  return {
2320
2568
  id: e.id,
2321
2569
  type: e.type,
@@ -2326,7 +2574,9 @@ function createServerHandlers(registry, executor, config) {
2326
2574
  customActions: e.customActions ? Object.keys(e.customActions) : void 0,
2327
2575
  registeredHandlers: handlers.length > 0 ? handlers : void 0,
2328
2576
  registrationRoute: e.registrationRoute,
2329
- visibility
2577
+ visibility,
2578
+ ...bbox ? { bbox } : {},
2579
+ ...vision
2330
2580
  };
2331
2581
  });
2332
2582
  return success2({ elements });
@@ -2344,7 +2594,7 @@ function createServerHandlers(registry, executor, config) {
2344
2594
  type: element.type,
2345
2595
  label: element.label,
2346
2596
  identifier: element.getIdentifier(),
2347
- state: element.getState(),
2597
+ state: resolveElementState(element),
2348
2598
  actions: element.actions,
2349
2599
  customActions: element.customActions ? Object.keys(element.customActions) : void 0,
2350
2600
  registeredHandlers: handlers.length > 0 ? handlers : void 0,
@@ -2358,18 +2608,19 @@ function createServerHandlers(registry, executor, config) {
2358
2608
  if (!element) {
2359
2609
  return error2(`Element not found: ${id}`, "ELEMENT_NOT_FOUND");
2360
2610
  }
2361
- return success2({ state: element.getState() });
2611
+ return success2({ state: resolveElementState(element) });
2362
2612
  },
2363
2613
  executeAction: async (ctx) => {
2364
- const { id } = ctx.params;
2365
- const body = ctx.body;
2366
- if (!body?.action) {
2614
+ const rawBody = ctx.body ?? {};
2615
+ const envelope = rawBody.request && typeof rawBody.request === "object" ? rawBody.request : rawBody;
2616
+ const id = ctx.params.id ?? rawBody.id ?? "";
2617
+ if (!envelope?.action) {
2367
2618
  return error2("Action is required", "INVALID_REQUEST");
2368
2619
  }
2369
2620
  const response = await executor.executeAction(id, {
2370
- action: body.action,
2371
- params: body.params,
2372
- waitOptions: body.waitOptions
2621
+ action: envelope.action,
2622
+ params: envelope.params,
2623
+ waitOptions: envelope.waitOptions
2373
2624
  });
2374
2625
  if (!response.success) {
2375
2626
  return error2(response.error || "Action failed", "ACTION_FAILED");
@@ -3008,7 +3259,7 @@ function createServerHandlers(registry, executor, config) {
3008
3259
  };
3009
3260
  if (config?.appInfo) {
3010
3261
  response.uiBridge = {
3011
- version: "0.3.0",
3262
+ version: "0.6.11",
3012
3263
  ...config.appInfo,
3013
3264
  capabilities: ["elements", "components", "actions", "design"],
3014
3265
  elementCount: stats.elements,
@@ -3600,6 +3851,14 @@ var NativeUIBridgeServer = class {
3600
3851
  };
3601
3852
  };
3602
3853
  }
3854
+ /**
3855
+ * Whether the console/network capture should be installed. The dedicated
3856
+ * `observability` flag wins when set; otherwise falls back to `testHooks`
3857
+ * so consumers predating the flag keep their exact behavior.
3858
+ */
3859
+ observabilityEnabled() {
3860
+ return this.config.observability ?? this.config.testHooks === true;
3861
+ }
3603
3862
  /**
3604
3863
  * Set the server adapter
3605
3864
  */
@@ -3813,7 +4072,7 @@ var NativeUIBridgeServer = class {
3813
4072
  console.warn("[ui-bridge-native] See documentation for supported adapters.");
3814
4073
  return;
3815
4074
  }
3816
- if (this.config.testHooks === true) {
4075
+ if (this.observabilityEnabled()) {
3817
4076
  this.consoleErrorBuffer.install();
3818
4077
  this.networkRequestBuffer.install();
3819
4078
  }
@@ -5315,6 +5574,7 @@ function UIBridgeNativeProvider({
5315
5574
  verbose: config.verbose,
5316
5575
  onEvent
5317
5576
  });
5577
+ registryRef.current.setPixelRatio(reactNative.PixelRatio.get());
5318
5578
  setGlobalRegistry(registryRef.current);
5319
5579
  }
5320
5580
  const registry = registryRef.current;
@@ -5345,6 +5605,10 @@ function UIBridgeNativeProvider({
5345
5605
  cors: true,
5346
5606
  appInfo: config.appInfo,
5347
5607
  testHooks: features.testHooks === true,
5608
+ // Dedicated console/network-capture flag; the server defaults it to
5609
+ // the `testHooks` value when undefined, so passing it through verbatim
5610
+ // keeps existing consumers unchanged.
5611
+ observability: features.observability,
5348
5612
  // Injected device-viewport getter for POST /control/page-health. The
5349
5613
  // server doesn't import `react-native` itself — the require/import
5350
5614
  // pattern there crashed the host RN app in 0.6.3/0.6.4 (Metro/Hermes
@@ -5412,6 +5676,7 @@ function UIBridgeNativeProvider({
5412
5676
  }, [
5413
5677
  features.server,
5414
5678
  features.testHooks,
5679
+ features.observability,
5415
5680
  config.serverPort,
5416
5681
  config.appInfo,
5417
5682
  registry,
@@ -5450,6 +5715,7 @@ function UIBridgeNativeProvider({
5450
5715
  cors: true,
5451
5716
  appInfo: config.appInfo,
5452
5717
  testHooks: features.testHooks === true,
5718
+ observability: features.observability,
5453
5719
  viewportProvider: () => {
5454
5720
  const win = reactNative.Dimensions.get("window");
5455
5721
  return { width: win.width, height: win.height };
@@ -5653,12 +5919,41 @@ function scheduleDeadButtonWarning(bridge, id, type) {
5653
5919
  }
5654
5920
  function useUIElement(options) {
5655
5921
  const bridge = useUIBridgeNativeOptional();
5656
- const ref = react.useRef(null);
5657
5922
  const [registered, setRegistered] = react.useState(false);
5658
5923
  const [_layout, setLayout] = react.useState(null);
5659
5924
  const propsRef = react.useRef({});
5660
5925
  const registeredRef = react.useRef(false);
5661
5926
  const registeredIdRef = react.useRef(null);
5927
+ const bridgeRef = react.useRef(bridge);
5928
+ bridgeRef.current = bridge;
5929
+ const nodeRef = react.useRef(null);
5930
+ const refInterceptorRef = react.useRef(null);
5931
+ if (refInterceptorRef.current === null) {
5932
+ refInterceptorRef.current = {
5933
+ get current() {
5934
+ return nodeRef.current;
5935
+ },
5936
+ set current(node) {
5937
+ const prev = nodeRef.current;
5938
+ nodeRef.current = node;
5939
+ const liveBridge = bridgeRef.current;
5940
+ const registeredId = registeredIdRef.current;
5941
+ if (!liveBridge || !registeredRef.current || registeredId === null) return;
5942
+ if (node == null && prev != null) {
5943
+ const state = liveBridge.registry.getElement(registeredId)?.getState();
5944
+ if (state && state.visible !== false) {
5945
+ liveBridge.registry.updateElementState(registeredId, { visible: false });
5946
+ }
5947
+ } else if (node != null && prev == null) {
5948
+ const state = liveBridge.registry.getElement(registeredId)?.getState();
5949
+ if (state && state.visible !== true) {
5950
+ liveBridge.registry.updateElementState(registeredId, { visible: true });
5951
+ }
5952
+ }
5953
+ }
5954
+ };
5955
+ }
5956
+ const ref = refInterceptorRef.current;
5662
5957
  const {
5663
5958
  id,
5664
5959
  type = "custom",
@@ -5702,7 +5997,7 @@ function useUIElement(options) {
5702
5997
  }
5703
5998
  setRegistered(true);
5704
5999
  scheduleDeadButtonWarning(bridge, id, type);
5705
- }, [bridge, id, type, label, actions, customActions, treePath, style, stateStylesProp, valueProp]);
6000
+ }, [bridge, id, type, label, actions, customActions, treePath, style, stateStylesProp, valueProp, ref]);
5706
6001
  const unregister = react.useCallback(() => {
5707
6002
  if (!bridge || !registeredRef.current) return;
5708
6003
  bridge.registry.unregisterElement(registeredIdRef.current ?? id);
@@ -5738,7 +6033,8 @@ function useUIElement(options) {
5738
6033
  writeLayout({ x, y, width, height, pageX: x, pageY: y });
5739
6034
  }
5740
6035
  },
5741
- [bridge, id]
6036
+ // `ref` is the once-per-hook interceptor object — identity-stable.
6037
+ [bridge, id, ref]
5742
6038
  );
5743
6039
  const registerRef = react.useRef(register);
5744
6040
  const unregisterRef = react.useRef(unregister);
@@ -5759,7 +6055,14 @@ function useUIElement(options) {
5759
6055
  react.useEffect(() => {
5760
6056
  if (!bridge || !registered) return;
5761
6057
  const node = ref.current;
5762
- if (!node || typeof node.measureInWindow !== "function") return;
6058
+ if (!node) {
6059
+ const seeded = bridge.registry.getElement(id)?.getState();
6060
+ if (seeded && seeded.visible !== false) {
6061
+ bridge.registry.updateElementState(id, { visible: false });
6062
+ }
6063
+ return;
6064
+ }
6065
+ if (typeof node.measureInWindow !== "function") return;
5763
6066
  let cancelled = false;
5764
6067
  let pendingTimer = null;
5765
6068
  const backoffMs = [50, 200, 500, 1e3, 2500];
@@ -5798,7 +6101,7 @@ function useUIElement(options) {
5798
6101
  cancelled = true;
5799
6102
  if (pendingTimer != null) clearTimeout(pendingTimer);
5800
6103
  };
5801
- }, [bridge, registered, id]);
6104
+ }, [bridge, registered, id, ref]);
5802
6105
  const registeredHandlerKeysRef = react.useRef([]);
5803
6106
  react.useEffect(() => {
5804
6107
  if (!bridge || !registered || !handlersProp) return;