electrobun 0.5.0-beta.0 → 0.6.0-beta.0

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 (78) hide show
  1. package/{templates/multitab-browser/bun.lock → bun.lock} +20 -13
  2. package/dist/api/bun/proc/native.ts +84 -16
  3. package/package.json +14 -16
  4. package/BETA_RELEASE.md +0 -67
  5. package/BUILD.md +0 -90
  6. package/LICENSE +0 -21
  7. package/README.md +0 -102
  8. package/debug.js +0 -5
  9. package/templates/hello-world/README.md +0 -57
  10. package/templates/hello-world/bun.lock +0 -225
  11. package/templates/hello-world/electrobun.config.ts +0 -28
  12. package/templates/hello-world/package.json +0 -16
  13. package/templates/hello-world/src/bun/index.ts +0 -15
  14. package/templates/hello-world/src/mainview/index.css +0 -124
  15. package/templates/hello-world/src/mainview/index.html +0 -46
  16. package/templates/hello-world/src/mainview/index.ts +0 -1
  17. package/templates/interactive-playground/README.md +0 -26
  18. package/templates/interactive-playground/assets/tray-icon.png +0 -0
  19. package/templates/interactive-playground/electrobun.config.ts +0 -36
  20. package/templates/interactive-playground/package-lock.json +0 -1112
  21. package/templates/interactive-playground/package.json +0 -15
  22. package/templates/interactive-playground/src/bun/demos/files.ts +0 -70
  23. package/templates/interactive-playground/src/bun/demos/menus.ts +0 -139
  24. package/templates/interactive-playground/src/bun/demos/rpc.ts +0 -83
  25. package/templates/interactive-playground/src/bun/demos/system.ts +0 -72
  26. package/templates/interactive-playground/src/bun/demos/updates.ts +0 -105
  27. package/templates/interactive-playground/src/bun/demos/windows.ts +0 -90
  28. package/templates/interactive-playground/src/bun/index.ts +0 -124
  29. package/templates/interactive-playground/src/bun/types/rpc.ts +0 -109
  30. package/templates/interactive-playground/src/mainview/components/EventLog.ts +0 -107
  31. package/templates/interactive-playground/src/mainview/components/Sidebar.ts +0 -65
  32. package/templates/interactive-playground/src/mainview/components/Toast.ts +0 -57
  33. package/templates/interactive-playground/src/mainview/demos/FileDemo.ts +0 -211
  34. package/templates/interactive-playground/src/mainview/demos/MenuDemo.ts +0 -102
  35. package/templates/interactive-playground/src/mainview/demos/RPCDemo.ts +0 -229
  36. package/templates/interactive-playground/src/mainview/demos/TrayDemo.ts +0 -132
  37. package/templates/interactive-playground/src/mainview/demos/WebViewDemo.ts +0 -465
  38. package/templates/interactive-playground/src/mainview/demos/WindowDemo.ts +0 -207
  39. package/templates/interactive-playground/src/mainview/index.css +0 -538
  40. package/templates/interactive-playground/src/mainview/index.html +0 -103
  41. package/templates/interactive-playground/src/mainview/index.ts +0 -238
  42. package/templates/multitab-browser/README.md +0 -34
  43. package/templates/multitab-browser/electrobun.config.ts +0 -32
  44. package/templates/multitab-browser/package-lock.json +0 -20
  45. package/templates/multitab-browser/package.json +0 -12
  46. package/templates/multitab-browser/src/bun/index.ts +0 -144
  47. package/templates/multitab-browser/src/bun/tabManager.ts +0 -200
  48. package/templates/multitab-browser/src/bun/types/rpc.ts +0 -78
  49. package/templates/multitab-browser/src/mainview/index.css +0 -487
  50. package/templates/multitab-browser/src/mainview/index.html +0 -94
  51. package/templates/multitab-browser/src/mainview/index.ts +0 -634
  52. package/templates/photo-booth/README.md +0 -108
  53. package/templates/photo-booth/bun.lock +0 -239
  54. package/templates/photo-booth/electrobun.config.ts +0 -32
  55. package/templates/photo-booth/package.json +0 -17
  56. package/templates/photo-booth/src/bun/index.ts +0 -92
  57. package/templates/photo-booth/src/mainview/index.css +0 -465
  58. package/templates/photo-booth/src/mainview/index.html +0 -124
  59. package/templates/photo-booth/src/mainview/index.ts +0 -499
  60. package/test-new-window-events.ts +0 -26
  61. package/test-new-window.html +0 -75
  62. package/test-npm-install.sh +0 -34
  63. package/tests/bun.lock +0 -14
  64. package/tests/electrobun.config.ts +0 -45
  65. package/tests/package-lock.json +0 -36
  66. package/tests/package.json +0 -13
  67. package/tests/src/bun/index.ts +0 -100
  68. package/tests/src/bun/test-runner.ts +0 -508
  69. package/tests/src/mainview/index.html +0 -110
  70. package/tests/src/mainview/index.ts +0 -458
  71. package/tests/src/mainview/styles/main.css +0 -451
  72. package/tests/src/testviews/tray-test.html +0 -57
  73. package/tests/src/testviews/webview-mask.html +0 -114
  74. package/tests/src/testviews/webview-navigation.html +0 -36
  75. package/tests/src/testviews/window-create.html +0 -17
  76. package/tests/src/testviews/window-events.html +0 -29
  77. package/tests/src/testviews/window-focus.html +0 -37
  78. package/tests/src/webviewtag/index.ts +0 -11
@@ -1,499 +0,0 @@
1
- import Electrobun, { Electroview } from "electrobun/view";
2
- import type { PhotoBoothRPC } from "../bun/index";
3
-
4
- // Create RPC client
5
- const rpc = Electroview.defineRPC<PhotoBoothRPC>({
6
- maxRequestTime: 5000,
7
- handlers: {
8
- requests: {},
9
- messages: {}
10
- }
11
- });
12
-
13
- // Initialize Electrobun with RPC
14
- const electrobun = new Electrobun.Electroview({ rpc });
15
-
16
- interface Photo {
17
- id: string;
18
- dataUrl: string;
19
- timestamp: Date;
20
- type: 'camera' | 'screen';
21
- }
22
-
23
- type CaptureMode = 'camera' | 'screen';
24
-
25
- class PhotoBooth {
26
- private video: HTMLVideoElement;
27
- private canvas: HTMLCanvasElement;
28
- private captureBtn: HTMLButtonElement;
29
- private gallery: HTMLElement;
30
- private cameraSelect: HTMLSelectElement;
31
- private timerToggle: HTMLInputElement;
32
- private cameraModeBtn: HTMLButtonElement;
33
- private screenModeBtn: HTMLButtonElement;
34
- private startCameraBtn: HTMLButtonElement;
35
- private selectScreenBtn: HTMLButtonElement;
36
- private status: HTMLElement;
37
- private statusText: HTMLElement;
38
- private countdown: HTMLElement;
39
- private modal: HTMLElement;
40
- private modalImage: HTMLImageElement;
41
- private captureBtnText: HTMLElement;
42
- private cameraIcon: HTMLElement;
43
- private screenIcon: HTMLElement;
44
-
45
- private stream: MediaStream | null = null;
46
- private photos: Photo[] = [];
47
- private currentPhotoId: string | null = null;
48
- private currentMode: CaptureMode = 'camera';
49
-
50
- constructor() {
51
- // Get DOM elements
52
- this.video = document.getElementById('video') as HTMLVideoElement;
53
- this.canvas = document.getElementById('canvas') as HTMLCanvasElement;
54
- this.captureBtn = document.getElementById('captureBtn') as HTMLButtonElement;
55
- this.gallery = document.getElementById('gallery') as HTMLElement;
56
- this.cameraSelect = document.getElementById('cameraSelect') as HTMLSelectElement;
57
- this.timerToggle = document.getElementById('timerToggle') as HTMLInputElement;
58
- this.cameraModeBtn = document.getElementById('cameraModeBtn') as HTMLButtonElement;
59
- this.screenModeBtn = document.getElementById('screenModeBtn') as HTMLButtonElement;
60
- this.startCameraBtn = document.getElementById('startCameraBtn') as HTMLButtonElement;
61
- this.selectScreenBtn = document.getElementById('selectScreenBtn') as HTMLButtonElement;
62
- this.status = document.getElementById('status') as HTMLElement;
63
- this.statusText = this.status.querySelector('.status-text') as HTMLElement;
64
- this.countdown = document.getElementById('countdown') as HTMLElement;
65
- this.modal = document.getElementById('photoModal') as HTMLElement;
66
- this.modalImage = document.getElementById('modalImage') as HTMLImageElement;
67
- this.captureBtnText = this.captureBtn.querySelector('.capture-btn-text') as HTMLElement;
68
- this.cameraIcon = this.captureBtn.querySelector('.capture-icon-camera') as HTMLElement;
69
- this.screenIcon = this.captureBtn.querySelector('.capture-icon-screen') as HTMLElement;
70
-
71
- this.initializeEventListeners();
72
- this.initializeApp();
73
- }
74
-
75
- private initializeEventListeners() {
76
- // Mode toggle buttons
77
- this.cameraModeBtn.addEventListener('click', () => this.setMode('camera'));
78
- this.screenModeBtn.addEventListener('click', () => this.setMode('screen'));
79
-
80
- // Capture button
81
- this.captureBtn.addEventListener('click', () => this.capturePhoto());
82
-
83
- // Camera controls
84
- this.startCameraBtn.addEventListener('click', () => this.startCamera());
85
- this.cameraSelect.addEventListener('change', (e) => {
86
- const deviceId = (e.target as HTMLSelectElement).value;
87
- if (deviceId) {
88
- this.switchCamera(deviceId);
89
- }
90
- });
91
-
92
- // Screen controls
93
- this.selectScreenBtn.addEventListener('click', () => this.selectScreen());
94
-
95
- // Modal controls
96
- document.getElementById('modalClose')?.addEventListener('click', () => this.closeModal());
97
- document.getElementById('downloadBtn')?.addEventListener('click', () => this.saveCurrentPhoto());
98
- document.getElementById('deleteBtn')?.addEventListener('click', () => this.deleteCurrentPhoto());
99
-
100
- // Close modal on background click
101
- this.modal.addEventListener('click', (e) => {
102
- if (e.target === this.modal) {
103
- this.closeModal();
104
- }
105
- });
106
- }
107
-
108
- private async initializeApp() {
109
- // Set initial mode
110
- this.setMode('camera');
111
-
112
- // Check available cameras
113
- await this.populateCameraList();
114
- }
115
-
116
- private setMode(mode: CaptureMode) {
117
- this.currentMode = mode;
118
-
119
- // Update UI classes
120
- document.body.classList.toggle('mode-screen', mode === 'screen');
121
-
122
- // Update mode buttons
123
- this.cameraModeBtn.classList.toggle('active', mode === 'camera');
124
- this.screenModeBtn.classList.toggle('active', mode === 'screen');
125
-
126
- // Update capture button
127
- this.cameraIcon.style.display = mode === 'camera' ? 'block' : 'none';
128
- this.screenIcon.style.display = mode === 'screen' ? 'block' : 'none';
129
- this.captureBtnText.textContent = mode === 'camera' ? 'Take Photo' : 'Take Screenshot';
130
-
131
- // Reset state when switching modes
132
- this.stopStream();
133
- this.captureBtn.disabled = true;
134
-
135
- // Reset video display and hide any placeholders
136
- this.video.style.display = 'block';
137
- const placeholder = this.video.parentElement?.querySelector('.native-capture-placeholder') as HTMLElement;
138
- if (placeholder) {
139
- placeholder.style.display = 'none';
140
- }
141
-
142
- // Update status based on mode
143
- if (mode === 'camera') {
144
- this.setStatus('Click "Start Camera" to begin', false);
145
- this.startCameraBtn.style.display = 'flex';
146
- this.selectScreenBtn.style.display = 'none';
147
- } else {
148
- this.setStatus('Screen capture mode - tests getDisplayMedia browser API', false);
149
- this.selectScreenBtn.style.display = 'flex';
150
- this.startCameraBtn.style.display = 'none';
151
- }
152
- }
153
-
154
- private stopStream() {
155
- if (this.stream) {
156
- this.stream.getTracks().forEach(track => track.stop());
157
- this.stream = null;
158
- this.video.srcObject = null;
159
- }
160
- }
161
-
162
- private async populateCameraList() {
163
- try {
164
- const devices = await navigator.mediaDevices.enumerateDevices();
165
- const videoDevices = devices.filter(device => device.kind === 'videoinput');
166
-
167
- // Clear existing options
168
- this.cameraSelect.innerHTML = '<option value="">Select Camera</option>';
169
-
170
- // Add camera options
171
- videoDevices.forEach((device, index) => {
172
- const option = document.createElement('option');
173
- option.value = device.deviceId;
174
- option.textContent = device.label || `Camera ${index + 1}`;
175
- this.cameraSelect.appendChild(option);
176
- });
177
-
178
- if (videoDevices.length > 0) {
179
- this.startCameraBtn.style.display = 'flex';
180
- } else {
181
- this.setStatus('No cameras found on this device', false);
182
- }
183
- } catch (error) {
184
- console.error('Error enumerating cameras:', error);
185
- this.setStatus('Unable to access camera list', false);
186
- }
187
- }
188
-
189
- private async startCamera() {
190
- try {
191
- const constraints: MediaStreamConstraints = {
192
- video: {
193
- width: { ideal: 1280 },
194
- height: { ideal: 720 }
195
- },
196
- audio: false
197
- };
198
-
199
- // If a specific camera is selected, use it
200
- const selectedCamera = this.cameraSelect.value;
201
- if (selectedCamera) {
202
- (constraints.video as MediaTrackConstraints).deviceId = selectedCamera;
203
- }
204
-
205
- this.stream = await navigator.mediaDevices.getUserMedia(constraints);
206
- this.video.srcObject = this.stream;
207
-
208
- // Update status and enable capture
209
- this.setStatus('Camera active - ready to take photos', true);
210
- this.captureBtn.disabled = false;
211
- this.startCameraBtn.style.display = 'none';
212
-
213
- } catch (error) {
214
- console.error('Error starting camera:', error);
215
- this.setStatus(`Camera error: ${(error as Error).message}`, false);
216
- }
217
- }
218
-
219
- private async switchCamera(deviceId: string) {
220
- if (this.stream) {
221
- this.stopStream();
222
- }
223
-
224
- try {
225
- const constraints: MediaStreamConstraints = {
226
- video: {
227
- deviceId: deviceId,
228
- width: { ideal: 1280 },
229
- height: { ideal: 720 }
230
- },
231
- audio: false
232
- };
233
-
234
- this.stream = await navigator.mediaDevices.getUserMedia(constraints);
235
- this.video.srcObject = this.stream;
236
- this.setStatus('Camera switched successfully', true);
237
- this.captureBtn.disabled = false;
238
- } catch (error) {
239
- console.error('Error switching camera:', error);
240
- this.setStatus('Failed to switch camera', false);
241
- }
242
- }
243
-
244
- private async selectScreen() {
245
- try {
246
- // Log what's available for debugging
247
- console.log('Browser capabilities:');
248
- console.log(' navigator.mediaDevices:', !!navigator.mediaDevices);
249
- console.log(' getDisplayMedia:', !!(navigator.mediaDevices && (navigator.mediaDevices as any).getDisplayMedia));
250
- console.log(' getUserMedia:', !!(navigator.mediaDevices && navigator.mediaDevices.getUserMedia));
251
- console.log(' User agent:', navigator.userAgent);
252
-
253
- // Check if getDisplayMedia is available
254
- if (navigator.mediaDevices && (navigator.mediaDevices as any).getDisplayMedia) {
255
- console.log('getDisplayMedia is available, attempting screen capture');
256
-
257
- try {
258
- this.stream = await (navigator.mediaDevices as any).getDisplayMedia({
259
- video: true,
260
- audio: false
261
- });
262
-
263
- this.video.srcObject = this.stream;
264
- this.setStatus('Screen capture active - ready to take screenshots', true);
265
- this.captureBtn.disabled = false;
266
- this.selectScreenBtn.style.display = 'none';
267
-
268
- // Listen for when the user stops sharing
269
- if (this.stream) {
270
- const videoTracks = this.stream.getVideoTracks();
271
- if (videoTracks.length > 0) {
272
- videoTracks[0].addEventListener('ended', () => {
273
- this.setStatus('Screen sharing stopped', false);
274
- this.captureBtn.disabled = true;
275
- this.selectScreenBtn.style.display = 'flex';
276
- });
277
- }
278
- }
279
- } catch (permissionError) {
280
- // Handle permission denial or other getDisplayMedia errors
281
- console.log('getDisplayMedia failed:', permissionError);
282
- throw new Error(`Screen capture failed: ${(permissionError as Error).message}`);
283
- }
284
- } else {
285
- // getDisplayMedia not available
286
- console.log('getDisplayMedia not available in this browser');
287
- throw new Error('getDisplayMedia API is not available in this browser. This may be due to:\n• WKWebView limitations\n• Browser version\n• Security restrictions\n• Platform limitations');
288
- }
289
- } catch (error) {
290
- console.error('Error selecting screen:', error);
291
- this.setStatus(`Screen capture error: ${(error as Error).message}`, false);
292
- }
293
- }
294
-
295
- private async capturePhoto() {
296
- if (this.currentMode === 'camera') {
297
- await this.captureCameraPhoto();
298
- } else {
299
- await this.captureScreenshot();
300
- }
301
- }
302
-
303
- private async captureCameraPhoto() {
304
- if (!this.stream) {
305
- this.setStatus('No camera stream available', false);
306
- return;
307
- }
308
-
309
- try {
310
- // Optional timer countdown
311
- if (this.timerToggle.checked) {
312
- await this.showCountdown();
313
- }
314
-
315
- // Capture from video stream
316
- const context = this.canvas.getContext('2d');
317
- if (!context) return;
318
-
319
- this.canvas.width = this.video.videoWidth;
320
- this.canvas.height = this.video.videoHeight;
321
- context.drawImage(this.video, 0, 0);
322
-
323
- // Convert to data URL
324
- const dataUrl = this.canvas.toDataURL('image/png');
325
-
326
- // Add to gallery
327
- const photo: Photo = {
328
- id: Date.now().toString(),
329
- dataUrl: dataUrl,
330
- timestamp: new Date(),
331
- type: 'camera'
332
- };
333
-
334
- this.photos.push(photo);
335
- this.addPhotoToGallery(photo);
336
- this.setStatus('Photo captured!', true);
337
- this.playCaptureFeedback();
338
-
339
- } catch (error) {
340
- console.error('Error capturing photo:', error);
341
- this.setStatus(`Capture failed: ${(error as Error).message}`, false);
342
- }
343
- }
344
-
345
- private async captureScreenshot() {
346
- try {
347
- if (this.stream) {
348
- // We have a screen share stream from getDisplayMedia - capture it
349
- await this.captureCameraPhoto(); // Same capture logic, but from screen stream
350
- } else {
351
- // No stream available - this shouldn't happen if selectScreen worked
352
- throw new Error('No screen capture stream available. Make sure to select a screen first.');
353
- }
354
- } catch (error) {
355
- console.error('Error capturing screenshot:', error);
356
- this.setStatus(`Screenshot failed: ${(error as Error).message}`, false);
357
- }
358
- }
359
-
360
- private async showCountdown() {
361
- for (let i = 3; i > 0; i--) {
362
- this.countdown.textContent = i.toString();
363
- this.countdown.style.display = 'flex';
364
- await new Promise(resolve => setTimeout(resolve, 1000));
365
- }
366
- this.countdown.style.display = 'none';
367
- }
368
-
369
- private playCaptureFeedback() {
370
- // Flash effect
371
- document.body.style.backgroundColor = 'white';
372
- setTimeout(() => {
373
- document.body.style.backgroundColor = '';
374
- }, 100);
375
- }
376
-
377
- private addPhotoToGallery(photo: Photo) {
378
- // Remove empty state if it exists
379
- const emptyState = this.gallery.querySelector('.empty-state');
380
- if (emptyState) {
381
- emptyState.remove();
382
- }
383
-
384
- // Create photo element
385
- const photoElement = document.createElement('div');
386
- photoElement.className = 'photo-item';
387
- photoElement.dataset['photoId'] = photo.id;
388
-
389
- const typeIcon = photo.type === 'camera' ? '📷' : '🖥️';
390
- photoElement.innerHTML = `
391
- <img src="${photo.dataUrl}" alt="Captured ${photo.type}">
392
- <div class="photo-info">
393
- <span class="photo-type">${typeIcon}</span>
394
- <span class="photo-time">${photo.timestamp.toLocaleTimeString()}</span>
395
- </div>
396
- `;
397
-
398
- photoElement.addEventListener('click', () => this.openModal(photo.id));
399
- this.gallery.insertBefore(photoElement, this.gallery.firstChild);
400
- }
401
-
402
- private openModal(photoId: string) {
403
- const photo = this.photos.find(p => p.id === photoId);
404
- if (!photo) return;
405
-
406
- this.currentPhotoId = photoId;
407
- this.modalImage.src = photo.dataUrl;
408
- this.modal.style.display = 'flex';
409
- }
410
-
411
- private closeModal() {
412
- this.modal.style.display = 'none';
413
- this.currentPhotoId = null;
414
- }
415
-
416
- private async saveCurrentPhoto() {
417
- if (!this.currentPhotoId) return;
418
-
419
- const photo = this.photos.find(p => p.id === this.currentPhotoId);
420
- if (!photo) return;
421
-
422
- try {
423
- const filename = `${photo.type}-${new Date().toISOString().slice(0, 19).replace(/[:.]/g, '-')}.png`;
424
- const result = await electrobun.rpc!.request.savePhoto({
425
- dataUrl: photo.dataUrl,
426
- filename: filename
427
- });
428
-
429
- if (result.success) {
430
- this.showStatus('Photo saved successfully!', 'success');
431
- if (result.path) {
432
- console.log('Photo saved to:', result.path);
433
- }
434
- } else if (result.reason === 'canceled') {
435
- this.showStatus('Save canceled', 'info');
436
- } else {
437
- this.showStatus('Failed to save photo', 'error');
438
- }
439
- } catch (error) {
440
- console.error('Error saving photo:', error);
441
- this.showStatus('Error saving photo', 'error');
442
- }
443
- }
444
-
445
- private deleteCurrentPhoto() {
446
- if (!this.currentPhotoId) return;
447
-
448
- const photoIndex = this.photos.findIndex(p => p.id === this.currentPhotoId);
449
- if (photoIndex === -1) return;
450
-
451
- // Remove from array
452
- this.photos.splice(photoIndex, 1);
453
-
454
- // Remove from DOM
455
- const photoElement = this.gallery.querySelector(`[data-photo-id="${this.currentPhotoId}"]`);
456
- if (photoElement) {
457
- photoElement.remove();
458
- }
459
-
460
- // Show empty state if no photos left
461
- if (this.photos.length === 0) {
462
- this.gallery.innerHTML = `
463
- <div class="empty-state">
464
- No photos/screenshots yet. Take some photos or screenshots to get started!
465
- </div>
466
- `;
467
- }
468
-
469
- this.closeModal();
470
- this.showStatus('Photo deleted', 'info');
471
- }
472
-
473
- private setStatus(message: string, active: boolean, error: boolean = false) {
474
- this.statusText.textContent = message;
475
- this.status.classList.toggle('active', active && !error);
476
- this.status.classList.toggle('error', error);
477
- }
478
-
479
- private showStatus(message: string, type: 'success' | 'error' | 'info') {
480
- console.log(`[${type}] ${message}`);
481
-
482
- // Update status bar temporarily
483
- const originalText = this.statusText.textContent;
484
- const originalClasses = this.status.className;
485
-
486
- this.setStatus(message, type === 'success', type === 'error');
487
-
488
- // Restore original status after 3 seconds
489
- setTimeout(() => {
490
- this.statusText.textContent = originalText;
491
- this.status.className = originalClasses;
492
- }, 3000);
493
- }
494
- }
495
-
496
- // Initialize the app when DOM is loaded
497
- document.addEventListener('DOMContentLoaded', () => {
498
- new PhotoBooth();
499
- });
@@ -1,26 +0,0 @@
1
- import { BrowserWindow } from "./src/bun/core/BrowserWindow";
2
-
3
- const win = new BrowserWindow({
4
- title: "New Window Event Test",
5
- frame: {
6
- width: 800,
7
- height: 600,
8
- x: 100,
9
- y: 100
10
- },
11
- url: null,
12
- html: null,
13
- renderer: 'native', // Test with native WebKit first
14
- });
15
-
16
- // Listen for new-window-open events
17
- win.webview.on("new-window-open", (event) => {
18
- console.log("🚀 NEW-WINDOW-OPEN EVENT:", event.detail);
19
- });
20
-
21
- // Load our test HTML
22
- const testHTML = await Bun.file("./test-new-window.html").text();
23
- win.webview.loadHTML(testHTML);
24
-
25
- console.log("Test window created. Try clicking links with and without CMD key.");
26
- console.log("Watch for 'NEW-WINDOW-OPEN EVENT' in the console.");
@@ -1,75 +0,0 @@
1
- <!DOCTYPE html>
2
- <html>
3
- <head>
4
- <title>New Window Event Test</title>
5
- <style>
6
- body {
7
- font-family: system-ui;
8
- padding: 20px;
9
- max-width: 600px;
10
- margin: 0 auto;
11
- }
12
- a, button {
13
- display: block;
14
- margin: 15px 0;
15
- padding: 10px;
16
- background: #f0f0f0;
17
- text-decoration: none;
18
- color: #333;
19
- border: 1px solid #ddd;
20
- cursor: pointer;
21
- }
22
- a:hover, button:hover {
23
- background: #e0e0e0;
24
- }
25
- h2 {
26
- color: #444;
27
- border-bottom: 2px solid #ddd;
28
- padding-bottom: 10px;
29
- }
30
- .note {
31
- background: #fffbdd;
32
- padding: 10px;
33
- border-left: 4px solid #ffc107;
34
- margin: 20px 0;
35
- }
36
- </style>
37
- </head>
38
- <body>
39
- <h1>Test New Window Events</h1>
40
-
41
- <div class="note">
42
- <strong>Instructions:</strong> Open the console and watch for "new-window-open" events.
43
- Try each link/button below with and without holding CMD key.
44
- </div>
45
-
46
- <h2>Links that SHOULD fire new-window-open:</h2>
47
- <a href="https://example.com" target="_blank">1. Link with target="_blank"</a>
48
- <a href="https://example.com" target="newwindow">2. Link with target="newwindow"</a>
49
- <button onclick="window.open('https://example.com', '_blank')">3. JavaScript window.open()</button>
50
-
51
- <h2>Links that should NOT fire (without CMD):</h2>
52
- <a href="https://example.com">4. Regular link (no target)</a>
53
- <a href="https://example.com" target="_self">5. Link with target="_self"</a>
54
-
55
- <h2>CMD+Click Test:</h2>
56
- <p>Hold CMD and click this to see if it fires the event:</p>
57
- <a href="https://example.com">6. CMD+Click me (regular link)</a>
58
-
59
- <script>
60
- // Log all clicks for debugging
61
- document.addEventListener('click', (e) => {
62
- if (e.target.tagName === 'A') {
63
- console.log('Link clicked:', {
64
- href: e.target.href,
65
- target: e.target.target,
66
- cmdKey: e.metaKey,
67
- ctrlKey: e.ctrlKey,
68
- shiftKey: e.shiftKey,
69
- altKey: e.altKey
70
- });
71
- }
72
- });
73
- </script>
74
- </body>
75
- </html>
@@ -1,34 +0,0 @@
1
- #!/bin/bash
2
-
3
- # Test npm installation locally
4
- echo "Testing Electrobun npm installation..."
5
-
6
- # Create a temporary test directory
7
- TEST_DIR=$(mktemp -d)
8
- cd $TEST_DIR
9
-
10
- echo "Test directory: $TEST_DIR"
11
-
12
- # Initialize a test project
13
- npm init -y
14
-
15
- # Set environment variable to use specific version
16
- export ELECTROBUN_VERSION=v0.0.19-beta.1
17
-
18
- # Install electrobun (will use local package.json)
19
- npm install file:///home/yoav/code/electrobun
20
-
21
- # Check if installation worked
22
- if [ -f "node_modules/electrobun/dist/electrobun" ]; then
23
- echo "✓ Electrobun CLI installed successfully"
24
- ./node_modules/.bin/electrobun --version
25
- else
26
- echo "✗ Electrobun CLI not found"
27
- fi
28
-
29
- # List installed files
30
- echo -e "\nInstalled files:"
31
- find node_modules/electrobun -type f -name "*.ts" | head -10
32
- find node_modules/electrobun/dist -type f | head -10
33
-
34
- echo -e "\nTest complete. Directory: $TEST_DIR"
package/tests/bun.lock DELETED
@@ -1,14 +0,0 @@
1
- {
2
- "lockfileVersion": 1,
3
- "workspaces": {
4
- "": {
5
- "name": "electrobun-tests",
6
- "dependencies": {
7
- "electrobun": "file:..",
8
- },
9
- },
10
- },
11
- "packages": {
12
- "electrobun": ["..@file:..", { "bin": { "electrobun": "bin/electrobun.cjs" } }],
13
- }
14
- }
@@ -1,45 +0,0 @@
1
- export default {
2
- app: {
3
- name: "Electrobun Test Harness",
4
- identifier: "dev.electrobun.tests",
5
- version: "1.0.0",
6
- },
7
- build: {
8
- bun: {
9
- entrypoint: "src/bun/index.ts",
10
- external: [],
11
- },
12
- views: {
13
- mainview: {
14
- entrypoint: "src/mainview/index.ts",
15
- external: [],
16
- },
17
- webviewtag: {
18
- entrypoint: "src/webviewtag/index.ts",
19
- external: [],
20
- },
21
- },
22
- copy: {
23
- "src/mainview/index.html": "views/mainview/index.html",
24
- "src/mainview/styles/main.css": "views/mainview/styles/main.css",
25
- "src/testviews/window-create.html": "views/testviews/window-create.html",
26
- "src/testviews/window-events.html": "views/testviews/window-events.html",
27
- "src/testviews/webview-mask.html": "views/testviews/webview-mask.html",
28
- "src/testviews/webview-navigation.html": "views/testviews/webview-navigation.html",
29
- "src/testviews/tray-test.html": "views/testviews/tray-test.html",
30
- "src/testviews/window-focus.html": "views/testviews/window-focus.html",
31
- },
32
- mac: {
33
- codesign: false,
34
- notarize: false,
35
- bundleCEF: true,
36
- entitlements: {},
37
- },
38
- linux: {
39
- bundleCEF: true,
40
- },
41
- win: {
42
- bundleCEF: true,
43
- },
44
- },
45
- };