@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.
- package/dist/control/action-executor.d.ts.map +1 -1
- package/dist/control/index.js +2 -1
- package/dist/control/index.js.map +1 -1
- package/dist/control/index.mjs +2 -1
- package/dist/control/index.mjs.map +1 -1
- package/dist/core/index.js +232 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.mjs +232 -2
- package/dist/core/index.mjs.map +1 -1
- package/dist/core/registry.d.ts +46 -1
- package/dist/core/registry.d.ts.map +1 -1
- package/dist/core/types.d.ts +114 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/vision-fields.d.ts +142 -0
- package/dist/core/vision-fields.d.ts.map +1 -0
- package/dist/debug/index.js.map +1 -1
- package/dist/debug/index.mjs.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +371 -20
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +365 -22
- package/dist/index.mjs.map +1 -1
- package/dist/react/UIBridgeNativeProvider.d.ts.map +1 -1
- package/dist/react/index.js +323 -20
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +324 -21
- package/dist/react/index.mjs.map +1 -1
- package/dist/react/useUIElement.d.ts.map +1 -1
- package/dist/server/bind-retry.d.ts +64 -0
- package/dist/server/bind-retry.d.ts.map +1 -0
- package/dist/server/handlers.d.ts.map +1 -1
- package/dist/server/http-server.d.ts +9 -1
- package/dist/server/http-server.d.ts.map +1 -1
- package/dist/server/index.d.ts +2 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +275 -13
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +274 -14
- package/dist/server/index.mjs.map +1 -1
- package/dist/server/observability.d.ts +4 -3
- package/dist/server/observability.d.ts.map +1 -1
- package/dist/server/types.d.ts +10 -0
- package/dist/server/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/core/index.mjs
CHANGED
|
@@ -1,3 +1,176 @@
|
|
|
1
|
+
// src/core/vision-fields.ts
|
|
2
|
+
var INTERACTIVE_HANDLER_NAMES = /* @__PURE__ */ new Set([
|
|
3
|
+
"onPress",
|
|
4
|
+
"onPressIn",
|
|
5
|
+
"onPressOut",
|
|
6
|
+
"onLongPress",
|
|
7
|
+
"onChangeText",
|
|
8
|
+
"onValueChange",
|
|
9
|
+
"onChange",
|
|
10
|
+
"onSubmitEditing",
|
|
11
|
+
"onClick",
|
|
12
|
+
"onTouchStart",
|
|
13
|
+
"onTouchEnd"
|
|
14
|
+
]);
|
|
15
|
+
var INTERACTIVE_TYPES = /* @__PURE__ */ new Set([
|
|
16
|
+
"button",
|
|
17
|
+
"input",
|
|
18
|
+
"switch",
|
|
19
|
+
"checkbox",
|
|
20
|
+
"radio",
|
|
21
|
+
"touchable",
|
|
22
|
+
"pressable",
|
|
23
|
+
"listItem"
|
|
24
|
+
]);
|
|
25
|
+
function roleForType(type) {
|
|
26
|
+
switch (type) {
|
|
27
|
+
case "button":
|
|
28
|
+
case "touchable":
|
|
29
|
+
case "pressable":
|
|
30
|
+
return "button";
|
|
31
|
+
case "input":
|
|
32
|
+
return "textbox";
|
|
33
|
+
case "text":
|
|
34
|
+
return "text";
|
|
35
|
+
case "switch":
|
|
36
|
+
return "switch";
|
|
37
|
+
case "checkbox":
|
|
38
|
+
return "checkbox";
|
|
39
|
+
case "radio":
|
|
40
|
+
return "radio";
|
|
41
|
+
case "image":
|
|
42
|
+
return "img";
|
|
43
|
+
case "list":
|
|
44
|
+
return "list";
|
|
45
|
+
case "listItem":
|
|
46
|
+
return "listitem";
|
|
47
|
+
case "modal":
|
|
48
|
+
return "dialog";
|
|
49
|
+
case "scroll":
|
|
50
|
+
case "view":
|
|
51
|
+
case "custom":
|
|
52
|
+
default:
|
|
53
|
+
return void 0;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function deriveInteractable(type, handlerNames) {
|
|
57
|
+
if (INTERACTIVE_TYPES.has(type)) return true;
|
|
58
|
+
if (handlerNames) {
|
|
59
|
+
for (const name of handlerNames) {
|
|
60
|
+
if (INTERACTIVE_HANDLER_NAMES.has(name)) return true;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
function deriveText(state, label) {
|
|
66
|
+
const candidates = [state.value, state.textContent, label];
|
|
67
|
+
for (const c of candidates) {
|
|
68
|
+
if (typeof c === "string") {
|
|
69
|
+
const trimmed = c.trim();
|
|
70
|
+
if (trimmed.length > 0) return trimmed;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return void 0;
|
|
74
|
+
}
|
|
75
|
+
var NAMED_COLORS = {
|
|
76
|
+
black: { r: 0, g: 0, b: 0 },
|
|
77
|
+
white: { r: 255, g: 255, b: 255 },
|
|
78
|
+
red: { r: 255, g: 0, b: 0 },
|
|
79
|
+
green: { r: 0, g: 128, b: 0 },
|
|
80
|
+
blue: { r: 0, g: 0, b: 255 },
|
|
81
|
+
gray: { r: 128, g: 128, b: 128 },
|
|
82
|
+
grey: { r: 128, g: 128, b: 128 },
|
|
83
|
+
silver: { r: 192, g: 192, b: 192 },
|
|
84
|
+
transparent: { r: 0, g: 0, b: 0 },
|
|
85
|
+
orange: { r: 255, g: 165, b: 0 },
|
|
86
|
+
yellow: { r: 255, g: 255, b: 0 },
|
|
87
|
+
purple: { r: 128, g: 0, b: 128 },
|
|
88
|
+
navy: { r: 0, g: 0, b: 128 }
|
|
89
|
+
};
|
|
90
|
+
var clamp255 = (n) => Math.max(0, Math.min(255, Math.round(n)));
|
|
91
|
+
function parseColorToRgb(input) {
|
|
92
|
+
if (typeof input !== "string") return void 0;
|
|
93
|
+
const raw = input.trim().toLowerCase();
|
|
94
|
+
if (raw.length === 0) return void 0;
|
|
95
|
+
if (Object.prototype.hasOwnProperty.call(NAMED_COLORS, raw)) {
|
|
96
|
+
return NAMED_COLORS[raw];
|
|
97
|
+
}
|
|
98
|
+
if (raw.startsWith("#")) {
|
|
99
|
+
const hex = raw.slice(1);
|
|
100
|
+
if (hex.length === 3 || hex.length === 4) {
|
|
101
|
+
const r = parseInt(hex[0] + hex[0], 16);
|
|
102
|
+
const g = parseInt(hex[1] + hex[1], 16);
|
|
103
|
+
const b = parseInt(hex[2] + hex[2], 16);
|
|
104
|
+
if ([r, g, b].every((v) => Number.isFinite(v))) return { r, g, b };
|
|
105
|
+
return void 0;
|
|
106
|
+
}
|
|
107
|
+
if (hex.length === 6 || hex.length === 8) {
|
|
108
|
+
const r = parseInt(hex.slice(0, 2), 16);
|
|
109
|
+
const g = parseInt(hex.slice(2, 4), 16);
|
|
110
|
+
const b = parseInt(hex.slice(4, 6), 16);
|
|
111
|
+
if ([r, g, b].every((v) => Number.isFinite(v))) return { r, g, b };
|
|
112
|
+
return void 0;
|
|
113
|
+
}
|
|
114
|
+
return void 0;
|
|
115
|
+
}
|
|
116
|
+
const rgbMatch = raw.match(/^rgba?\(([^)]+)\)$/);
|
|
117
|
+
if (rgbMatch) {
|
|
118
|
+
const parts = rgbMatch[1].split(",").map((p) => p.trim());
|
|
119
|
+
if (parts.length < 3) return void 0;
|
|
120
|
+
const channel = (p) => {
|
|
121
|
+
if (p.endsWith("%")) {
|
|
122
|
+
const pct = parseFloat(p.slice(0, -1));
|
|
123
|
+
if (!Number.isFinite(pct)) return void 0;
|
|
124
|
+
return clamp255(pct / 100 * 255);
|
|
125
|
+
}
|
|
126
|
+
const n = parseFloat(p);
|
|
127
|
+
if (!Number.isFinite(n)) return void 0;
|
|
128
|
+
return clamp255(n);
|
|
129
|
+
};
|
|
130
|
+
const r = channel(parts[0]);
|
|
131
|
+
const g = channel(parts[1]);
|
|
132
|
+
const b = channel(parts[2]);
|
|
133
|
+
if (r === void 0 || g === void 0 || b === void 0) return void 0;
|
|
134
|
+
return { r, g, b };
|
|
135
|
+
}
|
|
136
|
+
return void 0;
|
|
137
|
+
}
|
|
138
|
+
function parseFontSizePx(input) {
|
|
139
|
+
if (typeof input === "number") {
|
|
140
|
+
return Number.isFinite(input) && input > 0 ? input : void 0;
|
|
141
|
+
}
|
|
142
|
+
if (typeof input === "string") {
|
|
143
|
+
const m = input.trim().match(/^(-?\d*\.?\d+)/);
|
|
144
|
+
if (m) {
|
|
145
|
+
const n = parseFloat(m[1]);
|
|
146
|
+
return Number.isFinite(n) && n > 0 ? n : void 0;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return void 0;
|
|
150
|
+
}
|
|
151
|
+
function projectVisionFields(args) {
|
|
152
|
+
const { type, label, handlerNames, state, flatStyle } = args;
|
|
153
|
+
const fields = {
|
|
154
|
+
interactable: deriveInteractable(type, handlerNames)
|
|
155
|
+
};
|
|
156
|
+
const text = deriveText(state, label);
|
|
157
|
+
if (text !== void 0) fields.text = text;
|
|
158
|
+
const role = roleForType(type);
|
|
159
|
+
if (role !== void 0) fields.role = role;
|
|
160
|
+
if (flatStyle) {
|
|
161
|
+
const fg = parseColorToRgb(flatStyle.color);
|
|
162
|
+
if (fg !== void 0) fields.fg_color = fg;
|
|
163
|
+
const bg = parseColorToRgb(flatStyle.backgroundColor);
|
|
164
|
+
if (bg !== void 0) fields.bg_color = bg;
|
|
165
|
+
const size = parseFontSizePx(flatStyle.fontSize);
|
|
166
|
+
if (size !== void 0) fields.font_size_px = size;
|
|
167
|
+
if (typeof flatStyle.fontFamily === "string" && flatStyle.fontFamily.trim().length > 0) {
|
|
168
|
+
fields.font_family = flatStyle.fontFamily;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return fields;
|
|
172
|
+
}
|
|
173
|
+
|
|
1
174
|
// src/core/registry.ts
|
|
2
175
|
function extractHandlerNames(props) {
|
|
3
176
|
if (!props) return [];
|
|
@@ -7,6 +180,25 @@ function matchesCurrentRoute(registrationRoute, currentRoute) {
|
|
|
7
180
|
if (registrationRoute == null || registrationRoute === "") return true;
|
|
8
181
|
return registrationRoute === currentRoute;
|
|
9
182
|
}
|
|
183
|
+
function projectBbox(state, visibility, pixelRatio = 1) {
|
|
184
|
+
if (visibility !== "visible") return void 0;
|
|
185
|
+
const layout = state.layout;
|
|
186
|
+
if (!layout) return void 0;
|
|
187
|
+
const ratio = pixelRatio > 0 && Number.isFinite(pixelRatio) ? pixelRatio : 1;
|
|
188
|
+
const toPx = (v) => Math.max(0, Math.round(v * ratio));
|
|
189
|
+
const hasPage = typeof layout.pageX === "number" && typeof layout.pageY === "number" && Number.isFinite(layout.pageX) && Number.isFinite(layout.pageY);
|
|
190
|
+
const originX = hasPage ? layout.pageX : layout.x;
|
|
191
|
+
const originY = hasPage ? layout.pageY : layout.y;
|
|
192
|
+
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)) {
|
|
193
|
+
return void 0;
|
|
194
|
+
}
|
|
195
|
+
return {
|
|
196
|
+
x: toPx(originX),
|
|
197
|
+
y: toPx(originY),
|
|
198
|
+
w: toPx(layout.width),
|
|
199
|
+
h: toPx(layout.height)
|
|
200
|
+
};
|
|
201
|
+
}
|
|
10
202
|
function inferActions(type) {
|
|
11
203
|
const baseActions = ["focus", "blur"];
|
|
12
204
|
switch (type) {
|
|
@@ -71,6 +263,15 @@ var NativeUIBridgeRegistry = class {
|
|
|
71
263
|
* already installs.
|
|
72
264
|
*/
|
|
73
265
|
this.routeProvider = null;
|
|
266
|
+
/**
|
|
267
|
+
* Device pixel ratio used to project `state.layout` (logical dp) into the
|
|
268
|
+
* physical-pixel `bbox` emitted on each snapshot element. Defaults to `1`
|
|
269
|
+
* (dp ≈ px) so callers/tests that never inject a ratio still get a usable
|
|
270
|
+
* box; the React provider wires the real `PixelRatio.get()` via
|
|
271
|
+
* {@link setPixelRatio}. Read from a non-React core module on purpose — see
|
|
272
|
+
* the `projectBbox` doc comment for why we don't import `react-native` here.
|
|
273
|
+
*/
|
|
274
|
+
this.pixelRatio = 1;
|
|
74
275
|
/**
|
|
75
276
|
* Sticky flag: flips `true` the first time any element is registered and
|
|
76
277
|
* stays `true` even after elements are unregistered. Lets agents distinguish
|
|
@@ -108,6 +309,21 @@ var NativeUIBridgeRegistry = class {
|
|
|
108
309
|
getRouteProvider() {
|
|
109
310
|
return this.routeProvider;
|
|
110
311
|
}
|
|
312
|
+
/**
|
|
313
|
+
* Set the device pixel ratio used to project per-element `bbox` geometry
|
|
314
|
+
* into physical pixels. The React provider passes `PixelRatio.get()` here
|
|
315
|
+
* once at startup. Ignores non-finite / non-positive values (keeps the
|
|
316
|
+
* previous ratio) so a bad call can't zero out every bbox.
|
|
317
|
+
*/
|
|
318
|
+
setPixelRatio(ratio) {
|
|
319
|
+
if (typeof ratio === "number" && Number.isFinite(ratio) && ratio > 0) {
|
|
320
|
+
this.pixelRatio = ratio;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
/** Read-only accessor for the device pixel ratio used for bbox projection. */
|
|
324
|
+
getPixelRatio() {
|
|
325
|
+
return this.pixelRatio;
|
|
326
|
+
}
|
|
111
327
|
// ============================================================================
|
|
112
328
|
// Snapshot Enricher Slots
|
|
113
329
|
// ============================================================================
|
|
@@ -647,6 +863,18 @@ var NativeUIBridgeRegistry = class {
|
|
|
647
863
|
const handlers = extractHandlerNames(e.props);
|
|
648
864
|
const state = e.getState();
|
|
649
865
|
const visibility = !state.visible ? "hidden" : state.layout !== null ? "visible" : "likely-visible";
|
|
866
|
+
const bbox = projectBbox(state, visibility, this.pixelRatio);
|
|
867
|
+
const vision = projectVisionFields({
|
|
868
|
+
type: e.type,
|
|
869
|
+
label: e.label,
|
|
870
|
+
// Real interactivity signal: the names of props that are actually
|
|
871
|
+
// functions (onPress/onChangeText/...). NOT `e.actions`, which
|
|
872
|
+
// `inferActions` synthesizes press/click onto for every element —
|
|
873
|
+
// using it would mark plain text/view nodes interactable.
|
|
874
|
+
handlerNames: handlers,
|
|
875
|
+
state,
|
|
876
|
+
flatStyle: e.flatStyle
|
|
877
|
+
});
|
|
650
878
|
return {
|
|
651
879
|
id: e.id,
|
|
652
880
|
type: e.type,
|
|
@@ -657,7 +885,9 @@ var NativeUIBridgeRegistry = class {
|
|
|
657
885
|
customActions: e.customActions ? Object.keys(e.customActions) : void 0,
|
|
658
886
|
registeredHandlers: handlers.length > 0 ? handlers : void 0,
|
|
659
887
|
registrationRoute: e.registrationRoute,
|
|
660
|
-
visibility
|
|
888
|
+
visibility,
|
|
889
|
+
...bbox ? { bbox } : {},
|
|
890
|
+
...vision
|
|
661
891
|
};
|
|
662
892
|
}),
|
|
663
893
|
components: this.getAllComponents().map((c) => ({
|
|
@@ -872,6 +1102,6 @@ function matchesIdentifier(identifier, criteria) {
|
|
|
872
1102
|
return true;
|
|
873
1103
|
}
|
|
874
1104
|
|
|
875
|
-
export { NativeUIBridgeRegistry, buildTreePath, createNativeElementIdentifier, extractHandlerNames, findAllByPattern, findElementByIdentifier, getGlobalRegistry, matchesCurrentRoute, matchesIdentifier, parseTreePath, resetGlobalRegistry, setGlobalRegistry };
|
|
1105
|
+
export { NativeUIBridgeRegistry, buildTreePath, createNativeElementIdentifier, extractHandlerNames, findAllByPattern, findElementByIdentifier, getGlobalRegistry, matchesCurrentRoute, matchesIdentifier, parseTreePath, projectBbox, resetGlobalRegistry, setGlobalRegistry };
|
|
876
1106
|
//# sourceMappingURL=index.mjs.map
|
|
877
1107
|
//# sourceMappingURL=index.mjs.map
|