@boba-cli/dsl 0.1.0-alpha.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.
@@ -0,0 +1,738 @@
1
+ import { Cmd, Msg, Model } from '@boba-cli/tea';
2
+ import { Style } from '@boba-cli/chapstick';
3
+ export { Style } from '@boba-cli/chapstick';
4
+ import { Spinner, SpinnerModel } from '@boba-cli/spinner';
5
+ export { Spinner, dot, ellipsis, line, meter, miniDot, moon, points, pulse } from '@boba-cli/spinner';
6
+ import { EchoMode, ValidateFunc, TextInputModel } from '@boba-cli/textinput';
7
+ export { CursorMode, EchoMode, TextInputModel, ValidateFunc } from '@boba-cli/textinput';
8
+
9
+ /**
10
+ * View node types for the view DSL.
11
+ * @public
12
+ */
13
+ type ViewNode = string | TextNode | LayoutNode | ComponentView;
14
+ /**
15
+ * Text node with chainable style methods.
16
+ *
17
+ * @remarks
18
+ * Text nodes provide a fluent API for applying terminal styling to text content.
19
+ * All styling methods return a new {@link TextNode} instance, allowing for method chaining.
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * text('Hello').bold().foreground('#ff79c6')
24
+ * text('Warning').dim().italic()
25
+ * ```
26
+ *
27
+ * @public
28
+ */
29
+ interface TextNode {
30
+ /** Internal discriminator for type narrowing. */
31
+ readonly _type: 'text';
32
+ /** The text content to display. */
33
+ readonly content: string;
34
+ /** Whether bold styling is applied. */
35
+ readonly _bold: boolean;
36
+ /** Whether dim styling is applied. */
37
+ readonly _dim: boolean;
38
+ /** Whether italic styling is applied. */
39
+ readonly _italic: boolean;
40
+ /** Foreground color (hex or named color). */
41
+ readonly _foreground: string | undefined;
42
+ /** Background color (hex or named color). */
43
+ readonly _background: string | undefined;
44
+ /**
45
+ * Apply bold styling to the text.
46
+ * @returns A new {@link TextNode} with bold styling applied.
47
+ */
48
+ bold(): TextNode;
49
+ /**
50
+ * Apply dim styling to the text.
51
+ * @returns A new {@link TextNode} with dim styling applied.
52
+ */
53
+ dim(): TextNode;
54
+ /**
55
+ * Apply italic styling to the text.
56
+ * @returns A new {@link TextNode} with italic styling applied.
57
+ */
58
+ italic(): TextNode;
59
+ /**
60
+ * Set the foreground color.
61
+ * @param color - Hex color (e.g., '#ff79c6') or named color
62
+ * @returns A new {@link TextNode} with the foreground color applied.
63
+ */
64
+ foreground(color: string): TextNode;
65
+ /**
66
+ * Set the background color.
67
+ * @param color - Hex color (e.g., '#282a36') or named color
68
+ * @returns A new {@link TextNode} with the background color applied.
69
+ */
70
+ background(color: string): TextNode;
71
+ }
72
+ /**
73
+ * Layout node for stacking views vertically or horizontally.
74
+ *
75
+ * @remarks
76
+ * Layout nodes arrange child views in either a vertical stack ({@link vstack})
77
+ * or horizontal stack ({@link hstack}). Children are rendered with optional
78
+ * spacing between them.
79
+ *
80
+ * @example
81
+ * ```typescript
82
+ * vstack(
83
+ * text('Line 1'),
84
+ * text('Line 2')
85
+ * )
86
+ *
87
+ * hstack(
88
+ * text('Left'),
89
+ * text('Right')
90
+ * )
91
+ * ```
92
+ *
93
+ * @public
94
+ */
95
+ interface LayoutNode {
96
+ /** Layout direction: 'vstack' for vertical, 'hstack' for horizontal. */
97
+ readonly _type: 'vstack' | 'hstack';
98
+ /** Child view nodes to arrange. */
99
+ readonly children: ViewNode[];
100
+ /** Spacing between children (in newlines for vstack, spaces for hstack). */
101
+ readonly spacing: number;
102
+ }
103
+ /**
104
+ * Component view wrapper containing rendered output from a TEA component.
105
+ *
106
+ * @remarks
107
+ * Component views are returned by the builder when registering components
108
+ * via {@link AppBuilder.component}. They contain the pre-rendered string
109
+ * output from the component's `view()` method.
110
+ *
111
+ * @example
112
+ * ```typescript
113
+ * createApp()
114
+ * .component('spinner', spinner())
115
+ * .view(({ components }) => components.spinner)
116
+ * // ^^^^^^^^^^^^^^^^^ ComponentView
117
+ * ```
118
+ *
119
+ * @public
120
+ */
121
+ interface ComponentView {
122
+ /** Internal discriminator for type narrowing. */
123
+ readonly _type: 'component';
124
+ /** The rendered view string from the component. */
125
+ readonly view: string;
126
+ }
127
+ /**
128
+ * Component builder interface for wrapping TEA components.
129
+ *
130
+ * @remarks
131
+ * Component builders provide an adapter between TEA components (which follow
132
+ * the Model-Update-View pattern) and the DSL. When you register a component
133
+ * via {@link AppBuilder.component}, you provide a `ComponentBuilder` that
134
+ * handles initialization, updates, and rendering.
135
+ *
136
+ * @example
137
+ * ```typescript
138
+ * const spinnerBuilder: ComponentBuilder<SpinnerModel> = {
139
+ * init: () => {
140
+ * const model = new SpinnerModel()
141
+ * return [model, model.tick()]
142
+ * },
143
+ * update: (model, msg) => model.update(msg),
144
+ * view: (model) => model.view(),
145
+ * }
146
+ * ```
147
+ *
148
+ * @typeParam M - The model type managed by this component
149
+ *
150
+ * @public
151
+ */
152
+ interface ComponentBuilder<M> {
153
+ /**
154
+ * Initialize the component and return the initial model and command.
155
+ * @returns A tuple of [initial model, initial command]
156
+ */
157
+ init(): [M, Cmd<Msg>];
158
+ /**
159
+ * Update the component with a message.
160
+ * @param model - The current component model
161
+ * @param msg - The message to process
162
+ * @returns A tuple of [next model, next command]
163
+ */
164
+ update(model: M, msg: Msg): [M, Cmd<Msg>];
165
+ /**
166
+ * Render the component to a string.
167
+ * @param model - The current component model
168
+ * @returns The rendered view string
169
+ */
170
+ view(model: M): string;
171
+ }
172
+ /**
173
+ * Event context passed to key event handlers.
174
+ *
175
+ * @remarks
176
+ * The event context provides access to the current application state and
177
+ * component views, along with methods to update state or quit the application.
178
+ * It's passed to handlers registered via {@link AppBuilder.onKey}.
179
+ *
180
+ * @example
181
+ * ```typescript
182
+ * createApp()
183
+ * .state({ count: 0 })
184
+ * .onKey('up', ({ state, update }) => {
185
+ * update({ count: state.count + 1 })
186
+ * })
187
+ * .onKey('q', ({ quit }) => quit())
188
+ * ```
189
+ *
190
+ * @typeParam State - The application state type
191
+ * @typeParam Components - Record of registered components
192
+ *
193
+ * @public
194
+ */
195
+ interface EventContext<State, Components extends Record<string, unknown>> {
196
+ /** Current application state. */
197
+ readonly state: State;
198
+ /** Current component views (rendered strings). */
199
+ readonly components: {
200
+ [K in keyof Components]: ComponentView;
201
+ };
202
+ /**
203
+ * Update state with a partial patch (shallow merge).
204
+ * @param patch - Partial state object to merge with current state
205
+ */
206
+ update(patch: Partial<State>): void;
207
+ /**
208
+ * Replace entire state with a new value.
209
+ * @param newState - The new complete state
210
+ */
211
+ setState(newState: State): void;
212
+ /**
213
+ * Quit the application gracefully.
214
+ */
215
+ quit(): void;
216
+ }
217
+ /**
218
+ * Key handler function type.
219
+ *
220
+ * @remarks
221
+ * Key handlers are registered via {@link AppBuilder.onKey} and receive an
222
+ * {@link EventContext} with the current state and component views. Handlers
223
+ * can update state or quit the application.
224
+ *
225
+ * @typeParam State - The application state type
226
+ * @typeParam Components - Record of registered components
227
+ *
228
+ * @public
229
+ */
230
+ type KeyHandler<State, Components extends Record<string, unknown>> = (ctx: EventContext<State, Components>) => void;
231
+ /**
232
+ * View function type.
233
+ *
234
+ * @remarks
235
+ * The view function is registered via {@link AppBuilder.view} and is called
236
+ * on every render cycle. It receives the current state and component views,
237
+ * and returns a {@link ViewNode} tree to display.
238
+ *
239
+ * @typeParam State - The application state type
240
+ * @typeParam Components - Record of registered components
241
+ *
242
+ * @public
243
+ */
244
+ type ViewFunction<State, Components extends Record<string, unknown>> = (ctx: {
245
+ state: State;
246
+ components: {
247
+ [K in keyof Components]: ComponentView;
248
+ };
249
+ }) => ViewNode;
250
+ /**
251
+ * Built application ready to run.
252
+ *
253
+ * @remarks
254
+ * An `App` is created by calling {@link AppBuilder.build}. It provides a
255
+ * `run()` method to start the application event loop and a `getModel()` escape
256
+ * hatch to access the underlying TEA model for advanced use cases.
257
+ *
258
+ * @typeParam State - The application state type
259
+ * @typeParam _Components - Record of registered components (phantom type)
260
+ *
261
+ * @public
262
+ */
263
+ interface App<State, _Components extends Record<string, unknown>> {
264
+ /**
265
+ * Run the application and block until it quits.
266
+ * @returns A promise resolving to the final application state
267
+ */
268
+ run(): Promise<{
269
+ state: State;
270
+ }>;
271
+ /**
272
+ * Get the underlying TEA model (escape hatch for advanced use cases).
273
+ * @returns The generated TEA Model from `@boba-cli/tea`
274
+ */
275
+ getModel(): Model<Msg>;
276
+ }
277
+
278
+ /**
279
+ * Builder for creating declarative CLI applications.
280
+ *
281
+ * @example
282
+ * ```typescript
283
+ * const app = createApp()
284
+ * .state({ count: 0 })
285
+ * .component('spinner', spinner())
286
+ * .onKey('q', ({ quit }) => quit())
287
+ * .view(({ state, components }) => vstack(
288
+ * text('Count: ' + state.count),
289
+ * components.spinner
290
+ * ))
291
+ * .build()
292
+ *
293
+ * await app.run()
294
+ * ```
295
+ *
296
+ * @public
297
+ */
298
+ declare class AppBuilder<State = undefined, Components extends Record<string, unknown> = Record<string, never>> {
299
+ #private;
300
+ private constructor();
301
+ /**
302
+ * Create a new AppBuilder instance.
303
+ * @internal
304
+ */
305
+ static create(): AppBuilder<undefined, Record<string, never>>;
306
+ /**
307
+ * Set the initial application state.
308
+ *
309
+ * @remarks
310
+ * This should typically be called early in the builder chain. If called after
311
+ * registering key handlers or a view function, those will be preserved but
312
+ * their type information will be updated to reflect the new state type.
313
+ *
314
+ * @example
315
+ * ```typescript
316
+ * createApp()
317
+ * .state({ count: 0, name: 'World' })
318
+ * ```
319
+ *
320
+ * @typeParam S - The application state type
321
+ * @param initial - The initial state object
322
+ * @returns A new {@link AppBuilder} with the state type parameter set
323
+ *
324
+ * @public
325
+ */
326
+ state<S>(initial: S): AppBuilder<S, Components>;
327
+ /**
328
+ * Register a component with a unique key.
329
+ *
330
+ * @remarks
331
+ * Components are TEA models wrapped in a {@link ComponentBuilder} that
332
+ * manages their lifecycle. The component's rendered view is available in
333
+ * the view function via `components[key]`.
334
+ *
335
+ * @example
336
+ * ```typescript
337
+ * createApp()
338
+ * .component('loading', spinner())
339
+ * .component('input', textInput())
340
+ * ```
341
+ *
342
+ * @typeParam K - The component key (string literal type)
343
+ * @typeParam M - The component model type
344
+ * @param key - Unique identifier for this component
345
+ * @param builder - Component builder implementing init/update/view
346
+ * @returns A new {@link AppBuilder} with the component registered
347
+ *
348
+ * @public
349
+ */
350
+ component<K extends string, M>(key: K, builder: ComponentBuilder<M>): AppBuilder<State, Components & Record<K, M>>;
351
+ /**
352
+ * Register a key handler.
353
+ *
354
+ * @remarks
355
+ * Key handlers receive an {@link EventContext} with the current state and
356
+ * components. Multiple keys can be bound to the same handler by passing an
357
+ * array of key strings. Key strings support modifiers like 'ctrl+c', 'alt+enter'.
358
+ *
359
+ * @example
360
+ * ```typescript
361
+ * createApp()
362
+ * .onKey('q', ({ quit }) => quit())
363
+ * .onKey(['up', 'k'], ({ state, update }) => update({ index: state.index - 1 }))
364
+ * .onKey('ctrl+c', ({ quit }) => quit())
365
+ * ```
366
+ *
367
+ * @param keys - Single key string or array of key strings
368
+ * @param handler - Function to call when any of the keys are pressed
369
+ * @returns A new {@link AppBuilder} with the key handler registered
370
+ *
371
+ * @public
372
+ */
373
+ onKey(keys: string | string[], handler: KeyHandler<State, Components>): AppBuilder<State, Components>;
374
+ /**
375
+ * Set the view function.
376
+ *
377
+ * @remarks
378
+ * The view function is called on every render cycle and receives the current
379
+ * state and component views. It should return a {@link ViewNode} tree
380
+ * describing the UI to display.
381
+ *
382
+ * @example
383
+ * ```typescript
384
+ * createApp()
385
+ * .view(({ state, components }) => vstack(
386
+ * text('Hello ' + state.name),
387
+ * components.spinner
388
+ * ))
389
+ * ```
390
+ *
391
+ * @param fn - Function that returns a {@link ViewNode} tree
392
+ * @returns A new {@link AppBuilder} with the view function set
393
+ *
394
+ * @public
395
+ */
396
+ view(fn: ViewFunction<State, Components>): AppBuilder<State, Components>;
397
+ /**
398
+ * Build the application.
399
+ *
400
+ * @remarks
401
+ * Finalizes the builder chain and creates an {@link App} instance ready
402
+ * to run. This method must be called after setting a view function via
403
+ * {@link AppBuilder.view}.
404
+ *
405
+ * @throws Error if no view function has been set
406
+ *
407
+ * @returns The built {@link App} ready to run
408
+ *
409
+ * @public
410
+ */
411
+ build(): App<State, Components>;
412
+ }
413
+ /**
414
+ * Create a new application builder.
415
+ *
416
+ * @example
417
+ * ```typescript
418
+ * const app = createApp()
419
+ * .state({ count: 0 })
420
+ * .onKey('q', ({ quit }) => quit())
421
+ * .view(({ state }) => text('Count: ' + state.count))
422
+ * .build()
423
+ * ```
424
+ *
425
+ * @public
426
+ */
427
+ declare function createApp(): AppBuilder<undefined, Record<string, never>>;
428
+
429
+ /**
430
+ * Create a text node with chainable style methods.
431
+ *
432
+ * @remarks
433
+ * Text nodes support fluent styling via methods like `bold()`,
434
+ * `dim()`, `italic()`, `foreground()`, and `background()`.
435
+ *
436
+ * @example
437
+ * ```typescript
438
+ * text('Hello').bold().foreground('#ff79c6')
439
+ * text('Warning').dim()
440
+ * ```
441
+ *
442
+ * @param content - The text content to display
443
+ * @returns A new {@link TextNode}
444
+ *
445
+ * @public
446
+ */
447
+ declare function text(content: string): TextNode;
448
+ /**
449
+ * Create a vertical stack layout.
450
+ *
451
+ * @remarks
452
+ * Arranges child views vertically with newlines between them. Children are
453
+ * rendered in order from top to bottom.
454
+ *
455
+ * @example
456
+ * ```typescript
457
+ * vstack(
458
+ * text('Line 1'),
459
+ * text('Line 2'),
460
+ * text('Line 3')
461
+ * )
462
+ * ```
463
+ *
464
+ * @param children - View nodes to stack vertically
465
+ * @returns A new {@link LayoutNode} with vertical stacking
466
+ *
467
+ * @public
468
+ */
469
+ declare function vstack(...children: ViewNode[]): LayoutNode;
470
+ /**
471
+ * Create a horizontal stack layout.
472
+ *
473
+ * @remarks
474
+ * Arranges child views horizontally on the same line. Children are
475
+ * rendered in order from left to right.
476
+ *
477
+ * @example
478
+ * ```typescript
479
+ * hstack(
480
+ * text('Left'),
481
+ * text(' | '),
482
+ * text('Right')
483
+ * )
484
+ * ```
485
+ *
486
+ * @param children - View nodes to stack horizontally
487
+ * @returns A new {@link LayoutNode} with horizontal stacking
488
+ *
489
+ * @public
490
+ */
491
+ declare function hstack(...children: ViewNode[]): LayoutNode;
492
+ /**
493
+ * Create empty vertical space.
494
+ *
495
+ * @remarks
496
+ * Useful for adding vertical spacing between sections of your UI.
497
+ *
498
+ * @example
499
+ * ```typescript
500
+ * vstack(
501
+ * text('Header'),
502
+ * spacer(2),
503
+ * text('Content')
504
+ * )
505
+ * ```
506
+ *
507
+ * @param height - Number of blank lines to insert (default: 1)
508
+ * @returns A string containing the specified number of newlines
509
+ *
510
+ * @public
511
+ */
512
+ declare function spacer(height?: number): string;
513
+ /**
514
+ * Create a divider line.
515
+ *
516
+ * @remarks
517
+ * Renders a horizontal line using a repeated character.
518
+ *
519
+ * @example
520
+ * ```typescript
521
+ * vstack(
522
+ * text('Section 1'),
523
+ * divider(),
524
+ * text('Section 2'),
525
+ * divider('=', 50)
526
+ * )
527
+ * ```
528
+ *
529
+ * @param char - Character to repeat (default: '─')
530
+ * @param width - Number of times to repeat the character (default: 40)
531
+ * @returns A string containing the divider line
532
+ *
533
+ * @public
534
+ */
535
+ declare function divider(char?: string, width?: number): string;
536
+ /**
537
+ * Conditionally render a node.
538
+ *
539
+ * @remarks
540
+ * Returns the node if the condition is true, otherwise returns an empty string.
541
+ *
542
+ * @example
543
+ * ```typescript
544
+ * vstack(
545
+ * text('Always visible'),
546
+ * when(state.showHelp, text('Help text'))
547
+ * )
548
+ * ```
549
+ *
550
+ * @param condition - Boolean condition to test
551
+ * @param node - View node to render if condition is true
552
+ * @returns The node if condition is true, empty string otherwise
553
+ *
554
+ * @public
555
+ */
556
+ declare function when(condition: boolean, node: ViewNode): ViewNode;
557
+ /**
558
+ * Choose between two nodes based on condition.
559
+ *
560
+ * @remarks
561
+ * Returns one node if the condition is true, another if false.
562
+ *
563
+ * @example
564
+ * ```typescript
565
+ * vstack(
566
+ * choose(
567
+ * state.isLoading,
568
+ * text('Loading...').dim(),
569
+ * text('Ready!').bold()
570
+ * )
571
+ * )
572
+ * ```
573
+ *
574
+ * @param condition - Boolean condition to test
575
+ * @param ifTrue - View node to render if condition is true
576
+ * @param ifFalse - View node to render if condition is false
577
+ * @returns Either ifTrue or ifFalse depending on condition
578
+ *
579
+ * @public
580
+ */
581
+ declare function choose(condition: boolean, ifTrue: ViewNode, ifFalse: ViewNode): ViewNode;
582
+ /**
583
+ * Map items to view nodes.
584
+ *
585
+ * @remarks
586
+ * Transforms an array of items into an array of view nodes. The render
587
+ * function receives each item and its index.
588
+ *
589
+ * @example
590
+ * ```typescript
591
+ * vstack(
592
+ * ...map(state.items, (item, index) =>
593
+ * text(`${index + 1}. ${item.name}`)
594
+ * )
595
+ * )
596
+ * ```
597
+ *
598
+ * @typeParam T - The type of items in the array
599
+ * @param items - Array of items to map
600
+ * @param render - Function to transform each item into a view node
601
+ * @returns Array of view nodes
602
+ *
603
+ * @public
604
+ */
605
+ declare function map<T>(items: T[], render: (item: T, index: number) => ViewNode): ViewNode[];
606
+
607
+ /**
608
+ * Render a view node tree to a string.
609
+ *
610
+ * @remarks
611
+ * Recursively renders a {@link ViewNode} tree into a terminal-ready string.
612
+ * Handles text styling, layout stacking, and component views. This function
613
+ * is typically called internally by the DSL, but can be used directly for
614
+ * testing or custom rendering.
615
+ *
616
+ * @example
617
+ * ```typescript
618
+ * const tree = vstack(
619
+ * text('Hello').bold(),
620
+ * text('World').foreground('#ff79c6')
621
+ * )
622
+ * const output = render(tree)
623
+ * console.log(output)
624
+ * ```
625
+ *
626
+ * @param node - The view node tree to render
627
+ * @returns A string ready to display in the terminal
628
+ *
629
+ * @public
630
+ */
631
+ declare function render(node: ViewNode): string;
632
+
633
+ /**
634
+ * Options for the spinner component builder.
635
+ *
636
+ * @remarks
637
+ * Configure the spinner animation and styling when creating a spinner component.
638
+ *
639
+ * @public
640
+ */
641
+ interface SpinnerBuilderOptions {
642
+ /**
643
+ * Spinner animation to use (default: `line`).
644
+ *
645
+ * @remarks
646
+ * Available spinners include `line`, `dot`, `miniDot`,
647
+ * `pulse`, `points`, `moon`, `meter`, and `ellipsis`.
648
+ */
649
+ spinner?: Spinner;
650
+ /**
651
+ * Style for rendering the spinner.
652
+ *
653
+ * @remarks
654
+ * Uses `Style` from `@boba-cli/chapstick` to apply terminal colors and formatting.
655
+ */
656
+ style?: Style;
657
+ }
658
+ /**
659
+ * Create a spinner component builder.
660
+ *
661
+ * @remarks
662
+ * Creates a {@link ComponentBuilder} wrapping the `@boba-cli/spinner` package.
663
+ * The spinner automatically animates and can be styled with custom colors.
664
+ *
665
+ * @example
666
+ * Basic usage:
667
+ * ```typescript
668
+ * const app = createApp()
669
+ * .component('loading', spinner())
670
+ * .view(({ components }) => components.loading)
671
+ * .build()
672
+ * ```
673
+ *
674
+ * @example
675
+ * With custom styling:
676
+ * ```typescript
677
+ * const app = createApp()
678
+ * .component('loading', spinner({
679
+ * style: new Style().foreground('#50fa7b')
680
+ * }))
681
+ * .view(({ components }) => hstack(
682
+ * components.loading,
683
+ * text('Loading...')
684
+ * ))
685
+ * .build()
686
+ * ```
687
+ *
688
+ * @param options - Configuration options for the spinner
689
+ * @returns A {@link ComponentBuilder} ready to use with {@link AppBuilder.component}
690
+ *
691
+ * @public
692
+ */
693
+ declare function spinner(options?: SpinnerBuilderOptions): ComponentBuilder<SpinnerModel>;
694
+
695
+ /**
696
+ * Options for the textInput component builder.
697
+ * @public
698
+ */
699
+ interface TextInputBuilderOptions {
700
+ /** Placeholder text shown when input is empty. */
701
+ placeholder?: string;
702
+ /** Width constraint for the input field. */
703
+ width?: number;
704
+ /** Echo mode for input display (Normal, Password, or None). */
705
+ echoMode?: EchoMode;
706
+ /** Character limit for input. */
707
+ charLimit?: number;
708
+ /** Prompt string shown before the input. */
709
+ prompt?: string;
710
+ /** Style for the prompt. */
711
+ promptStyle?: Style;
712
+ /** Style for the input text. */
713
+ textStyle?: Style;
714
+ /** Style for the placeholder text. */
715
+ placeholderStyle?: Style;
716
+ /** Validation function. */
717
+ validate?: ValidateFunc;
718
+ }
719
+ /**
720
+ * Create a textInput component builder.
721
+ *
722
+ * @example
723
+ * ```typescript
724
+ * const app = createApp()
725
+ * .component('nameInput', textInput({
726
+ * placeholder: 'Enter your name...',
727
+ * width: 40,
728
+ * validate: (value) => value.length < 3 ? new Error('Too short') : null
729
+ * }))
730
+ * .view(({ components }) => components.nameInput)
731
+ * .build()
732
+ * ```
733
+ *
734
+ * @public
735
+ */
736
+ declare function textInput(options?: TextInputBuilderOptions): ComponentBuilder<TextInputModel>;
737
+
738
+ export { type App, AppBuilder, type ComponentBuilder, type ComponentView, type EventContext, type KeyHandler, type LayoutNode, type SpinnerBuilderOptions, type TextInputBuilderOptions, type TextNode, type ViewFunction, type ViewNode, choose, createApp, divider, hstack, map, render, spacer, spinner, text, textInput, vstack, when };