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,659 @@
1
+ """Stack, tab, and drawer navigators built on one shared core.
2
+
3
+ All three navigators are ordinary components. Each owns a
4
+ [`NavigationState`][pythonnative.navigation.NavigationState] in
5
+ ``use_state``, wraps it in a
6
+ [`NavigatorCore`][pythonnative.navigation.handle.NavigatorCore], and
7
+ renders its screens under a
8
+ [`Navigation`][pythonnative.Navigation] provider. Only the *rendering*
9
+ differs:
10
+
11
+ - **Stack**: keeps every route mounted (hidden below the top one) so
12
+ popping back restores the previous screen's state, and draws a
13
+ header with a back button. When the stack is the root of a native
14
+ host it pushes real native screens instead and lets the host draw
15
+ the navigation bar.
16
+ - **Tabs**: keeps visited tabs alive and hidden (``lazy`` mounts them
17
+ on first focus; ``unmount_on_blur`` opts out), and renders the
18
+ native ``TabBar``.
19
+ - **Drawer**: like tabs, with a slide-in menu instead of a tab bar.
20
+
21
+ Inactive screens read ``False`` from
22
+ [`use_is_focused`][pythonnative.use_is_focused]; ``focus`` and ``blur``
23
+ listeners fire as the active route changes.
24
+ """
25
+
26
+ from __future__ import annotations
27
+
28
+ from typing import Any, Callable, Dict, List, Literal, Optional, Sequence, Tuple
29
+
30
+ from ..component import component
31
+ from ..element import Element, Node
32
+ from ..hooks import use_back_handler, use_context, use_effect, use_memo, use_ref, use_state
33
+ from .container import ContainerContext
34
+ from .handle import FocusContext, Navigation, NavigationContext, NavigatorCore
35
+ from .host import HostContext
36
+ from .screen import ScreenDef, ScreenOptions, Unpack
37
+ from .state import NavigationState, Route
38
+
39
+ __all__ = [
40
+ "DrawerNavigator",
41
+ "StackNavigator",
42
+ "TabNavigator",
43
+ "create_drawer_navigator",
44
+ "create_stack_navigator",
45
+ "create_tab_navigator",
46
+ ]
47
+
48
+ NavigatorKind = Literal["stack", "tab", "drawer"]
49
+
50
+ _HEADER_HEIGHT = 44.0
51
+ _DRAWER_WIDTH = 280.0
52
+
53
+
54
+ # ======================================================================
55
+ # Shared core hook
56
+ # ======================================================================
57
+
58
+
59
+ def _use_navigator(
60
+ kind: NavigatorKind,
61
+ screens: Sequence[ScreenDef],
62
+ initial_route: Optional[str],
63
+ ) -> Tuple[NavigatorCore, NavigationState, bool]:
64
+ """Create (once) and refresh the navigator core for the calling component.
65
+
66
+ Returns ``(core, state, parent_focused)``.
67
+ """
68
+ screen_map: Dict[str, ScreenDef] = {s.name: s for s in screens}
69
+ parent = use_context(NavigationContext)
70
+ host = use_context(HostContext)
71
+ parent_focused = use_context(FocusContext)
72
+ container = use_context(ContainerContext) if parent is None else None
73
+ is_native_root = kind == "stack" and parent is None and host is not None
74
+ first = initial_route if initial_route in screen_map else next(iter(screen_map))
75
+
76
+ def default_state() -> NavigationState:
77
+ if kind == "stack":
78
+ return NavigationState([Route(first, screen_map[first].initial_params)])
79
+ routes = [Route(s.name, s.initial_params) for s in screens]
80
+ return NavigationState(routes, [s.name for s in screens].index(first))
81
+
82
+ def initial_state() -> NavigationState:
83
+ if is_native_root:
84
+ serialized = host.initial_navigation_state()
85
+ if serialized:
86
+ try:
87
+ restored = NavigationState.from_dict(serialized)
88
+ except Exception:
89
+ restored = None
90
+ if restored is not None and all(r.name in screen_map for r in restored.routes):
91
+ return restored
92
+ seed = parent.route.state if parent is not None else (container.initial_state if container else None)
93
+ if seed is not None:
94
+ seeded = _apply_seed(kind, screen_map, default_state(), seed)
95
+ if seeded is not None:
96
+ return seeded
97
+ return default_state()
98
+
99
+ state, set_state = use_state(initial_state)
100
+ _version, set_version = use_state(0)
101
+ core: NavigatorCore = use_memo(
102
+ lambda: NavigatorCore(
103
+ kind,
104
+ screen_map,
105
+ state,
106
+ set_state,
107
+ parent,
108
+ host,
109
+ request_render=lambda: set_version(lambda v: v + 1),
110
+ ),
111
+ [],
112
+ )
113
+ core.update(screen_map, state, set_state, parent, host)
114
+ _use_focus_events(core, state, parent_focused)
115
+ _use_seed_updates(core, parent)
116
+ _use_container(core, state, container)
117
+ return core, state, parent_focused
118
+
119
+
120
+ def _apply_seed(
121
+ kind: NavigatorKind,
122
+ screen_map: Dict[str, ScreenDef],
123
+ base: NavigationState,
124
+ seed: NavigationState,
125
+ ) -> Optional[NavigationState]:
126
+ """Merge a seed state (deep link, ``navigate(screen=...)``) into ``base``.
127
+
128
+ Stacks keep their initial route underneath so back works; tabs and
129
+ drawers switch to the seeded route and merge its params. Unknown
130
+ route names make the seed invalid (``None``).
131
+ """
132
+ if any(r.name not in screen_map for r in seed.routes):
133
+ return None
134
+ if kind == "stack":
135
+ routes = list(seed.routes)
136
+ if routes[0].name != base.routes[0].name:
137
+ routes.insert(0, base.routes[0])
138
+ return NavigationState(routes)
139
+ target = seed.current
140
+ return base.jump_to(target.name, target.params, target.state)
141
+
142
+
143
+ def _use_seed_updates(core: NavigatorCore, parent: Optional[Navigation]) -> None:
144
+ """Follow later ``navigate("Nested", screen=...)`` calls made on the parent."""
145
+ seed = parent.route.state if parent is not None else None
146
+ applied: Any = use_ref(seed)
147
+
148
+ def run() -> None:
149
+ if seed is None or seed is applied.current:
150
+ return
151
+ applied.current = seed
152
+ target = seed.current
153
+ if target.name in core.screens:
154
+ core.navigate(target.name, target.params, target.state)
155
+
156
+ use_effect(run, [seed])
157
+
158
+
159
+ def _use_container(core: NavigatorCore, state: NavigationState, container: Any) -> None:
160
+ """Attach a root navigator to its container (deep links, ``on_state_change``)."""
161
+
162
+ def attach() -> Any:
163
+ return container.attach_root(core) if container is not None else None
164
+
165
+ use_effect(attach, [container])
166
+
167
+ def report() -> None:
168
+ if container is not None and container.on_state_change is not None:
169
+ container.on_state_change(state)
170
+
171
+ use_effect(report, [state])
172
+
173
+ def cache() -> None:
174
+ publish = getattr(core.host, "cache_navigation_state", None)
175
+ if core.is_native_root and publish is not None:
176
+ publish(state.to_dict())
177
+
178
+ use_effect(cache, [state])
179
+
180
+
181
+ def _use_focus_events(core: NavigatorCore, state: NavigationState, parent_focused: bool) -> None:
182
+ """Emit ``blur`` / ``focus`` / ``state`` as the active route or focus changes."""
183
+ last: Any = use_ref(None)
184
+
185
+ def run() -> None:
186
+ active: Optional[Route] = state.current if parent_focused else None
187
+ prev: Optional[Route] = last.current
188
+ if (prev.key if prev else None) == (active.key if active else None):
189
+ return
190
+ if prev is not None:
191
+ core.emit(prev, "blur")
192
+ if active is not None:
193
+ core.emit(active, "focus")
194
+ last.current = active
195
+
196
+ use_effect(run, [state.current.key, parent_focused])
197
+
198
+ def emit_state() -> None:
199
+ core.emit(state.current, "state", {"state": state})
200
+
201
+ use_effect(emit_state, [state])
202
+
203
+
204
+ def _use_host_options(core: NavigatorCore, state: NavigationState) -> None:
205
+ """Push the active route's header options to the native host (root stacks only)."""
206
+ options = core.options_for(state.current) if core.is_native_root else None
207
+ signature = _options_signature(options)
208
+
209
+ def apply() -> None:
210
+ if options is None or core.host is None:
211
+ return
212
+ try:
213
+ core.host.set_screen_options(options)
214
+ except Exception:
215
+ pass
216
+
217
+ use_effect(apply, [signature, state.current.key])
218
+
219
+
220
+ def _options_signature(options: Optional[Dict[str, Any]]) -> Any:
221
+ if options is None:
222
+ return None
223
+ out = []
224
+ for key in sorted(options):
225
+ value = options[key]
226
+ out.append((key, value if isinstance(value, (str, int, float, bool, type(None))) else id(value)))
227
+ return tuple(out)
228
+
229
+
230
+ def _screen_element(
231
+ core: NavigatorCore,
232
+ route: Route,
233
+ *,
234
+ active: bool,
235
+ parent_focused: bool,
236
+ ) -> Element:
237
+ """Render ``route``'s component under its navigation and focus providers."""
238
+ screen = core.screens.get(route.name)
239
+ if screen is None:
240
+ from ..components import Text
241
+
242
+ body: Node = Text(f"Unknown route: {route.name}")
243
+ else:
244
+ body = screen.component()
245
+ handle = core.handle_for(route)
246
+ return NavigationContext.Provider(handle, FocusContext.Provider(parent_focused and active, body), key=route.key)
247
+
248
+
249
+ def _hidden_style(active: bool) -> Dict[str, Any]:
250
+ return {"flex": 1, "display": "flex" if active else "none"}
251
+
252
+
253
+ # ======================================================================
254
+ # Stack
255
+ # ======================================================================
256
+
257
+
258
+ @component
259
+ def _StackHeader(*, core: NavigatorCore, route: Route, options: Dict[str, Any]) -> Optional[Element]:
260
+ from ..components import Pressable, Text, View
261
+
262
+ if options.get("header_shown", True) is False:
263
+ return None
264
+ handle = core.handle_for(route)
265
+ style = {
266
+ "height": _HEADER_HEIGHT,
267
+ "flex_direction": "row",
268
+ "align_items": "center",
269
+ "padding_horizontal": 8,
270
+ "background_color": "#F8F8F8",
271
+ "border_bottom_width": 0.5,
272
+ "border_color": "#C7C7CC",
273
+ **(options.get("header_style") or {}),
274
+ }
275
+ tint = options.get("header_tint_color", "#007AFF")
276
+ title_style = {
277
+ "font_size": 17,
278
+ "bold": True,
279
+ "flex": 1,
280
+ "text_align": "center",
281
+ **(options.get("header_title_style") or {}),
282
+ }
283
+
284
+ def slot(value: Any) -> Optional[Element]:
285
+ if value is None:
286
+ return None
287
+ return value() if callable(value) and not isinstance(value, Element) else value
288
+
289
+ left = slot(options.get("header_left"))
290
+ if left is None and handle.can_go_back() and options.get("header_back_visible", True):
291
+ back_title = options.get("header_back_title") or "Back"
292
+ left = Pressable(
293
+ Text(f"\u2039 {back_title}", style={"color": tint, "font_size": 17}),
294
+ on_press=handle.go_back,
295
+ accessibility_label="Back",
296
+ )
297
+ right = slot(options.get("header_right"))
298
+ return View(
299
+ View(left, style={"min_width": 60, "align_items": "flex_start"}),
300
+ Text(str(options.get("title", route.name)), style=title_style),
301
+ View(right, style={"min_width": 60, "align_items": "flex_end"}),
302
+ style=style,
303
+ )
304
+
305
+
306
+ @component
307
+ def _StackNavigatorImpl(*, screens: Tuple[ScreenDef, ...], initial_route: Optional[str] = None) -> Element:
308
+ from ..components import View
309
+
310
+ if not screens:
311
+ return View(style={"flex": 1})
312
+ core, state, parent_focused = _use_navigator("stack", screens, initial_route)
313
+
314
+ def on_back() -> bool:
315
+ if len(state) > 1:
316
+ return core.pop(1, source="back")
317
+ return False
318
+
319
+ use_back_handler(on_back)
320
+
321
+ current = state.current
322
+ stack_ref = use_ref(None)
323
+ if core.is_native_root:
324
+
325
+ def native_back(count: int = 1) -> None:
326
+ if not core.pop(count, source="back") and stack_ref.current is not None:
327
+ from ..native_views import get_registry
328
+
329
+ get_registry().command(stack_ref.current.tag, "restore_stack")
330
+
331
+ return Element(
332
+ "ScreenStack",
333
+ {"flex": 1, "on_native_back": native_back, "ref": stack_ref},
334
+ [
335
+ Element(
336
+ "Screen",
337
+ {"flex": 1, "active": route is current, "route_key": route.key, **core.options_for(route)},
338
+ [_screen_element(core, route, active=route is current, parent_focused=parent_focused)],
339
+ key=route.key,
340
+ )
341
+ for route in state.routes
342
+ ],
343
+ )
344
+
345
+ layers: List[Element] = []
346
+ for route in state.routes:
347
+ active = route is current
348
+ header = _StackHeader(core=core, route=route, options=core.options_for(route))
349
+ layers.append(
350
+ View(
351
+ header,
352
+ View(_screen_element(core, route, active=active, parent_focused=parent_focused), style={"flex": 1}),
353
+ style=_hidden_style(active),
354
+ key=route.key,
355
+ )
356
+ )
357
+ return View(*layers, style={"flex": 1})
358
+
359
+
360
+ class StackNavigator:
361
+ """Factory returned by [`create_stack_navigator`][pythonnative.create_stack_navigator]."""
362
+
363
+ __slots__ = ()
364
+
365
+ @staticmethod
366
+ def Screen(
367
+ name: str,
368
+ component: Callable[[], Any],
369
+ *,
370
+ options: Any = None,
371
+ initial_params: Optional[Dict[str, Any]] = None,
372
+ **option_kwargs: Unpack[ScreenOptions],
373
+ ) -> ScreenDef:
374
+ """Define a screen. ``options`` may be a dict or ``(route) -> dict``; keywords merge on top."""
375
+ return ScreenDef(name, component, options=options, initial_params=initial_params, **option_kwargs)
376
+
377
+ @staticmethod
378
+ def Navigator(*screens: ScreenDef, initial_route: Optional[str] = None, key: Optional[str] = None) -> Element:
379
+ """Render the stack with the given screens (the first, or ``initial_route``, shows first)."""
380
+ return _StackNavigatorImpl(screens=tuple(screens), initial_route=initial_route).with_key(key)
381
+
382
+
383
+ def create_stack_navigator() -> StackNavigator:
384
+ """Create a stack navigator: push and pop screens with history.
385
+
386
+ At the root of a native host the stack pushes real native screens
387
+ (``UINavigationController`` on iOS, fragments on Android), so users
388
+ get system transitions and swipe-back for free. Nested stacks are
389
+ drawn in Python with their own header.
390
+
391
+ Example:
392
+ ```python
393
+ import pythonnative as pn
394
+
395
+ Stack = pn.create_stack_navigator()
396
+
397
+ @pn.component
398
+ def App():
399
+ return pn.NavigationContainer(
400
+ Stack.Navigator(
401
+ Stack.Screen("Home", HomeScreen, title="Home"),
402
+ Stack.Screen("Detail", DetailScreen, title="Detail"),
403
+ )
404
+ )
405
+ ```
406
+ """
407
+ return StackNavigator()
408
+
409
+
410
+ # ======================================================================
411
+ # Keep-alive helpers shared by tabs and drawers
412
+ # ======================================================================
413
+
414
+
415
+ def _use_visited(state: NavigationState) -> Any:
416
+ """Track which route keys have been active at least once (for ``lazy``)."""
417
+ visited: Any = use_ref(None)
418
+ if visited.current is None:
419
+ visited.current = set()
420
+ visited.current.add(state.current.key)
421
+ live = {r.key for r in state.routes}
422
+ visited.current.intersection_update(live)
423
+ return visited.current
424
+
425
+
426
+ def _render_keep_alive(
427
+ core: NavigatorCore, state: NavigationState, parent_focused: bool, visited: Any
428
+ ) -> List[Element]:
429
+ from ..components import View
430
+
431
+ out: List[Element] = []
432
+ for route in state.routes:
433
+ active = route is state.current
434
+ options = core.options_for(route)
435
+ if not active:
436
+ if options.get("unmount_on_blur", False):
437
+ continue
438
+ if options.get("lazy", True) and route.key not in visited:
439
+ continue
440
+ out.append(
441
+ View(
442
+ _screen_element(core, route, active=active, parent_focused=parent_focused),
443
+ style=_hidden_style(active),
444
+ key=route.key,
445
+ )
446
+ )
447
+ return out
448
+
449
+
450
+ # ======================================================================
451
+ # Tabs
452
+ # ======================================================================
453
+
454
+
455
+ @component
456
+ def _TabNavigatorImpl(*, screens: Tuple[ScreenDef, ...], initial_route: Optional[str] = None) -> Element:
457
+ from ..components import View
458
+
459
+ if not screens:
460
+ return View(style={"flex": 1})
461
+ core, state, parent_focused = _use_navigator("tab", screens, initial_route)
462
+ visited = _use_visited(state)
463
+
464
+ items: List[Dict[str, Any]] = []
465
+ for route in state.routes:
466
+ options = core.options_for(route)
467
+ item: Dict[str, Any] = {
468
+ "name": route.name,
469
+ "title": options.get("tab_bar_label") or options.get("title", route.name),
470
+ }
471
+ icon = options.get("tab_bar_icon")
472
+ if icon is not None:
473
+ item["icon"] = icon
474
+ badge = options.get("tab_bar_badge")
475
+ if badge is not None:
476
+ item["badge"] = str(badge)
477
+ items.append(item)
478
+
479
+ def on_tab_select(name: str) -> None:
480
+ core.navigate(name, {})
481
+
482
+ tab_bar = Element(
483
+ "TabBar",
484
+ {"items": items, "active_tab": state.current.name, "on_tab_select": on_tab_select},
485
+ [],
486
+ key="__tab_bar__",
487
+ )
488
+ return View(
489
+ View(*_render_keep_alive(core, state, parent_focused, visited), style={"flex": 1}),
490
+ tab_bar,
491
+ style={"flex": 1, "flex_direction": "column"},
492
+ )
493
+
494
+
495
+ class TabNavigator:
496
+ """Factory returned by [`create_tab_navigator`][pythonnative.create_tab_navigator]."""
497
+
498
+ __slots__ = ()
499
+
500
+ @staticmethod
501
+ def Screen(
502
+ name: str,
503
+ component: Callable[[], Any],
504
+ *,
505
+ options: Any = None,
506
+ initial_params: Optional[Dict[str, Any]] = None,
507
+ **option_kwargs: Unpack[ScreenOptions],
508
+ ) -> ScreenDef:
509
+ """Define a tab. ``options`` may be a dict or ``(route) -> dict``; keywords merge on top."""
510
+ return ScreenDef(name, component, options=options, initial_params=initial_params, **option_kwargs)
511
+
512
+ @staticmethod
513
+ def Navigator(*screens: ScreenDef, initial_route: Optional[str] = None, key: Optional[str] = None) -> Element:
514
+ """Render the tab bar with the given screens (the first, or ``initial_route``, is selected first)."""
515
+ return _TabNavigatorImpl(screens=tuple(screens), initial_route=initial_route).with_key(key)
516
+
517
+
518
+ def create_tab_navigator() -> TabNavigator:
519
+ """Create a tab navigator with a native tab bar.
520
+
521
+ Tabs stay mounted once visited (hidden while inactive) so switching
522
+ back restores scroll position and state. Use ``lazy=False`` on a
523
+ screen to mount it eagerly, or ``unmount_on_blur=True`` to tear it
524
+ down when it loses focus.
525
+
526
+ Example:
527
+ ```python
528
+ Tab = pn.create_tab_navigator()
529
+
530
+ Tab.Navigator(
531
+ Tab.Screen("Home", HomeScreen, title="Home", tab_bar_icon="house.fill"),
532
+ Tab.Screen("Settings", SettingsScreen, title="Settings"),
533
+ )
534
+ ```
535
+ """
536
+ return TabNavigator()
537
+
538
+
539
+ # ======================================================================
540
+ # Drawer
541
+ # ======================================================================
542
+
543
+
544
+ @component
545
+ def _DrawerNavigatorImpl(
546
+ *,
547
+ screens: Tuple[ScreenDef, ...],
548
+ initial_route: Optional[str] = None,
549
+ drawer_width: float = _DRAWER_WIDTH,
550
+ ) -> Element:
551
+ from ..components import Pressable, Text, View
552
+
553
+ if not screens:
554
+ return View(style={"flex": 1})
555
+ core, state, parent_focused = _use_navigator("drawer", screens, initial_route)
556
+ visited = _use_visited(state)
557
+ drawer_open, set_drawer_open = use_state(False)
558
+ core.drawer_open = drawer_open
559
+ core._set_drawer_open = set_drawer_open
560
+
561
+ def on_back() -> bool:
562
+ if drawer_open:
563
+ set_drawer_open(False)
564
+ return True
565
+ return False
566
+
567
+ use_back_handler(on_back)
568
+
569
+ content = View(*_render_keep_alive(core, state, parent_focused, visited), style={"flex": 1})
570
+ if not drawer_open:
571
+ return View(content, style={"flex": 1})
572
+
573
+ def select(name: str) -> Callable[[], None]:
574
+ def _select() -> None:
575
+ core.navigate(name, {})
576
+ set_drawer_open(False)
577
+
578
+ return _select
579
+
580
+ rows: List[Element] = []
581
+ for route in state.routes:
582
+ options = core.options_for(route)
583
+ active = route is state.current
584
+ rows.append(
585
+ Pressable(
586
+ Text(
587
+ str(options.get("title", route.name)),
588
+ style={"font_size": 16, "color": "#007AFF" if active else "#1C1C1E", "bold": active},
589
+ ),
590
+ on_press=select(route.name),
591
+ style={
592
+ "padding_vertical": 14,
593
+ "padding_horizontal": 20,
594
+ "background_color": "#EEF3FF" if active else "#00000000",
595
+ },
596
+ key=f"__drawer_{route.key}",
597
+ )
598
+ )
599
+ panel = View(
600
+ *rows,
601
+ style={
602
+ "width": drawer_width,
603
+ "background_color": "#FFFFFF",
604
+ "padding_top": 24,
605
+ "border_right_width": 0.5,
606
+ "border_color": "#C7C7CC",
607
+ },
608
+ )
609
+ scrim = Pressable(on_press=lambda: set_drawer_open(False), style={"flex": 1, "background_color": "#00000040"})
610
+ return View(
611
+ content,
612
+ View(
613
+ panel,
614
+ scrim,
615
+ style={"position": "absolute", "top": 0, "left": 0, "right": 0, "bottom": 0, "flex_direction": "row"},
616
+ ),
617
+ style={"flex": 1},
618
+ )
619
+
620
+
621
+ class DrawerNavigator:
622
+ """Factory returned by [`create_drawer_navigator`][pythonnative.create_drawer_navigator]."""
623
+
624
+ __slots__ = ()
625
+
626
+ @staticmethod
627
+ def Screen(
628
+ name: str,
629
+ component: Callable[[], Any],
630
+ *,
631
+ options: Any = None,
632
+ initial_params: Optional[Dict[str, Any]] = None,
633
+ **option_kwargs: Unpack[ScreenOptions],
634
+ ) -> ScreenDef:
635
+ """Define a drawer screen. ``options`` may be a dict or ``(route) -> dict``; keywords merge on top."""
636
+ return ScreenDef(name, component, options=options, initial_params=initial_params, **option_kwargs)
637
+
638
+ @staticmethod
639
+ def Navigator(
640
+ *screens: ScreenDef,
641
+ initial_route: Optional[str] = None,
642
+ drawer_width: float = _DRAWER_WIDTH,
643
+ key: Optional[str] = None,
644
+ ) -> Element:
645
+ """Render the drawer with the given screens (the first, or ``initial_route``, shows first)."""
646
+ return _DrawerNavigatorImpl(
647
+ screens=tuple(screens), initial_route=initial_route, drawer_width=drawer_width
648
+ ).with_key(key)
649
+
650
+
651
+ def create_drawer_navigator() -> DrawerNavigator:
652
+ """Create a drawer navigator: sibling screens behind a slide-in menu.
653
+
654
+ The handle returned by [`use_navigation`][pythonnative.use_navigation]
655
+ inside a drawer screen is a
656
+ [`DrawerNavigation`][pythonnative.navigation.DrawerNavigation] with
657
+ ``open_drawer()``, ``close_drawer()``, and ``toggle_drawer()``.
658
+ """
659
+ return DrawerNavigator()