mirinjs 0.0.1-alpha.3 → 0.0.1-alpha.5
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/package.json +1 -1
- package/src/app.ts +42 -1
- package/src/config.ts +9 -0
- package/src/index.ts +1 -0
- package/src/native.ts +5 -0
- package/src/runtime.ts +7 -2
package/package.json
CHANGED
package/src/app.ts
CHANGED
|
@@ -32,6 +32,14 @@ export type AppEvents = {
|
|
|
32
32
|
"window-all-closed": void;
|
|
33
33
|
};
|
|
34
34
|
|
|
35
|
+
/** A window's frame in screen points (bottom-left origin, like AppKit). */
|
|
36
|
+
export interface WindowFrame {
|
|
37
|
+
x: number;
|
|
38
|
+
y: number;
|
|
39
|
+
width: number;
|
|
40
|
+
height: number;
|
|
41
|
+
}
|
|
42
|
+
|
|
35
43
|
type Listener<P> = (payload: P) => void;
|
|
36
44
|
|
|
37
45
|
class Emitter<Events extends Record<string, unknown>> {
|
|
@@ -127,6 +135,31 @@ export class WindowHandle extends Emitter<WindowEvents> {
|
|
|
127
135
|
runtime().core.windowSetMaterial(this.id, JSON.stringify(normalizeMaterial(material)));
|
|
128
136
|
}
|
|
129
137
|
|
|
138
|
+
/** Move the window's bottom-left origin to screen point (x, y), in points. */
|
|
139
|
+
setPosition(x: number, y: number): void {
|
|
140
|
+
runtime().core.windowSetPosition(this.id, x, y);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/** The latest known window frame (screen points, bottom-left origin). Tracked
|
|
144
|
+
* from `moved`/`resized` events, so it's current without a round-trip. */
|
|
145
|
+
getFrame(): WindowFrame {
|
|
146
|
+
return this.#frame ?? { x: 0, y: 0, width: 0, height: 0 };
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** Whether the window is currently zoomed (maximized). */
|
|
150
|
+
isMaximized(): boolean {
|
|
151
|
+
return this.#maximized;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
#frame: WindowFrame | null = null;
|
|
155
|
+
#maximized = false;
|
|
156
|
+
|
|
157
|
+
/** @internal — fed from native window frame events. */
|
|
158
|
+
_setFrame(frame: WindowFrame, maximized: boolean): void {
|
|
159
|
+
this.#frame = frame;
|
|
160
|
+
this.#maximized = maximized;
|
|
161
|
+
}
|
|
162
|
+
|
|
130
163
|
#control(verb: string): void {
|
|
131
164
|
runtime().core.windowControl(this.id, verb);
|
|
132
165
|
}
|
|
@@ -322,7 +355,15 @@ export function wireAppEvents(): void {
|
|
|
322
355
|
for (const kind of WINDOW_EVENTS) {
|
|
323
356
|
onNativeEvent(`window.${kind}`, (event: NativeEvent) => {
|
|
324
357
|
const id = event.id as number | undefined;
|
|
325
|
-
if (id
|
|
358
|
+
if (id == null) return;
|
|
359
|
+
const handle = app.windows._byId(id);
|
|
360
|
+
if (!handle) return;
|
|
361
|
+
// moved/resized carry the current frame + maximized state; track them so
|
|
362
|
+
// getFrame()/isMaximized() are answerable without a round-trip.
|
|
363
|
+
if (event.frame) {
|
|
364
|
+
handle._setFrame(event.frame as WindowFrame, Boolean(event.maximized));
|
|
365
|
+
}
|
|
366
|
+
handle._emit(kind, undefined);
|
|
326
367
|
});
|
|
327
368
|
}
|
|
328
369
|
}
|
package/src/config.ts
CHANGED
|
@@ -42,6 +42,9 @@ export interface WindowConfig {
|
|
|
42
42
|
title?: string;
|
|
43
43
|
width?: number;
|
|
44
44
|
height?: number;
|
|
45
|
+
/** Screen position (bottom-left origin, points). Centered when absent. */
|
|
46
|
+
x?: number;
|
|
47
|
+
y?: number;
|
|
45
48
|
/** "ready" (default) shows on first paint to avoid a white flash. */
|
|
46
49
|
show?: "ready" | "immediately";
|
|
47
50
|
/** "auto" (default) opens at launch; "manual" windows are templates for app.windows.open(name). */
|
|
@@ -70,6 +73,12 @@ export interface MirinConfig {
|
|
|
70
73
|
name: string;
|
|
71
74
|
/** Main-process entry, relative to the project root (runs in the Bun Worker). */
|
|
72
75
|
main: string;
|
|
76
|
+
/**
|
|
77
|
+
* App icon, relative to the project root (macOS). Accepts a `.icns`, a
|
|
78
|
+
* `.iconset` directory, or a single square `.png` (≥512px) that mirin renders
|
|
79
|
+
* into an `.icns`. Embedded in the bundle for the Dock and Finder.
|
|
80
|
+
*/
|
|
81
|
+
icon?: string;
|
|
73
82
|
windows: Record<string, WindowConfig>;
|
|
74
83
|
}
|
|
75
84
|
|
package/src/index.ts
CHANGED
package/src/native.ts
CHANGED
|
@@ -23,6 +23,7 @@ const symbols = {
|
|
|
23
23
|
mirin_window_set_title: { args: [FFIType.u32, FFIType.ptr], returns: FFIType.void },
|
|
24
24
|
mirin_window_control: { args: [FFIType.u32, FFIType.ptr], returns: FFIType.void },
|
|
25
25
|
mirin_window_set_material: { args: [FFIType.u32, FFIType.ptr], returns: FFIType.void },
|
|
26
|
+
mirin_window_set_position: { args: [FFIType.u32, FFIType.f64, FFIType.f64], returns: FFIType.void },
|
|
26
27
|
mirin_app_quit: { args: [], returns: FFIType.void },
|
|
27
28
|
mirin_app_set_dock_visible: { args: [FFIType.i32], returns: FFIType.void },
|
|
28
29
|
mirin_set_app_menu: { args: [FFIType.ptr], returns: FFIType.void },
|
|
@@ -108,6 +109,10 @@ export class Core {
|
|
|
108
109
|
this.#lib.symbols.mirin_window_set_material(id, ptr(buf));
|
|
109
110
|
}
|
|
110
111
|
|
|
112
|
+
windowSetPosition(id: number, x: number, y: number): void {
|
|
113
|
+
this.#lib.symbols.mirin_window_set_position(id, x, y);
|
|
114
|
+
}
|
|
115
|
+
|
|
111
116
|
quit(): void {
|
|
112
117
|
this.#lib.symbols.mirin_app_quit();
|
|
113
118
|
}
|
package/src/runtime.ts
CHANGED
|
@@ -35,9 +35,14 @@ export function runtime(): Runtime {
|
|
|
35
35
|
return current;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
/** Dev: every window loads the Vite server. Production: its manifest app:// URL.
|
|
38
|
+
/** Dev: every window loads the Vite server. Production: its manifest app:// URL.
|
|
39
|
+
* Any query/hash on the requested URL (e.g. "#devtools") is preserved so
|
|
40
|
+
* hash-routed sub-windows reach the right view through the dev server too. */
|
|
39
41
|
export function resolveUrl(url: string): string {
|
|
40
|
-
|
|
42
|
+
const devUrl = current?.devUrl;
|
|
43
|
+
if (!devUrl) return url;
|
|
44
|
+
const suffix = url.match(/[?#].*$/)?.[0] ?? "";
|
|
45
|
+
return devUrl + suffix;
|
|
41
46
|
}
|
|
42
47
|
|
|
43
48
|
// ---- native event dispatch ----
|