react-native-gtkx 0.2.0-alpha.1 → 0.2.0-alpha.2

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.
Files changed (144) hide show
  1. package/README.md +11 -2
  2. package/dist/adw/widgets.generated.d.ts +4 -4
  3. package/dist/adw/widgets.generated.js +51 -51
  4. package/dist/adw/widgets.generated.js.map +1 -1
  5. package/dist/animated/create-animated.d.ts +2 -0
  6. package/dist/animated/create-animated.js +2 -0
  7. package/dist/animated/create-animated.js.map +1 -1
  8. package/dist/animated/index.d.ts +2 -0
  9. package/dist/animated/index.js +1 -0
  10. package/dist/animated/index.js.map +1 -1
  11. package/dist/animated/value-xy.d.ts +41 -0
  12. package/dist/animated/value-xy.js +90 -0
  13. package/dist/animated/value-xy.js.map +1 -0
  14. package/dist/animated/value.d.ts +9 -0
  15. package/dist/animated/value.js +30 -2
  16. package/dist/animated/value.js.map +1 -1
  17. package/dist/common/icon.d.ts +23 -0
  18. package/dist/common/icon.js +14 -0
  19. package/dist/common/icon.js.map +1 -0
  20. package/dist/common/index.d.ts +2 -0
  21. package/dist/common/index.js +2 -0
  22. package/dist/common/index.js.map +1 -1
  23. package/dist/common/list.d.ts +82 -0
  24. package/dist/common/list.js +166 -0
  25. package/dist/common/list.js.map +1 -0
  26. package/dist/common/widget.d.ts +1 -22
  27. package/dist/common/widget.js +75 -8
  28. package/dist/common/widget.js.map +1 -1
  29. package/dist/components/animated.d.ts +4 -2
  30. package/dist/components/animated.js +3 -1
  31. package/dist/components/animated.js.map +1 -1
  32. package/dist/components/app-registry.d.ts +26 -0
  33. package/dist/components/app-registry.js.map +1 -1
  34. package/dist/components/host-node.d.ts +7 -0
  35. package/dist/components/host-node.js +26 -1
  36. package/dist/components/host-node.js.map +1 -1
  37. package/dist/components/index.d.ts +6 -2
  38. package/dist/components/index.js +2 -1
  39. package/dist/components/index.js.map +1 -1
  40. package/dist/components/measure.d.ts +13 -0
  41. package/dist/components/measure.js +51 -0
  42. package/dist/components/measure.js.map +1 -0
  43. package/dist/components/modal.d.ts +1 -1
  44. package/dist/components/press-event.d.ts +28 -0
  45. package/dist/components/press-event.js +46 -0
  46. package/dist/components/press-event.js.map +1 -0
  47. package/dist/components/pressable.d.ts +2 -6
  48. package/dist/components/pressable.js +14 -8
  49. package/dist/components/pressable.js.map +1 -1
  50. package/dist/components/scroll-view.d.ts +4 -0
  51. package/dist/components/scroll-view.js +8 -2
  52. package/dist/components/scroll-view.js.map +1 -1
  53. package/dist/components/text-input.js +1 -1
  54. package/dist/components/text-input.js.map +1 -1
  55. package/dist/components/text.js +25 -1
  56. package/dist/components/text.js.map +1 -1
  57. package/dist/components/use-layout-child.js +17 -14
  58. package/dist/components/use-layout-child.js.map +1 -1
  59. package/dist/components/view.d.ts +9 -4
  60. package/dist/components/view.js +8 -2
  61. package/dist/components/view.js.map +1 -1
  62. package/dist/contracts.d.ts +19 -3
  63. package/dist/contracts.js.map +1 -1
  64. package/dist/gtk/index.d.ts +2 -1
  65. package/dist/gtk/index.js +8 -1
  66. package/dist/gtk/index.js.map +1 -1
  67. package/dist/gtk/widgets.generated.d.ts +14 -14
  68. package/dist/gtk/widgets.generated.js +101 -102
  69. package/dist/gtk/widgets.generated.js.map +1 -1
  70. package/dist/gtk/window-actions.d.ts +77 -0
  71. package/dist/gtk/window-actions.js +193 -0
  72. package/dist/gtk/window-actions.js.map +1 -0
  73. package/dist/gtkx/bridge/geometry.d.ts +15 -0
  74. package/dist/gtkx/bridge/geometry.js +38 -0
  75. package/dist/gtkx/bridge/geometry.js.map +1 -0
  76. package/dist/gtkx/bridge/index.d.ts +2 -0
  77. package/dist/gtkx/bridge/index.js +7 -2
  78. package/dist/gtkx/bridge/index.js.map +1 -1
  79. package/dist/gtkx/bridge/slot-portal.d.ts +12 -0
  80. package/dist/gtkx/bridge/slot-portal.js +17 -0
  81. package/dist/gtkx/bridge/slot-portal.js.map +1 -0
  82. package/dist/gtkx/bridge/svg-node.js +10 -54
  83. package/dist/gtkx/bridge/svg-node.js.map +1 -1
  84. package/dist/gtkx/bridge/use-signal.js +2 -2
  85. package/dist/gtkx/bridge/use-signal.js.map +1 -1
  86. package/dist/index.d.ts +2 -2
  87. package/dist/index.js +1 -1
  88. package/dist/index.js.map +1 -1
  89. package/dist/mcp/data/generated.d.ts +99 -77
  90. package/dist/mcp/data/generated.js +107 -76
  91. package/dist/mcp/data/generated.js.map +1 -1
  92. package/dist/mcp/server.js +1 -1
  93. package/dist/mcp/server.js.map +1 -1
  94. package/dist/navigation/sidebar.d.ts +31 -1
  95. package/dist/navigation/sidebar.js +12 -2
  96. package/dist/navigation/sidebar.js.map +1 -1
  97. package/dist/responder/system.d.ts +27 -0
  98. package/dist/responder/system.js +184 -0
  99. package/dist/responder/system.js.map +1 -0
  100. package/dist/responder/touch-history.d.ts +10 -0
  101. package/dist/responder/touch-history.js +78 -0
  102. package/dist/responder/touch-history.js.map +1 -0
  103. package/dist/responder/types.d.ts +63 -0
  104. package/dist/responder/types.js +29 -0
  105. package/dist/responder/types.js.map +1 -0
  106. package/dist/responder/use-responder.d.ts +12 -0
  107. package/dist/responder/use-responder.js +98 -0
  108. package/dist/responder/use-responder.js.map +1 -0
  109. package/dist/runner/host-dev.js +3 -1
  110. package/dist/runner/host-dev.js.map +1 -1
  111. package/dist/runner/host.js +5 -1
  112. package/dist/runner/host.js.map +1 -1
  113. package/dist/runner/index.js +1 -1
  114. package/dist/runner/index.js.map +1 -1
  115. package/dist/sea/gtkx-config-module.js +1 -1
  116. package/dist/sea/gtkx-config-module.js.map +1 -1
  117. package/dist/style/box-shadow.d.ts +7 -0
  118. package/dist/style/box-shadow.js +197 -0
  119. package/dist/style/box-shadow.js.map +1 -0
  120. package/dist/style/index.d.ts +2 -0
  121. package/dist/style/index.js +2 -0
  122. package/dist/style/index.js.map +1 -1
  123. package/dist/style/split-style.d.ts +5 -2
  124. package/dist/style/split-style.js +31 -3
  125. package/dist/style/split-style.js.map +1 -1
  126. package/dist/style/text-decoration.d.ts +15 -0
  127. package/dist/style/text-decoration.js +26 -0
  128. package/dist/style/text-decoration.js.map +1 -0
  129. package/dist/style/visual-css.js +37 -1
  130. package/dist/style/visual-css.js.map +1 -1
  131. package/dist/svg/gradient-geometry.js +2 -5
  132. package/dist/svg/gradient-geometry.js.map +1 -1
  133. package/dist/testing/index.js.map +1 -1
  134. package/dist/vendor/react-native/pan-responder.d.ts +102 -0
  135. package/dist/vendor/react-native/pan-responder.js +196 -0
  136. package/dist/vendor/react-native/pan-responder.js.map +1 -0
  137. package/dist/vendor/react-native/touch-history-math.d.ts +18 -0
  138. package/dist/vendor/react-native/touch-history-math.js +102 -0
  139. package/dist/vendor/react-native/touch-history-math.js.map +1 -0
  140. package/dist/vite/index.js +1 -1
  141. package/dist/vite/index.js.map +1 -1
  142. package/dist/vitest/index.d.ts +1 -1
  143. package/dist/vitest/index.js.map +1 -1
  144. package/package.json +9 -9
@@ -1 +1 @@
1
- {"version":3,"file":"animated.js","sourceRoot":"","sources":["../../src/components/animated.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,EAAkB,MAAM,OAAO,CAAA;AAC/D,OAAO,EAAE,cAAc,EAAuB,MAAM,mBAAmB,CAAA;AAEvE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,aAAa,EAAY,MAAM,sBAAsB,CAAA;AAC5E,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAC7C,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;AACjD,OAAO,EACL,cAAc,EACd,cAAc,GAEf,MAAM,oBAAoB,CAAA;AAE3B,0EAA0E;AAC1E,yEAAyE;AACzE,MAAM,aAAa,GAAmB;IACpC,QAAQ,CAAC,QAAQ;QACf,IAAI,SAAS,GAAG,KAAK,CAAA;QACrB,MAAM,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAE,EAAE,GAAG,EAAE;YACzD,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,gBAAgB,EAAE,CAAC,GAAG,IAAI,CAAC,CAAA;YAClD,CAAC;YACD,OAAO,KAAK,CAAA;QACd,CAAC,CAAC,CAAA;QACF,OAAO,GAAG,EAAE;YACV,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,SAAS,GAAG,IAAI,CAAA;gBAChB,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;YACxB,CAAC;QACH,CAAC,CAAA;IACH,CAAC;CACF,CAAA;AAED,MAAM,GAAG,GAAG,cAAc,CAAC,aAAa,CAAC,CAAA;AAazC,MAAM,cAAc,GAAG,CAAC,KAAc,EAAyB,EAAE,CAC/D,OAAO,KAAK,KAAK,QAAQ;IACzB,KAAK,KAAK,IAAI;IACd,OAAQ,KAAsB,CAAC,WAAW,KAAK,UAAU;IACzD,OAAQ,KAAsB,CAAC,UAAU,KAAK,UAAU,CAAA;AAc1D,2EAA2E;AAC3E,4EAA4E;AAC5E,sEAAsE;AACtE,IAAI,UAAU,GAAG,CAAC,CAAA;AAClB,MAAM,OAAO,GAAG,IAAI,OAAO,EAAkB,CAAA;AAC7C,MAAM,MAAM,GAAG,CAAC,KAAa,EAAU,EAAE;IACvC,IAAI,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;IAC3B,IAAI,EAAE,KAAK,SAAS,EAAE,CAAC;QACrB,EAAE,GAAG,UAAU,EAAE,CAAA;QACjB,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;IACxB,CAAC;IACD,OAAO,EAAE,CAAA;AACX,CAAC,CAAA;AAgBD,MAAM,aAAa,GAAG,CACpB,KAAiC,EAKjC,EAAE;IACF,MAAM,IAAI,GAA4B,EAAE,CAAA;IACxC,MAAM,OAAO,GAAG,CAAC,KAAiC,EAAQ,EAAE;QAC1D,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAM;QACR,CAAC;QACD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;YACtB,OAAM;QACR,CAAC;QACD,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;IAC5B,CAAC,CAAA;IACD,OAAO,CAAC,KAAK,CAAC,CAAA;IAEd,IAAI,OAAO,GAAwB,IAAI,CAAA;IACvC,MAAM,KAAK,GAAoB,EAAE,CAAA;IAEjC,IAAI,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACjC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAA;QACtB,OAAO,IAAI,CAAC,OAAO,CAAA;IACrB,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;QAClC,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,SAAoC,EAAE,CAAC;YAC7D,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAA;YAChC,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;gBACtB,SAAQ;YACV,CAAC;YACD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAA;YACvB,KAAK,CAAC,IAAI,CACR,cAAc,CAAC,KAAK,CAAC;gBACnB,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,UAAU,EAAE,EAAE;gBACjD,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,KAAsB,EAAE,CACvD,CAAA;QACH,CAAC;QACD,sEAAsE;QACtE,qEAAqE;QACrE,mEAAmE;QACnE,2BAA2B;QAC3B,OAAO,IAAI,CAAC,SAAS,CAAA;IACvB,CAAC;IAED,OAAO,EAAE,WAAW,EAAE,IAAiB,EAAE,OAAO,EAAE,KAAK,EAAE,CAAA;AAC3D,CAAC,CAAA;AAED,yEAAyE;AACzE,uEAAuE;AACvE,0EAA0E;AAC1E,iEAAiE;AACjE,MAAM,YAAY,GAAG,CAAC,EACpB,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,MAAM,GACY,EAAE,EAAE;IACtB,MAAM,SAAS,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAA;IAC9C,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,aAAa,CAAC,KAAK,CAAC,CAAA;IAE5D,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,cAAc,CAAC,SAAS,EAAE;QACzD,KAAK,EAAE,WAAW;QAClB,QAAQ;KACT,CAAC,CAAA;IACF,cAAc,CAAC,SAAS,EAAE,IAAI,CAAC,CAAA;IAE/B,yEAAyE;IACzE,0CAA0C;IAC1C,MAAM,QAAQ,GAAG,MAAM,CAAkB,KAAK,CAAC,CAAA;IAC/C,QAAQ,CAAC,OAAO,GAAG,KAAK,CAAA;IAExB,yEAAyE;IACzE,uEAAuE;IACvE,qDAAqD;IACrD,MAAM,UAAU,GACd,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7C,KAAK;aACF,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CACZ,IAAI,CAAC,IAAI;YACP,CAAC,CAAC,IAAI,IAAI,CAAC,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;YACrC,CAAC,CAAC,IAAI,IAAI,CAAC,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CACzC;aACA,IAAI,CAAC,EAAE,CAAC,CAAA;IAEb,eAAe,CAAC,GAAG,EAAE;QACnB,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAA;QAChC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAM;QACR,CAAC;QAED,qEAAqE;QACrE,uEAAuE;QACvE,oEAAoE;QACpE,EAAE;QACF,qEAAqE;QACrE,qEAAqE;QACrE,uEAAuE;QACvE,4BAA4B;QAC5B,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAChC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,KAAK,EAAE,CAAkC,CACxE,CAAA;QAED,MAAM,KAAK,GAAG,GAAS,EAAE;YACvB,kBAAkB,CAAC,MAAM,EAAE,KAAmC,CAAC,CAAA;YAC/D,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAA;YAC3C,IAAI,YAAY,EAAE,CAAC;gBACjB,aAAa,CAAC,YAAY,CAAC,CAAA;YAC7B,CAAC;QACH,CAAC,CAAA;QAED,MAAM,aAAa,GAAyC,EAAE,CAAA;QAC9D,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;YACvC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;gBACf,OAAM;YACR,CAAC;YACD,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAE,CAAA;YAC1B,aAAa,CAAC,IAAI,CAAC;gBACjB,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE;oBACtC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;oBACtB,KAAK,EAAE,CAAA;gBACT,CAAC,CAAC;aACH,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;QAEF,IAAI,OAAO,EAAE,CAAC;YACZ,MAAM,YAAY,GAAG,CAAC,KAAoB,EAAQ,EAAE;gBAClD,MAAM,OAAO,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAA;gBACrE,SAAS,CAAC,OAAO,EAAE,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA;YAClE,CAAC,CAAA;YACD,aAAa,CAAC,IAAI,CAAC;gBACjB,IAAI,EAAE,OAAO;gBACb,EAAE,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE;oBACpC,YAAY,CAAC,KAAK,CAAC,CAAA;gBACrB,CAAC,CAAC;aACH,CAAC,CAAA;YACF,YAAY,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,CAAA;QACpC,CAAC;QAED,KAAK,EAAE,CAAA;QAEP,OAAO,GAAG,EAAE;YACV,KAAK,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,IAAI,aAAa,EAAE,CAAC;gBACnD,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC,CAAA;YAC7B,CAAC;QACH,CAAC,CAAA;QACD,uDAAuD;IACzD,CAAC,EAAE,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,CAAA;IAEtB,OAAO,CACL,KAAC,MAAM,IACL,GAAG,EAAE,SAAS,EACd,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,YAEtC,KAAC,eAAe,CAAC,QAAQ,IACvB,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,YAE9C,QAAQ,GACgB,GACpB,CACV,CAAA;AACH,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,GAAG,GAAG;IACN,IAAI,EAAE,YAAY;CACnB,CAAA;AAED,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA","sourcesContent":["import { useLayoutEffect, useRef, type ReactNode } from \"react\"\nimport { createAnimated, type FrameScheduler } from \"../animated/index\"\nimport type { FlatStyle, StyleProp, TransformPart } from \"../contracts\"\nimport { GLib, GtkBox, queueAllocate, type Gtk } from \"../gtkx/bridge/index\"\nimport { HostNodeContext } from \"./host-node\"\nimport { setStoredTransform } from \"./rect-store\"\nimport {\n useLayoutChild,\n useRnContainer,\n type LayoutEvent,\n} from \"./use-layout-child\"\n\n// ~60fps one-shot ticks off the GLib main loop. A frame-clock driver (per\n// window) is a later optimization; timeouts keep the driver widget-free.\nconst glibScheduler: FrameScheduler = {\n schedule(callback) {\n let cancelled = false\n const id = GLib.timeoutAdd(GLib.PRIORITY_DEFAULT, 16, () => {\n if (!cancelled) {\n callback(Number(GLib.getMonotonicTime()) / 1000)\n }\n return false\n })\n return () => {\n if (!cancelled) {\n cancelled = true\n GLib.Source.remove(id)\n }\n }\n },\n}\n\nconst api = createAnimated(glibScheduler)\n\n// Interpolations produce suffixed strings (\"45deg\"), so a driven value is\n// not necessarily a number — `rotate` is normally an interpolate() with a\n// deg outputRange.\ntype AnimatedValue = number | string\n\ntype AnimatedNode = {\n addListener(callback: (state: { value: AnimatedValue }) => void): string\n removeListener(id: string): void\n __getValue(): AnimatedValue\n}\n\nconst isAnimatedNode = (value: unknown): value is AnimatedNode =>\n typeof value === \"object\" &&\n value !== null &&\n typeof (value as AnimatedNode).addListener === \"function\" &&\n typeof (value as AnimatedNode).__getValue === \"function\"\n\ntype AnimatedTransformPart = { [key: string]: number | string | AnimatedNode }\n\n// One entry of the style's transform array, kept in source order. The array\n// order IS the composition order in RN, so an animated entry updates its own\n// slot in place instead of being lifted out of the list — that is what makes\n// [{rotate}, {translateX}] compose differently from the reverse, as in RN.\ntype TransformSlot = {\n key: string\n node: AnimatedNode | null\n value: AnimatedValue\n}\n\n// Stable per-node identity for the effect's dependency key: Animated nodes\n// are objects, and the bindings must be rebuilt when the node behind a slot\n// changes — not on every render that rebuilds an equal-looking array.\nlet nextNodeId = 1\nconst nodeIds = new WeakMap<object, number>()\nconst nodeId = (value: object): number => {\n let id = nodeIds.get(value)\n if (id === undefined) {\n id = nextNodeId++\n nodeIds.set(value, id)\n }\n return id\n}\n\n// Omit, not plain intersection: intersecting would AND the animated transform\n// with FlatStyle's numeric one, rejecting Animated.Value entries.\nexport type AnimatedViewStyle = Omit<FlatStyle, \"opacity\" | \"transform\"> & {\n opacity?: number | AnimatedNode\n transform?: (TransformPart | AnimatedTransformPart)[]\n}\n\nexport type AnimatedViewProps = {\n style?: AnimatedViewStyle | AnimatedViewStyle[]\n children?: ReactNode\n onLayout?: (event: LayoutEvent) => void\n testID?: string\n}\n\nconst splitAnimated = (\n style: AnimatedViewProps[\"style\"],\n): {\n staticStyle: StyleProp\n opacity: AnimatedNode | null\n slots: TransformSlot[]\n} => {\n const flat: Record<string, unknown> = {}\n const collect = (entry: AnimatedViewProps[\"style\"]): void => {\n if (!entry) {\n return\n }\n if (Array.isArray(entry)) {\n entry.forEach(collect)\n return\n }\n Object.assign(flat, entry)\n }\n collect(style)\n\n let opacity: AnimatedNode | null = null\n const slots: TransformSlot[] = []\n\n if (isAnimatedNode(flat.opacity)) {\n opacity = flat.opacity\n delete flat.opacity\n }\n if (Array.isArray(flat.transform)) {\n for (const part of flat.transform as AnimatedTransformPart[]) {\n const key = Object.keys(part)[0]\n if (key === undefined) {\n continue\n }\n const value = part[key]\n slots.push(\n isAnimatedNode(value)\n ? { key, node: value, value: value.__getValue() }\n : { key, node: null, value: value as AnimatedValue },\n )\n }\n // The whole array is owned here from now on, static entries included:\n // leaving them in the style would make useLayoutChild write the same\n // rect-store slot from the other side, and the two would overwrite\n // each other every render.\n delete flat.transform\n }\n\n return { staticStyle: flat as StyleProp, opacity, slots }\n}\n\n// Animated values bypass React entirely: listeners write straight to the\n// widget (opacity) and to the rect store (the transform applied by the\n// parent's allocate), on top of the engine-committed base rect — the fast\n// path measured in the spike. Animation frames never touch Yoga.\nconst AnimatedView = ({\n style,\n children,\n onLayout,\n testID,\n}: AnimatedViewProps) => {\n const widgetRef = useRef<Gtk.Box | null>(null)\n const { staticStyle, opacity, slots } = splitAnimated(style)\n\n const { host, node, cssClass } = useLayoutChild(widgetRef, {\n style: staticStyle,\n onLayout,\n })\n useRnContainer(widgetRef, node)\n\n // The effect reads the slots of the render that (re)armed it; the values\n // inside are then owned by the listeners.\n const slotsRef = useRef<TransformSlot[]>(slots)\n slotsRef.current = slots\n\n // Rebind on a change of shape (which transforms, in which order), of the\n // node behind an animated entry, or of a static entry's value — not on\n // every render that rebuilds an equal-looking array.\n const bindingKey =\n (opacity ? `opacity#${nodeId(opacity)}` : \"\") +\n slots\n .map((slot) =>\n slot.node\n ? `|${slot.key}#${nodeId(slot.node)}`\n : `|${slot.key}=${String(slot.value)}`,\n )\n .join(\"\")\n\n useLayoutEffect(() => {\n const widget = widgetRef.current\n if (!widget) {\n return\n }\n\n // The live transform array, mutated in place: an Animated write must\n // stay one numeric store plus one queued allocation — no React render,\n // no Yoga pass, no allocation per frame beyond the composed matrix.\n //\n // RN transform semantics: this is paint-only. The result goes to the\n // rect store unclamped — the parent's measure ignores children, so a\n // transformed child draws past the boundary over its neighbors without\n // moving a single ancestor.\n const parts = slotsRef.current.map(\n (slot) => ({ [slot.key]: slot.value }) as Record<string, AnimatedValue>,\n )\n\n const flush = (): void => {\n setStoredTransform(widget, parts as unknown as TransformPart[])\n const parentWidget = host.widgetRef.current\n if (parentWidget) {\n queueAllocate(parentWidget)\n }\n }\n\n const subscriptions: { node: AnimatedNode; id: string }[] = []\n slotsRef.current.forEach((slot, index) => {\n if (!slot.node) {\n return\n }\n const part = parts[index]!\n subscriptions.push({\n node: slot.node,\n id: slot.node.addListener(({ value }) => {\n part[slot.key] = value\n flush()\n }),\n })\n })\n\n if (opacity) {\n const applyOpacity = (value: AnimatedValue): void => {\n const numeric = typeof value === \"number\" ? value : parseFloat(value)\n widgetRef.current?.setOpacity(Math.min(1, Math.max(0, numeric)))\n }\n subscriptions.push({\n node: opacity,\n id: opacity.addListener(({ value }) => {\n applyOpacity(value)\n }),\n })\n applyOpacity(opacity.__getValue())\n }\n\n flush()\n\n return () => {\n for (const { node: animated, id } of subscriptions) {\n animated.removeListener(id)\n }\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [bindingKey, node])\n\n return (\n <GtkBox\n ref={widgetRef}\n name={testID}\n cssClasses={cssClass ? [cssClass] : []}\n >\n <HostNodeContext.Provider\n value={{ engine: host.engine, node, widgetRef }}\n >\n {children}\n </HostNodeContext.Provider>\n </GtkBox>\n )\n}\n\nexport const Animated = {\n ...api,\n View: AnimatedView,\n}\n\nexport { Easing } from \"../animated/index\"\n"]}
1
+ {"version":3,"file":"animated.js","sourceRoot":"","sources":["../../src/components/animated.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useLayoutEffect, useRef, type ReactNode } from \"react\"\nimport { createAnimated, type FrameScheduler } from \"../animated/index\"\nimport type { FlatStyle, StyleProp, TransformPart } from \"../contracts\"\nimport { GLib, GtkBox, queueAllocate, type Gtk } from \"../gtkx/bridge/index\"\nimport type { ResponderProps } from \"../responder/types\"\nimport { useResponder } from \"../responder/use-responder\"\nimport { HostNodeContext } from \"./host-node\"\nimport { setStoredTransform } from \"./rect-store\"\nimport {\n useLayoutChild,\n useRnContainer,\n type LayoutEvent,\n} from \"./use-layout-child\"\n\n// ~60fps one-shot ticks off the GLib main loop. A frame-clock driver (per\n// window) is a later optimization; timeouts keep the driver widget-free.\nconst glibScheduler: FrameScheduler = {\n schedule(callback) {\n let cancelled = false\n const id = GLib.timeoutAdd(GLib.PRIORITY_DEFAULT, 16, () => {\n if (!cancelled) {\n callback(Number(GLib.getMonotonicTime()) / 1000)\n }\n return false\n })\n return () => {\n if (!cancelled) {\n cancelled = true\n GLib.Source.remove(id)\n }\n }\n },\n}\n\nconst api = createAnimated(glibScheduler)\n\n// Interpolations produce suffixed strings (\"45deg\"), so a driven value is\n// not necessarily a number — `rotate` is normally an interpolate() with a\n// deg outputRange.\ntype AnimatedValue = number | string\n\ntype AnimatedNode = {\n addListener(callback: (state: { value: AnimatedValue }) => void): string\n removeListener(id: string): void\n __getValue(): AnimatedValue\n}\n\nconst isAnimatedNode = (value: unknown): value is AnimatedNode =>\n typeof value === \"object\" &&\n value !== null &&\n typeof (value as AnimatedNode).addListener === \"function\" &&\n typeof (value as AnimatedNode).__getValue === \"function\"\n\ntype AnimatedTransformPart = { [key: string]: number | string | AnimatedNode }\n\n// One entry of the style's transform array, kept in source order. The array\n// order IS the composition order in RN, so an animated entry updates its own\n// slot in place instead of being lifted out of the list — that is what makes\n// [{rotate}, {translateX}] compose differently from the reverse, as in RN.\ntype TransformSlot = {\n key: string\n node: AnimatedNode | null\n value: AnimatedValue\n}\n\n// Stable per-node identity for the effect's dependency key: Animated nodes\n// are objects, and the bindings must be rebuilt when the node behind a slot\n// changes — not on every render that rebuilds an equal-looking array.\nlet nextNodeId = 1\nconst nodeIds = new WeakMap<object, number>()\nconst nodeId = (value: object): number => {\n let id = nodeIds.get(value)\n if (id === undefined) {\n id = nextNodeId++\n nodeIds.set(value, id)\n }\n return id\n}\n\n// Omit, not plain intersection: intersecting would AND the animated transform\n// with FlatStyle's numeric one, rejecting Animated.Value entries.\nexport type AnimatedViewStyle = Omit<FlatStyle, \"opacity\" | \"transform\"> & {\n opacity?: number | AnimatedNode\n transform?: (TransformPart | AnimatedTransformPart)[]\n}\n\n// Animated.View is where a PanResponder drag lands in idiomatic RN — the\n// dragged box is animated by definition — so it takes the responder props\n// exactly as View does.\nexport type AnimatedViewProps = ResponderProps & {\n style?: AnimatedViewStyle | AnimatedViewStyle[]\n children?: ReactNode\n onLayout?: (event: LayoutEvent) => void\n testID?: string\n}\n\nconst splitAnimated = (\n style: AnimatedViewProps[\"style\"],\n): {\n staticStyle: StyleProp\n opacity: AnimatedNode | null\n slots: TransformSlot[]\n} => {\n const flat: Record<string, unknown> = {}\n const collect = (entry: AnimatedViewProps[\"style\"]): void => {\n if (!entry) {\n return\n }\n if (Array.isArray(entry)) {\n entry.forEach(collect)\n return\n }\n Object.assign(flat, entry)\n }\n collect(style)\n\n let opacity: AnimatedNode | null = null\n const slots: TransformSlot[] = []\n\n if (isAnimatedNode(flat.opacity)) {\n opacity = flat.opacity\n delete flat.opacity\n }\n if (Array.isArray(flat.transform)) {\n for (const part of flat.transform as AnimatedTransformPart[]) {\n const key = Object.keys(part)[0]\n if (key === undefined) {\n continue\n }\n const value = part[key]\n slots.push(\n isAnimatedNode(value)\n ? { key, node: value, value: value.__getValue() }\n : { key, node: null, value: value as AnimatedValue },\n )\n }\n // The whole array is owned here from now on, static entries included:\n // leaving them in the style would make useLayoutChild write the same\n // rect-store slot from the other side, and the two would overwrite\n // each other every render.\n delete flat.transform\n }\n\n return { staticStyle: flat as StyleProp, opacity, slots }\n}\n\n// Animated values bypass React entirely: listeners write straight to the\n// widget (opacity) and to the rect store (the transform applied by the\n// parent's allocate), on top of the engine-committed base rect — the fast\n// path measured in the spike. Animation frames never touch Yoga.\nconst AnimatedView = ({\n style,\n children,\n onLayout,\n testID,\n ...responderProps\n}: AnimatedViewProps) => {\n const widgetRef = useRef<Gtk.Box | null>(null)\n const { staticStyle, opacity, slots } = splitAnimated(style)\n\n const { host, node, cssClass } = useLayoutChild(widgetRef, {\n style: staticStyle,\n onLayout,\n })\n useRnContainer(widgetRef, node)\n useResponder(widgetRef, responderProps)\n\n // The effect reads the slots of the render that (re)armed it; the values\n // inside are then owned by the listeners.\n const slotsRef = useRef<TransformSlot[]>(slots)\n slotsRef.current = slots\n\n // Rebind on a change of shape (which transforms, in which order), of the\n // node behind an animated entry, or of a static entry's value — not on\n // every render that rebuilds an equal-looking array.\n const bindingKey =\n (opacity ? `opacity#${nodeId(opacity)}` : \"\") +\n slots\n .map((slot) =>\n slot.node\n ? `|${slot.key}#${nodeId(slot.node)}`\n : `|${slot.key}=${String(slot.value)}`,\n )\n .join(\"\")\n\n useLayoutEffect(() => {\n const widget = widgetRef.current\n if (!widget) {\n return\n }\n\n // The live transform array, mutated in place: an Animated write must\n // stay one numeric store plus one queued allocation — no React render,\n // no Yoga pass, no allocation per frame beyond the composed matrix.\n //\n // RN transform semantics: this is paint-only. The result goes to the\n // rect store unclamped — the parent's measure ignores children, so a\n // transformed child draws past the boundary over its neighbors without\n // moving a single ancestor.\n const parts = slotsRef.current.map(\n (slot) => ({ [slot.key]: slot.value }) as Record<string, AnimatedValue>,\n )\n\n const flush = (): void => {\n setStoredTransform(widget, parts as unknown as TransformPart[])\n const parentWidget = host.widgetRef.current\n if (parentWidget) {\n queueAllocate(parentWidget)\n }\n }\n\n const subscriptions: { node: AnimatedNode; id: string }[] = []\n slotsRef.current.forEach((slot, index) => {\n if (!slot.node) {\n return\n }\n const part = parts[index]!\n subscriptions.push({\n node: slot.node,\n id: slot.node.addListener(({ value }) => {\n part[slot.key] = value\n flush()\n }),\n })\n })\n\n if (opacity) {\n const applyOpacity = (value: AnimatedValue): void => {\n const numeric = typeof value === \"number\" ? value : parseFloat(value)\n widgetRef.current?.setOpacity(Math.min(1, Math.max(0, numeric)))\n }\n subscriptions.push({\n node: opacity,\n id: opacity.addListener(({ value }) => {\n applyOpacity(value)\n }),\n })\n applyOpacity(opacity.__getValue())\n }\n\n flush()\n\n return () => {\n for (const { node: animated, id } of subscriptions) {\n animated.removeListener(id)\n }\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [bindingKey, node])\n\n return (\n <GtkBox\n ref={widgetRef}\n name={testID}\n cssClasses={cssClass ? [cssClass] : []}\n >\n <HostNodeContext.Provider\n value={{ engine: host.engine, node, widgetRef }}\n >\n {children}\n </HostNodeContext.Provider>\n </GtkBox>\n )\n}\n\nexport const Animated = {\n ...api,\n View: AnimatedView,\n}\n\nexport { Easing } from \"../animated/index\"\n"]}
@@ -11,9 +11,35 @@ export type RunApplicationParams = {
11
11
  width?: number;
12
12
  height?: number;
13
13
  chrome?: "system" | "content";
14
+ /**
15
+ * GSimpleAction elements registered on the GApplication itself
16
+ * ("app.<name>" — reachable from anywhere, including a Gio.Notification's
17
+ * action buttons, which can only ever target an app-level action).
18
+ *
19
+ * @deprecated Render `<ApplicationActions>` (react-native-gtkx/gtk) inside
20
+ * the app instead. Options render as SIBLINGS of the app tree, so no
21
+ * context of the app's can reach them and the set is fixed for the
22
+ * process's lifetime. Still supported; see docs/api.md.
23
+ */
14
24
  applicationActions?: ReactNode;
15
25
  actionAccels?: ActionAccel[];
26
+ /**
27
+ * GSimpleAction elements registered on the window ("win.<name>" — what a
28
+ * HeaderBar button's actionName or a GMenu item usually targets).
29
+ *
30
+ * @deprecated Render `<WindowActions>` (react-native-gtkx/gtk) inside the
31
+ * app instead — it can read the app's context and registers/unregisters
32
+ * with the component that declares it. Still supported; see docs/api.md.
33
+ */
16
34
  windowActions?: ReactNode;
35
+ /**
36
+ * Event controllers attached to the window itself — a
37
+ * GtkShortcutController scoped to the whole window is the common case.
38
+ *
39
+ * @deprecated Render `<WindowControllers>` (react-native-gtkx/gtk) inside
40
+ * the app instead, for the same reasons as `windowActions`. Still
41
+ * supported; see docs/api.md.
42
+ */
17
43
  windowControllers?: ReactNode;
18
44
  breakpoints?: ReactNode;
19
45
  };
@@ -1 +1 @@
1
- {"version":3,"file":"app-registry.js","sourceRoot":"","sources":["../../src/components/app-registry.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useLayoutEffect, type ComponentType, type ReactNode } from \"react\"\nimport {\n AdwApplicationWindow,\n createRoot,\n Gtk,\n GtkApplication,\n GtkApplicationWindow,\n quit,\n} from \"../gtkx/bridge/index\"\nimport { Root } from \"./root\"\n\ntype ComponentProvider = () => ComponentType<Record<string, unknown>>\n\nconst registry = new Map<string, ComponentProvider>()\n\n// The chrome the running app was started with — read by the navigation\n// dev-mode hint (a HeaderBar page under \"system\" chrome renders a doubled\n// titlebar). null until runApplication ran (test harnesses never set it).\nlet activeChrome: \"system\" | \"content\" | null = null\nexport const getActiveChrome = (): \"system\" | \"content\" | null => activeChrome\n\n// One accelerator binding on the GApplication — the shape GtkApplication's\n// own `actionAccels` prop takes, restated locally so this file needs\n// nothing from @gtkx/react/internal (the \"internal\" subpath is where the\n// real type lives, but nothing else in this package reaches for it).\nexport type ActionAccel = {\n detailedActionName: string\n accels: string[]\n}\n\nexport type RunApplicationParams = {\n initialProps?: Record<string, unknown>\n title?: string\n width?: number\n height?: number\n // Window chrome. \"system\" (default): a GtkApplicationWindow with its own\n // titlebar. \"content\": an AdwApplicationWindow with NO window titlebar —\n // the app's content provides HeaderBars (navigation apps: the page\n // HeaderBar becomes the titlebar, with the window controls in it).\n chrome?: \"system\" | \"content\"\n // GSimpleAction elements registered on the GApplication itself\n // (\"app.<name>\" — reachable from anywhere, including a\n // Gio.Notification's action buttons, which can only ever target an\n // app-level action).\n applicationActions?: ReactNode\n // Keyboard accelerators bound to actions, at the application level —\n // GtkApplication's own actionAccels prop, unchanged.\n actionAccels?: ActionAccel[]\n // GSimpleAction elements registered on the window (\"win.<name>\" —\n // what a HeaderBar button's actionName or a GMenu item usually targets).\n windowActions?: ReactNode\n // Event controllers attached to the window itself — a\n // GtkShortcutController scoped to the whole window is the common case.\n windowControllers?: ReactNode\n // AdwBreakpoint elements, evaluated against the window's own allocated\n // size. Only meaningful under chrome: \"content\" (AdwApplicationWindow) —\n // GtkApplicationWindow has no such concept, so this is ignored (with a\n // dev warning) under the default \"system\" chrome.\n breakpoints?: ReactNode\n}\n\n// RN parity: system \"reduce animations\" hints never auto-stop RN animations\n// (ActivityIndicator keeps spinning; honoring reduce-motion is an explicit\n// opt-in via AccessibilityInfo). Our Animated runs on GLib timers and already\n// ignores the hint, so GTK-internal animations (GtkSpinner, switch slides)\n// must behave the same — otherwise e.g. GNOME under software rendering\n// reports enable-animations=false through the settings portal and spinners\n// freeze while Animated keeps moving.\nlet animationsForced = false\nconst forceEnableAnimations = (): void => {\n if (animationsForced) {\n return\n }\n const settings = Gtk.Settings.getDefault()\n if (!settings) {\n return\n }\n animationsForced = true\n // Application-set GtkSettings values outrank the desktop backend, so a\n // later portal update cannot flip this back.\n settings.gtkEnableAnimations = true\n}\n\n// chrome \"content\": the app component IS the window content (a navigation\n// container whose pages host their own NestedRoots) — no window-level Yoga\n// root in between: the layout root would not allocate foreign GTK children.\nconst ContentChrome = ({\n App,\n initialProps,\n}: {\n App: ComponentType<Record<string, unknown>>\n initialProps: Record<string, unknown>\n}) => {\n useLayoutEffect(() => {\n forceEnableAnimations()\n }, [])\n return <App {...initialProps} />\n}\n\nconst WindowContent = ({\n App,\n initialProps,\n initialWidth,\n initialHeight,\n}: {\n App: ComponentType<Record<string, unknown>>\n initialProps: Record<string, unknown>\n initialWidth: number\n initialHeight: number\n}) => {\n // Settings need an initialized display, and writing them mid-render is\n // unsafe — apply after the window mounts.\n useLayoutEffect(() => {\n forceEnableAnimations()\n }, [])\n\n // The Root is the window's direct child: RnGtkxLayout reports a zero\n // minimum (the window shrinks freely — no ratchet) and adopts the actual\n // content-area allocation as the layout viewport. No scrollable wrapper\n // means a window can never scroll its own root — RN semantics, scrolling\n // stays opt-in via <ScrollView>.\n return (\n <Root\n width={initialWidth}\n height={initialHeight}\n followAllocation\n >\n <App {...initialProps} />\n </Root>\n )\n}\n\nexport const AppRegistry = {\n registerComponent(appKey: string, provider: ComponentProvider): string {\n registry.set(appKey, provider)\n return appKey\n },\n\n getAppKeys(): string[] {\n return [...registry.keys()]\n },\n\n runApplication(appKey: string, params: RunApplicationParams = {}): void {\n const provider = registry.get(appKey)\n if (!provider) {\n throw new Error(\n `AppRegistry: no component registered for \"${appKey}\". ` +\n `Registered: ${[...registry.keys()].join(\", \") || \"(none)\"}`,\n )\n }\n const App = provider()\n const width = params.width ?? 800\n const height = params.height ?? 600\n\n const contentChrome = params.chrome === \"content\"\n activeChrome = contentChrome ? \"content\" : \"system\"\n\n if (\n process.env.NODE_ENV !== \"production\" &&\n params.breakpoints &&\n !contentChrome\n ) {\n console.warn(\n '[react-native-gtkx] breakpoints was passed to runApplication without chrome: \"content\" — GtkApplicationWindow (the \"system\" chrome default) has no breakpoints concept, so it is ignored.',\n )\n }\n\n const content = contentChrome ? (\n <ContentChrome\n App={App}\n initialProps={params.initialProps ?? {}}\n />\n ) : (\n <WindowContent\n App={App}\n initialProps={params.initialProps ?? {}}\n initialWidth={width}\n initialHeight={height}\n />\n )\n\n const AppWindow = () =>\n contentChrome ? (\n <AdwApplicationWindow\n title={params.title ?? appKey}\n defaultWidth={width}\n defaultHeight={height}\n onCloseRequest={quit}\n actions={params.windowActions}\n controllers={params.windowControllers}\n breakpoints={params.breakpoints}\n >\n {content}\n </AdwApplicationWindow>\n ) : (\n <GtkApplicationWindow\n title={params.title ?? appKey}\n defaultWidth={width}\n defaultHeight={height}\n onCloseRequest={quit}\n actions={params.windowActions}\n controllers={params.windowControllers}\n >\n {content}\n </GtkApplicationWindow>\n )\n\n createRoot().render(\n <GtkApplication\n actions={params.applicationActions}\n actionAccels={params.actionAccels}\n >\n <AppWindow />\n </GtkApplication>,\n )\n },\n}\n"]}
1
+ {"version":3,"file":"app-registry.js","sourceRoot":"","sources":["../../src/components/app-registry.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useLayoutEffect, type ComponentType, type ReactNode } from \"react\"\nimport {\n AdwApplicationWindow,\n createRoot,\n Gtk,\n GtkApplication,\n GtkApplicationWindow,\n quit,\n} from \"../gtkx/bridge/index\"\nimport { Root } from \"./root\"\n\ntype ComponentProvider = () => ComponentType<Record<string, unknown>>\n\nconst registry = new Map<string, ComponentProvider>()\n\n// The chrome the running app was started with — read by the navigation\n// dev-mode hint (a HeaderBar page under \"system\" chrome renders a doubled\n// titlebar). null until runApplication ran (test harnesses never set it).\nlet activeChrome: \"system\" | \"content\" | null = null\nexport const getActiveChrome = (): \"system\" | \"content\" | null => activeChrome\n\n// One accelerator binding on the GApplication — the shape GtkApplication's\n// own `actionAccels` prop takes, restated locally so this file needs\n// nothing from @gtkx/react/internal (the \"internal\" subpath is where the\n// real type lives, but nothing else in this package reaches for it).\nexport type ActionAccel = {\n detailedActionName: string\n accels: string[]\n}\n\nexport type RunApplicationParams = {\n initialProps?: Record<string, unknown>\n title?: string\n width?: number\n height?: number\n // Window chrome. \"system\" (default): a GtkApplicationWindow with its own\n // titlebar. \"content\": an AdwApplicationWindow with NO window titlebar —\n // the app's content provides HeaderBars (navigation apps: the page\n // HeaderBar becomes the titlebar, with the window controls in it).\n chrome?: \"system\" | \"content\"\n /**\n * GSimpleAction elements registered on the GApplication itself\n * (\"app.<name>\" — reachable from anywhere, including a Gio.Notification's\n * action buttons, which can only ever target an app-level action).\n *\n * @deprecated Render `<ApplicationActions>` (react-native-gtkx/gtk) inside\n * the app instead. Options render as SIBLINGS of the app tree, so no\n * context of the app's can reach them and the set is fixed for the\n * process's lifetime. Still supported; see docs/api.md.\n */\n applicationActions?: ReactNode\n // Keyboard accelerators bound to actions, at the application level —\n // GtkApplication's own actionAccels prop, unchanged. NOT deprecated with\n // the three ReactNode options below: this is a flat name→keys table with\n // no children and nothing to read from context, and it is deliberately\n // process-wide (an accelerator for an action that is not currently\n // registered simply does nothing). A shortcut that should come and go\n // with a screen is a GtkShortcutController in <WindowControllers>.\n actionAccels?: ActionAccel[]\n /**\n * GSimpleAction elements registered on the window (\"win.<name>\" — what a\n * HeaderBar button's actionName or a GMenu item usually targets).\n *\n * @deprecated Render `<WindowActions>` (react-native-gtkx/gtk) inside the\n * app instead — it can read the app's context and registers/unregisters\n * with the component that declares it. Still supported; see docs/api.md.\n */\n windowActions?: ReactNode\n /**\n * Event controllers attached to the window itself — a\n * GtkShortcutController scoped to the whole window is the common case.\n *\n * @deprecated Render `<WindowControllers>` (react-native-gtkx/gtk) inside\n * the app instead, for the same reasons as `windowActions`. Still\n * supported; see docs/api.md.\n */\n windowControllers?: ReactNode\n // AdwBreakpoint elements, evaluated against the window's own allocated\n // size. Only meaningful under chrome: \"content\" (AdwApplicationWindow) —\n // GtkApplicationWindow has no such concept, so this is ignored (with a\n // dev warning) under the default \"system\" chrome.\n breakpoints?: ReactNode\n}\n\n// RN parity: system \"reduce animations\" hints never auto-stop RN animations\n// (ActivityIndicator keeps spinning; honoring reduce-motion is an explicit\n// opt-in via AccessibilityInfo). Our Animated runs on GLib timers and already\n// ignores the hint, so GTK-internal animations (GtkSpinner, switch slides)\n// must behave the same — otherwise e.g. GNOME under software rendering\n// reports enable-animations=false through the settings portal and spinners\n// freeze while Animated keeps moving.\nlet animationsForced = false\nconst forceEnableAnimations = (): void => {\n if (animationsForced) {\n return\n }\n const settings = Gtk.Settings.getDefault()\n if (!settings) {\n return\n }\n animationsForced = true\n // Application-set GtkSettings values outrank the desktop backend, so a\n // later portal update cannot flip this back.\n settings.gtkEnableAnimations = true\n}\n\n// chrome \"content\": the app component IS the window content (a navigation\n// container whose pages host their own NestedRoots) — no window-level Yoga\n// root in between: the layout root would not allocate foreign GTK children.\nconst ContentChrome = ({\n App,\n initialProps,\n}: {\n App: ComponentType<Record<string, unknown>>\n initialProps: Record<string, unknown>\n}) => {\n useLayoutEffect(() => {\n forceEnableAnimations()\n }, [])\n return <App {...initialProps} />\n}\n\nconst WindowContent = ({\n App,\n initialProps,\n initialWidth,\n initialHeight,\n}: {\n App: ComponentType<Record<string, unknown>>\n initialProps: Record<string, unknown>\n initialWidth: number\n initialHeight: number\n}) => {\n // Settings need an initialized display, and writing them mid-render is\n // unsafe — apply after the window mounts.\n useLayoutEffect(() => {\n forceEnableAnimations()\n }, [])\n\n // The Root is the window's direct child: RnGtkxLayout reports a zero\n // minimum (the window shrinks freely — no ratchet) and adopts the actual\n // content-area allocation as the layout viewport. No scrollable wrapper\n // means a window can never scroll its own root — RN semantics, scrolling\n // stays opt-in via <ScrollView>.\n return (\n <Root\n width={initialWidth}\n height={initialHeight}\n followAllocation\n >\n <App {...initialProps} />\n </Root>\n )\n}\n\nexport const AppRegistry = {\n registerComponent(appKey: string, provider: ComponentProvider): string {\n registry.set(appKey, provider)\n return appKey\n },\n\n getAppKeys(): string[] {\n return [...registry.keys()]\n },\n\n runApplication(appKey: string, params: RunApplicationParams = {}): void {\n const provider = registry.get(appKey)\n if (!provider) {\n throw new Error(\n `AppRegistry: no component registered for \"${appKey}\". ` +\n `Registered: ${[...registry.keys()].join(\", \") || \"(none)\"}`,\n )\n }\n const App = provider()\n const width = params.width ?? 800\n const height = params.height ?? 600\n\n const contentChrome = params.chrome === \"content\"\n activeChrome = contentChrome ? \"content\" : \"system\"\n\n if (\n process.env.NODE_ENV !== \"production\" &&\n params.breakpoints &&\n !contentChrome\n ) {\n console.warn(\n '[react-native-gtkx] breakpoints was passed to runApplication without chrome: \"content\" — GtkApplicationWindow (the \"system\" chrome default) has no breakpoints concept, so it is ignored.',\n )\n }\n\n const content = contentChrome ? (\n <ContentChrome\n App={App}\n initialProps={params.initialProps ?? {}}\n />\n ) : (\n <WindowContent\n App={App}\n initialProps={params.initialProps ?? {}}\n initialWidth={width}\n initialHeight={height}\n />\n )\n\n const AppWindow = () =>\n contentChrome ? (\n <AdwApplicationWindow\n title={params.title ?? appKey}\n defaultWidth={width}\n defaultHeight={height}\n onCloseRequest={quit}\n actions={params.windowActions}\n controllers={params.windowControllers}\n breakpoints={params.breakpoints}\n >\n {content}\n </AdwApplicationWindow>\n ) : (\n <GtkApplicationWindow\n title={params.title ?? appKey}\n defaultWidth={width}\n defaultHeight={height}\n onCloseRequest={quit}\n actions={params.windowActions}\n controllers={params.windowControllers}\n >\n {content}\n </GtkApplicationWindow>\n )\n\n createRoot().render(\n <GtkApplication\n actions={params.applicationActions}\n actionAccels={params.actionAccels}\n >\n <AppWindow />\n </GtkApplication>,\n )\n },\n}\n"]}
@@ -7,4 +7,11 @@ export type HostNode = {
7
7
  widgetRef: RefObject<Gtk.Box | null>;
8
8
  };
9
9
  export declare const HostNodeContext: React.Context<HostNode | null>;
10
+ export type SlotLocation = {
11
+ /** The widget this content was handed to, e.g. "AdwBottomSheet". */
12
+ widget: string;
13
+ /** The slot property, e.g. "sheet" — or null for an ordinary child. */
14
+ slot: string | null;
15
+ };
16
+ export declare const SlotContext: React.Context<SlotLocation | null>;
10
17
  export declare const useHostNode: () => HostNode;
@@ -1,9 +1,34 @@
1
1
  import { createContext, useContext } from "react";
2
2
  export const HostNodeContext = createContext(null);
3
+ export const SlotContext = createContext(null);
4
+ const slotError = ({ widget, slot }) => {
5
+ // The two shapes differ only in how you write the wrapper, so the message
6
+ // shows the caller their own syntax rather than a generic one.
7
+ const where = slot
8
+ ? `${widget}'s \`${slot}\` slot`
9
+ : `${widget}, as its child`;
10
+ const wrap = (root) => slot
11
+ ? ` ${slot}={<${root}>…</${root}>}`
12
+ : ` <${widget}>…</${widget}> → <${widget}><${root}>…</${root}></${widget}>`;
13
+ return (`react-native-gtkx: React Native content was put in ${where} without a layout root.\n` +
14
+ `A GTK widget hands out a rectangle, and React Native needs a root to lay out inside it. Wrap the content:\n` +
15
+ `${wrap("SlotContent")} — fill the area (a page body, a pane, a content area)\n` +
16
+ `${wrap("IntrinsicContent")} — size the area to the content (a bar, a header slot, a row)\n` +
17
+ // The subpath is named without quoting it as a specifier: the metro-preset
18
+ // test scans src for bare imports with a regex, and an import-shaped
19
+ // sentence in a string literal reads to it exactly like a real one.
20
+ `Both are exported by react-native-gtkx/common. GTK widgets need neither — they are what a widget takes natively.`);
21
+ };
3
22
  export const useHostNode = () => {
4
23
  const host = useContext(HostNodeContext);
24
+ // One extra context read per layout child. Deliberate: it is what turns the
25
+ // single most confusing failure on this platform — content silently laid
26
+ // out against the wrong rectangle — into a sentence naming where it landed.
27
+ const slot = useContext(SlotContext);
5
28
  if (host === null) {
6
- throw new Error("react-native-gtkx components must be rendered inside AppRegistry.runApplication() or a <Root>");
29
+ throw new Error(slot
30
+ ? slotError(slot)
31
+ : "react-native-gtkx components must be rendered inside AppRegistry.runApplication() or a <Root>");
7
32
  }
8
33
  return host;
9
34
  };
@@ -1 +1 @@
1
- {"version":3,"file":"host-node.js","sourceRoot":"","sources":["../../src/components/host-node.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAkB,MAAM,OAAO,CAAA;AAajE,MAAM,CAAC,MAAM,eAAe,GAAG,aAAa,CAAkB,IAAI,CAAC,CAAA;AAEnE,MAAM,CAAC,MAAM,WAAW,GAAG,GAAa,EAAE;IACxC,MAAM,IAAI,GAAG,UAAU,CAAC,eAAe,CAAC,CAAA;IACxC,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CACb,+FAA+F,CAChG,CAAA;IACH,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC,CAAA","sourcesContent":["import { createContext, useContext, type RefObject } from \"react\"\nimport type { LayoutEngine, LayoutNode } from \"../layout/index\"\nimport type { Gtk } from \"../gtkx/bridge/index\"\n\n// One per mounted container (Root or View): children register their layout\n// nodes here and commit rects into the store read by the parent's\n// RnGtkxLayout allocate().\nexport type HostNode = {\n engine: LayoutEngine\n node: LayoutNode\n widgetRef: RefObject<Gtk.Box | null>\n}\n\nexport const HostNodeContext = createContext<HostNode | null>(null)\n\nexport const useHostNode = (): HostNode => {\n const host = useContext(HostNodeContext)\n if (host === null) {\n throw new Error(\n \"react-native-gtkx components must be rendered inside AppRegistry.runApplication() or a <Root>\",\n )\n }\n return host\n}\n"]}
1
+ {"version":3,"file":"host-node.js","sourceRoot":"","sources":["../../src/components/host-node.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAkB,MAAM,OAAO,CAAA;AAajE,MAAM,CAAC,MAAM,eAAe,GAAG,aAAa,CAAkB,IAAI,CAAC,CAAA;AAenE,MAAM,CAAC,MAAM,WAAW,GAAG,aAAa,CAAsB,IAAI,CAAC,CAAA;AAEnE,MAAM,SAAS,GAAG,CAAC,EAAE,MAAM,EAAE,IAAI,EAAgB,EAAU,EAAE;IAC3D,0EAA0E;IAC1E,+DAA+D;IAC/D,MAAM,KAAK,GAAG,IAAI;QAChB,CAAC,CAAC,GAAG,MAAM,QAAQ,IAAI,SAAS;QAChC,CAAC,CAAC,GAAG,MAAM,gBAAgB,CAAA;IAC7B,MAAM,IAAI,GAAG,CAAC,IAAY,EAAU,EAAE,CACpC,IAAI;QACF,CAAC,CAAC,KAAK,IAAI,MAAM,IAAI,OAAO,IAAI,IAAI;QACpC,CAAC,CAAC,MAAM,MAAM,OAAO,MAAM,QAAQ,MAAM,KAAK,IAAI,OAAO,IAAI,MAAM,MAAM,GAAG,CAAA;IAChF,OAAO,CACL,sDAAsD,KAAK,2BAA2B;QACtF,6GAA6G;QAC7G,GAAG,IAAI,CAAC,aAAa,CAAC,0DAA0D;QAChF,GAAG,IAAI,CAAC,kBAAkB,CAAC,iEAAiE;QAC5F,2EAA2E;QAC3E,qEAAqE;QACrE,oEAAoE;QACpE,kHAAkH,CACnH,CAAA;AACH,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,WAAW,GAAG,GAAa,EAAE;IACxC,MAAM,IAAI,GAAG,UAAU,CAAC,eAAe,CAAC,CAAA;IACxC,4EAA4E;IAC5E,yEAAyE;IACzE,4EAA4E;IAC5E,MAAM,IAAI,GAAG,UAAU,CAAC,WAAW,CAAC,CAAA;IACpC,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CACb,IAAI;YACF,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC;YACjB,CAAC,CAAC,+FAA+F,CACpG,CAAA;IACH,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC,CAAA","sourcesContent":["import { createContext, useContext, type RefObject } from \"react\"\nimport type { LayoutEngine, LayoutNode } from \"../layout/index\"\nimport type { Gtk } from \"../gtkx/bridge/index\"\n\n// One per mounted container (Root or View): children register their layout\n// nodes here and commit rects into the store read by the parent's\n// RnGtkxLayout allocate().\nexport type HostNode = {\n engine: LayoutEngine\n node: LayoutNode\n widgetRef: RefObject<Gtk.Box | null>\n}\n\nexport const HostNodeContext = createContext<HostNode | null>(null)\n\n// Which widget content area the current subtree was handed to, when it was\n// handed to one. Set by wrapReactNative for every element-valued prop it\n// forwards AND for the widget's children (see ../common/widget), and read\n// ONLY to build the error below — the boundary clears the layout root, so\n// React Native content that lands inside a widget without bringing its own\n// root has to be told where it is, and what to wrap it in.\nexport type SlotLocation = {\n /** The widget this content was handed to, e.g. \"AdwBottomSheet\". */\n widget: string\n /** The slot property, e.g. \"sheet\" — or null for an ordinary child. */\n slot: string | null\n}\n\nexport const SlotContext = createContext<SlotLocation | null>(null)\n\nconst slotError = ({ widget, slot }: SlotLocation): string => {\n // The two shapes differ only in how you write the wrapper, so the message\n // shows the caller their own syntax rather than a generic one.\n const where = slot\n ? `${widget}'s \\`${slot}\\` slot`\n : `${widget}, as its child`\n const wrap = (root: string): string =>\n slot\n ? ` ${slot}={<${root}>…</${root}>}`\n : ` <${widget}>…</${widget}> → <${widget}><${root}>…</${root}></${widget}>`\n return (\n `react-native-gtkx: React Native content was put in ${where} without a layout root.\\n` +\n `A GTK widget hands out a rectangle, and React Native needs a root to lay out inside it. Wrap the content:\\n` +\n `${wrap(\"SlotContent\")} — fill the area (a page body, a pane, a content area)\\n` +\n `${wrap(\"IntrinsicContent\")} — size the area to the content (a bar, a header slot, a row)\\n` +\n // The subpath is named without quoting it as a specifier: the metro-preset\n // test scans src for bare imports with a regex, and an import-shaped\n // sentence in a string literal reads to it exactly like a real one.\n `Both are exported by react-native-gtkx/common. GTK widgets need neither — they are what a widget takes natively.`\n )\n}\n\nexport const useHostNode = (): HostNode => {\n const host = useContext(HostNodeContext)\n // One extra context read per layout child. Deliberate: it is what turns the\n // single most confusing failure on this platform — content silently laid\n // out against the wrong rectangle — into a sentence naming where it landed.\n const slot = useContext(SlotContext)\n if (host === null) {\n throw new Error(\n slot\n ? slotError(slot)\n : \"react-native-gtkx components must be rendered inside AppRegistry.runApplication() or a <Root>\",\n )\n }\n return host\n}\n"]}
@@ -4,11 +4,15 @@ export { AppRegistry, type RunApplicationParams } from "./app-registry";
4
4
  export { FlatList, SectionList, type FlatListProps, type ListRenderItemInfo, type SectionListData, type SectionListProps, type ViewabilityConfig, type ViewToken, } from "./flat-list";
5
5
  export { Image, type ImageProps, type ImageSource } from "./image";
6
6
  export { Modal, type ModalProps } from "./modal";
7
- export { Pressable, TouchableOpacity, type PressableProps, type PressableStateCallbackType, type PressEvent, type TouchableOpacityProps, } from "./pressable";
7
+ export { Pressable, TouchableOpacity, type NativeTouch, type PressableProps, type PressableStateCallbackType, type PressEvent, type TouchableOpacityProps, } from "./pressable";
8
8
  export { IntrinsicRoot, NestedRoot, Root, type IntrinsicRootProps, type NestedRootProps, type RootProps, } from "./root";
9
9
  export { ScrollView, type ScrollEvent, type ScrollViewHandle, type ScrollViewProps, } from "./scroll-view";
10
10
  export { Switch, type SwitchProps } from "./switch";
11
11
  export { Text, type TextProps } from "./text";
12
12
  export { TextInput, type TextInputProps } from "./text-input";
13
- export { SafeAreaView, StatusBar, View, type ViewProps } from "./view";
13
+ export { SafeAreaView, StatusBar, View, type ViewHandle, type ViewProps, } from "./view";
14
+ export type { MeasureHandle, MeasureInWindowOnSuccessCallback, MeasureLayoutOnSuccessCallback, MeasureOnSuccessCallback, } from "./measure";
14
15
  export { type LayoutEvent } from "./use-layout-child";
16
+ export { default as PanResponder } from "../vendor/react-native/pan-responder";
17
+ export type { PanResponderCallbacks, PanResponderGestureState, PanResponderInstance, } from "../vendor/react-native/pan-responder";
18
+ export type { GestureResponderEvent, ResponderProps, TouchHistory, TouchRecord, } from "../responder/types";
@@ -10,5 +10,6 @@ export { ScrollView, } from "./scroll-view";
10
10
  export { Switch } from "./switch";
11
11
  export { Text } from "./text";
12
12
  export { TextInput } from "./text-input";
13
- export { SafeAreaView, StatusBar, View } from "./view";
13
+ export { SafeAreaView, StatusBar, View, } from "./view";
14
+ export { default as PanResponder } from "../vendor/react-native/pan-responder";
14
15
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,GAElB,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EACL,QAAQ,EACR,MAAM,GAGP,MAAM,YAAY,CAAA;AACnB,OAAO,EAAE,WAAW,EAA6B,MAAM,gBAAgB,CAAA;AACvE,OAAO,EACL,QAAQ,EACR,WAAW,GAOZ,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,KAAK,EAAqC,MAAM,SAAS,CAAA;AAClE,OAAO,EAAE,KAAK,EAAmB,MAAM,SAAS,CAAA;AAChD,OAAO,EACL,SAAS,EACT,gBAAgB,GAKjB,MAAM,aAAa,CAAA;AACpB,OAAO,EACL,aAAa,EACb,UAAU,EACV,IAAI,GAIL,MAAM,QAAQ,CAAA;AACf,OAAO,EACL,UAAU,GAIX,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,MAAM,EAAoB,MAAM,UAAU,CAAA;AACnD,OAAO,EAAE,IAAI,EAAkB,MAAM,QAAQ,CAAA;AAC7C,OAAO,EAAE,SAAS,EAAuB,MAAM,cAAc,CAAA;AAC7D,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,IAAI,EAAkB,MAAM,QAAQ,CAAA","sourcesContent":["export {\n ActivityIndicator,\n type ActivityIndicatorProps,\n} from \"./activity-indicator\"\nexport {\n Animated,\n Easing,\n type AnimatedViewProps,\n type AnimatedViewStyle,\n} from \"./animated\"\nexport { AppRegistry, type RunApplicationParams } from \"./app-registry\"\nexport {\n FlatList,\n SectionList,\n type FlatListProps,\n type ListRenderItemInfo,\n type SectionListData,\n type SectionListProps,\n type ViewabilityConfig,\n type ViewToken,\n} from \"./flat-list\"\nexport { Image, type ImageProps, type ImageSource } from \"./image\"\nexport { Modal, type ModalProps } from \"./modal\"\nexport {\n Pressable,\n TouchableOpacity,\n type PressableProps,\n type PressableStateCallbackType,\n type PressEvent,\n type TouchableOpacityProps,\n} from \"./pressable\"\nexport {\n IntrinsicRoot,\n NestedRoot,\n Root,\n type IntrinsicRootProps,\n type NestedRootProps,\n type RootProps,\n} from \"./root\"\nexport {\n ScrollView,\n type ScrollEvent,\n type ScrollViewHandle,\n type ScrollViewProps,\n} from \"./scroll-view\"\nexport { Switch, type SwitchProps } from \"./switch\"\nexport { Text, type TextProps } from \"./text\"\nexport { TextInput, type TextInputProps } from \"./text-input\"\nexport { SafeAreaView, StatusBar, View, type ViewProps } from \"./view\"\nexport { type LayoutEvent } from \"./use-layout-child\"\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,GAElB,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EACL,QAAQ,EACR,MAAM,GAGP,MAAM,YAAY,CAAA;AACnB,OAAO,EAAE,WAAW,EAA6B,MAAM,gBAAgB,CAAA;AACvE,OAAO,EACL,QAAQ,EACR,WAAW,GAOZ,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,KAAK,EAAqC,MAAM,SAAS,CAAA;AAClE,OAAO,EAAE,KAAK,EAAmB,MAAM,SAAS,CAAA;AAChD,OAAO,EACL,SAAS,EACT,gBAAgB,GAMjB,MAAM,aAAa,CAAA;AACpB,OAAO,EACL,aAAa,EACb,UAAU,EACV,IAAI,GAIL,MAAM,QAAQ,CAAA;AACf,OAAO,EACL,UAAU,GAIX,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,MAAM,EAAoB,MAAM,UAAU,CAAA;AACnD,OAAO,EAAE,IAAI,EAAkB,MAAM,QAAQ,CAAA;AAC7C,OAAO,EAAE,SAAS,EAAuB,MAAM,cAAc,CAAA;AAC7D,OAAO,EACL,YAAY,EACZ,SAAS,EACT,IAAI,GAGL,MAAM,QAAQ,CAAA;AAQf,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,sCAAsC,CAAA","sourcesContent":["export {\n ActivityIndicator,\n type ActivityIndicatorProps,\n} from \"./activity-indicator\"\nexport {\n Animated,\n Easing,\n type AnimatedViewProps,\n type AnimatedViewStyle,\n} from \"./animated\"\nexport { AppRegistry, type RunApplicationParams } from \"./app-registry\"\nexport {\n FlatList,\n SectionList,\n type FlatListProps,\n type ListRenderItemInfo,\n type SectionListData,\n type SectionListProps,\n type ViewabilityConfig,\n type ViewToken,\n} from \"./flat-list\"\nexport { Image, type ImageProps, type ImageSource } from \"./image\"\nexport { Modal, type ModalProps } from \"./modal\"\nexport {\n Pressable,\n TouchableOpacity,\n type NativeTouch,\n type PressableProps,\n type PressableStateCallbackType,\n type PressEvent,\n type TouchableOpacityProps,\n} from \"./pressable\"\nexport {\n IntrinsicRoot,\n NestedRoot,\n Root,\n type IntrinsicRootProps,\n type NestedRootProps,\n type RootProps,\n} from \"./root\"\nexport {\n ScrollView,\n type ScrollEvent,\n type ScrollViewHandle,\n type ScrollViewProps,\n} from \"./scroll-view\"\nexport { Switch, type SwitchProps } from \"./switch\"\nexport { Text, type TextProps } from \"./text\"\nexport { TextInput, type TextInputProps } from \"./text-input\"\nexport {\n SafeAreaView,\n StatusBar,\n View,\n type ViewHandle,\n type ViewProps,\n} from \"./view\"\nexport type {\n MeasureHandle,\n MeasureInWindowOnSuccessCallback,\n MeasureLayoutOnSuccessCallback,\n MeasureOnSuccessCallback,\n} from \"./measure\"\nexport { type LayoutEvent } from \"./use-layout-child\"\nexport { default as PanResponder } from \"../vendor/react-native/pan-responder\"\nexport type {\n PanResponderCallbacks,\n PanResponderGestureState,\n PanResponderInstance,\n} from \"../vendor/react-native/pan-responder\"\nexport type {\n GestureResponderEvent,\n ResponderProps,\n TouchHistory,\n TouchRecord,\n} from \"../responder/types\"\n"]}
@@ -0,0 +1,13 @@
1
+ import type { RefObject } from "react";
2
+ import type { LayoutNodeApi } from "../contracts";
3
+ import { type Gtk } from "../gtkx/bridge/index";
4
+ export type MeasureOnSuccessCallback = (x: number, y: number, width: number, height: number, pageX: number, pageY: number) => void;
5
+ export type MeasureInWindowOnSuccessCallback = (x: number, y: number, width: number, height: number) => void;
6
+ export type MeasureLayoutOnSuccessCallback = (left: number, top: number, width: number, height: number) => void;
7
+ /** The measurement half of a component ref, matching RN's method set. */
8
+ export type MeasureHandle = {
9
+ measure(callback: MeasureOnSuccessCallback): void;
10
+ measureInWindow(callback: MeasureInWindowOnSuccessCallback): void;
11
+ measureLayout(relativeTo: MeasureHandle, onSuccess: MeasureLayoutOnSuccessCallback, onFail?: () => void): void;
12
+ };
13
+ export declare const createMeasureHandle: (widgetRef: RefObject<Gtk.Widget | null>, node: LayoutNodeApi) => MeasureHandle;
@@ -0,0 +1,51 @@
1
+ import { computePointIn, computePointInWindow, } from "../gtkx/bridge/index";
2
+ // measureLayout needs the OTHER view's widget, and the public handle type
3
+ // deliberately does not carry one — a portable API should not hand out a
4
+ // Gtk.Widget. The lookup lives here instead, keyed by the handle identity.
5
+ const widgetOf = new WeakMap();
6
+ export const createMeasureHandle = (widgetRef, node) => {
7
+ const handle = {
8
+ measure(callback) {
9
+ const widget = widgetRef.current;
10
+ const rect = node.getRect();
11
+ if (!widget || !rect) {
12
+ return;
13
+ }
14
+ const page = computePointInWindow(widget, 0, 0);
15
+ if (!page) {
16
+ return;
17
+ }
18
+ callback(rect.x, rect.y, rect.width, rect.height, page.x, page.y);
19
+ },
20
+ measureInWindow(callback) {
21
+ const widget = widgetRef.current;
22
+ const rect = node.getRect();
23
+ if (!widget || !rect) {
24
+ return;
25
+ }
26
+ const page = computePointInWindow(widget, 0, 0);
27
+ if (!page) {
28
+ return;
29
+ }
30
+ callback(page.x, page.y, rect.width, rect.height);
31
+ },
32
+ measureLayout(relativeTo, onSuccess, onFail) {
33
+ const widget = widgetRef.current;
34
+ const other = widgetOf.get(relativeTo)?.() ?? null;
35
+ const rect = node.getRect();
36
+ if (!widget || !other || !rect) {
37
+ onFail?.();
38
+ return;
39
+ }
40
+ const origin = computePointIn(widget, other, 0, 0);
41
+ if (!origin) {
42
+ onFail?.();
43
+ return;
44
+ }
45
+ onSuccess(origin.x, origin.y, rect.width, rect.height);
46
+ },
47
+ };
48
+ widgetOf.set(handle, () => widgetRef.current);
49
+ return handle;
50
+ };
51
+ //# sourceMappingURL=measure.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"measure.js","sourceRoot":"","sources":["../../src/components/measure.ts"],"names":[],"mappings":"AAeA,OAAO,EACL,cAAc,EACd,oBAAoB,GAErB,MAAM,sBAAsB,CAAA;AAoC7B,0EAA0E;AAC1E,yEAAyE;AACzE,2EAA2E;AAC3E,MAAM,QAAQ,GAAG,IAAI,OAAO,EAA0C,CAAA;AAEtE,MAAM,CAAC,MAAM,mBAAmB,GAAG,CACjC,SAAuC,EACvC,IAAmB,EACJ,EAAE;IACjB,MAAM,MAAM,GAAkB;QAC5B,OAAO,CAAC,QAAQ;YACd,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAA;YAChC,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,CAAA;YAC3B,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;gBACrB,OAAM;YACR,CAAC;YACD,MAAM,IAAI,GAAG,oBAAoB,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;YAC/C,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,OAAM;YACR,CAAC;YACD,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAA;QACnE,CAAC;QAED,eAAe,CAAC,QAAQ;YACtB,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAA;YAChC,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,CAAA;YAC3B,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;gBACrB,OAAM;YACR,CAAC;YACD,MAAM,IAAI,GAAG,oBAAoB,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;YAC/C,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,OAAM;YACR,CAAC;YACD,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAA;QACnD,CAAC;QAED,aAAa,CAAC,UAAU,EAAE,SAAS,EAAE,MAAM;YACzC,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAA;YAChC,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,IAAI,IAAI,CAAA;YAClD,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,CAAA;YAC3B,IAAI,CAAC,MAAM,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,EAAE,CAAC;gBAC/B,MAAM,EAAE,EAAE,CAAA;gBACV,OAAM;YACR,CAAC;YACD,MAAM,MAAM,GAAG,cAAc,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;YAClD,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,MAAM,EAAE,EAAE,CAAA;gBACV,OAAM;YACR,CAAC;YACD,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAA;QACxD,CAAC;KACF,CAAA;IAED,QAAQ,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,CAAA;IAC7C,OAAO,MAAM,CAAA;AACf,CAAC,CAAA","sourcesContent":["// RN's imperative geometry API (measure / measureInWindow / measureLayout),\n// shared by every component that exposes a ref.\n//\n// The size and the parent-relative position come from the Yoga rect the\n// component's layout node already holds — that is the layout truth, and it\n// is what RN reports (a rotated view still measures its own box, not its\n// axis-aligned bounding box). Only the translation into another coordinate\n// space goes through GTK, where compute_point walks the transform chain and\n// therefore already accounts for scroll offsets.\n//\n// RN's contract on failure is to not call back rather than to invent a\n// number: a view whose layout has not been committed yet (before the first\n// onLayout) or that is not in a window has nothing true to report.\nimport type { RefObject } from \"react\"\nimport type { LayoutNodeApi } from \"../contracts\"\nimport {\n computePointIn,\n computePointInWindow,\n type Gtk,\n} from \"../gtkx/bridge/index\"\n\nexport type MeasureOnSuccessCallback = (\n x: number,\n y: number,\n width: number,\n height: number,\n pageX: number,\n pageY: number,\n) => void\n\nexport type MeasureInWindowOnSuccessCallback = (\n x: number,\n y: number,\n width: number,\n height: number,\n) => void\n\nexport type MeasureLayoutOnSuccessCallback = (\n left: number,\n top: number,\n width: number,\n height: number,\n) => void\n\n/** The measurement half of a component ref, matching RN's method set. */\nexport type MeasureHandle = {\n measure(callback: MeasureOnSuccessCallback): void\n measureInWindow(callback: MeasureInWindowOnSuccessCallback): void\n measureLayout(\n relativeTo: MeasureHandle,\n onSuccess: MeasureLayoutOnSuccessCallback,\n onFail?: () => void,\n ): void\n}\n\n// measureLayout needs the OTHER view's widget, and the public handle type\n// deliberately does not carry one — a portable API should not hand out a\n// Gtk.Widget. The lookup lives here instead, keyed by the handle identity.\nconst widgetOf = new WeakMap<MeasureHandle, () => Gtk.Widget | null>()\n\nexport const createMeasureHandle = (\n widgetRef: RefObject<Gtk.Widget | null>,\n node: LayoutNodeApi,\n): MeasureHandle => {\n const handle: MeasureHandle = {\n measure(callback) {\n const widget = widgetRef.current\n const rect = node.getRect()\n if (!widget || !rect) {\n return\n }\n const page = computePointInWindow(widget, 0, 0)\n if (!page) {\n return\n }\n callback(rect.x, rect.y, rect.width, rect.height, page.x, page.y)\n },\n\n measureInWindow(callback) {\n const widget = widgetRef.current\n const rect = node.getRect()\n if (!widget || !rect) {\n return\n }\n const page = computePointInWindow(widget, 0, 0)\n if (!page) {\n return\n }\n callback(page.x, page.y, rect.width, rect.height)\n },\n\n measureLayout(relativeTo, onSuccess, onFail) {\n const widget = widgetRef.current\n const other = widgetOf.get(relativeTo)?.() ?? null\n const rect = node.getRect()\n if (!widget || !other || !rect) {\n onFail?.()\n return\n }\n const origin = computePointIn(widget, other, 0, 0)\n if (!origin) {\n onFail?.()\n return\n }\n onSuccess(origin.x, origin.y, rect.width, rect.height)\n },\n }\n\n widgetOf.set(handle, () => widgetRef.current)\n return handle\n}\n"]}
@@ -9,4 +9,4 @@ export type ModalProps = {
9
9
  height?: number;
10
10
  children?: ReactNode;
11
11
  };
12
- export declare const Modal: ({ visible, onRequestClose, title, width, height, children, }: ModalProps) => ReactNode;
12
+ export declare const Modal: ({ visible, onRequestClose, title, width, height, children, }: ModalProps) => React.ReactPortal | null;
@@ -0,0 +1,28 @@
1
+ import type { Gtk } from "../gtkx/bridge/index";
2
+ /** One touch point, in RN's shape. */
3
+ export type NativeTouch = {
4
+ identifier: number;
5
+ target: number | null;
6
+ locationX: number;
7
+ locationY: number;
8
+ pageX: number;
9
+ pageY: number;
10
+ timestamp: number;
11
+ force: number;
12
+ };
13
+ export type PressEvent = {
14
+ nativeEvent: NativeTouch & {
15
+ touches: readonly NativeTouch[];
16
+ changedTouches: readonly NativeTouch[];
17
+ };
18
+ };
19
+ export declare const touchTimestamp: () => number;
20
+ /** A stable numeric id for a widget, standing in for RN's node handle. */
21
+ export declare const targetIdOf: (widget: object | null) => number | null;
22
+ /**
23
+ * Builds a touch from coordinates in the target widget's own space — which
24
+ * is what every GTK gesture reports.
25
+ */
26
+ export declare const createTouch: (widget: Gtk.Widget | null, locationX: number, locationY: number, identifier?: number) => NativeTouch;
27
+ /** Wraps a single touch as a complete RN press event. */
28
+ export declare const createPressEvent: (touch: NativeTouch) => PressEvent;
@@ -0,0 +1,46 @@
1
+ import { computePointInWindow } from "../gtkx/bridge/index";
2
+ // performance.now() is monotonic and sub-millisecond — see the note above.
3
+ export const touchTimestamp = () => performance.now();
4
+ let nextTargetId = 1;
5
+ const targetIds = new WeakMap();
6
+ /** A stable numeric id for a widget, standing in for RN's node handle. */
7
+ export const targetIdOf = (widget) => {
8
+ if (!widget) {
9
+ return null;
10
+ }
11
+ const existing = targetIds.get(widget);
12
+ if (existing !== undefined) {
13
+ return existing;
14
+ }
15
+ const id = nextTargetId;
16
+ nextTargetId += 1;
17
+ targetIds.set(widget, id);
18
+ return id;
19
+ };
20
+ /**
21
+ * Builds a touch from coordinates in the target widget's own space — which
22
+ * is what every GTK gesture reports.
23
+ */
24
+ export const createTouch = (widget, locationX, locationY, identifier = 0) => {
25
+ const page = widget
26
+ ? computePointInWindow(widget, locationX, locationY)
27
+ : null;
28
+ return {
29
+ identifier,
30
+ target: targetIdOf(widget),
31
+ locationX,
32
+ locationY,
33
+ // A widget outside a window has no page space; falling back to the
34
+ // local point keeps the fields numeric without pretending to a
35
+ // translation that does not exist.
36
+ pageX: page?.x ?? locationX,
37
+ pageY: page?.y ?? locationY,
38
+ timestamp: touchTimestamp(),
39
+ force: 0,
40
+ };
41
+ };
42
+ /** Wraps a single touch as a complete RN press event. */
43
+ export const createPressEvent = (touch) => ({
44
+ nativeEvent: { ...touch, touches: [touch], changedTouches: [touch] },
45
+ });
46
+ //# sourceMappingURL=press-event.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"press-event.js","sourceRoot":"","sources":["../../src/components/press-event.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAA;AA+B3D,2EAA2E;AAC3E,MAAM,CAAC,MAAM,cAAc,GAAG,GAAW,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE,CAAA;AAE7D,IAAI,YAAY,GAAG,CAAC,CAAA;AACpB,MAAM,SAAS,GAAG,IAAI,OAAO,EAAkB,CAAA;AAE/C,0EAA0E;AAC1E,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,MAAqB,EAAiB,EAAE;IACjE,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,IAAI,CAAA;IACb,CAAC;IACD,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;IACtC,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,OAAO,QAAQ,CAAA;IACjB,CAAC;IACD,MAAM,EAAE,GAAG,YAAY,CAAA;IACvB,YAAY,IAAI,CAAC,CAAA;IACjB,SAAS,CAAC,GAAG,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;IACzB,OAAO,EAAE,CAAA;AACX,CAAC,CAAA;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CACzB,MAAyB,EACzB,SAAiB,EACjB,SAAiB,EACjB,UAAU,GAAG,CAAC,EACD,EAAE;IACf,MAAM,IAAI,GAAG,MAAM;QACjB,CAAC,CAAC,oBAAoB,CAAC,MAAM,EAAE,SAAS,EAAE,SAAS,CAAC;QACpD,CAAC,CAAC,IAAI,CAAA;IACR,OAAO;QACL,UAAU;QACV,MAAM,EAAE,UAAU,CAAC,MAAM,CAAC;QAC1B,SAAS;QACT,SAAS;QACT,mEAAmE;QACnE,+DAA+D;QAC/D,mCAAmC;QACnC,KAAK,EAAE,IAAI,EAAE,CAAC,IAAI,SAAS;QAC3B,KAAK,EAAE,IAAI,EAAE,CAAC,IAAI,SAAS;QAC3B,SAAS,EAAE,cAAc,EAAE;QAC3B,KAAK,EAAE,CAAC;KACT,CAAA;AACH,CAAC,CAAA;AAED,yDAAyD;AACzD,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,KAAkB,EAAc,EAAE,CAAC,CAAC;IACnE,WAAW,EAAE,EAAE,GAAG,KAAK,EAAE,OAAO,EAAE,CAAC,KAAK,CAAC,EAAE,cAAc,EAAE,CAAC,KAAK,CAAC,EAAE;CACrE,CAAC,CAAA","sourcesContent":["// RN's touch payload. One shape, shared by Pressable today and by the touch\n// and responder props when they land — in RN a single native touch stream\n// feeds both, and splitting it here would guarantee the two drift.\n//\n// Two details that look cosmetic and are not:\n//\n// - `timestamp` must be monotonic and finer than a millisecond tick.\n// PanResponder and TouchHistoryMath compute velocity by differencing it,\n// so a coarse clock makes consecutive frames compare equal and silently\n// reports ZERO movement. That is the standing diagnosis for\n// react-native-windows' New-Architecture PanResponder bug (#14119, open\n// since 2024-11): Date.now() granularity, not a logic error.\n// - `pageX/pageY` and `locationX/locationY` are different spaces (window vs\n// target-relative) and code in the wild reads both. Reporting one twice\n// is the kind of bug that only shows up once something is nested.\nimport type { Gtk } from \"../gtkx/bridge/index\"\nimport { computePointInWindow } from \"../gtkx/bridge/index\"\n\n/** One touch point, in RN's shape. */\nexport type NativeTouch = {\n // A desktop pointer is a single fabricated touch: RN's own event plugin\n // has always had a mouse path, and react-native-web documents converting\n // mouse events into one emulated touch. Real multitouch will hand out the\n // GdkEventSequence's own identity here.\n identifier: number\n // Stable per-widget id; RN's is a React node handle, which we have no\n // equivalent of. Null before the widget exists.\n target: number | null\n // Relative to the target view.\n locationX: number\n locationY: number\n // Relative to the window (\"page\" in RN's vocabulary).\n pageX: number\n pageY: number\n timestamp: number\n // No pressure-sensitive input plumbed yet; RN reports 0 for devices\n // without it, which is exactly what a mouse is.\n force: number\n}\n\nexport type PressEvent = {\n nativeEvent: NativeTouch & {\n touches: readonly NativeTouch[]\n changedTouches: readonly NativeTouch[]\n }\n}\n\n// performance.now() is monotonic and sub-millisecond — see the note above.\nexport const touchTimestamp = (): number => performance.now()\n\nlet nextTargetId = 1\nconst targetIds = new WeakMap<object, number>()\n\n/** A stable numeric id for a widget, standing in for RN's node handle. */\nexport const targetIdOf = (widget: object | null): number | null => {\n if (!widget) {\n return null\n }\n const existing = targetIds.get(widget)\n if (existing !== undefined) {\n return existing\n }\n const id = nextTargetId\n nextTargetId += 1\n targetIds.set(widget, id)\n return id\n}\n\n/**\n * Builds a touch from coordinates in the target widget's own space — which\n * is what every GTK gesture reports.\n */\nexport const createTouch = (\n widget: Gtk.Widget | null,\n locationX: number,\n locationY: number,\n identifier = 0,\n): NativeTouch => {\n const page = widget\n ? computePointInWindow(widget, locationX, locationY)\n : null\n return {\n identifier,\n target: targetIdOf(widget),\n locationX,\n locationY,\n // A widget outside a window has no page space; falling back to the\n // local point keeps the fields numeric without pretending to a\n // translation that does not exist.\n pageX: page?.x ?? locationX,\n pageY: page?.y ?? locationY,\n timestamp: touchTimestamp(),\n force: 0,\n }\n}\n\n/** Wraps a single touch as a complete RN press event. */\nexport const createPressEvent = (touch: NativeTouch): PressEvent => ({\n nativeEvent: { ...touch, touches: [touch], changedTouches: [touch] },\n})\n"]}
@@ -1,16 +1,12 @@
1
1
  import { type ReactNode } from "react";
2
2
  import type { StyleProp } from "../contracts";
3
+ import { type PressEvent } from "./press-event";
3
4
  import { type LayoutEvent } from "./use-layout-child";
4
5
  export type PressableStateCallbackType = {
5
6
  pressed: boolean;
6
7
  hovered: boolean;
7
8
  };
8
- export type PressEvent = {
9
- nativeEvent: {
10
- x: number;
11
- y: number;
12
- };
13
- };
9
+ export type { NativeTouch, PressEvent } from "./press-event";
14
10
  export type PressableProps = {
15
11
  style?: StyleProp | ((state: PressableStateCallbackType) => StyleProp);
16
12
  children?: ReactNode | ((state: PressableStateCallbackType) => ReactNode);
@@ -5,10 +5,12 @@ import { defaultCssRegistry } from "../style/registry.gtkx";
5
5
  import { Gtk, GtkBox } from "../gtkx/bridge/index";
6
6
  import { perfAddTime, perfCount, perfEnabled, perfNow } from "../perf";
7
7
  import { HostNodeContext } from "./host-node";
8
+ import { createPressEvent, createTouch } from "./press-event";
8
9
  import { useLayoutChild, useRnContainer, } from "./use-layout-child";
9
- const pressEvent = (x, y) => ({
10
- nativeEvent: { x, y },
11
- });
10
+ // Coordinates arrive from GtkGestureClick in the widget's own space, which
11
+ // is exactly RN's locationX/locationY; createTouch translates them into the
12
+ // window for pageX/pageY.
13
+ const pressEvent = (widget, x, y) => createPressEvent(createTouch(widget, x, y));
12
14
  // A View with a click gesture and hover tracking. State-dependent style and
13
15
  // children follow the RN Pressable function-prop contract.
14
16
  export const Pressable = ({ style, children, onPress, onPressIn, onPressOut, onLongPress, onHoverIn, onHoverOut, disabled = false, delayLongPress = 500, onLayout, testID, }) => {
@@ -38,7 +40,7 @@ export const Pressable = ({ style, children, onPress, onPressIn, onPressOut, onL
38
40
  pressed,
39
41
  hovered: hoveredRef.current,
40
42
  };
41
- // Gestures are attached imperatively even though rc.2 has a declarative
43
+ // Gestures are attached imperatively even though rc.3 has a declarative
42
44
  // `controllers` slot: the controllers are wired exactly once per widget and
43
45
  // the handlers read the latest props through a ref, so a re-render never
44
46
  // detaches and re-adds a gesture mid-press.
@@ -119,12 +121,15 @@ export const Pressable = ({ style, children, onPress, onPressIn, onPressOut, onL
119
121
  }
120
122
  longPressFired.current = false;
121
123
  setPressed(true);
122
- onPressIn?.(pressEvent(x, y));
124
+ const widget = widgetRef.current;
125
+ onPressIn?.(pressEvent(widget, x, y));
123
126
  if (onLongPress) {
124
127
  clearLongPress();
125
128
  longPressTimer.current = setTimeout(() => {
126
129
  longPressFired.current = true;
127
- onLongPress(pressEvent(x, y));
130
+ // Timestamped when it FIRES, not when the press started — the delay
131
+ // is the whole point of the event.
132
+ onLongPress(pressEvent(widgetRef.current, x, y));
128
133
  }, delayLongPress);
129
134
  }
130
135
  };
@@ -134,9 +139,10 @@ export const Pressable = ({ style, children, onPress, onPressIn, onPressOut, onL
134
139
  }
135
140
  clearLongPress();
136
141
  setPressed(false);
137
- onPressOut?.(pressEvent(x, y));
142
+ const widget = widgetRef.current;
143
+ onPressOut?.(pressEvent(widget, x, y));
138
144
  if (!longPressFired.current) {
139
- onPress?.(pressEvent(x, y));
145
+ onPress?.(pressEvent(widget, x, y));
140
146
  }
141
147
  };
142
148
  const handleCancel = () => {