electrobun 0.0.2 → 0.0.3
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/.colab.json +1 -0
- package/README.md +14 -12
- package/bun.lockb +0 -0
- package/dist/bsdiff +0 -0
- package/dist/bspatch +0 -0
- package/dist/webview +0 -0
- package/docs-old/architecture.md +46 -0
- package/documentation/README.md +41 -0
- package/documentation/babel.config.js +3 -0
- package/documentation/blog/2024-08-20-electrobun.md +22 -0
- package/documentation/blog/authors.yml +8 -0
- package/documentation/blog/tags.yml +0 -0
- package/documentation/docs/apis/Application Icons.md +9 -0
- package/documentation/docs/apis/Bundled Assets.md +95 -0
- package/documentation/docs/apis/browser/DraggableRegions.md +36 -0
- package/documentation/docs/apis/browser/Electrobun Webview Tag.md +200 -0
- package/documentation/docs/apis/browser/Electroview Class.md +158 -0
- package/documentation/docs/apis/browser/GlobalProperties.md +11 -0
- package/documentation/docs/apis/browser/index.md +25 -0
- package/documentation/docs/apis/bun/ApplicationMenu.md +141 -0
- package/documentation/docs/apis/bun/BrowserView.md +513 -0
- package/documentation/docs/apis/bun/BrowserWindow.md +423 -0
- package/documentation/docs/apis/bun/ContextMenu.md +50 -0
- package/documentation/docs/apis/bun/Events.md +50 -0
- package/documentation/docs/apis/bun/PATHS.md +17 -0
- package/documentation/docs/apis/bun/Tray.md +115 -0
- package/documentation/docs/apis/bun/Updater.md +74 -0
- package/documentation/docs/apis/bun/Utils.md +51 -0
- package/documentation/docs/apis/bun/index.md +26 -0
- package/documentation/docs/apis/cli/Electrobun.config.md +97 -0
- package/documentation/docs/apis/cli/cli args.md +76 -0
- package/documentation/docs/guides/Architecture/Events.md +19 -0
- package/documentation/docs/guides/Architecture/IPC and Isolation.md +20 -0
- package/documentation/docs/guides/Architecture/Overview.md +140 -0
- package/documentation/docs/guides/Architecture/Updates.md +7 -0
- package/documentation/docs/guides/Architecture/Webview Tag.md +5 -0
- package/documentation/docs/guides/Compatability.md +8 -0
- package/documentation/docs/guides/Getting Started/Creating UI.md +147 -0
- package/documentation/docs/guides/Getting Started/Distributing.md +116 -0
- package/documentation/docs/guides/Getting Started/Getting Started.md +7 -0
- package/documentation/docs/guides/Getting Started/Hello World.md +93 -0
- package/documentation/docs/guides/Getting Started/What is Electrobun.md +39 -0
- package/documentation/docs/guides/Guides/Build UI with React +0 -0
- package/documentation/docs/guides/Guides/Build UI with Solidjs +0 -0
- package/documentation/docs/guides/Guides/Build a Web Browser +0 -0
- package/documentation/docs/guides/Guides/Bun <-> Browser RPC +0 -0
- package/documentation/docs/guides/Guides/Using Tailwind +0 -0
- package/documentation/docusaurus.config.ts +153 -0
- package/documentation/package-lock.json +14530 -0
- package/documentation/package.json +47 -0
- package/documentation/sidebars.ts +32 -0
- package/documentation/src/components/HomepageFeatures/index.tsx +70 -0
- package/documentation/src/components/HomepageFeatures/styles.module.css +11 -0
- package/documentation/src/css/custom.css +30 -0
- package/documentation/src/pages/index.module.css +23 -0
- package/documentation/src/pages/index.tsx +137 -0
- package/documentation/static/.nojekyll +0 -0
- package/documentation/static/img/electrobun-logo-256.png +0 -0
- package/documentation/static/img/electrobun-logo-32.png +0 -0
- package/documentation/tsconfig.json +7 -0
- package/package.json +11 -6
- package/src/browser/index.ts +2 -2
- package/src/bun/core/BrowserView.ts +14 -1
- package/src/cli/build/electrobun +0 -0
- package/src/cli/index.ts +3 -1
- package/docs/architecture.md +0 -84
- /package/{docs → docs-old}/api/bun-api.md +0 -0
- /package/{docs → docs-old}/api/view-api.md +0 -0
- /package/{docs → docs-old}/electrobun-config.md +0 -0
- /package/{docs → docs-old}/getting-started.md +0 -0
- /package/{docs → docs-old}/node_modules/.cache/webpack/client-development-en/0.pack +0 -0
- /package/{docs → docs-old}/node_modules/.cache/webpack/client-development-en/index.pack +0 -0
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
> Create and control browser windows
|
|
2
|
+
|
|
3
|
+
```typescript
|
|
4
|
+
// in the main process
|
|
5
|
+
import { BrowserWindow } from "electrobun/bun";
|
|
6
|
+
|
|
7
|
+
const win = new BrowserWindow({
|
|
8
|
+
title: "my url window",
|
|
9
|
+
frame: {
|
|
10
|
+
width: 1800,
|
|
11
|
+
height: 600,
|
|
12
|
+
x: 2000,
|
|
13
|
+
y: 2000,
|
|
14
|
+
},
|
|
15
|
+
url: "views://mainview/index.html",
|
|
16
|
+
});
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Constructor Options
|
|
20
|
+
|
|
21
|
+
### title
|
|
22
|
+
|
|
23
|
+
Set the title of the window.
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
const win = new BrowserWindow({
|
|
27
|
+
title: "my url window",
|
|
28
|
+
});
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### frame
|
|
32
|
+
|
|
33
|
+
Set the window dimensions
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
const win = new BrowserWindow({
|
|
37
|
+
frame: {
|
|
38
|
+
width: 1800,
|
|
39
|
+
height: 600,
|
|
40
|
+
x: 2000,
|
|
41
|
+
y: 2000,
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### styleMask
|
|
47
|
+
|
|
48
|
+
This controls the OSX window appearance and functionality. You can set the following:
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
const win = new BrowserWindow({
|
|
52
|
+
title: "my url window",
|
|
53
|
+
url: "views://mainview/index.html",
|
|
54
|
+
frame: {
|
|
55
|
+
width: 1800,
|
|
56
|
+
height: 600,
|
|
57
|
+
x: 2000,
|
|
58
|
+
y: 2000,
|
|
59
|
+
},
|
|
60
|
+
styleMask: {
|
|
61
|
+
// These are the current defaults
|
|
62
|
+
Borderless: false,
|
|
63
|
+
Titled: true,
|
|
64
|
+
Closable: true,
|
|
65
|
+
Miniaturizable: true,
|
|
66
|
+
Resizable: true,
|
|
67
|
+
UnifiedTitleAndToolbar: false,
|
|
68
|
+
FullScreen: false,
|
|
69
|
+
FullSizeContentView: false,
|
|
70
|
+
UtilityWindow: false,
|
|
71
|
+
DocModalWindow: false,
|
|
72
|
+
NonactivatingPanel: false,
|
|
73
|
+
HUDWindow: false,
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### titleBarStyle
|
|
79
|
+
|
|
80
|
+
This is an additional window configuration for OSX. This can be set to either `hiddenInset` or `default`. When setting it to `hiddenInset` it will also override `Titled` and `FullSizeContentView` to be `true`
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
const win = new BrowserWindow({
|
|
84
|
+
title: "my url window",
|
|
85
|
+
url: "views://mainview/index.html",
|
|
86
|
+
frame: {
|
|
87
|
+
width: 1800,
|
|
88
|
+
height: 600,
|
|
89
|
+
x: 2000,
|
|
90
|
+
y: 2000,
|
|
91
|
+
},
|
|
92
|
+
titleBarStyle: 'hiddenInset',
|
|
93
|
+
styleMask: {
|
|
94
|
+
// In addition to the defaults, these will be forced to true when titleBarStyle
|
|
95
|
+
// is set to hiddenInset
|
|
96
|
+
Titled: true,
|
|
97
|
+
FullSizeContentView: true,
|
|
98
|
+
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
:::info
|
|
105
|
+
The following options are used to instantiate the default BrowserView
|
|
106
|
+
:::
|
|
107
|
+
|
|
108
|
+
### url
|
|
109
|
+
|
|
110
|
+
Set the initial url for the window's default BrowserView to navigate to when it opens.
|
|
111
|
+
|
|
112
|
+
```
|
|
113
|
+
// Use any url on the internet
|
|
114
|
+
const win = new BrowserWindow({
|
|
115
|
+
url: "https://electrobun.dev",
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// or use the views:// url scheme to load local
|
|
119
|
+
// content that you've bundled with your app.
|
|
120
|
+
|
|
121
|
+
const win = new BrowserWindow({
|
|
122
|
+
url: "views://mainview/index.html",
|
|
123
|
+
});
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### html
|
|
127
|
+
|
|
128
|
+
Set an html string for the window's default BrowserView to load when it opens. Anything that would be valid in an html file including javascript and css can be used.
|
|
129
|
+
|
|
130
|
+
Use this instead of setting the `url` property.
|
|
131
|
+
|
|
132
|
+
```
|
|
133
|
+
const htmlString = "<html><head></head><body><h1>hello world</h1></body></html>";
|
|
134
|
+
|
|
135
|
+
const win = new BrowserWindow({
|
|
136
|
+
html: htmlString,
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### partition
|
|
142
|
+
|
|
143
|
+
Partitions allow you to separate the browser session. Things like cookies and so on. For example if you have two BrowserViews with the same partition and log into gmail in one, the other will also be logged into gmail. If you use two different partitions then you could log into a different gmail account in each BrowserView.
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
// ephemeral partition. If you close and reopen your app
|
|
147
|
+
// even if you use the same partition name it will not
|
|
148
|
+
// have persisted.
|
|
149
|
+
const win = new BrowserWindow({
|
|
150
|
+
partition: "partition1",
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
// To make partitions persistent just prefix it with `persist:`
|
|
154
|
+
const win = new BrowserWindow({
|
|
155
|
+
partition: "persist:partition1",
|
|
156
|
+
});
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### preload
|
|
160
|
+
|
|
161
|
+
Set a preload script for the window's default BrowserView to render after html is parsed but before any other javascript is executed. The preload script will be run after any navigation before the page's scripts are run.
|
|
162
|
+
|
|
163
|
+
You can use either inline javascript or a url.
|
|
164
|
+
|
|
165
|
+
```
|
|
166
|
+
// Use any url on the internet
|
|
167
|
+
const win = new BrowserWindow({
|
|
168
|
+
preload: "https://electrobun.dev/some/remote/file.js",
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
// or use the views:// preload scheme to load local
|
|
172
|
+
// content that you've bundled with your app.
|
|
173
|
+
|
|
174
|
+
const win = new BrowserWindow({
|
|
175
|
+
preload: "views://somebundledview/preloadscript.js",
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
// or use inline javascript
|
|
179
|
+
|
|
180
|
+
const win = new BrowserWindow({
|
|
181
|
+
preload: "document.body.innerHTML = 'Hello world'; console.log('hello console')",
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### rpc
|
|
187
|
+
|
|
188
|
+
The RPC property allows you to establish RPC (remote procedure calls) between the bun process and this window's default BrowserView. In other words it lets you define functions that execute in the bun process that are callable and return a value back to the browser process and visa versa.
|
|
189
|
+
|
|
190
|
+
These RPC functions are asynchronous.
|
|
191
|
+
|
|
192
|
+
```typescript title="src/shared/types.ts"
|
|
193
|
+
export type MyWebviewRPCType = {
|
|
194
|
+
// functions that execute in the main process
|
|
195
|
+
bun: RPCSchema<{
|
|
196
|
+
requests: {
|
|
197
|
+
someBunFunction: {
|
|
198
|
+
params: {
|
|
199
|
+
a: number;
|
|
200
|
+
b: number;
|
|
201
|
+
};
|
|
202
|
+
response: number;
|
|
203
|
+
};
|
|
204
|
+
};
|
|
205
|
+
messages: {
|
|
206
|
+
logToBun: {
|
|
207
|
+
msg: string;
|
|
208
|
+
};
|
|
209
|
+
};
|
|
210
|
+
}>;
|
|
211
|
+
// functions that execute in the browser context
|
|
212
|
+
webview: RPCSchema<{
|
|
213
|
+
requests: {
|
|
214
|
+
someWebviewFunction: {
|
|
215
|
+
params: {
|
|
216
|
+
a: number;
|
|
217
|
+
b: number;
|
|
218
|
+
};
|
|
219
|
+
response: number;
|
|
220
|
+
};
|
|
221
|
+
};
|
|
222
|
+
messages: {
|
|
223
|
+
logToWebview: {
|
|
224
|
+
msg: string;
|
|
225
|
+
};
|
|
226
|
+
};
|
|
227
|
+
}>;
|
|
228
|
+
};
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
```typescript title="src/bun/index.ts"
|
|
232
|
+
import { BrowserWindow, BrowserView } from "electrobun/bun";
|
|
233
|
+
import { type MyWebviewRPCType } from "../shared/types";
|
|
234
|
+
|
|
235
|
+
// Create an RPC object for the bun handlers with the shared type
|
|
236
|
+
const myWebviewRPC = BrowserView.defineRPC<MyWebviewRPC>({
|
|
237
|
+
maxRequestTime: 5000,
|
|
238
|
+
handlers: {
|
|
239
|
+
requests: {
|
|
240
|
+
someBunFunction: ({ a, b }) => {
|
|
241
|
+
console.log(`browser asked me to do math with: ${a} and ${b}`);
|
|
242
|
+
return a + b;
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
// When the browser sends a message we can handle it
|
|
246
|
+
// in the main bun process
|
|
247
|
+
messages: {
|
|
248
|
+
"*": (messageName, payload) => {
|
|
249
|
+
console.log("global message handler", messageName, payload);
|
|
250
|
+
},
|
|
251
|
+
logToBun: ({ msg }) => {
|
|
252
|
+
console.log("Log to bun: ", msg);
|
|
253
|
+
},
|
|
254
|
+
},
|
|
255
|
+
},
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
// Pass the RPC object to the BrowserWindow, which will set it
|
|
259
|
+
// on the window's default BrowserView
|
|
260
|
+
const win = new BrowserWindow({
|
|
261
|
+
title: "my window",
|
|
262
|
+
url: "views://mainview/index.html",
|
|
263
|
+
frame: {
|
|
264
|
+
width: 1800,
|
|
265
|
+
height: 600,
|
|
266
|
+
x: 2000,
|
|
267
|
+
y: 2000,
|
|
268
|
+
},
|
|
269
|
+
rpc: myWebviewRPC,
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
// ... later on
|
|
273
|
+
|
|
274
|
+
// Note: These RPC methods will inherit types from the shared type
|
|
275
|
+
|
|
276
|
+
// Call a browser function from bun
|
|
277
|
+
const answer = await win.webview.rpc.someWebviewFunction(4, 6);
|
|
278
|
+
|
|
279
|
+
// Send a message to the BrowserView from bun
|
|
280
|
+
win.webview.rpc.logToBrowser("my message");
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
:::info
|
|
284
|
+
The above code snippet shows defining the bun process rpc handlers and calling the browser process handlers from bun. To see how to handle the Browser context code take a look at the [Browser API](/docs/apis/browser/Electroview%20Class)
|
|
285
|
+
:::
|
|
286
|
+
|
|
287
|
+
### syncRpc
|
|
288
|
+
|
|
289
|
+
:::warning
|
|
290
|
+
The `SyncRpc` api is blocking. Calling `syncRpc` methods from the browser will completely block the browser thread and halt javascript while waiting for the bun process to respond.
|
|
291
|
+
:::
|
|
292
|
+
|
|
293
|
+
:::info
|
|
294
|
+
Really the only time you may want to use the `syncRpc` api instead of the regular async `rpc` api is when you're migrating from Electron to Electrobun and you had a lot of browser code with the node integration enabled. Using the `syncRpc` api can save you lots of time on the initial refactor/migration.
|
|
295
|
+
|
|
296
|
+
It's strongly advised to later follow up and migrate `syncRpc` methods to async `rpc` later on.
|
|
297
|
+
:::
|
|
298
|
+
|
|
299
|
+
```typescript title="src/bun/index.ts"
|
|
300
|
+
const win = new BrowserWindow({
|
|
301
|
+
title: "my url window",
|
|
302
|
+
url: "views://mainview/index.html",
|
|
303
|
+
frame: {
|
|
304
|
+
width: 1800,
|
|
305
|
+
height: 600,
|
|
306
|
+
x: 2000,
|
|
307
|
+
y: 2000,
|
|
308
|
+
},
|
|
309
|
+
syncRpc: {
|
|
310
|
+
someSyncBunMethod: ({ a, b }) => {
|
|
311
|
+
console.log("doing sync math in bun", a, b);
|
|
312
|
+
return a + b;
|
|
313
|
+
},
|
|
314
|
+
},
|
|
315
|
+
});
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
To see how to call syncRpc methods from the browser take a look at the [Browser API](/docs/apis/browser/Electroview%20Class)
|
|
319
|
+
|
|
320
|
+
## Properties
|
|
321
|
+
|
|
322
|
+
### webview
|
|
323
|
+
|
|
324
|
+
This is a getter for the window's default [BrowserView](/docs/apis/bun/BrowserView)
|
|
325
|
+
|
|
326
|
+
```
|
|
327
|
+
const win = new BrowserWindow({
|
|
328
|
+
...
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
const defaultWebview = win.webview;
|
|
332
|
+
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
## Methods
|
|
336
|
+
|
|
337
|
+
### setTitle
|
|
338
|
+
|
|
339
|
+
Change the window title:
|
|
340
|
+
|
|
341
|
+
```
|
|
342
|
+
win.setTitle('new title')
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
### close
|
|
346
|
+
|
|
347
|
+
Close a window
|
|
348
|
+
|
|
349
|
+
```
|
|
350
|
+
win.close();
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
### on(name, handler)
|
|
354
|
+
|
|
355
|
+
Subscribe to BrowserWindow events (see below)
|
|
356
|
+
|
|
357
|
+
## Events
|
|
358
|
+
|
|
359
|
+
### close
|
|
360
|
+
|
|
361
|
+
When a window closes.
|
|
362
|
+
|
|
363
|
+
```
|
|
364
|
+
// listen to a specific window's close event
|
|
365
|
+
win.on('close', (event) => {
|
|
366
|
+
const {id} = event.data;
|
|
367
|
+
|
|
368
|
+
console.log('window closed')
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
// listen globally to window close events
|
|
372
|
+
import Electrobun from 'electrobun/bun';
|
|
373
|
+
|
|
374
|
+
Electrobun.events.on('close', (event) => {
|
|
375
|
+
const {id} = event.data;
|
|
376
|
+
|
|
377
|
+
if (win.id === id) {
|
|
378
|
+
console.log('my window closed');
|
|
379
|
+
} else {
|
|
380
|
+
console.log(`some other window with id ${id}` closed);
|
|
381
|
+
}
|
|
382
|
+
});
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
### resize
|
|
386
|
+
|
|
387
|
+
When a window's width or height changes. This events sends the x and y as part of the data because a window may be resized by dragging the top-left corner which would also reposition it.
|
|
388
|
+
|
|
389
|
+
```
|
|
390
|
+
// listen to a specific window's resize event
|
|
391
|
+
win.on("resize", (event) => {
|
|
392
|
+
const { id, x, y, width, height } = event.data;
|
|
393
|
+
console.log("window resized", id, x, y, width, height);
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
// listen globally to window resize events
|
|
397
|
+
import Electrobun from 'electrobun/bun';
|
|
398
|
+
|
|
399
|
+
Electrobun.events.on("resize", (event) => {
|
|
400
|
+
const { id, x, y, width, height } = event.data;
|
|
401
|
+
console.log("window resized", id, x, y, width, height);
|
|
402
|
+
});
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
### move
|
|
406
|
+
|
|
407
|
+
When a window's width or height changes
|
|
408
|
+
|
|
409
|
+
```
|
|
410
|
+
// listen to a specific window's move event
|
|
411
|
+
win.on("move", (event) => {
|
|
412
|
+
const { id, x, y } = event.data;
|
|
413
|
+
console.log("window moved", id, x, y);
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
// listen globally to window move events
|
|
417
|
+
import Electrobun from 'electrobun/bun';
|
|
418
|
+
|
|
419
|
+
Electrobun.eventson("move", (event) => {
|
|
420
|
+
const { id, x, y } = event.data;
|
|
421
|
+
console.log("window moved", id, x, y);
|
|
422
|
+
});
|
|
423
|
+
```
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
> Show a context menu
|
|
2
|
+
|
|
3
|
+
Typically you'd wire up a rightclick event with preventDefault in the browser context, rpc to bun, then create a native context menu from the bun context. But you can also create and show a context menu entirely from bun which will show at the mouse cursor's position globally positioned on screen even outside of your application window. Even if you have no windows open and another app is focused.
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
import {ContextMenu} from "electrobun/bun";
|
|
7
|
+
|
|
8
|
+
// Show a context menu wherever the mouse cursor is on screen
|
|
9
|
+
// after 5 seconds.
|
|
10
|
+
setTimeout(() => {
|
|
11
|
+
ContextMenu.showContextMenu([
|
|
12
|
+
{ role: "undo" },
|
|
13
|
+
{ role: "redo" },
|
|
14
|
+
{ type: "separator" },
|
|
15
|
+
{
|
|
16
|
+
label: "Custom Menu Item 🚀",
|
|
17
|
+
action: "custom-action-1",
|
|
18
|
+
tooltip: "I'm a tooltip",
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
label: "Custom menu disabled",
|
|
22
|
+
enabled: false,
|
|
23
|
+
action: "custom-action-2",
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
label: "Custom menu disabled",
|
|
27
|
+
enabled: false,
|
|
28
|
+
action: "custom-action-2",
|
|
29
|
+
// todo: support a data property on all menus (app, tray, context)
|
|
30
|
+
data: {
|
|
31
|
+
some: "data",
|
|
32
|
+
that: "is serialized",
|
|
33
|
+
nested: { thing: 23 },
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
{ type: "separator" },
|
|
37
|
+
{ role: "cut" },
|
|
38
|
+
{ role: "copy" },
|
|
39
|
+
{ role: "paste" },
|
|
40
|
+
{ role: "pasteAndMatchStyle" },
|
|
41
|
+
{ role: "delete" },
|
|
42
|
+
{ role: "selectAll" },
|
|
43
|
+
]);
|
|
44
|
+
}, 5000);
|
|
45
|
+
|
|
46
|
+
Electrobun.events.on("context-menu-clicked", (e) => {
|
|
47
|
+
console.log("context event", e.data.action);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
```
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
> Event system in the main bun process
|
|
2
|
+
|
|
3
|
+
## Event Propagation
|
|
4
|
+
|
|
5
|
+
### Global Events
|
|
6
|
+
|
|
7
|
+
Most events can be listened to directly on the thing firing them or globally.
|
|
8
|
+
|
|
9
|
+
Global Event handlers fire first. Then handlers are fired in the sequence that they were registered in.
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
// listen to global event
|
|
13
|
+
Electrobun.events.on("will-navigate", (e) => {
|
|
14
|
+
// handle
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
// listen to event on object
|
|
18
|
+
win.webview.on('will-navigate', (e) => {
|
|
19
|
+
// handle
|
|
20
|
+
})
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Event.response
|
|
24
|
+
|
|
25
|
+
You can set a response on some events. Typically these are events initiated from zig which freeze the zig process while waiting for a reply from bun. An example of this is the BrowserView `will-navigate` where objc requires a synchronous response. By freezing the zig process and waiting for bun we allow bun to remain async while the events propagate.
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
Electrobun.events.on("will-navigate", (e) => {
|
|
29
|
+
console.log(
|
|
30
|
+
"example global will-navigate handler",
|
|
31
|
+
e.data.url,
|
|
32
|
+
e.data.webviewId
|
|
33
|
+
);
|
|
34
|
+
e.response = { allow: true };
|
|
35
|
+
});
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
As the event propagates through different handlers you can both read and write from the e.response value.
|
|
39
|
+
|
|
40
|
+
### Event.responseWasSet
|
|
41
|
+
|
|
42
|
+
A property that indicates the response has been set to something which can be useful when an event propagates through multiple handlers instead of trying to infer from the response value whether it was set or not.
|
|
43
|
+
|
|
44
|
+
### Event.clearResponse
|
|
45
|
+
|
|
46
|
+
If a previous handler has set the e.response to something and you want to clear it, you can simply call `e.clearResponse()`
|
|
47
|
+
|
|
48
|
+
### Event.data
|
|
49
|
+
|
|
50
|
+
Each event will set different event data
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
> Global paths exposed by Electrobun
|
|
2
|
+
|
|
3
|
+
```
|
|
4
|
+
import {PATHS} from "electrobun/bun";
|
|
5
|
+
|
|
6
|
+
// in a macOS bundle this is where static bundled resources are kept.
|
|
7
|
+
|
|
8
|
+
// Note: You shouldn't modify or write to the bundle at runtime as it will affect code signing
|
|
9
|
+
// integrity.
|
|
10
|
+
PATHS.RESOURCES_FOLDER
|
|
11
|
+
|
|
12
|
+
// Typically you would use the views:// url scheme which maps to
|
|
13
|
+
// RESOURCES_FOLDER + '/app/views/'
|
|
14
|
+
// But there may be cases in bun where you want to read a file directly.
|
|
15
|
+
PATHS.VIEWS_FOLDER
|
|
16
|
+
|
|
17
|
+
```
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
> Create and manage system tray icon and menu.
|
|
2
|
+
|
|
3
|
+
```
|
|
4
|
+
import {Tray} from "electrobun/bun";
|
|
5
|
+
|
|
6
|
+
const tray = new Tray({
|
|
7
|
+
title: "Example Tray Item (click to create menu)",
|
|
8
|
+
// This can be a views url or an absolute file path
|
|
9
|
+
image: `views://assets/electrobun-logo-32-template.png`,
|
|
10
|
+
template: true,
|
|
11
|
+
width: 32,
|
|
12
|
+
height: 32,
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
// map action names to clicked state
|
|
16
|
+
// Note: This is just used for this example
|
|
17
|
+
const menuState = {
|
|
18
|
+
"item-1": false,
|
|
19
|
+
"sub-item-1": false,
|
|
20
|
+
"sub-item-2": true,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const updateTrayMenu = () => {
|
|
24
|
+
tray.setMenu([
|
|
25
|
+
{
|
|
26
|
+
type: "normal",
|
|
27
|
+
label: `Toggle me`,
|
|
28
|
+
action: "item-1",
|
|
29
|
+
checked: menuState["item-1"],
|
|
30
|
+
tooltip: `I'm a tooltip`,
|
|
31
|
+
submenu: [
|
|
32
|
+
{
|
|
33
|
+
type: "normal",
|
|
34
|
+
label: "Click me to toggle sub-item 2",
|
|
35
|
+
tooltip: "i will also unhide sub-item-3",
|
|
36
|
+
action: "sub-item-1",
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
type: "divider",
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
type: "normal",
|
|
43
|
+
label: "Toggle sub-item-3's visibility",
|
|
44
|
+
action: "sub-item-2",
|
|
45
|
+
enabled: menuState["sub-item-1"],
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
type: "normal",
|
|
49
|
+
label: "I was hidden",
|
|
50
|
+
action: "sub-item-3",
|
|
51
|
+
hidden: menuState["sub-item-2"],
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
},
|
|
55
|
+
]);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// TODO: events should be typed
|
|
59
|
+
tray.on("tray-clicked", (e) => {
|
|
60
|
+
const { id, action } = e.data as { id: number; action: string };
|
|
61
|
+
|
|
62
|
+
if (action === "") {
|
|
63
|
+
// main menu was clicked before we create a system tray menu for it.
|
|
64
|
+
updateTrayMenu();
|
|
65
|
+
tray.setTitle("Example Tray Item (click to open menu)");
|
|
66
|
+
} else {
|
|
67
|
+
// once there's a menu, we can toggle the state of the menu items
|
|
68
|
+
menuState[action] = !menuState[action];
|
|
69
|
+
updateTrayMenu();
|
|
70
|
+
}
|
|
71
|
+
// respond to left and right clicks on the tray icon/name
|
|
72
|
+
console.log("event listener for tray clicked", e.data.action);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Constructor Options
|
|
78
|
+
|
|
79
|
+
### title
|
|
80
|
+
|
|
81
|
+
This is the text that will appear in your system tray
|
|
82
|
+
|
|
83
|
+
### image
|
|
84
|
+
|
|
85
|
+
This is an optional url to an image to load. You can use the `views://` schema to access local bundled images.
|
|
86
|
+
|
|
87
|
+
### template
|
|
88
|
+
|
|
89
|
+
You can use a full-color image like a png but that image will just be shown as is. On MacOS you can create a template image and set the `template` property to true. A template image uses opacity to define a black and white image that adapts to your systems light/dark mode.
|
|
90
|
+
|
|
91
|
+
### width and height
|
|
92
|
+
|
|
93
|
+
Set the dimensions of the image used in the system tray
|
|
94
|
+
|
|
95
|
+
## Methods
|
|
96
|
+
|
|
97
|
+
### setMenu
|
|
98
|
+
|
|
99
|
+
Call setMenu whenever you want to show the menu. Typically you would listen for the `tray-clicked` event, then show the menu and listen for the `tray-item-clicked`. Your app could also listen for keyboard shortcuts or show the system tray menu in response to something else.
|
|
100
|
+
|
|
101
|
+
A common pattern is to create a function that dynamically generates the menu from some kind of state to implement things like checkbox toggles.
|
|
102
|
+
|
|
103
|
+
### Menu Items
|
|
104
|
+
|
|
105
|
+
See [Application Menu](/docs/apis/bun/ApplicationMenu) for more info on available properties for menu items.
|
|
106
|
+
|
|
107
|
+
## Events
|
|
108
|
+
|
|
109
|
+
### tray-clicked
|
|
110
|
+
|
|
111
|
+
This is fired when the system tray item itself is clicked
|
|
112
|
+
|
|
113
|
+
### tray-item-clicked
|
|
114
|
+
|
|
115
|
+
This is fired when a system tray menu item or submenu item is clicked.
|