xray-manager 1.1.1 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,181 @@
1
+ "use strict";
2
+ /**
3
+ * Layout Manager Service
4
+ *
5
+ * Manages terminal layout detection, caching, and resize events
6
+ * Feature: 005-ui-layout-expansion
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.LayoutManager = void 0;
10
+ const layout_1 = require("../types/layout");
11
+ /**
12
+ * Resize debounce delay (300ms as per research.md)
13
+ */
14
+ const RESIZE_DEBOUNCE_MS = 300;
15
+ /**
16
+ * Layout Manager class
17
+ *
18
+ * Singleton service for managing terminal layouts
19
+ */
20
+ class LayoutManager {
21
+ constructor() {
22
+ this.currentLayout = null;
23
+ this.layoutCache = new Map();
24
+ this.resizeCallbacks = [];
25
+ this.resizeTimer = null;
26
+ }
27
+ /**
28
+ * Detect current terminal size
29
+ */
30
+ detectTerminalSize() {
31
+ const isTTY = process.stdout.isTTY ?? false;
32
+ if (isTTY && process.stdout.columns && process.stdout.rows) {
33
+ return {
34
+ width: process.stdout.columns,
35
+ height: process.stdout.rows,
36
+ isTTY: true,
37
+ };
38
+ }
39
+ // Fallback to default size
40
+ return {
41
+ width: layout_1.DEFAULT_LAYOUT.width,
42
+ height: layout_1.DEFAULT_LAYOUT.height,
43
+ isTTY,
44
+ };
45
+ }
46
+ /**
47
+ * Calculate layout mode based on terminal width
48
+ */
49
+ calculateLayoutMode(width) {
50
+ if (width < layout_1.LAYOUT_MODE_THRESHOLDS.STANDARD_MIN) {
51
+ return layout_1.LayoutMode.COMPACT;
52
+ }
53
+ else if (width > layout_1.LAYOUT_MODE_THRESHOLDS.STANDARD_MAX) {
54
+ return layout_1.LayoutMode.WIDE;
55
+ }
56
+ else {
57
+ return layout_1.LayoutMode.STANDARD;
58
+ }
59
+ }
60
+ /**
61
+ * Create a new layout configuration
62
+ */
63
+ createLayout(mode, regions, options) {
64
+ const size = this.detectTerminalSize();
65
+ // Determine columns based on mode
66
+ let columns = 1;
67
+ if (mode === layout_1.LayoutMode.WIDE) {
68
+ columns = 2; // Default to 2 columns for WIDE mode
69
+ }
70
+ // Allow force mode override
71
+ const actualMode = options?.forceMode ?? mode;
72
+ const layout = {
73
+ width: size.width,
74
+ height: size.height,
75
+ mode: actualMode,
76
+ columns,
77
+ regions,
78
+ timestamp: Date.now(),
79
+ };
80
+ // Validate before returning
81
+ (0, layout_1.validateLayout)(layout);
82
+ // Cache if enabled
83
+ if (options?.enableCache !== false) {
84
+ const cacheKey = `${actualMode}-${regions.length}`;
85
+ this.layoutCache.set(cacheKey, {
86
+ layout,
87
+ timestamp: Date.now(),
88
+ });
89
+ }
90
+ this.currentLayout = layout;
91
+ return layout;
92
+ }
93
+ /**
94
+ * Get current cached layout
95
+ */
96
+ getCurrentLayout() {
97
+ return this.currentLayout;
98
+ }
99
+ /**
100
+ * Clear layout cache
101
+ */
102
+ clearCache() {
103
+ this.layoutCache.clear();
104
+ }
105
+ /**
106
+ * Refresh layout (re-detect and re-create)
107
+ */
108
+ refreshLayout(regions, options) {
109
+ const size = this.detectTerminalSize();
110
+ const mode = this.calculateLayoutMode(size.width);
111
+ const regionsToUse = regions ?? this.currentLayout?.regions ?? [];
112
+ return this.createLayout(mode, regionsToUse, options);
113
+ }
114
+ /**
115
+ * Register resize event listener with debounce
116
+ */
117
+ onResize(callback) {
118
+ this.resizeCallbacks.push(callback);
119
+ // Set up resize listener if this is the first callback
120
+ if (this.resizeCallbacks.length === 1) {
121
+ process.stdout.on('resize', this.handleResize.bind(this));
122
+ }
123
+ // Return unsubscribe function
124
+ return () => {
125
+ const index = this.resizeCallbacks.indexOf(callback);
126
+ if (index > -1) {
127
+ this.resizeCallbacks.splice(index, 1);
128
+ }
129
+ // Remove listener if no more callbacks
130
+ if (this.resizeCallbacks.length === 0) {
131
+ process.stdout.off('resize', this.handleResize.bind(this));
132
+ }
133
+ };
134
+ }
135
+ /**
136
+ * Handle resize event with debounce
137
+ */
138
+ handleResize() {
139
+ // Clear existing timer
140
+ if (this.resizeTimer) {
141
+ clearTimeout(this.resizeTimer);
142
+ }
143
+ // Set new timer
144
+ this.resizeTimer = setTimeout(() => {
145
+ const newLayout = this.refreshLayout();
146
+ // Notify all callbacks
147
+ for (const callback of this.resizeCallbacks) {
148
+ callback(newLayout);
149
+ }
150
+ this.resizeTimer = null;
151
+ }, RESIZE_DEBOUNCE_MS);
152
+ }
153
+ /**
154
+ * Validate terminal size meets minimum requirements
155
+ */
156
+ validateTerminalSize(size) {
157
+ if (size.width < layout_1.MIN_TERMINAL_SIZE.width) {
158
+ return {
159
+ isValid: false,
160
+ message: `Terminal too narrow (${size.width} cols). Minimum: ${layout_1.MIN_TERMINAL_SIZE.width} cols.`,
161
+ suggestion: `Please resize your terminal to at least ${layout_1.MIN_TERMINAL_SIZE.width}x${layout_1.MIN_TERMINAL_SIZE.height} for optimal display.`,
162
+ };
163
+ }
164
+ if (size.height < layout_1.MIN_TERMINAL_SIZE.height) {
165
+ return {
166
+ isValid: false,
167
+ message: `Terminal too short (${size.height} rows). Minimum: ${layout_1.MIN_TERMINAL_SIZE.height} rows.`,
168
+ suggestion: `Please resize your terminal to at least ${layout_1.MIN_TERMINAL_SIZE.width}x${layout_1.MIN_TERMINAL_SIZE.height} for optimal display.`,
169
+ };
170
+ }
171
+ return {
172
+ isValid: true,
173
+ };
174
+ }
175
+ }
176
+ exports.LayoutManager = LayoutManager;
177
+ /**
178
+ * Singleton instance
179
+ */
180
+ exports.default = new LayoutManager();
181
+ //# sourceMappingURL=layout-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout-manager.js","sourceRoot":"","sources":["../../src/services/layout-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Layout Type Definitions
3
+ *
4
+ * Core types for terminal layout system supporting responsive layouts
5
+ * and multi-column displays.
6
+ *
7
+ * Feature: 005-ui-layout-expansion
8
+ */
9
+ /**
10
+ * Layout mode enum - defines different terminal size strategies
11
+ */
12
+ export declare enum LayoutMode {
13
+ /** Narrow terminals (< 80 columns) */
14
+ COMPACT = "compact",
15
+ /** Standard terminals (80-120 columns) */
16
+ STANDARD = "standard",
17
+ /** Wide terminals (> 120 columns) */
18
+ WIDE = "wide"
19
+ }
20
+ /**
21
+ * Content region type enum - categorizes different UI regions
22
+ */
23
+ export declare enum ContentRegionType {
24
+ /** Page header/title area */
25
+ HEADER = "header",
26
+ /** Menu options area */
27
+ MENU = "menu",
28
+ /** Status information area */
29
+ STATUS = "status",
30
+ /** Main content area */
31
+ CONTENT = "content",
32
+ /** Footer/hints area */
33
+ FOOTER = "footer"
34
+ }
35
+ /**
36
+ * Content region interface - defines a rectangular area in the terminal
37
+ */
38
+ export interface ContentRegion {
39
+ /** Unique identifier for this region */
40
+ id: string;
41
+ /** Type of content this region contains */
42
+ type: ContentRegionType;
43
+ /** Position in the terminal (row, column) */
44
+ position: {
45
+ row: number;
46
+ column: number;
47
+ };
48
+ /** Size of the region (width, height in characters) */
49
+ size: {
50
+ width: number;
51
+ height: number;
52
+ };
53
+ /** Padding inside the region (top, right, bottom, left in characters) */
54
+ padding: {
55
+ top: number;
56
+ right: number;
57
+ bottom: number;
58
+ left: number;
59
+ };
60
+ /** Whether to display a border around this region */
61
+ showBorder: boolean;
62
+ /** Optional content data (type depends on region type) */
63
+ content?: unknown;
64
+ }
65
+ /**
66
+ * Terminal layout interface - complete layout configuration
67
+ */
68
+ export interface TerminalLayout {
69
+ /** Terminal width in columns */
70
+ width: number;
71
+ /** Terminal height in rows */
72
+ height: number;
73
+ /** Current layout mode based on terminal width */
74
+ mode: LayoutMode;
75
+ /** Number of columns for multi-column layouts (1 for COMPACT/STANDARD, 2-3 for WIDE) */
76
+ columns: number;
77
+ /** List of content regions in this layout */
78
+ regions: ContentRegion[];
79
+ /** Timestamp when layout was calculated (for cache invalidation) */
80
+ timestamp: number;
81
+ }
82
+ /**
83
+ * Default layout configuration for non-TTY or fallback scenarios
84
+ */
85
+ export declare const DEFAULT_LAYOUT: TerminalLayout;
86
+ /**
87
+ * Minimum terminal size constraints
88
+ */
89
+ export declare const MIN_TERMINAL_SIZE: {
90
+ readonly width: 60;
91
+ readonly height: 20;
92
+ };
93
+ /**
94
+ * Layout mode thresholds for width-based mode selection
95
+ */
96
+ export declare const LAYOUT_MODE_THRESHOLDS: {
97
+ readonly COMPACT_MAX: 79;
98
+ readonly STANDARD_MIN: 80;
99
+ readonly STANDARD_MAX: 120;
100
+ readonly WIDE_MIN: 121;
101
+ };
102
+ /**
103
+ * Validate that a TerminalLayout configuration is valid
104
+ *
105
+ * @param layout - Layout to validate
106
+ * @returns true if valid
107
+ * @throws Error if validation fails
108
+ */
109
+ export declare function validateLayout(layout: TerminalLayout): boolean;
110
+ /**
111
+ * Validate that a ContentRegion is valid within a given layout
112
+ *
113
+ * @param region - Region to validate
114
+ * @param layout - Parent layout
115
+ * @returns true if valid
116
+ * @throws Error if validation fails
117
+ */
118
+ export declare function validateRegion(region: ContentRegion, layout: TerminalLayout): boolean;
119
+ //# sourceMappingURL=layout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../src/types/layout.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;GAEG;AAEH,oBAAY,UAAU;IACpB,sCAAsC;IACtC,OAAO,YAAY;IACnB,0CAA0C;IAC1C,QAAQ,aAAa;IACrB,qCAAqC;IACrC,IAAI,SAAS;CACd;AAGD;;GAEG;AAEH,oBAAY,iBAAiB;IAC3B,6BAA6B;IAC7B,MAAM,WAAW;IACjB,wBAAwB;IACxB,IAAI,SAAS;IACb,8BAA8B;IAC9B,MAAM,WAAW;IACjB,wBAAwB;IACxB,OAAO,YAAY;IACnB,wBAAwB;IACxB,MAAM,WAAW;CAClB;AAGD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,wCAAwC;IACxC,EAAE,EAAE,MAAM,CAAC;IAEX,2CAA2C;IAC3C,IAAI,EAAE,iBAAiB,CAAC;IAExB,6CAA6C;IAC7C,QAAQ,EAAE;QACR,GAAG,EAAE,MAAM,CAAC;QACZ,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IAEF,uDAAuD;IACvD,IAAI,EAAE;QACJ,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IAEF,yEAAyE;IACzE,OAAO,EAAE;QACP,GAAG,EAAE,MAAM,CAAC;QACZ,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IAEF,qDAAqD;IACrD,UAAU,EAAE,OAAO,CAAC;IAEpB,0DAA0D;IAC1D,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,gCAAgC;IAChC,KAAK,EAAE,MAAM,CAAC;IAEd,8BAA8B;IAC9B,MAAM,EAAE,MAAM,CAAC;IAEf,kDAAkD;IAClD,IAAI,EAAE,UAAU,CAAC;IAEjB,wFAAwF;IACxF,OAAO,EAAE,MAAM,CAAC;IAEhB,6CAA6C;IAC7C,OAAO,EAAE,aAAa,EAAE,CAAC;IAEzB,oEAAoE;IACpE,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,cAO5B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,iBAAiB;;;CAGpB,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,sBAAsB;;;;;CAKzB,CAAC;AAEX;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAoC9D;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,cAAc,GAAG,OAAO,CAsCrF"}
@@ -0,0 +1,142 @@
1
+ "use strict";
2
+ /**
3
+ * Layout Type Definitions
4
+ *
5
+ * Core types for terminal layout system supporting responsive layouts
6
+ * and multi-column displays.
7
+ *
8
+ * Feature: 005-ui-layout-expansion
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.LAYOUT_MODE_THRESHOLDS = exports.MIN_TERMINAL_SIZE = exports.DEFAULT_LAYOUT = exports.ContentRegionType = exports.LayoutMode = void 0;
12
+ exports.validateLayout = validateLayout;
13
+ exports.validateRegion = validateRegion;
14
+ /**
15
+ * Layout mode enum - defines different terminal size strategies
16
+ */
17
+ /* eslint-disable @typescript-eslint/no-unused-vars, no-unused-vars */
18
+ var LayoutMode;
19
+ (function (LayoutMode) {
20
+ /** Narrow terminals (< 80 columns) */
21
+ LayoutMode["COMPACT"] = "compact";
22
+ /** Standard terminals (80-120 columns) */
23
+ LayoutMode["STANDARD"] = "standard";
24
+ /** Wide terminals (> 120 columns) */
25
+ LayoutMode["WIDE"] = "wide";
26
+ })(LayoutMode || (exports.LayoutMode = LayoutMode = {}));
27
+ /* eslint-enable @typescript-eslint/no-unused-vars, no-unused-vars */
28
+ /**
29
+ * Content region type enum - categorizes different UI regions
30
+ */
31
+ /* eslint-disable @typescript-eslint/no-unused-vars, no-unused-vars */
32
+ var ContentRegionType;
33
+ (function (ContentRegionType) {
34
+ /** Page header/title area */
35
+ ContentRegionType["HEADER"] = "header";
36
+ /** Menu options area */
37
+ ContentRegionType["MENU"] = "menu";
38
+ /** Status information area */
39
+ ContentRegionType["STATUS"] = "status";
40
+ /** Main content area */
41
+ ContentRegionType["CONTENT"] = "content";
42
+ /** Footer/hints area */
43
+ ContentRegionType["FOOTER"] = "footer";
44
+ })(ContentRegionType || (exports.ContentRegionType = ContentRegionType = {}));
45
+ /**
46
+ * Default layout configuration for non-TTY or fallback scenarios
47
+ */
48
+ exports.DEFAULT_LAYOUT = {
49
+ width: 80,
50
+ height: 24,
51
+ mode: LayoutMode.STANDARD,
52
+ columns: 1,
53
+ regions: [],
54
+ timestamp: 0,
55
+ };
56
+ /**
57
+ * Minimum terminal size constraints
58
+ */
59
+ exports.MIN_TERMINAL_SIZE = {
60
+ width: 60,
61
+ height: 20,
62
+ };
63
+ /**
64
+ * Layout mode thresholds for width-based mode selection
65
+ */
66
+ exports.LAYOUT_MODE_THRESHOLDS = {
67
+ COMPACT_MAX: 79,
68
+ STANDARD_MIN: 80,
69
+ STANDARD_MAX: 120,
70
+ WIDE_MIN: 121,
71
+ };
72
+ /**
73
+ * Validate that a TerminalLayout configuration is valid
74
+ *
75
+ * @param layout - Layout to validate
76
+ * @returns true if valid
77
+ * @throws Error if validation fails
78
+ */
79
+ function validateLayout(layout) {
80
+ // 1. Check minimum size
81
+ if (layout.width < exports.MIN_TERMINAL_SIZE.width || layout.height < exports.MIN_TERMINAL_SIZE.height) {
82
+ throw new Error(`Terminal too small: ${layout.width}x${layout.height} (min: ${exports.MIN_TERMINAL_SIZE.width}x${exports.MIN_TERMINAL_SIZE.height})`);
83
+ }
84
+ // 2. Check mode matches width
85
+ const expectedMode = layout.width < exports.LAYOUT_MODE_THRESHOLDS.STANDARD_MIN
86
+ ? LayoutMode.COMPACT
87
+ : layout.width > exports.LAYOUT_MODE_THRESHOLDS.STANDARD_MAX
88
+ ? LayoutMode.WIDE
89
+ : LayoutMode.STANDARD;
90
+ if (layout.mode !== expectedMode) {
91
+ throw new Error(`LayoutMode mismatch: expected ${expectedMode} for width ${layout.width}, got ${layout.mode}`);
92
+ }
93
+ // 3. Check columns constraint
94
+ if (layout.mode === LayoutMode.WIDE && layout.columns < 2) {
95
+ throw new Error(`WIDE mode requires columns >= 2, got ${layout.columns}`);
96
+ }
97
+ if (layout.mode !== LayoutMode.WIDE && layout.columns !== 1) {
98
+ throw new Error(`Non-WIDE mode requires columns = 1, got ${layout.columns}`);
99
+ }
100
+ // 4. Validate all content regions
101
+ for (const region of layout.regions) {
102
+ validateRegion(region, layout);
103
+ }
104
+ return true;
105
+ }
106
+ /**
107
+ * Validate that a ContentRegion is valid within a given layout
108
+ *
109
+ * @param region - Region to validate
110
+ * @param layout - Parent layout
111
+ * @returns true if valid
112
+ * @throws Error if validation fails
113
+ */
114
+ function validateRegion(region, layout) {
115
+ // 1. Check position bounds
116
+ if (region.position.row < 0 || region.position.row >= layout.height) {
117
+ throw new Error(`Region ${region.id}: row ${region.position.row} out of bounds (0-${layout.height - 1})`);
118
+ }
119
+ if (region.position.column < 0 || region.position.column >= layout.width) {
120
+ throw new Error(`Region ${region.id}: column ${region.position.column} out of bounds (0-${layout.width - 1})`);
121
+ }
122
+ // 2. Check size bounds
123
+ const maxWidth = layout.width - region.position.column;
124
+ const maxHeight = layout.height - region.position.row;
125
+ if (region.size.width <= 0 || region.size.width > maxWidth) {
126
+ throw new Error(`Region ${region.id}: width ${region.size.width} out of bounds (1-${maxWidth})`);
127
+ }
128
+ if (region.size.height <= 0 || region.size.height > maxHeight) {
129
+ throw new Error(`Region ${region.id}: height ${region.size.height} out of bounds (1-${maxHeight})`);
130
+ }
131
+ // 3. Check padding validity
132
+ const totalHorizontalPadding = region.padding.left + region.padding.right;
133
+ const totalVerticalPadding = region.padding.top + region.padding.bottom;
134
+ if (totalHorizontalPadding >= region.size.width) {
135
+ throw new Error(`Region ${region.id}: horizontal padding ${totalHorizontalPadding} >= width ${region.size.width}`);
136
+ }
137
+ if (totalVerticalPadding >= region.size.height) {
138
+ throw new Error(`Region ${region.id}: vertical padding ${totalVerticalPadding} >= height ${region.size.height}`);
139
+ }
140
+ return true;
141
+ }
142
+ //# sourceMappingURL=layout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout.js","sourceRoot":"","sources":["../../src/types/layout.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,142 @@
1
+ /**
2
+ * Layout Utility Functions
3
+ *
4
+ * Pure functions for layout calculations, text fitting, and rendering
5
+ * Feature: 005-ui-layout-expansion
6
+ */
7
+ /**
8
+ * Table column definition
9
+ */
10
+ export interface TableColumn {
11
+ header: string;
12
+ key: string;
13
+ width?: number;
14
+ align?: 'left' | 'center' | 'right';
15
+ }
16
+ /**
17
+ * Render options for tables and sections
18
+ */
19
+ export interface RenderOptions {
20
+ showBorder?: boolean;
21
+ borderStyle?: 'single' | 'double' | 'compact';
22
+ padding?: {
23
+ top: number;
24
+ right: number;
25
+ bottom: number;
26
+ left: number;
27
+ };
28
+ }
29
+ /**
30
+ * Calculate the display width of a string, accounting for Chinese characters
31
+ *
32
+ * Chinese characters (and other full-width characters) occupy 2 columns,
33
+ * while ASCII characters occupy 1 column.
34
+ *
35
+ * @param text - Input text
36
+ * @returns Display width in terminal columns
37
+ */
38
+ export declare function calculateDisplayWidth(text: string): number;
39
+ /**
40
+ * Calculate the width of each column in a multi-column layout
41
+ *
42
+ * Formula: (totalWidth - (columns - 1) * gap) / columns
43
+ *
44
+ * @param totalWidth - Total available width
45
+ * @param columns - Number of columns
46
+ * @param gap - Space between columns
47
+ * @returns Width of each column (rounded down)
48
+ */
49
+ export declare function calculateColumnWidth(totalWidth: number, columns: number, gap: number): number;
50
+ /**
51
+ * Fit text to a specific width by truncating or padding
52
+ *
53
+ * @param text - Input text
54
+ * @param width - Target width in columns
55
+ * @param align - Alignment ('left', 'center', 'right')
56
+ * @param ellipsis - Ellipsis string for truncation (default '...')
57
+ * @returns Text adjusted to exact width
58
+ */
59
+ export declare function fitText(text: string, width: number, align?: 'left' | 'center' | 'right', ellipsis?: string): string;
60
+ /**
61
+ * Render a horizontal separator line
62
+ *
63
+ * @param width - Width of separator in columns
64
+ * @param char - Character to use (default '─')
65
+ * @param color - Optional chalk color name
66
+ * @returns Separator string
67
+ */
68
+ export declare function renderSeparator(width: number, char?: string, color?: string): string;
69
+ /**
70
+ * Render a header with optional alignment and border
71
+ *
72
+ * @param title - Header title text
73
+ * @param width - Total width
74
+ * @param align - Alignment
75
+ * @param options - Render options
76
+ * @returns Rendered header string
77
+ */
78
+ export declare function renderHeader(title: string, width: number, align?: 'left' | 'center' | 'right', options?: {
79
+ showBorder?: boolean;
80
+ color?: string;
81
+ }): string;
82
+ /**
83
+ * Apply padding to a text block
84
+ *
85
+ * @param text - Original text (can be multi-line)
86
+ * @param padding - Padding configuration
87
+ * @param width - Target width (for horizontal padding)
88
+ * @returns Padded text
89
+ */
90
+ export declare function applyPadding(text: string, padding: {
91
+ top: number;
92
+ right: number;
93
+ bottom: number;
94
+ left: number;
95
+ }, width: number): string;
96
+ /**
97
+ * Render a table using cli-table3
98
+ *
99
+ * @param columns - Column definitions
100
+ * @param rows - Data rows
101
+ * @param options - Render options
102
+ * @returns Rendered table string
103
+ */
104
+ export declare function renderTable(columns: TableColumn[], rows: Record<string, unknown>[], options?: RenderOptions): string;
105
+ /**
106
+ * Render a section with title and content
107
+ *
108
+ * @param title - Section title
109
+ * @param content - Section content (can be multi-line)
110
+ * @param options - Render options
111
+ * @returns Rendered section string
112
+ */
113
+ export declare function renderSection(title: string, content: string, options?: RenderOptions): string;
114
+ /**
115
+ * Distribute items evenly across multiple columns
116
+ *
117
+ * @param items - Array of items to distribute
118
+ * @param columnCount - Number of columns to create
119
+ * @returns Array of columns, each containing a subset of items
120
+ *
121
+ * @example
122
+ * distributeToColumns(['A', 'B', 'C', 'D', 'E', 'F'], 2)
123
+ * // Returns: [['A', 'B', 'C'], ['D', 'E', 'F']]
124
+ *
125
+ * distributeToColumns(['A', 'B', 'C', 'D', 'E'], 2)
126
+ * // Returns: [['A', 'B', 'C'], ['D', 'E']]
127
+ */
128
+ export declare function distributeToColumns<T>(items: T[], columnCount: number): T[][];
129
+ /**
130
+ * Render multiple columns of text side by side
131
+ *
132
+ * @param columns - Array of columns, each containing lines of text
133
+ * @param totalWidth - Total width available for all columns
134
+ * @param gap - Space between columns (default: 2)
135
+ * @returns Rendered multi-column text
136
+ *
137
+ * @example
138
+ * renderColumns([['Line 1', 'Line 2'], ['Col 2 Line 1', 'Col 2 Line 2']], 80, 2)
139
+ * // Returns text with two columns side by side
140
+ */
141
+ export declare function renderColumns(columns: string[][], totalWidth: number, gap?: number): string;
142
+ //# sourceMappingURL=layout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../src/utils/layout.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;CACrC;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,WAAW,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;IAC9C,OAAO,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CACxE;AAED;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAwB1D;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAE7F;AAED;;;;;;;;GAQG;AACH,wBAAgB,OAAO,CACrB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,KAAK,GAAE,MAAM,GAAG,QAAQ,GAAG,OAAgB,EAC3C,QAAQ,GAAE,MAAc,GACvB,MAAM,CAwCR;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,GAAE,MAAY,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAczF;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,KAAK,GAAE,MAAM,GAAG,QAAQ,GAAG,OAAkB,EAC7C,OAAO,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GACjD,MAAM,CAiBR;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EACrE,KAAK,EAAE,MAAM,GACZ,MAAM,CAuBR;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,WAAW,EAAE,EACtB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAC/B,OAAO,CAAC,EAAE,aAAa,GACtB,MAAM,CAkFR;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,aAAa,GACtB,MAAM,CAoDR;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,WAAW,EAAE,MAAM,GAAG,CAAC,EAAE,EAAE,CAoB7E;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,GAAE,MAAU,GAAG,MAAM,CAyB9F"}