plusui-native-core 0.1.55 → 0.1.57
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/Core/CMakeLists.txt +1 -1
- package/Core/Features/App/app.cpp +0 -56
- package/Core/Features/App/app.ts +3 -0
- package/Core/Features/Browser/browser.ts +6 -0
- package/Core/Features/Clipboard/clipboard.ts +3 -0
- package/Core/Features/Connection/README.md +50 -38
- package/Core/Features/Connection/connect.cpp +27 -50
- package/Core/Features/Connection/connect.ts +86 -0
- package/Core/Features/Display/display.ts +4 -0
- package/Core/Features/FileDrop/filedrop.ts +3 -0
- package/Core/Features/Keyboard/keyboard.ts +3 -0
- package/Core/Features/Menu/menu.ts +3 -0
- package/Core/Features/Tray/tray.ts +4 -0
- package/Core/Features/WebGPU/webgpu.ts +3 -0
- package/Core/Features/Window/window.cpp +176 -7
- package/Core/Features/Window/window.ts +4 -0
- package/Core/include/plusui/connect.hpp +150 -14
- package/Core/include/plusui/connection.hpp +3 -0
- package/Core/include/plusui/plusui.hpp +1 -0
- package/Core/include/plusui/window.hpp +3 -0
- package/package.json +1 -1
- package/Core/Features/Connection/ARCHITECTURE.md +0 -369
- package/Core/Features/Connection/examples/simple_tags_example.hpp +0 -130
- package/Core/Features/Connection/examples/simple_tags_example.ts +0 -247
- package/Core/generated/bridge.hpp +0 -302
package/Core/CMakeLists.txt
CHANGED
|
@@ -7,31 +7,8 @@
|
|
|
7
7
|
#include <plusui/tray.hpp>
|
|
8
8
|
#include <plusui/window.hpp>
|
|
9
9
|
|
|
10
|
-
#include <bridge.hpp> // Generated generated bridge
|
|
11
|
-
|
|
12
10
|
namespace plusui {
|
|
13
11
|
|
|
14
|
-
// --- Bridge Implementation (Demo) ---
|
|
15
|
-
class DemoBridge : public bridge::GeneratedBridge {
|
|
16
|
-
public:
|
|
17
|
-
nlohmann::json handle_greet(const nlohmann::json &args) override {
|
|
18
|
-
std::string name = args.value("name", "Guest");
|
|
19
|
-
return {{"message", "Hello from C++, " + name + "!"}};
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
void handle_log(const nlohmann::json &args) override {
|
|
23
|
-
std::string msg = args.value("msg", "");
|
|
24
|
-
std::cout << "[Client Log] " << msg << std::endl;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
void handle_minimize(const nlohmann::json &args) override {
|
|
28
|
-
// We need access to the window to minimize it.
|
|
29
|
-
// For now, we'll just log. In a real app, Bridge might hold a reference to
|
|
30
|
-
// WindowController.
|
|
31
|
-
std::cout << "[Client] Requested minimize" << std::endl;
|
|
32
|
-
}
|
|
33
|
-
};
|
|
34
|
-
|
|
35
12
|
struct App::Impl {
|
|
36
13
|
bool running = false;
|
|
37
14
|
};
|
|
@@ -151,39 +128,6 @@ Window App::Builder::build() {
|
|
|
151
128
|
}
|
|
152
129
|
}
|
|
153
130
|
|
|
154
|
-
// --- Initialize Bridge ---
|
|
155
|
-
// Create the bridge instance
|
|
156
|
-
auto bridge = std::make_shared<DemoBridge>();
|
|
157
|
-
|
|
158
|
-
// Hook 1: Window -> Bridge (Inbound)
|
|
159
|
-
webviewWin.onMessage(
|
|
160
|
-
[bridge](const std::string &msg) { bridge->dispatch(msg); });
|
|
161
|
-
|
|
162
|
-
// Hook 2: Bridge -> Window (Outbound)
|
|
163
|
-
// We capture webviewWin by value (it's a lightweight handle)
|
|
164
|
-
bridge->setOutboundHandler([webviewWin](const std::string &msg) mutable {
|
|
165
|
-
webviewWin.postMessage(msg);
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
// Keep bridge alive?
|
|
169
|
-
// Since webviewWin.onMessage captures 'bridge', the bridge is kept alive by
|
|
170
|
-
// the Window. And 'bridge' outbound handler captures 'webviewWin', keeping
|
|
171
|
-
// Window alive. Cycle exists, but ensures lifetime match.
|
|
172
|
-
|
|
173
|
-
// Optional: Emit an initial event
|
|
174
|
-
bridge->emit_onResize(config.width, config.height);
|
|
175
|
-
|
|
176
|
-
// Hook 3: File Drop
|
|
177
|
-
webviewWin.onFileDrop([bridge](const std::string &jsonStr) {
|
|
178
|
-
if (jsonStr.empty())
|
|
179
|
-
return;
|
|
180
|
-
try {
|
|
181
|
-
auto j = nlohmann::json::parse(jsonStr);
|
|
182
|
-
bridge->emit_onFileDrop(j);
|
|
183
|
-
} catch (...) {
|
|
184
|
-
}
|
|
185
|
-
});
|
|
186
|
-
|
|
187
131
|
return webviewWin;
|
|
188
132
|
}
|
|
189
133
|
|
package/Core/Features/App/app.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { connect } from '../Connection/connect';
|
|
2
|
+
|
|
1
3
|
export interface AppConfig {
|
|
2
4
|
title?: string;
|
|
3
5
|
width?: number;
|
|
@@ -20,6 +22,7 @@ export interface InvokeOptions {
|
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
export class App {
|
|
25
|
+
public readonly connect = connect.feature('app');
|
|
23
26
|
private initialized = false;
|
|
24
27
|
|
|
25
28
|
constructor(
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { connect } from '../Connection/connect';
|
|
2
|
+
|
|
1
3
|
export interface BrowserState {
|
|
2
4
|
url: string;
|
|
3
5
|
title: string;
|
|
@@ -62,6 +64,8 @@ if (typeof window !== 'undefined') {
|
|
|
62
64
|
}
|
|
63
65
|
|
|
64
66
|
export const browser = {
|
|
67
|
+
connect: connect.feature('browser'),
|
|
68
|
+
|
|
65
69
|
async navigate(url: string): Promise<void> {
|
|
66
70
|
await invoke('browser.navigate', [url]);
|
|
67
71
|
},
|
|
@@ -160,6 +164,8 @@ export const browser = {
|
|
|
160
164
|
};
|
|
161
165
|
|
|
162
166
|
export const router = {
|
|
167
|
+
connect: connect.feature('router'),
|
|
168
|
+
|
|
163
169
|
setRoutes(routes: Record<string, string>): void {
|
|
164
170
|
_routes = routes;
|
|
165
171
|
},
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { connect } from '../Connection/connect';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Clipboard API - Cross-platform clipboard management
|
|
3
5
|
*
|
|
@@ -24,6 +26,7 @@ export interface ClipboardAPI {
|
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
export class Clipboard implements ClipboardAPI {
|
|
29
|
+
public readonly connect = connect.feature('clipboard');
|
|
27
30
|
private invokeFn: (name: string, args?: unknown[]) => Promise<unknown>;
|
|
28
31
|
private onFn: (event: string, callback: (data: unknown) => void) => () => void;
|
|
29
32
|
|
|
@@ -9,7 +9,7 @@ The **Connection Feature** is PlusUI's absurdly simple system for frontend ↔ b
|
|
|
9
9
|
Just `emit()` and `on()` handle all communication patterns:
|
|
10
10
|
|
|
11
11
|
| Keyword | Pattern | Direction | Use Cases |
|
|
12
|
-
|
|
12
|
+
| --------- | --------- | ----------- | ----------- |
|
|
13
13
|
| **EVENT** | Fire & forget | One way → | Notifications, commands, logging |
|
|
14
14
|
| **CALL** | Request/response | Two ways ↔ | Get data, save data, RPC |
|
|
15
15
|
| **STREAM** | Continuous data | One way push → | Real-time updates, monitoring |
|
|
@@ -46,29 +46,18 @@ connect.emit('greet', { name: 'World' });
|
|
|
46
46
|
```cpp
|
|
47
47
|
#include <plusui/connect.hpp>
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
protected:
|
|
51
|
-
void handleMessage(const Envelope& env) override {
|
|
52
|
-
// Listen for messages from frontend
|
|
53
|
-
if (env.kind == MessageKind::Fire && env.name == "greet") {
|
|
54
|
-
std::string name = env.payload["name"];
|
|
55
|
-
|
|
56
|
-
// Respond by emitting back
|
|
57
|
-
emit("greetResponse", {{"message", "Hello, " + name + "!"}});
|
|
58
|
-
}
|
|
59
|
-
}
|
|
49
|
+
plusui::Connect connect;
|
|
60
50
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}
|
|
51
|
+
connect.on("greet", [&connect](const nlohmann::json& payload) {
|
|
52
|
+
std::string user = payload.value("name", "World");
|
|
53
|
+
connect.emit("greetResponse", {{"message", "Hello, " + user + "!"}});
|
|
54
|
+
});
|
|
66
55
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
};
|
|
56
|
+
// Wire backend connect ↔ window bridge once
|
|
57
|
+
plusui::bindConnect(mainWindow, connect);
|
|
58
|
+
|
|
59
|
+
// Example: backend push to frontend
|
|
60
|
+
connect.emit("resize", {{"width", 1280}, {"height", 720}});
|
|
72
61
|
```
|
|
73
62
|
|
|
74
63
|
### Listen on Frontend
|
|
@@ -98,17 +87,42 @@ connect.on('messageName', (data) => {
|
|
|
98
87
|
### Backend
|
|
99
88
|
|
|
100
89
|
```cpp
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
}
|
|
90
|
+
plusui::Connect connect;
|
|
91
|
+
|
|
92
|
+
// Listen for messages
|
|
93
|
+
connect.on("messageName", [](const nlohmann::json& payload) {
|
|
94
|
+
// process payload
|
|
95
|
+
});
|
|
107
96
|
|
|
108
97
|
// Send messages
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
98
|
+
connect.emit("messageName", {{"key", "value"}});
|
|
99
|
+
|
|
100
|
+
// Bridge window <-> connect runtime
|
|
101
|
+
plusui::bindConnect(mainWindow, connect);
|
|
102
|
+
|
|
103
|
+
// Optional: call primitive support
|
|
104
|
+
connect.onCall("getUser", [](const nlohmann::json& payload) {
|
|
105
|
+
return nlohmann::json{{"id", payload.value("id", 0)}, {"name", "Ada"}};
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// Optional: stream/query subscription hooks
|
|
109
|
+
connect.onSubscription("cpu", [](bool subscribed, const nlohmann::json&) {
|
|
110
|
+
if (subscribed) {
|
|
111
|
+
startCpuStream();
|
|
112
|
+
} else {
|
|
113
|
+
stopCpuStream();
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Feature-Scoped Names
|
|
119
|
+
|
|
120
|
+
Use `connect` for custom global channels, and `feature.connect` when you want automatic namespacing:
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
window.connect.emit('resized', { width: 1200, height: 800 }); // -> "window.resized"
|
|
124
|
+
clipboard.connect.emit('changed', { text: 'hello' }); // -> "clipboard.changed"
|
|
125
|
+
connect.emit('custom.appEvent', { ok: true }); // custom/global channel
|
|
112
126
|
```
|
|
113
127
|
|
|
114
128
|
## 💡 Design Your Own Patterns
|
|
@@ -124,13 +138,11 @@ connect.emit('getUser', { id: 123 });
|
|
|
124
138
|
```
|
|
125
139
|
|
|
126
140
|
```cpp
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
}
|
|
133
|
-
}
|
|
141
|
+
plusui::Connect connect;
|
|
142
|
+
connect.onCall("getUser", [](const nlohmann::json& payload) {
|
|
143
|
+
auto user = database.findUser(payload["id"]);
|
|
144
|
+
return nlohmann::json{{"user", user}};
|
|
145
|
+
});
|
|
134
146
|
```
|
|
135
147
|
|
|
136
148
|
### Notifications
|
|
@@ -1,57 +1,34 @@
|
|
|
1
1
|
#include <plusui/connect.hpp>
|
|
2
|
+
#include <plusui/window.hpp>
|
|
2
3
|
|
|
3
4
|
namespace plusui {
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
//
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
//
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
// }
|
|
32
|
-
//
|
|
33
|
-
// // STREAM: continuous updates (start streaming)
|
|
34
|
-
// if (name == "subscribeCPU") {
|
|
35
|
-
// startCPUMonitor(); // Will call emit("cpu", ...) repeatedly
|
|
36
|
-
// }
|
|
37
|
-
//
|
|
38
|
-
// // QUERY: request + stream responses
|
|
39
|
-
// if (name == "search") {
|
|
40
|
-
// auto query = data["query"].get<std::string>();
|
|
41
|
-
// for (auto& result : searchDatabase(query)) {
|
|
42
|
-
// emit("searchResult", result); // Multiple results
|
|
43
|
-
// }
|
|
44
|
-
// }
|
|
45
|
-
//
|
|
46
|
-
// // STATE: synced value
|
|
47
|
-
// if (name == "theme") {
|
|
48
|
-
// currentTheme = data["mode"].get<std::string>();
|
|
49
|
-
// emit("theme", data); // Sync back to frontend
|
|
50
|
-
// }
|
|
51
|
-
// }
|
|
52
|
-
// };
|
|
53
|
-
//
|
|
54
|
-
// See Core/Features/Connection/README.md for more details.
|
|
6
|
+
namespace {
|
|
7
|
+
|
|
8
|
+
std::string makeConnectionDispatchScript(const nlohmann::json &message) {
|
|
9
|
+
return "(function(){const m=" + message.dump() +
|
|
10
|
+
";if(typeof globalThis.__plusuiConnectionMessage === 'function'){"
|
|
11
|
+
"globalThis.__plusuiConnectionMessage(m);}"
|
|
12
|
+
"window.dispatchEvent(new CustomEvent('plusui:connection:message',"
|
|
13
|
+
"{detail:m}));})();";
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
} // namespace
|
|
17
|
+
|
|
18
|
+
void bindConnect(Window &window, Connect &connect) {
|
|
19
|
+
window.onMessage([&connect](const std::string &message) {
|
|
20
|
+
connect.dispatchMessage(message);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
connect.setOutbound([&window](const std::string &message) {
|
|
24
|
+
try {
|
|
25
|
+
auto parsed = nlohmann::json::parse(message);
|
|
26
|
+
window.executeScript(makeConnectionDispatchScript(parsed));
|
|
27
|
+
} catch (...) {
|
|
28
|
+
// Ignore malformed outbound payloads
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
}
|
|
55
32
|
|
|
56
33
|
}
|
|
57
34
|
|
|
@@ -180,7 +180,93 @@ export const connect = {
|
|
|
180
180
|
on: <TData = unknown>(name: string, callback: (payload: TData) => void): (() => void) => {
|
|
181
181
|
return connectionClient.on<TData>(name, callback);
|
|
182
182
|
},
|
|
183
|
+
|
|
184
|
+
feature: (scope: string): FeatureConnect => {
|
|
185
|
+
return createFeatureConnect(scope);
|
|
186
|
+
},
|
|
183
187
|
};
|
|
184
188
|
|
|
185
189
|
// Export the raw client for advanced use cases (call, fire, stream, channel)
|
|
186
190
|
export const connection = connectionClient;
|
|
191
|
+
|
|
192
|
+
export type FeatureConnect = {
|
|
193
|
+
emit: <TIn = Record<string, unknown>>(name: string, payload: TIn) => void;
|
|
194
|
+
on: <TData = unknown>(name: string, callback: (payload: TData) => void) => (() => void);
|
|
195
|
+
call: <TOut = unknown, TIn = Record<string, unknown>>(name: string, payload: TIn) => Promise<TOut>;
|
|
196
|
+
stream: <TData = unknown>(name: string) => {
|
|
197
|
+
subscribe: (callback: (payload: TData) => void) => (() => void);
|
|
198
|
+
};
|
|
199
|
+
channel: <TData = unknown>(name: string) => {
|
|
200
|
+
subscribe: (callback: (payload: TData) => void) => (() => void);
|
|
201
|
+
publish: (payload: TData) => void;
|
|
202
|
+
};
|
|
203
|
+
scoped: (scope: string) => FeatureConnect;
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
function scopeName(scope: string, name: string): string {
|
|
207
|
+
if (name.startsWith(`${scope}.`)) {
|
|
208
|
+
return name;
|
|
209
|
+
}
|
|
210
|
+
return `${scope}.${name}`;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
async function invokeScoped(method: string, payload?: unknown): Promise<unknown> {
|
|
214
|
+
const host = globalThis as any;
|
|
215
|
+
if (typeof host.__invoke__ !== 'function') {
|
|
216
|
+
return undefined;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const args = payload === undefined ? [] : [payload];
|
|
220
|
+
return host.__invoke__(method, args);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export function createFeatureConnect(scope: string): FeatureConnect {
|
|
224
|
+
return {
|
|
225
|
+
emit: <TIn = Record<string, unknown>>(name: string, payload: TIn) => {
|
|
226
|
+
const scoped = scopeName(scope, name);
|
|
227
|
+
void invokeScoped(scoped, payload);
|
|
228
|
+
connect.emit(scoped, payload);
|
|
229
|
+
|
|
230
|
+
if (typeof window !== 'undefined') {
|
|
231
|
+
window.dispatchEvent(new CustomEvent(`plusui:${scoped}`, { detail: payload }));
|
|
232
|
+
}
|
|
233
|
+
},
|
|
234
|
+
on: <TData = unknown>(name: string, callback: (payload: TData) => void): (() => void) => {
|
|
235
|
+
const scoped = scopeName(scope, name);
|
|
236
|
+
const offConnect = connect.on<TData>(scoped, callback);
|
|
237
|
+
|
|
238
|
+
if (typeof window === 'undefined') {
|
|
239
|
+
return offConnect;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const domHandler = (event: Event) => {
|
|
243
|
+
const custom = event as CustomEvent<TData>;
|
|
244
|
+
callback(custom.detail);
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
window.addEventListener(`plusui:${scoped}`, domHandler as EventListener);
|
|
248
|
+
|
|
249
|
+
return () => {
|
|
250
|
+
offConnect();
|
|
251
|
+
window.removeEventListener(`plusui:${scoped}`, domHandler as EventListener);
|
|
252
|
+
};
|
|
253
|
+
},
|
|
254
|
+
call: <TOut = unknown, TIn = Record<string, unknown>>(name: string, payload: TIn): Promise<TOut> => {
|
|
255
|
+
const scoped = scopeName(scope, name);
|
|
256
|
+
const host = globalThis as any;
|
|
257
|
+
|
|
258
|
+
if (typeof host.__invoke__ === 'function') {
|
|
259
|
+
return invokeScoped(scoped, payload) as Promise<TOut>;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
return connection.call<TOut, TIn>(scoped, payload);
|
|
263
|
+
},
|
|
264
|
+
stream: <TData = unknown>(name: string) => {
|
|
265
|
+
return connection.stream<TData>(scopeName(scope, name));
|
|
266
|
+
},
|
|
267
|
+
channel: <TData = unknown>(name: string) => {
|
|
268
|
+
return connection.channel<TData>(scopeName(scope, name));
|
|
269
|
+
},
|
|
270
|
+
scoped: (childScope: string) => createFeatureConnect(scopeName(scope, childScope)),
|
|
271
|
+
};
|
|
272
|
+
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { connect } from '../Connection/connect';
|
|
2
|
+
|
|
1
3
|
export interface DisplayMode {
|
|
2
4
|
width: number;
|
|
3
5
|
height: number;
|
|
@@ -32,6 +34,8 @@ export interface Display {
|
|
|
32
34
|
}
|
|
33
35
|
|
|
34
36
|
export class DisplayAPI {
|
|
37
|
+
public readonly connect = connect.feature('display');
|
|
38
|
+
|
|
35
39
|
constructor(
|
|
36
40
|
private invokeFn: (name: string, args?: unknown[]) => Promise<unknown>
|
|
37
41
|
) {}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { connect } from '../Connection/connect';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* FileDrop API - Cross-platform drag & drop file handling
|
|
3
5
|
*
|
|
@@ -77,6 +79,7 @@ export interface FileDropAPI {
|
|
|
77
79
|
}
|
|
78
80
|
|
|
79
81
|
export class FileDrop implements FileDropAPI {
|
|
82
|
+
public readonly connect = connect.feature('fileDrop');
|
|
80
83
|
private invokeFn: (name: string, args?: unknown[]) => Promise<unknown>;
|
|
81
84
|
private onFn: (event: string, callback: (data: unknown) => void) => () => void;
|
|
82
85
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { connect } from '../Connection/connect';
|
|
2
|
+
|
|
1
3
|
export enum KeyCode {
|
|
2
4
|
Unknown = 0,
|
|
3
5
|
Space = 32,
|
|
@@ -53,6 +55,7 @@ export type KeyEventCallback = (event: KeyEvent) => void;
|
|
|
53
55
|
export type ShortcutCallback = () => void;
|
|
54
56
|
|
|
55
57
|
export class KeyboardAPI {
|
|
58
|
+
public readonly connect = connect.feature('keyboard');
|
|
56
59
|
private shortcutHandlers: Map<string, ShortcutCallback> = new Map();
|
|
57
60
|
|
|
58
61
|
constructor(
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { connect } from '../Connection/connect';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* PlusUI Menu API
|
|
3
5
|
*
|
|
@@ -68,6 +70,7 @@ export interface ContextInfo {
|
|
|
68
70
|
// ============================================================================
|
|
69
71
|
|
|
70
72
|
export class MenuAPI {
|
|
73
|
+
public readonly connect = connect.feature('menu');
|
|
71
74
|
private clickHandlers: Map<string, (item: MenuItem) => void> = new Map();
|
|
72
75
|
private contextMenuItems: MenuItem[] = [];
|
|
73
76
|
private contextMenuEnabled = false;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { connect } from '../Connection/connect';
|
|
2
|
+
|
|
1
3
|
export interface TrayMenuItem {
|
|
2
4
|
id: string;
|
|
3
5
|
label: string;
|
|
@@ -16,6 +18,8 @@ export interface TrayIconData {
|
|
|
16
18
|
}
|
|
17
19
|
|
|
18
20
|
export class TrayAPI {
|
|
21
|
+
public readonly connect = connect.feature('tray');
|
|
22
|
+
|
|
19
23
|
constructor(
|
|
20
24
|
private invokeFn: (name: string, args?: unknown[]) => Promise<unknown>,
|
|
21
25
|
private eventFn: (event: string, callback: (...args: unknown[]) => void) => () => void
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { connect } from '../Connection/connect';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* WebGPU Frontend API Wrapper
|
|
3
5
|
*
|
|
@@ -561,6 +563,7 @@ export function createWebGPU(
|
|
|
561
563
|
* Global WebGPU namespace (like navigator.gpu)
|
|
562
564
|
*/
|
|
563
565
|
class WebGPUNamespace {
|
|
566
|
+
public readonly connect = connect.feature('webgpu');
|
|
564
567
|
private invokeFn: (name: string, args?: unknown[]) => Promise<unknown>;
|
|
565
568
|
private onFn: (event: string, callback: (data: unknown) => void) => () => void;
|
|
566
569
|
|