@heinrichb/console-toolkit 1.0.9 → 1.0.13

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.
@@ -5,7 +5,7 @@ export type StandardColor = "black" | "red" | "green" | "yellow" | "blue" | "mag
5
5
  /**
6
6
  * Text style modifiers.
7
7
  */
8
- export type StyleModifier = "bold" | "dim" | "italic" | "underline" | "default" | "hidden" | "inverse" | "strikethrough";
8
+ export type StyleModifier = "bold" | "dim" | "italic" | "underline" | "hidden" | "inverse" | "strikethrough";
9
9
  /**
10
10
  * A valid Hex color string (e.g., "#FF0000").
11
11
  */
@@ -14,6 +14,14 @@ export type HexColor = `#${string}`;
14
14
  * A color can be a standard color name or a hex color string.
15
15
  */
16
16
  export type Color = StandardColor | HexColor;
17
+ /**
18
+ * Represents an RGB color value.
19
+ */
20
+ export interface RGB {
21
+ r: number;
22
+ g: number;
23
+ b: number;
24
+ }
17
25
  /**
18
26
  * Represents the style configuration for a text segment, line, or block.
19
27
  */
@@ -24,6 +32,12 @@ export interface PrintStyle {
24
32
  * - An array of colors applies a gradient.
25
33
  */
26
34
  color?: Color | Color[];
35
+ /**
36
+ * The background color to apply.
37
+ * - A single color (string) applies a solid background.
38
+ * - An array of colors applies a background gradient.
39
+ */
40
+ bgColor?: Color | Color[];
27
41
  /**
28
42
  * A list of style modifiers (e.g., bold, italic) to apply.
29
43
  */
@@ -17,9 +17,16 @@ export declare function computeMaxWidth(lines: PrintLine[]): number;
17
17
  /**
18
18
  * Pads a PrintLine to a target width by adding an empty segment at the end.
19
19
  *
20
- * @param line - The line to pad.
20
+ * @param inputLine - The line to pad.
21
21
  * @param targetWidth - The desired minimum width.
22
22
  * @param padStyle - The style to apply to the padding spaces.
23
23
  * @returns A new PrintLine with padding added if necessary.
24
24
  */
25
- export declare function padLine(line: PrintLine, targetWidth: number, padStyle?: PrintStyle): PrintLine;
25
+ export declare function padLine(inputLine: PrintLine, targetWidth: number, padStyle?: PrintStyle): PrintLine;
26
+ /**
27
+ * Strips all ANSI escape sequences from a string, returning plain text.
28
+ *
29
+ * @param text - The string potentially containing ANSI codes.
30
+ * @returns The plain text with all ANSI sequences removed.
31
+ */
32
+ export declare function stripAnsi(text: string): string;
package/dist/index.d.ts CHANGED
@@ -1,8 +1,11 @@
1
1
  export * from "./core/types";
2
2
  export * from "./core/style";
3
3
  export * from "./core/utils";
4
+ export * from "./core/builders";
4
5
  export * from "./core/printer";
5
6
  export * from "./core/layout";
6
7
  export * from "./components/progress";
7
8
  export * from "./components/spinner";
9
+ export * from "./components/table";
8
10
  export * from "./presets/ascii";
11
+ export * from "./presets/gradients";
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // src/core/style.ts
2
2
  var ESC = "\x1B";
3
3
  var RESET = `${ESC}[0m`;
4
- var STANDARD_COLORS = {
4
+ var STANDARD_COLORS = Object.assign(Object.create(null), {
5
5
  black: "#000000",
6
6
  red: "#EF4444",
7
7
  green: "#10B981",
@@ -12,9 +12,8 @@ var STANDARD_COLORS = {
12
12
  white: "#FFFFFF",
13
13
  gray: "#6B7280",
14
14
  grey: "#6B7280"
15
- };
16
- var MODIFIER_CODES = {
17
- default: "0",
15
+ });
16
+ var MODIFIER_CODES = Object.assign(Object.create(null), {
18
17
  bold: "1",
19
18
  dim: "2",
20
19
  italic: "3",
@@ -22,7 +21,7 @@ var MODIFIER_CODES = {
22
21
  inverse: "7",
23
22
  hidden: "8",
24
23
  strikethrough: "9"
25
- };
24
+ });
26
25
  function colorToHex(color) {
27
26
  if (color.startsWith("#"))
28
27
  return color;
@@ -44,11 +43,17 @@ function hexToRgb(hex) {
44
43
  function rgbToAnsi(r, g, b) {
45
44
  return `${ESC}[38;2;${r};${g};${b}m`;
46
45
  }
46
+ function rgbToBgAnsi(r, g, b) {
47
+ return `${ESC}[48;2;${r};${g};${b}m`;
48
+ }
47
49
  function resolveColorToAnsi(color) {
48
- const hex = colorToHex(color);
49
- const { r, g, b } = hexToRgb(hex);
50
+ const { r, g, b } = resolveColorToRgb(color);
50
51
  return rgbToAnsi(r, g, b);
51
52
  }
53
+ function resolveColorToRgb(color) {
54
+ const hex = colorToHex(color);
55
+ return hexToRgb(hex);
56
+ }
52
57
  function resolveModifiersToAnsi(modifiers) {
53
58
  if (!modifiers || modifiers.length === 0)
54
59
  return "";
@@ -70,22 +75,38 @@ function interpolateHex(color1, color2, factor) {
70
75
  const b = c1.b + f * (c2.b - c1.b);
71
76
  return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
72
77
  }
73
- function interpolateColor(color1, color2, factor) {
74
- return interpolateHex(colorToHex(color1), colorToHex(color2), factor);
78
+ function gradientSegment(colorCount, factor) {
79
+ const f = Math.max(0, Math.min(1, factor));
80
+ const segmentLength = 1 / (colorCount - 1);
81
+ const index = Math.min(Math.floor(f / segmentLength), colorCount - 2);
82
+ return { index, factor: (f - index * segmentLength) / segmentLength };
75
83
  }
76
- function getGradientColor(colors, factor) {
84
+ function getGradientAnsiFromRgb(colors, factor, toAnsi) {
77
85
  if (colors.length === 0)
78
86
  return "";
79
87
  if (colors.length === 1)
80
- return resolveColorToAnsi(colors[0]);
81
- const f = Math.max(0, Math.min(1, factor));
82
- const segmentLength = 1 / (colors.length - 1);
83
- const segmentIndex = Math.min(Math.floor(f / segmentLength), colors.length - 2);
84
- const segmentFactor = (f - segmentIndex * segmentLength) / segmentLength;
85
- const c1 = colors[segmentIndex];
86
- const c2 = colors[segmentIndex + 1];
87
- const hex = interpolateColor(c1, c2, segmentFactor);
88
- return resolveColorToAnsi(hex);
88
+ return toAnsi(colors[0].r, colors[0].g, colors[0].b);
89
+ const seg = gradientSegment(colors.length, factor);
90
+ const c1 = colors[seg.index];
91
+ const c2 = colors[seg.index + 1];
92
+ const r = Math.round(c1.r + seg.factor * (c2.r - c1.r));
93
+ const g = Math.round(c1.g + seg.factor * (c2.g - c1.g));
94
+ const b = Math.round(c1.b + seg.factor * (c2.b - c1.b));
95
+ return toAnsi(r, g, b);
96
+ }
97
+ function getGradientColorFromRgb(colors, factor) {
98
+ return getGradientAnsiFromRgb(colors, factor, rgbToAnsi);
99
+ }
100
+ function getGradientBgColorFromRgb(colors, factor) {
101
+ return getGradientAnsiFromRgb(colors, factor, rgbToBgAnsi);
102
+ }
103
+ function interpolateGradient(colors, factor) {
104
+ if (colors.length === 0)
105
+ return "#FFFFFF";
106
+ if (colors.length === 1)
107
+ return colorToHex(colors[0]);
108
+ const seg = gradientSegment(colors.length, factor);
109
+ return interpolateHex(colorToHex(colors[seg.index]), colorToHex(colors[seg.index + 1]), seg.factor);
89
110
  }
90
111
  function mergeStyles(parent, child) {
91
112
  if (!parent && !child)
@@ -94,10 +115,17 @@ function mergeStyles(parent, child) {
94
115
  return child ?? {};
95
116
  if (!child)
96
117
  return parent;
97
- const mergedModifiers = Array.from(new Set([...parent.modifiers ?? [], ...child.modifiers ?? []]));
118
+ const parentMods = parent.modifiers ?? [];
119
+ const childMods = child.modifiers ?? [];
120
+ const mergedModifiers = [...parentMods];
121
+ for (const mod of childMods) {
122
+ if (!mergedModifiers.includes(mod))
123
+ mergedModifiers.push(mod);
124
+ }
98
125
  return {
99
126
  modifiers: mergedModifiers,
100
- color: child.color ?? parent.color
127
+ color: child.color ?? parent.color,
128
+ bgColor: child.bgColor ?? parent.bgColor
101
129
  };
102
130
  }
103
131
  function resolveStyle(style, gradientFactor = 0) {
@@ -109,33 +137,53 @@ function resolveStyle(style, gradientFactor = 0) {
109
137
  }
110
138
  if (style.color) {
111
139
  if (Array.isArray(style.color)) {
112
- const hex = getGradientColor(style.color, gradientFactor);
113
- ansi += hex;
140
+ const rgbColors = style.color.map(resolveColorToRgb);
141
+ ansi += getGradientColorFromRgb(rgbColors, gradientFactor);
114
142
  } else {
115
143
  ansi += resolveColorToAnsi(style.color);
116
144
  }
117
145
  }
146
+ if (style.bgColor) {
147
+ if (Array.isArray(style.bgColor)) {
148
+ const bgRgbColors = style.bgColor.map(resolveColorToRgb);
149
+ ansi += getGradientBgColorFromRgb(bgRgbColors, gradientFactor);
150
+ } else {
151
+ const { r, g, b } = resolveColorToRgb(style.bgColor);
152
+ ansi += rgbToBgAnsi(r, g, b);
153
+ }
154
+ }
118
155
  return ansi;
119
156
  }
157
+ // src/core/builders.ts
158
+ function segment(text, style) {
159
+ return { text, style };
160
+ }
161
+ function line(segments = [], style) {
162
+ return { segments, style };
163
+ }
164
+ function block(lines = [], style) {
165
+ return { lines, style };
166
+ }
167
+
120
168
  // src/core/utils.ts
121
- function getLineLength(line) {
122
- return line.segments.reduce((acc, seg) => acc + seg.text.length, 0);
169
+ function getLineLength(line2) {
170
+ return line2.segments.reduce((acc, seg) => acc + seg.text.length, 0);
123
171
  }
124
172
  function computeMaxWidth(lines) {
125
- return lines.length > 0 ? Math.max(...lines.map(getLineLength)) : 0;
173
+ return lines.reduce((max, l) => Math.max(max, getLineLength(l)), 0);
126
174
  }
127
- function padLine(line, targetWidth, padStyle) {
128
- const currentLength = getLineLength(line);
175
+ function padLine(inputLine, targetWidth, padStyle) {
176
+ const currentLength = getLineLength(inputLine);
129
177
  if (currentLength < targetWidth) {
130
- return {
131
- segments: [...line.segments, { text: " ".repeat(targetWidth - currentLength), style: padStyle }]
132
- };
178
+ return line([...inputLine.segments, segment(" ".repeat(targetWidth - currentLength), padStyle)], inputLine.style);
133
179
  }
134
- return line;
180
+ return inputLine;
181
+ }
182
+ var ANSI_REGEX = /\x1b\[[0-9;]*m/g;
183
+ function stripAnsi(text) {
184
+ return text.replace(ANSI_REGEX, "");
135
185
  }
136
186
  // src/core/printer.ts
137
- var ESC2 = "\x1B";
138
-
139
187
  class Printer {
140
188
  linesRendered = 0;
141
189
  isLive;
@@ -147,7 +195,7 @@ class Printer {
147
195
  getClearSequence() {
148
196
  if (!this.isLive || this.linesRendered === 0)
149
197
  return "";
150
- return `${ESC2}[1A${ESC2}[2K\r`.repeat(this.linesRendered);
198
+ return `${ESC}[1A${ESC}[2K\r`.repeat(this.linesRendered);
151
199
  }
152
200
  clear() {
153
201
  if (this.linesRendered > 0) {
@@ -155,6 +203,14 @@ class Printer {
155
203
  this.linesRendered = 0;
156
204
  }
157
205
  }
206
+ renderToString(data) {
207
+ if (data) {
208
+ this.data = data;
209
+ }
210
+ if (!this.data)
211
+ return "";
212
+ return this.renderBlock(this.data);
213
+ }
158
214
  print(data) {
159
215
  if (data) {
160
216
  this.data = data;
@@ -162,51 +218,67 @@ class Printer {
162
218
  if (!this.data) {
163
219
  return;
164
220
  }
165
- let output = this.getClearSequence();
166
- const lines = this.data.lines;
167
- const blockStyle = this.data.style ?? {};
168
- lines.forEach((line, lineIndex) => {
169
- output += this.renderLine(line, lineIndex, lines.length, blockStyle);
221
+ const output = this.getClearSequence() + this.renderBlock(this.data);
222
+ process.stdout.write(output);
223
+ this.linesRendered = this.data.lines.length;
224
+ }
225
+ renderBlock(blockData) {
226
+ let output = "";
227
+ const lines = blockData.lines;
228
+ const blockStyle = blockData.style ?? {};
229
+ lines.forEach((ln, lineIndex) => {
230
+ output += this.renderLine(ln, lineIndex, lines.length, blockStyle);
170
231
  output += `
171
232
  `;
172
233
  });
173
- process.stdout.write(output);
174
- this.linesRendered = lines.length;
234
+ return output;
175
235
  }
176
- resolveBlockColorForLine(blockStyle, lineIndex, totalLines) {
177
- if (!blockStyle.color)
236
+ resolveBlockStyleForLine(blockStyle, lineIndex, totalLines) {
237
+ return {
238
+ modifiers: blockStyle.modifiers,
239
+ color: this.resolveGradientForLine(blockStyle.color, lineIndex, totalLines),
240
+ bgColor: this.resolveGradientForLine(blockStyle.bgColor, lineIndex, totalLines)
241
+ };
242
+ }
243
+ resolveGradientForLine(color, lineIndex, totalLines) {
244
+ if (!color)
178
245
  return;
179
- if (Array.isArray(blockStyle.color)) {
246
+ if (Array.isArray(color)) {
180
247
  if (totalLines <= 1)
181
- return blockStyle.color[0];
182
- const colors = blockStyle.color;
183
- const factor = lineIndex / (totalLines - 1);
184
- const f = Math.max(0, Math.min(1, factor));
185
- const segmentLength = 1 / (colors.length - 1);
186
- const segmentIndex = Math.min(Math.floor(f / segmentLength), colors.length - 2);
187
- const segmentFactor = (f - segmentIndex * segmentLength) / segmentLength;
188
- const c1 = colors[segmentIndex];
189
- const c2 = colors[segmentIndex + 1];
190
- return interpolateColor(c1, c2, segmentFactor);
248
+ return color[0];
249
+ return interpolateGradient(color, lineIndex / (totalLines - 1));
191
250
  }
192
- return blockStyle.color;
251
+ return color;
193
252
  }
194
- renderLine(line, lineIndex, totalLines, parentBlockStyle) {
195
- const blockColorForLine = this.resolveBlockColorForLine(parentBlockStyle, lineIndex, totalLines);
196
- const baseLineStyle = {
197
- modifiers: parentBlockStyle.modifiers,
198
- color: blockColorForLine
199
- };
200
- const effectiveLineStyle = mergeStyles(baseLineStyle, line.style);
201
- const totalChars = line.segments.reduce((acc, seg) => acc + seg.text.length, 0);
253
+ renderLine(line2, lineIndex, totalLines, parentBlockStyle) {
254
+ const baseLineStyle = this.resolveBlockStyleForLine(parentBlockStyle, lineIndex, totalLines);
255
+ const effectiveLineStyle = mergeStyles(baseLineStyle, line2.style);
256
+ const totalChars = line2.segments.reduce((acc, seg) => acc + seg.text.length, 0);
202
257
  let currentCharIndex = 0;
203
258
  let lineOutput = "";
204
- line.segments.forEach((seg) => {
259
+ line2.segments.forEach((seg) => {
205
260
  const effectiveSegmentStyle = mergeStyles(effectiveLineStyle, seg.style);
206
- if (Array.isArray(effectiveSegmentStyle.color)) {
207
- const colors = effectiveSegmentStyle.color;
261
+ const hasFgGradient = Array.isArray(effectiveSegmentStyle.color);
262
+ const hasBgGradient = Array.isArray(effectiveSegmentStyle.bgColor);
263
+ if (hasFgGradient || hasBgGradient) {
208
264
  const text = seg.text;
209
265
  const isGlobalGradient = effectiveSegmentStyle.color === effectiveLineStyle.color;
266
+ let fgRgbColors;
267
+ let solidFgAnsi = "";
268
+ if (hasFgGradient) {
269
+ fgRgbColors = effectiveSegmentStyle.color.map(resolveColorToRgb);
270
+ } else if (effectiveSegmentStyle.color) {
271
+ const { r, g, b } = resolveColorToRgb(effectiveSegmentStyle.color);
272
+ solidFgAnsi = rgbToAnsi(r, g, b);
273
+ }
274
+ let bgRgbColors;
275
+ let solidBgAnsi = "";
276
+ if (hasBgGradient) {
277
+ bgRgbColors = effectiveSegmentStyle.bgColor.map(resolveColorToRgb);
278
+ } else if (effectiveSegmentStyle.bgColor) {
279
+ const { r, g, b } = resolveColorToRgb(effectiveSegmentStyle.bgColor);
280
+ solidBgAnsi = rgbToBgAnsi(r, g, b);
281
+ }
210
282
  const modifiersAnsi = resolveModifiersToAnsi(effectiveSegmentStyle.modifiers);
211
283
  for (let i = 0;i < text.length; i++) {
212
284
  let factor = 0;
@@ -215,8 +287,9 @@ class Printer {
215
287
  } else if (!isGlobalGradient && text.length > 1) {
216
288
  factor = i / (text.length - 1);
217
289
  }
218
- const colorAnsi = getGradientColor(colors, factor);
219
- lineOutput += `${modifiersAnsi}${colorAnsi}${text[i]}`;
290
+ const fgAnsi = fgRgbColors ? getGradientColorFromRgb(fgRgbColors, factor) : solidFgAnsi;
291
+ const bgAnsi = bgRgbColors ? getGradientBgColorFromRgb(bgRgbColors, factor) : solidBgAnsi;
292
+ lineOutput += `${modifiersAnsi}${fgAnsi}${bgAnsi}${text[i]}`;
220
293
  }
221
294
  lineOutput += RESET;
222
295
  } else {
@@ -232,7 +305,7 @@ class Printer {
232
305
  function mergeColumns(columns, separator = " ", defaultStyle, widths) {
233
306
  if (columns.length === 0)
234
307
  return [];
235
- const maxLines = Math.max(...columns.map((c) => c.length));
308
+ const maxLines = columns.reduce((max, c) => Math.max(max, c.length), 0);
236
309
  const colWidths = columns.map((col, i) => {
237
310
  if (widths?.[i] !== undefined)
238
311
  return widths[i];
@@ -240,24 +313,24 @@ function mergeColumns(columns, separator = " ", defaultStyle, widths) {
240
313
  });
241
314
  const output = [];
242
315
  for (let i = 0;i < maxLines; i++) {
243
- let segments = [];
316
+ const segments = [];
244
317
  for (let j = 0;j < columns.length; j++) {
245
- const line = columns[j][i] || { segments: [] };
318
+ const currentLine = columns[j][i] || line();
246
319
  if (j < columns.length - 1) {
247
- const padded = padLine(line, colWidths[j], defaultStyle);
248
- segments = [...segments, ...padded.segments, { text: separator, style: defaultStyle }];
320
+ const padded = padLine(currentLine, colWidths[j], defaultStyle);
321
+ segments.push(...padded.segments, segment(separator, defaultStyle));
249
322
  } else {
250
- segments = [...segments, ...line.segments];
323
+ segments.push(...currentLine.segments);
251
324
  }
252
325
  }
253
- output.push({ segments });
326
+ output.push(line(segments));
254
327
  }
255
328
  return output;
256
329
  }
257
330
  function printColumns(columns, options = {}) {
258
- const { widths, separator = " ", printer = new Printer } = options;
259
- const mergedLines = mergeColumns(columns, separator, undefined, widths);
260
- printer.print({ lines: mergedLines });
331
+ const { widths, separator = " ", defaultStyle, printer = new Printer } = options;
332
+ const mergedLines = mergeColumns(columns, separator, defaultStyle, widths);
333
+ printer.print(block(mergedLines));
261
334
  }
262
335
  // src/components/progress.ts
263
336
  function createProgressBar(options) {
@@ -275,7 +348,9 @@ function createProgressBar(options) {
275
348
  startChar = "[",
276
349
  endChar = "]",
277
350
  fillChar = "█",
351
+ completeChar,
278
352
  emptyChar = "░",
353
+ completeStyle,
279
354
  showPercentage = true,
280
355
  formatPercentage
281
356
  } = options;
@@ -286,27 +361,29 @@ function createProgressBar(options) {
286
361
  const resolvedStartStyle = startStyle ?? resolvedBracketStyle;
287
362
  const resolvedEndStyle = endStyle ?? resolvedBracketStyle;
288
363
  const resolvedBarStyle = barStyle ?? style;
289
- const resolvedFillStyle = fillStyle ?? resolvedBarStyle;
364
+ const isComplete = p >= 1;
365
+ const resolvedFillStyle = isComplete ? completeStyle ?? fillStyle ?? resolvedBarStyle : fillStyle ?? resolvedBarStyle;
290
366
  const resolvedEmptyStyle = emptyStyle ?? resolvedBarStyle;
291
367
  const resolvedPercentageStyle = percentageStyle ?? style;
292
368
  const segments = [];
293
369
  if (startChar) {
294
- segments.push({ text: startChar, style: resolvedStartStyle });
370
+ segments.push(segment(startChar, resolvedStartStyle));
295
371
  }
372
+ const effectiveFillChar = isComplete ? completeChar ?? fillChar : fillChar;
296
373
  if (filledWidth > 0) {
297
- segments.push({ text: fillChar.repeat(filledWidth), style: resolvedFillStyle });
374
+ segments.push(segment(effectiveFillChar.repeat(filledWidth), resolvedFillStyle));
298
375
  }
299
376
  if (emptyWidth > 0) {
300
- segments.push({ text: emptyChar.repeat(emptyWidth), style: resolvedEmptyStyle });
377
+ segments.push(segment(emptyChar.repeat(emptyWidth), resolvedEmptyStyle));
301
378
  }
302
379
  if (endChar) {
303
- segments.push({ text: endChar, style: resolvedEndStyle });
380
+ segments.push(segment(endChar, resolvedEndStyle));
304
381
  }
305
382
  if (showPercentage) {
306
383
  const percentageText = formatPercentage ? formatPercentage(p) : ` ${Math.round(p * 100)}%`;
307
- segments.push({ text: percentageText, style: resolvedPercentageStyle });
384
+ segments.push(segment(percentageText, resolvedPercentageStyle));
308
385
  }
309
- return { segments };
386
+ return line(segments);
310
387
  }
311
388
  // src/components/spinner.ts
312
389
  var SPINNERS = {
@@ -333,8 +410,133 @@ class Spinner {
333
410
  return this.frames[index];
334
411
  }
335
412
  }
413
+ // src/components/table.ts
414
+ var BORDERS = {
415
+ single: {
416
+ tl: "┌",
417
+ t: "─",
418
+ tr: "┐",
419
+ l: "│",
420
+ r: "│",
421
+ bl: "└",
422
+ b: "─",
423
+ br: "┘",
424
+ ml: "├",
425
+ m: "─",
426
+ mr: "┤",
427
+ tj: "┬",
428
+ bj: "┴",
429
+ mj: "┼"
430
+ },
431
+ double: {
432
+ tl: "╔",
433
+ t: "═",
434
+ tr: "╗",
435
+ l: "║",
436
+ r: "║",
437
+ bl: "╚",
438
+ b: "═",
439
+ br: "╝",
440
+ ml: "╠",
441
+ m: "═",
442
+ mr: "╣",
443
+ tj: "╦",
444
+ bj: "╩",
445
+ mj: "╬"
446
+ },
447
+ rounded: {
448
+ tl: "╭",
449
+ t: "─",
450
+ tr: "╮",
451
+ l: "│",
452
+ r: "│",
453
+ bl: "╰",
454
+ b: "─",
455
+ br: "╯",
456
+ ml: "├",
457
+ m: "─",
458
+ mr: "┤",
459
+ tj: "┬",
460
+ bj: "┴",
461
+ mj: "┼"
462
+ }
463
+ };
464
+ function buildBorderLine(left, fill, junction, right, colWidths, padding, borderStyle) {
465
+ const parts = [left];
466
+ for (let i = 0;i < colWidths.length; i++) {
467
+ parts.push(fill.repeat(colWidths[i] + padding * 2));
468
+ if (i < colWidths.length - 1)
469
+ parts.push(junction);
470
+ }
471
+ parts.push(right);
472
+ return line([segment(parts.join(""), borderStyle)]);
473
+ }
474
+ function buildDataRow(cells, colWidths, padding, colCount, borderChar, cellStyle, borderStyle) {
475
+ const segments = [];
476
+ segments.push(segment(borderChar, borderStyle));
477
+ for (let i = 0;i < colCount; i++) {
478
+ const cellText = cells[i] ?? "";
479
+ const padded = " ".repeat(padding) + cellText.padEnd(colWidths[i]) + " ".repeat(padding);
480
+ segments.push(segment(padded, cellStyle));
481
+ if (i < colCount - 1) {
482
+ segments.push(segment(borderChar, borderStyle));
483
+ }
484
+ }
485
+ segments.push(segment(borderChar, borderStyle));
486
+ return line(segments);
487
+ }
488
+ function createTable(options) {
489
+ const { headers, rows, style, headerStyle, borderStyle, border = "single", columnWidths, cellPadding = 1 } = options;
490
+ const colCount = rows.reduce((max, r) => Math.max(max, r.length), headers?.length ?? 0);
491
+ if (colCount === 0)
492
+ return [];
493
+ const colWidths = [];
494
+ for (let i = 0;i < colCount; i++) {
495
+ if (columnWidths?.[i] !== undefined) {
496
+ colWidths.push(columnWidths[i]);
497
+ } else {
498
+ const headerWidth = headers?.[i]?.length ?? 0;
499
+ const maxRowWidth = rows.reduce((max, row) => Math.max(max, row[i]?.length ?? 0), 0);
500
+ colWidths.push(Math.max(headerWidth, maxRowWidth));
501
+ }
502
+ }
503
+ if (border === "none") {
504
+ return buildNoBorderTable(headers, rows, colWidths, cellPadding, colCount, style, headerStyle);
505
+ }
506
+ const chars = BORDERS[border];
507
+ const output = [];
508
+ output.push(buildBorderLine(chars.tl, chars.t, chars.tj, chars.tr, colWidths, cellPadding, borderStyle));
509
+ if (headers) {
510
+ output.push(buildDataRow(headers, colWidths, cellPadding, colCount, chars.l, headerStyle ?? style, borderStyle));
511
+ output.push(buildBorderLine(chars.ml, chars.m, chars.mj, chars.mr, colWidths, cellPadding, borderStyle));
512
+ }
513
+ for (const row of rows) {
514
+ output.push(buildDataRow(row, colWidths, cellPadding, colCount, chars.l, style, borderStyle));
515
+ }
516
+ output.push(buildBorderLine(chars.bl, chars.b, chars.bj, chars.br, colWidths, cellPadding, borderStyle));
517
+ return output;
518
+ }
519
+ function buildNoBorderTable(headers, rows, colWidths, padding, colCount, style, headerStyle) {
520
+ const output = [];
521
+ const space = " ".repeat(padding);
522
+ function buildRow(cells, cellStyle) {
523
+ const segments = [];
524
+ for (let i = 0;i < colCount; i++) {
525
+ const cellText = cells[i] ?? "";
526
+ segments.push(segment(space + cellText.padEnd(colWidths[i]) + space, cellStyle));
527
+ }
528
+ return line(segments);
529
+ }
530
+ if (headers) {
531
+ output.push(buildRow(headers, headerStyle ?? style));
532
+ }
533
+ for (const row of rows) {
534
+ output.push(buildRow(row, style));
535
+ }
536
+ return output;
537
+ }
336
538
  // src/presets/ascii.ts
337
- function getDragon(startColor = "#EF4444", endColor = "#F59E0B") {
539
+ function getDragon(colors = ["#EF4444", "#F59E0B"]) {
338
540
  const rawDragon = [
339
541
  " ^ ^",
340
542
  " / \\ //\\",
@@ -356,30 +558,49 @@ function getDragon(startColor = "#EF4444", endColor = "#F59E0B") {
356
558
  ];
357
559
  return rawDragon.map((text, i) => {
358
560
  const factor = rawDragon.length <= 1 ? 0 : i / (rawDragon.length - 1);
359
- const colorStyle = interpolateColor(startColor, endColor, factor);
360
- return { segments: [{ text, style: { color: colorStyle } }] };
561
+ const color = interpolateGradient(colors, factor);
562
+ return line([segment(text, { color })]);
361
563
  });
362
564
  }
565
+ // src/presets/gradients.ts
566
+ var GRADIENTS = {
567
+ rainbow: ["#EF4444", "#F59E0B", "#10B981", "#06B6D4", "#3B82F6", "#8B5CF6"],
568
+ ocean: ["#1E3A5F", "#0E7490", "#06B6D4", "#67E8F9"],
569
+ fire: ["#7F1D1D", "#EF4444", "#F59E0B", "#FDE047"],
570
+ sunset: ["#7C3AED", "#EC4899", "#F97316", "#FBBF24"],
571
+ forest: ["#064E3B", "#10B981", "#84CC16", "#BEF264"],
572
+ monochrome: ["#000000", "#6B7280", "#FFFFFF"]
573
+ };
363
574
  export {
575
+ stripAnsi,
576
+ segment,
577
+ rgbToBgAnsi,
364
578
  rgbToAnsi,
365
579
  resolveStyle,
366
580
  resolveModifiersToAnsi,
581
+ resolveColorToRgb,
367
582
  resolveColorToAnsi,
368
583
  printColumns,
369
584
  padLine,
370
585
  mergeStyles,
371
586
  mergeColumns,
587
+ line,
372
588
  interpolateHex,
373
- interpolateColor,
589
+ interpolateGradient,
374
590
  hexToRgb,
375
591
  getLineLength,
376
- getGradientColor,
592
+ getGradientColorFromRgb,
593
+ getGradientBgColorFromRgb,
377
594
  getDragon,
595
+ createTable,
378
596
  createProgressBar,
379
597
  computeMaxWidth,
380
598
  colorToHex,
599
+ block,
381
600
  Spinner,
382
601
  SPINNERS,
383
602
  RESET,
384
- Printer
603
+ Printer,
604
+ GRADIENTS,
605
+ ESC
385
606
  };