@rlabs-inc/tui 0.1.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 (44) hide show
  1. package/README.md +141 -0
  2. package/index.ts +45 -0
  3. package/package.json +59 -0
  4. package/src/api/index.ts +7 -0
  5. package/src/api/mount.ts +230 -0
  6. package/src/engine/arrays/core.ts +60 -0
  7. package/src/engine/arrays/dimensions.ts +68 -0
  8. package/src/engine/arrays/index.ts +166 -0
  9. package/src/engine/arrays/interaction.ts +112 -0
  10. package/src/engine/arrays/layout.ts +175 -0
  11. package/src/engine/arrays/spacing.ts +100 -0
  12. package/src/engine/arrays/text.ts +55 -0
  13. package/src/engine/arrays/visual.ts +140 -0
  14. package/src/engine/index.ts +25 -0
  15. package/src/engine/inheritance.ts +138 -0
  16. package/src/engine/registry.ts +180 -0
  17. package/src/pipeline/frameBuffer.ts +473 -0
  18. package/src/pipeline/layout/index.ts +105 -0
  19. package/src/pipeline/layout/titan-engine.ts +798 -0
  20. package/src/pipeline/layout/types.ts +194 -0
  21. package/src/pipeline/layout/utils/hierarchy.ts +202 -0
  22. package/src/pipeline/layout/utils/math.ts +134 -0
  23. package/src/pipeline/layout/utils/text-measure.ts +160 -0
  24. package/src/pipeline/layout.ts +30 -0
  25. package/src/primitives/box.ts +312 -0
  26. package/src/primitives/index.ts +12 -0
  27. package/src/primitives/text.ts +199 -0
  28. package/src/primitives/types.ts +222 -0
  29. package/src/primitives/utils.ts +37 -0
  30. package/src/renderer/ansi.ts +625 -0
  31. package/src/renderer/buffer.ts +667 -0
  32. package/src/renderer/index.ts +40 -0
  33. package/src/renderer/input.ts +518 -0
  34. package/src/renderer/output.ts +451 -0
  35. package/src/state/cursor.ts +176 -0
  36. package/src/state/focus.ts +241 -0
  37. package/src/state/index.ts +43 -0
  38. package/src/state/keyboard.ts +771 -0
  39. package/src/state/mouse.ts +524 -0
  40. package/src/state/scroll.ts +341 -0
  41. package/src/state/theme.ts +687 -0
  42. package/src/types/color.ts +401 -0
  43. package/src/types/index.ts +316 -0
  44. package/src/utils/text.ts +471 -0
@@ -0,0 +1,222 @@
1
+ /**
2
+ * TUI Framework - Primitive Types
3
+ *
4
+ * Type definitions for all component primitives.
5
+ * Props can be static values OR reactive (signals/bindings).
6
+ */
7
+
8
+ import type { RGBA, CellAttrs, Dimension } from '../types'
9
+ import type { WritableSignal, Binding, ReadonlyBinding } from '@rlabs-inc/signals'
10
+ import type { Variant } from '../state/theme'
11
+
12
+ // =============================================================================
13
+ // REACTIVE PROP TYPES
14
+ // =============================================================================
15
+
16
+ /**
17
+ * A prop value that can be static or reactive.
18
+ * Components will sync reactive values automatically.
19
+ */
20
+ export type Reactive<T> = T | WritableSignal<T> | Binding<T> | ReadonlyBinding<T>
21
+
22
+ /**
23
+ * Make specific props reactive while keeping others static.
24
+ */
25
+ export type WithReactive<T, K extends keyof T> = Omit<T, K> & {
26
+ [P in K]: Reactive<T[P]>
27
+ }
28
+
29
+ // =============================================================================
30
+ // COMMON PROPS
31
+ // =============================================================================
32
+
33
+ export interface StyleProps {
34
+ /** Foreground color (text) */
35
+ fg?: Reactive<RGBA | null>
36
+ /** Background color */
37
+ bg?: Reactive<RGBA | null>
38
+ /** Opacity 0-1 */
39
+ opacity?: Reactive<number>
40
+ }
41
+
42
+ export interface BorderProps {
43
+ /** Border style (0=none, 1=single, 2=double, 3=rounded, etc.) */
44
+ border?: Reactive<number>
45
+ /** Border color */
46
+ borderColor?: Reactive<RGBA | null>
47
+ /** Per-side border styles */
48
+ borderTop?: Reactive<number>
49
+ borderRight?: Reactive<number>
50
+ borderBottom?: Reactive<number>
51
+ borderLeft?: Reactive<number>
52
+ }
53
+
54
+ export interface DimensionProps {
55
+ /** Width (0 = auto, '100%' = full parent, '50%' = half parent) */
56
+ width?: Reactive<Dimension>
57
+ /** Height (0 = auto, '100%' = full parent, '50%' = half parent) */
58
+ height?: Reactive<Dimension>
59
+ /** Minimum width */
60
+ minWidth?: Reactive<Dimension>
61
+ /** Maximum width (0 = no max) */
62
+ maxWidth?: Reactive<Dimension>
63
+ /** Minimum height */
64
+ minHeight?: Reactive<Dimension>
65
+ /** Maximum height (0 = no max) */
66
+ maxHeight?: Reactive<Dimension>
67
+ }
68
+
69
+ export interface SpacingProps {
70
+ /** Padding all sides */
71
+ padding?: Reactive<number>
72
+ /** Padding per side */
73
+ paddingTop?: Reactive<number>
74
+ paddingRight?: Reactive<number>
75
+ paddingBottom?: Reactive<number>
76
+ paddingLeft?: Reactive<number>
77
+ /** Margin all sides */
78
+ margin?: Reactive<number>
79
+ /** Margin per side */
80
+ marginTop?: Reactive<number>
81
+ marginRight?: Reactive<number>
82
+ marginBottom?: Reactive<number>
83
+ marginLeft?: Reactive<number>
84
+ /** Gap between children */
85
+ gap?: Reactive<number>
86
+ }
87
+
88
+ export interface LayoutProps {
89
+ /** Flex direction: 'column' | 'row' | 'column-reverse' | 'row-reverse' */
90
+ flexDirection?: Reactive<'column' | 'row' | 'column-reverse' | 'row-reverse'>
91
+ /** Flex wrap: 'nowrap' | 'wrap' | 'wrap-reverse' */
92
+ flexWrap?: Reactive<'nowrap' | 'wrap' | 'wrap-reverse'>
93
+ /** Justify content */
94
+ justifyContent?: Reactive<'flex-start' | 'center' | 'flex-end' | 'space-between' | 'space-around' | 'space-evenly'>
95
+ /** Align items (container) */
96
+ alignItems?: Reactive<'stretch' | 'flex-start' | 'center' | 'flex-end' | 'baseline'>
97
+ /** Align self (item override) */
98
+ alignSelf?: Reactive<'auto' | 'stretch' | 'flex-start' | 'center' | 'flex-end' | 'baseline'>
99
+ /** Flex grow */
100
+ grow?: Reactive<number>
101
+ /** Flex shrink */
102
+ shrink?: Reactive<number>
103
+ /** Flex basis (initial size before grow/shrink) */
104
+ flexBasis?: Reactive<number>
105
+ /** Overflow: 'visible' | 'hidden' | 'scroll' | 'auto' */
106
+ overflow?: Reactive<'visible' | 'hidden' | 'scroll' | 'auto'>
107
+ /** Z-index for stacking */
108
+ zIndex?: Reactive<number>
109
+ }
110
+
111
+ export interface InteractionProps {
112
+ /** Can this component receive focus */
113
+ focusable?: Reactive<boolean>
114
+ /** Tab order for focus navigation (-1 = not in tab order) */
115
+ tabIndex?: Reactive<number>
116
+ }
117
+
118
+ // =============================================================================
119
+ // BOX PROPS
120
+ // =============================================================================
121
+
122
+ export interface BoxProps extends StyleProps, BorderProps, DimensionProps, SpacingProps, LayoutProps, InteractionProps {
123
+ /** Component ID (optional, auto-generated if not provided) */
124
+ id?: string
125
+ /** Is visible */
126
+ visible?: Reactive<boolean>
127
+ /** Children renderer */
128
+ children?: () => void
129
+ /**
130
+ * Style variant - applies theme colors automatically.
131
+ * Variants: 'default' | 'primary' | 'secondary' | 'success' | 'warning' | 'error' | 'info' | 'ghost' | 'outline'
132
+ */
133
+ variant?: Variant
134
+ }
135
+
136
+ // =============================================================================
137
+ // TEXT PROPS
138
+ // =============================================================================
139
+
140
+ export interface TextProps extends StyleProps, DimensionProps, SpacingProps {
141
+ /** Text content */
142
+ content: Reactive<string>
143
+ /** Text alignment: 'left' | 'center' | 'right' */
144
+ align?: Reactive<'left' | 'center' | 'right'>
145
+ /** Text attributes (bold, italic, etc.) */
146
+ attrs?: Reactive<CellAttrs>
147
+ /** Text wrapping: 'wrap' | 'nowrap' | 'truncate' */
148
+ wrap?: Reactive<'wrap' | 'nowrap' | 'truncate'>
149
+ /** Is visible */
150
+ visible?: Reactive<boolean>
151
+ /**
152
+ * Style variant - applies theme colors automatically.
153
+ * Variants: 'default' | 'primary' | 'secondary' | 'success' | 'warning' | 'error' | 'info' | 'ghost' | 'outline'
154
+ */
155
+ variant?: Variant
156
+ }
157
+
158
+ // =============================================================================
159
+ // INPUT PROPS
160
+ // =============================================================================
161
+
162
+ export interface InputProps extends StyleProps, BorderProps, DimensionProps, SpacingProps {
163
+ /** Current value (two-way bound) */
164
+ value: WritableSignal<string> | Binding<string>
165
+ /** Placeholder text */
166
+ placeholder?: string
167
+ /** Text attributes */
168
+ attrs?: Reactive<CellAttrs>
169
+ /** Is visible */
170
+ visible?: Reactive<boolean>
171
+ /** Is focused by default */
172
+ autoFocus?: boolean
173
+ /** Called when value changes */
174
+ onChange?: (value: string) => void
175
+ /** Called on Enter key */
176
+ onSubmit?: (value: string) => void
177
+ }
178
+
179
+ // =============================================================================
180
+ // SELECT PROPS
181
+ // =============================================================================
182
+
183
+ export interface SelectOption {
184
+ value: string
185
+ label: string
186
+ }
187
+
188
+ export interface SelectProps extends StyleProps, BorderProps, DimensionProps {
189
+ /** Selected value (two-way bound) */
190
+ value: WritableSignal<string> | Binding<string>
191
+ /** Available options */
192
+ options: SelectOption[]
193
+ /** Placeholder when nothing selected */
194
+ placeholder?: string
195
+ /** Is visible */
196
+ visible?: Reactive<boolean>
197
+ /** Called when selection changes */
198
+ onChange?: (value: string) => void
199
+ }
200
+
201
+ // =============================================================================
202
+ // PROGRESS PROPS
203
+ // =============================================================================
204
+
205
+ export interface ProgressProps extends StyleProps, DimensionProps {
206
+ /** Progress value 0-1 */
207
+ value: Reactive<number>
208
+ /** Show percentage text */
209
+ showPercent?: boolean
210
+ /** Is visible */
211
+ visible?: Reactive<boolean>
212
+ }
213
+
214
+ // =============================================================================
215
+ // COMPONENT RETURN TYPE
216
+ // =============================================================================
217
+
218
+ /**
219
+ * Components return a cleanup function.
220
+ * Call it to unmount the component and release its index.
221
+ */
222
+ export type Cleanup = () => void
@@ -0,0 +1,37 @@
1
+ /**
2
+ * TUI Framework - Primitive Utilities
3
+ *
4
+ * Shared helpers for primitives.
5
+ * Most conversion functions are now inline in each primitive.
6
+ */
7
+
8
+ import { isBinding, type WritableSignal, type Binding } from '@rlabs-inc/signals'
9
+
10
+ // =============================================================================
11
+ // TYPE GUARDS
12
+ // =============================================================================
13
+
14
+ /**
15
+ * Check if a value is a signal (has .value getter/setter)
16
+ */
17
+ export function isWritableSignal<T>(value: unknown): value is WritableSignal<T> {
18
+ return value !== null && typeof value === 'object' && 'value' in value
19
+ }
20
+
21
+ /**
22
+ * Check if a value is reactive (signal or binding)
23
+ */
24
+ export function isReactive<T>(value: unknown): value is WritableSignal<T> | Binding<T> {
25
+ return isWritableSignal(value) || isBinding(value)
26
+ }
27
+
28
+ /**
29
+ * Unwrap a potentially reactive value to get current value.
30
+ * Handles: signals, bindings, getters, or raw values.
31
+ */
32
+ export function getValue<T>(prop: T | { value: T } | (() => T) | undefined, defaultVal: T): T {
33
+ if (prop === undefined) return defaultVal
34
+ if (typeof prop === 'function') return (prop as () => T)()
35
+ if (typeof prop === 'object' && prop !== null && 'value' in prop) return (prop as { value: T }).value
36
+ return prop as T
37
+ }