@qontinui/ui-bridge-native 0.7.0 → 0.8.0
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/index.js +2 -0
- package/dist/control/index.js.map +1 -1
- package/dist/control/index.mjs +2 -0
- package/dist/control/index.mjs.map +1 -1
- package/dist/core/index.js +267 -15
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.mjs +267 -16
- package/dist/core/index.mjs.map +1 -1
- package/dist/core/registry.d.ts +13 -0
- package/dist/core/registry.d.ts.map +1 -1
- package/dist/core/sha256.d.ts +19 -0
- package/dist/core/sha256.d.ts.map +1 -0
- package/dist/core/types.d.ts +20 -7
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/vision-fields.d.ts +164 -11
- package/dist/core/vision-fields.d.ts.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +320 -44
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +315 -45
- package/dist/index.mjs.map +1 -1
- package/dist/react/index.js +314 -44
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +314 -44
- package/dist/react/index.mjs.map +1 -1
- package/dist/react/useRouteAwareness.d.ts.map +1 -1
- package/dist/server/handlers.d.ts.map +1 -1
- package/dist/server/index.js +303 -37
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +303 -37
- package/dist/server/index.mjs.map +1 -1
- package/dist/server/page-health.d.ts +10 -1
- package/dist/server/page-health.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/server/index.mjs
CHANGED
|
@@ -335,6 +335,164 @@ var UI_BRIDGE_NATIVE_ROUTES = {
|
|
|
335
335
|
}
|
|
336
336
|
};
|
|
337
337
|
|
|
338
|
+
// src/core/sha256.ts
|
|
339
|
+
var K = new Uint32Array([
|
|
340
|
+
1116352408,
|
|
341
|
+
1899447441,
|
|
342
|
+
3049323471,
|
|
343
|
+
3921009573,
|
|
344
|
+
961987163,
|
|
345
|
+
1508970993,
|
|
346
|
+
2453635748,
|
|
347
|
+
2870763221,
|
|
348
|
+
3624381080,
|
|
349
|
+
310598401,
|
|
350
|
+
607225278,
|
|
351
|
+
1426881987,
|
|
352
|
+
1925078388,
|
|
353
|
+
2162078206,
|
|
354
|
+
2614888103,
|
|
355
|
+
3248222580,
|
|
356
|
+
3835390401,
|
|
357
|
+
4022224774,
|
|
358
|
+
264347078,
|
|
359
|
+
604807628,
|
|
360
|
+
770255983,
|
|
361
|
+
1249150122,
|
|
362
|
+
1555081692,
|
|
363
|
+
1996064986,
|
|
364
|
+
2554220882,
|
|
365
|
+
2821834349,
|
|
366
|
+
2952996808,
|
|
367
|
+
3210313671,
|
|
368
|
+
3336571891,
|
|
369
|
+
3584528711,
|
|
370
|
+
113926993,
|
|
371
|
+
338241895,
|
|
372
|
+
666307205,
|
|
373
|
+
773529912,
|
|
374
|
+
1294757372,
|
|
375
|
+
1396182291,
|
|
376
|
+
1695183700,
|
|
377
|
+
1986661051,
|
|
378
|
+
2177026350,
|
|
379
|
+
2456956037,
|
|
380
|
+
2730485921,
|
|
381
|
+
2820302411,
|
|
382
|
+
3259730800,
|
|
383
|
+
3345764771,
|
|
384
|
+
3516065817,
|
|
385
|
+
3600352804,
|
|
386
|
+
4094571909,
|
|
387
|
+
275423344,
|
|
388
|
+
430227734,
|
|
389
|
+
506948616,
|
|
390
|
+
659060556,
|
|
391
|
+
883997877,
|
|
392
|
+
958139571,
|
|
393
|
+
1322822218,
|
|
394
|
+
1537002063,
|
|
395
|
+
1747873779,
|
|
396
|
+
1955562222,
|
|
397
|
+
2024104815,
|
|
398
|
+
2227730452,
|
|
399
|
+
2361852424,
|
|
400
|
+
2428436474,
|
|
401
|
+
2756734187,
|
|
402
|
+
3204031479,
|
|
403
|
+
3329325298
|
|
404
|
+
]);
|
|
405
|
+
var H0 = [
|
|
406
|
+
1779033703,
|
|
407
|
+
3144134277,
|
|
408
|
+
1013904242,
|
|
409
|
+
2773480762,
|
|
410
|
+
1359893119,
|
|
411
|
+
2600822924,
|
|
412
|
+
528734635,
|
|
413
|
+
1541459225
|
|
414
|
+
];
|
|
415
|
+
function utf8Bytes(input) {
|
|
416
|
+
const out = [];
|
|
417
|
+
for (let i = 0; i < input.length; i++) {
|
|
418
|
+
let cp = input.charCodeAt(i);
|
|
419
|
+
if (cp >= 55296 && cp <= 56319) {
|
|
420
|
+
const next = i + 1 < input.length ? input.charCodeAt(i + 1) : 0;
|
|
421
|
+
if (next >= 56320 && next <= 57343) {
|
|
422
|
+
cp = 65536 + (cp - 55296 << 10) + (next - 56320);
|
|
423
|
+
i++;
|
|
424
|
+
} else {
|
|
425
|
+
cp = 65533;
|
|
426
|
+
}
|
|
427
|
+
} else if (cp >= 56320 && cp <= 57343) {
|
|
428
|
+
cp = 65533;
|
|
429
|
+
}
|
|
430
|
+
if (cp < 128) {
|
|
431
|
+
out.push(cp);
|
|
432
|
+
} else if (cp < 2048) {
|
|
433
|
+
out.push(192 | cp >> 6, 128 | cp & 63);
|
|
434
|
+
} else if (cp < 65536) {
|
|
435
|
+
out.push(224 | cp >> 12, 128 | cp >> 6 & 63, 128 | cp & 63);
|
|
436
|
+
} else {
|
|
437
|
+
out.push(
|
|
438
|
+
240 | cp >> 18,
|
|
439
|
+
128 | cp >> 12 & 63,
|
|
440
|
+
128 | cp >> 6 & 63,
|
|
441
|
+
128 | cp & 63
|
|
442
|
+
);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
return Uint8Array.from(out);
|
|
446
|
+
}
|
|
447
|
+
var rotr = (x, n) => x >>> n | x << 32 - n;
|
|
448
|
+
function sha256Hex(input) {
|
|
449
|
+
const bytes = utf8Bytes(input);
|
|
450
|
+
const blockBytes = Math.ceil((bytes.length + 9) / 64) * 64;
|
|
451
|
+
const buffer = new Uint8Array(blockBytes);
|
|
452
|
+
buffer.set(bytes);
|
|
453
|
+
buffer[bytes.length] = 128;
|
|
454
|
+
const view = new DataView(buffer.buffer);
|
|
455
|
+
const bitLength = bytes.length * 8;
|
|
456
|
+
view.setUint32(blockBytes - 8, Math.floor(bitLength / 4294967296));
|
|
457
|
+
view.setUint32(blockBytes - 4, bitLength >>> 0);
|
|
458
|
+
const h = H0.slice();
|
|
459
|
+
const w = new Uint32Array(64);
|
|
460
|
+
for (let block = 0; block < blockBytes; block += 64) {
|
|
461
|
+
for (let t = 0; t < 16; t++) w[t] = view.getUint32(block + t * 4);
|
|
462
|
+
for (let t = 16; t < 64; t++) {
|
|
463
|
+
const s0 = rotr(w[t - 15], 7) ^ rotr(w[t - 15], 18) ^ w[t - 15] >>> 3;
|
|
464
|
+
const s1 = rotr(w[t - 2], 17) ^ rotr(w[t - 2], 19) ^ w[t - 2] >>> 10;
|
|
465
|
+
w[t] = w[t - 16] + s0 + w[t - 7] + s1;
|
|
466
|
+
}
|
|
467
|
+
let [a, b, c, d, e, f, g, hh] = h;
|
|
468
|
+
for (let t = 0; t < 64; t++) {
|
|
469
|
+
const S1 = rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25);
|
|
470
|
+
const ch = e & f ^ ~e & g;
|
|
471
|
+
const t1 = hh + S1 + ch + K[t] + w[t] | 0;
|
|
472
|
+
const S0 = rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22);
|
|
473
|
+
const maj = a & b ^ a & c ^ b & c;
|
|
474
|
+
const t2 = S0 + maj | 0;
|
|
475
|
+
hh = g;
|
|
476
|
+
g = f;
|
|
477
|
+
f = e;
|
|
478
|
+
e = d + t1 | 0;
|
|
479
|
+
d = c;
|
|
480
|
+
c = b;
|
|
481
|
+
b = a;
|
|
482
|
+
a = t1 + t2 | 0;
|
|
483
|
+
}
|
|
484
|
+
h[0] = h[0] + a | 0;
|
|
485
|
+
h[1] = h[1] + b | 0;
|
|
486
|
+
h[2] = h[2] + c | 0;
|
|
487
|
+
h[3] = h[3] + d | 0;
|
|
488
|
+
h[4] = h[4] + e | 0;
|
|
489
|
+
h[5] = h[5] + f | 0;
|
|
490
|
+
h[6] = h[6] + g | 0;
|
|
491
|
+
h[7] = h[7] + hh | 0;
|
|
492
|
+
}
|
|
493
|
+
return h.map((word) => (word >>> 0).toString(16).padStart(8, "0")).join("");
|
|
494
|
+
}
|
|
495
|
+
|
|
338
496
|
// src/core/vision-fields.ts
|
|
339
497
|
var INTERACTIVE_HANDLER_NAMES = /* @__PURE__ */ new Set([
|
|
340
498
|
"onPress",
|
|
@@ -418,13 +576,18 @@ var NAMED_COLORS = {
|
|
|
418
576
|
gray: { r: 128, g: 128, b: 128 },
|
|
419
577
|
grey: { r: 128, g: 128, b: 128 },
|
|
420
578
|
silver: { r: 192, g: 192, b: 192 },
|
|
421
|
-
transparent: { r: 0, g: 0, b: 0 },
|
|
422
579
|
orange: { r: 255, g: 165, b: 0 },
|
|
423
580
|
yellow: { r: 255, g: 255, b: 0 },
|
|
424
581
|
purple: { r: 128, g: 0, b: 128 },
|
|
425
582
|
navy: { r: 0, g: 0, b: 128 }
|
|
426
583
|
};
|
|
427
584
|
var clamp255 = (n) => Math.max(0, Math.min(255, Math.round(n)));
|
|
585
|
+
function parseAlpha(p) {
|
|
586
|
+
const pct = p.endsWith("%");
|
|
587
|
+
const n = parseFloat(pct ? p.slice(0, -1) : p);
|
|
588
|
+
if (!Number.isFinite(n)) return void 0;
|
|
589
|
+
return Math.min(1, pct ? n / 100 : n);
|
|
590
|
+
}
|
|
428
591
|
function parseColorToRgb(input) {
|
|
429
592
|
if (typeof input !== "string") return void 0;
|
|
430
593
|
const raw = input.trim().toLowerCase();
|
|
@@ -435,6 +598,7 @@ function parseColorToRgb(input) {
|
|
|
435
598
|
if (raw.startsWith("#")) {
|
|
436
599
|
const hex = raw.slice(1);
|
|
437
600
|
if (hex.length === 3 || hex.length === 4) {
|
|
601
|
+
if (hex.length === 4 && hex[3] !== "f") return void 0;
|
|
438
602
|
const r = parseInt(hex[0] + hex[0], 16);
|
|
439
603
|
const g = parseInt(hex[1] + hex[1], 16);
|
|
440
604
|
const b = parseInt(hex[2] + hex[2], 16);
|
|
@@ -442,6 +606,7 @@ function parseColorToRgb(input) {
|
|
|
442
606
|
return void 0;
|
|
443
607
|
}
|
|
444
608
|
if (hex.length === 6 || hex.length === 8) {
|
|
609
|
+
if (hex.length === 8 && hex.slice(6, 8) !== "ff") return void 0;
|
|
445
610
|
const r = parseInt(hex.slice(0, 2), 16);
|
|
446
611
|
const g = parseInt(hex.slice(2, 4), 16);
|
|
447
612
|
const b = parseInt(hex.slice(4, 6), 16);
|
|
@@ -453,7 +618,11 @@ function parseColorToRgb(input) {
|
|
|
453
618
|
const rgbMatch = raw.match(/^rgba?\(([^)]+)\)$/);
|
|
454
619
|
if (rgbMatch) {
|
|
455
620
|
const parts = rgbMatch[1].split(",").map((p) => p.trim());
|
|
456
|
-
if (parts.length < 3) return void 0;
|
|
621
|
+
if (parts.length < 3 || parts.length > 4) return void 0;
|
|
622
|
+
if (parts.length === 4) {
|
|
623
|
+
const alpha = parseAlpha(parts[3]);
|
|
624
|
+
if (alpha === void 0 || alpha < 1) return void 0;
|
|
625
|
+
}
|
|
457
626
|
const channel = (p) => {
|
|
458
627
|
if (p.endsWith("%")) {
|
|
459
628
|
const pct = parseFloat(p.slice(0, -1));
|
|
@@ -485,13 +654,87 @@ function parseFontSizePx(input) {
|
|
|
485
654
|
}
|
|
486
655
|
return void 0;
|
|
487
656
|
}
|
|
657
|
+
var ASCII_WHITESPACE_EDGES = /^[\t\n\f\r ]+|[\t\n\f\r ]+$/g;
|
|
658
|
+
function nonEmptyString(v) {
|
|
659
|
+
return typeof v === "string" && v.length > 0 ? v : void 0;
|
|
660
|
+
}
|
|
661
|
+
var OBJECT_FIT_TO_RESIZE_MODE = /* @__PURE__ */ new Map([
|
|
662
|
+
["contain", "contain"],
|
|
663
|
+
["cover", "cover"],
|
|
664
|
+
["fill", "stretch"],
|
|
665
|
+
["scale-down", "contain"],
|
|
666
|
+
["none", "none"]
|
|
667
|
+
]);
|
|
668
|
+
var RESIZE_MODE_TO_OBJECT_FIT = /* @__PURE__ */ new Map([
|
|
669
|
+
["cover", "cover"],
|
|
670
|
+
["contain", "contain"],
|
|
671
|
+
["stretch", "fill"],
|
|
672
|
+
["center", "scale-down"],
|
|
673
|
+
["none", "none"]
|
|
674
|
+
]);
|
|
675
|
+
function resolveObjectFit(props, flatStyle) {
|
|
676
|
+
const styleFit = nonEmptyString(flatStyle?.objectFit);
|
|
677
|
+
const mode = (styleFit !== void 0 ? OBJECT_FIT_TO_RESIZE_MODE.get(styleFit) : void 0) ?? nonEmptyString(props?.resizeMode) ?? nonEmptyString(flatStyle?.resizeMode);
|
|
678
|
+
return mode !== void 0 ? RESIZE_MODE_TO_OBJECT_FIT.get(mode) : void 0;
|
|
679
|
+
}
|
|
680
|
+
function resolveImageSource(props) {
|
|
681
|
+
if (!props) return void 0;
|
|
682
|
+
if (props.srcSet !== void 0 && props.srcSet !== null) return void 0;
|
|
683
|
+
const src = nonEmptyString(props.src);
|
|
684
|
+
if (src !== void 0) return src;
|
|
685
|
+
const source = props.source;
|
|
686
|
+
const one = Array.isArray(source) ? source.length === 1 ? source[0] : void 0 : source;
|
|
687
|
+
if (one && typeof one === "object") {
|
|
688
|
+
return nonEmptyString(one.uri);
|
|
689
|
+
}
|
|
690
|
+
return void 0;
|
|
691
|
+
}
|
|
692
|
+
function isHiddenFromAccessibility(props) {
|
|
693
|
+
if (!props) return false;
|
|
694
|
+
return props.accessible === false && props.alt === void 0 || props.importantForAccessibility === "no" || props.importantForAccessibility === "no-hide-descendants" || props.accessibilityElementsHidden === true;
|
|
695
|
+
}
|
|
696
|
+
function resolveImageLabel(props, registryLabel) {
|
|
697
|
+
if (props === void 0) return registryLabel;
|
|
698
|
+
const own = props["aria-label"] ?? props.accessibilityLabel ?? props.alt;
|
|
699
|
+
return typeof own === "string" ? own : void 0;
|
|
700
|
+
}
|
|
701
|
+
function projectMedia(args) {
|
|
702
|
+
const { layout, props, flatStyle, accessibilityLabel, inViewport } = args;
|
|
703
|
+
const media = { kind: "img" };
|
|
704
|
+
if (layout && Number.isFinite(layout.width) && Number.isFinite(layout.height) && layout.width >= 0 && layout.height >= 0) {
|
|
705
|
+
media.rendered_px = { w: layout.width, h: layout.height };
|
|
706
|
+
}
|
|
707
|
+
const objectFit = resolveObjectFit(props, flatStyle);
|
|
708
|
+
if (objectFit !== void 0) media.object_fit = objectFit;
|
|
709
|
+
if (isHiddenFromAccessibility(props)) {
|
|
710
|
+
media.alt = { decorative: true };
|
|
711
|
+
} else {
|
|
712
|
+
const label = resolveImageLabel(props, accessibilityLabel);
|
|
713
|
+
const text = label?.replace(ASCII_WHITESPACE_EDGES, "");
|
|
714
|
+
if (text) media.alt = { decorative: false, text };
|
|
715
|
+
}
|
|
716
|
+
const src = resolveImageSource(props);
|
|
717
|
+
if (src !== void 0) media.src_digest = sha256Hex(src);
|
|
718
|
+
if (inViewport !== void 0) media.in_viewport = inViewport;
|
|
719
|
+
return media;
|
|
720
|
+
}
|
|
488
721
|
function projectVisionFields(args) {
|
|
489
722
|
const { type, label, handlerNames, state, flatStyle } = args;
|
|
490
723
|
const fields = {
|
|
491
724
|
interactable: deriveInteractable(type, handlerNames)
|
|
492
725
|
};
|
|
493
|
-
|
|
494
|
-
|
|
726
|
+
if (type === "image") {
|
|
727
|
+
fields.media = projectMedia({
|
|
728
|
+
layout: state.layout,
|
|
729
|
+
props: args.props,
|
|
730
|
+
flatStyle,
|
|
731
|
+
accessibilityLabel: args.accessibilityLabel,
|
|
732
|
+
inViewport: args.inViewport
|
|
733
|
+
});
|
|
734
|
+
} else {
|
|
735
|
+
const text = deriveText(state, label);
|
|
736
|
+
if (text !== void 0) fields.text = text;
|
|
737
|
+
}
|
|
495
738
|
const role = roleForType(type);
|
|
496
739
|
if (role !== void 0) fields.role = role;
|
|
497
740
|
if (flatStyle) {
|
|
@@ -585,11 +828,17 @@ function computeVisibility(state, clip) {
|
|
|
585
828
|
if (!rect) {
|
|
586
829
|
return { visibility: "visible" };
|
|
587
830
|
}
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
return
|
|
831
|
+
return rectReachesClip(rect, clip) ? { visibility: "visible" } : { visibility: "hidden", visibilityReason: "off-screen" };
|
|
832
|
+
}
|
|
833
|
+
function rectReachesClip(rect, clip) {
|
|
834
|
+
if (isEmptyRect(clip)) return false;
|
|
835
|
+
return spansOverlap(rect.left, rect.right, clip.left, clip.right) && spansOverlap(rect.top, rect.bottom, clip.top, clip.bottom);
|
|
836
|
+
}
|
|
837
|
+
function computeInViewport(state, clip) {
|
|
838
|
+
if (!state.visible || !clip) return void 0;
|
|
839
|
+
const rect = pageRectOf(state);
|
|
840
|
+
if (!rect) return void 0;
|
|
841
|
+
return rectReachesClip(rect, clip);
|
|
593
842
|
}
|
|
594
843
|
|
|
595
844
|
// src/design/design-inspector-native.ts
|
|
@@ -1264,7 +1513,7 @@ var NATIVE_PAGE_HEALTH_PRODUCER_ID = "sdk-native/page-health";
|
|
|
1264
1513
|
function defaultProducer() {
|
|
1265
1514
|
return {
|
|
1266
1515
|
id: NATIVE_PAGE_HEALTH_PRODUCER_ID,
|
|
1267
|
-
version: "0.
|
|
1516
|
+
version: "0.8.0"
|
|
1268
1517
|
};
|
|
1269
1518
|
}
|
|
1270
1519
|
function pageHealthUnknown(code, detail, options = {}) {
|
|
@@ -1306,14 +1555,7 @@ var LOADING_PHRASES = [
|
|
|
1306
1555
|
"initializing",
|
|
1307
1556
|
"fetching"
|
|
1308
1557
|
];
|
|
1309
|
-
var EMPTY_PHRASES = [
|
|
1310
|
-
"no data",
|
|
1311
|
-
"no results",
|
|
1312
|
-
"nothing here",
|
|
1313
|
-
"empty",
|
|
1314
|
-
"no items",
|
|
1315
|
-
"get started"
|
|
1316
|
-
];
|
|
1558
|
+
var EMPTY_PHRASES = ["no data", "no results", "nothing here", "empty", "no items", "get started"];
|
|
1317
1559
|
function severityRank(s) {
|
|
1318
1560
|
if (s === "CRITICAL") return 3;
|
|
1319
1561
|
if (s === "WARNING") return 2;
|
|
@@ -1388,20 +1630,44 @@ function observe(input, producer, evaluatedAt) {
|
|
|
1388
1630
|
}
|
|
1389
1631
|
return analyze(elements, viewport, base);
|
|
1390
1632
|
}
|
|
1633
|
+
function nothingOnScreenDetail(elements, visibleCount, visibilityUnstated) {
|
|
1634
|
+
if (visibilityUnstated === 0 && visibleCount > 0) {
|
|
1635
|
+
return `all ${visibleCount} visible element(s) have no measured layout yet, so spatial coverage, layout regions and visual anomalies cannot be measured`;
|
|
1636
|
+
}
|
|
1637
|
+
if (visibilityUnstated > 0) {
|
|
1638
|
+
const geometry = visibleCount > 0 ? ` and none of the ${visibleCount} visible one(s) has a measured layout` : "";
|
|
1639
|
+
return `${visibilityUnstated} of ${elements.length} element(s) carry no boolean \`state.visible\`${geometry}, so no element can be placed on screen; spatial coverage, layout regions and visual anomalies cannot be measured`;
|
|
1640
|
+
}
|
|
1641
|
+
const unmounted = elements.filter((el) => el.state?.mounted === false).length;
|
|
1642
|
+
return `all ${elements.length} registered element(s) report visible: false (unmounted=${unmounted}, off-screen route or otherwise=${elements.length - unmounted}), so whatever is on screen is not a registered element and there is nothing on screen to measure; this says nothing about whether the screen is blank`;
|
|
1643
|
+
}
|
|
1391
1644
|
function analyze(elements, viewport, base) {
|
|
1392
1645
|
const findings = [];
|
|
1393
|
-
const
|
|
1394
|
-
const
|
|
1646
|
+
const onScreen = elements.filter((el) => el.state?.visible === true);
|
|
1647
|
+
const visibilityUnstated = elements.filter(
|
|
1648
|
+
(el) => typeof el.state?.visible !== "boolean"
|
|
1649
|
+
).length;
|
|
1650
|
+
const visible = onScreen.flatMap((el) => {
|
|
1395
1651
|
const rect = normalizeRect(el.state, viewport);
|
|
1396
1652
|
return rect ? [{ el, rect }] : [];
|
|
1397
1653
|
});
|
|
1398
|
-
const withoutGeometry =
|
|
1399
|
-
const unmeasured =
|
|
1400
|
-
|
|
1401
|
-
|
|
1654
|
+
const withoutGeometry = onScreen.length - visible.length;
|
|
1655
|
+
const unmeasured = [];
|
|
1656
|
+
if (withoutGeometry > 0) {
|
|
1657
|
+
unmeasured.push({ dimension: "geometry", count: withoutGeometry, code: "input_missing" });
|
|
1658
|
+
}
|
|
1659
|
+
if (visibilityUnstated > 0) {
|
|
1660
|
+
unmeasured.push({ dimension: "visibility", count: visibilityUnstated, code: "input_missing" });
|
|
1661
|
+
}
|
|
1662
|
+
const coverage = {
|
|
1663
|
+
considered: onScreen.length + visibilityUnstated,
|
|
1664
|
+
measured: visible.length,
|
|
1665
|
+
unmeasured
|
|
1666
|
+
};
|
|
1667
|
+
if (elements.length > 0 && visible.length === 0) {
|
|
1402
1668
|
return Observation.unknown(
|
|
1403
1669
|
"input_missing",
|
|
1404
|
-
|
|
1670
|
+
nothingOnScreenDetail(elements, onScreen.length, visibilityUnstated),
|
|
1405
1671
|
Observation.provenance({ ...base, coverage })
|
|
1406
1672
|
);
|
|
1407
1673
|
}
|
|
@@ -1491,7 +1757,7 @@ function analyze(elements, viewport, base) {
|
|
|
1491
1757
|
for (const el of elements) {
|
|
1492
1758
|
const elType = el.type ?? "";
|
|
1493
1759
|
if (SKIP_TEXT_TYPES.has(elType)) continue;
|
|
1494
|
-
const text = (el.state
|
|
1760
|
+
const text = (el.state?.textContent ?? "").toString();
|
|
1495
1761
|
if (!text) continue;
|
|
1496
1762
|
const textLower = text.toLowerCase();
|
|
1497
1763
|
for (const p of ERROR_PHRASES) {
|
|
@@ -1532,7 +1798,7 @@ function analyze(elements, viewport, base) {
|
|
|
1532
1798
|
for (const el of elements) {
|
|
1533
1799
|
if (!INTERACTIVE_TYPES2.has(el.type)) continue;
|
|
1534
1800
|
interactiveTotal++;
|
|
1535
|
-
if (el.state
|
|
1801
|
+
if (el.state?.enabled === false) interactiveDisabled++;
|
|
1536
1802
|
}
|
|
1537
1803
|
const interactiveSeverity = interactiveTotal > 0 && interactiveDisabled / interactiveTotal > 0.5 ? "WARNING" : "OK";
|
|
1538
1804
|
findings.push({
|
|
@@ -1556,9 +1822,7 @@ function analyze(elements, viewport, base) {
|
|
|
1556
1822
|
detail: `zero_size=${zeroSize}, outside_viewport=${outsideViewport} (horizontal-overflow only; below/above-fold scrollable content is not an anomaly)`,
|
|
1557
1823
|
data: { zero_size: zeroSize, outside_viewport: outsideViewport }
|
|
1558
1824
|
});
|
|
1559
|
-
const heatmap = grid.map(
|
|
1560
|
-
(row) => row.map((cell) => cell ? "#" : ".").join("")
|
|
1561
|
-
);
|
|
1825
|
+
const heatmap = grid.map((row) => row.map((cell) => cell ? "#" : ".").join(""));
|
|
1562
1826
|
return Observation.measured(
|
|
1563
1827
|
{
|
|
1564
1828
|
summary: worstSeverity(findings),
|
|
@@ -1818,10 +2082,9 @@ function createServerHandlers(registry, executor, config) {
|
|
|
1818
2082
|
const elements = allElements.map((e) => {
|
|
1819
2083
|
const handlers = extractHandlerNames(e.props);
|
|
1820
2084
|
const state = e.getState();
|
|
1821
|
-
const
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
);
|
|
2085
|
+
const identifier = e.getIdentifier();
|
|
2086
|
+
const clip = registry.getClipRectFor(e, viewport);
|
|
2087
|
+
const { visibility, visibilityReason } = computeVisibility(state, clip);
|
|
1825
2088
|
const bbox = projectBbox(state, visibility, registry.getPixelRatio());
|
|
1826
2089
|
const vision = projectVisionFields({
|
|
1827
2090
|
type: e.type,
|
|
@@ -1830,13 +2093,16 @@ function createServerHandlers(registry, executor, config) {
|
|
|
1830
2093
|
// synthesize press/click onto every element. See projectVisionFields.
|
|
1831
2094
|
handlerNames: handlers,
|
|
1832
2095
|
state,
|
|
1833
|
-
flatStyle: e.flatStyle
|
|
2096
|
+
flatStyle: e.flatStyle,
|
|
2097
|
+
props: e.props,
|
|
2098
|
+
accessibilityLabel: identifier.accessibilityLabel,
|
|
2099
|
+
inViewport: computeInViewport(state, clip)
|
|
1834
2100
|
});
|
|
1835
2101
|
return {
|
|
1836
2102
|
id: e.id,
|
|
1837
2103
|
type: e.type,
|
|
1838
2104
|
label: e.label,
|
|
1839
|
-
identifier
|
|
2105
|
+
identifier,
|
|
1840
2106
|
state,
|
|
1841
2107
|
actions: e.actions,
|
|
1842
2108
|
customActions: serializeElementCustomActions(e.customActions),
|
|
@@ -2544,7 +2810,7 @@ function createServerHandlers(registry, executor, config) {
|
|
|
2544
2810
|
};
|
|
2545
2811
|
if (config?.appInfo) {
|
|
2546
2812
|
response.uiBridge = {
|
|
2547
|
-
version: "0.
|
|
2813
|
+
version: "0.8.0",
|
|
2548
2814
|
...config.appInfo,
|
|
2549
2815
|
capabilities: ["elements", "components", "actions", "design"],
|
|
2550
2816
|
elementCount: stats.elements,
|