take4-console 0.15.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.
Files changed (131) hide show
  1. package/CHANGELOG.md +287 -0
  2. package/LICENSE +21 -0
  3. package/README.md +986 -0
  4. package/dist/Screen/InterfaceBuilder.d.mts +43 -0
  5. package/dist/Screen/InterfaceBuilder.d.mts.map +1 -0
  6. package/dist/Screen/InterfaceBuilder.mjs +355 -0
  7. package/dist/Screen/InterfaceBuilder.mjs.map +1 -0
  8. package/dist/Screen/Pos.d.mts +52 -0
  9. package/dist/Screen/Pos.d.mts.map +1 -0
  10. package/dist/Screen/Pos.mjs +105 -0
  11. package/dist/Screen/Pos.mjs.map +1 -0
  12. package/dist/Screen/Region.d.mts +31 -0
  13. package/dist/Screen/Region.d.mts.map +1 -0
  14. package/dist/Screen/Region.mjs +73 -0
  15. package/dist/Screen/Region.mjs.map +1 -0
  16. package/dist/Screen/RegistryHolder.d.mts +6 -0
  17. package/dist/Screen/RegistryHolder.d.mts.map +1 -0
  18. package/dist/Screen/RegistryHolder.mjs +14 -0
  19. package/dist/Screen/RegistryHolder.mjs.map +1 -0
  20. package/dist/Screen/Screen.d.mts +25 -0
  21. package/dist/Screen/Screen.d.mts.map +1 -0
  22. package/dist/Screen/Screen.mjs +100 -0
  23. package/dist/Screen/Screen.mjs.map +1 -0
  24. package/dist/Screen/Size.d.mts +23 -0
  25. package/dist/Screen/Size.d.mts.map +1 -0
  26. package/dist/Screen/Size.mjs +48 -0
  27. package/dist/Screen/Size.mjs.map +1 -0
  28. package/dist/Screen/StyleRegistry.d.mts +32 -0
  29. package/dist/Screen/StyleRegistry.d.mts.map +1 -0
  30. package/dist/Screen/StyleRegistry.mjs +80 -0
  31. package/dist/Screen/StyleRegistry.mjs.map +1 -0
  32. package/dist/Screen/Window.d.mts +121 -0
  33. package/dist/Screen/Window.d.mts.map +1 -0
  34. package/dist/Screen/Window.mjs +407 -0
  35. package/dist/Screen/Window.mjs.map +1 -0
  36. package/dist/Screen/WindowManager.d.mts +86 -0
  37. package/dist/Screen/WindowManager.d.mts.map +1 -0
  38. package/dist/Screen/WindowManager.mjs +399 -0
  39. package/dist/Screen/WindowManager.mjs.map +1 -0
  40. package/dist/Screen/controls/BarChart.d.mts +29 -0
  41. package/dist/Screen/controls/BarChart.d.mts.map +1 -0
  42. package/dist/Screen/controls/BarChart.mjs +90 -0
  43. package/dist/Screen/controls/BarChart.mjs.map +1 -0
  44. package/dist/Screen/controls/Button.d.mts +16 -0
  45. package/dist/Screen/controls/Button.d.mts.map +1 -0
  46. package/dist/Screen/controls/Button.mjs +34 -0
  47. package/dist/Screen/controls/Button.mjs.map +1 -0
  48. package/dist/Screen/controls/Checkbox.d.mts +23 -0
  49. package/dist/Screen/controls/Checkbox.d.mts.map +1 -0
  50. package/dist/Screen/controls/Checkbox.mjs +55 -0
  51. package/dist/Screen/controls/Checkbox.mjs.map +1 -0
  52. package/dist/Screen/controls/LineChart.d.mts +29 -0
  53. package/dist/Screen/controls/LineChart.d.mts.map +1 -0
  54. package/dist/Screen/controls/LineChart.mjs +172 -0
  55. package/dist/Screen/controls/LineChart.mjs.map +1 -0
  56. package/dist/Screen/controls/ListBox.d.mts +34 -0
  57. package/dist/Screen/controls/ListBox.d.mts.map +1 -0
  58. package/dist/Screen/controls/ListBox.mjs +138 -0
  59. package/dist/Screen/controls/ListBox.mjs.map +1 -0
  60. package/dist/Screen/controls/ProgressBar.d.mts +26 -0
  61. package/dist/Screen/controls/ProgressBar.d.mts.map +1 -0
  62. package/dist/Screen/controls/ProgressBar.mjs +70 -0
  63. package/dist/Screen/controls/ProgressBar.mjs.map +1 -0
  64. package/dist/Screen/controls/ProgressBarV.d.mts +22 -0
  65. package/dist/Screen/controls/ProgressBarV.d.mts.map +1 -0
  66. package/dist/Screen/controls/ProgressBarV.mjs +61 -0
  67. package/dist/Screen/controls/ProgressBarV.mjs.map +1 -0
  68. package/dist/Screen/controls/Radio.d.mts +23 -0
  69. package/dist/Screen/controls/Radio.d.mts.map +1 -0
  70. package/dist/Screen/controls/Radio.mjs +55 -0
  71. package/dist/Screen/controls/Radio.mjs.map +1 -0
  72. package/dist/Screen/controls/Sparkline.d.mts +29 -0
  73. package/dist/Screen/controls/Sparkline.d.mts.map +1 -0
  74. package/dist/Screen/controls/Sparkline.mjs +82 -0
  75. package/dist/Screen/controls/Sparkline.mjs.map +1 -0
  76. package/dist/Screen/controls/Spinner.d.mts +37 -0
  77. package/dist/Screen/controls/Spinner.d.mts.map +1 -0
  78. package/dist/Screen/controls/Spinner.mjs +87 -0
  79. package/dist/Screen/controls/Spinner.mjs.map +1 -0
  80. package/dist/Screen/controls/StatusLED.d.mts +22 -0
  81. package/dist/Screen/controls/StatusLED.d.mts.map +1 -0
  82. package/dist/Screen/controls/StatusLED.mjs +51 -0
  83. package/dist/Screen/controls/StatusLED.mjs.map +1 -0
  84. package/dist/Screen/controls/Tabs.d.mts +42 -0
  85. package/dist/Screen/controls/Tabs.d.mts.map +1 -0
  86. package/dist/Screen/controls/Tabs.mjs +126 -0
  87. package/dist/Screen/controls/Tabs.mjs.map +1 -0
  88. package/dist/Screen/controls/TextArea.d.mts +41 -0
  89. package/dist/Screen/controls/TextArea.d.mts.map +1 -0
  90. package/dist/Screen/controls/TextArea.mjs +197 -0
  91. package/dist/Screen/controls/TextArea.mjs.map +1 -0
  92. package/dist/Screen/controls/TextBox.d.mts +35 -0
  93. package/dist/Screen/controls/TextBox.d.mts.map +1 -0
  94. package/dist/Screen/controls/TextBox.mjs +135 -0
  95. package/dist/Screen/controls/TextBox.mjs.map +1 -0
  96. package/dist/Screen/types.d.mts +399 -0
  97. package/dist/Screen/types.d.mts.map +1 -0
  98. package/dist/Screen/types.mjs +22 -0
  99. package/dist/Screen/types.mjs.map +1 -0
  100. package/dist/index.d.mts +26 -0
  101. package/dist/index.d.mts.map +1 -0
  102. package/dist/index.mjs +41 -0
  103. package/dist/index.mjs.map +1 -0
  104. package/package.json +72 -0
  105. package/src/Screen/InterfaceBuilder.mts +403 -0
  106. package/src/Screen/Pos.mts +119 -0
  107. package/src/Screen/Region.mts +88 -0
  108. package/src/Screen/RegistryHolder.mts +16 -0
  109. package/src/Screen/Screen.mts +103 -0
  110. package/src/Screen/Size.mts +55 -0
  111. package/src/Screen/StyleRegistry.mts +95 -0
  112. package/src/Screen/Window.mts +439 -0
  113. package/src/Screen/WindowManager.mts +472 -0
  114. package/src/Screen/controls/BarChart.mts +109 -0
  115. package/src/Screen/controls/Button.mts +40 -0
  116. package/src/Screen/controls/Checkbox.mts +66 -0
  117. package/src/Screen/controls/LineChart.mts +202 -0
  118. package/src/Screen/controls/ListBox.mts +154 -0
  119. package/src/Screen/controls/ProgressBar.mts +88 -0
  120. package/src/Screen/controls/ProgressBarV.mts +77 -0
  121. package/src/Screen/controls/Radio.mts +66 -0
  122. package/src/Screen/controls/Sparkline.mts +101 -0
  123. package/src/Screen/controls/Spinner.mts +102 -0
  124. package/src/Screen/controls/StatusLED.mts +65 -0
  125. package/src/Screen/controls/Tabs.mts +140 -0
  126. package/src/Screen/controls/TextArea.mts +194 -0
  127. package/src/Screen/controls/TextBox.mts +139 -0
  128. package/src/Screen/types.mts +416 -0
  129. package/src/demo.mts +171 -0
  130. package/src/index.mts +105 -0
  131. package/src/layout.yaml +236 -0
@@ -0,0 +1,416 @@
1
+ import type { Pos } from './Pos.mjs';
2
+ import type { Size } from './Size.mjs';
3
+
4
+ /** Text and background color, expressed as ANSI color number (0–255) or hex string (e.g. '#ff0000'). */
5
+ export type Color = number | string;
6
+
7
+ // ── Built-in style names ──────────────────────────────────────────────────────
8
+
9
+ /** Name of the default background style used by windows and controls. */
10
+ export const BUILTIN_WINDOW_BG = 'builtin:window-bg';
11
+ /** Name of the default border color style (foreground = border color). */
12
+ export const BUILTIN_BORDER = 'builtin:border';
13
+ /** Name of the focused border color style. */
14
+ export const BUILTIN_BORDER_FOCUSED = 'builtin:border-focused';
15
+ /** Name of the disabled border color style. */
16
+ export const BUILTIN_BORDER_DISABLED = 'builtin:border-disabled';
17
+ /** Name of the normal text style used by controls. */
18
+ export const BUILTIN_TEXT = 'builtin:text';
19
+ /** Name of the focused text style used by controls. */
20
+ export const BUILTIN_TEXT_FOCUSED = 'builtin:text-focused';
21
+ /** Name of the disabled text style used by controls. */
22
+ export const BUILTIN_TEXT_DISABLED = 'builtin:text-disabled';
23
+ /** Name of the placeholder text style used by text input controls. */
24
+ export const BUILTIN_TEXT_PLACEHOLDER = 'builtin:text-placeholder';
25
+ /** Name of the checked/selected indicator style used by Checkbox and Radio. */
26
+ export const BUILTIN_TEXT_CHECKED = 'builtin:text-checked';
27
+ /** Name of the cursor highlight style (inverse) used by text input controls. */
28
+ export const BUILTIN_CURSOR = 'builtin:cursor';
29
+
30
+ /** Integer handle returned by StyleRegistry.register(). ID 0 always means no style (empty {}). */
31
+ export type StyleId = number;
32
+
33
+ /** Visual attributes for a single terminal cell. */
34
+ export interface CellAttributes {
35
+ foreground?: Color;
36
+ background?: Color;
37
+ bold?: boolean;
38
+ dim?: boolean;
39
+ italic?: boolean;
40
+ underline?: boolean;
41
+ strikethrough?: boolean;
42
+ blink?: boolean;
43
+ inverse?: boolean;
44
+ }
45
+
46
+ /** A single cell in the terminal grid. */
47
+ export interface Cell {
48
+ /** Single character stored in this cell, or a space for blank. */
49
+ char: string;
50
+ /** Visual attributes applied to this cell. */
51
+ attributes: CellAttributes;
52
+ }
53
+
54
+ /** Terminal dimensions expressed as columns × rows. */
55
+ export interface TerminalSize {
56
+ width: number;
57
+ height: number;
58
+ }
59
+
60
+ /** Box-drawing character style for window borders. */
61
+ export type BorderStyle = 'single' | 'double' | 'rounded';
62
+
63
+ /** Per-side border configuration. */
64
+ export interface WindowBorder {
65
+ top?: boolean;
66
+ right?: boolean;
67
+ bottom?: boolean;
68
+ left?: boolean;
69
+ /** Box-drawing style. Default: 'single'. */
70
+ style?: BorderStyle;
71
+ /** Border color. Default: inherits from cell. */
72
+ color?: Color;
73
+ }
74
+
75
+ /** Common properties shared by Window and all controls. Passed as the first constructor parameter. */
76
+ export interface WindowProperties {
77
+ /** Position of the window within its parent. */
78
+ pos: Pos;
79
+ /** Dimensions of the window. Optional for auto-sized controls (Checkbox, Radio, StatusLED, Spinner). */
80
+ size?: Size;
81
+ /** Background style ID registered in a StyleRegistry. 0 or undefined = transparent. Default: undefined. */
82
+ background?: StyleId;
83
+ /** Border config, or true for all sides with single style. Default: false. */
84
+ border?: WindowBorder | boolean;
85
+ /** Default border shape used when the user does not supply border. Set by control subclasses. */
86
+ defaultBorder?: WindowBorder | boolean;
87
+ /** Whether the window is active. Affects border/background appearance. Default: true. */
88
+ active?: boolean;
89
+ /** Whether the control currently has keyboard focus. Default: false. */
90
+ focused?: boolean;
91
+ /** Whether the control is non-interactive and visually dimmed. Default: false. */
92
+ disabled?: boolean;
93
+ /** Text label displayed by the control. Default: ''. */
94
+ label?: string;
95
+ }
96
+
97
+ /** Internal per-axis position spec used by Pos. */
98
+ export type AxisSpec =
99
+ | { mode: 'start'; value: number }
100
+ | { mode: 'end'; value: number }
101
+ | { mode: 'pct'; value: number }
102
+ | { mode: 'center' };
103
+
104
+ /** Internal per-axis size spec used by Size. */
105
+ export type DimSpec =
106
+ | { mode: 'abs'; value: number }
107
+ | { mode: 'pct'; value: number };
108
+
109
+ /** Options for Window.writeText() – position defaults to (0, 0). */
110
+ export interface WriteTextOptions {
111
+ /** Column to start writing at. Default: 0. */
112
+ x?: number;
113
+ /** Row to start writing at. Default: 0. */
114
+ y?: number;
115
+ /** Style ID registered in a StyleRegistry. Default: 0 (no style). */
116
+ style?: StyleId;
117
+ }
118
+
119
+ /** Control-specific properties for the Button control. */
120
+ export interface ButtonProperties {
121
+ /** Called when the button is activated (Enter or Space while focused). */
122
+ onPress?: () => void;
123
+ }
124
+
125
+ /** Control-specific properties for the TextBox control. */
126
+ export interface TextBoxProperties {
127
+ /** Initial text value. Default: ''. */
128
+ value?: string;
129
+ /** Placeholder shown when value is empty and the control is not focused. Default: ''. */
130
+ placeholder?: string;
131
+ /** Initial cursor position (character index). Default: end of value. */
132
+ cursor?: number;
133
+ }
134
+
135
+ /** Control-specific properties for the TextArea control. */
136
+ export interface TextAreaProperties {
137
+ /** Initial text value; may contain newline characters. Default: ''. */
138
+ value?: string;
139
+ /** Placeholder shown when value is empty and the control is not focused. Default: ''. */
140
+ placeholder?: string;
141
+ /** Initial cursor position. Default: { x: 0, y: 0 }. */
142
+ cursor?: { x: number; y: number };
143
+ }
144
+
145
+ /** Control-specific properties for the Checkbox control. */
146
+ export interface CheckboxProperties {
147
+ /** Whether the checkbox is initially checked. Default: false. */
148
+ checked?: boolean;
149
+ /** Called when the checked state changes via handleKey(). */
150
+ onChange?: (checked: boolean) => void;
151
+ }
152
+
153
+ /** Control-specific properties for the Radio control. */
154
+ export interface RadioProperties {
155
+ /** Whether the radio button is initially selected. Default: false. */
156
+ checked?: boolean;
157
+ /** Called when the radio button is selected via handleKey(). */
158
+ onChange?: (checked: boolean) => void;
159
+ }
160
+
161
+ /** Control-specific properties for the StatusLED control. */
162
+ export interface StatusLEDProperties {
163
+ /** Visual state of the LED. Default: 'off'. */
164
+ state?: 'ok' | 'warn' | 'error' | 'off';
165
+ }
166
+
167
+ /** Control-specific properties for the ProgressBar (horizontal) control. */
168
+ export interface ProgressBarProperties {
169
+ /** Current value. Default: 0. */
170
+ value?: number;
171
+ /** Maximum value. Default: 100. */
172
+ max?: number;
173
+ /** Whether to show the percentage label centred over the bar. Default: true. */
174
+ showLabel?: boolean;
175
+ /** ANSI color number for the filled portion. Default: 75. */
176
+ fillColor?: number;
177
+ /** ANSI color number for the empty portion. Default: 237. */
178
+ emptyColor?: number;
179
+ }
180
+
181
+ /** Control-specific properties for the ProgressBarV (vertical) control. */
182
+ export interface ProgressBarVProperties {
183
+ /** Current value. Default: 0. */
184
+ value?: number;
185
+ /** Maximum value. Default: 100. */
186
+ max?: number;
187
+ /** ANSI color number for the filled portion. Default: 75. */
188
+ fillColor?: number;
189
+ /** ANSI color number for the empty portion. Default: 237. */
190
+ emptyColor?: number;
191
+ }
192
+
193
+ /** Control-specific properties for the LineChart control. */
194
+ export interface LineChartProperties {
195
+ /** Data points to plot. Default: []. */
196
+ data?: number[];
197
+ /** Minimum Y value; if omitted, derived from data. */
198
+ min?: number;
199
+ /** Maximum Y value; if omitted, derived from data. */
200
+ max?: number;
201
+ /** ANSI color number for the line. Default: 75. */
202
+ color?: number;
203
+ }
204
+
205
+ /** Control-specific properties for the ListBox control. */
206
+ export interface ListBoxProperties {
207
+ /** Initial items shown in the list. Default: []. */
208
+ items?: string[];
209
+ /** Initial selected index, or -1 for no selection. Default: 0 if items is non-empty, else -1. */
210
+ selectedIndex?: number;
211
+ /** Called when the selected index changes via handleKey(). */
212
+ onChange?: (index: number, item: string) => void;
213
+ }
214
+
215
+ /** Control-specific properties for the Tabs control. */
216
+ export interface TabsProperties {
217
+ /** Tab titles shown in the header row. Default: []. */
218
+ titles?: string[];
219
+ /** Initially active tab index. Default: 0. */
220
+ activeIndex?: number;
221
+ /** Called when the active tab changes via handleKey(). */
222
+ onChange?: (index: number, title: string) => void;
223
+ }
224
+
225
+ /** Control-specific properties for the Sparkline control. */
226
+ export interface SparklineProperties {
227
+ /** Data values to plot as a one-row block-character chart. Default: []. */
228
+ data?: number[];
229
+ /** Minimum Y value; if omitted, derived from data. */
230
+ min?: number;
231
+ /** Maximum Y value; if omitted, derived from data. */
232
+ max?: number;
233
+ /** ANSI color number for the sparkline glyphs. Default: 75. */
234
+ color?: number;
235
+ }
236
+
237
+ /** Control-specific properties for the Spinner control. */
238
+ export interface SpinnerProperties {
239
+ /** Visual style of the spinner animation. Default: 'braille'. */
240
+ style?: 'braille' | 'dots' | 'line' | 'circle' | 'arrow';
241
+ /** Initial frame index. Default: 0. */
242
+ frame?: number;
243
+ /** Whether the spinner is actively animating. Default: true. */
244
+ running?: boolean;
245
+ /** ANSI color number for the spinner glyph. Default: 75. */
246
+ color?: number;
247
+ }
248
+
249
+ /** Control-specific properties for the BarChart control. */
250
+ export interface BarChartProperties {
251
+ /** Data values for each bar. Default: []. */
252
+ data?: number[];
253
+ /** Label string for each bar (truncated to barWidth columns). Default: []. */
254
+ labels?: string[];
255
+ /** Maximum Y value; if omitted, derived from data. */
256
+ max?: number;
257
+ /** ANSI color number for the bars. Default: 75. */
258
+ barColor?: number;
259
+ /** Width in columns of each bar. Default: 1. */
260
+ barWidth?: number;
261
+ }
262
+
263
+ // ── InterfaceBuilder YAML schema ──────────────────────────────────────────────
264
+
265
+ /** A single axis value: absolute number, edge-relative negative, or percentage string ("N%"). */
266
+ export type YamlAxisValue = number | string;
267
+
268
+ /** YAML position specification for a window. */
269
+ export type YamlPosSpec =
270
+ | 'center' | 'topLeft' | 'topRight' | 'bottomLeft' | 'bottomRight'
271
+ | { preset: 'top'; offset?: YamlAxisValue }
272
+ | { preset: 'left'; offset?: YamlAxisValue }
273
+ | { preset: 'right'; offset?: YamlAxisValue }
274
+ | { preset: 'bottom'; offset?: YamlAxisValue }
275
+ | { x: YamlAxisValue; y: YamlAxisValue };
276
+
277
+ /** YAML size specification for a window. */
278
+ export type YamlSizeSpec =
279
+ | 'fill'
280
+ | { fillWidth: YamlAxisValue }
281
+ | { fillHeight: YamlAxisValue }
282
+ | { width: YamlAxisValue; height: YamlAxisValue };
283
+
284
+ /** Control type tags supported by InterfaceBuilder. */
285
+ export type YamlWindowType = 'window' | 'button' | 'textbox' | 'textarea' | 'checkbox' | 'radio'
286
+ | 'statusled' | 'progressbar' | 'progressbarv' | 'linechart' | 'barchart'
287
+ | 'listbox' | 'tabs' | 'sparkline' | 'spinner';
288
+
289
+ /** A named style entry in the YAML layout's `styles:` section. Extends CellAttributes with a required name. */
290
+ export interface YamlStyleDef extends CellAttributes {
291
+ /** Name used to reference this style. May override built-in names (e.g. 'builtin:window-bg'). */
292
+ name: string;
293
+ }
294
+
295
+ /** A single window or control definition in a YAML layout. */
296
+ export interface YamlWindowDef {
297
+ /** Optional identifier for retrieving the built window from the result map. */
298
+ id?: string;
299
+ /** Widget type. Defaults to 'window'. */
300
+ type?: YamlWindowType;
301
+ /** Position within the parent. Defaults to { x: 0, y: 0 }. */
302
+ pos?: YamlPosSpec;
303
+ /** Dimensions of the window. Required for window/button/textbox/textarea; ignored for checkbox/radio (auto-sized). */
304
+ size?: YamlSizeSpec;
305
+ /** Background style: a named style string (e.g. 'builtin:window-bg') or a numeric StyleId. Omit for transparent. */
306
+ background?: string | number;
307
+ /** Border configuration. true enables all sides with single style. */
308
+ border?: WindowBorder | boolean;
309
+ /** Whether the window is active (affects dim). Default: true. */
310
+ active?: boolean;
311
+ /** Text written at the top-left of the content area after construction. */
312
+ content?: string;
313
+ /** Nested children added via addChild(). */
314
+ children?: YamlWindowDef[];
315
+ /** Label text (Button, Checkbox, Radio). */
316
+ label?: string;
317
+ /** Placeholder text shown when value is empty (TextBox, TextArea). */
318
+ placeholder?: string;
319
+ /** Initial text value (TextBox, TextArea). */
320
+ value?: string;
321
+ /** Initial checked state (Checkbox, Radio). Default: false. */
322
+ checked?: boolean;
323
+ /** Whether the control starts focused. Default: false. */
324
+ focused?: boolean;
325
+ /** Whether the control is disabled. Default: false. */
326
+ disabled?: boolean;
327
+ /** Callback ID registered via InterfaceBuilder.registerCallback() — fired on button press. */
328
+ onPress?: string;
329
+ /** Callback ID registered via InterfaceBuilder.registerCallback() — fired on value change. */
330
+ onChange?: string;
331
+ /** LED state ('ok' | 'warn' | 'error' | 'off') — used by statusled. */
332
+ state?: 'ok' | 'warn' | 'error' | 'off';
333
+ /** Whether to show a percentage label over a progress bar. Default: true. */
334
+ showLabel?: boolean;
335
+ /** ANSI color for the filled portion (ProgressBar, ProgressBarV). */
336
+ fillColor?: number;
337
+ /** ANSI color for the empty portion (ProgressBar, ProgressBarV). */
338
+ emptyColor?: number;
339
+ /** Current numeric value for ProgressBar / ProgressBarV. */
340
+ barValue?: number;
341
+ /** Maximum numeric value for ProgressBar, ProgressBarV, LineChart, BarChart. */
342
+ max?: number;
343
+ /** Minimum numeric value for LineChart. */
344
+ min?: number;
345
+ /** Numeric data array for LineChart / BarChart. */
346
+ data?: number[];
347
+ /** String label array for BarChart bars. */
348
+ barLabels?: string[];
349
+ /** Line color for LineChart or bar color for BarChart (ANSI number). */
350
+ chartColor?: number;
351
+ /** Width of each bar in BarChart columns. Default: 1. */
352
+ barWidth?: number;
353
+ /** Items shown in a ListBox. */
354
+ items?: string[];
355
+ /** Initial selection index for ListBox. */
356
+ selectedIndex?: number;
357
+ /** Tab titles for a Tabs control. */
358
+ titles?: string[];
359
+ /** Initially active tab index for a Tabs control. */
360
+ activeIndex?: number;
361
+ /** Visual style for Spinner animation. */
362
+ spinnerStyle?: 'braille' | 'dots' | 'line' | 'circle' | 'arrow';
363
+ /** Initial frame index for Spinner. */
364
+ frame?: number;
365
+ /** Whether Spinner is actively animating. */
366
+ running?: boolean;
367
+ /** Tab index this child belongs to when its parent is a Tabs control. */
368
+ tab?: number;
369
+ }
370
+
371
+ /** Top-level YAML layout document consumed by InterfaceBuilder. */
372
+ export interface YamlLayout {
373
+ /** Named style definitions registered before windows are built. */
374
+ styles?: YamlStyleDef[];
375
+ /** Top-level windows to add to the Screen. */
376
+ windows: YamlWindowDef[];
377
+ }
378
+
379
+ // ── Focusable ─────────────────────────────────────────────────────────────────
380
+
381
+ /** Interface that interactive controls must satisfy to integrate with WindowManager. */
382
+ export interface Focusable {
383
+ isFocused(): boolean;
384
+ setFocused(focused: boolean): void;
385
+ isDisabled(): boolean;
386
+ handleKey?(key: string): void;
387
+ }
388
+
389
+ /** Mouse event emitted by the terminal (SGR or X10 protocol). */
390
+ export interface TerminalMouseEvent {
391
+ /** Whether this is a button press, release, or cursor move. */
392
+ type: 'press' | 'release' | 'move';
393
+ /** Button index: 0 = left, 1 = middle, 2 = right. */
394
+ button: number;
395
+ /** 0-based column of the event. */
396
+ x: number;
397
+ /** 0-based row of the event. */
398
+ y: number;
399
+ shift?: boolean;
400
+ alt?: boolean;
401
+ ctrl?: boolean;
402
+ }
403
+
404
+ /** Constructor options for WindowManager. */
405
+ export interface WindowManagerOptions {
406
+ /** Key strings that trigger application exit. Default: ['\x03'] (Ctrl+C). */
407
+ exitKeys?: string[];
408
+ /** Called after the input loop stops and the terminal state is restored. */
409
+ onExit?: () => void;
410
+ /** Called for every raw key string before it is dispatched to a control. */
411
+ onKey?: (key: string) => void;
412
+ /** Called for every mouse event when mouse support is enabled. */
413
+ onMouse?: (event: TerminalMouseEvent) => void;
414
+ /** Enable mouse click tracking (SGR protocol). Default: false. */
415
+ mouse?: boolean;
416
+ }
package/src/demo.mts ADDED
@@ -0,0 +1,171 @@
1
+ import { fileURLToPath } from 'node:url';
2
+ import { join, dirname } from 'node:path';
3
+ import { Screen } from './Screen/Screen.mjs';
4
+ import { WindowManager } from './Screen/WindowManager.mjs';
5
+ import { InterfaceBuilder } from './Screen/InterfaceBuilder.mjs';
6
+ import { LineChart } from './Screen/controls/LineChart.mjs';
7
+ import { BarChart } from './Screen/controls/BarChart.mjs';
8
+ import { StatusLED } from './Screen/controls/StatusLED.mjs';
9
+ import { ProgressBar } from './Screen/controls/ProgressBar.mjs';
10
+ import { ProgressBarV } from './Screen/controls/ProgressBarV.mjs';
11
+ import { Spinner } from './Screen/controls/Spinner.mjs';
12
+ import { Sparkline } from './Screen/controls/Sparkline.mjs';
13
+ import { ListBox } from './Screen/controls/ListBox.mjs';
14
+ import { Tabs } from './Screen/controls/Tabs.mjs';
15
+
16
+ type LedState = 'ok' | 'warn' | 'error' | 'off';
17
+
18
+ // ── Entry point ───────────────────────────────────────────────────────────────
19
+
20
+ /** Renders the controls demo. */
21
+ const main = async (): Promise<void> => {
22
+ const screen = new Screen();
23
+ const { width, height } = screen.getSize();
24
+
25
+ screen.fill(' ', screen.registerStyle({ background: 234 }));
26
+
27
+ let demoTimer: NodeJS.Timeout | null = null;
28
+
29
+ const wm = new WindowManager(screen, {
30
+ exitKeys: ['q', '\x03'],
31
+ onExit: () => {
32
+ if (demoTimer) clearInterval(demoTimer);
33
+ process.exit(0);
34
+ },
35
+ mouse: true,
36
+ });
37
+
38
+ const layoutPath = join(dirname(fileURLToPath(import.meta.url)), 'layout.yaml');
39
+ const result = await new InterfaceBuilder().buildFromFile(layoutPath, screen, wm);
40
+
41
+ // ── Header & status bar ───────────────────────────────────────────────────
42
+ const headerStyle = screen.registerStyle({ background: 24, foreground: 255, bold: true });
43
+ result.get('header')!.writeText(' take4_console │ controls demo ', { style: headerStyle });
44
+
45
+ const statusStyle = screen.registerStyle({ background: 24, foreground: 250 });
46
+ result.get('statusBar')!.writeText(
47
+ ` ${width}×${height} │ `
48
+ + 'Button Checkbox Radio TextBox '
49
+ + 'StatusLED ProgressBar ProgressBarV LineChart BarChart',
50
+ { style: statusStyle },
51
+ );
52
+
53
+ // ── Resource labels in monitorPanel ──────────────────────────────────────
54
+ const labelStyle = screen.registerStyle({ foreground: 245 });
55
+ const monitor = result.get('monitorPanel')!;
56
+ monitor.writeText('CPU', { x: 1, y: 1, style: labelStyle });
57
+ monitor.writeText('MEM', { x: 1, y: 3, style: labelStyle });
58
+ monitor.writeText('DSK', { x: 1, y: 5, style: labelStyle });
59
+ monitor.writeText('SYS', { x: -4, y: 0, style: labelStyle });
60
+
61
+ // ── Chart data ────────────────────────────────────────────────────────────
62
+ const lc = result.get('lineChart') as LineChart;
63
+ let lineData: number[] = [5, 18, 8, 45, 22, 60, 38, 72, 50, 65];
64
+ lc.setData(lineData);
65
+
66
+ const bc = result.get('barChart') as BarChart;
67
+ const barLabels: string[] = ['A', 'B', 'C', 'D', 'E'];
68
+ bc.setData([80, 45, 62, 30, 75]);
69
+ bc.setLabels(barLabels);
70
+
71
+ // ── Sparkline trend buffers (rolling 30-sample history) ──────────────────
72
+ const sparkCpu = result.get('sparkCpu') as Sparkline;
73
+ const sparkMem = result.get('sparkMem') as Sparkline;
74
+ const sparkDsk = result.get('sparkDsk') as Sparkline;
75
+ let cpuHistory: number[] = Array.from({ length: 30 }, () => Math.floor(Math.random() * 100));
76
+ let memHistory: number[] = Array.from({ length: 30 }, () => Math.floor(Math.random() * 100));
77
+ let dskHistory: number[] = Array.from({ length: 30 }, () => Math.floor(Math.random() * 100));
78
+ sparkCpu.setMin(0); sparkCpu.setMax(100); sparkCpu.setData(cpuHistory);
79
+ sparkMem.setMin(0); sparkMem.setMax(100); sparkMem.setData(memHistory);
80
+ sparkDsk.setMin(0); sparkDsk.setMax(100); sparkDsk.setData(dskHistory);
81
+
82
+ // ── Sparkline labels (written into the Tabs container's content) ─────────
83
+ const tabs = result.get('chartsPanel') as Tabs;
84
+ const sparkLblStyle = screen.registerStyle({ foreground: 245 });
85
+ tabs.writeText('CPU', { x: 1, y: 2, style: sparkLblStyle });
86
+ tabs.writeText('MEM', { x: 1, y: 3, style: sparkLblStyle });
87
+ tabs.writeText('DSK', { x: 1, y: 4, style: sparkLblStyle });
88
+
89
+ // ── Events list (tab 2) ──────────────────────────────────────────────────
90
+ const events = result.get('eventsList') as ListBox;
91
+ const EVENT_TEMPLATES = [
92
+ 'user logged in', 'cache warmed', 'metric collected', 'job completed',
93
+ 'config reloaded', 'heartbeat ok', 'worker spawned', 'session expired',
94
+ 'gc finished', 'index rebuilt',
95
+ ];
96
+
97
+ // ── Live-updating handles ─────────────────────────────────────────────────
98
+ const pbCpu = result.get('pbCpu') as ProgressBar;
99
+ const pbMem = result.get('pbMem') as ProgressBar;
100
+ const pbDisk = result.get('pbDisk') as ProgressBar;
101
+ const pbvLoad = result.get('pbvLoad') as ProgressBarV;
102
+
103
+ const leds: StatusLED[] = [
104
+ result.get('ledApi') as StatusLED,
105
+ result.get('ledDb') as StatusLED,
106
+ result.get('ledCache') as StatusLED,
107
+ result.get('ledWorker') as StatusLED,
108
+ ];
109
+
110
+ const headerSpinner = result.get('headerSpinner') as Spinner;
111
+
112
+ const ledStates: LedState[] = ['ok', 'ok', 'ok', 'warn', 'error', 'off'];
113
+
114
+ /** Returns a random integer in [0, max). */
115
+ const rand = (max: number): number => Math.floor(Math.random() * max);
116
+
117
+ /** Formats the current wall-clock time as HH:MM:SS. */
118
+ const timestamp = (): string => {
119
+ const d = new Date();
120
+ const pad = (n: number): string => n.toString().padStart(2, '0');
121
+ return `${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
122
+ };
123
+
124
+ /** Periodic tick: refresh charts, progress bars, status LEDs, sparklines, and event log. */
125
+ const tick = (): void => {
126
+ // scroll line chart left and append a new sample
127
+ lineData = [...lineData.slice(1), rand(100)];
128
+ lc.setData(lineData);
129
+
130
+ // shuffle bar chart values
131
+ bc.setData([rand(100), rand(100), rand(100), rand(100), rand(100)]);
132
+
133
+ // jitter progress bars
134
+ const cpu = rand(101);
135
+ const mem = rand(101);
136
+ const dsk = rand(101);
137
+ pbCpu .setValue(cpu);
138
+ pbMem .setValue(mem);
139
+ pbDisk .setValue(dsk);
140
+ pbvLoad.setValue(rand(101));
141
+
142
+ // shift sparkline history buffers (the same samples as the progress bars)
143
+ cpuHistory = [...cpuHistory.slice(1), cpu];
144
+ memHistory = [...memHistory.slice(1), mem];
145
+ dskHistory = [...dskHistory.slice(1), dsk];
146
+ sparkCpu.setData(cpuHistory);
147
+ sparkMem.setData(memHistory);
148
+ sparkDsk.setData(dskHistory);
149
+
150
+ // randomize LED states (weighted toward "ok")
151
+ for (const led of leds) {
152
+ led.setState(ledStates[rand(ledStates.length)]!);
153
+ }
154
+
155
+ // advance the header spinner
156
+ headerSpinner.step();
157
+
158
+ // prepend a new event to the log; keep the list bounded
159
+ const msg = EVENT_TEMPLATES[rand(EVENT_TEMPLATES.length)]!;
160
+ const next = [`[${timestamp()}] ${msg}`, ...events.getItems()];
161
+ events.setItems(next.slice(0, 20));
162
+
163
+ screen.render();
164
+ };
165
+
166
+ demoTimer = setInterval(tick, 1000);
167
+
168
+ wm.run();
169
+ };
170
+
171
+ main();