plusui-native-core 0.1.52 → 0.1.53
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 +2 -3
- package/Core/Features/App/app.cpp +58 -1
- package/Core/Features/Connection/ARCHITECTURE.md +369 -0
- package/Core/Features/Connection/README.md +165 -0
- package/Core/Features/Connection/connection.cpp +57 -0
- package/Core/Features/Connection/connection.ts +186 -0
- package/Core/Features/Connection/examples/simple_tags_example.hpp +130 -0
- package/Core/Features/Connection/examples/simple_tags_example.ts +247 -0
- package/Core/Features/Window/window.cpp +187 -151
- package/Core/generated/bridge.hpp +302 -0
- package/Core/include/plusui/connection.hpp +145 -0
- package/Core/include/plusui/plusui.hpp +1 -3
- package/Core/include/plusui/window.hpp +17 -19
- package/package.json +1 -1
- package/Core/Features/Bindings/ARCHITECTURE.md +0 -328
- package/Core/Features/Bindings/CustomBindings/custom_bindings.cpp +0 -55
- package/Core/Features/Bindings/CustomBindings/custom_bindings.ts +0 -35
- package/Core/Features/Bindings/EXAMPLE_USAGE.hpp +0 -143
- package/Core/Features/Bindings/EXAMPLE_USAGE.tsx +0 -210
- package/Core/Features/Bindings/IPC_GUIDE.md +0 -325
- package/Core/Features/Bindings/NativeBindings/native_bindings.cpp +0 -30
- package/Core/Features/Bindings/NativeBindings/native_bindings.ts +0 -29
- package/Core/Features/Bindings/UNIFIED_SYSTEM.md +0 -351
- package/Core/Features/Event/Events.ts +0 -166
- package/Core/Features/Event/events.cpp +0 -200
- package/Core/include/plusui/bindings.hpp +0 -65
- package/Core/include/plusui/custom_bindings.hpp +0 -17
- package/Core/include/plusui/events.hpp +0 -58
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
export type ConnectionKind =
|
|
2
|
+
| "call"
|
|
3
|
+
| "fire"
|
|
4
|
+
| "result"
|
|
5
|
+
| "event"
|
|
6
|
+
| "stream"
|
|
7
|
+
| "sub"
|
|
8
|
+
| "unsub"
|
|
9
|
+
| "publish"
|
|
10
|
+
| "error";
|
|
11
|
+
|
|
12
|
+
export type ConnectionEnvelope = {
|
|
13
|
+
kind: ConnectionKind;
|
|
14
|
+
id?: string;
|
|
15
|
+
name: string;
|
|
16
|
+
payload?: unknown;
|
|
17
|
+
error?: string;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
type MessageCallback = (payload: any) => void;
|
|
21
|
+
|
|
22
|
+
class ConnectionClient {
|
|
23
|
+
private pending = new Map<string, { resolve: (v: any) => void; reject: (e: Error) => void }>();
|
|
24
|
+
private listeners = new Map<string, Set<MessageCallback>>();
|
|
25
|
+
|
|
26
|
+
constructor() {
|
|
27
|
+
const host = globalThis as any;
|
|
28
|
+
|
|
29
|
+
host.__plusuiConnectionMessage = (message: unknown) => {
|
|
30
|
+
this.handleIncoming(message);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
if (typeof window !== "undefined") {
|
|
34
|
+
window.addEventListener("plusui:connection:message", (ev: Event) => {
|
|
35
|
+
const custom = ev as CustomEvent<unknown>;
|
|
36
|
+
this.handleIncoming(custom.detail);
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
private nextId(): string {
|
|
42
|
+
return `${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
private async send(env: ConnectionEnvelope): Promise<any> {
|
|
46
|
+
const host = globalThis as any;
|
|
47
|
+
|
|
48
|
+
if (typeof host.__invoke__ === "function") {
|
|
49
|
+
return host.__invoke__("connection.dispatch", env);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (host.ipc?.postMessage) {
|
|
53
|
+
host.ipc.postMessage(JSON.stringify(env));
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
private decode(message: unknown): ConnectionEnvelope | null {
|
|
61
|
+
if (!message) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
if (typeof message === "string") {
|
|
65
|
+
try {
|
|
66
|
+
return JSON.parse(message) as ConnectionEnvelope;
|
|
67
|
+
} catch {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (typeof message === "object") {
|
|
72
|
+
return message as ConnectionEnvelope;
|
|
73
|
+
}
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
private handleIncoming(message: unknown): void {
|
|
78
|
+
const env = this.decode(message);
|
|
79
|
+
if (!env) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if ((env.kind === "result" || env.kind === "error") && env.id) {
|
|
84
|
+
const entry = this.pending.get(env.id);
|
|
85
|
+
if (!entry) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
this.pending.delete(env.id);
|
|
89
|
+
if (env.kind === "error") {
|
|
90
|
+
entry.reject(new Error(env.error || "Connection call failed"));
|
|
91
|
+
} else {
|
|
92
|
+
entry.resolve(env.payload);
|
|
93
|
+
}
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (env.kind === "event" || env.kind === "stream" || env.kind === "publish") {
|
|
98
|
+
const handlers = this.listeners.get(env.name);
|
|
99
|
+
if (!handlers) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
for (const handler of handlers) {
|
|
103
|
+
handler(env.payload);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async call<TOut = unknown, TIn = Record<string, unknown>>(name: string, payload: TIn): Promise<TOut> {
|
|
109
|
+
const id = this.nextId();
|
|
110
|
+
const promise = new Promise<TOut>((resolve, reject) => {
|
|
111
|
+
this.pending.set(id, { resolve, reject });
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
await this.send({ kind: "call", id, name, payload });
|
|
115
|
+
return promise;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
fire<TIn = Record<string, unknown>>(name: string, payload: TIn): void {
|
|
119
|
+
void this.send({ kind: "fire", name, payload });
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
on<TData = unknown>(name: string, callback: (payload: TData) => void): () => void {
|
|
123
|
+
const existing = this.listeners.get(name) ?? new Set<MessageCallback>();
|
|
124
|
+
existing.add(callback as MessageCallback);
|
|
125
|
+
this.listeners.set(name, existing);
|
|
126
|
+
|
|
127
|
+
return () => {
|
|
128
|
+
const current = this.listeners.get(name);
|
|
129
|
+
if (!current) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
current.delete(callback as MessageCallback);
|
|
133
|
+
if (current.size === 0) {
|
|
134
|
+
this.listeners.delete(name);
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
stream<TData = unknown>(name: string) {
|
|
140
|
+
return {
|
|
141
|
+
subscribe: (callback: (payload: TData) => void): (() => void) => {
|
|
142
|
+
void this.send({ kind: "sub", name });
|
|
143
|
+
const off = this.on<TData>(name, callback);
|
|
144
|
+
return () => {
|
|
145
|
+
off();
|
|
146
|
+
void this.send({ kind: "unsub", name });
|
|
147
|
+
};
|
|
148
|
+
},
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
channel<TData = unknown>(name: string) {
|
|
153
|
+
return {
|
|
154
|
+
subscribe: (callback: (payload: TData) => void): (() => void) => {
|
|
155
|
+
void this.send({ kind: "sub", name });
|
|
156
|
+
const off = this.on<TData>(name, callback);
|
|
157
|
+
return () => {
|
|
158
|
+
off();
|
|
159
|
+
void this.send({ kind: "unsub", name });
|
|
160
|
+
};
|
|
161
|
+
},
|
|
162
|
+
publish: (payload: TData): void => {
|
|
163
|
+
void this.send({ kind: "publish", name, payload });
|
|
164
|
+
},
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Create the connection client instance
|
|
170
|
+
const connectionClient = new ConnectionClient();
|
|
171
|
+
|
|
172
|
+
// Simple connection API - just emit() and on()
|
|
173
|
+
export const connect = {
|
|
174
|
+
// Send a message to backend
|
|
175
|
+
emit: <TIn = Record<string, unknown>>(name: string, payload: TIn): void => {
|
|
176
|
+
connectionClient.fire(name, payload);
|
|
177
|
+
},
|
|
178
|
+
|
|
179
|
+
// Listen for messages from backend
|
|
180
|
+
on: <TData = unknown>(name: string, callback: (payload: TData) => void): (() => void) => {
|
|
181
|
+
return connectionClient.on<TData>(name, callback);
|
|
182
|
+
},
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
// Export the raw client for advanced use cases (call, fire, stream, channel)
|
|
186
|
+
export const connection = connectionClient;
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Example: Simple Tag-Based Connection (C++ Backend)
|
|
3
|
+
*
|
|
4
|
+
* No schema file needed! Just tag your methods and bindgen does the rest.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
#pragma once
|
|
8
|
+
#include <plusui/connection.hpp>
|
|
9
|
+
#include <string>
|
|
10
|
+
|
|
11
|
+
namespace example {
|
|
12
|
+
|
|
13
|
+
class SimpleApp : public plusui::Connection {
|
|
14
|
+
public:
|
|
15
|
+
|
|
16
|
+
// ============================================
|
|
17
|
+
// CONNECT_CALL: Request/Response
|
|
18
|
+
// Frontend can await the result
|
|
19
|
+
// ============================================
|
|
20
|
+
|
|
21
|
+
// Simple call with one parameter
|
|
22
|
+
CONNECT_CALL(greet, std::string, std::string name)
|
|
23
|
+
std::string greet(const std::string& name) {
|
|
24
|
+
return "Hello, " + name + "!";
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Call with multiple parameters → returns object
|
|
28
|
+
CONNECT_CALL(calculate, double, double a, double b)
|
|
29
|
+
double calculate(double a, double b) {
|
|
30
|
+
return a + b;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Call with complex return (auto-generates struct)
|
|
34
|
+
CONNECT_CALL(getUser, {int id, std::string name, std::string email}, int userId)
|
|
35
|
+
auto getUser(int userId) {
|
|
36
|
+
struct Result { int id; std::string name; std::string email; };
|
|
37
|
+
return Result{ userId, "John Doe", "john@example.com" };
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// ============================================
|
|
41
|
+
// CONNECT_FIRE: One-way to Backend
|
|
42
|
+
// No response expected
|
|
43
|
+
// ============================================
|
|
44
|
+
|
|
45
|
+
CONNECT_FIRE(minimize, void)
|
|
46
|
+
void minimize() {
|
|
47
|
+
// Minimize window
|
|
48
|
+
std::cout << "Minimizing..." << std::endl;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
CONNECT_FIRE(log, void, std::string level, std::string message)
|
|
52
|
+
void log(const std::string& level, const std::string& message) {
|
|
53
|
+
std::cout << "[" << level << "] " << message << std::endl;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// ============================================
|
|
57
|
+
// CONNECT_EVENT: Backend → Frontend
|
|
58
|
+
// Backend emits, frontend listens
|
|
59
|
+
// ============================================
|
|
60
|
+
|
|
61
|
+
CONNECT_EVENT(onResize, int width, int height)
|
|
62
|
+
void emitResize(int width, int height) {
|
|
63
|
+
// Auto-generated emit method
|
|
64
|
+
emit_onResize(width, height);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
CONNECT_EVENT(onFileDrop, std::vector<std::string> files)
|
|
68
|
+
void emitFileDrop(const std::vector<std::string>& files) {
|
|
69
|
+
emit_onFileDrop(files);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// ============================================
|
|
73
|
+
// CONNECT_STREAM: Continuous Data
|
|
74
|
+
// Backend streams, frontend subscribes
|
|
75
|
+
// ============================================
|
|
76
|
+
|
|
77
|
+
CONNECT_STREAM(cpuUsage, double percent)
|
|
78
|
+
void startMonitoring() {
|
|
79
|
+
// Stream CPU usage continuously
|
|
80
|
+
std::thread([this]() {
|
|
81
|
+
while (running) {
|
|
82
|
+
double cpu = getCpuUsage();
|
|
83
|
+
emit_cpuUsage(cpu);
|
|
84
|
+
std::this_thread::sleep_for(std::chrono::seconds(1));
|
|
85
|
+
}
|
|
86
|
+
}).detach();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// ============================================
|
|
90
|
+
// CONNECT_CHANNEL: Bidirectional
|
|
91
|
+
// Both sides can send and receive
|
|
92
|
+
// ============================================
|
|
93
|
+
|
|
94
|
+
CONNECT_CHANNEL(logBus, std::string level, std::string line)
|
|
95
|
+
|
|
96
|
+
// Receive from frontend
|
|
97
|
+
void onLogFromFrontend(const std::string& level, const std::string& line) {
|
|
98
|
+
std::cout << "[Frontend] " << level << ": " << line << std::endl;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Send to frontend
|
|
102
|
+
void sendLogToFrontend(const std::string& level, const std::string& line) {
|
|
103
|
+
emit_logBus(level, line);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
private:
|
|
107
|
+
bool running = true;
|
|
108
|
+
|
|
109
|
+
double getCpuUsage() {
|
|
110
|
+
return 50.0 + (rand() % 30);
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
} // namespace example
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* This example shows how simple it is:
|
|
118
|
+
*
|
|
119
|
+
* 1. Tag your methods with CONNECT_* macros
|
|
120
|
+
* 2. Run: npm run bindgen
|
|
121
|
+
* 3. Use in TypeScript:
|
|
122
|
+
*
|
|
123
|
+
* const result = await connect.greet({ name: 'World' });
|
|
124
|
+
* connect.minimize();
|
|
125
|
+
* connect.onResize((w, h) => updateUI(w, h));
|
|
126
|
+
* connect.cpuUsage.subscribe((cpu) => showCpu(cpu));
|
|
127
|
+
* connect.logBus.publish({ level: 'info', line: 'msg' });
|
|
128
|
+
*
|
|
129
|
+
* That's it! No separate schema file, no manual typing.
|
|
130
|
+
*/
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Example: Simple Tag-Based Connection (TypeScript Frontend)
|
|
3
|
+
*
|
|
4
|
+
* After running bindgen, use the auto-generated connect API
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { connect } from '../generated/bindings';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* All these methods are auto-generated from C++ CONNECT_* tags!
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
// ============================================
|
|
14
|
+
// CALL - Request/Response
|
|
15
|
+
// ============================================
|
|
16
|
+
|
|
17
|
+
async function callExamples() {
|
|
18
|
+
// Simple call
|
|
19
|
+
const greeting = await connect.greet({ name: 'PlusUI' });
|
|
20
|
+
console.log(greeting); // "Hello, PlusUI!"
|
|
21
|
+
|
|
22
|
+
// Call with multiple params
|
|
23
|
+
const sum = await connect.calculate({ a: 10, b: 20 });
|
|
24
|
+
console.log(sum); // 30
|
|
25
|
+
|
|
26
|
+
// Complex return type
|
|
27
|
+
const user = await connect.getUser({ userId: 123 });
|
|
28
|
+
console.log(user.name, user.email);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// ============================================
|
|
32
|
+
// FIRE - One-way to Backend
|
|
33
|
+
// ============================================
|
|
34
|
+
|
|
35
|
+
function fireExamples() {
|
|
36
|
+
// Fire with no params
|
|
37
|
+
connect.minimize();
|
|
38
|
+
|
|
39
|
+
// Fire with params
|
|
40
|
+
connect.log({
|
|
41
|
+
level: 'info',
|
|
42
|
+
message: 'User clicked button'
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// Fire and forget - doesn't wait
|
|
46
|
+
connect.log({ level: 'debug', message: 'Debug info' });
|
|
47
|
+
doSomethingElse(); // Runs immediately
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// ============================================
|
|
51
|
+
// EVENT - Listen to Backend
|
|
52
|
+
// ============================================
|
|
53
|
+
|
|
54
|
+
function eventExamples() {
|
|
55
|
+
// Listen for resize events
|
|
56
|
+
const unsubResize = connect.onResize((data) => {
|
|
57
|
+
console.log(`Window: ${data.width}x${data.height}`);
|
|
58
|
+
updateLayout(data.width, data.height);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// Listen for file drops
|
|
62
|
+
connect.onFileDrop((data) => {
|
|
63
|
+
console.log('Files dropped:', data.files);
|
|
64
|
+
data.files.forEach(file => processFile(file));
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// Clean up when done
|
|
68
|
+
// unsubResize();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// ============================================
|
|
72
|
+
// STREAM - Subscribe to Continuous Data
|
|
73
|
+
// ============================================
|
|
74
|
+
|
|
75
|
+
function streamExamples() {
|
|
76
|
+
// Subscribe to CPU usage stream
|
|
77
|
+
const unsub = connect.cpuUsage.subscribe((data) => {
|
|
78
|
+
updateCpuChart(data.percent);
|
|
79
|
+
|
|
80
|
+
if (data.percent > 90) {
|
|
81
|
+
showWarning('High CPU!');
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
// Unsubscribe when component unmounts
|
|
86
|
+
return unsub;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// ============================================
|
|
90
|
+
// CHANNEL - Bidirectional Communication
|
|
91
|
+
// ============================================
|
|
92
|
+
|
|
93
|
+
function channelExamples() {
|
|
94
|
+
// Subscribe to receive from backend
|
|
95
|
+
connect.logBus.subscribe((msg) => {
|
|
96
|
+
const color = msg.level === 'error' ? 'red' : 'gray';
|
|
97
|
+
console.log(`%c[${msg.level}] ${msg.line}`, `color: ${color}`);
|
|
98
|
+
addToLogView(msg);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// Publish to backend
|
|
102
|
+
connect.logBus.publish({
|
|
103
|
+
level: 'info',
|
|
104
|
+
line: 'Frontend initialized'
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// Both sides can communicate freely
|
|
108
|
+
document.onclick = () => {
|
|
109
|
+
connect.logBus.publish({
|
|
110
|
+
level: 'debug',
|
|
111
|
+
line: 'User clicked somewhere'
|
|
112
|
+
});
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// ============================================
|
|
117
|
+
// React Component Example
|
|
118
|
+
// ============================================
|
|
119
|
+
|
|
120
|
+
function ReactExample() {
|
|
121
|
+
const [greeting, setGreeting] = React.useState('');
|
|
122
|
+
const [cpu, setCpu] = React.useState(0);
|
|
123
|
+
|
|
124
|
+
React.useEffect(() => {
|
|
125
|
+
// Call on mount
|
|
126
|
+
connect.greet({ name: 'React' })
|
|
127
|
+
.then(result => setGreeting(result));
|
|
128
|
+
|
|
129
|
+
// Subscribe to events
|
|
130
|
+
const unsubResize = connect.onResize((data) => {
|
|
131
|
+
console.log('Resize:', data);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
// Subscribe to stream
|
|
135
|
+
const unsubCpu = connect.cpuUsage.subscribe((data) => {
|
|
136
|
+
setCpu(data.percent);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
// Subscribe to channel
|
|
140
|
+
const unsubLog = connect.logBus.subscribe((msg) => {
|
|
141
|
+
console.log(msg);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
// Cleanup all subscriptions
|
|
145
|
+
return () => {
|
|
146
|
+
unsubResize();
|
|
147
|
+
unsubCpu();
|
|
148
|
+
unsubLog();
|
|
149
|
+
};
|
|
150
|
+
}, []);
|
|
151
|
+
|
|
152
|
+
const handleMinimize = () => {
|
|
153
|
+
connect.minimize();
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
const handleLog = () => {
|
|
157
|
+
connect.log({
|
|
158
|
+
level: 'info',
|
|
159
|
+
message: 'Button clicked!'
|
|
160
|
+
});
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
return (
|
|
164
|
+
<div>
|
|
165
|
+
<h1>{greeting}</h1>
|
|
166
|
+
<div>CPU: {cpu.toFixed(1)}%</div>
|
|
167
|
+
<button onClick={handleMinimize}>Minimize</button>
|
|
168
|
+
<button onClick={handleLog}>Log Message</button>
|
|
169
|
+
</div>
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// ============================================
|
|
174
|
+
// Vue Composition API Example
|
|
175
|
+
// ============================================
|
|
176
|
+
|
|
177
|
+
function vueExample() {
|
|
178
|
+
const greeting = ref('');
|
|
179
|
+
const cpu = ref(0);
|
|
180
|
+
|
|
181
|
+
onMounted(async () => {
|
|
182
|
+
// Call backend
|
|
183
|
+
const result = await connect.greet({ name: 'Vue' });
|
|
184
|
+
greeting.value = result;
|
|
185
|
+
|
|
186
|
+
// Subscribe to stream
|
|
187
|
+
const unsub = connect.cpuUsage.subscribe((data) => {
|
|
188
|
+
cpu.value = data.percent;
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
onUnmounted(() => {
|
|
192
|
+
unsub();
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
return {
|
|
197
|
+
greeting,
|
|
198
|
+
cpu,
|
|
199
|
+
minimize: () => connect.minimize(),
|
|
200
|
+
log: (msg: string) => connect.log({ level: 'info', message: msg }),
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// ============================================
|
|
205
|
+
// Helper Functions
|
|
206
|
+
// ============================================
|
|
207
|
+
|
|
208
|
+
function updateLayout(width: number, height: number) {
|
|
209
|
+
// Update UI layout
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function processFile(file: string) {
|
|
213
|
+
// Process dropped file
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function updateCpuChart(percent: number) {
|
|
217
|
+
// Update chart
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function showWarning(msg: string) {
|
|
221
|
+
// Show warning toast
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function addToLogView(msg: any) {
|
|
225
|
+
// Add to log view
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function doSomethingElse() {
|
|
229
|
+
// Continue execution
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* THAT'S IT!
|
|
234
|
+
*
|
|
235
|
+
* No schema file needed.
|
|
236
|
+
* No manual type definitions.
|
|
237
|
+
* Just tag your C++ methods and use them in TypeScript.
|
|
238
|
+
*
|
|
239
|
+
* Bindgen automatically:
|
|
240
|
+
* - Finds all CONNECT_* tags
|
|
241
|
+
* - Generates TypeScript types
|
|
242
|
+
* - Creates the connect.* API
|
|
243
|
+
* - Handles all serialization
|
|
244
|
+
* - Manages subscriptions
|
|
245
|
+
*
|
|
246
|
+
* Perfect developer experience! 🚀
|
|
247
|
+
*/
|