@zappdev/runtime 0.1.0 → 0.6.0-alpha.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.
package/windows.ts DELETED
@@ -1,222 +0,0 @@
1
- import { Events, WindowEvent, getWindowEventName, type WindowEventPayload, type WindowSizeEventPayload } from "./events";
2
-
3
- /** Options for creating a new window. */
4
- export interface WindowOptions {
5
- /** Window title text. */
6
- title?: string;
7
- /** Initial width in logical pixels. */
8
- width?: number;
9
- /** Initial height in logical pixels. */
10
- height?: number;
11
- /** Initial x position on screen. */
12
- x?: number;
13
- /** Initial y position on screen. */
14
- y?: number;
15
- /** URL to load in the window. */
16
- url?: string;
17
- /** Whether the window can be resized by the user. */
18
- resizable?: boolean;
19
- /** Whether the window shows a close button. */
20
- closable?: boolean;
21
- /** Whether the window can be minimized. */
22
- minimizable?: boolean;
23
- /** Whether the window can be maximized. */
24
- maximizable?: boolean;
25
- /** Whether the window starts in fullscreen. */
26
- fullscreen?: boolean;
27
- /** Whether the window floats above other windows. */
28
- alwaysOnTop?: boolean;
29
- /** Title bar appearance style. */
30
- titleBarStyle?: "default" | "hidden" | "hiddenInset";
31
- /** Whether the window is visible on creation. */
32
- visible?: boolean;
33
- }
34
-
35
- /** Window events that carry size + position */
36
- type SizeEvent =
37
- | WindowEvent.RESIZE
38
- | WindowEvent.MOVE
39
- | WindowEvent.MAXIMIZE
40
- | WindowEvent.RESTORE;
41
-
42
- /** Handle for controlling an individual window instance. */
43
- export type WindowHandle = {
44
- /** Unique identifier for this window. */
45
- readonly id: string;
46
- /** Show the window. */
47
- show(): void;
48
- /** Hide the window. */
49
- hide(): void;
50
- /** Minimize the window. */
51
- minimize(): void;
52
- /** Maximize the window. */
53
- maximize(): void;
54
- /** Restore the window from minimized state. */
55
- unminimize(): void;
56
- /** Restore the window from maximized state. */
57
- unmaximize(): void;
58
- /** Toggle between minimized and restored. */
59
- toggleMinimize(): void;
60
- /** Toggle between maximized and restored. */
61
- toggleMaximize(): void;
62
- /** Request the window to close (may be intercepted by close guards). */
63
- close(): void;
64
- /** Set the window title. */
65
- setTitle(title: string): void;
66
- /** Set the window size in logical pixels. */
67
- setSize(width: number, height: number): void;
68
- /** Set the window position on screen. */
69
- setPosition(x: number, y: number): void;
70
- /** Enter or exit fullscreen mode. */
71
- setFullscreen(on: boolean): void;
72
- /** Set whether the window floats above other windows. */
73
- setAlwaysOnTop(on: boolean): void;
74
- /** Force-close the window, bypassing all close guards */
75
- destroy(): void;
76
- /** Typed event listener — size events get a payload with size + position */
77
- on(event: SizeEvent, handler: (payload: WindowSizeEventPayload) => void): () => void;
78
- /** Typed event listener — other window events get base payload */
79
- on(event: WindowEvent, handler: (payload: WindowEventPayload) => void): () => void;
80
- /** Typed one-time listener — size events */
81
- once(event: SizeEvent, handler: (payload: WindowSizeEventPayload) => void): () => void;
82
- /** Typed one-time listener — other window events */
83
- once(event: WindowEvent, handler: (payload: WindowEventPayload) => void): () => void;
84
- /** Remove all listeners for an event */
85
- off(event: WindowEvent): void;
86
- };
87
-
88
- type WindowBridge = {
89
- windowCreate?: (options: WindowOptions) => Promise<{ id: string }>;
90
- windowAction?: (windowId: string, action: string, params?: Record<string, unknown>) => void;
91
- };
92
-
93
- const getBridge = (): WindowBridge | null =>
94
- ((globalThis as unknown as Record<symbol, unknown>)[
95
- Symbol.for("zapp.bridge")
96
- ] as WindowBridge | undefined) ?? null;
97
-
98
- function makeHandle(windowId: string): WindowHandle {
99
- const action = (name: string, params?: Record<string, unknown>) => {
100
- const bridge = getBridge();
101
- bridge?.windowAction?.(windowId, name, params);
102
- };
103
-
104
- const isWindowReady = (): boolean => {
105
- const ss = globalThis as unknown as Record<symbol, unknown>;
106
- return ss[Symbol.for("zapp.windowReady")] === true;
107
- };
108
-
109
- let closeListenerCount = 0;
110
-
111
- const handleOn = (event: WindowEvent, handler: (payload: WindowEventPayload) => void): (() => void) => {
112
- const eventName = getWindowEventName(event);
113
- const off = Events.on(`window:${eventName}`, (payload) => {
114
- const p = payload as WindowEventPayload | undefined;
115
- if (p?.windowId === windowId) {
116
- handler(p);
117
- }
118
- });
119
-
120
- // Auto-guard: registering a CLOSE listener enables the native close guard
121
- if (event === WindowEvent.CLOSE) {
122
- closeListenerCount++;
123
- if (closeListenerCount === 1) {
124
- action("setCloseGuard", { guard: true });
125
- }
126
- }
127
-
128
- if (event === WindowEvent.READY && isWindowReady()) {
129
- queueMicrotask(() => handler({ windowId, timestamp: Date.now() }));
130
- }
131
-
132
- // Return unsubscribe that also manages the close guard
133
- return () => {
134
- off();
135
- if (event === WindowEvent.CLOSE) {
136
- closeListenerCount--;
137
- if (closeListenerCount <= 0) {
138
- closeListenerCount = 0;
139
- action("setCloseGuard", { guard: false });
140
- }
141
- }
142
- };
143
- };
144
-
145
- const handleOnce = (event: WindowEvent, handler: (payload: WindowEventPayload) => void): (() => void) => {
146
- if (event === WindowEvent.READY && isWindowReady()) {
147
- queueMicrotask(() => handler({ windowId, timestamp: Date.now() }));
148
- return () => {};
149
- }
150
- const eventName = getWindowEventName(event);
151
- return Events.once(`window:${eventName}`, (payload) => {
152
- const p = payload as WindowEventPayload | undefined;
153
- if (p?.windowId === windowId) {
154
- handler(p);
155
- }
156
- });
157
- };
158
-
159
- const handleOff: WindowHandle["off"] = (event: WindowEvent) => {
160
- const eventName = getWindowEventName(event);
161
- Events.off(`window:${eventName}`);
162
- };
163
-
164
- return {
165
- get id() { return windowId; },
166
- show() { action("show"); },
167
- hide() { action("hide"); },
168
- minimize() { action("minimize"); },
169
- maximize() { action("maximize"); },
170
- unminimize() { action("unminimize"); },
171
- unmaximize() { action("unmaximize"); },
172
- toggleMinimize() { action("toggle_minimize"); },
173
- toggleMaximize() { action("toggle_maximize"); },
174
- close() { action("close"); },
175
- destroy() { action("destroy"); },
176
- setTitle(title: string) { action("set_title", { title }); },
177
- setSize(width: number, height: number) { action("set_size", { width, height }); },
178
- setPosition(x: number, y: number) { action("set_position", { x, y }); },
179
- setFullscreen(on: boolean) { action("set_fullscreen", { on }); },
180
- setAlwaysOnTop(on: boolean) { action("set_always_on_top", { on }); },
181
- on: handleOn as WindowHandle["on"],
182
- once: handleOnce as WindowHandle["once"],
183
- off: handleOff,
184
- };
185
- }
186
-
187
- /** API for creating and accessing windows. */
188
- export interface WindowAPI {
189
- /** Create a new window with the given options. */
190
- create(options?: WindowOptions): Promise<WindowHandle>;
191
- /** Get a handle to the current webview's window. Throws in worker contexts. */
192
- current(): WindowHandle;
193
- }
194
-
195
- /** The singleton window management API instance. */
196
- export const Window: WindowAPI = {
197
- async create(options: WindowOptions = {}): Promise<WindowHandle> {
198
- const bridge = getBridge();
199
- if (!bridge?.windowCreate) {
200
- throw new Error("Window bridge unavailable. Is the Zapp runtime loaded?");
201
- }
202
- const result = await bridge.windowCreate(options);
203
- return makeHandle(result.id);
204
- },
205
-
206
- current(): WindowHandle {
207
- const symbolStore = globalThis as unknown as Record<symbol, unknown>;
208
- if (symbolStore[Symbol.for("zapp.context")] === "worker") {
209
- throw new Error("Window.current() is not available in a worker context. Use Window.create() instead.");
210
- }
211
- const windowId = symbolStore[Symbol.for("zapp.windowId")] as string | undefined;
212
- const ownerId = symbolStore[Symbol.for("zapp.ownerId")] as string | undefined;
213
- const contextWindowId = symbolStore[Symbol.for("zapp.currentWindowId")] as string | undefined;
214
- const id = windowId ?? contextWindowId ?? ownerId;
215
- if (!id) {
216
- throw new Error(
217
- "Window.current() is only available in a webview context with an associated window.",
218
- );
219
- }
220
- return makeHandle(id);
221
- },
222
- };