plusui-native-core 0.1.3 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/Core/CMakeLists.txt +190 -7
  2. package/Core/Features/App/app.cpp +129 -0
  3. package/Core/Features/App/app.ts +126 -0
  4. package/Core/Features/Browser/browser.cpp +181 -0
  5. package/Core/Features/Browser/browser.ts +182 -0
  6. package/Core/Features/Clipboard/clipboard.cpp +234 -0
  7. package/Core/Features/Clipboard/clipboard.ts +113 -0
  8. package/Core/Features/Display/display.cpp +209 -0
  9. package/Core/Features/Display/display.ts +104 -0
  10. package/Core/Features/Event/Events.ts +166 -0
  11. package/Core/Features/Event/events.cpp +200 -0
  12. package/Core/Features/Keyboard/keyboard.cpp +186 -0
  13. package/Core/Features/Keyboard/keyboard.ts +175 -0
  14. package/Core/Features/Menu/context-menu.css +293 -0
  15. package/Core/Features/Menu/menu.cpp +481 -0
  16. package/Core/Features/Menu/menu.ts +439 -0
  17. package/Core/Features/Tray/tray.cpp +310 -0
  18. package/Core/Features/Tray/tray.ts +68 -0
  19. package/Core/Features/WebGPU/webgpu.cpp +937 -0
  20. package/Core/Features/WebGPU/webgpu.ts +1013 -0
  21. package/Core/Features/WebView/webview.cpp +1052 -0
  22. package/Core/Features/WebView/webview.ts +510 -0
  23. package/Core/Features/Window/window.cpp +664 -0
  24. package/Core/Features/Window/window.ts +142 -0
  25. package/Core/Features/WindowManager/window_manager.cpp +341 -0
  26. package/Core/include/plusui/app.hpp +73 -0
  27. package/Core/include/plusui/browser.hpp +66 -0
  28. package/Core/include/plusui/clipboard.hpp +41 -0
  29. package/Core/include/plusui/events.hpp +58 -0
  30. package/Core/include/{keyboard.hpp → plusui/keyboard.hpp} +21 -44
  31. package/Core/include/plusui/menu.hpp +153 -0
  32. package/Core/include/plusui/tray.hpp +93 -0
  33. package/Core/include/plusui/webgpu.hpp +434 -0
  34. package/Core/include/plusui/webview.hpp +142 -0
  35. package/Core/include/plusui/window.hpp +111 -0
  36. package/Core/include/plusui/window_manager.hpp +57 -0
  37. package/Core/vendor/WebView2EnvironmentOptions.h +406 -0
  38. package/Core/vendor/stb_image.h +7988 -0
  39. package/Core/vendor/webview.h +618 -510
  40. package/Core/vendor/webview2.h +52079 -0
  41. package/README.md +19 -0
  42. package/package.json +12 -15
  43. package/Core/include/app.hpp +0 -121
  44. package/Core/include/menu.hpp +0 -79
  45. package/Core/include/tray.hpp +0 -81
  46. package/Core/include/window.hpp +0 -106
  47. package/Core/src/app.cpp +0 -311
  48. package/Core/src/display.cpp +0 -424
  49. package/Core/src/tray.cpp +0 -275
  50. package/Core/src/window.cpp +0 -528
  51. package/dist/index.d.ts +0 -205
  52. package/dist/index.js +0 -198
  53. package/src/index.ts +0 -574
  54. /package/Core/include/{display.hpp → plusui/display.hpp} +0 -0
@@ -0,0 +1,182 @@
1
+ export interface BrowserState {
2
+ url: string;
3
+ title: string;
4
+ canGoBack: boolean;
5
+ canGoForward: boolean;
6
+ isLoading: boolean;
7
+ }
8
+
9
+ export type NavigateCallback = (url: string) => void;
10
+ export type StateCallback = (state: BrowserState) => void;
11
+ export type LoadCallback = () => void;
12
+ export type ErrorCallback = (error: string) => void;
13
+
14
+ let _invoke: ((method: string, args?: unknown[]) => Promise<unknown>) | null = null;
15
+
16
+ export function setInvokeFn(fn: (method: string, args?: unknown[]) => Promise<unknown>) {
17
+ _invoke = fn;
18
+ }
19
+
20
+ async function invoke(method: string, args?: unknown[]): Promise<unknown> {
21
+ if (!_invoke) {
22
+ if (typeof window !== 'undefined' && (window as any).__invoke__) {
23
+ _invoke = (window as any).__invoke__;
24
+ } else {
25
+ throw new Error('Browser API not initialized');
26
+ }
27
+ }
28
+ return _invoke(method, args);
29
+ }
30
+
31
+ const _navigateCallbacks: NavigateCallback[] = [];
32
+ const _stateCallbacks: StateCallback[] = [];
33
+ const _loadStartCallbacks: LoadCallback[] = [];
34
+ const _loadEndCallbacks: LoadCallback[] = [];
35
+ const _loadErrorCallbacks: ErrorCallback[] = [];
36
+ let _currentState: BrowserState = { url: '', title: '', canGoBack: false, canGoForward: false, isLoading: false };
37
+ let _routes: Record<string, string> = {};
38
+ let _currentRoute: string = '/';
39
+
40
+ // Setup event listeners from native backend
41
+ if (typeof window !== 'undefined') {
42
+ (window as any).__onNavigate__ = (url: string) => {
43
+ _currentState.url = url;
44
+ _navigateCallbacks.forEach(cb => cb(url));
45
+ };
46
+ (window as any).__onBrowserState__ = (state: BrowserState) => {
47
+ _currentState = state;
48
+ _stateCallbacks.forEach(cb => cb(state));
49
+ };
50
+ (window as any).__onLoadStart__ = () => {
51
+ _currentState.isLoading = true;
52
+ _loadStartCallbacks.forEach(cb => cb());
53
+ };
54
+ (window as any).__onLoadEnd__ = () => {
55
+ _currentState.isLoading = false;
56
+ _loadEndCallbacks.forEach(cb => cb());
57
+ };
58
+ (window as any).__onLoadError__ = (error: string) => {
59
+ _currentState.isLoading = false;
60
+ _loadErrorCallbacks.forEach(cb => cb(error));
61
+ };
62
+ }
63
+
64
+ export const browser = {
65
+ async navigate(url: string): Promise<void> {
66
+ await invoke('browser.navigate', [url]);
67
+ },
68
+
69
+ async goBack(): Promise<void> {
70
+ await invoke('browser.goBack', []);
71
+ },
72
+
73
+ async goForward(): Promise<void> {
74
+ await invoke('browser.goForward', []);
75
+ },
76
+
77
+ async reload(): Promise<void> {
78
+ await invoke('browser.reload', []);
79
+ },
80
+
81
+ async stop(): Promise<void> {
82
+ await invoke('browser.stop', []);
83
+ },
84
+
85
+ async getUrl(): Promise<string> {
86
+ return await invoke('browser.getUrl', []) as Promise<string>;
87
+ },
88
+
89
+ async getTitle(): Promise<string> {
90
+ return await invoke('browser.getTitle', []) as Promise<string>;
91
+ },
92
+
93
+ getState(): BrowserState {
94
+ return { ..._currentState };
95
+ },
96
+
97
+ async canGoBack(): Promise<boolean> {
98
+ return await invoke('browser.canGoBack', []) as Promise<boolean>;
99
+ },
100
+
101
+ async canGoForward(): Promise<boolean> {
102
+ return await invoke('browser.canGoForward', []) as Promise<boolean>;
103
+ },
104
+
105
+ async isLoading(): Promise<boolean> {
106
+ return _currentState.isLoading;
107
+ },
108
+
109
+ onNavigate(callback: NavigateCallback): () => void {
110
+ _navigateCallbacks.push(callback);
111
+ return () => {
112
+ const idx = _navigateCallbacks.indexOf(callback);
113
+ if (idx > -1) _navigateCallbacks.splice(idx, 1);
114
+ };
115
+ },
116
+
117
+ onStateChange(callback: StateCallback): () => void {
118
+ _stateCallbacks.push(callback);
119
+ return () => {
120
+ const idx = _stateCallbacks.indexOf(callback);
121
+ if (idx > -1) _stateCallbacks.splice(idx, 1);
122
+ };
123
+ },
124
+
125
+ onLoadStart(callback: LoadCallback): () => void {
126
+ _loadStartCallbacks.push(callback);
127
+ return () => {
128
+ const idx = _loadStartCallbacks.indexOf(callback);
129
+ if (idx > -1) _loadStartCallbacks.splice(idx, 1);
130
+ };
131
+ },
132
+
133
+ onLoadEnd(callback: LoadCallback): () => void {
134
+ _loadEndCallbacks.push(callback);
135
+ return () => {
136
+ const idx = _loadEndCallbacks.indexOf(callback);
137
+ if (idx > -1) _loadEndCallbacks.splice(idx, 1);
138
+ };
139
+ },
140
+
141
+ onLoadError(callback: ErrorCallback): () => void {
142
+ _loadErrorCallbacks.push(callback);
143
+ return () => {
144
+ const idx = _loadErrorCallbacks.indexOf(callback);
145
+ if (idx > -1) _loadErrorCallbacks.splice(idx, 1);
146
+ };
147
+ }
148
+ };
149
+
150
+ export const router = {
151
+ setRoutes(routes: Record<string, string>): void {
152
+ _routes = routes;
153
+ },
154
+
155
+ getRoutes(): Record<string, string> {
156
+ return { ..._routes };
157
+ },
158
+
159
+ async push(route: string): Promise<void> {
160
+ _currentRoute = route;
161
+ const url = _routes[route] || route;
162
+ await browser.navigate(url);
163
+ },
164
+
165
+ async replace(route: string): Promise<void> {
166
+ _currentRoute = route;
167
+ const url = _routes[route] || route;
168
+ await browser.navigate(url);
169
+ },
170
+
171
+ getCurrentRoute(): string {
172
+ return _currentRoute;
173
+ },
174
+
175
+ async setInitialRoute(route: string): Promise<void> {
176
+ _currentRoute = route;
177
+ const url = _routes[route] || route;
178
+ await browser.navigate(url);
179
+ }
180
+ };
181
+
182
+ export default { browser, router };
@@ -0,0 +1,234 @@
1
+ #include <memory>
2
+ #include <mutex>
3
+ #include <plusui/clipboard.hpp>
4
+
5
+ #ifdef _WIN32
6
+ #define WIN32_LEAN_AND_MEAN
7
+ #include <windows.h>
8
+ #elif defined(__APPLE__)
9
+ #include <AppKit/AppKit.h>
10
+ #include <CoreFoundation/CoreFoundation.h>
11
+ #else
12
+ // Linux/GTK - would use GTK clipboard APIs
13
+ #include <gtk/gtk.h>
14
+ #endif
15
+
16
+ namespace PlusUI {
17
+
18
+ struct Clipboard::Impl {
19
+ std::mutex mtx;
20
+ std::function<void(const std::string &)> changeCallback;
21
+
22
+ #ifdef _WIN32
23
+ HWND hwnd = nullptr;
24
+ #endif
25
+ };
26
+
27
+ Clipboard::Clipboard() : pImpl(new Impl()) {
28
+ #ifdef _WIN32
29
+ // Create hidden window for clipboard monitoring
30
+ // This would be done properly in a full implementation
31
+ #endif
32
+ }
33
+
34
+ Clipboard::~Clipboard() { delete pImpl; }
35
+
36
+ std::string Clipboard::getText() {
37
+ std::lock_guard<std::mutex> lock(pImpl->mtx);
38
+
39
+ #ifdef _WIN32
40
+ if (!OpenClipboard(nullptr)) {
41
+ return "";
42
+ }
43
+
44
+ HANDLE hData = GetClipboardData(CF_UNICODETEXT);
45
+ if (hData == nullptr) {
46
+ CloseClipboard();
47
+ return "";
48
+ }
49
+
50
+ wchar_t *pszText = static_cast<wchar_t *>(GlobalLock(hData));
51
+ if (pszText == nullptr) {
52
+ CloseClipboard();
53
+ return "";
54
+ }
55
+
56
+ // Convert wide string to UTF-8
57
+ int size = WideCharToMultiByte(CP_UTF8, 0, pszText, -1, nullptr, 0, nullptr,
58
+ nullptr);
59
+ std::string text(size - 1, '\0');
60
+ WideCharToMultiByte(CP_UTF8, 0, pszText, -1, &text[0], size, nullptr,
61
+ nullptr);
62
+
63
+ GlobalUnlock(hData);
64
+ CloseClipboard();
65
+
66
+ return text;
67
+
68
+ #elif defined(__APPLE__)
69
+ @autoreleasepool {
70
+ NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
71
+ NSString *str = [pasteboard stringForType:NSPasteboardTypeString];
72
+ if (str) {
73
+ return std::string([str UTF8String]);
74
+ }
75
+ return "";
76
+ }
77
+
78
+ #else
79
+ // Linux/GTK implementation
80
+ if (!gtk_init_check(nullptr, nullptr)) {
81
+ return "";
82
+ }
83
+
84
+ GtkClipboard *clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
85
+ gchar *text = gtk_clipboard_wait_for_text(clipboard);
86
+
87
+ std::string result;
88
+ if (text) {
89
+ result = text;
90
+ g_free(text);
91
+ }
92
+
93
+ return result;
94
+ #endif
95
+ }
96
+
97
+ void Clipboard::setText(const std::string &text) {
98
+ std::lock_guard<std::mutex> lock(pImpl->mtx);
99
+
100
+ #ifdef _WIN32
101
+ if (!OpenClipboard(nullptr)) {
102
+ return;
103
+ }
104
+
105
+ EmptyClipboard();
106
+
107
+ // Convert UTF-8 to wide string
108
+ int size = MultiByteToWideChar(CP_UTF8, 0, text.c_str(), -1, nullptr, 0);
109
+ HGLOBAL hGlob = GlobalAlloc(GMEM_MOVEABLE, size * sizeof(wchar_t));
110
+ if (hGlob) {
111
+ wchar_t *pGlob = static_cast<wchar_t *>(GlobalLock(hGlob));
112
+ MultiByteToWideChar(CP_UTF8, 0, text.c_str(), -1, pGlob, size);
113
+ GlobalUnlock(hGlob);
114
+ SetClipboardData(CF_UNICODETEXT, hGlob);
115
+ }
116
+
117
+ CloseClipboard();
118
+
119
+ #elif defined(__APPLE__)
120
+ @autoreleasepool {
121
+ NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
122
+ [pasteboard clearContents];
123
+ NSString *str = [NSString stringWithUTF8String:text.c_str()];
124
+ [pasteboard setString:str forType:NSPasteboardTypeString];
125
+ }
126
+
127
+ #else
128
+ // Linux/GTK implementation
129
+ if (!gtk_init_check(nullptr, nullptr)) {
130
+ return;
131
+ }
132
+
133
+ GtkClipboard *clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
134
+ gtk_clipboard_set_text(clipboard, text.c_str(), -1);
135
+ #endif
136
+
137
+ // Trigger change callback
138
+ if (pImpl->changeCallback) {
139
+ pImpl->changeCallback(text);
140
+ }
141
+ }
142
+
143
+ bool Clipboard::hasText() {
144
+ #ifdef _WIN32
145
+ return IsClipboardFormatAvailable(CF_UNICODETEXT) != 0;
146
+
147
+ #elif defined(__APPLE__)
148
+ @autoreleasepool {
149
+ NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
150
+ return
151
+ [pasteboard availableTypeFromArray:@[ NSPasteboardTypeString ]] != nil;
152
+ }
153
+
154
+ #else
155
+ // Linux/GTK implementation
156
+ if (!gtk_init_check(nullptr, nullptr)) {
157
+ return false;
158
+ }
159
+
160
+ GtkClipboard *clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
161
+ return gtk_clipboard_wait_is_text_available(clipboard);
162
+ #endif
163
+ }
164
+
165
+ std::string Clipboard::getImage() {
166
+ // Image support would require base64 encoding/decoding
167
+ // Platform-specific image clipboard handling
168
+ // This is a placeholder for now
169
+ return "";
170
+ }
171
+
172
+ void Clipboard::setImage(const std::string &base64Data) {
173
+ // Image support would require base64 decoding
174
+ // Platform-specific image clipboard handling
175
+ // This is a placeholder for now
176
+ }
177
+
178
+ bool Clipboard::hasImage() {
179
+ #ifdef _WIN32
180
+ return IsClipboardFormatAvailable(CF_DIB) != 0 ||
181
+ IsClipboardFormatAvailable(CF_BITMAP) != 0;
182
+
183
+ #elif defined(__APPLE__)
184
+ @autoreleasepool {
185
+ NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
186
+ return [pasteboard availableTypeFromArray:@[
187
+ NSPasteboardTypePNG, NSPasteboardTypeTIFF
188
+ ]] != nil;
189
+ }
190
+
191
+ #else
192
+ // Linux/GTK implementation
193
+ if (!gtk_init_check(nullptr, nullptr)) {
194
+ return false;
195
+ }
196
+
197
+ GtkClipboard *clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
198
+ return gtk_clipboard_wait_is_image_available(clipboard);
199
+ #endif
200
+ }
201
+
202
+ void Clipboard::clear() {
203
+ std::lock_guard<std::mutex> lock(pImpl->mtx);
204
+
205
+ #ifdef _WIN32
206
+ if (OpenClipboard(nullptr)) {
207
+ EmptyClipboard();
208
+ CloseClipboard();
209
+ }
210
+
211
+ #elif defined(__APPLE__)
212
+ @autoreleasepool {
213
+ NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
214
+ [pasteboard clearContents];
215
+ }
216
+
217
+ #else
218
+ // Linux/GTK implementation
219
+ if (!gtk_init_check(nullptr, nullptr)) {
220
+ return;
221
+ }
222
+
223
+ GtkClipboard *clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
224
+ gtk_clipboard_clear(clipboard);
225
+ #endif
226
+ }
227
+
228
+ void Clipboard::onClipboardChange(
229
+ std::function<void(const std::string &)> callback) {
230
+ std::lock_guard<std::mutex> lock(pImpl->mtx);
231
+ pImpl->changeCallback = callback;
232
+ }
233
+
234
+ } // namespace PlusUI
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Clipboard API - Cross-platform clipboard management
3
+ *
4
+ * Provides access to system clipboard for text and images.
5
+ * Supports clipboard change events.
6
+ */
7
+
8
+ export interface ClipboardAPI {
9
+ // Text operations
10
+ getText(): Promise<string>;
11
+ setText(text: string): Promise<void>;
12
+ hasText(): Promise<boolean>;
13
+
14
+ // Image operations (base64 encoded)
15
+ getImage(): Promise<string>;
16
+ setImage(base64Data: string): Promise<void>;
17
+ hasImage(): Promise<boolean>;
18
+
19
+ // Clear clipboard
20
+ clear(): Promise<void>;
21
+
22
+ // Events
23
+ onClipboardChange(callback: (text: string) => void): () => void;
24
+ }
25
+
26
+ export class Clipboard implements ClipboardAPI {
27
+ private invokeFn: (name: string, args?: unknown[]) => Promise<unknown>;
28
+ private onFn: (event: string, callback: (data: unknown) => void) => () => void;
29
+
30
+ constructor(
31
+ invokeFn: (name: string, args?: unknown[]) => Promise<unknown>,
32
+ onFn: (event: string, callback: (data: unknown) => void) => () => void
33
+ ) {
34
+ this.invokeFn = invokeFn;
35
+ this.onFn = onFn;
36
+ }
37
+
38
+ /**
39
+ * Get text from clipboard
40
+ * @returns Current clipboard text content
41
+ */
42
+ async getText(): Promise<string> {
43
+ return (await this.invokeFn('clipboard.getText')) as string;
44
+ }
45
+
46
+ /**
47
+ * Set clipboard text
48
+ * @param text - Text to copy to clipboard
49
+ */
50
+ async setText(text: string): Promise<void> {
51
+ await this.invokeFn('clipboard.setText', [text]);
52
+ }
53
+
54
+ /**
55
+ * Check if clipboard has text
56
+ * @returns True if clipboard contains text
57
+ */
58
+ async hasText(): Promise<boolean> {
59
+ return (await this.invokeFn('clipboard.hasText')) as boolean;
60
+ }
61
+
62
+ /**
63
+ * Get image from clipboard as base64
64
+ * @returns Base64 encoded image data
65
+ */
66
+ async getImage(): Promise<string> {
67
+ return (await this.invokeFn('clipboard.getImage')) as string;
68
+ }
69
+
70
+ /**
71
+ * Set clipboard image from base64 data
72
+ * @param base64Data - Base64 encoded image data
73
+ */
74
+ async setImage(base64Data: string): Promise<void> {
75
+ await this.invokeFn('clipboard.setImage', [base64Data]);
76
+ }
77
+
78
+ /**
79
+ * Check if clipboard has image
80
+ * @returns True if clipboard contains image
81
+ */
82
+ async hasImage(): Promise<boolean> {
83
+ return (await this.invokeFn('clipboard.hasImage')) as boolean;
84
+ }
85
+
86
+ /**
87
+ * Clear clipboard contents
88
+ */
89
+ async clear(): Promise<void> {
90
+ await this.invokeFn('clipboard.clear');
91
+ }
92
+
93
+ /**
94
+ * Listen for clipboard changes
95
+ * @param callback - Function called when clipboard changes
96
+ * @returns Cleanup function to remove listener
97
+ */
98
+ onClipboardChange(callback: (text: string) => void): () => void {
99
+ return this.onFn('clipboard:change', (data) => {
100
+ callback(data as string);
101
+ });
102
+ }
103
+ }
104
+
105
+ /**
106
+ * Factory function to create Clipboard instance
107
+ */
108
+ export function createClipboard(
109
+ invokeFn: (name: string, args?: unknown[]) => Promise<unknown>,
110
+ onFn: (event: string, callback: (data: unknown) => void) => () => void
111
+ ): Clipboard {
112
+ return new Clipboard(invokeFn, onFn);
113
+ }