@zakmandhro/bunti 0.1.3 → 0.1.5

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 (92) hide show
  1. package/README.md +66 -25
  2. package/dist/colors.d.ts +74 -0
  3. package/dist/colors.d.ts.map +1 -0
  4. package/dist/colors.js +227 -0
  5. package/dist/colors.js.map +1 -0
  6. package/dist/components/Box.d.ts +5 -0
  7. package/dist/components/Box.d.ts.map +1 -0
  8. package/dist/components/Box.js +4 -0
  9. package/dist/components/Box.js.map +1 -0
  10. package/dist/components/Button.d.ts +14 -0
  11. package/dist/components/Button.d.ts.map +1 -0
  12. package/dist/components/Button.js +91 -0
  13. package/dist/components/Button.js.map +1 -0
  14. package/dist/components/Card.d.ts +11 -0
  15. package/dist/components/Card.d.ts.map +1 -0
  16. package/dist/components/Card.js +37 -0
  17. package/dist/components/Card.js.map +1 -0
  18. package/dist/components/Header.d.ts +13 -0
  19. package/dist/components/Header.d.ts.map +1 -0
  20. package/dist/components/Header.js +54 -0
  21. package/dist/components/Header.js.map +1 -0
  22. package/dist/components/Input.d.ts +16 -0
  23. package/dist/components/Input.d.ts.map +1 -0
  24. package/dist/components/Input.js +101 -0
  25. package/dist/components/Input.js.map +1 -0
  26. package/dist/components/Modal.d.ts +13 -0
  27. package/dist/components/Modal.d.ts.map +1 -0
  28. package/dist/components/Modal.js +28 -0
  29. package/dist/components/Modal.js.map +1 -0
  30. package/dist/components/index.d.ts +7 -0
  31. package/dist/components/index.d.ts.map +1 -0
  32. package/{src/components/index.ts → dist/components/index.js} +3 -0
  33. package/dist/components/index.js.map +1 -0
  34. package/dist/data/glyphs.d.ts +5 -0
  35. package/dist/data/glyphs.d.ts.map +1 -0
  36. package/dist/data/glyphs.js +29 -0
  37. package/dist/data/glyphs.js.map +1 -0
  38. package/dist/detect.d.ts +15 -0
  39. package/dist/detect.d.ts.map +1 -0
  40. package/dist/detect.js +49 -0
  41. package/dist/detect.js.map +1 -0
  42. package/dist/dsl.d.ts +159 -0
  43. package/dist/dsl.d.ts.map +1 -0
  44. package/dist/dsl.js +663 -0
  45. package/dist/dsl.js.map +1 -0
  46. package/dist/easing.d.ts +5 -0
  47. package/dist/easing.d.ts.map +1 -0
  48. package/dist/easing.js +18 -0
  49. package/dist/easing.js.map +1 -0
  50. package/dist/geometry.d.ts +38 -0
  51. package/dist/geometry.d.ts.map +1 -0
  52. package/dist/geometry.js +110 -0
  53. package/dist/geometry.js.map +1 -0
  54. package/dist/icons.d.ts +21 -0
  55. package/dist/icons.d.ts.map +1 -0
  56. package/dist/icons.js +185 -0
  57. package/dist/icons.js.map +1 -0
  58. package/dist/index.d.ts +157 -0
  59. package/dist/index.d.ts.map +1 -0
  60. package/dist/index.js +36 -0
  61. package/dist/index.js.map +1 -0
  62. package/dist/layout.d.ts +89 -0
  63. package/dist/layout.d.ts.map +1 -0
  64. package/dist/layout.js +533 -0
  65. package/dist/layout.js.map +1 -0
  66. package/dist/render.d.ts +17 -0
  67. package/dist/render.d.ts.map +1 -0
  68. package/dist/render.js +335 -0
  69. package/dist/render.js.map +1 -0
  70. package/dist/state.d.ts +92 -0
  71. package/dist/state.d.ts.map +1 -0
  72. package/dist/state.js +105 -0
  73. package/dist/state.js.map +1 -0
  74. package/dist/utils.d.ts +27 -0
  75. package/dist/utils.d.ts.map +1 -0
  76. package/dist/utils.js +157 -0
  77. package/dist/utils.js.map +1 -0
  78. package/package.json +33 -8
  79. package/src/colors.ts +0 -255
  80. package/src/components/Button.ts +0 -104
  81. package/src/components/Card.ts +0 -53
  82. package/src/components/Header.ts +0 -65
  83. package/src/components/Input.ts +0 -124
  84. package/src/data/glyphs.ts +0 -30
  85. package/src/detect.ts +0 -60
  86. package/src/dsl.ts +0 -661
  87. package/src/icons.ts +0 -186
  88. package/src/index.ts +0 -72
  89. package/src/layout.ts +0 -640
  90. package/src/render.ts +0 -302
  91. package/src/state.ts +0 -148
  92. package/src/utils.ts +0 -165
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,UAAU,CAAC;AACnC,OAAO,KAAK,MAAM,MAAM,UAAU,CAAC;AACnC,OAAO,KAAK,GAAG,MAAM,OAAO,CAAC;AAE7B,OAAO,KAAK,QAAQ,MAAM,YAAY,CAAC;AACvC,OAAO,KAAK,KAAK,MAAM,SAAS,CAAC;AACjC,OAAO,KAAK,MAAM,MAAM,UAAU,CAAC;AAEnC,OAAO,KAAK,KAAK,MAAM,SAAS,CAAC;AAGjC,OAAO,EAAE,EAAE,EAAE,cAAc,EAAE,IAAI,EAAE,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAEhF,YAAY,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAErD,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAC9C,YAAY,EACV,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,iBAAiB,EACjB,eAAe,GAChB,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAC9E,YAAY,EACV,eAAe,EACf,iBAAiB,EACjB,IAAI,EACJ,SAAS,EACT,YAAY,GACb,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,SAAS,EACT,iBAAiB,EACjB,WAAW,EACX,SAAS,GACV,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAC9C,OAAO,EACL,SAAS,EACT,QAAQ,EACR,IAAI,EACJ,IAAI,EACJ,IAAI,EACJ,QAAQ,EACR,QAAQ,EACR,aAAa,GACd,MAAM,SAAS,CAAC;AACjB,YAAY,EACV,WAAW,EACX,WAAW,EACX,YAAY,EACZ,YAAY,GACb,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,KAAK,EACL,IAAI,EACJ,GAAG,EACH,WAAW,EACX,SAAS,EACT,QAAQ,EACR,cAAc,EACd,YAAY,EACZ,IAAI,EACJ,IAAI,EACJ,OAAO,EACP,KAAK,EACL,QAAQ,EACR,SAAS,GACV,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AACvC,YAAY,EAAE,IAAI,EAAE,GAAG,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACrE,OAAO,EACL,IAAI,EACJ,eAAe,EACf,iBAAiB,EACjB,YAAY,GACb,MAAM,SAAS,CAAC;AACjB,OAAO,EACL,SAAS,EACT,WAAW,EACX,SAAS,EACT,QAAQ,EACR,YAAY,GACb,MAAM,SAAS,CAAC;AAGjB,eAAO,MAAM,KAAK;;;;WAcsR,CAAC;aAAe,CAAC;cAAgB,CAAC;YAAc,CAAC;;;;;;;;;YAAwy0B,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;0CAArqtB,YAAY;2CAA6O,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iDAAmoS,eAAe,EAAC,+BAA6B;;;;;;;;;;;;;;;iBAAw+J,CAAC;;;;gBAA/qd,CAAC;;;;;;;;;;CAH5sH,CAAC;AAEF,eAAe,KAAK,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,36 @@
1
+ import * as colors from './colors';
2
+ import * as detect from './detect';
3
+ import * as dsl from './dsl';
4
+ import * as easing from './easing';
5
+ import * as geometry from './geometry';
6
+ import * as icons from './icons';
7
+ import * as layout from './layout';
8
+ import * as render from './render';
9
+ import * as state from './state';
10
+ import * as utils from './utils';
11
+ export { bg, createGradient, fade, fg, hexToRGB, PALETTE, rgb } from './colors';
12
+ // Functional API Individual Exports
13
+ export { detectCapabilities } from './detect';
14
+ export { KEYS, render } from './dsl';
15
+ export { clamp01, easeInOutCubic, easeOutBack, easeOutCubic } from './easing';
16
+ export { innerRect, resolvePlacedRect, resolveRect, splitRect, } from './geometry';
17
+ export { EMOJI_MAP, ICON_MAP, icon, init, nerd, nerdIcon, register, replaceEmojis, } from './icons';
18
+ export { badge, blit, box, createStyle, getWindow, gradient, joinHorizontal, joinVertical, list, rect, setCell, table, viewport, wallpaper, } from './layout';
19
+ export { flush, loop } from './render';
20
+ export { ANSI, clearBackBuffer, createScreenState, resizeScreen, } from './state';
21
+ export { charWidth, indentBlock, stripAnsi, truncate, visibleWidth, } from './utils';
22
+ // Namespaced export for bunti.render style usage
23
+ export const bunti = {
24
+ ...detect,
25
+ ...icons,
26
+ ...layout,
27
+ ...render,
28
+ ...utils,
29
+ ...colors,
30
+ ...state,
31
+ ...dsl,
32
+ ...easing,
33
+ ...geometry,
34
+ };
35
+ export default bunti;
36
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,UAAU,CAAC;AACnC,OAAO,KAAK,MAAM,MAAM,UAAU,CAAC;AACnC,OAAO,KAAK,GAAG,MAAM,OAAO,CAAC;AAC7B,OAAO,KAAK,MAAM,MAAM,UAAU,CAAC;AACnC,OAAO,KAAK,QAAQ,MAAM,YAAY,CAAC;AACvC,OAAO,KAAK,KAAK,MAAM,SAAS,CAAC;AACjC,OAAO,KAAK,MAAM,MAAM,UAAU,CAAC;AACnC,OAAO,KAAK,MAAM,MAAM,UAAU,CAAC;AACnC,OAAO,KAAK,KAAK,MAAM,SAAS,CAAC;AACjC,OAAO,KAAK,KAAK,MAAM,SAAS,CAAC;AAEjC,OAAO,EAAE,EAAE,EAAE,cAAc,EAAE,IAAI,EAAE,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAGhF,oCAAoC;AACpC,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAQ9C,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAQ9E,OAAO,EACL,SAAS,EACT,iBAAiB,EACjB,WAAW,EACX,SAAS,GACV,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,SAAS,EACT,QAAQ,EACR,IAAI,EACJ,IAAI,EACJ,IAAI,EACJ,QAAQ,EACR,QAAQ,EACR,aAAa,GACd,MAAM,SAAS,CAAC;AAOjB,OAAO,EACL,KAAK,EACL,IAAI,EACJ,GAAG,EACH,WAAW,EACX,SAAS,EACT,QAAQ,EACR,cAAc,EACd,YAAY,EACZ,IAAI,EACJ,IAAI,EACJ,OAAO,EACP,KAAK,EACL,QAAQ,EACR,SAAS,GACV,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAEvC,OAAO,EACL,IAAI,EACJ,eAAe,EACf,iBAAiB,EACjB,YAAY,GACb,MAAM,SAAS,CAAC;AACjB,OAAO,EACL,SAAS,EACT,WAAW,EACX,SAAS,EACT,QAAQ,EACR,YAAY,GACb,MAAM,SAAS,CAAC;AAEjB,iDAAiD;AACjD,MAAM,CAAC,MAAM,KAAK,GAAG;IACnB,GAAG,MAAM;IACT,GAAG,KAAK;IACR,GAAG,MAAM;IACT,GAAG,MAAM;IACT,GAAG,KAAK;IACR,GAAG,MAAM;IACT,GAAG,KAAK;IACR,GAAG,GAAG;IACN,GAAG,MAAM;IACT,GAAG,QAAQ;CACZ,CAAC;AAEF,eAAe,KAAK,CAAC"}
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Bunti Functional Layout & Drawing
3
+ * Strictly functional primitives for buffer manipulation and layout generation.
4
+ */
5
+ import type { Cell, RGB, ScreenState } from './state';
6
+ export declare function setCell(state: ScreenState, x: number, y: number, cell: Partial<Cell>): void;
7
+ import type { Gradient } from './colors';
8
+ export interface RectOptions {
9
+ char?: string;
10
+ fg?: string | number | RGB;
11
+ bg?: string | number | RGB | Gradient;
12
+ }
13
+ export declare function rect(state: ScreenState, x: number, y: number, w: number, h: number, style: RectOptions): void;
14
+ export declare function blit(state: ScreenState, startX: number, startY: number, content: string, style?: Partial<Cell>): void;
15
+ export type BorderStyle = 'default' | 'rounded' | 'double' | 'dashed' | 'dotted' | 'frame' | 'thick-frame' | 'classic' | 'none';
16
+ export interface SideColors {
17
+ top?: any;
18
+ bottom?: any;
19
+ left?: any;
20
+ right?: any;
21
+ }
22
+ export type SizeUnit = number | string;
23
+ export interface StyleOptions {
24
+ width?: SizeUnit;
25
+ minWidth?: number;
26
+ maxWidth?: number;
27
+ height?: SizeUnit;
28
+ minHeight?: number;
29
+ maxHeight?: number;
30
+ padding?: [number, number];
31
+ border?: BorderStyle;
32
+ borderColor?: string | number | RGB | ((s: string) => string) | SideColors;
33
+ bgColor?: string | number | RGB | Gradient;
34
+ align?: 'left' | 'center' | 'right';
35
+ valign?: 'top' | 'middle' | 'bottom';
36
+ wrap?: boolean;
37
+ title?: string;
38
+ titleStyle?: (s: string) => string;
39
+ }
40
+ /**
41
+ * Resolves a SizeUnit to an absolute integer based on parent dimensions.
42
+ */
43
+ export declare function resolveSize(unit: SizeUnit | undefined, parentDim: number, contentDim: number): number;
44
+ /**
45
+ * Generates a styled box string with perfect alignment and optional wrapping.
46
+ */
47
+ export declare function box(content: string, options?: StyleOptions, parentW?: number, parentH?: number): string;
48
+ export declare function joinHorizontal(...blocks: string[]): string;
49
+ export declare function joinVertical(...blocks: string[]): string;
50
+ export declare function createStyle(defaults: StyleOptions): (content: string, overrides?: StyleOptions) => string;
51
+ export declare function badge(text: string, colorFn?: (s: string) => string): string;
52
+ export interface TableOptions {
53
+ width?: SizeUnit;
54
+ columns?: {
55
+ width?: SizeUnit;
56
+ align?: 'left' | 'center' | 'right';
57
+ }[];
58
+ border?: BorderStyle;
59
+ padding?: [number, number];
60
+ }
61
+ /**
62
+ * Renders a data table with perfectly aligned columns and shared borders.
63
+ */
64
+ export declare function table(rows: string[][], options?: TableOptions, parentW?: number): string;
65
+ export declare function getWindow<T>(items: T[], selectedIndex: number, maxVisible: number): {
66
+ visible: T[];
67
+ start: number;
68
+ hasMoreAbove: boolean;
69
+ hasMoreBelow: boolean;
70
+ };
71
+ export interface ListOptions {
72
+ bullet?: string;
73
+ indent?: number;
74
+ focusedIndex?: number;
75
+ focusStyle?: (s: string) => string;
76
+ selectedBg?: string | number | RGB;
77
+ width?: SizeUnit;
78
+ maxVisible?: number;
79
+ interactive?: boolean;
80
+ }
81
+ export declare function list(items: string[], options?: ListOptions, parentW?: number): string;
82
+ export declare function viewport(content: string, width: number, height: number, scrollY?: number): string;
83
+ export declare function wallpaper(state: any, options: {
84
+ bg: any;
85
+ }): void;
86
+ export declare function gradient(state: any, colors: any[], options?: {
87
+ direction?: 'vertical' | 'horizontal';
88
+ }): void;
89
+ //# sourceMappingURL=layout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../src/layout.ts"],"names":[],"mappings":"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"}
package/dist/layout.js ADDED
@@ -0,0 +1,533 @@
1
+ /**
2
+ * Bunti Functional Layout & Drawing
3
+ * Strictly functional primitives for buffer manipulation and layout generation.
4
+ */
5
+ import { resolveColor } from './colors';
6
+ import { replaceEmojis } from './icons';
7
+ import { charWidth, truncate, visibleWidth, wrapText } from './utils';
8
+ // --- Functional Primitives (Buffer Manipulation) ---
9
+ export function setCell(state, x, y, cell) {
10
+ if (x >= 0 && x < state.width && y >= 0 && y < state.height) {
11
+ const target = state.backBuffer[y * state.width + x];
12
+ let displayWidth = 1;
13
+ if (cell.char !== undefined) {
14
+ target.char = cell.raw ? cell.char : replaceEmojis(cell.char);
15
+ // Single-ASCII-char cells (fills, borders' spaces, plain text) skip width math.
16
+ displayWidth =
17
+ target.char.length === 1 && target.char.charCodeAt(0) < 0x80
18
+ ? 1
19
+ : charWidth(target.char);
20
+ target.fg = undefined;
21
+ target.fgCode = undefined;
22
+ target.bold = false;
23
+ }
24
+ if (cell.fg !== undefined) {
25
+ target.fg = cell.fg;
26
+ target.fgCode = resolveColor(cell.fg);
27
+ }
28
+ if (cell.bg !== undefined) {
29
+ target.bg = cell.bg;
30
+ target.bgCode = resolveColor(cell.bg);
31
+ }
32
+ if (cell.bold !== undefined)
33
+ target.bold = cell.bold;
34
+ target.skip = cell.skip ?? false;
35
+ for (let dx = 1; dx < displayWidth; dx++) {
36
+ const skipX = x + dx;
37
+ if (skipX >= state.width)
38
+ break;
39
+ const skip = state.backBuffer[y * state.width + skipX];
40
+ skip.char = '';
41
+ skip.fg = target.fg;
42
+ skip.bg = target.bg;
43
+ skip.fgCode = target.fgCode;
44
+ skip.bgCode = target.bgCode;
45
+ skip.bold = target.bold;
46
+ skip.skip = true;
47
+ }
48
+ }
49
+ }
50
+ export function rect(state, x, y, w, h, style) {
51
+ const isGradient = style.bg && typeof style.bg === 'object' && 'colors' in style.bg;
52
+ for (let dy = 0; dy < h; dy++) {
53
+ const row = y + dy;
54
+ if (row < 0 || row >= state.height)
55
+ continue;
56
+ for (let dx = 0; dx < w; dx++) {
57
+ const col = x + dx;
58
+ if (col < 0 || col >= state.width)
59
+ continue;
60
+ let resolvedBg;
61
+ if (isGradient) {
62
+ const grad = style.bg;
63
+ if (grad.direction === 'horizontal') {
64
+ resolvedBg = grad.colors[Math.floor((dx / w) * grad.colors.length)];
65
+ }
66
+ else {
67
+ resolvedBg = grad.colors[Math.floor((dy / h) * grad.colors.length)];
68
+ }
69
+ }
70
+ else {
71
+ resolvedBg =
72
+ style.bg !== undefined
73
+ ? resolveColor(style.bg)
74
+ : undefined;
75
+ }
76
+ const cell = { bg: resolvedBg };
77
+ if (style.char)
78
+ cell.char = style.char;
79
+ if (style.fg)
80
+ cell.fg = resolveColor(style.fg);
81
+ const existing = state.backBuffer[row * state.width + col];
82
+ if (existing.char !== ' ' && !style.char) {
83
+ // Keep existing char/fg if drawing a pure background
84
+ cell.char = existing.char;
85
+ cell.fg = existing.fg;
86
+ }
87
+ setCell(state, col, row, cell);
88
+ }
89
+ }
90
+ }
91
+ export function blit(state, startX, startY, content, style = {}) {
92
+ const lines = content.split('\n');
93
+ for (let row = 0; row < lines.length; row++) {
94
+ const line = lines[row];
95
+ let x = startX;
96
+ let currentFg, currentBg;
97
+ let currentBold = false;
98
+ const regex = /\x1B\[([0-9;]*)m|([^\x1B]+)/g;
99
+ let match = null;
100
+ while ((match = regex.exec(line)) !== null) {
101
+ if (match[1] !== undefined) {
102
+ const codes = match[1].split(';');
103
+ for (let i = 0; i < codes.length; i++) {
104
+ const code = parseInt(codes[i] || '0', 10);
105
+ if (code === 0) {
106
+ currentFg = undefined;
107
+ currentBg = undefined;
108
+ currentBold = false;
109
+ }
110
+ else if (code === 1)
111
+ currentBold = true;
112
+ else if (code === 22)
113
+ currentBold = false;
114
+ else if (code >= 30 && code <= 37)
115
+ currentFg = (code - 30).toString();
116
+ else if (code >= 40 && code <= 47)
117
+ currentBg = (code - 40).toString();
118
+ else if (code >= 90 && code <= 97)
119
+ currentFg = (code - 90 + 8).toString();
120
+ else if (code >= 100 && code <= 107)
121
+ currentBg = (code - 100 + 8).toString();
122
+ else if (code === 38 && codes[i + 1] === '5') {
123
+ currentFg = parseInt(codes[i + 2], 10);
124
+ i += 2;
125
+ }
126
+ else if (code === 38 && codes[i + 1] === '2') {
127
+ currentFg = {
128
+ r: parseInt(codes[i + 2], 10),
129
+ g: parseInt(codes[i + 3], 10),
130
+ b: parseInt(codes[i + 4], 10),
131
+ };
132
+ i += 4;
133
+ }
134
+ else if (code === 48 && codes[i + 1] === '5') {
135
+ currentBg = parseInt(codes[i + 2], 10);
136
+ i += 2;
137
+ }
138
+ else if (code === 48 && codes[i + 1] === '2') {
139
+ currentBg = {
140
+ r: parseInt(codes[i + 2], 10),
141
+ g: parseInt(codes[i + 3], 10),
142
+ b: parseInt(codes[i + 4], 10),
143
+ };
144
+ i += 4;
145
+ }
146
+ else if (code === 39)
147
+ currentFg = undefined;
148
+ else if (code === 49)
149
+ currentBg = undefined;
150
+ }
151
+ }
152
+ else if (match[2]) {
153
+ const processedText = replaceEmojis(match[2]);
154
+ const segmenter = new Intl.Segmenter('en', {
155
+ granularity: 'grapheme',
156
+ });
157
+ for (const { segment } of segmenter.segment(processedText)) {
158
+ const w = charWidth(segment);
159
+ if (w === 0)
160
+ continue;
161
+ const cell = { char: segment, ...style };
162
+ // Only overwrite buffer colors if explicitly set in the string or style
163
+ if (currentFg !== undefined)
164
+ cell.fg = currentFg;
165
+ else if (style.fg !== undefined)
166
+ cell.fg = style.fg;
167
+ else if (state.options.defaultFg !== undefined)
168
+ cell.fg = state.options.defaultFg;
169
+ if (currentBg !== undefined)
170
+ cell.bg = currentBg;
171
+ else if (style.bg !== undefined)
172
+ cell.bg = style.bg;
173
+ if (currentBold)
174
+ cell.bold = true;
175
+ setCell(state, x, startY + row, cell);
176
+ x += w;
177
+ }
178
+ }
179
+ }
180
+ }
181
+ }
182
+ const BORDERS = {
183
+ default: { tl: '┌', tr: '┐', bl: '└', br: '┘', h: '─', v: '│' },
184
+ rounded: { tl: '╭', tr: '╮', bl: '╰', br: '╯', h: '─', v: '│' },
185
+ double: { tl: '╔', tr: '╗', bl: '╚', br: '╝', h: '═', v: '║' },
186
+ dashed: { tl: '┌', tr: '┐', bl: '└', br: '┘', h: '╌', v: '╎' },
187
+ dotted: { tl: '┌', tr: '┐', bl: '└', br: '┘', h: '┈', v: '┊' },
188
+ frame: {
189
+ tl: '█',
190
+ tr: '█',
191
+ bl: '█',
192
+ br: '█',
193
+ top: '▀',
194
+ bottom: '▄',
195
+ left: '█',
196
+ right: '█',
197
+ },
198
+ 'thick-frame': { tl: '█', tr: '█', bl: '█', br: '█', h: '█', v: '█' },
199
+ classic: { tl: '+', tr: '+', bl: '+', br: '+', h: '-', v: '|' },
200
+ };
201
+ /**
202
+ * Resolves a SizeUnit to an absolute integer based on parent dimensions.
203
+ */
204
+ export function resolveSize(unit, parentDim, contentDim) {
205
+ if (unit === undefined || unit === 'auto')
206
+ return contentDim;
207
+ if (typeof unit === 'number')
208
+ return unit;
209
+ if (typeof unit === 'string') {
210
+ if (unit.endsWith('%')) {
211
+ const pct = parseFloat(unit) / 100;
212
+ return Math.floor(parentDim * pct);
213
+ }
214
+ if (unit.endsWith('fr')) {
215
+ return parentDim;
216
+ }
217
+ }
218
+ return contentDim;
219
+ }
220
+ /**
221
+ * Generates a styled box string with perfect alignment and optional wrapping.
222
+ */
223
+ export function box(content, options = {}, parentW, parentH) {
224
+ // Ensure we operate on the swapped glyphs for all layout math
225
+ content = replaceEmojis(content);
226
+ const px = options.padding?.[1] ?? 0;
227
+ const py = options.padding?.[0] ?? 0;
228
+ const borderStyle = options.border || 'none';
229
+ const borderOffset = borderStyle === 'none' ? 0 : 2;
230
+ const rawLines = content.split('\n');
231
+ const maxRawW = Math.max(...rawLines.map((l) => visibleWidth(l)), 0);
232
+ const intrinsicW = maxRawW + px * 2 + borderOffset;
233
+ // 1. Resolve Target Width (Outer)
234
+ const resolvedW = resolveSize(options.width, parentW || 0, intrinsicW);
235
+ // 2. Calculate Inner Width (between borders, including padding)
236
+ let targetInnerW = Math.max(0, resolvedW - borderOffset);
237
+ if (options.minWidth)
238
+ targetInnerW = Math.max(targetInnerW, options.minWidth - borderOffset);
239
+ if (options.maxWidth)
240
+ targetInnerW = Math.min(targetInnerW, options.maxWidth - borderOffset);
241
+ let lines = [];
242
+ const contentWidth = Math.max(0, targetInnerW - px * 2);
243
+ if (options.wrap && contentWidth > 0) {
244
+ lines = wrapText(content, contentWidth);
245
+ }
246
+ else {
247
+ lines = content.split('\n').map((l) => truncate(l, contentWidth));
248
+ }
249
+ const contentH = lines.length + py * 2;
250
+ const resolvedH = resolveSize(options.height, parentH || 0, contentH);
251
+ let finalInnerH = resolvedH ? resolvedH - borderOffset : contentH;
252
+ if (options.minHeight)
253
+ finalInnerH = Math.max(finalInnerH, options.minHeight - borderOffset);
254
+ if (options.maxHeight)
255
+ finalInnerH = Math.min(finalInnerH, options.maxHeight - borderOffset);
256
+ const b = borderStyle === 'none'
257
+ ? null
258
+ : BORDERS[borderStyle] || BORDERS.default;
259
+ // Color Resolution
260
+ const { fg } = require('./colors');
261
+ const resolveSide = (color) => typeof color === 'function' ? color : (s) => fg(color, s);
262
+ const wrapBg = (s) => {
263
+ if (!options.bgColor)
264
+ return s;
265
+ if (typeof options.bgColor === 'object' && 'colors' in options.bgColor) {
266
+ // Gradients cannot be wrapped as a single ANSI string because they change per-cell.
267
+ // In string-building mode, we must ignore gradients. They are handled in absolute rect mode.
268
+ return s;
269
+ }
270
+ const { resolveColor } = require('./colors');
271
+ const code = resolveColor(options.bgColor);
272
+ const prefix = typeof options.bgColor === 'object' || String(code).startsWith('2;')
273
+ ? '48'
274
+ : '48;5';
275
+ const bgOn = `\x1b[${prefix};${code}m`;
276
+ // Apply bg, and if the string contains resets, re-apply the bg right after the reset.
277
+ // We add a final reset at the very end to clean up.
278
+ return `${bgOn + s.replace(/\x1b\[0m/g, `\x1b[0m${bgOn}`)}\x1b[0m`;
279
+ };
280
+ const bc = options.borderColor;
281
+ const colors = typeof bc === 'object' && !('r' in bc)
282
+ ? {
283
+ top: resolveSide(bc.top ||
284
+ bc.left ||
285
+ bc.right),
286
+ bottom: resolveSide(bc.bottom ||
287
+ bc.left ||
288
+ bc.right),
289
+ left: resolveSide(bc.left || bc.top),
290
+ right: resolveSide(bc.right || bc.top),
291
+ }
292
+ : {
293
+ top: resolveSide(bc || ((s) => s)),
294
+ bottom: resolveSide(bc || ((s) => s)),
295
+ left: resolveSide(bc || ((s) => s)),
296
+ right: resolveSide(bc || ((s) => s)),
297
+ };
298
+ const hTop = b?.top || b?.h || ' ';
299
+ const hBottom = b?.bottom || b?.h || ' ';
300
+ const vLeft = b?.left || b?.v || ' ';
301
+ const vRight = b?.right || b?.v || ' ';
302
+ const vSpace = Math.max(0, finalInnerH - lines.length - py * 2);
303
+ let topS = 0, bottomS = vSpace;
304
+ if (options.valign === 'middle') {
305
+ topS = Math.floor(vSpace / 2);
306
+ bottomS = Math.ceil(vSpace / 2);
307
+ }
308
+ else if (options.valign === 'bottom') {
309
+ topS = vSpace;
310
+ bottomS = 0;
311
+ }
312
+ const out = [];
313
+ // Top Border
314
+ if (b) {
315
+ const title = options.title && targetInnerW > 2
316
+ ? truncate(` ${options.title.trim()} `, targetInnerW)
317
+ : '';
318
+ const styledTitle = options.titleStyle ? options.titleStyle(title) : title;
319
+ const titleW = visibleWidth(title);
320
+ const beforeTitle = title ? 1 : 0;
321
+ const afterTitle = Math.max(0, targetInnerW - beforeTitle - titleW);
322
+ out.push(wrapBg(colors.top(b.tl) +
323
+ colors.top(hTop.repeat(beforeTitle)) +
324
+ styledTitle +
325
+ colors.top(hTop.repeat(afterTitle)) +
326
+ colors.top(b.tr)));
327
+ }
328
+ // Top Padding
329
+ for (let i = 0; i < py + topS; i++) {
330
+ let row = b ? colors.left(vLeft) : '';
331
+ row += wrapBg(' '.repeat(targetInnerW));
332
+ if (b)
333
+ row += colors.right(vRight);
334
+ out.push(row);
335
+ }
336
+ // Content Lines
337
+ for (let i = 0; i < lines.length; i++) {
338
+ const line = lines[i].trimEnd();
339
+ const lineW = visibleWidth(line);
340
+ const extra = Math.max(0, targetInnerW - lineW - px * 2);
341
+ let left = 0, right = 0;
342
+ const align = options.align || 'left';
343
+ if (align === 'center') {
344
+ left = px + Math.floor(extra / 2);
345
+ right = px + Math.ceil(extra / 2);
346
+ }
347
+ else if (align === 'right') {
348
+ left = px + extra;
349
+ right = px;
350
+ }
351
+ else {
352
+ left = px;
353
+ right = px + extra;
354
+ }
355
+ let row = b ? colors.left(vLeft) : '';
356
+ row += wrapBg(' '.repeat(Math.max(0, left)) + line + ' '.repeat(Math.max(0, right)));
357
+ if (b)
358
+ row += colors.right(vRight);
359
+ out.push(row);
360
+ }
361
+ // Bottom Padding
362
+ for (let i = 0; i < py + bottomS; i++) {
363
+ let row = b ? colors.left(vLeft) : '';
364
+ row += wrapBg(' '.repeat(targetInnerW));
365
+ if (b)
366
+ row += colors.right(vRight);
367
+ out.push(row);
368
+ }
369
+ // Bottom Border
370
+ if (b) {
371
+ out.push(wrapBg(colors.bottom(b.bl) +
372
+ colors.bottom(hBottom.repeat(targetInnerW)) +
373
+ colors.bottom(b.br)));
374
+ }
375
+ return out.join('\n');
376
+ }
377
+ export function joinHorizontal(...blocks) {
378
+ const parsed = blocks.map((b) => b.split('\n'));
379
+ const maxH = Math.max(...parsed.map((p) => p.length));
380
+ const widths = parsed.map((p) => Math.max(...p.map(visibleWidth)));
381
+ const out = [];
382
+ for (let i = 0; i < maxH; i++) {
383
+ let row = '';
384
+ for (let j = 0; j < parsed.length; j++) {
385
+ const block = parsed[j];
386
+ const targetW = widths[j];
387
+ if (block[i] !== undefined) {
388
+ row +=
389
+ block[i] +
390
+ ' '.repeat(Math.max(0, targetW - visibleWidth(block[i])));
391
+ }
392
+ else {
393
+ row += ' '.repeat(targetW);
394
+ }
395
+ }
396
+ out.push(row);
397
+ }
398
+ return out.join('\n');
399
+ }
400
+ export function joinVertical(...blocks) {
401
+ return blocks.filter(Boolean).join('\n');
402
+ }
403
+ export function createStyle(defaults) {
404
+ return (content, overrides = {}) => {
405
+ return box(content, { ...defaults, ...overrides });
406
+ };
407
+ }
408
+ export function badge(text, colorFn = (s) => s) {
409
+ return colorFn(` ${text.toUpperCase()} `);
410
+ }
411
+ /**
412
+ * Renders a data table with perfectly aligned columns and shared borders.
413
+ */
414
+ export function table(rows, options = {}, parentW) {
415
+ const borderStyle = options.border || 'default';
416
+ const _px = options.padding?.[1] ?? 1;
417
+ const _py = options.padding?.[0] ?? 0;
418
+ const colCount = rows[0]?.length || 0;
419
+ if (colCount === 0)
420
+ return '';
421
+ // 1. Resolve Column Widths
422
+ const resolvedWidth = resolveSize(options.width, parentW || 0, 80);
423
+ const gutterW = 1;
424
+ const colWidth = Math.floor((resolvedWidth - (colCount - 1) * gutterW) / colCount);
425
+ // 2. Render each cell as a rigid block
426
+ const renderedRows = rows.map((row) => {
427
+ const cells = row.map((content, i) => {
428
+ // Explicitly pad empty content to ensure it occupies the full column width
429
+ const safeContent = content || ' '.repeat(colWidth);
430
+ const cellAlign = options.columns?.[i]?.align
431
+ ? options.columns[i].align
432
+ : 'left';
433
+ return box(safeContent, {
434
+ width: colWidth,
435
+ border: 'none',
436
+ // Strict internal zero-padding; let the gutter handle spacing
437
+ padding: [0, 0],
438
+ align: cellAlign,
439
+ }, colWidth, 0);
440
+ });
441
+ // Join with gutter
442
+ return joinHorizontal(...cells.flatMap((c, i) => i < cells.length - 1 ? [c, ' '.repeat(gutterW)] : [c]));
443
+ });
444
+ return box(joinVertical(...renderedRows), {
445
+ border: borderStyle,
446
+ padding: [0, 0],
447
+ width: resolvedWidth,
448
+ align: 'left',
449
+ });
450
+ }
451
+ export function getWindow(items, selectedIndex, maxVisible) {
452
+ const start = Math.max(0, Math.min(selectedIndex - Math.floor(maxVisible / 2), items.length - maxVisible));
453
+ const visible = items.slice(start, start + maxVisible);
454
+ return {
455
+ visible,
456
+ start,
457
+ hasMoreAbove: start > 0,
458
+ hasMoreBelow: start + maxVisible < items.length,
459
+ };
460
+ }
461
+ export function list(items, options = {}, parentW) {
462
+ const bullet = options.bullet || '';
463
+ const indent = ' '.repeat(options.indent || 0);
464
+ const resolvedW = resolveSize(options.width, parentW || 0, 0);
465
+ const { resolveColor } = require('./colors');
466
+ const wrapSelectedBg = (line) => {
467
+ if (!options.selectedBg)
468
+ return line;
469
+ const code = resolveColor(options.selectedBg);
470
+ const codeStr = String(code);
471
+ const prefix = typeof options.selectedBg === 'object' || codeStr.startsWith('2;')
472
+ ? '48'
473
+ : '48;5';
474
+ const bgOn = `\x1b[${prefix};${codeStr}m`;
475
+ return `${bgOn + line.replace(/\x1b\[0m/g, `\x1b[0m${bgOn}`)}\x1b[0m`;
476
+ };
477
+ let targetItems = items, offset = 0, hasMoreAbove = false, hasMoreBelow = false;
478
+ if (options.maxVisible && items.length > options.maxVisible) {
479
+ const win = getWindow(items, options.focusedIndex || 0, options.maxVisible);
480
+ targetItems = win.visible;
481
+ offset = win.start;
482
+ hasMoreAbove = win.hasMoreAbove;
483
+ hasMoreBelow = win.hasMoreBelow;
484
+ }
485
+ const rendered = targetItems
486
+ .map((item, idx) => {
487
+ const actualIdx = offset + idx;
488
+ const line = `${indent}${bullet}${item}`;
489
+ if (options.focusedIndex === actualIdx) {
490
+ const styledLine = options.focusStyle ? options.focusStyle(line) : line;
491
+ if (!options.selectedBg)
492
+ return styledLine;
493
+ const paddedLine = resolvedW > 0
494
+ ? styledLine +
495
+ ' '.repeat(Math.max(0, resolvedW - visibleWidth(styledLine)))
496
+ : styledLine;
497
+ return wrapSelectedBg(paddedLine);
498
+ }
499
+ return line;
500
+ })
501
+ .join('\n');
502
+ let out = rendered;
503
+ if (hasMoreAbove)
504
+ out = `${indent} ↑ more…\n${out}`;
505
+ if (hasMoreBelow)
506
+ out = `${out}\n${indent} ↓ more…`;
507
+ return out;
508
+ }
509
+ export function viewport(content, width, height, scrollY = 0) {
510
+ const lines = content.split('\n');
511
+ const visibleLines = lines.slice(scrollY, scrollY + height);
512
+ return visibleLines
513
+ .map((line) => {
514
+ return truncate(line, width, '');
515
+ })
516
+ .join('\n');
517
+ }
518
+ export function wallpaper(state, options) {
519
+ const { bg } = options;
520
+ rect(state, 0, 0, state.width, state.height, { char: ' ', bg });
521
+ }
522
+ export function gradient(state, colors, options = {}) {
523
+ const { direction = 'vertical' } = options;
524
+ rect(state, 0, 0, state.width, state.height, {
525
+ char: ' ',
526
+ bg: {
527
+ colors,
528
+ direction,
529
+ steps: direction === 'vertical' ? state.height : state.width,
530
+ },
531
+ });
532
+ }
533
+ //# sourceMappingURL=layout.js.map