plusui-native-core 0.1.8 → 0.1.10

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.
@@ -19,7 +19,8 @@ else()
19
19
  add_definitions(-DPLUSUI_GTK)
20
20
  endif()
21
21
 
22
- add_library(plusui STATIC
22
+ Features/Bindings/NativeBindings/native_bindings.cpp
23
+ Features/Bindings/CustomBindings/custom_bindings.cpp
23
24
  Features/App/app.cpp
24
25
  Features/Window/window.cpp
25
26
  Features/WindowManager/window_manager.cpp
@@ -0,0 +1,328 @@
1
+ # PlusUI Binding System Architecture
2
+
3
+ ## Complete Flow Diagram
4
+
5
+ ```
6
+ ┌─────────────────────────────────────────────────────────────────────┐
7
+ │ DEVELOPER WORKFLOW │
8
+ └─────────────────────────────────────────────────────────────────────┘
9
+
10
+ 1. Define Bindings in C++
11
+ ┌──────────────────────────────────────────────────┐
12
+ │ // src/features/myapp.hpp │
13
+ │ #include <plusui/bindings.hpp> │
14
+ │ │
15
+ │ // Methods (Frontend → Backend) │
16
+ │ PLUSUI_BIND(getUserName, string, void) │
17
+ │ PLUSUI_BIND(calculate, int, int, int) │
18
+ │ │
19
+ │ // Events (Backend → Frontend, start with "on") │
20
+ │ PLUSUI_BIND(onDataUpdated, void, json) │
21
+ └──────────────────────────────────────────────────┘
22
+
23
+
24
+ 2. Run Code Generation
25
+ ┌──────────────────────────────────────────────────┐
26
+ │ $ plusui generate │
27
+ │ │
28
+ │ plusui-bindgen: │
29
+ │ - Scans all C++ files │
30
+ │ - Finds PLUSUI_BIND macros │
31
+ │ - Detects native core usage │
32
+ │ - Generates TypeScript bindings │
33
+ │ - Generates C++ metadata │
34
+ └──────────────────────────────────────────────────┘
35
+
36
+
37
+ 3. Generated Files
38
+ ┌──────────────────────────────────────────────────┐
39
+ │ src/Bindings/ │
40
+ │ ├── bindings.gen.ts ← Import this! │
41
+ │ ├── bindings.gen.hpp ← C++ metadata │
42
+ │ ├── NativeBindings/ ← Core features │
43
+ │ │ ├── CPP_IO/ │
44
+ │ │ └── WEB_IO/ │
45
+ │ └── CustomBindings/ ← Your features │
46
+ │ ├── CPP_IO/ │
47
+ │ └── WEB_IO/ │
48
+ └──────────────────────────────────────────────────┘
49
+
50
+
51
+ 4. Use in TypeScript
52
+ ┌──────────────────────────────────────────────────┐
53
+ │ import { plusui } from './bindings.gen'; │
54
+ │ │
55
+ │ // Call backend │
56
+ │ const name = await plusui.myapp.getUserName(); │
57
+ │ const result = await plusui.myapp.calculate(5,3);│
58
+ │ │
59
+ │ // Listen to events │
60
+ │ plusui.myapp.onDataUpdated((data) => { │
61
+ │ updateUI(data); │
62
+ │ }); │
63
+ └──────────────────────────────────────────────────┘
64
+
65
+
66
+ 5. Build & Run
67
+ ┌──────────────────────────────────────────────────┐
68
+ │ $ plusui build │
69
+ │ │
70
+ │ - Compiles C++ with CMake │
71
+ │ - Bundles frontend with Vite │
72
+ │ - Links bindings at runtime │
73
+ │ - Creates single executable │
74
+ └──────────────────────────────────────────────────┘
75
+
76
+
77
+ ┌─────────────────────────────────────────────────────────────────────┐
78
+ │ RUNTIME FLOW │
79
+ └─────────────────────────────────────────────────────────────────────┘
80
+
81
+ Frontend → Backend (Method Call)
82
+ ──────────────────────────────────
83
+
84
+ TypeScript:
85
+ plusui.myapp.getUserName()
86
+
87
+ Generated binding class calls:
88
+ invoke("myapp.getUserName", [])
89
+
90
+ WebView bridge serializes:
91
+ { id: 1, method: "myapp.getUserName", params: [] }
92
+
93
+ IPC via window.__invoke__
94
+
95
+ C++:
96
+ Binding dispatcher receives JSON
97
+
98
+ Routes to registered handler
99
+
100
+ Executes: getUserName()
101
+
102
+ Returns: "John Doe"
103
+
104
+ Serializes result to JSON
105
+
106
+ WebView bridge sends back:
107
+ { id: 1, result: "John Doe" }
108
+
109
+ TypeScript:
110
+ Promise resolves with "John Doe"
111
+
112
+ const name = "John Doe" ✓
113
+
114
+
115
+ Backend → Frontend (Event Emission)
116
+ ────────────────────────────────────
117
+
118
+ C++:
119
+ plusui::bindings::emitToFrontend("onDataUpdated", {
120
+ {"count", 42},
121
+ {"status", "active"}
122
+ })
123
+
124
+ Serializes JSON data
125
+
126
+ WebView dispatches CustomEvent:
127
+ new CustomEvent("plusui:binding:myapp.onDataUpdated", {
128
+ detail: { count: 42, status: "active" }
129
+ })
130
+
131
+ TypeScript:
132
+ window.addEventListener receives event
133
+
134
+ Generated binding routes to handlers:
135
+ plusui.myapp.onDataUpdated((data) => { ... })
136
+
137
+ Handler executes with typed data:
138
+ data.count === 42
139
+ data.status === "active" ✓
140
+
141
+
142
+ ┌─────────────────────────────────────────────────────────────────────┐
143
+ │ TYPE SYSTEM │
144
+ └─────────────────────────────────────────────────────────────────────┘
145
+
146
+ PLUSUI_BIND(methodName, returnType, ...paramTypes)
147
+ │ │ │
148
+ │ │ └─→ Parameter types (0-N)
149
+ │ └──────────────→ Return type
150
+ └──────────────────────────→ Method/Event name
151
+
152
+ Auto-Detection Rules:
153
+ • Name starts with "on" + returnType is void = EVENT
154
+ • Otherwise = METHOD
155
+
156
+ Type Mapping Table:
157
+ ┌──────────────────┬─────────────────┬─────────────────┐
158
+ │ C++ Type │ TS Type │ Example │
159
+ ├──────────────────┼─────────────────┼─────────────────┤
160
+ │ void │ void │ (no return) │
161
+ │ bool │ boolean │ true, false │
162
+ │ int, float │ number │ 42, 3.14 │
163
+ │ string │ string │ "hello" │
164
+ │ json │ any │ {}, [] │
165
+ └──────────────────┴─────────────────┴─────────────────┘
166
+
167
+
168
+ ┌─────────────────────────────────────────────────────────────────────┐
169
+ │ BINDING CATEGORIES │
170
+ └─────────────────────────────────────────────────────────────────────┘
171
+
172
+ NativeBindings (Core Framework)
173
+ ────────────────────────────────
174
+ Auto-detected from imports:
175
+ import { window, app, display } from 'plusui-native-core';
176
+
177
+ Features:
178
+ • Window - minimize, maximize, show, hide, setTitle, etc.
179
+ • App - quit, ready, getVersion, etc.
180
+ • Display - getAll, getPrimary, etc.
181
+ • Clipboard - readText, writeText, etc.
182
+ • Keyboard - registerShortcut, etc.
183
+ • Menu - create, show, etc.
184
+ • Tray - create, setIcon, setTooltip, etc.
185
+ • Browser - open, etc.
186
+
187
+ Location: node_modules/plusui-native-core/Core/Features/
188
+
189
+
190
+ CustomBindings (Your App Logic)
191
+ ────────────────────────────────
192
+ Defined by you with PLUSUI_BIND:
193
+
194
+ Examples:
195
+ • Database operations
196
+ • Authentication/authorization
197
+ • File system operations
198
+ • Network requests
199
+ • Plugin systems
200
+ • Custom business logic
201
+
202
+ Location: Your project src/ files
203
+
204
+
205
+ ┌─────────────────────────────────────────────────────────────────────┐
206
+ │ GENERATED FILE STRUCTURE │
207
+ └─────────────────────────────────────────────────────────────────────┘
208
+
209
+ src/Bindings/
210
+ ├── bindings.gen.ts # ← MAIN IMPORT
211
+ │ export const plusui = {
212
+ │ window: WindowBindings,
213
+ │ app: AppBindings,
214
+ │ myFeature: MyFeatureBindings,
215
+ │ ...
216
+ │ }
217
+
218
+ ├── bindings.gen.hpp # C++ metadata
219
+ ├── bindings.report.json # Generation report
220
+
221
+ ├── NativeBindings/
222
+ │ ├── CPP_IO/
223
+ │ │ ├── core.bindings.gen.hpp # Core registration
224
+ │ │ └── core.bindings.gen.cpp # Implementation stub
225
+ │ └── WEB_IO/
226
+ │ └── core.bindings.gen.ts # Core TS classes
227
+
228
+ └── CustomBindings/
229
+ ├── CPP_IO/
230
+ │ ├── custom.bindings.gen.hpp # Custom registration
231
+ │ └── custom.bindings.gen.cpp # Implementation stub
232
+ └── WEB_IO/
233
+ └── custom.bindings.gen.ts # Custom TS classes
234
+
235
+ include/Bindings/ # Mirrored C++ headers
236
+ ├── bindings.gen.hpp
237
+ ├── NativeBindings/...
238
+ └── CustomBindings/...
239
+
240
+
241
+ ┌─────────────────────────────────────────────────────────────────────┐
242
+ │ BEST PRACTICES │
243
+ └─────────────────────────────────────────────────────────────────────┘
244
+
245
+ 1. ✅ Use PLUSUI_BIND for everything
246
+ ❌ Don't mix with manual bindings
247
+
248
+ 2. ✅ Events start with "on" prefix
249
+ ✓ onDataChanged, onError, onProgress
250
+ ✗ dataChanged, error, progress
251
+
252
+ 3. ✅ Group related bindings in files
253
+ src/features/
254
+ ├── database.hpp (DB bindings)
255
+ ├── auth.hpp (Auth bindings)
256
+ └── files.hpp (File bindings)
257
+
258
+ 4. ✅ Use json for complex data
259
+ PLUSUI_BIND(getUser, json, int)
260
+ ❌ Not: (string, string, int, bool, ...)
261
+
262
+ 5. ✅ Run generate after changes
263
+ $ plusui generate
264
+
265
+ 6. ✅ Clean up event listeners
266
+ const unsub = plusui.feature.onEvent(...);
267
+ return () => unsub();
268
+
269
+ 7. ✅ Handle errors gracefully
270
+ try {
271
+ await plusui.feature.method();
272
+ } catch (error) {
273
+ // Handle error
274
+ }
275
+
276
+
277
+ ┌─────────────────────────────────────────────────────────────────────┐
278
+ │ COMPARISON │
279
+ └─────────────────────────────────────────────────────────────────────┘
280
+
281
+ Old System (❌ Deprecated)
282
+ ──────────────────────────
283
+ • Multiple macros: PLUSUI_METHOD, PLUSUI_EVENT, PLUSUI_SERVICE
284
+ • Confusing overlap between Events and Bindings docs
285
+ • Manual type mapping
286
+ • Inconsistent naming
287
+
288
+ New System (✅ Recommended)
289
+ ───────────────────────────
290
+ • Single macro: PLUSUI_BIND
291
+ • Clear distinction: methods vs events (naming convention)
292
+ • Auto-generated types
293
+ • Simple, unified system
294
+ • One import: import { plusui } from './bindings.gen'
295
+
296
+
297
+ ┌─────────────────────────────────────────────────────────────────────┐
298
+ │ QUICK REFERENCE │
299
+ └─────────────────────────────────────────────────────────────────────┘
300
+
301
+ Define Binding:
302
+ PLUSUI_BIND(name, returnType, ...paramTypes)
303
+
304
+ Methods (Frontend → Backend):
305
+ PLUSUI_BIND(getUserData, json, int)
306
+
307
+ Events (Backend → Frontend):
308
+ PLUSUI_BIND(onUserLoggedIn, void, json)
309
+
310
+ Generate:
311
+ $ plusui generate
312
+
313
+ Use in TypeScript:
314
+ import { plusui } from './bindings.gen';
315
+
316
+ // Methods
317
+ await plusui.feature.method(args);
318
+
319
+ // Events
320
+ const unsub = plusui.feature.onEvent((data) => { });
321
+
322
+ Emit from C++:
323
+ plusui::bindings::emitToFrontend("onEvent", jsonData);
324
+
325
+
326
+ ═══════════════════════════════════════════════════════════════════════
327
+ Simple. Type-Safe. Bidirectional. 🚀
328
+ ═══════════════════════════════════════════════════════════════════════
@@ -0,0 +1,53 @@
1
+ #include <plusui/bindings.hpp>
2
+ #include <map>
3
+ #include <string>
4
+
5
+ namespace plusui {
6
+ namespace bindings {
7
+
8
+ // Runtime method registry (advanced use)
9
+ static std::map<std::string, InvokeHandler> runtime_methods;
10
+
11
+ // Runtime event registry (advanced use)
12
+ static std::map<std::string, EventHandler> runtime_events;
13
+
14
+ void registerMethod(const std::string& name, InvokeHandler handler) {
15
+ runtime_methods[name] = handler;
16
+ }
17
+
18
+ void registerEvent(const std::string& name, EventHandler handler) {
19
+ runtime_events[name] = handler;
20
+ }
21
+
22
+ void emitToFrontend(const std::string& name, const json& data) {
23
+ // Emit event to frontend via webview
24
+ // Implementation depends on webview instance
25
+ // This will be wired up by the generated binding code
26
+ }
27
+
28
+ json invokeFromFrontend(const std::string& name, const json& params) {
29
+ auto it = runtime_methods.find(name);
30
+ if (it != runtime_methods.end()) {
31
+ return it->second(params);
32
+ }
33
+ return json{"error", "Method not found: " + name};
34
+ }
35
+
36
+ std::vector<std::string> getRegisteredMethods() {
37
+ std::vector<std::string> result;
38
+ for (const auto& pair : runtime_methods) {
39
+ result.push_back(pair.first);
40
+ }
41
+ return result;
42
+ }
43
+
44
+ std::vector<std::string> getRegisteredEvents() {
45
+ std::vector<std::string> result;
46
+ for (const auto& pair : runtime_events) {
47
+ result.push_back(pair.first);
48
+ }
49
+ return result;
50
+ }
51
+
52
+ } // namespace bindings
53
+ } // namespace plusui
@@ -0,0 +1,35 @@
1
+ /**
2
+ * CustomBindings - Runtime Registration
3
+ *
4
+ * This file provides runtime binding registration for advanced use cases.
5
+ * Most users should use PLUSUI_BIND macro for compile-time bindings.
6
+ *
7
+ * Use this for:
8
+ * - Dynamic runtime method registration
9
+ * - Plugin systems
10
+ * - Hot-reloading scenarios
11
+ */
12
+
13
+ export type BindingHandler = (params: unknown[]) => Promise<unknown> | unknown;
14
+ export type EventHandler = (data: unknown) => void;
15
+
16
+ /**
17
+ * Register a method at runtime (advanced)
18
+ */
19
+ export function registerMethod(name: string, handler: BindingHandler): void {
20
+ const w = typeof window !== 'undefined' ? window as any : globalThis as any;
21
+ if (!w.__plusui_runtime_methods__) {
22
+ w.__plusui_runtime_methods__ = new Map<string, BindingHandler>();
23
+ }
24
+ w.__plusui_runtime_methods__.set(name, handler);
25
+ }
26
+
27
+ /**
28
+ * Register an event listener at runtime (advanced)
29
+ */
30
+ export function registerEvent(name: string, handler: EventHandler): () => void {
31
+ const eventName = `plusui:binding:${name}`;
32
+ const listener = (e: Event) => handler((e as CustomEvent).detail);
33
+ window.addEventListener(eventName, listener);
34
+ return () => window.removeEventListener(eventName, listener);
35
+ }
@@ -0,0 +1,143 @@
1
+ /**
2
+ * Example: Using the Unified PLUSUI_BIND System
3
+ *
4
+ * This example demonstrates how to create custom bindings
5
+ * for a simple task management app.
6
+ */
7
+
8
+ #pragma once
9
+ #include <plusui/bindings.hpp>
10
+ #include <string>
11
+ #include <vector>
12
+
13
+ namespace taskapp {
14
+
15
+ using json = nlohmann::json;
16
+
17
+ //========================================
18
+ // Frontend → Backend Methods
19
+ //========================================
20
+
21
+ // Get all tasks
22
+ PLUSUI_BIND(getAllTasks, json, void)
23
+
24
+ // Add a new task
25
+ PLUSUI_BIND(addTask, int, string, string)
26
+
27
+ // Complete a task
28
+ PLUSUI_BIND(completeTask, bool, int)
29
+
30
+ // Delete a task
31
+ PLUSUI_BIND(deleteTask, bool, int)
32
+
33
+ // Get task by ID
34
+ PLUSUI_BIND(getTask, json, int)
35
+
36
+ //========================================
37
+ // Backend → Frontend Events
38
+ // (Names starting with "on")
39
+ //========================================
40
+
41
+ // Fired when a task is added
42
+ PLUSUI_BIND(onTaskAdded, void, json)
43
+
44
+ // Fired when a task is completed
45
+ PLUSUI_BIND(onTaskCompleted, void, int)
46
+
47
+ // Fired when a task is deleted
48
+ PLUSUI_BIND(onTaskDeleted, void, int)
49
+
50
+ // Fired when tasks are reordered
51
+ PLUSUI_BIND(onTasksReordered, void, json)
52
+
53
+ //========================================
54
+ // Implementation (would be in .cpp file)
55
+ //========================================
56
+
57
+ struct Task {
58
+ int id;
59
+ std::string title;
60
+ std::string description;
61
+ bool completed;
62
+ };
63
+
64
+ static std::vector<Task> tasks;
65
+ static int nextId = 1;
66
+
67
+ // Methods
68
+ json getAllTasks() {
69
+ json result = json::array();
70
+ for (const auto& task : tasks) {
71
+ result.push_back({
72
+ {"id", task.id},
73
+ {"title", task.title},
74
+ {"description", task.description},
75
+ {"completed", task.completed}
76
+ });
77
+ }
78
+ return result;
79
+ }
80
+
81
+ int addTask(const std::string& title, const std::string& description) {
82
+ Task task = {
83
+ .id = nextId++,
84
+ .title = title,
85
+ .description = description,
86
+ .completed = false
87
+ };
88
+
89
+ tasks.push_back(task);
90
+
91
+ // Emit event to frontend
92
+ plusui::bindings::emitToFrontend("onTaskAdded", {
93
+ {"id", task.id},
94
+ {"title", task.title},
95
+ {"description", task.description},
96
+ {"completed", task.completed}
97
+ });
98
+
99
+ return task.id;
100
+ }
101
+
102
+ bool completeTask(int id) {
103
+ for (auto& task : tasks) {
104
+ if (task.id == id) {
105
+ task.completed = true;
106
+
107
+ // Emit event
108
+ plusui::bindings::emitToFrontend("onTaskCompleted", id);
109
+ return true;
110
+ }
111
+ }
112
+ return false;
113
+ }
114
+
115
+ bool deleteTask(int id) {
116
+ auto it = std::find_if(tasks.begin(), tasks.end(),
117
+ [id](const Task& t) { return t.id == id; });
118
+
119
+ if (it != tasks.end()) {
120
+ tasks.erase(it);
121
+
122
+ // Emit event
123
+ plusui::bindings::emitToFrontend("onTaskDeleted", id);
124
+ return true;
125
+ }
126
+ return false;
127
+ }
128
+
129
+ json getTask(int id) {
130
+ for (const auto& task : tasks) {
131
+ if (task.id == id) {
132
+ return {
133
+ {"id", task.id},
134
+ {"title", task.title},
135
+ {"description", task.description},
136
+ {"completed", task.completed}
137
+ };
138
+ }
139
+ }
140
+ return nullptr;
141
+ }
142
+
143
+ } // namespace taskapp