react-native-gtkx 0.1.0-alpha.4 → 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 (257) hide show
  1. package/README.md +22 -9
  2. package/dist/adw/index.d.ts +3 -0
  3. package/dist/adw/index.js +41 -0
  4. package/dist/adw/index.js.map +1 -0
  5. package/dist/adw/widgets.generated.d.ts +63 -0
  6. package/dist/adw/widgets.generated.js +125 -0
  7. package/dist/adw/widgets.generated.js.map +1 -0
  8. package/dist/animated/create-animated.d.ts +2 -0
  9. package/dist/animated/create-animated.js +2 -0
  10. package/dist/animated/create-animated.js.map +1 -1
  11. package/dist/animated/index.d.ts +2 -0
  12. package/dist/animated/index.js +1 -0
  13. package/dist/animated/index.js.map +1 -1
  14. package/dist/animated/value-xy.d.ts +41 -0
  15. package/dist/animated/value-xy.js +90 -0
  16. package/dist/animated/value-xy.js.map +1 -0
  17. package/dist/animated/value.d.ts +9 -0
  18. package/dist/animated/value.js +30 -2
  19. package/dist/animated/value.js.map +1 -1
  20. package/dist/common/content.d.ts +69 -0
  21. package/dist/common/content.js +84 -0
  22. package/dist/common/content.js.map +1 -0
  23. package/dist/common/icon.d.ts +23 -0
  24. package/dist/common/icon.js +14 -0
  25. package/dist/common/icon.js.map +1 -0
  26. package/dist/common/index.d.ts +5 -0
  27. package/dist/common/index.js +21 -0
  28. package/dist/common/index.js.map +1 -0
  29. package/dist/common/list.d.ts +82 -0
  30. package/dist/common/list.js +166 -0
  31. package/dist/common/list.js.map +1 -0
  32. package/dist/common/navigation-stack.d.ts +84 -0
  33. package/dist/common/navigation-stack.js +313 -0
  34. package/dist/common/navigation-stack.js.map +1 -0
  35. package/dist/common/widget.d.ts +62 -0
  36. package/dist/common/widget.js +209 -0
  37. package/dist/common/widget.js.map +1 -0
  38. package/dist/components/animated.d.ts +7 -4
  39. package/dist/components/animated.js +88 -67
  40. package/dist/components/animated.js.map +1 -1
  41. package/dist/components/app-registry.d.ts +36 -1
  42. package/dist/components/app-registry.js +8 -3
  43. package/dist/components/app-registry.js.map +1 -1
  44. package/dist/components/host-node.d.ts +7 -0
  45. package/dist/components/host-node.js +26 -1
  46. package/dist/components/host-node.js.map +1 -1
  47. package/dist/components/index.d.ts +6 -2
  48. package/dist/components/index.js +2 -1
  49. package/dist/components/index.js.map +1 -1
  50. package/dist/components/measure.d.ts +13 -0
  51. package/dist/components/measure.js +51 -0
  52. package/dist/components/measure.js.map +1 -0
  53. package/dist/components/modal.d.ts +1 -1
  54. package/dist/components/press-event.d.ts +28 -0
  55. package/dist/components/press-event.js +46 -0
  56. package/dist/components/press-event.js.map +1 -0
  57. package/dist/components/pressable.d.ts +2 -6
  58. package/dist/components/pressable.js +119 -20
  59. package/dist/components/pressable.js.map +1 -1
  60. package/dist/components/rect-store.d.ts +11 -1
  61. package/dist/components/rect-store.js +27 -3
  62. package/dist/components/rect-store.js.map +1 -1
  63. package/dist/components/scroll-view.d.ts +4 -0
  64. package/dist/components/scroll-view.js +8 -2
  65. package/dist/components/scroll-view.js.map +1 -1
  66. package/dist/components/svg/animated-support.d.ts +19 -0
  67. package/dist/components/svg/animated-support.js +64 -0
  68. package/dist/components/svg/animated-support.js.map +1 -0
  69. package/dist/components/svg/context.d.ts +8 -0
  70. package/dist/components/svg/context.js +15 -0
  71. package/dist/components/svg/context.js.map +1 -0
  72. package/dist/components/svg/gradients.d.ts +31 -0
  73. package/dist/components/svg/gradients.js +93 -0
  74. package/dist/components/svg/gradients.js.map +1 -0
  75. package/dist/components/svg/group.d.ts +8 -0
  76. package/dist/components/svg/group.js +30 -0
  77. package/dist/components/svg/group.js.map +1 -0
  78. package/dist/components/svg/index.d.ts +6 -0
  79. package/dist/components/svg/index.js +5 -0
  80. package/dist/components/svg/index.js.map +1 -0
  81. package/dist/components/svg/node.d.ts +7 -0
  82. package/dist/components/svg/node.js +7 -0
  83. package/dist/components/svg/node.js.map +1 -0
  84. package/dist/components/svg/paint.d.ts +24 -0
  85. package/dist/components/svg/paint.js +57 -0
  86. package/dist/components/svg/paint.js.map +1 -0
  87. package/dist/components/svg/shapes.d.ts +47 -0
  88. package/dist/components/svg/shapes.js +51 -0
  89. package/dist/components/svg/shapes.js.map +1 -0
  90. package/dist/components/svg/svg.d.ts +14 -0
  91. package/dist/components/svg/svg.js +48 -0
  92. package/dist/components/svg/svg.js.map +1 -0
  93. package/dist/components/svg/use-shape-node.d.ts +12 -0
  94. package/dist/components/svg/use-shape-node.js +52 -0
  95. package/dist/components/svg/use-shape-node.js.map +1 -0
  96. package/dist/components/text-input.js +1 -1
  97. package/dist/components/text-input.js.map +1 -1
  98. package/dist/components/text.js +36 -3
  99. package/dist/components/text.js.map +1 -1
  100. package/dist/components/use-layout-child.js +50 -4
  101. package/dist/components/use-layout-child.js.map +1 -1
  102. package/dist/components/view.d.ts +9 -4
  103. package/dist/components/view.js +8 -2
  104. package/dist/components/view.js.map +1 -1
  105. package/dist/contracts.d.ts +31 -4
  106. package/dist/contracts.js.map +1 -1
  107. package/dist/gtk/index.d.ts +7 -0
  108. package/dist/gtk/index.js +46 -0
  109. package/dist/gtk/index.js.map +1 -0
  110. package/dist/gtk/widgets.generated.d.ts +103 -0
  111. package/dist/gtk/widgets.generated.js +205 -0
  112. package/dist/gtk/widgets.generated.js.map +1 -0
  113. package/dist/gtk/window-actions.d.ts +77 -0
  114. package/dist/gtk/window-actions.js +193 -0
  115. package/dist/gtk/window-actions.js.map +1 -0
  116. package/dist/gtkx/bridge/geometry.d.ts +15 -0
  117. package/dist/gtkx/bridge/geometry.js +38 -0
  118. package/dist/gtkx/bridge/geometry.js.map +1 -0
  119. package/dist/gtkx/bridge/index.d.ts +11 -4
  120. package/dist/gtkx/bridge/index.js +47 -6
  121. package/dist/gtkx/bridge/index.js.map +1 -1
  122. package/dist/gtkx/bridge/layout-manager.d.ts +2 -1
  123. package/dist/gtkx/bridge/layout-manager.js +31 -9
  124. package/dist/gtkx/bridge/layout-manager.js.map +1 -1
  125. package/dist/gtkx/bridge/slot-portal.d.ts +12 -0
  126. package/dist/gtkx/bridge/slot-portal.js +17 -0
  127. package/dist/gtkx/bridge/slot-portal.js.map +1 -0
  128. package/dist/gtkx/bridge/svg-node.d.ts +79 -0
  129. package/dist/gtkx/bridge/svg-node.js +323 -0
  130. package/dist/gtkx/bridge/svg-node.js.map +1 -0
  131. package/dist/gtkx/bridge/use-signal.js +19 -9
  132. package/dist/gtkx/bridge/use-signal.js.map +1 -1
  133. package/dist/gtkx/bridge/widgets.generated.d.ts +2 -0
  134. package/dist/gtkx/bridge/widgets.generated.js +14 -0
  135. package/dist/gtkx/bridge/widgets.generated.js.map +1 -0
  136. package/dist/index.d.ts +2 -2
  137. package/dist/index.js +1 -1
  138. package/dist/index.js.map +1 -1
  139. package/dist/mcp/bin.d.ts +2 -0
  140. package/dist/mcp/bin.js +17 -0
  141. package/dist/mcp/bin.js.map +1 -0
  142. package/dist/mcp/data/generated.d.ts +1304 -0
  143. package/dist/mcp/data/generated.js +1179 -0
  144. package/dist/mcp/data/generated.js.map +1 -0
  145. package/dist/mcp/index.d.ts +5 -0
  146. package/dist/mcp/index.js +9 -0
  147. package/dist/mcp/index.js.map +1 -0
  148. package/dist/mcp/list.d.ts +4 -0
  149. package/dist/mcp/list.js +56 -0
  150. package/dist/mcp/list.js.map +1 -0
  151. package/dist/mcp/resolve.d.ts +55 -0
  152. package/dist/mcp/resolve.js +151 -0
  153. package/dist/mcp/resolve.js.map +1 -0
  154. package/dist/mcp/search.d.ts +13 -0
  155. package/dist/mcp/search.js +48 -0
  156. package/dist/mcp/search.js.map +1 -0
  157. package/dist/mcp/server.d.ts +7 -0
  158. package/dist/mcp/server.js +135 -0
  159. package/dist/mcp/server.js.map +1 -0
  160. package/dist/mcp/tool.d.ts +21 -0
  161. package/dist/mcp/tool.js +36 -0
  162. package/dist/mcp/tool.js.map +1 -0
  163. package/dist/metro/index.js +10 -0
  164. package/dist/metro/index.js.map +1 -1
  165. package/dist/navigation/index.d.ts +50 -13
  166. package/dist/navigation/index.js +183 -148
  167. package/dist/navigation/index.js.map +1 -1
  168. package/dist/navigation/option-warnings.js +9 -1
  169. package/dist/navigation/option-warnings.js.map +1 -1
  170. package/dist/navigation/sidebar.d.ts +207 -9
  171. package/dist/navigation/sidebar.js +294 -10
  172. package/dist/navigation/sidebar.js.map +1 -1
  173. package/dist/responder/system.d.ts +27 -0
  174. package/dist/responder/system.js +184 -0
  175. package/dist/responder/system.js.map +1 -0
  176. package/dist/responder/touch-history.d.ts +10 -0
  177. package/dist/responder/touch-history.js +78 -0
  178. package/dist/responder/touch-history.js.map +1 -0
  179. package/dist/responder/types.d.ts +63 -0
  180. package/dist/responder/types.js +29 -0
  181. package/dist/responder/types.js.map +1 -0
  182. package/dist/responder/use-responder.d.ts +12 -0
  183. package/dist/responder/use-responder.js +98 -0
  184. package/dist/responder/use-responder.js.map +1 -0
  185. package/dist/runner/host-dev.js +3 -1
  186. package/dist/runner/host-dev.js.map +1 -1
  187. package/dist/runner/host.js +5 -1
  188. package/dist/runner/host.js.map +1 -1
  189. package/dist/runner/index.d.ts +22 -2
  190. package/dist/runner/index.js +163 -13
  191. package/dist/runner/index.js.map +1 -1
  192. package/dist/sea/assemble.d.ts +29 -0
  193. package/dist/sea/assemble.js +129 -0
  194. package/dist/sea/assemble.js.map +1 -0
  195. package/dist/sea/bundle.d.ts +61 -0
  196. package/dist/sea/bundle.js +202 -0
  197. package/dist/sea/bundle.js.map +1 -0
  198. package/dist/sea/gtkx-config-module.d.ts +18 -0
  199. package/dist/sea/gtkx-config-module.js +67 -0
  200. package/dist/sea/gtkx-config-module.js.map +1 -0
  201. package/dist/sea/native-shim.d.ts +40 -0
  202. package/dist/sea/native-shim.js +121 -0
  203. package/dist/sea/native-shim.js.map +1 -0
  204. package/dist/sea/react-anchor-plugin.d.ts +2 -0
  205. package/dist/sea/react-anchor-plugin.js +30 -0
  206. package/dist/sea/react-anchor-plugin.js.map +1 -0
  207. package/dist/style/box-shadow.d.ts +7 -0
  208. package/dist/style/box-shadow.js +197 -0
  209. package/dist/style/box-shadow.js.map +1 -0
  210. package/dist/style/index.d.ts +3 -0
  211. package/dist/style/index.js +3 -0
  212. package/dist/style/index.js.map +1 -1
  213. package/dist/style/split-style.d.ts +5 -2
  214. package/dist/style/split-style.js +33 -5
  215. package/dist/style/split-style.js.map +1 -1
  216. package/dist/style/text-decoration.d.ts +15 -0
  217. package/dist/style/text-decoration.js +26 -0
  218. package/dist/style/text-decoration.js.map +1 -0
  219. package/dist/style/transform.d.ts +22 -0
  220. package/dist/style/transform.js +137 -0
  221. package/dist/style/transform.js.map +1 -0
  222. package/dist/style/visual-css.js +40 -3
  223. package/dist/style/visual-css.js.map +1 -1
  224. package/dist/svg/geometry.d.ts +19 -0
  225. package/dist/svg/geometry.js +80 -0
  226. package/dist/svg/geometry.js.map +1 -0
  227. package/dist/svg/gradient-geometry.d.ts +15 -0
  228. package/dist/svg/gradient-geometry.js +15 -0
  229. package/dist/svg/gradient-geometry.js.map +1 -0
  230. package/dist/svg/transform.d.ts +22 -0
  231. package/dist/svg/transform.js +74 -0
  232. package/dist/svg/transform.js.map +1 -0
  233. package/dist/svg/view-box.d.ts +34 -0
  234. package/dist/svg/view-box.js +108 -0
  235. package/dist/svg/view-box.js.map +1 -0
  236. package/dist/svg-compat/index.d.ts +1 -0
  237. package/dist/svg-compat/index.js +16 -0
  238. package/dist/svg-compat/index.js.map +1 -0
  239. package/dist/testing/index.d.ts +14 -0
  240. package/dist/testing/index.js +14 -0
  241. package/dist/testing/index.js.map +1 -0
  242. package/dist/vendor/react-native/pan-responder.d.ts +102 -0
  243. package/dist/vendor/react-native/pan-responder.js +196 -0
  244. package/dist/vendor/react-native/pan-responder.js.map +1 -0
  245. package/dist/vendor/react-native/touch-history-math.d.ts +18 -0
  246. package/dist/vendor/react-native/touch-history-math.js +102 -0
  247. package/dist/vendor/react-native/touch-history-math.js.map +1 -0
  248. package/dist/vite/index.d.ts +7 -3
  249. package/dist/vite/index.js +16 -4
  250. package/dist/vite/index.js.map +1 -1
  251. package/dist/vitest/index.d.ts +52 -0
  252. package/dist/vitest/index.js +58 -0
  253. package/dist/vitest/index.js.map +1 -0
  254. package/dist/vitest/setup.d.ts +4 -0
  255. package/dist/vitest/setup.js +22 -0
  256. package/dist/vitest/setup.js.map +1 -0
  257. package/package.json +52 -13
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.js","sourceRoot":"","sources":["../../src/common/list.tsx"],"names":[],"mappings":";AAmBA,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAA;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAA;AACzC,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAa1D,+EAA+E;AAC/E,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,KAAa,EAAE,KAAa,EAAmB,EAAE;IAC3E,MAAM,KAAK,GAAG,KAAK,KAAK,CAAC,CAAA;IACzB,MAAM,IAAI,GAAG,KAAK,KAAK,KAAK,GAAG,CAAC,CAAA;IAChC,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;QAClB,OAAO,MAAM,CAAA;IACf,CAAC;IACD,OAAO,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAA;AACnD,CAAC,CAAA;AAED,qDAAqD;AACrD,mFAAmF;AACnF,2DAA2D;AAC3D,+DAA+D;AAC/D,iEAAiE;AACjE,MAAM,MAAM,GAAG,EAAE,CAAA;AAEjB,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC;IAC/B,IAAI,EAAE;QACJ,eAAe,EAAE,aAAa,CAAC,eAAe,CAAC;QAC/C,YAAY,EAAE,MAAM;QACpB,oEAAoE;QACpE,0EAA0E;QAC1E,qDAAqD;QACrD,SAAS,EAAE;YACT;gBACE,OAAO,EAAE,CAAC;gBACV,OAAO,EAAE,CAAC;gBACV,cAAc,EAAE,CAAC;gBACjB,KAAK,EAAE,qBAAqB;aAC7B;YACD;gBACE,OAAO,EAAE,CAAC;gBACV,OAAO,EAAE,CAAC;gBACV,UAAU,EAAE,CAAC;gBACb,cAAc,EAAE,CAAC;gBACjB,KAAK,EAAE,qBAAqB;aAC7B;YACD;gBACE,OAAO,EAAE,CAAC;gBACV,OAAO,EAAE,CAAC;gBACV,UAAU,EAAE,CAAC;gBACb,cAAc,EAAE,CAAC;gBACjB,KAAK,EAAE,qBAAqB;aAC7B;SACF;KACF;IACD,qCAAqC;IACrC,+EAA+E;IAC/E,0EAA0E;IAC1E,2BAA2B;IAC3B,GAAG,EAAE;QACH,aAAa,EAAE,KAAK;QACpB,UAAU,EAAE,QAAQ;QACpB,SAAS,EAAE,EAAE;QACb,eAAe,EAAE,CAAC;QAClB,iBAAiB,EAAE,EAAE;QACrB,GAAG,EAAE,CAAC;KACP;IACD,cAAc,EAAE;QACd,iBAAiB,EAAE,CAAC;QACpB,iBAAiB,EAAE,aAAa,CAAC,kBAAkB,CAAC;KACrD;IACD,QAAQ,EAAE,EAAE,mBAAmB,EAAE,MAAM,EAAE,oBAAoB,EAAE,MAAM,EAAE;IACvE,OAAO,EAAE;QACP,sBAAsB,EAAE,MAAM;QAC9B,uBAAuB,EAAE,MAAM;KAChC;IACD,wEAAwE;IACxE,QAAQ,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE;IAChD,6EAA6E;IAC7E,4EAA4E;IAC5E,uEAAuE;IACvE,0EAA0E;IAC1E,0CAA0C;IAC1C,KAAK,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE;IACzB,yEAAyE;IACzE,mBAAmB;IACnB,QAAQ,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE;IAC3C,SAAS,EAAE;QACT,MAAM,EAAE,CAAC;QACT,eAAe,EAAE,aAAa,CAAC,kBAAkB,CAAC;KACnD;CACF,CAAC,CAAA;AAEF,6EAA6E;AAC7E,8EAA8E;AAC9E,yEAAyE;AACzE,4EAA4E;AAC5E,4CAA4C;AAC5C,MAAM,KAAK,GAAG;IACZ,KAAK,EAAE,EAAE,KAAK,EAAE,qBAAqB,EAAE,KAAK,EAAE,qBAAqB,EAAE;IACrE,IAAI,EAAE;QACJ,KAAK,EAAE,2BAA2B;QAClC,KAAK,EAAE,2BAA2B;KACnC;CACO,CAAA;AAQV;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAa,EAAa,EAAE,CAAC,CACzE,KAAC,IAAI,IACH,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,YAE1B,QAAQ,GACJ,CACR,CAAA;AA4BD;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,EACtB,KAAK,EACL,QAAQ,EACR,MAAM,EACN,MAAM,EACN,OAAO,EACP,QAAQ,GAAG,QAAQ,EACnB,SAAS,EACT,KAAK,EACL,MAAM,GACO,EAAa,EAAE;IAC5B,MAAM,MAAM,GAAG,cAAc,EAAE,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAA;IAC7D,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,CAAA;IAC3B,MAAM,OAAO,GAAG,QAAQ,KAAK,OAAO,IAAI,QAAQ,KAAK,MAAM,CAAA;IAC3D,MAAM,MAAM,GAAG,QAAQ,KAAK,MAAM,IAAI,QAAQ,KAAK,MAAM,CAAA;IACzD,MAAM,aAAa,GAAG,SAAS,IAAI,CAAC,MAAM,CAAA;IAE1C,MAAM,IAAI,GAAG,CACX,8BACG,MAAM,EACP,MAAC,IAAI,IAAC,KAAK,EAAE,MAAM,CAAC,QAAQ,aACzB,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,CAC3B,KAAC,IAAI,IAAC,KAAK,EAAE,MAAM,CAAC,KAAK,YAAG,KAAK,GAAQ,CAC1C,CAAC,CAAC,CAAC,CACF,KAAK,CACN,EACA,OAAO,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,CAC9B,KAAC,IAAI,IAAC,KAAK,EAAE,MAAM,CAAC,QAAQ,YAAG,QAAQ,GAAQ,CAChD,CAAC,CAAC,CAAC,CACF,QAAQ,CACT,IACI,EACN,MAAM,IACN,CACJ,CAAA;IAED,MAAM,IAAI,GAAG;QACX,MAAM,CAAC,GAAG;QACV,OAAO,IAAI,MAAM,CAAC,QAAQ;QAC1B,MAAM,IAAI,MAAM,CAAC,OAAO;QACxB,aAAa,IAAI,MAAM,CAAC,cAAc;QACtC,KAAK;KACN,CAAA;IAED,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,CACL,KAAC,IAAI,IACH,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,IAAI,YAEV,IAAI,GACA,CACR,CAAA;IACH,CAAC;IAED,OAAO,CACL,KAAC,SAAS,IACR,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,OAAO;QAChB,wEAAwE;QACxE,wEAAwE;QACxE,+DAA+D;QAC/D,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;YAC/B,GAAG,IAAI;YACP,OAAO,IAAI,EAAE,eAAe,EAAE,KAAK,CAAC,KAAK,EAAE;YAC3C,OAAO,IAAI,EAAE,eAAe,EAAE,KAAK,CAAC,KAAK,EAAE;SAC5C,YAEA,IAAI,GACK,CACb,CAAA;AACH,CAAC,CAAA;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,GAAc,EAAE,CAAC,KAAC,IAAI,IAAC,KAAK,EAAE,MAAM,CAAC,SAAS,GAAI,CAAA","sourcesContent":["// Adwaita's boxed list, for code written in React Native.\n//\n// WHY this is here rather than in an app. `.boxed-list` is the single most\n// recognisable piece of GNOME chrome, and docs/research/react-native-first-showcase.md\n// measured what it actually is: a rounded, shadowed card whose rows carry\n// hairline separators, a hover tint and a press tint. Every one of those is a\n// style — there is no widget BEHAVIOUR in the look at all. So an app can build\n// it from `View` and `Pressable`, and `examples/tasks-nav` proves it.\n//\n// What an app should not have to do is rediscover the numbers. They come from\n// libadwaita's own compiled stylesheet, they are not obvious (the frame is a\n// three-part `box-shadow`, not a border; the first and last rows carry the\n// corner radii, not the container), and they move when libadwaita moves. That\n// is a platform's job, which is what this subpath is.\n//\n// Everything below is portable React Native underneath — no widget is created\n// that an app could not have created itself. Compare `Widget`/`SlotContent`\n// next door, which exist precisely because they CANNOT be written in RN.\nimport { type ReactNode } from \"react\"\nimport { useColorScheme } from \"../apis/index\"\nimport { Pressable } from \"../components/pressable\"\nimport { Text } from \"../components/text\"\nimport { View } from \"../components/view\"\nimport { PlatformColor, StyleSheet } from \"../style/index\"\nimport type { StyleProp } from \"../contracts\"\n\n/**\n * Where a row sits in its list, which is what decides its corner radii and\n * whether it draws a separator under itself.\n *\n * RN has no `:first-child`, so this is explicit. From a `FlatList` it is\n * `rowPosition(index, data.length)`; from a static list it is the same\n * expression over the array.\n */\nexport type ListRowPosition = \"first\" | \"middle\" | \"last\" | \"only\"\n\n/** The usual derivation, so no call site has to get the one-row case wrong. */\nexport const rowPosition = (index: number, count: number): ListRowPosition => {\n const first = index === 0\n const last = index === count - 1\n if (first && last) {\n return \"only\"\n }\n return first ? \"first\" : last ? \"last\" : \"middle\"\n}\n\n// libadwaita 1.9, /org/gnome/Adwaita/styles/gtk.css:\n// list.boxed-list { background-color: var(--card-bg-color); border-radius: 12px;\n// box-shadow: 0 0 0 1px RGB(0 0 6/3%),\n// 0 1px 3px 1px RGB(0 0 6/7%),\n// 0 2px 6px 2px RGB(0 0 6/3%); }\nconst RADIUS = 12\n\nconst styles = StyleSheet.create({\n list: {\n backgroundColor: PlatformColor(\"card-bg-color\"),\n borderRadius: RADIUS,\n // The frame is a shadow, not a border, and that distinction is load\n // bearing: a border would consume the box and inset every row by a pixel,\n // and no border draws the two soft drops underneath.\n boxShadow: [\n {\n offsetX: 0,\n offsetY: 0,\n spreadDistance: 1,\n color: \"rgba(0, 0, 6, 0.03)\",\n },\n {\n offsetX: 0,\n offsetY: 1,\n blurRadius: 3,\n spreadDistance: 1,\n color: \"rgba(0, 0, 6, 0.07)\",\n },\n {\n offsetX: 0,\n offsetY: 2,\n blurRadius: 6,\n spreadDistance: 2,\n color: \"rgba(0, 0, 6, 0.03)\",\n },\n ],\n },\n // `list > row { padding: 2px }` plus\n // `row > box.header { margin: 0 12px; border-spacing: 6px; min-height: 50px }`\n // — 2 + 50 + 2 + the 1px separator is the 55px row pitch measured off the\n // widget's own screenshot.\n row: {\n flexDirection: \"row\",\n alignItems: \"center\",\n minHeight: 54,\n paddingVertical: 2,\n paddingHorizontal: 14,\n gap: 6,\n },\n separatorUnder: {\n borderBottomWidth: 1,\n borderBottomColor: PlatformColor(\"card-shade-color\"),\n },\n firstRow: { borderTopLeftRadius: RADIUS, borderTopRightRadius: RADIUS },\n lastRow: {\n borderBottomLeftRadius: RADIUS,\n borderBottomRightRadius: RADIUS,\n },\n // `row > box.header > box.title { margin: 6px 0; border-spacing: 3px }`\n titleBox: { flex: 1, marginVertical: 6, gap: 3 },\n // The theme font is `Adwaita Sans 11`, i.e. 11pt = 14.67px, and Adwaita sets\n // the subtitle to `font-size: smaller` — Pango's one-step-down, 1/1.2. RN's\n // fontSize is numeric only (there is no `smaller`, no em, no inherited\n // percentage), so the computed value is what an app can write. Documented\n // in docs/api.md rather than hidden here.\n title: { fontSize: 14.7 },\n // `row label.subtitle { opacity: var(--dim-opacity) }`, 55% in the light\n // Adwaita palette.\n subtitle: { fontSize: 12.2, opacity: 0.55 },\n separator: {\n height: 1,\n backgroundColor: PlatformColor(\"card-shade-color\"),\n },\n})\n\n// Adwaita tints the hover and press states with a fraction of the FOREGROUND\n// colour (`color-mix(in srgb, currentColor 4%, transparent)`), so one literal\n// cannot serve both themes and CSS colour functions are not part of RN's\n// colour contract. Two literals plus the scheme is what an RN app writes on\n// every platform, and it is what this does.\nconst TINTS = {\n light: { hover: \"rgba(0, 0, 0, 0.04)\", press: \"rgba(0, 0, 0, 0.08)\" },\n dark: {\n hover: \"rgba(255, 255, 255, 0.04)\",\n press: \"rgba(255, 255, 255, 0.08)\",\n },\n} as const\n\nexport type ListProps = {\n children?: ReactNode\n style?: StyleProp\n testID?: string\n}\n\n/**\n * The `.boxed-list` frame: a rounded, shadowed card. Put `ListRow`s in it\n * directly, or a `FlatList` whose `renderItem` returns them.\n *\n * ```tsx\n * <List>\n * {tasks.map((task, index) => (\n * <ListRow\n * key={task.id}\n * title={task.title}\n * position={rowPosition(index, tasks.length)}\n * onPress={() => open(task)}\n * />\n * ))}\n * </List>\n * ```\n */\nexport const List = ({ children, style, testID }: ListProps): ReactNode => (\n <View\n testID={testID}\n style={[styles.list, style]}\n >\n {children}\n </View>\n)\n\nexport type ListRowProps = {\n /** Primary line. A string renders with the row's own typography; a node is\n * rendered as given, for a title that needs its own styling. */\n title?: ReactNode\n /** Second, dimmed line. Omitted rows are single-line, as `AdwActionRow`'s\n * are. */\n subtitle?: ReactNode\n /** Leading content — a checkbox, an icon, a colour swatch. */\n prefix?: ReactNode\n /** Trailing content — buttons, a value, a chevron. */\n suffix?: ReactNode\n /** Makes the row activatable: it gains the hover and press tints and calls\n * this. Without it the row is inert, like a non-`activatable`\n * `AdwActionRow`. */\n onPress?: () => void\n /** Position in the list, for the corner radii and the separator. Defaults\n * to `\"middle\"`, which is right for a row that is neither. */\n position?: ListRowPosition\n /** Draw the hairline under this row. Default true for every position except\n * the last — set it false when the list supplies its own separators (a\n * `FlatList`'s `ItemSeparatorComponent`, say). */\n separator?: boolean\n style?: StyleProp\n testID?: string\n}\n\n/**\n * One row of a {@link List} — `AdwActionRow`'s layout and states, built from\n * `Pressable`, `View` and `Text`.\n *\n * Hover and press come from `Pressable`'s state callback, so they cost what\n * they cost anywhere else in this platform: the hover path swaps a CSS class\n * on the widget without a React render (see components/pressable.tsx).\n *\n * **Not yet:** keyboard navigation between rows and a focus ring.\n * `GtkListBox` implements those as widget behaviour and RN has no focus model\n * for `View` to hang them on — `Pressable`'s state is `{pressed, hovered}`\n * with no `focused`. The ring itself is now drawable (`outlineWidth` and\n * friends), so what is missing is the state, not the paint.\n */\nexport const ListRow = ({\n title,\n subtitle,\n prefix,\n suffix,\n onPress,\n position = \"middle\",\n separator,\n style,\n testID,\n}: ListRowProps): ReactNode => {\n const scheme = useColorScheme() === \"dark\" ? \"dark\" : \"light\"\n const tints = TINTS[scheme]\n const isFirst = position === \"first\" || position === \"only\"\n const isLast = position === \"last\" || position === \"only\"\n const drawSeparator = separator ?? !isLast\n\n const body = (\n <>\n {prefix}\n <View style={styles.titleBox}>\n {typeof title === \"string\" ? (\n <Text style={styles.title}>{title}</Text>\n ) : (\n title\n )}\n {typeof subtitle === \"string\" ? (\n <Text style={styles.subtitle}>{subtitle}</Text>\n ) : (\n subtitle\n )}\n </View>\n {suffix}\n </>\n )\n\n const base = [\n styles.row,\n isFirst && styles.firstRow,\n isLast && styles.lastRow,\n drawSeparator && styles.separatorUnder,\n style,\n ]\n\n if (!onPress) {\n return (\n <View\n testID={testID}\n style={base}\n >\n {body}\n </View>\n )\n }\n\n return (\n <Pressable\n testID={testID}\n onPress={onPress}\n // The tint goes on the ROW, which is why the corner radii above have to\n // be on the row too: a hovered first row must round its own top corners\n // or the highlight paints square over the card's rounded ones.\n style={({ hovered, pressed }) => [\n ...base,\n hovered && { backgroundColor: tints.hover },\n pressed && { backgroundColor: tints.press },\n ]}\n >\n {body}\n </Pressable>\n )\n}\n\n/**\n * The hairline between two rows, for lists that draw their own separators —\n * a `FlatList`'s `ItemSeparatorComponent` is exactly this, and using it means\n * the rows themselves stay position-agnostic apart from their corners.\n */\nexport const ListSeparator = (): ReactNode => <View style={styles.separator} />\n"]}
@@ -0,0 +1,84 @@
1
+ import { type ComponentProps, type ReactNode, type Ref } from "react";
2
+ import { AdwNavigationPage as RawAdwNavigationPage, AdwNavigationView as RawAdwNavigationView, type Adw } from "../gtkx/bridge/index";
3
+ type AdwPageProps = ComponentProps<typeof RawAdwNavigationPage>;
4
+ export type NavigationStackPageProps = AdwPageProps & {
5
+ /** Stable identity of this page inside the view. Required: the whole sync
6
+ * protocol is expressed in tags, and Adwaita itself pushes and pops by
7
+ * tag. Use the same string you put in NavigationView's `stack`. */
8
+ tag: string;
9
+ };
10
+ /**
11
+ * One page of an {@link NavigationStack}.
12
+ *
13
+ * Children are passed to the widget untouched. To put React Native content
14
+ * inside a page, wrap it in `SlotContent` (see ./content) — the primitive
15
+ * deliberately does not guess, so raw GTK children keep working.
16
+ */
17
+ export declare const NavigationStackPage: ({ tag, onHidden, onShown, ...rest }: NavigationStackPageProps) => React.JSX.Element;
18
+ type AdwViewProps = ComponentProps<typeof RawAdwNavigationView>;
19
+ export type NavigationStackProps = Omit<AdwViewProps, "onPopped" | "ref"> & {
20
+ /**
21
+ * The visible stack, root first, as page tags. Change it and the widget
22
+ * animates to match: appended tags push, removed tags pop, a changed root
23
+ * replaces the whole stack.
24
+ */
25
+ stack: readonly string[];
26
+ /** `NavigationStackPage` elements. Pages not in `stack` are still accepted —
27
+ * they simply are not shown — so a router may render all of its screens. */
28
+ children?: ReactNode;
29
+ /**
30
+ * Whether push/pop/replace transitions animate at all, forwarded straight
31
+ * to `Adw.NavigationView`'s own `animate-transitions` property (already
32
+ * reachable through this component's inherited `Adw.NavigationView` props —
33
+ * spelled out here because it is the one prop consumers most often go
34
+ * looking for). GTK has exactly one transition style; there is no per-style
35
+ * choice to make here, only whether it plays. Default true, matching the
36
+ * widget's own default. Interactive swipe-back gestures always animate
37
+ * regardless of this value — that is Adwaita's own behavior, not this
38
+ * primitive's.
39
+ */
40
+ animateTransitions?: boolean;
41
+ /**
42
+ * The widget popped a page by itself: the Adwaita back button, Escape, the
43
+ * back gesture, or the back-history menu. NOT called for pops you caused by
44
+ * changing `stack`. This is where a router follows the view.
45
+ */
46
+ onPopped?: (tag: string) => void;
47
+ /** A closing page finished animating out and was dropped from the tree. */
48
+ onPageClosed?: (tag: string) => void;
49
+ /** A push/pop/replace transition started. */
50
+ onTransitionStart?: () => void;
51
+ /** …and finished. Driven by the transitioning page's own real
52
+ * `shown`/`hidden` AdwNavigationPage signal (whichever settles it —
53
+ * see beginTransition), with `transitionDuration` as a fallback for the
54
+ * cases where neither arrives. */
55
+ onTransitionEnd?: () => void;
56
+ /** Fallback window in ms, used only when a page's own transition signal
57
+ * never arrives (see the file header comment for the two cases this
58
+ * covers) — for page retention and for the transition callbacks above.
59
+ * NOT a measurement of the real transition length. Default 400. */
60
+ transitionDuration?: number;
61
+ /** Escape hatch: the underlying Adw.NavigationView, for anything this
62
+ * primitive does not model. */
63
+ ref?: Ref<Adw.NavigationView | null>;
64
+ };
65
+ /**
66
+ * `Adw.NavigationView` driven declaratively.
67
+ *
68
+ * ```tsx
69
+ * const [stack, setStack] = useState(["home"])
70
+ *
71
+ * <NavigationStack
72
+ * stack={stack}
73
+ * onPopped={(tag) => setStack((s) => s.filter((t) => t !== tag))}
74
+ * >
75
+ * <NavigationStackPage tag="home" title="Home">…</NavigationStackPage>
76
+ * <NavigationStackPage tag="detail" title="Detail">…</NavigationStackPage>
77
+ * </NavigationStack>
78
+ * ```
79
+ *
80
+ * No router required. `react-native-gtkx/navigation` uses exactly this
81
+ * component to back `createStackNavigator`.
82
+ */
83
+ export declare const NavigationStack: ({ stack, children, onPopped, onPageClosed, onTransitionStart, onTransitionEnd, transitionDuration, ref, ...rest }: NavigationStackProps) => React.JSX.Element;
84
+ export {};
@@ -0,0 +1,313 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ // react-native-gtkx/adwaita — Adw.NavigationView as a declarative primitive.
3
+ //
4
+ // This layer knows NOTHING about react-navigation. You hand it the ordered
5
+ // stack of page tags you want visible, it animates the widget to that stack
6
+ // and tells you when the WIDGET popped on its own (back button, Escape, the
7
+ // back gesture). Bring react-navigation, bring your own router, or drive it
8
+ // from useState — the primitive does not care.
9
+ //
10
+ // react-native-gtkx/navigation is a thin adapter on top of this file, the
11
+ // same way @react-navigation/native-stack sits on top of react-native-screens.
12
+ //
13
+ // Why the primitive owns retention: react-navigation (and any router) drops a
14
+ // popped route immediately, while Adwaita still animates the page out. If the
15
+ // consumer had to keep rendering pages it already considers gone, every
16
+ // consumer would reimplement that bookkeeping and the primitive would be
17
+ // useless without a router. So NavigationView snapshots a page when it
18
+ // leaves `stack` and drops it on the page's "hidden" signal — the real
19
+ // AdwNavigationPage signal, not a guess — with `transitionDuration` as a
20
+ // fallback timer for two cases where the signal never arrives on its own:
21
+ // environments that never deliver it at all (headless compositors with
22
+ // animations disabled), and a page skipped entirely by a multi-hop pop
23
+ // (measured on the rig: `popToTag` from [a,b,c] to "a" fires hiding/hidden
24
+ // only on "c", the page that was actually visible — "b" gets no signal at
25
+ // all, on any environment, because it was never itself on screen during the
26
+ // transition). onTransitionStart/onTransitionEnd and the InteractionManager
27
+ // bracket around them use the exact same real-signal-first, timer-fallback
28
+ // mechanism — see beginTransition below.
29
+ import { Children, createContext, isValidElement, useCallback, useContext, useEffect, useInsertionEffect, useRef, useState, } from "react";
30
+ import { InteractionManager } from "../apis/interaction-manager";
31
+ import { AdwNavigationPage as RawAdwNavigationPage, AdwNavigationView as RawAdwNavigationView, } from "../gtkx/bridge/index";
32
+ /** A conservative fallback window for the two cases described above, where
33
+ * no real per-page signal ever arrives for this specific transition. This
34
+ * is NOT a measurement of Adwaita's actual transition length — an earlier
35
+ * version of this comment claimed "~200 ms measured", which was never
36
+ * actually measured (found while auditing this file). On the project's own
37
+ * headless GTK test rig the real signal always arrives, and in well under
38
+ * a millisecond, so there is no rig measurement to cite either; this
39
+ * number is simply a deliberately generous upper bound. Overridable
40
+ * because a consumer may want a shorter/longer safety margin. */
41
+ const DEFAULT_TRANSITION_MS = 400;
42
+ const PageLifecycleContext = createContext(null);
43
+ /**
44
+ * One page of an {@link NavigationStack}.
45
+ *
46
+ * Children are passed to the widget untouched. To put React Native content
47
+ * inside a page, wrap it in `SlotContent` (see ./content) — the primitive
48
+ * deliberately does not guess, so raw GTK children keep working.
49
+ */
50
+ export const NavigationStackPage = ({ tag, onHidden, onShown, ...rest }) => {
51
+ const lifecycle = useContext(PageLifecycleContext);
52
+ const handleHidden = ((...args) => {
53
+ lifecycle?.reportHidden(tag);
54
+ onHidden?.(...args);
55
+ });
56
+ const handleShown = ((...args) => {
57
+ lifecycle?.reportShown(tag);
58
+ onShown?.(...args);
59
+ });
60
+ return (_jsx(RawAdwNavigationPage, { ...rest, tag: tag, onHidden: handleHidden, onShown: handleShown }));
61
+ };
62
+ /**
63
+ * `Adw.NavigationView` driven declaratively.
64
+ *
65
+ * ```tsx
66
+ * const [stack, setStack] = useState(["home"])
67
+ *
68
+ * <NavigationStack
69
+ * stack={stack}
70
+ * onPopped={(tag) => setStack((s) => s.filter((t) => t !== tag))}
71
+ * >
72
+ * <NavigationStackPage tag="home" title="Home">…</NavigationStackPage>
73
+ * <NavigationStackPage tag="detail" title="Detail">…</NavigationStackPage>
74
+ * </NavigationStack>
75
+ * ```
76
+ *
77
+ * No router required. `react-native-gtkx/navigation` uses exactly this
78
+ * component to back `createStackNavigator`.
79
+ */
80
+ export const NavigationStack = ({ stack, children, onPopped, onPageClosed, onTransitionStart, onTransitionEnd, transitionDuration = DEFAULT_TRANSITION_MS, ref, ...rest }) => {
81
+ const viewRef = useRef(null);
82
+ // Mirror of the widget's visible stack. Maintained by the sync effect and
83
+ // by the popped handler; the two never race, because GTK signals run
84
+ // synchronously inside the very push/pop calls the effect makes.
85
+ const syncedRef = useRef([]);
86
+ const pagesByTag = new Map();
87
+ for (const child of Children.toArray(children)) {
88
+ if (isValidElement(child)) {
89
+ const tag = child.props.tag;
90
+ if (typeof tag === "string") {
91
+ pagesByTag.set(tag, child);
92
+ }
93
+ }
94
+ }
95
+ // Pages currently in the tree: everything in `stack`, plus pages that left
96
+ // it and are still animating out.
97
+ const [renderedTags, setRenderedTags] = useState(() => [...stack]);
98
+ const missing = stack.filter((tag) => !renderedTags.includes(tag));
99
+ if (missing.length > 0) {
100
+ // The sanctioned derive-state-during-render pattern: a new page must be
101
+ // in the tree within the same commit the sync effect pushes it.
102
+ setRenderedTags([...renderedTags, ...missing]);
103
+ }
104
+ // A state-held stable Map rather than a ref: the render path reads it for
105
+ // closing pages, and reading a ref during render is rightly banned.
106
+ const [snapshots] = useState(() => new Map());
107
+ useEffect(() => {
108
+ for (const [tag, element] of pagesByTag) {
109
+ snapshots.set(tag, element);
110
+ }
111
+ });
112
+ const dropPage = useCallback((tag) => {
113
+ let dropped = false;
114
+ setRenderedTags((tags) => {
115
+ if (!tags.includes(tag)) {
116
+ return tags;
117
+ }
118
+ dropped = true;
119
+ return tags.filter((rendered) => rendered !== tag);
120
+ });
121
+ if (dropped) {
122
+ snapshots.delete(tag);
123
+ onPageClosed?.(tag);
124
+ }
125
+ }, [onPageClosed, snapshots]);
126
+ // Signal handlers read the CURRENT requested stack, not the one captured
127
+ // when they were created. Refreshed in an insertion effect (the project's
128
+ // standard escape from writing refs during render): insertion effects run
129
+ // before layout effects, so the value is fresh by the time GTK can emit.
130
+ const stackRef = useRef(stack);
131
+ useInsertionEffect(() => {
132
+ stackRef.current = stack;
133
+ });
134
+ // Per-tag waiters for "this specific page's transition settled" — fed by
135
+ // reportHidden/reportShown below, drained (and deleted) the moment either
136
+ // fires. A page can end up "shown" after being "hiding" (an interrupted
137
+ // pop reversed) or "hidden" after being "showing" (an interrupted push
138
+ // superseded) — GObject-introspection documents both pairings — so a
139
+ // waiter for a given tag resolves on WHICHEVER of the two settles it,
140
+ // not just the one that would be expected in the common case.
141
+ const transitionWaitersRef = useRef(new Map());
142
+ const addTransitionWaiter = useCallback((tag, resolve) => {
143
+ const waiters = transitionWaitersRef.current.get(tag);
144
+ if (waiters) {
145
+ waiters.push(resolve);
146
+ }
147
+ else {
148
+ transitionWaitersRef.current.set(tag, [resolve]);
149
+ }
150
+ }, []);
151
+ const removeTransitionWaiter = useCallback((tag, resolve) => {
152
+ const waiters = transitionWaitersRef.current.get(tag);
153
+ if (!waiters) {
154
+ return;
155
+ }
156
+ const next = waiters.filter((waiter) => waiter !== resolve);
157
+ if (next.length > 0) {
158
+ transitionWaitersRef.current.set(tag, next);
159
+ }
160
+ else {
161
+ transitionWaitersRef.current.delete(tag);
162
+ }
163
+ }, []);
164
+ const resolveTransitionWaiters = useCallback((tag) => {
165
+ const waiters = transitionWaitersRef.current.get(tag);
166
+ if (!waiters) {
167
+ return;
168
+ }
169
+ transitionWaitersRef.current.delete(tag);
170
+ for (const resolve of waiters) {
171
+ resolve();
172
+ }
173
+ }, []);
174
+ const reportHidden = useCallback((tag) => {
175
+ resolveTransitionWaiters(tag);
176
+ // "hidden" also fires for a live page covered by a push — only pages
177
+ // gone from the requested stack are actually closing.
178
+ if (stackRef.current.includes(tag)) {
179
+ return;
180
+ }
181
+ dropPage(tag);
182
+ }, [dropPage, resolveTransitionWaiters]);
183
+ const reportShown = useCallback((tag) => {
184
+ resolveTransitionWaiters(tag);
185
+ }, [resolveTransitionWaiters]);
186
+ // Delivery of "hidden" is not guaranteed — see the file header comment for
187
+ // the two cases (a genuinely signal-less environment, and a page skipped
188
+ // over by a multi-hop pop) — so a timer slightly longer than the fallback
189
+ // window is the backstop. dropPage is idempotent: whichever wins, wins.
190
+ const scheduleDrop = useCallback((tag) => {
191
+ setTimeout(() => reportHidden(tag), transitionDuration);
192
+ }, [reportHidden, transitionDuration]);
193
+ // Bracket every transition with an InteractionManager handle so
194
+ // runAfterInteractions work (a screen's data load, a heavy render) waits
195
+ // for the slide instead of stealing its frames, closing it and firing
196
+ // onTransitionEnd exactly when the transition really settles: the real
197
+ // "shown"/"hidden" signal on `targetTag` (the page this specific push,
198
+ // popToTag or replaceWithTags call is bringing into view) if it arrives,
199
+ // `transitionDuration` otherwise. `targetTag` is undefined only for
200
+ // replaceWithTags([]) — no page becomes visible, nothing to wait on, the
201
+ // timer alone settles it. Overlapping transitions reference-count through
202
+ // the handle API.
203
+ const beginTransition = useCallback((targetTag) => {
204
+ const handle = InteractionManager.createInteractionHandle();
205
+ onTransitionStart?.();
206
+ let settled = false;
207
+ const settle = () => {
208
+ if (settled) {
209
+ return;
210
+ }
211
+ settled = true;
212
+ InteractionManager.clearInteractionHandle(handle);
213
+ onTransitionEnd?.();
214
+ };
215
+ if (targetTag !== undefined) {
216
+ addTransitionWaiter(targetTag, settle);
217
+ }
218
+ setTimeout(() => {
219
+ if (targetTag !== undefined) {
220
+ removeTransitionWaiter(targetTag, settle);
221
+ }
222
+ settle();
223
+ }, transitionDuration);
224
+ }, [
225
+ addTransitionWaiter,
226
+ removeTransitionWaiter,
227
+ onTransitionEnd,
228
+ onTransitionStart,
229
+ transitionDuration,
230
+ ]);
231
+ useEffect(() => {
232
+ const view = viewRef.current;
233
+ if (!view) {
234
+ return;
235
+ }
236
+ const target = [...stack];
237
+ if (syncedRef.current.length === 0 && target.length > 0) {
238
+ // First mount: NavigationView shows the first added page by itself.
239
+ syncedRef.current = target.slice(0, 1);
240
+ }
241
+ let common = 0;
242
+ while (common < syncedRef.current.length &&
243
+ common < target.length &&
244
+ syncedRef.current[common] === target[common]) {
245
+ common += 1;
246
+ }
247
+ if (common === 0 && syncedRef.current[0] !== target[0]) {
248
+ // The root changed (a reset): swap the whole visible stack. The last
249
+ // tag becomes the visible page (undefined only when target is empty —
250
+ // see beginTransition's targetTag doc above).
251
+ const leaving = syncedRef.current.filter((tag) => !target.includes(tag));
252
+ syncedRef.current = [...target];
253
+ beginTransition(target[target.length - 1]);
254
+ view.replaceWithTags(target);
255
+ for (const tag of leaving) {
256
+ scheduleDrop(tag);
257
+ }
258
+ return;
259
+ }
260
+ if (syncedRef.current.length > common) {
261
+ const anchor = target[common - 1];
262
+ const leaving = syncedRef.current.slice(common);
263
+ syncedRef.current = syncedRef.current.slice(0, common);
264
+ if (anchor !== undefined) {
265
+ beginTransition(anchor);
266
+ view.popToTag(anchor);
267
+ }
268
+ for (const tag of leaving) {
269
+ scheduleDrop(tag);
270
+ }
271
+ }
272
+ for (let index = syncedRef.current.length; index < target.length; index += 1) {
273
+ const tag = target[index];
274
+ syncedRef.current.push(tag);
275
+ beginTransition(tag);
276
+ view.pushByTag(tag);
277
+ }
278
+ }, [stack, scheduleDrop, beginTransition]);
279
+ const handlePopped = (page) => {
280
+ const tag = page?.getTag();
281
+ if (!tag) {
282
+ return;
283
+ }
284
+ syncedRef.current = syncedRef.current.filter((synced) => synced !== tag);
285
+ // Reported unconditionally: the consumer decides whether this pop was
286
+ // one it already knows about. The primitive has no router state to
287
+ // consult, and guessing here is exactly what would couple the layers.
288
+ onPopped?.(tag);
289
+ scheduleDrop(tag);
290
+ };
291
+ // The context value must be identity-stable (every page reads it), so the
292
+ // live handlers are reached through refs rather than baked into the value.
293
+ const reportHiddenRef = useRef(reportHidden);
294
+ const reportShownRef = useRef(reportShown);
295
+ useInsertionEffect(() => {
296
+ reportHiddenRef.current = reportHidden;
297
+ reportShownRef.current = reportShown;
298
+ });
299
+ const [lifecycle] = useState(() => ({
300
+ reportHidden: (tag) => reportHiddenRef.current(tag),
301
+ reportShown: (tag) => reportShownRef.current(tag),
302
+ }));
303
+ return (_jsx(PageLifecycleContext.Provider, { value: lifecycle, children: _jsx(RawAdwNavigationView, { ...rest, ref: (instance) => {
304
+ viewRef.current = instance;
305
+ if (typeof ref === "function") {
306
+ ref(instance);
307
+ }
308
+ else if (ref) {
309
+ ref.current = instance;
310
+ }
311
+ }, onPopped: (page) => handlePopped(page), children: renderedTags.map((tag) => pagesByTag.get(tag) ?? snapshots.get(tag) ?? null) }) }));
312
+ };
313
+ //# sourceMappingURL=navigation-stack.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"navigation-stack.js","sourceRoot":"","sources":["../../src/common/navigation-stack.tsx"],"names":[],"mappings":"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","sourcesContent":["// react-native-gtkx/adwaita — Adw.NavigationView as a declarative primitive.\n//\n// This layer knows NOTHING about react-navigation. You hand it the ordered\n// stack of page tags you want visible, it animates the widget to that stack\n// and tells you when the WIDGET popped on its own (back button, Escape, the\n// back gesture). Bring react-navigation, bring your own router, or drive it\n// from useState — the primitive does not care.\n//\n// react-native-gtkx/navigation is a thin adapter on top of this file, the\n// same way @react-navigation/native-stack sits on top of react-native-screens.\n//\n// Why the primitive owns retention: react-navigation (and any router) drops a\n// popped route immediately, while Adwaita still animates the page out. If the\n// consumer had to keep rendering pages it already considers gone, every\n// consumer would reimplement that bookkeeping and the primitive would be\n// useless without a router. So NavigationView snapshots a page when it\n// leaves `stack` and drops it on the page's \"hidden\" signal — the real\n// AdwNavigationPage signal, not a guess — with `transitionDuration` as a\n// fallback timer for two cases where the signal never arrives on its own:\n// environments that never deliver it at all (headless compositors with\n// animations disabled), and a page skipped entirely by a multi-hop pop\n// (measured on the rig: `popToTag` from [a,b,c] to \"a\" fires hiding/hidden\n// only on \"c\", the page that was actually visible — \"b\" gets no signal at\n// all, on any environment, because it was never itself on screen during the\n// transition). onTransitionStart/onTransitionEnd and the InteractionManager\n// bracket around them use the exact same real-signal-first, timer-fallback\n// mechanism — see beginTransition below.\nimport {\n Children,\n createContext,\n isValidElement,\n useCallback,\n useContext,\n useEffect,\n useInsertionEffect,\n useRef,\n useState,\n type ComponentProps,\n type ReactNode,\n type Ref,\n} from \"react\"\nimport { InteractionManager } from \"../apis/interaction-manager\"\nimport {\n AdwNavigationPage as RawAdwNavigationPage,\n AdwNavigationView as RawAdwNavigationView,\n type Adw,\n} from \"../gtkx/bridge/index\"\n\n/** A conservative fallback window for the two cases described above, where\n * no real per-page signal ever arrives for this specific transition. This\n * is NOT a measurement of Adwaita's actual transition length — an earlier\n * version of this comment claimed \"~200 ms measured\", which was never\n * actually measured (found while auditing this file). On the project's own\n * headless GTK test rig the real signal always arrives, and in well under\n * a millisecond, so there is no rig measurement to cite either; this\n * number is simply a deliberately generous upper bound. Overridable\n * because a consumer may want a shorter/longer safety margin. */\nconst DEFAULT_TRANSITION_MS = 400\n\ntype PageLifecycle = {\n reportHidden: (tag: string) => void\n reportShown: (tag: string) => void\n}\n\nconst PageLifecycleContext = createContext<PageLifecycle | null>(null)\n\n// Every prop Adw.NavigationPage exposes flows through untouched, so anything\n// gtkx binds today (and anything it binds tomorrow) is reachable without a\n// change here. Only `onHidden` is intercepted, and it is still forwarded.\ntype AdwPageProps = ComponentProps<typeof RawAdwNavigationPage>\n\nexport type NavigationStackPageProps = AdwPageProps & {\n /** Stable identity of this page inside the view. Required: the whole sync\n * protocol is expressed in tags, and Adwaita itself pushes and pops by\n * tag. Use the same string you put in NavigationView's `stack`. */\n tag: string\n}\n\n/**\n * One page of an {@link NavigationStack}.\n *\n * Children are passed to the widget untouched. To put React Native content\n * inside a page, wrap it in `SlotContent` (see ./content) — the primitive\n * deliberately does not guess, so raw GTK children keep working.\n */\nexport const NavigationStackPage = ({\n tag,\n onHidden,\n onShown,\n ...rest\n}: NavigationStackPageProps) => {\n const lifecycle = useContext(PageLifecycleContext)\n const handleHidden = ((...args: unknown[]) => {\n lifecycle?.reportHidden(tag)\n // The consumer's own handler still runs, and runs second: retention\n // bookkeeping must not depend on what the consumer does here.\n ;(onHidden as ((...a: unknown[]) => void) | undefined)?.(...args)\n }) as AdwPageProps[\"onHidden\"]\n const handleShown = ((...args: unknown[]) => {\n lifecycle?.reportShown(tag)\n // Same ordering guarantee as onHidden above.\n ;(onShown as ((...a: unknown[]) => void) | undefined)?.(...args)\n }) as AdwPageProps[\"onShown\"]\n return (\n <RawAdwNavigationPage\n {...rest}\n tag={tag}\n onHidden={handleHidden}\n onShown={handleShown}\n />\n )\n}\n\ntype AdwViewProps = ComponentProps<typeof RawAdwNavigationView>\n\nexport type NavigationStackProps = Omit<AdwViewProps, \"onPopped\" | \"ref\"> & {\n /**\n * The visible stack, root first, as page tags. Change it and the widget\n * animates to match: appended tags push, removed tags pop, a changed root\n * replaces the whole stack.\n */\n stack: readonly string[]\n /** `NavigationStackPage` elements. Pages not in `stack` are still accepted —\n * they simply are not shown — so a router may render all of its screens. */\n children?: ReactNode\n /**\n * Whether push/pop/replace transitions animate at all, forwarded straight\n * to `Adw.NavigationView`'s own `animate-transitions` property (already\n * reachable through this component's inherited `Adw.NavigationView` props —\n * spelled out here because it is the one prop consumers most often go\n * looking for). GTK has exactly one transition style; there is no per-style\n * choice to make here, only whether it plays. Default true, matching the\n * widget's own default. Interactive swipe-back gestures always animate\n * regardless of this value — that is Adwaita's own behavior, not this\n * primitive's.\n */\n animateTransitions?: boolean\n /**\n * The widget popped a page by itself: the Adwaita back button, Escape, the\n * back gesture, or the back-history menu. NOT called for pops you caused by\n * changing `stack`. This is where a router follows the view.\n */\n onPopped?: (tag: string) => void\n /** A closing page finished animating out and was dropped from the tree. */\n onPageClosed?: (tag: string) => void\n /** A push/pop/replace transition started. */\n onTransitionStart?: () => void\n /** …and finished. Driven by the transitioning page's own real\n * `shown`/`hidden` AdwNavigationPage signal (whichever settles it —\n * see beginTransition), with `transitionDuration` as a fallback for the\n * cases where neither arrives. */\n onTransitionEnd?: () => void\n /** Fallback window in ms, used only when a page's own transition signal\n * never arrives (see the file header comment for the two cases this\n * covers) — for page retention and for the transition callbacks above.\n * NOT a measurement of the real transition length. Default 400. */\n transitionDuration?: number\n /** Escape hatch: the underlying Adw.NavigationView, for anything this\n * primitive does not model. */\n ref?: Ref<Adw.NavigationView | null>\n}\n\n/**\n * `Adw.NavigationView` driven declaratively.\n *\n * ```tsx\n * const [stack, setStack] = useState([\"home\"])\n *\n * <NavigationStack\n * stack={stack}\n * onPopped={(tag) => setStack((s) => s.filter((t) => t !== tag))}\n * >\n * <NavigationStackPage tag=\"home\" title=\"Home\">…</NavigationStackPage>\n * <NavigationStackPage tag=\"detail\" title=\"Detail\">…</NavigationStackPage>\n * </NavigationStack>\n * ```\n *\n * No router required. `react-native-gtkx/navigation` uses exactly this\n * component to back `createStackNavigator`.\n */\nexport const NavigationStack = ({\n stack,\n children,\n onPopped,\n onPageClosed,\n onTransitionStart,\n onTransitionEnd,\n transitionDuration = DEFAULT_TRANSITION_MS,\n ref,\n ...rest\n}: NavigationStackProps) => {\n const viewRef = useRef<Adw.NavigationView | null>(null)\n // Mirror of the widget's visible stack. Maintained by the sync effect and\n // by the popped handler; the two never race, because GTK signals run\n // synchronously inside the very push/pop calls the effect makes.\n const syncedRef = useRef<string[]>([])\n\n const pagesByTag = new Map<string, ReactNode>()\n for (const child of Children.toArray(children)) {\n if (isValidElement<{ tag?: unknown }>(child)) {\n const tag = child.props.tag\n if (typeof tag === \"string\") {\n pagesByTag.set(tag, child)\n }\n }\n }\n\n // Pages currently in the tree: everything in `stack`, plus pages that left\n // it and are still animating out.\n const [renderedTags, setRenderedTags] = useState<string[]>(() => [...stack])\n const missing = stack.filter((tag) => !renderedTags.includes(tag))\n if (missing.length > 0) {\n // The sanctioned derive-state-during-render pattern: a new page must be\n // in the tree within the same commit the sync effect pushes it.\n setRenderedTags([...renderedTags, ...missing])\n }\n\n // A state-held stable Map rather than a ref: the render path reads it for\n // closing pages, and reading a ref during render is rightly banned.\n const [snapshots] = useState(() => new Map<string, ReactNode>())\n useEffect(() => {\n for (const [tag, element] of pagesByTag) {\n snapshots.set(tag, element)\n }\n })\n\n const dropPage = useCallback(\n (tag: string): void => {\n let dropped = false\n setRenderedTags((tags) => {\n if (!tags.includes(tag)) {\n return tags\n }\n dropped = true\n return tags.filter((rendered) => rendered !== tag)\n })\n if (dropped) {\n snapshots.delete(tag)\n onPageClosed?.(tag)\n }\n },\n [onPageClosed, snapshots],\n )\n\n // Signal handlers read the CURRENT requested stack, not the one captured\n // when they were created. Refreshed in an insertion effect (the project's\n // standard escape from writing refs during render): insertion effects run\n // before layout effects, so the value is fresh by the time GTK can emit.\n const stackRef = useRef<readonly string[]>(stack)\n useInsertionEffect(() => {\n stackRef.current = stack\n })\n\n // Per-tag waiters for \"this specific page's transition settled\" — fed by\n // reportHidden/reportShown below, drained (and deleted) the moment either\n // fires. A page can end up \"shown\" after being \"hiding\" (an interrupted\n // pop reversed) or \"hidden\" after being \"showing\" (an interrupted push\n // superseded) — GObject-introspection documents both pairings — so a\n // waiter for a given tag resolves on WHICHEVER of the two settles it,\n // not just the one that would be expected in the common case.\n const transitionWaitersRef = useRef<Map<string, Array<() => void>>>(new Map())\n\n const addTransitionWaiter = useCallback(\n (tag: string, resolve: () => void): void => {\n const waiters = transitionWaitersRef.current.get(tag)\n if (waiters) {\n waiters.push(resolve)\n } else {\n transitionWaitersRef.current.set(tag, [resolve])\n }\n },\n [],\n )\n\n const removeTransitionWaiter = useCallback(\n (tag: string, resolve: () => void): void => {\n const waiters = transitionWaitersRef.current.get(tag)\n if (!waiters) {\n return\n }\n const next = waiters.filter((waiter) => waiter !== resolve)\n if (next.length > 0) {\n transitionWaitersRef.current.set(tag, next)\n } else {\n transitionWaitersRef.current.delete(tag)\n }\n },\n [],\n )\n\n const resolveTransitionWaiters = useCallback((tag: string): void => {\n const waiters = transitionWaitersRef.current.get(tag)\n if (!waiters) {\n return\n }\n transitionWaitersRef.current.delete(tag)\n for (const resolve of waiters) {\n resolve()\n }\n }, [])\n\n const reportHidden = useCallback(\n (tag: string): void => {\n resolveTransitionWaiters(tag)\n // \"hidden\" also fires for a live page covered by a push — only pages\n // gone from the requested stack are actually closing.\n if (stackRef.current.includes(tag)) {\n return\n }\n dropPage(tag)\n },\n [dropPage, resolveTransitionWaiters],\n )\n\n const reportShown = useCallback(\n (tag: string): void => {\n resolveTransitionWaiters(tag)\n },\n [resolveTransitionWaiters],\n )\n\n // Delivery of \"hidden\" is not guaranteed — see the file header comment for\n // the two cases (a genuinely signal-less environment, and a page skipped\n // over by a multi-hop pop) — so a timer slightly longer than the fallback\n // window is the backstop. dropPage is idempotent: whichever wins, wins.\n const scheduleDrop = useCallback(\n (tag: string): void => {\n setTimeout(() => reportHidden(tag), transitionDuration)\n },\n [reportHidden, transitionDuration],\n )\n\n // Bracket every transition with an InteractionManager handle so\n // runAfterInteractions work (a screen's data load, a heavy render) waits\n // for the slide instead of stealing its frames, closing it and firing\n // onTransitionEnd exactly when the transition really settles: the real\n // \"shown\"/\"hidden\" signal on `targetTag` (the page this specific push,\n // popToTag or replaceWithTags call is bringing into view) if it arrives,\n // `transitionDuration` otherwise. `targetTag` is undefined only for\n // replaceWithTags([]) — no page becomes visible, nothing to wait on, the\n // timer alone settles it. Overlapping transitions reference-count through\n // the handle API.\n const beginTransition = useCallback(\n (targetTag: string | undefined): void => {\n const handle = InteractionManager.createInteractionHandle()\n onTransitionStart?.()\n let settled = false\n const settle = (): void => {\n if (settled) {\n return\n }\n settled = true\n InteractionManager.clearInteractionHandle(handle)\n onTransitionEnd?.()\n }\n if (targetTag !== undefined) {\n addTransitionWaiter(targetTag, settle)\n }\n setTimeout(() => {\n if (targetTag !== undefined) {\n removeTransitionWaiter(targetTag, settle)\n }\n settle()\n }, transitionDuration)\n },\n [\n addTransitionWaiter,\n removeTransitionWaiter,\n onTransitionEnd,\n onTransitionStart,\n transitionDuration,\n ],\n )\n\n useEffect(() => {\n const view = viewRef.current\n if (!view) {\n return\n }\n const target = [...stack]\n if (syncedRef.current.length === 0 && target.length > 0) {\n // First mount: NavigationView shows the first added page by itself.\n syncedRef.current = target.slice(0, 1)\n }\n let common = 0\n while (\n common < syncedRef.current.length &&\n common < target.length &&\n syncedRef.current[common] === target[common]\n ) {\n common += 1\n }\n if (common === 0 && syncedRef.current[0] !== target[0]) {\n // The root changed (a reset): swap the whole visible stack. The last\n // tag becomes the visible page (undefined only when target is empty —\n // see beginTransition's targetTag doc above).\n const leaving = syncedRef.current.filter((tag) => !target.includes(tag))\n syncedRef.current = [...target]\n beginTransition(target[target.length - 1])\n view.replaceWithTags(target)\n for (const tag of leaving) {\n scheduleDrop(tag)\n }\n return\n }\n if (syncedRef.current.length > common) {\n const anchor = target[common - 1]\n const leaving = syncedRef.current.slice(common)\n syncedRef.current = syncedRef.current.slice(0, common)\n if (anchor !== undefined) {\n beginTransition(anchor)\n view.popToTag(anchor)\n }\n for (const tag of leaving) {\n scheduleDrop(tag)\n }\n }\n for (\n let index = syncedRef.current.length;\n index < target.length;\n index += 1\n ) {\n const tag = target[index]!\n syncedRef.current.push(tag)\n beginTransition(tag)\n view.pushByTag(tag)\n }\n }, [stack, scheduleDrop, beginTransition])\n\n const handlePopped = (page: Adw.NavigationPage | null): void => {\n const tag = page?.getTag()\n if (!tag) {\n return\n }\n syncedRef.current = syncedRef.current.filter((synced) => synced !== tag)\n // Reported unconditionally: the consumer decides whether this pop was\n // one it already knows about. The primitive has no router state to\n // consult, and guessing here is exactly what would couple the layers.\n onPopped?.(tag)\n scheduleDrop(tag)\n }\n\n // The context value must be identity-stable (every page reads it), so the\n // live handlers are reached through refs rather than baked into the value.\n const reportHiddenRef = useRef<(tag: string) => void>(reportHidden)\n const reportShownRef = useRef<(tag: string) => void>(reportShown)\n useInsertionEffect(() => {\n reportHiddenRef.current = reportHidden\n reportShownRef.current = reportShown\n })\n const [lifecycle] = useState<PageLifecycle>(() => ({\n reportHidden: (tag: string) => reportHiddenRef.current(tag),\n reportShown: (tag: string) => reportShownRef.current(tag),\n }))\n\n return (\n <PageLifecycleContext.Provider value={lifecycle}>\n <RawAdwNavigationView\n {...rest}\n ref={(instance: Adw.NavigationView | null) => {\n viewRef.current = instance\n if (typeof ref === \"function\") {\n ref(instance)\n } else if (ref) {\n ref.current = instance\n }\n }}\n onPopped={(page: Adw.NavigationPage | null) => handlePopped(page)}\n >\n {renderedTags.map(\n (tag) => pagesByTag.get(tag) ?? snapshots.get(tag) ?? null,\n )}\n </RawAdwNavigationView>\n </PageLifecycleContext.Provider>\n )\n}\n"]}
@@ -0,0 +1,62 @@
1
+ import { type ComponentType, type ReactNode } from "react";
2
+ import { type LayoutEvent } from "../components/use-layout-child";
3
+ import type { StyleProp } from "../contracts";
4
+ import { type Gtk } from "../gtkx/bridge/index";
5
+ export type WidgetProps = {
6
+ /** React Native style. The layout half drives Yoga, the visual half becomes
7
+ * a GTK CSS class. Omit sizing and the widget's own natural size wins. */
8
+ style?: StyleProp;
9
+ onLayout?: (event: LayoutEvent) => void;
10
+ /** The GTK widget(s) to lay out. Your own `ref` on them is untouched. */
11
+ children: ReactNode;
12
+ testID?: string;
13
+ };
14
+ /**
15
+ * Put any GTK widget into React Native layout.
16
+ *
17
+ * ```tsx
18
+ * <View style={{ flexDirection: "row", gap: 8, padding: 12 }}>
19
+ * <Widget style={{ flex: 1 }}>
20
+ * <GtkEntry placeholderText="Search" />
21
+ * </Widget>
22
+ * <Widget>
23
+ * <GtkButton iconName="edit-find-symbolic" />
24
+ * </Widget>
25
+ * </View>
26
+ * ```
27
+ *
28
+ * The entry flexes, the button takes its natural size, both sit in the row
29
+ * exactly like React Native children — because to Yoga they now are.
30
+ *
31
+ * For the reverse direction (React Native content inside a GTK slot) see
32
+ * `SlotContent` and `IntrinsicContent`.
33
+ */
34
+ export declare const Widget: ({ style, onLayout, children, testID }: WidgetProps) => React.JSX.Element;
35
+ export type UseWidgetLayoutOptions = {
36
+ style?: StyleProp;
37
+ onLayout?: (event: LayoutEvent) => void;
38
+ };
39
+ /**
40
+ * The same thing as {@link Widget}, without the extra component — attach the
41
+ * ref yourself when you already hold one.
42
+ *
43
+ * ```tsx
44
+ * const ref = useRef<Gtk.Button | null>(null)
45
+ * useWidgetLayout(ref, { style: { width: 40, height: 40 } })
46
+ * return <GtkButton ref={ref} iconName="open-menu-symbolic" />
47
+ * ```
48
+ *
49
+ * Returns the GTK CSS class produced by the visual half of the style, or
50
+ * null — pass it to the widget's `cssClasses` if you want backgrounds and
51
+ * borders from the style to apply.
52
+ */
53
+ export declare const useWidgetLayout: (ref: {
54
+ current: Gtk.Widget | null;
55
+ }, options?: UseWidgetLayoutOptions) => string | null;
56
+ export type ReactNativeLayoutProps = {
57
+ /** React Native style. The layout half drives Yoga, the visual half becomes
58
+ * a GTK CSS class. Omit sizing and the widget's natural size wins. */
59
+ style?: StyleProp;
60
+ onLayout?: (event: LayoutEvent) => void;
61
+ };
62
+ export declare const wrapReactNative: <P extends object>(Component: ComponentType<P>, widgetName?: string) => ComponentType<P & ReactNativeLayoutProps>;