termcast 1.3.44 → 1.3.46

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.
@@ -580,15 +580,15 @@ test('form dropdown with default value', async () => {
580
580
 
581
581
 
582
582
 
583
- Dropdown Component Demo █
583
+ Dropdown Component Demo █
584
584
  │ Test dropdown with sections, multiple selection, and more █
585
585
  │ features █
586
586
  │ █
587
- Programming Languages █
587
+ Programming Languages █
588
588
  │ TypeScript, Rust █
589
589
  │ █
590
590
  │ Frontend █
591
- ● TypeScript █
591
+ │› ● TypeScript █
592
592
  │ ○ JavaScript █
593
593
  │ ○ React █
594
594
  │ ○ Vue █
@@ -1,5 +1,5 @@
1
1
  import React from 'react'
2
- import { List } from 'termcast'
2
+ import { List, Color } from 'termcast'
3
3
  import { renderWithProviders } from '../utils'
4
4
 
5
5
  const ListDetailMetadataExample = () => {
@@ -45,6 +45,34 @@ const ListDetailMetadataExample = () => {
45
45
  />
46
46
  }
47
47
  />
48
+ <List.Item
49
+ id="item3"
50
+ title="Colored & Tags"
51
+ detail={
52
+ <List.Item.Detail
53
+ markdown={`# Project Status
54
+
55
+ Overview of the current project state.`}
56
+ metadata={
57
+ <List.Item.Detail.Metadata>
58
+ <List.Item.Detail.Metadata.Label title="Info" />
59
+ <List.Item.Detail.Metadata.Label title="Status" text={{ value: "Active", color: Color.Green }} />
60
+ <List.Item.Detail.Metadata.Label title="Priority" text={{ value: "High", color: Color.Red }} />
61
+ <List.Item.Detail.Metadata.Label title="Type" text={{ value: "Feature", color: Color.Blue }} />
62
+ <List.Item.Detail.Metadata.Separator />
63
+ <List.Item.Detail.Metadata.Label title="Labels" />
64
+ <List.Item.Detail.Metadata.TagList title="Tags">
65
+ <List.Item.Detail.Metadata.TagList.Item text="bug" color={Color.Red} />
66
+ <List.Item.Detail.Metadata.TagList.Item text="feature" color={Color.Green} />
67
+ <List.Item.Detail.Metadata.TagList.Item text="urgent" color={Color.Orange} />
68
+ </List.Item.Detail.Metadata.TagList>
69
+ <List.Item.Detail.Metadata.Separator />
70
+ <List.Item.Detail.Metadata.Link title="Repo" target="https://github.com/example/repo" text="github.com/example" />
71
+ </List.Item.Detail.Metadata>
72
+ }
73
+ />
74
+ }
75
+ />
48
76
  </List>
49
77
  )
50
78
  }
@@ -8,7 +8,7 @@ beforeEach(async () => {
8
8
  command: 'bun',
9
9
  args: ['src/examples/list-detail-metadata.tsx'],
10
10
  cols: 80,
11
- rows: 20,
11
+ rows: 40,
12
12
  })
13
13
  })
14
14
 
@@ -38,17 +38,37 @@ test('list detail metadata label renders short values in row layout (key: value)
38
38
 
39
39
  ›Short Values
40
40
  Long Values │ Details
41
+ Colored & Tags │
41
42
 
43
+ │ Name: John Doe
42
44
 
43
- Name: John Doe
45
+ Email: john@example.com
44
46
 
45
- Email: john@example.com
46
- │ ─────────────────
47
+ ──────────────────────────────────
47
48
 
48
- │ Status: Active
49
- Website: example.com
49
+ │ Status: Active
50
+
51
+ │ Website: example.com
50
52
  ↑↓ navigate ^k actions │
51
53
 
54
+
55
+
56
+
57
+
58
+
59
+
60
+
61
+
62
+
63
+
64
+
65
+
66
+
67
+
68
+
69
+
70
+
71
+
52
72
  "
53
73
  `)
54
74
  }, 10000)
@@ -75,18 +95,111 @@ test('list detail metadata renders long values in column layout (key on one line
75
95
  > Search...
76
96
 
77
97
  Short Values
78
- ›Long Values │ Info with Long Values
79
-
98
+ ›Long Values │ Info with Long Values
99
+ Colored & Tags
100
+
101
+ │ Description: This is a very long
102
+ │ description that
103
+ │ would be truncated
104
+ │ if shown inline
105
+
106
+ │ Path: /Users/username/
107
+ │ Documents/Projects/
108
+ │ my-project/src/
109
+ │ components
80
110
 
81
- Description:
82
- │ This is a very long description
83
- │ that would be truncated if shown
84
- │ inline
111
+ ──────────────────────────────────
85
112
 
86
- Path:
87
- /Users/username/Documents/
88
- ↑↓ navigate ^k actions Projects/my-project/src/components▼
113
+ Short: OK
114
+
115
+ URL: example.com/very/
116
+ │ long/path
117
+ ↑↓ navigate ^k actions │
118
+
119
+
120
+
121
+
122
+
123
+
124
+
125
+
126
+
127
+
128
+
89
129
 
90
130
  "
91
131
  `)
92
132
  }, 10000)
133
+
134
+ test('list detail metadata renders colored values and tag lists', async () => {
135
+ await session.text({
136
+ waitFor: (text) => text.includes('Metadata Test'),
137
+ })
138
+
139
+ // Navigate to third item
140
+ await session.press('down')
141
+ await session.press('down')
142
+
143
+ const snapshot = await session.text({
144
+ waitFor: (text) => {
145
+ return text.includes('Colored & Tags') && text.includes('Project Status') && text.includes('Tags')
146
+ },
147
+ })
148
+
149
+ expect(snapshot).toMatchInlineSnapshot(`
150
+ "
151
+
152
+
153
+ Metadata Test ────────────────────────────────────────────────────────────
154
+
155
+ > Search...
156
+
157
+ Short Values
158
+ Long Values │ Project Status
159
+ ›Colored & Tags │
160
+ │ Overview of the current project
161
+ │ state.
162
+
163
+
164
+ │ Info
165
+
166
+ │ Status: Active
167
+
168
+ │ Priority: High
169
+
170
+ │ Type: Feature
171
+
172
+ │ ──────────────────────────────────
173
+
174
+ │ Labels
175
+
176
+ │ Tags: bug feature urgent
177
+
178
+ │ ──────────────────────────────────
179
+
180
+ │ Repo: github.com/example
181
+ ↑↓ navigate ^k actions │
182
+
183
+
184
+
185
+
186
+
187
+
188
+
189
+
190
+ "
191
+ `)
192
+
193
+ // Verify colored values present
194
+ expect(snapshot).toContain('Active')
195
+ expect(snapshot).toContain('High')
196
+ expect(snapshot).toContain('Feature')
197
+
198
+ // Verify tags present
199
+ expect(snapshot).toContain('bug')
200
+ expect(snapshot).toContain('feature')
201
+ expect(snapshot).toContain('urgent')
202
+
203
+ // Verify link
204
+ expect(snapshot).toContain('github.com/example')
205
+ }, 10000)
@@ -54,11 +54,11 @@ test('list with detail view display and navigation', async () => {
54
54
  │ Abilities
55
55
 
56
56
  │ - Chlorophyll
57
+ │ - Overgrow
57
58
 
58
-
59
-
60
-
61
-
59
+
60
+ │ Types
61
+ ↵ toggle detail ↑↓ navigate ^k a │ ▼
62
62
 
63
63
  "
64
64
  `)
@@ -332,23 +332,23 @@ test('list detail view search functionality', async () => {
332
332
  > water
333
333
 
334
334
 
335
- wartortle
336
- No items found │
335
+ bulbasaur
336
+ No items found │
337
337
  │ Illustration
338
338
 
339
339
  │ Types
340
340
 
341
- Water
341
+ Grass / Poison
342
342
 
343
343
  │ Characteristics
344
344
 
345
- │ - Height: 1m
346
- │ - Weight: 22.5kg
345
+ │ - Height: 0.7m
346
+ │ - Weight: 6.9kg
347
347
 
348
348
  │ Abilities
349
349
 
350
- │ - Torrent
351
- │ - Rain Dish
350
+ │ - Chlorophyll
351
+ │ - Overgrow
352
352
 
353
353
 
354
354
  │ Types
@@ -369,23 +369,23 @@ test('list detail view search functionality', async () => {
369
369
  > water
370
370
 
371
371
 
372
- wartortle
373
- No items found │
372
+ bulbasaur
373
+ No items found │
374
374
  │ Illustration
375
375
 
376
376
  │ Types
377
377
 
378
- Water
378
+ Grass / Poison
379
379
 
380
380
  │ Characteristics
381
381
 
382
- │ - Height: 1m
383
- │ - Weight: 22.5kg
382
+ │ - Height: 0.7m
383
+ │ - Weight: 6.9kg
384
384
 
385
385
  │ Abilities
386
386
 
387
- │ - Torrent
388
- │ - Rain Dish
387
+ │ - Chlorophyll
388
+ │ - Overgrow
389
389
 
390
390
 
391
391
  │ Types
@@ -597,7 +597,7 @@ test('filtering selects first visible item and navigation works', async () => {
597
597
  "
598
598
  `)
599
599
 
600
- // Press down again
600
+ // Press down again - should stay on Carrot (no wrap)
601
601
  await session.press('down')
602
602
 
603
603
  const afterSecondDownSnapshot = await session.text()
@@ -609,15 +609,15 @@ test('filtering selects first visible item and navigation works', async () => {
609
609
 
610
610
  > ora
611
611
 
612
- Orange Citrus and juicy Fresh
613
- Carrot Orange and crunchy [Healthy]
612
+ Orange Citrus and juicy Fresh
613
+ Carrot Orange and crunchy [Healthy]
614
614
 
615
615
 
616
616
 
617
617
 
618
618
 
619
619
 
620
- ↑↓ navigate ^k actions
620
+ ↵ view details ↑↓ navigate ^k actions
621
621
 
622
622
 
623
623
 
@@ -625,11 +625,11 @@ test('filtering selects first visible item and navigation works', async () => {
625
625
  "
626
626
  `)
627
627
 
628
- // Press down to wrap back
628
+ // Press down again - should still be on Carrot (no wrap at bottom)
629
629
  await session.press('down')
630
630
 
631
- const afterWrapSnapshot = await session.text()
632
- expect(afterWrapSnapshot).toMatchInlineSnapshot(`
631
+ const afterNoWrapSnapshot = await session.text()
632
+ expect(afterNoWrapSnapshot).toMatchInlineSnapshot(`
633
633
  "
634
634
 
635
635
 
@@ -652,6 +652,9 @@ test('filtering selects first visible item and navigation works', async () => {
652
652
 
653
653
  "
654
654
  `)
655
+ // Verify Carrot is still selected (not wrapped to Orange)
656
+ expect(afterNoWrapSnapshot).toContain('›Carrot')
657
+ expect(afterNoWrapSnapshot).not.toContain('›Orange')
655
658
  }, 10000)
656
659
 
657
660
  test('list scrollbox scrolling with sections', async () => {
@@ -795,15 +798,15 @@ test('list scrollbox scrolling with sections', async () => {
795
798
 
796
799
  > Search items...
797
800
 
798
- Carrot Orange and crunchy [Healthy]
799
- Lettuce Green and fresh
800
- Broccoli Green florets [Healthy]
801
- Spinach Leafy greens Organic
802
- Tomato Red and ripe
803
- Cucumber Cool and crisp
804
- Bell Pepper Colorful and crunchy [Fresh]
801
+ Fruits
802
+ ›Apple Red and sweet Fresh [Popular]
803
+ Banana Yellow and nutritious Ripe
804
+ Orange Citrus and juicy Fresh
805
+ Grape Sweet clusters [Seasonal]
806
+ Mango Tropical delight Imported
807
+ Pineapple Sweet and tangy
808
+ Strawberry Red and sweet [Popular]
805
809
 
806
- ›Bread Freshly baked Today [New]
807
810
 
808
811
 
809
812
  ↵ view details ↑↓ navigate ^k actions
@@ -845,3 +848,44 @@ test('search resets selection to first visible item without flash', async () =>
845
848
  expect(afterLet).toContain('›Lettuce')
846
849
  expect(afterLet).not.toContain('›Grape')
847
850
  }, 10000)
851
+
852
+ test('list does not wrap at top boundary', async () => {
853
+ await session.text({
854
+ waitFor: (text) => {
855
+ return /search/i.test(text)
856
+ },
857
+ })
858
+
859
+ // First item (Apple) should be selected
860
+ const initialSnapshot = await session.text()
861
+ expect(initialSnapshot).toContain('›Apple')
862
+
863
+ // Press up at top - should stay on Apple
864
+ await session.press('up')
865
+
866
+ const afterUpSnapshot = await session.text()
867
+ expect(afterUpSnapshot).toMatchInlineSnapshot(`
868
+ "
869
+
870
+
871
+ Simple List Example ────────────────────────────────────────────
872
+
873
+ > Search items...
874
+
875
+ Fruits
876
+ ›Apple Red and sweet Fresh [Popular]
877
+ Banana Yellow and nutritious Ripe
878
+ Orange Citrus and juicy Fresh
879
+ Grape Sweet clusters [Seasonal]
880
+ Mango Tropical delight Imported
881
+ Pineapple Sweet and tangy
882
+ Strawberry Red and sweet [Popular]
883
+
884
+
885
+
886
+ ↵ view details ↑↓ navigate ^k actions
887
+
888
+ "
889
+ `)
890
+ expect(afterUpSnapshot).toContain('›Apple')
891
+ }, 10000)
@@ -187,9 +187,9 @@ test('navigation between main and detail views', async () => {
187
187
  > Main view
188
188
 
189
189
  Items
190
- First Item Navigate to first detail
190
+ First Item Navigate to first detail
191
191
  Second Item Navigate to second detail
192
- Third Item Navigate to third detail
192
+ Third Item Navigate to third detail
193
193
 
194
194
 
195
195
 
@@ -215,12 +215,12 @@ test('navigation between main and detail views', async () => {
215
215
  "
216
216
 
217
217
 
218
- Detail: First Item ─────────────────────────────────────────────
218
+ Detail: Third Item ─────────────────────────────────────────────
219
219
 
220
220
  > Detail view - Press ESC to go back
221
221
 
222
222
  Details
223
- ›This is the detail view for First Item Press Enter to go back or
223
+ ›This is the detail view for Third Item Press Enter to go back or
224
224
 
225
225
 
226
226
 
@@ -259,9 +259,9 @@ test('navigation between main and detail views', async () => {
259
259
  > Main view
260
260
 
261
261
  Items
262
- First Item Navigate to first detail
262
+ First Item Navigate to first detail
263
263
  Second Item Navigate to second detail
264
- Third Item Navigate to third detail
264
+ Third Item Navigate to third detail
265
265
 
266
266
 
267
267
 
@@ -525,12 +525,12 @@ test('search functionality in main and detail views', async () => {
525
525
 
526
526
  Navigation Example ─────────────────────────────────────────────
527
527
 
528
- > second
529
-
530
- ›Second Item Navigate to second detail
531
-
532
-
528
+ > Main view
533
529
 
530
+ Items
531
+ ›First Item Navigate to first detail
532
+ Second Item Navigate to second detail
533
+ Third Item Navigate to third detail
534
534
 
535
535
 
536
536