termcast 1.3.49 → 1.3.51
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/apis/environment.d.ts +1 -0
- package/dist/apis/environment.d.ts.map +1 -1
- package/dist/apis/environment.js +5 -0
- package/dist/apis/environment.js.map +1 -1
- package/dist/app.d.ts +33 -0
- package/dist/app.d.ts.map +1 -0
- package/dist/app.js +1125 -0
- package/dist/app.js.map +1 -0
- package/dist/cli.js +80 -0
- package/dist/cli.js.map +1 -1
- package/dist/components/detail.d.ts.map +1 -1
- package/dist/components/detail.js +20 -17
- package/dist/components/detail.js.map +1 -1
- package/dist/components/dropdown.d.ts.map +1 -1
- package/dist/components/dropdown.js +3 -2
- package/dist/components/dropdown.js.map +1 -1
- package/dist/components/footer.d.ts +6 -0
- package/dist/components/footer.d.ts.map +1 -1
- package/dist/components/footer.js +15 -6
- package/dist/components/footer.js.map +1 -1
- package/dist/components/form/checkbox.d.ts.map +1 -1
- package/dist/components/form/checkbox.js +1 -13
- package/dist/components/form/checkbox.js.map +1 -1
- package/dist/components/form/date-picker.js +2 -2
- package/dist/components/form/date-picker.js.map +1 -1
- package/dist/components/form/description.js +1 -1
- package/dist/components/form/description.js.map +1 -1
- package/dist/components/form/dropdown.d.ts.map +1 -1
- package/dist/components/form/dropdown.js +19 -3
- package/dist/components/form/dropdown.js.map +1 -1
- package/dist/components/form/file-picker.d.ts.map +1 -1
- package/dist/components/form/file-picker.js +22 -4
- package/dist/components/form/file-picker.js.map +1 -1
- package/dist/components/form/index.d.ts +3 -1
- package/dist/components/form/index.d.ts.map +1 -1
- package/dist/components/form/index.js +6 -4
- package/dist/components/form/index.js.map +1 -1
- package/dist/components/form/password-field.js +3 -3
- package/dist/components/form/password-field.js.map +1 -1
- package/dist/components/form/text-area.d.ts.map +1 -1
- package/dist/components/form/text-area.js +29 -6
- package/dist/components/form/text-area.js.map +1 -1
- package/dist/components/form/text-field.js +3 -3
- package/dist/components/form/text-field.js.map +1 -1
- package/dist/components/heatmap.d.ts +80 -0
- package/dist/components/heatmap.d.ts.map +1 -0
- package/dist/components/heatmap.js +405 -0
- package/dist/components/heatmap.js.map +1 -0
- package/dist/components/list.d.ts +2 -0
- package/dist/components/list.d.ts.map +1 -1
- package/dist/components/list.js +80 -52
- package/dist/components/list.js.map +1 -1
- package/dist/components/markdown.d.ts +7 -0
- package/dist/components/markdown.d.ts.map +1 -0
- package/dist/components/markdown.js +19 -0
- package/dist/components/markdown.js.map +1 -0
- package/dist/components/metadata.d.ts.map +1 -1
- package/dist/components/metadata.js +4 -1
- package/dist/components/metadata.js.map +1 -1
- package/dist/components/progress-bar.d.ts +37 -0
- package/dist/components/progress-bar.d.ts.map +1 -0
- package/dist/components/progress-bar.js +34 -0
- package/dist/components/progress-bar.js.map +1 -0
- package/dist/components/table.d.ts +3 -2
- package/dist/components/table.d.ts.map +1 -1
- package/dist/components/table.js +78 -63
- package/dist/components/table.js.map +1 -1
- package/dist/diagram-parser.d.ts +17 -3
- package/dist/diagram-parser.d.ts.map +1 -1
- package/dist/diagram-parser.js +17 -3
- package/dist/diagram-parser.js.map +1 -1
- package/dist/examples/list-slot.d.ts +2 -0
- package/dist/examples/list-slot.d.ts.map +1 -0
- package/dist/examples/list-slot.js +14 -0
- package/dist/examples/list-slot.js.map +1 -0
- package/dist/examples/list-with-dropdown.js +2 -4
- package/dist/examples/list-with-dropdown.js.map +1 -1
- package/dist/examples/simple-heatmap.d.ts +2 -0
- package/dist/examples/simple-heatmap.d.ts.map +1 -0
- package/dist/examples/simple-heatmap.js +37 -0
- package/dist/examples/simple-heatmap.js.map +1 -0
- package/dist/examples/simple-progress-bar.d.ts +2 -0
- package/dist/examples/simple-progress-bar.d.ts.map +1 -0
- package/dist/examples/simple-progress-bar.js +36 -0
- package/dist/examples/simple-progress-bar.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/internal/date-picker-widget.d.ts.map +1 -1
- package/dist/internal/date-picker-widget.js +5 -4
- package/dist/internal/date-picker-widget.js.map +1 -1
- package/dist/internal/navigation.d.ts.map +1 -1
- package/dist/internal/navigation.js +7 -2
- package/dist/internal/navigation.js.map +1 -1
- package/dist/internal/providers.d.ts.map +1 -1
- package/dist/internal/providers.js +42 -4
- package/dist/internal/providers.js.map +1 -1
- package/dist/logger.js +6 -1
- package/dist/logger.js.map +1 -1
- package/dist/state.d.ts +2 -0
- package/dist/state.d.ts.map +1 -1
- package/dist/state.js +31 -2
- package/dist/state.js.map +1 -1
- package/dist/theme.d.ts +1 -0
- package/dist/theme.d.ts.map +1 -1
- package/dist/theme.js +23 -1
- package/dist/theme.js.map +1 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +6 -1
- package/dist/utils.js.map +1 -1
- package/package.json +4 -4
- package/src/apis/environment.tsx +6 -0
- package/src/app.tsx +1487 -0
- package/src/assets/default-app-icon.png +0 -0
- package/src/cli.tsx +105 -0
- package/src/components/detail.tsx +32 -22
- package/src/components/dropdown.tsx +3 -2
- package/src/components/footer.tsx +37 -7
- package/src/components/form/checkbox.tsx +2 -17
- package/src/components/form/date-picker.tsx +2 -2
- package/src/components/form/description.tsx +1 -1
- package/src/components/form/dropdown.tsx +22 -3
- package/src/components/form/file-picker.tsx +33 -10
- package/src/components/form/index.tsx +10 -6
- package/src/components/form/password-field.tsx +3 -3
- package/src/components/form/text-area.tsx +31 -6
- package/src/components/form/text-field.tsx +3 -3
- package/src/components/heatmap.tsx +584 -0
- package/src/components/list.tsx +135 -72
- package/src/components/markdown.tsx +30 -0
- package/src/components/metadata.tsx +9 -2
- package/src/components/progress-bar.tsx +112 -0
- package/src/components/table.tsx +88 -71
- package/src/diagram-parser.tsx +17 -3
- package/src/examples/bar-graph-weekly.vitest.tsx +4 -4
- package/src/examples/detail-metadata-showcase.vitest.tsx +12 -12
- package/src/examples/form-basic.vitest.tsx +117 -16
- package/src/examples/graph-bar-chart.vitest.tsx +2 -2
- package/src/examples/graph-row.vitest.tsx +10 -10
- package/src/examples/internal/descendants-rerender.vitest.tsx +94 -46
- package/src/examples/internal/simple-scrollbox.vitest.tsx +38 -14
- package/src/examples/list-dropdown-default.vitest.tsx +78 -58
- package/src/examples/list-slot.tsx +38 -0
- package/src/examples/list-with-detail.vitest.tsx +8 -8
- package/src/examples/list-with-dropdown.tsx +2 -2
- package/src/examples/list-with-dropdown.vitest.tsx +16 -16
- package/src/examples/list-with-sections.vitest.tsx +45 -32
- package/src/examples/simple-detail-table.vitest.tsx +2 -2
- package/src/examples/simple-file-picker.vitest.tsx +1 -1
- package/src/examples/simple-grid.vitest.tsx +27 -53
- package/src/examples/simple-heatmap.tsx +63 -0
- package/src/examples/simple-heatmap.vitest.tsx +88 -0
- package/src/examples/simple-progress-bar.tsx +82 -0
- package/src/examples/simple-progress-bar.vitest.tsx +72 -0
- package/src/examples/table-edge-cases.vitest.tsx +1 -1
- package/src/index.tsx +19 -0
- package/src/internal/date-picker-widget.tsx +23 -12
- package/src/internal/navigation.tsx +7 -2
- package/src/internal/providers.tsx +48 -3
- package/src/logger.tsx +6 -1
- package/src/state.tsx +38 -2
- package/src/theme.tsx +26 -2
- package/src/utils.tsx +6 -1
|
@@ -33,7 +33,7 @@ test('list with dropdown navigation', async () => {
|
|
|
33
33
|
"
|
|
34
34
|
|
|
35
35
|
|
|
36
|
-
Search Beers
|
|
36
|
+
Search Beers ──────────────────────────────────────────── ◆ Acme
|
|
37
37
|
|
|
38
38
|
> Search... All ▾
|
|
39
39
|
|
|
@@ -49,7 +49,7 @@ test('list with dropdown navigation', async () => {
|
|
|
49
49
|
Apple Juice Juice
|
|
50
50
|
|
|
51
51
|
|
|
52
|
-
↑↓ navigate ^
|
|
52
|
+
↑↓ navigate ^k actions ^p select drink type
|
|
53
53
|
|
|
54
54
|
|
|
55
55
|
|
|
@@ -69,7 +69,7 @@ test('list with dropdown navigation', async () => {
|
|
|
69
69
|
"
|
|
70
70
|
|
|
71
71
|
|
|
72
|
-
Search Beers
|
|
72
|
+
Search Beers ──────────────────────────────────────────── ◆ Acme
|
|
73
73
|
╭────────────────────────────────────────────────────────────────╮
|
|
74
74
|
│ │
|
|
75
75
|
│ Select Drink Type esc │
|
|
@@ -103,7 +103,7 @@ test('list with dropdown navigation', async () => {
|
|
|
103
103
|
"
|
|
104
104
|
|
|
105
105
|
|
|
106
|
-
Search Beers
|
|
106
|
+
Search Beers ──────────────────────────────────────────── ◆ Acme
|
|
107
107
|
╭────────────────────────────────────────────────────────────────╮
|
|
108
108
|
│ │
|
|
109
109
|
│ Select Drink Type esc │
|
|
@@ -135,7 +135,7 @@ test('list with dropdown navigation', async () => {
|
|
|
135
135
|
"
|
|
136
136
|
|
|
137
137
|
|
|
138
|
-
Search Beers
|
|
138
|
+
Search Beers ──────────────────────────────────────────── ◆ Acme
|
|
139
139
|
╭────────────────────────────────────────────────────────────────╮
|
|
140
140
|
│ │
|
|
141
141
|
│ Select Drink Type esc │
|
|
@@ -167,7 +167,7 @@ test('list with dropdown navigation', async () => {
|
|
|
167
167
|
"
|
|
168
168
|
|
|
169
169
|
|
|
170
|
-
Search Beers
|
|
170
|
+
Search Beers ──────────────────────────────────────────── ◆ Acme
|
|
171
171
|
╭────────────────────────────────────────────────────────────────╮
|
|
172
172
|
│ │
|
|
173
173
|
│ Select Drink Type esc │
|
|
@@ -203,7 +203,7 @@ test('list with dropdown navigation', async () => {
|
|
|
203
203
|
"
|
|
204
204
|
|
|
205
205
|
|
|
206
|
-
Search Beers
|
|
206
|
+
Search Beers ──────────────────────────────────────────── ◆ Acme
|
|
207
207
|
|
|
208
208
|
> Search... Wine ▾
|
|
209
209
|
|
|
@@ -215,7 +215,7 @@ test('list with dropdown navigation', async () => {
|
|
|
215
215
|
|
|
216
216
|
|
|
217
217
|
|
|
218
|
-
↑↓ navigate ^
|
|
218
|
+
↑↓ navigate ^k actions ^p select drink type
|
|
219
219
|
|
|
220
220
|
|
|
221
221
|
|
|
@@ -253,7 +253,7 @@ test('small screen: dropdown accessory wastes vertical space', async () => {
|
|
|
253
253
|
"
|
|
254
254
|
|
|
255
255
|
|
|
256
|
-
Search Beers
|
|
256
|
+
Search Beers ────────────────────────────────── ◆ Acme
|
|
257
257
|
|
|
258
258
|
> Search... All ▾
|
|
259
259
|
|
|
@@ -265,7 +265,7 @@ test('small screen: dropdown accessory wastes vertical space', async () => {
|
|
|
265
265
|
Pinot Noir Wine
|
|
266
266
|
|
|
267
267
|
|
|
268
|
-
↑↓ navigate ^
|
|
268
|
+
↑↓ navigate ^k actions ^p select drink type"
|
|
269
269
|
`)
|
|
270
270
|
} finally {
|
|
271
271
|
smallSession.close()
|
|
@@ -292,7 +292,7 @@ test('list with dropdown search and filter', async () => {
|
|
|
292
292
|
"
|
|
293
293
|
|
|
294
294
|
|
|
295
|
-
Search Beers
|
|
295
|
+
Search Beers ──────────────────────────────────────────── ◆ Acme
|
|
296
296
|
╭────────────────────────────────────────────────────────────────╮
|
|
297
297
|
│ │
|
|
298
298
|
│ Select Drink Type esc │
|
|
@@ -334,7 +334,7 @@ test('list with dropdown search and filter', async () => {
|
|
|
334
334
|
"
|
|
335
335
|
|
|
336
336
|
|
|
337
|
-
Search Beers
|
|
337
|
+
Search Beers ──────────────────────────────────────────── ◆ Acme
|
|
338
338
|
|
|
339
339
|
> Search... All ▾
|
|
340
340
|
|
|
@@ -370,7 +370,7 @@ test('list with dropdown search and filter', async () => {
|
|
|
370
370
|
"
|
|
371
371
|
|
|
372
372
|
|
|
373
|
-
Search Beers
|
|
373
|
+
Search Beers ──────────────────────────────────────────── ◆ Acme
|
|
374
374
|
|
|
375
375
|
> Search... Wine ▾
|
|
376
376
|
|
|
@@ -382,7 +382,7 @@ test('list with dropdown search and filter', async () => {
|
|
|
382
382
|
|
|
383
383
|
|
|
384
384
|
|
|
385
|
-
↑↓ navigate ^
|
|
385
|
+
↑↓ navigate ^k actions ^p select drink type
|
|
386
386
|
|
|
387
387
|
|
|
388
388
|
|
|
@@ -406,7 +406,7 @@ test('list with dropdown search and filter', async () => {
|
|
|
406
406
|
"
|
|
407
407
|
|
|
408
408
|
|
|
409
|
-
Search Beers
|
|
409
|
+
Search Beers ──────────────────────────────────────────── ◆ Acme
|
|
410
410
|
|
|
411
411
|
> pinot Wine ▾
|
|
412
412
|
|
|
@@ -418,7 +418,7 @@ test('list with dropdown search and filter', async () => {
|
|
|
418
418
|
|
|
419
419
|
|
|
420
420
|
|
|
421
|
-
↑↓ navigate ^
|
|
421
|
+
↑↓ navigate ^k actions ^p select drink type
|
|
422
422
|
|
|
423
423
|
|
|
424
424
|
|
|
@@ -334,67 +334,79 @@ test('list click functionality', async () => {
|
|
|
334
334
|
},
|
|
335
335
|
})
|
|
336
336
|
|
|
337
|
-
// Click on "Banana"
|
|
337
|
+
// Click on "Banana" — should immediately execute first action (navigate to detail)
|
|
338
338
|
await session.click('Banana', { first: true })
|
|
339
339
|
|
|
340
|
-
const
|
|
341
|
-
expect(
|
|
340
|
+
const afterClickBanana = await session.text()
|
|
341
|
+
expect(afterClickBanana).toMatchInlineSnapshot(`
|
|
342
342
|
"
|
|
343
343
|
|
|
344
344
|
|
|
345
|
-
Simple List Example ────────────────────────────────────────────
|
|
346
345
|
|
|
347
|
-
> Search items...
|
|
348
346
|
|
|
349
|
-
|
|
350
|
-
Apple Red and sweet Fresh Popular
|
|
351
|
-
›Banana Yellow and nutritious Ripe
|
|
352
|
-
Orange Citrus and juicy Fresh
|
|
353
|
-
Grape Sweet clusters Seasonal
|
|
354
|
-
Mango Tropical delight Imported
|
|
355
|
-
Pineapple Sweet and tangy
|
|
356
|
-
Strawberry Red and sweet Popular
|
|
347
|
+
Banana
|
|
357
348
|
|
|
349
|
+
A yellow tropical fruit that's nutritious and energy-rich.
|
|
358
350
|
|
|
351
|
+
Benefits
|
|
352
|
+
|
|
353
|
+
- High in potassium
|
|
354
|
+
- Natural energy booster
|
|
355
|
+
- Aids digestion
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
esc go back ^k actions
|
|
359
360
|
|
|
360
|
-
↵ view details ↑↓ navigate ^k actions
|
|
361
361
|
|
|
362
362
|
"
|
|
363
363
|
`)
|
|
364
|
+
expect(afterClickBanana).toContain('Banana')
|
|
365
|
+
expect(afterClickBanana).toContain('go back')
|
|
364
366
|
|
|
365
|
-
//
|
|
367
|
+
// Go back to list
|
|
368
|
+
await session.press('escape')
|
|
369
|
+
await session.text({ waitFor: (text) => /search/i.test(text) })
|
|
370
|
+
|
|
371
|
+
// Click on "Apple" — should also immediately execute (Apple has actions)
|
|
366
372
|
await session.click('Apple', { first: true })
|
|
367
373
|
|
|
368
|
-
const
|
|
369
|
-
expect(
|
|
374
|
+
const afterClickApple = await session.text()
|
|
375
|
+
expect(afterClickApple).toMatchInlineSnapshot(`
|
|
370
376
|
"
|
|
371
377
|
|
|
372
378
|
|
|
373
|
-
Simple List Example ────────────────────────────────────────────
|
|
374
379
|
|
|
375
|
-
> Search items...
|
|
376
380
|
|
|
377
|
-
|
|
378
|
-
›Apple Red and sweet Fresh Popular
|
|
379
|
-
Banana Yellow and nutritious Ripe
|
|
380
|
-
Orange Citrus and juicy Fresh
|
|
381
|
-
Grape Sweet clusters Seasonal
|
|
382
|
-
Mango Tropical delight Imported
|
|
383
|
-
Pineapple Sweet and tangy
|
|
384
|
-
Strawberry Red and sweet Popular
|
|
381
|
+
Apple
|
|
385
382
|
|
|
383
|
+
A delicious red fruit that's sweet and crunchy.
|
|
386
384
|
|
|
385
|
+
Nutrition Facts
|
|
386
|
+
|
|
387
|
+
- High in fiber
|
|
388
|
+
- Rich in antioxidants
|
|
389
|
+
- Good source of vitamin C
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
esc go back ^k actions
|
|
387
394
|
|
|
388
|
-
↵ view details ↑↓ navigate ^k actions
|
|
389
395
|
|
|
390
396
|
"
|
|
391
397
|
`)
|
|
398
|
+
expect(afterClickApple).toContain('Apple')
|
|
399
|
+
expect(afterClickApple).toContain('go back')
|
|
400
|
+
|
|
401
|
+
// Go back to list
|
|
402
|
+
await session.press('escape')
|
|
403
|
+
await session.text({ waitFor: (text) => /search/i.test(text) })
|
|
392
404
|
|
|
393
|
-
// Click on "Grape"
|
|
405
|
+
// Click on "Grape" — no actions, should just select
|
|
394
406
|
await session.click('Grape', { first: true })
|
|
395
407
|
|
|
396
|
-
const
|
|
397
|
-
expect(
|
|
408
|
+
const afterClickGrape = await session.text()
|
|
409
|
+
expect(afterClickGrape).toMatchInlineSnapshot(`
|
|
398
410
|
"
|
|
399
411
|
|
|
400
412
|
|
|
@@ -417,7 +429,8 @@ test('list click functionality', async () => {
|
|
|
417
429
|
|
|
418
430
|
"
|
|
419
431
|
`)
|
|
420
|
-
|
|
432
|
+
expect(afterClickGrape).toContain('Grape')
|
|
433
|
+
}, 15000)
|
|
421
434
|
|
|
422
435
|
test('list actions panel with ctrl+k', async () => {
|
|
423
436
|
await session.text({
|
|
@@ -66,7 +66,6 @@ test('markdown tables render with borderless layout', async () => {
|
|
|
66
66
|
ap-south-1 89ms /api/health 500
|
|
67
67
|
|
|
68
68
|
|
|
69
|
-
esc go back ^k actions powered by termcast.app
|
|
70
69
|
|
|
71
70
|
|
|
72
71
|
|
|
@@ -83,6 +82,7 @@ test('markdown tables render with borderless layout', async () => {
|
|
|
83
82
|
|
|
84
83
|
|
|
85
84
|
|
|
85
|
+
esc go back ^k actions powered by termcast.app
|
|
86
86
|
|
|
87
87
|
"
|
|
88
88
|
`)
|
|
@@ -166,7 +166,6 @@ test('two tables render side by side in a Row', async () => {
|
|
|
166
166
|
ap-south-1 89ms /api/health 500
|
|
167
167
|
|
|
168
168
|
|
|
169
|
-
esc go back ^k actions powered by termcast.app
|
|
170
169
|
|
|
171
170
|
|
|
172
171
|
|
|
@@ -183,6 +182,7 @@ test('two tables render side by side in a Row', async () => {
|
|
|
183
182
|
|
|
184
183
|
|
|
185
184
|
|
|
185
|
+
esc go back ^k actions powered by termcast.app
|
|
186
186
|
|
|
187
187
|
"
|
|
188
188
|
`)
|
|
@@ -271,7 +271,7 @@ test('selecting first item with enter adds it to the list', async () => {
|
|
|
271
271
|
│ Enter file path...
|
|
272
272
|
│
|
|
273
273
|
│ Selected files:
|
|
274
|
-
│ • /Users/morse/Documents/GitHub/termcast/termcast/src
|
|
274
|
+
│ • /Users/morse/Documents/GitHub/termcast/termcast/src ✕
|
|
275
275
|
│ Choose a folder for output
|
|
276
276
|
│
|
|
277
277
|
◇ Select Single File
|
|
@@ -522,30 +522,27 @@ test('grid mouse interaction', async () => {
|
|
|
522
522
|
Simple Grid Example ────────────────────────────────────────────
|
|
523
523
|
|
|
524
524
|
> Search items...
|
|
525
|
-
╭────────────────────────────────────────────────────────────────╮
|
|
526
|
-
│ │
|
|
527
|
-
│ Actions esc │
|
|
528
|
-
│ │
|
|
529
|
-
│ > Search actions... │
|
|
530
|
-
│ │
|
|
531
|
-
│ ›Show Details │
|
|
532
|
-
│ Copy Emoji ⌃C │
|
|
533
|
-
│ │
|
|
534
|
-
│ Settings │
|
|
535
|
-
│ Change Theme... │
|
|
536
|
-
│ Toggle Console Logs │
|
|
537
|
-
│ │
|
|
538
|
-
│ │
|
|
539
|
-
│ │
|
|
540
|
-
│ │
|
|
541
|
-
│ │
|
|
542
|
-
│ ↵ select ↑↓ navigate │
|
|
543
|
-
│ │
|
|
544
|
-
╰────────────────────────────────────────────────────────────────╯"
|
|
545
|
-
`)
|
|
546
525
|
|
|
547
|
-
|
|
548
|
-
|
|
526
|
+
|
|
527
|
+
Animals
|
|
528
|
+
🐕 Dog
|
|
529
|
+
🐱 Cat
|
|
530
|
+
🐰 Rabbit
|
|
531
|
+
|
|
532
|
+
Others
|
|
533
|
+
🏠 House
|
|
534
|
+
🚗 Car
|
|
535
|
+
🚀 Rocket
|
|
536
|
+
›⭐ Star
|
|
537
|
+
🌙 Moon
|
|
538
|
+
☀ Sun
|
|
539
|
+
|
|
540
|
+
|
|
541
|
+
|
|
542
|
+
↵ show details ↑↓ navigate ^k actions
|
|
543
|
+
|
|
544
|
+
"
|
|
545
|
+
`)
|
|
549
546
|
|
|
550
547
|
// Navigate back up to make Apple visible.
|
|
551
548
|
// Grid is implemented via List, which uses edge-triggered pagination.
|
|
@@ -562,36 +559,13 @@ test('grid mouse interaction', async () => {
|
|
|
562
559
|
timeout: 5000,
|
|
563
560
|
})
|
|
564
561
|
|
|
565
|
-
// Click on "Apple"
|
|
562
|
+
// Click on "Apple" - it's already selected (first item after scrolling up),
|
|
563
|
+
// so clicking executes the first action (Show Details) which logs to console.
|
|
564
|
+
// Verify no actions dialog opened (unlike old behavior).
|
|
566
565
|
await session.click('Apple', { first: true })
|
|
567
566
|
|
|
568
567
|
const afterClickAppleSnapshot = await session.text()
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
Simple Grid Example ────────────────────────────────────────────
|
|
574
|
-
|
|
575
|
-
> Search items...
|
|
576
|
-
╭────────────────────────────────────────────────────────────────╮
|
|
577
|
-
│ │
|
|
578
|
-
│ Actions esc │
|
|
579
|
-
│ │
|
|
580
|
-
│ > Search actions... │
|
|
581
|
-
│ │
|
|
582
|
-
│ ›Show Details │
|
|
583
|
-
│ Copy Emoji ⌃C │
|
|
584
|
-
│ │
|
|
585
|
-
│ Settings │
|
|
586
|
-
│ Change Theme... │
|
|
587
|
-
│ Toggle Console Logs │
|
|
588
|
-
│ │
|
|
589
|
-
│ │
|
|
590
|
-
│ │
|
|
591
|
-
│ │
|
|
592
|
-
│ │
|
|
593
|
-
│ ↵ select ↑↓ navigate │
|
|
594
|
-
│ │
|
|
595
|
-
╰────────────────────────────────────────────────────────────────╯"
|
|
596
|
-
`)
|
|
597
|
-
}, 10000)
|
|
568
|
+
// Apple should still be selected, no actions dialog visible
|
|
569
|
+
expect(afterClickAppleSnapshot).toContain('›🍎 Apple')
|
|
570
|
+
expect(afterClickAppleSnapshot).not.toContain('Actions')
|
|
571
|
+
}, 30000)
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// Example: CalendarHeatmap component showcase with various color combinations.
|
|
2
|
+
// Shows month splits, width-based truncation, and different color palettes.
|
|
3
|
+
// Demonstrates Markdown component interleaved with Heatmaps for descriptions.
|
|
4
|
+
|
|
5
|
+
import { CalendarHeatmap, Color, Detail, Markdown } from 'termcast'
|
|
6
|
+
import type { CalendarHeatmapData } from 'termcast'
|
|
7
|
+
import { renderWithProviders } from '../utils'
|
|
8
|
+
|
|
9
|
+
function createRangeData(start: Date, dayCount: number, offset: number): CalendarHeatmapData[] {
|
|
10
|
+
return Array.from({ length: dayCount }, (_, index) => {
|
|
11
|
+
const date = new Date(start)
|
|
12
|
+
date.setDate(start.getDate() + index)
|
|
13
|
+
|
|
14
|
+
const dayOfWeek = date.getDay()
|
|
15
|
+
const weekendPenalty = dayOfWeek === 0 || dayOfWeek === 6 ? 0.35 : 1
|
|
16
|
+
const wave = (Math.sin((index + offset) / 6) + 1) / 2
|
|
17
|
+
const value = Math.round((1 + wave * 7) * weekendPenalty)
|
|
18
|
+
|
|
19
|
+
return {
|
|
20
|
+
date,
|
|
21
|
+
value,
|
|
22
|
+
}
|
|
23
|
+
})
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const summerData = createRangeData(new Date(2025, 5, 1), 110, 0)
|
|
27
|
+
const winterData = createRangeData(new Date(2026, 0, 5), 45, 31)
|
|
28
|
+
const longHistoryData = createRangeData(new Date(2021, 0, 1), 1800, 13)
|
|
29
|
+
const recentData = createRangeData(new Date(2025, 9, 1), 150, 7)
|
|
30
|
+
const shortBurst = createRangeData(new Date(2025, 8, 1), 180, 3)
|
|
31
|
+
const journalData = [...summerData, ...winterData]
|
|
32
|
+
|
|
33
|
+
function SimpleHeatmap() {
|
|
34
|
+
return (
|
|
35
|
+
<Detail
|
|
36
|
+
markdown={[
|
|
37
|
+
'# Calendar Heatmap Color Showcase',
|
|
38
|
+
'',
|
|
39
|
+
'Each heatmap demonstrates a different color combination.',
|
|
40
|
+
'Data has a late-fall gap to show that empty weeks are skipped.',
|
|
41
|
+
'Last heatmap renders multi-year data to verify width truncation.',
|
|
42
|
+
].join('\n')}
|
|
43
|
+
metadata={
|
|
44
|
+
<Detail.Metadata>
|
|
45
|
+
<Markdown content="**Long history** — 5 years of daily data in purple. Months that don't fit the terminal width are truncated from the left." />
|
|
46
|
+
<CalendarHeatmap data={longHistoryData} color={Color.Purple} />
|
|
47
|
+
<Markdown content="**Journal** — summer + winter entries in green, with a fall gap between the two ranges." />
|
|
48
|
+
<CalendarHeatmap data={journalData} color={Color.Green} />
|
|
49
|
+
<Markdown content="**Recent activity** — last 150 days in red, showing the sine-wave pattern clearly." />
|
|
50
|
+
<CalendarHeatmap data={recentData} color={Color.Red} />
|
|
51
|
+
<Markdown content="**Short burst** — 180 days in blue on a purple empty background." />
|
|
52
|
+
<CalendarHeatmap data={shortBurst} color={Color.Blue} emptyColor={Color.Purple} />
|
|
53
|
+
<Markdown content="**Warm tones** — orange cells on magenta empty, same journal data." />
|
|
54
|
+
<CalendarHeatmap data={journalData} color={Color.Orange} emptyColor={Color.Magenta} />
|
|
55
|
+
<Markdown content="**Yellow on blue** — high-contrast palette for the recent data set." />
|
|
56
|
+
<CalendarHeatmap data={recentData} color={Color.Yellow} emptyColor={Color.Blue} />
|
|
57
|
+
</Detail.Metadata>
|
|
58
|
+
}
|
|
59
|
+
/>
|
|
60
|
+
)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
renderWithProviders(<SimpleHeatmap />)
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// E2E tests for CalendarHeatmap with normal and overflow data ranges.
|
|
2
|
+
// Verifies month truncation does not overflow terminal width.
|
|
3
|
+
|
|
4
|
+
import { test, expect, afterEach, beforeEach } from 'vitest'
|
|
5
|
+
import { launchTerminal, Session } from 'tuistory/src'
|
|
6
|
+
|
|
7
|
+
let session: Session
|
|
8
|
+
|
|
9
|
+
beforeEach(async () => {
|
|
10
|
+
session = await launchTerminal({
|
|
11
|
+
command: 'bun',
|
|
12
|
+
args: ['src/examples/simple-heatmap.tsx'],
|
|
13
|
+
cols: 88,
|
|
14
|
+
rows: 50,
|
|
15
|
+
})
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
afterEach(() => {
|
|
19
|
+
session?.close()
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
test('renders calendar heatmaps with various color combinations', async () => {
|
|
23
|
+
const text = await session.text({
|
|
24
|
+
waitFor: (text) => {
|
|
25
|
+
return text.includes('Calendar Heatmap Color Showcase') && text.includes('Less')
|
|
26
|
+
},
|
|
27
|
+
timeout: 10000,
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
expect(text).toMatchInlineSnapshot(`
|
|
31
|
+
"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
█
|
|
35
|
+
|
|
36
|
+
Calendar Heatmap Color Showcase
|
|
37
|
+
|
|
38
|
+
Each heatmap demonstrates a different color combination.
|
|
39
|
+
Data has a late-fall gap to show that empty weeks are skipped.
|
|
40
|
+
Last heatmap renders multi-year data to verify width truncation.
|
|
41
|
+
|
|
42
|
+
Long history — 5 years of daily data in purple. Months that don't fit the
|
|
43
|
+
terminal width are truncated from the left.
|
|
44
|
+
|
|
45
|
+
May Jun Jul Aug Sep Oct Nov
|
|
46
|
+
◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼
|
|
47
|
+
◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ Mon
|
|
48
|
+
◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼
|
|
49
|
+
◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ Wed
|
|
50
|
+
◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼
|
|
51
|
+
◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ Fri
|
|
52
|
+
◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼
|
|
53
|
+
Less ◼ ◼ ◼ ◼ ◼ More
|
|
54
|
+
|
|
55
|
+
Journal — summer + winter entries in green, with a fall gap between the two
|
|
56
|
+
ranges.
|
|
57
|
+
|
|
58
|
+
Jun Jul Aug Sep Jan Feb
|
|
59
|
+
◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼
|
|
60
|
+
◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ Mon
|
|
61
|
+
◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼
|
|
62
|
+
◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ Wed
|
|
63
|
+
◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼
|
|
64
|
+
◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ Fri
|
|
65
|
+
◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼
|
|
66
|
+
Less ◼ ◼ ◼ ◼ ◼ More
|
|
67
|
+
|
|
68
|
+
Recent activity — last 150 days in red, showing the sine-wave pattern clearly.
|
|
69
|
+
|
|
70
|
+
Se Oct Nov Dec Jan Feb
|
|
71
|
+
◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼
|
|
72
|
+
◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ Mon
|
|
73
|
+
◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼
|
|
74
|
+
◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ Wed
|
|
75
|
+
◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼
|
|
76
|
+
◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ ◼ Fri
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
esc go back ^k actions powered by termcast.app
|
|
80
|
+
|
|
81
|
+
"
|
|
82
|
+
`)
|
|
83
|
+
|
|
84
|
+
const maxLineLength = text.split('\n').reduce((maxLength, line) => {
|
|
85
|
+
return Math.max(maxLength, line.length)
|
|
86
|
+
}, 0)
|
|
87
|
+
expect(maxLineLength).toBeLessThanOrEqual(88)
|
|
88
|
+
}, 30000)
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// Example: ProgressBar rendered inside List.Item.Detail.Metadata.
|
|
2
|
+
// Shows usage-style rows with title, bar+percentage in one line, and reset labels.
|
|
3
|
+
|
|
4
|
+
import React from 'react'
|
|
5
|
+
import { List, ProgressBar } from 'termcast'
|
|
6
|
+
import { renderWithProviders } from '../utils'
|
|
7
|
+
|
|
8
|
+
interface UsageItem {
|
|
9
|
+
title: string
|
|
10
|
+
subtitle: string
|
|
11
|
+
sessionUsage: number
|
|
12
|
+
sessionReset: string
|
|
13
|
+
weekUsage: number
|
|
14
|
+
weekReset: string
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const usageItems: UsageItem[] = [
|
|
18
|
+
{
|
|
19
|
+
title: 'OpenAI account',
|
|
20
|
+
subtitle: 'default workspace',
|
|
21
|
+
sessionUsage: 37,
|
|
22
|
+
sessionReset: 'Resets 9pm (Asia/Bangkok)',
|
|
23
|
+
weekUsage: 7,
|
|
24
|
+
weekReset: 'Resets Feb 27, 1pm (Asia/Bangkok)',
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
title: 'Anthropic account',
|
|
28
|
+
subtitle: 'research workspace',
|
|
29
|
+
sessionUsage: 82,
|
|
30
|
+
sessionReset: 'Resets 11pm (Europe/Rome)',
|
|
31
|
+
weekUsage: 46,
|
|
32
|
+
weekReset: 'Resets Mar 1, 9am (Europe/Rome)',
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
title: 'Google account',
|
|
36
|
+
subtitle: 'sandbox workspace',
|
|
37
|
+
sessionUsage: 15,
|
|
38
|
+
sessionReset: 'Resets 6pm (America/New_York)',
|
|
39
|
+
weekUsage: 24,
|
|
40
|
+
weekReset: 'Resets Mar 3, 8am (America/New_York)',
|
|
41
|
+
},
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
function SimpleProgressBar() {
|
|
45
|
+
return (
|
|
46
|
+
<List navigationTitle="ProgressBar Metadata" isShowingDetail={true}>
|
|
47
|
+
{usageItems.map((item) => {
|
|
48
|
+
return (
|
|
49
|
+
<List.Item
|
|
50
|
+
key={item.title}
|
|
51
|
+
title={item.title}
|
|
52
|
+
subtitle={item.subtitle}
|
|
53
|
+
detail={
|
|
54
|
+
<List.Item.Detail
|
|
55
|
+
metadata={
|
|
56
|
+
<List.Item.Detail.Metadata>
|
|
57
|
+
<ProgressBar
|
|
58
|
+
title="Current session"
|
|
59
|
+
value={item.sessionUsage}
|
|
60
|
+
percentageSuffix="used"
|
|
61
|
+
label={item.sessionReset}
|
|
62
|
+
/>
|
|
63
|
+
<ProgressBar
|
|
64
|
+
title="Current week (all models)"
|
|
65
|
+
value={item.weekUsage}
|
|
66
|
+
percentageSuffix="used"
|
|
67
|
+
label={item.weekReset}
|
|
68
|
+
barCharacter="▁"
|
|
69
|
+
trackCharacter="▁"
|
|
70
|
+
/>
|
|
71
|
+
</List.Item.Detail.Metadata>
|
|
72
|
+
}
|
|
73
|
+
/>
|
|
74
|
+
}
|
|
75
|
+
/>
|
|
76
|
+
)
|
|
77
|
+
})}
|
|
78
|
+
</List>
|
|
79
|
+
)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
renderWithProviders(<SimpleProgressBar />)
|