pythonnative 0.40.0__cp314-cp314-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pythonnative/__init__.py +411 -0
- pythonnative/_ios_log.py +92 -0
- pythonnative/_yoga.cp314-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,82 @@
|
|
|
1
|
+
import UIKit
|
|
2
|
+
|
|
3
|
+
/// Builds `CGAffineTransform`s from the `transform` style prop.
|
|
4
|
+
///
|
|
5
|
+
/// The prop is a list of single-key dicts: `rotate` (degrees, or a
|
|
6
|
+
/// `"45deg"` / `"0.5rad"` string), `scale`, `scale_x`, `scale_y`,
|
|
7
|
+
/// `translate_x`, `translate_y`, `skew_x`, `skew_y` (degrees).
|
|
8
|
+
public enum PNTransform {
|
|
9
|
+
/// Build a transform from a spec list (or single dict). `nil` is identity.
|
|
10
|
+
public static func make(_ spec: Any?) -> CGAffineTransform {
|
|
11
|
+
var transform = CGAffineTransform.identity
|
|
12
|
+
guard let spec = spec, !(spec is NSNull) else { return transform }
|
|
13
|
+
let entries: [Any] = (spec as? [Any]) ?? [spec]
|
|
14
|
+
for entry in entries {
|
|
15
|
+
guard let dict = entry as? [String: Any] else { continue }
|
|
16
|
+
if let rotate = dict["rotate"] {
|
|
17
|
+
transform = transform.rotated(by: angle(rotate))
|
|
18
|
+
}
|
|
19
|
+
if let scale = PNProps.double(dict["scale"]) {
|
|
20
|
+
transform = transform.scaledBy(x: CGFloat(scale), y: CGFloat(scale))
|
|
21
|
+
}
|
|
22
|
+
if let sx = PNProps.double(dict["scale_x"]) {
|
|
23
|
+
transform = transform.scaledBy(x: CGFloat(sx), y: 1)
|
|
24
|
+
}
|
|
25
|
+
if let sy = PNProps.double(dict["scale_y"]) {
|
|
26
|
+
transform = transform.scaledBy(x: 1, y: CGFloat(sy))
|
|
27
|
+
}
|
|
28
|
+
if dict["translate_x"] != nil || dict["translate_y"] != nil {
|
|
29
|
+
let tx = PNProps.double(dict["translate_x"]) ?? 0
|
|
30
|
+
let ty = PNProps.double(dict["translate_y"]) ?? 0
|
|
31
|
+
transform = transform.translatedBy(x: CGFloat(tx), y: CGFloat(ty))
|
|
32
|
+
}
|
|
33
|
+
if dict["skew_x"] != nil || dict["skew_y"] != nil {
|
|
34
|
+
let skew = CGAffineTransform(
|
|
35
|
+
a: 1, b: tan(angle(dict["skew_y"] ?? 0)),
|
|
36
|
+
c: tan(angle(dict["skew_x"] ?? 0)), d: 1,
|
|
37
|
+
tx: 0, ty: 0
|
|
38
|
+
)
|
|
39
|
+
transform = skew.concatenating(transform)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return transform
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/// Whether every component of `t` is finite.
|
|
46
|
+
public static func isFinite(_ t: CGAffineTransform) -> Bool {
|
|
47
|
+
t.a.isFinite && t.b.isFinite && t.c.isFinite && t.d.isFinite && t.tx.isFinite && t.ty.isFinite
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/// Apply the `transform` prop to `view` (identity when `null`).
|
|
51
|
+
public static func apply(_ view: UIView, spec: Any?) {
|
|
52
|
+
let transform = make(spec)
|
|
53
|
+
guard isFinite(transform) else {
|
|
54
|
+
PNLog.rateLimited(PNLog.components, key: "set_transform:nan", "[set_transform:nan] spec=\(String(describing: spec))")
|
|
55
|
+
view.transform = .identity
|
|
56
|
+
return
|
|
57
|
+
}
|
|
58
|
+
view.transform = transform
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/// Parse a rotation value into radians (`"90deg"`, `"1.5rad"`, or numeric degrees).
|
|
62
|
+
public static func angle(_ value: Any) -> CGFloat {
|
|
63
|
+
if let text = value as? String {
|
|
64
|
+
let lower = text.lowercased()
|
|
65
|
+
if lower.hasSuffix("deg"), let degrees = Double(lower.dropLast(3)) {
|
|
66
|
+
return CGFloat(degrees * .pi / 180)
|
|
67
|
+
}
|
|
68
|
+
if lower.hasSuffix("rad"), let radians = Double(lower.dropLast(3)) {
|
|
69
|
+
return CGFloat(radians)
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return CGFloat((PNProps.double(value) ?? 0) * .pi / 180)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/// Decompose an affine transform into the animatable channels.
|
|
76
|
+
public static func decompose(_ t: CGAffineTransform) -> (translateX: CGFloat, translateY: CGFloat, scaleX: CGFloat, scaleY: CGFloat, rotateDegrees: CGFloat) {
|
|
77
|
+
let scaleX = sqrt(t.a * t.a + t.b * t.b)
|
|
78
|
+
let scaleY = sqrt(t.c * t.c + t.d * t.d)
|
|
79
|
+
let rotation = atan2(t.b, t.a)
|
|
80
|
+
return (t.tx, t.ty, scaleX, scaleY, rotation * 180 / .pi)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import UIKit
|
|
2
|
+
|
|
3
|
+
/// `View`, `Row`, and `Column`: a hit-test-aware flex container. All
|
|
4
|
+
/// layout semantics live in the Python layout engine; the manager only
|
|
5
|
+
/// applies visual props and frames.
|
|
6
|
+
public final class PNViewManager: PNComponentManager {
|
|
7
|
+
public override func makeView(props: [String: Any]) -> UIView {
|
|
8
|
+
PNContainerView(frame: .zero)
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/// `Spacer`: an empty layout placeholder.
|
|
13
|
+
public final class PNSpacerManager: PNComponentManager {
|
|
14
|
+
public override func makeView(props: [String: Any]) -> UIView {
|
|
15
|
+
UIView(frame: .zero)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
public override func apply(view: UIView, props: [String: Any], initial: Bool) {
|
|
19
|
+
// Sizing is entirely the layout engine's; nothing visual to apply.
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/// `SafeAreaView`: a plain container; insets are applied by the layout engine.
|
|
24
|
+
public final class PNSafeAreaViewManager: PNComponentManager {
|
|
25
|
+
public override func makeView(props: [String: Any]) -> UIView {
|
|
26
|
+
PNContainerView(frame: .zero)
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/// `KeyboardAvoidingView`: a container that keeps the keyboard observer
|
|
31
|
+
/// installed so Python receives keyboard height updates.
|
|
32
|
+
public final class PNKeyboardAvoidingViewManager: PNComponentManager {
|
|
33
|
+
public override func makeView(props: [String: Any]) -> UIView {
|
|
34
|
+
PNKeyboardObserver.shared.start()
|
|
35
|
+
return PNContainerView(frame: .zero)
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/// Publishes the keyboard height through
|
|
40
|
+
/// `callback("module", 0, "Host", {"event": "keyboard", "payload": {"height": h}})`.
|
|
41
|
+
public final class PNKeyboardObserver {
|
|
42
|
+
public static let shared = PNKeyboardObserver()
|
|
43
|
+
|
|
44
|
+
private var started = false
|
|
45
|
+
private(set) public var height: CGFloat = 0
|
|
46
|
+
|
|
47
|
+
private init() {}
|
|
48
|
+
|
|
49
|
+
/// Begin observing keyboard notifications (idempotent).
|
|
50
|
+
public func start() {
|
|
51
|
+
if started { return }
|
|
52
|
+
started = true
|
|
53
|
+
let center = NotificationCenter.default
|
|
54
|
+
center.addObserver(self, selector: #selector(willShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil)
|
|
55
|
+
center.addObserver(self, selector: #selector(willChange(_:)), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
|
|
56
|
+
center.addObserver(self, selector: #selector(willHide(_:)), name: UIResponder.keyboardWillHideNotification, object: nil)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
@objc private func willShow(_ note: Notification) {
|
|
60
|
+
publish(Self.keyboardHeight(from: note))
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
@objc private func willChange(_ note: Notification) {
|
|
64
|
+
publish(Self.keyboardHeight(from: note))
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
@objc private func willHide(_ note: Notification) {
|
|
68
|
+
publish(0)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
private func publish(_ value: CGFloat) {
|
|
72
|
+
let clamped = max(0, value)
|
|
73
|
+
if clamped == height { return }
|
|
74
|
+
height = clamped
|
|
75
|
+
PNModuleEvents.emit(module: "Host", event: "keyboard", payload: ["height": Double(clamped)])
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
static func keyboardHeight(from note: Notification) -> CGFloat {
|
|
79
|
+
guard let frame = (note.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue else {
|
|
80
|
+
return 0
|
|
81
|
+
}
|
|
82
|
+
let screen = PNWindow.screenBounds()
|
|
83
|
+
if screen.height > 0, frame.origin.y >= screen.height { return 0 }
|
|
84
|
+
return frame.height
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import UIKit
|
|
2
|
+
|
|
3
|
+
/// Per-view state attached to every bridge-created `UIView`.
|
|
4
|
+
///
|
|
5
|
+
/// Managers are shared per element type, so anything a manager needs
|
|
6
|
+
/// to remember about one view (its merged props, style bookkeeping,
|
|
7
|
+
/// recognizers, suppress flags) lives here. The state is stored as an
|
|
8
|
+
/// associated object so it can be reached from any `UIView` reference.
|
|
9
|
+
public final class PNViewState {
|
|
10
|
+
/// The reconciler tag of the view.
|
|
11
|
+
public let tag: Int64
|
|
12
|
+
/// Element type name.
|
|
13
|
+
public let typeName: String
|
|
14
|
+
/// Every prop the view has received so far (updates merge; `null` removes).
|
|
15
|
+
public var props: [String: Any] = [:]
|
|
16
|
+
/// Free-form storage for manager-specific values (suppress flags, delegates, ...).
|
|
17
|
+
public var extras: [String: Any] = [:]
|
|
18
|
+
/// Strong references the view's manager needs to keep alive (delegates, targets).
|
|
19
|
+
public var retained: [AnyObject] = []
|
|
20
|
+
/// Recognizers installed from the `gestures` prop.
|
|
21
|
+
public var gestureRecognizers: [UIGestureRecognizer] = []
|
|
22
|
+
|
|
23
|
+
// Style bookkeeping used by `PNViewStyler` at frame time.
|
|
24
|
+
var requestedCornerRadius: CGFloat?
|
|
25
|
+
var cornerRadii: [CGFloat]?
|
|
26
|
+
var sideBorderWidths: [CGFloat]?
|
|
27
|
+
var sideBorderColors: [UIColor]?
|
|
28
|
+
var sideBorderLayers: [CALayer?] = [nil, nil, nil, nil]
|
|
29
|
+
|
|
30
|
+
init(tag: Int64, typeName: String) {
|
|
31
|
+
self.tag = tag
|
|
32
|
+
self.typeName = typeName
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/// Names of the events wired on the element this render (`_pn_events`).
|
|
36
|
+
public var eventNames: Set<String> {
|
|
37
|
+
guard let list = props["_pn_events"] as? [Any] else { return [] }
|
|
38
|
+
return Set(list.compactMap { $0 as? String })
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/// Whether the element wired a callback named `name`.
|
|
42
|
+
public func hasEvent(_ name: String) -> Bool {
|
|
43
|
+
eventNames.contains(name)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/// Typed access to `extras`.
|
|
47
|
+
public func flag(_ key: String) -> Bool {
|
|
48
|
+
(extras[key] as? Bool) ?? false
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
private static var key: UInt8 = 0
|
|
52
|
+
|
|
53
|
+
/// Attach a fresh state object to `view`.
|
|
54
|
+
@discardableResult
|
|
55
|
+
static func attach(_ view: UIView, tag: Int64, typeName: String) -> PNViewState {
|
|
56
|
+
let state = PNViewState(tag: tag, typeName: typeName)
|
|
57
|
+
objc_setAssociatedObject(view, &key, state, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
|
|
58
|
+
return state
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/// The state attached to `view`, if any.
|
|
62
|
+
public static func existing(for view: UIView) -> PNViewState? {
|
|
63
|
+
objc_getAssociatedObject(view, &key) as? PNViewState
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
static func detach(_ view: UIView) {
|
|
67
|
+
objc_setAssociatedObject(view, &key, nil, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/// Event emission keyed by view.
|
|
72
|
+
public enum PNEvents {
|
|
73
|
+
/// Emit `name` for `view` with positional `args`. Returns Python's
|
|
74
|
+
/// JSON reply for request-style events, else `nil`.
|
|
75
|
+
@discardableResult
|
|
76
|
+
public static func emit(_ view: UIView, _ name: String, _ args: [Any?] = []) -> String? {
|
|
77
|
+
guard let state = PNViewState.existing(for: view) else { return nil }
|
|
78
|
+
return PNBridge.shared.emitEvent(tag: state.tag, name: name, args: args)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/// Emit only when the element wired a handler for `name`.
|
|
82
|
+
@discardableResult
|
|
83
|
+
public static func emitIfWired(_ view: UIView, _ name: String, _ args: [Any?] = []) -> String? {
|
|
84
|
+
guard let state = PNViewState.existing(for: view), state.hasEvent(name) else { return nil }
|
|
85
|
+
return PNBridge.shared.emitEvent(tag: state.tag, name: name, args: args)
|
|
86
|
+
}
|
|
87
|
+
}
|
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
import UIKit
|
|
2
|
+
|
|
3
|
+
/// Applies the visual props every element type shares.
|
|
4
|
+
///
|
|
5
|
+
/// `applyCommon` is the full container set (background, overflow,
|
|
6
|
+
/// display, opacity, z-index, pointer events, borders, shadows,
|
|
7
|
+
/// transform, accessibility). `applyDecoration` is the subset leaf
|
|
8
|
+
/// controls use (borders, shadow, transform, accessibility, opacity),
|
|
9
|
+
/// mirroring the per-handler behavior of the original iOS backend.
|
|
10
|
+
public enum PNViewStyler {
|
|
11
|
+
static let cornerRadiusKeys = [
|
|
12
|
+
"border_top_left_radius", "border_top_right_radius",
|
|
13
|
+
"border_bottom_left_radius", "border_bottom_right_radius",
|
|
14
|
+
]
|
|
15
|
+
static let sideWidthKeys = ["border_left_width", "border_top_width", "border_right_width", "border_bottom_width"]
|
|
16
|
+
static let sideColorKeys = ["border_left_color", "border_top_color", "border_right_color", "border_bottom_color"]
|
|
17
|
+
static let shadowKeys = ["shadow_color", "shadow_offset", "shadow_opacity", "shadow_radius", "elevation"]
|
|
18
|
+
static let maskedCornerBits: [CACornerMask] = [
|
|
19
|
+
.layerMinXMinYCorner, .layerMaxXMinYCorner, .layerMinXMaxYCorner, .layerMaxXMaxYCorner,
|
|
20
|
+
]
|
|
21
|
+
static let allCorners: CACornerMask = [
|
|
22
|
+
.layerMinXMinYCorner, .layerMaxXMinYCorner, .layerMinXMaxYCorner, .layerMaxXMaxYCorner,
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
// MARK: - Entry points
|
|
26
|
+
|
|
27
|
+
/// Apply every shared visual prop present in `props`.
|
|
28
|
+
public static func applyCommon(_ view: UIView, _ props: [String: Any]) {
|
|
29
|
+
if let color = PNColor.parse(PNProps.value(props, "background_color")) {
|
|
30
|
+
view.backgroundColor = color
|
|
31
|
+
}
|
|
32
|
+
if PNProps.has(props, "overflow") {
|
|
33
|
+
view.clipsToBounds = PNProps.string(PNProps.value(props, "overflow")) == "hidden"
|
|
34
|
+
}
|
|
35
|
+
if PNProps.has(props, "display") {
|
|
36
|
+
view.isHidden = PNProps.string(PNProps.value(props, "display")) == "none"
|
|
37
|
+
}
|
|
38
|
+
if let opacity = PNProps.double(PNProps.value(props, "opacity")) {
|
|
39
|
+
view.alpha = CGFloat(opacity)
|
|
40
|
+
}
|
|
41
|
+
if PNProps.has(props, "z_index") {
|
|
42
|
+
view.layer.zPosition = CGFloat(PNProps.double(PNProps.value(props, "z_index")) ?? 0)
|
|
43
|
+
}
|
|
44
|
+
if PNProps.has(props, "pointer_events") || PNProps.has(props, "hit_slop") {
|
|
45
|
+
applyInteraction(view, props)
|
|
46
|
+
}
|
|
47
|
+
applyBorder(view, props)
|
|
48
|
+
applySideBorders(view, props)
|
|
49
|
+
let merged = PNViewState.existing(for: view)?.props ?? props
|
|
50
|
+
let cornerKeysActive = cornerRadiusKeys.contains { PNProps.value(merged, $0) != nil }
|
|
51
|
+
if cornerRadiusKeys.contains(where: { PNProps.has(props, $0) }) || (PNProps.has(props, "border_radius") && cornerKeysActive) {
|
|
52
|
+
applyCornerRadii(view, merged)
|
|
53
|
+
}
|
|
54
|
+
applyShadow(view, props)
|
|
55
|
+
if PNProps.has(props, "transform") {
|
|
56
|
+
PNTransform.apply(view, spec: PNProps.value(props, "transform"))
|
|
57
|
+
}
|
|
58
|
+
applyAccessibility(view, props)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/// The leaf-control subset: border, shadow, transform, accessibility, opacity.
|
|
62
|
+
public static func applyDecoration(_ view: UIView, _ props: [String: Any]) {
|
|
63
|
+
applyBorder(view, props)
|
|
64
|
+
applyShadow(view, props)
|
|
65
|
+
if PNProps.has(props, "transform") {
|
|
66
|
+
PNTransform.apply(view, spec: PNProps.value(props, "transform"))
|
|
67
|
+
}
|
|
68
|
+
applyAccessibility(view, props)
|
|
69
|
+
if let opacity = PNProps.double(PNProps.value(props, "opacity")) {
|
|
70
|
+
view.alpha = CGFloat(opacity)
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/// Re-run the bounds-dependent parts of styling after a frame change.
|
|
75
|
+
public static func syncFrameDependentStyles(_ view: UIView, size: CGSize) {
|
|
76
|
+
guard let state = PNViewState.existing(for: view) else { return }
|
|
77
|
+
let maxRadius = max(0, min(size.width, size.height) / 2)
|
|
78
|
+
if let requested = state.requestedCornerRadius, maxRadius > 0 {
|
|
79
|
+
view.layer.cornerRadius = min(requested, maxRadius)
|
|
80
|
+
} else if state.requestedCornerRadius == nil, view.layer.cornerRadius > 0, maxRadius > 0 {
|
|
81
|
+
view.layer.cornerRadius = min(view.layer.cornerRadius, maxRadius)
|
|
82
|
+
}
|
|
83
|
+
updateCornerMask(view, state: state, size: size)
|
|
84
|
+
updateSideBorderLayers(view, state: state, size: size)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// MARK: - Borders
|
|
88
|
+
|
|
89
|
+
static func applyBorder(_ view: UIView, _ props: [String: Any]) {
|
|
90
|
+
let layer = view.layer
|
|
91
|
+
if let radius = PNProps.double(PNProps.value(props, "border_radius")) {
|
|
92
|
+
let requested = CGFloat(max(0, radius))
|
|
93
|
+
PNViewState.existing(for: view)?.requestedCornerRadius = requested
|
|
94
|
+
let size = view.bounds.size
|
|
95
|
+
var value = requested
|
|
96
|
+
if size.width > 0, size.height > 0 {
|
|
97
|
+
value = min(requested, min(size.width, size.height) / 2)
|
|
98
|
+
}
|
|
99
|
+
layer.cornerRadius = value
|
|
100
|
+
// Rounded corners clip implicitly (the React Native default).
|
|
101
|
+
layer.masksToBounds = true
|
|
102
|
+
} else if PNProps.has(props, "border_radius") {
|
|
103
|
+
PNViewState.existing(for: view)?.requestedCornerRadius = nil
|
|
104
|
+
layer.cornerRadius = 0
|
|
105
|
+
}
|
|
106
|
+
if let width = PNProps.double(PNProps.value(props, "border_width")) {
|
|
107
|
+
layer.borderWidth = CGFloat(width)
|
|
108
|
+
} else if PNProps.has(props, "border_width") {
|
|
109
|
+
layer.borderWidth = 0
|
|
110
|
+
}
|
|
111
|
+
if let color = PNColor.parse(PNProps.value(props, "border_color")) {
|
|
112
|
+
layer.borderColor = color.cgColor
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
static func applySideBorders(_ view: UIView, _ props: [String: Any]) {
|
|
117
|
+
guard sideWidthKeys.contains(where: { PNProps.value(props, $0) != nil }),
|
|
118
|
+
let state = PNViewState.existing(for: view)
|
|
119
|
+
else { return }
|
|
120
|
+
let merged = state.props
|
|
121
|
+
let baseWidth = CGFloat(PNProps.double(PNProps.value(merged, "border_width")) ?? 0)
|
|
122
|
+
let baseColor = PNColor.parse(PNProps.value(merged, "border_color")) ?? .black
|
|
123
|
+
state.sideBorderWidths = sideWidthKeys.map { key in
|
|
124
|
+
CGFloat(PNProps.double(PNProps.value(merged, key)) ?? Double(baseWidth))
|
|
125
|
+
}
|
|
126
|
+
state.sideBorderColors = sideColorKeys.map { key in
|
|
127
|
+
PNColor.parse(PNProps.value(merged, key)) ?? baseColor
|
|
128
|
+
}
|
|
129
|
+
view.layer.borderWidth = 0
|
|
130
|
+
let size = view.bounds.size
|
|
131
|
+
if size.width > 0, size.height > 0 {
|
|
132
|
+
updateSideBorderLayers(view, state: state, size: size)
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
static func updateSideBorderLayers(_ view: UIView, state: PNViewState, size: CGSize) {
|
|
137
|
+
guard let widths = state.sideBorderWidths, let colors = state.sideBorderColors else { return }
|
|
138
|
+
let frames = [
|
|
139
|
+
CGRect(x: 0, y: 0, width: widths[0], height: size.height),
|
|
140
|
+
CGRect(x: 0, y: 0, width: size.width, height: widths[1]),
|
|
141
|
+
CGRect(x: size.width - widths[2], y: 0, width: widths[2], height: size.height),
|
|
142
|
+
CGRect(x: 0, y: size.height - widths[3], width: size.width, height: widths[3]),
|
|
143
|
+
]
|
|
144
|
+
for i in 0..<4 {
|
|
145
|
+
if widths[i] <= 0 {
|
|
146
|
+
state.sideBorderLayers[i]?.removeFromSuperlayer()
|
|
147
|
+
state.sideBorderLayers[i] = nil
|
|
148
|
+
continue
|
|
149
|
+
}
|
|
150
|
+
let layer = state.sideBorderLayers[i] ?? {
|
|
151
|
+
let created = CALayer()
|
|
152
|
+
view.layer.addSublayer(created)
|
|
153
|
+
state.sideBorderLayers[i] = created
|
|
154
|
+
return created
|
|
155
|
+
}()
|
|
156
|
+
layer.backgroundColor = colors[i].cgColor
|
|
157
|
+
layer.frame = frames[i]
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// MARK: - Per-corner radii
|
|
162
|
+
|
|
163
|
+
static func applyCornerRadii(_ view: UIView, _ merged: [String: Any]) {
|
|
164
|
+
guard let state = PNViewState.existing(for: view) else { return }
|
|
165
|
+
let anyCorner = cornerRadiusKeys.contains { PNProps.value(merged, $0) != nil }
|
|
166
|
+
if !anyCorner {
|
|
167
|
+
if state.cornerRadii != nil {
|
|
168
|
+
state.cornerRadii = nil
|
|
169
|
+
view.layer.mask = nil
|
|
170
|
+
view.layer.maskedCorners = allCorners
|
|
171
|
+
applyBorder(view, merged)
|
|
172
|
+
}
|
|
173
|
+
return
|
|
174
|
+
}
|
|
175
|
+
let base = CGFloat(max(0, PNProps.double(PNProps.value(merged, "border_radius")) ?? 0))
|
|
176
|
+
let radii: [CGFloat] = cornerRadiusKeys.map { key in
|
|
177
|
+
guard let value = PNProps.double(PNProps.value(merged, key)), value.isFinite else { return base }
|
|
178
|
+
return CGFloat(max(0, value))
|
|
179
|
+
}
|
|
180
|
+
let distinct = Set(radii.filter { $0 > 0 })
|
|
181
|
+
if distinct.count <= 1 {
|
|
182
|
+
state.cornerRadii = nil
|
|
183
|
+
let value = distinct.first ?? 0
|
|
184
|
+
var mask: CACornerMask = []
|
|
185
|
+
for (bit, r) in zip(maskedCornerBits, radii) where r > 0 {
|
|
186
|
+
mask.insert(bit)
|
|
187
|
+
}
|
|
188
|
+
view.layer.mask = nil
|
|
189
|
+
view.layer.cornerRadius = value
|
|
190
|
+
view.layer.maskedCorners = mask.isEmpty ? allCorners : mask
|
|
191
|
+
view.layer.masksToBounds = true
|
|
192
|
+
state.requestedCornerRadius = value
|
|
193
|
+
return
|
|
194
|
+
}
|
|
195
|
+
state.requestedCornerRadius = nil
|
|
196
|
+
state.cornerRadii = radii
|
|
197
|
+
view.layer.cornerRadius = 0
|
|
198
|
+
view.layer.maskedCorners = allCorners
|
|
199
|
+
let size = view.bounds.size
|
|
200
|
+
if size.width > 0, size.height > 0 {
|
|
201
|
+
updateCornerMask(view, state: state, size: size)
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
static func updateCornerMask(_ view: UIView, state: PNViewState, size: CGSize) {
|
|
206
|
+
guard let radii = state.cornerRadii, size.width > 0, size.height > 0 else { return }
|
|
207
|
+
var scale: CGFloat = 1
|
|
208
|
+
let (tl0, tr0, bl0, br0) = (radii[0], radii[1], radii[2], radii[3])
|
|
209
|
+
for (sum, extent) in [(tl0 + tr0, size.width), (bl0 + br0, size.width), (tl0 + bl0, size.height), (tr0 + br0, size.height)]
|
|
210
|
+
where sum > extent && extent > 0 {
|
|
211
|
+
scale = min(scale, extent / sum)
|
|
212
|
+
}
|
|
213
|
+
let (tl, tr, bl, br) = (tl0 * scale, tr0 * scale, bl0 * scale, br0 * scale)
|
|
214
|
+
let w = size.width, h = size.height
|
|
215
|
+
let path = UIBezierPath()
|
|
216
|
+
let halfPi = CGFloat.pi / 2
|
|
217
|
+
path.move(to: CGPoint(x: tl, y: 0))
|
|
218
|
+
path.addLine(to: CGPoint(x: w - tr, y: 0))
|
|
219
|
+
if tr > 0 { path.addArc(withCenter: CGPoint(x: w - tr, y: tr), radius: tr, startAngle: -halfPi, endAngle: 0, clockwise: true) }
|
|
220
|
+
path.addLine(to: CGPoint(x: w, y: h - br))
|
|
221
|
+
if br > 0 { path.addArc(withCenter: CGPoint(x: w - br, y: h - br), radius: br, startAngle: 0, endAngle: halfPi, clockwise: true) }
|
|
222
|
+
path.addLine(to: CGPoint(x: bl, y: h))
|
|
223
|
+
if bl > 0 { path.addArc(withCenter: CGPoint(x: bl, y: h - bl), radius: bl, startAngle: halfPi, endAngle: .pi, clockwise: true) }
|
|
224
|
+
path.addLine(to: CGPoint(x: 0, y: tl))
|
|
225
|
+
if tl > 0 { path.addArc(withCenter: CGPoint(x: tl, y: tl), radius: tl, startAngle: .pi, endAngle: .pi + halfPi, clockwise: true) }
|
|
226
|
+
path.close()
|
|
227
|
+
let shape = CAShapeLayer()
|
|
228
|
+
shape.frame = CGRect(origin: .zero, size: size)
|
|
229
|
+
shape.path = path.cgPath
|
|
230
|
+
view.layer.mask = shape
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// MARK: - Shadow
|
|
234
|
+
|
|
235
|
+
static func applyShadow(_ view: UIView, _ props: [String: Any]) {
|
|
236
|
+
let layer = view.layer
|
|
237
|
+
let hasShadow = shadowKeys.contains { PNProps.value(props, $0) != nil }
|
|
238
|
+
if hasShadow, PNProps.string(PNProps.value(props, "overflow")) != "hidden" {
|
|
239
|
+
layer.masksToBounds = false
|
|
240
|
+
view.clipsToBounds = false
|
|
241
|
+
}
|
|
242
|
+
if let color = PNColor.parse(PNProps.value(props, "shadow_color")) {
|
|
243
|
+
layer.shadowColor = color.cgColor
|
|
244
|
+
}
|
|
245
|
+
if let opacity = PNProps.double(PNProps.value(props, "shadow_opacity")) {
|
|
246
|
+
layer.shadowOpacity = Float(opacity)
|
|
247
|
+
}
|
|
248
|
+
if let radius = PNProps.double(PNProps.value(props, "shadow_radius")) {
|
|
249
|
+
layer.shadowRadius = CGFloat(radius)
|
|
250
|
+
}
|
|
251
|
+
if let offset = PNProps.value(props, "shadow_offset") {
|
|
252
|
+
let (dx, dy) = shadowOffset(offset)
|
|
253
|
+
layer.shadowOffset = CGSize(width: dx, height: dy)
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/// Coerce a `shadow_offset` / `text_shadow_offset` value to `(dx, dy)`.
|
|
258
|
+
public static func shadowOffset(_ value: Any?) -> (CGFloat, CGFloat) {
|
|
259
|
+
if let dict = value as? [String: Any] {
|
|
260
|
+
return (CGFloat(PNProps.double(dict["width"]) ?? 0), CGFloat(PNProps.double(dict["height"]) ?? 0))
|
|
261
|
+
}
|
|
262
|
+
if let list = value as? [Any], list.count >= 2 {
|
|
263
|
+
return (CGFloat(PNProps.double(list[0]) ?? 0), CGFloat(PNProps.double(list[1]) ?? 0))
|
|
264
|
+
}
|
|
265
|
+
return (0, 0)
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// MARK: - Interaction
|
|
269
|
+
|
|
270
|
+
static func applyInteraction(_ view: UIView, _ props: [String: Any]) {
|
|
271
|
+
guard let container = view as? PNContainerView else {
|
|
272
|
+
PNLog.once(PNLog.components, key: "interaction:\(PNViewState.existing(for: view)?.tag ?? 0)",
|
|
273
|
+
"pointer_events / hit_slop only work on container elements; ignored")
|
|
274
|
+
return
|
|
275
|
+
}
|
|
276
|
+
if PNProps.has(props, "pointer_events") {
|
|
277
|
+
let mode = PNProps.string(PNProps.value(props, "pointer_events"))
|
|
278
|
+
container.pointerEvents = ["none", "box_none", "box_only"].contains(mode ?? "") ? mode : nil
|
|
279
|
+
}
|
|
280
|
+
if PNProps.has(props, "hit_slop") {
|
|
281
|
+
container.hitSlop = hitSlop(PNProps.value(props, "hit_slop"))
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/// Normalize a `hit_slop` prop into edge insets.
|
|
286
|
+
public static func hitSlop(_ value: Any?) -> UIEdgeInsets {
|
|
287
|
+
if let dict = value as? [String: Any] {
|
|
288
|
+
return UIEdgeInsets(
|
|
289
|
+
top: CGFloat(PNProps.double(dict["top"]) ?? 0), left: CGFloat(PNProps.double(dict["left"]) ?? 0),
|
|
290
|
+
bottom: CGFloat(PNProps.double(dict["bottom"]) ?? 0), right: CGFloat(PNProps.double(dict["right"]) ?? 0)
|
|
291
|
+
)
|
|
292
|
+
}
|
|
293
|
+
if let uniform = PNProps.double(value) {
|
|
294
|
+
let v = CGFloat(uniform)
|
|
295
|
+
return UIEdgeInsets(top: v, left: v, bottom: v, right: v)
|
|
296
|
+
}
|
|
297
|
+
return .zero
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// MARK: - Accessibility
|
|
301
|
+
|
|
302
|
+
static let traitByRole: [String: UIAccessibilityTraits] = [
|
|
303
|
+
"button": .button, "link": .link, "image": .image, "search": .searchField,
|
|
304
|
+
"keyboard_key": .keyboardKey, "static_text": .staticText, "summary_element": .summaryElement,
|
|
305
|
+
"adjustable": .adjustable, "header": .header, "selected": .selected, "checkbox": .button, "none": [],
|
|
306
|
+
]
|
|
307
|
+
|
|
308
|
+
static func applyAccessibility(_ view: UIView, _ props: [String: Any]) {
|
|
309
|
+
if PNProps.has(props, "accessible") {
|
|
310
|
+
view.isAccessibilityElement = PNProps.bool(PNProps.value(props, "accessible")) ?? false
|
|
311
|
+
}
|
|
312
|
+
if PNProps.has(props, "accessibility_label") {
|
|
313
|
+
view.accessibilityLabel = PNProps.string(PNProps.value(props, "accessibility_label")) ?? ""
|
|
314
|
+
}
|
|
315
|
+
if PNProps.has(props, "accessibility_hint") {
|
|
316
|
+
view.accessibilityHint = PNProps.string(PNProps.value(props, "accessibility_hint")) ?? ""
|
|
317
|
+
}
|
|
318
|
+
if PNProps.has(props, "test_id") {
|
|
319
|
+
view.accessibilityIdentifier = PNProps.string(PNProps.value(props, "test_id"))
|
|
320
|
+
}
|
|
321
|
+
let role = PNProps.string(PNProps.value(props, "accessibility_role"))
|
|
322
|
+
let state = PNProps.dict(PNProps.value(props, "accessibility_state"))
|
|
323
|
+
if role == nil, state == nil { return }
|
|
324
|
+
var traits: UIAccessibilityTraits = []
|
|
325
|
+
if let role = role {
|
|
326
|
+
traits.formUnion(traitByRole[role.lowercased()] ?? [])
|
|
327
|
+
}
|
|
328
|
+
if let state = state {
|
|
329
|
+
if PNProps.bool(state["selected"]) == true || PNProps.bool(state["checked"]) == true {
|
|
330
|
+
traits.insert(.selected)
|
|
331
|
+
}
|
|
332
|
+
if PNProps.bool(state["disabled"]) == true { traits.insert(.notEnabled) }
|
|
333
|
+
if PNProps.bool(state["busy"]) == true { traits.insert(.updatesFrequently) }
|
|
334
|
+
if let expanded = PNProps.bool(state["expanded"]) {
|
|
335
|
+
view.accessibilityValue = expanded ? "expanded" : "collapsed"
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
view.accessibilityTraits = traits
|
|
339
|
+
}
|
|
340
|
+
}
|