@qontinui/ui-bridge-native 0.6.11 → 0.6.12
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.
- package/dist/core/index.js +97 -0
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.mjs +97 -0
- package/dist/core/index.mjs.map +1 -1
- package/dist/core/registry.d.ts +45 -0
- package/dist/core/registry.d.ts.map +1 -1
- package/dist/index.js +102 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +102 -2
- package/dist/index.mjs.map +1 -1
- package/dist/react/index.js +102 -2
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +102 -2
- package/dist/react/index.mjs.map +1 -1
- package/dist/react/useUIElement.d.ts.map +1 -1
- package/dist/server/handlers.d.ts.map +1 -1
- package/dist/server/index.js +4 -1
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +4 -1
- package/dist/server/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -560,6 +560,103 @@ var NativeUIBridgeRegistry = class {
|
|
|
560
560
|
console.log(`[ui-bridge-native] Marked ${cleared} elements offscreen for route: ${route}`);
|
|
561
561
|
}
|
|
562
562
|
}
|
|
563
|
+
/**
|
|
564
|
+
* Re-measure every mounted-visible element's geometry via its stored React
|
|
565
|
+
* ref and write the fresh coordinates into the registry ("measure-on-
|
|
566
|
+
* snapshot").
|
|
567
|
+
*
|
|
568
|
+
* Why: element geometry is otherwise captured ONCE at mount time
|
|
569
|
+
* (`onLayout` + `measureInWindow` in `useUIElement`) and RN never re-fires
|
|
570
|
+
* `onLayout` on pure translation — scrolling a virtualized list
|
|
571
|
+
* (FlashList), recycling a cell, a keyboard shift or an orientation change
|
|
572
|
+
* all move elements WITHOUT updating the stored `state.layout`. Snapshot
|
|
573
|
+
* consumers (vision analyzers hit-testing `bbox`, coord-based tap) then
|
|
574
|
+
* operate on stale positions. Re-measuring at READ time is correct
|
|
575
|
+
* regardless of what moved the element and needs zero per-consumer wiring:
|
|
576
|
+
* every registry entry already stores its ref (see `registerElement`).
|
|
577
|
+
*
|
|
578
|
+
* Per-element outcomes:
|
|
579
|
+
* - non-zero dims → write a fresh full layout (same state shape as the
|
|
580
|
+
* mount-time measure loop in `useUIElement`); counted as `measured`.
|
|
581
|
+
* - zero dims AND the element previously had a non-null `state.layout` →
|
|
582
|
+
* the view collapsed / left the screen; clear to
|
|
583
|
+
* `{ visible: false, layout: null }` (same shape `markRouteOffscreen`
|
|
584
|
+
* writes); counted as `cleared`.
|
|
585
|
+
* - zero dims and it never had a layout → leave state untouched (element
|
|
586
|
+
* in the mount→first-onLayout gap; don't demote `likely-visible`);
|
|
587
|
+
* counted as `skipped`.
|
|
588
|
+
* - no ref / no callable `measureInWindow` (test fixtures, web) → leave
|
|
589
|
+
* untouched; counted as `skipped`.
|
|
590
|
+
*
|
|
591
|
+
* The whole sweep races an overall timeout (default 250 ms) so a dead ref
|
|
592
|
+
* whose `measureInWindow` never calls back can never hang a snapshot: the
|
|
593
|
+
* returned promise resolves at the deadline with whatever counts have
|
|
594
|
+
* accumulated. Late callbacks may still write state afterwards — harmless,
|
|
595
|
+
* freshest data wins. Never throws.
|
|
596
|
+
*
|
|
597
|
+
* Non-React core module on purpose — `measureInWindow` is duck-typed off
|
|
598
|
+
* the stored ref rather than imported from `react-native` (see the
|
|
599
|
+
* `projectBbox` doc comment for why this file must not import RN).
|
|
600
|
+
*/
|
|
601
|
+
async refreshMeasurements(options) {
|
|
602
|
+
const timeoutMs = typeof options?.timeoutMs === "number" && Number.isFinite(options.timeoutMs) && options.timeoutMs > 0 ? options.timeoutMs : 250;
|
|
603
|
+
const counts = { measured: 0, cleared: 0, skipped: 0 };
|
|
604
|
+
const pending = [];
|
|
605
|
+
for (const element of this.getMountedVisibleElements()) {
|
|
606
|
+
const node = element.ref?.current;
|
|
607
|
+
if (!node || typeof node.measureInWindow !== "function") {
|
|
608
|
+
counts.skipped++;
|
|
609
|
+
continue;
|
|
610
|
+
}
|
|
611
|
+
const id = element.id;
|
|
612
|
+
pending.push(
|
|
613
|
+
new Promise((resolve) => {
|
|
614
|
+
let settled = false;
|
|
615
|
+
try {
|
|
616
|
+
node.measureInWindow((pageX, pageY, w, h) => {
|
|
617
|
+
if (settled) return;
|
|
618
|
+
settled = true;
|
|
619
|
+
try {
|
|
620
|
+
if (w > 0 && h > 0) {
|
|
621
|
+
this.updateElementState(id, {
|
|
622
|
+
mounted: true,
|
|
623
|
+
visible: true,
|
|
624
|
+
enabled: true,
|
|
625
|
+
focused: false,
|
|
626
|
+
layout: { x: pageX, y: pageY, width: w, height: h, pageX, pageY }
|
|
627
|
+
});
|
|
628
|
+
counts.measured++;
|
|
629
|
+
} else if (this.elements.get(id)?.getState().layout != null) {
|
|
630
|
+
this.updateElementState(id, { visible: false, layout: null });
|
|
631
|
+
counts.cleared++;
|
|
632
|
+
} else {
|
|
633
|
+
counts.skipped++;
|
|
634
|
+
}
|
|
635
|
+
} finally {
|
|
636
|
+
resolve();
|
|
637
|
+
}
|
|
638
|
+
});
|
|
639
|
+
} catch {
|
|
640
|
+
if (!settled) {
|
|
641
|
+
settled = true;
|
|
642
|
+
counts.skipped++;
|
|
643
|
+
resolve();
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
})
|
|
647
|
+
);
|
|
648
|
+
}
|
|
649
|
+
if (pending.length > 0) {
|
|
650
|
+
await new Promise((resolve) => {
|
|
651
|
+
const timer = setTimeout(resolve, timeoutMs);
|
|
652
|
+
void Promise.all(pending).then(() => {
|
|
653
|
+
clearTimeout(timer);
|
|
654
|
+
resolve();
|
|
655
|
+
});
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
return counts;
|
|
659
|
+
}
|
|
563
660
|
/**
|
|
564
661
|
* Update element state
|
|
565
662
|
*/
|
|
@@ -2594,6 +2691,7 @@ function createServerHandlers(registry, executor, config) {
|
|
|
2594
2691
|
return {
|
|
2595
2692
|
// Elements
|
|
2596
2693
|
getElements: async (ctx) => {
|
|
2694
|
+
await registry.refreshMeasurements();
|
|
2597
2695
|
const visibleOnly = ctx.query?.visibleOnly === "true" || ctx.body?.visibleOnly === true;
|
|
2598
2696
|
const forRoute = ctx.query?.route || ctx.body?.route;
|
|
2599
2697
|
let allElements = visibleOnly ? registry.getMountedVisibleElements() : registry.getAllElements();
|
|
@@ -2787,6 +2885,7 @@ function createServerHandlers(registry, executor, config) {
|
|
|
2787
2885
|
});
|
|
2788
2886
|
},
|
|
2789
2887
|
getSnapshot: async (ctx) => {
|
|
2888
|
+
await registry.refreshMeasurements();
|
|
2790
2889
|
const visibleOnly = ctx.query?.visibleOnly === "true" || ctx.body?.visibleOnly === true;
|
|
2791
2890
|
const currentRouteOnly = ctx.query?.currentRouteOnly === "true" || ctx.body?.currentRouteOnly === true;
|
|
2792
2891
|
const snapshot = registry.createSnapshot(void 0, { visibleOnly, currentRouteOnly });
|
|
@@ -3102,6 +3201,7 @@ function createServerHandlers(registry, executor, config) {
|
|
|
3102
3201
|
// that don't measure (the fallback only matches single-rooted screens but
|
|
3103
3202
|
// is good enough for the unit suite).
|
|
3104
3203
|
tapAt: async (ctx) => {
|
|
3204
|
+
await registry.refreshMeasurements();
|
|
3105
3205
|
const body = ctx.body;
|
|
3106
3206
|
const x = body?.x;
|
|
3107
3207
|
const y = body?.y;
|
|
@@ -3309,7 +3409,7 @@ function createServerHandlers(registry, executor, config) {
|
|
|
3309
3409
|
};
|
|
3310
3410
|
if (config?.appInfo) {
|
|
3311
3411
|
response.uiBridge = {
|
|
3312
|
-
version: "0.6.
|
|
3412
|
+
version: "0.6.12",
|
|
3313
3413
|
...config.appInfo,
|
|
3314
3414
|
capabilities: ["elements", "components", "actions", "design"],
|
|
3315
3415
|
elementCount: stats.elements,
|
|
@@ -6101,7 +6201,7 @@ function useUIElement(options) {
|
|
|
6101
6201
|
unregisterRef.current();
|
|
6102
6202
|
}
|
|
6103
6203
|
};
|
|
6104
|
-
}, [autoRegister, bridge]);
|
|
6204
|
+
}, [autoRegister, bridge, id]);
|
|
6105
6205
|
useEffect(() => {
|
|
6106
6206
|
if (!bridge || !registered) return;
|
|
6107
6207
|
const node = ref.current;
|