termcast 1.5.0 → 1.7.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 (106) hide show
  1. package/dist/build.d.ts.map +1 -1
  2. package/dist/build.js +22 -5
  3. package/dist/build.js.map +1 -1
  4. package/dist/compile.d.ts.map +1 -1
  5. package/dist/compile.js +7 -1
  6. package/dist/compile.js.map +1 -1
  7. package/dist/components/bar-chart.d.ts.map +1 -1
  8. package/dist/components/bar-chart.js +14 -3
  9. package/dist/components/bar-chart.js.map +1 -1
  10. package/dist/components/bar-graph.d.ts +4 -4
  11. package/dist/components/bar-graph.d.ts.map +1 -1
  12. package/dist/components/bar-graph.js +23 -5
  13. package/dist/components/bar-graph.js.map +1 -1
  14. package/dist/components/candle-chart.d.ts +15 -0
  15. package/dist/components/candle-chart.d.ts.map +1 -1
  16. package/dist/components/candle-chart.js +41 -3
  17. package/dist/components/candle-chart.js.map +1 -1
  18. package/dist/components/chart-tooltip.d.ts +83 -0
  19. package/dist/components/chart-tooltip.d.ts.map +1 -0
  20. package/dist/components/chart-tooltip.js +127 -0
  21. package/dist/components/chart-tooltip.js.map +1 -0
  22. package/dist/components/dotted-line-graph.d.ts +11 -0
  23. package/dist/components/dotted-line-graph.d.ts.map +1 -1
  24. package/dist/components/dotted-line-graph.js +43 -2
  25. package/dist/components/dotted-line-graph.js.map +1 -1
  26. package/dist/components/graph.d.ts +11 -0
  27. package/dist/components/graph.d.ts.map +1 -1
  28. package/dist/components/graph.js +53 -4
  29. package/dist/components/graph.js.map +1 -1
  30. package/dist/components/horizontal-bar-graph.d.ts.map +1 -1
  31. package/dist/components/horizontal-bar-graph.js +16 -5
  32. package/dist/components/horizontal-bar-graph.js.map +1 -1
  33. package/dist/components/list.d.ts +7 -0
  34. package/dist/components/list.d.ts.map +1 -1
  35. package/dist/components/list.js +75 -14
  36. package/dist/components/list.js.map +1 -1
  37. package/dist/examples/chart-tooltips.d.ts +2 -0
  38. package/dist/examples/chart-tooltips.d.ts.map +1 -0
  39. package/dist/examples/chart-tooltips.js +16 -0
  40. package/dist/examples/chart-tooltips.js.map +1 -0
  41. package/dist/examples/list-detail-height-ratchet.d.ts +2 -0
  42. package/dist/examples/list-detail-height-ratchet.d.ts.map +1 -0
  43. package/dist/examples/list-detail-height-ratchet.js +26 -0
  44. package/dist/examples/list-detail-height-ratchet.js.map +1 -0
  45. package/dist/extensions/dev.d.ts.map +1 -1
  46. package/dist/extensions/dev.js +1 -0
  47. package/dist/extensions/dev.js.map +1 -1
  48. package/dist/globals.js +8 -0
  49. package/dist/globals.js.map +1 -1
  50. package/dist/package-json.d.ts +2 -0
  51. package/dist/package-json.d.ts.map +1 -1
  52. package/dist/package-json.js +20 -17
  53. package/dist/package-json.js.map +1 -1
  54. package/dist/profiler.d.ts +2 -0
  55. package/dist/profiler.d.ts.map +1 -0
  56. package/dist/profiler.js +390 -0
  57. package/dist/profiler.js.map +1 -0
  58. package/package.json +14 -15
  59. package/src/build.tsx +27 -5
  60. package/src/cli.tsx +0 -0
  61. package/src/compile.tsx +9 -1
  62. package/src/compile.vitest.tsx +8 -8
  63. package/src/components/bar-chart.tsx +23 -3
  64. package/src/components/bar-graph.tsx +32 -13
  65. package/src/components/candle-chart.tsx +63 -16
  66. package/src/components/chart-tooltip.tsx +191 -0
  67. package/src/components/dotted-line-graph.tsx +49 -3
  68. package/src/components/graph.tsx +76 -18
  69. package/src/components/horizontal-bar-graph.tsx +24 -4
  70. package/src/components/list.tsx +93 -20
  71. package/src/examples/action-shortcut.vitest.tsx +4 -4
  72. package/src/examples/actions-context.vitest.tsx +2 -2
  73. package/src/examples/bar-graph-weekly.vitest.tsx +97 -97
  74. package/src/examples/chart-tooltips.tsx +54 -0
  75. package/src/examples/form-basic.vitest.tsx +8 -8
  76. package/src/examples/github.vitest.tsx +19 -28
  77. package/src/examples/graph-bar-chart.vitest.tsx +40 -40
  78. package/src/examples/graph-polymarket.vitest.tsx +24 -24
  79. package/src/examples/graph-row.vitest.tsx +8 -8
  80. package/src/examples/graph-styles.vitest.tsx +65 -65
  81. package/src/examples/horizontal-bar-graph-weekly.vitest.tsx +52 -52
  82. package/src/examples/list-detail-height-ratchet.tsx +48 -0
  83. package/src/examples/list-detail-height-ratchet.vitest.tsx +161 -0
  84. package/src/examples/list-detail-metadata.vitest.tsx +49 -49
  85. package/src/examples/list-dropdown-default.vitest.tsx +27 -27
  86. package/src/examples/list-fetch-data.vitest.tsx +3 -3
  87. package/src/examples/list-item-accessories.vitest.tsx +2 -2
  88. package/src/examples/list-loading-empty-view.vitest.tsx +1 -1
  89. package/src/examples/list-no-actions.vitest.tsx +3 -3
  90. package/src/examples/list-scrollbox.vitest.tsx +6 -6
  91. package/src/examples/list-spacing-mode.vitest.tsx +3 -3
  92. package/src/examples/list-with-detail.vitest.tsx +11 -11
  93. package/src/examples/list-with-dropdown.vitest.tsx +7 -7
  94. package/src/examples/list-with-sections.vitest.tsx +32 -32
  95. package/src/examples/list-with-toast.vitest.tsx +4 -4
  96. package/src/examples/simple-candle-chart.vitest.tsx +63 -61
  97. package/src/examples/simple-grid.vitest.tsx +13 -13
  98. package/src/examples/simple-navigation.vitest.tsx +25 -25
  99. package/src/examples/simple-progress-bar.vitest.tsx +8 -8
  100. package/src/examples/swift-extension.vitest.tsx +3 -3
  101. package/src/examples/toast-action.vitest.tsx +4 -4
  102. package/src/extensions/dev.tsx +2 -1
  103. package/src/extensions/dev.vitest.tsx +17 -17
  104. package/src/globals.ts +9 -0
  105. package/src/package-json.tsx +24 -23
  106. package/src/profiler.tsx +487 -0
@@ -32,19 +32,19 @@ test('area style renders braille characters', async () => {
32
32
 
33
33
  > Search...
34
34
 
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 │ ─────────────────────────────────
35
+ ›Area - Stock PriceOrange ...lle dots │ 211│ ⣠ ▲
36
+ Area - ...i Series CPU + M...overlay │ │ ⢀⣴⣦⣼⣿ █
37
+ Area - Wave Purple + M...sine/cosine │ │ ⢠⣦⣄⣴⣿⣿⣿⣿⣿ █
38
+ Area - ... Revenu Single ...to range │ 189│ ⢀⣴⣷⣦⣿⣿⣿⣿⣿⣿⣿⣿⣿ █
39
+ Filled ... RevenueSolid b...th chart │ │ ⣠⣀⢠⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿ ▀
40
+ Filled ...een Tem Daily t...re curve │ │ ⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
41
+ Filled ...llow CPUHigh co... on dark │ 167│ ⢀⣴⣿⣶⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
42
+ Filled -...nta Wave Smooth... blocks │ │ ⣰⣤⣰⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
43
+ Striped -...le/Orang Warm a...colors │ │⢀⣴⡄⢰⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
44
+ Striped - Blue/Re High co... stripes │ 145│⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
45
+ Striped ...e Defaultprimar...o prop) │ 1 5 10 15 20
46
+ Striped - Green/Yello Natur...spired
47
+ Striped ...d/MagentaWarm g...nt feel │ ─────────────────────────────────
48
48
 
49
49
  │ Variant: area
50
50
  ↵ open detail ↑↓ navigate ^k act │ ▼
@@ -84,19 +84,19 @@ test('filled style renders block characters', async () => {
84
84
 
85
85
  > Search...
86
86
 
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│ ▖▌▌▌▌▌▌▌▌▌▌
87
+ Area - Stock PriceOrange ...lle dots │ Revenue Growth ▲
88
+ Area - ...i Series CPU + M...overlay │ █
89
+ Area - Wave Purple + M...sine/cosine │
90
+ Area - ... Revenu Single ...to range │ Quarterly revenue from $10k** to
91
+ ›Filled ... RevenueSolid b...th chart │ **$75k.
92
+ Filled ...een Tem Daily t...re curve │ Q1: $10k → Q2: $25k (+150%)
93
+ Filled ...llow CPUHigh co... on dark │ Q2: $25k → Q3: $50k (+100%)
94
+ Filled -...nta Wave Smooth... blocks │ Q3: $50k → Q4: $75k (+50%)
95
+ Striped -...le/Orang Warm a...colors │
96
+ Striped - Blue/Re High co... stripes │ 78│ ▖
97
+ Striped ...e Defaultprimar...o prop) │ │ ▖▌▖▌▌
98
+ Striped - Green/Yello Natur...spired │ │ ▖▖▖▌▌▌▌▌▌
99
+ Striped ...d/MagentaWarm g...nt feel │ 54│ ▖▌▌▌▌▌▌▌▌▌▌
100
100
  │ │ ▖▖▖▌▌▌▌▌▌▌▌▌▌▌▌
101
101
  │ │ ▖ ▖▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌
102
102
  ↵ open detail ↑↓ navigate ^k act │ 31│ ▖▌▌▖▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌ ▼
@@ -136,19 +136,19 @@ test('striped style renders alternating columns', async () => {
136
136
 
137
137
  > Search...
138
138
 
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 │ ─────────────────────────────────
139
+ Area - Stock PriceOrange ...lle dots │ 211│ ▖ ▲
140
+ Area - ...i Series CPU + M...overlay │ │ ▖▖▌▌ █
141
+ Area - Wave Purple + M...sine/cosine │ │ ▖▖▖▌▌▌▌▌ █
142
+ Area - ... Revenu Single ...to range │ 189│ ▖▖▌▖▌▌▌▌▌▌▌▌▌
143
+ Filled ... RevenueSolid b...th chart │ │ ▖▖▖▌▌▌▌▌▌▌▌▌▌▌▌▌
144
+ Filled ...een Tem Daily t...re curve │ │ ▖▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌
145
+ Filled ...llow CPUHigh co... on dark │ 167│ ▖▖▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌
146
+ Filled -...nta Wave Smooth... blocks │ │ ▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌
147
+ ›Striped -...le/Orang Warm a...colors │ │▖▌▖▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌
148
+ Striped - Blue/Re High co... stripes │ 145│▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌
149
+ Striped ...e Defaultprimar...o prop) │ 1 5 10 15 20
150
+ Striped - Green/Yello Natur...spired
151
+ Striped ...d/MagentaWarm g...nt feel │ ─────────────────────────────────
152
152
 
153
153
  │ Even cols: Purple
154
154
  ↵ open detail ↑↓ navigate ^k act │ ▼
@@ -186,19 +186,19 @@ test('markdown + metadata detail view in list', async () => {
186
186
 
187
187
  > Search...
188
188
 
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│ ⢀⣴⣧ ⢀⣰⣿⣿⣿⣷⣾⣿⣿⣿⣿⣿
189
+ Area - Stock PriceOrange ...lle dots │ System Metrics ▲
190
+ ›Area - ...i Series CPU + M...overlay │ ▀
191
+ Area - Wave Purple + M...sine/cosine │
192
+ Area - ... Revenu Single ...to range │ CPU usage (blue) vs memory usage (
193
+ Filled ... RevenueSolid b...th chart │ green) over 24 hours.
194
+ Filled ...een Tem Daily t...re curve │ - Peak CPU at 90% around 15h
195
+ Filled ...llow CPUHigh co... on dark │ - Memory steadily climbing to 86%
196
+ Filled -...nta Wave Smooth... blocks │ - CPU has high variance, memory
197
+ Striped -...le/Orang Warm a...colors │ is monotonic
198
+ Striped - Blue/Re High co... stripes │
199
+ Striped ...e Defaultprimar...o prop) │ 100│
200
+ Striped - Green/Yello Natur...spired │ │ ⣠⣶⣧ ⣀⣠⣤⣶
201
+ Striped ...d/MagentaWarm g...nt feel │ 75│ ⢀⣴⣧ ⢀⣰⣿⣿⣿⣷⣾⣿⣿⣿⣿⣿
202
202
  │ │ ⢀⣾⣿⣿⣧⢀⣀⣤⣶⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
203
203
  │ │ ⢀⣾⣶⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
204
204
  ↵ open detail ↑↓ navigate ^k act │ 50│⣀⣀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿ ▼
@@ -297,19 +297,19 @@ test('esc returns from detail to list', async () => {
297
297
 
298
298
  > Search...
299
299
 
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 │ ─────────────────────────────────
300
+ ›Area - Stock PriceOrange ...lle dots │ 211│ ⣠ ▲
301
+ Area - ...i Series CPU + M...overlay │ │ ⢀⣴⣦⣼⣿ █
302
+ Area - Wave Purple + M...sine/cosine │ │ ⢠⣦⣄⣴⣿⣿⣿⣿⣿ █
303
+ Area - ... Revenu Single ...to range │ 189│ ⢀⣴⣷⣦⣿⣿⣿⣿⣿⣿⣿⣿⣿ █
304
+ Filled ... RevenueSolid b...th chart │ │ ⣠⣀⢠⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿ ▀
305
+ Filled ...een Tem Daily t...re curve │ │ ⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
306
+ Filled ...llow CPUHigh co... on dark │ 167│ ⢀⣴⣿⣶⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
307
+ Filled -...nta Wave Smooth... blocks │ │ ⣰⣤⣰⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
308
+ Striped -...le/Orang Warm a...colors │ │⢀⣴⡄⢰⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
309
+ Striped - Blue/Re High co... stripes │ 145│⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
310
+ Striped ...e Defaultprimar...o prop) │ 1 5 10 15 20
311
+ Striped - Green/Yello Natur...spired
312
+ Striped ...d/MagentaWarm g...nt feel │ ─────────────────────────────────
313
313
 
314
314
  │ Variant: area
315
315
  ↵ open detail ↑↓ navigate ^k act │ ▼
@@ -34,29 +34,29 @@ test('renders horizontal stacked rows and compact legend', async () => {
34
34
 
35
35
  > Search...
36
36
 
37
- Wee...fficDirect / Organ... across 6 days │ category distribution legend
37
+ Weekl...affi Direct / Org...across 6 days │ category distribution legend
38
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%
39
+ Lon...belsThe left label...g legend space │ Mon ╻╻╻╻╻╻╻╻╻╻ ● Direct 42%
40
+ Man...riesLegend grows o... content needs │ Tue ╻╻╻╻╻╻╻╻╻╻ ● Organic 35%
41
41
  │ Wed ╻╻╻╻╻ ● Referral 23%
42
42
  │ Thu ╻╻╻╻╻
43
43
  │ Fri ╻╻╻╻╻╻╻╻╻╻╻╻
44
44
  │ Sat ╻╻╻╻╻╻╻╻╻╻
45
+
46
+
47
+
48
+
49
+
50
+
51
+
52
+
53
+
54
+
55
+
56
+
57
+
45
58
  ↵ open detail ↑↓ navigate ^k actions │
46
59
 
47
-
48
-
49
-
50
-
51
-
52
-
53
-
54
-
55
-
56
-
57
-
58
-
59
-
60
60
  "
61
61
  `)
62
62
  expect(text).toContain('Mon')
@@ -65,13 +65,13 @@ test('renders horizontal stacked rows and compact legend', async () => {
65
65
  }, 30000)
66
66
 
67
67
  test('long labels truncate and leave legend visible', async () => {
68
- await session.text({ waitFor: (content) => content.includes('Lon...el'), timeout: 10000 })
68
+ await session.text({ waitFor: (content) => content.includes('The left label'), timeout: 10000 })
69
69
  session.sendKey('down')
70
70
  session.sendKey('down')
71
71
 
72
72
  const text = await session.text({
73
73
  waitFor: (content) => {
74
- return content.includes('›Lon...el') && content.includes('Views')
74
+ return content.includes('›Lon') && content.includes('Views')
75
75
  },
76
76
  timeout: 10000,
77
77
  })
@@ -84,29 +84,29 @@ test('long labels truncate and leave legend visible', async () => {
84
84
 
85
85
  > Search...
86
86
 
87
- Wee...fficDirect / Organ... across 6 days │ day traffi source
87
+ Weekl...affi Direct / Org...across 6 days │ day traffi source
88
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%
89
+ ›Lon...belsThe left label...g legend space │ Monday ╻╻╻╻╻ ● Views 65%
90
+ Man...riesLegend grows o... content needs │ Tuesday ╻╻╻╻ ● Clicks 35%
91
91
  │ Wednesday ╻╻╻
92
92
  │ Thursday ╻╻
93
93
  │ Friday ╻╻╻╻╻╻
94
94
  │ Saturday & Sund… ╻╻╻╻╻
95
+
96
+
97
+
98
+
99
+
100
+
101
+
102
+
103
+
104
+
105
+
106
+
107
+
95
108
  ↵ open detail ↑↓ navigate ^k actions │
96
109
 
97
-
98
-
99
-
100
-
101
-
102
-
103
-
104
-
105
-
106
-
107
-
108
-
109
-
110
110
  "
111
111
  `)
112
112
  expect(text).toContain('Saturday')
@@ -114,14 +114,14 @@ test('long labels truncate and leave legend visible', async () => {
114
114
  }, 30000)
115
115
 
116
116
  test('many series keeps bars readable and clips legend vertically', async () => {
117
- await session.text({ waitFor: (content) => content.includes('Man...ie'), timeout: 10000 })
117
+ await session.text({ waitFor: (content) => content.includes('Legend grows'), timeout: 10000 })
118
118
  session.sendKey('down')
119
119
  session.sendKey('down')
120
120
  session.sendKey('down')
121
121
 
122
122
  const text = await session.text({
123
123
  waitFor: (content) => {
124
- return content.includes('›Man...ie') && content.includes('Series 8')
124
+ return content.includes('›Man') && content.includes('Series 8')
125
125
  },
126
126
  timeout: 10000,
127
127
  })
@@ -134,29 +134,29 @@ test('many series keeps bars readable and clips legend vertically', async () =>
134
134
 
135
135
  > Search...
136
136
 
137
- Wee...fficDirect / Organ... across 6 days │ category distribution legend
137
+ Weekl...affi Direct / Org...across 6 days │ category distribution legend
138
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%
139
+ Lon...belsThe left label...g legend space │ Mon ╻╻╻╻╻╻╻╻ ● Series 8 20%
140
+ ›Man...riesLegend grows o... content needs │ Tue ╻╻╻╻╻╻╻ ● Series 7 18%
141
141
  │ Wed ╻╻╻╻╻╻ ● Series 6 16%
142
142
  │ Thu ╻╻╻╻╻╻ ● Series 5 14%
143
143
  │ Fri ╻╻╻╻╻╻╻╻╻╻╻╻ ● Series 4 11%
144
144
  │ Sat ╻╻╻╻╻╻╻╻╻ ● Series 3 9%
145
+
146
+
147
+
148
+
149
+
150
+
151
+
152
+
153
+
154
+
155
+
156
+
157
+
145
158
  ↵ open detail ↑↓ navigate ^k actions │
146
159
 
147
-
148
-
149
-
150
-
151
-
152
-
153
-
154
-
155
-
156
-
157
-
158
-
159
-
160
160
  "
161
161
  `)
162
162
  expect(text).toContain('Series 8')
@@ -0,0 +1,48 @@
1
+ // Example: List with varying detail heights to test the grow-only minHeight
2
+ // ratchet on the detail panel. Navigating from a tall detail to a short one
3
+ // should NOT cause the footer to jump up (no layout shift).
4
+ import React from 'react'
5
+ import { List } from 'termcast'
6
+ import { renderWithProviders } from '../utils'
7
+
8
+ // Generate 25 items with alternating short/tall detail content.
9
+ // Odd-indexed items have tall detail (many lines), even-indexed have short detail.
10
+ const items = Array.from({ length: 25 }, (_, i) => {
11
+ const isTall = i % 2 === 1
12
+ const markdown = isTall
13
+ ? [
14
+ `# Item ${i} (tall)`,
15
+ '',
16
+ ...Array.from({ length: 12 }, (_, j) => `Line ${j + 1} of detail content for item ${i}.`),
17
+ ].join('\n')
18
+ : `# Item ${i} (short)\n\nBrief.`
19
+
20
+ return {
21
+ id: `item-${i}`,
22
+ title: `Item ${i}`,
23
+ subtitle: isTall ? 'tall' : 'short',
24
+ markdown,
25
+ }
26
+ })
27
+
28
+ function ListDetailHeightRatchet() {
29
+ return (
30
+ <List
31
+ navigationTitle="Height Ratchet Test"
32
+ searchBarPlaceholder="Search..."
33
+ isShowingDetail={true}
34
+ >
35
+ {items.map((item) => (
36
+ <List.Item
37
+ key={item.id}
38
+ id={item.id}
39
+ title={item.title}
40
+ subtitle={item.subtitle}
41
+ detail={<List.Item.Detail markdown={item.markdown} />}
42
+ />
43
+ ))}
44
+ </List>
45
+ )
46
+ }
47
+
48
+ await renderWithProviders(<ListDetailHeightRatchet />)
@@ -0,0 +1,161 @@
1
+ // E2E tests for the detail panel grow-only height ratchet.
2
+ // Verifies that the footer does not shift up when navigating from a tall
3
+ // detail item to a short one. The detail panel's minHeight should ratchet
4
+ // upward and never shrink back.
5
+ import { test, expect, afterEach, beforeEach } from 'vitest'
6
+ import { launchTerminal, Session } from 'tuistory/src'
7
+
8
+ let session: Session
9
+
10
+ beforeEach(async () => {
11
+ session = await launchTerminal({
12
+ command: 'bun',
13
+ args: ['src/examples/list-detail-height-ratchet.tsx'],
14
+ cols: 80,
15
+ rows: 30,
16
+ })
17
+ })
18
+
19
+ afterEach(() => {
20
+ session?.close()
21
+ })
22
+
23
+ function getFooterLineNumber(snapshot: string): number {
24
+ const lines = snapshot.split('\n')
25
+ return lines.findIndex((line) => line.includes('navigate'))
26
+ }
27
+
28
+ test('detail panel height ratchet prevents footer layout shift', async () => {
29
+ // Item 0 is short detail
30
+ const shortSnapshot = await session.text({
31
+ waitFor: (text) => {
32
+ return text.includes('›Item 0') && text.includes('Brief') && text.includes('navigate')
33
+ },
34
+ timeout: 10000,
35
+ })
36
+ expect(shortSnapshot).toMatchInlineSnapshot(`
37
+ "
38
+
39
+
40
+ Height Ratchet Test ──────────────────────────────────────────────────────
41
+
42
+ > Search...
43
+
44
+ ›Item 0 short │ Item 0 (short)
45
+ Item 1 tall │
46
+ Item 2 short │
47
+ Item 3 tall │ Brief.
48
+ Item 4 short │
49
+ Item 5 tall │
50
+ Item 6 short │
51
+ Item 7 tall │
52
+ Item 8 short │
53
+ Item 9 tall │
54
+ Item 10 short │
55
+ Item 11 tall │
56
+ Item 12 short │
57
+ Item 13 tall │
58
+ Item 14 short │
59
+ Item 15 tall │
60
+ Item 16 short │
61
+ Item 17 tall │
62
+ Item 18 short │
63
+
64
+
65
+ ↑↓ navigate ^k actions │
66
+
67
+ "
68
+ `)
69
+
70
+ // Navigate to Item 1 (tall detail) to ratchet the height up
71
+ await session.press('down')
72
+
73
+ const tallSnapshot = await session.text({
74
+ waitFor: (text) => {
75
+ return text.includes('›Item 1') && text.includes('Line 1') && text.includes('navigate')
76
+ },
77
+ })
78
+ expect(tallSnapshot).toMatchInlineSnapshot(`
79
+ "
80
+
81
+
82
+ Height Ratchet Test ──────────────────────────────────────────────────────
83
+
84
+ > Search...
85
+
86
+ Item 0 short │ Item 1 (tall) ▲
87
+ ›Item 1 tall │ Line 1 of detail content for item █
88
+ Item 2 short │ 1. █
89
+ Item 3 tall │ Line 2 of detail content for item █
90
+ Item 4 short │ 1. █
91
+ Item 5 tall │ Line 3 of detail content for item █
92
+ Item 6 short │ 1.
93
+ Item 7 tall │ Line 4 of detail content for item
94
+ Item 8 short │ 1.
95
+ Item 9 tall │ Line 5 of detail content for item
96
+ Item 10 short │ 1.
97
+ Item 11 tall │ Line 6 of detail content for item
98
+ Item 12 short │ 1.
99
+ Item 13 tall │ Line 7 of detail content for item
100
+ Item 14 short │ 1.
101
+ Item 15 tall │ Line 8 of detail content for item
102
+ Item 16 short │ 1.
103
+ Item 17 tall │ Line 9 of detail content for item
104
+ Item 18 short │ 1.
105
+ │ Line 10 of detail content for
106
+ │ item 1.
107
+ ↑↓ navigate ^k actions │ Line 11 of detail content for ▼
108
+
109
+ "
110
+ `)
111
+
112
+ // Navigate back to Item 0 (short detail).
113
+ // The footer should stay at the same line as the tall snapshot.
114
+ await session.press('up')
115
+
116
+ const backToShortSnapshot = await session.text({
117
+ waitFor: (text) => {
118
+ return text.includes('›Item 0') && text.includes('Brief') && text.includes('navigate')
119
+ },
120
+ })
121
+ expect(backToShortSnapshot).toMatchInlineSnapshot(`
122
+ "
123
+
124
+
125
+ Height Ratchet Test ──────────────────────────────────────────────────────
126
+
127
+ > Search...
128
+
129
+ ›Item 0 short │ Item 0 (short)
130
+ Item 1 tall │ Brief.
131
+ Item 2 short │
132
+ Item 3 tall │
133
+ Item 4 short │
134
+ Item 5 tall │
135
+ Item 6 short │
136
+ Item 7 tall │
137
+ Item 8 short │
138
+ Item 9 tall │
139
+ Item 10 short │
140
+ Item 11 tall │
141
+ Item 12 short │
142
+ Item 13 tall │
143
+ Item 14 short │
144
+ Item 15 tall │
145
+ Item 16 short │
146
+ Item 17 tall │
147
+ Item 18 short │
148
+
149
+
150
+ ↑↓ navigate ^k actions │
151
+
152
+ "
153
+ `)
154
+
155
+ // The key assertion: footer line should not move up when going from tall to short
156
+ const footerLineTall = getFooterLineNumber(tallSnapshot)
157
+ const footerLineBackToShort = getFooterLineNumber(backToShortSnapshot)
158
+
159
+ expect(footerLineBackToShort).toBe(footerLineTall)
160
+ expect(backToShortSnapshot).toContain('navigate')
161
+ }, 20000)