@thelacanians/vue-native-cli 0.4.14 → 0.6.0
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.
- package/dist/cli.js +789 -200
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Bridge/NativeBridge.kt +156 -5
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VListFactory.kt +33 -13
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VScrollViewFactory.kt +27 -6
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VSliderFactory.kt +9 -2
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VViewFactory.kt +178 -1
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Helpers/EventThrottle.kt +57 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/GeneratedModuleRegistry.kt +28 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/NativeModuleRegistry.kt +3 -0
- package/native/android/VueNativeCore/src/test/kotlin/com/vuenative/core/ComponentFactoryTest.kt +674 -0
- package/native/android/VueNativeCore/src/test/kotlin/com/vuenative/core/ErrorOverlayViewTest.kt +183 -0
- package/native/android/VueNativeCore/src/test/kotlin/com/vuenative/core/EventThrottleTest.kt +203 -0
- package/native/android/VueNativeCore/src/test/kotlin/com/vuenative/core/HotReloadManagerTest.kt +162 -0
- package/native/android/VueNativeCore/src/test/kotlin/com/vuenative/core/JSPolyfillsTest.kt +153 -0
- package/native/android/VueNativeCore/src/test/kotlin/com/vuenative/core/NativeBridgeTest.kt +6 -3
- package/native/android/VueNativeCore/src/test/kotlin/com/vuenative/core/NativeModuleTest.kt +475 -0
- package/native/android/gradle.properties +1 -0
- package/native/android/gradlew +1 -1
- package/native/ios/VueNativeCore/Package.swift +1 -1
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/EventThrottle.swift +80 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/NativeBridge.swift +244 -112
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VListFactory.swift +19 -2
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VScrollViewFactory.swift +9 -4
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VSliderFactory.swift +8 -3
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VTextFactory.swift +43 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VViewFactory.swift +116 -4
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Helpers/GestureWrapper.swift +100 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/GeneratedModuleRegistry.swift +28 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/NativeModuleRegistry.swift +3 -0
- package/native/ios/VueNativeCore/Tests/VueNativeCoreTests/CertificatePinningTests.swift +190 -0
- package/native/ios/VueNativeCore/Tests/VueNativeCoreTests/ComponentFactoryTests.swift +585 -0
- package/native/ios/VueNativeCore/Tests/VueNativeCoreTests/EventThrottleTests.swift +161 -0
- package/native/ios/VueNativeCore/Tests/VueNativeCoreTests/HotReloadManagerTests.swift +88 -0
- package/native/ios/VueNativeCore/Tests/VueNativeCoreTests/JSPolyfillsTests.swift +319 -0
- package/native/ios/VueNativeCore/Tests/VueNativeCoreTests/NativeModuleTests.swift +400 -0
- package/native/macos/VueNativeMacOS/Package.swift +34 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Bridge/ErrorOverlayView.swift +112 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Bridge/EventThrottle.swift +58 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Bridge/HotReloadManager.swift +153 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Bridge/JSPolyfills.swift +696 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Bridge/JSRuntime.swift +347 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Bridge/NativeBridge.swift +877 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Bridge/VueNativeWindowController.swift +125 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/ComponentRegistry.swift +209 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VActionSheetFactory.swift +155 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VActivityIndicatorFactory.swift +85 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VAlertDialogFactory.swift +132 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VButtonFactory.swift +83 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VCheckboxFactory.swift +108 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VDropdownFactory.swift +155 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VImageFactory.swift +270 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VInputFactory.swift +257 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VKeyboardAvoidingFactory.swift +22 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VListFactory.swift +324 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VModalFactory.swift +231 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VOutlineViewFactory.swift +276 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VPickerFactory.swift +134 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VPressableFactory.swift +120 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VProgressBarFactory.swift +71 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VRadioFactory.swift +193 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VRefreshControlFactory.swift +25 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VSafeAreaFactory.swift +46 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VScrollViewFactory.swift +190 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VSectionListFactory.swift +374 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VSegmentedControlFactory.swift +125 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VSliderFactory.swift +131 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VSplitViewFactory.swift +215 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VStatusBarFactory.swift +25 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VSwitchFactory.swift +92 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VTextFactory.swift +336 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VToolbarFactory.swift +212 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VVideoFactory.swift +245 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VViewFactory.swift +314 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VWebViewFactory.swift +162 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/NativeComponentFactory.swift +54 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Helpers/ClickableView.swift +100 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Helpers/Extensions.swift +23 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Helpers/GestureWrapper.swift +183 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Helpers/NSColor+Hex.swift +78 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Layout/FlippedView.swift +19 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Layout/LayoutNode.swift +493 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/AnimationModule.swift +354 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/AppStateModule.swift +62 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/BiometryModule.swift +60 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/CameraModule.swift +167 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/ClipboardModule.swift +34 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/DeviceInfoModule.swift +49 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/DragDropModule.swift +50 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/FileDialogModule.swift +86 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/HapticsModule.swift +42 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/KeyboardModule.swift +28 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/LinkingModule.swift +49 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/MenuModule.swift +95 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/NativeModuleRegistry.swift +63 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/NotificationsModule.swift +112 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/PermissionsModule.swift +149 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/ShareModule.swift +37 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/WindowModule.swift +71 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Resources/vue-native-placeholder.js +2 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Styling/StyleEngine.swift +885 -0
- package/native/macos/VueNativeMacOS/Tests/VueNativeMacOSTests/ComponentFactoryTests.swift +80 -0
- package/native/macos/VueNativeMacOS/Tests/VueNativeMacOSTests/VueNativeMacOSTests.swift +149 -0
- package/native/shared/VueNativeShared/AGENTS.md +129 -0
- package/native/shared/VueNativeShared/Package.swift +14 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/CertificatePinning.swift +134 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/EventThrottle.swift +78 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/HotReloadManager.swift +162 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/JSRuntime.swift +412 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/AsyncStorageModule.swift +68 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/AudioModule.swift +359 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/DatabaseModule.swift +259 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/FileSystemModule.swift +233 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/GeolocationModule.swift +156 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/NetworkModule.swift +59 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/PerformanceModule.swift +113 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/SecureStorageModule.swift +119 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/WebSocketModule.swift +212 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/NativeEventDispatcher.swift +6 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/NativeModule.swift +26 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/NativeModuleRegistry.swift +37 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/SharedJSPolyfills.swift +673 -0
- package/native/shared/VueNativeShared/Tests/VueNativeSharedTests/VueNativeSharedTests.swift +44 -0
- package/package.json +8 -2
package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VViewFactory.swift
CHANGED
|
@@ -87,6 +87,51 @@ final class VViewFactory: NativeComponentFactory {
|
|
|
87
87
|
view.isUserInteractionEnabled = true
|
|
88
88
|
GestureStorage.storeObject(pinchWrapper, for: view, event: event)
|
|
89
89
|
|
|
90
|
+
// MARK: Rotation
|
|
91
|
+
case "rotate":
|
|
92
|
+
let rotationWrapper = RotationWrapper(handler: handler)
|
|
93
|
+
let rotation = UIRotationGestureRecognizer(
|
|
94
|
+
target: rotationWrapper,
|
|
95
|
+
action: #selector(RotationWrapper.handle(_:))
|
|
96
|
+
)
|
|
97
|
+
view.addGestureRecognizer(rotation)
|
|
98
|
+
view.isUserInteractionEnabled = true
|
|
99
|
+
GestureStorage.storeObject(rotationWrapper, for: view, event: event)
|
|
100
|
+
|
|
101
|
+
// MARK: Double Tap
|
|
102
|
+
case "doubleTap":
|
|
103
|
+
let wrapper = DoubleTapWrapper(handler: handler)
|
|
104
|
+
let tapRecognizer = UITapGestureRecognizer(
|
|
105
|
+
target: wrapper,
|
|
106
|
+
action: #selector(DoubleTapWrapper.handleGesture(_:))
|
|
107
|
+
)
|
|
108
|
+
tapRecognizer.numberOfTapsRequired = 2
|
|
109
|
+
view.addGestureRecognizer(tapRecognizer)
|
|
110
|
+
view.isUserInteractionEnabled = true
|
|
111
|
+
GestureStorage.storeObject(wrapper, for: view, event: event)
|
|
112
|
+
|
|
113
|
+
// MARK: Force Touch (3D Touch)
|
|
114
|
+
case "forceTouch":
|
|
115
|
+
let wrapper = ForceTouchWrapper(handler: handler)
|
|
116
|
+
// Force touch is handled via touch events, not gesture recognizers
|
|
117
|
+
// We store the wrapper and will handle it in a custom touch handler
|
|
118
|
+
GestureStorage.storeObject(wrapper, for: view, event: event)
|
|
119
|
+
// Enable force touch on the view
|
|
120
|
+
view.isUserInteractionEnabled = true
|
|
121
|
+
attachForceTouchHandler(to: view, wrapper: wrapper)
|
|
122
|
+
|
|
123
|
+
// MARK: Hover (iOS 13+)
|
|
124
|
+
case "hover":
|
|
125
|
+
if #available(iOS 13.0, *) {
|
|
126
|
+
let hoverWrapper = HoverWrapper(handler: handler)
|
|
127
|
+
let hover = UIHoverGestureRecognizer(
|
|
128
|
+
target: hoverWrapper,
|
|
129
|
+
action: #selector(HoverWrapper.handleGesture(_:))
|
|
130
|
+
)
|
|
131
|
+
view.addGestureRecognizer(hover)
|
|
132
|
+
GestureStorage.storeObject(hoverWrapper, for: view, event: event)
|
|
133
|
+
}
|
|
134
|
+
|
|
90
135
|
default:
|
|
91
136
|
break
|
|
92
137
|
}
|
|
@@ -97,24 +142,91 @@ final class VViewFactory: NativeComponentFactory {
|
|
|
97
142
|
// Remove matching gesture recognizers
|
|
98
143
|
view.gestureRecognizers?.forEach { recognizer in
|
|
99
144
|
switch event {
|
|
100
|
-
case "press"
|
|
101
|
-
|
|
145
|
+
case "press":
|
|
146
|
+
if let tap = recognizer as? UITapGestureRecognizer, tap.numberOfTapsRequired == 1 {
|
|
147
|
+
view.removeGestureRecognizer(recognizer)
|
|
148
|
+
}
|
|
102
149
|
case "longpress" where recognizer is UILongPressGestureRecognizer:
|
|
103
150
|
view.removeGestureRecognizer(recognizer)
|
|
104
151
|
case "pan" where recognizer is UIPanGestureRecognizer:
|
|
105
152
|
view.removeGestureRecognizer(recognizer)
|
|
106
|
-
case "swipeLeft"
|
|
107
|
-
|
|
153
|
+
case "swipeLeft" where recognizer is UISwipeGestureRecognizer:
|
|
154
|
+
view.removeGestureRecognizer(recognizer)
|
|
155
|
+
case "swipeRight" where recognizer is UISwipeGestureRecognizer:
|
|
156
|
+
view.removeGestureRecognizer(recognizer)
|
|
157
|
+
case "swipeUp" where recognizer is UISwipeGestureRecognizer:
|
|
158
|
+
view.removeGestureRecognizer(recognizer)
|
|
159
|
+
case "swipeDown" where recognizer is UISwipeGestureRecognizer:
|
|
108
160
|
view.removeGestureRecognizer(recognizer)
|
|
109
161
|
case "pinch" where recognizer is UIPinchGestureRecognizer:
|
|
110
162
|
view.removeGestureRecognizer(recognizer)
|
|
163
|
+
case "rotate" where recognizer is UIRotationGestureRecognizer:
|
|
164
|
+
view.removeGestureRecognizer(recognizer)
|
|
165
|
+
case "doubleTap":
|
|
166
|
+
if let tap = recognizer as? UITapGestureRecognizer, tap.numberOfTapsRequired == 2 {
|
|
167
|
+
view.removeGestureRecognizer(recognizer)
|
|
168
|
+
}
|
|
169
|
+
case "hover":
|
|
170
|
+
if #available(iOS 13.0, *) {
|
|
171
|
+
if recognizer is UIHoverGestureRecognizer {
|
|
172
|
+
view.removeGestureRecognizer(recognizer)
|
|
173
|
+
}
|
|
174
|
+
}
|
|
111
175
|
default:
|
|
112
176
|
break
|
|
113
177
|
}
|
|
114
178
|
}
|
|
115
179
|
}
|
|
180
|
+
|
|
181
|
+
// MARK: - Force Touch Helper
|
|
182
|
+
|
|
183
|
+
private func attachForceTouchHandler(to view: UIView, wrapper: ForceTouchWrapper) {
|
|
184
|
+
// ForceTouchHandler is attached via associated object
|
|
185
|
+
let handler = ForceTouchHandlerView(wrapper: wrapper)
|
|
186
|
+
objc_setAssociatedObject(view, &forceTouchHandlerKey, handler, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
|
|
187
|
+
handler.attach(to: view)
|
|
188
|
+
}
|
|
116
189
|
}
|
|
117
190
|
|
|
191
|
+
// MARK: - ForceTouchHandlerView
|
|
192
|
+
|
|
193
|
+
/// Custom UIView subclass that monitors force touch events
|
|
194
|
+
private class ForceTouchHandlerView: UIView {
|
|
195
|
+
private let wrapper: ForceTouchWrapper
|
|
196
|
+
private weak var targetView: UIView?
|
|
197
|
+
|
|
198
|
+
init(wrapper: ForceTouchWrapper) {
|
|
199
|
+
self.wrapper = wrapper
|
|
200
|
+
super.init(frame: .zero)
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
required init?(coder: NSCoder) {
|
|
204
|
+
fatalError("init(coder:) has not been implemented")
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
func attach(to view: UIView) {
|
|
208
|
+
targetView = view
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
|
|
212
|
+
super.touchesMoved(touches, with: event)
|
|
213
|
+
guard let touch = touches.first else { return }
|
|
214
|
+
let force = touch.force
|
|
215
|
+
let location = touch.location(in: targetView)
|
|
216
|
+
wrapper.handleTouch(force: force, location: location)
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
|
|
220
|
+
super.touchesBegan(touches, with: event)
|
|
221
|
+
guard let touch = touches.first else { return }
|
|
222
|
+
let force = touch.force
|
|
223
|
+
let location = touch.location(in: targetView)
|
|
224
|
+
wrapper.handleTouch(force: force, location: location)
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
private var forceTouchHandlerKey: UInt8 = 0
|
|
229
|
+
|
|
118
230
|
// MARK: - GestureStorage
|
|
119
231
|
|
|
120
232
|
/// Stores gesture wrapper references as associated objects on views to prevent deallocation.
|
|
@@ -104,4 +104,104 @@ import UIKit
|
|
|
104
104
|
] as [String: Any])
|
|
105
105
|
}
|
|
106
106
|
}
|
|
107
|
+
|
|
108
|
+
// MARK: - RotationWrapper
|
|
109
|
+
|
|
110
|
+
/// ObjC-compatible wrapper for UIRotationGestureRecognizer action handlers.
|
|
111
|
+
@objc final class RotationWrapper: NSObject {
|
|
112
|
+
private let handler: (Any?) -> Void
|
|
113
|
+
|
|
114
|
+
init(handler: @escaping (Any?) -> Void) {
|
|
115
|
+
self.handler = handler
|
|
116
|
+
super.init()
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
@objc func handle(_ recognizer: UIRotationGestureRecognizer) {
|
|
120
|
+
let stateStr: String
|
|
121
|
+
switch recognizer.state {
|
|
122
|
+
case .began: stateStr = "began"
|
|
123
|
+
case .changed: stateStr = "changed"
|
|
124
|
+
case .ended: stateStr = "ended"
|
|
125
|
+
default: stateStr = "cancelled"
|
|
126
|
+
}
|
|
127
|
+
handler([
|
|
128
|
+
"rotation": recognizer.rotation,
|
|
129
|
+
"velocity": recognizer.velocity,
|
|
130
|
+
"state": stateStr
|
|
131
|
+
] as [String: Any])
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// MARK: - ForceTouchWrapper
|
|
136
|
+
|
|
137
|
+
/// Wrapper for 3D Touch / Force Touch gesture handlers.
|
|
138
|
+
@objc final class ForceTouchWrapper: NSObject {
|
|
139
|
+
private let handler: (Any?) -> Void
|
|
140
|
+
private var lastForce: CGFloat = 0
|
|
141
|
+
|
|
142
|
+
init(handler: @escaping (Any?) -> Void) {
|
|
143
|
+
self.handler = handler
|
|
144
|
+
super.init()
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
func handleTouch(force: CGFloat, location: CGPoint) {
|
|
148
|
+
let payload: [String: Any] = [
|
|
149
|
+
"force": force,
|
|
150
|
+
"locationX": location.x,
|
|
151
|
+
"locationY": location.y
|
|
152
|
+
]
|
|
153
|
+
handler(payload)
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// MARK: - DoubleTapWrapper
|
|
158
|
+
|
|
159
|
+
/// ObjC-compatible wrapper for double-tap gesture handlers.
|
|
160
|
+
@objc final class DoubleTapWrapper: NSObject {
|
|
161
|
+
private let handler: (Any?) -> Void
|
|
162
|
+
|
|
163
|
+
init(handler: @escaping (Any?) -> Void) {
|
|
164
|
+
self.handler = handler
|
|
165
|
+
super.init()
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
@objc func handleGesture(_ gesture: UITapGestureRecognizer) {
|
|
169
|
+
let location = gesture.location(in: gesture.view)
|
|
170
|
+
let payload: [String: Any] = [
|
|
171
|
+
"locationX": location.x,
|
|
172
|
+
"locationY": location.y
|
|
173
|
+
]
|
|
174
|
+
handler(payload)
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// MARK: - HoverWrapper
|
|
179
|
+
|
|
180
|
+
/// Wrapper for hover gesture handlers (iOS 13+).
|
|
181
|
+
@objc final class HoverWrapper: NSObject {
|
|
182
|
+
private let handler: (Any?) -> Void
|
|
183
|
+
|
|
184
|
+
init(handler: @escaping (Any?) -> Void) {
|
|
185
|
+
self.handler = handler
|
|
186
|
+
super.init()
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
@objc func handleGesture(_ gesture: UIHoverGestureRecognizer) {
|
|
190
|
+
guard let view = gesture.view else { return }
|
|
191
|
+
let location = gesture.location(in: view)
|
|
192
|
+
let stateStr: String
|
|
193
|
+
switch gesture.state {
|
|
194
|
+
case .began: stateStr = "began"
|
|
195
|
+
case .changed: stateStr = "changed"
|
|
196
|
+
case .ended: stateStr = "ended"
|
|
197
|
+
default: stateStr = "cancelled"
|
|
198
|
+
}
|
|
199
|
+
let payload: [String: Any] = [
|
|
200
|
+
"locationX": location.x,
|
|
201
|
+
"locationY": location.y,
|
|
202
|
+
"state": stateStr
|
|
203
|
+
]
|
|
204
|
+
handler(payload)
|
|
205
|
+
}
|
|
206
|
+
}
|
|
107
207
|
#endif
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// ────────────────────────────────────────────────────────────────────────────────
|
|
2
|
+
// Auto-Generated Module Registration
|
|
3
|
+
// ────────────────────────────────────────────────────────────────────────────────
|
|
4
|
+
//
|
|
5
|
+
// ⚠️ WARNING: This file is auto-generated. DO NOT EDIT MANUALLY.
|
|
6
|
+
// Changes will be overwritten by the vue-native-codegen tool.
|
|
7
|
+
//
|
|
8
|
+
// Generated: {{GENERATED_DATE}}
|
|
9
|
+
//
|
|
10
|
+
// This file registers all native modules generated from <native> blocks
|
|
11
|
+
// in Vue SFC files.
|
|
12
|
+
//
|
|
13
|
+
// ────────────────────────────────────────────────────────────────────────────────
|
|
14
|
+
|
|
15
|
+
import Foundation
|
|
16
|
+
|
|
17
|
+
@MainActor
|
|
18
|
+
extension NativeModuleRegistry {
|
|
19
|
+
/// Register all generated native modules from <native> blocks
|
|
20
|
+
func registerGeneratedModules() {
|
|
21
|
+
// Generated modules will be registered here
|
|
22
|
+
// Example:
|
|
23
|
+
// register(HapticsModule())
|
|
24
|
+
// register(CameraModule())
|
|
25
|
+
|
|
26
|
+
// This function is called automatically after registerDefaults()
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -55,6 +55,9 @@ final class NativeModuleRegistry {
|
|
|
55
55
|
register(BluetoothModule(bridge: bridge))
|
|
56
56
|
register(CalendarModule())
|
|
57
57
|
register(ContactsModule())
|
|
58
|
+
|
|
59
|
+
// Register generated modules from <native> blocks
|
|
60
|
+
registerGeneratedModules()
|
|
58
61
|
}
|
|
59
62
|
|
|
60
63
|
// MARK: - Invocation
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
#if canImport(UIKit)
|
|
2
|
+
import XCTest
|
|
3
|
+
import UIKit
|
|
4
|
+
@testable import VueNativeCore
|
|
5
|
+
|
|
6
|
+
@MainActor
|
|
7
|
+
final class CertificatePinningTests: XCTestCase {
|
|
8
|
+
|
|
9
|
+
// MARK: - Properties
|
|
10
|
+
|
|
11
|
+
private var pinning: CertificatePinning!
|
|
12
|
+
|
|
13
|
+
// MARK: - Setup / Teardown
|
|
14
|
+
|
|
15
|
+
override func setUp() {
|
|
16
|
+
super.setUp()
|
|
17
|
+
pinning = CertificatePinning.shared
|
|
18
|
+
pinning.clearPins()
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
override func tearDown() {
|
|
22
|
+
pinning.clearPins()
|
|
23
|
+
pinning = nil
|
|
24
|
+
super.tearDown()
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// MARK: - Singleton Tests
|
|
28
|
+
|
|
29
|
+
func testSharedInstanceIsSingleton() {
|
|
30
|
+
let instance1 = CertificatePinning.shared
|
|
31
|
+
let instance2 = CertificatePinning.shared
|
|
32
|
+
XCTAssertTrue(instance1 === instance2, "CertificatePinning.shared should always return the same instance")
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// MARK: - configurePins Tests
|
|
36
|
+
|
|
37
|
+
func testConfigurePinsStoresHashesForDomain() {
|
|
38
|
+
pinning.configurePins([
|
|
39
|
+
"api.example.com": ["sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="]
|
|
40
|
+
])
|
|
41
|
+
|
|
42
|
+
XCTAssertTrue(pinning.hasPins(for: "api.example.com"), "Should have pins for configured domain")
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
func testConfigurePinsMultipleDomains() {
|
|
46
|
+
pinning.configurePins([
|
|
47
|
+
"api.example.com": ["sha256/AAA="],
|
|
48
|
+
"cdn.example.com": ["sha256/BBB="]
|
|
49
|
+
])
|
|
50
|
+
|
|
51
|
+
XCTAssertTrue(pinning.hasPins(for: "api.example.com"), "Should have pins for api.example.com")
|
|
52
|
+
XCTAssertTrue(pinning.hasPins(for: "cdn.example.com"), "Should have pins for cdn.example.com")
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
func testConfigurePinsMultipleHashesPerDomain() {
|
|
56
|
+
pinning.configurePins([
|
|
57
|
+
"api.example.com": ["sha256/PrimaryHash=", "sha256/BackupHash="]
|
|
58
|
+
])
|
|
59
|
+
|
|
60
|
+
XCTAssertTrue(pinning.hasPins(for: "api.example.com"),
|
|
61
|
+
"Should have pins with multiple hashes")
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
func testConfigurePinsIgnoresMalformedPins() {
|
|
65
|
+
// Pins without "sha256/" prefix should be ignored
|
|
66
|
+
pinning.configurePins([
|
|
67
|
+
"api.example.com": ["md5/NotSupported"]
|
|
68
|
+
])
|
|
69
|
+
|
|
70
|
+
XCTAssertFalse(pinning.hasPins(for: "api.example.com"),
|
|
71
|
+
"Malformed pins (without sha256/ prefix) should not register")
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
func testConfigurePinsIsCaseInsensitiveForDomain() {
|
|
75
|
+
pinning.configurePins([
|
|
76
|
+
"API.Example.COM": ["sha256/TestHash="]
|
|
77
|
+
])
|
|
78
|
+
|
|
79
|
+
XCTAssertTrue(pinning.hasPins(for: "api.example.com"),
|
|
80
|
+
"Domain lookup should be case-insensitive")
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// MARK: - hasPins Tests
|
|
84
|
+
|
|
85
|
+
func testHasPinsReturnsFalseForUnconfiguredDomain() {
|
|
86
|
+
XCTAssertFalse(pinning.hasPins(for: "unknown.com"),
|
|
87
|
+
"Should return false for domains without pins")
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
func testHasPinsReturnsTrueForConfiguredDomain() {
|
|
91
|
+
pinning.configurePins([
|
|
92
|
+
"example.com": ["sha256/TestHash="]
|
|
93
|
+
])
|
|
94
|
+
|
|
95
|
+
XCTAssertTrue(pinning.hasPins(for: "example.com"),
|
|
96
|
+
"Should return true for configured domain")
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
func testHasPinsIsCaseInsensitive() {
|
|
100
|
+
pinning.configurePins([
|
|
101
|
+
"example.com": ["sha256/TestHash="]
|
|
102
|
+
])
|
|
103
|
+
|
|
104
|
+
XCTAssertTrue(pinning.hasPins(for: "EXAMPLE.COM"),
|
|
105
|
+
"hasPins lookup should be case-insensitive")
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// MARK: - clearPins Tests
|
|
109
|
+
|
|
110
|
+
func testClearPinsRemovesAllPins() {
|
|
111
|
+
pinning.configurePins([
|
|
112
|
+
"api.example.com": ["sha256/AAA="],
|
|
113
|
+
"cdn.example.com": ["sha256/BBB="]
|
|
114
|
+
])
|
|
115
|
+
|
|
116
|
+
pinning.clearPins()
|
|
117
|
+
|
|
118
|
+
XCTAssertFalse(pinning.hasPins(for: "api.example.com"),
|
|
119
|
+
"clearPins should remove all configured pins")
|
|
120
|
+
XCTAssertFalse(pinning.hasPins(for: "cdn.example.com"),
|
|
121
|
+
"clearPins should remove all configured pins")
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
func testClearPinsOnEmptyDoesNotCrash() {
|
|
125
|
+
// Should not crash when called with no pins configured
|
|
126
|
+
pinning.clearPins()
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// MARK: - Session Tests
|
|
130
|
+
|
|
131
|
+
func testSessionIsURLSession() {
|
|
132
|
+
let session = pinning.session
|
|
133
|
+
XCTAssertNotNil(session, "session should return a valid URLSession")
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
func testSessionIsSameInstance() {
|
|
137
|
+
let session1 = pinning.session
|
|
138
|
+
let session2 = pinning.session
|
|
139
|
+
XCTAssertTrue(session1 === session2, "session should return the same URLSession instance")
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// MARK: - URLSessionDelegate Conformance
|
|
143
|
+
|
|
144
|
+
func testConformsToURLSessionDelegate() {
|
|
145
|
+
XCTAssertTrue(pinning is URLSessionDelegate,
|
|
146
|
+
"CertificatePinning should conform to URLSessionDelegate")
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// MARK: - Empty Pins Allows Default Handling
|
|
150
|
+
|
|
151
|
+
func testNoPinsConfiguredAllowsDefaultHandling() {
|
|
152
|
+
// With no pins configured, hasPins should return false for any domain
|
|
153
|
+
XCTAssertFalse(pinning.hasPins(for: "anything.com"),
|
|
154
|
+
"Without pins configured, all domains should use default handling")
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// MARK: - Backup Pin Support
|
|
158
|
+
|
|
159
|
+
func testBackupPinConfigured() {
|
|
160
|
+
// Configure primary + backup pins for a domain
|
|
161
|
+
pinning.configurePins([
|
|
162
|
+
"api.example.com": ["sha256/PrimaryHash=", "sha256/BackupHash="]
|
|
163
|
+
])
|
|
164
|
+
|
|
165
|
+
// Both pins should be stored
|
|
166
|
+
XCTAssertTrue(pinning.hasPins(for: "api.example.com"),
|
|
167
|
+
"Domain should have pins configured including backup")
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// MARK: - Additive Configuration
|
|
171
|
+
|
|
172
|
+
func testConfigurePinsIsAdditive() {
|
|
173
|
+
pinning.configurePins(["api.example.com": ["sha256/AAA="]])
|
|
174
|
+
pinning.configurePins(["cdn.example.com": ["sha256/BBB="]])
|
|
175
|
+
|
|
176
|
+
// First domain's pins may be overwritten or preserved depending on implementation.
|
|
177
|
+
// At minimum, the second domain should be configured.
|
|
178
|
+
XCTAssertTrue(pinning.hasPins(for: "cdn.example.com"),
|
|
179
|
+
"Adding pins for a new domain should work")
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
func testConfigurePinsSameDomainOverwrites() {
|
|
183
|
+
pinning.configurePins(["api.example.com": ["sha256/OldHash="]])
|
|
184
|
+
pinning.configurePins(["api.example.com": ["sha256/NewHash="]])
|
|
185
|
+
|
|
186
|
+
XCTAssertTrue(pinning.hasPins(for: "api.example.com"),
|
|
187
|
+
"Reconfiguring the same domain should still have pins")
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
#endif
|