termcast 1.4.1 → 1.5.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.
Files changed (140) hide show
  1. package/dist/build.d.ts.map +1 -1
  2. package/dist/build.js +8 -7
  3. package/dist/build.js.map +1 -1
  4. package/dist/cli.js +0 -40
  5. package/dist/cli.js.map +1 -1
  6. package/dist/components/bar-graph.d.ts +23 -8
  7. package/dist/components/bar-graph.d.ts.map +1 -1
  8. package/dist/components/bar-graph.js +84 -40
  9. package/dist/components/bar-graph.js.map +1 -1
  10. package/dist/components/dotted-line-graph.d.ts +86 -0
  11. package/dist/components/dotted-line-graph.d.ts.map +1 -0
  12. package/dist/components/dotted-line-graph.js +260 -0
  13. package/dist/components/dotted-line-graph.js.map +1 -0
  14. package/dist/components/extension-preferences.d.ts.map +1 -1
  15. package/dist/components/extension-preferences.js +1 -10
  16. package/dist/components/extension-preferences.js.map +1 -1
  17. package/dist/components/graph.d.ts.map +1 -1
  18. package/dist/components/graph.js +7 -1
  19. package/dist/components/graph.js.map +1 -1
  20. package/dist/components/histogram.d.ts +42 -0
  21. package/dist/components/histogram.d.ts.map +1 -0
  22. package/dist/components/histogram.js +115 -0
  23. package/dist/components/histogram.js.map +1 -0
  24. package/dist/components/horizontal-bar-graph.d.ts +47 -0
  25. package/dist/components/horizontal-bar-graph.d.ts.map +1 -0
  26. package/dist/components/horizontal-bar-graph.js +137 -0
  27. package/dist/components/horizontal-bar-graph.js.map +1 -0
  28. package/dist/components/list.d.ts +2 -0
  29. package/dist/components/list.d.ts.map +1 -1
  30. package/dist/components/list.js +10 -10
  31. package/dist/components/list.js.map +1 -1
  32. package/dist/examples/bar-graph-weekly.js +2 -2
  33. package/dist/examples/bar-graph-weekly.js.map +1 -1
  34. package/dist/examples/charts-showcase-barchart.d.ts +2 -0
  35. package/dist/examples/charts-showcase-barchart.d.ts.map +1 -0
  36. package/dist/examples/charts-showcase-barchart.js +10 -0
  37. package/dist/examples/charts-showcase-barchart.js.map +1 -0
  38. package/dist/examples/charts-showcase-bargraph.d.ts +2 -0
  39. package/dist/examples/charts-showcase-bargraph.d.ts.map +1 -0
  40. package/dist/examples/charts-showcase-bargraph.js +60 -0
  41. package/dist/examples/charts-showcase-bargraph.js.map +1 -0
  42. package/dist/examples/charts-showcase-candle.d.ts +2 -0
  43. package/dist/examples/charts-showcase-candle.d.ts.map +1 -0
  44. package/dist/examples/charts-showcase-candle.js +30 -0
  45. package/dist/examples/charts-showcase-candle.js.map +1 -0
  46. package/dist/examples/charts-showcase-graph.d.ts +2 -0
  47. package/dist/examples/charts-showcase-graph.d.ts.map +1 -0
  48. package/dist/examples/charts-showcase-graph.js +33 -0
  49. package/dist/examples/charts-showcase-graph.js.map +1 -0
  50. package/dist/examples/charts-showcase-heatmap.d.ts +2 -0
  51. package/dist/examples/charts-showcase-heatmap.d.ts.map +1 -0
  52. package/dist/examples/charts-showcase-heatmap.js +36 -0
  53. package/dist/examples/charts-showcase-heatmap.js.map +1 -0
  54. package/dist/examples/charts-showcase-mixed.d.ts +2 -0
  55. package/dist/examples/charts-showcase-mixed.d.ts.map +1 -0
  56. package/dist/examples/charts-showcase-mixed.js +30 -0
  57. package/dist/examples/charts-showcase-mixed.js.map +1 -0
  58. package/dist/examples/charts-showcase-progress.d.ts +2 -0
  59. package/dist/examples/charts-showcase-progress.d.ts.map +1 -0
  60. package/dist/examples/charts-showcase-progress.js +10 -0
  61. package/dist/examples/charts-showcase-progress.js.map +1 -0
  62. package/dist/examples/graph-multi-series.js +1 -1
  63. package/dist/examples/graph-multi-series.js.map +1 -1
  64. package/dist/examples/horizontal-bar-graph-weekly.d.ts +2 -0
  65. package/dist/examples/horizontal-bar-graph-weekly.d.ts.map +1 -0
  66. package/dist/examples/horizontal-bar-graph-weekly.js +67 -0
  67. package/dist/examples/horizontal-bar-graph-weekly.js.map +1 -0
  68. package/dist/examples/simple-dotted-line-graph.d.ts +2 -0
  69. package/dist/examples/simple-dotted-line-graph.d.ts.map +1 -0
  70. package/dist/examples/simple-dotted-line-graph.js +39 -0
  71. package/dist/examples/simple-dotted-line-graph.js.map +1 -0
  72. package/dist/examples/simple-histogram.d.ts +2 -0
  73. package/dist/examples/simple-histogram.d.ts.map +1 -0
  74. package/dist/examples/simple-histogram.js +47 -0
  75. package/dist/examples/simple-histogram.js.map +1 -0
  76. package/dist/index.d.ts +6 -0
  77. package/dist/index.d.ts.map +1 -1
  78. package/dist/index.js +6 -0
  79. package/dist/index.js.map +1 -1
  80. package/dist/platform/node/sqlite.d.ts +6 -5
  81. package/dist/platform/node/sqlite.d.ts.map +1 -1
  82. package/dist/platform/node/sqlite.js +30 -14
  83. package/dist/platform/node/sqlite.js.map +1 -1
  84. package/dist/theme.d.ts.map +1 -1
  85. package/dist/theme.js +11 -9
  86. package/dist/theme.js.map +1 -1
  87. package/dist/utils/run-command.d.ts.map +1 -1
  88. package/dist/utils/run-command.js +8 -19
  89. package/dist/utils/run-command.js.map +1 -1
  90. package/dist/utils.d.ts +1 -19
  91. package/dist/utils.d.ts.map +1 -1
  92. package/dist/utils.js +1 -100
  93. package/dist/utils.js.map +1 -1
  94. package/package.json +6 -8
  95. package/src/build.tsx +11 -10
  96. package/src/cli.tsx +3 -40
  97. package/src/compile.vitest.tsx +3 -3
  98. package/src/components/bar-graph.tsx +217 -111
  99. package/src/components/dotted-line-graph.tsx +407 -0
  100. package/src/components/extension-preferences.tsx +2 -12
  101. package/src/components/graph.tsx +5 -1
  102. package/src/components/histogram.tsx +228 -0
  103. package/src/components/horizontal-bar-graph.tsx +279 -0
  104. package/src/components/list.tsx +20 -15
  105. package/src/examples/action-shortcut.vitest.tsx +17 -17
  106. package/src/examples/bar-graph-weekly.tsx +2 -2
  107. package/src/examples/bar-graph-weekly.vitest.tsx +63 -62
  108. package/src/examples/charts-showcase-bargraph.tsx +103 -0
  109. package/src/examples/detail-metadata-showcase.vitest.tsx +12 -12
  110. package/src/examples/form-basic.vitest.tsx +11 -11
  111. package/src/examples/form-dropdown.vitest.tsx +11 -11
  112. package/src/examples/form-scroll.vitest.tsx +1 -1
  113. package/src/examples/form-tagpicker.vitest.tsx +11 -11
  114. package/src/examples/github.vitest.tsx +22 -22
  115. package/src/examples/graph-bar-chart.vitest.tsx +8 -8
  116. package/src/examples/graph-multi-series.tsx +1 -1
  117. package/src/examples/graph-row.vitest.tsx +14 -14
  118. package/src/examples/graph-styles.vitest.tsx +77 -77
  119. package/src/examples/horizontal-bar-graph-weekly.tsx +138 -0
  120. package/src/examples/horizontal-bar-graph-weekly.vitest.tsx +164 -0
  121. package/src/examples/list-detail-metadata.vitest.tsx +4 -4
  122. package/src/examples/list-with-detail.vitest.tsx +46 -46
  123. package/src/examples/simple-candle-chart.vitest.tsx +8 -8
  124. package/src/examples/simple-dotted-line-graph.tsx +53 -0
  125. package/src/examples/simple-dotted-line-graph.vitest.tsx +62 -0
  126. package/src/examples/simple-grid.vitest.tsx +4 -4
  127. package/src/examples/simple-heatmap.vitest.tsx +9 -9
  128. package/src/examples/simple-histogram.tsx +90 -0
  129. package/src/examples/simple-navigation.vitest.tsx +4 -4
  130. package/src/examples/swift-extension.vitest.tsx +3 -3
  131. package/src/extensions/dev.vitest.tsx +8 -8
  132. package/src/index.tsx +21 -0
  133. package/src/platform/node/sqlite.ts +29 -13
  134. package/src/theme.tsx +11 -10
  135. package/src/utils/run-command.tsx +10 -19
  136. package/src/utils.tsx +0 -163
  137. package/src/examples/store.tsx +0 -4
  138. package/src/examples/store.vitest.tsx +0 -78
  139. package/src/extensions/home.tsx +0 -227
  140. package/src/extensions/store.tsx +0 -375
@@ -19,7 +19,7 @@ afterEach(() => {
19
19
  test('area style renders braille characters', async () => {
20
20
  const text = await session.text({
21
21
  waitFor: (text) => {
22
- return text.includes('Area - Stock') && text.includes('│')
22
+ return /Area.*Price/i.test(text) && text.includes('│')
23
23
  },
24
24
  timeout: 10000,
25
25
  })
@@ -32,19 +32,19 @@ test('area style renders braille characters', async () => {
32
32
 
33
33
  > Search...
34
34
 
35
- ›Area - Stock Price Orange braille do │ 211│ ⣠ ▲
36
- Area - Multi Series CPU + Memory ove │ │ ⢀⣴⣦⣼⣿ █
37
- Area - Waves Purple + Magenta sine/c │ │ ⢠⣦⣄⣴⣿⣿⣿⣿⣿ █
38
- Area - Blue Revenue Single series, a │ 189│ ⢀⣴⣷⣦⣿⣿⣿⣿⣿⣿⣿⣿⣿ █
39
- Filled - Red Revenue Solid block gro │ │ ⣠⣀⢠⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿ ▀
40
- Filled - Green Temp Daily temperatur │ │ ⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
41
- Filled - Yellow CPU High contrast on │ 167│ ⢀⣴⣿⣶⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
42
- Filled - Magenta Waves Smooth curve │ │ ⣰⣤⣰⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
43
- Striped - Purple/Orange Warm alterna │ │⢀⣴⡄⢰⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
44
- Striped - Blue/Red High contrast str │ 145│⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
45
- Striped - Theme Default primary + ac │ 1 5 10 15 20
46
- Striped - Green/Yellow Nature-inspir
47
- Striped - Red/Magenta Warm gradient │ ─────────────────────────────────
35
+ ›Area - ...k Price Orange ...lle dots │ 211│ ⣠ ▲
36
+ Area - ... Series CPU + M... overlay │ │ ⢀⣴⣦⣼⣿ █
37
+ Area...ave Purple + Ma...sine/cosine │ │ ⢠⣦⣄⣴⣿⣿⣿⣿⣿ █
38
+ Area -...evenue Single s...uto range │ 189│ ⢀⣴⣷⣦⣿⣿⣿⣿⣿⣿⣿⣿⣿ █
39
+ Filled...RevenueSolid bl...wth chart │ │ ⣠⣀⢠⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿ ▀
40
+ Filled...en TempDaily te...ure curve │ │ ⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
41
+ Filled ...low CPUHigh con... on dark │ 167│ ⢀⣴⣿⣶⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
42
+ Filled ...a WavesSmooth c...h blocks │ │ ⣰⣤⣰⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
43
+ Striped...e/Orang Warm al...g colors │ │⢀⣴⡄⢰⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
44
+ Striped...lue/Re High con... stripes │ 145│⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
45
+ Striped...Defaul primary ...no prop) │ 1 5 10 15 20
46
+ Striped -...en/YellowNature-inspired
47
+ Striped .../MagentaWarm gr...nt feel │ ─────────────────────────────────
48
48
 
49
49
  │ Variant: area
50
50
  ↵ open detail ↑↓ navigate ^k act │ ▼
@@ -53,7 +53,7 @@ test('area style renders braille characters', async () => {
53
53
  `)
54
54
 
55
55
  expect(text).toMatch(/[\u2800-\u28FF]/)
56
- expect(text).toContain('Stock Price')
56
+ expect(text).toContain('Price')
57
57
  }, 30000)
58
58
 
59
59
  test('filled style renders block characters', async () => {
@@ -71,7 +71,7 @@ test('filled style renders block characters', async () => {
71
71
 
72
72
  const text = await session.text({
73
73
  waitFor: (text) => {
74
- return text.includes('›Filled - Red')
74
+ return /›Filled.*Revenue/i.test(text)
75
75
  },
76
76
  timeout: 5000,
77
77
  })
@@ -84,19 +84,19 @@ test('filled style renders block characters', async () => {
84
84
 
85
85
  > Search...
86
86
 
87
- Area - Stock Price Orange braille do │ Revenue Growth ▲
88
- Area - Multi Series CPU + Memory ove │ █
89
- Area - Waves Purple + Magenta sine/c
90
- Area - Blue Revenue Single series, a │ Quarterly revenue from $10k** to
91
- ›Filled - Red Revenue Solid block gro │ **$75k.
92
- Filled - Green Temp Daily temperatur │ Q1: $10k → Q2: $25k (+150%)
93
- Filled - Yellow CPU High contrast on │ Q2: $25k → Q3: $50k (+100%)
94
- Filled - Magenta Waves Smooth curve │ Q3: $50k → Q4: $75k (+50%)
95
- Striped - Purple/Orange Warm alterna
96
- Striped - Blue/Red High contrast str │ 78│ ▖
97
- Striped - Theme Default primary + ac │ │ ▖▌▖▌▌
98
- Striped - Green/Yellow Nature-inspir │ │ ▖▖▖▌▌▌▌▌▌
99
- Striped - Red/Magenta Warm gradient │ 54│ ▖▌▌▌▌▌▌▌▌▌▌
87
+ Area - ...k Price Orange ...lle dots │ Revenue Growth ▲
88
+ Area - ... Series CPU + M... overlay │ █
89
+ Area...ave Purple + Ma...sine/cosine
90
+ Area -...evenue Single s...uto range │ Quarterly revenue from $10k** to
91
+ ›Filled...RevenueSolid bl...wth chart │ **$75k.
92
+ Filled...en TempDaily te...ure curve │ Q1: $10k → Q2: $25k (+150%)
93
+ Filled ...low CPUHigh con... on dark │ Q2: $25k → Q3: $50k (+100%)
94
+ Filled ...a WavesSmooth c...h blocks │ Q3: $50k → Q4: $75k (+50%)
95
+ Striped...e/Orang Warm al...g colors
96
+ Striped...lue/Re High con... stripes │ 78│ ▖
97
+ Striped...Defaul primary ...no prop) │ │ ▖▌▖▌▌
98
+ Striped -...en/YellowNature-inspired │ │ ▖▖▖▌▌▌▌▌▌
99
+ Striped .../MagentaWarm gr...nt feel │ 54│ ▖▌▌▌▌▌▌▌▌▌▌
100
100
  │ │ ▖▖▖▌▌▌▌▌▌▌▌▌▌▌▌
101
101
  │ │ ▖ ▖▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌
102
102
  ↵ open detail ↑↓ navigate ^k act │ 31│ ▖▌▌▖▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌ ▼
@@ -105,7 +105,7 @@ test('filled style renders block characters', async () => {
105
105
  `)
106
106
 
107
107
  expect(text).toMatch(/[▌▘▖]/)
108
- expect(text).toContain('›Filled - Red')
108
+ expect(text).toContain('›Filled')
109
109
  }, 30000)
110
110
 
111
111
  test('striped style renders alternating columns', async () => {
@@ -123,7 +123,7 @@ test('striped style renders alternating columns', async () => {
123
123
 
124
124
  const text = await session.text({
125
125
  waitFor: (text) => {
126
- return text.includes('›Striped - Purple')
126
+ return /›Striped.*Warm/i.test(text)
127
127
  },
128
128
  timeout: 5000,
129
129
  })
@@ -136,19 +136,19 @@ test('striped style renders alternating columns', async () => {
136
136
 
137
137
  > Search...
138
138
 
139
- Area - Stock Price Orange braille do │ 211│ ▖ ▲
140
- Area - Multi Series CPU + Memory ove │ │ ▖▖▌▌ █
141
- Area - Waves Purple + Magenta sine/c │ │ ▖▖▖▌▌▌▌▌ █
142
- Area - Blue Revenue Single series, a │ 189│ ▖▖▌▖▌▌▌▌▌▌▌▌▌
143
- Filled - Red Revenue Solid block gro │ │ ▖▖▖▌▌▌▌▌▌▌▌▌▌▌▌▌
144
- Filled - Green Temp Daily temperatur │ │ ▖▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌
145
- Filled - Yellow CPU High contrast on │ 167│ ▖▖▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌
146
- Filled - Magenta Waves Smooth curve │ │ ▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌
147
- ›Striped - Purple/Orange Warm alterna │ │▖▌▖▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌
148
- Striped - Blue/Red High contrast str │ 145│▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌
149
- Striped - Theme Default primary + ac │ 1 5 10 15 20
150
- Striped - Green/Yellow Nature-inspir
151
- Striped - Red/Magenta Warm gradient │ ─────────────────────────────────
139
+ Area - ...k Price Orange ...lle dots │ 211│ ▖ ▲
140
+ Area - ... Series CPU + M... overlay │ │ ▖▖▌▌ █
141
+ Area...ave Purple + Ma...sine/cosine │ │ ▖▖▖▌▌▌▌▌ █
142
+ Area -...evenue Single s...uto range │ 189│ ▖▖▌▖▌▌▌▌▌▌▌▌▌
143
+ Filled...RevenueSolid bl...wth chart │ │ ▖▖▖▌▌▌▌▌▌▌▌▌▌▌▌▌
144
+ Filled...en TempDaily te...ure curve │ │ ▖▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌
145
+ Filled ...low CPUHigh con... on dark │ 167│ ▖▖▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌
146
+ Filled ...a WavesSmooth c...h blocks │ │ ▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌
147
+ ›Striped...e/Orang Warm al...g colors │ │▖▌▖▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌
148
+ Striped...lue/Re High con... stripes │ 145│▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌
149
+ Striped...Defaul primary ...no prop) │ 1 5 10 15 20
150
+ Striped -...en/YellowNature-inspired
151
+ Striped .../MagentaWarm gr...nt feel │ ─────────────────────────────────
152
152
 
153
153
  │ Even cols: Purple
154
154
  ↵ open detail ↑↓ navigate ^k act │ ▼
@@ -157,13 +157,13 @@ test('striped style renders alternating columns', async () => {
157
157
  `)
158
158
 
159
159
  expect(text).toMatch(/[▌▘▖]/)
160
- expect(text).toContain('›Striped - Purple')
160
+ expect(text).toContain('›Striped')
161
161
  }, 30000)
162
162
 
163
163
  test('markdown + metadata detail view in list', async () => {
164
164
  await session.text({
165
165
  waitFor: (text) => {
166
- return text.includes('Area - Multi') && text.includes('│')
166
+ return /Area.*Series/i.test(text) && text.includes('│')
167
167
  },
168
168
  timeout: 10000,
169
169
  })
@@ -173,7 +173,7 @@ test('markdown + metadata detail view in list', async () => {
173
173
 
174
174
  const text = await session.text({
175
175
  waitFor: (text) => {
176
- return text.includes('›Area - Multi') && text.includes('System Metrics')
176
+ return /›Area.*Series/i.test(text) && text.includes('System Metrics')
177
177
  },
178
178
  timeout: 5000,
179
179
  })
@@ -186,19 +186,19 @@ test('markdown + metadata detail view in list', async () => {
186
186
 
187
187
  > Search...
188
188
 
189
- Area - Stock Price Orange braille do │ System Metrics ▲
190
- ›Area - Multi Series CPU + Memory ove │ ▀
191
- Area - Waves Purple + Magenta sine/c
192
- Area - Blue Revenue Single series, a │ CPU usage (blue) vs memory usage (
193
- Filled - Red Revenue Solid block gro │ green) over 24 hours.
194
- Filled - Green Temp Daily temperatur │ - Peak CPU at 90% around 15h
195
- Filled - Yellow CPU High contrast on │ - Memory steadily climbing to 86%
196
- Filled - Magenta Waves Smooth curve │ - CPU has high variance, memory
197
- Striped - Purple/Orange Warm alterna is monotonic
198
- Striped - Blue/Red High contrast str
199
- Striped - Theme Default primary + ac │ 100│
200
- Striped - Green/Yellow Nature-inspir │ │ ⣠⣶⣧ ⣀⣠⣤⣶
201
- Striped - Red/Magenta Warm gradient │ 75│ ⢀⣴⣧ ⢀⣰⣿⣿⣿⣷⣾⣿⣿⣿⣿⣿
189
+ Area - ...k Price Orange ...lle dots │ System Metrics ▲
190
+ ›Area - ... Series CPU + M... overlay │ ▀
191
+ Area...ave Purple + Ma...sine/cosine
192
+ Area -...evenue Single s...uto range │ CPU usage (blue) vs memory usage (
193
+ Filled...RevenueSolid bl...wth chart │ green) over 24 hours.
194
+ Filled...en TempDaily te...ure curve │ - Peak CPU at 90% around 15h
195
+ Filled ...low CPUHigh con... on dark │ - Memory steadily climbing to 86%
196
+ Filled ...a WavesSmooth c...h blocks │ - CPU has high variance, memory
197
+ Striped...e/Orang Warm al...g colors is monotonic
198
+ Striped...lue/Re High con... stripes
199
+ Striped...Defaul primary ...no prop) │ 100│
200
+ Striped -...en/YellowNature-inspired │ │ ⣠⣶⣧ ⣀⣠⣤⣶
201
+ Striped .../MagentaWarm gr...nt feel │ 75│ ⢀⣴⣧ ⢀⣰⣿⣿⣿⣷⣾⣿⣿⣿⣿⣿
202
202
  │ │ ⢀⣾⣿⣿⣧⢀⣀⣤⣶⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
203
203
  │ │ ⢀⣾⣶⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
204
204
  ↵ open detail ↑↓ navigate ^k act │ 50│⣀⣀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿ ▼
@@ -213,7 +213,7 @@ test('markdown + metadata detail view in list', async () => {
213
213
  test('enter pushes full detail view with graph', async () => {
214
214
  await session.text({
215
215
  waitFor: (text) => {
216
- return text.includes('Area - Stock') && text.includes('│')
216
+ return /Area.*Price/i.test(text) && text.includes('│')
217
217
  },
218
218
  timeout: 10000,
219
219
  })
@@ -265,7 +265,7 @@ test('enter pushes full detail view with graph', async () => {
265
265
  test('esc returns from detail to list', async () => {
266
266
  await session.text({
267
267
  waitFor: (text) => {
268
- return text.includes('Area - Stock') && text.includes('│')
268
+ return /Area.*Price/i.test(text) && text.includes('│')
269
269
  },
270
270
  timeout: 10000,
271
271
  })
@@ -284,7 +284,7 @@ test('esc returns from detail to list', async () => {
284
284
 
285
285
  const text = await session.text({
286
286
  waitFor: (text) => {
287
- return text.includes('›Area - Stock Price') && text.includes('Graph Styles')
287
+ return /›Area.*Price/i.test(text) && text.includes('Graph Styles')
288
288
  },
289
289
  timeout: 5000,
290
290
  })
@@ -297,19 +297,19 @@ test('esc returns from detail to list', async () => {
297
297
 
298
298
  > Search...
299
299
 
300
- ›Area - Stock Price Orange braille do │ 211│ ⣠ ▲
301
- Area - Multi Series CPU + Memory ove │ │ ⢀⣴⣦⣼⣿ █
302
- Area - Waves Purple + Magenta sine/c │ │ ⢠⣦⣄⣴⣿⣿⣿⣿⣿ █
303
- Area - Blue Revenue Single series, a │ 189│ ⢀⣴⣷⣦⣿⣿⣿⣿⣿⣿⣿⣿⣿ █
304
- Filled - Red Revenue Solid block gro │ │ ⣠⣀⢠⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿ ▀
305
- Filled - Green Temp Daily temperatur │ │ ⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
306
- Filled - Yellow CPU High contrast on │ 167│ ⢀⣴⣿⣶⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
307
- Filled - Magenta Waves Smooth curve │ │ ⣰⣤⣰⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
308
- Striped - Purple/Orange Warm alterna │ │⢀⣴⡄⢰⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
309
- Striped - Blue/Red High contrast str │ 145│⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
310
- Striped - Theme Default primary + ac │ 1 5 10 15 20
311
- Striped - Green/Yellow Nature-inspir
312
- Striped - Red/Magenta Warm gradient │ ─────────────────────────────────
300
+ ›Area - ...k Price Orange ...lle dots │ 211│ ⣠ ▲
301
+ Area - ... Series CPU + M... overlay │ │ ⢀⣴⣦⣼⣿ █
302
+ Area...ave Purple + Ma...sine/cosine │ │ ⢠⣦⣄⣴⣿⣿⣿⣿⣿ █
303
+ Area -...evenue Single s...uto range │ 189│ ⢀⣴⣷⣦⣿⣿⣿⣿⣿⣿⣿⣿⣿ █
304
+ Filled...RevenueSolid bl...wth chart │ │ ⣠⣀⢠⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿ ▀
305
+ Filled...en TempDaily te...ure curve │ │ ⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
306
+ Filled ...low CPUHigh con... on dark │ 167│ ⢀⣴⣿⣶⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
307
+ Filled ...a WavesSmooth c...h blocks │ │ ⣰⣤⣰⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
308
+ Striped...e/Orang Warm al...g colors │ │⢀⣴⡄⢰⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
309
+ Striped...lue/Re High con... stripes │ 145│⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
310
+ Striped...Defaul primary ...no prop) │ 1 5 10 15 20
311
+ Striped -...en/YellowNature-inspired
312
+ Striped .../MagentaWarm gr...nt feel │ ─────────────────────────────────
313
313
 
314
314
  │ Variant: area
315
315
  ↵ open detail ↑↓ navigate ^k act │ ▼
@@ -317,6 +317,6 @@ test('esc returns from detail to list', async () => {
317
317
  "
318
318
  `)
319
319
 
320
- expect(text).toContain('›Area - Stock')
320
+ expect(text).toContain('›Area')
321
321
  expect(text).toContain('Graph Styles')
322
322
  }, 30000)
@@ -0,0 +1,138 @@
1
+ // Example: HorizontalBarGraph stacked horizontal rows with a compact right legend.
2
+
3
+ import React from 'react'
4
+ import { Action, ActionPanel, Detail, HorizontalBarGraph, List } from 'termcast'
5
+ import { useNavigation } from 'termcast/src/internal/navigation'
6
+ import { renderWithProviders } from '../utils'
7
+
8
+ const days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
9
+
10
+ interface DataSet {
11
+ title: string
12
+ subtitle: string
13
+ labels: string[]
14
+ categoryTitle?: string
15
+ distributionTitle?: string
16
+ legendTitle?: string
17
+ series: Array<{ data: number[]; title: string }>
18
+ }
19
+
20
+ const dataSets: DataSet[] = [
21
+ {
22
+ title: 'Weekly Traffic',
23
+ subtitle: 'Direct / Organic / Referral across 6 days',
24
+ labels: days,
25
+ series: [
26
+ { data: [40, 30, 25, 15, 50, 40], title: 'Direct' },
27
+ { data: [30, 35, 15, 20, 35, 30], title: 'Organic' },
28
+ { data: [20, 25, 10, 10, 25, 20], title: 'Referral' },
29
+ ],
30
+ },
31
+ {
32
+ title: 'Revenue by Region',
33
+ subtitle: 'Americas / EMEA / APAC',
34
+ labels: days,
35
+ series: [
36
+ { data: [60, 45, 30, 55, 70, 50], title: 'Americas' },
37
+ { data: [25, 30, 20, 35, 25, 30], title: 'EMEA' },
38
+ { data: [15, 20, 10, 10, 20, 15], title: 'APAC' },
39
+ ],
40
+ },
41
+ {
42
+ title: 'Long Labels',
43
+ subtitle: 'The left label column truncates without stealing legend space',
44
+ labels: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday & Sunday'],
45
+ categoryTitle: 'day',
46
+ distributionTitle: 'traffic',
47
+ legendTitle: 'source',
48
+ series: [
49
+ { data: [40, 30, 25, 15, 50, 40], title: 'Views' },
50
+ { data: [20, 25, 10, 10, 25, 20], title: 'Clicks' },
51
+ ],
52
+ },
53
+ {
54
+ title: 'Many Series',
55
+ subtitle: 'Legend grows only as wide as its content needs',
56
+ labels: days,
57
+ series: Array.from({ length: 8 }, (_, i) => {
58
+ return {
59
+ data: [10 + i * 5, 15 + i * 3, 8 + i * 4, 12 + i * 2, 20 + i * 6, 5 + i * 7],
60
+ title: `Series ${i + 1}`,
61
+ }
62
+ }),
63
+ },
64
+ ]
65
+
66
+ function Chart({ item, height }: { item: DataSet; height: number }): any {
67
+ return (
68
+ <HorizontalBarGraph
69
+ labels={item.labels}
70
+ height={height}
71
+ categoryTitle={item.categoryTitle}
72
+ distributionTitle={item.distributionTitle}
73
+ legendTitle={item.legendTitle}
74
+ >
75
+ {item.series.map((series) => {
76
+ return <HorizontalBarGraph.Series key={series.title} data={series.data} title={series.title} />
77
+ })}
78
+ </HorizontalBarGraph>
79
+ )
80
+ }
81
+
82
+ function HorizontalBarGraphDetailView({ item }: { item: DataSet }): any {
83
+ const { pop } = useNavigation()
84
+
85
+ return (
86
+ <Detail
87
+ navigationTitle={item.title}
88
+ markdown={`# ${item.title}\n\n${item.subtitle}`}
89
+ metadata={
90
+ <Detail.Metadata>
91
+ <Chart item={item} height={12} />
92
+ </Detail.Metadata>
93
+ }
94
+ actions={
95
+ <ActionPanel>
96
+ <Action title="Go Back" onAction={() => { pop() }} />
97
+ </ActionPanel>
98
+ }
99
+ />
100
+ )
101
+ }
102
+
103
+ function HorizontalBarGraphWeeklyExample() {
104
+ const { push } = useNavigation()
105
+
106
+ return (
107
+ <List navigationTitle="HorizontalBarGraph Showcase" isShowingDetail={true}>
108
+ {dataSets.map((item) => {
109
+ return (
110
+ <List.Item
111
+ key={item.title}
112
+ title={item.title}
113
+ subtitle={item.subtitle}
114
+ detail={
115
+ <List.Item.Detail
116
+ metadata={
117
+ <List.Item.Detail.Metadata>
118
+ <Chart item={item} height={10} />
119
+ </List.Item.Detail.Metadata>
120
+ }
121
+ />
122
+ }
123
+ actions={
124
+ <ActionPanel>
125
+ <Action
126
+ title="Open Detail"
127
+ onAction={() => { push(<HorizontalBarGraphDetailView item={item} />) }}
128
+ />
129
+ </ActionPanel>
130
+ }
131
+ />
132
+ )
133
+ })}
134
+ </List>
135
+ )
136
+ }
137
+
138
+ void renderWithProviders(<HorizontalBarGraphWeeklyExample />)
@@ -0,0 +1,164 @@
1
+ // E2E tests for HorizontalBarGraph stacked horizontal rows and right-side legend.
2
+
3
+ import { afterEach, beforeEach, expect, test } from 'vitest'
4
+ import { launchTerminal, Session } from 'tuistory/src'
5
+
6
+ let session: Session
7
+
8
+ beforeEach(async () => {
9
+ session = await launchTerminal({
10
+ command: 'bun',
11
+ args: ['src/examples/horizontal-bar-graph-weekly.tsx'],
12
+ cols: 90,
13
+ rows: 30,
14
+ })
15
+ })
16
+
17
+ afterEach(() => {
18
+ session?.close()
19
+ })
20
+
21
+ test('renders horizontal stacked rows and compact legend', async () => {
22
+ const text = await session.text({
23
+ waitFor: (content) => {
24
+ return content.includes('Mon') && content.includes('Direct') && content.includes('%')
25
+ },
26
+ timeout: 10000,
27
+ })
28
+
29
+ expect(text).toMatchInlineSnapshot(`
30
+ "
31
+
32
+
33
+ HorizontalBarGraph Showcase ────────────────────────────────────────────────────────
34
+
35
+ > Search...
36
+
37
+ ›Wee...fficDirect / Organ... across 6 days │ category distribution legend
38
+ Revenue by Region Americas / EMEA / APAC │ ──────── ──────────── ───────────────
39
+ Lon...el The left label...ng legend space │ Mon ╻╻╻╻╻╻╻╻╻╻ ● Direct 42%
40
+ Man...ie Legend grows o...s content needs │ Tue ╻╻╻╻╻╻╻╻╻╻ ● Organic 35%
41
+ │ Wed ╻╻╻╻╻ ● Referral 23%
42
+ │ Thu ╻╻╻╻╻
43
+ │ Fri ╻╻╻╻╻╻╻╻╻╻╻╻
44
+ │ Sat ╻╻╻╻╻╻╻╻╻╻
45
+ ↵ open detail ↑↓ navigate ^k actions │
46
+
47
+
48
+
49
+
50
+
51
+
52
+
53
+
54
+
55
+
56
+
57
+
58
+
59
+
60
+ "
61
+ `)
62
+ expect(text).toContain('Mon')
63
+ expect(text).toContain('Direct')
64
+ expect(text).toContain('╻')
65
+ }, 30000)
66
+
67
+ test('long labels truncate and leave legend visible', async () => {
68
+ await session.text({ waitFor: (content) => content.includes('Lon...el'), timeout: 10000 })
69
+ session.sendKey('down')
70
+ session.sendKey('down')
71
+
72
+ const text = await session.text({
73
+ waitFor: (content) => {
74
+ return content.includes('›Lon...el') && content.includes('Views')
75
+ },
76
+ timeout: 10000,
77
+ })
78
+
79
+ expect(text).toMatchInlineSnapshot(`
80
+ "
81
+
82
+
83
+ HorizontalBarGraph Showcase ────────────────────────────────────────────────────────
84
+
85
+ > Search...
86
+
87
+ Wee...fficDirect / Organ... across 6 days │ day traffi source
88
+ Revenue by Region Americas / EMEA / APAC │ ──────────────── ────── ─────────────
89
+ ›Lon...el The left label...ng legend space │ Monday ╻╻╻╻╻ ● Views 65%
90
+ Man...ie Legend grows o...s content needs │ Tuesday ╻╻╻╻ ● Clicks 35%
91
+ │ Wednesday ╻╻╻
92
+ │ Thursday ╻╻
93
+ │ Friday ╻╻╻╻╻╻
94
+ │ Saturday & Sund… ╻╻╻╻╻
95
+ ↵ open detail ↑↓ navigate ^k actions │
96
+
97
+
98
+
99
+
100
+
101
+
102
+
103
+
104
+
105
+
106
+
107
+
108
+
109
+
110
+ "
111
+ `)
112
+ expect(text).toContain('Saturday')
113
+ expect(text).toContain('Views')
114
+ }, 30000)
115
+
116
+ test('many series keeps bars readable and clips legend vertically', async () => {
117
+ await session.text({ waitFor: (content) => content.includes('Man...ie'), timeout: 10000 })
118
+ session.sendKey('down')
119
+ session.sendKey('down')
120
+ session.sendKey('down')
121
+
122
+ const text = await session.text({
123
+ waitFor: (content) => {
124
+ return content.includes('›Man...ie') && content.includes('Series 8')
125
+ },
126
+ timeout: 10000,
127
+ })
128
+
129
+ expect(text).toMatchInlineSnapshot(`
130
+ "
131
+
132
+
133
+ HorizontalBarGraph Showcase ────────────────────────────────────────────────────────
134
+
135
+ > Search...
136
+
137
+ Wee...fficDirect / Organ... across 6 days │ category distribution legend
138
+ Revenue by Region Americas / EMEA / APAC │ ──────── ──────────── ───────────────
139
+ Lon...el The left label...ng legend space │ Mon ╻╻╻╻╻╻╻╻ ● Series 8 20%
140
+ ›Man...ie Legend grows o...s content needs │ Tue ╻╻╻╻╻╻╻ ● Series 7 18%
141
+ │ Wed ╻╻╻╻╻╻ ● Series 6 16%
142
+ │ Thu ╻╻╻╻╻╻ ● Series 5 14%
143
+ │ Fri ╻╻╻╻╻╻╻╻╻╻╻╻ ● Series 4 11%
144
+ │ Sat ╻╻╻╻╻╻╻╻╻ ● Series 3 9%
145
+ ↵ open detail ↑↓ navigate ^k actions │
146
+
147
+
148
+
149
+
150
+
151
+
152
+
153
+
154
+
155
+
156
+
157
+
158
+
159
+
160
+ "
161
+ `)
162
+ expect(text).toContain('Series 8')
163
+ expect(text).toContain('╻')
164
+ }, 30000)
@@ -157,10 +157,8 @@ test('list detail metadata renders colored values and tag lists', async () => {
157
157
  > Search...
158
158
 
159
159
  Short Values │ Project Status
160
- Long Values │
161
- ›Colored & Tags │
162
- │ Overview of the current project
163
- │ state.
160
+ Long Values │ Overview of the current project
161
+ ›Colored & Tags │ state.
164
162
 
165
163
  │ Info
166
164
 
@@ -189,6 +187,8 @@ test('list detail metadata renders colored values and tag lists', async () => {
189
187
 
190
188
 
191
189
 
190
+
191
+
192
192
  "
193
193
  `)
194
194