@bettertui/shared 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.
- package/LICENSE +21 -0
- package/README.md +18 -0
- package/index.d.mts +361 -0
- package/index.mjs +299 -0
- package/index.mjs.map +1 -0
- package/package.json +36 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026, Localfirstai Inc.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# @bettertui/shared
|
|
2
|
+
|
|
3
|
+
**Type-only package. Zero runtime code.** The shared vocabulary used by every other package.
|
|
4
|
+
|
|
5
|
+
## Exports
|
|
6
|
+
|
|
7
|
+
Types: `NodeId`, `Point`, `Size`, `Rect`, `FlexDirection`, `JustifyContent`, `AlignItems`, `AlignSelf`, `Position`, `Sizing`, `Overflow`, `Padding`, `Margin`, `Inset`, `Gap`, `LayoutConstraints`, `KeyEvent`, `KeyEventSource`, `KeyEventType`, `MouseButton`, `MouseEvent`, `ColorValue`, `Style`, `BorderStyleKind`, `BorderStyle`, `Display`, `FlexWrap`, `ThemeColors`, `ThemeSpacing`, `Theme`, `ValidationError`, `ValidationResult`
|
|
8
|
+
|
|
9
|
+
Constants: `COLOR_REGEX`, `RGB_REGEX`, `RGBA_REGEX`, `NAMED_COLORS`, `DEFAULT_THEME`, `VALID_ALIGN_ITEMS`, `VALID_ALIGN_SELVES`, `VALID_FLEX_DIRECTIONS`, `VALID_FLEX_WRAPS`, `VALID_JUSTIFY_CONTENTS`, `VALID_OVERFLOWS`, `VALID_POSITIONS`
|
|
10
|
+
|
|
11
|
+
Functions: `generateId()`, `isValidColor(value)`, `mergeTheme(base, override)`, `validate(layout, style)`, `validateLayoutConstraints(layout)`, `validateStyle(style)`, `warnIfInvalid(layout, style, context?)`
|
|
12
|
+
|
|
13
|
+
Widget types: `TimelineOptions`, `TweenConfig`
|
|
14
|
+
|
|
15
|
+
## Notes
|
|
16
|
+
|
|
17
|
+
- This is the leaf of the dependency graph — depends on nothing internal
|
|
18
|
+
- `@bettertui/core` and `@bettertui/react` re-export these types; consumers should import from those packages (shared is an internal package)
|
package/index.d.mts
ADDED
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
//#region src/types/layout.types.d.ts
|
|
2
|
+
/** Direction of the main axis in a flex layout. */
|
|
3
|
+
type FlexDirection = "row" | "column" | "row-reverse" | "column-reverse";
|
|
4
|
+
/** Alignment of children along the main axis. */
|
|
5
|
+
type JustifyContent = "flex-start" | "center" | "flex-end" | "space-between" | "space-around" | "space-evenly";
|
|
6
|
+
/** Alignment of children along the cross axis. */
|
|
7
|
+
type AlignItems = "flex-start" | "center" | "flex-end" | "stretch" | "baseline";
|
|
8
|
+
/** Alignment of multiple lines along the cross axis (multi-line flex containers). */
|
|
9
|
+
type AlignContent = "flex-start" | "center" | "flex-end" | "stretch" | "space-between" | "space-around";
|
|
10
|
+
/** Alignment of a single child along the cross axis, overriding AlignItems. */
|
|
11
|
+
type AlignSelf = "flex-start" | "center" | "flex-end" | "stretch" | "baseline";
|
|
12
|
+
/** Positioning strategy for a layout node. */
|
|
13
|
+
type Position = "relative" | "absolute";
|
|
14
|
+
/** A dimension value — number for fixed columns/rows, string for percentage or calc. */
|
|
15
|
+
type Sizing = number | string;
|
|
16
|
+
/** Behavior when content overflows the container bounds. */
|
|
17
|
+
type Overflow = "visible" | "hidden" | "scroll";
|
|
18
|
+
/** Flex wrap behavior. */
|
|
19
|
+
type FlexWrap = "nowrap" | "wrap";
|
|
20
|
+
/** Display mode. */
|
|
21
|
+
type Display = "flex" | "none";
|
|
22
|
+
/** Shorthand for all four padding sides. */
|
|
23
|
+
interface Padding {
|
|
24
|
+
top?: number;
|
|
25
|
+
right?: number;
|
|
26
|
+
bottom?: number;
|
|
27
|
+
left?: number;
|
|
28
|
+
}
|
|
29
|
+
/** Shorthand for all four margin sides. */
|
|
30
|
+
interface Margin {
|
|
31
|
+
top?: number;
|
|
32
|
+
right?: number;
|
|
33
|
+
bottom?: number;
|
|
34
|
+
left?: number;
|
|
35
|
+
}
|
|
36
|
+
/** Shorthand for all four inset offsets (used with absolute positioning). */
|
|
37
|
+
interface Inset {
|
|
38
|
+
top?: number;
|
|
39
|
+
right?: number;
|
|
40
|
+
bottom?: number;
|
|
41
|
+
left?: number;
|
|
42
|
+
}
|
|
43
|
+
/** Row and column gap values for flex layouts. */
|
|
44
|
+
interface Gap {
|
|
45
|
+
row?: number;
|
|
46
|
+
column?: number;
|
|
47
|
+
}
|
|
48
|
+
/** All layout-affecting properties for a UI node. */
|
|
49
|
+
interface LayoutConstraints {
|
|
50
|
+
display?: Display;
|
|
51
|
+
flexDirection?: FlexDirection;
|
|
52
|
+
justifyContent?: JustifyContent;
|
|
53
|
+
alignItems?: AlignItems;
|
|
54
|
+
alignSelf?: AlignSelf;
|
|
55
|
+
flexWrap?: FlexWrap;
|
|
56
|
+
alignContent?: AlignContent;
|
|
57
|
+
flexGrow?: number;
|
|
58
|
+
flexShrink?: number;
|
|
59
|
+
flexBasis?: Sizing;
|
|
60
|
+
gap?: number | Gap;
|
|
61
|
+
padding?: number | Padding;
|
|
62
|
+
paddingTop?: number;
|
|
63
|
+
paddingRight?: number;
|
|
64
|
+
paddingBottom?: number;
|
|
65
|
+
paddingLeft?: number;
|
|
66
|
+
margin?: number | Margin;
|
|
67
|
+
marginTop?: number;
|
|
68
|
+
marginRight?: number;
|
|
69
|
+
marginBottom?: number;
|
|
70
|
+
marginLeft?: number;
|
|
71
|
+
width?: Sizing;
|
|
72
|
+
height?: Sizing;
|
|
73
|
+
minWidth?: Sizing;
|
|
74
|
+
maxWidth?: Sizing;
|
|
75
|
+
minHeight?: Sizing;
|
|
76
|
+
maxHeight?: Sizing;
|
|
77
|
+
position?: Position;
|
|
78
|
+
inset?: Inset;
|
|
79
|
+
top?: number;
|
|
80
|
+
right?: number;
|
|
81
|
+
bottom?: number;
|
|
82
|
+
left?: number;
|
|
83
|
+
zIndex?: number;
|
|
84
|
+
visible?: boolean;
|
|
85
|
+
overflow?: Overflow;
|
|
86
|
+
/** Layout space reserved for a border (0 or 1 cell per side, used with border-box sizing). */
|
|
87
|
+
borderTop?: number;
|
|
88
|
+
borderRight?: number;
|
|
89
|
+
borderBottom?: number;
|
|
90
|
+
borderLeft?: number;
|
|
91
|
+
}
|
|
92
|
+
//#endregion
|
|
93
|
+
//#region src/types/events.types.d.ts
|
|
94
|
+
/** Event type for keyboard events. */
|
|
95
|
+
type KeyEventType = "press" | "repeat" | "release";
|
|
96
|
+
/** Source of a keyboard event. */
|
|
97
|
+
type KeyEventSource = "raw" | "kitty";
|
|
98
|
+
/** Mouse button identifier. */
|
|
99
|
+
type MouseButton = "left" | "right" | "middle" | "none" | "scroll_up" | "scroll_down";
|
|
100
|
+
/** A keyboard event from the terminal. */
|
|
101
|
+
interface KeyEvent {
|
|
102
|
+
/** The key value (e.g. "a", "Enter", "Escape") */
|
|
103
|
+
key: string;
|
|
104
|
+
/** Physical key code (e.g. "KeyA", "Enter") */
|
|
105
|
+
code: string;
|
|
106
|
+
/** Whether Ctrl was held */
|
|
107
|
+
ctrl: boolean;
|
|
108
|
+
/** Whether Shift was held */
|
|
109
|
+
shift: boolean;
|
|
110
|
+
/** Whether Alt was held */
|
|
111
|
+
alt: boolean;
|
|
112
|
+
/** Whether Meta (Cmd/Windows) was held */
|
|
113
|
+
meta: boolean;
|
|
114
|
+
/** Event type: press, repeat, or release */
|
|
115
|
+
eventType: KeyEventType;
|
|
116
|
+
/** Source of the event: raw terminal or Kitty keyboard protocol */
|
|
117
|
+
source: KeyEventSource;
|
|
118
|
+
/** Whether Super (Cmd/Windows) was held */
|
|
119
|
+
super?: boolean;
|
|
120
|
+
/** Whether Hyper was held */
|
|
121
|
+
hyper?: boolean;
|
|
122
|
+
/** Whether CapsLock was active */
|
|
123
|
+
capsLock?: boolean;
|
|
124
|
+
/** Whether NumLock was active */
|
|
125
|
+
numLock?: boolean;
|
|
126
|
+
/** Base layout codepoint for layout-independent shortcut matching */
|
|
127
|
+
baseCode?: number;
|
|
128
|
+
/** Whether this is a repeated keypress */
|
|
129
|
+
repeated?: boolean;
|
|
130
|
+
}
|
|
131
|
+
/** A mouse event from the terminal. */
|
|
132
|
+
interface MouseEvent {
|
|
133
|
+
button: MouseButton;
|
|
134
|
+
/** Terminal-grid position where the event occurred */
|
|
135
|
+
position: {
|
|
136
|
+
x: number;
|
|
137
|
+
y: number;
|
|
138
|
+
};
|
|
139
|
+
ctrl: boolean;
|
|
140
|
+
shift: boolean;
|
|
141
|
+
alt: boolean;
|
|
142
|
+
}
|
|
143
|
+
//#endregion
|
|
144
|
+
//#region src/types/style.types.d.ts
|
|
145
|
+
/** A CSS-like color value: named color, hex, rgb(), or rgba(). */
|
|
146
|
+
type ColorValue = string;
|
|
147
|
+
/** Visual style properties for a UI node. */
|
|
148
|
+
interface Style {
|
|
149
|
+
/** Foreground (text) color */
|
|
150
|
+
fg?: ColorValue;
|
|
151
|
+
/** Background color */
|
|
152
|
+
bg?: ColorValue;
|
|
153
|
+
bold?: boolean;
|
|
154
|
+
italic?: boolean;
|
|
155
|
+
underline?: boolean;
|
|
156
|
+
dim?: boolean;
|
|
157
|
+
strikethrough?: boolean;
|
|
158
|
+
/** Swap foreground and background colors */
|
|
159
|
+
inverse?: boolean;
|
|
160
|
+
/** Text alignment */
|
|
161
|
+
textAlign?: "left" | "center" | "right" | "justify";
|
|
162
|
+
}
|
|
163
|
+
/** All possible border visual styles. */
|
|
164
|
+
type BorderStyleKind = "none" | "solid" | "dashed" | "dotted" | "double";
|
|
165
|
+
/** Border visual configuration. */
|
|
166
|
+
interface BorderStyle {
|
|
167
|
+
style: BorderStyleKind;
|
|
168
|
+
/** Border foreground color */
|
|
169
|
+
fg?: ColorValue;
|
|
170
|
+
}
|
|
171
|
+
//#endregion
|
|
172
|
+
//#region src/types/theme.types.d.ts
|
|
173
|
+
/** Semantic color slots used by a Theme. Matches the Rust engine's ThemeColors struct. */
|
|
174
|
+
interface ThemeColors {
|
|
175
|
+
/** Primary background for the entire application */
|
|
176
|
+
background: string;
|
|
177
|
+
/** Default surface background for containers */
|
|
178
|
+
surface: string;
|
|
179
|
+
/** Elevated surface with higher emphasis */
|
|
180
|
+
surfaceHigh: string;
|
|
181
|
+
/** Lower-emphasis surface for subtle backgrounds */
|
|
182
|
+
surfaceLow: string;
|
|
183
|
+
/** Primary brand color for interactive elements */
|
|
184
|
+
primary: string;
|
|
185
|
+
/** Text on primary backgrounds */
|
|
186
|
+
primaryForeground: string;
|
|
187
|
+
/** Secondary brand accent */
|
|
188
|
+
secondary: string;
|
|
189
|
+
/** Text on secondary backgrounds */
|
|
190
|
+
secondaryForeground: string;
|
|
191
|
+
/** Primary text color */
|
|
192
|
+
text: string;
|
|
193
|
+
/** Muted text for less prominent content */
|
|
194
|
+
textMuted: string;
|
|
195
|
+
/** Dimmed text for placeholders and disabled state */
|
|
196
|
+
textDim: string;
|
|
197
|
+
/** Default border color */
|
|
198
|
+
border: string;
|
|
199
|
+
/** Border color for focused/active elements */
|
|
200
|
+
borderFocused: string;
|
|
201
|
+
/** Accent color for highlights and call-to-actions */
|
|
202
|
+
accent: string;
|
|
203
|
+
/** Text on accent backgrounds */
|
|
204
|
+
accentForeground: string;
|
|
205
|
+
/** Error/semantic red */
|
|
206
|
+
error: string;
|
|
207
|
+
/** Warning/semantic yellow */
|
|
208
|
+
warning: string;
|
|
209
|
+
/** Success/semantic green */
|
|
210
|
+
success: string;
|
|
211
|
+
/** Info/semantic blue */
|
|
212
|
+
info: string;
|
|
213
|
+
/** Scrollbar track background */
|
|
214
|
+
scrollbar: string;
|
|
215
|
+
/** Scrollbar thumb (draggable handle) */
|
|
216
|
+
scrollbarThumb: string;
|
|
217
|
+
}
|
|
218
|
+
/** Spacing scale tokens. Maps to the Rust engine's ThemeSpacing struct. */
|
|
219
|
+
interface ThemeSpacing {
|
|
220
|
+
none: number;
|
|
221
|
+
xxs: number;
|
|
222
|
+
xs: number;
|
|
223
|
+
sm: number;
|
|
224
|
+
md: number;
|
|
225
|
+
lg: number;
|
|
226
|
+
xl: number;
|
|
227
|
+
xxl: number;
|
|
228
|
+
}
|
|
229
|
+
/** A complete theme definition. Mirrors the Rust engine's Theme struct exactly. */
|
|
230
|
+
interface Theme {
|
|
231
|
+
/** Human-readable theme identifier (e.g. "dark", "light") */
|
|
232
|
+
name: string;
|
|
233
|
+
colors: ThemeColors;
|
|
234
|
+
spacing: ThemeSpacing;
|
|
235
|
+
borders: BorderStyle;
|
|
236
|
+
}
|
|
237
|
+
//#endregion
|
|
238
|
+
//#region src/types/validation.types.d.ts
|
|
239
|
+
/** Describes a single validation failure. */
|
|
240
|
+
interface ValidationError {
|
|
241
|
+
/** The name of the property that failed validation */
|
|
242
|
+
field: string;
|
|
243
|
+
/** Human-readable description of the failure */
|
|
244
|
+
message: string;
|
|
245
|
+
}
|
|
246
|
+
/** Aggregated result of running validations. */
|
|
247
|
+
interface ValidationResult {
|
|
248
|
+
/** Whether all validations passed */
|
|
249
|
+
valid: boolean;
|
|
250
|
+
/** List of individual validation errors (empty when valid) */
|
|
251
|
+
errors: ValidationError[];
|
|
252
|
+
}
|
|
253
|
+
//#endregion
|
|
254
|
+
//#region src/consts.d.ts
|
|
255
|
+
/**
|
|
256
|
+
* The default dark theme.
|
|
257
|
+
* Values match the Rust engine's `Theme::dark()` output exactly.
|
|
258
|
+
* Used as the base when no user theme is provided.
|
|
259
|
+
*/
|
|
260
|
+
declare const DEFAULT_THEME: Theme;
|
|
261
|
+
/** Matches hex color strings: #RGB, #RRGGBB, or #RRGGBBAA. */
|
|
262
|
+
declare const COLOR_REGEX: RegExp;
|
|
263
|
+
/** Matches rgb() CSS color strings. */
|
|
264
|
+
declare const RGB_REGEX: RegExp;
|
|
265
|
+
/** Matches rgba() CSS color strings. */
|
|
266
|
+
declare const RGBA_REGEX: RegExp;
|
|
267
|
+
/** Set of CSS named colors supported by the terminal renderer. */
|
|
268
|
+
declare const NAMED_COLORS: Set<string>;
|
|
269
|
+
/** All valid values for FlexDirection. */
|
|
270
|
+
declare const VALID_FLEX_DIRECTIONS: readonly ["row", "column", "row-reverse", "column-reverse"];
|
|
271
|
+
/** All valid values for JustifyContent. */
|
|
272
|
+
declare const VALID_JUSTIFY_CONTENTS: readonly ["flex-start", "center", "flex-end", "space-between", "space-around", "space-evenly"];
|
|
273
|
+
/** All valid values for AlignItems. */
|
|
274
|
+
declare const VALID_ALIGN_ITEMS: readonly ["flex-start", "center", "flex-end", "stretch", "baseline"];
|
|
275
|
+
/** All valid values for AlignSelf. */
|
|
276
|
+
declare const VALID_ALIGN_SELVES: readonly ["flex-start", "center", "flex-end", "stretch", "baseline"];
|
|
277
|
+
/** All valid values for Position. */
|
|
278
|
+
declare const VALID_POSITIONS: readonly ["relative", "absolute"];
|
|
279
|
+
/** All valid values for Overflow. */
|
|
280
|
+
declare const VALID_OVERFLOWS: readonly ["visible", "hidden", "scroll"];
|
|
281
|
+
/** All valid values for flex-wrap. */
|
|
282
|
+
declare const VALID_FLEX_WRAPS: readonly ["nowrap", "wrap"];
|
|
283
|
+
//#endregion
|
|
284
|
+
//#region src/utils.d.ts
|
|
285
|
+
/**
|
|
286
|
+
* Deep-merge a partial theme into a base theme.
|
|
287
|
+
* Only the provided keys in each subsection are overridden;
|
|
288
|
+
* missing keys fall through to the base.
|
|
289
|
+
*
|
|
290
|
+
* @param base - The fallback theme (usually DEFAULT_THEME).
|
|
291
|
+
* @param overrides - Partial theme values to merge in.
|
|
292
|
+
* @returns A new Theme with overrides applied.
|
|
293
|
+
*/
|
|
294
|
+
declare function mergeTheme(base: Theme, overrides: Partial<Theme>): Theme;
|
|
295
|
+
/**
|
|
296
|
+
* Check whether a string is a valid CSS-like color value.
|
|
297
|
+
* Supports named colors, hex (#RGB/#RRGGBB/#RRGGBBAA), rgb(), and rgba().
|
|
298
|
+
*
|
|
299
|
+
* @param color - The color string to validate.
|
|
300
|
+
* @returns True if the color is recognized as valid.
|
|
301
|
+
*/
|
|
302
|
+
declare function isValidColor(color: ColorValue): boolean;
|
|
303
|
+
/**
|
|
304
|
+
* Validate layout constraint values.
|
|
305
|
+
* Checks numeric fields for finiteness, percentage strings for valid range,
|
|
306
|
+
* and enum fields for allowed values.
|
|
307
|
+
*
|
|
308
|
+
* @param layout - A partial LayoutConstraints object to validate.
|
|
309
|
+
* @returns An array of validation errors (empty if valid).
|
|
310
|
+
*/
|
|
311
|
+
declare function validateLayoutConstraints(layout: Partial<LayoutConstraints>): ValidationError[];
|
|
312
|
+
/**
|
|
313
|
+
* Validate style property values.
|
|
314
|
+
* Currently checks foreground and background colors.
|
|
315
|
+
*
|
|
316
|
+
* @param style - A partial Style object to validate.
|
|
317
|
+
* @returns An array of validation errors (empty if valid).
|
|
318
|
+
*/
|
|
319
|
+
declare function validateStyle(style: Partial<Style>): ValidationError[];
|
|
320
|
+
/**
|
|
321
|
+
* Run both layout and style validation, returning an aggregated result.
|
|
322
|
+
*
|
|
323
|
+
* @param layout - Optional partial LayoutConstraints to validate.
|
|
324
|
+
* @param style - Optional partial Style to validate.
|
|
325
|
+
* @returns A ValidationResult with combined errors.
|
|
326
|
+
*/
|
|
327
|
+
declare function validate(layout?: Partial<LayoutConstraints>, style?: Partial<Style>): ValidationResult;
|
|
328
|
+
/**
|
|
329
|
+
* Validate props and log a warning to the console if invalid.
|
|
330
|
+
* No-op in production builds.
|
|
331
|
+
*
|
|
332
|
+
* @param layout - Optional partial LayoutConstraints to check.
|
|
333
|
+
* @param style - Optional partial Style to check.
|
|
334
|
+
* @param componentName - Optional component name for the warning message.
|
|
335
|
+
*/
|
|
336
|
+
declare function warnIfInvalid(layout?: Partial<LayoutConstraints>, style?: Partial<Style>, componentName?: string): void;
|
|
337
|
+
/**
|
|
338
|
+
* Generate a unique identifier string.
|
|
339
|
+
* Each call increments an internal counter and returns the next value.
|
|
340
|
+
*
|
|
341
|
+
* @returns A monotonically increasing unique ID string.
|
|
342
|
+
*/
|
|
343
|
+
declare function generateId(): string;
|
|
344
|
+
//#endregion
|
|
345
|
+
//#region src/widget.types.d.ts
|
|
346
|
+
interface TimelineOptions {
|
|
347
|
+
duration?: number;
|
|
348
|
+
looping?: boolean;
|
|
349
|
+
autoPlay?: boolean;
|
|
350
|
+
onComplete?: () => void;
|
|
351
|
+
}
|
|
352
|
+
interface TweenConfig {
|
|
353
|
+
from: number;
|
|
354
|
+
to: number;
|
|
355
|
+
duration: number;
|
|
356
|
+
startTime?: number;
|
|
357
|
+
easing?: string;
|
|
358
|
+
}
|
|
359
|
+
//#endregion
|
|
360
|
+
export { type AlignItems, type AlignSelf, type BorderStyle, type BorderStyleKind, COLOR_REGEX, type ColorValue, DEFAULT_THEME, type Display, type FlexDirection, type FlexWrap, type Gap, type Inset, type JustifyContent, type KeyEvent, type KeyEventSource, type KeyEventType, type LayoutConstraints, type Margin, type MouseButton, type MouseEvent, NAMED_COLORS, type Overflow, type Padding, type Position, RGBA_REGEX, RGB_REGEX, type Sizing, type Style, type Theme, type ThemeColors, type ThemeSpacing, type TimelineOptions, type TweenConfig, VALID_ALIGN_ITEMS, VALID_ALIGN_SELVES, VALID_FLEX_DIRECTIONS, VALID_FLEX_WRAPS, VALID_JUSTIFY_CONTENTS, VALID_OVERFLOWS, VALID_POSITIONS, type ValidationError, type ValidationResult, generateId, isValidColor, mergeTheme, validate, validateLayoutConstraints, validateStyle, warnIfInvalid };
|
|
361
|
+
//# sourceMappingURL=index.d.mts.map
|
package/index.mjs
ADDED
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
//#region src/consts.ts
|
|
2
|
+
/**
|
|
3
|
+
* The default dark theme.
|
|
4
|
+
* Values match the Rust engine's `Theme::dark()` output exactly.
|
|
5
|
+
* Used as the base when no user theme is provided.
|
|
6
|
+
*/
|
|
7
|
+
const DEFAULT_THEME = {
|
|
8
|
+
name: "dark",
|
|
9
|
+
colors: {
|
|
10
|
+
background: "#1e1e28",
|
|
11
|
+
surface: "#1e1e28",
|
|
12
|
+
surfaceHigh: "#282837",
|
|
13
|
+
surfaceLow: "#14141c",
|
|
14
|
+
primary: "#648cdc",
|
|
15
|
+
primaryForeground: "#ffffff",
|
|
16
|
+
secondary: "#8c64c8",
|
|
17
|
+
secondaryForeground: "#ffffff",
|
|
18
|
+
text: "#dcdce6",
|
|
19
|
+
textMuted: "#8c8ca0",
|
|
20
|
+
textDim: "#5a5a69",
|
|
21
|
+
border: "#3c3c50",
|
|
22
|
+
borderFocused: "#648cdc",
|
|
23
|
+
accent: "#50c8a0",
|
|
24
|
+
accentForeground: "#ffffff",
|
|
25
|
+
error: "#dc5050",
|
|
26
|
+
warning: "#dcb43c",
|
|
27
|
+
success: "#50c878",
|
|
28
|
+
info: "#50a0dc",
|
|
29
|
+
scrollbar: "#323241",
|
|
30
|
+
scrollbarThumb: "#646482"
|
|
31
|
+
},
|
|
32
|
+
spacing: {
|
|
33
|
+
none: 0,
|
|
34
|
+
xxs: 1,
|
|
35
|
+
xs: 2,
|
|
36
|
+
sm: 4,
|
|
37
|
+
md: 8,
|
|
38
|
+
lg: 12,
|
|
39
|
+
xl: 16,
|
|
40
|
+
xxl: 24
|
|
41
|
+
},
|
|
42
|
+
borders: {
|
|
43
|
+
style: "solid",
|
|
44
|
+
fg: "#3c3c50"
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
/** Matches hex color strings: #RGB, #RRGGBB, or #RRGGBBAA. */
|
|
48
|
+
const COLOR_REGEX = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;
|
|
49
|
+
/** Matches rgb() CSS color strings. */
|
|
50
|
+
const RGB_REGEX = /^rgb\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*\)$/;
|
|
51
|
+
/** Matches rgba() CSS color strings. */
|
|
52
|
+
const RGBA_REGEX = /^rgba\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*,\s*[\d.]+\s*\)$/;
|
|
53
|
+
/** Set of CSS named colors supported by the terminal renderer. */
|
|
54
|
+
const NAMED_COLORS = /* @__PURE__ */ new Set([
|
|
55
|
+
"black",
|
|
56
|
+
"white",
|
|
57
|
+
"red",
|
|
58
|
+
"green",
|
|
59
|
+
"blue",
|
|
60
|
+
"yellow",
|
|
61
|
+
"cyan",
|
|
62
|
+
"magenta",
|
|
63
|
+
"gray",
|
|
64
|
+
"grey",
|
|
65
|
+
"transparent"
|
|
66
|
+
]);
|
|
67
|
+
/** All valid values for FlexDirection. */
|
|
68
|
+
const VALID_FLEX_DIRECTIONS = [
|
|
69
|
+
"row",
|
|
70
|
+
"column",
|
|
71
|
+
"row-reverse",
|
|
72
|
+
"column-reverse"
|
|
73
|
+
];
|
|
74
|
+
/** All valid values for JustifyContent. */
|
|
75
|
+
const VALID_JUSTIFY_CONTENTS = [
|
|
76
|
+
"flex-start",
|
|
77
|
+
"center",
|
|
78
|
+
"flex-end",
|
|
79
|
+
"space-between",
|
|
80
|
+
"space-around",
|
|
81
|
+
"space-evenly"
|
|
82
|
+
];
|
|
83
|
+
/** All valid values for AlignItems. */
|
|
84
|
+
const VALID_ALIGN_ITEMS = [
|
|
85
|
+
"flex-start",
|
|
86
|
+
"center",
|
|
87
|
+
"flex-end",
|
|
88
|
+
"stretch",
|
|
89
|
+
"baseline"
|
|
90
|
+
];
|
|
91
|
+
/** All valid values for AlignSelf. */
|
|
92
|
+
const VALID_ALIGN_SELVES = [
|
|
93
|
+
"flex-start",
|
|
94
|
+
"center",
|
|
95
|
+
"flex-end",
|
|
96
|
+
"stretch",
|
|
97
|
+
"baseline"
|
|
98
|
+
];
|
|
99
|
+
/** All valid values for Position. */
|
|
100
|
+
const VALID_POSITIONS = ["relative", "absolute"];
|
|
101
|
+
/** All valid values for Overflow. */
|
|
102
|
+
const VALID_OVERFLOWS = [
|
|
103
|
+
"visible",
|
|
104
|
+
"hidden",
|
|
105
|
+
"scroll"
|
|
106
|
+
];
|
|
107
|
+
/** All valid values for flex-wrap. */
|
|
108
|
+
const VALID_FLEX_WRAPS = ["nowrap", "wrap"];
|
|
109
|
+
//#endregion
|
|
110
|
+
//#region src/utils.ts
|
|
111
|
+
/**
|
|
112
|
+
* Deep-merge a partial theme into a base theme.
|
|
113
|
+
* Only the provided keys in each subsection are overridden;
|
|
114
|
+
* missing keys fall through to the base.
|
|
115
|
+
*
|
|
116
|
+
* @param base - The fallback theme (usually DEFAULT_THEME).
|
|
117
|
+
* @param overrides - Partial theme values to merge in.
|
|
118
|
+
* @returns A new Theme with overrides applied.
|
|
119
|
+
*/
|
|
120
|
+
function mergeTheme(base, overrides) {
|
|
121
|
+
return {
|
|
122
|
+
...base,
|
|
123
|
+
...overrides,
|
|
124
|
+
colors: {
|
|
125
|
+
...base.colors,
|
|
126
|
+
...overrides.colors
|
|
127
|
+
},
|
|
128
|
+
spacing: {
|
|
129
|
+
...base.spacing,
|
|
130
|
+
...overrides.spacing
|
|
131
|
+
},
|
|
132
|
+
borders: {
|
|
133
|
+
...base.borders,
|
|
134
|
+
...overrides.borders
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Check whether a string is a valid CSS-like color value.
|
|
140
|
+
* Supports named colors, hex (#RGB/#RRGGBB/#RRGGBBAA), rgb(), and rgba().
|
|
141
|
+
*
|
|
142
|
+
* @param color - The color string to validate.
|
|
143
|
+
* @returns True if the color is recognized as valid.
|
|
144
|
+
*/
|
|
145
|
+
function isValidColor(color) {
|
|
146
|
+
if (NAMED_COLORS.has(color.toLowerCase())) return true;
|
|
147
|
+
if (COLOR_REGEX.test(color)) return true;
|
|
148
|
+
if (RGB_REGEX.test(color)) return true;
|
|
149
|
+
if (RGBA_REGEX.test(color)) return true;
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Validate layout constraint values.
|
|
154
|
+
* Checks numeric fields for finiteness, percentage strings for valid range,
|
|
155
|
+
* and enum fields for allowed values.
|
|
156
|
+
*
|
|
157
|
+
* @param layout - A partial LayoutConstraints object to validate.
|
|
158
|
+
* @returns An array of validation errors (empty if valid).
|
|
159
|
+
*/
|
|
160
|
+
function validateLayoutConstraints(layout) {
|
|
161
|
+
const errors = [];
|
|
162
|
+
for (const field of [
|
|
163
|
+
"flexGrow",
|
|
164
|
+
"flexShrink",
|
|
165
|
+
"padding",
|
|
166
|
+
"margin",
|
|
167
|
+
"width",
|
|
168
|
+
"height",
|
|
169
|
+
"minWidth",
|
|
170
|
+
"maxWidth",
|
|
171
|
+
"minHeight",
|
|
172
|
+
"maxHeight",
|
|
173
|
+
"top",
|
|
174
|
+
"right",
|
|
175
|
+
"bottom",
|
|
176
|
+
"left",
|
|
177
|
+
"zIndex"
|
|
178
|
+
]) {
|
|
179
|
+
const value = layout[field];
|
|
180
|
+
if (value !== void 0 && typeof value === "number") {
|
|
181
|
+
if (Number.isNaN(value) || !Number.isFinite(value)) errors.push({
|
|
182
|
+
field,
|
|
183
|
+
message: `${field} must be a finite number`
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
for (const field of [
|
|
188
|
+
"width",
|
|
189
|
+
"height",
|
|
190
|
+
"minWidth",
|
|
191
|
+
"maxWidth",
|
|
192
|
+
"minHeight",
|
|
193
|
+
"maxHeight"
|
|
194
|
+
]) {
|
|
195
|
+
const value = layout[field];
|
|
196
|
+
if (typeof value === "string") if (!value.endsWith("%")) errors.push({
|
|
197
|
+
field,
|
|
198
|
+
message: `${field} string value must be a percentage (e.g., "50%")`
|
|
199
|
+
});
|
|
200
|
+
else {
|
|
201
|
+
const num = Number.parseFloat(value);
|
|
202
|
+
if (Number.isNaN(num) || num < 0 || num > 100) errors.push({
|
|
203
|
+
field,
|
|
204
|
+
message: `${field} percentage must be between 0% and 100%`
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
if (layout.flexDirection !== void 0 && !VALID_FLEX_DIRECTIONS.includes(layout.flexDirection)) errors.push({
|
|
209
|
+
field: "flexDirection",
|
|
210
|
+
message: `flexDirection must be one of: ${VALID_FLEX_DIRECTIONS.join(", ")}`
|
|
211
|
+
});
|
|
212
|
+
if (layout.justifyContent !== void 0 && !VALID_JUSTIFY_CONTENTS.includes(layout.justifyContent)) errors.push({
|
|
213
|
+
field: "justifyContent",
|
|
214
|
+
message: `justifyContent must be one of: ${VALID_JUSTIFY_CONTENTS.join(", ")}`
|
|
215
|
+
});
|
|
216
|
+
if (layout.alignItems !== void 0 && !VALID_ALIGN_ITEMS.includes(layout.alignItems)) errors.push({
|
|
217
|
+
field: "alignItems",
|
|
218
|
+
message: `alignItems must be one of: ${VALID_ALIGN_ITEMS.join(", ")}`
|
|
219
|
+
});
|
|
220
|
+
if (layout.alignSelf !== void 0 && !VALID_ALIGN_SELVES.includes(layout.alignSelf)) errors.push({
|
|
221
|
+
field: "alignSelf",
|
|
222
|
+
message: `alignSelf must be one of: ${VALID_ALIGN_SELVES.join(", ")}`
|
|
223
|
+
});
|
|
224
|
+
if (layout.position !== void 0 && !VALID_POSITIONS.includes(layout.position)) errors.push({
|
|
225
|
+
field: "position",
|
|
226
|
+
message: `position must be one of: ${VALID_POSITIONS.join(", ")}`
|
|
227
|
+
});
|
|
228
|
+
if (layout.overflow !== void 0 && !VALID_OVERFLOWS.includes(layout.overflow)) errors.push({
|
|
229
|
+
field: "overflow",
|
|
230
|
+
message: `overflow must be one of: ${VALID_OVERFLOWS.join(", ")}`
|
|
231
|
+
});
|
|
232
|
+
if (layout.flexWrap !== void 0 && !VALID_FLEX_WRAPS.includes(layout.flexWrap)) errors.push({
|
|
233
|
+
field: "flexWrap",
|
|
234
|
+
message: `flexWrap must be one of: ${VALID_FLEX_WRAPS.join(", ")}`
|
|
235
|
+
});
|
|
236
|
+
return errors;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Validate style property values.
|
|
240
|
+
* Currently checks foreground and background colors.
|
|
241
|
+
*
|
|
242
|
+
* @param style - A partial Style object to validate.
|
|
243
|
+
* @returns An array of validation errors (empty if valid).
|
|
244
|
+
*/
|
|
245
|
+
function validateStyle(style) {
|
|
246
|
+
const errors = [];
|
|
247
|
+
if (style.fg !== void 0 && !isValidColor(style.fg)) errors.push({
|
|
248
|
+
field: "fg",
|
|
249
|
+
message: `Invalid foreground color: ${style.fg}`
|
|
250
|
+
});
|
|
251
|
+
if (style.bg !== void 0 && !isValidColor(style.bg)) errors.push({
|
|
252
|
+
field: "bg",
|
|
253
|
+
message: `Invalid background color: ${style.bg}`
|
|
254
|
+
});
|
|
255
|
+
return errors;
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Run both layout and style validation, returning an aggregated result.
|
|
259
|
+
*
|
|
260
|
+
* @param layout - Optional partial LayoutConstraints to validate.
|
|
261
|
+
* @param style - Optional partial Style to validate.
|
|
262
|
+
* @returns A ValidationResult with combined errors.
|
|
263
|
+
*/
|
|
264
|
+
function validate(layout, style) {
|
|
265
|
+
const errors = [];
|
|
266
|
+
if (layout) errors.push(...validateLayoutConstraints(layout));
|
|
267
|
+
if (style) errors.push(...validateStyle(style));
|
|
268
|
+
return {
|
|
269
|
+
valid: errors.length === 0,
|
|
270
|
+
errors
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Validate props and log a warning to the console if invalid.
|
|
275
|
+
* No-op in production builds.
|
|
276
|
+
*
|
|
277
|
+
* @param layout - Optional partial LayoutConstraints to check.
|
|
278
|
+
* @param style - Optional partial Style to check.
|
|
279
|
+
* @param componentName - Optional component name for the warning message.
|
|
280
|
+
*/
|
|
281
|
+
function warnIfInvalid(layout, style, componentName) {
|
|
282
|
+
if (process.env["NODE_ENV"] === "production") return;
|
|
283
|
+
const result = validate(layout, style);
|
|
284
|
+
if (!result.valid) console.warn(`[${componentName ?? "Component"}] Invalid props:`, result.errors);
|
|
285
|
+
}
|
|
286
|
+
let nextId = 0;
|
|
287
|
+
/**
|
|
288
|
+
* Generate a unique identifier string.
|
|
289
|
+
* Each call increments an internal counter and returns the next value.
|
|
290
|
+
*
|
|
291
|
+
* @returns A monotonically increasing unique ID string.
|
|
292
|
+
*/
|
|
293
|
+
function generateId() {
|
|
294
|
+
return `${nextId++}`;
|
|
295
|
+
}
|
|
296
|
+
//#endregion
|
|
297
|
+
export { COLOR_REGEX, DEFAULT_THEME, NAMED_COLORS, RGBA_REGEX, RGB_REGEX, VALID_ALIGN_ITEMS, VALID_ALIGN_SELVES, VALID_FLEX_DIRECTIONS, VALID_FLEX_WRAPS, VALID_JUSTIFY_CONTENTS, VALID_OVERFLOWS, VALID_POSITIONS, generateId, isValidColor, mergeTheme, validate, validateLayoutConstraints, validateStyle, warnIfInvalid };
|
|
298
|
+
|
|
299
|
+
//# sourceMappingURL=index.mjs.map
|
package/index.mjs.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/consts.ts","../src/utils.ts"],"sourcesContent":["import type { Theme } from \"./types\";\n\n/**\n * The default dark theme.\n * Values match the Rust engine's `Theme::dark()` output exactly.\n * Used as the base when no user theme is provided.\n */\nexport const DEFAULT_THEME: Theme = {\n name: \"dark\",\n colors: {\n background: \"#1e1e28\",\n surface: \"#1e1e28\",\n surfaceHigh: \"#282837\",\n surfaceLow: \"#14141c\",\n primary: \"#648cdc\",\n primaryForeground: \"#ffffff\",\n secondary: \"#8c64c8\",\n secondaryForeground: \"#ffffff\",\n text: \"#dcdce6\",\n textMuted: \"#8c8ca0\",\n textDim: \"#5a5a69\",\n border: \"#3c3c50\",\n borderFocused: \"#648cdc\",\n accent: \"#50c8a0\",\n accentForeground: \"#ffffff\",\n error: \"#dc5050\",\n warning: \"#dcb43c\",\n success: \"#50c878\",\n info: \"#50a0dc\",\n scrollbar: \"#323241\",\n scrollbarThumb: \"#646482\",\n },\n spacing: {\n none: 0,\n xxs: 1,\n xs: 2,\n sm: 4,\n md: 8,\n lg: 12,\n xl: 16,\n xxl: 24,\n },\n borders: {\n style: \"solid\",\n fg: \"#3c3c50\",\n },\n};\n\n/** Matches hex color strings: #RGB, #RRGGBB, or #RRGGBBAA. */\nexport const COLOR_REGEX = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;\n\n/** Matches rgb() CSS color strings. */\nexport const RGB_REGEX = /^rgb\\(\\s*\\d+\\s*,\\s*\\d+\\s*,\\s*\\d+\\s*\\)$/;\n\n/** Matches rgba() CSS color strings. */\nexport const RGBA_REGEX = /^rgba\\(\\s*\\d+\\s*,\\s*\\d+\\s*,\\s*\\d+\\s*,\\s*[\\d.]+\\s*\\)$/;\n\n/** Set of CSS named colors supported by the terminal renderer. */\nexport const NAMED_COLORS = new Set([\n \"black\",\n \"white\",\n \"red\",\n \"green\",\n \"blue\",\n \"yellow\",\n \"cyan\",\n \"magenta\",\n \"gray\",\n \"grey\",\n \"transparent\",\n]);\n\n/** All valid values for FlexDirection. */\nexport const VALID_FLEX_DIRECTIONS = [\"row\", \"column\", \"row-reverse\", \"column-reverse\"] as const;\n\n/** All valid values for JustifyContent. */\nexport const VALID_JUSTIFY_CONTENTS = [\n \"flex-start\",\n \"center\",\n \"flex-end\",\n \"space-between\",\n \"space-around\",\n \"space-evenly\",\n] as const;\n\n/** All valid values for AlignItems. */\nexport const VALID_ALIGN_ITEMS = [\n \"flex-start\",\n \"center\",\n \"flex-end\",\n \"stretch\",\n \"baseline\",\n] as const;\n\n/** All valid values for AlignSelf. */\nexport const VALID_ALIGN_SELVES = [\n \"flex-start\",\n \"center\",\n \"flex-end\",\n \"stretch\",\n \"baseline\",\n] as const;\n\n/** All valid values for Position. */\nexport const VALID_POSITIONS = [\"relative\", \"absolute\"] as const;\n\n/** All valid values for Overflow. */\nexport const VALID_OVERFLOWS = [\"visible\", \"hidden\", \"scroll\"] as const;\n\n/** All valid values for flex-wrap. */\nexport const VALID_FLEX_WRAPS = [\"nowrap\", \"wrap\"] as const;\n","import {\n COLOR_REGEX,\n NAMED_COLORS,\n RGBA_REGEX,\n RGB_REGEX,\n VALID_ALIGN_ITEMS,\n VALID_ALIGN_SELVES,\n VALID_FLEX_DIRECTIONS,\n VALID_FLEX_WRAPS,\n VALID_JUSTIFY_CONTENTS,\n VALID_OVERFLOWS,\n VALID_POSITIONS,\n} from \"./consts\";\nimport type {\n ColorValue,\n LayoutConstraints,\n Style,\n Theme,\n ValidationError,\n ValidationResult,\n} from \"./types\";\n\n/**\n * Deep-merge a partial theme into a base theme.\n * Only the provided keys in each subsection are overridden;\n * missing keys fall through to the base.\n *\n * @param base - The fallback theme (usually DEFAULT_THEME).\n * @param overrides - Partial theme values to merge in.\n * @returns A new Theme with overrides applied.\n */\nexport function mergeTheme(base: Theme, overrides: Partial<Theme>): Theme {\n return {\n ...base,\n ...overrides,\n colors: { ...base.colors, ...overrides.colors },\n spacing: { ...base.spacing, ...overrides.spacing },\n borders: { ...base.borders, ...overrides.borders },\n };\n}\n\n/**\n * Check whether a string is a valid CSS-like color value.\n * Supports named colors, hex (#RGB/#RRGGBB/#RRGGBBAA), rgb(), and rgba().\n *\n * @param color - The color string to validate.\n * @returns True if the color is recognized as valid.\n */\nexport function isValidColor(color: ColorValue): boolean {\n if (NAMED_COLORS.has(color.toLowerCase())) return true;\n if (COLOR_REGEX.test(color)) return true;\n if (RGB_REGEX.test(color)) return true;\n if (RGBA_REGEX.test(color)) return true;\n return false;\n}\n\n/**\n * Validate layout constraint values.\n * Checks numeric fields for finiteness, percentage strings for valid range,\n * and enum fields for allowed values.\n *\n * @param layout - A partial LayoutConstraints object to validate.\n * @returns An array of validation errors (empty if valid).\n */\nexport function validateLayoutConstraints(layout: Partial<LayoutConstraints>): ValidationError[] {\n const errors: ValidationError[] = [];\n\n const numericFields = [\n \"flexGrow\",\n \"flexShrink\",\n \"padding\",\n \"margin\",\n \"width\",\n \"height\",\n \"minWidth\",\n \"maxWidth\",\n \"minHeight\",\n \"maxHeight\",\n \"top\",\n \"right\",\n \"bottom\",\n \"left\",\n \"zIndex\",\n ] as const;\n\n for (const field of numericFields) {\n const value = layout[field];\n if (value !== undefined && typeof value === \"number\") {\n if (Number.isNaN(value) || !Number.isFinite(value)) {\n errors.push({ field, message: `${field} must be a finite number` });\n }\n }\n }\n\n const percentageFields = [\n \"width\",\n \"height\",\n \"minWidth\",\n \"maxWidth\",\n \"minHeight\",\n \"maxHeight\",\n ] as const;\n for (const field of percentageFields) {\n const value = layout[field];\n if (typeof value === \"string\") {\n if (!value.endsWith(\"%\")) {\n errors.push({ field, message: `${field} string value must be a percentage (e.g., \"50%\")` });\n } else {\n const num = Number.parseFloat(value);\n if (Number.isNaN(num) || num < 0 || num > 100) {\n errors.push({ field, message: `${field} percentage must be between 0% and 100%` });\n }\n }\n }\n }\n\n if (\n layout.flexDirection !== undefined &&\n !VALID_FLEX_DIRECTIONS.includes(layout.flexDirection as (typeof VALID_FLEX_DIRECTIONS)[number])\n ) {\n errors.push({\n field: \"flexDirection\",\n message: `flexDirection must be one of: ${VALID_FLEX_DIRECTIONS.join(\", \")}`,\n });\n }\n\n if (\n layout.justifyContent !== undefined &&\n !VALID_JUSTIFY_CONTENTS.includes(\n layout.justifyContent as (typeof VALID_JUSTIFY_CONTENTS)[number],\n )\n ) {\n errors.push({\n field: \"justifyContent\",\n message: `justifyContent must be one of: ${VALID_JUSTIFY_CONTENTS.join(\", \")}`,\n });\n }\n\n if (\n layout.alignItems !== undefined &&\n !VALID_ALIGN_ITEMS.includes(layout.alignItems as (typeof VALID_ALIGN_ITEMS)[number])\n ) {\n errors.push({\n field: \"alignItems\",\n message: `alignItems must be one of: ${VALID_ALIGN_ITEMS.join(\", \")}`,\n });\n }\n\n if (\n layout.alignSelf !== undefined &&\n !VALID_ALIGN_SELVES.includes(layout.alignSelf as (typeof VALID_ALIGN_SELVES)[number])\n ) {\n errors.push({\n field: \"alignSelf\",\n message: `alignSelf must be one of: ${VALID_ALIGN_SELVES.join(\", \")}`,\n });\n }\n\n if (\n layout.position !== undefined &&\n !VALID_POSITIONS.includes(layout.position as (typeof VALID_POSITIONS)[number])\n ) {\n errors.push({\n field: \"position\",\n message: `position must be one of: ${VALID_POSITIONS.join(\", \")}`,\n });\n }\n\n if (\n layout.overflow !== undefined &&\n !VALID_OVERFLOWS.includes(layout.overflow as (typeof VALID_OVERFLOWS)[number])\n ) {\n errors.push({\n field: \"overflow\",\n message: `overflow must be one of: ${VALID_OVERFLOWS.join(\", \")}`,\n });\n }\n\n if (\n layout.flexWrap !== undefined &&\n !VALID_FLEX_WRAPS.includes(layout.flexWrap as (typeof VALID_FLEX_WRAPS)[number])\n ) {\n errors.push({\n field: \"flexWrap\",\n message: `flexWrap must be one of: ${VALID_FLEX_WRAPS.join(\", \")}`,\n });\n }\n\n return errors;\n}\n\n/**\n * Validate style property values.\n * Currently checks foreground and background colors.\n *\n * @param style - A partial Style object to validate.\n * @returns An array of validation errors (empty if valid).\n */\nexport function validateStyle(style: Partial<Style>): ValidationError[] {\n const errors: ValidationError[] = [];\n\n if (style.fg !== undefined && !isValidColor(style.fg)) {\n errors.push({ field: \"fg\", message: `Invalid foreground color: ${style.fg}` });\n }\n\n if (style.bg !== undefined && !isValidColor(style.bg)) {\n errors.push({ field: \"bg\", message: `Invalid background color: ${style.bg}` });\n }\n\n return errors;\n}\n\n/**\n * Run both layout and style validation, returning an aggregated result.\n *\n * @param layout - Optional partial LayoutConstraints to validate.\n * @param style - Optional partial Style to validate.\n * @returns A ValidationResult with combined errors.\n */\nexport function validate(\n layout?: Partial<LayoutConstraints>,\n style?: Partial<Style>,\n): ValidationResult {\n const errors: ValidationError[] = [];\n\n if (layout) {\n errors.push(...validateLayoutConstraints(layout));\n }\n\n if (style) {\n errors.push(...validateStyle(style));\n }\n\n return {\n valid: errors.length === 0,\n errors,\n };\n}\n\n/**\n * Validate props and log a warning to the console if invalid.\n * No-op in production builds.\n *\n * @param layout - Optional partial LayoutConstraints to check.\n * @param style - Optional partial Style to check.\n * @param componentName - Optional component name for the warning message.\n */\nexport function warnIfInvalid(\n layout?: Partial<LayoutConstraints>,\n style?: Partial<Style>,\n componentName?: string,\n): void {\n if (process.env[\"NODE_ENV\"] === \"production\") return;\n\n const result = validate(layout, style);\n if (!result.valid) {\n const name = componentName ?? \"Component\";\n console.warn(`[${name}] Invalid props:`, result.errors);\n }\n}\n\nlet nextId = 0;\n\n/**\n * Generate a unique identifier string.\n * Each call increments an internal counter and returns the next value.\n *\n * @returns A monotonically increasing unique ID string.\n */\nexport function generateId(): string {\n return `${nextId++}`;\n}\n"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bettertui/shared",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Shared type definitions and protocols for the BetterTUI terminal UI framework",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"types",
|
|
7
|
+
"tui",
|
|
8
|
+
"terminal",
|
|
9
|
+
"protocol",
|
|
10
|
+
"definitions"
|
|
11
|
+
],
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"author": "SOUMITRO-SAHA <soumitrosahaofficial@gmail.com>",
|
|
14
|
+
"homepage": "https://github.com/bettertui/bettertui/tree/main/packages/shared#readme",
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "https://github.com/bettertui/bettertui.git",
|
|
18
|
+
"directory": "packages/shared"
|
|
19
|
+
},
|
|
20
|
+
"bugs": {
|
|
21
|
+
"url": "https://github.com/bettertui/bettertui/issues"
|
|
22
|
+
},
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=24.15.0"
|
|
25
|
+
},
|
|
26
|
+
"type": "module",
|
|
27
|
+
"main": "./index.mjs",
|
|
28
|
+
"module": "./index.mjs",
|
|
29
|
+
"types": "./index.d.mts",
|
|
30
|
+
"exports": {
|
|
31
|
+
".": {
|
|
32
|
+
"types": "./index.d.mts",
|
|
33
|
+
"import": "./index.mjs"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|