glimpse-sdk 0.5.0 → 0.8.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 +32 -30
- 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 +10 -15
- package/dist/src/protocol.js +15 -18
- package/dist/src/widgets.d.ts +415 -256
- package/dist/src/widgets.js +396 -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 +18 -23
- package/src/widgets.ts +365 -794
package/src/widgets.ts
CHANGED
|
@@ -1,920 +1,491 @@
|
|
|
1
|
-
|
|
1
|
+
export type InlineHandler = (event: unknown) => void | Promise<void>;
|
|
2
|
+
export class InlineHandlerRegistry {
|
|
3
|
+
readonly handlers = new Map<string, InlineHandler>();
|
|
2
4
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
export type ButtonVariant = "primary" | "secondary" | "compact" | "flat" | "danger";
|
|
7
|
-
export type PagerAppearance = "dots" | "numbers";
|
|
8
|
-
export type ContentFit = "fill" | "contain" | "cover" | "scale_down";
|
|
9
|
-
export type LevelBarMode = "continuous" | "discrete";
|
|
10
|
-
|
|
11
|
-
export interface WidgetNode {
|
|
12
|
-
toProtocol(): Record<string, unknown>;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export interface CommonProps {
|
|
16
|
-
id?: string;
|
|
17
|
-
visible?: boolean;
|
|
18
|
-
hexpand?: boolean;
|
|
19
|
-
vexpand?: boolean;
|
|
20
|
-
halign?: Align;
|
|
21
|
-
valign?: Align;
|
|
22
|
-
tooltip?: string;
|
|
23
|
-
variant?: Variant;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function applyCommonProps(
|
|
27
|
-
payload: Record<string, unknown>,
|
|
28
|
-
props: CommonProps,
|
|
29
|
-
): Record<string, unknown> {
|
|
30
|
-
if (props.id !== undefined) payload.id = props.id;
|
|
31
|
-
if (props.visible !== undefined) payload.visible = props.visible;
|
|
32
|
-
if (props.hexpand !== undefined) payload.hexpand = props.hexpand;
|
|
33
|
-
if (props.vexpand !== undefined) payload.vexpand = props.vexpand;
|
|
34
|
-
if (props.halign !== undefined) payload.halign = props.halign;
|
|
35
|
-
if (props.valign !== undefined) payload.valign = props.valign;
|
|
36
|
-
if (props.tooltip !== undefined) payload.tooltip = props.tooltip;
|
|
37
|
-
if (props.variant !== undefined) payload.variant = props.variant;
|
|
38
|
-
return payload;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
abstract class WidgetBase implements WidgetNode {
|
|
42
|
-
protected constructor(protected readonly common: CommonProps = {}) {}
|
|
43
|
-
|
|
44
|
-
protected withCommon(payload: Record<string, unknown>): Record<string, unknown> {
|
|
45
|
-
return applyCommonProps(payload, this.common);
|
|
5
|
+
generatedId(event: "click" | "toggle" | "change", path: number[]): string {
|
|
6
|
+
const suffix = path.length === 0 ? "root" : path.join(".");
|
|
7
|
+
return `__glimpse:${event}:${suffix}`;
|
|
46
8
|
}
|
|
47
9
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
export class Label extends WidgetBase {
|
|
52
|
-
constructor(
|
|
53
|
-
public readonly text: string,
|
|
54
|
-
private readonly options: CommonProps & {
|
|
55
|
-
wrap?: boolean;
|
|
56
|
-
xalign?: number;
|
|
57
|
-
selectable?: boolean;
|
|
58
|
-
} = {},
|
|
59
|
-
) {
|
|
60
|
-
super(options);
|
|
10
|
+
targetId(event: "click" | "toggle" | "change", id: string | undefined, path: number[]): string {
|
|
11
|
+
return id ?? this.generatedId(event, path);
|
|
61
12
|
}
|
|
62
13
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
if (this.options.wrap !== undefined) payload.wrap = this.options.wrap;
|
|
66
|
-
if (this.options.xalign !== undefined) payload.xalign = this.options.xalign;
|
|
67
|
-
if (this.options.selectable !== undefined) payload.selectable = this.options.selectable;
|
|
68
|
-
return { type: "label", data: payload };
|
|
14
|
+
add(event: "click" | "toggle" | "change", id: string, handler: InlineHandler): void {
|
|
15
|
+
this.handlers.set(`${event}:${id}`, handler);
|
|
69
16
|
}
|
|
70
17
|
}
|
|
71
18
|
|
|
72
|
-
export
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
) {
|
|
77
|
-
super(options);
|
|
78
|
-
}
|
|
19
|
+
export type BadgeKind = "default" | "success" | "warning" | "error" | "accent";
|
|
20
|
+
export type StatusDotStatus = "neutral" | "success" | "warning" | "error" | "accent";
|
|
21
|
+
export type PagerAppearance = "dots" | "numbers";
|
|
22
|
+
export type PopoverSize = "small" | "medium" | "large" | "wide";
|
|
79
23
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
return { type: "image", data: payload };
|
|
84
|
-
}
|
|
24
|
+
export interface ProtocolNode {
|
|
25
|
+
type: string;
|
|
26
|
+
data: Record<string, unknown>;
|
|
85
27
|
}
|
|
86
28
|
|
|
87
|
-
export
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
show_text?: boolean;
|
|
93
|
-
text?: string;
|
|
94
|
-
},
|
|
95
|
-
) {
|
|
96
|
-
super(options);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
toProtocol(): Record<string, unknown> {
|
|
100
|
-
const payload = this.withCommon({
|
|
101
|
-
value: this.options.value,
|
|
102
|
-
max: this.options.max ?? 1,
|
|
103
|
-
});
|
|
104
|
-
if (this.options.show_text !== undefined) payload.show_text = this.options.show_text;
|
|
105
|
-
if (this.options.text !== undefined) payload.text = this.options.text;
|
|
106
|
-
return { type: "progress", data: payload };
|
|
107
|
-
}
|
|
29
|
+
export interface CommonOptions {
|
|
30
|
+
visible?: boolean;
|
|
31
|
+
tooltip?: string;
|
|
32
|
+
css_classes?: string[];
|
|
33
|
+
styles?: Record<string, string>;
|
|
108
34
|
}
|
|
109
35
|
|
|
110
|
-
export class
|
|
111
|
-
constructor(
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
max?: number;
|
|
116
|
-
mode?: LevelBarMode;
|
|
117
|
-
},
|
|
118
|
-
) {
|
|
119
|
-
super(options);
|
|
120
|
-
}
|
|
36
|
+
export abstract class WidgetBase {
|
|
37
|
+
protected constructor(protected readonly common: CommonOptions = {}) {}
|
|
38
|
+
abstract readonly type: string;
|
|
39
|
+
abstract data(): Record<string, unknown>;
|
|
40
|
+
bindHandlers(_registry: InlineHandlerRegistry, _path: number[]): void {}
|
|
121
41
|
|
|
122
|
-
toProtocol():
|
|
123
|
-
return {
|
|
124
|
-
type: "level_bar",
|
|
125
|
-
data: this.withCommon({
|
|
126
|
-
value: this.options.value,
|
|
127
|
-
min: this.options.min ?? 0,
|
|
128
|
-
max: this.options.max ?? 1,
|
|
129
|
-
mode: this.options.mode ?? "continuous",
|
|
130
|
-
}),
|
|
131
|
-
};
|
|
42
|
+
toProtocol(): ProtocolNode {
|
|
43
|
+
return { type: this.type, data: this.data() };
|
|
132
44
|
}
|
|
133
|
-
}
|
|
134
45
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
toProtocol(): Record<string, unknown> {
|
|
143
|
-
const payload = this.withCommon({ path: this.options.path });
|
|
144
|
-
if (this.options.content_fit !== undefined) payload.content_fit = this.options.content_fit;
|
|
145
|
-
return { type: "picture", data: payload };
|
|
46
|
+
protected commonData(): Record<string, unknown> {
|
|
47
|
+
const out: Record<string, unknown> = {};
|
|
48
|
+
if (this.common.visible !== undefined) out.visible = this.common.visible;
|
|
49
|
+
if (this.common.tooltip !== undefined) out.tooltip = this.common.tooltip;
|
|
50
|
+
if (this.common.css_classes?.length) out.css_classes = this.common.css_classes;
|
|
51
|
+
if (this.common.styles && Object.keys(this.common.styles).length > 0) out.styles = this.common.styles;
|
|
52
|
+
return out;
|
|
146
53
|
}
|
|
147
54
|
}
|
|
148
55
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
label?: string;
|
|
152
|
-
icon?: string;
|
|
153
|
-
enabled?: boolean;
|
|
154
|
-
variant?: ButtonVariant;
|
|
155
|
-
};
|
|
56
|
+
const child = (node?: TreeNode): ProtocolNode | undefined => node?.toProtocol();
|
|
57
|
+
const children = (nodes: TreeNode[]): ProtocolNode[] => nodes.map((node) => node.toProtocol());
|
|
156
58
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
super(common);
|
|
165
|
-
this.options = options;
|
|
59
|
+
export class Label extends WidgetBase {
|
|
60
|
+
readonly type = "label";
|
|
61
|
+
private readonly options: CommonOptions & { label: string; xalign?: number; wrap?: boolean };
|
|
62
|
+
constructor(options: string | CommonOptions & { label: string; xalign?: number; wrap?: boolean }) {
|
|
63
|
+
const normalized = typeof options === "string" ? { label: options } : options;
|
|
64
|
+
super(normalized);
|
|
65
|
+
this.options = normalized;
|
|
166
66
|
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
if (this.options.icon !== undefined) payload.icon = this.options.icon;
|
|
173
|
-
if (this.options.enabled !== undefined) payload.enabled = this.options.enabled;
|
|
174
|
-
if (variant !== undefined) payload.variant = variant;
|
|
175
|
-
return { type: "button", data: payload };
|
|
67
|
+
data(): Record<string, unknown> {
|
|
68
|
+
const out: Record<string, unknown> = { ...this.commonData(), label: this.options.label };
|
|
69
|
+
if (this.options.xalign !== undefined) out.xalign = this.options.xalign;
|
|
70
|
+
if (this.options.wrap !== undefined) out.wrap = this.options.wrap;
|
|
71
|
+
return out;
|
|
176
72
|
}
|
|
177
73
|
}
|
|
178
74
|
|
|
179
|
-
export class
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
label?: string;
|
|
184
|
-
},
|
|
185
|
-
) {
|
|
186
|
-
super(options);
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
toProtocol(): Record<string, unknown> {
|
|
190
|
-
const payload = this.withCommon({ uri: this.options.uri });
|
|
191
|
-
if (this.options.label !== undefined) payload.label = this.options.label;
|
|
192
|
-
return { type: "link_button", data: payload };
|
|
193
|
-
}
|
|
75
|
+
export class Header extends WidgetBase {
|
|
76
|
+
readonly type = "header";
|
|
77
|
+
constructor(private readonly options: CommonOptions & { label: string }) { super(options); }
|
|
78
|
+
data(): Record<string, unknown> { return { ...this.commonData(), label: this.options.label }; }
|
|
194
79
|
}
|
|
195
80
|
|
|
196
|
-
export class
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
}),
|
|
215
|
-
};
|
|
81
|
+
export class Hero extends WidgetBase {
|
|
82
|
+
readonly type = "hero";
|
|
83
|
+
constructor(private readonly options: CommonOptions & { title: string; subtitle?: string; id?: string; icon?: string; icon_size?: number; toggle?: boolean; toggle_sensitive?: boolean; separator?: boolean; trailing?: TreeNode; on_toggle?: InlineHandler }) { super(options); }
|
|
84
|
+
data(): Record<string, unknown> {
|
|
85
|
+
const out: Record<string, unknown> = { ...this.commonData(), title: this.options.title, subtitle: this.options.subtitle ?? "" };
|
|
86
|
+
for (const key of ["id", "icon", "icon_size", "toggle", "toggle_sensitive", "separator"] as const) {
|
|
87
|
+
if (this.options[key] !== undefined) out[key] = this.options[key];
|
|
88
|
+
}
|
|
89
|
+
const trailing = child(this.options.trailing);
|
|
90
|
+
if (trailing) out.trailing = trailing;
|
|
91
|
+
return out;
|
|
92
|
+
}
|
|
93
|
+
bindHandlers(registry: InlineHandlerRegistry, path: number[]): void {
|
|
94
|
+
if (this.options.on_toggle) {
|
|
95
|
+
this.options.id = registry.targetId("toggle", this.options.id, path);
|
|
96
|
+
registry.add("toggle", this.options.id, this.options.on_toggle);
|
|
97
|
+
}
|
|
98
|
+
this.options.trailing?.bindHandlers(registry, [...path, 0]);
|
|
216
99
|
}
|
|
217
100
|
}
|
|
218
101
|
|
|
219
|
-
export class
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
hide_expander?: boolean;
|
|
224
|
-
indent_for_depth?: boolean;
|
|
225
|
-
indent_for_icon?: boolean;
|
|
226
|
-
},
|
|
227
|
-
) {
|
|
228
|
-
super(options);
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
toProtocol(): Record<string, unknown> {
|
|
232
|
-
return {
|
|
233
|
-
type: "tree_expander",
|
|
234
|
-
data: this.withCommon({
|
|
235
|
-
child: this.options.child.toProtocol(),
|
|
236
|
-
hide_expander: this.options.hide_expander ?? false,
|
|
237
|
-
indent_for_depth: this.options.indent_for_depth ?? false,
|
|
238
|
-
indent_for_icon: this.options.indent_for_icon ?? false,
|
|
239
|
-
}),
|
|
240
|
-
};
|
|
241
|
-
}
|
|
102
|
+
export class Badge extends WidgetBase {
|
|
103
|
+
readonly type = "badge";
|
|
104
|
+
constructor(private readonly options: CommonOptions & { label: string; kind?: BadgeKind }) { super(options); }
|
|
105
|
+
data(): Record<string, unknown> { return { ...this.commonData(), label: this.options.label, kind: this.options.kind ?? "default" }; }
|
|
242
106
|
}
|
|
243
107
|
|
|
244
|
-
export class
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
icon?: string;
|
|
249
|
-
popover: TreeNode;
|
|
250
|
-
},
|
|
251
|
-
) {
|
|
252
|
-
super(options);
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
toProtocol(): Record<string, unknown> {
|
|
256
|
-
const payload = this.withCommon({ popover: this.options.popover.toProtocol() });
|
|
257
|
-
if (this.options.label !== undefined) payload.label = this.options.label;
|
|
258
|
-
if (this.options.icon !== undefined) payload.icon = this.options.icon;
|
|
259
|
-
return { type: "menu_button", data: payload };
|
|
260
|
-
}
|
|
108
|
+
export class StatusDot extends WidgetBase {
|
|
109
|
+
readonly type = "status_dot";
|
|
110
|
+
constructor(private readonly options: CommonOptions & { status?: StatusDotStatus } = {}) { super(options); }
|
|
111
|
+
data(): Record<string, unknown> { return { ...this.commonData(), status: this.options.status ?? "neutral" }; }
|
|
261
112
|
}
|
|
262
113
|
|
|
263
|
-
export class
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
114
|
+
export class PanelIndicator extends WidgetBase {
|
|
115
|
+
readonly type = "panel_indicator";
|
|
116
|
+
constructor(private readonly options: CommonOptions & { id?: string; icon?: string; label?: string; active?: boolean; checked?: boolean; needs_attention?: boolean; extra?: TreeNode; on_click?: InlineHandler }) { super(options); }
|
|
117
|
+
data(): Record<string, unknown> {
|
|
118
|
+
const out: Record<string, unknown> = { ...this.commonData(), active: this.options.active ?? false, checked: this.options.checked ?? false, needs_attention: this.options.needs_attention ?? false };
|
|
119
|
+
for (const key of ["id", "icon", "label"] as const) if (this.options[key] !== undefined) out[key] = this.options[key];
|
|
120
|
+
const extra = child(this.options.extra);
|
|
121
|
+
if (extra) out.extra = extra;
|
|
122
|
+
return out;
|
|
271
123
|
}
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
if (this.options.label !== undefined) payload.label = this.options.label;
|
|
276
|
-
return { type: "switch", data: payload };
|
|
124
|
+
bindHandlers(registry: InlineHandlerRegistry, path: number[]): void {
|
|
125
|
+
if (this.options.id && this.options.on_click) registry.add("click", this.options.id, this.options.on_click);
|
|
126
|
+
this.options.extra?.bindHandlers(registry, [...path, 0]);
|
|
277
127
|
}
|
|
278
128
|
}
|
|
279
129
|
|
|
280
|
-
export class
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
super(options);
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
toProtocol(): Record<string, unknown> {
|
|
291
|
-
const payload = this.withCommon({ active: this.options.active ?? false });
|
|
292
|
-
if (this.options.label !== undefined) payload.label = this.options.label;
|
|
293
|
-
return { type: "toggle_button", data: payload };
|
|
130
|
+
export class EmptyState extends WidgetBase {
|
|
131
|
+
readonly type = "empty_state";
|
|
132
|
+
constructor(private readonly options: CommonOptions & { title: string; subtitle?: string }) { super(options); }
|
|
133
|
+
data(): Record<string, unknown> {
|
|
134
|
+
const out: Record<string, unknown> = { ...this.commonData(), title: this.options.title };
|
|
135
|
+
if (this.options.subtitle !== undefined) out.subtitle = this.options.subtitle;
|
|
136
|
+
return out;
|
|
294
137
|
}
|
|
295
138
|
}
|
|
296
139
|
|
|
297
|
-
export class
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
step?: number;
|
|
303
|
-
value?: number;
|
|
304
|
-
orientation?: Orientation;
|
|
305
|
-
draw_value?: boolean;
|
|
306
|
-
} = {},
|
|
307
|
-
) {
|
|
308
|
-
super(options);
|
|
309
|
-
}
|
|
140
|
+
export class Spinner extends WidgetBase {
|
|
141
|
+
readonly type = "spinner";
|
|
142
|
+
constructor(private readonly options: CommonOptions & { spinning?: boolean } = {}) { super(options); }
|
|
143
|
+
data(): Record<string, unknown> { return { ...this.commonData(), spinning: this.options.spinning ?? true }; }
|
|
144
|
+
}
|
|
310
145
|
|
|
311
|
-
|
|
312
|
-
|
|
146
|
+
export class Meter extends WidgetBase {
|
|
147
|
+
readonly type = "meter";
|
|
148
|
+
constructor(private readonly options: CommonOptions & { id?: string; icon?: string; label?: string; value?: number; min?: number; max?: number; step?: number; text?: string; interactive?: boolean; on_change?: InlineHandler } = {}) { super(options); }
|
|
149
|
+
data(): Record<string, unknown> {
|
|
150
|
+
const out: Record<string, unknown> = {
|
|
151
|
+
...this.commonData(),
|
|
152
|
+
label: this.options.label ?? "",
|
|
153
|
+
value: this.options.value ?? 0,
|
|
313
154
|
min: this.options.min ?? 0,
|
|
314
155
|
max: this.options.max ?? 1,
|
|
315
|
-
step: this.options.step ?? 0.
|
|
316
|
-
|
|
317
|
-
}
|
|
318
|
-
if (this.options
|
|
319
|
-
|
|
320
|
-
return { type: "slider", data: payload };
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
export class Checkbox extends WidgetBase {
|
|
325
|
-
constructor(
|
|
326
|
-
private readonly options: CommonProps & {
|
|
327
|
-
label?: string;
|
|
328
|
-
active?: boolean;
|
|
329
|
-
} = {},
|
|
330
|
-
) {
|
|
331
|
-
super(options);
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
toProtocol(): Record<string, unknown> {
|
|
335
|
-
const payload = this.withCommon({ active: this.options.active ?? false });
|
|
336
|
-
if (this.options.label !== undefined) payload.label = this.options.label;
|
|
337
|
-
return { type: "checkbox", data: payload };
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
export class SelectOption {
|
|
342
|
-
constructor(
|
|
343
|
-
public readonly id: string,
|
|
344
|
-
public readonly label: string,
|
|
345
|
-
) {}
|
|
346
|
-
|
|
347
|
-
toProtocol(): Record<string, unknown> {
|
|
348
|
-
return { id: this.id, label: this.label };
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
export class Select extends WidgetBase {
|
|
353
|
-
constructor(
|
|
354
|
-
private readonly options: CommonProps & {
|
|
355
|
-
items?: SelectOption[];
|
|
356
|
-
selected?: number;
|
|
357
|
-
} = {},
|
|
358
|
-
) {
|
|
359
|
-
super(options);
|
|
156
|
+
step: this.options.step ?? 0.01,
|
|
157
|
+
interactive: this.options.interactive ?? this.options.on_change !== undefined,
|
|
158
|
+
};
|
|
159
|
+
for (const key of ["id", "icon", "text"] as const) if (this.options[key] !== undefined) out[key] = this.options[key];
|
|
160
|
+
return out;
|
|
360
161
|
}
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
const payload = this.withCommon({
|
|
364
|
-
items: (this.options.items ?? []).map((item) => item.toProtocol()),
|
|
365
|
-
});
|
|
366
|
-
if (this.options.selected !== undefined) payload.selected = this.options.selected;
|
|
367
|
-
return { type: "select", data: payload };
|
|
162
|
+
bindHandlers(registry: InlineHandlerRegistry, _path: number[]): void {
|
|
163
|
+
if (this.options.id && this.options.on_change) registry.add("change", this.options.id, this.options.on_change);
|
|
368
164
|
}
|
|
369
165
|
}
|
|
370
166
|
|
|
371
167
|
export class Separator extends WidgetBase {
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
toProtocol(): Record<string, unknown> {
|
|
377
|
-
const payload = this.withCommon({});
|
|
378
|
-
if (this.options.orientation !== undefined) payload.orientation = this.options.orientation;
|
|
379
|
-
return { type: "separator", data: payload };
|
|
380
|
-
}
|
|
168
|
+
readonly type = "separator";
|
|
169
|
+
constructor(common: CommonOptions = {}) { super(common); }
|
|
170
|
+
data(): Record<string, unknown> { return this.commonData(); }
|
|
381
171
|
}
|
|
382
172
|
|
|
383
173
|
export class Scroll extends WidgetBase {
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
) {
|
|
388
|
-
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
toProtocol(): Record<string, unknown> {
|
|
392
|
-
return { type: "scroll", data: this.withCommon({ child: this.child.toProtocol() }) };
|
|
174
|
+
readonly type = "scroll";
|
|
175
|
+
constructor(private readonly options: CommonOptions & { child: TreeNode }) { super(options); }
|
|
176
|
+
data(): Record<string, unknown> { return { ...this.commonData(), child: this.options.child.toProtocol() }; }
|
|
177
|
+
bindHandlers(registry: InlineHandlerRegistry, path: number[]): void {
|
|
178
|
+
this.options.child.bindHandlers(registry, [...path, 0]);
|
|
393
179
|
}
|
|
394
180
|
}
|
|
395
181
|
|
|
396
|
-
|
|
397
|
-
constructor(
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
) {
|
|
403
|
-
super(options);
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
toProtocol(): Record<string, unknown> {
|
|
407
|
-
return {
|
|
408
|
-
type: "overlay",
|
|
409
|
-
data: this.withCommon({
|
|
410
|
-
child: this.options.child.toProtocol(),
|
|
411
|
-
overlays: (this.options.overlays ?? []).map((overlay) => overlay.toProtocol()),
|
|
412
|
-
}),
|
|
413
|
-
};
|
|
182
|
+
abstract class ChildrenWidget extends WidgetBase {
|
|
183
|
+
constructor(common: CommonOptions & { children?: TreeNode[] } = {}) { super(common); this.kids = common.children ?? []; }
|
|
184
|
+
protected readonly kids: TreeNode[];
|
|
185
|
+
data(): Record<string, unknown> { return { ...this.commonData(), children: children(this.kids) }; }
|
|
186
|
+
bindHandlers(registry: InlineHandlerRegistry, path: number[]): void {
|
|
187
|
+
this.kids.forEach((kid, index) => kid.bindHandlers(registry, [...path, index]));
|
|
414
188
|
}
|
|
415
189
|
}
|
|
416
190
|
|
|
417
|
-
export class
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
} = {},
|
|
422
|
-
) {
|
|
423
|
-
super(options);
|
|
424
|
-
}
|
|
191
|
+
export class Row extends ChildrenWidget { readonly type = "row"; }
|
|
192
|
+
export class Column extends ChildrenWidget { readonly type = "column"; }
|
|
193
|
+
export class BoxedList extends ChildrenWidget { readonly type = "boxed_list"; }
|
|
194
|
+
export class ButtonRow extends ChildrenWidget { readonly type = "button_row"; }
|
|
425
195
|
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
196
|
+
export class CircleBox extends WidgetBase {
|
|
197
|
+
readonly type = "circle_box";
|
|
198
|
+
constructor(private readonly options: CommonOptions & { color: string }) { super(options); }
|
|
199
|
+
data(): Record<string, unknown> {
|
|
200
|
+
const out = this.commonData();
|
|
201
|
+
out.color = this.options.color;
|
|
202
|
+
return out;
|
|
433
203
|
}
|
|
434
204
|
}
|
|
435
205
|
|
|
436
|
-
export class
|
|
437
|
-
|
|
438
|
-
public readonly row: number,
|
|
439
|
-
public readonly column: number,
|
|
440
|
-
public readonly child: TreeNode,
|
|
441
|
-
public readonly width: number = 1,
|
|
442
|
-
public readonly height: number = 1,
|
|
443
|
-
) {}
|
|
444
|
-
|
|
445
|
-
toProtocol(): Record<string, unknown> {
|
|
446
|
-
return {
|
|
447
|
-
row: this.row,
|
|
448
|
-
column: this.column,
|
|
449
|
-
width: this.width,
|
|
450
|
-
height: this.height,
|
|
451
|
-
child: this.child.toProtocol(),
|
|
452
|
-
};
|
|
453
|
-
}
|
|
206
|
+
export class Container extends ChildrenWidget {
|
|
207
|
+
readonly type = "container";
|
|
454
208
|
}
|
|
455
209
|
|
|
456
|
-
export class
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
super(options);
|
|
210
|
+
export class PopoverShell extends ChildrenWidget {
|
|
211
|
+
readonly type = "popover_shell";
|
|
212
|
+
constructor(private readonly options: CommonOptions & { children?: TreeNode[]; size?: PopoverSize; footer?: TreeNode[]; footer_visible?: boolean } = {}) { super(options); }
|
|
213
|
+
data(): Record<string, unknown> {
|
|
214
|
+
const out: Record<string, unknown> = { ...super.data(), size: this.options.size ?? "medium" };
|
|
215
|
+
if ((this.options.footer ?? []).length > 0) out.footer = children(this.options.footer ?? []);
|
|
216
|
+
if (this.options.footer_visible) out.footer_visible = this.options.footer_visible;
|
|
217
|
+
return out;
|
|
465
218
|
}
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
type: "grid",
|
|
470
|
-
data: this.withCommon({
|
|
471
|
-
row_spacing: this.options.row_spacing ?? 0,
|
|
472
|
-
column_spacing: this.options.column_spacing ?? 0,
|
|
473
|
-
children: (this.options.children ?? []).map((child) => child.toProtocol()),
|
|
474
|
-
}),
|
|
475
|
-
};
|
|
219
|
+
bindHandlers(registry: InlineHandlerRegistry, path: number[]): void {
|
|
220
|
+
super.bindHandlers(registry, path);
|
|
221
|
+
(this.options.footer ?? []).forEach((kid, index) => kid.bindHandlers(registry, [...path, this.kids.length + index]));
|
|
476
222
|
}
|
|
477
223
|
}
|
|
478
224
|
|
|
479
|
-
export class
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
225
|
+
export class Tile extends WidgetBase {
|
|
226
|
+
readonly type: string = "tile";
|
|
227
|
+
constructor(protected readonly options: CommonOptions & { primary: string; id?: string; secondary?: string; left_icon?: string; left?: TreeNode; right?: TreeNode; on_click?: InlineHandler }) { super(options); }
|
|
228
|
+
data(): Record<string, unknown> {
|
|
229
|
+
const out: Record<string, unknown> = { ...this.commonData(), primary: this.options.primary };
|
|
230
|
+
for (const key of ["id", "secondary", "left_icon"] as const) if (this.options[key] !== undefined) out[key] = this.options[key];
|
|
231
|
+
const left = child(this.options.left);
|
|
232
|
+
const right = child(this.options.right);
|
|
233
|
+
if (left) out.left = left;
|
|
234
|
+
if (right) out.right = right;
|
|
235
|
+
return out;
|
|
488
236
|
}
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
237
|
+
bindHandlers(registry: InlineHandlerRegistry, path: number[]): void {
|
|
238
|
+
if (this.options.on_click) {
|
|
239
|
+
this.options.id = registry.targetId("click", this.options.id, path);
|
|
240
|
+
registry.add("click", this.options.id, this.options.on_click);
|
|
241
|
+
}
|
|
242
|
+
this.options.left?.bindHandlers(registry, [...path, 0]);
|
|
243
|
+
this.options.right?.bindHandlers(registry, [...path, 1]);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
export class SegmentedTile extends Tile {
|
|
248
|
+
readonly type = "segmented_tile";
|
|
249
|
+
constructor(protected readonly options: ConstructorParameters<typeof Tile>[0] & { child?: TreeNode; expanded?: boolean; on_toggle?: InlineHandler }) { super(options); }
|
|
250
|
+
data(): Record<string, unknown> {
|
|
251
|
+
const out = super.data();
|
|
252
|
+
const nested = child(this.options.child);
|
|
253
|
+
if (nested) out.child = nested;
|
|
254
|
+
out.expanded = this.options.expanded ?? false;
|
|
255
|
+
return out;
|
|
256
|
+
}
|
|
257
|
+
bindHandlers(registry: InlineHandlerRegistry, path: number[]): void {
|
|
258
|
+
super.bindHandlers(registry, path);
|
|
259
|
+
if (this.options.on_toggle) {
|
|
260
|
+
this.options.id = registry.targetId("toggle", this.options.id, path);
|
|
261
|
+
registry.add("toggle", this.options.id, this.options.on_toggle);
|
|
262
|
+
}
|
|
263
|
+
this.options.child?.bindHandlers(registry, [...path, 2]);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
export class SwitchTile extends WidgetBase {
|
|
268
|
+
readonly type = "switch_tile";
|
|
269
|
+
constructor(private readonly options: CommonOptions & { id: string; primary: string; secondary?: string; left_icon?: string; left?: TreeNode; active?: boolean; on_toggle?: InlineHandler }) { super(options); }
|
|
270
|
+
data(): Record<string, unknown> {
|
|
271
|
+
const out: Record<string, unknown> = { ...this.commonData(), id: this.options.id, primary: this.options.primary, active: this.options.active ?? false };
|
|
272
|
+
for (const key of ["secondary", "left_icon"] as const) if (this.options[key] !== undefined) out[key] = this.options[key];
|
|
273
|
+
const left = child(this.options.left);
|
|
274
|
+
if (left) out.left = left;
|
|
275
|
+
return out;
|
|
276
|
+
}
|
|
277
|
+
bindHandlers(registry: InlineHandlerRegistry, path: number[]): void {
|
|
278
|
+
if (this.options.on_toggle) registry.add("toggle", this.options.id, this.options.on_toggle);
|
|
279
|
+
this.options.left?.bindHandlers(registry, [...path, 0]);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
export class ExpanderTile extends WidgetBase {
|
|
284
|
+
readonly type = "expander_tile";
|
|
285
|
+
constructor(private readonly options: CommonOptions & { primary: string; id?: string; secondary?: string; left_icon?: string; left?: TreeNode; child?: TreeNode; expanded?: boolean; on_toggle?: InlineHandler }) { super(options); }
|
|
286
|
+
data(): Record<string, unknown> {
|
|
287
|
+
const out: Record<string, unknown> = { ...this.commonData(), primary: this.options.primary, expanded: this.options.expanded ?? false };
|
|
288
|
+
for (const key of ["id", "secondary", "left_icon"] as const) if (this.options[key] !== undefined) out[key] = this.options[key];
|
|
289
|
+
const left = child(this.options.left);
|
|
290
|
+
const nested = child(this.options.child);
|
|
291
|
+
if (left) out.left = left;
|
|
292
|
+
if (nested) out.child = nested;
|
|
293
|
+
return out;
|
|
294
|
+
}
|
|
295
|
+
bindHandlers(registry: InlineHandlerRegistry, path: number[]): void {
|
|
296
|
+
if (this.options.on_toggle) {
|
|
297
|
+
this.options.id = registry.targetId("toggle", this.options.id, path);
|
|
298
|
+
registry.add("toggle", this.options.id, this.options.on_toggle);
|
|
299
|
+
}
|
|
300
|
+
this.options.left?.bindHandlers(registry, [...path, 0]);
|
|
301
|
+
this.options.child?.bindHandlers(registry, [...path, 1]);
|
|
497
302
|
}
|
|
498
303
|
}
|
|
499
304
|
|
|
500
|
-
export class
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
305
|
+
export class SliderTile extends WidgetBase {
|
|
306
|
+
readonly type = "slider_tile";
|
|
307
|
+
constructor(private readonly options: CommonOptions & { id: string; label?: string; left_icon?: string; left?: TreeNode; value?: number; min?: number; max?: number; step?: number; page?: number; digits?: number; snap_step?: number; on_change?: InlineHandler }) { super(options); }
|
|
308
|
+
data(): Record<string, unknown> {
|
|
309
|
+
const out: Record<string, unknown> = { ...this.commonData(), id: this.options.id, value: this.options.value ?? 0, min: this.options.min ?? 0, max: this.options.max ?? 1, step: this.options.step ?? 0.01, page: this.options.page ?? 0.1, digits: this.options.digits ?? 0 };
|
|
310
|
+
for (const key of ["label", "left_icon", "snap_step"] as const) if (this.options[key] !== undefined) out[key] = this.options[key];
|
|
311
|
+
const left = child(this.options.left);
|
|
312
|
+
if (left) out.left = left;
|
|
313
|
+
return out;
|
|
507
314
|
}
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
type: "card",
|
|
512
|
-
data: this.withCommon({
|
|
513
|
-
children: (this.options.children ?? []).map((child) => child.toProtocol()),
|
|
514
|
-
}),
|
|
515
|
-
};
|
|
315
|
+
bindHandlers(registry: InlineHandlerRegistry, path: number[]): void {
|
|
316
|
+
if (this.options.on_change) registry.add("change", this.options.id, this.options.on_change);
|
|
317
|
+
this.options.left?.bindHandlers(registry, [...path, 0]);
|
|
516
318
|
}
|
|
517
319
|
}
|
|
518
320
|
|
|
519
|
-
export class
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
321
|
+
export class ChoiceTile extends WidgetBase {
|
|
322
|
+
readonly type = "choice_tile";
|
|
323
|
+
constructor(private readonly options: CommonOptions & { primary: string; id?: string; secondary?: string; left_icon?: string; left?: TreeNode; selected?: boolean; on_click?: InlineHandler }) { super(options); }
|
|
324
|
+
data(): Record<string, unknown> {
|
|
325
|
+
const out: Record<string, unknown> = { ...this.commonData(), primary: this.options.primary, selected: this.options.selected ?? false };
|
|
326
|
+
for (const key of ["id", "secondary", "left_icon"] as const) if (this.options[key] !== undefined) out[key] = this.options[key];
|
|
327
|
+
const left = child(this.options.left);
|
|
328
|
+
if (left) out.left = left;
|
|
329
|
+
return out;
|
|
528
330
|
}
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
children: (this.options.children ?? []).map((child) => child.toProtocol()),
|
|
534
|
-
};
|
|
535
|
-
if (this.options.subtitle !== undefined && this.options.subtitle !== "") {
|
|
536
|
-
payload.subtitle = this.options.subtitle;
|
|
331
|
+
bindHandlers(registry: InlineHandlerRegistry, path: number[]): void {
|
|
332
|
+
if (this.options.on_click) {
|
|
333
|
+
this.options.id = registry.targetId("click", this.options.id, path);
|
|
334
|
+
registry.add("click", this.options.id, this.options.on_click);
|
|
537
335
|
}
|
|
538
|
-
|
|
539
|
-
type: "section",
|
|
540
|
-
data: this.withCommon(payload),
|
|
541
|
-
};
|
|
336
|
+
this.options.left?.bindHandlers(registry, [...path, 0]);
|
|
542
337
|
}
|
|
543
338
|
}
|
|
544
339
|
|
|
545
|
-
export class
|
|
546
|
-
constructor(
|
|
547
|
-
private readonly options: CommonProps & {
|
|
548
|
-
icon?: Icon;
|
|
549
|
-
label?: string;
|
|
550
|
-
value: number;
|
|
551
|
-
min?: number;
|
|
552
|
-
max?: number;
|
|
553
|
-
step?: number;
|
|
554
|
-
text?: string;
|
|
555
|
-
interactive?: boolean;
|
|
556
|
-
},
|
|
557
|
-
) {
|
|
558
|
-
super(options);
|
|
559
|
-
}
|
|
560
|
-
|
|
340
|
+
export class Choice {
|
|
341
|
+
constructor(public readonly options: { id: string; primary: string; secondary?: string; icon?: string }) {}
|
|
561
342
|
toProtocol(): Record<string, unknown> {
|
|
562
|
-
const
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
max: this.options.max ?? 1,
|
|
567
|
-
step: this.options.step ?? 0.01,
|
|
568
|
-
interactive: this.options.interactive ?? false,
|
|
569
|
-
});
|
|
570
|
-
if (this.options.icon !== undefined) payload.icon = this.options.icon.toProtocol();
|
|
571
|
-
if (this.options.text !== undefined) payload.text = this.options.text;
|
|
572
|
-
return { type: "meter", data: payload };
|
|
343
|
+
const out: Record<string, unknown> = { id: this.options.id, primary: this.options.primary };
|
|
344
|
+
if (this.options.secondary !== undefined) out.secondary = this.options.secondary;
|
|
345
|
+
if (this.options.icon !== undefined) out.icon = this.options.icon;
|
|
346
|
+
return out;
|
|
573
347
|
}
|
|
574
348
|
}
|
|
575
349
|
|
|
576
|
-
export class
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
super(options);
|
|
350
|
+
export class ChoiceList extends WidgetBase {
|
|
351
|
+
readonly type = "choice_list";
|
|
352
|
+
constructor(private readonly options: CommonOptions & { id: string; choices?: Choice[]; active?: string; on_change?: InlineHandler }) { super(options); }
|
|
353
|
+
data(): Record<string, unknown> {
|
|
354
|
+
const out: Record<string, unknown> = { ...this.commonData(), id: this.options.id, choices: (this.options.choices ?? []).map((choice) => choice.toProtocol()) };
|
|
355
|
+
if (this.options.active !== undefined) out.active = this.options.active;
|
|
356
|
+
return out;
|
|
584
357
|
}
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
return {
|
|
588
|
-
type: "copyable",
|
|
589
|
-
data: this.withCommon({
|
|
590
|
-
label: this.options.label ?? "",
|
|
591
|
-
value: this.options.value,
|
|
592
|
-
}),
|
|
593
|
-
};
|
|
358
|
+
bindHandlers(registry: InlineHandlerRegistry, _path: number[]): void {
|
|
359
|
+
if (this.options.on_change) registry.add("change", this.options.id, this.options.on_change);
|
|
594
360
|
}
|
|
595
361
|
}
|
|
596
362
|
|
|
597
|
-
export class
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
children?: TreeNode[];
|
|
602
|
-
} = {},
|
|
603
|
-
) {
|
|
604
|
-
super(options);
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
toProtocol(): Record<string, unknown> {
|
|
608
|
-
return {
|
|
609
|
-
type: "row",
|
|
610
|
-
data: this.withCommon({
|
|
611
|
-
spacing: this.options.spacing ?? 0,
|
|
612
|
-
children: (this.options.children ?? []).map((child) => child.toProtocol()),
|
|
613
|
-
}),
|
|
614
|
-
};
|
|
615
|
-
}
|
|
363
|
+
export class KeyValueGrid extends WidgetBase {
|
|
364
|
+
readonly type = "key_value_grid";
|
|
365
|
+
constructor(private readonly options: CommonOptions & { rows?: { key: string; value: string }[] } = {}) { super(options); }
|
|
366
|
+
data(): Record<string, unknown> { return { ...this.commonData(), rows: this.options.rows ?? [] }; }
|
|
616
367
|
}
|
|
617
368
|
|
|
618
|
-
export class
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
} = {},
|
|
624
|
-
) {
|
|
625
|
-
super(options);
|
|
626
|
-
}
|
|
627
|
-
|
|
628
|
-
toProtocol(): Record<string, unknown> {
|
|
629
|
-
return {
|
|
630
|
-
type: "column",
|
|
631
|
-
data: this.withCommon({
|
|
632
|
-
spacing: this.options.spacing ?? 0,
|
|
633
|
-
children: (this.options.children ?? []).map((child) => child.toProtocol()),
|
|
634
|
-
}),
|
|
635
|
-
};
|
|
636
|
-
}
|
|
369
|
+
export class PagerItem extends WidgetBase {
|
|
370
|
+
readonly type = "pager_item";
|
|
371
|
+
constructor(private readonly options: CommonOptions & { id: number; label?: string; appearance?: PagerAppearance; active?: boolean; inactive?: boolean; occupied?: boolean; urgent?: boolean; on_click?: InlineHandler }) { super(options); }
|
|
372
|
+
data(): Record<string, unknown> { return { ...this.commonData(), id: this.options.id, label: this.options.label ?? "", appearance: this.options.appearance ?? "dots", active: this.options.active ?? false, inactive: this.options.inactive ?? false, occupied: this.options.occupied ?? false, urgent: this.options.urgent ?? false }; }
|
|
373
|
+
bindHandlers(registry: InlineHandlerRegistry, _path: number[]): void { if (this.options.on_click) registry.add("click", String(this.options.id), this.options.on_click); }
|
|
637
374
|
}
|
|
638
375
|
|
|
639
|
-
export class
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
376
|
+
export class PagerStrip extends WidgetBase {
|
|
377
|
+
readonly type = "pager_strip";
|
|
378
|
+
constructor(private readonly options: CommonOptions & { id?: string; items?: PagerItem[]; placeholder?: boolean; on_change?: InlineHandler } = {}) { super(options); }
|
|
379
|
+
data(): Record<string, unknown> {
|
|
380
|
+
const out: Record<string, unknown> = { ...this.commonData(), placeholder: this.options.placeholder ?? false, items: (this.options.items ?? []).map((item) => item.data()) };
|
|
381
|
+
if (this.options.id !== undefined) out.id = this.options.id;
|
|
382
|
+
return out;
|
|
646
383
|
}
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
type: "spinner",
|
|
651
|
-
data: this.withCommon({ spinning: this.options.spinning ?? true }),
|
|
652
|
-
};
|
|
384
|
+
bindHandlers(registry: InlineHandlerRegistry, path: number[]): void {
|
|
385
|
+
if (this.options.id && this.options.on_change) registry.add("change", this.options.id, this.options.on_change);
|
|
386
|
+
(this.options.items ?? []).forEach((item, index) => item.bindHandlers(registry, [...path, index]));
|
|
653
387
|
}
|
|
654
388
|
}
|
|
655
389
|
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
constructor(
|
|
660
|
-
private readonly options: CommonProps & {
|
|
661
|
-
title?: string;
|
|
662
|
-
rows?: Properties;
|
|
663
|
-
} = {},
|
|
664
|
-
) {
|
|
665
|
-
super(options);
|
|
666
|
-
}
|
|
667
|
-
|
|
668
|
-
toProtocol(): Record<string, unknown> {
|
|
669
|
-
const payload: Record<string, unknown> = {
|
|
670
|
-
rows: Object.entries(this.options.rows ?? {}).map(([key, value]) => ({ key, value })),
|
|
671
|
-
};
|
|
672
|
-
if (this.options.title !== undefined && this.options.title !== "") {
|
|
673
|
-
payload.title = this.options.title;
|
|
674
|
-
}
|
|
675
|
-
return {
|
|
676
|
-
type: "property_list",
|
|
677
|
-
data: this.withCommon(payload),
|
|
678
|
-
};
|
|
679
|
-
}
|
|
390
|
+
abstract class ActiveIndicator extends WidgetBase {
|
|
391
|
+
constructor(protected readonly options: CommonOptions & { active?: boolean } = {}) { super(options); }
|
|
392
|
+
data(): Record<string, unknown> { return { ...this.commonData(), active: this.options.active ?? false }; }
|
|
680
393
|
}
|
|
681
394
|
|
|
682
|
-
export class
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
sublabel?: string;
|
|
687
|
-
icon?: string;
|
|
688
|
-
right?: TreeNode;
|
|
689
|
-
},
|
|
690
|
-
) {
|
|
691
|
-
super(options);
|
|
692
|
-
}
|
|
395
|
+
export class CameraIndicator extends ActiveIndicator { readonly type = "camera_indicator"; }
|
|
396
|
+
export class MicIndicator extends ActiveIndicator { readonly type = "mic_indicator"; }
|
|
397
|
+
export class MutedIndicator extends ActiveIndicator { readonly type = "muted_indicator"; }
|
|
398
|
+
export class LocationIndicator extends ActiveIndicator { readonly type = "location_indicator"; }
|
|
693
399
|
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
if (this.options.sublabel !== undefined && this.options.sublabel !== "") {
|
|
702
|
-
payload.sublabel = this.options.sublabel;
|
|
703
|
-
}
|
|
704
|
-
if (this.options.right !== undefined) {
|
|
705
|
-
payload.right = this.options.right.toProtocol();
|
|
706
|
-
}
|
|
707
|
-
return {
|
|
708
|
-
type: "item",
|
|
709
|
-
data: this.withCommon(payload),
|
|
710
|
-
};
|
|
400
|
+
export class ScreenCastIndicator extends ActiveIndicator {
|
|
401
|
+
readonly type = "screencast_indicator";
|
|
402
|
+
constructor(protected readonly options: CommonOptions & { active?: boolean; timer_text?: string } = {}) { super(options); }
|
|
403
|
+
data(): Record<string, unknown> {
|
|
404
|
+
const out = super.data();
|
|
405
|
+
if (this.options.timer_text !== undefined) out.timer_text = this.options.timer_text;
|
|
406
|
+
return out;
|
|
711
407
|
}
|
|
712
408
|
}
|
|
713
409
|
|
|
714
|
-
export class
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
enabled?: boolean;
|
|
722
|
-
},
|
|
723
|
-
) {
|
|
724
|
-
super(options);
|
|
725
|
-
}
|
|
726
|
-
|
|
727
|
-
toProtocol(): Record<string, unknown> {
|
|
728
|
-
const payload: Record<string, unknown> = {
|
|
729
|
-
label: this.options.label,
|
|
730
|
-
};
|
|
731
|
-
if (this.options.icon !== undefined && this.options.icon !== "") {
|
|
732
|
-
payload.icon = this.options.icon;
|
|
733
|
-
}
|
|
734
|
-
if (this.options.sublabel !== undefined && this.options.sublabel !== "") {
|
|
735
|
-
payload.sublabel = this.options.sublabel;
|
|
736
|
-
}
|
|
737
|
-
if (this.options.right !== undefined) {
|
|
738
|
-
payload.right = this.options.right.toProtocol();
|
|
739
|
-
}
|
|
740
|
-
if (this.options.enabled !== undefined) {
|
|
741
|
-
payload.enabled = this.options.enabled;
|
|
742
|
-
}
|
|
743
|
-
return {
|
|
744
|
-
type: "action_item",
|
|
745
|
-
data: this.withCommon(payload),
|
|
746
|
-
};
|
|
410
|
+
export class Calendar extends WidgetBase {
|
|
411
|
+
readonly type = "calendar";
|
|
412
|
+
constructor(private readonly options: CommonOptions & { selected_date: string; id?: string; event_days?: string[]; on_change?: InlineHandler }) { super(options); }
|
|
413
|
+
data(): Record<string, unknown> {
|
|
414
|
+
const out: Record<string, unknown> = { ...this.commonData(), selected_date: this.options.selected_date, event_days: this.options.event_days ?? [] };
|
|
415
|
+
if (this.options.id !== undefined) out.id = this.options.id;
|
|
416
|
+
return out;
|
|
747
417
|
}
|
|
418
|
+
bindHandlers(registry: InlineHandlerRegistry, _path: number[]): void { if (this.options.id && this.options.on_change) registry.add("change", this.options.id, this.options.on_change); }
|
|
748
419
|
}
|
|
749
420
|
|
|
750
|
-
export class
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
subtitle?: string;
|
|
755
|
-
},
|
|
756
|
-
) {
|
|
757
|
-
super(options);
|
|
758
|
-
}
|
|
759
|
-
|
|
760
|
-
toProtocol(): Record<string, unknown> {
|
|
761
|
-
return {
|
|
762
|
-
type: "empty_state",
|
|
763
|
-
data: this.withCommon({
|
|
764
|
-
title: this.options.title,
|
|
765
|
-
subtitle: this.options.subtitle ?? "",
|
|
766
|
-
}),
|
|
767
|
-
};
|
|
768
|
-
}
|
|
421
|
+
export class BatteryHero extends WidgetBase {
|
|
422
|
+
readonly type = "battery_hero";
|
|
423
|
+
constructor(private readonly options: CommonOptions & { icon: string; percentage: string; fraction: number; state: string }) { super(options); }
|
|
424
|
+
data(): Record<string, unknown> { return { ...this.commonData(), icon: this.options.icon, percentage: this.options.percentage, fraction: this.options.fraction, state: this.options.state }; }
|
|
769
425
|
}
|
|
770
426
|
|
|
771
|
-
export class
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
) {
|
|
777
|
-
super(options);
|
|
778
|
-
}
|
|
427
|
+
export class DateHero extends WidgetBase {
|
|
428
|
+
readonly type = "date_hero";
|
|
429
|
+
constructor(private readonly options: CommonOptions & { weekday: string; date: string }) { super(options); }
|
|
430
|
+
data(): Record<string, unknown> { return { ...this.commonData(), weekday: this.options.weekday, date: this.options.date }; }
|
|
431
|
+
}
|
|
779
432
|
|
|
433
|
+
export class EventItem {
|
|
434
|
+
constructor(public readonly options: { id: string; title: string; start: string; end?: string; location?: string; all_day?: boolean }) {}
|
|
780
435
|
toProtocol(): Record<string, unknown> {
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
label: this.options.label,
|
|
785
|
-
}),
|
|
786
|
-
};
|
|
436
|
+
const out: Record<string, unknown> = { id: this.options.id, title: this.options.title, start: this.options.start, end: this.options.end ?? "", all_day: this.options.all_day ?? false };
|
|
437
|
+
if (this.options.location !== undefined) out.location = this.options.location;
|
|
438
|
+
return out;
|
|
787
439
|
}
|
|
788
440
|
}
|
|
789
441
|
|
|
790
|
-
export class
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
}
|
|
442
|
+
export class Events extends WidgetBase {
|
|
443
|
+
readonly type = "events";
|
|
444
|
+
constructor(private readonly options: CommonOptions & { date: string; events?: EventItem[]; loading?: boolean }) { super(options); }
|
|
445
|
+
data(): Record<string, unknown> { return { ...this.commonData(), date: this.options.date, loading: this.options.loading ?? false, events: (this.options.events ?? []).map((event) => event.toProtocol()) }; }
|
|
446
|
+
}
|
|
794
447
|
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
}
|
|
448
|
+
export class WeatherForecastItem {
|
|
449
|
+
constructor(public readonly options: { day_name: string; icon: string; condition: string; temperatures: string; is_today?: boolean }) {}
|
|
450
|
+
toProtocol(): Record<string, unknown> { return { day_name: this.options.day_name, icon: this.options.icon, condition: this.options.condition, temperatures: this.options.temperatures, is_today: this.options.is_today ?? false }; }
|
|
798
451
|
}
|
|
799
452
|
|
|
800
|
-
export class
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
active?: boolean;
|
|
806
|
-
inactive?: boolean;
|
|
807
|
-
occupied?: boolean;
|
|
808
|
-
urgent?: boolean;
|
|
809
|
-
} = {},
|
|
810
|
-
) {
|
|
811
|
-
super(options);
|
|
812
|
-
}
|
|
813
|
-
|
|
814
|
-
toData(): Record<string, unknown> {
|
|
815
|
-
return this.withCommon({
|
|
816
|
-
appearance: this.options.appearance ?? "dots",
|
|
817
|
-
label: this.options.label ?? "",
|
|
818
|
-
active: this.options.active ?? false,
|
|
819
|
-
inactive: this.options.inactive ?? false,
|
|
820
|
-
occupied: this.options.occupied ?? false,
|
|
821
|
-
urgent: this.options.urgent ?? false,
|
|
822
|
-
});
|
|
823
|
-
}
|
|
453
|
+
export class WeatherForecastList extends WidgetBase {
|
|
454
|
+
readonly type = "weather_forecast_list";
|
|
455
|
+
constructor(private readonly options: CommonOptions & { items?: WeatherForecastItem[] } = {}) { super(options); }
|
|
456
|
+
data(): Record<string, unknown> { return { ...this.commonData(), items: (this.options.items ?? []).map((item) => item.toProtocol()) }; }
|
|
457
|
+
}
|
|
824
458
|
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
data: this.toData(),
|
|
829
|
-
};
|
|
830
|
-
}
|
|
459
|
+
export class WeatherHourlyItem {
|
|
460
|
+
constructor(public readonly options: { time: string; icon: string; temperature: string }) {}
|
|
461
|
+
toProtocol(): Record<string, unknown> { return { time: this.options.time, icon: this.options.icon, temperature: this.options.temperature }; }
|
|
831
462
|
}
|
|
832
463
|
|
|
833
|
-
export class
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
) {
|
|
839
|
-
super(options);
|
|
840
|
-
}
|
|
464
|
+
export class WeatherHourlyStrip extends WidgetBase {
|
|
465
|
+
readonly type = "weather_hourly_strip";
|
|
466
|
+
constructor(private readonly options: CommonOptions & { items?: WeatherHourlyItem[] } = {}) { super(options); }
|
|
467
|
+
data(): Record<string, unknown> { return { ...this.commonData(), items: (this.options.items ?? []).map((item) => item.toProtocol()) }; }
|
|
468
|
+
}
|
|
841
469
|
|
|
470
|
+
export class WorldClockRow {
|
|
471
|
+
constructor(public readonly options: { name: string; timezone: string; time: string; offset: string; day_label?: string }) {}
|
|
842
472
|
toProtocol(): Record<string, unknown> {
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
items: (this.options.items ?? []).map((item) => item.toData()),
|
|
847
|
-
}),
|
|
848
|
-
};
|
|
473
|
+
const out: Record<string, unknown> = { name: this.options.name, timezone: this.options.timezone, time: this.options.time, offset: this.options.offset };
|
|
474
|
+
if (this.options.day_label !== undefined) out.day_label = this.options.day_label;
|
|
475
|
+
return out;
|
|
849
476
|
}
|
|
850
477
|
}
|
|
851
478
|
|
|
852
|
-
export class
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
spacing?: number;
|
|
857
|
-
children?: TreeNode[];
|
|
858
|
-
} = {},
|
|
859
|
-
) {
|
|
860
|
-
super(options);
|
|
861
|
-
}
|
|
862
|
-
|
|
863
|
-
static vertical(children: TreeNode[], spacing = 0, options: CommonProps = {}): Box {
|
|
864
|
-
return new Box({ ...options, orientation: "vertical", spacing, children });
|
|
865
|
-
}
|
|
866
|
-
|
|
867
|
-
static horizontal(children: TreeNode[], spacing = 0, options: CommonProps = {}): Box {
|
|
868
|
-
return new Box({ ...options, orientation: "horizontal", spacing, children });
|
|
869
|
-
}
|
|
870
|
-
|
|
871
|
-
toProtocol(): Record<string, unknown> {
|
|
872
|
-
return {
|
|
873
|
-
type: "box",
|
|
874
|
-
data: this.withCommon({
|
|
875
|
-
orientation: this.options.orientation ?? "vertical",
|
|
876
|
-
spacing: this.options.spacing ?? 0,
|
|
877
|
-
children: (this.options.children ?? []).map((child) => child.toProtocol()),
|
|
878
|
-
}),
|
|
879
|
-
};
|
|
880
|
-
}
|
|
479
|
+
export class WorldClock extends WidgetBase {
|
|
480
|
+
readonly type = "world_clock";
|
|
481
|
+
constructor(private readonly options: CommonOptions & { rows?: WorldClockRow[] } = {}) { super(options); }
|
|
482
|
+
data(): Record<string, unknown> { return { ...this.commonData(), rows: (this.options.rows ?? []).map((row) => row.toProtocol()) }; }
|
|
881
483
|
}
|
|
882
484
|
|
|
883
485
|
export type TreeNode =
|
|
884
|
-
|
|
|
885
|
-
|
|
|
886
|
-
|
|
|
887
|
-
|
|
|
888
|
-
|
|
|
889
|
-
|
|
|
890
|
-
| Item
|
|
891
|
-
| ActionItem
|
|
892
|
-
| EmptyState
|
|
893
|
-
| Badge
|
|
894
|
-
| StatusDot
|
|
895
|
-
| PagerItem
|
|
896
|
-
| PagerStrip
|
|
897
|
-
| Box
|
|
898
|
-
| Row
|
|
899
|
-
| Column
|
|
900
|
-
| Grid
|
|
901
|
-
| Scroll
|
|
902
|
-
| Overlay
|
|
903
|
-
| ListBox
|
|
904
|
-
| LevelBar
|
|
905
|
-
| TreeExpander
|
|
906
|
-
| MenuButton
|
|
907
|
-
| Progress
|
|
908
|
-
| Separator
|
|
909
|
-
| Spinner
|
|
910
|
-
| Label
|
|
911
|
-
| Image
|
|
912
|
-
| Picture
|
|
913
|
-
| Button
|
|
914
|
-
| LinkButton
|
|
915
|
-
| Expander
|
|
916
|
-
| Switch
|
|
917
|
-
| ToggleButton
|
|
918
|
-
| Slider
|
|
919
|
-
| Select
|
|
920
|
-
| Checkbox;
|
|
486
|
+
| Row | Column | Container | CircleBox | BoxedList | PopoverShell
|
|
487
|
+
| Label | Header | Hero | Badge | StatusDot | PanelIndicator | EmptyState | Spinner | Meter | Separator | Scroll
|
|
488
|
+
| Tile | SegmentedTile | ButtonRow | SwitchTile | ExpanderTile | SliderTile | ChoiceTile | ChoiceList | KeyValueGrid
|
|
489
|
+
| PagerItem | PagerStrip
|
|
490
|
+
| CameraIndicator | MicIndicator | MutedIndicator | ScreenCastIndicator | LocationIndicator
|
|
491
|
+
| Calendar | BatteryHero | DateHero | Events | WeatherForecastList | WeatherHourlyStrip | WorldClock;
|