electrobun 0.0.2 → 0.0.4

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 (76) hide show
  1. package/.colab.json +1 -0
  2. package/README.md +14 -12
  3. package/bun.lockb +0 -0
  4. package/dist/bsdiff +0 -0
  5. package/dist/bspatch +0 -0
  6. package/dist/webview +0 -0
  7. package/docs-old/architecture.md +46 -0
  8. package/documentation/README.md +41 -0
  9. package/documentation/babel.config.js +3 -0
  10. package/documentation/blog/2024-08-20-electrobun.md +22 -0
  11. package/documentation/blog/authors.yml +8 -0
  12. package/documentation/blog/tags.yml +0 -0
  13. package/documentation/docs/apis/Application Icons.md +9 -0
  14. package/documentation/docs/apis/Bundled Assets.md +95 -0
  15. package/documentation/docs/apis/browser/DraggableRegions.md +36 -0
  16. package/documentation/docs/apis/browser/Electrobun Webview Tag.md +200 -0
  17. package/documentation/docs/apis/browser/Electroview Class.md +158 -0
  18. package/documentation/docs/apis/browser/GlobalProperties.md +11 -0
  19. package/documentation/docs/apis/browser/index.md +25 -0
  20. package/documentation/docs/apis/bun/ApplicationMenu.md +141 -0
  21. package/documentation/docs/apis/bun/BrowserView.md +513 -0
  22. package/documentation/docs/apis/bun/BrowserWindow.md +423 -0
  23. package/documentation/docs/apis/bun/ContextMenu.md +50 -0
  24. package/documentation/docs/apis/bun/Events.md +50 -0
  25. package/documentation/docs/apis/bun/PATHS.md +17 -0
  26. package/documentation/docs/apis/bun/Tray.md +115 -0
  27. package/documentation/docs/apis/bun/Updater.md +74 -0
  28. package/documentation/docs/apis/bun/Utils.md +51 -0
  29. package/documentation/docs/apis/bun/index.md +26 -0
  30. package/documentation/docs/apis/cli/Electrobun.config.md +97 -0
  31. package/documentation/docs/apis/cli/cli args.md +76 -0
  32. package/documentation/docs/guides/Architecture/Events.md +19 -0
  33. package/documentation/docs/guides/Architecture/IPC and Isolation.md +20 -0
  34. package/documentation/docs/guides/Architecture/Overview.md +140 -0
  35. package/documentation/docs/guides/Architecture/Updates.md +7 -0
  36. package/documentation/docs/guides/Architecture/Webview Tag.md +5 -0
  37. package/documentation/docs/guides/Compatability.md +8 -0
  38. package/documentation/docs/guides/Getting Started/Creating UI.md +147 -0
  39. package/documentation/docs/guides/Getting Started/Distributing.md +116 -0
  40. package/documentation/docs/guides/Getting Started/Getting Started.md +7 -0
  41. package/documentation/docs/guides/Getting Started/Hello World.md +93 -0
  42. package/documentation/docs/guides/Getting Started/What is Electrobun.md +39 -0
  43. package/documentation/docs/guides/Guides/Build UI with React +0 -0
  44. package/documentation/docs/guides/Guides/Build UI with Solidjs +0 -0
  45. package/documentation/docs/guides/Guides/Build a Web Browser +0 -0
  46. package/documentation/docs/guides/Guides/Bun <-> Browser RPC +0 -0
  47. package/documentation/docs/guides/Guides/Using Tailwind +0 -0
  48. package/documentation/docusaurus.config.ts +153 -0
  49. package/documentation/package-lock.json +14530 -0
  50. package/documentation/package.json +47 -0
  51. package/documentation/sidebars.ts +32 -0
  52. package/documentation/src/components/HomepageFeatures/index.tsx +70 -0
  53. package/documentation/src/components/HomepageFeatures/styles.module.css +11 -0
  54. package/documentation/src/css/custom.css +30 -0
  55. package/documentation/src/pages/index.module.css +23 -0
  56. package/documentation/src/pages/index.tsx +137 -0
  57. package/documentation/static/.nojekyll +0 -0
  58. package/documentation/static/img/electrobun-logo-256.png +0 -0
  59. package/documentation/static/img/electrobun-logo-32.png +0 -0
  60. package/documentation/tsconfig.json +7 -0
  61. package/package.json +11 -6
  62. package/src/browser/index.ts +7 -2
  63. package/src/browser/webviewtag.ts +149 -17
  64. package/src/bun/core/BrowserView.ts +19 -2
  65. package/src/bun/proc/zig.ts +1 -0
  66. package/src/cli/build/electrobun +0 -0
  67. package/src/cli/index.ts +3 -1
  68. package/src/extractor/zig-out/bin/extractor +0 -0
  69. package/src/launcher/zig-out/bin/launcher +0 -0
  70. package/docs/architecture.md +0 -84
  71. /package/{docs → docs-old}/api/bun-api.md +0 -0
  72. /package/{docs → docs-old}/api/view-api.md +0 -0
  73. /package/{docs → docs-old}/electrobun-config.md +0 -0
  74. /package/{docs → docs-old}/getting-started.md +0 -0
  75. /package/{docs → docs-old}/node_modules/.cache/webpack/client-development-en/0.pack +0 -0
  76. /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.