termcast 1.3.24 → 1.3.25

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 (51) hide show
  1. package/dist/apis/toast.d.ts +5 -0
  2. package/dist/apis/toast.d.ts.map +1 -1
  3. package/dist/apis/toast.js +7 -43
  4. package/dist/apis/toast.js.map +1 -1
  5. package/dist/build.d.ts.map +1 -1
  6. package/dist/build.js +1 -0
  7. package/dist/build.js.map +1 -1
  8. package/dist/cli.js +20 -10
  9. package/dist/cli.js.map +1 -1
  10. package/dist/compile.d.ts +2 -1
  11. package/dist/compile.d.ts.map +1 -1
  12. package/dist/compile.js +9 -7
  13. package/dist/compile.js.map +1 -1
  14. package/dist/components/form/index.d.ts.map +1 -1
  15. package/dist/components/form/index.js +5 -3
  16. package/dist/components/form/index.js.map +1 -1
  17. package/dist/components/list.d.ts.map +1 -1
  18. package/dist/components/list.js +16 -9
  19. package/dist/components/list.js.map +1 -1
  20. package/dist/examples/toast-variations.d.ts +2 -0
  21. package/dist/examples/toast-variations.d.ts.map +1 -0
  22. package/dist/examples/toast-variations.js +122 -0
  23. package/dist/examples/toast-variations.js.map +1 -0
  24. package/dist/release.d.ts +1 -1
  25. package/dist/release.d.ts.map +1 -1
  26. package/dist/release.js +29 -33
  27. package/dist/release.js.map +1 -1
  28. package/dist/utils/run-command.d.ts +3 -2
  29. package/dist/utils/run-command.d.ts.map +1 -1
  30. package/dist/utils/run-command.js +9 -3
  31. package/dist/utils/run-command.js.map +1 -1
  32. package/package.json +1 -3
  33. package/src/apis/toast.tsx +37 -62
  34. package/src/build.tsx +1 -0
  35. package/src/cli.tsx +21 -11
  36. package/src/compile.tsx +10 -6
  37. package/src/components/form/index.tsx +20 -11
  38. package/src/components/list.tsx +54 -31
  39. package/src/examples/form-basic.vitest.tsx +8 -8
  40. package/src/examples/list-with-detail.vitest.tsx +8 -8
  41. package/src/examples/list-with-sections.vitest.tsx +9 -9
  42. package/src/examples/list-with-toast.vitest.tsx +16 -16
  43. package/src/examples/simple-file-picker.vitest.tsx +12 -8
  44. package/src/examples/simple-grid.vitest.tsx +2 -2
  45. package/src/examples/simple-navigation.vitest.tsx +16 -16
  46. package/src/examples/swift-extension.vitest.tsx +2 -2
  47. package/src/examples/toast-variations.tsx +150 -0
  48. package/src/examples/toast-variations.vitest.tsx +370 -0
  49. package/src/extensions/dev.vitest.tsx +12 -10
  50. package/src/release.tsx +32 -38
  51. package/src/utils/run-command.tsx +10 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "termcast",
3
- "version": "1.3.24",
3
+ "version": "1.3.25",
4
4
  "description": "Raycast for the terminal",
5
5
  "repository": "https://github.com/remorses/termcast",
6
6
  "scripts": {
@@ -37,13 +37,11 @@
37
37
  "@tanstack/react-query-persist-client": "^5.85.5",
38
38
  "cac": "^6.7.14",
39
39
  "change-case": "^5.4.4",
40
- "cheerio": "^1.1.2",
41
40
  "colord": "^2.9.3",
42
41
  "google-auth-library": "^10.3.0",
43
42
  "jszip": "^3.10.1",
44
43
  "nanoid": "^5.1.5",
45
44
  "node-diff3": "^3.2.0",
46
- "node-pty": "^1.0.0",
47
45
  "react": "^19.2.0",
48
46
  "react-dom": "^19.2.0",
49
47
  "react-hook-form": "^7.62.0",
@@ -1,7 +1,6 @@
1
1
  import React, { useEffect, useState } from 'react'
2
2
  import { Theme } from 'termcast/src/theme'
3
3
  import { TextAttributes } from '@opentui/core'
4
- import { logger } from 'termcast/src/logger'
5
4
  import { useStore } from 'termcast/src/state'
6
5
  import { useKeyboard, useTerminalDimensions } from '@opentui/react'
7
6
  import { useIsInFocus } from 'termcast/src/internal/focus-context'
@@ -121,14 +120,13 @@ export class Toast {
121
120
  }
122
121
  }
123
122
 
124
- interface ToastContentProps {
123
+ export interface ToastContentProps {
125
124
  toast: Toast
126
125
  onHide: () => void
127
126
  }
128
127
 
129
- function ToastContent({ toast, onHide }: ToastContentProps): any {
128
+ export function ToastContent({ toast, onHide }: ToastContentProps): any {
130
129
  const [, forceUpdate] = useState(0)
131
- const dimensions = useTerminalDimensions()
132
130
  const inFocus = useIsInFocus()
133
131
 
134
132
  useEffect(() => {
@@ -203,78 +201,55 @@ function ToastContent({ toast, onHide }: ToastContentProps): any {
203
201
  const icon =
204
202
  toast.style === Toast.Style.Animated ? getIcon()[animationFrame] : getIcon()
205
203
 
206
- const wrapText = (text: string, maxWidth: number): string[] => {
207
- if (!text) return []
208
-
209
- const words = text.split(' ')
210
- const lines: string[] = []
211
- let currentLine = ''
212
-
213
- for (const word of words) {
214
- const testLine = currentLine ? `${currentLine} ${word}` : word
215
- if (testLine.length <= maxWidth) {
216
- currentLine = testLine
217
- } else {
218
- if (currentLine) {
219
- lines.push(currentLine)
220
- }
221
- currentLine = word
222
- }
223
- }
224
-
225
- if (currentLine) {
226
- lines.push(currentLine)
227
- }
228
-
229
- return lines.slice(0, 3)
230
- }
231
-
232
- const iconLength = 2
233
- const titleLength = toast.title.length
234
- const actionsLength = (() => {
235
- let length = 0
236
- if (toast.primaryAction) {
237
- length += toast.primaryAction.title.length + 4
238
- }
239
- if (toast.secondaryAction) {
240
- length += toast.secondaryAction.title.length + 4
241
- }
242
- return length
243
- })()
244
-
245
- const availableWidth =
246
- dimensions.width - iconLength - titleLength - actionsLength - 8
247
- const messageLines = toast.message
248
- ? wrapText(toast.message, Math.max(20, availableWidth))
249
- : []
250
-
251
204
  return (
252
205
  <box
253
206
  borderColor={Theme.border}
207
+ backgroundColor={Theme.background}
254
208
  paddingLeft={1}
255
209
  paddingRight={1}
256
210
  flexDirection='column'
257
211
  >
258
212
  <box flexDirection='row' alignItems='center'>
259
- <text fg={getIconColor()}>{icon} </text>
260
- <text fg={Theme.text} attributes={TextAttributes.BOLD}>
213
+ <text flexShrink={0} fg={getIconColor()}>
214
+ {icon}{' '}
215
+ </text>
216
+ <text flexShrink={0} fg={Theme.text} attributes={TextAttributes.BOLD}>
261
217
  {toast.title}
262
218
  </text>
263
- {messageLines.length > 0 && (
264
- <text fg={Theme.textMuted}> - {messageLines[0]}</text>
265
- )}
266
219
  {toast.primaryAction && (
267
- <text fg={Theme.primary}> [{toast.primaryAction.title} ↵]</text>
220
+ <box
221
+ flexShrink={0}
222
+ onMouseDown={() => {
223
+ toast.primaryAction?.onAction(toast)
224
+ }}
225
+ >
226
+ <text fg={Theme.primary}>
227
+ {' '}
228
+ [{toast.primaryAction.title} ↵]
229
+ </text>
230
+ </box>
268
231
  )}
269
232
  {toast.secondaryAction && (
270
- <text fg={Theme.textMuted}> [{toast.secondaryAction.title} ⇥]</text>
233
+ <box
234
+ flexShrink={0}
235
+ onMouseDown={() => {
236
+ toast.secondaryAction?.onAction(toast)
237
+ }}
238
+ >
239
+ <text fg={Theme.textMuted}>
240
+ {' '}
241
+ [{toast.secondaryAction.title} ⇥]
242
+ </text>
243
+ </box>
271
244
  )}
272
245
  </box>
273
- {messageLines.slice(1).map((line, index) => (
274
- <box key={index} paddingLeft={iconLength + titleLength + 3}>
275
- <text fg={Theme.textMuted}>{line}</text>
246
+ {toast.message && (
247
+ <box paddingLeft={2}>
248
+ <text flexShrink={0} fg={Theme.textMuted}>
249
+ {toast.message}
250
+ </text>
276
251
  </box>
277
- ))}
252
+ )}
278
253
  </box>
279
254
  )
280
255
  }
@@ -291,9 +266,9 @@ export function ToastOverlay(): any {
291
266
  <box
292
267
  position='absolute'
293
268
  left={0}
294
- top={dimensions.height - 3}
269
+ bottom={0}
295
270
  width={dimensions.width}
296
- height={3}
271
+ maxHeight={10}
297
272
  justifyContent='flex-end'
298
273
  alignItems='center'
299
274
  >
package/src/build.tsx CHANGED
@@ -204,6 +204,7 @@ export async function buildExtensionCommands({
204
204
  if (!fs.existsSync(bundleDir)) {
205
205
  fs.mkdirSync(bundleDir, { recursive: true })
206
206
  }
207
+ fs.writeFileSync(path.join(bundleDir, '.gitignore'), '*\n')
207
208
 
208
209
  const commandsData = getCommandsWithFiles({
209
210
  packageJsonPath: path.join(resolvedPath, 'package.json'),
package/src/cli.tsx CHANGED
@@ -222,7 +222,7 @@ cli
222
222
  single: options.single,
223
223
  })
224
224
 
225
- console.log(`\nRelease complete: v${result.version}`)
225
+ console.log(`\nRelease complete: ${result.tag}`)
226
226
  console.log(`Uploaded ${result.uploadedFiles.length} binaries`)
227
227
  } catch (error: any) {
228
228
  console.error('Release failed:', error.message)
@@ -409,14 +409,17 @@ cli
409
409
  cli
410
410
  .command('download <extensionName>', 'Download extension from Raycast extensions repo')
411
411
  .option('-o, --output <path>', 'Output directory', { default: '.' })
412
- .action(async (extensionName: string, options: { output: string }) => {
412
+ .option('--no-dir', 'Put files directly in output directory instead of creating extension subdirectory')
413
+ .action(async (extensionName: string, options: { output: string; dir: boolean }) => {
413
414
  try {
414
415
  const destPath = path.resolve(options.output)
415
- const extensionDir = path.join(destPath, extensionName)
416
+ // When --no-dir is passed, dir is false; put files directly in destPath
417
+ const extensionDir = options.dir ? path.join(destPath, extensionName) : destPath
418
+ const tempCloneDir = path.join(destPath, `.tmp-${extensionName}-${Date.now()}`)
416
419
 
417
420
  console.log(`Downloading extension '${extensionName}' from raycast/extensions...`)
418
421
 
419
- if (fs.existsSync(extensionDir)) {
422
+ if (options.dir && fs.existsSync(extensionDir)) {
420
423
  console.log(`Removing existing directory: ${extensionDir}`)
421
424
  fs.rmSync(extensionDir, { recursive: true, force: true })
422
425
  }
@@ -424,7 +427,8 @@ cli
424
427
  fs.mkdirSync(destPath, { recursive: true })
425
428
 
426
429
  const repoUrl = 'https://github.com/raycast/extensions.git'
427
- const cloneCmd = `git clone -n --depth=1 --filter=tree:0 "${repoUrl}" "${extensionName}"`
430
+ const cloneDirName = path.basename(tempCloneDir)
431
+ const cloneCmd = `git clone -n --depth=1 --filter=tree:0 "${repoUrl}" "${cloneDirName}"`
428
432
  console.log(`Running: ${cloneCmd}`)
429
433
  try {
430
434
  execSync(cloneCmd, {
@@ -440,11 +444,12 @@ cli
440
444
  console.log(`Running: ${sparseCmd}`)
441
445
  try {
442
446
  execSync(sparseCmd, {
443
- cwd: extensionDir,
447
+ cwd: tempCloneDir,
444
448
  stdio: 'inherit',
445
449
  })
446
450
  } catch (error) {
447
451
  console.error(`Failed to set sparse-checkout`)
452
+ fs.rmSync(tempCloneDir, { recursive: true, force: true })
448
453
  process.exit(1)
449
454
  }
450
455
 
@@ -452,22 +457,27 @@ cli
452
457
  console.log(`Running: ${checkoutCmd}`)
453
458
  try {
454
459
  execSync(checkoutCmd, {
455
- cwd: extensionDir,
460
+ cwd: tempCloneDir,
456
461
  stdio: 'inherit',
457
462
  })
458
463
  } catch (error) {
459
464
  console.error(`Failed to checkout files`)
465
+ fs.rmSync(tempCloneDir, { recursive: true, force: true })
460
466
  process.exit(1)
461
467
  }
462
468
 
463
- const extensionPath = path.join(extensionDir, 'extensions', extensionName)
469
+ const extensionPath = path.join(tempCloneDir, 'extensions', extensionName)
464
470
 
465
471
  if (!fs.existsSync(extensionPath)) {
466
472
  console.error(`Extension '${extensionName}' not found in raycast/extensions repo`)
467
- fs.rmSync(extensionDir, { recursive: true, force: true })
473
+ fs.rmSync(tempCloneDir, { recursive: true, force: true })
468
474
  process.exit(1)
469
475
  }
470
476
 
477
+ // Move files to final destination
478
+ if (options.dir) {
479
+ fs.mkdirSync(extensionDir, { recursive: true })
480
+ }
471
481
  const filesToMove = fs.readdirSync(extensionPath)
472
482
  for (const file of filesToMove) {
473
483
  const src = path.join(extensionPath, file)
@@ -475,8 +485,8 @@ cli
475
485
  fs.renameSync(src, dest)
476
486
  }
477
487
 
478
- fs.rmSync(path.join(extensionDir, 'extensions'), { recursive: true, force: true })
479
- fs.rmSync(path.join(extensionDir, '.git'), { recursive: true, force: true })
488
+ // Clean up temp clone directory
489
+ fs.rmSync(tempCloneDir, { recursive: true, force: true })
480
490
 
481
491
  console.log(`\nInstalling dependencies...`)
482
492
  execSync('npm install', {
package/src/compile.tsx CHANGED
@@ -105,15 +105,15 @@ export function getArchiveExtension(target: CompileTarget): string {
105
105
  export const ALL_TARGETS: CompileTarget[] = [
106
106
  { os: 'linux', arch: 'arm64' },
107
107
  { os: 'linux', arch: 'x64' },
108
- { os: 'linux', arch: 'x64', avx2: false },
109
- { os: 'linux', arch: 'arm64', abi: 'musl' },
110
- { os: 'linux', arch: 'x64', abi: 'musl' },
111
- { os: 'linux', arch: 'x64', abi: 'musl', avx2: false },
108
+ // { os: 'linux', arch: 'x64', avx2: false },
109
+ // { os: 'linux', arch: 'arm64', abi: 'musl' },
110
+ // { os: 'linux', arch: 'x64', abi: 'musl' },
111
+ // { os: 'linux', arch: 'x64', abi: 'musl', avx2: false },
112
112
  { os: 'darwin', arch: 'arm64' },
113
113
  { os: 'darwin', arch: 'x64' },
114
- { os: 'darwin', arch: 'x64', avx2: false },
114
+ // { os: 'darwin', arch: 'x64', avx2: false },
115
115
  { os: 'win32', arch: 'x64' },
116
- { os: 'win32', arch: 'x64', avx2: false },
116
+ // { os: 'win32', arch: 'x64', avx2: false },
117
117
  ]
118
118
 
119
119
  export function getCurrentTarget(): CompileTarget {
@@ -127,6 +127,7 @@ export interface CompileOptions {
127
127
  outfile?: string
128
128
  minify?: boolean
129
129
  target?: CompileTarget
130
+ version?: string
130
131
  }
131
132
 
132
133
  export interface CompileResult {
@@ -139,6 +140,7 @@ export async function compileExtension({
139
140
  outfile,
140
141
  minify = false,
141
142
  target,
143
+ version,
142
144
  }: CompileOptions): Promise<CompileResult> {
143
145
  const resolvedPath = path.resolve(extensionPath)
144
146
 
@@ -164,6 +166,7 @@ export async function compileExtension({
164
166
  if (!fs.existsSync(bundleDir)) {
165
167
  fs.mkdirSync(bundleDir, { recursive: true })
166
168
  }
169
+ fs.writeFileSync(path.join(bundleDir, '.gitignore'), '*\n')
167
170
 
168
171
  const entryCode = generateEntryCode({
169
172
  extensionPath: resolvedPath,
@@ -191,6 +194,7 @@ export async function compileExtension({
191
194
  compile: {
192
195
  outfile: defaultOutfile,
193
196
  },
197
+ define: { 'process.env.VERSION': JSON.stringify(version || '') },
194
198
  plugins: [raycastAliasPlugin, swiftLoaderPlugin],
195
199
  throw: false,
196
200
  } as Parameters<typeof Bun.build>[0])
@@ -102,17 +102,10 @@ export const useFormSubmit = () => {
102
102
  }
103
103
 
104
104
  function FormFooter(): any {
105
- return (
106
- <box
107
- border={false}
108
- style={{
109
- paddingLeft: 1,
110
- paddingRight: 1,
111
- paddingTop: 1,
112
- marginTop: 1,
113
- flexDirection: 'row',
114
- }}
115
- >
105
+ const hasToast = useStore((s) => s.toast !== null)
106
+
107
+ const content = hasToast ? null : (
108
+ <>
116
109
  <text fg={Theme.text} attributes={TextAttributes.BOLD}>
117
110
  ctrl ↵
118
111
  </text>
@@ -125,6 +118,22 @@ function FormFooter(): any {
125
118
  {' '}^k
126
119
  </text>
127
120
  <text fg={Theme.textMuted}> actions</text>
121
+ </>
122
+ )
123
+
124
+ return (
125
+ <box
126
+ border={false}
127
+ height={1}
128
+ style={{
129
+ paddingLeft: 1,
130
+ paddingRight: 1,
131
+ paddingTop: 1,
132
+ marginTop: 1,
133
+ flexDirection: 'row',
134
+ }}
135
+ >
136
+ {content}
128
137
  </box>
129
138
  )
130
139
  }
@@ -70,19 +70,10 @@ interface ActionsInterface {
70
70
 
71
71
  function ListFooter(): any {
72
72
  const firstActionTitle = useStore((s) => s.firstActionTitle)
73
+ const hasToast = useStore((s) => s.toast !== null)
73
74
 
74
- return (
75
- <box
76
- border={false}
77
- style={{
78
- paddingLeft: 1,
79
- flexShrink: 0,
80
- paddingRight: 1,
81
- paddingTop: 1,
82
- marginTop: 1,
83
- flexDirection: 'row',
84
- }}
85
- >
75
+ const content = hasToast ? null : (
76
+ <>
86
77
  {firstActionTitle && (
87
78
  <>
88
79
  <text fg={Theme.text} attributes={TextAttributes.BOLD}>
@@ -99,6 +90,23 @@ function ListFooter(): any {
99
90
  {' '}^k
100
91
  </text>
101
92
  <text fg={Theme.textMuted}> actions</text>
93
+ </>
94
+ )
95
+
96
+ return (
97
+ <box
98
+ border={false}
99
+ height={1}
100
+ style={{
101
+ paddingLeft: 1,
102
+ flexShrink: 0,
103
+ paddingRight: 1,
104
+ paddingTop: 1,
105
+ marginTop: 1,
106
+ flexDirection: 'row',
107
+ }}
108
+ >
109
+ {content}
102
110
  </box>
103
111
  )
104
112
  }
@@ -515,30 +523,45 @@ function ListDropdownDialog(props: ListDropdownDialogProps): any {
515
523
  )}
516
524
  </box>
517
525
 
518
- <box
519
- border={false}
520
- style={{
521
- paddingRight: 2,
522
- paddingLeft: 3,
523
- paddingBottom: 1,
524
- paddingTop: 1,
525
- flexDirection: 'row',
526
- }}
527
- >
528
- <text fg={Theme.text} attributes={TextAttributes.BOLD}>
529
-
530
- </text>
531
- <text fg={Theme.textMuted}> select</text>
532
- <text fg={Theme.text} attributes={TextAttributes.BOLD}>
533
- {' '}↑↓
534
- </text>
535
- <text fg={Theme.textMuted}> navigate</text>
536
- </box>
526
+ <DropdownFooter />
537
527
  </box>
538
528
  </DropdownDescendantsProvider>
539
529
  )
540
530
  }
541
531
 
532
+ function DropdownFooter(): any {
533
+ const hasToast = useStore((s) => s.toast !== null)
534
+
535
+ const content = hasToast ? null : (
536
+ <>
537
+ <text fg={Theme.text} attributes={TextAttributes.BOLD}>
538
+
539
+ </text>
540
+ <text fg={Theme.textMuted}> select</text>
541
+ <text fg={Theme.text} attributes={TextAttributes.BOLD}>
542
+ {' '}↑↓
543
+ </text>
544
+ <text fg={Theme.textMuted}> navigate</text>
545
+ </>
546
+ )
547
+
548
+ return (
549
+ <box
550
+ border={false}
551
+ height={1}
552
+ style={{
553
+ paddingRight: 2,
554
+ paddingLeft: 3,
555
+ paddingBottom: 1,
556
+ paddingTop: 1,
557
+ flexDirection: 'row',
558
+ }}
559
+ >
560
+ {content}
561
+ </box>
562
+ )
563
+ }
564
+
542
565
  // Render a single list item row
543
566
  function ListItemRow(props: {
544
567
  title: string
@@ -113,7 +113,7 @@ test('password field always shows asterisks and submits real value', async () =>
113
113
  │ Required field
114
114
 
115
115
  ◆ Password
116
- *********
116
+ **********
117
117
  │ Must be at least 8 characters
118
118
 
119
119
  ◇ Biography
@@ -170,7 +170,7 @@ test('password field always shows asterisks and submits real value', async () =>
170
170
  │ Required field
171
171
 
172
172
  ◇ Password
173
- *********
173
+ **********
174
174
  │ Must be at least 8 characters
175
175
 
176
176
  ◆ Biography
@@ -232,7 +232,7 @@ test('password field always shows asterisks and submits real value', async () =>
232
232
  │ Required field
233
233
 
234
234
  ◇ Password
235
- *********
235
+ **********
236
236
  │ Must be at least 8 characters
237
237
  │┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
238
238
  ◆┃
@@ -290,7 +290,7 @@ test('password field always shows asterisks and submits real value', async () =>
290
290
  │ Required field
291
291
 
292
292
  ◇ Password
293
- *********
293
+ **********
294
294
  │ Must be at least 8 characters
295
295
 
296
296
  ◆ Biography
@@ -324,10 +324,10 @@ test('password field always shows asterisks and submits real value', async () =>
324
324
 
325
325
  │ Mo Tu We Th Fr Sa Su
326
326
  │ 1 2 3 4 5 6 7
327
-
328
- ┌─────────────────────────────────────────────────────────────────┐
329
- c✓rFormsSubmitteda- Alliform data hasibeen captured successfully │
330
- └─────────────────────────────────────────────────────────────────┘"
327
+ ┌────────────────────────────────────────────────┐
328
+ │ ✓ Form Submitted │
329
+ All form data has been captured successfully │
330
+ └────────────────────────────────────────────────┘"
331
331
  `)
332
332
 
333
333
  // The toast "Form Submitted" in afterEnterSnapshot proves the form was submitted
@@ -47,18 +47,18 @@ test('list with detail view display and navigation', async () => {
47
47
 
48
48
  │ Characteristics
49
49
  │ - Height: 0.7m
50
- │ - ───────────────
50
+ │ - Weight: 6.9kg
51
51
 
52
- Characteristics:
53
- Height:
54
- 0.7m
52
+ Abilities
53
+ - Chlorophyll
54
+ - Overgrow
55
+ │ ─────────────────────────────────
55
56
 
56
- ─────────────────
57
- │ Weight:
58
- │ 6.9kg
57
+ Types:
59
58
 
59
+ │ Grass:
60
60
  ↵toggle detail ↑↓ navigate ^kactions │ ─────────────────
61
- Abilities: ▼"
61
+ ▼"
62
62
  `)
63
63
 
64
64
  await session.press('down')
@@ -480,19 +480,19 @@ test('list actions panel with ctrl+k', async () => {
480
480
  Search items...
481
481
 
482
482
  Fruits ▲
483
- ›Apple Red and sweet Fresh [Popular]
484
- Banana Yellow and nutritious Ripe
485
- Orange Citrus and juicy Fresh
486
- Grape Sweet clusters [Seasonal]
483
+ ›Apple Red and sweet Fresh [Popular]
484
+ Banana Yellow and nutritious Ripe
485
+ Orange Citrus and juicy Fresh
486
+ Grape Sweet clusters [Seasonal]
487
487
  Mango Tropical delight Imported
488
488
  Pineapple Sweet and tangy
489
489
  Strawberry Red and sweet [Popular]
490
-
491
-
492
490
 
493
- ↵ vie┌─────────────────────────────────────────────────────┐
494
- │ ✓ Added to Cart - Apple has been added to your cart │
495
- └─────────────────────────────────────────────────────┘"
491
+ Vegetables ▼
492
+ ┌─────────────────────────────────────┐
493
+ │ ✓ Added to Cart │
494
+ │ Apple has been added to your cart │
495
+ └─────────────────────────────────────┘"
496
496
  `)
497
497
  }, 10000)
498
498
 
@@ -42,10 +42,10 @@ test('list navigation works while toast is shown', async () => {
42
42
 
43
43
 
44
44
 
45
-
46
- ↑↓ navigate ^k a┌─────────────────────────┐
47
- ✓ Selected - First Item │
48
- └─────────────────────────┘"
45
+ ┌──────────────┐
46
+ Selected │
47
+ First Item │
48
+ └──────────────┘"
49
49
  `)
50
50
 
51
51
  await session.press('down')
@@ -70,10 +70,10 @@ test('list navigation works while toast is shown', async () => {
70
70
 
71
71
 
72
72
 
73
-
74
- ↑↓ navigate ^k ┌──────────────────────────┐
75
- ✓ Selected - Second Item │
76
- └──────────────────────────┘"
73
+ ┌───────────────┐
74
+ Selected │
75
+ Second Item │
76
+ └───────────────┘"
77
77
  `)
78
78
 
79
79
  await session.press('down')
@@ -98,10 +98,10 @@ test('list navigation works while toast is shown', async () => {
98
98
 
99
99
 
100
100
 
101
-
102
- ↑↓ navigate ^k a┌─────────────────────────┐
103
- ✓ Selected - Third Item │
104
- └─────────────────────────┘"
101
+ ┌──────────────┐
102
+ Selected │
103
+ Third Item │
104
+ └──────────────┘"
105
105
  `)
106
106
 
107
107
  await session.press('up')
@@ -126,9 +126,9 @@ test('list navigation works while toast is shown', async () => {
126
126
 
127
127
 
128
128
 
129
-
130
- ↑↓ navigate ^k ┌──────────────────────────┐
131
- ✓ Selected - Second Item │
132
- └──────────────────────────┘"
129
+ ┌───────────────┐
130
+ Selected │
131
+ Second Item │
132
+ └───────────────┘"
133
133
  `)
134
134
  }, 10000)