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.
- pythonnative/__init__.py +411 -0
- pythonnative/_ios_log.py +92 -0
- pythonnative/_yoga.cp313-win_amd64.pyd +0 -0
- pythonnative/alerts.py +236 -0
- pythonnative/animated.py +1687 -0
- pythonnative/animation_graph.py +78 -0
- pythonnative/appearance.py +124 -0
- pythonnative/bootstrap.py +100 -0
- pythonnative/bridge/__init__.py +302 -0
- pythonnative/bridge/android.py +78 -0
- pythonnative/bridge/codec.py +170 -0
- pythonnative/bridge/commits.py +114 -0
- pythonnative/bridge/fake.py +243 -0
- pythonnative/bridge/ios.py +138 -0
- pythonnative/bridge/web.py +489 -0
- pythonnative/cli/__init__.py +7 -0
- pythonnative/cli/pn.py +1214 -0
- pythonnative/component.py +271 -0
- pythonnative/components/__init__.py +111 -0
- pythonnative/components/_base.py +166 -0
- pythonnative/components/controls.py +521 -0
- pythonnative/components/layout.py +518 -0
- pythonnative/components/lists.py +785 -0
- pythonnative/components/media.py +204 -0
- pythonnative/components/overlays.py +107 -0
- pythonnative/components/pressable.py +252 -0
- pythonnative/components/structural.py +167 -0
- pythonnative/components/text.py +291 -0
- pythonnative/devclient.py +824 -0
- pythonnative/devserver/__init__.py +34 -0
- pythonnative/devserver/server.py +718 -0
- pythonnative/devserver/static/animation_graph.js +82 -0
- pythonnative/devserver/static/bridge.js +147 -0
- pythonnative/devserver/static/colors.js +70 -0
- pythonnative/devserver/static/host.js +552 -0
- pythonnative/devserver/static/index.html +60 -0
- pythonnative/devserver/static/layout.js +85 -0
- pythonnative/devserver/static/preview.css +415 -0
- pythonnative/devserver/static/renderer.js +1994 -0
- pythonnative/devserver/static/shell.js +345 -0
- pythonnative/devserver/static/yoga/LICENSE +21 -0
- pythonnative/devserver/static/yoga/binaries/yoga-wasm-base64-esm.js +75 -0
- pythonnative/devserver/static/yoga/src/generated/YGEnums.d.ts +189 -0
- pythonnative/devserver/static/yoga/src/generated/YGEnums.js +211 -0
- pythonnative/devserver/static/yoga/src/generated/YGEnums.js.map +1 -0
- pythonnative/devserver/static/yoga/src/index.d.ts +12 -0
- pythonnative/devserver/static/yoga/src/index.js +16 -0
- pythonnative/devserver/static/yoga/src/index.js.map +1 -0
- pythonnative/devserver/static/yoga/src/load.d.ts +11 -0
- pythonnative/devserver/static/yoga/src/load.js +17 -0
- pythonnative/devserver/static/yoga/src/load.js.map +1 -0
- pythonnative/devserver/static/yoga/src/wrapAssembly.d.ts +155 -0
- pythonnative/devserver/static/yoga/src/wrapAssembly.js +125 -0
- pythonnative/devserver/static/yoga/src/wrapAssembly.js.map +1 -0
- pythonnative/devserver/watcher.py +267 -0
- pythonnative/devserver/ws.py +421 -0
- pythonnative/diagnostics.py +241 -0
- pythonnative/element.py +159 -0
- pythonnative/equality.py +19 -0
- pythonnative/events.py +231 -0
- pythonnative/gestures.py +1333 -0
- pythonnative/hooks.py +1621 -0
- pythonnative/hosts/__init__.py +63 -0
- pythonnative/hosts/base.py +596 -0
- pythonnative/hosts/native.py +302 -0
- pythonnative/hot_reload.py +585 -0
- pythonnative/layout.py +328 -0
- pythonnative/mutations.py +142 -0
- pythonnative/native/android/build.gradle +52 -0
- pythonnative/native/android/gradle.properties +3 -0
- pythonnative/native/android/settings.gradle +12 -0
- pythonnative/native/android/src/main/AndroidManifest.xml +11 -0
- pythonnative/native/android/src/main/cpp/CMakeLists.txt +9 -0
- pythonnative/native/android/src/main/cpp/yoga_jni.cpp +52 -0
- pythonnative/native/android/src/main/java/com/pythonnative/generated/NativeModules.kt +5 -0
- pythonnative/native/android/src/main/java/com/pythonnative/generated/NativeProps.kt +3705 -0
- pythonnative/native/android/src/main/java/com/pythonnative/generated/PNContracts.kt +129 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/PNBridge.kt +261 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/PythonHost.kt +20 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/animation/AnimationGraph.kt +108 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/animation/AnimationSpecs.kt +141 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/animation/PNAnimator.kt +257 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/CommitState.kt +106 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/JsonUtil.kt +175 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/MainThread.kt +40 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/PNLog.kt +33 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/PNRegistry.kt +82 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/PNTransaction.kt +80 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/TransactionApplier.kt +117 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/bridge/ViewRegistry.kt +74 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/BuiltinComponents.kt +37 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ButtonManager.kt +32 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ComponentManager.kt +213 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ContainerManagers.kt +69 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ControlManagers.kt +186 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/DatePickerManager.kt +123 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ImageLoader.kt +141 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ImageManager.kt +162 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ModalManager.kt +134 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/PNColor.kt +201 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/PickerManager.kt +86 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/PortalManager.kt +55 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/PressableManager.kt +122 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ScreenStackManager.kt +110 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ScrollViewManager.kt +214 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/SegmentedControlManager.kt +113 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/StatusBarManager.kt +52 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/TabBarManager.kt +131 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/TextInputManager.kt +250 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/TextManager.kt +233 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/ViewStyler.kt +355 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/VirtualListManager.kt +159 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/components/WebViewManager.kt +149 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/gestures/GestureArbiter.kt +233 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/gestures/GestureCoordinator.kt +127 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/gestures/GestureRecognizers.kt +527 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/layout/NativeLayout.kt +145 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/layout/YogaNode.kt +29 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/BuiltinModules.kt +73 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/DeviceModules.kt +316 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/HostModule.kt +61 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/MediaModules.kt +200 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/NativeModule.kt +158 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/NotificationsModule.kt +100 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/PermissionsModule.kt +99 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/StorageModules.kt +89 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/modules/SystemModules.kt +178 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/plugins/GeneratedPlugins.kt +16 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/screens/PNScreenFragment.kt +188 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/screens/ScreenRegistry.kt +80 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/views/PNAccessibilityDelegate.kt +48 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/views/PNBorderDrawable.kt +76 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/views/PNEditText.kt +18 -0
- pythonnative/native/android/src/main/java/com/pythonnative/runtime/views/PNFrameLayout.kt +49 -0
- pythonnative/native/android/src/test/java/com/pythonnative/runtime/AnimationSpecsTest.kt +75 -0
- pythonnative/native/android/src/test/java/com/pythonnative/runtime/GestureArbiterTest.kt +197 -0
- pythonnative/native/android/src/test/java/com/pythonnative/runtime/PNColorTest.kt +47 -0
- pythonnative/native/android/src/test/java/com/pythonnative/runtime/PNTransactionTest.kt +78 -0
- pythonnative/native/android/src/test/java/com/pythonnative/runtime/PromiseTest.kt +89 -0
- pythonnative/native/ios/Package.swift +23 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Animation/PNAnimationGraph.swift +199 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Animation/PNAnimator.swift +312 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Bridge/PNBridge.swift +255 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Bridge/PNCommit.swift +104 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Bridge/PNRegistry.swift +142 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Bridge/PNTransaction.swift +166 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Bridge/PNViewRegistry.swift +53 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNButtonManagers.swift +207 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNColor.swift +173 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNComponentManager.swift +183 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNContainerView.swift +56 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNControlManagers.swift +281 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNImageManager.swift +222 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNOverlayManagers.swift +243 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNPressableManager.swift +114 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNScreenStackManager.swift +107 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNScrollViewManager.swift +197 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNTabBarManager.swift +106 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNTextInputManager.swift +297 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNTextManager.swift +230 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNTransform.swift +82 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNViewManager.swift +86 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNViewState.swift +87 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNViewStyler.swift +340 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNVirtualListManager.swift +155 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Components/PNWebViewManager.swift +124 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Generated/NativeModules.swift +1 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Generated/NativeProps.swift +3775 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Generated/PNContracts.swift +46 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Gestures/PNGestureCoordinator.swift +260 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Layout/PNLayout.swift +173 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Modules/AlertModule.swift +92 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Modules/HostModule.swift +80 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Modules/LifecycleModules.swift +174 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Modules/MediaModules.swift +177 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Modules/PNNativeModule.swift +168 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Modules/PermissionModules.swift +266 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Modules/SystemModules.swift +251 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Plugins/PNPluginRegistration.swift +8 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Screens/PNScreenRegistry.swift +46 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Screens/PNViewController.swift +237 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Support/PNCompat.swift +46 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Support/PNJSON.swift +173 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Support/PNLog.swift +47 -0
- pythonnative/native/ios/Sources/PythonNativeKit/Support/PNWindow.swift +51 -0
- pythonnative/native/ios/Tests/PythonNativeKitTests/PNAnimationGraphTests.swift +26 -0
- pythonnative/native/ios/Tests/PythonNativeKitTests/PNColorTests.swift +50 -0
- pythonnative/native/ios/Tests/PythonNativeKitTests/PNCommitTests.swift +86 -0
- pythonnative/native/ios/Tests/PythonNativeKitTests/PNGestureTests.swift +101 -0
- pythonnative/native/ios/Tests/PythonNativeKitTests/PNManagerTests.swift +126 -0
- pythonnative/native/ios/Tests/PythonNativeKitTests/PNModuleTests.swift +111 -0
- pythonnative/native/ios/Tests/PythonNativeKitTests/PNTransactionTests.swift +91 -0
- pythonnative/native/yoga/LICENSE +21 -0
- pythonnative/native/yoga/Package.swift +9 -0
- pythonnative/native/yoga/VENDORED.md +2 -0
- pythonnative/native/yoga/include/PNStyle.h +10 -0
- pythonnative/native/yoga/include/module.modulemap +5 -0
- pythonnative/native/yoga/include/yoga/YGConfig.h +158 -0
- pythonnative/native/yoga/include/yoga/YGEnums.h +142 -0
- pythonnative/native/yoga/include/yoga/YGMacros.h +99 -0
- pythonnative/native/yoga/include/yoga/YGNode.h +304 -0
- pythonnative/native/yoga/include/yoga/YGNodeLayout.h +35 -0
- pythonnative/native/yoga/include/yoga/YGNodeStyle.h +130 -0
- pythonnative/native/yoga/include/yoga/YGPixelGrid.h +29 -0
- pythonnative/native/yoga/include/yoga/YGValue.h +84 -0
- pythonnative/native/yoga/include/yoga/Yoga.h +21 -0
- pythonnative/native/yoga/python.cpp +16 -0
- pythonnative/native/yoga/style.cpp +272 -0
- pythonnative/native/yoga/yoga/CMakeLists.txt +41 -0
- pythonnative/native/yoga/yoga/YGConfig.cpp +92 -0
- pythonnative/native/yoga/yoga/YGConfig.h +158 -0
- pythonnative/native/yoga/yoga/YGEnums.cpp +262 -0
- pythonnative/native/yoga/yoga/YGEnums.h +142 -0
- pythonnative/native/yoga/yoga/YGMacros.h +99 -0
- pythonnative/native/yoga/yoga/YGNode.cpp +366 -0
- pythonnative/native/yoga/yoga/YGNode.h +304 -0
- pythonnative/native/yoga/yoga/YGNodeLayout.cpp +92 -0
- pythonnative/native/yoga/yoga/YGNodeLayout.h +35 -0
- pythonnative/native/yoga/yoga/YGNodeStyle.cpp +405 -0
- pythonnative/native/yoga/yoga/YGNodeStyle.h +130 -0
- pythonnative/native/yoga/yoga/YGPixelGrid.cpp +22 -0
- pythonnative/native/yoga/yoga/YGPixelGrid.h +29 -0
- pythonnative/native/yoga/yoga/YGValue.cpp +20 -0
- pythonnative/native/yoga/yoga/YGValue.h +84 -0
- pythonnative/native/yoga/yoga/Yoga.h +21 -0
- pythonnative/native/yoga/yoga/algorithm/AbsoluteLayout.cpp +563 -0
- pythonnative/native/yoga/yoga/algorithm/AbsoluteLayout.h +41 -0
- pythonnative/native/yoga/yoga/algorithm/Align.h +72 -0
- pythonnative/native/yoga/yoga/algorithm/Baseline.cpp +78 -0
- pythonnative/native/yoga/yoga/algorithm/Baseline.h +21 -0
- pythonnative/native/yoga/yoga/algorithm/BoundAxis.h +79 -0
- pythonnative/native/yoga/yoga/algorithm/Cache.cpp +121 -0
- pythonnative/native/yoga/yoga/algorithm/Cache.h +30 -0
- pythonnative/native/yoga/yoga/algorithm/CalculateLayout.cpp +2428 -0
- pythonnative/native/yoga/yoga/algorithm/CalculateLayout.h +38 -0
- pythonnative/native/yoga/yoga/algorithm/FlexDirection.h +120 -0
- pythonnative/native/yoga/yoga/algorithm/FlexLine.cpp +124 -0
- pythonnative/native/yoga/yoga/algorithm/FlexLine.h +75 -0
- pythonnative/native/yoga/yoga/algorithm/PixelGrid.cpp +132 -0
- pythonnative/native/yoga/yoga/algorithm/PixelGrid.h +29 -0
- pythonnative/native/yoga/yoga/algorithm/SizingMode.h +73 -0
- pythonnative/native/yoga/yoga/algorithm/TrailingPosition.h +44 -0
- pythonnative/native/yoga/yoga/config/Config.cpp +135 -0
- pythonnative/native/yoga/yoga/config/Config.h +92 -0
- pythonnative/native/yoga/yoga/debug/AssertFatal.cpp +53 -0
- pythonnative/native/yoga/yoga/debug/AssertFatal.h +29 -0
- pythonnative/native/yoga/yoga/debug/Log.cpp +107 -0
- pythonnative/native/yoga/yoga/debug/Log.h +34 -0
- pythonnative/native/yoga/yoga/enums/Align.h +47 -0
- pythonnative/native/yoga/yoga/enums/BoxSizing.h +40 -0
- pythonnative/native/yoga/yoga/enums/Dimension.h +40 -0
- pythonnative/native/yoga/yoga/enums/Direction.h +41 -0
- pythonnative/native/yoga/yoga/enums/Display.h +41 -0
- pythonnative/native/yoga/yoga/enums/Edge.h +47 -0
- pythonnative/native/yoga/yoga/enums/Errata.h +41 -0
- pythonnative/native/yoga/yoga/enums/ExperimentalFeature.h +39 -0
- pythonnative/native/yoga/yoga/enums/FlexDirection.h +42 -0
- pythonnative/native/yoga/yoga/enums/Gutter.h +41 -0
- pythonnative/native/yoga/yoga/enums/Justify.h +44 -0
- pythonnative/native/yoga/yoga/enums/LogLevel.h +44 -0
- pythonnative/native/yoga/yoga/enums/MeasureMode.h +41 -0
- pythonnative/native/yoga/yoga/enums/NodeType.h +40 -0
- pythonnative/native/yoga/yoga/enums/Overflow.h +41 -0
- pythonnative/native/yoga/yoga/enums/PhysicalEdge.h +21 -0
- pythonnative/native/yoga/yoga/enums/PositionType.h +41 -0
- pythonnative/native/yoga/yoga/enums/Unit.h +42 -0
- pythonnative/native/yoga/yoga/enums/Wrap.h +41 -0
- pythonnative/native/yoga/yoga/enums/YogaEnums.h +85 -0
- pythonnative/native/yoga/yoga/event/event.cpp +87 -0
- pythonnative/native/yoga/yoga/event/event.h +130 -0
- pythonnative/native/yoga/yoga/module.modulemap +21 -0
- pythonnative/native/yoga/yoga/node/CachedMeasurement.h +53 -0
- pythonnative/native/yoga/yoga/node/LayoutResults.cpp +48 -0
- pythonnative/native/yoga/yoga/node/LayoutResults.h +122 -0
- pythonnative/native/yoga/yoga/node/LayoutableChildren.h +148 -0
- pythonnative/native/yoga/yoga/node/Node.cpp +443 -0
- pythonnative/native/yoga/yoga/node/Node.h +337 -0
- pythonnative/native/yoga/yoga/numeric/Comparison.h +81 -0
- pythonnative/native/yoga/yoga/numeric/FloatOptional.h +93 -0
- pythonnative/native/yoga/yoga/style/SmallValueBuffer.h +133 -0
- pythonnative/native/yoga/yoga/style/Style.h +757 -0
- pythonnative/native/yoga/yoga/style/StyleLength.h +107 -0
- pythonnative/native/yoga/yoga/style/StyleValueHandle.h +98 -0
- pythonnative/native/yoga/yoga/style/StyleValuePool.h +127 -0
- pythonnative/native_modules/__init__.py +124 -0
- pythonnative/native_modules/app_state.py +99 -0
- pythonnative/native_modules/battery.py +75 -0
- pythonnative/native_modules/biometrics.py +42 -0
- pythonnative/native_modules/camera.py +65 -0
- pythonnative/native_modules/clipboard.py +46 -0
- pythonnative/native_modules/fallback.py +324 -0
- pythonnative/native_modules/file_system.py +145 -0
- pythonnative/native_modules/haptics.py +75 -0
- pythonnative/native_modules/linking.py +123 -0
- pythonnative/native_modules/location.py +75 -0
- pythonnative/native_modules/net_info.py +112 -0
- pythonnative/native_modules/notifications.py +129 -0
- pythonnative/native_modules/permissions.py +108 -0
- pythonnative/native_modules/registry.py +526 -0
- pythonnative/native_modules/secure_store.py +52 -0
- pythonnative/native_modules/share.py +51 -0
- pythonnative/native_views/__init__.py +375 -0
- pythonnative/native_views/base.py +316 -0
- pythonnative/native_views/bridge_backend.py +277 -0
- pythonnative/navigation/__init__.py +103 -0
- pythonnative/navigation/container.py +154 -0
- pythonnative/navigation/handle.py +540 -0
- pythonnative/navigation/hooks.py +133 -0
- pythonnative/navigation/host.py +58 -0
- pythonnative/navigation/linking.py +200 -0
- pythonnative/navigation/navigators.py +659 -0
- pythonnative/navigation/screen.py +149 -0
- pythonnative/navigation/state.py +269 -0
- pythonnative/net.py +248 -0
- pythonnative/platform.py +166 -0
- pythonnative/platform_metrics.py +252 -0
- pythonnative/preview.py +287 -0
- pythonnative/profiling.py +101 -0
- pythonnative/project/__init__.py +68 -0
- pythonnative/project/android.py +557 -0
- pythonnative/project/builder.py +817 -0
- pythonnative/project/config.py +773 -0
- pythonnative/project/deps.py +719 -0
- pythonnative/project/devices.py +304 -0
- pythonnative/project/doctor.py +283 -0
- pythonnative/project/fingerprint.py +171 -0
- pythonnative/project/icons.py +247 -0
- pythonnative/project/ios.py +325 -0
- pythonnative/project/lockfile.py +100 -0
- pythonnative/project/permissions.py +361 -0
- pythonnative/project/plugins.py +519 -0
- pythonnative/project/runtime_assets.py +183 -0
- pythonnative/py.typed +0 -0
- pythonnative/query.py +153 -0
- pythonnative/reconciler/__init__.py +29 -0
- pythonnative/reconciler/boundaries.py +375 -0
- pythonnative/reconciler/children.py +88 -0
- pythonnative/reconciler/core.py +1165 -0
- pythonnative/reconciler/layout_pass.py +393 -0
- pythonnative/reconciler/vnode.py +266 -0
- pythonnative/refresh.py +55 -0
- pythonnative/runtime.py +306 -0
- pythonnative/scheduler.py +159 -0
- pythonnative/sdk/__init__.py +153 -0
- pythonnative/sdk/_components.py +427 -0
- pythonnative/sdk/builtins.py +91 -0
- pythonnative/sdk/codegen.py +149 -0
- pythonnative/sdk/module_codegen.py +184 -0
- pythonnative/sdk/schema.py +224 -0
- pythonnative/sdk/templates/contracts.kt +46 -0
- pythonnative/sdk/templates/contracts.swift +46 -0
- pythonnative/storage.py +184 -0
- pythonnative/style.py +841 -0
- pythonnative/suspense.py +183 -0
- pythonnative/templates/android_template/app/build.gradle +75 -0
- pythonnative/templates/android_template/app/proguard-rules.pro +21 -0
- pythonnative/templates/android_template/app/src/androidTest/java/com/pythonnative/android_template/ExampleInstrumentedTest.kt +24 -0
- pythonnative/templates/android_template/app/src/debug/AndroidManifest.xml +7 -0
- pythonnative/templates/android_template/app/src/main/AndroidManifest.xml +32 -0
- pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/MainActivity.kt +130 -0
- pythonnative/templates/android_template/app/src/main/java/com/pythonnative/android_template/ScreenFragment.kt +13 -0
- pythonnative/templates/android_template/app/src/main/res/drawable/ic_launcher_background.xml +170 -0
- pythonnative/templates/android_template/app/src/main/res/drawable-v24/ic_launcher_foreground.xml +30 -0
- pythonnative/templates/android_template/app/src/main/res/layout/activity_main.xml +10 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +6 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +6 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-hdpi/ic_launcher.webp +0 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp +0 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-mdpi/ic_launcher.webp +0 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp +0 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-xhdpi/ic_launcher.webp +0 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp +0 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp +0 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp +0 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp +0 -0
- pythonnative/templates/android_template/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp +0 -0
- pythonnative/templates/android_template/app/src/main/res/navigation/nav_graph.xml +22 -0
- pythonnative/templates/android_template/app/src/main/res/values/colors.xml +5 -0
- pythonnative/templates/android_template/app/src/main/res/values/strings.xml +5 -0
- pythonnative/templates/android_template/app/src/main/res/values/themes.xml +9 -0
- pythonnative/templates/android_template/app/src/main/res/values-night/themes.xml +7 -0
- pythonnative/templates/android_template/app/src/main/res/xml/backup_rules.xml +13 -0
- pythonnative/templates/android_template/app/src/main/res/xml/data_extraction_rules.xml +19 -0
- pythonnative/templates/android_template/app/src/test/java/com/pythonnative/android_template/ExampleUnitTest.kt +17 -0
- pythonnative/templates/android_template/build.gradle +10 -0
- pythonnative/templates/android_template/gradle/wrapper/gradle-wrapper.jar +0 -0
- pythonnative/templates/android_template/gradle/wrapper/gradle-wrapper.properties +6 -0
- pythonnative/templates/android_template/gradle.properties +23 -0
- pythonnative/templates/android_template/gradlew +185 -0
- pythonnative/templates/android_template/gradlew.bat +89 -0
- pythonnative/templates/android_template/settings.gradle +17 -0
- pythonnative/templates/ios_template/ios_template/AppDelegate.swift +51 -0
- pythonnative/templates/ios_template/ios_template/Assets.xcassets/AccentColor.colorset/Contents.json +11 -0
- pythonnative/templates/ios_template/ios_template/Assets.xcassets/AppIcon.appiconset/Contents.json +13 -0
- pythonnative/templates/ios_template/ios_template/Assets.xcassets/Contents.json +6 -0
- pythonnative/templates/ios_template/ios_template/Base.lproj/LaunchScreen.storyboard +25 -0
- pythonnative/templates/ios_template/ios_template/BridgingHeader.h +14 -0
- pythonnative/templates/ios_template/ios_template/Info.plist +28 -0
- pythonnative/templates/ios_template/ios_template/PythonRuntime.swift +390 -0
- pythonnative/templates/ios_template/ios_template/SceneDelegate.swift +61 -0
- pythonnative/templates/ios_template/ios_template/ViewController.swift +23 -0
- pythonnative/templates/ios_template/ios_template.xcodeproj/project.pbxproj +745 -0
- pythonnative/templates/ios_template/ios_template.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
- pythonnative/templates/ios_template/ios_templateTests/ios_templateTests.swift +36 -0
- pythonnative/templates/ios_template/ios_templateUITests/ios_templateUITests.swift +41 -0
- pythonnative/templates/ios_template/ios_templateUITests/ios_templateUITestsLaunchTests.swift +32 -0
- pythonnative/testing/__init__.py +53 -0
- pythonnative/testing/backend.py +276 -0
- pythonnative/testing/harness.py +369 -0
- pythonnative/utils.py +145 -0
- pythonnative-0.40.0.dist-info/DELVEWHEEL +2 -0
- pythonnative-0.40.0.dist-info/METADATA +150 -0
- pythonnative-0.40.0.dist-info/RECORD +418 -0
- pythonnative-0.40.0.dist-info/WHEEL +5 -0
- pythonnative-0.40.0.dist-info/entry_points.txt +2 -0
- pythonnative-0.40.0.dist-info/licenses/LICENSE +21 -0
- pythonnative-0.40.0.dist-info/top_level.txt +1 -0
- pythonnative.libs/msvcp140-a4c2229bdc2a2a630acdc095b4d86008.dll +0 -0
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import UIKit
|
|
2
|
+
|
|
3
|
+
/// A native plugin bundled into the app by `pn build`. The generated
|
|
4
|
+
/// `PNGeneratedPlugins.registerAll(into:)` calls each entry's `register`.
|
|
5
|
+
public protocol PNPlugin {
|
|
6
|
+
/// Register component managers and native modules.
|
|
7
|
+
static func register(into registry: PNRegistry)
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/// Component-manager and native-module registry.
|
|
11
|
+
///
|
|
12
|
+
/// Built-ins register lazily on first use; plugins register through
|
|
13
|
+
/// `PNPlugin.register(into:)`. Component factories are invoked once per
|
|
14
|
+
/// element type and the resulting manager is shared by every view of
|
|
15
|
+
/// that type (managers are stateless; per-view state lives in
|
|
16
|
+
/// `PNViewState`).
|
|
17
|
+
public final class PNRegistry {
|
|
18
|
+
public static let shared = PNRegistry()
|
|
19
|
+
|
|
20
|
+
private var componentFactories: [String: () -> PNComponentManager] = [:]
|
|
21
|
+
private var componentManagers: [String: PNComponentManager] = [:]
|
|
22
|
+
private var moduleTypes: [String: PNNativeModule.Type] = [:]
|
|
23
|
+
private var moduleInstances: [String: PNNativeModule] = [:]
|
|
24
|
+
private var builtinsRegistered = false
|
|
25
|
+
private let placeholder = PNPlaceholderManager()
|
|
26
|
+
|
|
27
|
+
private init() {}
|
|
28
|
+
|
|
29
|
+
// MARK: - Registration
|
|
30
|
+
|
|
31
|
+
/// Register (or replace) the manager factory for element type `name`.
|
|
32
|
+
public func registerComponent(_ name: String, factory: @escaping () -> PNComponentManager) {
|
|
33
|
+
componentFactories[name] = factory
|
|
34
|
+
componentManagers.removeValue(forKey: name)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/// Register (or replace) a native module by its `name`.
|
|
38
|
+
public func registerModule(_ type: PNNativeModule.Type) {
|
|
39
|
+
moduleTypes[type.name] = type
|
|
40
|
+
moduleInstances.removeValue(forKey: type.name)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/// Element type names currently registered.
|
|
44
|
+
public var componentNames: [String] {
|
|
45
|
+
ensureBuiltins()
|
|
46
|
+
return Array(componentFactories.keys).sorted()
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/// Module names currently registered.
|
|
50
|
+
public var moduleNames: [String] {
|
|
51
|
+
ensureBuiltins()
|
|
52
|
+
return Array(moduleTypes.keys).sorted()
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// MARK: - Lookup
|
|
56
|
+
|
|
57
|
+
/// The shared manager for `type`, or a placeholder manager for unknown types.
|
|
58
|
+
public func manager(for type: String) -> PNComponentManager {
|
|
59
|
+
ensureBuiltins()
|
|
60
|
+
if let existing = componentManagers[type] { return existing }
|
|
61
|
+
if let factory = componentFactories[type] {
|
|
62
|
+
let manager = factory()
|
|
63
|
+
componentManagers[type] = manager
|
|
64
|
+
return manager
|
|
65
|
+
}
|
|
66
|
+
PNLog.once(PNLog.components, key: "unknown-type:\(type)", "unknown element type '\(type)'; using a placeholder UIView")
|
|
67
|
+
return placeholder
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/// The module instance registered under `name`, created on first use.
|
|
71
|
+
public func module(named name: String) -> PNNativeModule? {
|
|
72
|
+
ensureBuiltins()
|
|
73
|
+
if let existing = moduleInstances[name] { return existing }
|
|
74
|
+
guard let type = moduleTypes[name] else { return nil }
|
|
75
|
+
let instance = type.init()
|
|
76
|
+
moduleInstances[name] = instance
|
|
77
|
+
return instance
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// MARK: - Built-ins
|
|
81
|
+
|
|
82
|
+
/// Register every built-in manager and module, then the generated plugins.
|
|
83
|
+
public func ensureBuiltins() {
|
|
84
|
+
if builtinsRegistered { return }
|
|
85
|
+
builtinsRegistered = true
|
|
86
|
+
PNBuiltins.register(into: self)
|
|
87
|
+
PNGeneratedPlugins.registerAll(into: self)
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/// Registration of the components and modules that ship with PythonNativeKit.
|
|
92
|
+
enum PNBuiltins {
|
|
93
|
+
static func register(into registry: PNRegistry) {
|
|
94
|
+
let flex: () -> PNComponentManager = { PNViewManager() }
|
|
95
|
+
registry.registerComponent("View", factory: flex)
|
|
96
|
+
registry.registerComponent("Screen") { PNScreenManager() }
|
|
97
|
+
registry.registerComponent("ScreenStack") { PNScreenStackManager() }
|
|
98
|
+
registry.registerComponent("Column", factory: flex)
|
|
99
|
+
registry.registerComponent("Row", factory: flex)
|
|
100
|
+
registry.registerComponent("Text") { PNTextManager() }
|
|
101
|
+
registry.registerComponent("Button") { PNButtonManager() }
|
|
102
|
+
registry.registerComponent("TextInput") { PNTextInputManager() }
|
|
103
|
+
registry.registerComponent("Image") { PNImageManager() }
|
|
104
|
+
registry.registerComponent("Switch") { PNSwitchManager() }
|
|
105
|
+
registry.registerComponent("ProgressBar") { PNProgressBarManager() }
|
|
106
|
+
registry.registerComponent("ActivityIndicator") { PNActivityIndicatorManager() }
|
|
107
|
+
registry.registerComponent("WebView") { PNWebViewManager() }
|
|
108
|
+
registry.registerComponent("Spacer") { PNSpacerManager() }
|
|
109
|
+
registry.registerComponent("ScrollView") { PNScrollViewManager() }
|
|
110
|
+
registry.registerComponent("SafeAreaView") { PNSafeAreaViewManager() }
|
|
111
|
+
registry.registerComponent("Modal") { PNModalManager() }
|
|
112
|
+
registry.registerComponent("Portal") { PNPortalManager() }
|
|
113
|
+
registry.registerComponent("Slider") { PNSliderManager() }
|
|
114
|
+
registry.registerComponent("TabBar") { PNTabBarManager() }
|
|
115
|
+
registry.registerComponent("Pressable") { PNPressableManager() }
|
|
116
|
+
registry.registerComponent("StatusBar") { PNStatusBarManager() }
|
|
117
|
+
registry.registerComponent("KeyboardAvoidingView") { PNKeyboardAvoidingViewManager() }
|
|
118
|
+
registry.registerComponent("Picker") { PNPickerManager() }
|
|
119
|
+
registry.registerComponent("Checkbox") { PNCheckboxManager() }
|
|
120
|
+
registry.registerComponent("SegmentedControl") { PNSegmentedControlManager() }
|
|
121
|
+
registry.registerComponent("DatePicker") { PNDatePickerManager() }
|
|
122
|
+
registry.registerComponent("VirtualList") { PNVirtualListManager() }
|
|
123
|
+
|
|
124
|
+
registry.registerModule(HostModule.self)
|
|
125
|
+
registry.registerModule(DeviceModule.self)
|
|
126
|
+
registry.registerModule(AlertModule.self)
|
|
127
|
+
registry.registerModule(StorageModule.self)
|
|
128
|
+
registry.registerModule(SecureStoreModule.self)
|
|
129
|
+
registry.registerModule(ClipboardModule.self)
|
|
130
|
+
registry.registerModule(ShareModule.self)
|
|
131
|
+
registry.registerModule(LinkingModule.self)
|
|
132
|
+
registry.registerModule(HapticsModule.self)
|
|
133
|
+
registry.registerModule(BatteryModule.self)
|
|
134
|
+
registry.registerModule(NetInfoModule.self)
|
|
135
|
+
registry.registerModule(AppStateModule.self)
|
|
136
|
+
registry.registerModule(PermissionsModule.self)
|
|
137
|
+
registry.registerModule(NotificationsModule.self)
|
|
138
|
+
registry.registerModule(CameraModule.self)
|
|
139
|
+
registry.registerModule(LocationModule.self)
|
|
140
|
+
registry.registerModule(BiometricsModule.self)
|
|
141
|
+
}
|
|
142
|
+
}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import UIKit
|
|
2
|
+
|
|
3
|
+
/// Decodes and applies reconciler transactions.
|
|
4
|
+
///
|
|
5
|
+
/// A transaction is a JSON array of ops:
|
|
6
|
+
///
|
|
7
|
+
/// - `["c", tag, "Type", {props}]` create a view
|
|
8
|
+
/// - `["u", tag, {changed}]` apply changed props (`null` removes a prop)
|
|
9
|
+
/// - `["i", parent, child, index]` ensure `child` is at `index` under `parent`
|
|
10
|
+
/// - `["d", tag]` destroy the view
|
|
11
|
+
/// - `["f", tag, x, y, w, h]` set the frame in points
|
|
12
|
+
///
|
|
13
|
+
/// Ops are applied strictly in order; a failing op is logged and skipped
|
|
14
|
+
/// so one bad prop can't desync the rest of the tree.
|
|
15
|
+
public enum PNTransaction {
|
|
16
|
+
/// A decoded op.
|
|
17
|
+
public enum Op: Equatable {
|
|
18
|
+
case create(tag: Int64, type: String, props: [String: Any])
|
|
19
|
+
case update(tag: Int64, changed: [String: Any])
|
|
20
|
+
case insert(parent: Int64, child: Int64, index: Int)
|
|
21
|
+
case destroy(tag: Int64)
|
|
22
|
+
case frame(tag: Int64, x: Double, y: Double, w: Double, h: Double)
|
|
23
|
+
|
|
24
|
+
public static func == (lhs: Op, rhs: Op) -> Bool {
|
|
25
|
+
switch (lhs, rhs) {
|
|
26
|
+
case let (.create(t1, ty1, p1), .create(t2, ty2, p2)):
|
|
27
|
+
return t1 == t2 && ty1 == ty2 && NSDictionary(dictionary: p1).isEqual(to: p2)
|
|
28
|
+
case let (.update(t1, p1), .update(t2, p2)):
|
|
29
|
+
return t1 == t2 && NSDictionary(dictionary: p1).isEqual(to: p2)
|
|
30
|
+
case let (.insert(p1, c1, i1), .insert(p2, c2, i2)):
|
|
31
|
+
return p1 == p2 && c1 == c2 && i1 == i2
|
|
32
|
+
case let (.destroy(t1), .destroy(t2)):
|
|
33
|
+
return t1 == t2
|
|
34
|
+
case let (.frame(t1, x1, y1, w1, h1), .frame(t2, x2, y2, w2, h2)):
|
|
35
|
+
return t1 == t2 && x1 == x2 && y1 == y2 && w1 == w2 && h1 == h2
|
|
36
|
+
default:
|
|
37
|
+
return false
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/// Errors raised while decoding a single op.
|
|
43
|
+
public enum DecodeError: Error, Equatable {
|
|
44
|
+
case notAnArray
|
|
45
|
+
case malformedOp(index: Int)
|
|
46
|
+
case unknownOpcode(String)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// MARK: - Decoding
|
|
50
|
+
|
|
51
|
+
/// Decode a transaction document into ops. Malformed ops are skipped
|
|
52
|
+
/// (and logged) rather than failing the whole batch.
|
|
53
|
+
public static func decode(_ json: String) throws -> [Op] {
|
|
54
|
+
guard let root = PNJSON.decode(json) as? [Any] else { throw DecodeError.notAnArray }
|
|
55
|
+
var ops: [Op] = []
|
|
56
|
+
ops.reserveCapacity(root.count)
|
|
57
|
+
for (index, raw) in root.enumerated() {
|
|
58
|
+
do {
|
|
59
|
+
ops.append(try decodeOp(raw, index: index))
|
|
60
|
+
} catch {
|
|
61
|
+
PNLog.rateLimited(PNLog.bridge, key: "decode-op", "skipping malformed op #\(index): \(error)")
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return ops
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
static func decodeOp(_ raw: Any, index: Int) throws -> Op {
|
|
68
|
+
guard let parts = raw as? [Any], let code = parts.first as? String else {
|
|
69
|
+
throw DecodeError.malformedOp(index: index)
|
|
70
|
+
}
|
|
71
|
+
func tag(_ i: Int) throws -> Int64 {
|
|
72
|
+
guard i < parts.count, let value = PNProps.double(parts[i]), value.isFinite else {
|
|
73
|
+
throw DecodeError.malformedOp(index: index)
|
|
74
|
+
}
|
|
75
|
+
return Int64(value)
|
|
76
|
+
}
|
|
77
|
+
func number(_ i: Int) throws -> Double {
|
|
78
|
+
guard i < parts.count, let value = PNProps.double(parts[i]) else {
|
|
79
|
+
throw DecodeError.malformedOp(index: index)
|
|
80
|
+
}
|
|
81
|
+
return value
|
|
82
|
+
}
|
|
83
|
+
switch code {
|
|
84
|
+
case "c":
|
|
85
|
+
guard parts.count >= 4, let type = parts[2] as? String else { throw DecodeError.malformedOp(index: index) }
|
|
86
|
+
let props = (PNJSON.resolveInfinity(parts[3]) as? [String: Any]) ?? [:]
|
|
87
|
+
return .create(tag: try tag(1), type: type, props: props)
|
|
88
|
+
case "u":
|
|
89
|
+
guard parts.count >= 3 else { throw DecodeError.malformedOp(index: index) }
|
|
90
|
+
let changed = (PNJSON.resolveInfinity(parts[2]) as? [String: Any]) ?? [:]
|
|
91
|
+
return .update(tag: try tag(1), changed: changed)
|
|
92
|
+
case "i":
|
|
93
|
+
guard parts.count >= 4 else { throw DecodeError.malformedOp(index: index) }
|
|
94
|
+
return .insert(parent: try tag(1), child: try tag(2), index: Int(try number(3)))
|
|
95
|
+
case "d":
|
|
96
|
+
return .destroy(tag: try tag(1))
|
|
97
|
+
case "f":
|
|
98
|
+
guard parts.count >= 6 else { throw DecodeError.malformedOp(index: index) }
|
|
99
|
+
return .frame(tag: try tag(1), x: try number(2), y: try number(3), w: try number(4), h: try number(5))
|
|
100
|
+
default:
|
|
101
|
+
throw DecodeError.unknownOpcode(code)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// MARK: - Applying
|
|
106
|
+
|
|
107
|
+
/// Decode and apply a transaction document.
|
|
108
|
+
public static func apply(_ json: String) {
|
|
109
|
+
let ops: [Op]
|
|
110
|
+
do {
|
|
111
|
+
ops = try decode(json)
|
|
112
|
+
} catch {
|
|
113
|
+
PNLog.bridge.error("transaction rejected: \(String(describing: error))")
|
|
114
|
+
return
|
|
115
|
+
}
|
|
116
|
+
apply(ops)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/// Apply already-decoded ops in order with per-op error isolation.
|
|
120
|
+
public static func apply(_ ops: [Op]) {
|
|
121
|
+
let registry = PNViewRegistry.shared
|
|
122
|
+
for op in ops {
|
|
123
|
+
switch op {
|
|
124
|
+
case let .create(tag, type, props):
|
|
125
|
+
if registry.resolve(tag) != nil {
|
|
126
|
+
PNLog.rateLimited(PNLog.bridge, key: "dup-create", "create for tag \(tag) ignored: already exists")
|
|
127
|
+
continue
|
|
128
|
+
}
|
|
129
|
+
let manager = PNRegistry.shared.manager(for: type)
|
|
130
|
+
let view = manager.createView(tag: tag, props: props)
|
|
131
|
+
registry.register(PNViewRecord(tag: tag, typeName: type, view: view, manager: manager))
|
|
132
|
+
manager.didCreate(view: view, tag: tag, props: props)
|
|
133
|
+
|
|
134
|
+
case let .update(tag, changed):
|
|
135
|
+
guard let record = registry.resolve(tag) else {
|
|
136
|
+
PNLog.rateLimited(PNLog.bridge, key: "missing-update", "update for unknown tag \(tag)")
|
|
137
|
+
continue
|
|
138
|
+
}
|
|
139
|
+
record.manager.update(view: record.view, changed: changed)
|
|
140
|
+
|
|
141
|
+
case let .insert(parent, child, index):
|
|
142
|
+
guard let parentRecord = registry.resolve(parent), let childRecord = registry.resolve(child) else {
|
|
143
|
+
PNLog.rateLimited(PNLog.bridge, key: "missing-insert", "insert \(child) into \(parent): unknown tag")
|
|
144
|
+
continue
|
|
145
|
+
}
|
|
146
|
+
parentRecord.manager.insertChild(parent: parentRecord.view, child: childRecord.view, index: index)
|
|
147
|
+
|
|
148
|
+
case let .destroy(tag):
|
|
149
|
+
PNAnimationGraph.forget(tag)
|
|
150
|
+
guard let record = registry.unregister(tag) else { continue }
|
|
151
|
+
if let parentTag = PNLayout.nodes[tag]?.parent, let parentRecord = registry.resolve(parentTag) {
|
|
152
|
+
parentRecord.manager.removeChild(parent: parentRecord.view, child: record.view)
|
|
153
|
+
} else if let parent = record.view.superview,
|
|
154
|
+
let state = PNViewState.existing(for: parent), let parentRecord = registry.resolve(state.tag) {
|
|
155
|
+
parentRecord.manager.removeChild(parent: parent, child: record.view)
|
|
156
|
+
}
|
|
157
|
+
record.manager.destroy(view: record.view)
|
|
158
|
+
PNViewState.detach(record.view)
|
|
159
|
+
|
|
160
|
+
case let .frame(tag, x, y, w, h):
|
|
161
|
+
guard let record = registry.resolve(tag) else { continue }
|
|
162
|
+
record.manager.setFrame(view: record.view, x: x, y: y, w: w, h: h)
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import UIKit
|
|
2
|
+
|
|
3
|
+
/// One live native view addressed by its reconciler tag.
|
|
4
|
+
public final class PNViewRecord {
|
|
5
|
+
public let tag: Int64
|
|
6
|
+
public let typeName: String
|
|
7
|
+
public let view: UIView
|
|
8
|
+
public let manager: PNComponentManager
|
|
9
|
+
|
|
10
|
+
init(tag: Int64, typeName: String, view: UIView, manager: PNComponentManager) {
|
|
11
|
+
self.tag = tag
|
|
12
|
+
self.typeName = typeName
|
|
13
|
+
self.view = view
|
|
14
|
+
self.manager = manager
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/// Tag -> view table. Every view created through a transaction is
|
|
19
|
+
/// registered here until its `d` op arrives.
|
|
20
|
+
public final class PNViewRegistry {
|
|
21
|
+
public static let shared = PNViewRegistry()
|
|
22
|
+
|
|
23
|
+
private var records: [Int64: PNViewRecord] = [:]
|
|
24
|
+
|
|
25
|
+
private init() {}
|
|
26
|
+
|
|
27
|
+
/// The record for `tag`, or `nil` when no such view exists.
|
|
28
|
+
public func resolve(_ tag: Int64) -> PNViewRecord? {
|
|
29
|
+
records[tag]
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/// The registered view for `tag`.
|
|
33
|
+
public func view(for tag: Int64) -> UIView? {
|
|
34
|
+
records[tag]?.view
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/// Number of live records (used by tests and diagnostics).
|
|
38
|
+
public var count: Int { records.count }
|
|
39
|
+
|
|
40
|
+
func register(_ record: PNViewRecord) {
|
|
41
|
+
records[record.tag] = record
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
@discardableResult
|
|
45
|
+
func unregister(_ tag: Int64) -> PNViewRecord? {
|
|
46
|
+
records.removeValue(forKey: tag)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/// Drop every record. Intended for tests.
|
|
50
|
+
public func removeAll() {
|
|
51
|
+
records.removeAll()
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import UIKit
|
|
2
|
+
|
|
3
|
+
/// A closure-backed `UIControl` target with the duplicate-send filter the
|
|
4
|
+
/// simulator's event injection needs (one `UIEvent`, two action sends).
|
|
5
|
+
public final class PNActionTarget: NSObject {
|
|
6
|
+
private let handler: () -> Void
|
|
7
|
+
private var lastTimestamp: TimeInterval?
|
|
8
|
+
|
|
9
|
+
public init(_ handler: @escaping () -> Void) {
|
|
10
|
+
self.handler = handler
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/// Attach `handler` to `control` for `events`, retained by the view's state.
|
|
14
|
+
@discardableResult
|
|
15
|
+
public static func attach(_ control: UIControl, events: UIControl.Event, _ handler: @escaping () -> Void) -> PNActionTarget {
|
|
16
|
+
let target = PNActionTarget(handler)
|
|
17
|
+
control.addTarget(target, action: #selector(fire(_:forEvent:)), for: events)
|
|
18
|
+
PNViewState.existing(for: control)?.retained.append(target)
|
|
19
|
+
return target
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
@objc func fire(_ sender: Any?, forEvent event: UIEvent?) {
|
|
23
|
+
if let timestamp = event?.timestamp {
|
|
24
|
+
if lastTimestamp == timestamp {
|
|
25
|
+
PNLog.once(PNLog.components, key: "control-dedupe", "dropped a duplicated control action (one UIEvent, two sends)")
|
|
26
|
+
return
|
|
27
|
+
}
|
|
28
|
+
lastTimestamp = timestamp
|
|
29
|
+
}
|
|
30
|
+
handler()
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/// `Button`: a system `UIButton` emitting `on_press`.
|
|
35
|
+
public final class PNButtonManager: PNComponentManager {
|
|
36
|
+
public override func makeView(props: [String: Any]) -> UIView {
|
|
37
|
+
UIButton(type: .system)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
public override func createView(tag: Int64, props: [String: Any]) -> UIView {
|
|
41
|
+
let view = super.createView(tag: tag, props: props)
|
|
42
|
+
if let button = view as? UIButton {
|
|
43
|
+
PNActionTarget.attach(button, events: .touchUpInside) { [weak button] in
|
|
44
|
+
guard let button = button else { return }
|
|
45
|
+
PNEvents.emit(button, "on_press")
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return view
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
public override func apply(view: UIView, props: [String: Any], initial: Bool) {
|
|
52
|
+
guard let button = view as? UIButton else { return }
|
|
53
|
+
if PNProps.has(props, "title") {
|
|
54
|
+
button.setTitle(PNProps.string(PNProps.value(props, "title")) ?? "", for: .normal)
|
|
55
|
+
}
|
|
56
|
+
if let size = PNProps.double(PNProps.value(props, "font_size")) {
|
|
57
|
+
button.titleLabel?.font = UIFont.systemFont(ofSize: CGFloat(size))
|
|
58
|
+
}
|
|
59
|
+
if let color = PNColor.parse(PNProps.value(props, "background_color")) {
|
|
60
|
+
button.backgroundColor = color
|
|
61
|
+
if !PNProps.has(props, "color") {
|
|
62
|
+
button.setTitleColor(.white, for: .normal)
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if let color = PNColor.parse(PNProps.value(props, "color")) {
|
|
66
|
+
button.setTitleColor(color, for: .normal)
|
|
67
|
+
}
|
|
68
|
+
if PNProps.has(props, "disabled") {
|
|
69
|
+
button.isEnabled = !(PNProps.bool(PNProps.value(props, "disabled")) ?? false)
|
|
70
|
+
}
|
|
71
|
+
PNViewStyler.applyDecoration(button, props)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
public override func measure(view: UIView, maxW: CGFloat, maxH: CGFloat) -> CGSize {
|
|
75
|
+
let intrinsic = view.intrinsicContentSize
|
|
76
|
+
var w = intrinsic.width + 24
|
|
77
|
+
var h = intrinsic.height + 12
|
|
78
|
+
if maxW.isFinite { w = min(w, maxW) }
|
|
79
|
+
if maxH.isFinite { h = min(h, maxH) }
|
|
80
|
+
return CGSize(width: max(w, 44), height: max(h, 32))
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/// `Checkbox`: an SF Symbol button toggling checked / unchecked.
|
|
85
|
+
public final class PNCheckboxManager: PNComponentManager {
|
|
86
|
+
public override func makeView(props: [String: Any]) -> UIView {
|
|
87
|
+
UIButton(type: .custom)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
public override func createView(tag: Int64, props: [String: Any]) -> UIView {
|
|
91
|
+
let view = super.createView(tag: tag, props: props)
|
|
92
|
+
if let button = view as? UIButton {
|
|
93
|
+
PNActionTarget.attach(button, events: .touchUpInside) { [weak self, weak button] in
|
|
94
|
+
guard let self = self, let button = button else { return }
|
|
95
|
+
self.toggle(button)
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return view
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
public override func apply(view: UIView, props: [String: Any], initial: Bool) {
|
|
102
|
+
guard let button = view as? UIButton, let state = PNViewState.existing(for: button) else { return }
|
|
103
|
+
if initial {
|
|
104
|
+
let ink = PNColor.parse("#111111") ?? .label
|
|
105
|
+
button.setTitleColor(ink, for: .normal)
|
|
106
|
+
button.tintColor = ink
|
|
107
|
+
}
|
|
108
|
+
if PNProps.has(props, "value") {
|
|
109
|
+
state.extras["value"] = PNProps.bool(PNProps.value(props, "value")) ?? false
|
|
110
|
+
}
|
|
111
|
+
if PNProps.has(props, "label") {
|
|
112
|
+
let label = PNProps.string(PNProps.value(props, "label")) ?? ""
|
|
113
|
+
button.setTitle(label, for: .normal)
|
|
114
|
+
button.accessibilityLabel = label
|
|
115
|
+
}
|
|
116
|
+
if PNProps.has(props, "disabled") {
|
|
117
|
+
button.isEnabled = !(PNProps.bool(PNProps.value(props, "disabled")) ?? false)
|
|
118
|
+
}
|
|
119
|
+
updateImage(button)
|
|
120
|
+
PNViewStyler.applyAccessibility(button, props)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
private func toggle(_ button: UIButton) {
|
|
124
|
+
guard let state = PNViewState.existing(for: button) else { return }
|
|
125
|
+
if PNProps.bool(PNProps.value(state.props, "disabled")) == true { return }
|
|
126
|
+
let newValue = !state.flag("value")
|
|
127
|
+
// Optimistic flip so the box feels instant; the `value` prop re-syncs it.
|
|
128
|
+
state.extras["value"] = newValue
|
|
129
|
+
updateImage(button)
|
|
130
|
+
PNEvents.emit(button, "on_change", [newValue])
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
private func updateImage(_ button: UIButton) {
|
|
134
|
+
guard let state = PNViewState.existing(for: button) else { return }
|
|
135
|
+
let checked = state.flag("value")
|
|
136
|
+
guard var image = UIImage(systemName: checked ? "checkmark.square.fill" : "square") else { return }
|
|
137
|
+
if checked, let color = PNColor.parse(PNProps.value(state.props, "color")) {
|
|
138
|
+
image = image.withTintColor(color, renderingMode: .alwaysOriginal)
|
|
139
|
+
}
|
|
140
|
+
button.setImage(image, for: .normal)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
public override func measure(view: UIView, maxW: CGFloat, maxH: CGFloat) -> CGSize {
|
|
144
|
+
let size = view.sizeThatFits(CGSize(width: PNComponentManager.clampConstraint(maxW), height: PNComponentManager.clampConstraint(maxH)))
|
|
145
|
+
var w = max(size.width + 8, 28)
|
|
146
|
+
if maxW.isFinite { w = min(w, maxW) }
|
|
147
|
+
return CGSize(width: w, height: max(size.height, 28))
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/// `Picker`: a button that presents an action sheet listing the options.
|
|
152
|
+
public final class PNPickerManager: PNComponentManager {
|
|
153
|
+
public override func makeView(props: [String: Any]) -> UIView {
|
|
154
|
+
UIButton(type: .system)
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
public override func createView(tag: Int64, props: [String: Any]) -> UIView {
|
|
158
|
+
let view = super.createView(tag: tag, props: props)
|
|
159
|
+
if let button = view as? UIButton {
|
|
160
|
+
PNActionTarget.attach(button, events: .touchUpInside) { [weak self, weak button] in
|
|
161
|
+
guard let self = self, let button = button else { return }
|
|
162
|
+
self.presentSheet(button)
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return view
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
public override func apply(view: UIView, props: [String: Any], initial: Bool) {
|
|
169
|
+
guard let button = view as? UIButton else { return }
|
|
170
|
+
button.setTitle(PNPickerManager.title(for: mergedProps(button)), for: .normal)
|
|
171
|
+
if PNProps.has(props, "disabled") { button.isEnabled = !(PNProps.bool(PNProps.value(props, "disabled")) ?? false) }
|
|
172
|
+
PNViewStyler.applyAccessibility(button, props)
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
static func items(_ props: [String: Any]) -> [[String: Any]] {
|
|
176
|
+
((PNProps.value(props, "items") as? [Any]) ?? []).compactMap { $0 as? [String: Any] }
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
static func title(for props: [String: Any]) -> String {
|
|
180
|
+
let selected = PNProps.value(props, "value")
|
|
181
|
+
for item in items(props) {
|
|
182
|
+
if let value = PNProps.value(item, "value"), PNJSON.encode(value) == PNJSON.encode(selected) {
|
|
183
|
+
return PNProps.string(item["label"]) ?? PNProps.string(item["value"]) ?? ""
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return PNProps.string(PNProps.value(props, "placeholder")) ?? "Select…"
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
private func presentSheet(_ button: UIButton) {
|
|
190
|
+
let merged = mergedProps(button)
|
|
191
|
+
let items = PNPickerManager.items(merged)
|
|
192
|
+
var buttons: [[String: Any]] = items.map { ["label": PNProps.string($0["label"]) ?? PNProps.string($0["value"]) ?? ""] }
|
|
193
|
+
buttons.append(["label": "Cancel", "style": "cancel"])
|
|
194
|
+
PNAlertPresenter.present(
|
|
195
|
+
title: PNProps.string(PNProps.value(merged, "placeholder")) ?? "Select…",
|
|
196
|
+
message: nil, buttons: buttons, style: "action_sheet"
|
|
197
|
+
) { index in
|
|
198
|
+
guard index >= 0, index < items.count else { return }
|
|
199
|
+
PNEvents.emit(button, "on_change", [PNProps.value(items[index], "value")])
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
public override func measure(view: UIView, maxW: CGFloat, maxH: CGFloat) -> CGSize {
|
|
204
|
+
let size = view.sizeThatFits(CGSize(width: PNComponentManager.clampConstraint(maxW), height: PNComponentManager.clampConstraint(maxH)))
|
|
205
|
+
return CGSize(width: size.width + 16, height: size.height + 8)
|
|
206
|
+
}
|
|
207
|
+
}
|