@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/react/index.js
CHANGED
|
@@ -562,6 +562,103 @@ var NativeUIBridgeRegistry = class {
|
|
|
562
562
|
console.log(`[ui-bridge-native] Marked ${cleared} elements offscreen for route: ${route}`);
|
|
563
563
|
}
|
|
564
564
|
}
|
|
565
|
+
/**
|
|
566
|
+
* Re-measure every mounted-visible element's geometry via its stored React
|
|
567
|
+
* ref and write the fresh coordinates into the registry ("measure-on-
|
|
568
|
+
* snapshot").
|
|
569
|
+
*
|
|
570
|
+
* Why: element geometry is otherwise captured ONCE at mount time
|
|
571
|
+
* (`onLayout` + `measureInWindow` in `useUIElement`) and RN never re-fires
|
|
572
|
+
* `onLayout` on pure translation — scrolling a virtualized list
|
|
573
|
+
* (FlashList), recycling a cell, a keyboard shift or an orientation change
|
|
574
|
+
* all move elements WITHOUT updating the stored `state.layout`. Snapshot
|
|
575
|
+
* consumers (vision analyzers hit-testing `bbox`, coord-based tap) then
|
|
576
|
+
* operate on stale positions. Re-measuring at READ time is correct
|
|
577
|
+
* regardless of what moved the element and needs zero per-consumer wiring:
|
|
578
|
+
* every registry entry already stores its ref (see `registerElement`).
|
|
579
|
+
*
|
|
580
|
+
* Per-element outcomes:
|
|
581
|
+
* - non-zero dims → write a fresh full layout (same state shape as the
|
|
582
|
+
* mount-time measure loop in `useUIElement`); counted as `measured`.
|
|
583
|
+
* - zero dims AND the element previously had a non-null `state.layout` →
|
|
584
|
+
* the view collapsed / left the screen; clear to
|
|
585
|
+
* `{ visible: false, layout: null }` (same shape `markRouteOffscreen`
|
|
586
|
+
* writes); counted as `cleared`.
|
|
587
|
+
* - zero dims and it never had a layout → leave state untouched (element
|
|
588
|
+
* in the mount→first-onLayout gap; don't demote `likely-visible`);
|
|
589
|
+
* counted as `skipped`.
|
|
590
|
+
* - no ref / no callable `measureInWindow` (test fixtures, web) → leave
|
|
591
|
+
* untouched; counted as `skipped`.
|
|
592
|
+
*
|
|
593
|
+
* The whole sweep races an overall timeout (default 250 ms) so a dead ref
|
|
594
|
+
* whose `measureInWindow` never calls back can never hang a snapshot: the
|
|
595
|
+
* returned promise resolves at the deadline with whatever counts have
|
|
596
|
+
* accumulated. Late callbacks may still write state afterwards — harmless,
|
|
597
|
+
* freshest data wins. Never throws.
|
|
598
|
+
*
|
|
599
|
+
* Non-React core module on purpose — `measureInWindow` is duck-typed off
|
|
600
|
+
* the stored ref rather than imported from `react-native` (see the
|
|
601
|
+
* `projectBbox` doc comment for why this file must not import RN).
|
|
602
|
+
*/
|
|
603
|
+
async refreshMeasurements(options) {
|
|
604
|
+
const timeoutMs = typeof options?.timeoutMs === "number" && Number.isFinite(options.timeoutMs) && options.timeoutMs > 0 ? options.timeoutMs : 250;
|
|
605
|
+
const counts = { measured: 0, cleared: 0, skipped: 0 };
|
|
606
|
+
const pending = [];
|
|
607
|
+
for (const element of this.getMountedVisibleElements()) {
|
|
608
|
+
const node = element.ref?.current;
|
|
609
|
+
if (!node || typeof node.measureInWindow !== "function") {
|
|
610
|
+
counts.skipped++;
|
|
611
|
+
continue;
|
|
612
|
+
}
|
|
613
|
+
const id = element.id;
|
|
614
|
+
pending.push(
|
|
615
|
+
new Promise((resolve) => {
|
|
616
|
+
let settled = false;
|
|
617
|
+
try {
|
|
618
|
+
node.measureInWindow((pageX, pageY, w, h) => {
|
|
619
|
+
if (settled) return;
|
|
620
|
+
settled = true;
|
|
621
|
+
try {
|
|
622
|
+
if (w > 0 && h > 0) {
|
|
623
|
+
this.updateElementState(id, {
|
|
624
|
+
mounted: true,
|
|
625
|
+
visible: true,
|
|
626
|
+
enabled: true,
|
|
627
|
+
focused: false,
|
|
628
|
+
layout: { x: pageX, y: pageY, width: w, height: h, pageX, pageY }
|
|
629
|
+
});
|
|
630
|
+
counts.measured++;
|
|
631
|
+
} else if (this.elements.get(id)?.getState().layout != null) {
|
|
632
|
+
this.updateElementState(id, { visible: false, layout: null });
|
|
633
|
+
counts.cleared++;
|
|
634
|
+
} else {
|
|
635
|
+
counts.skipped++;
|
|
636
|
+
}
|
|
637
|
+
} finally {
|
|
638
|
+
resolve();
|
|
639
|
+
}
|
|
640
|
+
});
|
|
641
|
+
} catch {
|
|
642
|
+
if (!settled) {
|
|
643
|
+
settled = true;
|
|
644
|
+
counts.skipped++;
|
|
645
|
+
resolve();
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
})
|
|
649
|
+
);
|
|
650
|
+
}
|
|
651
|
+
if (pending.length > 0) {
|
|
652
|
+
await new Promise((resolve) => {
|
|
653
|
+
const timer = setTimeout(resolve, timeoutMs);
|
|
654
|
+
void Promise.all(pending).then(() => {
|
|
655
|
+
clearTimeout(timer);
|
|
656
|
+
resolve();
|
|
657
|
+
});
|
|
658
|
+
});
|
|
659
|
+
}
|
|
660
|
+
return counts;
|
|
661
|
+
}
|
|
565
662
|
/**
|
|
566
663
|
* Update element state
|
|
567
664
|
*/
|
|
@@ -2544,6 +2641,7 @@ function createServerHandlers(registry, executor, config) {
|
|
|
2544
2641
|
return {
|
|
2545
2642
|
// Elements
|
|
2546
2643
|
getElements: async (ctx) => {
|
|
2644
|
+
await registry.refreshMeasurements();
|
|
2547
2645
|
const visibleOnly = ctx.query?.visibleOnly === "true" || ctx.body?.visibleOnly === true;
|
|
2548
2646
|
const forRoute = ctx.query?.route || ctx.body?.route;
|
|
2549
2647
|
let allElements = visibleOnly ? registry.getMountedVisibleElements() : registry.getAllElements();
|
|
@@ -2737,6 +2835,7 @@ function createServerHandlers(registry, executor, config) {
|
|
|
2737
2835
|
});
|
|
2738
2836
|
},
|
|
2739
2837
|
getSnapshot: async (ctx) => {
|
|
2838
|
+
await registry.refreshMeasurements();
|
|
2740
2839
|
const visibleOnly = ctx.query?.visibleOnly === "true" || ctx.body?.visibleOnly === true;
|
|
2741
2840
|
const currentRouteOnly = ctx.query?.currentRouteOnly === "true" || ctx.body?.currentRouteOnly === true;
|
|
2742
2841
|
const snapshot = registry.createSnapshot(void 0, { visibleOnly, currentRouteOnly });
|
|
@@ -3052,6 +3151,7 @@ function createServerHandlers(registry, executor, config) {
|
|
|
3052
3151
|
// that don't measure (the fallback only matches single-rooted screens but
|
|
3053
3152
|
// is good enough for the unit suite).
|
|
3054
3153
|
tapAt: async (ctx) => {
|
|
3154
|
+
await registry.refreshMeasurements();
|
|
3055
3155
|
const body = ctx.body;
|
|
3056
3156
|
const x = body?.x;
|
|
3057
3157
|
const y = body?.y;
|
|
@@ -3259,7 +3359,7 @@ function createServerHandlers(registry, executor, config) {
|
|
|
3259
3359
|
};
|
|
3260
3360
|
if (config?.appInfo) {
|
|
3261
3361
|
response.uiBridge = {
|
|
3262
|
-
version: "0.6.
|
|
3362
|
+
version: "0.6.12",
|
|
3263
3363
|
...config.appInfo,
|
|
3264
3364
|
capabilities: ["elements", "components", "actions", "design"],
|
|
3265
3365
|
elementCount: stats.elements,
|
|
@@ -6051,7 +6151,7 @@ function useUIElement(options) {
|
|
|
6051
6151
|
unregisterRef.current();
|
|
6052
6152
|
}
|
|
6053
6153
|
};
|
|
6054
|
-
}, [autoRegister, bridge]);
|
|
6154
|
+
}, [autoRegister, bridge, id]);
|
|
6055
6155
|
react.useEffect(() => {
|
|
6056
6156
|
if (!bridge || !registered) return;
|
|
6057
6157
|
const node = ref.current;
|