glimpse-sdk 0.5.0 → 0.7.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/README.md +1 -1
- package/dist/src/app.d.ts +16 -12
- package/dist/src/app.js +83 -7
- package/dist/src/events.d.ts +1 -1
- package/dist/src/events.js +1 -1
- package/dist/src/index.d.ts +4 -4
- package/dist/src/index.js +4 -4
- package/dist/src/protocol.d.ts +2 -15
- package/dist/src/protocol.js +1 -18
- package/dist/src/widgets.d.ts +415 -256
- package/dist/src/widgets.js +379 -457
- package/package.json +1 -1
- package/src/app.ts +94 -17
- package/src/events.ts +2 -2
- package/src/index.ts +39 -36
- package/src/protocol.ts +2 -23
- package/src/widgets.ts +334 -787
package/README.md
CHANGED
package/dist/src/app.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type CallbackEvent, type ChangeEvent, type ClickEvent, type InitEvent, type InputEvent, type ScrollEvent, type ToggleEvent } from "./events.js";
|
|
1
|
+
import { type CallbackEvent, type ChangeEvent, type ClickEvent, type InitEvent, type InputEvent, type PopoverEvent, type ScrollEvent, type ToggleEvent } from "./events.js";
|
|
2
2
|
import { StatusItem } from "./protocol.js";
|
|
3
3
|
import { type TreeNode } from "./widgets.js";
|
|
4
4
|
type Handler<EventT> = (event: EventT) => void | Promise<void>;
|
|
@@ -7,16 +7,13 @@ interface OutgoingMessage {
|
|
|
7
7
|
data: unknown;
|
|
8
8
|
line: string;
|
|
9
9
|
}
|
|
10
|
-
interface
|
|
11
|
-
summary: string;
|
|
10
|
+
interface ShowNotificationOptions {
|
|
12
11
|
body?: string;
|
|
13
|
-
urgency?: string;
|
|
14
12
|
}
|
|
15
|
-
interface
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
text: string;
|
|
13
|
+
export interface CommandResult {
|
|
14
|
+
stdout: string;
|
|
15
|
+
stderr: string;
|
|
16
|
+
rc: number;
|
|
20
17
|
}
|
|
21
18
|
interface DismissNotificationArgs {
|
|
22
19
|
id: number;
|
|
@@ -24,6 +21,7 @@ interface DismissNotificationArgs {
|
|
|
24
21
|
export declare abstract class Applet<State extends object> {
|
|
25
22
|
state: State;
|
|
26
23
|
private readonly handlerMap;
|
|
24
|
+
private inlineHandlerMap;
|
|
27
25
|
private readonly outgoing;
|
|
28
26
|
private flushPromise;
|
|
29
27
|
private renderQueued;
|
|
@@ -32,6 +30,7 @@ export declare abstract class Applet<State extends object> {
|
|
|
32
30
|
private popoverOpen;
|
|
33
31
|
protected constructor();
|
|
34
32
|
protected abstract initialState(): State;
|
|
33
|
+
protected cssClass(): string | null;
|
|
35
34
|
protected onStart(): Promise<void>;
|
|
36
35
|
protected onInit(_event: InitEvent): Promise<void>;
|
|
37
36
|
protected onCallback(_event: CallbackEvent): Promise<void>;
|
|
@@ -43,12 +42,16 @@ export declare abstract class Applet<State extends object> {
|
|
|
43
42
|
onInput(id: string, handler: Handler<InputEvent>): void;
|
|
44
43
|
onChange(id: string, handler: Handler<ChangeEvent>): void;
|
|
45
44
|
onToggle(id: string, handler: Handler<ToggleEvent>): void;
|
|
45
|
+
onPopover(handler: Handler<PopoverEvent>): void;
|
|
46
46
|
isPopoverOpen(): boolean;
|
|
47
|
-
|
|
48
|
-
protected
|
|
49
|
-
protected
|
|
47
|
+
log(...args: unknown[]): void;
|
|
48
|
+
protected showNotification(summary: string, options?: ShowNotificationOptions): Promise<void>;
|
|
49
|
+
protected openUri(uri: string): Promise<void>;
|
|
50
|
+
protected copyToClipboard(text: string): Promise<void>;
|
|
51
|
+
protected runCommand(command: string[]): Promise<CommandResult>;
|
|
50
52
|
protected dismissNotification(args: DismissNotificationArgs): void;
|
|
51
53
|
protected closePopover(): void;
|
|
54
|
+
protected runDesktopCommand(command: string, args: string[], input?: string): Promise<void>;
|
|
52
55
|
run(): Promise<void>;
|
|
53
56
|
protected drainOutgoingForTest(): Promise<OutgoingMessage[]>;
|
|
54
57
|
private register;
|
|
@@ -59,4 +62,5 @@ export declare abstract class Applet<State extends object> {
|
|
|
59
62
|
private emit;
|
|
60
63
|
private emitAction;
|
|
61
64
|
}
|
|
65
|
+
export declare function runCommand(command: string[]): Promise<CommandResult>;
|
|
62
66
|
export {};
|
package/dist/src/app.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { createInterface } from "node:readline";
|
|
2
|
+
import { spawn } from "node:child_process";
|
|
2
3
|
import { parseCallbackEvent, parseInitEvent, } from "./events.js";
|
|
4
|
+
import { InlineHandlerRegistry } from "./widgets.js";
|
|
3
5
|
export class Applet {
|
|
4
6
|
state;
|
|
5
7
|
handlerMap = new Map();
|
|
8
|
+
inlineHandlerMap = new Map();
|
|
6
9
|
outgoing = [];
|
|
7
10
|
flushPromise = null;
|
|
8
11
|
renderQueued = false;
|
|
@@ -12,6 +15,9 @@ export class Applet {
|
|
|
12
15
|
constructor() {
|
|
13
16
|
this.state = this.initialState();
|
|
14
17
|
}
|
|
18
|
+
cssClass() {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
15
21
|
async onStart() { }
|
|
16
22
|
async onInit(_event) { }
|
|
17
23
|
async onCallback(_event) { }
|
|
@@ -40,17 +46,31 @@ export class Applet {
|
|
|
40
46
|
onToggle(id, handler) {
|
|
41
47
|
this.register("toggle", id, handler);
|
|
42
48
|
}
|
|
49
|
+
onPopover(handler) {
|
|
50
|
+
this.register("open", "popover", handler);
|
|
51
|
+
this.register("close", "popover", handler);
|
|
52
|
+
}
|
|
43
53
|
isPopoverOpen() {
|
|
44
54
|
return this.popoverOpen;
|
|
45
55
|
}
|
|
46
|
-
|
|
47
|
-
|
|
56
|
+
log(...args) {
|
|
57
|
+
process.stderr.write(args.map(String).join(" ") + "\n");
|
|
58
|
+
}
|
|
59
|
+
async showNotification(summary, options = {}) {
|
|
60
|
+
const args = [summary];
|
|
61
|
+
if (options.body !== undefined) {
|
|
62
|
+
args.push(options.body);
|
|
63
|
+
}
|
|
64
|
+
await this.runDesktopCommand("notify-send", args);
|
|
65
|
+
}
|
|
66
|
+
async openUri(uri) {
|
|
67
|
+
await this.runDesktopCommand("xdg-open", [uri]);
|
|
48
68
|
}
|
|
49
|
-
|
|
50
|
-
this.
|
|
69
|
+
async copyToClipboard(text) {
|
|
70
|
+
await this.runDesktopCommand("wl-copy", [], text);
|
|
51
71
|
}
|
|
52
|
-
|
|
53
|
-
|
|
72
|
+
async runCommand(command) {
|
|
73
|
+
return await runCommand(command);
|
|
54
74
|
}
|
|
55
75
|
dismissNotification(args) {
|
|
56
76
|
this.emitAction("dismiss_notification", args);
|
|
@@ -58,6 +78,9 @@ export class Applet {
|
|
|
58
78
|
closePopover() {
|
|
59
79
|
this.emitAction("close_popover", {});
|
|
60
80
|
}
|
|
81
|
+
async runDesktopCommand(command, args, input) {
|
|
82
|
+
await runDesktopCommand([command, ...args], input);
|
|
83
|
+
}
|
|
61
84
|
async run() {
|
|
62
85
|
process.stdout.on("error", (err) => {
|
|
63
86
|
if (err.code === "EPIPE") {
|
|
@@ -65,6 +88,10 @@ export class Applet {
|
|
|
65
88
|
}
|
|
66
89
|
});
|
|
67
90
|
await this.onStart();
|
|
91
|
+
const cssClass = this.cssClass();
|
|
92
|
+
if (cssClass !== null) {
|
|
93
|
+
process.stdout.write(`class ${cssClass}\n`);
|
|
94
|
+
}
|
|
68
95
|
await this.scheduleRender();
|
|
69
96
|
const rl = createInterface({
|
|
70
97
|
input: process.stdin,
|
|
@@ -104,7 +131,13 @@ export class Applet {
|
|
|
104
131
|
this.handlerMap.set(`${event}:${id}`, handler);
|
|
105
132
|
}
|
|
106
133
|
async dispatchCallback(event) {
|
|
107
|
-
const
|
|
134
|
+
const key = `${event.event}:${event.id}`;
|
|
135
|
+
const inlineHandler = this.inlineHandlerMap.get(key);
|
|
136
|
+
if (inlineHandler !== undefined) {
|
|
137
|
+
await inlineHandler(event);
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
const handler = this.handlerMap.get(key);
|
|
108
141
|
if (handler !== undefined) {
|
|
109
142
|
await handler(event);
|
|
110
143
|
return;
|
|
@@ -151,6 +184,14 @@ export class Applet {
|
|
|
151
184
|
this.emit("status", { items: status });
|
|
152
185
|
}
|
|
153
186
|
const widget = await this.popover(this.state);
|
|
187
|
+
if (widget !== null) {
|
|
188
|
+
const registry = new InlineHandlerRegistry();
|
|
189
|
+
widget.bindHandlers?.(registry, []);
|
|
190
|
+
this.inlineHandlerMap = registry.handlers;
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
this.inlineHandlerMap = new Map();
|
|
194
|
+
}
|
|
154
195
|
const tree = { root: widget?.toProtocol() ?? null };
|
|
155
196
|
if (!deepEqual(tree, this.lastTree)) {
|
|
156
197
|
this.lastTree = tree;
|
|
@@ -194,3 +235,38 @@ function deepEqual(left, right) {
|
|
|
194
235
|
function isPopoverEvent(event) {
|
|
195
236
|
return event.event === "open" || event.event === "close";
|
|
196
237
|
}
|
|
238
|
+
export async function runCommand(command) {
|
|
239
|
+
return await runCommandWithInput(command);
|
|
240
|
+
}
|
|
241
|
+
async function runDesktopCommand(command, input) {
|
|
242
|
+
const result = await runCommandWithInput(command, input);
|
|
243
|
+
if (result.rc !== 0) {
|
|
244
|
+
throw new Error(`${command[0]} exited with status ${result.rc}`);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
async function runCommandWithInput(command, input) {
|
|
248
|
+
if (command.length === 0) {
|
|
249
|
+
throw new Error("command must not be empty");
|
|
250
|
+
}
|
|
251
|
+
return await new Promise((resolve, reject) => {
|
|
252
|
+
const child = spawn(command[0], command.slice(1), { stdio: ["pipe", "pipe", "pipe"] });
|
|
253
|
+
const stdout = [];
|
|
254
|
+
const stderr = [];
|
|
255
|
+
child.on("error", reject);
|
|
256
|
+
child.stdout.on("data", (chunk) => stdout.push(chunk));
|
|
257
|
+
child.stderr.on("data", (chunk) => stderr.push(chunk));
|
|
258
|
+
child.on("close", (code) => {
|
|
259
|
+
resolve({
|
|
260
|
+
stdout: Buffer.concat(stdout).toString("utf8"),
|
|
261
|
+
stderr: Buffer.concat(stderr).toString("utf8"),
|
|
262
|
+
rc: code ?? -1,
|
|
263
|
+
});
|
|
264
|
+
});
|
|
265
|
+
if (input !== undefined) {
|
|
266
|
+
child.stdin.end(input);
|
|
267
|
+
}
|
|
268
|
+
else {
|
|
269
|
+
child.stdin.end();
|
|
270
|
+
}
|
|
271
|
+
});
|
|
272
|
+
}
|
package/dist/src/events.d.ts
CHANGED
package/dist/src/events.js
CHANGED
|
@@ -8,7 +8,7 @@ export function parseCallbackEvent(payload) {
|
|
|
8
8
|
const event = String(payload.type ?? payload.event ?? "");
|
|
9
9
|
const id = String(payload.id ?? "");
|
|
10
10
|
if (event === "click") {
|
|
11
|
-
return { id, event, button: payload.button === undefined ?
|
|
11
|
+
return { id, event, button: payload.button === undefined ? null : String(payload.button) };
|
|
12
12
|
}
|
|
13
13
|
if (event === "scroll") {
|
|
14
14
|
return {
|
package/dist/src/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { Applet } from "./app.js";
|
|
1
|
+
export { Applet, runCommand } from "./app.js";
|
|
2
2
|
export { type CallbackEvent, type ChangeEvent, type ClickEvent, type InitEvent, type InputEvent, type PopoverEvent, type ScrollEvent, type ToggleEvent, parseCallbackEvent, parseInitEvent, } from "./events.js";
|
|
3
|
-
export {
|
|
4
|
-
export {
|
|
5
|
-
export {
|
|
3
|
+
export { ipc, IpcError, Subscriber } from "./ipc.js";
|
|
4
|
+
export { StatusItem } from "./protocol.js";
|
|
5
|
+
export { Badge, type BadgeKind, BatteryHero, BoxedList, ButtonRow, Calendar, CameraIndicator, Choice, ChoiceList, ChoiceTile, CircleBox, Column, Container, DateHero, EmptyState, EventItem, Events, ExpanderTile, Header, Hero, KeyValueGrid, Label, LocationIndicator, Meter, MicIndicator, MutedIndicator, type PagerAppearance, PagerItem, PagerStrip, PanelIndicator, PopoverShell, type PopoverSize, Row, ScreenCastIndicator, Scroll, SegmentedTile, Separator, SliderTile, Spinner, StatusDot, type StatusDotStatus, SwitchTile, Tile, type TreeNode, WeatherForecastItem, WeatherForecastList, WeatherHourlyItem, WeatherHourlyStrip, WidgetBase, WorldClock, WorldClockRow, } from "./widgets.js";
|
package/dist/src/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { Applet } from "./app.js";
|
|
1
|
+
export { Applet, runCommand } from "./app.js";
|
|
2
2
|
export { parseCallbackEvent, parseInitEvent, } from "./events.js";
|
|
3
|
-
export {
|
|
4
|
-
export {
|
|
5
|
-
export {
|
|
3
|
+
export { ipc, IpcError, Subscriber } from "./ipc.js";
|
|
4
|
+
export { StatusItem } from "./protocol.js";
|
|
5
|
+
export { Badge, BatteryHero, BoxedList, ButtonRow, Calendar, CameraIndicator, Choice, ChoiceList, ChoiceTile, CircleBox, Column, Container, DateHero, EmptyState, EventItem, Events, ExpanderTile, Header, Hero, KeyValueGrid, Label, LocationIndicator, Meter, MicIndicator, MutedIndicator, PagerItem, PagerStrip, PanelIndicator, PopoverShell, Row, ScreenCastIndicator, Scroll, SegmentedTile, Separator, SliderTile, Spinner, StatusDot, SwitchTile, Tile, WeatherForecastItem, WeatherForecastList, WeatherHourlyItem, WeatherHourlyStrip, WidgetBase, WorldClock, WorldClockRow, } from "./widgets.js";
|
package/dist/src/protocol.d.ts
CHANGED
|
@@ -1,26 +1,13 @@
|
|
|
1
|
-
export type IconKind = "name" | "path";
|
|
2
|
-
export declare class Icon {
|
|
3
|
-
readonly kind: IconKind;
|
|
4
|
-
readonly value: string;
|
|
5
|
-
constructor(kind: IconKind, value: string);
|
|
6
|
-
static name(value: string): Icon;
|
|
7
|
-
static path(value: string): Icon;
|
|
8
|
-
toProtocol(): {
|
|
9
|
-
name: string;
|
|
10
|
-
} | {
|
|
11
|
-
path: string;
|
|
12
|
-
};
|
|
13
|
-
}
|
|
14
1
|
export declare class StatusItem {
|
|
15
2
|
readonly options: {
|
|
16
3
|
id?: string;
|
|
17
|
-
icon?:
|
|
4
|
+
icon?: string;
|
|
18
5
|
label?: string;
|
|
19
6
|
tooltip?: string;
|
|
20
7
|
};
|
|
21
8
|
constructor(options?: {
|
|
22
9
|
id?: string;
|
|
23
|
-
icon?:
|
|
10
|
+
icon?: string;
|
|
24
11
|
label?: string;
|
|
25
12
|
tooltip?: string;
|
|
26
13
|
});
|
package/dist/src/protocol.js
CHANGED
|
@@ -1,20 +1,3 @@
|
|
|
1
|
-
export class Icon {
|
|
2
|
-
kind;
|
|
3
|
-
value;
|
|
4
|
-
constructor(kind, value) {
|
|
5
|
-
this.kind = kind;
|
|
6
|
-
this.value = value;
|
|
7
|
-
}
|
|
8
|
-
static name(value) {
|
|
9
|
-
return new Icon("name", value);
|
|
10
|
-
}
|
|
11
|
-
static path(value) {
|
|
12
|
-
return new Icon("path", value);
|
|
13
|
-
}
|
|
14
|
-
toProtocol() {
|
|
15
|
-
return this.kind === "name" ? { name: this.value } : { path: this.value };
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
1
|
export class StatusItem {
|
|
19
2
|
options;
|
|
20
3
|
constructor(options = {}) {
|
|
@@ -26,7 +9,7 @@ export class StatusItem {
|
|
|
26
9
|
payload.id = this.options.id;
|
|
27
10
|
}
|
|
28
11
|
if (this.options.icon !== undefined) {
|
|
29
|
-
payload.icon = this.options.icon
|
|
12
|
+
payload.icon = this.options.icon;
|
|
30
13
|
}
|
|
31
14
|
if (this.options.label !== undefined) {
|
|
32
15
|
payload.label = this.options.label;
|