@thelacanians/vue-native-cli 0.4.14 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +789 -200
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Bridge/NativeBridge.kt +156 -5
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VListFactory.kt +33 -13
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VScrollViewFactory.kt +27 -6
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VSliderFactory.kt +9 -2
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VViewFactory.kt +178 -1
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Helpers/EventThrottle.kt +57 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/GeneratedModuleRegistry.kt +28 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/NativeModuleRegistry.kt +3 -0
- package/native/android/VueNativeCore/src/test/kotlin/com/vuenative/core/ComponentFactoryTest.kt +674 -0
- package/native/android/VueNativeCore/src/test/kotlin/com/vuenative/core/ErrorOverlayViewTest.kt +183 -0
- package/native/android/VueNativeCore/src/test/kotlin/com/vuenative/core/EventThrottleTest.kt +203 -0
- package/native/android/VueNativeCore/src/test/kotlin/com/vuenative/core/HotReloadManagerTest.kt +162 -0
- package/native/android/VueNativeCore/src/test/kotlin/com/vuenative/core/JSPolyfillsTest.kt +153 -0
- package/native/android/VueNativeCore/src/test/kotlin/com/vuenative/core/NativeBridgeTest.kt +6 -3
- package/native/android/VueNativeCore/src/test/kotlin/com/vuenative/core/NativeModuleTest.kt +475 -0
- package/native/android/gradle.properties +1 -0
- package/native/android/gradlew +1 -1
- package/native/ios/VueNativeCore/Package.swift +1 -1
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/EventThrottle.swift +80 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/NativeBridge.swift +244 -112
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VListFactory.swift +19 -2
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VScrollViewFactory.swift +9 -4
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VSliderFactory.swift +8 -3
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VTextFactory.swift +43 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VViewFactory.swift +116 -4
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Helpers/GestureWrapper.swift +100 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/GeneratedModuleRegistry.swift +28 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/NativeModuleRegistry.swift +3 -0
- package/native/ios/VueNativeCore/Tests/VueNativeCoreTests/CertificatePinningTests.swift +190 -0
- package/native/ios/VueNativeCore/Tests/VueNativeCoreTests/ComponentFactoryTests.swift +585 -0
- package/native/ios/VueNativeCore/Tests/VueNativeCoreTests/EventThrottleTests.swift +161 -0
- package/native/ios/VueNativeCore/Tests/VueNativeCoreTests/HotReloadManagerTests.swift +88 -0
- package/native/ios/VueNativeCore/Tests/VueNativeCoreTests/JSPolyfillsTests.swift +319 -0
- package/native/ios/VueNativeCore/Tests/VueNativeCoreTests/NativeModuleTests.swift +400 -0
- package/native/macos/VueNativeMacOS/Package.swift +34 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Bridge/ErrorOverlayView.swift +112 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Bridge/EventThrottle.swift +58 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Bridge/HotReloadManager.swift +153 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Bridge/JSPolyfills.swift +696 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Bridge/JSRuntime.swift +347 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Bridge/NativeBridge.swift +877 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Bridge/VueNativeWindowController.swift +125 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/ComponentRegistry.swift +209 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VActionSheetFactory.swift +155 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VActivityIndicatorFactory.swift +85 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VAlertDialogFactory.swift +132 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VButtonFactory.swift +83 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VCheckboxFactory.swift +108 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VDropdownFactory.swift +155 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VImageFactory.swift +270 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VInputFactory.swift +257 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VKeyboardAvoidingFactory.swift +22 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VListFactory.swift +324 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VModalFactory.swift +231 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VOutlineViewFactory.swift +276 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VPickerFactory.swift +134 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VPressableFactory.swift +120 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VProgressBarFactory.swift +71 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VRadioFactory.swift +193 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VRefreshControlFactory.swift +25 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VSafeAreaFactory.swift +46 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VScrollViewFactory.swift +190 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VSectionListFactory.swift +374 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VSegmentedControlFactory.swift +125 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VSliderFactory.swift +131 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VSplitViewFactory.swift +215 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VStatusBarFactory.swift +25 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VSwitchFactory.swift +92 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VTextFactory.swift +336 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VToolbarFactory.swift +212 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VVideoFactory.swift +245 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VViewFactory.swift +314 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VWebViewFactory.swift +162 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/NativeComponentFactory.swift +54 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Helpers/ClickableView.swift +100 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Helpers/Extensions.swift +23 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Helpers/GestureWrapper.swift +183 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Helpers/NSColor+Hex.swift +78 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Layout/FlippedView.swift +19 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Layout/LayoutNode.swift +493 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/AnimationModule.swift +354 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/AppStateModule.swift +62 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/BiometryModule.swift +60 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/CameraModule.swift +167 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/ClipboardModule.swift +34 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/DeviceInfoModule.swift +49 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/DragDropModule.swift +50 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/FileDialogModule.swift +86 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/HapticsModule.swift +42 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/KeyboardModule.swift +28 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/LinkingModule.swift +49 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/MenuModule.swift +95 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/NativeModuleRegistry.swift +63 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/NotificationsModule.swift +112 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/PermissionsModule.swift +149 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/ShareModule.swift +37 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Modules/WindowModule.swift +71 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Resources/vue-native-placeholder.js +2 -0
- package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Styling/StyleEngine.swift +885 -0
- package/native/macos/VueNativeMacOS/Tests/VueNativeMacOSTests/ComponentFactoryTests.swift +80 -0
- package/native/macos/VueNativeMacOS/Tests/VueNativeMacOSTests/VueNativeMacOSTests.swift +149 -0
- package/native/shared/VueNativeShared/AGENTS.md +129 -0
- package/native/shared/VueNativeShared/Package.swift +14 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/CertificatePinning.swift +134 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/EventThrottle.swift +78 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/HotReloadManager.swift +162 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/JSRuntime.swift +412 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/AsyncStorageModule.swift +68 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/AudioModule.swift +359 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/DatabaseModule.swift +259 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/FileSystemModule.swift +233 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/GeolocationModule.swift +156 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/NetworkModule.swift +59 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/PerformanceModule.swift +113 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/SecureStorageModule.swift +119 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/Modules/WebSocketModule.swift +212 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/NativeEventDispatcher.swift +6 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/NativeModule.swift +26 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/NativeModuleRegistry.swift +37 -0
- package/native/shared/VueNativeShared/Sources/VueNativeShared/SharedJSPolyfills.swift +673 -0
- package/native/shared/VueNativeShared/Tests/VueNativeSharedTests/VueNativeSharedTests.swift +44 -0
- package/package.json +8 -2
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
import AppKit
|
|
2
|
+
import ObjectiveC
|
|
3
|
+
|
|
4
|
+
/// Factory for VOutlineView — macOS-specific tree/outline view component.
|
|
5
|
+
/// Maps to NSOutlineView wrapped in an NSScrollView.
|
|
6
|
+
///
|
|
7
|
+
/// Props:
|
|
8
|
+
/// - data: [{ id, label, children?: [...] }]
|
|
9
|
+
/// - expandAll: Bool
|
|
10
|
+
/// - selectionMode: "single" | "multiple" | "none"
|
|
11
|
+
///
|
|
12
|
+
/// Events:
|
|
13
|
+
/// - select -> { id, label }
|
|
14
|
+
/// - expand -> { id }
|
|
15
|
+
/// - collapse -> { id }
|
|
16
|
+
final class VOutlineViewFactory: NativeComponentFactory {
|
|
17
|
+
|
|
18
|
+
// MARK: - Associated object keys
|
|
19
|
+
|
|
20
|
+
private static var dataSourceKey: UInt8 = 0
|
|
21
|
+
private static var selectHandlerKey: UInt8 = 0
|
|
22
|
+
private static var expandHandlerKey: UInt8 = 0
|
|
23
|
+
private static var collapseHandlerKey: UInt8 = 0
|
|
24
|
+
private static var outlineViewKey: UInt8 = 0
|
|
25
|
+
|
|
26
|
+
// MARK: - NativeComponentFactory
|
|
27
|
+
|
|
28
|
+
func createView() -> NSView {
|
|
29
|
+
let scrollView = NSScrollView()
|
|
30
|
+
scrollView.wantsLayer = true
|
|
31
|
+
scrollView.hasVerticalScroller = true
|
|
32
|
+
scrollView.hasHorizontalScroller = false
|
|
33
|
+
scrollView.autohidesScrollers = true
|
|
34
|
+
scrollView.drawsBackground = false
|
|
35
|
+
|
|
36
|
+
let outlineView = NSOutlineView()
|
|
37
|
+
outlineView.headerView = nil
|
|
38
|
+
outlineView.usesAlternatingRowBackgroundColors = false
|
|
39
|
+
outlineView.allowsMultipleSelection = false
|
|
40
|
+
outlineView.selectionHighlightStyle = .regular
|
|
41
|
+
|
|
42
|
+
let column = NSTableColumn(identifier: NSUserInterfaceItemIdentifier("label"))
|
|
43
|
+
column.title = ""
|
|
44
|
+
column.resizingMask = .autoresizingMask
|
|
45
|
+
outlineView.addTableColumn(column)
|
|
46
|
+
outlineView.outlineTableColumn = column
|
|
47
|
+
|
|
48
|
+
scrollView.documentView = outlineView
|
|
49
|
+
|
|
50
|
+
// Create and attach data source/delegate
|
|
51
|
+
let handler = OutlineHandler(outlineView: outlineView, scrollView: scrollView)
|
|
52
|
+
outlineView.dataSource = handler
|
|
53
|
+
outlineView.delegate = handler
|
|
54
|
+
|
|
55
|
+
objc_setAssociatedObject(
|
|
56
|
+
scrollView, &VOutlineViewFactory.dataSourceKey,
|
|
57
|
+
handler, .OBJC_ASSOCIATION_RETAIN_NONATOMIC
|
|
58
|
+
)
|
|
59
|
+
objc_setAssociatedObject(
|
|
60
|
+
scrollView, &VOutlineViewFactory.outlineViewKey,
|
|
61
|
+
outlineView, .OBJC_ASSOCIATION_RETAIN_NONATOMIC
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
scrollView.ensureLayoutNode()
|
|
65
|
+
return scrollView
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
func updateProp(view: NSView, key: String, value: Any?) {
|
|
69
|
+
let outlineView = objc_getAssociatedObject(
|
|
70
|
+
view, &VOutlineViewFactory.outlineViewKey
|
|
71
|
+
) as? NSOutlineView
|
|
72
|
+
|
|
73
|
+
let handler = objc_getAssociatedObject(
|
|
74
|
+
view, &VOutlineViewFactory.dataSourceKey
|
|
75
|
+
) as? OutlineHandler
|
|
76
|
+
|
|
77
|
+
switch key {
|
|
78
|
+
case "data":
|
|
79
|
+
guard let dataArray = value as? [[String: Any]] else { return }
|
|
80
|
+
let nodes = OutlineNode.parse(dataArray)
|
|
81
|
+
handler?.rootNodes = nodes
|
|
82
|
+
outlineView?.reloadData()
|
|
83
|
+
|
|
84
|
+
// If expandAll was previously set, re-expand
|
|
85
|
+
if handler?.shouldExpandAll == true {
|
|
86
|
+
outlineView?.expandItem(nil, expandChildren: true)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
case "expandAll":
|
|
90
|
+
let expand = (value as? Bool) ?? false
|
|
91
|
+
handler?.shouldExpandAll = expand
|
|
92
|
+
if expand {
|
|
93
|
+
outlineView?.expandItem(nil, expandChildren: true)
|
|
94
|
+
} else {
|
|
95
|
+
outlineView?.collapseItem(nil, collapseChildren: true)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
case "selectionMode":
|
|
99
|
+
guard let outlineView = outlineView else { return }
|
|
100
|
+
if let mode = value as? String {
|
|
101
|
+
switch mode {
|
|
102
|
+
case "multiple":
|
|
103
|
+
outlineView.allowsMultipleSelection = true
|
|
104
|
+
outlineView.allowsEmptySelection = true
|
|
105
|
+
case "none":
|
|
106
|
+
outlineView.allowsMultipleSelection = false
|
|
107
|
+
outlineView.allowsEmptySelection = true
|
|
108
|
+
outlineView.selectionHighlightStyle = .none
|
|
109
|
+
default: // "single"
|
|
110
|
+
outlineView.allowsMultipleSelection = false
|
|
111
|
+
outlineView.allowsEmptySelection = true
|
|
112
|
+
outlineView.selectionHighlightStyle = .regular
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
default:
|
|
117
|
+
StyleEngine.apply(key: key, value: value, to: view)
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
func addEventListener(view: NSView, event: String, handler: @escaping (Any?) -> Void) {
|
|
122
|
+
let outlineHandler = objc_getAssociatedObject(
|
|
123
|
+
view, &VOutlineViewFactory.dataSourceKey
|
|
124
|
+
) as? OutlineHandler
|
|
125
|
+
|
|
126
|
+
switch event {
|
|
127
|
+
case "select":
|
|
128
|
+
outlineHandler?.onSelect = handler
|
|
129
|
+
|
|
130
|
+
case "expand":
|
|
131
|
+
outlineHandler?.onExpand = handler
|
|
132
|
+
|
|
133
|
+
case "collapse":
|
|
134
|
+
outlineHandler?.onCollapse = handler
|
|
135
|
+
|
|
136
|
+
default:
|
|
137
|
+
break
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
func removeEventListener(view: NSView, event: String) {
|
|
142
|
+
let outlineHandler = objc_getAssociatedObject(
|
|
143
|
+
view, &VOutlineViewFactory.dataSourceKey
|
|
144
|
+
) as? OutlineHandler
|
|
145
|
+
|
|
146
|
+
switch event {
|
|
147
|
+
case "select":
|
|
148
|
+
outlineHandler?.onSelect = nil
|
|
149
|
+
|
|
150
|
+
case "expand":
|
|
151
|
+
outlineHandler?.onExpand = nil
|
|
152
|
+
|
|
153
|
+
case "collapse":
|
|
154
|
+
outlineHandler?.onCollapse = nil
|
|
155
|
+
|
|
156
|
+
default:
|
|
157
|
+
break
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// MARK: - OutlineNode
|
|
163
|
+
|
|
164
|
+
private final class OutlineNode {
|
|
165
|
+
let id: String
|
|
166
|
+
let label: String
|
|
167
|
+
var children: [OutlineNode]
|
|
168
|
+
|
|
169
|
+
init(id: String, label: String, children: [OutlineNode] = []) {
|
|
170
|
+
self.id = id
|
|
171
|
+
self.label = label
|
|
172
|
+
self.children = children
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
static func parse(_ array: [[String: Any]]) -> [OutlineNode] {
|
|
176
|
+
return array.map { dict in
|
|
177
|
+
let id = (dict["id"] as? String) ?? UUID().uuidString
|
|
178
|
+
let label = (dict["label"] as? String) ?? ""
|
|
179
|
+
let childDicts = dict["children"] as? [[String: Any]] ?? []
|
|
180
|
+
let children = parse(childDicts)
|
|
181
|
+
return OutlineNode(id: id, label: label, children: children)
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// MARK: - OutlineHandler
|
|
187
|
+
|
|
188
|
+
private final class OutlineHandler: NSObject,
|
|
189
|
+
NSOutlineViewDataSource, NSOutlineViewDelegate
|
|
190
|
+
{
|
|
191
|
+
var rootNodes: [OutlineNode] = []
|
|
192
|
+
var shouldExpandAll: Bool = false
|
|
193
|
+
|
|
194
|
+
var onSelect: ((Any?) -> Void)?
|
|
195
|
+
var onExpand: ((Any?) -> Void)?
|
|
196
|
+
var onCollapse: ((Any?) -> Void)?
|
|
197
|
+
|
|
198
|
+
private weak var outlineView: NSOutlineView?
|
|
199
|
+
private weak var scrollView: NSScrollView?
|
|
200
|
+
|
|
201
|
+
init(outlineView: NSOutlineView, scrollView: NSScrollView) {
|
|
202
|
+
self.outlineView = outlineView
|
|
203
|
+
self.scrollView = scrollView
|
|
204
|
+
super.init()
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// MARK: - NSOutlineViewDataSource
|
|
208
|
+
|
|
209
|
+
func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int {
|
|
210
|
+
if let node = item as? OutlineNode {
|
|
211
|
+
return node.children.count
|
|
212
|
+
}
|
|
213
|
+
return rootNodes.count
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
func outlineView(_ outlineView: NSOutlineView, child index: Int, ofItem item: Any?) -> Any {
|
|
217
|
+
if let node = item as? OutlineNode {
|
|
218
|
+
return node.children[index]
|
|
219
|
+
}
|
|
220
|
+
return rootNodes[index]
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
func outlineView(_ outlineView: NSOutlineView, isItemExpandable item: Any) -> Bool {
|
|
224
|
+
if let node = item as? OutlineNode {
|
|
225
|
+
return !node.children.isEmpty
|
|
226
|
+
}
|
|
227
|
+
return false
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// MARK: - NSOutlineViewDelegate
|
|
231
|
+
|
|
232
|
+
func outlineView(_ outlineView: NSOutlineView, viewFor tableColumn: NSTableColumn?, item: Any) -> NSView? {
|
|
233
|
+
guard let node = item as? OutlineNode else { return nil }
|
|
234
|
+
|
|
235
|
+
let cellId = NSUserInterfaceItemIdentifier("OutlineCell")
|
|
236
|
+
let cellView: NSTableCellView
|
|
237
|
+
|
|
238
|
+
if let reused = outlineView.makeView(withIdentifier: cellId, owner: nil) as? NSTableCellView {
|
|
239
|
+
cellView = reused
|
|
240
|
+
} else {
|
|
241
|
+
cellView = NSTableCellView()
|
|
242
|
+
cellView.identifier = cellId
|
|
243
|
+
|
|
244
|
+
let textField = NSTextField(labelWithString: "")
|
|
245
|
+
textField.translatesAutoresizingMaskIntoConstraints = false
|
|
246
|
+
cellView.addSubview(textField)
|
|
247
|
+
cellView.textField = textField
|
|
248
|
+
|
|
249
|
+
NSLayoutConstraint.activate([
|
|
250
|
+
textField.leadingAnchor.constraint(equalTo: cellView.leadingAnchor, constant: 4),
|
|
251
|
+
textField.trailingAnchor.constraint(equalTo: cellView.trailingAnchor, constant: -4),
|
|
252
|
+
textField.centerYAnchor.constraint(equalTo: cellView.centerYAnchor),
|
|
253
|
+
])
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
cellView.textField?.stringValue = node.label
|
|
257
|
+
return cellView
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
func outlineViewSelectionDidChange(_ notification: Notification) {
|
|
261
|
+
guard let outlineView = outlineView else { return }
|
|
262
|
+
let row = outlineView.selectedRow
|
|
263
|
+
guard row >= 0, let node = outlineView.item(atRow: row) as? OutlineNode else { return }
|
|
264
|
+
onSelect?(["id": node.id, "label": node.label])
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
func outlineViewItemDidExpand(_ notification: Notification) {
|
|
268
|
+
guard let node = notification.userInfo?["NSObject"] as? OutlineNode else { return }
|
|
269
|
+
onExpand?(["id": node.id])
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
func outlineViewItemDidCollapse(_ notification: Notification) {
|
|
273
|
+
guard let node = notification.userInfo?["NSObject"] as? OutlineNode else { return }
|
|
274
|
+
onCollapse?(["id": node.id])
|
|
275
|
+
}
|
|
276
|
+
}
|
package/native/macos/VueNativeMacOS/Sources/VueNativeMacOS/Components/Factories/VPickerFactory.swift
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import AppKit
|
|
2
|
+
import ObjectiveC
|
|
3
|
+
|
|
4
|
+
/// Factory for VPicker — a popup button for selecting from a list of items.
|
|
5
|
+
/// Maps to NSPopUpButton.
|
|
6
|
+
final class VPickerFactory: NativeComponentFactory {
|
|
7
|
+
|
|
8
|
+
private static var changeHandlerKey: UInt8 = 0
|
|
9
|
+
nonisolated(unsafe) static var itemsKey: UInt8 = 0
|
|
10
|
+
|
|
11
|
+
// MARK: - NativeComponentFactory
|
|
12
|
+
|
|
13
|
+
func createView() -> NSView {
|
|
14
|
+
let popup = NSPopUpButton()
|
|
15
|
+
popup.pullsDown = false
|
|
16
|
+
popup.wantsLayer = true
|
|
17
|
+
popup.ensureLayoutNode()
|
|
18
|
+
return popup
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
func updateProp(view: NSView, key: String, value: Any?) {
|
|
22
|
+
guard let popup = view as? NSPopUpButton else {
|
|
23
|
+
StyleEngine.apply(key: key, value: value, to: view)
|
|
24
|
+
return
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
switch key {
|
|
28
|
+
case "items":
|
|
29
|
+
popup.removeAllItems()
|
|
30
|
+
var storedItems: [[String: Any]] = []
|
|
31
|
+
|
|
32
|
+
if let strings = value as? [String] {
|
|
33
|
+
popup.addItems(withTitles: strings)
|
|
34
|
+
storedItems = strings.map { ["label": $0, "value": $0] }
|
|
35
|
+
} else if let items = value as? [[String: Any]] {
|
|
36
|
+
for item in items {
|
|
37
|
+
let label = item["label"] as? String ?? item["value"] as? String ?? ""
|
|
38
|
+
popup.addItem(withTitle: label)
|
|
39
|
+
storedItems.append(item)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
objc_setAssociatedObject(popup, &VPickerFactory.itemsKey, storedItems, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
|
|
43
|
+
|
|
44
|
+
case "selectedIndex":
|
|
45
|
+
if let idx = value as? Int {
|
|
46
|
+
if idx >= 0 && idx < popup.numberOfItems {
|
|
47
|
+
popup.selectItem(at: idx)
|
|
48
|
+
}
|
|
49
|
+
} else if let idx = value as? Double {
|
|
50
|
+
let i = Int(idx)
|
|
51
|
+
if i >= 0 && i < popup.numberOfItems {
|
|
52
|
+
popup.selectItem(at: i)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
case "selectedValue":
|
|
57
|
+
if let val = value as? String,
|
|
58
|
+
let items = objc_getAssociatedObject(popup, &VPickerFactory.itemsKey) as? [[String: Any]] {
|
|
59
|
+
if let idx = items.firstIndex(where: { ($0["value"] as? String) == val }) {
|
|
60
|
+
popup.selectItem(at: idx)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
case "enabled":
|
|
65
|
+
if let enabled = value as? Bool {
|
|
66
|
+
popup.isEnabled = enabled
|
|
67
|
+
} else {
|
|
68
|
+
popup.isEnabled = true
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
case "disabled":
|
|
72
|
+
if let disabled = value as? Bool {
|
|
73
|
+
popup.isEnabled = !disabled
|
|
74
|
+
} else if let disabled = value as? Int {
|
|
75
|
+
popup.isEnabled = disabled == 0
|
|
76
|
+
} else {
|
|
77
|
+
popup.isEnabled = true
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
default:
|
|
81
|
+
StyleEngine.apply(key: key, value: value, to: view)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
func addEventListener(view: NSView, event: String, handler: @escaping (Any?) -> Void) {
|
|
86
|
+
guard let popup = view as? NSPopUpButton, event == "change" else { return }
|
|
87
|
+
|
|
88
|
+
let proxy = PickerActionProxy(popup: popup, handler: handler)
|
|
89
|
+
popup.target = proxy
|
|
90
|
+
popup.action = #selector(PickerActionProxy.selectionChanged(_:))
|
|
91
|
+
objc_setAssociatedObject(
|
|
92
|
+
popup,
|
|
93
|
+
&VPickerFactory.changeHandlerKey,
|
|
94
|
+
proxy,
|
|
95
|
+
.OBJC_ASSOCIATION_RETAIN_NONATOMIC
|
|
96
|
+
)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
func removeEventListener(view: NSView, event: String) {
|
|
100
|
+
guard let popup = view as? NSPopUpButton, event == "change" else { return }
|
|
101
|
+
|
|
102
|
+
popup.target = nil
|
|
103
|
+
popup.action = nil
|
|
104
|
+
objc_setAssociatedObject(popup, &VPickerFactory.changeHandlerKey, nil, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// MARK: - PickerActionProxy
|
|
109
|
+
|
|
110
|
+
/// Target-action proxy that routes NSPopUpButton selection changes to a closure handler.
|
|
111
|
+
final class PickerActionProxy: NSObject {
|
|
112
|
+
|
|
113
|
+
private weak var popup: NSPopUpButton?
|
|
114
|
+
private let handler: (Any?) -> Void
|
|
115
|
+
|
|
116
|
+
init(popup: NSPopUpButton, handler: @escaping (Any?) -> Void) {
|
|
117
|
+
self.popup = popup
|
|
118
|
+
self.handler = handler
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
@objc func selectionChanged(_ sender: NSPopUpButton) {
|
|
122
|
+
let index = sender.indexOfSelectedItem
|
|
123
|
+
let items = objc_getAssociatedObject(sender, &VPickerFactory.itemsKey) as? [[String: Any]]
|
|
124
|
+
let item = items?[safe: index]
|
|
125
|
+
let label = sender.titleOfSelectedItem ?? ""
|
|
126
|
+
let value = item?["value"] as? String ?? label
|
|
127
|
+
|
|
128
|
+
handler([
|
|
129
|
+
"selectedIndex": index,
|
|
130
|
+
"value": value,
|
|
131
|
+
"label": label
|
|
132
|
+
])
|
|
133
|
+
}
|
|
134
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import AppKit
|
|
2
|
+
import ObjectiveC
|
|
3
|
+
|
|
4
|
+
/// Factory for VPressable — custom mouse-tracking view for pressable interactions.
|
|
5
|
+
/// Maps to a PressableView (ClickableView subclass) with press, longPress,
|
|
6
|
+
/// pressIn (mouseDown), and pressOut (mouseUp) events.
|
|
7
|
+
final class VPressableFactory: NativeComponentFactory {
|
|
8
|
+
|
|
9
|
+
// MARK: - Associated object keys
|
|
10
|
+
|
|
11
|
+
private static var pressInHandlerKey: UInt8 = 0
|
|
12
|
+
private static var pressOutHandlerKey: UInt8 = 0
|
|
13
|
+
|
|
14
|
+
// MARK: - NativeComponentFactory
|
|
15
|
+
|
|
16
|
+
func createView() -> NSView {
|
|
17
|
+
let pressable = PressableView()
|
|
18
|
+
pressable.ensureLayoutNode()
|
|
19
|
+
return pressable
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
func updateProp(view: NSView, key: String, value: Any?) {
|
|
23
|
+
guard let pressable = view as? PressableView else {
|
|
24
|
+
StyleEngine.apply(key: key, value: value, to: view)
|
|
25
|
+
return
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
switch key {
|
|
29
|
+
case "disabled":
|
|
30
|
+
if let disabled = value as? Bool {
|
|
31
|
+
pressable.isDisabled = disabled
|
|
32
|
+
} else if let disabled = value as? Int {
|
|
33
|
+
pressable.isDisabled = disabled != 0
|
|
34
|
+
} else {
|
|
35
|
+
pressable.isDisabled = false
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
case "activeOpacity":
|
|
39
|
+
if let opacity = value as? Double {
|
|
40
|
+
pressable.activeOpacity = CGFloat(opacity)
|
|
41
|
+
} else if let opacity = value as? Int {
|
|
42
|
+
pressable.activeOpacity = CGFloat(opacity)
|
|
43
|
+
} else {
|
|
44
|
+
pressable.activeOpacity = 0.7
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
default:
|
|
48
|
+
StyleEngine.apply(key: key, value: value, to: view)
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
func addEventListener(view: NSView, event: String, handler: @escaping (Any?) -> Void) {
|
|
53
|
+
guard let pressable = view as? PressableView else { return }
|
|
54
|
+
|
|
55
|
+
switch event {
|
|
56
|
+
case "press":
|
|
57
|
+
pressable.onPress = {
|
|
58
|
+
handler(nil)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
case "longPress":
|
|
62
|
+
pressable.onLongPress = {
|
|
63
|
+
handler(nil)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
case "pressIn":
|
|
67
|
+
pressable.onPressIn = {
|
|
68
|
+
handler(nil)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
case "pressOut":
|
|
72
|
+
pressable.onPressOut = {
|
|
73
|
+
handler(nil)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
default:
|
|
77
|
+
break
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
func removeEventListener(view: NSView, event: String) {
|
|
82
|
+
guard let pressable = view as? PressableView else { return }
|
|
83
|
+
|
|
84
|
+
switch event {
|
|
85
|
+
case "press":
|
|
86
|
+
pressable.onPress = nil
|
|
87
|
+
case "longPress":
|
|
88
|
+
pressable.onLongPress = nil
|
|
89
|
+
case "pressIn":
|
|
90
|
+
pressable.onPressIn = nil
|
|
91
|
+
case "pressOut":
|
|
92
|
+
pressable.onPressOut = nil
|
|
93
|
+
default:
|
|
94
|
+
break
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// MARK: - PressableView
|
|
100
|
+
|
|
101
|
+
/// ClickableView subclass that adds pressIn (mouseDown) and pressOut (mouseUp) callbacks.
|
|
102
|
+
/// Provides the full set of press interaction events for the VPressable component.
|
|
103
|
+
final class PressableView: ClickableView {
|
|
104
|
+
|
|
105
|
+
/// Called immediately when the mouse button goes down.
|
|
106
|
+
var onPressIn: (() -> Void)?
|
|
107
|
+
|
|
108
|
+
/// Called when the mouse button is released (regardless of position).
|
|
109
|
+
var onPressOut: (() -> Void)?
|
|
110
|
+
|
|
111
|
+
override func mouseDown(with event: NSEvent) {
|
|
112
|
+
onPressIn?()
|
|
113
|
+
super.mouseDown(with: event)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
override func mouseUp(with event: NSEvent) {
|
|
117
|
+
onPressOut?()
|
|
118
|
+
super.mouseUp(with: event)
|
|
119
|
+
}
|
|
120
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import AppKit
|
|
2
|
+
|
|
3
|
+
/// Factory for VProgressBar — a determinate/indeterminate progress indicator.
|
|
4
|
+
/// Maps to NSProgressIndicator with bar style.
|
|
5
|
+
final class VProgressBarFactory: NativeComponentFactory {
|
|
6
|
+
|
|
7
|
+
// MARK: - NativeComponentFactory
|
|
8
|
+
|
|
9
|
+
func createView() -> NSView {
|
|
10
|
+
let indicator = NSProgressIndicator()
|
|
11
|
+
indicator.style = .bar
|
|
12
|
+
indicator.isIndeterminate = false
|
|
13
|
+
indicator.minValue = 0
|
|
14
|
+
indicator.maxValue = 1
|
|
15
|
+
indicator.doubleValue = 0
|
|
16
|
+
indicator.wantsLayer = true
|
|
17
|
+
indicator.ensureLayoutNode()
|
|
18
|
+
return indicator
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
func updateProp(view: NSView, key: String, value: Any?) {
|
|
22
|
+
guard let indicator = view as? NSProgressIndicator else {
|
|
23
|
+
StyleEngine.apply(key: key, value: value, to: view)
|
|
24
|
+
return
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
switch key {
|
|
28
|
+
case "progress", "value":
|
|
29
|
+
if let val = value as? Double {
|
|
30
|
+
indicator.isIndeterminate = false
|
|
31
|
+
indicator.doubleValue = val
|
|
32
|
+
} else if let val = value as? Int {
|
|
33
|
+
indicator.isIndeterminate = false
|
|
34
|
+
indicator.doubleValue = Double(val)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
case "progressTintColor":
|
|
38
|
+
if let colorStr = value as? String {
|
|
39
|
+
indicator.wantsLayer = true
|
|
40
|
+
indicator.layer?.backgroundColor = NSColor.fromHex(colorStr).cgColor
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
case "trackTintColor":
|
|
44
|
+
// No direct API; would require custom drawing
|
|
45
|
+
break
|
|
46
|
+
|
|
47
|
+
case "animated", "indeterminate":
|
|
48
|
+
let indeterminate: Bool
|
|
49
|
+
if let val = value as? Bool {
|
|
50
|
+
indeterminate = val
|
|
51
|
+
} else if let val = value as? Int {
|
|
52
|
+
indeterminate = val != 0
|
|
53
|
+
} else {
|
|
54
|
+
indeterminate = false
|
|
55
|
+
}
|
|
56
|
+
indicator.isIndeterminate = indeterminate
|
|
57
|
+
if indeterminate {
|
|
58
|
+
indicator.startAnimation(nil)
|
|
59
|
+
} else {
|
|
60
|
+
indicator.stopAnimation(nil)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
default:
|
|
64
|
+
StyleEngine.apply(key: key, value: value, to: view)
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
func addEventListener(view: NSView, event: String, handler: @escaping (Any?) -> Void) {
|
|
69
|
+
// No events for progress bar
|
|
70
|
+
}
|
|
71
|
+
}
|