pythonnative 0.40.0__cp314-cp314-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.cp314-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,393 @@
1
+ """The layout phase of a reconciler pass.
2
+
3
+ After native mutations commit, the reconciler builds a
4
+ [`LayoutNode`][pythonnative.layout.LayoutNode] tree mirroring the
5
+ native nodes of the mounted tree, runs the flexbox engine against the
6
+ viewport, and emits a ``SetFrameOp`` for every frame that changed.
7
+
8
+ Two details keep this cheap on every state update:
9
+
10
+ - **Incremental rebuild.** Each native ``VNode`` caches its
11
+ ``LayoutNode``; subtrees whose props and child list are unchanged
12
+ reuse the cached node with ``dirty=False`` so the engine can serve
13
+ their sizes from its measurement memo.
14
+ - **Frame diffing.** Frames equal to the last applied frame produce no
15
+ op at all.
16
+
17
+ Detached subtrees (``Modal``, ``Portal``) are excluded from the main
18
+ flow and laid out against the viewport as independent trees, since
19
+ their content lives in a separately presented native container.
20
+ """
21
+
22
+ from __future__ import annotations
23
+
24
+ from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, Tuple
25
+
26
+ from .. import diagnostics
27
+ from ..element import Element
28
+ from ..layout import LAYOUT_STYLE_KEYS, LayoutNode, calculate_layout, extract_layout_style
29
+ from ..mutations import Mutation, SetFrameOp
30
+ from ..profiling import profiled
31
+ from .vnode import DETACHED_TYPES, VNode
32
+
33
+ if TYPE_CHECKING:
34
+ pass
35
+
36
+ Frame = Tuple[float, float, float, float]
37
+
38
+ # Native leaves whose size derives from their content; any prop change
39
+ # invalidates their measurement.
40
+ INTRINSIC_TYPES = frozenset(
41
+ {
42
+ "Text",
43
+ "Button",
44
+ "Image",
45
+ "TextInput",
46
+ "Switch",
47
+ "Slider",
48
+ "ProgressBar",
49
+ "ActivityIndicator",
50
+ "TabBar",
51
+ "Picker",
52
+ "Checkbox",
53
+ "SegmentedControl",
54
+ "DatePicker",
55
+ }
56
+ )
57
+
58
+ # Childless native leaves that get a measure callback. Extends the
59
+ # intrinsic set with ``VirtualList``, whose handlers report "fill the
60
+ # available space" (like a ScrollView clamped to its parent): without
61
+ # the callback an unstyled list would collapse to 0 points and the
62
+ # platform virtualizer would never bind a row.
63
+ MEASURED_LEAF_TYPES = INTRINSIC_TYPES | {"VirtualList"}
64
+
65
+
66
+ def affects_layout(type_name: str, changed: Dict[str, Any]) -> bool:
67
+ """Whether ``changed`` props can alter a native node's layout."""
68
+ from ..sdk.schema import COMPONENTS
69
+
70
+ schema = COMPONENTS.get(type_name)
71
+ if schema is None or schema.measurement == "intrinsic":
72
+ return True
73
+ if any(schema.props.get(key, {}).get("native", {}).get("invalidates_layout") for key in changed):
74
+ return True
75
+ return any(key in LAYOUT_STYLE_KEYS for key in changed)
76
+
77
+
78
+ class LayoutMixin:
79
+ """Layout-pass behavior mixed into the reconciler."""
80
+
81
+ # Provided by the concrete reconciler.
82
+ backend: Any
83
+ root: Optional[VNode]
84
+ _ops: List[Mutation]
85
+
86
+ def _init_layout_state(self) -> None:
87
+ self._viewport_size: Tuple[float, float] = (0.0, 0.0)
88
+ self._layout_pass_count = 0
89
+ # ``(tag, frame)`` pairs whose ``on_layout`` should fire after
90
+ # the layout pass commits (frames are only queued on change).
91
+ self._pending_layout_events: List[Tuple[int, Frame]] = []
92
+
93
+ # ------------------------------------------------------------------
94
+ # Public surface
95
+ # ------------------------------------------------------------------
96
+
97
+ @property
98
+ def viewport_size(self) -> Tuple[float, float]:
99
+ """The last viewport size supplied by the host, ``(0, 0)`` before layout is possible."""
100
+ return self._viewport_size
101
+
102
+ def set_viewport_size(self, width: float, height: float) -> None:
103
+ """Update the viewport size and re-run layout if it changed.
104
+
105
+ Called by the screen host whenever the platform reports a new
106
+ container size. The first call after mount triggers the
107
+ initial layout pass; identical sizes are no-ops.
108
+ """
109
+ if width <= 0 or height <= 0:
110
+ return
111
+ if self._viewport_size == (width, height):
112
+ return
113
+ self._viewport_size = (width, height)
114
+ if self.root is not None:
115
+ self._run_layout()
116
+ self._flush_ops()
117
+ self._dispatch_layout_events()
118
+
119
+ def compute_layout_for_test(self, viewport_width: float, viewport_height: float) -> Optional[LayoutNode]:
120
+ """Build and compute a layout tree without touching the backend.
121
+
122
+ Returns the synthetic viewport ``LayoutNode`` with all
123
+ descendants positioned, or ``None`` if nothing is mounted.
124
+ """
125
+ if self.root is None:
126
+ return None
127
+ roots = self._build_layout_list(self.root)
128
+ if not roots:
129
+ return None
130
+ viewport = LayoutNode(style={"width": viewport_width, "height": viewport_height}, children=list(roots))
131
+ calculate_layout(viewport, viewport_width, viewport_height)
132
+ return viewport
133
+
134
+ # ------------------------------------------------------------------
135
+ # Hooks used by the core
136
+ # ------------------------------------------------------------------
137
+
138
+ def _flush_ops(self) -> None: ... # pragma: no cover
139
+
140
+ @staticmethod
141
+ def _mark_layout_dirty(node: VNode) -> None:
142
+ node.layout_dirty = True
143
+ node.layout_node = None
144
+
145
+ # ------------------------------------------------------------------
146
+ # The pass
147
+ # ------------------------------------------------------------------
148
+
149
+ @profiled("layout")
150
+ def _run_layout(self) -> None:
151
+ """Build/refresh the layout tree, compute frames, and emit changed ones.
152
+
153
+ Wraps the user's native roots in a synthetic outer ``LayoutNode``
154
+ sized to the viewport so the root fills the screen by default.
155
+ Skipped until the host has supplied a viewport size.
156
+
157
+ The first native root's own frame is intentionally left alone:
158
+ its position and size are owned by the screen host (iOS places
159
+ it below the safe-area inset; Android attaches it with
160
+ ``MATCH_PARENT``).
161
+ """
162
+ root = self.root
163
+ if root is None:
164
+ return
165
+ viewport_w, viewport_h = self._viewport_size
166
+ if viewport_w <= 0 or viewport_h <= 0:
167
+ return
168
+
169
+ self._layout_pass_count += 1
170
+ if getattr(self.backend, "native_layout", False):
171
+ self.backend.compute_layout([node.tag for node in self._native_roots(root)], viewport_w, viewport_h)
172
+ return
173
+ layout_roots = self._build_layout_list_cached(root)
174
+ if layout_roots:
175
+ viewport = LayoutNode(style={"width": viewport_w, "height": viewport_h}, children=list(layout_roots))
176
+ viewport.dirty = True
177
+ calculate_layout(viewport, viewport_w, viewport_h)
178
+ for i, layout_root in enumerate(layout_roots):
179
+ if i == 0:
180
+ for child in layout_root.children:
181
+ self._collect_frames(child, 0.0, 0.0)
182
+ else:
183
+ self._collect_frames(layout_root, 0.0, 0.0)
184
+ self._layout_detached_subtrees(root, viewport_w, viewport_h)
185
+ self._clear_layout_dirty(root)
186
+
187
+ def _accept_native_layout(self, frames: list[list[float]]) -> None:
188
+ """Update refs and queue observations only for acknowledged native frames."""
189
+ for tag, x, y, width, height in frames:
190
+ node = self._tag_nodes.get(int(tag))
191
+ if node is None or not node.mounted:
192
+ continue
193
+ frame = (x, y, width, height)
194
+ node.last_frame = frame
195
+ ref = node.element.props.get("ref")
196
+ if ref is not None:
197
+ ref._pn_frame = frame
198
+ if "on_layout" in node.element.props:
199
+ self._pending_layout_events.append((int(tag), frame))
200
+ if not self._rendering:
201
+ self._dispatch_layout_events()
202
+
203
+ def _layout_detached_subtrees(self, node: VNode, viewport_w: float, viewport_h: float) -> None:
204
+ element = node.element
205
+ if isinstance(element.type, str) and element.type in DETACHED_TYPES:
206
+ active = bool(element.props.get("visible")) if element.type == "Modal" else True
207
+ if not active:
208
+ return
209
+ child_layouts: List[LayoutNode] = []
210
+ for child in node.children:
211
+ child_layouts.extend(self._build_layout_list(child))
212
+ if child_layouts:
213
+ viewport = LayoutNode(style={"width": viewport_w, "height": viewport_h}, children=child_layouts)
214
+ calculate_layout(viewport, viewport_w, viewport_h)
215
+ for c in viewport.children:
216
+ self._collect_frames(c, 0.0, 0.0)
217
+ for child in node.children:
218
+ self._layout_detached_subtrees(child, viewport_w, viewport_h)
219
+ return
220
+ for child in node.children:
221
+ self._layout_detached_subtrees(child, viewport_w, viewport_h)
222
+
223
+ def _build_layout_list_cached(self, node: VNode) -> List[LayoutNode]:
224
+ """Like ``_build_layout_list`` but reuses cached subtrees when clean."""
225
+ element = node.element
226
+ if not node.is_native:
227
+ out: List[LayoutNode] = []
228
+ for child in node.children:
229
+ out.extend(self._build_layout_list_cached(child))
230
+ return out
231
+ if element.type in DETACHED_TYPES:
232
+ return []
233
+
234
+ child_layouts: List[LayoutNode] = []
235
+ for child in node.children:
236
+ child_layouts.extend(self._build_layout_list_cached(child))
237
+
238
+ cached = node.layout_node
239
+ if cached is not None and not node.layout_dirty:
240
+ cached_children = self._direct_child_layouts(cached, element)
241
+ if len(cached_children) == len(child_layouts) and all(
242
+ a is b for a, b in zip(cached_children, child_layouts)
243
+ ):
244
+ return [cached]
245
+
246
+ layout = self._new_layout_node(node)
247
+ for child_layout in child_layouts:
248
+ if element.type == "ScrollView":
249
+ child_layout = self._wrap_scroll_axis(child_layout, self._scroll_axis(element))
250
+ child_layout.dirty = True
251
+ layout.children.append(child_layout)
252
+ node.layout_node = layout
253
+ return [layout]
254
+
255
+ def _build_layout_list(self, node: VNode) -> List[LayoutNode]:
256
+ """Build fresh (uncached) ``LayoutNode`` for ``node`` and its subtree."""
257
+ element = node.element
258
+ if not node.is_native:
259
+ out: List[LayoutNode] = []
260
+ for child in node.children:
261
+ out.extend(self._build_layout_list(child))
262
+ return out
263
+ if element.type in DETACHED_TYPES:
264
+ return []
265
+ layout = self._new_layout_node(node)
266
+ for child in node.children:
267
+ for child_layout in self._build_layout_list(child):
268
+ if element.type == "ScrollView":
269
+ child_layout = self._wrap_scroll_axis(child_layout, self._scroll_axis(element))
270
+ child_layout.dirty = True
271
+ layout.children.append(child_layout)
272
+ return [layout]
273
+
274
+ def _new_layout_node(self, node: VNode) -> LayoutNode:
275
+ element = node.element
276
+ layout = LayoutNode(style=extract_layout_style(element.props), user_data=node)
277
+ layout.dirty = True
278
+ if element.type == "ScrollView":
279
+ # Mark the scroll axis so the engine clamps the container's
280
+ # main-axis size to its parent's available space; otherwise
281
+ # the container grows to fit its content and nothing scrolls.
282
+ layout._pn_scroll_axis = self._scroll_axis(element)
283
+ if not node.children:
284
+ measure = self._make_measure_callback(node)
285
+ if measure is not None:
286
+ layout.measure = measure
287
+ return layout
288
+
289
+ @staticmethod
290
+ def _scroll_axis(element: Element) -> str:
291
+ return "x" if element.props.get("scroll_axis", "vertical") == "horizontal" else "y"
292
+
293
+ @staticmethod
294
+ def _direct_child_layouts(layout: LayoutNode, element: Element) -> List[LayoutNode]:
295
+ """Return the cached child layout nodes, unwrapping ScrollView wrappers."""
296
+ if element.type == "ScrollView":
297
+ out: List[LayoutNode] = []
298
+ for wrapper in layout.children:
299
+ out.extend(wrapper.children)
300
+ return out
301
+ return list(layout.children)
302
+
303
+ def _clear_layout_dirty(self, node: VNode) -> None:
304
+ node.layout_dirty = False
305
+ layout = node.layout_node
306
+ if layout is not None:
307
+ layout.dirty = False
308
+ for layout_child in layout.children:
309
+ layout_child.dirty = False
310
+ for child in node.children:
311
+ self._clear_layout_dirty(child)
312
+
313
+ @staticmethod
314
+ def _wrap_scroll_axis(child: LayoutNode, axis: str) -> LayoutNode:
315
+ """Wrap ``child`` so the layout engine treats one axis as unbounded."""
316
+ wrapper = LayoutNode(style={"flex_direction": "column" if axis == "y" else "row"}, user_data=None)
317
+ wrapper.children.append(child)
318
+ return wrapper
319
+
320
+ def _make_measure_callback(self, node: VNode) -> Optional[Callable[[float, float], Tuple[float, float]]]:
321
+ """Return a measure callback for ``node`` if it has an intrinsic size."""
322
+ if node.tag is None or node.element.type in {
323
+ "View",
324
+ "Row",
325
+ "Column",
326
+ "ScrollView",
327
+ "Modal",
328
+ "Portal",
329
+ "ScreenStack",
330
+ }:
331
+ return None
332
+ backend = self.backend
333
+ tag = node.tag
334
+
335
+ def measure(max_w: float, max_h: float) -> Tuple[float, float]:
336
+ cache = node.measure_cache
337
+ if cache is not None and cache[0] == max_w and cache[1] == max_h:
338
+ return (cache[2], cache[3])
339
+ try:
340
+ w, h = backend.measure_intrinsic(tag, max_w, max_h)
341
+ result = (float(w), float(h))
342
+ node.measure_cache = (max_w, max_h, result[0], result[1])
343
+ return result
344
+ except Exception:
345
+ return (0.0, 0.0)
346
+
347
+ return measure
348
+
349
+ def _collect_frames(self, layout_node: LayoutNode, parent_x: float, parent_y: float) -> None:
350
+ """Walk a positioned layout tree and emit ``SetFrameOp`` for changed frames.
351
+
352
+ Coordinates accumulate through transparent wrapper nodes (the
353
+ ScrollView axis wrapper) so the native view receives its
354
+ position relative to its true native parent.
355
+ """
356
+ node: Optional[VNode] = layout_node.user_data
357
+ if node is not None and node.tag is not None:
358
+ frame: Frame = (
359
+ layout_node.x + parent_x,
360
+ layout_node.y + parent_y,
361
+ layout_node.width,
362
+ layout_node.height,
363
+ )
364
+ if node.last_frame != frame:
365
+ node.last_frame = frame
366
+ self._ops.append(SetFrameOp(node.tag, *frame))
367
+ ref = node.element.props.get("ref")
368
+ if ref is not None and hasattr(ref, "current"):
369
+ try:
370
+ ref._pn_frame = frame
371
+ except Exception:
372
+ pass
373
+ if "on_layout" in node.element.props:
374
+ self._pending_layout_events.append((node.tag, frame))
375
+ child_x = child_y = 0.0
376
+ else:
377
+ child_x = layout_node.x + parent_x
378
+ child_y = layout_node.y + parent_y
379
+ for child in layout_node.children:
380
+ self._collect_frames(child, child_x, child_y)
381
+
382
+ def _dispatch_layout_events(self) -> None:
383
+ """Fire queued ``on_layout`` callbacks after frames were applied."""
384
+ if not self._pending_layout_events:
385
+ return
386
+ from ..events import dispatch_event
387
+
388
+ pending, self._pending_layout_events = self._pending_layout_events, []
389
+ for tag, frame in pending:
390
+ try:
391
+ dispatch_event(tag, "on_layout", {"x": frame[0], "y": frame[1], "width": frame[2], "height": frame[3]})
392
+ except Exception as exc:
393
+ diagnostics.report_error(exc, phase="event")
@@ -0,0 +1,266 @@
1
+ """Mounted-tree nodes and the pure helpers the reconciler shares.
2
+
3
+ [`VNode`][pythonnative.reconciler.VNode] pairs an
4
+ [`Element`][pythonnative.Element] with the identity of the native view
5
+ it produced (its **tag**) plus the bookkeeping the reconciler needs
6
+ across passes (layout cache, boundary state, hook state).
7
+
8
+ Everything in this module is side-effect free with respect to the
9
+ native layer.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import itertools
15
+ from typing import Any, Dict, List, Optional, Set, Tuple
16
+
17
+ from .. import diagnostics
18
+ from ..component import Component
19
+ from ..element import ERROR_BOUNDARY, FRAGMENT, SUSPENSE, Element, type_label
20
+ from ..hooks import Context, HookState
21
+ from ..layout import LayoutNode
22
+
23
+ __all__ = [
24
+ "DETACHED_TYPES",
25
+ "VNode",
26
+ "next_tag",
27
+ "normalize_children",
28
+ "shallow_equal_props",
29
+ ]
30
+
31
+ # Native element types whose subtree is laid out against the viewport
32
+ # in a detached pass instead of participating in the main layout flow.
33
+ # Their handlers host the children in a separately presented native
34
+ # container (a modal, an overlay, a pushed screen).
35
+ DETACHED_TYPES = frozenset({"Modal", "Portal"})
36
+
37
+ # Tags are globally unique so multiple reconcilers (screens, list rows)
38
+ # can share one registry without collisions.
39
+ _tag_counter = itertools.count(1)
40
+
41
+
42
+ def next_tag() -> int:
43
+ """Allocate a fresh, process-unique view tag."""
44
+ return next(_tag_counter)
45
+
46
+
47
+ def shallow_equal_props(old: dict, new: dict) -> bool:
48
+ """Return whether two prop dicts are equal under shallow comparison.
49
+
50
+ Used by [`memo`][pythonnative.memo] to skip re-rendering when none
51
+ of a component's props changed identity. Callables only count as
52
+ equal if they're the *same object*; fresh closures always invalidate
53
+ the memo (matching React's behavior; pair with
54
+ [`use_callback`][pythonnative.use_callback] when stability matters).
55
+ """
56
+ if old is new:
57
+ return True
58
+ if old.keys() != new.keys():
59
+ return False
60
+ for key, ov in old.items():
61
+ nv = new[key]
62
+ if ov is nv:
63
+ continue
64
+ if callable(ov) or callable(nv):
65
+ return False
66
+ try:
67
+ if ov != nv:
68
+ return False
69
+ except Exception:
70
+ return False
71
+ return True
72
+
73
+
74
+ def normalize_children(children: Any, owner: str = "") -> List[Element]:
75
+ """Normalize arbitrary render output into a flat list of Elements.
76
+
77
+ Accepts a single element, ``None``, ``True``/``False`` (both
78
+ skipped, enabling inline conditionals like ``cond and Text(...)``),
79
+ lists/tuples/generators (flattened recursively), and unkeyed
80
+ Fragments (expanded inline so they never touch the native tree).
81
+ Keyed Fragments are preserved so they can participate in keyed
82
+ reconciliation as a unit.
83
+
84
+ Non-Element values other than the above are dropped with a
85
+ dev-mode warning.
86
+ """
87
+ out: List[Element] = []
88
+
89
+ def add(item: Any) -> None:
90
+ if item is None or item is True or item is False:
91
+ return
92
+ if isinstance(item, Element):
93
+ if item.type is FRAGMENT and item.key is None:
94
+ for sub in item.children:
95
+ add(sub)
96
+ return
97
+ out.append(item)
98
+ return
99
+ if isinstance(item, (str, bytes)):
100
+ diagnostics.warn_once(
101
+ f"Ignoring bare string child {item!r}"
102
+ + (f" under {owner}" if owner else "")
103
+ + ". Wrap text in pn.Text(...).",
104
+ key=f"strchild:{owner}",
105
+ )
106
+ return
107
+ try:
108
+ iterator = iter(item)
109
+ except TypeError:
110
+ diagnostics.warn_once(
111
+ f"Ignoring non-Element child {item!r} ({type(item).__name__})"
112
+ + (f" under {owner}" if owner else "")
113
+ + ". Children must be Elements, iterables of Elements, or None/False for conditionals.",
114
+ key=f"badchild:{owner}:{type(item).__name__}",
115
+ )
116
+ return
117
+ for sub in iterator:
118
+ add(sub)
119
+
120
+ add(children)
121
+
122
+ if diagnostics.is_dev() and len(out) > 1:
123
+ seen: Set[Any] = set()
124
+ for el in out:
125
+ if el.key is None:
126
+ continue
127
+ if el.key in seen:
128
+ diagnostics.warn_once(
129
+ f"Duplicate key {el.key!r} among children"
130
+ + (f" of {owner}" if owner else "")
131
+ + ". Keys must be unique among siblings; duplicates break "
132
+ "keyed reconciliation and can cross-wire component state.",
133
+ key=f"dupkey:{owner}:{el.key!r}",
134
+ )
135
+ seen.add(el.key)
136
+ return out
137
+
138
+
139
+ class VNode:
140
+ """A mounted [`Element`][pythonnative.Element] plus its native identity.
141
+
142
+ The reconciler walks parallel trees of ``VNode`` and incoming
143
+ ``Element`` to compute the minimal set of native mutations.
144
+
145
+ Attributes:
146
+ element: The ``Element`` last rendered into this slot.
147
+ tag: Integer identity of the underlying native view. Native
148
+ elements own a fresh tag; transparent wrappers (components,
149
+ providers, boundaries, keyed fragments) delegate the tag of
150
+ their first native root. ``None`` when the subtree renders
151
+ no native view.
152
+ native_view: The platform-native view object, resolved from the
153
+ backend after commit. ``None`` for wrappers that rendered
154
+ nothing.
155
+ children: Ordered list of child ``VNode`` instances.
156
+ parent: The owning ``VNode``, or ``None`` for the tree root.
157
+ hook_state: The component's
158
+ [`HookState`][pythonnative.hooks.HookState] when the node
159
+ wraps a component, otherwise ``None``.
160
+ mounted: ``False`` once the node has been destroyed, so stale
161
+ entries in the reconciler's dirty set are skipped.
162
+ """
163
+
164
+ __slots__ = (
165
+ "element",
166
+ "tag",
167
+ "native_view",
168
+ "children",
169
+ "parent",
170
+ "hook_state",
171
+ "mounted",
172
+ "rendered",
173
+ "clean_props",
174
+ "measure_cache",
175
+ "last_frame",
176
+ "layout_node",
177
+ "layout_dirty",
178
+ "error",
179
+ "suspense_showing_fallback",
180
+ "suspense_hydration",
181
+ "suspense_waits",
182
+ )
183
+
184
+ def __init__(self, element: Element, children: Optional[List["VNode"]] = None, tag: Optional[int] = None) -> None:
185
+ self.element = element
186
+ self.tag = tag
187
+ self.native_view: Any = None
188
+ self.children: List[VNode] = children if children is not None else []
189
+ self.parent: Optional[VNode] = None
190
+ self.hook_state: Optional[HookState] = None
191
+ self.mounted: bool = True
192
+ # The normalized element list a component body last produced.
193
+ self.rendered: Optional[List[Element]] = None
194
+ # Native-safe props (events and reconciler-owned keys stripped)
195
+ # from the last commit; the baseline for prop diffing.
196
+ self.clean_props: Dict[str, Any] = {}
197
+ # Cache for the leaf intrinsic-size measure callback:
198
+ # ``(max_w, max_h, width, height)``. Invalidated whenever the
199
+ # node's props change, so unchanged leaves skip native
200
+ # ``measure_intrinsic`` calls entirely.
201
+ self.measure_cache: Optional[Tuple[float, float, float, float]] = None
202
+ # Last frame sent to the native side; unchanged frames are
203
+ # skipped (frame diffing).
204
+ self.last_frame: Optional[Tuple[float, float, float, float]] = None
205
+ # Cached LayoutNode reused across passes while the subtree is
206
+ # clean (see the layout mixin).
207
+ self.layout_node: Optional[LayoutNode] = None
208
+ # True when this node's layout-relevant props or child list
209
+ # changed since the last layout pass.
210
+ self.layout_dirty: bool = True
211
+ # For error-boundary nodes: the caught exception while the
212
+ # fallback is showing, else ``None``.
213
+ self.error: Optional[BaseException] = None
214
+ # For Suspense nodes: whether the fallback is showing, the hook
215
+ # states of suspended descendants preserved for the next retry
216
+ # (keyed by ``(component identity, element key)``), and the ids
217
+ # of waitables already wired to trigger a retry.
218
+ self.suspense_showing_fallback: bool = False
219
+ self.suspense_hydration: Optional[Dict[Tuple[int, Any], List[HookState]]] = None
220
+ self.suspense_waits: Optional[Set[int]] = None
221
+
222
+ # ------------------------------------------------------------------
223
+ # Classification helpers
224
+ # ------------------------------------------------------------------
225
+
226
+ @property
227
+ def is_native(self) -> bool:
228
+ """Whether this node owns a native view."""
229
+ return isinstance(self.element.type, str)
230
+
231
+ @property
232
+ def is_component(self) -> bool:
233
+ """Whether this node renders a user component (a ``@component`` function)."""
234
+ return isinstance(self.element.type, Component)
235
+
236
+ @property
237
+ def is_provider(self) -> bool:
238
+ """Whether this node is a context provider."""
239
+ return isinstance(self.element.type, Context)
240
+
241
+ @property
242
+ def is_error_boundary(self) -> bool:
243
+ """Whether this node is an ``ErrorBoundary``."""
244
+ return self.element.type is ERROR_BOUNDARY
245
+
246
+ @property
247
+ def is_suspense(self) -> bool:
248
+ """Whether this node is a ``Suspense`` boundary."""
249
+ return self.element.type is SUSPENSE
250
+
251
+ @property
252
+ def label(self) -> str:
253
+ """Human-readable name of the element type (for diagnostics and tree dumps)."""
254
+ return type_label(self.element.type)
255
+
256
+ def depth(self) -> int:
257
+ """Return the number of ancestors above this node (the root has depth 0)."""
258
+ depth = 0
259
+ node = self.parent
260
+ while node is not None:
261
+ depth += 1
262
+ node = node.parent
263
+ return depth
264
+
265
+ def __repr__(self) -> str:
266
+ return f"VNode({self.label!r}, tag={self.tag}, children={len(self.children)})"