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,540 @@
1
+ """The [`Navigation`][pythonnative.Navigation] handle and the navigator core behind it.
2
+
3
+ Every screen rendered by a navigator receives a ``Navigation`` object
4
+ through [`use_navigation`][pythonnative.use_navigation]. The handle is
5
+ scoped to the screen's route (so ``add_listener("focus", ...)`` fires
6
+ for *that* screen) and forwards every action to the
7
+ [`NavigatorCore`][pythonnative.navigation.handle.NavigatorCore] that
8
+ owns the navigator's state.
9
+
10
+ Actions the core can't satisfy (an unknown route, popping past the
11
+ first screen) bubble to the parent navigator, so a stack nested in a
12
+ tab still pops correctly and ``navigate("Settings")`` from deep inside
13
+ one tab can switch to another.
14
+
15
+ When the core belongs to the **root stack of a native host** it
16
+ mutates its own state for pushes and pops: it asks the host to push or
17
+ pop a real native screen carrying the serialized next state, and the
18
+ new screen's navigator boots from that state.
19
+ """
20
+
21
+ from __future__ import annotations
22
+
23
+ from typing import Any, Callable, Dict, List, Literal, Mapping, Optional, Protocol, Sequence, Tuple, Union
24
+
25
+ from .. import diagnostics
26
+ from ..hooks import Context, create_context
27
+ from .screen import ScreenDef
28
+ from .state import NavigationState, Route
29
+
30
+ __all__ = [
31
+ "DrawerNavigation",
32
+ "FocusContext",
33
+ "HostNavigator",
34
+ "Navigation",
35
+ "NavigationContext",
36
+ "NavigationEvent",
37
+ "NavigatorCore",
38
+ "TabNavigation",
39
+ ]
40
+
41
+ NavigatorKind = Literal["stack", "tab", "drawer"]
42
+ EventName = Literal["focus", "blur", "before_remove", "state"]
43
+ Listener = Callable[["NavigationEvent"], None]
44
+
45
+
46
+ class HostNavigator(Protocol):
47
+ """What a root stack needs from the native screen host.
48
+
49
+ Hosts and FakeHost publish application focus and cached navigation state.
50
+ Screen presentation belongs to the logical tree and its native containers.
51
+ """
52
+
53
+ is_focused: bool
54
+
55
+ def initial_navigation_state(self) -> Optional[Dict[str, Any]]:
56
+ """The serialized state this screen was pushed with, if any."""
57
+ ...
58
+
59
+ def set_screen_options(self, options: Dict[str, Any]) -> None:
60
+ """Apply header options (``title`` and friends) to the native bar."""
61
+ ...
62
+
63
+ def add_focus_listener(self, callback: Callable[[bool], None]) -> Callable[[], None]:
64
+ """Subscribe to the host covering / revealing this screen; returns an unsubscribe."""
65
+ ...
66
+
67
+
68
+ class NavigationEvent:
69
+ """Payload delivered to ``add_listener`` callbacks.
70
+
71
+ Attributes:
72
+ type: ``"focus"``, ``"blur"``, ``"before_remove"``, or ``"state"``.
73
+ route: The route the event concerns.
74
+ data: Extra event data (``before_remove`` carries the
75
+ ``action`` that caused it).
76
+ """
77
+
78
+ __slots__ = ("type", "route", "data", "default_prevented")
79
+
80
+ def __init__(self, type_: str, route: Route, data: Optional[Mapping[str, Any]] = None) -> None:
81
+ self.type = type_
82
+ self.route = route
83
+ self.data: Dict[str, Any] = dict(data or {})
84
+ self.default_prevented = False
85
+
86
+ def prevent_default(self) -> None:
87
+ """Cancel the action (only meaningful for ``before_remove``)."""
88
+ self.default_prevented = True
89
+
90
+ def __repr__(self) -> str:
91
+ return f"NavigationEvent({self.type!r}, {self.route.name!r})"
92
+
93
+
94
+ class NavigatorCore:
95
+ """State machine shared by every ``Navigation`` handle a navigator hands out.
96
+
97
+ Owned by the navigator component: created once per mount, updated
98
+ every render with the latest state and setter (see ``update``).
99
+ """
100
+
101
+ def __init__(
102
+ self,
103
+ kind: NavigatorKind,
104
+ screens: Mapping[str, ScreenDef],
105
+ state: NavigationState,
106
+ set_state: Callable[[Any], None],
107
+ parent: Optional["Navigation"] = None,
108
+ host: Optional[HostNavigator] = None,
109
+ request_render: Optional[Callable[[], None]] = None,
110
+ ) -> None:
111
+ self.kind = kind
112
+ self.screens: Dict[str, ScreenDef] = dict(screens)
113
+ self.state = state
114
+ self._set_state = set_state
115
+ self.parent = parent
116
+ self.host = host
117
+ self._request_render = request_render
118
+ self._listeners: Dict[Tuple[str, str], List[Listener]] = {}
119
+ # ``set_options`` results, keyed by route key.
120
+ self.runtime_options: Dict[str, Dict[str, Any]] = {}
121
+ self._handles: Dict[str, Navigation] = {}
122
+ self.drawer_open = False
123
+ self._set_drawer_open: Optional[Callable[[bool], None]] = None
124
+ self.on_state_change: Optional[Callable[[NavigationState], None]] = None
125
+
126
+ # ------------------------------------------------------------------
127
+ # Wiring from the owning component
128
+ # ------------------------------------------------------------------
129
+
130
+ def update(
131
+ self,
132
+ screens: Mapping[str, ScreenDef],
133
+ state: NavigationState,
134
+ set_state: Callable[[Any], None],
135
+ parent: Optional["Navigation"],
136
+ host: Optional[HostNavigator],
137
+ ) -> None:
138
+ """Sync the core with the owning component's latest render.
139
+
140
+ Handles and ``set_options`` overrides for routes no longer in ``state`` are dropped.
141
+ """
142
+ self.screens = dict(screens)
143
+ self.state = state
144
+ self._set_state = set_state
145
+ self.parent = parent
146
+ self.host = host
147
+ live = {r.key for r in state.routes}
148
+ for key in list(self._handles):
149
+ if key not in live:
150
+ del self._handles[key]
151
+ for key in list(self.runtime_options):
152
+ if key not in live:
153
+ del self.runtime_options[key]
154
+
155
+ @property
156
+ def is_native_root(self) -> bool:
157
+ """Whether this core drives a native screen stack through the host."""
158
+ return self.kind == "stack" and self.host is not None and self.parent is None
159
+
160
+ def handle_for(self, route: Route) -> "Navigation":
161
+ """The (cached) handle scoped to ``route``."""
162
+ handle = self._handles.get(route.key)
163
+ if handle is None:
164
+ cls = {"tab": TabNavigation, "drawer": DrawerNavigation}.get(self.kind, Navigation)
165
+ handle = cls(self, route.key)
166
+ self._handles[route.key] = handle
167
+ return handle
168
+
169
+ def route_by_key(self, key: str) -> Route:
170
+ """Return the route with ``key``, falling back to the active route once it has left the state."""
171
+ for route in self.state.routes:
172
+ if route.key == key:
173
+ return route
174
+ return self.state.current
175
+
176
+ def options_for(self, route: Route) -> Dict[str, Any]:
177
+ """Static screen options merged with any ``set_options`` overrides."""
178
+ screen = self.screens.get(route.name)
179
+ options = screen.resolve_options(route) if screen is not None else {}
180
+ options.update(self.runtime_options.get(route.key, {}))
181
+ return options
182
+
183
+ # ------------------------------------------------------------------
184
+ # Events
185
+ # ------------------------------------------------------------------
186
+
187
+ def add_listener(self, route_key: str, event: str, listener: Listener) -> Callable[[], None]:
188
+ """Subscribe ``listener`` to ``event`` for the route with ``route_key``; returns an unsubscribe callable."""
189
+ bucket = self._listeners.setdefault((route_key, event), [])
190
+ bucket.append(listener)
191
+
192
+ def remove() -> None:
193
+ try:
194
+ bucket.remove(listener)
195
+ except ValueError:
196
+ pass
197
+
198
+ return remove
199
+
200
+ def emit(self, route: Route, event: str, data: Optional[Mapping[str, Any]] = None) -> NavigationEvent:
201
+ """Deliver ``event`` to the listeners registered for ``route`` and return the event.
202
+
203
+ Check ``default_prevented`` on the result to see whether a ``before_remove`` listener cancelled the action.
204
+ """
205
+ evt = NavigationEvent(event, route, data)
206
+ for listener in list(self._listeners.get((route.key, event), ())):
207
+ try:
208
+ listener(evt)
209
+ except Exception as exc:
210
+ if not diagnostics.report_error(exc, phase=f"navigation {event} listener"):
211
+ raise
212
+ return evt
213
+
214
+ # ------------------------------------------------------------------
215
+ # State transitions
216
+ # ------------------------------------------------------------------
217
+
218
+ def _commit(self, new_state: NavigationState) -> None:
219
+ if new_state == self.state:
220
+ return
221
+ self._set_state(new_state)
222
+ if self.on_state_change is not None:
223
+ self.on_state_change(new_state)
224
+
225
+ def _validate(self, name: str) -> bool:
226
+ return name in self.screens
227
+
228
+ def _with_initial_params(self, name: str, params: Mapping[str, Any]) -> Dict[str, Any]:
229
+ screen = self.screens.get(name)
230
+ base = dict(screen.initial_params) if screen is not None else {}
231
+ base.update(params)
232
+ return base
233
+
234
+ def navigate(self, name: str, params: Mapping[str, Any], nested: Optional[NavigationState] = None) -> None:
235
+ """Go to the screen ``name``: stacks pop back to it or push it; tabs and drawers jump to it.
236
+
237
+ Unknown routes bubble to the parent navigator. On a native root stack, popping back is delegated to the host.
238
+ """
239
+ if not self._validate(name):
240
+ if self.parent is not None:
241
+ self.parent._core.navigate(name, params, nested)
242
+ return
243
+ raise ValueError(f"Unknown route {name!r}. Known routes: {list(self.screens)}")
244
+ if self.kind == "stack":
245
+ existing = self.state.find(name)
246
+ if existing is None:
247
+ self.push(name, params, nested)
248
+ return
249
+ if existing == self.state.index:
250
+ new_state = self.state.set_params(params) if params else self.state
251
+ if nested is not None:
252
+ routes = list(new_state.routes)
253
+ routes[new_state.index] = routes[new_state.index].with_state(nested)
254
+ new_state = NavigationState(routes, new_state.index)
255
+ if new_state is not self.state:
256
+ self._commit(new_state)
257
+ return
258
+ new_state = self.state.pop_to(name, params, nested)
259
+ self._commit(new_state)
260
+ return
261
+ self._commit(self.state.jump_to(name, params, nested))
262
+
263
+ def push(self, name: str, params: Mapping[str, Any], nested: Optional[NavigationState] = None) -> None:
264
+ """Push a new instance of ``name`` with its ``initial_params`` merged under ``params``.
265
+
266
+ Non-stack navigators fall back to ``navigate``; unknown routes bubble to the parent navigator.
267
+ """
268
+ if self.kind != "stack":
269
+ self.navigate(name, params, nested)
270
+ return
271
+ if not self._validate(name):
272
+ if self.parent is not None:
273
+ self.parent._core.push(name, params, nested)
274
+ return
275
+ raise ValueError(f"Unknown route {name!r}. Known routes: {list(self.screens)}")
276
+ new_state = self.state.push(name, self._with_initial_params(name, params), nested)
277
+ self._commit(new_state)
278
+
279
+ def replace(self, name: str, params: Mapping[str, Any], nested: Optional[NavigationState] = None) -> None:
280
+ """Swap the active screen for a fresh ``name`` (stacks); tabs and drawers fall back to ``navigate``."""
281
+ if not self._validate(name):
282
+ if self.parent is not None:
283
+ self.parent._core.replace(name, params, nested)
284
+ return
285
+ raise ValueError(f"Unknown route {name!r}. Known routes: {list(self.screens)}")
286
+ if self.kind != "stack":
287
+ self.navigate(name, params, nested)
288
+ return
289
+ new_state = self.state.replace(name, self._with_initial_params(name, params), nested)
290
+ self._commit(new_state)
291
+
292
+ def pop(self, count: int = 1, *, source: str = "pop") -> bool:
293
+ """Pop ``count`` screens. Returns whether anything was popped here or by a parent."""
294
+ if self.kind != "stack" or len(self.state) <= 1:
295
+ if self.parent is not None:
296
+ return self.parent.pop(count)
297
+ return False
298
+ count = max(1, min(count, len(self.state) - 1))
299
+ for route in reversed(self.state.routes[len(self.state) - count :]):
300
+ evt = self.emit(route, "before_remove", {"action": source})
301
+ if evt.default_prevented:
302
+ return True
303
+ self._commit(self.state.pop(count))
304
+ return True
305
+
306
+ def pop_to_top(self) -> None:
307
+ """Pop every screen above the first one (no-op when only one screen is present)."""
308
+ if len(self.state) > 1:
309
+ self.pop(len(self.state) - 1, source="pop_to_top")
310
+
311
+ def reset(self, routes: Sequence[Route], index: Optional[int] = None) -> None:
312
+ """Replace the whole history with ``routes``, activating ``index`` (the last route by default).
313
+
314
+ Raises ``ValueError`` if any route name is unknown to this navigator.
315
+ """
316
+ for route in routes:
317
+ if not self._validate(route.name):
318
+ raise ValueError(f"Unknown route {route.name!r}. Known routes: {list(self.screens)}")
319
+ new_state = NavigationState(routes, index)
320
+ self._commit(new_state)
321
+
322
+ def set_params(self, route_key: str, params: Mapping[str, Any]) -> None:
323
+ """Merge ``params`` into the route with ``route_key`` and commit the new state."""
324
+ routes = list(self.state.routes)
325
+ for i, route in enumerate(routes):
326
+ if route.key == route_key:
327
+ routes[i] = route.with_params(params)
328
+ self._commit(NavigationState(routes, self.state.index))
329
+ return
330
+
331
+ def set_options(self, route_key: str, options: Mapping[str, Any]) -> None:
332
+ """Merge runtime ``options`` for the route with ``route_key`` and request a render if anything changed."""
333
+ current = self.runtime_options.setdefault(route_key, {})
334
+ if all(current.get(k) == v for k, v in options.items()) and all(k in current for k in options):
335
+ return
336
+ current.update(options)
337
+ if self._request_render is not None:
338
+ self._request_render()
339
+
340
+ def set_drawer_open(self, open_: bool) -> None:
341
+ """Open or close the drawer (no-op unless a drawer navigator owns this core)."""
342
+ if self._set_drawer_open is not None:
343
+ self._set_drawer_open(bool(open_))
344
+
345
+
346
+ class Navigation:
347
+ """Imperative navigation API for one screen.
348
+
349
+ Obtained with [`use_navigation`][pythonnative.use_navigation]. Every
350
+ method that changes screens accepts the destination route name
351
+ followed by params as keyword arguments:
352
+
353
+ ```python
354
+ nav.navigate("Detail", id=42)
355
+ nav.push("Detail", id=43)
356
+ nav.replace("Login")
357
+ nav.pop()
358
+ nav.pop_to_top()
359
+ nav.set_params(id=44)
360
+ nav.set_options(title="Edited")
361
+ unsubscribe = nav.add_listener("focus", lambda e: print("focused", e.route.name))
362
+ ```
363
+
364
+ Unknown routes bubble to the parent navigator, so screens can
365
+ navigate across nested navigators without knowing the tree shape.
366
+ """
367
+
368
+ __slots__ = ("_core", "_route_key")
369
+
370
+ def __init__(self, core: NavigatorCore, route_key: str) -> None:
371
+ self._core = core
372
+ self._route_key = route_key
373
+
374
+ # ------------------------------------------------------------------
375
+ # Introspection
376
+ # ------------------------------------------------------------------
377
+
378
+ @property
379
+ def route(self) -> Route:
380
+ """The route this handle belongs to."""
381
+ return self._core.route_by_key(self._route_key)
382
+
383
+ @property
384
+ def kind(self) -> NavigatorKind:
385
+ """``"stack"``, ``"tab"``, or ``"drawer"``."""
386
+ return self._core.kind
387
+
388
+ def get_params(self) -> Dict[str, Any]:
389
+ """Params of this handle's route."""
390
+ return dict(self.route.params)
391
+
392
+ def get_state(self) -> NavigationState:
393
+ """The owning navigator's current state."""
394
+ return self._core.state
395
+
396
+ def get_parent(self) -> Optional["Navigation"]:
397
+ """The handle of the enclosing navigator, or ``None`` at the top."""
398
+ return self._core.parent
399
+
400
+ def get_options(self) -> Dict[str, Any]:
401
+ """Effective options for this handle's route (static merged with ``set_options``)."""
402
+ return self._core.options_for(self.route)
403
+
404
+ def can_go_back(self) -> bool:
405
+ """Whether ``pop()`` would do anything (here or in a parent)."""
406
+ if self._core.kind == "stack" and len(self._core.state) > 1:
407
+ return True
408
+ parent = self._core.parent
409
+ return parent.can_go_back() if parent is not None else False
410
+
411
+ def is_focused(self) -> bool:
412
+ """Whether this handle's route is the navigator's active route."""
413
+ return self._core.state.current.key == self._route_key
414
+
415
+ # ------------------------------------------------------------------
416
+ # Actions
417
+ # ------------------------------------------------------------------
418
+
419
+ def navigate(self, route: str, /, *, screen: Optional[str] = None, **params: Any) -> None:
420
+ """Go to ``route``: switch to it if already present, otherwise push it.
421
+
422
+ When ``route`` renders a nested navigator, ``screen`` names the
423
+ screen to show inside it and ``params`` go to that screen:
424
+
425
+ ```python
426
+ nav.navigate("Tabs", screen="Profile", user="ada")
427
+ ```
428
+ """
429
+ self._core.navigate(route, *_split_nested(screen, params))
430
+
431
+ def push(self, route: str, /, *, screen: Optional[str] = None, **params: Any) -> None:
432
+ """Push a new instance of ``route`` (stacks; tabs fall back to ``navigate``)."""
433
+ self._core.push(route, *_split_nested(screen, params))
434
+
435
+ def replace(self, route: str, /, *, screen: Optional[str] = None, **params: Any) -> None:
436
+ """Replace the current screen with ``route``."""
437
+ self._core.replace(route, *_split_nested(screen, params))
438
+
439
+ def pop(self, count: int = 1) -> bool:
440
+ """Pop ``count`` screens off the nearest stack; returns whether anything happened."""
441
+ return self._core.pop(count)
442
+
443
+ def go_back(self) -> bool:
444
+ """Alias for ``pop()``."""
445
+ return self._core.pop(1, source="go_back")
446
+
447
+ def pop_to_top(self) -> None:
448
+ """Pop every screen above the first one."""
449
+ self._core.pop_to_top()
450
+
451
+ def reset(self, *routes: Union[str, Route], index: Optional[int] = None, **params: Any) -> None:
452
+ """Replace the whole history.
453
+
454
+ ``nav.reset("Home")`` installs a single route (``params`` apply
455
+ to it); ``nav.reset(Route("A"), Route("B", {...}))`` installs
456
+ several, with ``index`` selecting the active one (last by
457
+ default).
458
+ """
459
+ if not routes:
460
+ raise TypeError("reset() needs at least one route")
461
+ if len(routes) == 1 and isinstance(routes[0], str):
462
+ self._core.reset([Route(routes[0], params)], index)
463
+ return
464
+ if params:
465
+ raise TypeError("params keywords are only allowed when resetting to a single route name")
466
+ resolved = [Route(r) if isinstance(r, str) else r for r in routes]
467
+ self._core.reset(resolved, index)
468
+
469
+ def set_params(self, **params: Any) -> None:
470
+ """Merge ``params`` into this handle's route."""
471
+ self._core.set_params(self._route_key, params)
472
+
473
+ def set_options(self, **options: Any) -> None:
474
+ """Override [`ScreenOptions`][pythonnative.ScreenOptions] for this route at runtime."""
475
+ self._core.set_options(self._route_key, options)
476
+
477
+ def add_listener(self, event: EventName, listener: Listener) -> Callable[[], None]:
478
+ """Subscribe to ``"focus"``, ``"blur"``, ``"before_remove"``, or ``"state"`` for this route.
479
+
480
+ Returns an unsubscribe callable. ``before_remove`` listeners may
481
+ call ``event.prevent_default()`` to keep the screen (useful for
482
+ unsaved-changes prompts). Native back gestures on iOS can't be
483
+ intercepted this way; use ``gesture_enabled=False`` to disable
484
+ them for such screens.
485
+ """
486
+ return self._core.add_listener(self._route_key, event, listener)
487
+
488
+ def __repr__(self) -> str:
489
+ return f"<Navigation {self._core.kind} route={self.route.name!r}>"
490
+
491
+
492
+ def _split_nested(screen: Optional[str], params: Dict[str, Any]) -> Tuple[Dict[str, Any], Optional[NavigationState]]:
493
+ """Turn ``screen=...`` into a nested seed state (params then belong to the nested screen)."""
494
+ if screen is None:
495
+ return params, None
496
+ return {}, NavigationState([Route(screen, params)])
497
+
498
+
499
+ class TabNavigation(Navigation):
500
+ """Handle for screens inside a tab navigator (adds ``jump_to``)."""
501
+
502
+ __slots__ = ()
503
+
504
+ def jump_to(self, route: str, /, **params: Any) -> None:
505
+ """Switch to the tab named ``route``."""
506
+ self._core.navigate(route, params)
507
+
508
+
509
+ class DrawerNavigation(Navigation):
510
+ """Handle for screens inside a drawer navigator (adds drawer controls)."""
511
+
512
+ __slots__ = ()
513
+
514
+ def jump_to(self, route: str, /, **params: Any) -> None:
515
+ """Switch to the drawer screen named ``route`` and close the drawer."""
516
+ self._core.navigate(route, params)
517
+ self._core.set_drawer_open(False)
518
+
519
+ def open_drawer(self) -> None:
520
+ """Slide the drawer menu open."""
521
+ self._core.set_drawer_open(True)
522
+
523
+ def close_drawer(self) -> None:
524
+ """Close the drawer menu."""
525
+ self._core.set_drawer_open(False)
526
+
527
+ def toggle_drawer(self) -> None:
528
+ """Open the drawer menu if it's closed, otherwise close it."""
529
+ self._core.set_drawer_open(not self._core.drawer_open)
530
+
531
+ def is_drawer_open(self) -> bool:
532
+ """Return whether the drawer menu is currently open."""
533
+ return self._core.drawer_open
534
+
535
+
536
+ NavigationContext: Context[Optional[Navigation]] = create_context(None, name="Navigation")
537
+ """Provides the [`Navigation`][pythonnative.Navigation] handle for the current screen."""
538
+
539
+ FocusContext: Context[bool] = create_context(True, name="Focus")
540
+ """Whether the current subtree is the focused screen (see [`use_is_focused`][pythonnative.use_is_focused])."""
@@ -0,0 +1,133 @@
1
+ """Hooks for reading navigation state from inside a screen."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any, Callable, Dict, Optional, Sequence, overload
6
+
7
+ from ..hooks import use_context, use_effect
8
+ from .handle import FocusContext, Navigation, NavigationContext
9
+ from .state import Route, RouteParams
10
+
11
+ __all__ = ["use_focus_effect", "use_is_focused", "use_navigation", "use_route"]
12
+
13
+
14
+ def use_navigation() -> Navigation:
15
+ """Return the [`Navigation`][pythonnative.Navigation] handle for the current screen.
16
+
17
+ Raises:
18
+ RuntimeError: When no navigator encloses the calling component.
19
+
20
+ Example:
21
+ ```python
22
+ @pn.component
23
+ def HomeScreen():
24
+ nav = pn.use_navigation()
25
+ return pn.Button("Open", on_press=lambda: nav.navigate("Detail", id=42))
26
+ ```
27
+ """
28
+ nav = use_context(NavigationContext)
29
+ if nav is None:
30
+ raise RuntimeError(
31
+ "use_navigation() was called outside a navigator. Render the component inside "
32
+ "Stack.Navigator / Tab.Navigator / Drawer.Navigator (see pn.NavigationContainer)."
33
+ )
34
+ return nav
35
+
36
+
37
+ @overload
38
+ def use_route() -> Route[Dict[str, Any]]: ...
39
+
40
+
41
+ @overload
42
+ def use_route[P: RouteParams](params_type: type[P], /) -> Route[P]: ...
43
+
44
+
45
+ def use_route(params_type: Optional[type] = None, /) -> Route[Any]:
46
+ """Return the current screen's [`Route`][pythonnative.navigation.Route].
47
+
48
+ Pass a ``TypedDict`` class as ``params_type`` to get a
49
+ ``Route[MyParams]`` whose ``params`` attribute is typed for editors
50
+ and type checkers. At runtime the hook also verifies that every
51
+ *required* key of the ``TypedDict`` is present on the active route,
52
+ so a screen opened with the wrong params fails at its first render
53
+ with a message naming the missing keys, instead of a ``KeyError``
54
+ deep inside the render.
55
+
56
+ Outside any navigator a placeholder route named ``"__root__"`` with
57
+ empty params is returned (and no validation is performed), so
58
+ components can be rendered standalone (previews, tests) without
59
+ special-casing.
60
+
61
+ Args:
62
+ params_type: Optional ``TypedDict`` describing this screen's
63
+ params.
64
+
65
+ Raises:
66
+ TypeError: If the active route is missing a required param
67
+ declared by ``params_type``.
68
+
69
+ Example:
70
+ ```python
71
+ class DetailParams(TypedDict):
72
+ id: int
73
+ title: NotRequired[str]
74
+
75
+ @pn.component
76
+ def DetailScreen():
77
+ route = pn.use_route(DetailParams)
78
+ return pn.Text(f"Item {route.params['id']}")
79
+ ```
80
+ """
81
+ nav = use_context(NavigationContext)
82
+ if nav is None:
83
+ return Route("__root__", {}, key="__root__")
84
+ route = nav.route
85
+ if params_type is not None:
86
+ required = getattr(params_type, "__required_keys__", None)
87
+ if required:
88
+ missing = sorted(k for k in required if k not in route.params)
89
+ if missing:
90
+ raise TypeError(
91
+ f"Screen {route.name!r} is missing required params {missing} "
92
+ f"declared by {params_type.__name__}; got {sorted(route.params)}"
93
+ )
94
+ return route
95
+
96
+
97
+ def use_is_focused() -> bool:
98
+ """Whether the calling component is on the focused screen.
99
+
100
+ Combines the native host's lifecycle (a screen covered by a pushed
101
+ native screen is not focused) with the in-tree state of declarative
102
+ navigators (inactive tabs are not focused).
103
+ """
104
+ return bool(use_context(FocusContext))
105
+
106
+
107
+ def use_focus_effect(effect: Callable[[], Any], deps: Optional[Sequence[Any]] = None) -> None:
108
+ """Run ``effect`` while the screen is focused; its cleanup runs on blur.
109
+
110
+ Like [`use_effect`][pythonnative.use_effect], but the callback runs
111
+ only when [`use_is_focused`][pythonnative.use_is_focused] is
112
+ ``True`` and re-runs each time the screen regains focus.
113
+
114
+ Args:
115
+ effect: Zero-arg callable, optionally returning a cleanup.
116
+ deps: Extra dependencies (``None`` re-runs on every focused render).
117
+
118
+ Example:
119
+ ```python
120
+ @pn.component
121
+ def Feed():
122
+ pn.use_focus_effect(lambda: refresh(), [])
123
+ ...
124
+ ```
125
+ """
126
+ focused = use_is_focused()
127
+
128
+ def wrapped() -> Any:
129
+ if focused:
130
+ return effect()
131
+ return None
132
+
133
+ use_effect(wrapped, None if deps is None else [focused, *deps])