@flighthq/tray 0.3.1-next.975.01aea94 → 0.4.0-edge.1908.751021c
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/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/tray.d.ts +5 -1
- package/dist/tray.d.ts.map +1 -1
- package/dist/tray.js +108 -78
- package/dist/tray.js.map +1 -1
- package/package.json +3 -3
- package/src/tray.test.ts +116 -36
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { disableTrayGuards, enableTrayGuards, createTrayIcon, destroyTrayIcon, displayTrayBalloon, getTrayCapabilities, getTrayIconBounds, getTrayIconTitle, getTrayIconTooltip, getTrayIcons, isTrayDestroyed, isTrayIconAnimating, onTrayEvent, popupTrayContextMenu, removeTrayBalloon, setTrayIcon, setTrayIconContextMenu, setTrayIconTemplate, setTrayIconTitle, setTrayIconTooltip, setTrayIgnoreDoubleClickEvents, setTrayPressedIcon, startTrayIconAnimation, stopTrayIconAnimation, } from './contract';
|
|
1
|
+
export { disableTrayGuards, enableTrayGuards, createTrayIcon, destroyTrayIcon, displayTrayBalloon, explainTrayBackend, getTrayCapabilities, getTrayIconBounds, getTrayIconTitle, getTrayIconTooltip, getTrayIcons, isTrayDestroyed, isTrayIconAnimating, onTrayEvent, popupTrayContextMenu, removeTrayBalloon, setTrayIcon, setTrayIconContextMenu, setTrayIconTemplate, setTrayIconTitle, setTrayIconTooltip, setTrayIgnoreDoubleClickEvents, setTrayPressedIcon, startTrayIconAnimation, stopTrayIconAnimation, } from './contract';
|
|
2
2
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,cAAc,EACd,eAAe,EACf,kBAAkB,EAClB,mBAAmB,EACnB,iBAAiB,EACjB,gBAAgB,EAChB,kBAAkB,EAClB,YAAY,EACZ,eAAe,EACf,mBAAmB,EACnB,WAAW,EACX,oBAAoB,EACpB,iBAAiB,EACjB,WAAW,EACX,sBAAsB,EACtB,mBAAmB,EACnB,gBAAgB,EAChB,kBAAkB,EAClB,8BAA8B,EAC9B,kBAAkB,EAClB,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,cAAc,EACd,eAAe,EACf,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,EACnB,iBAAiB,EACjB,gBAAgB,EAChB,kBAAkB,EAClB,YAAY,EACZ,eAAe,EACf,mBAAmB,EACnB,WAAW,EACX,oBAAoB,EACpB,iBAAiB,EACjB,WAAW,EACX,sBAAsB,EACtB,mBAAmB,EACnB,gBAAgB,EAChB,kBAAkB,EAClB,8BAA8B,EAC9B,kBAAkB,EAClB,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { disableTrayGuards, enableTrayGuards, createTrayIcon, destroyTrayIcon, displayTrayBalloon, getTrayCapabilities, getTrayIconBounds, getTrayIconTitle, getTrayIconTooltip, getTrayIcons, isTrayDestroyed, isTrayIconAnimating, onTrayEvent, popupTrayContextMenu, removeTrayBalloon, setTrayIcon, setTrayIconContextMenu, setTrayIconTemplate, setTrayIconTitle, setTrayIconTooltip, setTrayIgnoreDoubleClickEvents, setTrayPressedIcon, startTrayIconAnimation, stopTrayIconAnimation, } from './contract';
|
|
1
|
+
export { disableTrayGuards, enableTrayGuards, createTrayIcon, destroyTrayIcon, displayTrayBalloon, explainTrayBackend, getTrayCapabilities, getTrayIconBounds, getTrayIconTitle, getTrayIconTooltip, getTrayIcons, isTrayDestroyed, isTrayIconAnimating, onTrayEvent, popupTrayContextMenu, removeTrayBalloon, setTrayIcon, setTrayIconContextMenu, setTrayIconTemplate, setTrayIconTitle, setTrayIconTooltip, setTrayIgnoreDoubleClickEvents, setTrayPressedIcon, startTrayIconAnimation, stopTrayIconAnimation, } from './contract';
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,cAAc,EACd,eAAe,EACf,kBAAkB,EAClB,mBAAmB,EACnB,iBAAiB,EACjB,gBAAgB,EAChB,kBAAkB,EAClB,YAAY,EACZ,eAAe,EACf,mBAAmB,EACnB,WAAW,EACX,oBAAoB,EACpB,iBAAiB,EACjB,WAAW,EACX,sBAAsB,EACtB,mBAAmB,EACnB,gBAAgB,EAChB,kBAAkB,EAClB,8BAA8B,EAC9B,kBAAkB,EAClB,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,cAAc,EACd,eAAe,EACf,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,EACnB,iBAAiB,EACjB,gBAAgB,EAChB,kBAAkB,EAClB,YAAY,EACZ,eAAe,EACf,mBAAmB,EACnB,WAAW,EACX,oBAAoB,EACpB,iBAAiB,EACjB,WAAW,EACX,sBAAsB,EACtB,mBAAmB,EACnB,gBAAgB,EAChB,kBAAkB,EAClB,8BAA8B,EAC9B,kBAAkB,EAClB,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,YAAY,CAAC"}
|
package/dist/tray.d.ts
CHANGED
|
@@ -1,20 +1,24 @@
|
|
|
1
|
+
import type { BackendExplanation } from '@flighthq/types/contract';
|
|
1
2
|
import type { MenuItemTemplate, RectangleLike, TrayBackend, TrayBalloonOptions, TrayCapabilities, TrayEventData, TrayIcon, TrayIconOptions } from '@flighthq/types/contract';
|
|
2
3
|
import type { Vector2Like } from '@flighthq/types/contract';
|
|
3
4
|
export declare function createTrayIcon(options?: Readonly<TrayIconOptions>): TrayIcon | null;
|
|
4
|
-
export declare function createWebTrayBackend(): TrayBackend;
|
|
5
5
|
export declare function destroyTrayIcon(tray: TrayIcon): void;
|
|
6
6
|
export declare function displayTrayBalloon(tray: TrayIcon, options: Readonly<TrayBalloonOptions>): void;
|
|
7
|
+
export declare function explainTrayBackend(): BackendExplanation;
|
|
7
8
|
export declare function getTrayBackend(): TrayBackend;
|
|
8
9
|
export declare function getTrayCapabilities(): Readonly<TrayCapabilities>;
|
|
9
10
|
export declare function getTrayIconBounds(tray: TrayIcon): Readonly<RectangleLike> | null;
|
|
10
11
|
export declare function getTrayIcons(): readonly TrayIcon[];
|
|
11
12
|
export declare function getTrayIconTitle(tray: TrayIcon): string;
|
|
12
13
|
export declare function getTrayIconTooltip(tray: TrayIcon): string;
|
|
14
|
+
export declare function installTrayHostBackend(backend: TrayBackend): void;
|
|
13
15
|
export declare function isTrayDestroyed(tray: TrayIcon): boolean;
|
|
14
16
|
export declare function isTrayIconAnimating(tray: TrayIcon): boolean;
|
|
17
|
+
export declare function observeTrayHostResult(operation: string, succeeded: boolean): void;
|
|
15
18
|
export declare function onTrayEvent(listener: (event: Readonly<TrayEventData>) => void): () => void;
|
|
16
19
|
export declare function popupTrayContextMenu(tray: TrayIcon, position?: Readonly<Vector2Like>): void;
|
|
17
20
|
export declare function removeTrayBalloon(tray: TrayIcon): void;
|
|
21
|
+
export declare function resetTrayBackendForTest(): void;
|
|
18
22
|
/** Installs the tray guard, or clears it with `null`. The seam exists so the messages and the
|
|
19
23
|
* `@flighthq/log` dependency live in the separately-importable guard module rather than here; not
|
|
20
24
|
* importing that module costs production nothing. Called by `enableTrayGuards`, not directly. */
|
package/dist/tray.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tray.d.ts","sourceRoot":"","sources":["../src/tray.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,gBAAgB,EAChB,aAAa,EACb,WAAW,EACX,kBAAkB,EAClB,gBAAgB,EAChB,aAAa,EACb,QAAQ,EACR,eAAe,EAChB,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAgB5D,wBAAgB,cAAc,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,eAAe,CAAC,GAAG,QAAQ,GAAG,IAAI,CAGnF;
|
|
1
|
+
{"version":3,"file":"tray.d.ts","sourceRoot":"","sources":["../src/tray.ts"],"names":[],"mappings":"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"}
|
package/dist/tray.js
CHANGED
|
@@ -15,77 +15,6 @@ export function createTrayIcon(options) {
|
|
|
15
15
|
const id = getTrayBackend().create(options ?? {});
|
|
16
16
|
return id < 0 ? null : { id };
|
|
17
17
|
}
|
|
18
|
-
// Builds the default web backend. Web has no system tray, so create returns -1 and the tray mutators
|
|
19
|
-
// are no-ops — a native host (Electron's Tray, Tauri) is required for the tray icon itself. (The
|
|
20
|
-
// application/dock badge lives in @flighthq/app's setAppBadgeCount, not here.)
|
|
21
|
-
export function createWebTrayBackend() {
|
|
22
|
-
return {
|
|
23
|
-
create() {
|
|
24
|
-
// No tray on web. -1 signals "unsupported"; createTrayIcon maps it to null.
|
|
25
|
-
return -1;
|
|
26
|
-
},
|
|
27
|
-
destroy() {
|
|
28
|
-
// No-op: web has no tray icon to destroy.
|
|
29
|
-
},
|
|
30
|
-
displayBalloon() {
|
|
31
|
-
// No-op: balloon notifications require a native host (Windows only).
|
|
32
|
-
},
|
|
33
|
-
getBounds() {
|
|
34
|
-
// No tray on web; null signals unavailable.
|
|
35
|
-
return null;
|
|
36
|
-
},
|
|
37
|
-
getCapabilities() {
|
|
38
|
-
return WEB_CAPABILITIES;
|
|
39
|
-
},
|
|
40
|
-
getTitle() {
|
|
41
|
-
// No tray on web.
|
|
42
|
-
return '';
|
|
43
|
-
},
|
|
44
|
-
getTooltip() {
|
|
45
|
-
// No tray on web.
|
|
46
|
-
return '';
|
|
47
|
-
},
|
|
48
|
-
isDestroyed() {
|
|
49
|
-
// No tray icons exist on web; treat every id as destroyed.
|
|
50
|
-
return true;
|
|
51
|
-
},
|
|
52
|
-
listIds() {
|
|
53
|
-
// No tray icons exist on web.
|
|
54
|
-
return [];
|
|
55
|
-
},
|
|
56
|
-
popUpContextMenu() {
|
|
57
|
-
// No-op: web has no context menu to pop up.
|
|
58
|
-
},
|
|
59
|
-
removeBalloon() {
|
|
60
|
-
// No-op: balloon notifications require a native host (Windows only).
|
|
61
|
-
},
|
|
62
|
-
setContextMenu() {
|
|
63
|
-
// No-op: web has no tray icon — a native host (Electron/Tauri) is required.
|
|
64
|
-
},
|
|
65
|
-
setIcon() {
|
|
66
|
-
// No-op: web has no tray icon to update.
|
|
67
|
-
},
|
|
68
|
-
setIgnoreDoubleClickEvents() {
|
|
69
|
-
// No-op: web has no tray icon double-click behavior to configure.
|
|
70
|
-
},
|
|
71
|
-
setPressedIcon() {
|
|
72
|
-
// No-op: web has no tray icon; pressed icon is macOS-specific.
|
|
73
|
-
},
|
|
74
|
-
setTemplate() {
|
|
75
|
-
// No-op: template images are a macOS menu-bar concept; irrelevant on web.
|
|
76
|
-
},
|
|
77
|
-
setTitle() {
|
|
78
|
-
// No-op: web has no tray icon to update.
|
|
79
|
-
},
|
|
80
|
-
setTooltip() {
|
|
81
|
-
// No-op: web has no tray icon to update.
|
|
82
|
-
},
|
|
83
|
-
subscribe() {
|
|
84
|
-
// No tray on web — a native host (Electron/Tauri) is required to emit tray events.
|
|
85
|
-
return () => { };
|
|
86
|
-
},
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
18
|
// Destroys a tray icon and frees its host resource. No-op when the host has no tray.
|
|
90
19
|
// Any icon animation running on this tray is stopped first: the interval writes through setTrayIcon,
|
|
91
20
|
// and left running it would keep calling into a resource the host has freed — forever, since the
|
|
@@ -100,11 +29,23 @@ export function destroyTrayIcon(tray) {
|
|
|
100
29
|
export function displayTrayBalloon(tray, options) {
|
|
101
30
|
getTrayBackend().displayBalloon(tray.id, options);
|
|
102
31
|
}
|
|
103
|
-
|
|
32
|
+
export function explainTrayBackend() {
|
|
33
|
+
if (_custom !== null) {
|
|
34
|
+
return { conflict: _hostConflict, layer: 'custom', operation: null, viability: 'unobserved' };
|
|
35
|
+
}
|
|
36
|
+
if (_host !== null) {
|
|
37
|
+
return {
|
|
38
|
+
conflict: _hostConflict,
|
|
39
|
+
layer: 'host',
|
|
40
|
+
operation: _hostObservation !== null ? _hostObservation.operation : null,
|
|
41
|
+
viability: _hostObservation !== null ? _hostObservation.viability : 'unobserved',
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
return { conflict: false, layer: 'host-not-enabled', operation: null, viability: 'unobserved' };
|
|
45
|
+
}
|
|
46
|
+
// The active tray backend. Precedence: custom > host > sentinel.
|
|
104
47
|
export function getTrayBackend() {
|
|
105
|
-
|
|
106
|
-
_backend = createWebTrayBackend();
|
|
107
|
-
return _backend;
|
|
48
|
+
return _custom ?? _host ?? _sentinel;
|
|
108
49
|
}
|
|
109
50
|
// Returns the capability flags for the active tray backend. Use before calling APIs that may
|
|
110
51
|
// silently no-op — for example, check capabilities.balloon before displayTrayBalloon, or
|
|
@@ -131,6 +72,14 @@ export function getTrayIconTitle(tray) {
|
|
|
131
72
|
export function getTrayIconTooltip(tray) {
|
|
132
73
|
return getTrayBackend().getTooltip(tray.id);
|
|
133
74
|
}
|
|
75
|
+
export function installTrayHostBackend(backend) {
|
|
76
|
+
if (_host !== null) {
|
|
77
|
+
if (_host !== backend)
|
|
78
|
+
_hostConflict = true;
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
_host = backend;
|
|
82
|
+
}
|
|
134
83
|
// Returns whether a tray icon has been destroyed. Returns true on web (no trays exist).
|
|
135
84
|
// Use this to guard calls after destroyTrayIcon when the tray lifecycle is unclear.
|
|
136
85
|
export function isTrayDestroyed(tray) {
|
|
@@ -141,6 +90,12 @@ export function isTrayDestroyed(tray) {
|
|
|
141
90
|
export function isTrayIconAnimating(tray) {
|
|
142
91
|
return _animations.has(tray.id);
|
|
143
92
|
}
|
|
93
|
+
export function observeTrayHostResult(operation, succeeded) {
|
|
94
|
+
_hostObservation = {
|
|
95
|
+
operation,
|
|
96
|
+
viability: succeeded ? 'available' : 'runtime-api-unavailable',
|
|
97
|
+
};
|
|
98
|
+
}
|
|
144
99
|
// Subscribes to tray icon events, delivering a rich TrayEventData payload (id, type, bounds,
|
|
145
100
|
// position, modifier keys, and drop payloads). Returns an unsubscribe function. On web this
|
|
146
101
|
// never fires (no tray); a native host is required.
|
|
@@ -157,15 +112,21 @@ export function popupTrayContextMenu(tray, position) {
|
|
|
157
112
|
export function removeTrayBalloon(tray) {
|
|
158
113
|
getTrayBackend().removeBalloon(tray.id);
|
|
159
114
|
}
|
|
115
|
+
export function resetTrayBackendForTest() {
|
|
116
|
+
_custom = null;
|
|
117
|
+
_host = null;
|
|
118
|
+
_hostConflict = false;
|
|
119
|
+
_hostObservation = null;
|
|
120
|
+
}
|
|
160
121
|
/** Installs the tray guard, or clears it with `null`. The seam exists so the messages and the
|
|
161
122
|
* `@flighthq/log` dependency live in the separately-importable guard module rather than here; not
|
|
162
123
|
* importing that module costs production nothing. Called by `enableTrayGuards`, not directly. */
|
|
163
124
|
export function setTrayAnimationGuard(guard) {
|
|
164
125
|
_animationGuard = guard;
|
|
165
126
|
}
|
|
166
|
-
// Installs a
|
|
127
|
+
// Installs a custom tray backend; pass null to clear the custom override.
|
|
167
128
|
export function setTrayBackend(backend) {
|
|
168
|
-
|
|
129
|
+
_custom = backend;
|
|
169
130
|
}
|
|
170
131
|
// Sets the image for the tray icon. Accepts the same icon path/data-URI accepted by createTrayIcon.
|
|
171
132
|
// Use this for runtime status updates (indicators, spinners, theme changes).
|
|
@@ -233,7 +194,6 @@ export function startTrayIconAnimation(tray, frames, intervalMs) {
|
|
|
233
194
|
_animations.delete(tray.id);
|
|
234
195
|
};
|
|
235
196
|
}
|
|
236
|
-
let _backend = null;
|
|
237
197
|
// The interval per animating tray id. Module-scoped like the backend, and correct at that scope: an
|
|
238
198
|
// id is the host's, so one id is one icon is one animation.
|
|
239
199
|
const _animations = new Map();
|
|
@@ -250,4 +210,74 @@ export function stopTrayIconAnimation(tray) {
|
|
|
250
210
|
_animations.delete(tray.id);
|
|
251
211
|
}
|
|
252
212
|
let _animationGuard = null;
|
|
213
|
+
let _custom = null;
|
|
214
|
+
let _host = null;
|
|
215
|
+
let _hostConflict = false;
|
|
216
|
+
let _hostObservation = null;
|
|
217
|
+
const _sentinel = {
|
|
218
|
+
create() {
|
|
219
|
+
// No tray on web. -1 signals "unsupported"; createTrayIcon maps it to null.
|
|
220
|
+
return -1;
|
|
221
|
+
},
|
|
222
|
+
destroy() {
|
|
223
|
+
// No-op: web has no tray icon to destroy.
|
|
224
|
+
},
|
|
225
|
+
displayBalloon() {
|
|
226
|
+
// No-op: balloon notifications require a native host (Windows only).
|
|
227
|
+
},
|
|
228
|
+
getBounds() {
|
|
229
|
+
// No tray on web; null signals unavailable.
|
|
230
|
+
return null;
|
|
231
|
+
},
|
|
232
|
+
getCapabilities() {
|
|
233
|
+
return WEB_CAPABILITIES;
|
|
234
|
+
},
|
|
235
|
+
getTitle() {
|
|
236
|
+
// No tray on web.
|
|
237
|
+
return '';
|
|
238
|
+
},
|
|
239
|
+
getTooltip() {
|
|
240
|
+
// No tray on web.
|
|
241
|
+
return '';
|
|
242
|
+
},
|
|
243
|
+
isDestroyed() {
|
|
244
|
+
// No tray icons exist on web; treat every id as destroyed.
|
|
245
|
+
return true;
|
|
246
|
+
},
|
|
247
|
+
listIds() {
|
|
248
|
+
// No tray icons exist on web.
|
|
249
|
+
return [];
|
|
250
|
+
},
|
|
251
|
+
popUpContextMenu() {
|
|
252
|
+
// No-op: web has no context menu to pop up.
|
|
253
|
+
},
|
|
254
|
+
removeBalloon() {
|
|
255
|
+
// No-op: balloon notifications require a native host (Windows only).
|
|
256
|
+
},
|
|
257
|
+
setContextMenu() {
|
|
258
|
+
// No-op: web has no tray icon — a native host (Electron/Tauri) is required.
|
|
259
|
+
},
|
|
260
|
+
setIcon() {
|
|
261
|
+
// No-op: web has no tray icon to update.
|
|
262
|
+
},
|
|
263
|
+
setIgnoreDoubleClickEvents() {
|
|
264
|
+
// No-op: web has no tray icon double-click behavior to configure.
|
|
265
|
+
},
|
|
266
|
+
setPressedIcon() {
|
|
267
|
+
// No-op: web has no tray icon; pressed icon is macOS-specific.
|
|
268
|
+
},
|
|
269
|
+
setTemplate() {
|
|
270
|
+
// No-op: template images are a macOS menu-bar concept; irrelevant on web.
|
|
271
|
+
},
|
|
272
|
+
setTitle() {
|
|
273
|
+
// No-op: web has no tray icon to update.
|
|
274
|
+
},
|
|
275
|
+
setTooltip() {
|
|
276
|
+
// No-op: web has no tray icon to update.
|
|
277
|
+
},
|
|
278
|
+
subscribe() {
|
|
279
|
+
// No tray on web — a native host (Electron/Tauri) is required to emit tray events.
|
|
280
|
+
return () => { };
|
|
281
|
+
},
|
|
282
|
+
};
|
|
253
283
|
//# sourceMappingURL=tray.js.map
|
package/dist/tray.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tray.js","sourceRoot":"","sources":["../src/tray.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"tray.js","sourceRoot":"","sources":["../src/tray.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flighthq/tray",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0-edge.1908.751021c",
|
|
4
4
|
"author": "Joshua Granick and other contributors",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -38,8 +38,8 @@
|
|
|
38
38
|
"clean:dist": "tsx ../../scripts/clean-package-dist.ts"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@flighthq/log": "0.
|
|
42
|
-
"@flighthq/types": "0.
|
|
41
|
+
"@flighthq/log": "0.4.0-edge.1908.751021c",
|
|
42
|
+
"@flighthq/types": "0.4.0-edge.1908.751021c"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"typescript": "^5.3.0"
|
package/src/tray.test.ts
CHANGED
|
@@ -10,7 +10,6 @@ import type {
|
|
|
10
10
|
|
|
11
11
|
import {
|
|
12
12
|
createTrayIcon,
|
|
13
|
-
createWebTrayBackend,
|
|
14
13
|
destroyTrayIcon,
|
|
15
14
|
displayTrayBalloon,
|
|
16
15
|
getTrayBackend,
|
|
@@ -35,6 +34,10 @@ import {
|
|
|
35
34
|
setTrayPressedIcon,
|
|
36
35
|
startTrayIconAnimation,
|
|
37
36
|
stopTrayIconAnimation,
|
|
37
|
+
explainTrayBackend,
|
|
38
|
+
installTrayHostBackend,
|
|
39
|
+
observeTrayHostResult,
|
|
40
|
+
resetTrayBackendForTest,
|
|
38
41
|
} from './tray';
|
|
39
42
|
|
|
40
43
|
// Fake backend state per icon.
|
|
@@ -213,41 +216,6 @@ describe('createTrayIcon', () => {
|
|
|
213
216
|
});
|
|
214
217
|
});
|
|
215
218
|
|
|
216
|
-
describe('createWebTrayBackend', () => {
|
|
217
|
-
it('returns sentinels without throwing (web has no tray)', () => {
|
|
218
|
-
const backend = createWebTrayBackend();
|
|
219
|
-
expect(backend.create({})).toBe(-1);
|
|
220
|
-
expect(() => backend.destroy(0)).not.toThrow();
|
|
221
|
-
expect(() => backend.setTooltip(0, 'x')).not.toThrow();
|
|
222
|
-
expect(() => backend.setTitle(0, 'x')).not.toThrow();
|
|
223
|
-
expect(() => backend.setContextMenu(0, [])).not.toThrow();
|
|
224
|
-
expect(() => backend.setIcon(0, 'icon.png')).not.toThrow();
|
|
225
|
-
expect(() => backend.setTemplate(0, true)).not.toThrow();
|
|
226
|
-
expect(() => backend.setPressedIcon(0, 'pressed.png')).not.toThrow();
|
|
227
|
-
expect(() => backend.setIgnoreDoubleClickEvents(0, true)).not.toThrow();
|
|
228
|
-
expect(() => backend.popUpContextMenu(0)).not.toThrow();
|
|
229
|
-
expect(() => backend.displayBalloon(0, { title: 'T', text: 'B' })).not.toThrow();
|
|
230
|
-
expect(() => backend.removeBalloon(0)).not.toThrow();
|
|
231
|
-
expect(backend.getBounds(0)).toBeNull();
|
|
232
|
-
expect(backend.getTitle(0)).toBe('');
|
|
233
|
-
expect(backend.getTooltip(0)).toBe('');
|
|
234
|
-
expect(backend.isDestroyed(0)).toBe(true);
|
|
235
|
-
expect(backend.listIds()).toEqual([]);
|
|
236
|
-
expect(typeof backend.subscribe(() => {})).toBe('function');
|
|
237
|
-
});
|
|
238
|
-
|
|
239
|
-
it('web capabilities are all false', () => {
|
|
240
|
-
const backend = createWebTrayBackend();
|
|
241
|
-
const caps = backend.getCapabilities();
|
|
242
|
-
expect(caps.balloon).toBe(false);
|
|
243
|
-
expect(caps.bounds).toBe(false);
|
|
244
|
-
expect(caps.clickEvents).toBe(false);
|
|
245
|
-
expect(caps.dropFiles).toBe(false);
|
|
246
|
-
expect(caps.pressedIcon).toBe(false);
|
|
247
|
-
expect(caps.title).toBe(false);
|
|
248
|
-
});
|
|
249
|
-
});
|
|
250
|
-
|
|
251
219
|
describe('destroyTrayIcon', () => {
|
|
252
220
|
it('destroys the tray via the active backend', () => {
|
|
253
221
|
const backend = fakeBackend();
|
|
@@ -289,6 +257,34 @@ describe('displayTrayBalloon', () => {
|
|
|
289
257
|
});
|
|
290
258
|
});
|
|
291
259
|
|
|
260
|
+
describe('explainTrayBackend', () => {
|
|
261
|
+
afterEach(() => resetTrayBackendForTest());
|
|
262
|
+
|
|
263
|
+
it('reports host-not-enabled when no backend is installed', () => {
|
|
264
|
+
resetTrayBackendForTest();
|
|
265
|
+
const explanation = explainTrayBackend();
|
|
266
|
+
expect(explanation.layer).toBe('host-not-enabled');
|
|
267
|
+
expect(explanation.conflict).toBe(false);
|
|
268
|
+
expect(explanation.viability).toBe('unobserved');
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
it('reports custom layer when a custom backend is set', () => {
|
|
272
|
+
setTrayBackend(fakeBackend());
|
|
273
|
+
expect(explainTrayBackend().layer).toBe('custom');
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
it('reports host layer when a host backend is installed', () => {
|
|
277
|
+
installTrayHostBackend(fakeBackend());
|
|
278
|
+
expect(explainTrayBackend().layer).toBe('host');
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
it('reports conflict when two different host backends are installed', () => {
|
|
282
|
+
installTrayHostBackend(fakeBackend());
|
|
283
|
+
installTrayHostBackend(fakeBackend());
|
|
284
|
+
expect(explainTrayBackend().conflict).toBe(true);
|
|
285
|
+
});
|
|
286
|
+
});
|
|
287
|
+
|
|
292
288
|
describe('getTrayBackend', () => {
|
|
293
289
|
it('falls back to a web backend', () => {
|
|
294
290
|
expect(getTrayBackend()).not.toBeNull();
|
|
@@ -301,6 +297,41 @@ describe('getTrayBackend', () => {
|
|
|
301
297
|
});
|
|
302
298
|
});
|
|
303
299
|
|
|
300
|
+
describe('getTrayBackend (sentinel)', () => {
|
|
301
|
+
it('returns sentinels without throwing (web has no tray)', () => {
|
|
302
|
+
const backend = getTrayBackend();
|
|
303
|
+
expect(backend.create({})).toBe(-1);
|
|
304
|
+
expect(() => backend.destroy(0)).not.toThrow();
|
|
305
|
+
expect(() => backend.setTooltip(0, 'x')).not.toThrow();
|
|
306
|
+
expect(() => backend.setTitle(0, 'x')).not.toThrow();
|
|
307
|
+
expect(() => backend.setContextMenu(0, [])).not.toThrow();
|
|
308
|
+
expect(() => backend.setIcon(0, 'icon.png')).not.toThrow();
|
|
309
|
+
expect(() => backend.setTemplate(0, true)).not.toThrow();
|
|
310
|
+
expect(() => backend.setPressedIcon(0, 'pressed.png')).not.toThrow();
|
|
311
|
+
expect(() => backend.setIgnoreDoubleClickEvents(0, true)).not.toThrow();
|
|
312
|
+
expect(() => backend.popUpContextMenu(0)).not.toThrow();
|
|
313
|
+
expect(() => backend.displayBalloon(0, { title: 'T', text: 'B' })).not.toThrow();
|
|
314
|
+
expect(() => backend.removeBalloon(0)).not.toThrow();
|
|
315
|
+
expect(backend.getBounds(0)).toBeNull();
|
|
316
|
+
expect(backend.getTitle(0)).toBe('');
|
|
317
|
+
expect(backend.getTooltip(0)).toBe('');
|
|
318
|
+
expect(backend.isDestroyed(0)).toBe(true);
|
|
319
|
+
expect(backend.listIds()).toEqual([]);
|
|
320
|
+
expect(typeof backend.subscribe(() => {})).toBe('function');
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
it('sentinel capabilities are all false', () => {
|
|
324
|
+
const backend = getTrayBackend();
|
|
325
|
+
const caps = backend.getCapabilities();
|
|
326
|
+
expect(caps.balloon).toBe(false);
|
|
327
|
+
expect(caps.bounds).toBe(false);
|
|
328
|
+
expect(caps.clickEvents).toBe(false);
|
|
329
|
+
expect(caps.dropFiles).toBe(false);
|
|
330
|
+
expect(caps.pressedIcon).toBe(false);
|
|
331
|
+
expect(caps.title).toBe(false);
|
|
332
|
+
});
|
|
333
|
+
});
|
|
334
|
+
|
|
304
335
|
describe('getTrayCapabilities', () => {
|
|
305
336
|
it('returns capabilities from the active backend', () => {
|
|
306
337
|
const backend = fakeBackend({ balloon: true, bounds: false });
|
|
@@ -385,6 +416,25 @@ describe('getTrayIconTooltip', () => {
|
|
|
385
416
|
});
|
|
386
417
|
});
|
|
387
418
|
|
|
419
|
+
describe('installTrayHostBackend', () => {
|
|
420
|
+
afterEach(() => resetTrayBackendForTest());
|
|
421
|
+
|
|
422
|
+
it('installs a host backend that getTrayBackend returns', () => {
|
|
423
|
+
const backend = fakeBackend();
|
|
424
|
+
installTrayHostBackend(backend);
|
|
425
|
+
expect(getTrayBackend()).toBe(backend);
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
it('is first-host-wins: a second different backend sets conflict', () => {
|
|
429
|
+
const first = fakeBackend();
|
|
430
|
+
const second = fakeBackend();
|
|
431
|
+
installTrayHostBackend(first);
|
|
432
|
+
installTrayHostBackend(second);
|
|
433
|
+
expect(getTrayBackend()).toBe(first);
|
|
434
|
+
expect(explainTrayBackend().conflict).toBe(true);
|
|
435
|
+
});
|
|
436
|
+
});
|
|
437
|
+
|
|
388
438
|
describe('isTrayDestroyed', () => {
|
|
389
439
|
it('returns false for a live tray', () => {
|
|
390
440
|
const backend = fakeBackend();
|
|
@@ -443,6 +493,24 @@ describe('isTrayIconAnimating', () => {
|
|
|
443
493
|
});
|
|
444
494
|
});
|
|
445
495
|
|
|
496
|
+
describe('observeTrayHostResult', () => {
|
|
497
|
+
afterEach(() => resetTrayBackendForTest());
|
|
498
|
+
|
|
499
|
+
it('records a successful observation', () => {
|
|
500
|
+
installTrayHostBackend(fakeBackend());
|
|
501
|
+
observeTrayHostResult('create', true);
|
|
502
|
+
const explanation = explainTrayBackend();
|
|
503
|
+
expect(explanation.operation).toBe('create');
|
|
504
|
+
expect(explanation.viability).toBe('available');
|
|
505
|
+
});
|
|
506
|
+
|
|
507
|
+
it('records a failed observation', () => {
|
|
508
|
+
installTrayHostBackend(fakeBackend());
|
|
509
|
+
observeTrayHostResult('create', false);
|
|
510
|
+
expect(explainTrayBackend().viability).toBe('runtime-api-unavailable');
|
|
511
|
+
});
|
|
512
|
+
});
|
|
513
|
+
|
|
446
514
|
describe('onTrayEvent', () => {
|
|
447
515
|
it('delivers rich TrayEventData via the active backend', () => {
|
|
448
516
|
const backend = fakeBackend();
|
|
@@ -541,6 +609,18 @@ describe('removeTrayBalloon', () => {
|
|
|
541
609
|
});
|
|
542
610
|
});
|
|
543
611
|
|
|
612
|
+
describe('resetTrayBackendForTest', () => {
|
|
613
|
+
it('clears all backend slots', () => {
|
|
614
|
+
setTrayBackend(fakeBackend());
|
|
615
|
+
installTrayHostBackend(fakeBackend());
|
|
616
|
+
observeTrayHostResult('create', true);
|
|
617
|
+
resetTrayBackendForTest();
|
|
618
|
+
expect(explainTrayBackend().layer).toBe('host-not-enabled');
|
|
619
|
+
expect(explainTrayBackend().conflict).toBe(false);
|
|
620
|
+
expect(explainTrayBackend().viability).toBe('unobserved');
|
|
621
|
+
});
|
|
622
|
+
});
|
|
623
|
+
|
|
544
624
|
describe('setTrayAnimationGuard', () => {
|
|
545
625
|
afterEach(() => {
|
|
546
626
|
setTrayAnimationGuard(null);
|