@thelacanians/vue-native-cli 0.4.3 → 0.4.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. package/dist/cli.js +102 -32
  2. package/native/android/README.md +205 -0
  3. package/native/android/VueNativeCore/build.gradle.kts +113 -0
  4. package/native/android/VueNativeCore/consumer-rules.pro +12 -0
  5. package/native/android/VueNativeCore/proguard-rules.pro +33 -0
  6. package/native/android/VueNativeCore/src/main/AndroidManifest.xml +17 -0
  7. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Bridge/ErrorOverlayView.kt +94 -0
  8. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Bridge/HotReloadManager.kt +105 -0
  9. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Bridge/JSPolyfills.kt +652 -0
  10. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Bridge/JSRuntime.kt +207 -0
  11. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Bridge/NativeBridge.kt +417 -0
  12. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/ComponentRegistry.kt +76 -0
  13. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VActionSheetFactory.kt +78 -0
  14. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VActivityIndicatorFactory.kt +46 -0
  15. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VAlertDialogFactory.kt +84 -0
  16. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VButtonFactory.kt +73 -0
  17. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VCheckboxFactory.kt +93 -0
  18. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VDropdownFactory.kt +125 -0
  19. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VImageFactory.kt +75 -0
  20. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VInputFactory.kt +210 -0
  21. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VKeyboardAvoidingFactory.kt +31 -0
  22. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VListFactory.kt +183 -0
  23. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VModalFactory.kt +105 -0
  24. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VPickerFactory.kt +57 -0
  25. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VPressableFactory.kt +109 -0
  26. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VProgressBarFactory.kt +43 -0
  27. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VRadioFactory.kt +103 -0
  28. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VRefreshControlFactory.kt +73 -0
  29. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VRootFactory.kt +39 -0
  30. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VSafeAreaFactory.kt +48 -0
  31. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VScrollViewFactory.kt +105 -0
  32. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VSectionListFactory.kt +144 -0
  33. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VSegmentedControlFactory.kt +77 -0
  34. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VSliderFactory.kt +74 -0
  35. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VStatusBarFactory.kt +52 -0
  36. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VSwitchFactory.kt +62 -0
  37. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VTextFactory.kt +53 -0
  38. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VVideoFactory.kt +191 -0
  39. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VViewFactory.kt +48 -0
  40. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VWebViewFactory.kt +90 -0
  41. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/NativeComponentFactory.kt +40 -0
  42. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/VTextNodeView.kt +23 -0
  43. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Helpers/GestureHelper.kt +16 -0
  44. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Helpers/TouchableView.kt +105 -0
  45. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/AnimationModule.kt +292 -0
  46. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/AppStateModule.kt +41 -0
  47. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/AsyncStorageModule.kt +59 -0
  48. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/AudioModule.kt +331 -0
  49. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/BackgroundTaskModule.kt +166 -0
  50. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/BiometryModule.kt +56 -0
  51. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/BluetoothModule.kt +302 -0
  52. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/CalendarModule.kt +198 -0
  53. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/CameraModule.kt +64 -0
  54. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/ClipboardModule.kt +36 -0
  55. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/ContactsModule.kt +288 -0
  56. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/DatabaseModule.kt +229 -0
  57. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/DeviceInfoModule.kt +39 -0
  58. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/FileSystemModule.kt +193 -0
  59. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/GeolocationModule.kt +68 -0
  60. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/HapticsModule.kt +61 -0
  61. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/HttpModule.kt +111 -0
  62. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/IAPModule.kt +302 -0
  63. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/KeyboardModule.kt +26 -0
  64. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/LinkingModule.kt +43 -0
  65. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/NativeModule.kt +27 -0
  66. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/NativeModuleRegistry.kt +92 -0
  67. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/NetworkModule.kt +75 -0
  68. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/NotificationsModule.kt +181 -0
  69. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/OTAModule.kt +255 -0
  70. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/PerformanceModule.kt +147 -0
  71. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/PermissionsModule.kt +126 -0
  72. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/SecureStorageModule.kt +51 -0
  73. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/SensorsModule.kt +134 -0
  74. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/ShareModule.kt +36 -0
  75. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/SocialAuthModule.kt +163 -0
  76. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/WebSocketModule.kt +155 -0
  77. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Styling/StyleEngine.kt +802 -0
  78. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Tags.kt +43 -0
  79. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/VueNativeActivity.kt +169 -0
  80. package/native/android/VueNativeCore/src/main/res/values/ids.xml +8 -0
  81. package/native/android/app/build.gradle.kts +45 -0
  82. package/native/android/app/proguard-rules.pro +5 -0
  83. package/native/android/app/src/main/AndroidManifest.xml +25 -0
  84. package/native/android/app/src/main/assets/.gitkeep +0 -0
  85. package/native/android/app/src/main/kotlin/com/vuenative/example/counter/MainActivity.kt +14 -0
  86. package/native/android/app/src/main/res/layout/activity_main.xml +6 -0
  87. package/native/android/app/src/main/res/values/strings.xml +3 -0
  88. package/native/android/app/src/main/res/values/themes.xml +9 -0
  89. package/native/android/app/src/main/res/xml/network_security_config.xml +8 -0
  90. package/native/android/build.gradle.kts +6 -0
  91. package/native/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  92. package/native/android/gradle/wrapper/gradle-wrapper.properties +7 -0
  93. package/native/android/gradle.properties +4 -0
  94. package/native/android/gradlew +87 -0
  95. package/native/android/gradlew.bat +48 -0
  96. package/native/android/settings.gradle.kts +20 -0
  97. package/native/ios/VueNativeCore/Package.resolved +23 -0
  98. package/native/ios/VueNativeCore/Package.swift +32 -0
  99. package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/CertificatePinning.swift +136 -0
  100. package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/ErrorOverlayView.swift +89 -0
  101. package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/HotReloadManager.swift +147 -0
  102. package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/JSPolyfills.swift +711 -0
  103. package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/JSRuntime.swift +421 -0
  104. package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/NativeBridge.swift +906 -0
  105. package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/VueNativeViewController.swift +88 -0
  106. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/ComponentRegistry.swift +193 -0
  107. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VActionSheetFactory.swift +90 -0
  108. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VActivityIndicatorFactory.swift +74 -0
  109. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VAlertDialogFactory.swift +149 -0
  110. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VButtonFactory.swift +93 -0
  111. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VCheckboxFactory.swift +114 -0
  112. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VDropdownFactory.swift +112 -0
  113. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VImageFactory.swift +172 -0
  114. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VInputFactory.swift +357 -0
  115. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VKeyboardAvoidingFactory.swift +99 -0
  116. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VListFactory.swift +250 -0
  117. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VModalFactory.swift +109 -0
  118. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VPickerFactory.swift +96 -0
  119. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VPressableFactory.swift +168 -0
  120. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VProgressBarFactory.swift +39 -0
  121. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VRadioFactory.swift +167 -0
  122. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VRefreshControlFactory.swift +153 -0
  123. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VSafeAreaFactory.swift +56 -0
  124. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VScrollViewFactory.swift +240 -0
  125. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VSectionListFactory.swift +248 -0
  126. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VSegmentedControlFactory.swift +73 -0
  127. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VSliderFactory.swift +63 -0
  128. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VStatusBarFactory.swift +50 -0
  129. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VSwitchFactory.swift +108 -0
  130. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VTextFactory.swift +290 -0
  131. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VVideoFactory.swift +250 -0
  132. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VViewFactory.swift +157 -0
  133. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VWebViewFactory.swift +174 -0
  134. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/NativeComponentFactory.swift +53 -0
  135. package/native/ios/VueNativeCore/Sources/VueNativeCore/Helpers/Extensions.swift +31 -0
  136. package/native/ios/VueNativeCore/Sources/VueNativeCore/Helpers/GestureWrapper.swift +107 -0
  137. package/native/ios/VueNativeCore/Sources/VueNativeCore/Helpers/TouchableView.swift +136 -0
  138. package/native/ios/VueNativeCore/Sources/VueNativeCore/Helpers/UIColor+Hex.swift +80 -0
  139. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/AnimationModule.swift +283 -0
  140. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/AppStateModule.swift +59 -0
  141. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/AsyncStorageModule.swift +68 -0
  142. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/AudioModule.swift +371 -0
  143. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/BackgroundTaskModule.swift +135 -0
  144. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/BiometryModule.swift +61 -0
  145. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/BluetoothModule.swift +379 -0
  146. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/CalendarModule.swift +154 -0
  147. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/CameraModule.swift +315 -0
  148. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/ClipboardModule.swift +33 -0
  149. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/ContactsModule.swift +173 -0
  150. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/DatabaseModule.swift +259 -0
  151. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/DeviceInfoModule.swift +34 -0
  152. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/FileSystemModule.swift +233 -0
  153. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/GeolocationModule.swift +147 -0
  154. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/HapticsModule.swift +50 -0
  155. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/IAPModule.swift +194 -0
  156. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/KeyboardModule.swift +31 -0
  157. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/LinkingModule.swift +42 -0
  158. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/NativeModule.swift +28 -0
  159. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/NativeModuleRegistry.swift +78 -0
  160. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/NetworkModule.swift +62 -0
  161. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/NotificationsModule.swift +215 -0
  162. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/OTAModule.swift +281 -0
  163. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/PerformanceModule.swift +141 -0
  164. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/PermissionsModule.swift +190 -0
  165. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/SecureStorageModule.swift +118 -0
  166. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/SensorsModule.swift +103 -0
  167. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/ShareModule.swift +48 -0
  168. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/SocialAuthModule.swift +256 -0
  169. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/WebSocketModule.swift +213 -0
  170. package/native/ios/VueNativeCore/Sources/VueNativeCore/Resources/vue-native-placeholder.js +8 -0
  171. package/native/ios/VueNativeCore/Sources/VueNativeCore/Styling/StyleEngine.swift +885 -0
  172. package/native/ios/VueNativeCore/Tests/VueNativeCoreTests/JSRuntimeTests.swift +362 -0
  173. package/package.json +3 -2
@@ -0,0 +1,109 @@
1
+ #if canImport(UIKit)
2
+ import UIKit
3
+ import FlexLayout
4
+
5
+ /// Factory for VModal — a window-level overlay component.
6
+ /// The VModal view itself is a zero-size placeholder in the native view tree.
7
+ /// Its children are rendered in a full-screen overlay view added to the key window.
8
+ final class VModalFactory: NativeComponentFactory {
9
+
10
+ private static var overlayKey: UInt8 = 0
11
+ private static var visibleKey: UInt8 = 1
12
+
13
+ func createView() -> UIView {
14
+ // Zero-size placeholder in the tree
15
+ let placeholder = UIView()
16
+ placeholder.isHidden = true
17
+ _ = placeholder.flex.width(0).height(0)
18
+ return placeholder
19
+ }
20
+
21
+ func updateProp(view: UIView, key: String, value: Any?) {
22
+ switch key {
23
+ case "visible":
24
+ let visible = (value as? Bool) ?? (value as? NSNumber)?.boolValue ?? false
25
+ updateVisibility(view: view, visible: visible)
26
+ case "onDismiss":
27
+ break // handled via event
28
+ default:
29
+ StyleEngine.apply(key: key, value: value, to: view)
30
+ }
31
+ }
32
+
33
+ private func updateVisibility(view: UIView, visible: Bool) {
34
+ if visible {
35
+ showOverlay(for: view)
36
+ } else {
37
+ hideOverlay(for: view)
38
+ }
39
+ }
40
+
41
+ private func showOverlay(for placeholder: UIView) {
42
+ guard let window = UIApplication.shared.vn_keyWindow else { return }
43
+
44
+ // Get or create overlay
45
+ let overlay: UIView
46
+ if let existing = objc_getAssociatedObject(placeholder, &VModalFactory.overlayKey) as? UIView {
47
+ overlay = existing
48
+ } else {
49
+ overlay = UIView()
50
+ overlay.backgroundColor = UIColor(white: 0, alpha: 0.5)
51
+ objc_setAssociatedObject(
52
+ placeholder,
53
+ &VModalFactory.overlayKey,
54
+ overlay,
55
+ .OBJC_ASSOCIATION_RETAIN_NONATOMIC
56
+ )
57
+ }
58
+
59
+ overlay.frame = window.bounds
60
+ window.addSubview(overlay)
61
+
62
+ // Run Yoga on overlay children
63
+ overlay.flex.layout(mode: .fitContainer)
64
+ }
65
+
66
+ private func hideOverlay(for placeholder: UIView) {
67
+ if let overlay = objc_getAssociatedObject(placeholder, &VModalFactory.overlayKey) as? UIView {
68
+ overlay.removeFromSuperview()
69
+ }
70
+ }
71
+
72
+ func addEventListener(view: UIView, event: String, handler: @escaping (Any?) -> Void) {
73
+ // dismiss event from tapping backdrop — no-op for now
74
+ }
75
+
76
+ func removeEventListener(view: UIView, event: String) {}
77
+
78
+ // Custom child management: route children to the overlay view
79
+ func insertChild(_ child: UIView, into parent: UIView, before anchor: UIView?) {
80
+ let overlay: UIView
81
+ if let existing = objc_getAssociatedObject(parent, &VModalFactory.overlayKey) as? UIView {
82
+ overlay = existing
83
+ } else {
84
+ // Create overlay early so children have somewhere to go
85
+ let newOverlay = UIView()
86
+ newOverlay.backgroundColor = UIColor(white: 0, alpha: 0.5)
87
+ _ = newOverlay.flex.grow(1)
88
+ objc_setAssociatedObject(
89
+ parent,
90
+ &VModalFactory.overlayKey,
91
+ newOverlay,
92
+ .OBJC_ASSOCIATION_RETAIN_NONATOMIC
93
+ )
94
+ overlay = newOverlay
95
+ }
96
+
97
+ if let anchor = anchor, let idx = overlay.subviews.firstIndex(of: anchor) {
98
+ overlay.insertSubview(child, at: idx)
99
+ } else {
100
+ overlay.addSubview(child)
101
+ }
102
+ _ = child.flex
103
+ }
104
+
105
+ func removeChild(_ child: UIView, from parent: UIView) {
106
+ child.removeFromSuperview()
107
+ }
108
+ }
109
+ #endif
@@ -0,0 +1,96 @@
1
+ #if canImport(UIKit)
2
+ import UIKit
3
+ import FlexLayout
4
+ import ObjectiveC
5
+
6
+ private var pickerOnChangeKey: UInt8 = 0
7
+ private var pickerItemsKey: UInt8 = 1
8
+ private var pickerDelegateKey: UInt8 = 2
9
+
10
+ /// Factory for VPicker.
11
+ /// Modes: "selector" (UIPickerView), "date", "time", "datetime" (UIDatePicker)
12
+ final class VPickerFactory: NativeComponentFactory {
13
+
14
+ func createView() -> UIView {
15
+ // Default: UIDatePicker (most common on mobile)
16
+ let picker = UIDatePicker()
17
+ picker.datePickerMode = .date
18
+ if #available(iOS 14.0, *) {
19
+ picker.preferredDatePickerStyle = .compact
20
+ }
21
+ _ = picker.flex
22
+ return picker
23
+ }
24
+
25
+ func updateProp(view: UIView, key: String, value: Any?) {
26
+ switch key {
27
+ case "mode":
28
+ guard let modeStr = value as? String else { return }
29
+ // If we have a UIDatePicker, set its mode
30
+ if let datePicker = view as? UIDatePicker {
31
+ switch modeStr {
32
+ case "date": datePicker.datePickerMode = .date
33
+ case "time": datePicker.datePickerMode = .time
34
+ case "datetime": datePicker.datePickerMode = .dateAndTime
35
+ default: break
36
+ }
37
+ }
38
+ case "value":
39
+ if let datePicker = view as? UIDatePicker {
40
+ if let ms = (value as? Double) ?? (value as? NSNumber)?.doubleValue {
41
+ datePicker.date = Date(timeIntervalSince1970: ms / 1000.0)
42
+ }
43
+ }
44
+ case "minimumDate":
45
+ if let datePicker = view as? UIDatePicker,
46
+ let ms = (value as? Double) ?? (value as? NSNumber)?.doubleValue {
47
+ datePicker.minimumDate = Date(timeIntervalSince1970: ms / 1000.0)
48
+ }
49
+ case "maximumDate":
50
+ if let datePicker = view as? UIDatePicker,
51
+ let ms = (value as? Double) ?? (value as? NSNumber)?.doubleValue {
52
+ datePicker.maximumDate = Date(timeIntervalSince1970: ms / 1000.0)
53
+ }
54
+ case "minuteInterval":
55
+ if let datePicker = view as? UIDatePicker,
56
+ let interval = (value as? Int) ?? (value as? NSNumber)?.intValue {
57
+ datePicker.minuteInterval = interval
58
+ }
59
+ case "items":
60
+ // UIPickerView items — not using UIPickerView in this simplified version
61
+ objc_setAssociatedObject(view, &pickerItemsKey, value, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
62
+ default:
63
+ StyleEngine.apply(key: key, value: value, to: view)
64
+ }
65
+ }
66
+
67
+ func addEventListener(view: UIView, event: String, handler: @escaping (Any?) -> Void) {
68
+ if event == "change" {
69
+ objc_setAssociatedObject(view, &pickerOnChangeKey, handler as AnyObject, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
70
+ if let datePicker = view as? UIDatePicker {
71
+ let target = PickerChangeTarget(view: view)
72
+ objc_setAssociatedObject(view, &pickerDelegateKey, target, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
73
+ datePicker.addTarget(target, action: #selector(PickerChangeTarget.handleChange(_:)), for: .valueChanged)
74
+ }
75
+ }
76
+ }
77
+
78
+ func removeEventListener(view: UIView, event: String) {
79
+ if event == "change" {
80
+ objc_setAssociatedObject(view, &pickerOnChangeKey, nil, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
81
+ }
82
+ }
83
+ }
84
+
85
+ private final class PickerChangeTarget: NSObject {
86
+ private weak var view: UIView?
87
+ init(view: UIView) { self.view = view }
88
+
89
+ @objc func handleChange(_ picker: UIDatePicker) {
90
+ guard let view = view else { return }
91
+ if let handler = objc_getAssociatedObject(view, &pickerOnChangeKey) as? ((Any?) -> Void) {
92
+ handler(["value": picker.date.timeIntervalSince1970 * 1000.0])
93
+ }
94
+ }
95
+ }
96
+ #endif
@@ -0,0 +1,168 @@
1
+ #if canImport(UIKit)
2
+ import UIKit
3
+ import ObjectiveC
4
+ import FlexLayout
5
+
6
+ /// Factory for VPressable — a generic pressable container component.
7
+ ///
8
+ /// Like VButton but without built-in text/label support. Provides press,
9
+ /// long press, pressIn, and pressOut events. Uses PressableView, a subclass
10
+ /// of TouchableView that adds pressIn/pressOut callbacks.
11
+ final class VPressableFactory: NativeComponentFactory {
12
+
13
+ // MARK: - Associated object keys for event handlers
14
+
15
+ private static var pressHandlerKey: UInt8 = 0
16
+ private static var longPressHandlerKey: UInt8 = 1
17
+ private static var pressInHandlerKey: UInt8 = 2
18
+ private static var pressOutHandlerKey: UInt8 = 3
19
+
20
+ // MARK: - NativeComponentFactory
21
+
22
+ func createView() -> UIView {
23
+ let pressable = PressableView()
24
+ // Accessing .flex automatically enables Yoga layout
25
+ _ = pressable.flex
26
+ return pressable
27
+ }
28
+
29
+ func updateProp(view: UIView, key: String, value: Any?) {
30
+ guard let pressable = view as? PressableView else {
31
+ StyleEngine.apply(key: key, value: value, to: view)
32
+ return
33
+ }
34
+
35
+ switch key {
36
+ case "disabled":
37
+ if let disabled = value as? Bool {
38
+ pressable.isDisabled = disabled
39
+ } else if let disabled = value as? Int {
40
+ pressable.isDisabled = disabled != 0
41
+ } else {
42
+ pressable.isDisabled = false
43
+ }
44
+
45
+ case "activeOpacity":
46
+ if let opacity = value as? Double {
47
+ pressable.activeOpacity = CGFloat(opacity)
48
+ } else if let opacity = value as? Int {
49
+ pressable.activeOpacity = CGFloat(opacity)
50
+ } else {
51
+ pressable.activeOpacity = 0.7
52
+ }
53
+
54
+ default:
55
+ StyleEngine.apply(key: key, value: value, to: view)
56
+ }
57
+ }
58
+
59
+ func addEventListener(view: UIView, event: String, handler: @escaping (Any?) -> Void) {
60
+ guard let pressable = view as? PressableView else { return }
61
+
62
+ switch event {
63
+ case "press":
64
+ pressable.onPress = {
65
+ handler(nil)
66
+ }
67
+ objc_setAssociatedObject(
68
+ view,
69
+ &VPressableFactory.pressHandlerKey,
70
+ handler as AnyObject,
71
+ .OBJC_ASSOCIATION_RETAIN_NONATOMIC
72
+ )
73
+
74
+ case "longpress":
75
+ pressable.onLongPress = {
76
+ handler(nil)
77
+ }
78
+ objc_setAssociatedObject(
79
+ view,
80
+ &VPressableFactory.longPressHandlerKey,
81
+ handler as AnyObject,
82
+ .OBJC_ASSOCIATION_RETAIN_NONATOMIC
83
+ )
84
+
85
+ case "pressIn", "pressin":
86
+ pressable.onPressIn = {
87
+ handler(nil)
88
+ }
89
+ objc_setAssociatedObject(
90
+ view,
91
+ &VPressableFactory.pressInHandlerKey,
92
+ handler as AnyObject,
93
+ .OBJC_ASSOCIATION_RETAIN_NONATOMIC
94
+ )
95
+
96
+ case "pressOut", "pressout":
97
+ pressable.onPressOut = {
98
+ handler(nil)
99
+ }
100
+ objc_setAssociatedObject(
101
+ view,
102
+ &VPressableFactory.pressOutHandlerKey,
103
+ handler as AnyObject,
104
+ .OBJC_ASSOCIATION_RETAIN_NONATOMIC
105
+ )
106
+
107
+ default:
108
+ break
109
+ }
110
+ }
111
+
112
+ func removeEventListener(view: UIView, event: String) {
113
+ guard let pressable = view as? PressableView else { return }
114
+
115
+ switch event {
116
+ case "press":
117
+ pressable.onPress = nil
118
+ objc_setAssociatedObject(view, &VPressableFactory.pressHandlerKey, nil, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
119
+
120
+ case "longpress":
121
+ pressable.onLongPress = nil
122
+ objc_setAssociatedObject(view, &VPressableFactory.longPressHandlerKey, nil, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
123
+
124
+ case "pressIn", "pressin":
125
+ pressable.onPressIn = nil
126
+ objc_setAssociatedObject(view, &VPressableFactory.pressInHandlerKey, nil, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
127
+
128
+ case "pressOut", "pressout":
129
+ pressable.onPressOut = nil
130
+ objc_setAssociatedObject(view, &VPressableFactory.pressOutHandlerKey, nil, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
131
+
132
+ default:
133
+ break
134
+ }
135
+ }
136
+ }
137
+
138
+ // MARK: - PressableView
139
+
140
+ /// Extension of TouchableView that adds pressIn and pressOut callbacks.
141
+ /// Fires pressIn when a touch begins and pressOut when the touch ends or is cancelled.
142
+ final class PressableView: TouchableView {
143
+
144
+ /// Called when a touch begins inside the view bounds.
145
+ var onPressIn: (() -> Void)?
146
+
147
+ /// Called when a touch ends or is cancelled.
148
+ var onPressOut: (() -> Void)?
149
+
150
+ override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
151
+ super.touchesBegan(touches, with: event)
152
+ guard !isDisabled else { return }
153
+ onPressIn?()
154
+ }
155
+
156
+ override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
157
+ super.touchesEnded(touches, with: event)
158
+ guard !isDisabled else { return }
159
+ onPressOut?()
160
+ }
161
+
162
+ override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
163
+ super.touchesCancelled(touches, with: event)
164
+ guard !isDisabled else { return }
165
+ onPressOut?()
166
+ }
167
+ }
168
+ #endif
@@ -0,0 +1,39 @@
1
+ #if canImport(UIKit)
2
+ import UIKit
3
+ import FlexLayout
4
+
5
+ /// Factory for VProgressBar — maps to UIProgressView.
6
+ final class VProgressBarFactory: NativeComponentFactory {
7
+
8
+ func createView() -> UIView {
9
+ let bar = UIProgressView(progressViewStyle: .default)
10
+ bar.progress = 0
11
+ _ = bar.flex
12
+ return bar
13
+ }
14
+
15
+ func updateProp(view: UIView, key: String, value: Any?) {
16
+ guard let bar = view as? UIProgressView else {
17
+ StyleEngine.apply(key: key, value: value, to: view)
18
+ return
19
+ }
20
+ switch key {
21
+ case "progress":
22
+ let p = (value as? Double) ?? (value as? NSNumber)?.doubleValue ?? 0
23
+ bar.setProgress(Float(max(0, min(1, p))), animated: false)
24
+ case "progressTintColor":
25
+ if let str = value as? String { bar.progressTintColor = UIColor.fromHex(str) }
26
+ case "trackTintColor":
27
+ if let str = value as? String { bar.trackTintColor = UIColor.fromHex(str) }
28
+ case "animated":
29
+ // stored for use in future progress updates — no-op here
30
+ break
31
+ default:
32
+ StyleEngine.apply(key: key, value: value, to: view)
33
+ }
34
+ }
35
+
36
+ func addEventListener(view: UIView, event: String, handler: @escaping (Any?) -> Void) {}
37
+ func removeEventListener(view: UIView, event: String) {}
38
+ }
39
+ #endif
@@ -0,0 +1,167 @@
1
+ #if canImport(UIKit)
2
+ import UIKit
3
+ import FlexLayout
4
+ import ObjectiveC
5
+
6
+ private var radioOnChangeKey: UInt8 = 0
7
+ private var radioOptionsKey: UInt8 = 1
8
+ private var radioSelectedKey: UInt8 = 2
9
+
10
+ /// Factory for VRadio — a radio button group.
11
+ /// Uses a vertical UIStackView with rows of custom radio circles and labels.
12
+ final class VRadioFactory: NativeComponentFactory {
13
+
14
+ func createView() -> UIView {
15
+ let stack = UIStackView()
16
+ stack.axis = .vertical
17
+ stack.spacing = 12
18
+ stack.alignment = .leading
19
+ _ = stack.flex
20
+ return stack
21
+ }
22
+
23
+ func updateProp(view: UIView, key: String, value: Any?) {
24
+ guard let stack = view as? UIStackView else {
25
+ StyleEngine.apply(key: key, value: value, to: view)
26
+ return
27
+ }
28
+
29
+ switch key {
30
+ case "options":
31
+ guard let items = value as? [[String: Any]] else { return }
32
+ let options = items.compactMap { dict -> (label: String, value: String)? in
33
+ guard let label = dict["label"] as? String,
34
+ let val = dict["value"] as? String else { return nil }
35
+ return (label, val)
36
+ }
37
+ objc_setAssociatedObject(view, &radioOptionsKey, options.map { $0.value }, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
38
+
39
+ // Rebuild radio buttons
40
+ stack.arrangedSubviews.forEach { $0.removeFromSuperview() }
41
+ for (index, option) in options.enumerated() {
42
+ let row = createRadioRow(label: option.label, index: index, in: view)
43
+ stack.addArrangedSubview(row)
44
+ }
45
+
46
+ // Re-apply selection
47
+ if let selected = objc_getAssociatedObject(view, &radioSelectedKey) as? String {
48
+ applySelection(stack, selectedValue: selected)
49
+ }
50
+
51
+ case "selectedValue":
52
+ let selected = value as? String ?? ""
53
+ objc_setAssociatedObject(view, &radioSelectedKey, selected, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
54
+ applySelection(stack, selectedValue: selected)
55
+
56
+ case "disabled":
57
+ let disabled = (value as? Bool) ?? false
58
+ stack.isUserInteractionEnabled = !disabled
59
+ stack.alpha = disabled ? 0.4 : 1.0
60
+
61
+ case "tintColor":
62
+ if let colorStr = value as? String {
63
+ let color = UIColor.fromHex(colorStr)
64
+ for subview in stack.arrangedSubviews {
65
+ if let circle = subview.viewWithTag(2001) as? UIImageView {
66
+ circle.tintColor = color
67
+ }
68
+ }
69
+ }
70
+
71
+ default:
72
+ StyleEngine.apply(key: key, value: value, to: view)
73
+ }
74
+ }
75
+
76
+ func addEventListener(view: UIView, event: String, handler: @escaping (Any?) -> Void) {
77
+ guard event == "change" else { return }
78
+ objc_setAssociatedObject(view, &radioOnChangeKey, handler as AnyObject, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
79
+ }
80
+
81
+ func removeEventListener(view: UIView, event: String) {
82
+ if event == "change" {
83
+ objc_setAssociatedObject(view, &radioOnChangeKey, nil, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
84
+ // Remove RadioTapGesture recognizers from all radio row subviews
85
+ if let stack = view as? UIStackView {
86
+ for row in stack.arrangedSubviews {
87
+ row.gestureRecognizers?.forEach { recognizer in
88
+ if recognizer is RadioTapGesture {
89
+ row.removeGestureRecognizer(recognizer)
90
+ }
91
+ }
92
+ }
93
+ }
94
+ }
95
+ }
96
+
97
+ // MARK: - Helpers
98
+
99
+ private func createRadioRow(label: String, index: Int, in container: UIView) -> UIView {
100
+ let row = UIStackView()
101
+ row.axis = .horizontal
102
+ row.spacing = 8
103
+ row.alignment = .center
104
+
105
+ let circle = UIImageView()
106
+ circle.contentMode = .scaleAspectFit
107
+ circle.tag = 2001
108
+ circle.tintColor = .systemBlue
109
+ circle.translatesAutoresizingMaskIntoConstraints = false
110
+ NSLayoutConstraint.activate([
111
+ circle.widthAnchor.constraint(equalToConstant: 22),
112
+ circle.heightAnchor.constraint(equalToConstant: 22),
113
+ ])
114
+ updateRadioImage(circle, selected: false)
115
+
116
+ let textLabel = UILabel()
117
+ textLabel.text = label
118
+ textLabel.font = UIFont.systemFont(ofSize: 16)
119
+ textLabel.tag = 2002
120
+
121
+ row.addArrangedSubview(circle)
122
+ row.addArrangedSubview(textLabel)
123
+
124
+ row.tag = 3000 + index
125
+ row.isUserInteractionEnabled = true
126
+ let tap = RadioTapGesture(target: self, action: #selector(handleRadioTap(_:)))
127
+ tap.radioIndex = index
128
+ tap.containerView = container
129
+ row.addGestureRecognizer(tap)
130
+
131
+ return row
132
+ }
133
+
134
+ @objc private func handleRadioTap(_ sender: RadioTapGesture) {
135
+ guard let container = sender.containerView else { return }
136
+ let values = objc_getAssociatedObject(container, &radioOptionsKey) as? [String] ?? []
137
+ guard sender.radioIndex < values.count else { return }
138
+ let value = values[sender.radioIndex]
139
+
140
+ if let handler = objc_getAssociatedObject(container, &radioOnChangeKey) as? ((Any?) -> Void) {
141
+ handler(["value": value])
142
+ }
143
+ }
144
+
145
+ private func applySelection(_ stack: UIStackView, selectedValue: String) {
146
+ let values = objc_getAssociatedObject(stack, &radioOptionsKey) as? [String] ?? []
147
+ for (index, subview) in stack.arrangedSubviews.enumerated() {
148
+ if let circle = subview.viewWithTag(2001) as? UIImageView {
149
+ let isSelected = index < values.count && values[index] == selectedValue
150
+ updateRadioImage(circle, selected: isSelected)
151
+ }
152
+ }
153
+ }
154
+
155
+ private func updateRadioImage(_ imageView: UIImageView, selected: Bool) {
156
+ let symbolName = selected ? "circle.inset.filled" : "circle"
157
+ let config = UIImage.SymbolConfiguration(pointSize: 20, weight: .regular)
158
+ imageView.image = UIImage(systemName: symbolName, withConfiguration: config)
159
+ }
160
+ }
161
+
162
+ /// Custom UITapGestureRecognizer that carries the radio index and parent view.
163
+ private final class RadioTapGesture: UITapGestureRecognizer {
164
+ var radioIndex: Int = 0
165
+ weak var containerView: UIView?
166
+ }
167
+ #endif