@elizaos/tui 2.0.0-alpha.10

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 (140) hide show
  1. package/README.md +761 -0
  2. package/dist/autocomplete.d.ts +48 -0
  3. package/dist/autocomplete.d.ts.map +1 -0
  4. package/dist/autocomplete.js +555 -0
  5. package/dist/components/box.d.ts +22 -0
  6. package/dist/components/box.d.ts.map +1 -0
  7. package/dist/components/box.js +103 -0
  8. package/dist/components/cancellable-loader.d.ts +22 -0
  9. package/dist/components/cancellable-loader.d.ts.map +1 -0
  10. package/dist/components/cancellable-loader.js +34 -0
  11. package/dist/components/editor/history.d.ts +38 -0
  12. package/dist/components/editor/history.d.ts.map +1 -0
  13. package/dist/components/editor/history.js +76 -0
  14. package/dist/components/editor/index.d.ts +18 -0
  15. package/dist/components/editor/index.d.ts.map +1 -0
  16. package/dist/components/editor/index.js +21 -0
  17. package/dist/components/editor/kill-ring.d.ts +41 -0
  18. package/dist/components/editor/kill-ring.d.ts.map +1 -0
  19. package/dist/components/editor/kill-ring.js +81 -0
  20. package/dist/components/editor/layout.d.ts +40 -0
  21. package/dist/components/editor/layout.d.ts.map +1 -0
  22. package/dist/components/editor/layout.js +205 -0
  23. package/dist/components/editor/types.d.ts +68 -0
  24. package/dist/components/editor/types.d.ts.map +1 -0
  25. package/dist/components/editor/types.js +4 -0
  26. package/dist/components/editor/undo.d.ts +46 -0
  27. package/dist/components/editor/undo.d.ts.map +1 -0
  28. package/dist/components/editor/undo.js +58 -0
  29. package/dist/components/editor.d.ts +196 -0
  30. package/dist/components/editor.d.ts.map +1 -0
  31. package/dist/components/editor.js +1707 -0
  32. package/dist/components/image.d.ts +28 -0
  33. package/dist/components/image.d.ts.map +1 -0
  34. package/dist/components/image.js +68 -0
  35. package/dist/components/input.d.ts +19 -0
  36. package/dist/components/input.d.ts.map +1 -0
  37. package/dist/components/input.js +195 -0
  38. package/dist/components/loader.d.ts +21 -0
  39. package/dist/components/loader.d.ts.map +1 -0
  40. package/dist/components/loader.js +49 -0
  41. package/dist/components/markdown/index.d.ts +13 -0
  42. package/dist/components/markdown/index.d.ts.map +1 -0
  43. package/dist/components/markdown/index.js +9 -0
  44. package/dist/components/markdown/inline-renderer.d.ts +22 -0
  45. package/dist/components/markdown/inline-renderer.d.ts.map +1 -0
  46. package/dist/components/markdown/inline-renderer.js +88 -0
  47. package/dist/components/markdown/list-renderer.d.ts +33 -0
  48. package/dist/components/markdown/list-renderer.d.ts.map +1 -0
  49. package/dist/components/markdown/list-renderer.js +110 -0
  50. package/dist/components/markdown/table-renderer.d.ts +43 -0
  51. package/dist/components/markdown/table-renderer.d.ts.map +1 -0
  52. package/dist/components/markdown/table-renderer.js +184 -0
  53. package/dist/components/markdown/types.d.ts +57 -0
  54. package/dist/components/markdown/types.d.ts.map +1 -0
  55. package/dist/components/markdown/types.js +13 -0
  56. package/dist/components/markdown.d.ts +44 -0
  57. package/dist/components/markdown.d.ts.map +1 -0
  58. package/dist/components/markdown.js +319 -0
  59. package/dist/components/progress-bar.d.ts +67 -0
  60. package/dist/components/progress-bar.d.ts.map +1 -0
  61. package/dist/components/progress-bar.js +124 -0
  62. package/dist/components/select-list.d.ts +32 -0
  63. package/dist/components/select-list.d.ts.map +1 -0
  64. package/dist/components/select-list.js +151 -0
  65. package/dist/components/settings-list.d.ts +50 -0
  66. package/dist/components/settings-list.d.ts.map +1 -0
  67. package/dist/components/settings-list.js +184 -0
  68. package/dist/components/spacer.d.ts +12 -0
  69. package/dist/components/spacer.d.ts.map +1 -0
  70. package/dist/components/spacer.js +22 -0
  71. package/dist/components/text.d.ts +19 -0
  72. package/dist/components/text.d.ts.map +1 -0
  73. package/dist/components/text.js +88 -0
  74. package/dist/components/toast.d.ts +73 -0
  75. package/dist/components/toast.d.ts.map +1 -0
  76. package/dist/components/toast.js +119 -0
  77. package/dist/components/truncated-text.d.ts +13 -0
  78. package/dist/components/truncated-text.d.ts.map +1 -0
  79. package/dist/components/truncated-text.js +50 -0
  80. package/dist/constants.d.ts +97 -0
  81. package/dist/constants.d.ts.map +1 -0
  82. package/dist/constants.js +126 -0
  83. package/dist/core/container.d.ts +32 -0
  84. package/dist/core/container.d.ts.map +1 -0
  85. package/dist/core/container.js +49 -0
  86. package/dist/core/index.d.ts +9 -0
  87. package/dist/core/index.d.ts.map +1 -0
  88. package/dist/core/index.js +10 -0
  89. package/dist/core/overlay.d.ts +44 -0
  90. package/dist/core/overlay.d.ts.map +1 -0
  91. package/dist/core/overlay.js +171 -0
  92. package/dist/core/types.d.ts +116 -0
  93. package/dist/core/types.d.ts.map +1 -0
  94. package/dist/core/types.js +14 -0
  95. package/dist/editor-component.d.ts +37 -0
  96. package/dist/editor-component.d.ts.map +1 -0
  97. package/dist/editor-component.js +1 -0
  98. package/dist/fuzzy.d.ts +16 -0
  99. package/dist/fuzzy.d.ts.map +1 -0
  100. package/dist/fuzzy.js +108 -0
  101. package/dist/index.d.ts +29 -0
  102. package/dist/index.d.ts.map +1 -0
  103. package/dist/index.js +59 -0
  104. package/dist/keybindings.d.ts +39 -0
  105. package/dist/keybindings.d.ts.map +1 -0
  106. package/dist/keybindings.js +113 -0
  107. package/dist/keys.d.ts +153 -0
  108. package/dist/keys.d.ts.map +1 -0
  109. package/dist/keys.js +951 -0
  110. package/dist/stdin-buffer.d.ts +48 -0
  111. package/dist/stdin-buffer.d.ts.map +1 -0
  112. package/dist/stdin-buffer.js +316 -0
  113. package/dist/terminal-image.d.ts +68 -0
  114. package/dist/terminal-image.d.ts.map +1 -0
  115. package/dist/terminal-image.js +287 -0
  116. package/dist/terminal.d.ts +71 -0
  117. package/dist/terminal.d.ts.map +1 -0
  118. package/dist/terminal.js +216 -0
  119. package/dist/themes/index.d.ts +103 -0
  120. package/dist/themes/index.d.ts.map +1 -0
  121. package/dist/themes/index.js +161 -0
  122. package/dist/tui.d.ts +90 -0
  123. package/dist/tui.d.ts.map +1 -0
  124. package/dist/tui.js +745 -0
  125. package/dist/types/marked-tokens.d.ts +57 -0
  126. package/dist/types/marked-tokens.d.ts.map +1 -0
  127. package/dist/types/marked-tokens.js +17 -0
  128. package/dist/utils/cursor-movement.d.ts +127 -0
  129. package/dist/utils/cursor-movement.d.ts.map +1 -0
  130. package/dist/utils/cursor-movement.js +251 -0
  131. package/dist/utils/index.d.ts +6 -0
  132. package/dist/utils/index.d.ts.map +1 -0
  133. package/dist/utils/index.js +7 -0
  134. package/dist/utils/paste-handler.d.ts +86 -0
  135. package/dist/utils/paste-handler.d.ts.map +1 -0
  136. package/dist/utils/paste-handler.js +121 -0
  137. package/dist/utils.d.ts +75 -0
  138. package/dist/utils.d.ts.map +1 -0
  139. package/dist/utils.js +796 -0
  140. package/package.json +53 -0
@@ -0,0 +1,319 @@
1
+ import { marked } from "marked";
2
+ import { isImageLine } from "../terminal-image.js";
3
+ import { applyBackgroundToLine, visibleWidth, wrapTextWithAnsi } from "../utils.js";
4
+ import { renderInlineTokens as renderInlineTokensUtil } from "./markdown/inline-renderer.js";
5
+ import { renderList as renderListUtil } from "./markdown/list-renderer.js";
6
+ import { renderTable as renderTableUtil } from "./markdown/table-renderer.js";
7
+ import { getStylePrefix } from "./markdown/types.js";
8
+ export class Markdown {
9
+ text;
10
+ paddingX; // Left/right padding
11
+ paddingY; // Top/bottom padding
12
+ defaultTextStyle;
13
+ theme;
14
+ defaultStylePrefix;
15
+ // Cache for rendered output
16
+ cachedText;
17
+ cachedWidth;
18
+ cachedLines;
19
+ constructor(text, paddingX, paddingY, theme, defaultTextStyle) {
20
+ this.text = text;
21
+ this.paddingX = paddingX;
22
+ this.paddingY = paddingY;
23
+ this.theme = theme;
24
+ this.defaultTextStyle = defaultTextStyle;
25
+ }
26
+ setText(text) {
27
+ this.text = text;
28
+ this.invalidate();
29
+ }
30
+ invalidate() {
31
+ this.cachedText = undefined;
32
+ this.cachedWidth = undefined;
33
+ this.cachedLines = undefined;
34
+ }
35
+ render(width) {
36
+ // Check cache
37
+ if (this.cachedLines && this.cachedText === this.text && this.cachedWidth === width) {
38
+ return this.cachedLines;
39
+ }
40
+ // Calculate available width for content (subtract horizontal padding)
41
+ const contentWidth = Math.max(1, width - this.paddingX * 2);
42
+ // Don't render anything if there's no actual text
43
+ if (!this.text || this.text.trim() === "") {
44
+ const result = [];
45
+ // Update cache
46
+ this.cachedText = this.text;
47
+ this.cachedWidth = width;
48
+ this.cachedLines = result;
49
+ return result;
50
+ }
51
+ // Replace tabs with 3 spaces for consistent rendering
52
+ const normalizedText = this.text.replace(/\t/g, " ");
53
+ // Parse markdown to HTML-like tokens
54
+ const tokens = marked.lexer(normalizedText);
55
+ // Convert tokens to styled terminal output
56
+ const renderedLines = [];
57
+ for (let i = 0; i < tokens.length; i++) {
58
+ const token = tokens[i];
59
+ const nextToken = tokens[i + 1];
60
+ const tokenLines = this.renderToken(token, contentWidth, nextToken?.type);
61
+ renderedLines.push(...tokenLines);
62
+ }
63
+ // Wrap lines (NO padding, NO background yet)
64
+ const wrappedLines = [];
65
+ for (const line of renderedLines) {
66
+ if (isImageLine(line)) {
67
+ wrappedLines.push(line);
68
+ }
69
+ else {
70
+ wrappedLines.push(...wrapTextWithAnsi(line, contentWidth));
71
+ }
72
+ }
73
+ // Add margins and background to each wrapped line
74
+ const leftMargin = " ".repeat(this.paddingX);
75
+ const rightMargin = " ".repeat(this.paddingX);
76
+ const backgroundFn = this.defaultTextStyle?.bgColor;
77
+ const contentLines = [];
78
+ for (const line of wrappedLines) {
79
+ if (isImageLine(line)) {
80
+ contentLines.push(line);
81
+ continue;
82
+ }
83
+ const lineWithMargins = leftMargin + line + rightMargin;
84
+ if (backgroundFn) {
85
+ contentLines.push(applyBackgroundToLine(lineWithMargins, width, backgroundFn));
86
+ }
87
+ else {
88
+ // No background - just pad to width
89
+ const visibleLen = visibleWidth(lineWithMargins);
90
+ const paddingNeeded = Math.max(0, width - visibleLen);
91
+ contentLines.push(lineWithMargins + " ".repeat(paddingNeeded));
92
+ }
93
+ }
94
+ // Add top/bottom padding (empty lines)
95
+ const emptyLine = " ".repeat(width);
96
+ const emptyLines = [];
97
+ for (let i = 0; i < this.paddingY; i++) {
98
+ const line = backgroundFn ? applyBackgroundToLine(emptyLine, width, backgroundFn) : emptyLine;
99
+ emptyLines.push(line);
100
+ }
101
+ // Combine top padding, content, and bottom padding
102
+ const result = [...emptyLines, ...contentLines, ...emptyLines];
103
+ // Update cache
104
+ this.cachedText = this.text;
105
+ this.cachedWidth = width;
106
+ this.cachedLines = result;
107
+ return result.length > 0 ? result : [""];
108
+ }
109
+ /**
110
+ * Apply default text style to a string.
111
+ * This is the base styling applied to all text content.
112
+ * NOTE: Background color is NOT applied here - it's applied at the padding stage
113
+ * to ensure it extends to the full line width.
114
+ */
115
+ applyDefaultStyle(text) {
116
+ if (!this.defaultTextStyle) {
117
+ return text;
118
+ }
119
+ let styled = text;
120
+ // Apply foreground color (NOT background - that's applied at padding stage)
121
+ if (this.defaultTextStyle.color) {
122
+ styled = this.defaultTextStyle.color(styled);
123
+ }
124
+ // Apply text decorations using this.theme
125
+ if (this.defaultTextStyle.bold) {
126
+ styled = this.theme.bold(styled);
127
+ }
128
+ if (this.defaultTextStyle.italic) {
129
+ styled = this.theme.italic(styled);
130
+ }
131
+ if (this.defaultTextStyle.strikethrough) {
132
+ styled = this.theme.strikethrough(styled);
133
+ }
134
+ if (this.defaultTextStyle.underline) {
135
+ styled = this.theme.underline(styled);
136
+ }
137
+ return styled;
138
+ }
139
+ getDefaultStylePrefix() {
140
+ if (!this.defaultTextStyle) {
141
+ return "";
142
+ }
143
+ if (this.defaultStylePrefix !== undefined) {
144
+ return this.defaultStylePrefix;
145
+ }
146
+ const sentinel = "\u0000";
147
+ let styled = sentinel;
148
+ if (this.defaultTextStyle.color) {
149
+ styled = this.defaultTextStyle.color(styled);
150
+ }
151
+ if (this.defaultTextStyle.bold) {
152
+ styled = this.theme.bold(styled);
153
+ }
154
+ if (this.defaultTextStyle.italic) {
155
+ styled = this.theme.italic(styled);
156
+ }
157
+ if (this.defaultTextStyle.strikethrough) {
158
+ styled = this.theme.strikethrough(styled);
159
+ }
160
+ if (this.defaultTextStyle.underline) {
161
+ styled = this.theme.underline(styled);
162
+ }
163
+ const sentinelIndex = styled.indexOf(sentinel);
164
+ this.defaultStylePrefix = sentinelIndex >= 0 ? styled.slice(0, sentinelIndex) : "";
165
+ return this.defaultStylePrefix;
166
+ }
167
+ // Use imported getStylePrefix from markdown/types.js
168
+ getDefaultInlineStyleContext() {
169
+ return {
170
+ applyText: (text) => this.applyDefaultStyle(text),
171
+ stylePrefix: this.getDefaultStylePrefix(),
172
+ };
173
+ }
174
+ renderToken(token, width, nextTokenType) {
175
+ const lines = [];
176
+ switch (token.type) {
177
+ case "heading": {
178
+ const headingLevel = token.depth;
179
+ const headingPrefix = `${"#".repeat(headingLevel)} `;
180
+ const headingText = this.renderInlineTokens(token.tokens || []);
181
+ let styledHeading;
182
+ if (headingLevel === 1) {
183
+ styledHeading = this.theme.heading(this.theme.bold(this.theme.underline(headingText)));
184
+ }
185
+ else if (headingLevel === 2) {
186
+ styledHeading = this.theme.heading(this.theme.bold(headingText));
187
+ }
188
+ else {
189
+ styledHeading = this.theme.heading(this.theme.bold(headingPrefix + headingText));
190
+ }
191
+ lines.push(styledHeading);
192
+ if (nextTokenType !== "space") {
193
+ lines.push(""); // Add spacing after headings (unless space token follows)
194
+ }
195
+ break;
196
+ }
197
+ case "paragraph": {
198
+ const paragraphText = this.renderInlineTokens(token.tokens || []);
199
+ lines.push(paragraphText);
200
+ // Don't add spacing if next token is space or list
201
+ if (nextTokenType && nextTokenType !== "list" && nextTokenType !== "space") {
202
+ lines.push("");
203
+ }
204
+ break;
205
+ }
206
+ case "code": {
207
+ const indent = this.theme.codeBlockIndent ?? " ";
208
+ lines.push(this.theme.codeBlockBorder(`\`\`\`${token.lang || ""}`));
209
+ if (this.theme.highlightCode) {
210
+ const highlightedLines = this.theme.highlightCode(token.text, token.lang);
211
+ for (const hlLine of highlightedLines) {
212
+ lines.push(`${indent}${hlLine}`);
213
+ }
214
+ }
215
+ else {
216
+ // Split code by newlines and style each line
217
+ const codeLines = token.text.split("\n");
218
+ for (const codeLine of codeLines) {
219
+ lines.push(`${indent}${this.theme.codeBlock(codeLine)}`);
220
+ }
221
+ }
222
+ lines.push(this.theme.codeBlockBorder("```"));
223
+ if (nextTokenType !== "space") {
224
+ lines.push(""); // Add spacing after code blocks (unless space token follows)
225
+ }
226
+ break;
227
+ }
228
+ case "list": {
229
+ const listLines = this.renderList(token, 0);
230
+ lines.push(...listLines);
231
+ // Don't add spacing after lists if a space token follows
232
+ // (the space token will handle it)
233
+ break;
234
+ }
235
+ case "table": {
236
+ const tableLines = this.renderTable(token, width);
237
+ lines.push(...tableLines);
238
+ break;
239
+ }
240
+ case "blockquote": {
241
+ const quoteStyle = (text) => this.theme.quote(this.theme.italic(text));
242
+ const quoteStyleContext = {
243
+ applyText: quoteStyle,
244
+ stylePrefix: getStylePrefix(quoteStyle),
245
+ };
246
+ const quoteText = this.renderInlineTokens(token.tokens || [], quoteStyleContext);
247
+ const quoteLines = quoteText.split("\n");
248
+ // Calculate available width for quote content (subtract border "│ " = 2 chars)
249
+ const quoteContentWidth = Math.max(1, width - 2);
250
+ for (const quoteLine of quoteLines) {
251
+ // Wrap the styled line, then add border to each wrapped line
252
+ const wrappedLines = wrapTextWithAnsi(quoteLine, quoteContentWidth);
253
+ for (const wrappedLine of wrappedLines) {
254
+ lines.push(this.theme.quoteBorder("│ ") + wrappedLine);
255
+ }
256
+ }
257
+ if (nextTokenType !== "space") {
258
+ lines.push(""); // Add spacing after blockquotes (unless space token follows)
259
+ }
260
+ break;
261
+ }
262
+ case "hr":
263
+ lines.push(this.theme.hr("─".repeat(Math.min(width, 80))));
264
+ if (nextTokenType !== "space") {
265
+ lines.push(""); // Add spacing after horizontal rules (unless space token follows)
266
+ }
267
+ break;
268
+ case "html":
269
+ // Render HTML as plain text (escaped for terminal)
270
+ if ("raw" in token && typeof token.raw === "string") {
271
+ lines.push(this.applyDefaultStyle(token.raw.trim()));
272
+ }
273
+ break;
274
+ case "space":
275
+ // Space tokens represent blank lines in markdown
276
+ lines.push("");
277
+ break;
278
+ default:
279
+ // Handle any other token types as plain text
280
+ if ("text" in token && typeof token.text === "string") {
281
+ lines.push(token.text);
282
+ }
283
+ }
284
+ return lines;
285
+ }
286
+ /**
287
+ * Render inline tokens to styled text.
288
+ * Delegates to the extracted inline-renderer utility.
289
+ */
290
+ renderInlineTokens(tokens, styleContext) {
291
+ const context = {
292
+ theme: this.theme,
293
+ getDefaultInlineStyleContext: () => this.getDefaultInlineStyleContext(),
294
+ };
295
+ return renderInlineTokensUtil(tokens, context, styleContext);
296
+ }
297
+ /**
298
+ * Render a list with proper nesting support.
299
+ * Delegates to the extracted list-renderer utility.
300
+ */
301
+ renderList(token, depth) {
302
+ const context = {
303
+ theme: this.theme,
304
+ renderInlineTokens: (tokens, styleContext) => this.renderInlineTokens(tokens, styleContext),
305
+ };
306
+ return renderListUtil(token, depth, context);
307
+ }
308
+ /**
309
+ * Render a table with width-aware cell wrapping.
310
+ * Delegates to the extracted table-renderer utility.
311
+ */
312
+ renderTable(token, availableWidth) {
313
+ const context = {
314
+ theme: this.theme,
315
+ renderInlineTokens: (tokens, styleContext) => this.renderInlineTokens(tokens, styleContext),
316
+ };
317
+ return renderTableUtil(token, availableWidth, context);
318
+ }
319
+ }
@@ -0,0 +1,67 @@
1
+ /**
2
+ * ProgressBar component for displaying progress indicators.
3
+ */
4
+ import type { Component } from "../tui.js";
5
+ /**
6
+ * Theme functions for ProgressBar styling.
7
+ */
8
+ export interface ProgressBarTheme {
9
+ /** Style function for the filled portion of the bar */
10
+ filled: (text: string) => string;
11
+ /** Style function for the empty portion of the bar */
12
+ empty: (text: string) => string;
13
+ /** Style function for the percentage label */
14
+ label?: (text: string) => string;
15
+ /** Style function for the optional message */
16
+ message?: (text: string) => string;
17
+ }
18
+ /**
19
+ * Options for ProgressBar configuration.
20
+ */
21
+ export interface ProgressBarOptions {
22
+ /** Theme for styling the progress bar */
23
+ theme?: ProgressBarTheme;
24
+ /** Character to use for the filled portion (default: "█") */
25
+ filledChar?: string;
26
+ /** Character to use for the empty portion (default: "░") */
27
+ emptyChar?: string;
28
+ /** Whether to show percentage label (default: true) */
29
+ showPercentage?: boolean;
30
+ /** Optional message to display */
31
+ message?: string;
32
+ /** Horizontal padding (default: 0) */
33
+ paddingX?: number;
34
+ /** Width of the bar portion (default: auto-calculate) */
35
+ barWidth?: number;
36
+ }
37
+ /**
38
+ * ProgressBar component that displays a visual progress indicator.
39
+ *
40
+ * Features:
41
+ * - Configurable filled/empty characters
42
+ * - Optional percentage label
43
+ * - Optional message
44
+ * - Theming support
45
+ */
46
+ export declare class ProgressBar implements Component {
47
+ private progress;
48
+ private theme;
49
+ private filledChar;
50
+ private emptyChar;
51
+ private showPercentage;
52
+ private message?;
53
+ private paddingX;
54
+ private barWidth?;
55
+ private cachedProgress?;
56
+ private cachedWidth?;
57
+ private cachedMessage?;
58
+ private cachedLines?;
59
+ constructor(progress?: number, options?: ProgressBarOptions);
60
+ setProgress(progress: number): void;
61
+ getProgress(): number;
62
+ setMessage(message?: string): void;
63
+ setTheme(theme: ProgressBarTheme): void;
64
+ invalidate(): void;
65
+ render(width: number): string[];
66
+ }
67
+ //# sourceMappingURL=progress-bar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"progress-bar.d.ts","sourceRoot":"","sources":["../../src/components/progress-bar.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAG3C;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAChC,uDAAuD;IACvD,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACjC,sDAAsD;IACtD,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAChC,8CAA8C;IAC9C,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACjC,8CAA8C;IAC9C,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CACnC;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAClC,yCAAyC;IACzC,KAAK,CAAC,EAAE,gBAAgB,CAAC;IACzB,6DAA6D;IAC7D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4DAA4D;IAC5D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uDAAuD;IACvD,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,kCAAkC;IAClC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,sCAAsC;IACtC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,yDAAyD;IACzD,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAYD;;;;;;;;GAQG;AACH,qBAAa,WAAY,YAAW,SAAS;IAC5C,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,KAAK,CAAmB;IAChC,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,cAAc,CAAU;IAChC,OAAO,CAAC,OAAO,CAAC,CAAS;IACzB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,QAAQ,CAAC,CAAS;IAG1B,OAAO,CAAC,cAAc,CAAC,CAAS;IAChC,OAAO,CAAC,WAAW,CAAC,CAAS;IAC7B,OAAO,CAAC,aAAa,CAAC,CAAS;IAC/B,OAAO,CAAC,WAAW,CAAC,CAAW;gBAEnB,QAAQ,SAAI,EAAE,OAAO,GAAE,kBAAuB;IAW1D,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAKnC,WAAW,IAAI,MAAM;IAIrB,UAAU,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI;IAKlC,QAAQ,CAAC,KAAK,EAAE,gBAAgB,GAAG,IAAI;IAKvC,UAAU,IAAI,IAAI;IAOlB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;CAmE/B"}
@@ -0,0 +1,124 @@
1
+ /**
2
+ * ProgressBar component for displaying progress indicators.
3
+ */
4
+ import { visibleWidth } from "../utils.js";
5
+ /**
6
+ * Default theme with no styling.
7
+ */
8
+ const DEFAULT_THEME = {
9
+ filled: (text) => text,
10
+ empty: (text) => text,
11
+ label: (text) => text,
12
+ message: (text) => text,
13
+ };
14
+ /**
15
+ * ProgressBar component that displays a visual progress indicator.
16
+ *
17
+ * Features:
18
+ * - Configurable filled/empty characters
19
+ * - Optional percentage label
20
+ * - Optional message
21
+ * - Theming support
22
+ */
23
+ export class ProgressBar {
24
+ progress; // 0-1 range
25
+ theme;
26
+ filledChar;
27
+ emptyChar;
28
+ showPercentage;
29
+ message;
30
+ paddingX;
31
+ barWidth;
32
+ // Cache
33
+ cachedProgress;
34
+ cachedWidth;
35
+ cachedMessage;
36
+ cachedLines;
37
+ constructor(progress = 0, options = {}) {
38
+ this.progress = Math.max(0, Math.min(1, progress));
39
+ this.theme = options.theme ?? DEFAULT_THEME;
40
+ this.filledChar = options.filledChar ?? "█";
41
+ this.emptyChar = options.emptyChar ?? "░";
42
+ this.showPercentage = options.showPercentage ?? true;
43
+ this.message = options.message;
44
+ this.paddingX = options.paddingX ?? 0;
45
+ this.barWidth = options.barWidth;
46
+ }
47
+ setProgress(progress) {
48
+ this.progress = Math.max(0, Math.min(1, progress));
49
+ this.invalidate();
50
+ }
51
+ getProgress() {
52
+ return this.progress;
53
+ }
54
+ setMessage(message) {
55
+ this.message = message;
56
+ this.invalidate();
57
+ }
58
+ setTheme(theme) {
59
+ this.theme = theme;
60
+ this.invalidate();
61
+ }
62
+ invalidate() {
63
+ this.cachedProgress = undefined;
64
+ this.cachedWidth = undefined;
65
+ this.cachedMessage = undefined;
66
+ this.cachedLines = undefined;
67
+ }
68
+ render(width) {
69
+ // Check cache
70
+ if (this.cachedLines &&
71
+ this.cachedProgress === this.progress &&
72
+ this.cachedWidth === width &&
73
+ this.cachedMessage === this.message) {
74
+ return this.cachedLines;
75
+ }
76
+ const contentWidth = Math.max(1, width - this.paddingX * 2);
77
+ const leftPad = " ".repeat(this.paddingX);
78
+ // Calculate percentage label
79
+ const percentLabel = this.showPercentage ? `${Math.round(this.progress * 100)}%` : "";
80
+ const percentLabelWidth = this.showPercentage ? visibleWidth(percentLabel) + 1 : 0; // +1 for space
81
+ // Calculate bar width
82
+ let barWidth;
83
+ if (this.barWidth !== undefined) {
84
+ barWidth = Math.max(1, Math.min(this.barWidth, contentWidth - percentLabelWidth));
85
+ }
86
+ else {
87
+ barWidth = Math.max(1, contentWidth - percentLabelWidth);
88
+ }
89
+ // Calculate filled/empty portions
90
+ const filledWidth = Math.round(barWidth * this.progress);
91
+ const emptyWidth = barWidth - filledWidth;
92
+ // Build the bar
93
+ const filledPart = this.theme.filled(this.filledChar.repeat(filledWidth));
94
+ const emptyPart = this.theme.empty(this.emptyChar.repeat(emptyWidth));
95
+ const bar = filledPart + emptyPart;
96
+ // Build the line
97
+ let line;
98
+ if (this.showPercentage) {
99
+ const styledLabel = this.theme.label ? this.theme.label(percentLabel) : percentLabel;
100
+ line = `${bar} ${styledLabel}`;
101
+ }
102
+ else {
103
+ line = bar;
104
+ }
105
+ // Pad to width
106
+ const lineWidth = visibleWidth(line);
107
+ const padding = Math.max(0, contentWidth - lineWidth);
108
+ const paddedLine = leftPad + line + " ".repeat(padding) + " ".repeat(this.paddingX);
109
+ const lines = [paddedLine];
110
+ // Add message line if present
111
+ if (this.message) {
112
+ const styledMessage = this.theme.message ? this.theme.message(this.message) : this.message;
113
+ const msgWidth = visibleWidth(styledMessage);
114
+ const msgPadding = Math.max(0, contentWidth - msgWidth);
115
+ lines.push(leftPad + styledMessage + " ".repeat(msgPadding) + " ".repeat(this.paddingX));
116
+ }
117
+ // Update cache
118
+ this.cachedProgress = this.progress;
119
+ this.cachedWidth = width;
120
+ this.cachedMessage = this.message;
121
+ this.cachedLines = lines;
122
+ return lines;
123
+ }
124
+ }
@@ -0,0 +1,32 @@
1
+ import type { Component } from "../tui.js";
2
+ export interface SelectItem {
3
+ value: string;
4
+ label: string;
5
+ description?: string;
6
+ }
7
+ export interface SelectListTheme {
8
+ selectedPrefix: (text: string) => string;
9
+ selectedText: (text: string) => string;
10
+ description: (text: string) => string;
11
+ scrollInfo: (text: string) => string;
12
+ noMatch: (text: string) => string;
13
+ }
14
+ export declare class SelectList implements Component {
15
+ private items;
16
+ private filteredItems;
17
+ private selectedIndex;
18
+ private maxVisible;
19
+ private theme;
20
+ onSelect?: (item: SelectItem) => void;
21
+ onCancel?: () => void;
22
+ onSelectionChange?: (item: SelectItem) => void;
23
+ constructor(items: SelectItem[], maxVisible: number, theme: SelectListTheme);
24
+ setFilter(filter: string): void;
25
+ setSelectedIndex(index: number): void;
26
+ invalidate(): void;
27
+ render(width: number): string[];
28
+ handleInput(keyData: string): void;
29
+ private notifySelectionChange;
30
+ getSelectedItem(): SelectItem | null;
31
+ }
32
+ //# sourceMappingURL=select-list.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"select-list.d.ts","sourceRoot":"","sources":["../../src/components/select-list.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAK3C,MAAM,WAAW,UAAU;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,eAAe;IAC/B,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACzC,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACvC,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACtC,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACrC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CAClC;AAED,qBAAa,UAAW,YAAW,SAAS;IAC3C,OAAO,CAAC,KAAK,CAAoB;IACjC,OAAO,CAAC,aAAa,CAAoB;IACzC,OAAO,CAAC,aAAa,CAAa;IAClC,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,KAAK,CAAkB;IAExB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,CAAC;IACtC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,CAAC;gBAE1C,KAAK,EAAE,UAAU,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe;IAO3E,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAM/B,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAIrC,UAAU,IAAI,IAAI;IAIlB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;IAiG/B,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IA2BlC,OAAO,CAAC,qBAAqB;IAO7B,eAAe,IAAI,UAAU,GAAG,IAAI;CAIpC"}