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.
- package/dist/components/detail.d.ts.map +1 -1
- package/dist/components/detail.js +14 -12
- package/dist/components/detail.js.map +1 -1
- package/dist/components/list.d.ts +4 -1
- package/dist/components/list.d.ts.map +1 -1
- package/dist/components/list.js +21 -10
- package/dist/components/list.js.map +1 -1
- package/dist/components/metadata.d.ts +15 -4
- package/dist/components/metadata.d.ts.map +1 -1
- package/dist/components/metadata.js +59 -20
- package/dist/components/metadata.js.map +1 -1
- package/dist/examples/detail-metadata-showcase.d.ts +11 -0
- package/dist/examples/detail-metadata-showcase.d.ts.map +1 -0
- package/dist/examples/detail-metadata-showcase.js +40 -0
- package/dist/examples/detail-metadata-showcase.js.map +1 -0
- package/dist/examples/list-detail-metadata.js +4 -2
- package/dist/examples/list-detail-metadata.js.map +1 -1
- package/package.json +6 -6
- package/src/components/detail.tsx +15 -12
- package/src/components/list.tsx +33 -12
- package/src/components/metadata.tsx +95 -44
- package/src/examples/detail-metadata-showcase.tsx +149 -0
- package/src/examples/detail-metadata-showcase.vitest.tsx +549 -0
- package/src/examples/form-dropdown.vitest.tsx +3 -3
- package/src/examples/list-detail-metadata.tsx +29 -1
- package/src/examples/list-detail-metadata.vitest.tsx +128 -15
- package/src/examples/list-with-detail.vitest.tsx +18 -18
- package/src/examples/list-with-sections.vitest.tsx +59 -15
- package/src/examples/simple-navigation.vitest.tsx +11 -11
|
@@ -580,15 +580,15 @@ test('form dropdown with default value', async () => {
|
|
|
580
580
|
|
|
581
581
|
|
|
582
582
|
|
|
583
|
-
|
|
583
|
+
▪ Dropdown Component Demo █
|
|
584
584
|
│ Test dropdown with sections, multiple selection, and more █
|
|
585
585
|
│ features █
|
|
586
586
|
│ █
|
|
587
|
-
|
|
587
|
+
◆ Programming Languages █
|
|
588
588
|
│ TypeScript, Rust █
|
|
589
589
|
│ █
|
|
590
590
|
│ Frontend █
|
|
591
|
-
|
|
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:
|
|
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
|
-
│
|
|
45
|
+
│ Email: john@example.com
|
|
44
46
|
│
|
|
45
|
-
│
|
|
46
|
-
│ ─────────────────
|
|
47
|
+
│ ──────────────────────────────────
|
|
47
48
|
│
|
|
48
|
-
│ Status:
|
|
49
|
-
│
|
|
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
|
-
│
|
|
82
|
-
│ This is a very long description
|
|
83
|
-
│ that would be truncated if shown
|
|
84
|
-
│ inline
|
|
111
|
+
│ ──────────────────────────────────
|
|
85
112
|
│
|
|
86
|
-
│
|
|
87
|
-
│
|
|
88
|
-
|
|
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
|
-
│
|
|
336
|
-
No items found │
|
|
335
|
+
│ bulbasaur ▲
|
|
336
|
+
No items found │ ▀
|
|
337
337
|
│ Illustration
|
|
338
338
|
│
|
|
339
339
|
│ Types
|
|
340
340
|
│
|
|
341
|
-
│
|
|
341
|
+
│ Grass / Poison
|
|
342
342
|
│
|
|
343
343
|
│ Characteristics
|
|
344
344
|
│
|
|
345
|
-
│ - Height:
|
|
346
|
-
│ - Weight:
|
|
345
|
+
│ - Height: 0.7m
|
|
346
|
+
│ - Weight: 6.9kg
|
|
347
347
|
│
|
|
348
348
|
│ Abilities
|
|
349
349
|
│
|
|
350
|
-
│ -
|
|
351
|
-
│ -
|
|
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
|
-
│
|
|
373
|
-
No items found │
|
|
372
|
+
│ bulbasaur ▲
|
|
373
|
+
No items found │ ▀
|
|
374
374
|
│ Illustration
|
|
375
375
|
│
|
|
376
376
|
│ Types
|
|
377
377
|
│
|
|
378
|
-
│
|
|
378
|
+
│ Grass / Poison
|
|
379
379
|
│
|
|
380
380
|
│ Characteristics
|
|
381
381
|
│
|
|
382
|
-
│ - Height:
|
|
383
|
-
│ - Weight:
|
|
382
|
+
│ - Height: 0.7m
|
|
383
|
+
│ - Weight: 6.9kg
|
|
384
384
|
│
|
|
385
385
|
│ Abilities
|
|
386
386
|
│
|
|
387
|
-
│ -
|
|
388
|
-
│ -
|
|
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
|
-
|
|
613
|
-
|
|
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
|
|
628
|
+
// Press down again - should still be on Carrot (no wrap at bottom)
|
|
629
629
|
await session.press('down')
|
|
630
630
|
|
|
631
|
-
const
|
|
632
|
-
expect(
|
|
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
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
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
|
-
|
|
190
|
+
First Item Navigate to first detail
|
|
191
191
|
Second Item Navigate to second detail
|
|
192
|
-
|
|
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:
|
|
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
|
|
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
|
-
|
|
262
|
+
First Item Navigate to first detail
|
|
263
263
|
Second Item Navigate to second detail
|
|
264
|
-
|
|
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
|
-
>
|
|
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
|
|