@orkestrel/terminal 0.0.14 → 0.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -11
- package/dist/src/core/index.cjs +115 -80
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +265 -150
- package/dist/src/core/index.d.ts +265 -150
- package/dist/src/core/index.js +115 -80
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/server/index.cjs +102 -78
- package/dist/src/server/index.cjs.map +1 -1
- package/dist/src/server/index.d.cts +122 -92
- package/dist/src/server/index.d.ts +122 -92
- package/dist/src/server/index.js +102 -78
- package/dist/src/server/index.js.map +1 -1
- package/package.json +18 -19
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
import { FieldChoice } from '@orkestrel/form';
|
|
2
|
-
import { FieldControl } from '@orkestrel/form';
|
|
3
|
-
import { FieldValue } from '@orkestrel/form';
|
|
4
|
-
import { FormField } from '@orkestrel/form';
|
|
5
|
-
import { FormInterface } from '@orkestrel/form';
|
|
6
|
-
import { FormValues } from '@orkestrel/form';
|
|
7
|
-
import { PromptTheme } from '@orkestrel/terminal';
|
|
8
|
-
import { PromptThemeOptions } from '@orkestrel/terminal';
|
|
9
|
-
import { StreamTargetInterface } from '@orkestrel/console/server';
|
|
10
|
-
import { StylerInterface } from '@orkestrel/console';
|
|
11
|
-
import { TerminalInterface } from '@orkestrel/terminal';
|
|
12
|
-
import { TextField } from '@orkestrel/form';
|
|
1
|
+
import type { FieldChoice } from '@orkestrel/form';
|
|
2
|
+
import type { FieldControl } from '@orkestrel/form';
|
|
3
|
+
import type { FieldValue } from '@orkestrel/form';
|
|
4
|
+
import type { FormField } from '@orkestrel/form';
|
|
5
|
+
import type { FormInterface } from '@orkestrel/form';
|
|
6
|
+
import type { FormValues } from '@orkestrel/form';
|
|
7
|
+
import type { PromptTheme } from '@orkestrel/terminal';
|
|
8
|
+
import type { PromptThemeOptions } from '@orkestrel/terminal';
|
|
9
|
+
import type { StreamTargetInterface } from '@orkestrel/console/server';
|
|
10
|
+
import type { StylerInterface } from '@orkestrel/console';
|
|
11
|
+
import type { TerminalInterface } from '@orkestrel/terminal';
|
|
12
|
+
import type { TextField } from '@orkestrel/form';
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
* Erases from the cursor down to the end of the screen (`ESC[J`) — wipes the
|
|
16
|
-
*
|
|
17
|
-
* never leaves orphaned rows
|
|
15
|
+
* Erases from the cursor down to the end of the screen (`ESC[J`) — wipes the whole previous view,
|
|
16
|
+
* which a `select` or `checkbox` can spread over several lines, in one write before the new view is
|
|
17
|
+
* rendered, so a redraw never leaves orphaned rows behind.
|
|
18
18
|
*/
|
|
19
19
|
export declare const CLEAR_DOWN: string;
|
|
20
20
|
|
|
@@ -28,12 +28,12 @@ export declare const CLEAR_DOWN: string;
|
|
|
28
28
|
export declare const CONTROL_HINTS: Readonly<Partial<Record<FieldControl, string>>>;
|
|
29
29
|
|
|
30
30
|
/**
|
|
31
|
-
* Creates the interactive terminal form driver — the local-keyboard arm of the terminal trio,
|
|
32
|
-
* the core headless `createPrompt` broker and the SSE `createPromptClient` bridge. Where the
|
|
33
|
-
*
|
|
34
|
-
* form's fields in schema order, drives each control's pure reducer over raw-mode stdin,
|
|
35
|
-
* answer through the form's own `fill`, and submits. It is the only impure part of the
|
|
36
|
-
* stack.
|
|
31
|
+
* Creates the interactive terminal form driver — the local-keyboard arm of the terminal trio,
|
|
32
|
+
* beside the core headless `createPrompt` broker and the SSE `createPromptClient` bridge. Where the
|
|
33
|
+
* broker parks a live form until somebody elsewhere answers it, a `Terminal` answers one here: it
|
|
34
|
+
* walks the form's fields in schema order, drives each control's pure reducer over raw-mode stdin,
|
|
35
|
+
* binds every answer through the form's own `fill`, and submits. It is the only impure part of the
|
|
36
|
+
* terminal stack.
|
|
37
37
|
*
|
|
38
38
|
* @param options - See {@link TerminalOptions}
|
|
39
39
|
* @returns A {@link TerminalInterface} whose `ask` drives one whole form over the resolved streams
|
|
@@ -53,29 +53,47 @@ export declare const CONTROL_HINTS: Readonly<Partial<Record<FieldControl, string
|
|
|
53
53
|
* - **Non-TTY fallback.** A piped stream cannot enter raw mode, so the same walk runs over
|
|
54
54
|
* `node:readline` line input.
|
|
55
55
|
*
|
|
56
|
-
* @example
|
|
56
|
+
* @example Ask one form at this keyboard
|
|
57
57
|
* ```ts
|
|
58
58
|
* import { createForm } from '@orkestrel/form'
|
|
59
|
+
* import { isTerminalError } from '@orkestrel/terminal'
|
|
59
60
|
* import { createTerminal } from '@orkestrel/terminal/server'
|
|
60
61
|
*
|
|
61
|
-
* const terminal = createTerminal()
|
|
62
|
-
* const
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
62
|
+
* const terminal = createTerminal() // process.stdin / process.stdout by default
|
|
63
|
+
* const form = createForm({
|
|
64
|
+
* label: 'Sign up',
|
|
65
|
+
* fields: [
|
|
66
|
+
* { control: 'text', name: 'name', label: 'Your name', rule: { required: true, minimum: 2 } },
|
|
67
|
+
* { control: 'text', name: 'email', label: 'Email', rule: { required: true, email: true } },
|
|
68
|
+
* { control: 'password', name: 'token', label: 'Token' },
|
|
69
|
+
* { control: 'confirm', name: 'terms', label: 'Accept the terms', rule: { required: true } },
|
|
70
|
+
* {
|
|
71
|
+
* control: 'select',
|
|
72
|
+
* name: 'role',
|
|
73
|
+
* label: 'Role',
|
|
74
|
+
* choices: [
|
|
75
|
+
* { value: 'admin', label: 'Admin' },
|
|
76
|
+
* { value: 'viewer', label: 'Viewer', help: 'read-only' },
|
|
77
|
+
* ],
|
|
78
|
+
* },
|
|
79
|
+
* ],
|
|
80
|
+
* })
|
|
81
|
+
*
|
|
82
|
+
* try {
|
|
83
|
+
* const values = await terminal.ask(form)
|
|
84
|
+
* deploy(values)
|
|
85
|
+
* } catch (error) {
|
|
86
|
+
* // Ctrl-c: the walk ended, and the form is still `editing` for whoever owns it.
|
|
87
|
+
* if (isTerminalError(error) && error.code === 'CANCEL') form.destroy()
|
|
88
|
+
* }
|
|
71
89
|
* ```
|
|
72
90
|
*/
|
|
73
91
|
export declare function createTerminal(options?: TerminalOptions): TerminalInterface;
|
|
74
92
|
|
|
75
93
|
/**
|
|
76
|
-
* Holds the cursor-
|
|
77
|
-
* interpolates the `{count}` placeholder with the
|
|
78
|
-
* the count stays out of the constant.
|
|
94
|
+
* Holds the cursor-up sequence template (`ESC[{count}A`) —
|
|
95
|
+
* {@link import('./helpers.js').renderCursorUp} interpolates the `{count}` placeholder with the
|
|
96
|
+
* number of lines to climb. Kept as a template so the count stays out of the constant.
|
|
79
97
|
*/
|
|
80
98
|
export declare const CSI_UP: string;
|
|
81
99
|
|
|
@@ -105,11 +123,11 @@ export declare const FALLBACK_EDITOR_HINT = "(end of input finishes)";
|
|
|
105
123
|
export declare const FALLBACK_SELECT_HINT = "Enter a number";
|
|
106
124
|
|
|
107
125
|
/**
|
|
108
|
-
* Projects any field the walk reads as a
|
|
109
|
-
* takes — `text` itself, and the controls a terminal has no widget for: `number`, `date`,
|
|
110
|
-
* `
|
|
111
|
-
*
|
|
112
|
-
* projection carries no rule, because the
|
|
126
|
+
* Projects any field the walk reads as a line of text into the {@link TextField} the text reducer
|
|
127
|
+
* takes — `text` itself, and the controls a terminal has no widget for: `number`, `date`, `time`,
|
|
128
|
+
* `datetime`, `color`, and one `file` entry. The label carries that control's format cue from
|
|
129
|
+
* {@link CONTROL_HINTS}, and a declared `default` becomes the line a bare return submits. The
|
|
130
|
+
* projection carries no rule, because the authoritative form still evaluates the answer this line
|
|
113
131
|
* binds; it exists only so one reducer covers every one of them.
|
|
114
132
|
*
|
|
115
133
|
* @param field - The field being read
|
|
@@ -127,7 +145,7 @@ export declare function fieldToText(field: FormField): TextField;
|
|
|
127
145
|
export declare const FILE_HINT = "One path per line, blank to finish";
|
|
128
146
|
|
|
129
147
|
/**
|
|
130
|
-
* Returns the choices a `select` or `checkbox` field
|
|
148
|
+
* Returns the choices a `select` or `checkbox` field shows but refuses — the complement of
|
|
131
149
|
* {@link filterEnabled}, rendered by {@link renderUnavailableLine} above the list so a reader sees
|
|
132
150
|
* why a declared choice is missing from it.
|
|
133
151
|
*
|
|
@@ -137,7 +155,7 @@ export declare const FILE_HINT = "One path per line, blank to finish";
|
|
|
137
155
|
export declare function filterDisabled(choices: readonly FieldChoice[]): readonly FieldChoice[];
|
|
138
156
|
|
|
139
157
|
/**
|
|
140
|
-
* Returns the choices a `select` or `checkbox` field actually
|
|
158
|
+
* Returns the choices a `select` or `checkbox` field actually offers — the form refuses a disabled
|
|
141
159
|
* choice's value at every door, including a fill, so the walk never puts one in front of the
|
|
142
160
|
* cursor. Pair with {@link filterDisabled} to tell the reader what was withheld.
|
|
143
161
|
*
|
|
@@ -166,24 +184,30 @@ export declare function filterEnabled(choices: readonly FieldChoice[]): readonly
|
|
|
166
184
|
* - `isTTY` — `true` on a real terminal, absent or `false` when piped to a file or another process.
|
|
167
185
|
*/
|
|
168
186
|
export declare interface InputStreamInterface {
|
|
187
|
+
/** Subscribes a `'data'` chunk listener — the irreducible event seam. */
|
|
169
188
|
on(event: 'data', listener: (chunk: string | Uint8Array) => void): void;
|
|
189
|
+
/** Unsubscribes that listener. The driver always pairs it, so no listener leaks. */
|
|
170
190
|
off(event: 'data', listener: (chunk: string | Uint8Array) => void): void;
|
|
191
|
+
/** Switches the TTY in and out of raw mode. Absent on a piped stream. */
|
|
171
192
|
setRawMode?(mode: boolean): void;
|
|
193
|
+
/** Starts the flow of `'data'` events. */
|
|
172
194
|
resume?(): void;
|
|
195
|
+
/** Stops it again on cleanup. */
|
|
173
196
|
pause?(): void;
|
|
197
|
+
/** Reports whether the stream is a real terminal; absent or false when piped. */
|
|
174
198
|
readonly isTTY?: boolean;
|
|
175
199
|
}
|
|
176
200
|
|
|
177
201
|
/**
|
|
178
|
-
* Checks whether `value` is a usable {@link InputStreamInterface} — a record with callable `on` /
|
|
179
|
-
* `'data'` subscription methods. A total type guard: it
|
|
180
|
-
*
|
|
181
|
-
* or a fake TTY a test injects) to the exact slice the driver reads
|
|
202
|
+
* Checks whether `value` is a usable {@link InputStreamInterface} — a record with callable `on` /
|
|
203
|
+
* `off` `'data'` subscription methods. A total type guard: it never throws and returns `false` for
|
|
204
|
+
* anything off-shape, so it narrows the one unavoidable input boundary (the real `process.stdin`,
|
|
205
|
+
* or a fake TTY a test injects) to the exact slice the driver reads, never an assertion.
|
|
182
206
|
*
|
|
183
207
|
* @remarks
|
|
184
208
|
* Only `on` / `off` are required (the irreducible event seam); `setRawMode` / `resume` / `pause` /
|
|
185
209
|
* `isTTY` are optional on {@link InputStreamInterface}, so their absence does not disqualify a stream
|
|
186
|
-
* — a piped, non-TTY stream is still a valid input,
|
|
210
|
+
* — a piped, non-TTY stream is still a valid input, one the driver reads through the readline
|
|
187
211
|
* fallback rather than raw mode.
|
|
188
212
|
*
|
|
189
213
|
* @param value - Any value crossing the boundary (a process stream, an injected fake, `unknown`)
|
|
@@ -193,11 +217,11 @@ export declare function isInputStream(value: unknown): value is InputStreamInter
|
|
|
193
217
|
|
|
194
218
|
/**
|
|
195
219
|
* Checks whether `value` is a Node {@link NodeJS.ReadableStream} — a total structural guard
|
|
196
|
-
* checking for the callable `read` / `pipe` / `on` that `node:readline`'s `createInterface`
|
|
197
|
-
* as its `input`. The non-TTY fallback narrows the resolved input stream through this
|
|
198
|
-
* it to readline
|
|
199
|
-
* crosses into the readline boundary honestly. Never throws; returns
|
|
200
|
-
* isn't a full readable.
|
|
220
|
+
* checking for the callable `read` / `pipe` / `on` that `node:readline`'s `createInterface`
|
|
221
|
+
* requires as its `input`. The non-TTY fallback narrows the resolved input stream through this
|
|
222
|
+
* before handing it to readline, never through an assertion, so a real piped `process.stdin` (or a
|
|
223
|
+
* `PassThrough` a test injects) crosses into the readline boundary honestly. Never throws; returns
|
|
224
|
+
* `false` for a minimal fake that isn't a full readable.
|
|
201
225
|
*
|
|
202
226
|
* @param value - The resolved input stream (or any value crossing the boundary)
|
|
203
227
|
* @returns True if `value` has the readable methods readline needs; false otherwise
|
|
@@ -205,10 +229,10 @@ export declare function isInputStream(value: unknown): value is InputStreamInter
|
|
|
205
229
|
export declare function isReadable(value: unknown): value is NodeJS.ReadableStream;
|
|
206
230
|
|
|
207
231
|
/**
|
|
208
|
-
* Counts the terminal
|
|
209
|
-
*
|
|
210
|
-
* re-render: the driver records the line count of the view it
|
|
211
|
-
* far up to move the cursor before overwriting. Total; an empty string is one
|
|
232
|
+
* Counts the terminal lines a rendered prompt `view` occupies — one more than its newline count, so
|
|
233
|
+
* a view with no newline is a single line and a view with N newlines spans N+1 lines. The basis of
|
|
234
|
+
* the in-place re-render: the driver records the line count of the view it wrote so the next redraw
|
|
235
|
+
* knows how far up to move the cursor before overwriting. Total; an empty string is one empty line.
|
|
212
236
|
*
|
|
213
237
|
* @param view - The rendered (possibly multi-line, possibly ANSI-styled) view string
|
|
214
238
|
* @returns The number of lines the view spans (always at least 1)
|
|
@@ -219,20 +243,20 @@ export declare function lineCount(view: string): number;
|
|
|
219
243
|
export declare const LOCKED_MARK = "(locked)";
|
|
220
244
|
|
|
221
245
|
/**
|
|
222
|
-
* Returns the full reposition-and-clear prefix to write
|
|
223
|
-
* the line count of the
|
|
224
|
-
* 0, and erases everything from there to the end of the screen, so the next view is drawn
|
|
225
|
-
*
|
|
226
|
-
* followed by the new view.
|
|
246
|
+
* Returns the full reposition-and-clear prefix to write before re-rendering a prompt view in place
|
|
247
|
+
* — given the line count of the previous view, it moves the cursor up over those lines, returns it
|
|
248
|
+
* to column 0, and erases everything from there to the end of the screen, so the next view is drawn
|
|
249
|
+
* on a clean region and a taller previous view leaves no orphaned rows. Pure; the driver writes
|
|
250
|
+
* this immediately followed by the new view.
|
|
227
251
|
*
|
|
228
252
|
* @remarks
|
|
229
|
-
* For the
|
|
230
|
-
* the prefix is
|
|
231
|
-
* subsequent render it climbs `previousLines - 1` lines (the cursor is on the
|
|
253
|
+
* For the first render `previousLines` is `1` (the cursor sits on the line the prompt opened on) so
|
|
254
|
+
* the prefix is a carriage return + clear-down — the prompt draws from the current line. For a
|
|
255
|
+
* subsequent render it climbs `previousLines - 1` lines (the cursor is on the last line of the prior
|
|
232
256
|
* view) before clearing. Keeping the math here (not in the driver) makes the re-render unit-testable
|
|
233
257
|
* without a real terminal.
|
|
234
258
|
*
|
|
235
|
-
* @param previousLines - The line count of the view
|
|
259
|
+
* @param previousLines - The line count of the view on screen (from {@link lineCount})
|
|
236
260
|
* @returns The control-sequence prefix to write before the new view
|
|
237
261
|
*/
|
|
238
262
|
export declare function redrawPrefix(previousLines: number): string;
|
|
@@ -246,10 +270,10 @@ export declare function redrawPrefix(previousLines: number): string;
|
|
|
246
270
|
export declare const REFUSAL_MESSAGE = "Enter a value this field accepts";
|
|
247
271
|
|
|
248
272
|
/**
|
|
249
|
-
* Returns the cursor-
|
|
250
|
-
* empty string when `count` is zero or negative
|
|
251
|
-
* The pure step the in-place re-render uses to climb back over the previous view
|
|
252
|
-
* Total.
|
|
273
|
+
* Returns the cursor-up control sequence that moves the cursor up `count` lines (`ESC[{count}A`),
|
|
274
|
+
* or the empty string when `count` is zero or negative, because no movement is needed and `ESC[0A`
|
|
275
|
+
* is a wasted write. The pure step the in-place re-render uses to climb back over the previous view
|
|
276
|
+
* before clearing it. Total.
|
|
253
277
|
*
|
|
254
278
|
* @param count - How many lines to move the cursor up
|
|
255
279
|
* @returns The `ESC[{count}A` sequence, or `''` when `count <= 0`
|
|
@@ -268,9 +292,9 @@ export declare function renderCursorUp(count: number): string;
|
|
|
268
292
|
export declare function renderGroupHeader(styler: StylerInterface, theme: PromptTheme, label: string): string;
|
|
269
293
|
|
|
270
294
|
/**
|
|
271
|
-
* Renders the read-only line a
|
|
272
|
-
* answer the form already holds. The walk writes this instead of a prompt, because the field is
|
|
273
|
-
* validated and still submitted but must not be edited here.
|
|
295
|
+
* Renders the read-only line a locked field shows — its label, the {@link LOCKED_MARK}, and the
|
|
296
|
+
* answer the form already holds. The walk writes this instead of a prompt, because the field is
|
|
297
|
+
* still validated and still submitted but must not be edited here.
|
|
274
298
|
*
|
|
275
299
|
* @param styler - The console styler that renders each role
|
|
276
300
|
* @param theme - The resolved prompt theme
|
|
@@ -293,7 +317,7 @@ export declare function renderLockedLine(styler: StylerInterface, theme: PromptT
|
|
|
293
317
|
export declare function renderNumberedList(styler: StylerInterface, theme: PromptTheme, choices: readonly FieldChoice[]): string;
|
|
294
318
|
|
|
295
319
|
/**
|
|
296
|
-
* Renders the line listing an
|
|
320
|
+
* Renders the line listing an open select's offered values above its text prompt — a suggestion
|
|
297
321
|
* list, because an open select admits an answer the list does not offer.
|
|
298
322
|
*
|
|
299
323
|
* @param styler - The console styler that renders each role
|
|
@@ -314,15 +338,18 @@ export declare function renderSuggestionLine(styler: StylerInterface, theme: Pro
|
|
|
314
338
|
*/
|
|
315
339
|
export declare function renderUnavailableLine(styler: StylerInterface, theme: PromptTheme, choices: readonly FieldChoice[]): string;
|
|
316
340
|
|
|
317
|
-
/**
|
|
341
|
+
/**
|
|
342
|
+
* Holds the lead on the line listing an open `select`'s offered values, which a typed answer can
|
|
343
|
+
* ignore.
|
|
344
|
+
*/
|
|
318
345
|
export declare const SUGGESTION_LEAD = "Suggestions";
|
|
319
346
|
|
|
320
347
|
/**
|
|
321
|
-
* Checks whether an input stream can be driven in
|
|
322
|
-
* exposes a callable `setRawMode`. The {@link import('./Terminal.js').Terminal} probes this to
|
|
323
|
-
*
|
|
324
|
-
* `node:readline` line-input fallback
|
|
325
|
-
* never throws.
|
|
348
|
+
* Checks whether an input stream can be driven in raw mode — it reports `isTTY === true` and
|
|
349
|
+
* exposes a callable `setRawMode`. The {@link import('./Terminal.js').Terminal} probes this to
|
|
350
|
+
* choose its path: true selects the interactive raw-mode fields, with arrow-key navigation and a
|
|
351
|
+
* live re-render; false selects the `node:readline` line-input fallback, because a piped or
|
|
352
|
+
* non-terminal stream cannot enter raw mode. Total — never throws.
|
|
326
353
|
*
|
|
327
354
|
* @param input - The resolved {@link InputStreamInterface}
|
|
328
355
|
* @returns True if the stream is a TTY with `setRawMode`; false otherwise
|
|
@@ -330,12 +357,13 @@ export declare const SUGGESTION_LEAD = "Suggestions";
|
|
|
330
357
|
export declare function supportsRawMode(input: InputStreamInterface): boolean;
|
|
331
358
|
|
|
332
359
|
/**
|
|
333
|
-
* Implements {@link TerminalInterface} for a human at this machine's keyboard — the interactive
|
|
334
|
-
*
|
|
335
|
-
*
|
|
336
|
-
*
|
|
337
|
-
*
|
|
338
|
-
* the form it is given, and this class owns only raw mode, the cursor, and
|
|
360
|
+
* Implements {@link TerminalInterface} for a human at this machine's keyboard — the interactive
|
|
361
|
+
* form driver, and the only impure part of the terminal stack. {@link ask} walks one form's fields
|
|
362
|
+
* in schema order, feeds raw-mode stdin bytes through `parseKey` into the matching pure reducer,
|
|
363
|
+
* renders each returned view in place, binds every answer through the form's own `fill`, and
|
|
364
|
+
* re-asks what the form refused. It owns no form logic: the schema, the rules, the values, and the
|
|
365
|
+
* settlement all belong to the form it is given, and this class owns only raw mode, the cursor, and
|
|
366
|
+
* the re-render.
|
|
339
367
|
*
|
|
340
368
|
* @remarks
|
|
341
369
|
* See {@link TerminalInterface} for the driving contract. The walk itself:
|
|
@@ -347,12 +375,11 @@ export declare function supportsRawMode(input: InputStreamInterface): boolean;
|
|
|
347
375
|
* `open` means the answer need not come from the list.
|
|
348
376
|
* - **The binding projects through `matchesAnswer`.** Every answer is filled as
|
|
349
377
|
* `fill(name, matchesAnswer(value) ? value : undefined)` after `parseValue` has coerced it to the
|
|
350
|
-
* control's own shape, so a bare return on a field with no default binds as
|
|
378
|
+
* control's own shape, so a bare return on a field with no default binds as absence and the
|
|
351
379
|
* form's `required` rule refuses it. A typed answer the control cannot hold binds as absence and
|
|
352
380
|
* invalidates the field, so the walk asks again with the reason on screen.
|
|
353
|
-
* - **Visibility is honored.** A `hidden` field and a field
|
|
354
|
-
*
|
|
355
|
-
* header.
|
|
381
|
+
* - **Visibility is honored.** A `hidden` field and a field in `form.disabled` are skipped; a
|
|
382
|
+
* `locked` field renders read-only; entering a new group writes its label as a section header.
|
|
356
383
|
* - **Refusal re-asks.** After the walk the form is submitted. A refusal re-walks only the erroring
|
|
357
384
|
* fields the walk can edit and submits again. When every erroring field is one the walk cannot
|
|
358
385
|
* edit — hidden, locked, or disabled — the form is abandoned instead, because asking again could
|
|
@@ -384,8 +411,8 @@ export declare class Terminal implements TerminalInterface {
|
|
|
384
411
|
* the rendered output. That is the console module's own boundary shape, so one target drives a
|
|
385
412
|
* console sink and this driver alike.
|
|
386
413
|
* - `theme` — the glyphs and role styles every rendered line is painted with, merged over
|
|
387
|
-
* {@link import('@
|
|
388
|
-
* {@link import('@
|
|
414
|
+
* {@link import('@orkestrel/terminal').DEFAULT_PROMPT_THEME} leaf by leaf by
|
|
415
|
+
* {@link import('@orkestrel/terminal').createPromptTheme}. Supplying one icon or one role leaves every
|
|
389
416
|
* other slot at its default.
|
|
390
417
|
*/
|
|
391
418
|
export declare interface TerminalOptions {
|
|
@@ -394,7 +421,10 @@ export declare interface TerminalOptions {
|
|
|
394
421
|
readonly theme?: PromptThemeOptions;
|
|
395
422
|
}
|
|
396
423
|
|
|
397
|
-
/**
|
|
424
|
+
/**
|
|
425
|
+
* Holds the lead on the line listing the choices a `select` or `checkbox` shows but refuses, so a
|
|
426
|
+
* reader sees why one is missing from the list it heads.
|
|
427
|
+
*/
|
|
398
428
|
export declare const UNAVAILABLE_LEAD = "Unavailable";
|
|
399
429
|
|
|
400
430
|
/**
|