pythonnative 0.40.0__cp313-cp313-win_amd64.whl

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 (418) hide show
  1. pythonnative/__init__.py +411 -0
  2. pythonnative/_ios_log.py +92 -0
  3. pythonnative/_yoga.cp313-win_amd64.pyd +0 -0
  4. pythonnative/alerts.py +236 -0
  5. pythonnative/animated.py +1687 -0
  6. pythonnative/animation_graph.py +78 -0
  7. pythonnative/appearance.py +124 -0
  8. pythonnative/bootstrap.py +100 -0
  9. pythonnative/bridge/__init__.py +302 -0
  10. pythonnative/bridge/android.py +78 -0
  11. pythonnative/bridge/codec.py +170 -0
  12. pythonnative/bridge/commits.py +114 -0
  13. pythonnative/bridge/fake.py +243 -0
  14. pythonnative/bridge/ios.py +138 -0
  15. pythonnative/bridge/web.py +489 -0
  16. pythonnative/cli/__init__.py +7 -0
  17. pythonnative/cli/pn.py +1214 -0
  18. pythonnative/component.py +271 -0
  19. pythonnative/components/__init__.py +111 -0
  20. pythonnative/components/_base.py +166 -0
  21. pythonnative/components/controls.py +521 -0
  22. pythonnative/components/layout.py +518 -0
  23. pythonnative/components/lists.py +785 -0
  24. pythonnative/components/media.py +204 -0
  25. pythonnative/components/overlays.py +107 -0
  26. pythonnative/components/pressable.py +252 -0
  27. pythonnative/components/structural.py +167 -0
  28. pythonnative/components/text.py +291 -0
  29. pythonnative/devclient.py +824 -0
  30. pythonnative/devserver/__init__.py +34 -0
  31. pythonnative/devserver/server.py +718 -0
  32. pythonnative/devserver/static/animation_graph.js +82 -0
  33. pythonnative/devserver/static/bridge.js +147 -0
  34. pythonnative/devserver/static/colors.js +70 -0
  35. pythonnative/devserver/static/host.js +552 -0
  36. pythonnative/devserver/static/index.html +60 -0
  37. pythonnative/devserver/static/layout.js +85 -0
  38. pythonnative/devserver/static/preview.css +415 -0
  39. pythonnative/devserver/static/renderer.js +1994 -0
  40. pythonnative/devserver/static/shell.js +345 -0
  41. pythonnative/devserver/static/yoga/LICENSE +21 -0
  42. pythonnative/devserver/static/yoga/binaries/yoga-wasm-base64-esm.js +75 -0
  43. pythonnative/devserver/static/yoga/src/generated/YGEnums.d.ts +189 -0
  44. pythonnative/devserver/static/yoga/src/generated/YGEnums.js +211 -0
  45. pythonnative/devserver/static/yoga/src/generated/YGEnums.js.map +1 -0
  46. pythonnative/devserver/static/yoga/src/index.d.ts +12 -0
  47. pythonnative/devserver/static/yoga/src/index.js +16 -0
  48. pythonnative/devserver/static/yoga/src/index.js.map +1 -0
  49. pythonnative/devserver/static/yoga/src/load.d.ts +11 -0
  50. pythonnative/devserver/static/yoga/src/load.js +17 -0
  51. pythonnative/devserver/static/yoga/src/load.js.map +1 -0
  52. pythonnative/devserver/static/yoga/src/wrapAssembly.d.ts +155 -0
  53. pythonnative/devserver/static/yoga/src/wrapAssembly.js +125 -0
  54. pythonnative/devserver/static/yoga/src/wrapAssembly.js.map +1 -0
  55. pythonnative/devserver/watcher.py +267 -0
  56. pythonnative/devserver/ws.py +421 -0
  57. pythonnative/diagnostics.py +241 -0
  58. pythonnative/element.py +159 -0
  59. pythonnative/equality.py +19 -0
  60. pythonnative/events.py +231 -0
  61. pythonnative/gestures.py +1333 -0
  62. pythonnative/hooks.py +1621 -0
  63. pythonnative/hosts/__init__.py +63 -0
  64. pythonnative/hosts/base.py +596 -0
  65. pythonnative/hosts/native.py +302 -0
  66. pythonnative/hot_reload.py +585 -0
  67. pythonnative/layout.py +328 -0
  68. pythonnative/mutations.py +142 -0
  69. pythonnative/native/android/build.gradle +52 -0
  70. pythonnative/native/android/gradle.properties +3 -0
  71. pythonnative/native/android/settings.gradle +12 -0
  72. pythonnative/native/android/src/main/AndroidManifest.xml +11 -0
  73. pythonnative/native/android/src/main/cpp/CMakeLists.txt +9 -0
  74. pythonnative/native/android/src/main/cpp/yoga_jni.cpp +52 -0
  75. pythonnative/native/android/src/main/java/com/pythonnative/generated/NativeModules.kt +5 -0
  76. pythonnative/native/android/src/main/java/com/pythonnative/generated/NativeProps.kt +3705 -0
  77. pythonnative/native/android/src/main/java/com/pythonnative/generated/PNContracts.kt +129 -0
  78. pythonnative/native/android/src/main/java/com/pythonnative/runtime/PNBridge.kt +261 -0
  79. pythonnative/native/android/src/main/java/com/pythonnative/runtime/PythonHost.kt +20 -0
  80. pythonnative/native/android/src/main/java/com/pythonnative/runtime/animation/AnimationGraph.kt +108 -0
  81. pythonnative/native/android/src/main/java/com/pythonnative/runtime/animation/AnimationSpecs.kt +141 -0
  82. pythonnative/native/android/src/main/java/com/pythonnative/runtime/animation/PNAnimator.kt +257 -0
  83. pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/CommitState.kt +106 -0
  84. pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/JsonUtil.kt +175 -0
  85. pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/MainThread.kt +40 -0
  86. pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/PNLog.kt +33 -0
  87. pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/PNRegistry.kt +82 -0
  88. pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/PNTransaction.kt +80 -0
  89. pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/TransactionApplier.kt +117 -0
  90. pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/ViewRegistry.kt +74 -0
  91. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/BuiltinComponents.kt +37 -0
  92. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ButtonManager.kt +32 -0
  93. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ComponentManager.kt +213 -0
  94. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ContainerManagers.kt +69 -0
  95. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ControlManagers.kt +186 -0
  96. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/DatePickerManager.kt +123 -0
  97. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ImageLoader.kt +141 -0
  98. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ImageManager.kt +162 -0
  99. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ModalManager.kt +134 -0
  100. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/PNColor.kt +201 -0
  101. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/PickerManager.kt +86 -0
  102. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/PortalManager.kt +55 -0
  103. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/PressableManager.kt +122 -0
  104. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ScreenStackManager.kt +110 -0
  105. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ScrollViewManager.kt +214 -0
  106. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/SegmentedControlManager.kt +113 -0
  107. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/StatusBarManager.kt +52 -0
  108. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/TabBarManager.kt +131 -0
  109. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/TextInputManager.kt +250 -0
  110. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/TextManager.kt +233 -0
  111. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ViewStyler.kt +355 -0
  112. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/VirtualListManager.kt +159 -0
  113. pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/WebViewManager.kt +149 -0
  114. pythonnative/native/android/src/main/java/com/pythonnative/runtime/gestures/GestureArbiter.kt +233 -0
  115. pythonnative/native/android/src/main/java/com/pythonnative/runtime/gestures/GestureCoordinator.kt +127 -0
  116. pythonnative/native/android/src/main/java/com/pythonnative/runtime/gestures/GestureRecognizers.kt +527 -0
  117. pythonnative/native/android/src/main/java/com/pythonnative/runtime/layout/NativeLayout.kt +145 -0
  118. pythonnative/native/android/src/main/java/com/pythonnative/runtime/layout/YogaNode.kt +29 -0
  119. pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/BuiltinModules.kt +73 -0
  120. pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/DeviceModules.kt +316 -0
  121. pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/HostModule.kt +61 -0
  122. pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/MediaModules.kt +200 -0
  123. pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/NativeModule.kt +158 -0
  124. pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/NotificationsModule.kt +100 -0
  125. pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/PermissionsModule.kt +99 -0
  126. pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/StorageModules.kt +89 -0
  127. pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/SystemModules.kt +178 -0
  128. pythonnative/native/android/src/main/java/com/pythonnative/runtime/plugins/GeneratedPlugins.kt +16 -0
  129. pythonnative/native/android/src/main/java/com/pythonnative/runtime/screens/PNScreenFragment.kt +188 -0
  130. pythonnative/native/android/src/main/java/com/pythonnative/runtime/screens/ScreenRegistry.kt +80 -0
  131. pythonnative/native/android/src/main/java/com/pythonnative/runtime/views/PNAccessibilityDelegate.kt +48 -0
  132. pythonnative/native/android/src/main/java/com/pythonnative/runtime/views/PNBorderDrawable.kt +76 -0
  133. pythonnative/native/android/src/main/java/com/pythonnative/runtime/views/PNEditText.kt +18 -0
  134. pythonnative/native/android/src/main/java/com/pythonnative/runtime/views/PNFrameLayout.kt +49 -0
  135. pythonnative/native/android/src/test/java/com/pythonnative/runtime/AnimationSpecsTest.kt +75 -0
  136. pythonnative/native/android/src/test/java/com/pythonnative/runtime/GestureArbiterTest.kt +197 -0
  137. pythonnative/native/android/src/test/java/com/pythonnative/runtime/PNColorTest.kt +47 -0
  138. pythonnative/native/android/src/test/java/com/pythonnative/runtime/PNTransactionTest.kt +78 -0
  139. pythonnative/native/android/src/test/java/com/pythonnative/runtime/PromiseTest.kt +89 -0
  140. pythonnative/native/ios/Package.swift +23 -0
  141. pythonnative/native/ios/Sources/PythonNativeKit/Animation/PNAnimationGraph.swift +199 -0
  142. pythonnative/native/ios/Sources/PythonNativeKit/Animation/PNAnimator.swift +312 -0
  143. pythonnative/native/ios/Sources/PythonNativeKit/Bridge/PNBridge.swift +255 -0
  144. pythonnative/native/ios/Sources/PythonNativeKit/Bridge/PNCommit.swift +104 -0
  145. pythonnative/native/ios/Sources/PythonNativeKit/Bridge/PNRegistry.swift +142 -0
  146. pythonnative/native/ios/Sources/PythonNativeKit/Bridge/PNTransaction.swift +166 -0
  147. pythonnative/native/ios/Sources/PythonNativeKit/Bridge/PNViewRegistry.swift +53 -0
  148. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNButtonManagers.swift +207 -0
  149. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNColor.swift +173 -0
  150. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNComponentManager.swift +183 -0
  151. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNContainerView.swift +56 -0
  152. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNControlManagers.swift +281 -0
  153. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNImageManager.swift +222 -0
  154. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNOverlayManagers.swift +243 -0
  155. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNPressableManager.swift +114 -0
  156. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNScreenStackManager.swift +107 -0
  157. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNScrollViewManager.swift +197 -0
  158. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNTabBarManager.swift +106 -0
  159. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNTextInputManager.swift +297 -0
  160. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNTextManager.swift +230 -0
  161. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNTransform.swift +82 -0
  162. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNViewManager.swift +86 -0
  163. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNViewState.swift +87 -0
  164. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNViewStyler.swift +340 -0
  165. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNVirtualListManager.swift +155 -0
  166. pythonnative/native/ios/Sources/PythonNativeKit/Components/PNWebViewManager.swift +124 -0
  167. pythonnative/native/ios/Sources/PythonNativeKit/Generated/NativeModules.swift +1 -0
  168. pythonnative/native/ios/Sources/PythonNativeKit/Generated/NativeProps.swift +3775 -0
  169. pythonnative/native/ios/Sources/PythonNativeKit/Generated/PNContracts.swift +46 -0
  170. pythonnative/native/ios/Sources/PythonNativeKit/Gestures/PNGestureCoordinator.swift +260 -0
  171. pythonnative/native/ios/Sources/PythonNativeKit/Layout/PNLayout.swift +173 -0
  172. pythonnative/native/ios/Sources/PythonNativeKit/Modules/AlertModule.swift +92 -0
  173. pythonnative/native/ios/Sources/PythonNativeKit/Modules/HostModule.swift +80 -0
  174. pythonnative/native/ios/Sources/PythonNativeKit/Modules/LifecycleModules.swift +174 -0
  175. pythonnative/native/ios/Sources/PythonNativeKit/Modules/MediaModules.swift +177 -0
  176. pythonnative/native/ios/Sources/PythonNativeKit/Modules/PNNativeModule.swift +168 -0
  177. pythonnative/native/ios/Sources/PythonNativeKit/Modules/PermissionModules.swift +266 -0
  178. pythonnative/native/ios/Sources/PythonNativeKit/Modules/SystemModules.swift +251 -0
  179. pythonnative/native/ios/Sources/PythonNativeKit/Plugins/PNPluginRegistration.swift +8 -0
  180. pythonnative/native/ios/Sources/PythonNativeKit/Screens/PNScreenRegistry.swift +46 -0
  181. pythonnative/native/ios/Sources/PythonNativeKit/Screens/PNViewController.swift +237 -0
  182. pythonnative/native/ios/Sources/PythonNativeKit/Support/PNCompat.swift +46 -0
  183. pythonnative/native/ios/Sources/PythonNativeKit/Support/PNJSON.swift +173 -0
  184. pythonnative/native/ios/Sources/PythonNativeKit/Support/PNLog.swift +47 -0
  185. pythonnative/native/ios/Sources/PythonNativeKit/Support/PNWindow.swift +51 -0
  186. pythonnative/native/ios/Tests/PythonNativeKitTests/PNAnimationGraphTests.swift +26 -0
  187. pythonnative/native/ios/Tests/PythonNativeKitTests/PNColorTests.swift +50 -0
  188. pythonnative/native/ios/Tests/PythonNativeKitTests/PNCommitTests.swift +86 -0
  189. pythonnative/native/ios/Tests/PythonNativeKitTests/PNGestureTests.swift +101 -0
  190. pythonnative/native/ios/Tests/PythonNativeKitTests/PNManagerTests.swift +126 -0
  191. pythonnative/native/ios/Tests/PythonNativeKitTests/PNModuleTests.swift +111 -0
  192. pythonnative/native/ios/Tests/PythonNativeKitTests/PNTransactionTests.swift +91 -0
  193. pythonnative/native/yoga/LICENSE +21 -0
  194. pythonnative/native/yoga/Package.swift +9 -0
  195. pythonnative/native/yoga/VENDORED.md +2 -0
  196. pythonnative/native/yoga/include/PNStyle.h +10 -0
  197. pythonnative/native/yoga/include/module.modulemap +5 -0
  198. pythonnative/native/yoga/include/yoga/YGConfig.h +158 -0
  199. pythonnative/native/yoga/include/yoga/YGEnums.h +142 -0
  200. pythonnative/native/yoga/include/yoga/YGMacros.h +99 -0
  201. pythonnative/native/yoga/include/yoga/YGNode.h +304 -0
  202. pythonnative/native/yoga/include/yoga/YGNodeLayout.h +35 -0
  203. pythonnative/native/yoga/include/yoga/YGNodeStyle.h +130 -0
  204. pythonnative/native/yoga/include/yoga/YGPixelGrid.h +29 -0
  205. pythonnative/native/yoga/include/yoga/YGValue.h +84 -0
  206. pythonnative/native/yoga/include/yoga/Yoga.h +21 -0
  207. pythonnative/native/yoga/python.cpp +16 -0
  208. pythonnative/native/yoga/style.cpp +272 -0
  209. pythonnative/native/yoga/yoga/CMakeLists.txt +41 -0
  210. pythonnative/native/yoga/yoga/YGConfig.cpp +92 -0
  211. pythonnative/native/yoga/yoga/YGConfig.h +158 -0
  212. pythonnative/native/yoga/yoga/YGEnums.cpp +262 -0
  213. pythonnative/native/yoga/yoga/YGEnums.h +142 -0
  214. pythonnative/native/yoga/yoga/YGMacros.h +99 -0
  215. pythonnative/native/yoga/yoga/YGNode.cpp +366 -0
  216. pythonnative/native/yoga/yoga/YGNode.h +304 -0
  217. pythonnative/native/yoga/yoga/YGNodeLayout.cpp +92 -0
  218. pythonnative/native/yoga/yoga/YGNodeLayout.h +35 -0
  219. pythonnative/native/yoga/yoga/YGNodeStyle.cpp +405 -0
  220. pythonnative/native/yoga/yoga/YGNodeStyle.h +130 -0
  221. pythonnative/native/yoga/yoga/YGPixelGrid.cpp +22 -0
  222. pythonnative/native/yoga/yoga/YGPixelGrid.h +29 -0
  223. pythonnative/native/yoga/yoga/YGValue.cpp +20 -0
  224. pythonnative/native/yoga/yoga/YGValue.h +84 -0
  225. pythonnative/native/yoga/yoga/Yoga.h +21 -0
  226. pythonnative/native/yoga/yoga/algorithm/AbsoluteLayout.cpp +563 -0
  227. pythonnative/native/yoga/yoga/algorithm/AbsoluteLayout.h +41 -0
  228. pythonnative/native/yoga/yoga/algorithm/Align.h +72 -0
  229. pythonnative/native/yoga/yoga/algorithm/Baseline.cpp +78 -0
  230. pythonnative/native/yoga/yoga/algorithm/Baseline.h +21 -0
  231. pythonnative/native/yoga/yoga/algorithm/BoundAxis.h +79 -0
  232. pythonnative/native/yoga/yoga/algorithm/Cache.cpp +121 -0
  233. pythonnative/native/yoga/yoga/algorithm/Cache.h +30 -0
  234. pythonnative/native/yoga/yoga/algorithm/CalculateLayout.cpp +2428 -0
  235. pythonnative/native/yoga/yoga/algorithm/CalculateLayout.h +38 -0
  236. pythonnative/native/yoga/yoga/algorithm/FlexDirection.h +120 -0
  237. pythonnative/native/yoga/yoga/algorithm/FlexLine.cpp +124 -0
  238. pythonnative/native/yoga/yoga/algorithm/FlexLine.h +75 -0
  239. pythonnative/native/yoga/yoga/algorithm/PixelGrid.cpp +132 -0
  240. pythonnative/native/yoga/yoga/algorithm/PixelGrid.h +29 -0
  241. pythonnative/native/yoga/yoga/algorithm/SizingMode.h +73 -0
  242. pythonnative/native/yoga/yoga/algorithm/TrailingPosition.h +44 -0
  243. pythonnative/native/yoga/yoga/config/Config.cpp +135 -0
  244. pythonnative/native/yoga/yoga/config/Config.h +92 -0
  245. pythonnative/native/yoga/yoga/debug/AssertFatal.cpp +53 -0
  246. pythonnative/native/yoga/yoga/debug/AssertFatal.h +29 -0
  247. pythonnative/native/yoga/yoga/debug/Log.cpp +107 -0
  248. pythonnative/native/yoga/yoga/debug/Log.h +34 -0
  249. pythonnative/native/yoga/yoga/enums/Align.h +47 -0
  250. pythonnative/native/yoga/yoga/enums/BoxSizing.h +40 -0
  251. pythonnative/native/yoga/yoga/enums/Dimension.h +40 -0
  252. pythonnative/native/yoga/yoga/enums/Direction.h +41 -0
  253. pythonnative/native/yoga/yoga/enums/Display.h +41 -0
  254. pythonnative/native/yoga/yoga/enums/Edge.h +47 -0
  255. pythonnative/native/yoga/yoga/enums/Errata.h +41 -0
  256. pythonnative/native/yoga/yoga/enums/ExperimentalFeature.h +39 -0
  257. pythonnative/native/yoga/yoga/enums/FlexDirection.h +42 -0
  258. pythonnative/native/yoga/yoga/enums/Gutter.h +41 -0
  259. pythonnative/native/yoga/yoga/enums/Justify.h +44 -0
  260. pythonnative/native/yoga/yoga/enums/LogLevel.h +44 -0
  261. pythonnative/native/yoga/yoga/enums/MeasureMode.h +41 -0
  262. pythonnative/native/yoga/yoga/enums/NodeType.h +40 -0
  263. pythonnative/native/yoga/yoga/enums/Overflow.h +41 -0
  264. pythonnative/native/yoga/yoga/enums/PhysicalEdge.h +21 -0
  265. pythonnative/native/yoga/yoga/enums/PositionType.h +41 -0
  266. pythonnative/native/yoga/yoga/enums/Unit.h +42 -0
  267. pythonnative/native/yoga/yoga/enums/Wrap.h +41 -0
  268. pythonnative/native/yoga/yoga/enums/YogaEnums.h +85 -0
  269. pythonnative/native/yoga/yoga/event/event.cpp +87 -0
  270. pythonnative/native/yoga/yoga/event/event.h +130 -0
  271. pythonnative/native/yoga/yoga/module.modulemap +21 -0
  272. pythonnative/native/yoga/yoga/node/CachedMeasurement.h +53 -0
  273. pythonnative/native/yoga/yoga/node/LayoutResults.cpp +48 -0
  274. pythonnative/native/yoga/yoga/node/LayoutResults.h +122 -0
  275. pythonnative/native/yoga/yoga/node/LayoutableChildren.h +148 -0
  276. pythonnative/native/yoga/yoga/node/Node.cpp +443 -0
  277. pythonnative/native/yoga/yoga/node/Node.h +337 -0
  278. pythonnative/native/yoga/yoga/numeric/Comparison.h +81 -0
  279. pythonnative/native/yoga/yoga/numeric/FloatOptional.h +93 -0
  280. pythonnative/native/yoga/yoga/style/SmallValueBuffer.h +133 -0
  281. pythonnative/native/yoga/yoga/style/Style.h +757 -0
  282. pythonnative/native/yoga/yoga/style/StyleLength.h +107 -0
  283. pythonnative/native/yoga/yoga/style/StyleValueHandle.h +98 -0
  284. pythonnative/native/yoga/yoga/style/StyleValuePool.h +127 -0
  285. pythonnative/native_modules/__init__.py +124 -0
  286. pythonnative/native_modules/app_state.py +99 -0
  287. pythonnative/native_modules/battery.py +75 -0
  288. pythonnative/native_modules/biometrics.py +42 -0
  289. pythonnative/native_modules/camera.py +65 -0
  290. pythonnative/native_modules/clipboard.py +46 -0
  291. pythonnative/native_modules/fallback.py +324 -0
  292. pythonnative/native_modules/file_system.py +145 -0
  293. pythonnative/native_modules/haptics.py +75 -0
  294. pythonnative/native_modules/linking.py +123 -0
  295. pythonnative/native_modules/location.py +75 -0
  296. pythonnative/native_modules/net_info.py +112 -0
  297. pythonnative/native_modules/notifications.py +129 -0
  298. pythonnative/native_modules/permissions.py +108 -0
  299. pythonnative/native_modules/registry.py +526 -0
  300. pythonnative/native_modules/secure_store.py +52 -0
  301. pythonnative/native_modules/share.py +51 -0
  302. pythonnative/native_views/__init__.py +375 -0
  303. pythonnative/native_views/base.py +316 -0
  304. pythonnative/native_views/bridge_backend.py +277 -0
  305. pythonnative/navigation/__init__.py +103 -0
  306. pythonnative/navigation/container.py +154 -0
  307. pythonnative/navigation/handle.py +540 -0
  308. pythonnative/navigation/hooks.py +133 -0
  309. pythonnative/navigation/host.py +58 -0
  310. pythonnative/navigation/linking.py +200 -0
  311. pythonnative/navigation/navigators.py +659 -0
  312. pythonnative/navigation/screen.py +149 -0
  313. pythonnative/navigation/state.py +269 -0
  314. pythonnative/net.py +248 -0
  315. pythonnative/platform.py +166 -0
  316. pythonnative/platform_metrics.py +252 -0
  317. pythonnative/preview.py +287 -0
  318. pythonnative/profiling.py +101 -0
  319. pythonnative/project/__init__.py +68 -0
  320. pythonnative/project/android.py +557 -0
  321. pythonnative/project/builder.py +817 -0
  322. pythonnative/project/config.py +773 -0
  323. pythonnative/project/deps.py +719 -0
  324. pythonnative/project/devices.py +304 -0
  325. pythonnative/project/doctor.py +283 -0
  326. pythonnative/project/fingerprint.py +171 -0
  327. pythonnative/project/icons.py +247 -0
  328. pythonnative/project/ios.py +325 -0
  329. pythonnative/project/lockfile.py +100 -0
  330. pythonnative/project/permissions.py +361 -0
  331. pythonnative/project/plugins.py +519 -0
  332. pythonnative/project/runtime_assets.py +183 -0
  333. pythonnative/py.typed +0 -0
  334. pythonnative/query.py +153 -0
  335. pythonnative/reconciler/__init__.py +29 -0
  336. pythonnative/reconciler/boundaries.py +375 -0
  337. pythonnative/reconciler/children.py +88 -0
  338. pythonnative/reconciler/core.py +1165 -0
  339. pythonnative/reconciler/layout_pass.py +393 -0
  340. pythonnative/reconciler/vnode.py +266 -0
  341. pythonnative/refresh.py +55 -0
  342. pythonnative/runtime.py +306 -0
  343. pythonnative/scheduler.py +159 -0
  344. pythonnative/sdk/__init__.py +153 -0
  345. pythonnative/sdk/_components.py +427 -0
  346. pythonnative/sdk/builtins.py +91 -0
  347. pythonnative/sdk/codegen.py +149 -0
  348. pythonnative/sdk/module_codegen.py +184 -0
  349. pythonnative/sdk/schema.py +224 -0
  350. pythonnative/sdk/templates/contracts.kt +46 -0
  351. pythonnative/sdk/templates/contracts.swift +46 -0
  352. pythonnative/storage.py +184 -0
  353. pythonnative/style.py +841 -0
  354. pythonnative/suspense.py +183 -0
  355. pythonnative/templates/android_template/app/build.gradle +75 -0
  356. pythonnative/templates/android_template/app/proguard-rules.pro +21 -0
  357. pythonnative/templates/android_template/app/src/androidTest/java/com/pythonnative/android_template/ExampleInstrumentedTest.kt +24 -0
  358. pythonnative/templates/android_template/app/src/debug/AndroidManifest.xml +7 -0
  359. pythonnative/templates/android_template/app/src/main/AndroidManifest.xml +32 -0
  360. pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/MainActivity.kt +130 -0
  361. pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/ScreenFragment.kt +13 -0
  362. pythonnative/templates/android_template/app/src/main/res/drawable/ic_launcher_background.xml +170 -0
  363. pythonnative/templates/android_template/app/src/main/res/drawable-v24/ic_launcher_foreground.xml +30 -0
  364. pythonnative/templates/android_template/app/src/main/res/layout/activity_main.xml +10 -0
  365. pythonnative/templates/android_template/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +6 -0
  366. pythonnative/templates/android_template/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +6 -0
  367. pythonnative/templates/android_template/app/src/main/res/mipmap-hdpi/ic_launcher.webp +0 -0
  368. pythonnative/templates/android_template/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp +0 -0
  369. pythonnative/templates/android_template/app/src/main/res/mipmap-mdpi/ic_launcher.webp +0 -0
  370. pythonnative/templates/android_template/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp +0 -0
  371. pythonnative/templates/android_template/app/src/main/res/mipmap-xhdpi/ic_launcher.webp +0 -0
  372. pythonnative/templates/android_template/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp +0 -0
  373. pythonnative/templates/android_template/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp +0 -0
  374. pythonnative/templates/android_template/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp +0 -0
  375. pythonnative/templates/android_template/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp +0 -0
  376. pythonnative/templates/android_template/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp +0 -0
  377. pythonnative/templates/android_template/app/src/main/res/navigation/nav_graph.xml +22 -0
  378. pythonnative/templates/android_template/app/src/main/res/values/colors.xml +5 -0
  379. pythonnative/templates/android_template/app/src/main/res/values/strings.xml +5 -0
  380. pythonnative/templates/android_template/app/src/main/res/values/themes.xml +9 -0
  381. pythonnative/templates/android_template/app/src/main/res/values-night/themes.xml +7 -0
  382. pythonnative/templates/android_template/app/src/main/res/xml/backup_rules.xml +13 -0
  383. pythonnative/templates/android_template/app/src/main/res/xml/data_extraction_rules.xml +19 -0
  384. pythonnative/templates/android_template/app/src/test/java/com/pythonnative/android_template/ExampleUnitTest.kt +17 -0
  385. pythonnative/templates/android_template/build.gradle +10 -0
  386. pythonnative/templates/android_template/gradle/wrapper/gradle-wrapper.jar +0 -0
  387. pythonnative/templates/android_template/gradle/wrapper/gradle-wrapper.properties +6 -0
  388. pythonnative/templates/android_template/gradle.properties +23 -0
  389. pythonnative/templates/android_template/gradlew +185 -0
  390. pythonnative/templates/android_template/gradlew.bat +89 -0
  391. pythonnative/templates/android_template/settings.gradle +17 -0
  392. pythonnative/templates/ios_template/ios_template/AppDelegate.swift +51 -0
  393. pythonnative/templates/ios_template/ios_template/Assets.xcassets/AccentColor.colorset/Contents.json +11 -0
  394. pythonnative/templates/ios_template/ios_template/Assets.xcassets/AppIcon.appiconset/Contents.json +13 -0
  395. pythonnative/templates/ios_template/ios_template/Assets.xcassets/Contents.json +6 -0
  396. pythonnative/templates/ios_template/ios_template/Base.lproj/LaunchScreen.storyboard +25 -0
  397. pythonnative/templates/ios_template/ios_template/BridgingHeader.h +14 -0
  398. pythonnative/templates/ios_template/ios_template/Info.plist +28 -0
  399. pythonnative/templates/ios_template/ios_template/PythonRuntime.swift +390 -0
  400. pythonnative/templates/ios_template/ios_template/SceneDelegate.swift +61 -0
  401. pythonnative/templates/ios_template/ios_template/ViewController.swift +23 -0
  402. pythonnative/templates/ios_template/ios_template.xcodeproj/project.pbxproj +745 -0
  403. pythonnative/templates/ios_template/ios_template.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  404. pythonnative/templates/ios_template/ios_templateTests/ios_templateTests.swift +36 -0
  405. pythonnative/templates/ios_template/ios_templateUITests/ios_templateUITests.swift +41 -0
  406. pythonnative/templates/ios_template/ios_templateUITests/ios_templateUITestsLaunchTests.swift +32 -0
  407. pythonnative/testing/__init__.py +53 -0
  408. pythonnative/testing/backend.py +276 -0
  409. pythonnative/testing/harness.py +369 -0
  410. pythonnative/utils.py +145 -0
  411. pythonnative-0.40.0.dist-info/DELVEWHEEL +2 -0
  412. pythonnative-0.40.0.dist-info/METADATA +150 -0
  413. pythonnative-0.40.0.dist-info/RECORD +418 -0
  414. pythonnative-0.40.0.dist-info/WHEEL +5 -0
  415. pythonnative-0.40.0.dist-info/entry_points.txt +2 -0
  416. pythonnative-0.40.0.dist-info/licenses/LICENSE +21 -0
  417. pythonnative-0.40.0.dist-info/top_level.txt +1 -0
  418. pythonnative.libs/msvcp140-a4c2229bdc2a2a630acdc095b4d86008.dll +0 -0
@@ -0,0 +1,260 @@
1
+ import UIKit
2
+
3
+ /// Installs `UIGestureRecognizer`s from the `gestures` prop and emits
4
+ /// `gesture:<index>` events with the payload dict Python's
5
+ /// `GestureEvent` expects.
6
+ ///
7
+ /// Spec fields:
8
+ /// - `kind`: `tap`, `long_press`, `pan`, `swipe`, `fling`, `pinch`, `rotation`
9
+ /// - per-kind config (`n_taps`, `max_distance`, `min_duration_ms`,
10
+ /// `min_distance`, `direction`, `n_pointers`, `min_velocity`)
11
+ /// - `simultaneous`: indices allowed to recognize together
12
+ /// - `wait_for`: indices that must fail before this one may begin
13
+ public final class PNGestureCoordinator: NSObject, UIGestureRecognizerDelegate {
14
+ public static let shared = PNGestureCoordinator()
15
+
16
+ /// Bookkeeping for one installed recognizer.
17
+ final class Entry {
18
+ let index: Int
19
+ let kind: String
20
+ var simultaneous: Set<Int>
21
+ var minVelocity: CGFloat
22
+ var direction: String
23
+ var lastLocation: CGPoint = .zero
24
+
25
+ init(index: Int, kind: String, simultaneous: Set<Int>, minVelocity: CGFloat, direction: String) {
26
+ self.index = index
27
+ self.kind = kind
28
+ self.simultaneous = simultaneous
29
+ self.minVelocity = minVelocity
30
+ self.direction = direction
31
+ }
32
+ }
33
+
34
+ private var entries: [ObjectIdentifier: Entry] = [:]
35
+
36
+ private override init() {
37
+ super.init()
38
+ }
39
+
40
+ // MARK: - Wiring
41
+
42
+ /// Replace the recognizers on `view` with the ones described by `specs`.
43
+ public func wire(view: UIView, specs: Any?) {
44
+ unwire(view: view)
45
+ guard let state = PNViewState.existing(for: view) else { return }
46
+ let list = ((specs as? [Any]) ?? []).map { ($0 as? [String: Any]) ?? [:] }
47
+ guard !list.isEmpty else { return }
48
+ // A spec may own several recognizers (an any-direction swipe is
49
+ // one `UISwipeGestureRecognizer` per direction), so relationships
50
+ // are wired spec-to-spec across every recognizer on each side.
51
+ var built: [Int: [UIGestureRecognizer]] = [:]
52
+ for (index, spec) in list.enumerated() {
53
+ let recognizers = makeRecognizers(spec)
54
+ if recognizers.isEmpty {
55
+ PNLog.once(PNLog.gestures, key: "kind:\(PNProps.string(spec["kind"]) ?? "")", "unsupported gesture kind '\(PNProps.string(spec["kind"]) ?? "")'")
56
+ continue
57
+ }
58
+ for (recognizer, direction) in recognizers {
59
+ let entry = Entry(
60
+ index: index,
61
+ kind: PNProps.string(spec["kind"]) ?? "",
62
+ simultaneous: Set(((spec["simultaneous"] as? [Any]) ?? []).compactMap { PNProps.int($0) }),
63
+ minVelocity: CGFloat(PNProps.double(spec["min_velocity"]) ?? 300),
64
+ direction: direction ?? PNProps.string(spec["direction"]) ?? "any"
65
+ )
66
+ entries[ObjectIdentifier(recognizer)] = entry
67
+ recognizer.delegate = self
68
+ recognizer.cancelsTouchesInView = false
69
+ recognizer.addTarget(self, action: #selector(handle(_:)))
70
+ view.addGestureRecognizer(recognizer)
71
+ state.gestureRecognizers.append(recognizer)
72
+ built[index, default: []].append(recognizer)
73
+ }
74
+ }
75
+ for (index, spec) in list.enumerated() {
76
+ guard let recognizers = built[index] else { continue }
77
+ for wait in ((spec["wait_for"] as? [Any]) ?? []).compactMap({ PNProps.int($0) }) {
78
+ guard wait != index, let others = built[wait] else { continue }
79
+ for recognizer in recognizers {
80
+ for other in others {
81
+ recognizer.require(toFail: other)
82
+ }
83
+ }
84
+ }
85
+ }
86
+ view.isUserInteractionEnabled = true
87
+ }
88
+
89
+ /// Remove every recognizer previously installed on `view`.
90
+ public func unwire(view: UIView) {
91
+ guard let state = PNViewState.existing(for: view) else { return }
92
+ for recognizer in state.gestureRecognizers {
93
+ recognizer.removeTarget(self, action: nil)
94
+ view.removeGestureRecognizer(recognizer)
95
+ entries.removeValue(forKey: ObjectIdentifier(recognizer))
96
+ }
97
+ state.gestureRecognizers = []
98
+ }
99
+
100
+ // MARK: - Recognizer construction
101
+
102
+ /// Build the recognizer(s) for one spec as `(recognizer, direction)`
103
+ /// pairs. `direction` is set only for swipe / fling recognizers: a
104
+ /// `UISwipeGestureRecognizer` reports its configured mask rather than
105
+ /// the direction it resolved, so `direction = "any"` installs one
106
+ /// recognizer per direction and tags each with its own name.
107
+ func makeRecognizers(_ spec: [String: Any]) -> [(UIGestureRecognizer, String?)] {
108
+ switch PNProps.string(spec["kind"]) ?? "" {
109
+ case "tap":
110
+ let tap = UITapGestureRecognizer()
111
+ tap.numberOfTapsRequired = max(1, PNProps.int(spec["n_taps"]) ?? 1)
112
+ return [(tap, nil)]
113
+ case "long_press":
114
+ let press = UILongPressGestureRecognizer()
115
+ press.minimumPressDuration = max(0.01, (PNProps.double(spec["min_duration_ms"]) ?? 500) / 1000)
116
+ press.allowableMovement = CGFloat(PNProps.double(spec["max_distance"]) ?? 12)
117
+ return [(press, nil)]
118
+ case "pan":
119
+ return [(PNPanGestureRecognizer(minDistance: CGFloat(PNProps.double(spec["min_distance"]) ?? 10)), nil)]
120
+ case "swipe", "fling":
121
+ let requested = PNProps.string(spec["direction"]) ?? "any"
122
+ let directions = PNGestureCoordinator.swipeDirectionNames.contains(requested)
123
+ ? [requested]
124
+ : PNGestureCoordinator.swipeDirectionNames
125
+ let touches = max(1, PNProps.int(spec["n_pointers"]) ?? 1)
126
+ return directions.map { name in
127
+ let swipe = UISwipeGestureRecognizer()
128
+ swipe.direction = PNGestureCoordinator.swipeDirection(name)
129
+ swipe.numberOfTouchesRequired = touches
130
+ return (swipe, name)
131
+ }
132
+ case "pinch":
133
+ return [(UIPinchGestureRecognizer(), nil)]
134
+ case "rotation":
135
+ return [(UIRotationGestureRecognizer(), nil)]
136
+ default:
137
+ return []
138
+ }
139
+ }
140
+
141
+ /// The single-direction names a swipe spec may request.
142
+ public static let swipeDirectionNames = ["left", "right", "up", "down"]
143
+
144
+ /// Map a Python direction name to `UISwipeGestureRecognizer.Direction`.
145
+ public static func swipeDirection(_ name: String) -> UISwipeGestureRecognizer.Direction {
146
+ switch name {
147
+ case "left": return .left
148
+ case "right": return .right
149
+ case "up": return .up
150
+ case "down": return .down
151
+ default: return [.left, .right, .up, .down]
152
+ }
153
+ }
154
+
155
+ // MARK: - Relationship lookups (exposed for tests)
156
+
157
+ /// The spec index recorded for `recognizer`, if it was installed by the coordinator.
158
+ public func index(of recognizer: UIGestureRecognizer) -> Int? {
159
+ entries[ObjectIdentifier(recognizer)]?.index
160
+ }
161
+
162
+ /// Whether the two recognizers are allowed to recognize together.
163
+ public func allowsSimultaneous(_ a: UIGestureRecognizer, _ b: UIGestureRecognizer) -> Bool {
164
+ guard let ea = entries[ObjectIdentifier(a)], let eb = entries[ObjectIdentifier(b)] else {
165
+ // One side isn't ours (Pressable, scroll view): don't block it.
166
+ return true
167
+ }
168
+ if a.view !== b.view { return true }
169
+ return ea.simultaneous.contains(eb.index) || eb.simultaneous.contains(ea.index)
170
+ }
171
+
172
+ // MARK: - UIGestureRecognizerDelegate
173
+
174
+ public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith other: UIGestureRecognizer) -> Bool {
175
+ allowsSimultaneous(gestureRecognizer, other)
176
+ }
177
+
178
+ // MARK: - Emission
179
+
180
+ @objc private func handle(_ recognizer: UIGestureRecognizer) {
181
+ guard let view = recognizer.view, let entry = entries[ObjectIdentifier(recognizer)] else { return }
182
+ let location = recognizer.location(in: view)
183
+ var payload: [String: Any] = [
184
+ "kind": entry.kind,
185
+ "x": Double(location.x),
186
+ "y": Double(location.y),
187
+ "translation_x": 0.0,
188
+ "translation_y": 0.0,
189
+ "velocity_x": 0.0,
190
+ "velocity_y": 0.0,
191
+ "scale": 1.0,
192
+ "rotation": 0.0,
193
+ "pointer_count": recognizer.numberOfTouches,
194
+ "direction": NSNull(),
195
+ ]
196
+ var state = PNGestureCoordinator.stateName(recognizer.state)
197
+ switch recognizer {
198
+ case let pan as UIPanGestureRecognizer:
199
+ let translation = pan.translation(in: view)
200
+ let velocity = pan.velocity(in: view)
201
+ payload["translation_x"] = Double(translation.x)
202
+ payload["translation_y"] = Double(translation.y)
203
+ payload["velocity_x"] = Double(velocity.x)
204
+ payload["velocity_y"] = Double(velocity.y)
205
+ case let pinch as UIPinchGestureRecognizer:
206
+ payload["scale"] = Double(pinch.scale)
207
+ payload["velocity_x"] = Double(pinch.velocity)
208
+ case let rotation as UIRotationGestureRecognizer:
209
+ payload["rotation"] = Double(rotation.rotation)
210
+ payload["velocity_x"] = Double(rotation.velocity)
211
+ case let swipe as UISwipeGestureRecognizer:
212
+ // UIKit reports swipes as a single `.ended`; Python expects `ended`.
213
+ guard swipe.state == .ended || swipe.state == .recognized else { return }
214
+ state = "ended"
215
+ payload["direction"] = entry.direction
216
+ payload["pointer_count"] = max(1, swipe.numberOfTouchesRequired)
217
+ case is UITapGestureRecognizer:
218
+ guard recognizer.state == .ended || recognizer.state == .recognized else { return }
219
+ state = "ended"
220
+ default:
221
+ break
222
+ }
223
+ guard state != "possible" else { return }
224
+ payload["state"] = state
225
+ PNEvents.emit(view, "gesture:\(entry.index)", [payload])
226
+ }
227
+
228
+ static func stateName(_ state: UIGestureRecognizer.State) -> String {
229
+ switch state {
230
+ case .began: return "began"
231
+ case .changed: return "changed"
232
+ case .ended: return "ended"
233
+ case .cancelled: return "cancelled"
234
+ case .failed: return "failed"
235
+ default: return "possible"
236
+ }
237
+ }
238
+
239
+ /// The direction name recorded for a swipe / fling recognizer (exposed for tests).
240
+ public func direction(of recognizer: UIGestureRecognizer) -> String? {
241
+ guard let entry = entries[ObjectIdentifier(recognizer)], entry.kind == "swipe" || entry.kind == "fling" else {
242
+ return nil
243
+ }
244
+ return entry.direction
245
+ }
246
+ }
247
+
248
+ /// A pan recognizer that records the Python `min_distance` threshold.
249
+ ///
250
+ /// UIKit applies its own ~10 pt hysteresis before a pan begins, which
251
+ /// matches the Python default; the value is kept for diagnostics and
252
+ /// for future tuning rather than overriding UIKit's touch pipeline.
253
+ final class PNPanGestureRecognizer: UIPanGestureRecognizer {
254
+ let minDistance: CGFloat
255
+
256
+ init(minDistance: CGFloat) {
257
+ self.minDistance = max(0, minDistance)
258
+ super.init(target: nil, action: nil)
259
+ }
260
+ }
@@ -0,0 +1,173 @@
1
+ import UIKit
2
+ import YogaCore
3
+
4
+ /// The layout tree stays beside UIKit, including intrinsic text measurement.
5
+ final class PNLayoutNode {
6
+ let tag: Int64
7
+ let node: YGNodeRef
8
+ var props: [String: Any] = [:]
9
+ var children: [Int64] = []
10
+ var parent: Int64?
11
+ var frame: [Double] = []
12
+ init(_ tag: Int64) {
13
+ self.tag = tag
14
+ node = YGNodeNew()!
15
+ YGNodeSetContext(node, Unmanaged.passUnretained(self).toOpaque())
16
+ }
17
+ deinit { YGNodeFree(node) }
18
+ }
19
+
20
+ private let measureLeaf: YGMeasureFunc = { raw, width, widthMode, height, heightMode in
21
+ guard let raw = raw, let context = YGNodeGetContext(raw) else { return YGSize(width: 0, height: 0) }
22
+ let node = Unmanaged<PNLayoutNode>.fromOpaque(context).takeUnretainedValue()
23
+ guard let record = PNViewRegistry.shared.resolve(node.tag) else { return YGSize(width: 0, height: 0) }
24
+ let size = record.manager.measure(view: record.view,
25
+ maxW: widthMode.rawValue == 0 ? 1e6 : CGFloat(width),
26
+ maxH: heightMode.rawValue == 0 ? 1e6 : CGFloat(height))
27
+ return YGSize(width: Float(max(0, size.width)), height: Float(max(0, size.height)))
28
+ }
29
+
30
+ private let baselineLeaf: YGBaselineFunc = { raw, _, height in
31
+ guard let raw = raw, let context = YGNodeGetContext(raw) else { return height }
32
+ let node = Unmanaged<PNLayoutNode>.fromOpaque(context).takeUnretainedValue()
33
+ if let label = PNViewRegistry.shared.view(for: node.tag) as? UILabel {
34
+ return Float(label.font.ascender)
35
+ }
36
+ return height
37
+ }
38
+
39
+ enum PNLayout {
40
+ static var nodes: [Int64: PNLayoutNode] = [:]
41
+ static var viewport: [String: Any] = [:]
42
+ private static var scheduled = false
43
+
44
+ static func containerDidLayout() {
45
+ guard !scheduled else { return }
46
+ scheduled = true
47
+ DispatchQueue.main.async {
48
+ scheduled = false
49
+ let frames = compute(viewport)
50
+ if !frames.isEmpty { PNBridge.shared.callPython(kind: "layout", tag: 0, name: "", payload: PNJSON.encode(frames)) }
51
+ }
52
+ }
53
+
54
+ static func reset() {
55
+ for entry in nodes.values { YGNodeRemoveAllChildren(entry.node) }
56
+ nodes.removeAll()
57
+ viewport = [:]
58
+ }
59
+
60
+ static func observe(_ ops: [PNTransaction.Op]) {
61
+ for op in ops {
62
+ switch op {
63
+ case let .create(tag, _, props):
64
+ let entry = PNLayoutNode(tag)
65
+ nodes[tag] = entry
66
+ update(entry, props)
67
+ case let .update(tag, changed):
68
+ if let entry = nodes[tag] { update(entry, changed) }
69
+ case let .insert(parent, child, index):
70
+ guard let p = nodes[parent], let c = nodes[child] else { continue }
71
+ if let old = c.parent, let previous = nodes[old] {
72
+ previous.children.removeAll { $0 == child }
73
+ YGNodeRemoveChild(previous.node, c.node)
74
+ }
75
+ p.children.insert(child, at: min(index, p.children.count))
76
+ c.parent = parent
77
+ // Detached surfaces keep logical ownership but supply their own viewport.
78
+ let type = PNViewRegistry.shared.resolve(parent)?.typeName ?? ""
79
+ if !["VirtualList", "Modal", "ScreenStack"].contains(type) {
80
+ YGNodeSetMeasureFunc(p.node, nil)
81
+ YGNodeInsertChild(p.node, c.node, min(index, Int(YGNodeGetChildCount(p.node))))
82
+ }
83
+ case let .destroy(tag):
84
+ if let entry = nodes.removeValue(forKey: tag), let parent = entry.parent, let p = nodes[parent] {
85
+ p.children.removeAll { $0 == tag }
86
+ YGNodeRemoveChild(p.node, entry.node)
87
+ }
88
+ case .frame: break
89
+ }
90
+ }
91
+ }
92
+
93
+ private static func update(_ entry: PNLayoutNode, _ changed: [String: Any]) {
94
+ for (key, value) in changed {
95
+ if value is NSNull { entry.props.removeValue(forKey: key) }
96
+ else { entry.props[key] = value }
97
+ }
98
+ let fresh = YGNodeNew()!
99
+ for (key, value) in entry.props {
100
+ if let edges = value as? [String: Any], key == "margin" || key == "padding" {
101
+ for (edge, amount) in edges {
102
+ let name = edge == "all" ? key : "\(key)_\(edge)"
103
+ _ = PNYogaSetStyle(fresh, name, String(describing: amount))
104
+ }
105
+ } else { _ = PNYogaSetStyle(fresh, key, String(describing: value)) }
106
+ }
107
+ let type = PNViewRegistry.shared.resolve(entry.tag)?.typeName ?? ""
108
+ if ["ScrollView", "VirtualList", "ScreenStack"].contains(type) {
109
+ YGNodeStyleSetOverflow(fresh, YGOverflow(rawValue: 1)!)
110
+ YGNodeStyleSetFlexShrink(fresh, 1)
111
+ }
112
+ YGNodeCopyStyle(entry.node, fresh)
113
+ YGNodeFree(fresh)
114
+ if YGNodeGetChildCount(entry.node) == 0 && !["View", "Column", "Row", "ScrollView", "Modal", "Portal", "ScreenStack"].contains(type) {
115
+ YGNodeSetMeasureFunc(entry.node, measureLeaf)
116
+ YGNodeSetBaselineFunc(entry.node, baselineLeaf)
117
+ YGNodeMarkDirty(entry.node)
118
+ }
119
+ }
120
+
121
+ static func compute(_ request: [String: Any]) -> [[Double]] {
122
+ viewport = request
123
+ let width = (request["width"] as? NSNumber)?.floatValue ?? 0
124
+ let height = (request["height"] as? NSNumber)?.floatValue ?? 0
125
+ guard width > 0, height > 0 else { return [] }
126
+ let roots = request["roots"] as? [Int64] ?? []
127
+ for tag in roots {
128
+ if let entry = nodes[tag] { YGNodeCalculateLayout(entry.node, width, height, YGDirection(rawValue: 1)!) }
129
+ }
130
+ // A portal is absent from the screen tree, but remains a Yoga parent
131
+ // so absolute insets and sibling layout resolve against its viewport.
132
+ for entry in nodes.values {
133
+ guard let record = PNViewRegistry.shared.resolve(entry.tag), record.typeName == "Portal" else { continue }
134
+ let size = record.view.bounds.size
135
+ let portalWidth = size.width > 0 ? Float(size.width) : width
136
+ let portalHeight = size.height > 0 ? Float(size.height) : height
137
+ YGNodeStyleSetWidth(entry.node, portalWidth)
138
+ YGNodeStyleSetHeight(entry.node, portalHeight)
139
+ YGNodeCalculateLayout(entry.node, portalWidth, portalHeight, YGDirection(rawValue: 1)!)
140
+ }
141
+ // Every detached root is laid out in its native container's available space.
142
+ for entry in nodes.values where entry.parent != nil && YGNodeGetOwner(entry.node) == nil {
143
+ let parent = entry.parent.flatMap { PNViewRegistry.shared.resolve($0) }
144
+ let screen = PNViewRegistry.shared.resolve(entry.tag)
145
+ let size = (screen?.typeName == "Screen" ? screen?.view.bounds.size : parent?.view.bounds.size)
146
+ ?? CGSize(width: CGFloat(width), height: CGFloat(height))
147
+ let isList = parent?.typeName == "VirtualList"
148
+ let horizontal = parent.flatMap { PNViewState.existing(for: $0.view)?.props["horizontal"] as? Bool } ?? false
149
+ YGNodeCalculateLayout(entry.node, isList && horizontal ? Float.nan : Float(size.width > 0 ? size.width : CGFloat(width)),
150
+ isList && !horizontal ? Float.nan : Float(size.height > 0 ? size.height : CGFloat(height)), YGDirection(rawValue: 1)!)
151
+ }
152
+ var frames: [[Double]] = []
153
+ for entry in nodes.values {
154
+ let frame = [Double(YGNodeLayoutGetLeft(entry.node)), Double(YGNodeLayoutGetTop(entry.node)),
155
+ Double(YGNodeLayoutGetWidth(entry.node)), Double(YGNodeLayoutGetHeight(entry.node))]
156
+ if frame == entry.frame { continue }
157
+ entry.frame = frame
158
+ if !roots.contains(entry.tag), let record = PNViewRegistry.shared.resolve(entry.tag) {
159
+ record.manager.setFrame(view: record.view, x: frame[0], y: frame[1], w: frame[2], h: frame[3])
160
+ }
161
+ PNVirtualListManager.measured(entry.tag, CGSize(width: frame[2], height: frame[3]))
162
+ frames.append([Double(entry.tag)] + frame)
163
+ }
164
+ return frames
165
+ }
166
+
167
+ static func invalidate(_ tag: Int64) {
168
+ guard let node = nodes[tag], YGNodeHasMeasureFunc(node.node) else { return }
169
+ YGNodeMarkDirty(node.node)
170
+ let frames = compute(viewport)
171
+ if !frames.isEmpty { PNBridge.shared.callPython(kind: "layout", tag: 0, name: "", payload: PNJSON.encode(frames)) }
172
+ }
173
+ }
@@ -0,0 +1,92 @@
1
+ import UIKit
2
+
3
+ /// Presents `UIAlertController`s from the top view controller.
4
+ public enum PNAlertPresenter {
5
+ /// Show an alert or action sheet. `buttons` are
6
+ /// `{"label", "style": "default"|"cancel"|"destructive"}` dicts;
7
+ /// `completion` receives the tapped index, or `-1` on dismissal.
8
+ public static func present(
9
+ title: String?, message: String?, buttons: [[String: Any]], style: String,
10
+ completion: @escaping (Int) -> Void
11
+ ) {
12
+ guard let top = PNWindow.topViewController() else {
13
+ completion(-1)
14
+ return
15
+ }
16
+ let preferred: UIAlertController.Style = style == "action_sheet" ? .actionSheet : .alert
17
+ let alert = UIAlertController(title: title, message: message, preferredStyle: preferred)
18
+ var settled = false
19
+ let finish: (Int) -> Void = { index in
20
+ if settled { return }
21
+ settled = true
22
+ completion(index)
23
+ }
24
+ let list = buttons.isEmpty ? [["label": "OK"]] : buttons
25
+ for (index, button) in list.enumerated() {
26
+ let label = PNProps.string(button["label"]) ?? PNProps.string(button["title"]) ?? "OK"
27
+ let actionStyle: UIAlertAction.Style
28
+ switch PNProps.string(button["style"]) {
29
+ case "cancel": actionStyle = .cancel
30
+ case "destructive": actionStyle = .destructive
31
+ default: actionStyle = .default
32
+ }
33
+ alert.addAction(UIAlertAction(title: label, style: actionStyle) { _ in finish(index) })
34
+ }
35
+ if preferred == .actionSheet, let popover = alert.popoverPresentationController {
36
+ popover.sourceView = top.view
37
+ popover.sourceRect = CGRect(x: top.view.bounds.midX, y: top.view.bounds.maxY - 1, width: 1, height: 1)
38
+ popover.permittedArrowDirections = []
39
+ }
40
+ top.present(alert, animated: true)
41
+ // A sheet dismissed by tapping outside (iPad popover) never runs
42
+ // an action; report -1 once it disappears.
43
+ PNAlertDismissWatcher.watch(alert) { finish(-1) }
44
+ }
45
+ }
46
+
47
+ /// Observes an alert's disappearance to report an outside-tap dismissal.
48
+ final class PNAlertDismissWatcher: NSObject, UIPopoverPresentationControllerDelegate {
49
+ private let onDismiss: () -> Void
50
+ private static var watchers: [ObjectIdentifier: PNAlertDismissWatcher] = [:]
51
+
52
+ private init(onDismiss: @escaping () -> Void) {
53
+ self.onDismiss = onDismiss
54
+ }
55
+
56
+ static func watch(_ alert: UIAlertController, onDismiss: @escaping () -> Void) {
57
+ let watcher = PNAlertDismissWatcher(onDismiss: onDismiss)
58
+ watchers[ObjectIdentifier(alert)] = watcher
59
+ alert.popoverPresentationController?.delegate = watcher
60
+ }
61
+
62
+ func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
63
+ onDismiss()
64
+ PNAlertDismissWatcher.watchers.removeValue(forKey: ObjectIdentifier(presentationController.presentedViewController))
65
+ }
66
+ }
67
+
68
+ /// `Alert`: `present` (async, resolves the tapped index) and `show` (fire-and-forget).
69
+ public final class AlertModule: PNNativeModule {
70
+ public static let name = "Alert"
71
+
72
+ public init() {}
73
+
74
+ public func call(_ method: String, args: [String: Any], promise: PNPromise) {
75
+ switch method {
76
+ case "present", "show":
77
+ let buttons = ((args["buttons"] as? [Any]) ?? []).compactMap { $0 as? [String: Any] }
78
+ let fireAndForget = method == "show"
79
+ if fireAndForget { promise.resolve(nil) }
80
+ PNAlertPresenter.present(
81
+ title: PNProps.string(args["title"]),
82
+ message: PNProps.string(args["message"]),
83
+ buttons: buttons,
84
+ style: PNProps.string(args["style"]) ?? "alert"
85
+ ) { index in
86
+ if !fireAndForget { promise.resolve(index) }
87
+ }
88
+ default:
89
+ promise.reject("Alert has no method '\(method)'", code: "unknown_method")
90
+ }
91
+ }
92
+ }
@@ -0,0 +1,80 @@
1
+ import UIKit
2
+
3
+ /// `Host`: screen root attachment, stack navigation, viewport queries,
4
+ /// and the main-queue pump.
5
+ public final class HostModule: PNNativeModule {
6
+ public static let name = "Host"
7
+
8
+ public init() {}
9
+
10
+ public func call(_ method: String, args: [String: Any], promise: PNPromise) {
11
+ switch method {
12
+ case "cache_state":
13
+ guard let controller = screen(args, promise) else { return }
14
+ controller.cachedStateJSON = args["state"] as? String
15
+ promise.resolve(nil)
16
+ case "attach_root":
17
+ guard let controller = screen(args, promise) else { return }
18
+ guard let tag = PNProps.int(args["tag"]), let view = PNViewRegistry.shared.view(for: Int64(tag)) else {
19
+ promise.reject("attach_root: unknown view tag", code: "unknown_tag")
20
+ return
21
+ }
22
+ controller.attachRoot(view)
23
+ promise.resolve(controller.viewport())
24
+ case "detach_root":
25
+ guard let controller = screen(args, promise) else { return }
26
+ if let tag = PNProps.int(args["tag"]), let view = PNViewRegistry.shared.view(for: Int64(tag)) {
27
+ controller.detachRoot(view)
28
+ }
29
+ promise.resolve(nil)
30
+ case "viewport":
31
+ guard let controller = screen(args, promise) else { return }
32
+ promise.resolve(controller.viewport())
33
+ case "set_options":
34
+ guard let controller = screen(args, promise) else { return }
35
+ HostModule.applyOptions(PNProps.dict(args["options"]) ?? [:], to: controller)
36
+ promise.resolve(nil)
37
+ case "finish":
38
+ promise.resolve(nil)
39
+ default:
40
+ promise.reject("Host has no method '\(method)'", code: "unknown_method")
41
+ }
42
+ }
43
+
44
+ // MARK: - Helpers
45
+
46
+ private func screen(_ args: [String: Any], _ promise: PNPromise) -> PNViewController? {
47
+ guard let id = PNProps.int(args["screen"]) else {
48
+ promise.reject("missing 'screen' id", code: "bad_args")
49
+ return nil
50
+ }
51
+ guard let controller = PNScreenRegistry.shared.controller(for: Int64(id)) else {
52
+ promise.reject("no screen with id \(id)", code: "unknown_screen")
53
+ return nil
54
+ }
55
+ return controller
56
+ }
57
+
58
+ static func applyOptions(_ options: [String: Any], to controller: UIViewController) {
59
+ if let title = PNProps.string(options["title"]) {
60
+ controller.title = title
61
+ }
62
+ if let hidden = PNProps.bool(options["header_shown"]) {
63
+ controller.navigationController?.setNavigationBarHidden(!hidden, animated: false)
64
+ }
65
+ if let hidesBack = PNProps.bool(options["hide_back_button"]) {
66
+ controller.navigationItem.hidesBackButton = hidesBack
67
+ }
68
+ if let color = PNColor.parse(options["header_tint_color"]) {
69
+ controller.navigationController?.navigationBar.tintColor = color
70
+ }
71
+ if let color = PNColor.parse(options["header_background_color"]) {
72
+ let appearance = UINavigationBarAppearance()
73
+ appearance.configureWithOpaqueBackground()
74
+ appearance.backgroundColor = color
75
+ controller.navigationItem.standardAppearance = appearance
76
+ controller.navigationItem.scrollEdgeAppearance = appearance
77
+ }
78
+ }
79
+
80
+ }