@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.
@@ -462,6 +462,164 @@ function resolveActionEffect(action) {
462
462
  return action.effect ?? nativeStandardActionEffect(action.id);
463
463
  }
464
464
 
465
+ // src/core/sha256.ts
466
+ var K = new Uint32Array([
467
+ 1116352408,
468
+ 1899447441,
469
+ 3049323471,
470
+ 3921009573,
471
+ 961987163,
472
+ 1508970993,
473
+ 2453635748,
474
+ 2870763221,
475
+ 3624381080,
476
+ 310598401,
477
+ 607225278,
478
+ 1426881987,
479
+ 1925078388,
480
+ 2162078206,
481
+ 2614888103,
482
+ 3248222580,
483
+ 3835390401,
484
+ 4022224774,
485
+ 264347078,
486
+ 604807628,
487
+ 770255983,
488
+ 1249150122,
489
+ 1555081692,
490
+ 1996064986,
491
+ 2554220882,
492
+ 2821834349,
493
+ 2952996808,
494
+ 3210313671,
495
+ 3336571891,
496
+ 3584528711,
497
+ 113926993,
498
+ 338241895,
499
+ 666307205,
500
+ 773529912,
501
+ 1294757372,
502
+ 1396182291,
503
+ 1695183700,
504
+ 1986661051,
505
+ 2177026350,
506
+ 2456956037,
507
+ 2730485921,
508
+ 2820302411,
509
+ 3259730800,
510
+ 3345764771,
511
+ 3516065817,
512
+ 3600352804,
513
+ 4094571909,
514
+ 275423344,
515
+ 430227734,
516
+ 506948616,
517
+ 659060556,
518
+ 883997877,
519
+ 958139571,
520
+ 1322822218,
521
+ 1537002063,
522
+ 1747873779,
523
+ 1955562222,
524
+ 2024104815,
525
+ 2227730452,
526
+ 2361852424,
527
+ 2428436474,
528
+ 2756734187,
529
+ 3204031479,
530
+ 3329325298
531
+ ]);
532
+ var H0 = [
533
+ 1779033703,
534
+ 3144134277,
535
+ 1013904242,
536
+ 2773480762,
537
+ 1359893119,
538
+ 2600822924,
539
+ 528734635,
540
+ 1541459225
541
+ ];
542
+ function utf8Bytes(input) {
543
+ const out = [];
544
+ for (let i = 0; i < input.length; i++) {
545
+ let cp = input.charCodeAt(i);
546
+ if (cp >= 55296 && cp <= 56319) {
547
+ const next = i + 1 < input.length ? input.charCodeAt(i + 1) : 0;
548
+ if (next >= 56320 && next <= 57343) {
549
+ cp = 65536 + (cp - 55296 << 10) + (next - 56320);
550
+ i++;
551
+ } else {
552
+ cp = 65533;
553
+ }
554
+ } else if (cp >= 56320 && cp <= 57343) {
555
+ cp = 65533;
556
+ }
557
+ if (cp < 128) {
558
+ out.push(cp);
559
+ } else if (cp < 2048) {
560
+ out.push(192 | cp >> 6, 128 | cp & 63);
561
+ } else if (cp < 65536) {
562
+ out.push(224 | cp >> 12, 128 | cp >> 6 & 63, 128 | cp & 63);
563
+ } else {
564
+ out.push(
565
+ 240 | cp >> 18,
566
+ 128 | cp >> 12 & 63,
567
+ 128 | cp >> 6 & 63,
568
+ 128 | cp & 63
569
+ );
570
+ }
571
+ }
572
+ return Uint8Array.from(out);
573
+ }
574
+ var rotr = (x, n) => x >>> n | x << 32 - n;
575
+ function sha256Hex(input) {
576
+ const bytes = utf8Bytes(input);
577
+ const blockBytes = Math.ceil((bytes.length + 9) / 64) * 64;
578
+ const buffer = new Uint8Array(blockBytes);
579
+ buffer.set(bytes);
580
+ buffer[bytes.length] = 128;
581
+ const view = new DataView(buffer.buffer);
582
+ const bitLength = bytes.length * 8;
583
+ view.setUint32(blockBytes - 8, Math.floor(bitLength / 4294967296));
584
+ view.setUint32(blockBytes - 4, bitLength >>> 0);
585
+ const h = H0.slice();
586
+ const w = new Uint32Array(64);
587
+ for (let block = 0; block < blockBytes; block += 64) {
588
+ for (let t = 0; t < 16; t++) w[t] = view.getUint32(block + t * 4);
589
+ for (let t = 16; t < 64; t++) {
590
+ const s0 = rotr(w[t - 15], 7) ^ rotr(w[t - 15], 18) ^ w[t - 15] >>> 3;
591
+ const s1 = rotr(w[t - 2], 17) ^ rotr(w[t - 2], 19) ^ w[t - 2] >>> 10;
592
+ w[t] = w[t - 16] + s0 + w[t - 7] + s1;
593
+ }
594
+ let [a, b, c, d, e, f, g, hh] = h;
595
+ for (let t = 0; t < 64; t++) {
596
+ const S1 = rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25);
597
+ const ch = e & f ^ ~e & g;
598
+ const t1 = hh + S1 + ch + K[t] + w[t] | 0;
599
+ const S0 = rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22);
600
+ const maj = a & b ^ a & c ^ b & c;
601
+ const t2 = S0 + maj | 0;
602
+ hh = g;
603
+ g = f;
604
+ f = e;
605
+ e = d + t1 | 0;
606
+ d = c;
607
+ c = b;
608
+ b = a;
609
+ a = t1 + t2 | 0;
610
+ }
611
+ h[0] = h[0] + a | 0;
612
+ h[1] = h[1] + b | 0;
613
+ h[2] = h[2] + c | 0;
614
+ h[3] = h[3] + d | 0;
615
+ h[4] = h[4] + e | 0;
616
+ h[5] = h[5] + f | 0;
617
+ h[6] = h[6] + g | 0;
618
+ h[7] = h[7] + hh | 0;
619
+ }
620
+ return h.map((word) => (word >>> 0).toString(16).padStart(8, "0")).join("");
621
+ }
622
+
465
623
  // src/core/vision-fields.ts
466
624
  var INTERACTIVE_HANDLER_NAMES = /* @__PURE__ */ new Set([
467
625
  "onPress",
@@ -545,13 +703,18 @@ var NAMED_COLORS = {
545
703
  gray: { r: 128, g: 128, b: 128 },
546
704
  grey: { r: 128, g: 128, b: 128 },
547
705
  silver: { r: 192, g: 192, b: 192 },
548
- transparent: { r: 0, g: 0, b: 0 },
549
706
  orange: { r: 255, g: 165, b: 0 },
550
707
  yellow: { r: 255, g: 255, b: 0 },
551
708
  purple: { r: 128, g: 0, b: 128 },
552
709
  navy: { r: 0, g: 0, b: 128 }
553
710
  };
554
711
  var clamp255 = (n) => Math.max(0, Math.min(255, Math.round(n)));
712
+ function parseAlpha(p) {
713
+ const pct = p.endsWith("%");
714
+ const n = parseFloat(pct ? p.slice(0, -1) : p);
715
+ if (!Number.isFinite(n)) return void 0;
716
+ return Math.min(1, pct ? n / 100 : n);
717
+ }
555
718
  function parseColorToRgb(input) {
556
719
  if (typeof input !== "string") return void 0;
557
720
  const raw = input.trim().toLowerCase();
@@ -562,6 +725,7 @@ function parseColorToRgb(input) {
562
725
  if (raw.startsWith("#")) {
563
726
  const hex = raw.slice(1);
564
727
  if (hex.length === 3 || hex.length === 4) {
728
+ if (hex.length === 4 && hex[3] !== "f") return void 0;
565
729
  const r = parseInt(hex[0] + hex[0], 16);
566
730
  const g = parseInt(hex[1] + hex[1], 16);
567
731
  const b = parseInt(hex[2] + hex[2], 16);
@@ -569,6 +733,7 @@ function parseColorToRgb(input) {
569
733
  return void 0;
570
734
  }
571
735
  if (hex.length === 6 || hex.length === 8) {
736
+ if (hex.length === 8 && hex.slice(6, 8) !== "ff") return void 0;
572
737
  const r = parseInt(hex.slice(0, 2), 16);
573
738
  const g = parseInt(hex.slice(2, 4), 16);
574
739
  const b = parseInt(hex.slice(4, 6), 16);
@@ -580,7 +745,11 @@ function parseColorToRgb(input) {
580
745
  const rgbMatch = raw.match(/^rgba?\(([^)]+)\)$/);
581
746
  if (rgbMatch) {
582
747
  const parts = rgbMatch[1].split(",").map((p) => p.trim());
583
- if (parts.length < 3) return void 0;
748
+ if (parts.length < 3 || parts.length > 4) return void 0;
749
+ if (parts.length === 4) {
750
+ const alpha = parseAlpha(parts[3]);
751
+ if (alpha === void 0 || alpha < 1) return void 0;
752
+ }
584
753
  const channel = (p) => {
585
754
  if (p.endsWith("%")) {
586
755
  const pct = parseFloat(p.slice(0, -1));
@@ -612,13 +781,87 @@ function parseFontSizePx(input) {
612
781
  }
613
782
  return void 0;
614
783
  }
784
+ var ASCII_WHITESPACE_EDGES = /^[\t\n\f\r ]+|[\t\n\f\r ]+$/g;
785
+ function nonEmptyString(v) {
786
+ return typeof v === "string" && v.length > 0 ? v : void 0;
787
+ }
788
+ var OBJECT_FIT_TO_RESIZE_MODE = /* @__PURE__ */ new Map([
789
+ ["contain", "contain"],
790
+ ["cover", "cover"],
791
+ ["fill", "stretch"],
792
+ ["scale-down", "contain"],
793
+ ["none", "none"]
794
+ ]);
795
+ var RESIZE_MODE_TO_OBJECT_FIT = /* @__PURE__ */ new Map([
796
+ ["cover", "cover"],
797
+ ["contain", "contain"],
798
+ ["stretch", "fill"],
799
+ ["center", "scale-down"],
800
+ ["none", "none"]
801
+ ]);
802
+ function resolveObjectFit(props, flatStyle) {
803
+ const styleFit = nonEmptyString(flatStyle?.objectFit);
804
+ const mode = (styleFit !== void 0 ? OBJECT_FIT_TO_RESIZE_MODE.get(styleFit) : void 0) ?? nonEmptyString(props?.resizeMode) ?? nonEmptyString(flatStyle?.resizeMode);
805
+ return mode !== void 0 ? RESIZE_MODE_TO_OBJECT_FIT.get(mode) : void 0;
806
+ }
807
+ function resolveImageSource(props) {
808
+ if (!props) return void 0;
809
+ if (props.srcSet !== void 0 && props.srcSet !== null) return void 0;
810
+ const src = nonEmptyString(props.src);
811
+ if (src !== void 0) return src;
812
+ const source = props.source;
813
+ const one = Array.isArray(source) ? source.length === 1 ? source[0] : void 0 : source;
814
+ if (one && typeof one === "object") {
815
+ return nonEmptyString(one.uri);
816
+ }
817
+ return void 0;
818
+ }
819
+ function isHiddenFromAccessibility(props) {
820
+ if (!props) return false;
821
+ return props.accessible === false && props.alt === void 0 || props.importantForAccessibility === "no" || props.importantForAccessibility === "no-hide-descendants" || props.accessibilityElementsHidden === true;
822
+ }
823
+ function resolveImageLabel(props, registryLabel) {
824
+ if (props === void 0) return registryLabel;
825
+ const own = props["aria-label"] ?? props.accessibilityLabel ?? props.alt;
826
+ return typeof own === "string" ? own : void 0;
827
+ }
828
+ function projectMedia(args) {
829
+ const { layout, props, flatStyle, accessibilityLabel, inViewport } = args;
830
+ const media = { kind: "img" };
831
+ if (layout && Number.isFinite(layout.width) && Number.isFinite(layout.height) && layout.width >= 0 && layout.height >= 0) {
832
+ media.rendered_px = { w: layout.width, h: layout.height };
833
+ }
834
+ const objectFit = resolveObjectFit(props, flatStyle);
835
+ if (objectFit !== void 0) media.object_fit = objectFit;
836
+ if (isHiddenFromAccessibility(props)) {
837
+ media.alt = { decorative: true };
838
+ } else {
839
+ const label = resolveImageLabel(props, accessibilityLabel);
840
+ const text = label?.replace(ASCII_WHITESPACE_EDGES, "");
841
+ if (text) media.alt = { decorative: false, text };
842
+ }
843
+ const src = resolveImageSource(props);
844
+ if (src !== void 0) media.src_digest = sha256Hex(src);
845
+ if (inViewport !== void 0) media.in_viewport = inViewport;
846
+ return media;
847
+ }
615
848
  function projectVisionFields(args) {
616
849
  const { type, label, handlerNames, state, flatStyle } = args;
617
850
  const fields = {
618
851
  interactable: deriveInteractable(type, handlerNames)
619
852
  };
620
- const text = deriveText(state, label);
621
- if (text !== void 0) fields.text = text;
853
+ if (type === "image") {
854
+ fields.media = projectMedia({
855
+ layout: state.layout,
856
+ props: args.props,
857
+ flatStyle,
858
+ accessibilityLabel: args.accessibilityLabel,
859
+ inViewport: args.inViewport
860
+ });
861
+ } else {
862
+ const text = deriveText(state, label);
863
+ if (text !== void 0) fields.text = text;
864
+ }
622
865
  const role = roleForType(type);
623
866
  if (role !== void 0) fields.role = role;
624
867
  if (flatStyle) {
@@ -758,11 +1001,17 @@ function computeVisibility(state, clip) {
758
1001
  if (!rect) {
759
1002
  return { visibility: "visible" };
760
1003
  }
761
- if (isEmptyRect(clip)) {
762
- return { visibility: "hidden", visibilityReason: "off-screen" };
763
- }
764
- const onScreen = spansOverlap(rect.left, rect.right, clip.left, clip.right) && spansOverlap(rect.top, rect.bottom, clip.top, clip.bottom);
765
- return onScreen ? { visibility: "visible" } : { visibility: "hidden", visibilityReason: "off-screen" };
1004
+ return rectReachesClip(rect, clip) ? { visibility: "visible" } : { visibility: "hidden", visibilityReason: "off-screen" };
1005
+ }
1006
+ function rectReachesClip(rect, clip) {
1007
+ if (isEmptyRect(clip)) return false;
1008
+ return spansOverlap(rect.left, rect.right, clip.left, clip.right) && spansOverlap(rect.top, rect.bottom, clip.top, clip.bottom);
1009
+ }
1010
+ function computeInViewport(state, clip) {
1011
+ if (!state.visible || !clip) return void 0;
1012
+ const rect = pageRectOf(state);
1013
+ if (!rect) return void 0;
1014
+ return rectReachesClip(rect, clip);
766
1015
  }
767
1016
  function copyRouteInfo(info) {
768
1017
  const copy = { ...info };
@@ -1705,10 +1954,9 @@ var NativeUIBridgeRegistry = class {
1705
1954
  elements: elements.map((e) => {
1706
1955
  const handlers = extractHandlerNames(e.props);
1707
1956
  const state = e.getState();
1708
- const { visibility, visibilityReason } = computeVisibility(
1709
- state,
1710
- this.getClipRectFor(e, viewport)
1711
- );
1957
+ const identifier = e.getIdentifier();
1958
+ const clip = this.getClipRectFor(e, viewport);
1959
+ const { visibility, visibilityReason } = computeVisibility(state, clip);
1712
1960
  const bbox = projectBbox(state, visibility, this.pixelRatio);
1713
1961
  const vision = projectVisionFields({
1714
1962
  type: e.type,
@@ -1719,13 +1967,16 @@ var NativeUIBridgeRegistry = class {
1719
1967
  // using it would mark plain text/view nodes interactable.
1720
1968
  handlerNames: handlers,
1721
1969
  state,
1722
- flatStyle: e.flatStyle
1970
+ flatStyle: e.flatStyle,
1971
+ props: e.props,
1972
+ accessibilityLabel: identifier.accessibilityLabel,
1973
+ inViewport: computeInViewport(state, clip)
1723
1974
  });
1724
1975
  return {
1725
1976
  id: e.id,
1726
1977
  type: e.type,
1727
1978
  label: e.label,
1728
- identifier: e.getIdentifier(),
1979
+ identifier,
1729
1980
  state,
1730
1981
  actions: e.actions,
1731
1982
  customActions: serializeElementCustomActions(e.customActions),
@@ -1970,6 +2221,7 @@ exports.MAX_ACTION_TIMEOUT_MS = MAX_ACTION_TIMEOUT_MS;
1970
2221
  exports.NATIVE_STANDARD_ACTION_EFFECTS = NATIVE_STANDARD_ACTION_EFFECTS;
1971
2222
  exports.NativeUIBridgeRegistry = NativeUIBridgeRegistry;
1972
2223
  exports.buildTreePath = buildTreePath;
2224
+ exports.computeInViewport = computeInViewport;
1973
2225
  exports.computeVisibility = computeVisibility;
1974
2226
  exports.createNativeElementIdentifier = createNativeElementIdentifier;
1975
2227
  exports.deriveActiveTabFromSegments = deriveActiveTabFromSegments;