ansimax 1.3.2 → 1.3.3

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/dist/index.d.ts CHANGED
@@ -1279,6 +1279,20 @@ interface BoxOptions {
1279
1279
  borderStyle?: BoxStyle;
1280
1280
  /** Fix inner content width. Lines are padded/truncated to fit. */
1281
1281
  width?: number | null;
1282
+ /**
1283
+ * Optional title shown in the top border, e.g. `─ Title ─────`.
1284
+ * When set, the box expands to fit the title if content is narrower.
1285
+ *
1286
+ * @since 1.3.3
1287
+ */
1288
+ title?: string | null;
1289
+ /**
1290
+ * Title alignment in the top border: `'left'` | `'center'` (default) | `'right'`.
1291
+ * Only applies when `title` is set.
1292
+ *
1293
+ * @since 1.3.3
1294
+ */
1295
+ titleAlign?: 'left' | 'center' | 'right';
1282
1296
  }
1283
1297
  interface BannerOptions {
1284
1298
  font?: FontName | string;
@@ -1294,6 +1308,13 @@ interface DividerOptions {
1294
1308
  width?: number | null;
1295
1309
  label?: string | null;
1296
1310
  style?: BoxStyle;
1311
+ /**
1312
+ * Label alignment: `'left'` | `'center'` (default) | `'right'`.
1313
+ * Only applies when `label` is set.
1314
+ *
1315
+ * @since 1.3.3
1316
+ */
1317
+ align?: 'left' | 'center' | 'right';
1297
1318
  }
1298
1319
  interface LogoOptions {
1299
1320
  gradient?: ColorFn | null;
@@ -2299,9 +2320,16 @@ interface FrameOptions {
2299
2320
  */
2300
2321
  bottomChar?: string;
2301
2322
  /**
2302
- * Optional title shown centered in the top edge.
2323
+ * Optional title shown in the top edge.
2303
2324
  */
2304
2325
  title?: string;
2326
+ /**
2327
+ * Title alignment: `'left'` | `'center'` (default) | `'right'`.
2328
+ * Only applies when `title` is set.
2329
+ *
2330
+ * @since 1.3.3
2331
+ */
2332
+ titleAlign?: 'left' | 'center' | 'right';
2305
2333
  }
2306
2334
  /**
2307
2335
  * Add decorative top/bottom rule lines around a block (lighter than `ascii.box`
@@ -2339,11 +2367,71 @@ interface FrameOptions {
2339
2367
  * ```
2340
2368
  */
2341
2369
  declare const frame: (block: string, opts?: FrameOptions) => string;
2370
+ interface GridOptions {
2371
+ /** Number of columns. Required. */
2372
+ columns: number;
2373
+ /** Horizontal gap between cells. Default `1`. */
2374
+ gapX?: number;
2375
+ /** Vertical gap between rows. Default `0`. */
2376
+ gapY?: number;
2377
+ /** Horizontal alignment of content within each cell. Default `'start'`. */
2378
+ alignX?: Alignment;
2379
+ /** Vertical alignment of content within each cell. Default `'start'`. */
2380
+ alignY?: Alignment;
2381
+ /**
2382
+ * Fix each cell to this width (in visible characters). If omitted, cells
2383
+ * use the max width of the widest block in their column.
2384
+ */
2385
+ cellWidth?: number | null;
2386
+ }
2387
+ /**
2388
+ * Arrange blocks in a grid of N columns, flowing left-to-right then
2389
+ * top-to-bottom. Each row is auto-sized to its tallest block, and each
2390
+ * column is auto-sized to its widest block (unless `cellWidth` is fixed).
2391
+ *
2392
+ * Internally uses `vsplit` for rows + `hsplit` for the column stack, so
2393
+ * all alignment + ANSI rules behave consistently.
2394
+ *
2395
+ * @param blocks - Pre-rendered string blocks. Flows in reading order.
2396
+ * @param opts - Grid configuration. `columns` is required.
2397
+ *
2398
+ * @example 2×2 grid of stats cards
2399
+ * ```js
2400
+ * import { panels, ascii } from 'ansimax';
2401
+ *
2402
+ * const cards = [
2403
+ * ascii.box('FILES\n42', { borderStyle: 'rounded', padding: 1 }),
2404
+ * ascii.box('LINES\n1247', { borderStyle: 'rounded', padding: 1 }),
2405
+ * ascii.box('TESTS\n38', { borderStyle: 'rounded', padding: 1 }),
2406
+ * ascii.box('COV\n98%', { borderStyle: 'rounded', padding: 1 }),
2407
+ * ];
2408
+ *
2409
+ * console.log(panels.grid(cards, { columns: 2, gapX: 2, gapY: 1 }));
2410
+ * ```
2411
+ *
2412
+ * @example 3-column gallery with auto-flow
2413
+ * ```js
2414
+ * // 7 items in 3 columns → 3 rows: [3, 3, 1]
2415
+ * const items = ['One', 'Two', 'Three', 'Four', 'Five', 'Six', 'Seven'];
2416
+ * console.log(panels.grid(items, { columns: 3, gapX: 4 }));
2417
+ * ```
2418
+ *
2419
+ * @example uniform cell width for visual consistency
2420
+ * ```js
2421
+ * console.log(panels.grid(blocks, {
2422
+ * columns: 4,
2423
+ * cellWidth: 15,
2424
+ * alignX: 'center',
2425
+ * }));
2426
+ * ```
2427
+ */
2428
+ declare const grid: (blocks: string[], opts: GridOptions) => string;
2342
2429
  declare const panels: {
2343
2430
  vsplit: (blocks: string[], opts?: VsplitOptions) => string;
2344
2431
  hsplit: (blocks: string[], opts?: HsplitOptions) => string;
2345
2432
  center: (block: string, opts: CenterOptions) => string;
2346
2433
  frame: (block: string, opts?: FrameOptions) => string;
2434
+ grid: (blocks: string[], opts: GridOptions) => string;
2347
2435
  };
2348
2436
 
2349
2437
  /**
@@ -2401,6 +2489,23 @@ interface PrettyOptions {
2401
2489
  * @since 1.3.1
2402
2490
  */
2403
2491
  inlineArrayMaxLength?: number;
2492
+ /**
2493
+ * Output mode controls what kind of string is produced:
2494
+ *
2495
+ * - `'display'` (default) — terminal-friendly output with colors (when
2496
+ * enabled) and informational placeholders like `[Circular]`,
2497
+ * `[Function: name]`, `Symbol(x)`, `Map(2) {...}`, `Set(3) {...}`,
2498
+ * `Date(2026-06-13T...)`, `BigInt(123n)`. Not parseable as JSON.
2499
+ *
2500
+ * - `'json'` — strict, parseable JSON output. Colors are forced off,
2501
+ * circular references throw `TypeError`, and types not representable
2502
+ * in JSON (functions, symbols, undefined) are omitted from objects /
2503
+ * replaced with `null` in arrays. Map/Set are converted to objects/arrays.
2504
+ * Dates become ISO strings. BigInt becomes a number (or string if too large).
2505
+ *
2506
+ * @since 1.3.3
2507
+ */
2508
+ mode?: 'display' | 'json';
2404
2509
  }
2405
2510
  /**
2406
2511
  * Pretty-print a JavaScript value with colored output suitable for
@@ -2618,4 +2723,4 @@ declare const ansimax: {
2618
2723
  configure: (opts?: AnsimaxConfig, meta?: ConfigureOptions) => void;
2619
2724
  };
2620
2725
 
2621
- export { ASCII_RAMPS, type Alignment, type AnimateGradientController, type AnimateGradientOptions, type AnimationHooks, type AnimationSpeed, type AnsiCode, type AnsimaxConfig, type AsciiRamp, BEL, BG, type BadgeOptions, type BallOptions, type BannerOptions, type BoxOptions, type BoxStyle, type BreatheOptions, DEFAULTS as CONFIG_DEFAULTS, CSI, type Canvas, type CanvasRenderOptions, type CenterOptions, type ColorChain, type ColorFn, type ColorLevel, type ColorMode, type ColorSupport, type ColumnsOptions, type ConfigChangeListener, type ConfigKey, type ConfigKeyListener, type ConfigureOptions, type CountdownOptions, type CustomOptions, DEFAULT_TERM_COLS, DEFAULT_TERM_ROWS, type DebounceOptions, type DiffType, type Dimensions, type DividerOptions, type DotsOptions, ESC, type EasingFn, type EasingName, type EraseMode, FG, FRAME_MS, type FadeOptions, type FigletFont, type FigletOptions, type FontMap, type FontName, type FrameCallback, type FrameHandle, type FrameOptions, type FromImageOptions, type GlitchOptions, type Glyph, type GradientOptions, type GradientRectOptions, type HsplitOptions, type PrettyOptions as JsonPrettyOptions, type LineDiff, type LiveController, type LiveOptions, type LoadingBarOptions, type LogoOptions, MENU_CANCELLED, type MemoizeOptions, type MenuInput, type MenuOptions, type MenuOutput, type MenuResult, type MultiLoader, type MultiLoaderItem, OSC, type OnResizeOptions, type OutputBuffer, type ParallelOptions, type ParallelStep, type Pixel, type PixelGrid, type PlayController, type PlayOptions, type PresetName, type ProgressAnimateOptions, type ProgressBarOptions, type ProgressOptions, type PulseOptions, type RGB, type RGBA, type RegisterFontOptions, type RenderOptions$1 as RenderOptions, type ResizeListener, type ReusableGradient, type RevealOptions, SPINNERS, SPRITES, ST, STYLE, type SectionOptions, type SleepOptions, type SlideOptions, type SpinOptions, type SpinnerType, type StatusOptions, type StatusType, type StopFn, type StreamOptions, type TableBorderStyle, type TableOptions, type Task, type TaskResult, type TasksOptions, type Theme, type BannerOpts as ThemeBannerOpts, type ThemeChangeListener, type ThemeInstance, type ThemeStyleName, type TimelineEvent, type TimelineOptions, type TreeData, type TreeDimensions, type TreeNode, type RenderOptions as TreeRenderOptions, type TreeStyle, type TypeDeleteOptions, type TypewriterOptions, type VsplitOptions, type WalkVisitor, type WaveOptions, type WriteAsyncOptions, animate, animateGradient, ascii, bell, bg256, bgRgb, box, canAnimate, cancelTerminalFrame, center$1 as center, center as centerBlock, chain, charWidth, clamp, clearAnsiCache, clearColorCache, clearRenderCache, clearThemeColorCache, color, colorLevel, presets as colorPresets, components, compose, configure, countNodes, createCanvas, createGradient, createOutputBuffer, createTheme, cursor, debounce, ansimax as default, diffLines, escapeRegex, fg256, fgRgb, figletText, filterTree, findInTree, flipHorizontal, flipVertical, frame, frames, fromImage, getConfig, getConfigValue, getRenderCacheSize, getSpeedMultiplier, getTerminalHeight, getTerminalWidth, gradient, gradientColor, gradientRect, graphemes, hasFont, hexToRgb, hideCursor, hsplit, images, isHexColor, isNoColor, json, pretty as jsonPretty, lerp, lerpColor, link, listFonts, listPresets, loader, mapTree, measureTree, memoize, nextTick, onConfigChange, onConfigKeyChange, onResize, once, padBoth, padEnd, padStart, panels, parseFiglet, pauseListeners, presetNames, presets, rainbow, registerFont, registerPreset, renderPixelArt, renderTree, renderTreeStream, repeatVisible, requestTerminalFrame, reset, resetColorSupportCache, resetConfig, resetCursorRefCount, resetFramesCursorCount, resetLoaderCursorCount, resetNoColor, resumeListeners, reverseGradient, rgbTo256, rgbToHex, rotate90, safeJson, screen, setNoColor, setTitle, sgr, showCursor, sleep, sleepFrame, sliceAnsi, stripAnsi$1 as stripAnsi, stripAnsi$2 as stripAnsiCodes, stripAnsi as stripAnsiColors, supportsColor, supportsColorLevel, termSize, themes, throttle, tree, trees, truncateAnsi, visibleLen, vsplit, walkTree, withConfig, wordWrap, wrapAnsi, write, writeAsync, writeErr, writeln, writelnErr };
2726
+ export { ASCII_RAMPS, type Alignment, type AnimateGradientController, type AnimateGradientOptions, type AnimationHooks, type AnimationSpeed, type AnsiCode, type AnsimaxConfig, type AsciiRamp, BEL, BG, type BadgeOptions, type BallOptions, type BannerOptions, type BoxOptions, type BoxStyle, type BreatheOptions, DEFAULTS as CONFIG_DEFAULTS, CSI, type Canvas, type CanvasRenderOptions, type CenterOptions, type ColorChain, type ColorFn, type ColorLevel, type ColorMode, type ColorSupport, type ColumnsOptions, type ConfigChangeListener, type ConfigKey, type ConfigKeyListener, type ConfigureOptions, type CountdownOptions, type CustomOptions, DEFAULT_TERM_COLS, DEFAULT_TERM_ROWS, type DebounceOptions, type DiffType, type Dimensions, type DividerOptions, type DotsOptions, ESC, type EasingFn, type EasingName, type EraseMode, FG, FRAME_MS, type FadeOptions, type FigletFont, type FigletOptions, type FontMap, type FontName, type FrameCallback, type FrameHandle, type FrameOptions, type FromImageOptions, type GlitchOptions, type Glyph, type GradientOptions, type GradientRectOptions, type GridOptions, type HsplitOptions, type PrettyOptions as JsonPrettyOptions, type LineDiff, type LiveController, type LiveOptions, type LoadingBarOptions, type LogoOptions, MENU_CANCELLED, type MemoizeOptions, type MenuInput, type MenuOptions, type MenuOutput, type MenuResult, type MultiLoader, type MultiLoaderItem, OSC, type OnResizeOptions, type OutputBuffer, type ParallelOptions, type ParallelStep, type Pixel, type PixelGrid, type PlayController, type PlayOptions, type PresetName, type ProgressAnimateOptions, type ProgressBarOptions, type ProgressOptions, type PulseOptions, type RGB, type RGBA, type RegisterFontOptions, type RenderOptions$1 as RenderOptions, type ResizeListener, type ReusableGradient, type RevealOptions, SPINNERS, SPRITES, ST, STYLE, type SectionOptions, type SleepOptions, type SlideOptions, type SpinOptions, type SpinnerType, type StatusOptions, type StatusType, type StopFn, type StreamOptions, type TableBorderStyle, type TableOptions, type Task, type TaskResult, type TasksOptions, type Theme, type BannerOpts as ThemeBannerOpts, type ThemeChangeListener, type ThemeInstance, type ThemeStyleName, type TimelineEvent, type TimelineOptions, type TreeData, type TreeDimensions, type TreeNode, type RenderOptions as TreeRenderOptions, type TreeStyle, type TypeDeleteOptions, type TypewriterOptions, type VsplitOptions, type WalkVisitor, type WaveOptions, type WriteAsyncOptions, animate, animateGradient, ascii, bell, bg256, bgRgb, box, canAnimate, cancelTerminalFrame, center$1 as center, center as centerBlock, chain, charWidth, clamp, clearAnsiCache, clearColorCache, clearRenderCache, clearThemeColorCache, color, colorLevel, presets as colorPresets, components, compose, configure, countNodes, createCanvas, createGradient, createOutputBuffer, createTheme, cursor, debounce, ansimax as default, diffLines, escapeRegex, fg256, fgRgb, figletText, filterTree, findInTree, flipHorizontal, flipVertical, frame, frames, fromImage, getConfig, getConfigValue, getRenderCacheSize, getSpeedMultiplier, getTerminalHeight, getTerminalWidth, gradient, gradientColor, gradientRect, graphemes, grid, hasFont, hexToRgb, hideCursor, hsplit, images, isHexColor, isNoColor, json, pretty as jsonPretty, lerp, lerpColor, link, listFonts, listPresets, loader, mapTree, measureTree, memoize, nextTick, onConfigChange, onConfigKeyChange, onResize, once, padBoth, padEnd, padStart, panels, parseFiglet, pauseListeners, presetNames, presets, rainbow, registerFont, registerPreset, renderPixelArt, renderTree, renderTreeStream, repeatVisible, requestTerminalFrame, reset, resetColorSupportCache, resetConfig, resetCursorRefCount, resetFramesCursorCount, resetLoaderCursorCount, resetNoColor, resumeListeners, reverseGradient, rgbTo256, rgbToHex, rotate90, safeJson, screen, setNoColor, setTitle, sgr, showCursor, sleep, sleepFrame, sliceAnsi, stripAnsi$1 as stripAnsi, stripAnsi$2 as stripAnsiCodes, stripAnsi as stripAnsiColors, supportsColor, supportsColorLevel, termSize, themes, throttle, tree, trees, truncateAnsi, visibleLen, vsplit, walkTree, withConfig, wordWrap, wrapAnsi, write, writeAsync, writeErr, writeln, writelnErr };
package/dist/index.js CHANGED
@@ -100,6 +100,7 @@ __export(index_exports, {
100
100
  gradientColor: () => gradientColor,
101
101
  gradientRect: () => gradientRect,
102
102
  graphemes: () => graphemes,
103
+ grid: () => grid,
103
104
  hasFont: () => hasFont,
104
105
  hexToRgb: () => hexToRgb,
105
106
  hideCursor: () => hideCursor,
@@ -2457,23 +2458,61 @@ var banner = (text, opts = {}) => {
2457
2458
  };
2458
2459
  var box = (text, opts = {}) => {
2459
2460
  const safe = ensureString2(text, "box(text)");
2460
- const { padding = 1, borderStyle = "rounded", width = null } = opts;
2461
+ const {
2462
+ padding = 1,
2463
+ borderStyle = "rounded",
2464
+ width = null,
2465
+ title = null,
2466
+ // v1.3.3
2467
+ titleAlign = "center"
2468
+ // v1.3.3
2469
+ } = opts;
2461
2470
  const padNum = typeof padding === "number" && Number.isFinite(padding) ? padding : 1;
2462
2471
  const safePadding = Math.max(0, Math.floor(padNum));
2463
2472
  const b = BOX_STYLES[borderStyle] ?? BOX_STYLES.rounded;
2464
2473
  const lines = safe.split("\n");
2465
2474
  const inner = width != null ? lines.map((l) => padEnd(truncateAnsi(l, width, ""), width)) : lines;
2466
- const w = inner.length > 0 ? Math.max(0, ...inner.map((l) => visibleLen(l))) : 0;
2475
+ const contentW = inner.length > 0 ? Math.max(0, ...inner.map((l) => visibleLen(l))) : 0;
2476
+ let w = contentW;
2477
+ let titleStr = "";
2478
+ let titleW = 0;
2479
+ if (typeof title === "string" && title.length > 0) {
2480
+ titleStr = ` ${title} `;
2481
+ titleW = visibleLen(titleStr);
2482
+ const titleNeeded = titleW + 2;
2483
+ const innerNeeded = w + safePadding * 2;
2484
+ if (titleNeeded > innerNeeded) {
2485
+ w = titleNeeded - safePadding * 2;
2486
+ }
2487
+ }
2488
+ const innerW = w + safePadding * 2;
2467
2489
  const pad = " ".repeat(safePadding);
2468
- const top = b.tl + b.h.repeat(w + safePadding * 2) + b.tr;
2469
- const bottom = b.bl + b.h.repeat(w + safePadding * 2) + b.br;
2470
- const emptyRow = b.v + " ".repeat(w + safePadding * 2) + b.v;
2490
+ let top;
2491
+ if (titleStr.length > 0 && titleW < innerW) {
2492
+ let before;
2493
+ let after;
2494
+ if (titleAlign === "left") {
2495
+ before = 1;
2496
+ after = innerW - titleW - before;
2497
+ } else if (titleAlign === "right") {
2498
+ after = 1;
2499
+ before = innerW - titleW - after;
2500
+ } else {
2501
+ before = Math.floor((innerW - titleW) / 2);
2502
+ after = innerW - titleW - before;
2503
+ }
2504
+ top = b.tl + b.h.repeat(before) + titleStr + b.h.repeat(after) + b.tr;
2505
+ } else {
2506
+ top = b.tl + b.h.repeat(innerW) + b.tr;
2507
+ }
2508
+ const bottom = b.bl + b.h.repeat(innerW) + b.br;
2509
+ const emptyRow = b.v + " ".repeat(innerW) + b.v;
2471
2510
  const rows = inner.map((l) => b.v + pad + padEnd(l, w) + pad + b.v);
2472
2511
  const vPad = Array(safePadding).fill(emptyRow);
2473
2512
  return [top, ...vPad, ...rows, ...vPad, bottom].join("\n");
2474
2513
  };
2475
2514
  var divider = (opts = {}) => {
2476
- const { char, width = null, label = null, style = "single" } = opts;
2515
+ const { char, width = null, label = null, style = "single", align = "center" } = opts;
2477
2516
  const { cols } = termSize();
2478
2517
  const w = Math.max(0, width ?? cols);
2479
2518
  const b = BOX_STYLES[style] ?? BOX_STYLES.single;
@@ -2482,8 +2521,18 @@ var divider = (opts = {}) => {
2482
2521
  if (label) {
2483
2522
  const labelLen = visibleLen(label);
2484
2523
  if (labelLen >= w - 2) return label;
2485
- const side = Math.max(0, Math.floor((w - labelLen - 2) / 2));
2486
- const trailLen = Math.max(0, w - side - labelLen - 2);
2524
+ let side;
2525
+ let trailLen;
2526
+ if (align === "left") {
2527
+ side = 1;
2528
+ trailLen = Math.max(0, w - labelLen - side - 2);
2529
+ } else if (align === "right") {
2530
+ trailLen = 1;
2531
+ side = Math.max(0, w - labelLen - trailLen - 2);
2532
+ } else {
2533
+ side = Math.max(0, Math.floor((w - labelLen - 2) / 2));
2534
+ trailLen = Math.max(0, w - side - labelLen - 2);
2535
+ }
2487
2536
  return fill.repeat(side) + " " + label + " " + fill.repeat(trailLen);
2488
2537
  }
2489
2538
  return fill.repeat(w);
@@ -5136,16 +5185,16 @@ var ensurePixelGrid = (pixels) => {
5136
5185
  return pixels.map((row) => Array.isArray(row) ? row : []);
5137
5186
  };
5138
5187
  var renderPixelArt = (pixels, opts = {}) => {
5139
- const grid = ensurePixelGrid(pixels);
5140
- if (!grid || grid.length === 0) return "";
5188
+ const grid2 = ensurePixelGrid(pixels);
5189
+ if (!grid2 || grid2.length === 0) return "";
5141
5190
  const { scale = 1, halfBlock = true, braille = false } = opts;
5142
5191
  const safeScale = clampInt(scale, 1, 100, 1);
5143
- if (braille) return _renderBraille(grid);
5192
+ if (braille) return _renderBraille(grid2);
5144
5193
  const lines = [];
5145
5194
  if (halfBlock) {
5146
- for (let row = 0; row < grid.length; row += 2) {
5147
- const topRow = grid[row] ?? [];
5148
- const botRow = grid[row + 1] ?? [];
5195
+ for (let row = 0; row < grid2.length; row += 2) {
5196
+ const topRow = grid2[row] ?? [];
5197
+ const botRow = grid2[row + 1] ?? [];
5149
5198
  const colCount = Math.max(topRow.length, botRow.length);
5150
5199
  let line = "";
5151
5200
  let curFg = -1;
@@ -5202,7 +5251,7 @@ var renderPixelArt = (pixels, opts = {}) => {
5202
5251
  lines.push(line);
5203
5252
  }
5204
5253
  } else {
5205
- for (const row of grid) {
5254
+ for (const row of grid2) {
5206
5255
  let line = "";
5207
5256
  let curFg = -1;
5208
5257
  for (const pixel of row) {
@@ -5317,24 +5366,24 @@ var SPRITES = {
5317
5366
  ] }
5318
5367
  };
5319
5368
  var flipHorizontal = (pixels) => {
5320
- const grid = ensurePixelGrid(pixels);
5321
- if (!grid) return [];
5322
- return grid.map((row) => [...row].reverse());
5369
+ const grid2 = ensurePixelGrid(pixels);
5370
+ if (!grid2) return [];
5371
+ return grid2.map((row) => [...row].reverse());
5323
5372
  };
5324
5373
  var flipVertical = (pixels) => {
5325
- const grid = ensurePixelGrid(pixels);
5326
- if (!grid) return [];
5327
- return [...grid].reverse();
5374
+ const grid2 = ensurePixelGrid(pixels);
5375
+ if (!grid2) return [];
5376
+ return [...grid2].reverse();
5328
5377
  };
5329
5378
  var rotate90 = (pixels) => {
5330
- const grid = ensurePixelGrid(pixels);
5331
- if (!grid || grid.length === 0) return [];
5332
- const rows = grid.length;
5333
- const cols = Math.max(0, ...grid.map((r) => r.length));
5379
+ const grid2 = ensurePixelGrid(pixels);
5380
+ if (!grid2 || grid2.length === 0) return [];
5381
+ const rows = grid2.length;
5382
+ const cols = Math.max(0, ...grid2.map((r) => r.length));
5334
5383
  if (cols === 0) return [];
5335
5384
  return Array.from(
5336
5385
  { length: cols },
5337
- (_, c) => Array.from({ length: rows }, (__, r) => grid[rows - 1 - r]?.[c] ?? null)
5386
+ (_, c) => Array.from({ length: rows }, (__, r) => grid2[rows - 1 - r]?.[c] ?? null)
5338
5387
  );
5339
5388
  };
5340
5389
  var BAYER_4x4 = [
@@ -5729,7 +5778,9 @@ var frame = (block, opts = {}) => {
5729
5778
  paddingX,
5730
5779
  topChar = "\u2500",
5731
5780
  bottomChar,
5732
- title
5781
+ title,
5782
+ titleAlign = "center"
5783
+ // v1.3.3
5733
5784
  } = opts;
5734
5785
  const safePadY = Math.max(0, Math.floor(paddingY ?? padding));
5735
5786
  const safePadX = Math.max(0, Math.floor(paddingX ?? padding));
@@ -5750,8 +5801,18 @@ var frame = (block, opts = {}) => {
5750
5801
  }
5751
5802
  let topLine;
5752
5803
  if (titleStr.length > 0 && titleW < innerW) {
5753
- const before = Math.floor((innerW - titleW) / 2);
5754
- const after = innerW - titleW - before;
5804
+ let before;
5805
+ let after;
5806
+ if (titleAlign === "left") {
5807
+ before = 1;
5808
+ after = innerW - titleW - before;
5809
+ } else if (titleAlign === "right") {
5810
+ after = 1;
5811
+ before = innerW - titleW - after;
5812
+ } else {
5813
+ before = Math.floor((innerW - titleW) / 2);
5814
+ after = innerW - titleW - before;
5815
+ }
5755
5816
  topLine = safeTop.repeat(before) + titleStr + safeTop.repeat(after);
5756
5817
  } else {
5757
5818
  topLine = safeTop.repeat(innerW);
@@ -5772,12 +5833,54 @@ var frame = (block, opts = {}) => {
5772
5833
  out.push(bottomLine);
5773
5834
  return out.join("\n");
5774
5835
  };
5836
+ var grid = (blocks, opts) => {
5837
+ if (!Array.isArray(blocks) || blocks.length === 0) return "";
5838
+ if (!opts || typeof opts !== "object") return "";
5839
+ const columns2 = Math.max(1, Math.floor(opts.columns ?? 1));
5840
+ const gapX = Math.max(0, Math.floor(opts.gapX ?? 1));
5841
+ const gapY = Math.max(0, Math.floor(opts.gapY ?? 0));
5842
+ const alignX = opts.alignX ?? "start";
5843
+ const alignY = opts.alignY ?? "start";
5844
+ const cellW = opts.cellWidth != null ? Math.max(0, Math.floor(opts.cellWidth)) : null;
5845
+ const rows = [];
5846
+ for (let i = 0; i < blocks.length; i += columns2) {
5847
+ rows.push(blocks.slice(i, i + columns2));
5848
+ }
5849
+ let widths = null;
5850
+ if (cellW != null) {
5851
+ widths = Array(columns2).fill(cellW);
5852
+ } else {
5853
+ widths = Array(columns2).fill(0);
5854
+ for (const row of rows) {
5855
+ for (let c = 0; c < row.length; c++) {
5856
+ const { maxWidth } = _splitBlock(row[c]);
5857
+ if (maxWidth > widths[c]) {
5858
+ widths[c] = maxWidth;
5859
+ }
5860
+ }
5861
+ }
5862
+ }
5863
+ const renderedRows = rows.map((row) => {
5864
+ const padded = [];
5865
+ for (let c = 0; c < columns2; c++) {
5866
+ padded.push(row[c] ?? "");
5867
+ }
5868
+ return vsplit(padded, {
5869
+ gap: gapX,
5870
+ align: alignY,
5871
+ widths
5872
+ });
5873
+ });
5874
+ return hsplit(renderedRows, { gap: gapY, align: alignX });
5875
+ };
5775
5876
  var panels = {
5776
5877
  vsplit,
5777
5878
  hsplit,
5778
5879
  // v1.3.1
5779
5880
  center: center2,
5780
- frame
5881
+ frame,
5882
+ // v1.3.3
5883
+ grid
5781
5884
  };
5782
5885
 
5783
5886
  // src/json/index.ts
@@ -5797,11 +5900,12 @@ var _truncString = (s, maxLength) => {
5797
5900
  return s.slice(0, maxLength - 3) + "...";
5798
5901
  };
5799
5902
  var _formatPrimitive = (value, opts) => {
5800
- const { useColor, maxStringLength } = opts;
5903
+ const { useColor, maxStringLength, mode } = opts;
5801
5904
  if (value === null) {
5802
5905
  return _c("null", COLORS.null, useColor);
5803
5906
  }
5804
5907
  if (value === void 0) {
5908
+ if (mode === "json") return _c("null", COLORS.null, useColor);
5805
5909
  return _c("undefined", COLORS.null, useColor);
5806
5910
  }
5807
5911
  if (typeof value === "string") {
@@ -5810,8 +5914,12 @@ var _formatPrimitive = (value, opts) => {
5810
5914
  return _c(quoted, COLORS.string, useColor);
5811
5915
  }
5812
5916
  if (typeof value === "number") {
5813
- if (Number.isNaN(value)) return _c("NaN", COLORS.number, useColor);
5917
+ if (Number.isNaN(value)) {
5918
+ if (mode === "json") return _c("null", COLORS.null, useColor);
5919
+ return _c("NaN", COLORS.number, useColor);
5920
+ }
5814
5921
  if (!Number.isFinite(value)) {
5922
+ if (mode === "json") return _c("null", COLORS.null, useColor);
5815
5923
  return _c(value > 0 ? "Infinity" : "-Infinity", COLORS.number, useColor);
5816
5924
  }
5817
5925
  return _c(String(value), COLORS.number, useColor);
@@ -5820,16 +5928,23 @@ var _formatPrimitive = (value, opts) => {
5820
5928
  return _c(String(value), COLORS.boolean, useColor);
5821
5929
  }
5822
5930
  if (typeof value === "bigint") {
5931
+ if (mode === "json") {
5932
+ const big2 = value;
5933
+ const asNum = Number(big2);
5934
+ if (Number.isSafeInteger(asNum) && BigInt(asNum) === big2) {
5935
+ return _c(String(asNum), COLORS.number, useColor);
5936
+ }
5937
+ return _c(JSON.stringify(String(big2)), COLORS.string, useColor);
5938
+ }
5823
5939
  return _c(`${value}n`, COLORS.number, useColor);
5824
5940
  }
5825
5941
  if (typeof value === "function") {
5942
+ if (mode === "json") return _c("null", COLORS.null, useColor);
5826
5943
  const name = value.name || "anonymous";
5827
5944
  return _c(`[Function: ${name}]`, COLORS.comment, useColor);
5828
5945
  }
5829
- if (typeof value === "symbol") {
5830
- return _c(value.toString(), COLORS.comment, useColor);
5831
- }
5832
- return _c(String(value), COLORS.comment, useColor);
5946
+ if (mode === "json") return _c("null", COLORS.null, useColor);
5947
+ return _c(value.toString(), COLORS.comment, useColor);
5833
5948
  };
5834
5949
  var _renderValue = (value, depth, config) => {
5835
5950
  const {
@@ -5840,15 +5955,56 @@ var _renderValue = (value, depth, config) => {
5840
5955
  useColor,
5841
5956
  seen,
5842
5957
  sortKeys,
5843
- inlineArrayMaxLength
5958
+ inlineArrayMaxLength,
5959
+ mode
5844
5960
  } = config;
5845
5961
  if (value === null || typeof value !== "object") {
5846
- return _formatPrimitive(value, { useColor, maxStringLength });
5962
+ return _formatPrimitive(value, { useColor, maxStringLength, mode });
5847
5963
  }
5848
5964
  if (seen.has(value)) {
5965
+ if (mode === "json") {
5966
+ throw new TypeError("Cannot serialize circular reference to JSON");
5967
+ }
5849
5968
  return _c("[Circular]", COLORS.comment, useColor);
5850
5969
  }
5851
5970
  seen.add(value);
5971
+ if (value instanceof Date) {
5972
+ const iso = value.toISOString();
5973
+ if (mode === "json") {
5974
+ return _c(JSON.stringify(iso), COLORS.string, useColor);
5975
+ }
5976
+ return _c(`Date(${iso})`, COLORS.comment, useColor);
5977
+ }
5978
+ if (value instanceof Map) {
5979
+ if (mode === "json") {
5980
+ const obj = {};
5981
+ for (const [k, v] of value) {
5982
+ if (typeof k === "string") obj[k] = v;
5983
+ else obj[String(k)] = v;
5984
+ }
5985
+ return _renderValue(obj, depth, config);
5986
+ }
5987
+ const entries2 = Array.from(value);
5988
+ const sizeLabel = _c(`Map(${entries2.length})`, COLORS.comment, useColor);
5989
+ if (entries2.length === 0) {
5990
+ return `${sizeLabel} ${_c("{}", COLORS.bracket, useColor)}`;
5991
+ }
5992
+ if (depth >= maxDepth - 1 && depth > 0) {
5993
+ return `${sizeLabel} ${_c("{...}", COLORS.bracket, useColor)}`;
5994
+ }
5995
+ return `${sizeLabel} ${_renderValue(entries2, depth, config)}`;
5996
+ }
5997
+ if (value instanceof Set) {
5998
+ if (mode === "json") {
5999
+ return _renderValue(Array.from(value), depth, config);
6000
+ }
6001
+ const arr = Array.from(value);
6002
+ const sizeLabel = _c(`Set(${arr.length})`, COLORS.comment, useColor);
6003
+ if (arr.length === 0) {
6004
+ return `${sizeLabel} ${_c("[]", COLORS.bracket, useColor)}`;
6005
+ }
6006
+ return `${sizeLabel} ${_renderValue(arr, depth, config)}`;
6007
+ }
5852
6008
  if (depth >= maxDepth) {
5853
6009
  if (Array.isArray(value)) {
5854
6010
  return _c("[", COLORS.bracket, useColor) + _c("...", COLORS.comment, useColor) + _c("]", COLORS.bracket, useColor);
@@ -5867,7 +6023,7 @@ var _renderValue = (value, depth, config) => {
5867
6023
  const displayCount2 = Math.min(value.length, maxItems);
5868
6024
  const inlineItems = [];
5869
6025
  for (let i = 0; i < displayCount2; i++) {
5870
- inlineItems.push(_formatPrimitive(value[i], { useColor, maxStringLength }));
6026
+ inlineItems.push(_formatPrimitive(value[i], { useColor, maxStringLength, mode }));
5871
6027
  }
5872
6028
  if (value.length > maxItems) {
5873
6029
  const remaining = value.length - maxItems;
@@ -5893,6 +6049,12 @@ var _renderValue = (value, depth, config) => {
5893
6049
  return _c("[", COLORS.bracket, useColor) + "\n" + items.join(",\n") + "\n" + closePad + _c("]", COLORS.bracket, useColor);
5894
6050
  }
5895
6051
  let keys = Object.keys(value);
6052
+ if (mode === "json") {
6053
+ keys = keys.filter((k) => {
6054
+ const v = value[k];
6055
+ return typeof v !== "function" && typeof v !== "symbol" && v !== void 0;
6056
+ });
6057
+ }
5896
6058
  if (keys.length === 0) {
5897
6059
  return _c("{}", COLORS.bracket, useColor);
5898
6060
  }
@@ -5921,14 +6083,17 @@ var pretty = (value, opts = {}) => {
5921
6083
  maxStringLength = Infinity,
5922
6084
  // v1.3.1
5923
6085
  sortKeys = false,
5924
- inlineArrayMaxLength = 60
6086
+ inlineArrayMaxLength = 60,
6087
+ // v1.3.3
6088
+ mode = "display"
5925
6089
  } = opts;
5926
6090
  const safeIndent = Math.max(0, Math.floor(Number(indent) || 0));
5927
6091
  const safeMaxDepth = Number.isFinite(maxDepth) ? Math.max(0, Math.floor(maxDepth)) : Infinity;
5928
6092
  const safeMaxItems = Number.isFinite(maxItems) ? Math.max(0, Math.floor(maxItems)) : Infinity;
5929
6093
  const safeMaxStrLen = Number.isFinite(maxStringLength) ? Math.max(0, Math.floor(maxStringLength)) : Infinity;
5930
6094
  const safeInlineMax = Number.isFinite(inlineArrayMaxLength) ? Math.max(0, Math.floor(inlineArrayMaxLength)) : 60;
5931
- const useColor = colors && !isNoColor();
6095
+ const safeMode = mode === "json" ? "json" : "display";
6096
+ const useColor = safeMode === "json" ? false : colors && !isNoColor();
5932
6097
  return _renderValue(value, 0, {
5933
6098
  indent: safeIndent,
5934
6099
  maxDepth: safeMaxDepth,
@@ -5937,7 +6102,8 @@ var pretty = (value, opts = {}) => {
5937
6102
  useColor,
5938
6103
  seen: /* @__PURE__ */ new WeakSet(),
5939
6104
  sortKeys: Boolean(sortKeys),
5940
- inlineArrayMaxLength: safeInlineMax
6105
+ inlineArrayMaxLength: safeInlineMax,
6106
+ mode: safeMode
5941
6107
  });
5942
6108
  };
5943
6109
  var json = {
@@ -6231,6 +6397,7 @@ var index_default = ansimax;
6231
6397
  gradientColor,
6232
6398
  gradientRect,
6233
6399
  graphemes,
6400
+ grid,
6234
6401
  hasFont,
6235
6402
  hexToRgb,
6236
6403
  hideCursor,