@thelacanians/vue-native-cli 0.4.15 → 0.6.2

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 (116) hide show
  1. package/dist/cli.js +329 -15
  2. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Bridge/NativeBridge.kt +118 -0
  3. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VViewFactory.kt +178 -1
  4. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/GeneratedModuleRegistry.kt +28 -0
  5. package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/NativeModuleRegistry.kt +3 -0
  6. package/native/android/VueNativeCore/src/test/kotlin/com/vuenative/core/ComponentFactoryTest.kt +674 -0
  7. package/native/android/VueNativeCore/src/test/kotlin/com/vuenative/core/ErrorOverlayViewTest.kt +183 -0
  8. package/native/android/VueNativeCore/src/test/kotlin/com/vuenative/core/EventThrottleTest.kt +203 -0
  9. package/native/android/VueNativeCore/src/test/kotlin/com/vuenative/core/HotReloadManagerTest.kt +162 -0
  10. package/native/android/VueNativeCore/src/test/kotlin/com/vuenative/core/JSPolyfillsTest.kt +153 -0
  11. package/native/android/VueNativeCore/src/test/kotlin/com/vuenative/core/NativeBridgeTest.kt +6 -3
  12. package/native/android/VueNativeCore/src/test/kotlin/com/vuenative/core/NativeModuleTest.kt +475 -0
  13. package/native/android/gradle.properties +1 -0
  14. package/native/android/gradlew +1 -1
  15. package/native/ios/VueNativeCore/Package.swift +1 -1
  16. package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/EventThrottle.swift +1 -0
  17. package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/NativeBridge.swift +143 -5
  18. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VTextFactory.swift +43 -0
  19. package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VViewFactory.swift +116 -4
  20. package/native/ios/VueNativeCore/Sources/VueNativeCore/Helpers/GestureWrapper.swift +100 -0
  21. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/GeneratedModuleRegistry.swift +28 -0
  22. package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/NativeModuleRegistry.swift +3 -0
  23. package/native/ios/VueNativeCore/Tests/VueNativeCoreTests/CertificatePinningTests.swift +190 -0
  24. package/native/ios/VueNativeCore/Tests/VueNativeCoreTests/ComponentFactoryTests.swift +585 -0
  25. package/native/ios/VueNativeCore/Tests/VueNativeCoreTests/EventThrottleTests.swift +161 -0
  26. package/native/ios/VueNativeCore/Tests/VueNativeCoreTests/HotReloadManagerTests.swift +88 -0
  27. package/native/ios/VueNativeCore/Tests/VueNativeCoreTests/JSPolyfillsTests.swift +319 -0
  28. package/native/ios/VueNativeCore/Tests/VueNativeCoreTests/NativeModuleTests.swift +400 -0
  29. package/native/macos/VueNativeMacOS/Package.swift +34 -0
  30. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Bridge/ErrorOverlayView.swift +112 -0
  31. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Bridge/EventThrottle.swift +58 -0
  32. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Bridge/HotReloadManager.swift +153 -0
  33. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Bridge/JSPolyfills.swift +696 -0
  34. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Bridge/JSRuntime.swift +347 -0
  35. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Bridge/NativeBridge.swift +877 -0
  36. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Bridge/VueNativeWindowController.swift +125 -0
  37. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/ComponentRegistry.swift +209 -0
  38. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VActionSheetFactory.swift +155 -0
  39. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VActivityIndicatorFactory.swift +85 -0
  40. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VAlertDialogFactory.swift +132 -0
  41. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VButtonFactory.swift +83 -0
  42. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VCheckboxFactory.swift +108 -0
  43. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VDropdownFactory.swift +155 -0
  44. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VImageFactory.swift +270 -0
  45. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VInputFactory.swift +257 -0
  46. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VKeyboardAvoidingFactory.swift +22 -0
  47. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VListFactory.swift +324 -0
  48. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VModalFactory.swift +231 -0
  49. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VOutlineViewFactory.swift +276 -0
  50. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VPickerFactory.swift +134 -0
  51. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VPressableFactory.swift +120 -0
  52. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VProgressBarFactory.swift +71 -0
  53. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VRadioFactory.swift +193 -0
  54. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VRefreshControlFactory.swift +25 -0
  55. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VSafeAreaFactory.swift +46 -0
  56. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VScrollViewFactory.swift +190 -0
  57. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VSectionListFactory.swift +374 -0
  58. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VSegmentedControlFactory.swift +125 -0
  59. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VSliderFactory.swift +131 -0
  60. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VSplitViewFactory.swift +215 -0
  61. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VStatusBarFactory.swift +25 -0
  62. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VSwitchFactory.swift +92 -0
  63. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VTextFactory.swift +336 -0
  64. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VToolbarFactory.swift +212 -0
  65. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VVideoFactory.swift +245 -0
  66. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VViewFactory.swift +314 -0
  67. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VWebViewFactory.swift +162 -0
  68. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/NativeComponentFactory.swift +54 -0
  69. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Helpers/ClickableView.swift +100 -0
  70. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Helpers/Extensions.swift +23 -0
  71. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Helpers/GestureWrapper.swift +183 -0
  72. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Helpers/NSColor+Hex.swift +78 -0
  73. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Layout/FlippedView.swift +19 -0
  74. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Layout/LayoutNode.swift +493 -0
  75. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/AnimationModule.swift +354 -0
  76. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/AppStateModule.swift +62 -0
  77. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/BiometryModule.swift +60 -0
  78. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/CameraModule.swift +167 -0
  79. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/ClipboardModule.swift +34 -0
  80. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/DeviceInfoModule.swift +49 -0
  81. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/DragDropModule.swift +50 -0
  82. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/FileDialogModule.swift +86 -0
  83. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/HapticsModule.swift +42 -0
  84. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/KeyboardModule.swift +28 -0
  85. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/LinkingModule.swift +49 -0
  86. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/MenuModule.swift +95 -0
  87. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/NativeModuleRegistry.swift +63 -0
  88. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/NotificationsModule.swift +112 -0
  89. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/PermissionsModule.swift +149 -0
  90. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/ShareModule.swift +37 -0
  91. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/WindowModule.swift +71 -0
  92. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Resources/vue-native-placeholder.js +2 -0
  93. package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Styling/StyleEngine.swift +885 -0
  94. package/native/macos/VueNativeMacOS/Tests/VueNativeMacOSTests/ComponentFactoryTests.swift +80 -0
  95. package/native/macos/VueNativeMacOS/Tests/VueNativeMacOSTests/VueNativeMacOSTests.swift +149 -0
  96. package/native/shared/VueNativeShared/AGENTS.md +129 -0
  97. package/native/shared/VueNativeShared/Package.swift +14 -0
  98. package/native/shared/VueNativeShared/Sources/VueNativeShared/CertificatePinning.swift +134 -0
  99. package/native/shared/VueNativeShared/Sources/VueNativeShared/EventThrottle.swift +78 -0
  100. package/native/shared/VueNativeShared/Sources/VueNativeShared/HotReloadManager.swift +162 -0
  101. package/native/shared/VueNativeShared/Sources/VueNativeShared/JSRuntime.swift +412 -0
  102. package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/AsyncStorageModule.swift +68 -0
  103. package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/AudioModule.swift +359 -0
  104. package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/DatabaseModule.swift +259 -0
  105. package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/FileSystemModule.swift +233 -0
  106. package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/GeolocationModule.swift +156 -0
  107. package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/NetworkModule.swift +59 -0
  108. package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/PerformanceModule.swift +113 -0
  109. package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/SecureStorageModule.swift +119 -0
  110. package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/WebSocketModule.swift +212 -0
  111. package/native/shared/VueNativeShared/Sources/VueNativeShared/NativeEventDispatcher.swift +6 -0
  112. package/native/shared/VueNativeShared/Sources/VueNativeShared/NativeModule.swift +26 -0
  113. package/native/shared/VueNativeShared/Sources/VueNativeShared/NativeModuleRegistry.swift +37 -0
  114. package/native/shared/VueNativeShared/Sources/VueNativeShared/SharedJSPolyfills.swift +673 -0
  115. package/native/shared/VueNativeShared/Tests/VueNativeSharedTests/VueNativeSharedTests.swift +44 -0
  116. package/package.json +8 -2
@@ -61,6 +61,23 @@ public final class NativeBridge {
61
61
  /// Reference to the JS runtime.
62
62
  private let runtime = JSRuntime.shared
63
63
 
64
+ // MARK: - Teleport Support
65
+
66
+ /// Maps teleport marker IDs (start, end) for cleanup
67
+ private var teleportMarkers: [Int: (start: Int, end: Int)] = [:]
68
+
69
+ /// Maps parent node IDs to their teleport containers
70
+ private var teleportContainers: [Int: UIView] = [:]
71
+
72
+ /// Modal container for teleporting modals
73
+ private lazy var modalContainer: UIView = {
74
+ let container = UIView()
75
+ container.backgroundColor = .clear
76
+ container.isUserInteractionEnabled = true
77
+ container.translatesAutoresizingMaskIntoConstraints = false
78
+ return container
79
+ }()
80
+
64
81
  // MARK: - Initialization
65
82
 
66
83
  private init() {}
@@ -239,6 +256,12 @@ public final class NativeBridge {
239
256
  handleRemoveEventListener(args: args)
240
257
  case "setRootView":
241
258
  handleSetRootView(args: args)
259
+ case "createTeleport":
260
+ handleCreateTeleport(args: args)
261
+ case "removeTeleport":
262
+ handleRemoveTeleport(args: args)
263
+ case "teleportTo":
264
+ handleTeleportTo(args: args)
242
265
  case "invokeNativeModule":
243
266
  handleInvokeNativeModule(args: args)
244
267
  case "invokeNativeModuleSync":
@@ -425,11 +448,8 @@ public final class NativeBridge {
425
448
  factory.insertChild(childView, into: container, before: beforeView)
426
449
  } else if let index = container.subviews.firstIndex(of: beforeView) {
427
450
  container.insertSubview(childView, at: index)
428
- // Rebuild Yoga children to match UIView subview order
429
- container.flex.removeAllChildren()
430
- for subview in container.subviews {
431
- container.flex.addItem(subview)
432
- }
451
+ container.flex.markDirty()
452
+ container.setNeedsLayout()
433
453
  } else {
434
454
  container.flex.addItem(childView)
435
455
  }
@@ -599,6 +619,124 @@ public final class NativeBridge {
599
619
  vc.view.addSubview(traitObserver)
600
620
  // Retain the observer for the lifetime of the root view controller's view
601
621
  objc_setAssociatedObject(vc.view as UIView, &NativeBridge.traitObserverKey, traitObserver as AnyObject, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
622
+
623
+ // Add modal container to root view for teleport
624
+ if rootView != nil {
625
+ rootView?.addSubview(modalContainer)
626
+ modalContainer.topAnchor.constraint(equalTo: rootView!.topAnchor).isActive = true
627
+ modalContainer.leadingAnchor.constraint(equalTo: rootView!.leadingAnchor).isActive = true
628
+ modalContainer.trailingAnchor.constraint(equalTo: rootView!.trailingAnchor).isActive = true
629
+ modalContainer.bottomAnchor.constraint(equalTo: rootView!.bottomAnchor).isActive = true
630
+ }
631
+ }
632
+
633
+ // MARK: - Teleport Handlers
634
+
635
+ /// createTeleport: [parentId: Int, startId: Int, endId: Int]
636
+ private func handleCreateTeleport(args: [Any]) {
637
+ guard args.count >= 3,
638
+ let parentId = asInt(args[0]),
639
+ let startId = asInt(args[1]),
640
+ let endId = asInt(args[2]) else {
641
+ NSLog("[VueNative Bridge] Error: Invalid createTeleport args: \(args)")
642
+ return
643
+ }
644
+
645
+ guard let parentView = viewRegistry[parentId] else {
646
+ NSLog("[VueNative Bridge] Error: Parent view not found for teleport (id: \(parentId))")
647
+ return
648
+ }
649
+
650
+ // Store teleport marker IDs
651
+ teleportMarkers[parentId] = (start: startId, end: endId)
652
+
653
+ // Create container for teleported content
654
+ let container = UIView()
655
+ container.tag = -parentId // Negative tag to identify as teleport container
656
+ container.backgroundColor = .clear
657
+ container.isUserInteractionEnabled = true
658
+ container.translatesAutoresizingMaskIntoConstraints = false
659
+
660
+ parentView.addSubview(container)
661
+ teleportContainers[parentId] = container
662
+
663
+ #if DEBUG
664
+ NSLog("[VueNative Bridge] Created teleport container for parent \(parentId)")
665
+ #endif
666
+ }
667
+
668
+ /// removeTeleport: [parentId: Int, startId: Int, endId: Int]
669
+ private func handleRemoveTeleport(args: [Any]) {
670
+ guard args.count >= 1,
671
+ let parentId = asInt(args[0]) else {
672
+ NSLog("[VueNative Bridge] Error: Invalid removeTeleport args: \(args)")
673
+ return
674
+ }
675
+
676
+ // Remove teleport container
677
+ if let container = teleportContainers.removeValue(forKey: parentId) {
678
+ container.removeFromSuperview()
679
+ }
680
+
681
+ // Clean up markers
682
+ teleportMarkers.removeValue(forKey: parentId)
683
+
684
+ #if DEBUG
685
+ NSLog("[VueNative Bridge] Removed teleport container for parent \(parentId)")
686
+ #endif
687
+ }
688
+
689
+ /// teleportTo: [target: String, nodeId: Int]
690
+ private func handleTeleportTo(args: [Any]) {
691
+ guard args.count >= 2,
692
+ let target = args[0] as? String,
693
+ let nodeId = asInt(args[1]) else {
694
+ NSLog("[VueNative Bridge] Error: Invalid teleportTo args: \(args)")
695
+ return
696
+ }
697
+
698
+ guard let targetView = getTeleportTarget(target) else {
699
+ NSLog("[VueNative Bridge] Warning: Teleport target '\(target)' not found")
700
+ return
701
+ }
702
+
703
+ guard let childView = viewRegistry[nodeId] else {
704
+ NSLog("[VueNative Bridge] Warning: Node view not found for teleport (id: \(nodeId))")
705
+ return
706
+ }
707
+
708
+ // Move view to teleport target
709
+ childView.removeFromSuperview()
710
+ targetView.addSubview(childView)
711
+
712
+ // Set up full-size constraints
713
+ childView.translatesAutoresizingMaskIntoConstraints = false
714
+ NSLayoutConstraint.activate([
715
+ childView.topAnchor.constraint(equalTo: targetView.topAnchor),
716
+ childView.leadingAnchor.constraint(equalTo: targetView.leadingAnchor),
717
+ childView.trailingAnchor.constraint(equalTo: targetView.trailingAnchor),
718
+ childView.bottomAnchor.constraint(equalTo: targetView.bottomAnchor),
719
+ ])
720
+
721
+ #if DEBUG
722
+ NSLog("[VueNative Bridge] Teleported node \(nodeId) to target '\(target)'")
723
+ #endif
724
+ }
725
+
726
+ /// Get teleport target view by name
727
+ private func getTeleportTarget(_ target: String) -> UIView? {
728
+ switch target {
729
+ case "root":
730
+ return rootView
731
+ case "modal":
732
+ // Ensure modal container is added to root if not already
733
+ if modalContainer.superview == nil && rootView != nil {
734
+ rootView?.addSubview(modalContainer)
735
+ }
736
+ return modalContainer
737
+ default:
738
+ return nil
739
+ }
602
740
  }
603
741
 
604
742
  // MARK: - Native Module Handlers
@@ -40,6 +40,7 @@ final class VTextFactory: NativeComponentFactory {
40
40
  private static var fontSizeKey: UInt8 = 0
41
41
  private static var fontWeightKey: UInt8 = 0
42
42
  private static var fontFamilyKey: UInt8 = 0
43
+ private static var textChildrenKey: UInt8 = 0
43
44
 
44
45
  // MARK: - NativeComponentFactory
45
46
 
@@ -57,6 +58,7 @@ final class VTextFactory: NativeComponentFactory {
57
58
 
58
59
  switch key {
59
60
  case "text":
61
+ storeTextChildren([], on: label)
60
62
  if let text = value as? String {
61
63
  label.text = text
62
64
  } else {
@@ -235,6 +237,31 @@ final class VTextFactory: NativeComponentFactory {
235
237
  }
236
238
  }
237
239
 
240
+ func insertChild(_ child: UIView, into parent: UIView, before anchor: UIView?) {
241
+ guard let label = parent as? UILabel else {
242
+ child.removeFromSuperview()
243
+ return
244
+ }
245
+
246
+ var children = storedTextChildren(on: label)
247
+ if let anchor = anchor, let index = children.firstIndex(where: { $0 === anchor }) {
248
+ children.insert(child, at: index)
249
+ } else {
250
+ children.append(child)
251
+ }
252
+
253
+ storeTextChildren(children, on: label)
254
+ rebuildText(from: children, on: label)
255
+ }
256
+
257
+ func removeChild(_ child: UIView, from parent: UIView) {
258
+ guard let label = parent as? UILabel else { return }
259
+ var children = storedTextChildren(on: label)
260
+ children.removeAll { $0 === child }
261
+ storeTextChildren(children, on: label)
262
+ rebuildText(from: children, on: label)
263
+ }
264
+
238
265
  // MARK: - Font rebuilding
239
266
 
240
267
  /// Rebuild the UIFont from stored fontSize, fontWeight, and fontFamily.
@@ -286,5 +313,21 @@ final class VTextFactory: NativeComponentFactory {
286
313
  private func storedFontFamily(on view: UIView) -> String? {
287
314
  return objc_getAssociatedObject(view, &VTextFactory.fontFamilyKey) as? String
288
315
  }
316
+
317
+ private func storeTextChildren(_ children: [UIView], on view: UIView) {
318
+ objc_setAssociatedObject(view, &VTextFactory.textChildrenKey, children, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
319
+ }
320
+
321
+ private func storedTextChildren(on view: UIView) -> [UIView] {
322
+ return objc_getAssociatedObject(view, &VTextFactory.textChildrenKey) as? [UIView] ?? []
323
+ }
324
+
325
+ private func rebuildText(from children: [UIView], on label: UILabel) {
326
+ let text = children.compactMap { child -> String? in
327
+ (child as? UILabel)?.text
328
+ }.joined()
329
+ label.text = text.isEmpty ? nil : text
330
+ label.flex.markDirty()
331
+ }
289
332
  }
290
333
  #endif
@@ -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" where recognizer is UITapGestureRecognizer:
101
- view.removeGestureRecognizer(recognizer)
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", "swipeRight", "swipeUp", "swipeDown"
107
- where recognizer is UISwipeGestureRecognizer:
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