take4-console 0.15.0 → 0.25.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/CHANGELOG.md +365 -0
- package/README.md +1 -1
- package/dist/Screen/InterfaceBuilder.d.mts +15 -4
- package/dist/Screen/InterfaceBuilder.d.mts.map +1 -1
- package/dist/Screen/InterfaceBuilder.mjs +104 -8
- package/dist/Screen/InterfaceBuilder.mjs.map +1 -1
- package/dist/Screen/Pos.d.mts +12 -0
- package/dist/Screen/Pos.d.mts.map +1 -1
- package/dist/Screen/Pos.mjs +23 -1
- package/dist/Screen/Pos.mjs.map +1 -1
- package/dist/Screen/Screen.d.mts +77 -3
- package/dist/Screen/Screen.d.mts.map +1 -1
- package/dist/Screen/Screen.mjs +168 -3
- package/dist/Screen/Screen.mjs.map +1 -1
- package/dist/Screen/Size.d.mts +49 -6
- package/dist/Screen/Size.d.mts.map +1 -1
- package/dist/Screen/Size.mjs +81 -7
- package/dist/Screen/Size.mjs.map +1 -1
- package/dist/Screen/Window.d.mts +131 -20
- package/dist/Screen/Window.d.mts.map +1 -1
- package/dist/Screen/Window.mjs +474 -57
- package/dist/Screen/Window.mjs.map +1 -1
- package/dist/Screen/WindowManager.d.mts +85 -5
- package/dist/Screen/WindowManager.d.mts.map +1 -1
- package/dist/Screen/WindowManager.mjs +279 -26
- package/dist/Screen/WindowManager.mjs.map +1 -1
- package/dist/Screen/controls/ListBox.d.mts +34 -12
- package/dist/Screen/controls/ListBox.d.mts.map +1 -1
- package/dist/Screen/controls/ListBox.mjs +127 -25
- package/dist/Screen/controls/ListBox.mjs.map +1 -1
- package/dist/Screen/controls/TextArea.d.mts +15 -1
- package/dist/Screen/controls/TextArea.d.mts.map +1 -1
- package/dist/Screen/controls/TextArea.mjs +74 -1
- package/dist/Screen/controls/TextArea.mjs.map +1 -1
- package/dist/Screen/controls/TextBox.d.mts +13 -1
- package/dist/Screen/controls/TextBox.d.mts.map +1 -1
- package/dist/Screen/controls/TextBox.mjs +36 -1
- package/dist/Screen/controls/TextBox.mjs.map +1 -1
- package/dist/Screen/textWidth.d.mts +13 -0
- package/dist/Screen/textWidth.d.mts.map +1 -0
- package/dist/Screen/textWidth.mjs +188 -0
- package/dist/Screen/textWidth.mjs.map +1 -0
- package/dist/Screen/types.d.mts +336 -20
- package/dist/Screen/types.d.mts.map +1 -1
- package/dist/Screen/types.mjs.map +1 -1
- package/dist/index.d.mts +3 -2
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +3 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -4
- package/src/Screen/InterfaceBuilder.mts +116 -20
- package/src/Screen/Pos.mts +24 -1
- package/src/Screen/Screen.mts +192 -4
- package/src/Screen/Size.mts +97 -12
- package/src/Screen/Window.mts +463 -63
- package/src/Screen/WindowManager.mts +301 -29
- package/src/Screen/controls/ListBox.mts +151 -32
- package/src/Screen/controls/TextArea.mts +82 -1
- package/src/Screen/controls/TextBox.mts +40 -1
- package/src/Screen/textWidth.mts +186 -0
- package/src/Screen/types.mts +328 -23
- package/src/demo.mts +232 -20
- package/src/index.mts +23 -3
- package/src/layout.yaml +56 -24
package/src/Screen/types.mts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { Pos } from './Pos.mjs';
|
|
2
2
|
import type { Size } from './Size.mjs';
|
|
3
|
+
import type { Window } from './Window.mjs';
|
|
4
|
+
import type { StyleRegistry } from './StyleRegistry.mjs';
|
|
3
5
|
|
|
4
6
|
/** Text and background color, expressed as ANSI color number (0–255) or hex string (e.g. '#ff0000'). */
|
|
5
7
|
export type Color = number | string;
|
|
@@ -57,8 +59,63 @@ export interface TerminalSize {
|
|
|
57
59
|
height: number;
|
|
58
60
|
}
|
|
59
61
|
|
|
60
|
-
/**
|
|
61
|
-
|
|
62
|
+
/** Constructor options for Screen. All fields are optional; defaults preserve
|
|
63
|
+
* the pre-0.19.0 behaviour where Screen does not touch the terminal state on
|
|
64
|
+
* construction (WindowManager.run/stop handle alt-screen and cursor hiding).
|
|
65
|
+
* Setting any flag here lets a Screen-only consumer (no WindowManager) opt
|
|
66
|
+
* into the same lifecycle semantics without writing the boilerplate by hand. */
|
|
67
|
+
export interface ScreenOptions {
|
|
68
|
+
/** Switch to the terminal's alternate screen buffer on construction and
|
|
69
|
+
* restore the primary buffer on dispose() / process exit. Default: false. */
|
|
70
|
+
altScreen?: boolean;
|
|
71
|
+
/** Hide the hardware cursor on construction and restore on dispose() /
|
|
72
|
+
* process exit. Default: false. */
|
|
73
|
+
hideCursor?: boolean;
|
|
74
|
+
/** Soft cap on render frequency in frames per second. Stored on the Screen
|
|
75
|
+
* for inspection; full enforcement (frame coalescing) lands with backlog
|
|
76
|
+
* item P2-47. Default: undefined (uncapped). */
|
|
77
|
+
targetFps?: number;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** Statistics emitted by the Screen 'frame' event after each render() call. */
|
|
81
|
+
export interface ScreenFrameStats {
|
|
82
|
+
/** Wall-clock duration of the render() call in milliseconds. */
|
|
83
|
+
ms: number;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Box-drawing character style for window borders.
|
|
87
|
+
* - 'single' ─│┌┐└┘ classic light box drawing
|
|
88
|
+
* - 'double' ═║╔╗╚╝ double-line box drawing
|
|
89
|
+
* - 'rounded' ─│╭╮╰╯ light box with rounded corners
|
|
90
|
+
* - 'thick' ━┃┏┓┗┛ heavy / bold box drawing
|
|
91
|
+
* - 'dashed' ╌╎┌┐└┘ dashed lines with light corners
|
|
92
|
+
* - 'ascii' -|+ plain ASCII fallback for non-Unicode terminals
|
|
93
|
+
* - 'none' placeholder equivalent to no border (no insets, no painting). */
|
|
94
|
+
export type BorderStyle = 'single' | 'double' | 'rounded' | 'thick' | 'dashed' | 'ascii' | 'none';
|
|
95
|
+
|
|
96
|
+
/** Glyphs used to draw a window border. The four corners and the two edge
|
|
97
|
+
* characters are mandatory; T-junctions and the cross are optional and only
|
|
98
|
+
* used by composite controls (tables, split panes) that draw inner lines. */
|
|
99
|
+
export interface BorderChars {
|
|
100
|
+
/** Horizontal edge glyph (top and bottom rows). */
|
|
101
|
+
horizontal: string;
|
|
102
|
+
/** Vertical edge glyph (left and right columns). */
|
|
103
|
+
vertical: string;
|
|
104
|
+
topLeft: string;
|
|
105
|
+
topRight: string;
|
|
106
|
+
bottomLeft: string;
|
|
107
|
+
bottomRight: string;
|
|
108
|
+
/** T-junction joining a horizontal line to the right side of a vertical line. */
|
|
109
|
+
verticalLeft?: string;
|
|
110
|
+
/** T-junction joining a horizontal line to the left side of a vertical line. */
|
|
111
|
+
verticalRight?: string;
|
|
112
|
+
/** T-junction joining a vertical line to the bottom of a horizontal line. */
|
|
113
|
+
horizontalTop?: string;
|
|
114
|
+
/** T-junction joining a vertical line to the top of a horizontal line. */
|
|
115
|
+
horizontalBottom?: string;
|
|
116
|
+
/** Four-way intersection. */
|
|
117
|
+
cross?: string;
|
|
118
|
+
}
|
|
62
119
|
|
|
63
120
|
/** Per-side border configuration. */
|
|
64
121
|
export interface WindowBorder {
|
|
@@ -70,6 +127,10 @@ export interface WindowBorder {
|
|
|
70
127
|
style?: BorderStyle;
|
|
71
128
|
/** Border color. Default: inherits from cell. */
|
|
72
129
|
color?: Color;
|
|
130
|
+
/** Optional per-glyph overrides applied on top of the chosen `style`'s char set.
|
|
131
|
+
* Useful for swapping individual characters (e.g. a custom corner) without
|
|
132
|
+
* redefining the entire set. */
|
|
133
|
+
chars?: Partial<BorderChars>;
|
|
73
134
|
}
|
|
74
135
|
|
|
75
136
|
/** Common properties shared by Window and all controls. Passed as the first constructor parameter. */
|
|
@@ -92,19 +153,92 @@ export interface WindowProperties {
|
|
|
92
153
|
disabled?: boolean;
|
|
93
154
|
/** Text label displayed by the control. Default: ''. */
|
|
94
155
|
label?: string;
|
|
156
|
+
/** Layout algorithm applied to the direct children of this window. Default:
|
|
157
|
+
* 'absolute' (pre-0.24 behaviour — each child is positioned by its Pos/Size).
|
|
158
|
+
* Setting this to 'row', 'column', or 'grid' enables flex-style auto-layout:
|
|
159
|
+
* the engine distributes the inner area, honours `gap` / `padding` /
|
|
160
|
+
* `alignItems` / `justifyContent`, and grows children with `Size.flex(...)`
|
|
161
|
+
* to fill remaining space. */
|
|
162
|
+
layout?: LayoutMode;
|
|
163
|
+
/** Spacing (in cells) inserted between adjacent children when `layout` is
|
|
164
|
+
* 'row', 'column', or 'grid'. Ignored by 'absolute' layout. Default: 0. */
|
|
165
|
+
gap?: number;
|
|
166
|
+
/** Extra inset applied inside the border — children are laid out within the
|
|
167
|
+
* padded inner area, and `getInnerSize()` / `getInnerOffset()` reflect the
|
|
168
|
+
* padding as well as the border. Default: 0 on every side. */
|
|
169
|
+
padding?: PaddingSpec;
|
|
170
|
+
/** Number of columns for `layout: 'grid'`. Children are placed row-major,
|
|
171
|
+
* so `gridColumns` implicitly determines the number of rows from the child
|
|
172
|
+
* count. Default: 1. */
|
|
173
|
+
gridColumns?: number;
|
|
174
|
+
/** Cross-axis alignment for `layout: 'row'` or `layout: 'column'`.
|
|
175
|
+
* Default: 'stretch' (children are stretched to fill the cross axis). */
|
|
176
|
+
alignItems?: AlignItems;
|
|
177
|
+
/** Main-axis distribution of leftover space for `layout: 'row'` / `'column'`
|
|
178
|
+
* when no child consumes it via flex-grow. Default: 'start'. */
|
|
179
|
+
justifyContent?: JustifyContent;
|
|
95
180
|
}
|
|
96
181
|
|
|
97
|
-
/** Internal per-axis position spec used by Pos.
|
|
182
|
+
/** Internal per-axis position spec used by Pos.
|
|
183
|
+
* - 'start' / 'end' / 'pct' / 'center' are resolved against the parent's
|
|
184
|
+
* inner area by the regular absolute-layout path.
|
|
185
|
+
* - 'flex' marks the child as belonging to a flex layout slot; the final
|
|
186
|
+
* (x, y) is computed by the parent's layout engine (see `WindowProperties.layout`).
|
|
187
|
+
* The `order` field lets users reorder flex children without changing the
|
|
188
|
+
* addChild() insertion order. */
|
|
98
189
|
export type AxisSpec =
|
|
99
190
|
| { mode: 'start'; value: number }
|
|
100
191
|
| { mode: 'end'; value: number }
|
|
101
192
|
| { mode: 'pct'; value: number }
|
|
102
|
-
| { mode: 'center' }
|
|
103
|
-
|
|
104
|
-
|
|
193
|
+
| { mode: 'center' }
|
|
194
|
+
| { mode: 'flex'; order: number };
|
|
195
|
+
|
|
196
|
+
/** Basis value stored inside `{ mode: 'flex' }` DimSpec entries. Supports
|
|
197
|
+
* absolute pixel values and parent-relative percentages. */
|
|
198
|
+
export type FlexBasis =
|
|
199
|
+
| { kind: 'abs'; value: number }
|
|
200
|
+
| { kind: 'pct'; value: number };
|
|
201
|
+
|
|
202
|
+
/** Internal per-axis size spec used by Size.
|
|
203
|
+
* - 'abs' / 'pct' mirror the pre-flex behaviour (fixed pixels or % of parent).
|
|
204
|
+
* - 'flex' marks the child as a flex item; the parent's layout engine
|
|
205
|
+
* distributes the inner area in proportion to `grow` and shrinks in
|
|
206
|
+
* proportion to `shrink` when space is tight. `basis` is the starting
|
|
207
|
+
* main-axis size before distribution (default `{ kind: 'abs', value: 0 }`).
|
|
208
|
+
* - 'content' marks the child as auto-sized; the layout engine measures the
|
|
209
|
+
* child's natural size (its current Region dimensions) and uses that. */
|
|
105
210
|
export type DimSpec =
|
|
106
|
-
| { mode: 'abs';
|
|
107
|
-
| { mode: 'pct';
|
|
211
|
+
| { mode: 'abs'; value: number }
|
|
212
|
+
| { mode: 'pct'; value: number }
|
|
213
|
+
| { mode: 'flex'; grow: number; shrink: number; basis: FlexBasis }
|
|
214
|
+
| { mode: 'content' };
|
|
215
|
+
|
|
216
|
+
/** Layout algorithm applied to a window's direct children.
|
|
217
|
+
* - 'absolute' (default): each child is positioned/sized via its own Pos/Size,
|
|
218
|
+
* matching the pre-0.24 behaviour — existing layouts continue to work unchanged.
|
|
219
|
+
* - 'row' : children flow horizontally; main axis = width, cross axis = height.
|
|
220
|
+
* - 'column' : children flow vertically; main axis = height, cross axis = width.
|
|
221
|
+
* - 'grid' : children are placed in a uniform N-column grid (see `gridColumns`). */
|
|
222
|
+
export type LayoutMode = 'absolute' | 'row' | 'column' | 'grid';
|
|
223
|
+
|
|
224
|
+
/** Cross-axis alignment for flex layouts (row/column). Default: 'stretch'. */
|
|
225
|
+
export type AlignItems = 'start' | 'center' | 'end' | 'stretch';
|
|
226
|
+
|
|
227
|
+
/** Main-axis distribution of leftover space when no flex-grow child consumes it.
|
|
228
|
+
* Default: 'start'. */
|
|
229
|
+
export type JustifyContent = 'start' | 'center' | 'end' | 'space-between' | 'space-around';
|
|
230
|
+
|
|
231
|
+
/** Resolved per-side padding values (in cells). */
|
|
232
|
+
export interface Padding {
|
|
233
|
+
top: number;
|
|
234
|
+
right: number;
|
|
235
|
+
bottom: number;
|
|
236
|
+
left: number;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/** User-supplied padding: a uniform number, a [vertical, horizontal] tuple, or
|
|
240
|
+
* a partial per-side record (missing sides default to 0). */
|
|
241
|
+
export type PaddingSpec = number | [number, number] | Partial<Padding>;
|
|
108
242
|
|
|
109
243
|
/** Options for Window.writeText() – position defaults to (0, 0). */
|
|
110
244
|
export interface WriteTextOptions {
|
|
@@ -112,10 +246,34 @@ export interface WriteTextOptions {
|
|
|
112
246
|
x?: number;
|
|
113
247
|
/** Row to start writing at. Default: 0. */
|
|
114
248
|
y?: number;
|
|
115
|
-
/**
|
|
249
|
+
/** Base style ID merged under every segment's style. Default: auto-picked
|
|
250
|
+
* from disabled/focused/normal state (see Window.writeText()). */
|
|
251
|
+
style?: StyleId;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/** A single inline-styled segment accepted by Window.writeText(). The cursor
|
|
255
|
+
* advances across consecutive segments without resetting, so segments flow
|
|
256
|
+
* inline on the same row like a rich-text span.
|
|
257
|
+
* - `style` is a pre-registered StyleId (merged with the base style).
|
|
258
|
+
* - `attrs` is registered on the fly (convenience, avoids pre-registering).
|
|
259
|
+
* - When both are present, `style` wins; when neither is present the base style applies. */
|
|
260
|
+
export interface WriteTextSegment {
|
|
261
|
+
/** Literal text for this segment. May contain '\n' which resets the cursor
|
|
262
|
+
* to the starting column and advances to the next row. */
|
|
263
|
+
text: string;
|
|
264
|
+
/** Optional pre-registered style ID merged with the base style. */
|
|
116
265
|
style?: StyleId;
|
|
266
|
+
/** Optional inline CellAttributes; registered into the StyleRegistry automatically. */
|
|
267
|
+
attrs?: CellAttributes;
|
|
117
268
|
}
|
|
118
269
|
|
|
270
|
+
/** Input accepted by Window.writeText().
|
|
271
|
+
* - A plain string keeps the pre-0.18.0 behaviour: one style for the whole text.
|
|
272
|
+
* - An array of segments applies per-segment styles while the cursor flows across
|
|
273
|
+
* them; each segment's style is merged with the base style.
|
|
274
|
+
* - An empty array is a no-op. */
|
|
275
|
+
export type WriteTextInput = string | WriteTextSegment[];
|
|
276
|
+
|
|
119
277
|
/** Control-specific properties for the Button control. */
|
|
120
278
|
export interface ButtonProperties {
|
|
121
279
|
/** Called when the button is activated (Enter or Space while focused). */
|
|
@@ -130,6 +288,16 @@ export interface TextBoxProperties {
|
|
|
130
288
|
placeholder?: string;
|
|
131
289
|
/** Initial cursor position (character index). Default: end of value. */
|
|
132
290
|
cursor?: number;
|
|
291
|
+
/** Fires after every value change driven by `handleKey` (typing, backspace,
|
|
292
|
+
* delete, paste of a single char, …). Not fired by `setValue`. */
|
|
293
|
+
onChange?: (value: string) => void;
|
|
294
|
+
/** Fires when the user presses Enter (`\r` / `\n`) while the TextBox has
|
|
295
|
+
* focus. The current value is passed unchanged. */
|
|
296
|
+
onSubmit?: (value: string) => void;
|
|
297
|
+
/** Pre-dispatch hook: runs before the built-in `handleKey` logic. Return
|
|
298
|
+
* `true` to mark the key as handled — the default behaviour (inserting,
|
|
299
|
+
* moving cursor, deleting, …) is then skipped. */
|
|
300
|
+
onKeyDown?: (key: string) => boolean | void;
|
|
133
301
|
}
|
|
134
302
|
|
|
135
303
|
/** Control-specific properties for the TextArea control. */
|
|
@@ -140,6 +308,22 @@ export interface TextAreaProperties {
|
|
|
140
308
|
placeholder?: string;
|
|
141
309
|
/** Initial cursor position. Default: { x: 0, y: 0 }. */
|
|
142
310
|
cursor?: { x: number; y: number };
|
|
311
|
+
/** Fires after every value change driven by `handleKey`. Not fired by
|
|
312
|
+
* `setValue`. */
|
|
313
|
+
onChange?: (value: string) => void;
|
|
314
|
+
/** Fires when the user submits — by default Ctrl+Enter. Plain Enter still
|
|
315
|
+
* inserts a newline. */
|
|
316
|
+
onSubmit?: (value: string) => void;
|
|
317
|
+
/** Pre-dispatch hook: runs before the built-in `handleKey` logic. Return
|
|
318
|
+
* `true` to short-circuit the default behaviour for this key. */
|
|
319
|
+
onKeyDown?: (key: string) => boolean | void;
|
|
320
|
+
/** When > 0, Tab inserts that many space characters instead of cycling
|
|
321
|
+
* focus. When 0 (default) Tab passes through unchanged so the
|
|
322
|
+
* WindowManager sees it. */
|
|
323
|
+
insertTabAsSpaces?: number;
|
|
324
|
+
/** When true, Ctrl+D deletes the character to the right of the cursor
|
|
325
|
+
* (or joins with the next line at end of line). Default: false. */
|
|
326
|
+
ctrlDDeletesForward?: boolean;
|
|
143
327
|
}
|
|
144
328
|
|
|
145
329
|
/** Control-specific properties for the Checkbox control. */
|
|
@@ -202,14 +386,49 @@ export interface LineChartProperties {
|
|
|
202
386
|
color?: number;
|
|
203
387
|
}
|
|
204
388
|
|
|
205
|
-
/**
|
|
206
|
-
export interface
|
|
389
|
+
/** Context passed to ListBox.renderItem() for a single row. */
|
|
390
|
+
export interface ListBoxRenderContext {
|
|
391
|
+
/** 0-based index of the item in the list. */
|
|
392
|
+
index: number;
|
|
393
|
+
/** Whether the owning ListBox currently has keyboard focus. */
|
|
394
|
+
focused: boolean;
|
|
395
|
+
/** Whether this particular row is the selected one. */
|
|
396
|
+
selected: boolean;
|
|
397
|
+
/** Inner width (in cells) available for the row. */
|
|
398
|
+
width: number;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/** A single styled text segment produced by ListBox.renderItem(). */
|
|
402
|
+
export interface ListBoxRowSegment {
|
|
403
|
+
/** Literal text drawn into the row at the segment's computed position. */
|
|
404
|
+
text: string;
|
|
405
|
+
/** Optional style ID merged onto the row's base (selection) style. */
|
|
406
|
+
style?: StyleId;
|
|
407
|
+
/** Horizontal alignment within the row. Default: 'left'.
|
|
408
|
+
* - 'left' segments are laid out left-to-right from column 0.
|
|
409
|
+
* - 'right' segments are flushed to the right edge of the row.
|
|
410
|
+
* - 'fill' segment occupies the remaining space between the left and right groups.
|
|
411
|
+
* Only the first 'fill' segment in a row is honoured. */
|
|
412
|
+
align?: 'left' | 'right' | 'fill';
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/** Return type of ListBox.renderItem(). A plain string is treated as a single left-aligned segment. */
|
|
416
|
+
export type ListBoxRowSegments = string | ListBoxRowSegment[];
|
|
417
|
+
|
|
418
|
+
/** Control-specific properties for the ListBox control. Generic over the item type. */
|
|
419
|
+
export interface ListBoxProperties<T = string> {
|
|
207
420
|
/** Initial items shown in the list. Default: []. */
|
|
208
|
-
items?:
|
|
421
|
+
items?: T[];
|
|
209
422
|
/** Initial selected index, or -1 for no selection. Default: 0 if items is non-empty, else -1. */
|
|
210
423
|
selectedIndex?: number;
|
|
211
424
|
/** Called when the selected index changes via handleKey(). */
|
|
212
|
-
onChange?: (index: number, item:
|
|
425
|
+
onChange?: (index: number, item: T) => void;
|
|
426
|
+
/** Optional per-row renderer returning styled segments. Default: single text segment (item.toString()). */
|
|
427
|
+
renderItem?: (item: T, ctx: ListBoxRenderContext) => ListBoxRowSegments;
|
|
428
|
+
/** Row height in cells. Default: 1. Items occupy this many consecutive rows in the viewport. */
|
|
429
|
+
rowHeight?: number;
|
|
430
|
+
/** Stable key for reconciliation — currently stored only; future use: preserve scroll/selection across setItems(). */
|
|
431
|
+
keyFn?: (item: T) => string;
|
|
213
432
|
}
|
|
214
433
|
|
|
215
434
|
/** Control-specific properties for the Tabs control. */
|
|
@@ -265,21 +484,38 @@ export interface BarChartProperties {
|
|
|
265
484
|
/** A single axis value: absolute number, edge-relative negative, or percentage string ("N%"). */
|
|
266
485
|
export type YamlAxisValue = number | string;
|
|
267
486
|
|
|
268
|
-
/** YAML position specification for a window.
|
|
487
|
+
/** YAML position specification for a window.
|
|
488
|
+
* - Shorthand strings ('center', 'topLeft', …, 'flex') map to the matching
|
|
489
|
+
* `Pos` static factory with no arguments.
|
|
490
|
+
* - `{ preset, offset? }` maps to `Pos.top/left/right/bottom(offset)`.
|
|
491
|
+
* - `{ flex: N }` is shorthand for `Pos.flex(N)` so authors can set a layout
|
|
492
|
+
* order from YAML.
|
|
493
|
+
* - `{ x, y }` defers to the two-argument `new Pos(x, y)` constructor. */
|
|
269
494
|
export type YamlPosSpec =
|
|
270
|
-
| 'center' | 'topLeft' | 'topRight' | 'bottomLeft' | 'bottomRight'
|
|
495
|
+
| 'center' | 'topLeft' | 'topRight' | 'bottomLeft' | 'bottomRight' | 'flex'
|
|
271
496
|
| { preset: 'top'; offset?: YamlAxisValue }
|
|
272
497
|
| { preset: 'left'; offset?: YamlAxisValue }
|
|
273
498
|
| { preset: 'right'; offset?: YamlAxisValue }
|
|
274
499
|
| { preset: 'bottom'; offset?: YamlAxisValue }
|
|
500
|
+
| { flex: number }
|
|
275
501
|
| { x: YamlAxisValue; y: YamlAxisValue };
|
|
276
502
|
|
|
277
|
-
/** YAML size specification for a window.
|
|
503
|
+
/** YAML size specification for a window.
|
|
504
|
+
* - `'fill'`, `'flex'`, `'content'` map to the matching zero-arg
|
|
505
|
+
* `Size.fill()` / `Size.flex()` / `Size.content()` factories.
|
|
506
|
+
* - `{ fillWidth }` / `{ fillHeight }` mirror the pre-0.24 shorthands.
|
|
507
|
+
* - `{ flex: { grow?, shrink?, basis? } }` builds `Size.flex(grow, shrink, basis)`.
|
|
508
|
+
* - `{ width, height }` maps to `new Size(width, height)`; the axis values may
|
|
509
|
+
* themselves be literal numbers, "N%" strings, `'flex'`/`'content'` strings,
|
|
510
|
+
* or `{ flex: {...} }` / `{ content: true }` objects for per-axis control. */
|
|
511
|
+
export type YamlDimValue = YamlAxisValue | 'flex' | 'content' | { flex: { grow?: number; shrink?: number; basis?: YamlAxisValue } } | { content: true };
|
|
512
|
+
|
|
278
513
|
export type YamlSizeSpec =
|
|
279
|
-
| 'fill'
|
|
514
|
+
| 'fill' | 'flex' | 'content'
|
|
280
515
|
| { fillWidth: YamlAxisValue }
|
|
281
516
|
| { fillHeight: YamlAxisValue }
|
|
282
|
-
| {
|
|
517
|
+
| { flex: { grow?: number; shrink?: number; basis?: YamlAxisValue } }
|
|
518
|
+
| { width: YamlDimValue; height: YamlDimValue };
|
|
283
519
|
|
|
284
520
|
/** Control type tags supported by InterfaceBuilder. */
|
|
285
521
|
export type YamlWindowType = 'window' | 'button' | 'textbox' | 'textarea' | 'checkbox' | 'radio'
|
|
@@ -296,8 +532,9 @@ export interface YamlStyleDef extends CellAttributes {
|
|
|
296
532
|
export interface YamlWindowDef {
|
|
297
533
|
/** Optional identifier for retrieving the built window from the result map. */
|
|
298
534
|
id?: string;
|
|
299
|
-
/** Widget type. Defaults to 'window'.
|
|
300
|
-
|
|
535
|
+
/** Widget type. Defaults to 'window'. May be a built-in tag or a custom
|
|
536
|
+
* name registered via `InterfaceBuilder.registerType()`. */
|
|
537
|
+
type?: YamlWindowType | (string & {});
|
|
301
538
|
/** Position within the parent. Defaults to { x: 0, y: 0 }. */
|
|
302
539
|
pos?: YamlPosSpec;
|
|
303
540
|
/** Dimensions of the window. Required for window/button/textbox/textarea; ignored for checkbox/radio (auto-sized). */
|
|
@@ -328,6 +565,16 @@ export interface YamlWindowDef {
|
|
|
328
565
|
onPress?: string;
|
|
329
566
|
/** Callback ID registered via InterfaceBuilder.registerCallback() — fired on value change. */
|
|
330
567
|
onChange?: string;
|
|
568
|
+
/** Callback ID registered via InterfaceBuilder.registerCallback() — fired on submit
|
|
569
|
+
* (Enter in TextBox; `ctrl+enter` in TextArea). */
|
|
570
|
+
onSubmit?: string;
|
|
571
|
+
/** Pre-dispatch hook callback ID — fired before the built-in handleKey logic
|
|
572
|
+
* in TextBox / TextArea; handler returning `true` short-circuits default. */
|
|
573
|
+
onKeyDown?: string;
|
|
574
|
+
/** TextArea: when > 0, Tab inserts that many spaces instead of cycling focus. */
|
|
575
|
+
insertTabAsSpaces?: number;
|
|
576
|
+
/** TextArea: when true, Ctrl+D deletes the character to the right of the cursor. */
|
|
577
|
+
ctrlDDeletesForward?: boolean;
|
|
331
578
|
/** LED state ('ok' | 'warn' | 'error' | 'off') — used by statusled. */
|
|
332
579
|
state?: 'ok' | 'warn' | 'error' | 'off';
|
|
333
580
|
/** Whether to show a percentage label over a progress bar. Default: true. */
|
|
@@ -366,8 +613,41 @@ export interface YamlWindowDef {
|
|
|
366
613
|
running?: boolean;
|
|
367
614
|
/** Tab index this child belongs to when its parent is a Tabs control. */
|
|
368
615
|
tab?: number;
|
|
616
|
+
/** Layout algorithm for direct children — 'absolute' / 'row' / 'column' / 'grid'. */
|
|
617
|
+
layout?: 'absolute' | 'row' | 'column' | 'grid';
|
|
618
|
+
/** Spacing (in cells) between adjacent children for flex / grid layouts. */
|
|
619
|
+
gap?: number;
|
|
620
|
+
/** Padding inside the border: uniform number, [vertical, horizontal] tuple,
|
|
621
|
+
* or a partial per-side record. */
|
|
622
|
+
padding?: number | [number, number] | { top?: number; right?: number; bottom?: number; left?: number };
|
|
623
|
+
/** Number of columns for `layout: grid`. */
|
|
624
|
+
gridColumns?: number;
|
|
625
|
+
/** Cross-axis alignment for `layout: row|column`. */
|
|
626
|
+
alignItems?: 'start' | 'center' | 'end' | 'stretch';
|
|
627
|
+
/** Main-axis distribution of leftover space for `layout: row|column`. */
|
|
628
|
+
justifyContent?: 'start' | 'center' | 'end' | 'space-between' | 'space-around';
|
|
629
|
+
/** Free-form property bag for user-registered custom types. Built-in types
|
|
630
|
+
* ignore this field; custom factories read it via `node.props`. */
|
|
631
|
+
props?: Record<string, unknown>;
|
|
369
632
|
}
|
|
370
633
|
|
|
634
|
+
/** Context passed to factories registered via `InterfaceBuilder.registerType`.
|
|
635
|
+
* Exposes pre-resolved common window properties plus the active style registry
|
|
636
|
+
* so factories can compose their own control-specific options. */
|
|
637
|
+
export interface CustomTypeContext {
|
|
638
|
+
/** Common window properties resolved from the YAML node (pos/size/border/…). */
|
|
639
|
+
wp: WindowProperties;
|
|
640
|
+
/** The style registry the builder is writing into. */
|
|
641
|
+
registry: StyleRegistry;
|
|
642
|
+
/** Looks up a callback registered via `InterfaceBuilder.registerCallback`. */
|
|
643
|
+
resolveCallback: (id: string | undefined) => ((...args: unknown[]) => void) | undefined;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
/** Signature for a custom type factory registered via
|
|
647
|
+
* `InterfaceBuilder.registerType`. The factory receives the raw YAML node
|
|
648
|
+
* together with a resolved `ctx.wp` and must return the constructed window. */
|
|
649
|
+
export type CustomTypeFactory = (node: YamlWindowDef, ctx: CustomTypeContext) => Window;
|
|
650
|
+
|
|
371
651
|
/** Top-level YAML layout document consumed by InterfaceBuilder. */
|
|
372
652
|
export interface YamlLayout {
|
|
373
653
|
/** Named style definitions registered before windows are built. */
|
|
@@ -384,6 +664,10 @@ export interface Focusable {
|
|
|
384
664
|
setFocused(focused: boolean): void;
|
|
385
665
|
isDisabled(): boolean;
|
|
386
666
|
handleKey?(key: string): void;
|
|
667
|
+
/** If present and returns `true`, the WindowManager skips Tab focus
|
|
668
|
+
* navigation and dispatches Tab to `handleKey` instead. Used by controls
|
|
669
|
+
* that consume Tab themselves (e.g. `TextArea` with `insertTabAsSpaces`). */
|
|
670
|
+
capturesTab?(): boolean;
|
|
387
671
|
}
|
|
388
672
|
|
|
389
673
|
/** Mouse event emitted by the terminal (SGR or X10 protocol). */
|
|
@@ -401,14 +685,35 @@ export interface TerminalMouseEvent {
|
|
|
401
685
|
ctrl?: boolean;
|
|
402
686
|
}
|
|
403
687
|
|
|
688
|
+
/** Context passed to global key handlers (`onKey`, `bindKey`). */
|
|
689
|
+
export interface KeyContext {
|
|
690
|
+
/** The control that currently has focus, or null when none. */
|
|
691
|
+
focusedControl: (Focusable & Window) | null;
|
|
692
|
+
/** True when at least one modal dialog is open. */
|
|
693
|
+
inDialog: boolean;
|
|
694
|
+
/** Nesting level of the dialog stack (0 = main context). */
|
|
695
|
+
dialogDepth: number;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
/** Signature for handlers registered via `WindowManager.bindKey`.
|
|
699
|
+
* Returning `true` marks the key as consumed — further handlers, exit keys,
|
|
700
|
+
* focus navigation, and dispatch to the focused control are all skipped. */
|
|
701
|
+
export type KeyBindHandler = (ctx: KeyContext) => boolean | void;
|
|
702
|
+
|
|
404
703
|
/** Constructor options for WindowManager. */
|
|
405
704
|
export interface WindowManagerOptions {
|
|
406
|
-
/** Key strings that trigger application exit. Default: ['\x03'] (Ctrl+C).
|
|
705
|
+
/** Key strings that trigger application exit. Default: ['\x03'] (Ctrl+C).
|
|
706
|
+
* Exit keys are checked **after** `onKey` / `bindKey` handlers; a handler
|
|
707
|
+
* returning `true` prevents the exit from firing. */
|
|
407
708
|
exitKeys?: string[];
|
|
408
709
|
/** Called after the input loop stops and the terminal state is restored. */
|
|
409
710
|
onExit?: () => void;
|
|
410
|
-
/** Called for every raw key string before it is dispatched to a control.
|
|
411
|
-
|
|
711
|
+
/** Called for every raw key string before it is dispatched to a control.
|
|
712
|
+
* Return `true` to mark the key as consumed — it will then **not** be
|
|
713
|
+
* checked against `exitKeys`, will not trigger focus navigation, and will
|
|
714
|
+
* not be dispatched to the focused control. Return `false` / `void` to
|
|
715
|
+
* keep the previous pass-through behaviour. */
|
|
716
|
+
onKey?: (key: string, ctx: KeyContext) => boolean | void;
|
|
412
717
|
/** Called for every mouse event when mouse support is enabled. */
|
|
413
718
|
onMouse?: (event: TerminalMouseEvent) => void;
|
|
414
719
|
/** Enable mouse click tracking (SGR protocol). Default: false. */
|