@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
@@ -0,0 +1,49 @@
1
+ import AppKit
2
+ import VueNativeShared
3
+
4
+ /// Native module providing device and screen information for macOS.
5
+ ///
6
+ /// Methods:
7
+ /// - getInfo() -> { platform, systemName, systemVersion, model, name, screenWidth, screenHeight, scale }
8
+ final class DeviceInfoModule: NativeModule {
9
+ let moduleName = "DeviceInfo"
10
+
11
+ func invoke(method: String, args: [Any], callback: @escaping (Any?, String?) -> Void) {
12
+ DispatchQueue.main.async {
13
+ switch method {
14
+ case "getInfo":
15
+ let processInfo = ProcessInfo.processInfo
16
+ let version = processInfo.operatingSystemVersion
17
+
18
+ var systemInfo = utsname()
19
+ uname(&systemInfo)
20
+ let machine = withUnsafePointer(to: &systemInfo.machine) {
21
+ $0.withMemoryRebound(to: CChar.self, capacity: 1) {
22
+ String(validatingUTF8: $0) ?? "unknown"
23
+ }
24
+ }
25
+
26
+ let screen = NSScreen.main
27
+ let screenWidth = screen?.frame.width ?? 0
28
+ let screenHeight = screen?.frame.height ?? 0
29
+ let scale = screen?.backingScaleFactor ?? 1.0
30
+
31
+ let info: [String: Any] = [
32
+ "platform": "macos",
33
+ "systemName": "macOS",
34
+ "systemVersion": "\(version.majorVersion).\(version.minorVersion).\(version.patchVersion)",
35
+ "model": machine,
36
+ "name": Host.current().localizedName ?? "Mac",
37
+ "isSimulator": false,
38
+ "screenWidth": screenWidth,
39
+ "screenHeight": screenHeight,
40
+ "scale": scale,
41
+ ]
42
+ callback(info, nil)
43
+
44
+ default:
45
+ callback(nil, "DeviceInfoModule: Unknown method '\(method)'")
46
+ }
47
+ }
48
+ }
49
+ }
@@ -0,0 +1,50 @@
1
+ import AppKit
2
+ import VueNativeShared
3
+
4
+ /// macOS-only module for drag and drop support.
5
+ ///
6
+ /// Methods:
7
+ /// - enableDropZone(viewId: Int) -- register a view for file/text drops
8
+ /// - startDrag(data: { text: String }) -- initiate a drag operation
9
+ ///
10
+ /// Events dispatched:
11
+ /// - dragDrop:drop { files: [String], text: String? }
12
+ final class DragDropModule: NativeModule {
13
+ let moduleName = "DragDrop"
14
+ private weak var dispatcher: NativeEventDispatcher?
15
+
16
+ init(dispatcher: NativeEventDispatcher) {
17
+ self.dispatcher = dispatcher
18
+ }
19
+
20
+ func invoke(method: String, args: [Any], callback: @escaping (Any?, String?) -> Void) {
21
+ DispatchQueue.main.async { [weak self] in
22
+ switch method {
23
+ case "enableDropZone":
24
+ guard args.first is Int else {
25
+ callback(nil, "Invalid viewId")
26
+ return
27
+ }
28
+ // Register the main window's content view for file and string drops.
29
+ // Full per-view registration would require access to the bridge's view registry.
30
+ if let window = NSApp.mainWindow, let view = window.contentView {
31
+ view.registerForDraggedTypes([.fileURL, .string])
32
+ }
33
+ callback(nil, nil)
34
+
35
+ case "startDrag":
36
+ guard let data = args.first as? [String: Any] else {
37
+ callback(nil, "Invalid args")
38
+ return
39
+ }
40
+ // Drag operations are typically initiated by mouse events.
41
+ // This method prepares drag data that can be used by event handlers.
42
+ _ = data
43
+ callback(nil, nil)
44
+
45
+ default:
46
+ callback(nil, "DragDropModule: Unknown method '\(method)'")
47
+ }
48
+ }
49
+ }
50
+ }
@@ -0,0 +1,86 @@
1
+ import AppKit
2
+ import UniformTypeIdentifiers
3
+ import VueNativeShared
4
+
5
+ /// macOS-only module for file open/save dialogs.
6
+ ///
7
+ /// Methods:
8
+ /// - openFile(options?: { multiple?, allowedTypes?, title? }) -> [String]? (file paths)
9
+ /// - openDirectory(options?: { title? }) -> String? (directory path)
10
+ /// - saveFile(options?: { title?, defaultName? }) -> String? (save path)
11
+ final class FileDialogModule: NativeModule {
12
+ let moduleName = "FileDialog"
13
+
14
+ func invoke(method: String, args: [Any], callback: @escaping (Any?, String?) -> Void) {
15
+ DispatchQueue.main.async {
16
+ switch method {
17
+ case "openFile":
18
+ let options = args.first as? [String: Any] ?? [:]
19
+ let panel = NSOpenPanel()
20
+ panel.canChooseFiles = true
21
+ panel.canChooseDirectories = false
22
+ panel.allowsMultipleSelection = (options["multiple"] as? Bool) ?? false
23
+
24
+ if let types = options["allowedTypes"] as? [String] {
25
+ panel.allowedContentTypes = types.compactMap { ext in
26
+ UTType(filenameExtension: ext)
27
+ }
28
+ }
29
+
30
+ if let title = options["title"] as? String {
31
+ panel.title = title
32
+ }
33
+
34
+ panel.begin { response in
35
+ if response == .OK {
36
+ let urls = panel.urls.map { $0.path }
37
+ callback(urls, nil)
38
+ } else {
39
+ callback(nil, nil) // cancelled
40
+ }
41
+ }
42
+
43
+ case "openDirectory":
44
+ let options = args.first as? [String: Any] ?? [:]
45
+ let panel = NSOpenPanel()
46
+ panel.canChooseFiles = false
47
+ panel.canChooseDirectories = true
48
+ panel.allowsMultipleSelection = false
49
+
50
+ if let title = options["title"] as? String {
51
+ panel.title = title
52
+ }
53
+
54
+ panel.begin { response in
55
+ if response == .OK {
56
+ callback(panel.url?.path, nil)
57
+ } else {
58
+ callback(nil, nil)
59
+ }
60
+ }
61
+
62
+ case "saveFile":
63
+ let options = args.first as? [String: Any] ?? [:]
64
+ let panel = NSSavePanel()
65
+
66
+ if let title = options["title"] as? String {
67
+ panel.title = title
68
+ }
69
+ if let defaultName = options["defaultName"] as? String {
70
+ panel.nameFieldStringValue = defaultName
71
+ }
72
+
73
+ panel.begin { response in
74
+ if response == .OK {
75
+ callback(panel.url?.path, nil)
76
+ } else {
77
+ callback(nil, nil)
78
+ }
79
+ }
80
+
81
+ default:
82
+ callback(nil, "FileDialogModule: Unknown method '\(method)'")
83
+ }
84
+ }
85
+ }
86
+ }
@@ -0,0 +1,42 @@
1
+ import AppKit
2
+ import VueNativeShared
3
+
4
+ /// Native module providing haptic feedback via Force Touch trackpad.
5
+ ///
6
+ /// Methods:
7
+ /// - vibrate(style: String) -- trigger haptic feedback ("light"|"medium"|"heavy")
8
+ /// - notificationFeedback(type: String) -- generic haptic (macOS has no distinct types)
9
+ /// - selectionChanged() -- alignment feedback
10
+ final class HapticsModule: NativeModule {
11
+ let moduleName = "Haptics"
12
+
13
+ func invoke(method: String, args: [Any], callback: @escaping (Any?, String?) -> Void) {
14
+ DispatchQueue.main.async {
15
+ switch method {
16
+ case "vibrate":
17
+ let style = args.first as? String ?? "medium"
18
+ let pattern: NSHapticFeedbackManager.FeedbackPattern
19
+ switch style {
20
+ case "light": pattern = .alignment
21
+ case "medium": pattern = .levelChange
22
+ case "heavy": pattern = .generic
23
+ default: pattern = .generic
24
+ }
25
+ NSHapticFeedbackManager.defaultPerformer.perform(pattern, performanceTime: .now)
26
+ callback(nil, nil)
27
+
28
+ case "notificationFeedback":
29
+ // macOS doesn't have distinct notification haptics — use generic
30
+ NSHapticFeedbackManager.defaultPerformer.perform(.generic, performanceTime: .now)
31
+ callback(nil, nil)
32
+
33
+ case "selectionChanged":
34
+ NSHapticFeedbackManager.defaultPerformer.perform(.alignment, performanceTime: .now)
35
+ callback(nil, nil)
36
+
37
+ default:
38
+ callback(nil, "HapticsModule: Unknown method '\(method)'")
39
+ }
40
+ }
41
+ }
42
+ }
@@ -0,0 +1,28 @@
1
+ import AppKit
2
+ import VueNativeShared
3
+
4
+ /// Native module providing keyboard management for macOS.
5
+ ///
6
+ /// Methods:
7
+ /// - dismiss() -- resign first responder (dismiss any focused input)
8
+ /// - getHeight() -> { height: 0, isVisible: false } (macOS has no virtual keyboard)
9
+ final class KeyboardModule: NativeModule {
10
+ let moduleName = "Keyboard"
11
+
12
+ func invoke(method: String, args: [Any], callback: @escaping (Any?, String?) -> Void) {
13
+ DispatchQueue.main.async {
14
+ switch method {
15
+ case "dismiss":
16
+ NSApp.mainWindow?.makeFirstResponder(nil)
17
+ callback(nil, nil)
18
+
19
+ case "getHeight":
20
+ // macOS has no virtual keyboard
21
+ callback(["height": 0.0, "isVisible": false], nil)
22
+
23
+ default:
24
+ callback(nil, "KeyboardModule: Unknown method '\(method)'")
25
+ }
26
+ }
27
+ }
28
+ }
@@ -0,0 +1,49 @@
1
+ import AppKit
2
+ import VueNativeShared
3
+
4
+ /// Native module for opening URLs and deep links on macOS.
5
+ ///
6
+ /// Methods:
7
+ /// - openURL(url: String) -> Bool
8
+ /// - canOpenURL(url: String) -> Bool
9
+ /// - getInitialURL() -> String?
10
+ final class LinkingModule: NativeModule {
11
+ var moduleName: String { "Linking" }
12
+
13
+ /// The URL that launched the app. Set by the host app before the JS bundle loads.
14
+ static var initialURL: String?
15
+
16
+ func invoke(method: String, args: [Any], callback: @escaping (Any?, String?) -> Void) {
17
+ switch method {
18
+ case "openURL":
19
+ guard let urlString = args.first as? String,
20
+ let url = URL(string: urlString) else {
21
+ callback(nil, "Invalid URL")
22
+ return
23
+ }
24
+ DispatchQueue.main.async {
25
+ let success = NSWorkspace.shared.open(url)
26
+ callback(success, success ? nil : "Failed to open URL")
27
+ }
28
+
29
+ case "canOpenURL":
30
+ guard let urlString = args.first as? String,
31
+ let url = URL(string: urlString) else {
32
+ callback(false, nil)
33
+ return
34
+ }
35
+ DispatchQueue.main.async {
36
+ let canOpen = NSWorkspace.shared.urlForApplication(toOpen: url) != nil
37
+ callback(canOpen, nil)
38
+ }
39
+
40
+ case "getInitialURL":
41
+ callback(LinkingModule.initialURL, nil)
42
+
43
+ default:
44
+ callback(nil, "LinkingModule: Unknown method '\(method)'")
45
+ }
46
+ }
47
+
48
+ func invokeSync(method: String, args: [Any]) -> Any? { nil }
49
+ }
@@ -0,0 +1,95 @@
1
+ import AppKit
2
+ import VueNativeShared
3
+
4
+ /// macOS-only module for menu bar control.
5
+ ///
6
+ /// Methods:
7
+ /// - setAppMenu(items: [{ title, items: [{ title, key?, id?, separator?, disabled? }] }])
8
+ /// - showContextMenu(items: [{ title, key?, id?, separator?, disabled? }])
9
+ ///
10
+ /// Events dispatched:
11
+ /// - menu:itemClick { id, title }
12
+ final class MenuModule: NativeModule {
13
+ let moduleName = "Menu"
14
+ private weak var dispatcher: NativeEventDispatcher?
15
+
16
+ init(dispatcher: NativeEventDispatcher) {
17
+ self.dispatcher = dispatcher
18
+ }
19
+
20
+ func invoke(method: String, args: [Any], callback: @escaping (Any?, String?) -> Void) {
21
+ DispatchQueue.main.async { [weak self] in
22
+ switch method {
23
+ case "setAppMenu":
24
+ guard let items = args.first as? [[String: Any]] else {
25
+ callback(nil, "Invalid args")
26
+ return
27
+ }
28
+ self?.buildMenu(items: items)
29
+ callback(nil, nil)
30
+
31
+ case "showContextMenu":
32
+ guard let items = args.first as? [[String: Any]] else {
33
+ callback(nil, "Invalid args")
34
+ return
35
+ }
36
+ let menu = NSMenu()
37
+ self?.addMenuItems(items, to: menu)
38
+
39
+ if let window = NSApp.mainWindow, let view = window.contentView {
40
+ let location = NSEvent.mouseLocation
41
+ let windowPoint = window.convertPoint(fromScreen: location)
42
+ let viewPoint = view.convert(windowPoint, from: nil)
43
+ menu.popUp(positioning: nil, at: viewPoint, in: view)
44
+ }
45
+ callback(nil, nil)
46
+
47
+ default:
48
+ callback(nil, "MenuModule: Unknown method '\(method)'")
49
+ }
50
+ }
51
+ }
52
+
53
+ private func buildMenu(items: [[String: Any]]) {
54
+ let mainMenu = NSMenu()
55
+ for item in items {
56
+ guard let title = item["title"] as? String else { continue }
57
+ let menuItem = NSMenuItem(title: title, action: nil, keyEquivalent: "")
58
+ let submenu = NSMenu(title: title)
59
+ if let children = item["items"] as? [[String: Any]] {
60
+ addMenuItems(children, to: submenu)
61
+ }
62
+ menuItem.submenu = submenu
63
+ mainMenu.addItem(menuItem)
64
+ }
65
+ NSApp.mainMenu = mainMenu
66
+ }
67
+
68
+ private func addMenuItems(_ items: [[String: Any]], to menu: NSMenu) {
69
+ for item in items {
70
+ if let separator = item["separator"] as? Bool, separator {
71
+ menu.addItem(.separator())
72
+ continue
73
+ }
74
+
75
+ guard let title = item["title"] as? String else { continue }
76
+ let key = item["key"] as? String ?? ""
77
+ let id = item["id"] as? String ?? title
78
+
79
+ let menuItem = NSMenuItem(title: title, action: #selector(menuItemClicked(_:)), keyEquivalent: key)
80
+ menuItem.target = self
81
+ menuItem.representedObject = id
82
+
83
+ if let disabled = item["disabled"] as? Bool, disabled {
84
+ menuItem.isEnabled = false
85
+ }
86
+
87
+ menu.addItem(menuItem)
88
+ }
89
+ }
90
+
91
+ @objc private func menuItemClicked(_ sender: NSMenuItem) {
92
+ guard let id = sender.representedObject as? String else { return }
93
+ dispatcher?.dispatchGlobalEvent("menu:itemClick", payload: ["id": id, "title": sender.title])
94
+ }
95
+ }
@@ -0,0 +1,63 @@
1
+ import AppKit
2
+ import VueNativeShared
3
+
4
+ /// Singleton registry for all native modules.
5
+ /// Modules are registered by name and looked up when JS invokes them.
6
+ @MainActor
7
+ final class NativeModuleRegistry {
8
+
9
+ static let shared = NativeModuleRegistry()
10
+
11
+ private var modules: [String: NativeModule] = [:]
12
+
13
+ private init() {}
14
+
15
+ // MARK: - Registration
16
+
17
+ func register(_ module: NativeModule) {
18
+ modules[module.moduleName] = module
19
+ }
20
+
21
+ /// Register all built-in macOS modules.
22
+ func registerDefaults(dispatcher: NativeEventDispatcher, viewLookup: @escaping (Int) -> NSView?) {
23
+ // Cross-platform ports
24
+ register(HapticsModule())
25
+ register(ClipboardModule())
26
+ register(DeviceInfoModule())
27
+ register(AnimationModule(viewLookup: viewLookup))
28
+ register(AppStateModule(dispatcher: dispatcher))
29
+ register(KeyboardModule())
30
+ register(LinkingModule())
31
+ register(ShareModule())
32
+
33
+ // macOS-only modules
34
+ register(WindowModule())
35
+ register(MenuModule(dispatcher: dispatcher))
36
+ register(FileDialogModule())
37
+ register(DragDropModule(dispatcher: dispatcher))
38
+
39
+ // Additional cross-platform modules
40
+ register(CameraModule())
41
+ register(NotificationsModule())
42
+ register(BiometryModule())
43
+ register(PermissionsModule())
44
+ }
45
+
46
+ // MARK: - Invocation
47
+
48
+ func invoke(module moduleName: String, method: String, args: [Any], callback: @escaping (Any?, String?) -> Void) {
49
+ guard let module = modules[moduleName] else {
50
+ callback(nil, "Module '\(moduleName)' not found")
51
+ return
52
+ }
53
+ module.invoke(method: method, args: args, callback: callback)
54
+ }
55
+
56
+ func invokeSync(module moduleName: String, method: String, args: [Any]) -> Any? {
57
+ guard let module = modules[moduleName] else {
58
+ NSLog("[VueNative] NativeModuleRegistry: Module '\(moduleName)' not found")
59
+ return nil
60
+ }
61
+ return module.invokeSync(method: method, args: args)
62
+ }
63
+ }
@@ -0,0 +1,112 @@
1
+ import UserNotifications
2
+ import AppKit
3
+ import VueNativeShared
4
+
5
+ /// Native module providing local notification access on macOS.
6
+ ///
7
+ /// Methods:
8
+ /// - requestPermission() -> Bool
9
+ /// - checkPermission() -> "granted"/"denied"/"notDetermined"
10
+ /// - scheduleLocal(title, body, delay) -> { id }
11
+ /// - cancelAll()
12
+ /// - cancel(id)
13
+ /// - getBadgeCount() -> String?
14
+ /// - setBadgeCount(count)
15
+ final class NotificationsModule: NativeModule {
16
+ let moduleName = "Notifications"
17
+
18
+ func invoke(method: String, args: [Any], callback: @escaping (Any?, String?) -> Void) {
19
+ let center = UNUserNotificationCenter.current()
20
+
21
+ switch method {
22
+ case "requestPermission":
23
+ center.requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in
24
+ if let error = error {
25
+ callback(nil, "Notification permission error: \(error.localizedDescription)")
26
+ } else {
27
+ callback(granted, nil)
28
+ }
29
+ }
30
+
31
+ case "checkPermission":
32
+ center.getNotificationSettings { settings in
33
+ let result: String
34
+ switch settings.authorizationStatus {
35
+ case .authorized, .provisional, .ephemeral:
36
+ result = "granted"
37
+ case .denied:
38
+ result = "denied"
39
+ case .notDetermined:
40
+ result = "notDetermined"
41
+ @unknown default:
42
+ result = "notDetermined"
43
+ }
44
+ callback(result, nil)
45
+ }
46
+
47
+ case "scheduleLocal":
48
+ let title = args.count > 0 ? (args[0] as? String ?? "") : ""
49
+ let body = args.count > 1 ? (args[1] as? String ?? "") : ""
50
+ let delay = args.count > 2 ? (args[2] as? Double ?? 1.0) : 1.0
51
+
52
+ let content = UNMutableNotificationContent()
53
+ content.title = title
54
+ content.body = body
55
+ content.sound = .default
56
+
57
+ let trigger = UNTimeIntervalNotificationTrigger(
58
+ timeInterval: max(delay, 0.1),
59
+ repeats: false
60
+ )
61
+
62
+ let requestId = UUID().uuidString
63
+ let request = UNNotificationRequest(
64
+ identifier: requestId,
65
+ content: content,
66
+ trigger: trigger
67
+ )
68
+
69
+ center.add(request) { error in
70
+ if let error = error {
71
+ callback(nil, "Schedule error: \(error.localizedDescription)")
72
+ } else {
73
+ callback(["id": requestId], nil)
74
+ }
75
+ }
76
+
77
+ case "cancelAll":
78
+ center.removeAllPendingNotificationRequests()
79
+ callback(nil, nil)
80
+
81
+ case "cancel":
82
+ guard let identifier = args.first as? String else {
83
+ callback(nil, "cancel: missing notification id")
84
+ return
85
+ }
86
+ center.removePendingNotificationRequests(withIdentifiers: [identifier])
87
+ callback(nil, nil)
88
+
89
+ case "getBadgeCount":
90
+ DispatchQueue.main.async {
91
+ let badge = NSApplication.shared.dockTile.badgeLabel
92
+ callback(badge, nil)
93
+ }
94
+
95
+ case "setBadgeCount":
96
+ let count = args.first
97
+ DispatchQueue.main.async {
98
+ if let num = count as? Int {
99
+ NSApplication.shared.dockTile.badgeLabel = num == 0 ? nil : String(num)
100
+ } else if let str = count as? String {
101
+ NSApplication.shared.dockTile.badgeLabel = str.isEmpty ? nil : str
102
+ } else {
103
+ NSApplication.shared.dockTile.badgeLabel = nil
104
+ }
105
+ callback(nil, nil)
106
+ }
107
+
108
+ default:
109
+ callback(nil, "NotificationsModule: Unknown method '\(method)'")
110
+ }
111
+ }
112
+ }