linecraft 0.2.1 → 0.2.2
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/LICENSE +0 -1
- package/README.md +3 -1
- package/lib/component.d.ts +34 -0
- package/lib/component.d.ts.map +1 -0
- package/lib/component.js +42 -0
- package/lib/component.js.map +1 -0
- package/lib/components/code-debug.d.ts +35 -0
- package/lib/components/code-debug.d.ts.map +1 -0
- package/lib/components/code-debug.js +294 -0
- package/lib/components/code-debug.js.map +1 -0
- package/lib/components/fill.d.ts +15 -0
- package/lib/components/fill.d.ts.map +1 -0
- package/lib/components/fill.js +37 -0
- package/lib/components/fill.js.map +1 -0
- package/lib/components/index.d.ts +2 -2
- package/lib/components/index.d.ts.map +1 -1
- package/lib/components/index.js +2 -2
- package/lib/components/index.js.map +1 -1
- package/lib/components/progress-bar-grid.d.ts +1 -1
- package/lib/components/progress-bar-grid.d.ts.map +1 -1
- package/lib/components/progress-bar-grid.js +6 -6
- package/lib/components/progress-bar-grid.js.map +1 -1
- package/lib/components/prompt.d.ts +4 -5
- package/lib/components/prompt.d.ts.map +1 -1
- package/lib/components/prompt.js +17 -69
- package/lib/components/prompt.js.map +1 -1
- package/lib/components/section.d.ts +33 -0
- package/lib/components/section.d.ts.map +1 -0
- package/lib/components/section.js +178 -0
- package/lib/components/section.js.map +1 -0
- package/lib/components/segments.d.ts +26 -0
- package/lib/components/segments.d.ts.map +1 -0
- package/lib/components/segments.js +105 -0
- package/lib/components/segments.js.map +1 -0
- package/lib/components/spinner.d.ts +18 -16
- package/lib/components/spinner.d.ts.map +1 -1
- package/lib/components/spinner.js +63 -47
- package/lib/components/spinner.js.map +1 -1
- package/lib/components/style.test.js +11 -11
- package/lib/components/style.test.js.map +1 -1
- package/lib/components/styled.d.ts +17 -0
- package/lib/components/styled.d.ts.map +1 -0
- package/lib/components/styled.js +107 -0
- package/lib/components/styled.js.map +1 -0
- package/lib/components/styled.test.d.ts +2 -0
- package/lib/components/styled.test.d.ts.map +1 -0
- package/lib/components/styled.test.js +135 -0
- package/lib/components/styled.test.js.map +1 -0
- package/lib/index.d.ts +17 -13
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +13 -13
- package/lib/index.js.map +1 -1
- package/lib/index.test.js +17 -11
- package/lib/index.test.js.map +1 -1
- package/lib/layout/grid.d.ts +31 -35
- package/lib/layout/grid.d.ts.map +1 -1
- package/lib/layout/grid.js +437 -216
- package/lib/layout/grid.js.map +1 -1
- package/lib/layout/grid.test.js +332 -36
- package/lib/layout/grid.test.js.map +1 -1
- package/lib/native/ansi.d.ts +9 -0
- package/lib/native/ansi.d.ts.map +1 -1
- package/lib/native/ansi.js +9 -0
- package/lib/native/ansi.js.map +1 -1
- package/lib/native/diff.d.ts +5 -1
- package/lib/native/diff.d.ts.map +1 -1
- package/lib/native/diff.js +25 -7
- package/lib/native/diff.js.map +1 -1
- package/lib/native/region-renderer-debug.test.d.ts +2 -0
- package/lib/native/region-renderer-debug.test.d.ts.map +1 -0
- package/lib/native/region-renderer-debug.test.js +45 -0
- package/lib/native/region-renderer-debug.test.js.map +1 -0
- package/lib/native/region-renderer.d.ts +57 -148
- package/lib/native/region-renderer.d.ts.map +1 -1
- package/lib/native/region-renderer.js +455 -1124
- package/lib/native/region-renderer.js.map +1 -1
- package/lib/native/region.test.js +2 -20
- package/lib/native/region.test.js.map +1 -1
- package/lib/region-resize.test.d.ts +2 -0
- package/lib/region-resize.test.d.ts.map +1 -0
- package/lib/region-resize.test.js +124 -0
- package/lib/region-resize.test.js.map +1 -0
- package/lib/region.d.ts +97 -9
- package/lib/region.d.ts.map +1 -1
- package/lib/region.js +591 -185
- package/lib/region.js.map +1 -1
- package/lib/region.test.js +3 -3
- package/lib/region.test.js.map +1 -1
- package/lib/types.d.ts +9 -0
- package/lib/types.d.ts.map +1 -1
- package/lib/utils/file-link.d.ts +16 -0
- package/lib/utils/file-link.d.ts.map +1 -0
- package/lib/utils/file-link.js +23 -0
- package/lib/utils/file-link.js.map +1 -0
- package/lib/utils/prompt.d.ts +15 -0
- package/lib/utils/prompt.d.ts.map +1 -0
- package/lib/utils/prompt.js +128 -0
- package/lib/utils/prompt.js.map +1 -0
- package/lib/utils/terminal-theme.d.ts +36 -0
- package/lib/utils/terminal-theme.d.ts.map +1 -0
- package/lib/utils/terminal-theme.js +61 -0
- package/lib/utils/terminal-theme.js.map +1 -0
- package/lib/utils/text.d.ts +53 -3
- package/lib/utils/text.d.ts.map +1 -1
- package/lib/utils/text.js +194 -36
- package/lib/utils/text.js.map +1 -1
- package/lib/utils/wait-for-spacebar.d.ts.map +1 -1
- package/lib/utils/wait-for-spacebar.js +9 -6
- package/lib/utils/wait-for-spacebar.js.map +1 -1
- package/package.json +13 -13
package/lib/components/prompt.js
CHANGED
|
@@ -1,77 +1,25 @@
|
|
|
1
1
|
// Prompt component - improved API for prompts like "Press SPACEBAR"
|
|
2
|
-
import {
|
|
2
|
+
import { Styled } from './styled';
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Create a Prompt component that can be added to a region
|
|
5
|
+
* The component renders a blank line followed by the prompt message
|
|
6
6
|
*/
|
|
7
|
-
export
|
|
8
|
-
const { message, key = 'SPACEBAR', color: promptColor = 'brightBlack',
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
else {
|
|
17
|
-
// Add prompt above current content
|
|
18
|
-
// This would require shifting all content down, which is complex
|
|
19
|
-
// For now, just add below
|
|
20
|
-
region.setLine(currentHeight + 1, '');
|
|
21
|
-
region.setLine(currentHeight + 2, promptText);
|
|
22
|
-
}
|
|
23
|
-
region.flush();
|
|
24
|
-
// Wait for keypress
|
|
25
|
-
return new Promise((resolve) => {
|
|
26
|
-
const stdin = process.stdin;
|
|
27
|
-
if (!stdin.isTTY) {
|
|
28
|
-
resolve();
|
|
29
|
-
return;
|
|
7
|
+
export function Prompt(options) {
|
|
8
|
+
const { message, key = 'SPACEBAR', color: promptColor = 'brightBlack', } = options;
|
|
9
|
+
return (ctx) => {
|
|
10
|
+
const promptText = `Press ${key} to ${message}...`;
|
|
11
|
+
const styledComponent = Styled({ color: promptColor }, promptText);
|
|
12
|
+
const styledResult = styledComponent(ctx);
|
|
13
|
+
// Return blank line + prompt
|
|
14
|
+
if (typeof styledResult === 'string') {
|
|
15
|
+
return ['', styledResult];
|
|
30
16
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
rawMode = stdin.isRaw || false;
|
|
34
|
-
stdin.setRawMode(true);
|
|
35
|
-
stdin.resume();
|
|
36
|
-
stdin.setEncoding('utf8');
|
|
17
|
+
else if (Array.isArray(styledResult)) {
|
|
18
|
+
return ['', ...styledResult];
|
|
37
19
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
resolve();
|
|
41
|
-
return;
|
|
20
|
+
else {
|
|
21
|
+
return ['', promptText];
|
|
42
22
|
}
|
|
43
|
-
|
|
44
|
-
// Handle spacebar, enter, or 'q'
|
|
45
|
-
if (key === ' ' || key === '\r' || key === '\n' || key === 'q' || key === 'Q') {
|
|
46
|
-
cleanup();
|
|
47
|
-
resolve();
|
|
48
|
-
}
|
|
49
|
-
// Handle Ctrl+C
|
|
50
|
-
if (key === '\u0003') {
|
|
51
|
-
cleanup();
|
|
52
|
-
process.exit(0);
|
|
53
|
-
}
|
|
54
|
-
};
|
|
55
|
-
const onSIGINT = () => {
|
|
56
|
-
cleanup();
|
|
57
|
-
process.exit(0);
|
|
58
|
-
};
|
|
59
|
-
const cleanup = () => {
|
|
60
|
-
stdin.removeListener('data', onData);
|
|
61
|
-
// CRITICAL: Remove SIGINT listener to prevent memory leak
|
|
62
|
-
// Use removeListener instead of once to ensure we can clean it up
|
|
63
|
-
process.removeListener('SIGINT', onSIGINT);
|
|
64
|
-
try {
|
|
65
|
-
stdin.setRawMode(rawMode);
|
|
66
|
-
stdin.pause();
|
|
67
|
-
}
|
|
68
|
-
catch (err) {
|
|
69
|
-
// Ignore errors
|
|
70
|
-
}
|
|
71
|
-
};
|
|
72
|
-
stdin.on('data', onData);
|
|
73
|
-
// Use on() instead of once() so we can remove it in cleanup
|
|
74
|
-
process.on('SIGINT', onSIGINT);
|
|
75
|
-
});
|
|
23
|
+
};
|
|
76
24
|
}
|
|
77
25
|
//# sourceMappingURL=prompt.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompt.js","sourceRoot":"","sources":["../../src/components/prompt.ts"],"names":[],"mappings":"AAAA,oEAAoE;
|
|
1
|
+
{"version":3,"file":"prompt.js","sourceRoot":"","sources":["../../src/components/prompt.ts"],"names":[],"mappings":"AAAA,oEAAoE;AAKpE,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAQlC;;;GAGG;AACH,MAAM,UAAU,MAAM,CAAC,OAAsB;IAC3C,MAAM,EACJ,OAAO,EACP,GAAG,GAAG,UAAU,EAChB,KAAK,EAAE,WAAW,GAAG,aAAa,GACnC,GAAG,OAAO,CAAC;IAEZ,OAAO,CAAC,GAAG,EAAE,EAAE;QACb,MAAM,UAAU,GAAG,SAAS,GAAG,OAAO,OAAO,KAAK,CAAC;QACnD,MAAM,eAAe,GAAG,MAAM,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,UAAU,CAAC,CAAC;QACnE,MAAM,YAAY,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;QAE1C,6BAA6B;QAC7B,IAAI,OAAO,YAAY,KAAK,QAAQ,EAAE,CAAC;YACrC,OAAO,CAAC,EAAE,EAAE,YAAY,CAAC,CAAC;QAC5B,CAAC;aAAM,IAAI,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC;YACvC,OAAO,CAAC,EAAE,EAAE,GAAG,YAAY,CAAC,CAAC;QACjC,CAAC;aAAM,CAAC;YACJ,OAAO,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;QAC5B,CAAC;IACD,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Component } from '../component';
|
|
2
|
+
import type { Color } from '../types';
|
|
3
|
+
export interface SectionOptions {
|
|
4
|
+
title: string;
|
|
5
|
+
titleColor?: Color;
|
|
6
|
+
borderColor?: Color;
|
|
7
|
+
padding?: number;
|
|
8
|
+
left?: boolean;
|
|
9
|
+
right?: boolean;
|
|
10
|
+
top?: boolean;
|
|
11
|
+
bottom?: boolean;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Section component - wraps content in a box with a tabbed title
|
|
15
|
+
*
|
|
16
|
+
* The title appears in a "tab" at the top, and the content is wrapped in a box.
|
|
17
|
+
* Uses rounded corners (╭ ╮ ╰ ╯) for a clean look. You can control which borders
|
|
18
|
+
* are shown using `left`, `right`, `top`, and `bottom` options.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* // Default: all borders shown
|
|
22
|
+
* Section({ title: 'My Section' }, ...)
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* // Only left and right borders (no top/bottom)
|
|
26
|
+
* Section({ title: 'My Section', top: false, bottom: false }, ...)
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* // Only left border
|
|
30
|
+
* Section({ title: 'My Section', right: false, top: false, bottom: false }, ...)
|
|
31
|
+
*/
|
|
32
|
+
export declare function Section(options: SectionOptions, ...children: Component[]): Component;
|
|
33
|
+
//# sourceMappingURL=section.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"section.d.ts","sourceRoot":"","sources":["../../src/components/section.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAiB,SAAS,EAAE,MAAM,cAAc,CAAC;AAE7D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AAGtC,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,KAAK,CAAC;IACnB,WAAW,CAAC,EAAE,KAAK,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,OAAO,CACrB,OAAO,EAAE,cAAc,EACvB,GAAG,QAAQ,EAAE,SAAS,EAAE,GACvB,SAAS,CAyLX"}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
// Section component - wraps content in a box with a tabbed title
|
|
2
|
+
import { renderChildren } from '../component';
|
|
3
|
+
import { applyStyle } from '../utils/colors';
|
|
4
|
+
/**
|
|
5
|
+
* Section component - wraps content in a box with a tabbed title
|
|
6
|
+
*
|
|
7
|
+
* The title appears in a "tab" at the top, and the content is wrapped in a box.
|
|
8
|
+
* Uses rounded corners (╭ ╮ ╰ ╯) for a clean look. You can control which borders
|
|
9
|
+
* are shown using `left`, `right`, `top`, and `bottom` options.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* // Default: all borders shown
|
|
13
|
+
* Section({ title: 'My Section' }, ...)
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* // Only left and right borders (no top/bottom)
|
|
17
|
+
* Section({ title: 'My Section', top: false, bottom: false }, ...)
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* // Only left border
|
|
21
|
+
* Section({ title: 'My Section', right: false, top: false, bottom: false }, ...)
|
|
22
|
+
*/
|
|
23
|
+
export function Section(options, ...children) {
|
|
24
|
+
return (ctx) => {
|
|
25
|
+
const { title, titleColor = 'brightCyan', borderColor = 'brightBlack', padding = 1, left = true, right = true, top = true, bottom = true, } = options;
|
|
26
|
+
const availableWidth = ctx.availableWidth;
|
|
27
|
+
const titleText = ` ${title} `;
|
|
28
|
+
const titleWidth = titleText.length;
|
|
29
|
+
// Calculate box width (full available width)
|
|
30
|
+
const boxWidth = availableWidth;
|
|
31
|
+
// Calculate content width: subtract borders and padding
|
|
32
|
+
const borderWidth = (left ? 1 : 0) + (right ? 1 : 0);
|
|
33
|
+
const contentWidth = Math.max(0, boxWidth - borderWidth - (padding * 2));
|
|
34
|
+
// Render children - simple and clean!
|
|
35
|
+
const contentLines = renderChildren(children, {
|
|
36
|
+
...ctx,
|
|
37
|
+
availableWidth: contentWidth,
|
|
38
|
+
});
|
|
39
|
+
// Build the section with tab and box (even if empty)
|
|
40
|
+
const lines = [];
|
|
41
|
+
// Always use rounded corners when showing them
|
|
42
|
+
const topLeftChar = '╭';
|
|
43
|
+
const topRightChar = '╮';
|
|
44
|
+
const bottomLeftChar = '╰';
|
|
45
|
+
const bottomRightChar = '╯';
|
|
46
|
+
const tabHorizontal = applyStyle('─', { color: borderColor });
|
|
47
|
+
const vertical = applyStyle('│', { color: borderColor });
|
|
48
|
+
const paddingSpaces = ' '.repeat(padding);
|
|
49
|
+
// Top border/tab line: ╭─ Title ────────────────╮
|
|
50
|
+
if (top) {
|
|
51
|
+
const tabTitle = applyStyle(titleText, { color: titleColor });
|
|
52
|
+
let tabLine = '';
|
|
53
|
+
// Top-left corner: always shown when top line is visible (top is true here)
|
|
54
|
+
// Also shown if left border is visible
|
|
55
|
+
tabLine += applyStyle(topLeftChar, { color: borderColor });
|
|
56
|
+
// Title
|
|
57
|
+
tabLine += tabTitle;
|
|
58
|
+
// Horizontal line after title
|
|
59
|
+
const spaceAfterTitle = Math.max(0, boxWidth - titleWidth - 1 - 1); // minus both corners
|
|
60
|
+
tabLine += tabHorizontal.repeat(spaceAfterTitle);
|
|
61
|
+
// Top-right corner: always shown when top line is visible (top is true here)
|
|
62
|
+
// Also shown if right border is visible
|
|
63
|
+
tabLine += applyStyle(topRightChar, { color: borderColor });
|
|
64
|
+
lines.push(tabLine);
|
|
65
|
+
}
|
|
66
|
+
// Calculate which line is first and last (excluding top/bottom border lines)
|
|
67
|
+
const totalContentLines = padding + contentLines.length + padding;
|
|
68
|
+
let lineIndex = 0;
|
|
69
|
+
// Top padding: empty lines with borders
|
|
70
|
+
for (let i = 0; i < padding; i++) {
|
|
71
|
+
const isFirstLine = lineIndex === 0;
|
|
72
|
+
const isLastLine = lineIndex === totalContentLines - 1;
|
|
73
|
+
let line = '';
|
|
74
|
+
// Left border: show top-left corner on first line if left is visible (unless top already added it)
|
|
75
|
+
if (left && isFirstLine && !top) {
|
|
76
|
+
line += applyStyle(topLeftChar, { color: borderColor });
|
|
77
|
+
}
|
|
78
|
+
else if (left && isLastLine && !bottom) {
|
|
79
|
+
// Left border: show bottom-left corner on last line if left is visible (unless bottom already added it)
|
|
80
|
+
line += applyStyle(bottomLeftChar, { color: borderColor });
|
|
81
|
+
}
|
|
82
|
+
else if (left) {
|
|
83
|
+
line += vertical;
|
|
84
|
+
}
|
|
85
|
+
line += paddingSpaces + ' '.repeat(contentWidth) + paddingSpaces;
|
|
86
|
+
// Right border: show top-right corner on first line if right is visible (unless top already added it)
|
|
87
|
+
if (right && isFirstLine && !top) {
|
|
88
|
+
line += applyStyle(topRightChar, { color: borderColor });
|
|
89
|
+
}
|
|
90
|
+
else if (right && isLastLine && !bottom) {
|
|
91
|
+
// Right border: show bottom-right corner on last line if right is visible (unless bottom already added it)
|
|
92
|
+
line += applyStyle(bottomRightChar, { color: borderColor });
|
|
93
|
+
}
|
|
94
|
+
else if (right) {
|
|
95
|
+
line += vertical;
|
|
96
|
+
}
|
|
97
|
+
lines.push(line);
|
|
98
|
+
lineIndex++;
|
|
99
|
+
}
|
|
100
|
+
// Content lines - children already know their available width
|
|
101
|
+
for (let i = 0; i < contentLines.length; i++) {
|
|
102
|
+
const isFirstLine = lineIndex === 0;
|
|
103
|
+
const isLastLine = lineIndex === totalContentLines - 1;
|
|
104
|
+
const contentLine = contentLines[i];
|
|
105
|
+
let line = '';
|
|
106
|
+
// Left border: show top-left corner on first line if left is visible (unless top already added it)
|
|
107
|
+
if (left && isFirstLine && !top) {
|
|
108
|
+
line += applyStyle(topLeftChar, { color: borderColor });
|
|
109
|
+
}
|
|
110
|
+
else if (left && isLastLine && !bottom) {
|
|
111
|
+
// Left border: show bottom-left corner on last line if left is visible (unless bottom already added it)
|
|
112
|
+
line += applyStyle(bottomLeftChar, { color: borderColor });
|
|
113
|
+
}
|
|
114
|
+
else if (left) {
|
|
115
|
+
line += vertical;
|
|
116
|
+
}
|
|
117
|
+
line += paddingSpaces + contentLine + paddingSpaces;
|
|
118
|
+
// Right border: show top-right corner on first line if right is visible (unless top already added it)
|
|
119
|
+
if (right && isFirstLine && !top) {
|
|
120
|
+
line += applyStyle(topRightChar, { color: borderColor });
|
|
121
|
+
}
|
|
122
|
+
else if (right && isLastLine && !bottom) {
|
|
123
|
+
// Right border: show bottom-right corner on last line if right is visible (unless bottom already added it)
|
|
124
|
+
line += applyStyle(bottomRightChar, { color: borderColor });
|
|
125
|
+
}
|
|
126
|
+
else if (right) {
|
|
127
|
+
line += vertical;
|
|
128
|
+
}
|
|
129
|
+
lines.push(line);
|
|
130
|
+
lineIndex++;
|
|
131
|
+
}
|
|
132
|
+
// Bottom padding: empty lines with borders
|
|
133
|
+
for (let i = 0; i < padding; i++) {
|
|
134
|
+
const isFirstLine = lineIndex === 0;
|
|
135
|
+
const isLastLine = lineIndex === totalContentLines - 1;
|
|
136
|
+
let line = '';
|
|
137
|
+
// Left border: show top-left corner on first line if left is visible (unless top already added it)
|
|
138
|
+
if (left && isFirstLine && !top) {
|
|
139
|
+
line += applyStyle(topLeftChar, { color: borderColor });
|
|
140
|
+
}
|
|
141
|
+
else if (left && isLastLine && !bottom) {
|
|
142
|
+
// Left border: show bottom-left corner on last line if left is visible (unless bottom already added it)
|
|
143
|
+
line += applyStyle(bottomLeftChar, { color: borderColor });
|
|
144
|
+
}
|
|
145
|
+
else if (left) {
|
|
146
|
+
line += vertical;
|
|
147
|
+
}
|
|
148
|
+
line += paddingSpaces + ' '.repeat(contentWidth) + paddingSpaces;
|
|
149
|
+
// Right border: show top-right corner on first line if right is visible (unless top already added it)
|
|
150
|
+
if (right && isFirstLine && !top) {
|
|
151
|
+
line += applyStyle(topRightChar, { color: borderColor });
|
|
152
|
+
}
|
|
153
|
+
else if (right && isLastLine && !bottom) {
|
|
154
|
+
// Right border: show bottom-right corner on last line if right is visible (unless bottom already added it)
|
|
155
|
+
line += applyStyle(bottomRightChar, { color: borderColor });
|
|
156
|
+
}
|
|
157
|
+
else if (right) {
|
|
158
|
+
line += vertical;
|
|
159
|
+
}
|
|
160
|
+
lines.push(line);
|
|
161
|
+
lineIndex++;
|
|
162
|
+
}
|
|
163
|
+
// Bottom border: ╰───────────────────────╯
|
|
164
|
+
if (bottom) {
|
|
165
|
+
let bottomLine = '';
|
|
166
|
+
// Bottom-left corner: always shown when bottom line is visible
|
|
167
|
+
bottomLine += applyStyle(bottomLeftChar, { color: borderColor });
|
|
168
|
+
// Horizontal line
|
|
169
|
+
const horizontalWidth = Math.max(0, boxWidth - 1 - 1); // minus both corners
|
|
170
|
+
bottomLine += tabHorizontal.repeat(horizontalWidth);
|
|
171
|
+
// Bottom-right corner: always shown when bottom line is visible
|
|
172
|
+
bottomLine += applyStyle(bottomRightChar, { color: borderColor });
|
|
173
|
+
lines.push(bottomLine);
|
|
174
|
+
}
|
|
175
|
+
return lines;
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=section.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"section.js","sourceRoot":"","sources":["../../src/components/section.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Component } from '../component';
|
|
2
|
+
import type { Color } from '../types';
|
|
3
|
+
export type BorderStyle = 'cap' | 'capHalf' | 'brace' | 'dot' | 'asterisk';
|
|
4
|
+
export interface Segment {
|
|
5
|
+
content: string;
|
|
6
|
+
color?: Color;
|
|
7
|
+
borderStyle?: BorderStyle;
|
|
8
|
+
}
|
|
9
|
+
export interface SegmentsOptions {
|
|
10
|
+
segments: Segment[];
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Segments component - renders decorated segments with automatic dividers
|
|
14
|
+
*
|
|
15
|
+
* Segments are decorated with borders/symbols on the default terminal background,
|
|
16
|
+
* and automatically connected with dash dividers (─). Content is automatically padded.
|
|
17
|
+
*
|
|
18
|
+
* Simple API:
|
|
19
|
+
* - content: Text content (padding added automatically)
|
|
20
|
+
* - color: Text color (borders use same color)
|
|
21
|
+
* - borderStyle: Border decoration style (default: 'cap')
|
|
22
|
+
*
|
|
23
|
+
* Border styles: 'cap' (default), 'capHalf', 'brace', 'dot', 'asterisk'
|
|
24
|
+
*/
|
|
25
|
+
export declare function Segments(options: SegmentsOptions): Component;
|
|
26
|
+
//# sourceMappingURL=segments.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"segments.d.ts","sourceRoot":"","sources":["../../src/components/segments.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAiB,SAAS,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AAKtC,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,SAAS,GAAG,OAAO,GAAG,KAAK,GAAG,UAAU,CAAC;AAE3E,MAAM,WAAW,OAAO;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB;AAiCD;;;;;;;;;;;;GAYG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,SAAS,CAkE5D"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
// Segments component - OhMyZsh/Powerline-style colored segments with angled dividers
|
|
2
|
+
import { applyStyle } from '../utils/colors';
|
|
3
|
+
import { truncateToWidth } from '../utils/text';
|
|
4
|
+
/**
|
|
5
|
+
* Get border characters for segment decoration
|
|
6
|
+
* Creates borders around segments on default terminal background
|
|
7
|
+
*/
|
|
8
|
+
function getBorderChars(style) {
|
|
9
|
+
switch (style) {
|
|
10
|
+
case 'cap':
|
|
11
|
+
// Half-filled circles - the favorite!
|
|
12
|
+
// ◐ (U+25D0) = Circle with left half black
|
|
13
|
+
// ◑ (U+25D1) = Circle with right half black
|
|
14
|
+
return { left: '◐', right: '◑' };
|
|
15
|
+
case 'capHalf':
|
|
16
|
+
// Upper half circles - mirrored to face the text
|
|
17
|
+
// ◖ (U+25D6) = Upper half circle (left)
|
|
18
|
+
// ◗ (U+25D7) = Lower half circle (right, creates mirror effect)
|
|
19
|
+
return { left: '◖', right: '◗' };
|
|
20
|
+
case 'brace':
|
|
21
|
+
// Curly braces - classic and clean
|
|
22
|
+
return { left: '{', right: '}' };
|
|
23
|
+
case 'dot':
|
|
24
|
+
// Small dot/point
|
|
25
|
+
// · (U+00B7) = Middle dot (smaller, lighter)
|
|
26
|
+
return { left: '·', right: '·' };
|
|
27
|
+
case 'asterisk':
|
|
28
|
+
// Asterisk/star points
|
|
29
|
+
// * (U+002A) = Asterisk
|
|
30
|
+
return { left: '*', right: '*' };
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Segments component - renders decorated segments with automatic dividers
|
|
35
|
+
*
|
|
36
|
+
* Segments are decorated with borders/symbols on the default terminal background,
|
|
37
|
+
* and automatically connected with dash dividers (─). Content is automatically padded.
|
|
38
|
+
*
|
|
39
|
+
* Simple API:
|
|
40
|
+
* - content: Text content (padding added automatically)
|
|
41
|
+
* - color: Text color (borders use same color)
|
|
42
|
+
* - borderStyle: Border decoration style (default: 'cap')
|
|
43
|
+
*
|
|
44
|
+
* Border styles: 'cap' (default), 'capHalf', 'brace', 'dot', 'asterisk'
|
|
45
|
+
*/
|
|
46
|
+
export function Segments(options) {
|
|
47
|
+
return (ctx) => {
|
|
48
|
+
const { segments } = options;
|
|
49
|
+
if (segments.length === 0) {
|
|
50
|
+
return '';
|
|
51
|
+
}
|
|
52
|
+
const availableWidth = ctx.availableWidth;
|
|
53
|
+
let result = '';
|
|
54
|
+
let usedWidth = 0;
|
|
55
|
+
for (let i = 0; i < segments.length; i++) {
|
|
56
|
+
const segment = segments[i];
|
|
57
|
+
const nextSegment = i < segments.length - 1 ? segments[i + 1] : null;
|
|
58
|
+
// Left divider (automatic - dash for middle segments)
|
|
59
|
+
if (i > 0) {
|
|
60
|
+
// Always use dash (─) for dividers - it works well with all border styles
|
|
61
|
+
const dividerColor = 'brightBlack';
|
|
62
|
+
const styledDivider = applyStyle('─', { color: dividerColor });
|
|
63
|
+
result += styledDivider;
|
|
64
|
+
usedWidth += 1;
|
|
65
|
+
}
|
|
66
|
+
// Left border decoration
|
|
67
|
+
const borderStyle = segment.borderStyle ?? 'cap';
|
|
68
|
+
const borderChars = getBorderChars(borderStyle);
|
|
69
|
+
if (borderChars.left) {
|
|
70
|
+
// Auto-theme: borders use text color
|
|
71
|
+
const borderColor = segment.color ?? 'brightCyan';
|
|
72
|
+
result += applyStyle(borderChars.left, { color: borderColor });
|
|
73
|
+
usedWidth += 1;
|
|
74
|
+
}
|
|
75
|
+
// Segment content with automatic padding (no background, just text color)
|
|
76
|
+
// Trim content and add padding automatically
|
|
77
|
+
const trimmedContent = segment.content.trim();
|
|
78
|
+
const paddedContent = ` ${trimmedContent} `;
|
|
79
|
+
const styledContent = applyStyle(paddedContent, {
|
|
80
|
+
color: segment.color,
|
|
81
|
+
// No backgroundColor - uses default terminal background
|
|
82
|
+
});
|
|
83
|
+
result += styledContent;
|
|
84
|
+
usedWidth += paddedContent.length;
|
|
85
|
+
// Right border decoration
|
|
86
|
+
if (borderChars.right) {
|
|
87
|
+
// Auto-theme: borders use text color
|
|
88
|
+
const borderColor = segment.color ?? 'brightCyan';
|
|
89
|
+
result += applyStyle(borderChars.right, { color: borderColor });
|
|
90
|
+
usedWidth += 1;
|
|
91
|
+
}
|
|
92
|
+
// Right divider (automatic - dash for middle segments)
|
|
93
|
+
if (i < segments.length - 1) {
|
|
94
|
+
// Always use dash (─) for dividers - it works well with all border styles
|
|
95
|
+
const dividerColor = 'brightBlack';
|
|
96
|
+
const styledDivider = applyStyle('─', { color: dividerColor });
|
|
97
|
+
result += styledDivider;
|
|
98
|
+
usedWidth += 1;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
// Truncate if needed (preserving ANSI codes)
|
|
102
|
+
return truncateToWidth(result, availableWidth);
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=segments.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"segments.js","sourceRoot":"","sources":["../../src/components/segments.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,18 +1,20 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type {
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
private frames;
|
|
11
|
-
private intervalMs;
|
|
12
|
-
constructor(region: TerminalRegion, lineNumber: number, options?: SpinnerOptions);
|
|
13
|
-
start(): void;
|
|
14
|
-
stop(): void;
|
|
15
|
-
setText(text: string): void;
|
|
16
|
-
private render;
|
|
1
|
+
import type { Component } from '../component';
|
|
2
|
+
import type { Color } from '../types';
|
|
3
|
+
export type SpinnerStyle = 'classic-dots' | 'bouncing-bar';
|
|
4
|
+
export interface SpinnerOptions {
|
|
5
|
+
style?: SpinnerStyle;
|
|
6
|
+
frames?: string[];
|
|
7
|
+
interval?: number;
|
|
8
|
+
color?: Color;
|
|
9
|
+
autoStart?: boolean;
|
|
17
10
|
}
|
|
11
|
+
/**
|
|
12
|
+
* Create a spinner component that manages its own animation state
|
|
13
|
+
* Returns an object with render(), start(), and stop() methods
|
|
14
|
+
*/
|
|
15
|
+
export declare function Spinner(options?: SpinnerOptions): {
|
|
16
|
+
render: Component;
|
|
17
|
+
start: () => void;
|
|
18
|
+
stop: () => void;
|
|
19
|
+
};
|
|
18
20
|
//# sourceMappingURL=spinner.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spinner.d.ts","sourceRoot":"","sources":["../../src/components/spinner.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"spinner.d.ts","sourceRoot":"","sources":["../../src/components/spinner.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAiB,MAAM,cAAc,CAAC;AAC7D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AAGtC,MAAM,MAAM,YAAY,GAAG,cAAc,GAAG,cAAc,CAAC;AAE3D,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAQD;;;GAGG;AACH,wBAAgB,OAAO,CAAC,OAAO,GAAE,cAAmB,GAAG;IACrD,MAAM,EAAE,SAAS,CAAC;IAClB,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,IAAI,EAAE,MAAM,IAAI,CAAC;CAClB,CAoEA"}
|
|
@@ -1,50 +1,66 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
//
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
stop() {
|
|
29
|
-
if (!this.isRunning)
|
|
30
|
-
return;
|
|
31
|
-
this.isRunning = false;
|
|
32
|
-
if (this.interval) {
|
|
33
|
-
clearInterval(this.interval);
|
|
1
|
+
// Spinner component - manages its own animation state
|
|
2
|
+
import { applyStyle } from '../utils/colors';
|
|
3
|
+
// Built-in spinner frame definitions
|
|
4
|
+
const SPINNER_FRAMES = {
|
|
5
|
+
'classic-dots': ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'], // Clockwise rotation with 3 connected dots
|
|
6
|
+
'bouncing-bar': ['▁', '▂', '▃', '▄', '▅', '▆', '▇', '█', '▇', '▆', '▅', '▄', '▃', '▂'],
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Create a spinner component that manages its own animation state
|
|
10
|
+
* Returns an object with render(), start(), and stop() methods
|
|
11
|
+
*/
|
|
12
|
+
export function Spinner(options = {}) {
|
|
13
|
+
const { style, frames, interval = 80, color = 'yellow', autoStart = true, } = options;
|
|
14
|
+
// Determine which frames to use: custom frames override style
|
|
15
|
+
const finalFrames = frames ?? (style ? SPINNER_FRAMES[style] : ['⠇', '⠋', '⠙', '⠴', '⠋', '⠙', '⠸', '⠴', '⠦']);
|
|
16
|
+
let currentFrameIndex = 0;
|
|
17
|
+
let intervalId = null;
|
|
18
|
+
let onUpdateCallback = null;
|
|
19
|
+
let cleanupRegistered = false;
|
|
20
|
+
const render = (ctx) => {
|
|
21
|
+
// Store the onUpdate callback from context (set by region)
|
|
22
|
+
if (ctx.onUpdate && !onUpdateCallback) {
|
|
23
|
+
onUpdateCallback = ctx.onUpdate;
|
|
24
|
+
// Start automatically if enabled and callback is available
|
|
25
|
+
if (autoStart) {
|
|
26
|
+
start();
|
|
27
|
+
}
|
|
34
28
|
}
|
|
35
|
-
//
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
29
|
+
// Register cleanup callback to stop the interval when component is removed (only once)
|
|
30
|
+
if (ctx.onCleanup && !cleanupRegistered) {
|
|
31
|
+
cleanupRegistered = true;
|
|
32
|
+
ctx.onCleanup(() => {
|
|
33
|
+
stop();
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
const frame = finalFrames[currentFrameIndex];
|
|
37
|
+
if (color) {
|
|
38
|
+
return applyStyle(frame, { color });
|
|
39
|
+
}
|
|
40
|
+
return frame;
|
|
41
|
+
};
|
|
42
|
+
const start = () => {
|
|
43
|
+
if (intervalId !== null) {
|
|
44
|
+
return; // Already running
|
|
45
|
+
}
|
|
46
|
+
intervalId = setInterval(() => {
|
|
47
|
+
currentFrameIndex = (currentFrameIndex + 1) % finalFrames.length;
|
|
48
|
+
// Trigger re-render using the callback from RenderContext
|
|
49
|
+
if (onUpdateCallback) {
|
|
50
|
+
onUpdateCallback();
|
|
51
|
+
}
|
|
52
|
+
}, interval);
|
|
53
|
+
};
|
|
54
|
+
const stop = () => {
|
|
55
|
+
if (intervalId !== null) {
|
|
56
|
+
clearInterval(intervalId);
|
|
57
|
+
intervalId = null;
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
return {
|
|
61
|
+
render,
|
|
62
|
+
start,
|
|
63
|
+
stop,
|
|
64
|
+
};
|
|
49
65
|
}
|
|
50
66
|
//# sourceMappingURL=spinner.js.map
|