create-cascade 0.1.6 → 0.1.8
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/index.js +272 -71
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -111,11 +111,13 @@ function printHelp() {
|
|
|
111
111
|
}
|
|
112
112
|
|
|
113
113
|
function normalizePackageName(name) {
|
|
114
|
-
return
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
114
|
+
return (
|
|
115
|
+
name
|
|
116
|
+
.trim()
|
|
117
|
+
.toLowerCase()
|
|
118
|
+
.replace(/[^a-z0-9-_]+/g, "-")
|
|
119
|
+
.replace(/^-+|-+$/g, "") || "cascade-app"
|
|
120
|
+
)
|
|
119
121
|
}
|
|
120
122
|
|
|
121
123
|
function ensureDirectoryIsEmpty(targetDir) {
|
|
@@ -158,7 +160,9 @@ async function selectOption(rl, label, options) {
|
|
|
158
160
|
const prefix = isSelected ? `${ANSI_BOLD}${ANSI_CYAN}>${ANSI_RESET}` : " "
|
|
159
161
|
const styleStart = isSelected ? `${ANSI_BOLD}${ANSI_CYAN}` : ""
|
|
160
162
|
const styleEnd = isSelected ? ANSI_RESET : ""
|
|
161
|
-
stdout.write(
|
|
163
|
+
stdout.write(
|
|
164
|
+
`${prefix} ${styleStart}${option.label}${styleEnd} ${ANSI_DIM}(${option.id}) - ${option.description}${ANSI_RESET}\n`
|
|
165
|
+
)
|
|
162
166
|
}
|
|
163
167
|
|
|
164
168
|
stdout.write(`${ANSI_DIM}Use Up/Down arrows and Enter${ANSI_RESET}\n`)
|
|
@@ -367,84 +371,212 @@ function getSource(framework, starter) {
|
|
|
367
371
|
|
|
368
372
|
const renderer = await createCliRenderer({ exitOnCtrlC: true })
|
|
369
373
|
|
|
370
|
-
const
|
|
374
|
+
const root = new BoxRenderable(renderer, {
|
|
375
|
+
width: "100%",
|
|
376
|
+
height: "100%",
|
|
377
|
+
padding: 1,
|
|
378
|
+
flexDirection: "column",
|
|
379
|
+
})
|
|
380
|
+
|
|
381
|
+
const card = new BoxRenderable(renderer, {
|
|
371
382
|
border: true,
|
|
372
383
|
borderStyle: "single",
|
|
373
384
|
padding: 1,
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
height: 8,
|
|
385
|
+
width: 72,
|
|
386
|
+
height: 16,
|
|
377
387
|
flexDirection: "column",
|
|
378
388
|
})
|
|
379
389
|
|
|
390
|
+
const header = new BoxRenderable(renderer, {
|
|
391
|
+
flexDirection: "column",
|
|
392
|
+
marginBottom: 1,
|
|
393
|
+
})
|
|
394
|
+
|
|
380
395
|
const title = new TextRenderable(renderer, {
|
|
381
|
-
content: "
|
|
396
|
+
content: "Cascade Core",
|
|
382
397
|
fg: "#00ff99",
|
|
383
398
|
})
|
|
384
399
|
|
|
385
400
|
const subtitle = new TextRenderable(renderer, {
|
|
386
|
-
content: "
|
|
401
|
+
content: "A tiny terminal UI runtime with clean layout primitives.",
|
|
402
|
+
fg: "#cbd5e1",
|
|
403
|
+
marginTop: 1,
|
|
404
|
+
})
|
|
405
|
+
|
|
406
|
+
header.add(title)
|
|
407
|
+
header.add(subtitle)
|
|
408
|
+
|
|
409
|
+
const steps = new BoxRenderable(renderer, {
|
|
410
|
+
flexDirection: "column",
|
|
387
411
|
marginTop: 1,
|
|
388
|
-
|
|
412
|
+
})
|
|
413
|
+
|
|
414
|
+
const s1 = new TextRenderable(renderer, { content: "1) Edit src/index.ts", fg: "#e2e8f0" })
|
|
415
|
+
const s2 = new TextRenderable(renderer, { content: "2) bun run dev", fg: "#e2e8f0", marginTop: 1 })
|
|
416
|
+
const s3 = new TextRenderable(renderer, { content: "3) Compose renderables into screens", fg: "#e2e8f0", marginTop: 1 })
|
|
417
|
+
|
|
418
|
+
steps.add(s1)
|
|
419
|
+
steps.add(s2)
|
|
420
|
+
steps.add(s3)
|
|
421
|
+
|
|
422
|
+
const footer = new BoxRenderable(renderer, {
|
|
423
|
+
marginTop: 2,
|
|
424
|
+
border: true,
|
|
425
|
+
borderStyle: "single",
|
|
426
|
+
padding: 1,
|
|
427
|
+
flexDirection: "column",
|
|
428
|
+
})
|
|
429
|
+
|
|
430
|
+
const keys = new TextRenderable(renderer, {
|
|
431
|
+
content: "Keys: Ctrl+C quit",
|
|
432
|
+
fg: "#94a3b8",
|
|
389
433
|
})
|
|
390
434
|
|
|
391
435
|
const hint = new TextRenderable(renderer, {
|
|
392
|
-
content: "
|
|
436
|
+
content: "Tip: Keep rendering deterministic. Let state drive UI updates.",
|
|
437
|
+
fg: "#94a3b8",
|
|
393
438
|
marginTop: 1,
|
|
394
|
-
fg: "#999999",
|
|
395
439
|
})
|
|
396
440
|
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
441
|
+
footer.add(keys)
|
|
442
|
+
footer.add(hint)
|
|
443
|
+
|
|
444
|
+
card.add(header)
|
|
445
|
+
card.add(steps)
|
|
446
|
+
card.add(footer)
|
|
447
|
+
|
|
448
|
+
root.add(card)
|
|
449
|
+
renderer.root.add(root)
|
|
401
450
|
`,
|
|
402
|
-
counter: `import { TextRenderable, createCliRenderer } from "@cascadetui/core"
|
|
451
|
+
counter: `import { BoxRenderable, TextRenderable, createCliRenderer } from "@cascadetui/core"
|
|
403
452
|
|
|
404
453
|
const renderer = await createCliRenderer({ exitOnCtrlC: true })
|
|
405
454
|
let count = 0
|
|
406
455
|
|
|
407
|
-
const
|
|
408
|
-
|
|
409
|
-
|
|
456
|
+
const root = new BoxRenderable(renderer, {
|
|
457
|
+
width: "100%",
|
|
458
|
+
height: "100%",
|
|
459
|
+
padding: 1,
|
|
460
|
+
flexDirection: "column",
|
|
461
|
+
})
|
|
462
|
+
|
|
463
|
+
const card = new BoxRenderable(renderer, {
|
|
464
|
+
border: true,
|
|
465
|
+
borderStyle: "single",
|
|
466
|
+
padding: 1,
|
|
467
|
+
width: 60,
|
|
468
|
+
height: 10,
|
|
469
|
+
flexDirection: "column",
|
|
470
|
+
})
|
|
471
|
+
|
|
472
|
+
const title = new TextRenderable(renderer, {
|
|
473
|
+
content: "Core Counter",
|
|
410
474
|
fg: "#00ff99",
|
|
411
475
|
})
|
|
412
476
|
|
|
413
|
-
renderer
|
|
477
|
+
const value = new TextRenderable(renderer, {
|
|
478
|
+
content: "Count: 0",
|
|
479
|
+
fg: "#e2e8f0",
|
|
480
|
+
marginTop: 1,
|
|
481
|
+
})
|
|
482
|
+
|
|
483
|
+
const meta = new TextRenderable(renderer, {
|
|
484
|
+
content: "Updates every second. Ctrl+C to exit.",
|
|
485
|
+
fg: "#94a3b8",
|
|
486
|
+
marginTop: 1,
|
|
487
|
+
})
|
|
488
|
+
|
|
489
|
+
card.add(title)
|
|
490
|
+
card.add(value)
|
|
491
|
+
card.add(meta)
|
|
492
|
+
|
|
493
|
+
root.add(card)
|
|
494
|
+
renderer.root.add(root)
|
|
414
495
|
|
|
415
496
|
setInterval(() => {
|
|
416
497
|
count += 1
|
|
417
|
-
|
|
498
|
+
value.content = \`Count: \${count}\`
|
|
418
499
|
}, 1000)
|
|
419
500
|
`,
|
|
420
501
|
layout: `import { BoxRenderable, TextRenderable, createCliRenderer } from "@cascadetui/core"
|
|
421
502
|
|
|
422
503
|
const renderer = await createCliRenderer({ exitOnCtrlC: true })
|
|
423
504
|
|
|
424
|
-
const
|
|
505
|
+
const root = new BoxRenderable(renderer, {
|
|
506
|
+
width: "100%",
|
|
507
|
+
height: "100%",
|
|
508
|
+
padding: 1,
|
|
509
|
+
flexDirection: "row",
|
|
510
|
+
gap: 2,
|
|
511
|
+
})
|
|
512
|
+
|
|
513
|
+
const sidebar = new BoxRenderable(renderer, {
|
|
425
514
|
border: true,
|
|
426
515
|
borderStyle: "single",
|
|
427
516
|
padding: 1,
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
height: 9,
|
|
517
|
+
width: 26,
|
|
518
|
+
height: 18,
|
|
431
519
|
flexDirection: "column",
|
|
432
520
|
})
|
|
433
521
|
|
|
434
|
-
const
|
|
435
|
-
content: "
|
|
522
|
+
const sideTitle = new TextRenderable(renderer, {
|
|
523
|
+
content: "Navigation",
|
|
436
524
|
fg: "#00ff99",
|
|
437
525
|
})
|
|
438
526
|
|
|
439
|
-
const
|
|
440
|
-
|
|
527
|
+
const nav1 = new TextRenderable(renderer, { content: "• Overview", fg: "#e2e8f0", marginTop: 1 })
|
|
528
|
+
const nav2 = new TextRenderable(renderer, { content: "• Components", fg: "#e2e8f0", marginTop: 1 })
|
|
529
|
+
const nav3 = new TextRenderable(renderer, { content: "• Input & Focus", fg: "#e2e8f0", marginTop: 1 })
|
|
530
|
+
const nav4 = new TextRenderable(renderer, { content: "• Performance", fg: "#e2e8f0", marginTop: 1 })
|
|
531
|
+
|
|
532
|
+
sidebar.add(sideTitle)
|
|
533
|
+
sidebar.add(nav1)
|
|
534
|
+
sidebar.add(nav2)
|
|
535
|
+
sidebar.add(nav3)
|
|
536
|
+
sidebar.add(nav4)
|
|
537
|
+
|
|
538
|
+
const main = new BoxRenderable(renderer, {
|
|
539
|
+
border: true,
|
|
540
|
+
borderStyle: "single",
|
|
541
|
+
padding: 1,
|
|
542
|
+
width: 74,
|
|
543
|
+
height: 18,
|
|
544
|
+
flexDirection: "column",
|
|
545
|
+
})
|
|
546
|
+
|
|
547
|
+
const mainTitle = new TextRenderable(renderer, {
|
|
548
|
+
content: "Layout Starter",
|
|
549
|
+
fg: "#00ff99",
|
|
550
|
+
})
|
|
551
|
+
|
|
552
|
+
const mainBody = new TextRenderable(renderer, {
|
|
553
|
+
content: "Compose a screen with a sidebar + content panel. Add your own state and update text/content deterministically.",
|
|
554
|
+
fg: "#cbd5e1",
|
|
441
555
|
marginTop: 1,
|
|
442
|
-
fg: "#cccccc",
|
|
443
556
|
})
|
|
444
557
|
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
558
|
+
const mainFooter = new BoxRenderable(renderer, {
|
|
559
|
+
border: true,
|
|
560
|
+
borderStyle: "single",
|
|
561
|
+
padding: 1,
|
|
562
|
+
marginTop: 2,
|
|
563
|
+
flexDirection: "column",
|
|
564
|
+
})
|
|
565
|
+
|
|
566
|
+
const footerText = new TextRenderable(renderer, {
|
|
567
|
+
content: "Keys: Ctrl+C quit",
|
|
568
|
+
fg: "#94a3b8",
|
|
569
|
+
})
|
|
570
|
+
|
|
571
|
+
mainFooter.add(footerText)
|
|
572
|
+
|
|
573
|
+
main.add(mainTitle)
|
|
574
|
+
main.add(mainBody)
|
|
575
|
+
main.add(mainFooter)
|
|
576
|
+
|
|
577
|
+
root.add(sidebar)
|
|
578
|
+
root.add(main)
|
|
579
|
+
renderer.root.add(root)
|
|
448
580
|
`,
|
|
449
581
|
},
|
|
450
582
|
react: {
|
|
@@ -453,10 +585,20 @@ import { createRoot } from "@cascadetui/react"
|
|
|
453
585
|
|
|
454
586
|
function App() {
|
|
455
587
|
return (
|
|
456
|
-
<box style={{
|
|
457
|
-
<
|
|
458
|
-
|
|
459
|
-
|
|
588
|
+
<box style={{ width: "100%", height: "100%", padding: 1, flexDirection: "column", alignItems: "flex-start" }}>
|
|
589
|
+
<box style={{ border: true, borderStyle: "single", padding: 1, width: 72, height: 16, flexDirection: "column" }}>
|
|
590
|
+
<text content="Cascade React" fg="#00ff99" />
|
|
591
|
+
<text content="Build interactive terminal UIs with components and hooks." fg="#cbd5e1" marginTop={1} />
|
|
592
|
+
<box style={{ flexDirection: "column", marginTop: 2 }}>
|
|
593
|
+
<text content="1) Edit src/index.tsx" fg="#e2e8f0" />
|
|
594
|
+
<text content="2) bun run dev" fg="#e2e8f0" marginTop={1} />
|
|
595
|
+
<text content="3) Add screens, keymaps, and deterministic state" fg="#e2e8f0" marginTop={1} />
|
|
596
|
+
</box>
|
|
597
|
+
<box style={{ border: true, borderStyle: "single", padding: 1, marginTop: 2, flexDirection: "column" }}>
|
|
598
|
+
<text content="Keys: Ctrl+C quit" fg="#94a3b8" />
|
|
599
|
+
<text content="Tip: Keep expensive panels stable. Avoid re-render storms in lists." fg="#94a3b8" marginTop={1} />
|
|
600
|
+
</box>
|
|
601
|
+
</box>
|
|
460
602
|
</box>
|
|
461
603
|
)
|
|
462
604
|
}
|
|
@@ -466,19 +608,27 @@ createRoot(renderer).render(<App />)
|
|
|
466
608
|
`,
|
|
467
609
|
counter: `import { createCliRenderer } from "@cascadetui/core"
|
|
468
610
|
import { createRoot } from "@cascadetui/react"
|
|
469
|
-
import { useEffect, useState } from "react"
|
|
611
|
+
import { useEffect, useMemo, useState } from "react"
|
|
470
612
|
|
|
471
613
|
function App() {
|
|
472
614
|
const [count, setCount] = useState(0)
|
|
615
|
+
const startedAt = useMemo(() => Date.now(), [])
|
|
473
616
|
|
|
474
617
|
useEffect(() => {
|
|
475
618
|
const timer = setInterval(() => setCount((value) => value + 1), 1000)
|
|
476
619
|
return () => clearInterval(timer)
|
|
477
620
|
}, [])
|
|
478
621
|
|
|
622
|
+
const seconds = Math.floor((Date.now() - startedAt) / 1000)
|
|
623
|
+
|
|
479
624
|
return (
|
|
480
|
-
<box style={{
|
|
481
|
-
<
|
|
625
|
+
<box style={{ width: "100%", height: "100%", padding: 1, flexDirection: "column" }}>
|
|
626
|
+
<box style={{ border: true, borderStyle: "single", padding: 1, width: 60, height: 10, flexDirection: "column" }}>
|
|
627
|
+
<text content="React Counter" fg="#00ff99" />
|
|
628
|
+
<text content={\`Count: \${count}\`} fg="#e2e8f0" marginTop={1} />
|
|
629
|
+
<text content={\`Uptime: \${seconds}s\`} fg="#cbd5e1" marginTop={1} />
|
|
630
|
+
<text content="Ctrl+C to exit" fg="#94a3b8" marginTop={1} />
|
|
631
|
+
</box>
|
|
482
632
|
</box>
|
|
483
633
|
)
|
|
484
634
|
}
|
|
@@ -488,22 +638,36 @@ createRoot(renderer).render(<App />)
|
|
|
488
638
|
`,
|
|
489
639
|
login: `import { createCliRenderer } from "@cascadetui/core"
|
|
490
640
|
import { createRoot, useKeyboard } from "@cascadetui/react"
|
|
491
|
-
import { useState } from "react"
|
|
641
|
+
import { useMemo, useState } from "react"
|
|
492
642
|
|
|
493
643
|
function App() {
|
|
494
644
|
const [username, setUsername] = useState("")
|
|
495
645
|
const [password, setPassword] = useState("")
|
|
496
|
-
const [focused, setFocused] = useState("username")
|
|
497
|
-
const [status, setStatus] = useState("idle")
|
|
646
|
+
const [focused, setFocused] = useState<"username" | "password">("username")
|
|
647
|
+
const [status, setStatus] = useState<"idle" | "invalid" | "success">("idle")
|
|
648
|
+
|
|
649
|
+
const statusText = useMemo(() => {
|
|
650
|
+
if (status === "success") return "Authenticated"
|
|
651
|
+
if (status === "invalid") return "Invalid credentials"
|
|
652
|
+
return "Idle"
|
|
653
|
+
}, [status])
|
|
498
654
|
|
|
499
655
|
useKeyboard((key) => {
|
|
500
656
|
if (key.name === "tab") {
|
|
501
657
|
setFocused((value) => (value === "username" ? "password" : "username"))
|
|
658
|
+
return
|
|
659
|
+
}
|
|
660
|
+
if (key.name === "escape") {
|
|
661
|
+
setUsername("")
|
|
662
|
+
setPassword("")
|
|
663
|
+
setStatus("idle")
|
|
664
|
+
setFocused("username")
|
|
665
|
+
return
|
|
502
666
|
}
|
|
503
667
|
})
|
|
504
668
|
|
|
505
669
|
const submit = () => {
|
|
506
|
-
if (username === "admin" && password === "secret") {
|
|
670
|
+
if (username.trim() === "admin" && password === "secret") {
|
|
507
671
|
setStatus("success")
|
|
508
672
|
return
|
|
509
673
|
}
|
|
@@ -511,15 +675,19 @@ function App() {
|
|
|
511
675
|
}
|
|
512
676
|
|
|
513
677
|
return (
|
|
514
|
-
<box style={{ padding: 2, flexDirection: "column" }}>
|
|
678
|
+
<box style={{ width: "100%", height: "100%", padding: 2, flexDirection: "column" }}>
|
|
515
679
|
<text content="Cascade Login" fg="#00ff99" />
|
|
516
|
-
<
|
|
517
|
-
|
|
680
|
+
<text content="Tab switch fields, Enter submit, Esc reset" fg="#94a3b8" marginTop={1} />
|
|
681
|
+
<box title="Username" style={{ border: true, borderStyle: "single", width: 44, height: 3, marginTop: 2 }}>
|
|
682
|
+
<input focused={focused === "username"} placeholder="admin" value={username} onInput={setUsername} onSubmit={submit} />
|
|
683
|
+
</box>
|
|
684
|
+
<box title="Password" style={{ border: true, borderStyle: "single", width: 44, height: 3, marginTop: 1 }}>
|
|
685
|
+
<input focused={focused === "password"} placeholder="secret" value={password} onInput={setPassword} onSubmit={submit} />
|
|
518
686
|
</box>
|
|
519
|
-
<box
|
|
520
|
-
<
|
|
687
|
+
<box style={{ border: true, borderStyle: "single", padding: 1, width: 44, marginTop: 2, flexDirection: "column" }}>
|
|
688
|
+
<text content={\`Status: \${statusText}\`} fg={status === "success" ? "green" : status === "invalid" ? "yellow" : "#cbd5e1"} />
|
|
689
|
+
<text content={\`Focused: \${focused}\`} fg="#94a3b8" marginTop={1} />
|
|
521
690
|
</box>
|
|
522
|
-
<text content={\`Status: \${status}\`} marginTop={1} fg={status === "success" ? "green" : "yellow"} />
|
|
523
691
|
</box>
|
|
524
692
|
)
|
|
525
693
|
}
|
|
@@ -532,10 +700,20 @@ createRoot(renderer).render(<App />)
|
|
|
532
700
|
minimal: `import { render } from "@cascadetui/solid"
|
|
533
701
|
|
|
534
702
|
const App = () => (
|
|
535
|
-
<box style={{
|
|
536
|
-
<
|
|
537
|
-
|
|
538
|
-
|
|
703
|
+
<box style={{ width: "100%", height: "100%", padding: 1, flexDirection: "column" }}>
|
|
704
|
+
<box style={{ border: true, borderStyle: "single", padding: 1, width: 72, height: 16, flexDirection: "column" }}>
|
|
705
|
+
<text content="Cascade Solid" fg="#00ff99" />
|
|
706
|
+
<text content="Write reactive terminal apps with signals and components." fg="#cbd5e1" marginTop={1} />
|
|
707
|
+
<box style={{ flexDirection: "column", marginTop: 2 }}>
|
|
708
|
+
<text content="1) Edit src/index.tsx" fg="#e2e8f0" />
|
|
709
|
+
<text content="2) bun run dev" fg="#e2e8f0" marginTop={1} />
|
|
710
|
+
<text content="3) Keep state and rendering deterministic" fg="#e2e8f0" marginTop={1} />
|
|
711
|
+
</box>
|
|
712
|
+
<box style={{ border: true, borderStyle: "single", padding: 1, marginTop: 2, flexDirection: "column" }}>
|
|
713
|
+
<text content="Keys: Ctrl+C quit" fg="#94a3b8" />
|
|
714
|
+
<text content="Tip: Keep list rows stable to avoid selection jumps." fg="#94a3b8" marginTop={1} />
|
|
715
|
+
</box>
|
|
716
|
+
</box>
|
|
539
717
|
</box>
|
|
540
718
|
)
|
|
541
719
|
|
|
@@ -546,12 +724,23 @@ import { createSignal, onCleanup } from "solid-js"
|
|
|
546
724
|
|
|
547
725
|
const App = () => {
|
|
548
726
|
const [count, setCount] = createSignal(0)
|
|
549
|
-
const
|
|
727
|
+
const [uptime, setUptime] = createSignal(0)
|
|
728
|
+
|
|
729
|
+
const timer = setInterval(() => {
|
|
730
|
+
setCount((value) => value + 1)
|
|
731
|
+
setUptime((value) => value + 1)
|
|
732
|
+
}, 1000)
|
|
733
|
+
|
|
550
734
|
onCleanup(() => clearInterval(timer))
|
|
551
735
|
|
|
552
736
|
return (
|
|
553
|
-
<box style={{
|
|
554
|
-
<
|
|
737
|
+
<box style={{ width: "100%", height: "100%", padding: 1, flexDirection: "column" }}>
|
|
738
|
+
<box style={{ border: true, borderStyle: "single", padding: 1, width: 60, height: 10, flexDirection: "column" }}>
|
|
739
|
+
<text content="Solid Counter" fg="#00ff99" />
|
|
740
|
+
<text content={\`Count: \${count()}\`} fg="#e2e8f0" marginTop={1} />
|
|
741
|
+
<text content={\`Uptime: \${uptime()}s\`} fg="#cbd5e1" marginTop={1} />
|
|
742
|
+
<text content="Ctrl+C to exit" fg="#94a3b8" marginTop={1} />
|
|
743
|
+
</box>
|
|
555
744
|
</box>
|
|
556
745
|
)
|
|
557
746
|
}
|
|
@@ -564,20 +753,32 @@ import { createSignal } from "solid-js"
|
|
|
564
753
|
const App = () => {
|
|
565
754
|
const [value, setValue] = createSignal("")
|
|
566
755
|
const [submitted, setSubmitted] = createSignal("")
|
|
756
|
+
const [status, setStatus] = createSignal<"idle" | "submitted">("idle")
|
|
567
757
|
|
|
568
758
|
return (
|
|
569
|
-
<box style={{ padding: 2, flexDirection: "column" }}>
|
|
570
|
-
<text content="
|
|
571
|
-
<
|
|
759
|
+
<box style={{ width: "100%", height: "100%", padding: 2, flexDirection: "column" }}>
|
|
760
|
+
<text content="Solid Input" fg="#00ff99" />
|
|
761
|
+
<text content="Enter submit, Ctrl+C quit" fg="#94a3b8" marginTop={1} />
|
|
762
|
+
<box title="Message" style={{ border: true, borderStyle: "single", width: 52, height: 3, marginTop: 2 }}>
|
|
572
763
|
<input
|
|
573
764
|
focused
|
|
574
765
|
placeholder="Type something..."
|
|
575
|
-
|
|
576
|
-
|
|
766
|
+
value={value()}
|
|
767
|
+
onInput={(nextValue) => {
|
|
768
|
+
setValue(nextValue)
|
|
769
|
+
setStatus("idle")
|
|
770
|
+
}}
|
|
771
|
+
onSubmit={(nextValue) => {
|
|
772
|
+
setSubmitted(nextValue)
|
|
773
|
+
setStatus("submitted")
|
|
774
|
+
}}
|
|
577
775
|
/>
|
|
578
776
|
</box>
|
|
579
|
-
<
|
|
580
|
-
|
|
777
|
+
<box style={{ border: true, borderStyle: "single", padding: 1, width: 52, marginTop: 2, flexDirection: "column" }}>
|
|
778
|
+
<text content={\`Current: \${value() || "-"}\`} fg="#cbd5e1" />
|
|
779
|
+
<text content={\`Last submit: \${submitted() || "-"}\`} fg="#cbd5e1" marginTop={1} />
|
|
780
|
+
<text content={\`Status: \${status()}\`} fg={status() === "submitted" ? "green" : "#94a3b8"} marginTop={1} />
|
|
781
|
+
</box>
|
|
581
782
|
</box>
|
|
582
783
|
)
|
|
583
784
|
}
|
|
@@ -689,6 +890,6 @@ async function main() {
|
|
|
689
890
|
}
|
|
690
891
|
|
|
691
892
|
main().catch((error) => {
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
})
|
|
893
|
+
console.error(error instanceof Error ? error.message : String(error))
|
|
894
|
+
process.exit(1)
|
|
895
|
+
})
|