@qontinui/ui-bridge-native 0.6.10 → 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.
@@ -207,6 +207,179 @@ var UI_BRIDGE_NATIVE_ROUTES = {
207
207
  }
208
208
  };
209
209
 
210
+ // src/core/vision-fields.ts
211
+ var INTERACTIVE_HANDLER_NAMES = /* @__PURE__ */ new Set([
212
+ "onPress",
213
+ "onPressIn",
214
+ "onPressOut",
215
+ "onLongPress",
216
+ "onChangeText",
217
+ "onValueChange",
218
+ "onChange",
219
+ "onSubmitEditing",
220
+ "onClick",
221
+ "onTouchStart",
222
+ "onTouchEnd"
223
+ ]);
224
+ var INTERACTIVE_TYPES = /* @__PURE__ */ new Set([
225
+ "button",
226
+ "input",
227
+ "switch",
228
+ "checkbox",
229
+ "radio",
230
+ "touchable",
231
+ "pressable",
232
+ "listItem"
233
+ ]);
234
+ function roleForType(type) {
235
+ switch (type) {
236
+ case "button":
237
+ case "touchable":
238
+ case "pressable":
239
+ return "button";
240
+ case "input":
241
+ return "textbox";
242
+ case "text":
243
+ return "text";
244
+ case "switch":
245
+ return "switch";
246
+ case "checkbox":
247
+ return "checkbox";
248
+ case "radio":
249
+ return "radio";
250
+ case "image":
251
+ return "img";
252
+ case "list":
253
+ return "list";
254
+ case "listItem":
255
+ return "listitem";
256
+ case "modal":
257
+ return "dialog";
258
+ case "scroll":
259
+ case "view":
260
+ case "custom":
261
+ default:
262
+ return void 0;
263
+ }
264
+ }
265
+ function deriveInteractable(type, handlerNames) {
266
+ if (INTERACTIVE_TYPES.has(type)) return true;
267
+ if (handlerNames) {
268
+ for (const name of handlerNames) {
269
+ if (INTERACTIVE_HANDLER_NAMES.has(name)) return true;
270
+ }
271
+ }
272
+ return false;
273
+ }
274
+ function deriveText(state, label) {
275
+ const candidates = [state.value, state.textContent, label];
276
+ for (const c of candidates) {
277
+ if (typeof c === "string") {
278
+ const trimmed = c.trim();
279
+ if (trimmed.length > 0) return trimmed;
280
+ }
281
+ }
282
+ return void 0;
283
+ }
284
+ var NAMED_COLORS = {
285
+ black: { r: 0, g: 0, b: 0 },
286
+ white: { r: 255, g: 255, b: 255 },
287
+ red: { r: 255, g: 0, b: 0 },
288
+ green: { r: 0, g: 128, b: 0 },
289
+ blue: { r: 0, g: 0, b: 255 },
290
+ gray: { r: 128, g: 128, b: 128 },
291
+ grey: { r: 128, g: 128, b: 128 },
292
+ silver: { r: 192, g: 192, b: 192 },
293
+ transparent: { r: 0, g: 0, b: 0 },
294
+ orange: { r: 255, g: 165, b: 0 },
295
+ yellow: { r: 255, g: 255, b: 0 },
296
+ purple: { r: 128, g: 0, b: 128 },
297
+ navy: { r: 0, g: 0, b: 128 }
298
+ };
299
+ var clamp255 = (n) => Math.max(0, Math.min(255, Math.round(n)));
300
+ function parseColorToRgb(input) {
301
+ if (typeof input !== "string") return void 0;
302
+ const raw = input.trim().toLowerCase();
303
+ if (raw.length === 0) return void 0;
304
+ if (Object.prototype.hasOwnProperty.call(NAMED_COLORS, raw)) {
305
+ return NAMED_COLORS[raw];
306
+ }
307
+ if (raw.startsWith("#")) {
308
+ const hex = raw.slice(1);
309
+ if (hex.length === 3 || hex.length === 4) {
310
+ const r = parseInt(hex[0] + hex[0], 16);
311
+ const g = parseInt(hex[1] + hex[1], 16);
312
+ const b = parseInt(hex[2] + hex[2], 16);
313
+ if ([r, g, b].every((v) => Number.isFinite(v))) return { r, g, b };
314
+ return void 0;
315
+ }
316
+ if (hex.length === 6 || hex.length === 8) {
317
+ const r = parseInt(hex.slice(0, 2), 16);
318
+ const g = parseInt(hex.slice(2, 4), 16);
319
+ const b = parseInt(hex.slice(4, 6), 16);
320
+ if ([r, g, b].every((v) => Number.isFinite(v))) return { r, g, b };
321
+ return void 0;
322
+ }
323
+ return void 0;
324
+ }
325
+ const rgbMatch = raw.match(/^rgba?\(([^)]+)\)$/);
326
+ if (rgbMatch) {
327
+ const parts = rgbMatch[1].split(",").map((p) => p.trim());
328
+ if (parts.length < 3) return void 0;
329
+ const channel = (p) => {
330
+ if (p.endsWith("%")) {
331
+ const pct = parseFloat(p.slice(0, -1));
332
+ if (!Number.isFinite(pct)) return void 0;
333
+ return clamp255(pct / 100 * 255);
334
+ }
335
+ const n = parseFloat(p);
336
+ if (!Number.isFinite(n)) return void 0;
337
+ return clamp255(n);
338
+ };
339
+ const r = channel(parts[0]);
340
+ const g = channel(parts[1]);
341
+ const b = channel(parts[2]);
342
+ if (r === void 0 || g === void 0 || b === void 0) return void 0;
343
+ return { r, g, b };
344
+ }
345
+ return void 0;
346
+ }
347
+ function parseFontSizePx(input) {
348
+ if (typeof input === "number") {
349
+ return Number.isFinite(input) && input > 0 ? input : void 0;
350
+ }
351
+ if (typeof input === "string") {
352
+ const m = input.trim().match(/^(-?\d*\.?\d+)/);
353
+ if (m) {
354
+ const n = parseFloat(m[1]);
355
+ return Number.isFinite(n) && n > 0 ? n : void 0;
356
+ }
357
+ }
358
+ return void 0;
359
+ }
360
+ function projectVisionFields(args) {
361
+ const { type, label, handlerNames, state, flatStyle } = args;
362
+ const fields = {
363
+ interactable: deriveInteractable(type, handlerNames)
364
+ };
365
+ const text = deriveText(state, label);
366
+ if (text !== void 0) fields.text = text;
367
+ const role = roleForType(type);
368
+ if (role !== void 0) fields.role = role;
369
+ if (flatStyle) {
370
+ const fg = parseColorToRgb(flatStyle.color);
371
+ if (fg !== void 0) fields.fg_color = fg;
372
+ const bg = parseColorToRgb(flatStyle.backgroundColor);
373
+ if (bg !== void 0) fields.bg_color = bg;
374
+ const size = parseFontSizePx(flatStyle.fontSize);
375
+ if (size !== void 0) fields.font_size_px = size;
376
+ if (typeof flatStyle.fontFamily === "string" && flatStyle.fontFamily.trim().length > 0) {
377
+ fields.font_family = flatStyle.fontFamily;
378
+ }
379
+ }
380
+ return fields;
381
+ }
382
+
210
383
  // src/core/registry.ts
211
384
  function extractHandlerNames(props) {
212
385
  if (!props) return [];
@@ -216,6 +389,25 @@ function matchesCurrentRoute(registrationRoute, currentRoute) {
216
389
  if (registrationRoute == null || registrationRoute === "") return true;
217
390
  return registrationRoute === currentRoute;
218
391
  }
392
+ function projectBbox(state, visibility, pixelRatio = 1) {
393
+ if (visibility !== "visible") return void 0;
394
+ const layout = state.layout;
395
+ if (!layout) return void 0;
396
+ const ratio = pixelRatio > 0 && Number.isFinite(pixelRatio) ? pixelRatio : 1;
397
+ const toPx = (v) => Math.max(0, Math.round(v * ratio));
398
+ const hasPage = typeof layout.pageX === "number" && typeof layout.pageY === "number" && Number.isFinite(layout.pageX) && Number.isFinite(layout.pageY);
399
+ const originX = hasPage ? layout.pageX : layout.x;
400
+ const originY = hasPage ? layout.pageY : layout.y;
401
+ 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)) {
402
+ return void 0;
403
+ }
404
+ return {
405
+ x: toPx(originX),
406
+ y: toPx(originY),
407
+ w: toPx(layout.width),
408
+ h: toPx(layout.height)
409
+ };
410
+ }
219
411
 
220
412
  // src/design/design-inspector-native.ts
221
413
  function toCssValue(value) {
@@ -693,7 +885,7 @@ function createDesignHandlers(registry, viewportProvider) {
693
885
  var GRID_SIZE = 20;
694
886
  var NAV_TYPES = /* @__PURE__ */ new Set(["button", "heading", "badge", "status-message"]);
695
887
  var SKIP_TEXT_TYPES = /* @__PURE__ */ new Set(["button", "link", "tab", "menuitem"]);
696
- var INTERACTIVE_TYPES = /* @__PURE__ */ new Set([
888
+ var INTERACTIVE_TYPES2 = /* @__PURE__ */ new Set([
697
889
  "button",
698
890
  "input",
699
891
  "switch",
@@ -890,7 +1082,7 @@ function diagnosePageHealth(elements, viewport) {
890
1082
  let interactiveTotal = 0;
891
1083
  let interactiveDisabled = 0;
892
1084
  for (const el of elements) {
893
- if (!INTERACTIVE_TYPES.has(el.type)) continue;
1085
+ if (!INTERACTIVE_TYPES2.has(el.type)) continue;
894
1086
  interactiveTotal++;
895
1087
  if (el.state.enabled === false) interactiveDisabled++;
896
1088
  }
@@ -1173,6 +1365,16 @@ function createServerHandlers(registry, executor, config) {
1173
1365
  const handlers = extractHandlerNames(e.props);
1174
1366
  const state = e.getState();
1175
1367
  const visibility = !state.visible ? "hidden" : state.layout !== null ? "visible" : "likely-visible";
1368
+ const bbox = projectBbox(state, visibility, registry.getPixelRatio());
1369
+ const vision = projectVisionFields({
1370
+ type: e.type,
1371
+ label: e.label,
1372
+ // Real handler names (onPress/...), NOT inferred actions which
1373
+ // synthesize press/click onto every element. See projectVisionFields.
1374
+ handlerNames: handlers,
1375
+ state,
1376
+ flatStyle: e.flatStyle
1377
+ });
1176
1378
  return {
1177
1379
  id: e.id,
1178
1380
  type: e.type,
@@ -1183,7 +1385,9 @@ function createServerHandlers(registry, executor, config) {
1183
1385
  customActions: e.customActions ? Object.keys(e.customActions) : void 0,
1184
1386
  registeredHandlers: handlers.length > 0 ? handlers : void 0,
1185
1387
  registrationRoute: e.registrationRoute,
1186
- visibility
1388
+ visibility,
1389
+ ...bbox ? { bbox } : {},
1390
+ ...vision
1187
1391
  };
1188
1392
  });
1189
1393
  return success2({ elements });
@@ -1866,7 +2070,7 @@ function createServerHandlers(registry, executor, config) {
1866
2070
  };
1867
2071
  if (config?.appInfo) {
1868
2072
  response.uiBridge = {
1869
- version: "0.6.10",
2073
+ version: "0.6.11",
1870
2074
  ...config.appInfo,
1871
2075
  capabilities: ["elements", "components", "actions", "design"],
1872
2076
  elementCount: stats.elements,
@@ -2458,6 +2662,14 @@ var NativeUIBridgeServer = class {
2458
2662
  };
2459
2663
  };
2460
2664
  }
2665
+ /**
2666
+ * Whether the console/network capture should be installed. The dedicated
2667
+ * `observability` flag wins when set; otherwise falls back to `testHooks`
2668
+ * so consumers predating the flag keep their exact behavior.
2669
+ */
2670
+ observabilityEnabled() {
2671
+ return this.config.observability ?? this.config.testHooks === true;
2672
+ }
2461
2673
  /**
2462
2674
  * Set the server adapter
2463
2675
  */
@@ -2671,7 +2883,7 @@ var NativeUIBridgeServer = class {
2671
2883
  console.warn("[ui-bridge-native] See documentation for supported adapters.");
2672
2884
  return;
2673
2885
  }
2674
- if (this.config.testHooks === true) {
2886
+ if (this.observabilityEnabled()) {
2675
2887
  this.consoleErrorBuffer.install();
2676
2888
  this.networkRequestBuffer.install();
2677
2889
  }