@sigrun/shared 0.0.0-stage → 0.1.1
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/CHANGELOG.md +16 -0
- package/LICENSE +21 -0
- package/README.md +9 -2
- package/dist/access.d.ts +55 -0
- package/dist/access.js +72 -0
- package/dist/ambient.d.ts +111 -0
- package/dist/ambient.js +23 -0
- package/dist/blocks/format.d.ts +28 -0
- package/dist/blocks/format.js +199 -0
- package/dist/blocks/icons.d.ts +12 -0
- package/dist/blocks/icons.js +64 -0
- package/dist/blocks/index.d.ts +24 -0
- package/dist/blocks/index.js +20 -0
- package/dist/blocks/lttb.d.ts +16 -0
- package/dist/blocks/lttb.js +67 -0
- package/dist/blocks/ops.d.ts +44 -0
- package/dist/blocks/ops.js +294 -0
- package/dist/blocks/text.d.ts +43 -0
- package/dist/blocks/text.js +790 -0
- package/dist/blocks/transport.d.ts +77 -0
- package/dist/blocks/transport.js +11 -0
- package/dist/blocks/types.d.ts +541 -0
- package/dist/blocks/types.js +17 -0
- package/dist/commands.d.ts +75 -0
- package/dist/commands.js +25 -0
- package/dist/conversations.d.ts +31 -0
- package/dist/conversations.js +94 -0
- package/dist/interactions.d.ts +91 -0
- package/dist/interactions.js +21 -0
- package/dist/jobs.d.ts +109 -0
- package/dist/jobs.js +19 -0
- package/dist/json.d.ts +20 -0
- package/dist/json.js +13 -0
- package/dist/live.d.ts +71 -0
- package/dist/live.js +82 -0
- package/dist/session-meta.d.ts +119 -0
- package/dist/session-meta.js +13 -0
- package/dist/settings.d.ts +408 -0
- package/dist/settings.js +19 -0
- package/dist/themes.d.ts +50 -0
- package/dist/themes.js +156 -0
- package/dist/turns.d.ts +119 -0
- package/dist/turns.js +197 -0
- package/dist/view-delta.d.ts +54 -0
- package/dist/view-delta.js +135 -0
- package/dist/views.d.ts +784 -0
- package/dist/views.js +38 -0
- package/package.json +90 -5
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The surface transport (UI-blocks U0): the ONE interface both clients'
|
|
3
|
+
* block renderers talk to a surface through. Implemented by U3
|
|
4
|
+
* (extension surfaces, over HTTP/SSE) and U5 (chat, in-process); U1
|
|
5
|
+
* (webui) and U2 (tui) consume it — so the clients' surface code never
|
|
6
|
+
* knows which kind of surface it is holding.
|
|
7
|
+
*
|
|
8
|
+
* Types only. The wire shapes come from the sibling modules; nothing
|
|
9
|
+
* here is runtime.
|
|
10
|
+
*/
|
|
11
|
+
import type { JsonObject, JsonValue } from "../json.js";
|
|
12
|
+
import type { Action, DataOp, Tree } from "./types.js";
|
|
13
|
+
/** The principal's access to a surface (spec §6.5). */
|
|
14
|
+
export type SurfaceAccess = "none" | "read" | "write";
|
|
15
|
+
/** The initial-load result: everything a first render needs. */
|
|
16
|
+
export interface SurfaceLoad {
|
|
17
|
+
tree: Tree;
|
|
18
|
+
data: JsonObject;
|
|
19
|
+
rev: number;
|
|
20
|
+
treeRev: number;
|
|
21
|
+
access: SurfaceAccess;
|
|
22
|
+
}
|
|
23
|
+
/** An incremental fetch: ops since `since` when the surface shares data
|
|
24
|
+
* (§7.3), else the full `data` object; `rev`/`treeRev` always current. */
|
|
25
|
+
export interface SurfaceFetch {
|
|
26
|
+
rev: number;
|
|
27
|
+
treeRev: number;
|
|
28
|
+
data?: JsonObject;
|
|
29
|
+
ops?: DataOp[];
|
|
30
|
+
}
|
|
31
|
+
/** What a handler's accepted action returns (§6.3). */
|
|
32
|
+
export type SurfaceActOk = {
|
|
33
|
+
ok: true;
|
|
34
|
+
rev: number;
|
|
35
|
+
ops?: DataOp[];
|
|
36
|
+
navigate?: Action;
|
|
37
|
+
toast?: string;
|
|
38
|
+
};
|
|
39
|
+
/** What a rejected action returns. */
|
|
40
|
+
export type SurfaceActErr = {
|
|
41
|
+
ok: false;
|
|
42
|
+
error: {
|
|
43
|
+
message: string;
|
|
44
|
+
field?: string;
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
export type SurfaceActResult = SurfaceActOk | SurfaceActErr;
|
|
48
|
+
/** An upload through the surface's upload route (§7.2). */
|
|
49
|
+
export interface SurfaceUploadBody {
|
|
50
|
+
field: string;
|
|
51
|
+
name: string;
|
|
52
|
+
bytes: Uint8Array;
|
|
53
|
+
actionId: string;
|
|
54
|
+
}
|
|
55
|
+
/** A change notification (fed by `surface.changed`, §7.3). */
|
|
56
|
+
export interface SurfaceChangedEvent {
|
|
57
|
+
rev: number;
|
|
58
|
+
treeRev: number;
|
|
59
|
+
}
|
|
60
|
+
/** The channel-facing surface handle (load, fetch, act, upload, image,
|
|
61
|
+
* subscribe). `image` fetches through the server's proxy for the TUI
|
|
62
|
+
* (§11.3); `onChanged` listeners fire on every surface change. */
|
|
63
|
+
export interface SurfaceTransport {
|
|
64
|
+
load(): Promise<SurfaceLoad>;
|
|
65
|
+
fetchData(since?: number): Promise<SurfaceFetch>;
|
|
66
|
+
act(body: {
|
|
67
|
+
action: string;
|
|
68
|
+
payload: JsonValue;
|
|
69
|
+
actionId: string;
|
|
70
|
+
}): Promise<SurfaceActResult>;
|
|
71
|
+
upload(body: SurfaceUploadBody): Promise<SurfaceActResult>;
|
|
72
|
+
/** TUI image fetch (U7 routes); `asPng` selects the decodable form. */
|
|
73
|
+
image(src: string, opts: {
|
|
74
|
+
asPng: boolean;
|
|
75
|
+
}): Promise<Uint8Array>;
|
|
76
|
+
onChanged(listener: (e: SurfaceChangedEvent) => void): () => void;
|
|
77
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The surface transport (UI-blocks U0): the ONE interface both clients'
|
|
3
|
+
* block renderers talk to a surface through. Implemented by U3
|
|
4
|
+
* (extension surfaces, over HTTP/SSE) and U5 (chat, in-process); U1
|
|
5
|
+
* (webui) and U2 (tui) consume it — so the clients' surface code never
|
|
6
|
+
* knows which kind of surface it is holding.
|
|
7
|
+
*
|
|
8
|
+
* Types only. The wire shapes come from the sibling modules; nothing
|
|
9
|
+
* here is runtime.
|
|
10
|
+
*/
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,541 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The block-set wire types (UI-blocks U0, spec §4/§5/§6.1/§12.2).
|
|
3
|
+
*
|
|
4
|
+
* Types only (plus the one version constant): the runtime half lives in
|
|
5
|
+
* `ops.ts`/`lttb.ts`/`icons.ts`, and everything here is the CHANNEL
|
|
6
|
+
* CONTRACT both clients (webui, tui) and the server share. Purity is
|
|
7
|
+
* guarded by `test/views-purity.test.ts`: every specifier resolves
|
|
8
|
+
* inside `shared/src/`, imports are type-only, and there is no
|
|
9
|
+
* dependency beyond the leaf itself.
|
|
10
|
+
*
|
|
11
|
+
* Convention: a prop that can change at runtime is `T | Binding`
|
|
12
|
+
* (spec §4.2). STRUCTURAL props — `type`, `id`, `display`, `groupBy`,
|
|
13
|
+
* `groups`, `reorder`, `select`, `mode`, field `name`s, `columns`, and
|
|
14
|
+
* every handler name — are literals, never bindings.
|
|
15
|
+
*/
|
|
16
|
+
import type { IconName } from "./icons.js";
|
|
17
|
+
import type { JsonObject, JsonValue } from "../json.js";
|
|
18
|
+
/** The block-set version this module defines (spec §4.4: this spec is `v: 1`). */
|
|
19
|
+
export declare const BLOCK_SET_VERSION = 1;
|
|
20
|
+
/** Meaning-based colouring (spec §10.1); each maps to the active theme's tokens. */
|
|
21
|
+
export type Tone = "neutral" | "accent" | "good" | "warn" | "bad" | "info";
|
|
22
|
+
/** Channel-defined width tokens (the webui maps s/m/l to 16/24/32 rem, the TUI to 30/45/60 cells). */
|
|
23
|
+
export type Size = "s" | "m" | "l";
|
|
24
|
+
/** A JSON Pointer into the surface's data model (spec §4.2). */
|
|
25
|
+
export type Binding = {
|
|
26
|
+
$: string;
|
|
27
|
+
};
|
|
28
|
+
/** Anything a block can show whose value lives in the data model. */
|
|
29
|
+
export type Bindable<T> = T | Binding;
|
|
30
|
+
/** Where a surface appears (spec §3); each placement allows a subset of blocks (§5.7). */
|
|
31
|
+
export type Placement = "view" | "panel" | "settings" | "chat" | "interaction" | "ambient";
|
|
32
|
+
/**
|
|
33
|
+
* The only width-dependent thing a block can say (spec §12.2): hidden in
|
|
34
|
+
* a compact container. Other values are added when a case needs them.
|
|
35
|
+
*/
|
|
36
|
+
export type WidthCondition = "atLeast:regular";
|
|
37
|
+
/** The value formats (spec §5.3), used on `stat`, `meter`, table columns and chart axes. */
|
|
38
|
+
export type Format = "number" | "compact" | "percent" | `currency:${string}` | "bytes" | "duration" | "datetime" | "date" | "time" | "relative";
|
|
39
|
+
export type Action = {
|
|
40
|
+
type: "submit";
|
|
41
|
+
name: string;
|
|
42
|
+
turn?: boolean;
|
|
43
|
+
confirm?: Confirm;
|
|
44
|
+
} | {
|
|
45
|
+
type: "navigate";
|
|
46
|
+
params?: JsonObject;
|
|
47
|
+
target?: CoreTarget;
|
|
48
|
+
} | {
|
|
49
|
+
type: "move";
|
|
50
|
+
name: string;
|
|
51
|
+
turn?: boolean;
|
|
52
|
+
} | {
|
|
53
|
+
type: "edit";
|
|
54
|
+
name: string;
|
|
55
|
+
turn?: boolean;
|
|
56
|
+
} | {
|
|
57
|
+
type: "open";
|
|
58
|
+
url: string;
|
|
59
|
+
} | {
|
|
60
|
+
type: "copy";
|
|
61
|
+
text: string | Binding;
|
|
62
|
+
} | {
|
|
63
|
+
type: "restart";
|
|
64
|
+
confirm?: Confirm;
|
|
65
|
+
};
|
|
66
|
+
export type Confirm = {
|
|
67
|
+
title: string;
|
|
68
|
+
body?: string;
|
|
69
|
+
tone?: "bad" | "warn";
|
|
70
|
+
confirmLabel?: string;
|
|
71
|
+
};
|
|
72
|
+
export type CoreTarget = {
|
|
73
|
+
conversation: number;
|
|
74
|
+
} | {
|
|
75
|
+
job: string;
|
|
76
|
+
} | {
|
|
77
|
+
settings: string;
|
|
78
|
+
} | {
|
|
79
|
+
view: {
|
|
80
|
+
extension: string;
|
|
81
|
+
id: string;
|
|
82
|
+
params?: JsonObject;
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
/** A block-offered button (spec §6.1): where `Action` objects appear. */
|
|
86
|
+
export interface ActionButton {
|
|
87
|
+
id: string;
|
|
88
|
+
label: Bindable<string>;
|
|
89
|
+
icon?: IconName;
|
|
90
|
+
action: Action;
|
|
91
|
+
}
|
|
92
|
+
/** Props every block may carry (spec §4.1). */
|
|
93
|
+
export interface BlockBase {
|
|
94
|
+
/** Required on blocks that carry actions or inputs; unique within the tree. */
|
|
95
|
+
readonly id?: string;
|
|
96
|
+
readonly visibleAt?: WidthCondition;
|
|
97
|
+
/** Plain text a channel shows when it can't render the block. */
|
|
98
|
+
readonly fallback?: string;
|
|
99
|
+
}
|
|
100
|
+
/** A block tree: the root block plus the version it was written against. */
|
|
101
|
+
export type Tree = {
|
|
102
|
+
v: number;
|
|
103
|
+
root: Block;
|
|
104
|
+
};
|
|
105
|
+
/** The state shown instead of `main` when main's first collection is empty. */
|
|
106
|
+
export interface PageEmpty {
|
|
107
|
+
icon: IconName;
|
|
108
|
+
title: string;
|
|
109
|
+
hint?: string;
|
|
110
|
+
}
|
|
111
|
+
export interface PageBlock extends BlockBase {
|
|
112
|
+
readonly type: "page";
|
|
113
|
+
readonly title: Bindable<string>;
|
|
114
|
+
readonly subtitle?: Bindable<string>;
|
|
115
|
+
/** A `choice` field in the header; selecting navigates. */
|
|
116
|
+
readonly switcher?: ChoiceField;
|
|
117
|
+
readonly actions?: readonly ActionButton[];
|
|
118
|
+
/** Blocks for the list column. */
|
|
119
|
+
readonly sidebar?: readonly Block[];
|
|
120
|
+
readonly main: readonly Block[];
|
|
121
|
+
/** Blocks for a side pane, shown when non-empty. */
|
|
122
|
+
readonly detail?: readonly Block[];
|
|
123
|
+
readonly empty?: PageEmpty;
|
|
124
|
+
}
|
|
125
|
+
export interface StackBlock extends BlockBase {
|
|
126
|
+
readonly type: "stack";
|
|
127
|
+
readonly children: readonly Block[];
|
|
128
|
+
readonly gap?: Size;
|
|
129
|
+
}
|
|
130
|
+
export interface ColumnChild {
|
|
131
|
+
readonly weight?: number;
|
|
132
|
+
readonly minWidth?: Size;
|
|
133
|
+
readonly block: Block;
|
|
134
|
+
}
|
|
135
|
+
export interface ColumnsBlock extends BlockBase {
|
|
136
|
+
readonly type: "columns";
|
|
137
|
+
readonly children: readonly ColumnChild[];
|
|
138
|
+
}
|
|
139
|
+
export interface GridChild {
|
|
140
|
+
readonly span?: 1 | 2 | "full";
|
|
141
|
+
readonly block: Block;
|
|
142
|
+
}
|
|
143
|
+
export interface GridBlock extends BlockBase {
|
|
144
|
+
readonly type: "grid";
|
|
145
|
+
readonly minItemWidth: Size;
|
|
146
|
+
readonly children: readonly GridChild[];
|
|
147
|
+
}
|
|
148
|
+
export interface SectionBlock extends BlockBase {
|
|
149
|
+
readonly type: "section";
|
|
150
|
+
readonly title?: Bindable<string>;
|
|
151
|
+
readonly subtitle?: Bindable<string>;
|
|
152
|
+
readonly tone?: Bindable<Tone>;
|
|
153
|
+
readonly collapsible?: boolean;
|
|
154
|
+
readonly collapsed?: boolean;
|
|
155
|
+
/** Blocks; inside a `form`, fields and nested `section`s. */
|
|
156
|
+
readonly children: readonly (Block | Field)[];
|
|
157
|
+
}
|
|
158
|
+
export interface MarkdownBlock extends BlockBase {
|
|
159
|
+
readonly type: "markdown";
|
|
160
|
+
readonly text: Bindable<string>;
|
|
161
|
+
}
|
|
162
|
+
export interface FieldsRow {
|
|
163
|
+
readonly label: Bindable<string>;
|
|
164
|
+
readonly value: Bindable<JsonValue>;
|
|
165
|
+
readonly tone?: Bindable<Tone>;
|
|
166
|
+
readonly icon?: Bindable<IconName>;
|
|
167
|
+
}
|
|
168
|
+
export interface FieldsBlock extends BlockBase {
|
|
169
|
+
readonly type: "fields";
|
|
170
|
+
readonly rows: Bindable<readonly FieldsRow[]>;
|
|
171
|
+
}
|
|
172
|
+
export interface StatBlock extends BlockBase {
|
|
173
|
+
readonly type: "stat";
|
|
174
|
+
readonly label: Bindable<string>;
|
|
175
|
+
readonly value: Bindable<JsonValue>;
|
|
176
|
+
readonly unit?: Bindable<string>;
|
|
177
|
+
readonly format?: Format;
|
|
178
|
+
readonly tone?: Bindable<Tone>;
|
|
179
|
+
readonly icon?: Bindable<IconName>;
|
|
180
|
+
readonly size?: Size;
|
|
181
|
+
readonly caption?: Bindable<string>;
|
|
182
|
+
readonly sparkline?: Bindable<readonly number[]>;
|
|
183
|
+
}
|
|
184
|
+
export interface CalloutBlock extends BlockBase {
|
|
185
|
+
readonly type: "callout";
|
|
186
|
+
readonly tone: Bindable<Tone>;
|
|
187
|
+
readonly title: Bindable<string>;
|
|
188
|
+
/** Markdown. */
|
|
189
|
+
readonly body?: Bindable<string>;
|
|
190
|
+
readonly actions?: readonly ActionButton[];
|
|
191
|
+
}
|
|
192
|
+
export interface ImageBlock extends BlockBase {
|
|
193
|
+
readonly type: "image";
|
|
194
|
+
readonly src: Bindable<string>;
|
|
195
|
+
/** Required. */
|
|
196
|
+
readonly alt: Bindable<string>;
|
|
197
|
+
}
|
|
198
|
+
export interface ChartAxisX {
|
|
199
|
+
readonly kind: "time" | "category" | "number";
|
|
200
|
+
readonly format?: Format;
|
|
201
|
+
readonly label?: Bindable<string>;
|
|
202
|
+
}
|
|
203
|
+
export interface ChartAxisY {
|
|
204
|
+
readonly format?: Format;
|
|
205
|
+
readonly unit?: Bindable<string>;
|
|
206
|
+
readonly label?: Bindable<string>;
|
|
207
|
+
readonly min?: number;
|
|
208
|
+
readonly max?: number;
|
|
209
|
+
}
|
|
210
|
+
export interface ChartSeries {
|
|
211
|
+
readonly name: Bindable<string>;
|
|
212
|
+
readonly kind: "line" | "area" | "bar";
|
|
213
|
+
readonly data: Binding | readonly [number, number][];
|
|
214
|
+
}
|
|
215
|
+
export interface ChartThreshold {
|
|
216
|
+
readonly at: number;
|
|
217
|
+
readonly tone: Tone;
|
|
218
|
+
readonly label?: Bindable<string>;
|
|
219
|
+
}
|
|
220
|
+
export interface ChartBlock extends BlockBase {
|
|
221
|
+
readonly type: "chart";
|
|
222
|
+
readonly title?: Bindable<string>;
|
|
223
|
+
readonly x: ChartAxisX;
|
|
224
|
+
readonly y?: ChartAxisY;
|
|
225
|
+
readonly series: readonly ChartSeries[];
|
|
226
|
+
/** Stack `area` and `bar` series. */
|
|
227
|
+
readonly stacked?: boolean;
|
|
228
|
+
/** Drawn as horizontal rules. */
|
|
229
|
+
readonly thresholds?: readonly ChartThreshold[];
|
|
230
|
+
}
|
|
231
|
+
export interface MeterThreshold {
|
|
232
|
+
readonly at: number;
|
|
233
|
+
readonly tone: Tone;
|
|
234
|
+
}
|
|
235
|
+
export interface MeterBlock extends BlockBase {
|
|
236
|
+
readonly type: "meter";
|
|
237
|
+
readonly value: Bindable<number>;
|
|
238
|
+
/** Default 0. */
|
|
239
|
+
readonly min?: number;
|
|
240
|
+
/** Default 1. */
|
|
241
|
+
readonly max?: number;
|
|
242
|
+
readonly label?: Bindable<string>;
|
|
243
|
+
readonly format?: Format;
|
|
244
|
+
readonly thresholds?: readonly MeterThreshold[];
|
|
245
|
+
}
|
|
246
|
+
export interface LogLine {
|
|
247
|
+
readonly at?: number | string;
|
|
248
|
+
readonly level?: string;
|
|
249
|
+
readonly text: string;
|
|
250
|
+
}
|
|
251
|
+
export interface LogBlock extends BlockBase {
|
|
252
|
+
readonly type: "log";
|
|
253
|
+
readonly lines: Binding;
|
|
254
|
+
readonly follow?: boolean;
|
|
255
|
+
readonly wrap?: boolean;
|
|
256
|
+
/** Per-level tones; default `error`→bad, `warn`→warn, `info`→neutral, `debug`→subtle. */
|
|
257
|
+
readonly tones?: Readonly<Record<string, Tone>>;
|
|
258
|
+
}
|
|
259
|
+
export interface TreeNode {
|
|
260
|
+
readonly id: string;
|
|
261
|
+
readonly label: string;
|
|
262
|
+
readonly icon?: IconName;
|
|
263
|
+
readonly hasChildren?: boolean;
|
|
264
|
+
readonly children?: readonly TreeNode[];
|
|
265
|
+
}
|
|
266
|
+
export interface TreeBlock extends BlockBase {
|
|
267
|
+
readonly type: "tree";
|
|
268
|
+
readonly nodes: Binding;
|
|
269
|
+
/** Handler for lazy children; it returns `DataOps` inserting them. */
|
|
270
|
+
readonly onExpand?: string;
|
|
271
|
+
readonly onActivate?: Action;
|
|
272
|
+
}
|
|
273
|
+
export interface DiffBlock extends BlockBase {
|
|
274
|
+
readonly type: "diff";
|
|
275
|
+
readonly before: string;
|
|
276
|
+
readonly after: string;
|
|
277
|
+
readonly path?: string;
|
|
278
|
+
readonly lang?: string;
|
|
279
|
+
}
|
|
280
|
+
export interface DetailsBlock extends BlockBase {
|
|
281
|
+
readonly type: "details";
|
|
282
|
+
/** Opaque JSON; shown collapsed and pretty-printed. */
|
|
283
|
+
readonly value: JsonValue;
|
|
284
|
+
}
|
|
285
|
+
/** One inline fact of a card's `meta` slot (spec §5.5.1). */
|
|
286
|
+
export type CardMeta = {
|
|
287
|
+
icon?: Bindable<IconName>;
|
|
288
|
+
text: Bindable<string>;
|
|
289
|
+
} | {
|
|
290
|
+
person: {
|
|
291
|
+
user: Bindable<string>;
|
|
292
|
+
name: Bindable<string>;
|
|
293
|
+
};
|
|
294
|
+
} | {
|
|
295
|
+
time: Bindable<string>;
|
|
296
|
+
format?: Format;
|
|
297
|
+
};
|
|
298
|
+
export interface CardMetric {
|
|
299
|
+
readonly label: Bindable<string>;
|
|
300
|
+
readonly value: Bindable<JsonValue>;
|
|
301
|
+
readonly format?: Format;
|
|
302
|
+
}
|
|
303
|
+
export interface CardBadge {
|
|
304
|
+
readonly text: Bindable<string>;
|
|
305
|
+
readonly tone?: Bindable<Tone>;
|
|
306
|
+
}
|
|
307
|
+
export interface CardStatus {
|
|
308
|
+
readonly label: Bindable<string>;
|
|
309
|
+
readonly tone?: Bindable<Tone>;
|
|
310
|
+
readonly spinner?: Bindable<boolean>;
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* The card template (spec §5.5.1): every slot except `title` is
|
|
314
|
+
* optional; each takes a binding relative to the item.
|
|
315
|
+
*/
|
|
316
|
+
export interface Card {
|
|
317
|
+
readonly eyebrow?: Bindable<string>;
|
|
318
|
+
readonly title: Bindable<string>;
|
|
319
|
+
readonly subtitle?: Bindable<string>;
|
|
320
|
+
/** Markdown, clamped to 4 lines in lists and lanes. */
|
|
321
|
+
readonly body?: Bindable<string>;
|
|
322
|
+
readonly image?: Bindable<string>;
|
|
323
|
+
readonly icon?: Bindable<IconName>;
|
|
324
|
+
readonly badges?: readonly CardBadge[];
|
|
325
|
+
readonly meta?: readonly CardMeta[];
|
|
326
|
+
readonly metrics?: readonly CardMetric[];
|
|
327
|
+
/** Accent stripe / TUI marker. */
|
|
328
|
+
readonly tone?: Bindable<Tone>;
|
|
329
|
+
/** Up to 3 buttons, then an overflow menu. */
|
|
330
|
+
readonly actions?: readonly ActionButton[];
|
|
331
|
+
readonly status?: CardStatus;
|
|
332
|
+
/** The item is folded away by default behind an "N more" toggle. */
|
|
333
|
+
readonly quiet?: Bindable<boolean>;
|
|
334
|
+
/** Ids of items this one depends on ("after: …" markers). */
|
|
335
|
+
readonly deps?: Bindable<readonly string[]>;
|
|
336
|
+
}
|
|
337
|
+
export interface CollectionGroup {
|
|
338
|
+
readonly id: string;
|
|
339
|
+
readonly title: Bindable<string>;
|
|
340
|
+
readonly tone?: Tone;
|
|
341
|
+
readonly collapsed?: boolean;
|
|
342
|
+
}
|
|
343
|
+
export interface CollectionSort {
|
|
344
|
+
readonly field: string;
|
|
345
|
+
readonly dir: "asc" | "desc";
|
|
346
|
+
}
|
|
347
|
+
export interface BulkAction {
|
|
348
|
+
readonly id: string;
|
|
349
|
+
readonly label: Bindable<string>;
|
|
350
|
+
readonly icon?: IconName;
|
|
351
|
+
readonly onSubmit: string;
|
|
352
|
+
readonly form?: Tree;
|
|
353
|
+
}
|
|
354
|
+
export interface CollectionColumn {
|
|
355
|
+
readonly field: string;
|
|
356
|
+
readonly label: Bindable<string>;
|
|
357
|
+
readonly format?: Format;
|
|
358
|
+
readonly cell?: "text" | "meter" | "badge";
|
|
359
|
+
readonly sortable?: boolean;
|
|
360
|
+
readonly priority?: "high" | "low";
|
|
361
|
+
readonly width?: Size;
|
|
362
|
+
}
|
|
363
|
+
export interface CollectionTime {
|
|
364
|
+
/** Item field names. */
|
|
365
|
+
readonly start: string;
|
|
366
|
+
readonly end?: string;
|
|
367
|
+
readonly allDay?: string;
|
|
368
|
+
readonly range: "month" | "week" | "day" | "agenda";
|
|
369
|
+
/** Enables dragging an item's end. */
|
|
370
|
+
readonly onResize?: string;
|
|
371
|
+
/** Enables drag-to-create; payload `{start, end}`. */
|
|
372
|
+
readonly onCreate?: string;
|
|
373
|
+
}
|
|
374
|
+
export interface CollectionBlock extends BlockBase {
|
|
375
|
+
readonly type: "collection";
|
|
376
|
+
/** Binding to an array; each item has a unique `id`. */
|
|
377
|
+
readonly items: Binding;
|
|
378
|
+
/** The card template. */
|
|
379
|
+
readonly item: Card;
|
|
380
|
+
readonly display: "list" | "table" | "lanes" | "grid" | "calendar";
|
|
381
|
+
/** Item field to group on. */
|
|
382
|
+
readonly groupBy?: string;
|
|
383
|
+
/** Ordered groups; with `lanes` these are the lanes. */
|
|
384
|
+
readonly groups?: readonly CollectionGroup[];
|
|
385
|
+
readonly sort?: CollectionSort;
|
|
386
|
+
readonly select?: "single" | "multi";
|
|
387
|
+
readonly bulkActions?: readonly BulkAction[];
|
|
388
|
+
/** Item field holding a boolean; toggling calls `onCheck`. */
|
|
389
|
+
readonly checkable?: string;
|
|
390
|
+
/** Requires `onMove`. */
|
|
391
|
+
readonly reorder?: {
|
|
392
|
+
within?: boolean;
|
|
393
|
+
across?: boolean;
|
|
394
|
+
};
|
|
395
|
+
/** Item field holding nested items (indented in `list`). */
|
|
396
|
+
readonly children?: string;
|
|
397
|
+
/** `list` only. */
|
|
398
|
+
readonly numbered?: boolean;
|
|
399
|
+
/** Handler names (spec §6.1). */
|
|
400
|
+
readonly onMove?: string;
|
|
401
|
+
readonly onCheck?: string;
|
|
402
|
+
/** An `Action` run when an item is activated. */
|
|
403
|
+
readonly onActivate?: Action;
|
|
404
|
+
/** `table` only. */
|
|
405
|
+
readonly columns?: readonly CollectionColumn[];
|
|
406
|
+
/** `calendar` only. */
|
|
407
|
+
readonly time?: CollectionTime;
|
|
408
|
+
/** `grid` only: `wrap` (default) or `scroll` (one horizontal row). */
|
|
409
|
+
readonly overflow?: "wrap" | "scroll";
|
|
410
|
+
}
|
|
411
|
+
/** Props shared by every field type (spec §5.6). */
|
|
412
|
+
export interface FieldBase {
|
|
413
|
+
/** The path its value is read from and written to, relative to the form's `bind`. */
|
|
414
|
+
readonly name: string;
|
|
415
|
+
readonly label: Bindable<string>;
|
|
416
|
+
readonly help?: Bindable<string>;
|
|
417
|
+
readonly placeholder?: Bindable<string>;
|
|
418
|
+
readonly required?: boolean;
|
|
419
|
+
readonly disabled?: boolean;
|
|
420
|
+
/** §13; settings only. */
|
|
421
|
+
readonly apply?: "live" | "restart";
|
|
422
|
+
readonly min?: number;
|
|
423
|
+
readonly max?: number;
|
|
424
|
+
readonly minLength?: number;
|
|
425
|
+
readonly maxLength?: number;
|
|
426
|
+
readonly pattern?: string;
|
|
427
|
+
}
|
|
428
|
+
export interface TextField extends FieldBase {
|
|
429
|
+
readonly type: "text";
|
|
430
|
+
readonly kind?: "plain" | "search" | "email" | "url";
|
|
431
|
+
/** Binding to strings. */
|
|
432
|
+
readonly suggest?: Binding;
|
|
433
|
+
}
|
|
434
|
+
export interface LongtextField extends FieldBase {
|
|
435
|
+
readonly type: "longtext";
|
|
436
|
+
readonly syntax?: "plain" | "markdown" | "code";
|
|
437
|
+
readonly lang?: string;
|
|
438
|
+
readonly rows?: number;
|
|
439
|
+
}
|
|
440
|
+
export interface NumberField extends FieldBase {
|
|
441
|
+
readonly type: "number";
|
|
442
|
+
readonly step?: number;
|
|
443
|
+
readonly format?: Format;
|
|
444
|
+
}
|
|
445
|
+
export interface ToggleField extends FieldBase {
|
|
446
|
+
readonly type: "toggle";
|
|
447
|
+
}
|
|
448
|
+
export interface ChoiceOption {
|
|
449
|
+
readonly id: string;
|
|
450
|
+
readonly label: Bindable<string>;
|
|
451
|
+
readonly description?: Bindable<string>;
|
|
452
|
+
readonly tone?: Tone;
|
|
453
|
+
readonly recommended?: boolean;
|
|
454
|
+
/** Markdown shown beside the options while one is focused (interactions). */
|
|
455
|
+
readonly preview?: string;
|
|
456
|
+
}
|
|
457
|
+
export interface ChoiceField extends FieldBase {
|
|
458
|
+
readonly type: "choice";
|
|
459
|
+
/** Literal or binding. */
|
|
460
|
+
readonly options: Bindable<readonly ChoiceOption[]>;
|
|
461
|
+
readonly multi?: boolean;
|
|
462
|
+
readonly allowOther?: {
|
|
463
|
+
label?: string;
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
export interface DateField extends FieldBase {
|
|
467
|
+
readonly type: "date";
|
|
468
|
+
}
|
|
469
|
+
export interface DatetimeField extends FieldBase {
|
|
470
|
+
readonly type: "datetime";
|
|
471
|
+
}
|
|
472
|
+
export interface DatePreset {
|
|
473
|
+
readonly id: string;
|
|
474
|
+
readonly label: string;
|
|
475
|
+
readonly duration: string;
|
|
476
|
+
}
|
|
477
|
+
export interface DaterangeField extends FieldBase {
|
|
478
|
+
readonly type: "daterange";
|
|
479
|
+
readonly presets?: readonly DatePreset[];
|
|
480
|
+
}
|
|
481
|
+
/** Write-only; the channel shows `set (stored)` / `set (env)` / `not set` from a bound status. */
|
|
482
|
+
export interface SecretField extends FieldBase {
|
|
483
|
+
readonly type: "secret";
|
|
484
|
+
}
|
|
485
|
+
export interface FileField extends FieldBase {
|
|
486
|
+
readonly type: "file";
|
|
487
|
+
/** MIME patterns. */
|
|
488
|
+
readonly accept?: string;
|
|
489
|
+
readonly maxBytes?: number;
|
|
490
|
+
readonly multi?: boolean;
|
|
491
|
+
/** Handler; uploads through the surface's upload route. */
|
|
492
|
+
readonly onUpload: string;
|
|
493
|
+
}
|
|
494
|
+
export interface ListField extends FieldBase {
|
|
495
|
+
readonly type: "list";
|
|
496
|
+
/** Fields for one entry (a repeatable group). */
|
|
497
|
+
readonly item: Field;
|
|
498
|
+
readonly reorder?: boolean;
|
|
499
|
+
readonly min?: number;
|
|
500
|
+
readonly max?: number;
|
|
501
|
+
}
|
|
502
|
+
export type Field = TextField | LongtextField | NumberField | ToggleField | ChoiceField | DateField | DatetimeField | DaterangeField | SecretField | FileField | ListField;
|
|
503
|
+
export interface FormBlock extends BlockBase {
|
|
504
|
+
readonly type: "form";
|
|
505
|
+
/** Path of the object the fields read and write. */
|
|
506
|
+
readonly bind: string;
|
|
507
|
+
/** `submit` (a Save/Send button), `live` (every change after 300 ms), `inline` (one row). */
|
|
508
|
+
readonly mode: "submit" | "live" | "inline";
|
|
509
|
+
readonly onSubmit?: string;
|
|
510
|
+
readonly submitLabel?: Bindable<string>;
|
|
511
|
+
/** Chat only (§6.2). */
|
|
512
|
+
readonly turn?: boolean;
|
|
513
|
+
/** Fields and `section`s grouping them. */
|
|
514
|
+
readonly children: readonly (Field | SectionBlock)[];
|
|
515
|
+
}
|
|
516
|
+
export type Block = PageBlock | StackBlock | ColumnsBlock | GridBlock | SectionBlock | MarkdownBlock | FieldsBlock | StatBlock | CalloutBlock | ImageBlock | ChartBlock | MeterBlock | LogBlock | TreeBlock | DiffBlock | DetailsBlock | CollectionBlock | FormBlock;
|
|
517
|
+
export type DataOp = {
|
|
518
|
+
op: "set";
|
|
519
|
+
path: string;
|
|
520
|
+
value: JsonValue;
|
|
521
|
+
} | {
|
|
522
|
+
op: "remove";
|
|
523
|
+
path: string;
|
|
524
|
+
} | {
|
|
525
|
+
op: "insert";
|
|
526
|
+
path: string;
|
|
527
|
+
value: JsonValue;
|
|
528
|
+
} | {
|
|
529
|
+
op: "move";
|
|
530
|
+
from: string;
|
|
531
|
+
path: string;
|
|
532
|
+
};
|
|
533
|
+
/** What extensions and tools hand the server (no rev). */
|
|
534
|
+
export type DataOps = {
|
|
535
|
+
ops: DataOp[];
|
|
536
|
+
};
|
|
537
|
+
/** What the server sends channels (it assigns the monotonic `rev`). */
|
|
538
|
+
export type DataUpdate = {
|
|
539
|
+
rev: number;
|
|
540
|
+
ops: DataOp[];
|
|
541
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The block-set wire types (UI-blocks U0, spec §4/§5/§6.1/§12.2).
|
|
3
|
+
*
|
|
4
|
+
* Types only (plus the one version constant): the runtime half lives in
|
|
5
|
+
* `ops.ts`/`lttb.ts`/`icons.ts`, and everything here is the CHANNEL
|
|
6
|
+
* CONTRACT both clients (webui, tui) and the server share. Purity is
|
|
7
|
+
* guarded by `test/views-purity.test.ts`: every specifier resolves
|
|
8
|
+
* inside `shared/src/`, imports are type-only, and there is no
|
|
9
|
+
* dependency beyond the leaf itself.
|
|
10
|
+
*
|
|
11
|
+
* Convention: a prop that can change at runtime is `T | Binding`
|
|
12
|
+
* (spec §4.2). STRUCTURAL props — `type`, `id`, `display`, `groupBy`,
|
|
13
|
+
* `groups`, `reorder`, `select`, `mode`, field `name`s, `columns`, and
|
|
14
|
+
* every handler name — are literals, never bindings.
|
|
15
|
+
*/
|
|
16
|
+
/** The block-set version this module defines (spec §4.4: this spec is `v: 1`). */
|
|
17
|
+
export const BLOCK_SET_VERSION = 1;
|