linecraft 0.1.0 → 0.2.1

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 (283) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +337 -64
  3. package/lib/api/color.d.ts +6 -0
  4. package/lib/api/color.d.ts.map +1 -0
  5. package/lib/api/color.js +9 -0
  6. package/lib/api/color.js.map +1 -0
  7. package/lib/api/color.test.d.ts +2 -0
  8. package/lib/api/color.test.d.ts.map +1 -0
  9. package/lib/api/color.test.js +23 -0
  10. package/lib/api/color.test.js.map +1 -0
  11. package/lib/api/flex.d.ts +55 -0
  12. package/lib/api/flex.d.ts.map +1 -0
  13. package/lib/api/flex.js +86 -0
  14. package/lib/api/flex.js.map +1 -0
  15. package/lib/api/flex.test.d.ts +2 -0
  16. package/lib/api/flex.test.d.ts.map +1 -0
  17. package/lib/api/flex.test.js +82 -0
  18. package/lib/api/flex.test.js.map +1 -0
  19. package/lib/api/grid.d.ts +22 -0
  20. package/lib/api/grid.d.ts.map +1 -0
  21. package/lib/api/grid.js +65 -0
  22. package/lib/api/grid.js.map +1 -0
  23. package/lib/api/grid.test.d.ts +2 -0
  24. package/lib/api/grid.test.d.ts.map +1 -0
  25. package/lib/api/grid.test.js +48 -0
  26. package/lib/api/grid.test.js.map +1 -0
  27. package/lib/components/base.d.ts +53 -0
  28. package/lib/components/base.d.ts.map +1 -0
  29. package/lib/components/base.js +47 -0
  30. package/lib/components/base.js.map +1 -0
  31. package/lib/components/col.d.ts +35 -0
  32. package/lib/components/col.d.ts.map +1 -0
  33. package/lib/components/col.js +168 -0
  34. package/lib/components/col.js.map +1 -0
  35. package/lib/components/col.test.d.ts +2 -0
  36. package/lib/components/col.test.d.ts.map +1 -0
  37. package/lib/components/col.test.js +96 -0
  38. package/lib/components/col.test.js.map +1 -0
  39. package/lib/components/index.d.ts +3 -0
  40. package/lib/components/index.d.ts.map +1 -0
  41. package/lib/components/index.js +5 -0
  42. package/lib/components/index.js.map +1 -0
  43. package/lib/components/progress-bar-grid.d.ts +20 -0
  44. package/lib/components/progress-bar-grid.d.ts.map +1 -0
  45. package/lib/components/progress-bar-grid.js +44 -0
  46. package/lib/components/progress-bar-grid.js.map +1 -0
  47. package/lib/components/progress-bar-grid.test.d.ts +2 -0
  48. package/lib/components/progress-bar-grid.test.d.ts.map +1 -0
  49. package/lib/components/progress-bar-grid.test.js +101 -0
  50. package/lib/components/progress-bar-grid.test.js.map +1 -0
  51. package/lib/components/progress-bar.d.ts +26 -3
  52. package/lib/components/progress-bar.d.ts.map +1 -1
  53. package/lib/components/progress-bar.js +62 -6
  54. package/lib/components/progress-bar.js.map +1 -1
  55. package/lib/components/progress-bar.test.d.ts +2 -0
  56. package/lib/components/progress-bar.test.d.ts.map +1 -0
  57. package/lib/components/progress-bar.test.js +153 -0
  58. package/lib/components/progress-bar.test.js.map +1 -0
  59. package/lib/components/prompt.d.ts +14 -0
  60. package/lib/components/prompt.d.ts.map +1 -0
  61. package/lib/components/prompt.js +77 -0
  62. package/lib/components/prompt.js.map +1 -0
  63. package/lib/components/renderable.d.ts +42 -0
  64. package/lib/components/renderable.d.ts.map +1 -0
  65. package/lib/components/renderable.js +225 -0
  66. package/lib/components/renderable.js.map +1 -0
  67. package/lib/components/spinner.d.ts +2 -2
  68. package/lib/components/spinner.d.ts.map +1 -1
  69. package/lib/components/spinner.js +3 -1
  70. package/lib/components/spinner.js.map +1 -1
  71. package/lib/components/spinner.test.d.ts +2 -0
  72. package/lib/components/spinner.test.d.ts.map +1 -0
  73. package/lib/components/spinner.test.js +168 -0
  74. package/lib/components/spinner.test.js.map +1 -0
  75. package/lib/components/style.d.ts +16 -0
  76. package/lib/components/style.d.ts.map +1 -0
  77. package/lib/components/style.js +72 -0
  78. package/lib/components/style.js.map +1 -0
  79. package/lib/components/style.test.d.ts +2 -0
  80. package/lib/components/style.test.d.ts.map +1 -0
  81. package/lib/components/style.test.js +135 -0
  82. package/lib/components/style.test.js.map +1 -0
  83. package/lib/components/text.d.ts +24 -0
  84. package/lib/components/text.d.ts.map +1 -0
  85. package/lib/components/text.js +65 -0
  86. package/lib/components/text.js.map +1 -0
  87. package/lib/drawing/boxes.d.ts +33 -0
  88. package/lib/drawing/boxes.d.ts.map +1 -0
  89. package/lib/drawing/boxes.js +76 -0
  90. package/lib/drawing/boxes.js.map +1 -0
  91. package/lib/index.d.ts +18 -11
  92. package/lib/index.d.ts.map +1 -1
  93. package/lib/index.js +21 -10
  94. package/lib/index.js.map +1 -1
  95. package/lib/index.test.d.ts +2 -0
  96. package/lib/index.test.d.ts.map +1 -0
  97. package/lib/index.test.js +80 -0
  98. package/lib/index.test.js.map +1 -0
  99. package/lib/layout/flex.d.ts +39 -0
  100. package/lib/layout/flex.d.ts.map +1 -0
  101. package/lib/layout/flex.js +300 -0
  102. package/lib/layout/flex.js.map +1 -0
  103. package/lib/layout/flex.test.d.ts +2 -0
  104. package/lib/layout/flex.test.d.ts.map +1 -0
  105. package/lib/layout/flex.test.js +206 -0
  106. package/lib/layout/flex.test.js.map +1 -0
  107. package/lib/layout/grid.d.ts +53 -0
  108. package/lib/layout/grid.d.ts.map +1 -0
  109. package/lib/layout/grid.js +421 -0
  110. package/lib/layout/grid.js.map +1 -0
  111. package/lib/layout/grid.test.d.ts +2 -0
  112. package/lib/layout/grid.test.d.ts.map +1 -0
  113. package/lib/layout/grid.test.js +139 -0
  114. package/lib/layout/grid.test.js.map +1 -0
  115. package/lib/native/ansi.d.ts +104 -0
  116. package/lib/native/ansi.d.ts.map +1 -0
  117. package/lib/native/ansi.js +120 -0
  118. package/lib/native/ansi.js.map +1 -0
  119. package/lib/native/ansi.test.d.ts +2 -0
  120. package/lib/native/ansi.test.d.ts.map +1 -0
  121. package/lib/native/ansi.test.js +57 -0
  122. package/lib/native/ansi.test.js.map +1 -0
  123. package/lib/native/buffer.d.ts +32 -0
  124. package/lib/native/buffer.d.ts.map +1 -0
  125. package/lib/native/buffer.js +49 -0
  126. package/lib/native/buffer.js.map +1 -0
  127. package/lib/native/buffer.test.d.ts +2 -0
  128. package/lib/native/buffer.test.d.ts.map +1 -0
  129. package/lib/native/buffer.test.js +64 -0
  130. package/lib/native/buffer.test.js.map +1 -0
  131. package/lib/native/diff.d.ts +20 -0
  132. package/lib/native/diff.d.ts.map +1 -0
  133. package/lib/native/diff.js +33 -0
  134. package/lib/native/diff.js.map +1 -0
  135. package/lib/native/diff.test.d.ts +2 -0
  136. package/lib/native/diff.test.d.ts.map +1 -0
  137. package/lib/native/diff.test.js +106 -0
  138. package/lib/native/diff.test.js.map +1 -0
  139. package/lib/native/region-old.d.ts +117 -0
  140. package/lib/native/region-old.d.ts.map +1 -0
  141. package/lib/native/region-old.js +539 -0
  142. package/lib/native/region-old.js.map +1 -0
  143. package/lib/native/region-renderer.d.ts +167 -0
  144. package/lib/native/region-renderer.d.ts.map +1 -0
  145. package/lib/native/region-renderer.js +1238 -0
  146. package/lib/native/region-renderer.js.map +1 -0
  147. package/lib/native/region-simple.d.ts +44 -0
  148. package/lib/native/region-simple.d.ts.map +1 -0
  149. package/lib/native/region-simple.js +290 -0
  150. package/lib/native/region-simple.js.map +1 -0
  151. package/lib/native/region.d.ts +53 -0
  152. package/lib/native/region.d.ts.map +1 -0
  153. package/lib/native/region.js +426 -0
  154. package/lib/native/region.js.map +1 -0
  155. package/lib/native/region.test.d.ts +2 -0
  156. package/lib/native/region.test.d.ts.map +1 -0
  157. package/lib/native/region.test.js +248 -0
  158. package/lib/native/region.test.js.map +1 -0
  159. package/lib/native/throttle.d.ts +29 -0
  160. package/lib/native/throttle.d.ts.map +1 -0
  161. package/lib/native/throttle.js +57 -0
  162. package/lib/native/throttle.js.map +1 -0
  163. package/lib/native/throttle.test.d.ts +2 -0
  164. package/lib/native/throttle.test.d.ts.map +1 -0
  165. package/lib/native/throttle.test.js +86 -0
  166. package/lib/native/throttle.test.js.map +1 -0
  167. package/lib/native.d.ts +5 -11
  168. package/lib/native.d.ts.map +1 -1
  169. package/lib/native.js +8 -64
  170. package/lib/native.js.map +1 -1
  171. package/lib/region.d.ts +48 -5
  172. package/lib/region.d.ts.map +1 -1
  173. package/lib/region.js +474 -36
  174. package/lib/region.js.map +1 -1
  175. package/lib/region.test.d.ts +2 -0
  176. package/lib/region.test.d.ts.map +1 -0
  177. package/lib/region.test.js +227 -0
  178. package/lib/region.test.js.map +1 -0
  179. package/lib/region.visual.test.d.ts +2 -0
  180. package/lib/region.visual.test.d.ts.map +1 -0
  181. package/lib/region.visual.test.js +55 -0
  182. package/lib/region.visual.test.js.map +1 -0
  183. package/lib/test-helpers/capturable-terminal.d.ts +61 -0
  184. package/lib/test-helpers/capturable-terminal.d.ts.map +1 -0
  185. package/lib/test-helpers/capturable-terminal.js +113 -0
  186. package/lib/test-helpers/capturable-terminal.js.map +1 -0
  187. package/lib/test-helpers/capturable-terminal.test.d.ts +2 -0
  188. package/lib/test-helpers/capturable-terminal.test.d.ts.map +1 -0
  189. package/lib/test-helpers/capturable-terminal.test.js +45 -0
  190. package/lib/test-helpers/capturable-terminal.test.js.map +1 -0
  191. package/lib/test-helpers/mock-region.d.ts +21 -0
  192. package/lib/test-helpers/mock-region.d.ts.map +1 -0
  193. package/lib/test-helpers/mock-region.js +37 -0
  194. package/lib/test-helpers/mock-region.js.map +1 -0
  195. package/lib/test-helpers/virtual-terminal-diff-reflow.test.d.ts +2 -0
  196. package/lib/test-helpers/virtual-terminal-diff-reflow.test.d.ts.map +1 -0
  197. package/lib/test-helpers/virtual-terminal-diff-reflow.test.js +256 -0
  198. package/lib/test-helpers/virtual-terminal-diff-reflow.test.js.map +1 -0
  199. package/lib/test-helpers/virtual-terminal-flex-resize.test.d.ts +2 -0
  200. package/lib/test-helpers/virtual-terminal-flex-resize.test.d.ts.map +1 -0
  201. package/lib/test-helpers/virtual-terminal-flex-resize.test.js +438 -0
  202. package/lib/test-helpers/virtual-terminal-flex-resize.test.js.map +1 -0
  203. package/lib/test-helpers/virtual-terminal.d.ts +176 -0
  204. package/lib/test-helpers/virtual-terminal.d.ts.map +1 -0
  205. package/lib/test-helpers/virtual-terminal.js +492 -0
  206. package/lib/test-helpers/virtual-terminal.js.map +1 -0
  207. package/lib/test-helpers/virtual-terminal.test.d.ts +2 -0
  208. package/lib/test-helpers/virtual-terminal.test.d.ts.map +1 -0
  209. package/lib/test-helpers/virtual-terminal.test.js +219 -0
  210. package/lib/test-helpers/virtual-terminal.test.js.map +1 -0
  211. package/lib/ts/components/spinner.test.d.ts +2 -0
  212. package/lib/ts/components/spinner.test.d.ts.map +1 -0
  213. package/lib/ts/components/spinner.test.js +168 -0
  214. package/lib/ts/components/spinner.test.js.map +1 -0
  215. package/lib/ts/utils/colors.test.d.ts +2 -0
  216. package/lib/ts/utils/colors.test.d.ts.map +1 -0
  217. package/lib/ts/utils/colors.test.js +87 -0
  218. package/lib/ts/utils/colors.test.js.map +1 -0
  219. package/lib/types.d.ts +8 -2
  220. package/lib/types.d.ts.map +1 -1
  221. package/lib/types.js.map +1 -1
  222. package/lib/utils/colors-simple.d.ts +51 -0
  223. package/lib/utils/colors-simple.d.ts.map +1 -0
  224. package/lib/utils/colors-simple.js +59 -0
  225. package/lib/utils/colors-simple.js.map +1 -0
  226. package/lib/utils/colors.d.ts +1 -1
  227. package/lib/utils/colors.d.ts.map +1 -1
  228. package/lib/utils/colors.js.map +1 -1
  229. package/lib/utils/colors.test.d.ts +2 -0
  230. package/lib/utils/colors.test.d.ts.map +1 -0
  231. package/lib/utils/colors.test.js +87 -0
  232. package/lib/utils/colors.test.js.map +1 -0
  233. package/lib/utils/cursor-position.d.ts +22 -0
  234. package/lib/utils/cursor-position.d.ts.map +1 -0
  235. package/lib/utils/cursor-position.js +139 -0
  236. package/lib/utils/cursor-position.js.map +1 -0
  237. package/lib/utils/debug-log.d.ts +2 -0
  238. package/lib/utils/debug-log.d.ts.map +1 -0
  239. package/lib/utils/debug-log.js +36 -0
  240. package/lib/utils/debug-log.js.map +1 -0
  241. package/lib/utils/terminal.d.ts +27 -0
  242. package/lib/utils/terminal.d.ts.map +1 -0
  243. package/lib/utils/terminal.js +116 -0
  244. package/lib/utils/terminal.js.map +1 -0
  245. package/lib/utils/text.d.ts +21 -0
  246. package/lib/utils/text.d.ts.map +1 -0
  247. package/lib/utils/text.js +82 -0
  248. package/lib/utils/text.js.map +1 -0
  249. package/lib/utils/wait-for-spacebar.d.ts +10 -0
  250. package/lib/utils/wait-for-spacebar.d.ts.map +1 -0
  251. package/lib/utils/wait-for-spacebar.js +71 -0
  252. package/lib/utils/wait-for-spacebar.js.map +1 -0
  253. package/package.json +35 -28
  254. package/.cursor/plan.md +0 -952
  255. package/TESTING.md +0 -102
  256. package/build.zig +0 -100
  257. package/examples/basic-progress.ts +0 -21
  258. package/examples/multi-lane.ts +0 -29
  259. package/examples/spinner.ts +0 -20
  260. package/examples/test-basic.ts +0 -23
  261. package/src/ts/components/progress-bar.ts +0 -53
  262. package/src/ts/components/spinner.ts +0 -56
  263. package/src/ts/index.ts +0 -37
  264. package/src/ts/native.ts +0 -86
  265. package/src/ts/region.ts +0 -89
  266. package/src/ts/types/ffi-napi.d.ts +0 -11
  267. package/src/ts/types/ref-napi.d.ts +0 -5
  268. package/src/ts/types.ts +0 -53
  269. package/src/ts/utils/colors.ts +0 -72
  270. package/src/zig/ansi.zig +0 -21
  271. package/src/zig/buffer.zig +0 -37
  272. package/src/zig/diff.zig +0 -43
  273. package/src/zig/region.zig +0 -292
  274. package/src/zig/renderer.zig +0 -92
  275. package/src/zig/test_ansi.zig +0 -66
  276. package/src/zig/test_buffer.zig +0 -82
  277. package/src/zig/test_diff.zig +0 -220
  278. package/src/zig/test_integration.zig +0 -76
  279. package/src/zig/test_region.zig +0 -191
  280. package/src/zig/test_runner.zig +0 -27
  281. package/src/zig/test_throttle.zig +0 -59
  282. package/src/zig/throttle.zig +0 -38
  283. package/tsconfig.json +0 -21
@@ -0,0 +1,96 @@
1
+ import { describe, it, expect, beforeEach, vi } from 'vitest';
2
+ import { Col } from './col.js';
3
+ describe('Col', () => {
4
+ let region;
5
+ let setLineSpy;
6
+ beforeEach(() => {
7
+ setLineSpy = vi.fn();
8
+ const lines = new Map();
9
+ region = {
10
+ setLine: (line, content) => {
11
+ lines.set(line, content);
12
+ setLineSpy(line, content);
13
+ },
14
+ getLine: (line) => lines.get(line) || '',
15
+ width: 80,
16
+ };
17
+ });
18
+ describe('constructor', () => {
19
+ it('should create a column with default options', () => {
20
+ const col = new Col(region, 'Hello');
21
+ expect(col.getPreferredWidth()).toBe(5);
22
+ expect(col.getHeight()).toBe(1);
23
+ });
24
+ it('should handle flex option', () => {
25
+ const col = new Col(region, 'Hello', { flex: 2 });
26
+ expect(col.flexGrow).toBe(2);
27
+ });
28
+ it('should handle min option', () => {
29
+ const col = new Col(region, 'Hello', { min: 10 });
30
+ expect(col.getMinWidth()).toBe(10);
31
+ });
32
+ it('should handle max option', () => {
33
+ const col = new Col(region, 'Hello', { max: 5 });
34
+ expect(col.getMaxWidth()).toBe(5);
35
+ });
36
+ it('should default min to content width', () => {
37
+ const col = new Col(region, 'Hello World');
38
+ expect(col.getMinWidth()).toBe(11); // "Hello World".length
39
+ });
40
+ it('should strip ANSI codes when calculating width', () => {
41
+ const col = new Col(region, '\x1b[31mHello\x1b[0m');
42
+ expect(col.getPreferredWidth()).toBe(5); // Just "Hello"
43
+ expect(col.getMinWidth()).toBe(5);
44
+ });
45
+ });
46
+ describe('overflow handling', () => {
47
+ it('should truncate with ellipsis-end by default', () => {
48
+ const col = new Col(region, 'Very long text that exceeds width', { max: 10 });
49
+ col.render(0, 1, 10);
50
+ expect(setLineSpy).toHaveBeenCalledWith(1, expect.stringMatching(/\.\.\./));
51
+ });
52
+ it('should truncate with ellipsis-start', () => {
53
+ const col = new Col(region, 'Very long text', { max: 10, overflow: 'ellipsis-start' });
54
+ col.render(0, 1, 10);
55
+ const call = setLineSpy.mock.calls[0];
56
+ expect(call[1]).toMatch(/^\.\.\./);
57
+ });
58
+ it('should truncate with ellipsis-middle', () => {
59
+ const col = new Col(region, 'Very long text', { max: 10, overflow: 'ellipsis-middle' });
60
+ col.render(0, 1, 10);
61
+ const call = setLineSpy.mock.calls[0];
62
+ expect(call[1]).toMatch(/\.\.\./);
63
+ // Should have text on both sides
64
+ expect(call[1].indexOf('...')).toBeGreaterThan(0);
65
+ expect(call[1].indexOf('...')).toBeLessThan(call[1].length - 3);
66
+ });
67
+ it('should wrap text when overflow is wrap', () => {
68
+ const col = new Col(region, 'Very long text that wraps', { overflow: 'wrap' });
69
+ // getHeight() for wrap needs width, but width is only available during render
70
+ // Without width, it defaults to contentWidth, which may not wrap
71
+ // So we test that render actually wraps correctly
72
+ col.render(0, 1, 10);
73
+ // Should render multiple lines for wrapped text
74
+ expect(setLineSpy).toHaveBeenCalledTimes(3); // "Very long ", "text that ", "wraps"
75
+ });
76
+ it('should not truncate when overflow is none', () => {
77
+ const col = new Col(region, 'Very long text', { max: 10, overflow: 'none' });
78
+ col.render(0, 1, 10);
79
+ const call = setLineSpy.mock.calls[0];
80
+ expect(call[1]).not.toMatch(/\.\.\./);
81
+ });
82
+ });
83
+ describe('render', () => {
84
+ it('should pad text to width', () => {
85
+ const col = new Col(region, 'Hi');
86
+ col.render(0, 1, 10);
87
+ expect(setLineSpy).toHaveBeenCalledWith(1, expect.stringMatching(/^Hi\s{8}$/));
88
+ });
89
+ it('should handle exact width match', () => {
90
+ const col = new Col(region, 'Hello');
91
+ col.render(0, 1, 5);
92
+ expect(setLineSpy).toHaveBeenCalledWith(1, 'Hello');
93
+ });
94
+ });
95
+ });
96
+ //# sourceMappingURL=col.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"col.test.js","sourceRoot":"","sources":["../../src/ts/components/col.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export { Spinner } from './spinner';
2
+ export { showPrompt } from './prompt';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC"}
@@ -0,0 +1,5 @@
1
+ // Component helpers and utilities
2
+ // Re-export component classes and functions
3
+ export { Spinner } from './spinner';
4
+ export { showPrompt } from './prompt';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,kCAAkC;AAElC,4CAA4C;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC"}
@@ -0,0 +1,20 @@
1
+ import type { Component } from '../layout/grid';
2
+ import type { Color } from '../types';
3
+ export interface ProgressBarOptions {
4
+ current: number;
5
+ total: number;
6
+ label?: string;
7
+ labelColor?: Color;
8
+ barColor?: Color;
9
+ bracketColor?: Color;
10
+ percentColor?: Color;
11
+ completeChar?: string;
12
+ incompleteChar?: string;
13
+ brackets?: [string, string];
14
+ }
15
+ /**
16
+ * Create a progress bar component using grid
17
+ * Uses grid internally to layout: [bracket] [bar (flex)] [bracket] [percent]
18
+ */
19
+ export declare function progressBar(options: ProgressBarOptions): Component;
20
+ //# sourceMappingURL=progress-bar-grid.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"progress-bar-grid.d.ts","sourceRoot":"","sources":["../../src/components/progress-bar-grid.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAiB,MAAM,gBAAgB,CAAC;AAC/D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AAKtC,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,KAAK,CAAC;IACnB,QAAQ,CAAC,EAAE,KAAK,CAAC;IACjB,YAAY,CAAC,EAAE,KAAK,CAAC;IACrB,YAAY,CAAC,EAAE,KAAK,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC7B;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,SAAS,CA0ClE"}
@@ -0,0 +1,44 @@
1
+ // Progress bar component using grid system
2
+ import { style } from './style';
3
+ import { grid as gridComponent } from '../layout/grid';
4
+ import { applyStyle } from '../utils/colors';
5
+ /**
6
+ * Create a progress bar component using grid
7
+ * Uses grid internally to layout: [bracket] [bar (flex)] [bracket] [percent]
8
+ */
9
+ export function progressBar(options) {
10
+ return (ctx) => {
11
+ const percent = Math.min(100, Math.max(0, (options.current / options.total) * 100));
12
+ const completeChar = options.completeChar ?? '━';
13
+ const incompleteChar = options.incompleteChar ?? '─';
14
+ const leftBracket = options.brackets?.[0] ?? '\u263E'; // ☾
15
+ const rightBracket = options.brackets?.[1] ?? '\u263D'; // ☽
16
+ const bracketColor = options.bracketColor ?? 'brightBlack';
17
+ // Use grid to layout: left bracket (1), bar (flex), right bracket (1), percent (6)
18
+ // The bar column will receive its allocated width and calculate fill based on that
19
+ const barComponent = (barCtx) => {
20
+ // Calculate bar based on allocated width (minus padding spaces)
21
+ const availableBarWidth = Math.max(0, barCtx.availableWidth - 2); // minus padding spaces
22
+ const filled = Math.floor((percent / 100) * availableBarWidth);
23
+ const empty = availableBarWidth - filled;
24
+ const filledBar = completeChar.repeat(filled);
25
+ const emptyBar = incompleteChar.repeat(empty);
26
+ const barText = ' ' +
27
+ (options.barColor ? applyStyle(filledBar, { color: options.barColor }) : filledBar) +
28
+ applyStyle(emptyBar, { color: 'brightBlack' }) +
29
+ ' ';
30
+ return barText;
31
+ };
32
+ // Build grid children
33
+ const children = [
34
+ style({ color: bracketColor }, leftBracket),
35
+ barComponent,
36
+ style({ color: bracketColor }, rightBracket),
37
+ style({ color: options.percentColor ?? 'brightBlack' }, percent.toFixed(1) + '%'),
38
+ ];
39
+ // Use grid to layout: [1] [flex] [1] [7]
40
+ const gridComp = gridComponent({ template: [1, '1*', 1, 7], columnGap: 0 }, ...children);
41
+ return gridComp(ctx);
42
+ };
43
+ }
44
+ //# sourceMappingURL=progress-bar-grid.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"progress-bar-grid.js","sourceRoot":"","sources":["../../src/components/progress-bar-grid.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAI3C,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,IAAI,IAAI,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAe7C;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,OAA2B;IACrD,OAAO,CAAC,GAAkB,EAAE,EAAE;QAC5B,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;QAEpF,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,IAAI,GAAG,CAAC;QACjD,MAAM,cAAc,GAAG,OAAO,CAAC,cAAc,IAAI,GAAG,CAAC;QACrD,MAAM,WAAW,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC,CAAC,IAAI;QAC3D,MAAM,YAAY,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC,CAAC,IAAI;QAE5D,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,IAAI,aAAa,CAAC;QAE3D,mFAAmF;QACnF,mFAAmF;QACnF,MAAM,YAAY,GAAG,CAAC,MAAqB,EAAU,EAAE;YACrD,gEAAgE;YAChE,MAAM,iBAAiB,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,cAAc,GAAG,CAAC,CAAC,CAAC,CAAC,uBAAuB;YACzF,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,GAAG,GAAG,CAAC,GAAG,iBAAiB,CAAC,CAAC;YAC/D,MAAM,KAAK,GAAG,iBAAiB,GAAG,MAAM,CAAC;YAEzC,MAAM,SAAS,GAAG,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAC9C,MAAM,QAAQ,GAAG,cAAc,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAE9C,MAAM,OAAO,GAAG,GAAG;gBACjB,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;gBACnF,UAAU,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC;gBAC9C,GAAG,CAAC;YAEN,OAAO,OAAO,CAAC;QACjB,CAAC,CAAC;QAEF,sBAAsB;QACtB,MAAM,QAAQ,GAAG;YACf,KAAK,CAAC,EAAE,KAAK,EAAE,YAAY,EAAE,EAAE,WAAW,CAAC;YAC3C,YAAY;YACZ,KAAK,CAAC,EAAE,KAAK,EAAE,YAAY,EAAE,EAAE,YAAY,CAAC;YAC5C,KAAK,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,YAAY,IAAI,aAAa,EAAE,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC;SAClF,CAAC;QAEF,yCAAyC;QACzC,MAAM,QAAQ,GAAG,aAAa,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,EAAE,GAAG,QAAQ,CAAC,CAAC;QACzF,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC;IACvB,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=progress-bar-grid.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"progress-bar-grid.test.d.ts","sourceRoot":"","sources":["../../src/components/progress-bar-grid.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,101 @@
1
+ import { describe, it, expect, beforeEach } from 'vitest';
2
+ import { progressBar } from './progress-bar-grid';
3
+ import { TerminalRegion } from '../region';
4
+ describe('ProgressBar (Grid)', () => {
5
+ let region;
6
+ beforeEach(() => {
7
+ region = new TerminalRegion({ disableRendering: true, width: 80 });
8
+ });
9
+ it('should create a progress bar component', () => {
10
+ const component = progressBar({
11
+ current: 50,
12
+ total: 100,
13
+ });
14
+ expect(typeof component).toBe('function');
15
+ const result = component({
16
+ availableWidth: 80,
17
+ region: region,
18
+ columnIndex: 0,
19
+ rowIndex: 0,
20
+ });
21
+ expect(result).toBeTruthy();
22
+ expect(typeof result === 'string').toBe(true);
23
+ });
24
+ it('should render progress bar with brackets and percent', () => {
25
+ const component = progressBar({
26
+ current: 50,
27
+ total: 100,
28
+ });
29
+ const result = component({
30
+ availableWidth: 80,
31
+ region: region,
32
+ columnIndex: 0,
33
+ rowIndex: 0,
34
+ });
35
+ const plain = result.replace(/\x1b\[[0-9;]*m/g, '');
36
+ expect(plain).toContain('☾');
37
+ expect(plain).toContain('☽');
38
+ expect(plain).toContain('50.0%');
39
+ });
40
+ it('should calculate bar fill correctly', () => {
41
+ const component = progressBar({
42
+ current: 25,
43
+ total: 100,
44
+ });
45
+ const result = component({
46
+ availableWidth: 80,
47
+ region: region,
48
+ columnIndex: 0,
49
+ rowIndex: 0,
50
+ });
51
+ const plain = result.replace(/\x1b\[[0-9;]*m/g, '');
52
+ expect(plain).toContain('25.0%');
53
+ });
54
+ it('should use custom colors', () => {
55
+ const component = progressBar({
56
+ current: 50,
57
+ total: 100,
58
+ barColor: 'green',
59
+ bracketColor: 'brightBlack',
60
+ percentColor: 'yellow',
61
+ });
62
+ const result = component({
63
+ availableWidth: 80,
64
+ region: region,
65
+ columnIndex: 0,
66
+ rowIndex: 0,
67
+ });
68
+ expect(result).toContain('\x1b[32m'); // green
69
+ expect(result).toContain('\x1b[33m'); // yellow
70
+ });
71
+ it('should handle 0% progress', () => {
72
+ const component = progressBar({
73
+ current: 0,
74
+ total: 100,
75
+ });
76
+ const result = component({
77
+ availableWidth: 80,
78
+ region: region,
79
+ columnIndex: 0,
80
+ rowIndex: 0,
81
+ });
82
+ const plain = result.replace(/\x1b\[[0-9;]*m/g, '');
83
+ expect(plain).toContain('0.0%');
84
+ });
85
+ it('should handle 100% progress', () => {
86
+ const component = progressBar({
87
+ current: 100,
88
+ total: 100,
89
+ });
90
+ const result = component({
91
+ availableWidth: 80,
92
+ region: region,
93
+ columnIndex: 0,
94
+ rowIndex: 0,
95
+ });
96
+ const plain = result.replace(/\x1b\[[0-9;]*m/g, '');
97
+ // Check for 100.0% or just 100% (depending on formatting)
98
+ expect(plain).toMatch(/100\.?0?%/);
99
+ });
100
+ });
101
+ //# sourceMappingURL=progress-bar-grid.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"progress-bar-grid.test.js","sourceRoot":"","sources":["../../src/components/progress-bar-grid.test.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,28 @@
1
- import { TerminalRegion } from '../region.js';
2
- import type { ProgressBarOptions } from '../types.js';
1
+ import type { TerminalRegion } from '../region.js';
2
+ import type { Renderable } from './renderable.js';
3
+ import type { Color } from '../types.js';
4
+ export interface ProgressBarComponentOptions {
5
+ current: number;
6
+ total: number;
7
+ label?: string;
8
+ width?: number;
9
+ labelColor?: Color;
10
+ barColor?: Color;
11
+ bracketColor?: Color;
12
+ percentColor?: Color;
13
+ completeChar?: string;
14
+ incompleteChar?: string;
15
+ brackets?: [string, string];
16
+ flex?: number;
17
+ flexGrow?: number;
18
+ flexShrink?: number;
19
+ minWidth?: number;
20
+ maxWidth?: number;
21
+ }
22
+ /**
23
+ * Create a progress bar component - just composes flex/col components
24
+ */
25
+ export declare function createProgressBar(region: TerminalRegion, options: ProgressBarComponentOptions): Renderable;
3
26
  export declare class ProgressBar {
4
27
  private region;
5
28
  private lineNumber;
@@ -10,7 +33,7 @@ export declare class ProgressBar {
10
33
  private completeChar;
11
34
  private incompleteChar;
12
35
  private brackets;
13
- constructor(region: TerminalRegion, lineNumber: number, options?: ProgressBarOptions);
36
+ constructor(region: TerminalRegion, lineNumber: number, options?: any);
14
37
  update(current: number, total: number): void;
15
38
  setLabel(label: string): void;
16
39
  private render;
@@ -1 +1 @@
1
- {"version":3,"file":"progress-bar.d.ts","sourceRoot":"","sources":["../../src/ts/components/progress-bar.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEtD,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,OAAO,CAAa;IAC5B,OAAO,CAAC,KAAK,CAAe;IAC5B,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAmB;gBAEvB,MAAM,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,GAAE,kBAAuB;IAUxF,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAM5C,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAK7B,OAAO,CAAC,MAAM;IAad,MAAM,IAAI,IAAI;CAGf"}
1
+ {"version":3,"file":"progress-bar.d.ts","sourceRoot":"","sources":["../../src/ts/components/progress-bar.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAIlD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEzC,MAAM,WAAW,2BAA2B;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,KAAK,CAAC;IACnB,QAAQ,CAAC,EAAE,KAAK,CAAC;IACjB,YAAY,CAAC,EAAE,KAAK,CAAC;IACrB,YAAY,CAAC,EAAE,KAAK,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,cAAc,EACtB,OAAO,EAAE,2BAA2B,GACnC,UAAU,CA4DZ;AAGD,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,OAAO,CAAa;IAC5B,OAAO,CAAC,KAAK,CAAe;IAC5B,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAmB;gBAEvB,MAAM,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,GAAE,GAAQ;IAUzE,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAM5C,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAK7B,OAAO,CAAC,MAAM;IAWd,MAAM,IAAI,IAAI;CAGf"}
@@ -1,3 +1,61 @@
1
+ import { flex, col, resolveFlexTree } from '../api/flex.js';
2
+ import { createCol } from './col.js';
3
+ import { color } from '../api/color.js';
4
+ /**
5
+ * Create a progress bar component - just composes flex/col components
6
+ */
7
+ export function createProgressBar(region, options) {
8
+ const percent = Math.min(100, Math.max(0, (options.current / options.total) * 100));
9
+ const barWidth = options.width ?? 40;
10
+ const filled = Math.floor((percent / 100) * barWidth);
11
+ const empty = barWidth - filled;
12
+ const completeChar = options.completeChar ?? '━';
13
+ const incompleteChar = options.incompleteChar ?? '─';
14
+ const leftBracket = options.brackets?.[0] ?? '\u2282';
15
+ const rightBracket = options.brackets?.[1] ?? '\u2283';
16
+ const bracketColor = options.bracketColor ?? 'brightBlack';
17
+ const children = [];
18
+ if (options.label) {
19
+ const labelColor = options.labelColor ?? 'white';
20
+ children.push(col({ width: options.label.length + 1 }, color(labelColor, options.label)));
21
+ }
22
+ children.push(col({ width: 1 }, color(bracketColor, leftBracket)));
23
+ // Bar column - calculates bar width dynamically based on available space
24
+ const barCol = {
25
+ flexGrow: 1,
26
+ flexShrink: 1,
27
+ getPreferredWidth: () => barWidth + 2,
28
+ getMinWidth: () => 0,
29
+ getMaxWidth: () => Infinity,
30
+ getHeight: () => 1,
31
+ render: (x, y, width) => {
32
+ // Calculate bar based on actual available width (minus spaces)
33
+ const availableBarWidth = Math.max(0, width - 2);
34
+ const actualFilled = Math.floor((percent / 100) * availableBarWidth);
35
+ const actualEmpty = availableBarWidth - actualFilled;
36
+ const actualFilledBar = completeChar.repeat(actualFilled);
37
+ const actualEmptyBar = incompleteChar.repeat(actualEmpty);
38
+ const barContent = ' ' + (options.barColor ? color(options.barColor, actualFilledBar) : actualFilledBar) + color('brightBlack', actualEmptyBar) + ' ';
39
+ createCol(region, barContent, { overflow: 'none' }).render(x, y, width);
40
+ },
41
+ };
42
+ children.push(barCol);
43
+ children.push(col({ width: 1 }, color(bracketColor, rightBracket)));
44
+ // Percentage column needs fixed width to prevent truncation when terminal is narrow
45
+ children.push(col({ width: 6 }, color(options.percentColor ?? 'brightBlack', percent.toFixed(1) + '%')));
46
+ const flexComponent = resolveFlexTree(region, flex({ gap: 0 }, ...children));
47
+ const flexGrow = options.flex ?? options.flexGrow ?? 0;
48
+ return {
49
+ flexGrow,
50
+ flexShrink: options.flexShrink ?? 1,
51
+ getPreferredWidth: () => flexComponent.getPreferredWidth(),
52
+ getMinWidth: () => options.minWidth ?? flexComponent.getMinWidth(),
53
+ getMaxWidth: () => options.maxWidth ?? flexComponent.getMaxWidth(),
54
+ getHeight: () => flexComponent.getHeight(),
55
+ render: (x, y, width) => flexComponent.render(x, y, width),
56
+ };
57
+ }
58
+ // Keep old ProgressBar class for backward compatibility (used in tests and createProgressBar)
1
59
  export class ProgressBar {
2
60
  region;
3
61
  lineNumber; // 1-based
@@ -13,9 +71,9 @@ export class ProgressBar {
13
71
  this.lineNumber = lineNumber;
14
72
  this.label = options.label || '';
15
73
  this.width = options.width ?? 40;
16
- this.completeChar = options.style?.complete ?? '';
17
- this.incompleteChar = options.style?.incomplete ?? '';
18
- this.brackets = options.style?.brackets ?? ['[', ']'];
74
+ this.completeChar = options.style?.complete ?? '';
75
+ this.incompleteChar = options.style?.incomplete ?? '';
76
+ this.brackets = options.style?.brackets ?? ['\u2282', '\u2283']; // ⊂ ⊃
19
77
  }
20
78
  update(current, total) {
21
79
  this.current = current;
@@ -31,10 +89,8 @@ export class ProgressBar {
31
89
  const filled = Math.floor((percentage / 100) * this.width);
32
90
  const empty = this.width - filled;
33
91
  const bar = this.completeChar.repeat(filled) + this.incompleteChar.repeat(empty);
34
- const text = `${this.label} ${this.brackets[0]}${bar}${this.brackets[1]} ${percentage.toFixed(1)}%`;
35
- // Just update the line - Zig handles batching and rendering
92
+ const text = `${this.label} ${this.brackets[0]} ${bar} ${this.brackets[1]} ${percentage.toFixed(1)}%`;
36
93
  this.region.setLine(this.lineNumber, text);
37
- // Optional: call flush() if you need immediate rendering
38
94
  }
39
95
  finish() {
40
96
  this.update(this.total, this.total);
@@ -1 +1 @@
1
- {"version":3,"file":"progress-bar.js","sourceRoot":"","sources":["../../src/ts/components/progress-bar.ts"],"names":[],"mappings":"AAGA,MAAM,OAAO,WAAW;IACd,MAAM,CAAiB;IACvB,UAAU,CAAS,CAAC,UAAU;IAC9B,OAAO,GAAW,CAAC,CAAC;IACpB,KAAK,GAAW,GAAG,CAAC;IACpB,KAAK,CAAS;IACd,KAAK,CAAS;IACd,YAAY,CAAS;IACrB,cAAc,CAAS;IACvB,QAAQ,CAAmB;IAEnC,YAAY,MAAsB,EAAE,UAAkB,EAAE,UAA8B,EAAE;QACtF,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC;QACjC,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC;QACjC,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC,KAAK,EAAE,QAAQ,IAAI,GAAG,CAAC;QACnD,IAAI,CAAC,cAAc,GAAG,OAAO,CAAC,KAAK,EAAE,UAAU,IAAI,GAAG,CAAC;QACvD,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,KAAK,EAAE,QAAQ,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IACxD,CAAC;IAED,MAAM,CAAC,OAAe,EAAE,KAAa;QACnC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,MAAM,EAAE,CAAC;IAChB,CAAC;IAED,QAAQ,CAAC,KAAa;QACpB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,MAAM,EAAE,CAAC;IAChB,CAAC;IAEO,MAAM;QACZ,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;QACjF,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,UAAU,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;QAC3D,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC;QAElC,MAAM,GAAG,GAAG,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACjF,MAAM,IAAI,GAAG,GAAG,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;QAEpG,4DAA4D;QAC5D,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;QAC3C,yDAAyD;IAC3D,CAAC;IAED,MAAM;QACJ,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;IACtC,CAAC;CACF"}
1
+ {"version":3,"file":"progress-bar.js","sourceRoot":"","sources":["../../src/ts/components/progress-bar.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=progress-bar.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"progress-bar.test.d.ts","sourceRoot":"","sources":["../../src/ts/components/progress-bar.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,153 @@
1
+ import { describe, it, expect, beforeEach, vi } from 'vitest';
2
+ import { ProgressBar } from './progress-bar.js';
3
+ // Mock the region
4
+ const createMockRegion = () => {
5
+ const setLineMock = vi.fn();
6
+ const mockRegion = {
7
+ setLine: setLineMock,
8
+ };
9
+ return { region: mockRegion, setLineMock };
10
+ };
11
+ describe('ProgressBar', () => {
12
+ let region;
13
+ let setLineMock;
14
+ let progressBar;
15
+ beforeEach(() => {
16
+ const mock = createMockRegion();
17
+ region = mock.region;
18
+ setLineMock = mock.setLineMock;
19
+ });
20
+ describe('constructor', () => {
21
+ it('should create a progress bar with default options', () => {
22
+ progressBar = new ProgressBar(region, 1);
23
+ expect(progressBar).toBeDefined();
24
+ });
25
+ it('should create a progress bar with custom options', () => {
26
+ progressBar = new ProgressBar(region, 2, {
27
+ label: 'Loading',
28
+ width: 50,
29
+ style: {
30
+ complete: '=',
31
+ incomplete: '-',
32
+ brackets: ['<', '>'],
33
+ },
34
+ });
35
+ expect(progressBar).toBeDefined();
36
+ });
37
+ it('should use default values for missing options', () => {
38
+ progressBar = new ProgressBar(region, 1, { label: 'Test' });
39
+ expect(progressBar).toBeDefined();
40
+ });
41
+ });
42
+ describe('update', () => {
43
+ it('should update progress and render', () => {
44
+ progressBar = new ProgressBar(region, 1, { label: 'Test', width: 20 });
45
+ progressBar.update(50, 100);
46
+ expect(setLineMock).toHaveBeenCalled();
47
+ const call = setLineMock.mock.calls[0];
48
+ expect(call[0]).toBe(1);
49
+ const content = typeof call[1] === 'string' ? call[1] : call[1].text;
50
+ expect(content).toContain('Test');
51
+ expect(content).toContain('50.0%');
52
+ });
53
+ it('should handle 0% progress', () => {
54
+ progressBar = new ProgressBar(region, 1, { width: 20 });
55
+ progressBar.update(0, 100);
56
+ const call = setLineMock.mock.calls[0];
57
+ const content = typeof call[1] === 'string' ? call[1] : call[1].text;
58
+ expect(content).toContain('0.0%');
59
+ });
60
+ it('should handle 100% progress', () => {
61
+ progressBar = new ProgressBar(region, 1, { width: 20 });
62
+ progressBar.update(100, 100);
63
+ const call = setLineMock.mock.calls[0];
64
+ const content = typeof call[1] === 'string' ? call[1] : call[1].text;
65
+ expect(content).toContain('100.0%');
66
+ });
67
+ it('should clamp progress above 100%', () => {
68
+ progressBar = new ProgressBar(region, 1, { width: 20 });
69
+ progressBar.update(150, 100);
70
+ const call = setLineMock.mock.calls[0];
71
+ const content = typeof call[1] === 'string' ? call[1] : call[1].text;
72
+ expect(content).toContain('100.0%');
73
+ });
74
+ it('should clamp progress below 0%', () => {
75
+ progressBar = new ProgressBar(region, 1, { width: 20 });
76
+ progressBar.update(-10, 100);
77
+ const call = setLineMock.mock.calls[0];
78
+ const content = typeof call[1] === 'string' ? call[1] : call[1].text;
79
+ expect(content).toContain('0.0%');
80
+ });
81
+ it('should calculate correct bar fill', () => {
82
+ progressBar = new ProgressBar(region, 1, { width: 10 });
83
+ progressBar.update(5, 10);
84
+ const call = setLineMock.mock.calls[0];
85
+ const barText = typeof call[1] === 'string' ? call[1] : call[1].text;
86
+ // New format uses ☾ ━━━━━ ───── ☽ (moon brackets facing each other, ━ for filled, ─ for empty)
87
+ // Extract the bar part (between brackets with padding)
88
+ // Format: "label ☾ bar ☽ percentage%"
89
+ const barMatch = barText.match(/☾ (.*) ☽/);
90
+ const barContent = barMatch ? barMatch[1] : '';
91
+ const completeCount = (barContent.match(/━/g) || []).length;
92
+ const incompleteCount = (barContent.match(/─/g) || []).length;
93
+ expect(completeCount).toBe(5);
94
+ expect(incompleteCount).toBe(5);
95
+ });
96
+ });
97
+ describe('setLabel', () => {
98
+ it('should update label and re-render', () => {
99
+ progressBar = new ProgressBar(region, 1, { label: 'Initial', width: 20 });
100
+ progressBar.update(50, 100);
101
+ progressBar.setLabel('Updated');
102
+ expect(setLineMock).toHaveBeenCalledTimes(2);
103
+ const lastCall = setLineMock.mock.calls[1];
104
+ const content = typeof lastCall[1] === 'string' ? lastCall[1] : lastCall[1].text;
105
+ expect(content).toContain('Updated');
106
+ });
107
+ });
108
+ describe('finish', () => {
109
+ it('should set progress to 100%', () => {
110
+ progressBar = new ProgressBar(region, 1, { width: 20 });
111
+ progressBar.update(30, 100);
112
+ progressBar.finish();
113
+ const calls = setLineMock.mock.calls;
114
+ const lastCall = calls[calls.length - 1];
115
+ const content = typeof lastCall[1] === 'string' ? lastCall[1] : lastCall[1].text;
116
+ expect(content).toContain('100.0%');
117
+ });
118
+ });
119
+ describe('custom styles', () => {
120
+ it('should use custom complete and incomplete characters', () => {
121
+ progressBar = new ProgressBar(region, 1, {
122
+ width: 10,
123
+ style: {
124
+ complete: '=',
125
+ incomplete: '-',
126
+ },
127
+ });
128
+ progressBar.update(5, 10);
129
+ const call = setLineMock.mock.calls[0];
130
+ const content = typeof call[1] === 'string' ? call[1] : call[1].text;
131
+ expect(content).toContain('=');
132
+ expect(content).toContain('-');
133
+ expect(content).not.toContain('━'); // Should not contain default thick line
134
+ expect(content).not.toContain('─'); // Should not contain default thin line
135
+ });
136
+ it('should use custom brackets', () => {
137
+ progressBar = new ProgressBar(region, 1, {
138
+ width: 10,
139
+ style: {
140
+ brackets: ['<', '>'],
141
+ },
142
+ });
143
+ progressBar.update(5, 10);
144
+ const call = setLineMock.mock.calls[0];
145
+ const content = typeof call[1] === 'string' ? call[1] : call[1].text;
146
+ expect(content).toContain('<');
147
+ expect(content).toContain('>');
148
+ expect(content).not.toContain('\u263D'); // ☽
149
+ expect(content).not.toContain('\u263E'); // ☾
150
+ });
151
+ });
152
+ });
153
+ //# sourceMappingURL=progress-bar.test.js.map