create-cascade 0.1.3 → 0.1.4

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/README.md ADDED
@@ -0,0 +1,79 @@
1
+ # Create Cascade App
2
+
3
+ A CLI tool to create Cascade projects with interactive framework and starter selection.
4
+
5
+ ## Quick Start
6
+
7
+ ```bash
8
+ bun create cascade
9
+ ```
10
+
11
+ ## Features
12
+
13
+ - Create in a new folder or directly in the current folder
14
+ - Interactive framework selection (`core`, `react`, `solid`)
15
+ - Multiple built-in starter code presets per framework
16
+ - Optional direct install and immediate app start
17
+
18
+ ## Frameworks
19
+
20
+ - `core`: Vanilla Cascade API
21
+ - `react`: Cascade + React renderer
22
+ - `solid`: Cascade + Solid renderer
23
+
24
+ ## Starter Presets
25
+
26
+ ### Core
27
+
28
+ - `minimal`
29
+ - `counter`
30
+ - `layout`
31
+
32
+ ### React
33
+
34
+ - `minimal`
35
+ - `counter`
36
+ - `login`
37
+
38
+ ### Solid
39
+
40
+ - `minimal`
41
+ - `counter`
42
+ - `input`
43
+
44
+ ## CLI Options
45
+
46
+ ```txt
47
+ Options:
48
+ -f, --framework <name> Framework: core, react, solid
49
+ -s, --starter <name> Starter preset for selected framework
50
+ --here Use current directory
51
+ --no-install Skip bun install
52
+ --no-start Skip bun run dev after install
53
+ -h, --help Show help
54
+ ```
55
+
56
+ ## Examples
57
+
58
+ ```bash
59
+ # Interactive mode
60
+ bun create cascade
61
+
62
+ # Create in current folder
63
+ bun create cascade --here
64
+
65
+ # Create React app with counter starter
66
+ bun create cascade my-app -f react -s counter
67
+
68
+ # Scaffold only, no install
69
+ bun create cascade my-app --no-install
70
+ ```
71
+
72
+ ## Behavior
73
+
74
+ - If installation is enabled, the CLI runs `bun install` in the target directory.
75
+ - If installation is enabled and `--no-start` is not set, the CLI starts the app with `bun run dev`.
76
+
77
+ ## Package
78
+
79
+ Published on npm as `create-cascade`.
package/index.js CHANGED
@@ -1,25 +1,72 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { cpSync, existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from "node:fs"
4
- import { dirname, join, resolve } from "node:path"
3
+ import { existsSync, mkdirSync, readdirSync, writeFileSync } from "node:fs"
4
+ import { basename, resolve } from "node:path"
5
5
  import process from "node:process"
6
- import { fileURLToPath } from "node:url"
6
+ import { spawnSync } from "node:child_process"
7
+ import { createInterface } from "node:readline/promises"
7
8
 
8
- const __filename = fileURLToPath(import.meta.url)
9
- const __dirname = dirname(__filename)
9
+ const FRAMEWORKS = [
10
+ { id: "core", label: "Core", description: "Vanilla Cascade API with renderables" },
11
+ { id: "react", label: "React", description: "Cascade renderer with React components" },
12
+ { id: "solid", label: "Solid", description: "Cascade renderer with SolidJS components" },
13
+ ]
14
+
15
+ const STARTERS = {
16
+ core: [
17
+ { id: "minimal", label: "Minimal", description: "Single welcome message" },
18
+ { id: "counter", label: "Counter", description: "Live counter updated every second" },
19
+ { id: "layout", label: "Layout", description: "Simple boxed layout starter" },
20
+ ],
21
+ react: [
22
+ { id: "minimal", label: "Minimal", description: "Render a single text node" },
23
+ { id: "counter", label: "Counter", description: "React state with interval updates" },
24
+ { id: "login", label: "Login", description: "Small interactive login form" },
25
+ ],
26
+ solid: [
27
+ { id: "minimal", label: "Minimal", description: "Render a single text node" },
28
+ { id: "counter", label: "Counter", description: "Solid signal with interval updates" },
29
+ { id: "input", label: "Input", description: "Basic input and submit interaction" },
30
+ ],
31
+ }
10
32
 
11
33
  function parseArgs(argv) {
12
34
  const args = argv.slice(2)
13
35
  const options = {
14
36
  noInstall: false,
37
+ noStart: false,
38
+ here: false,
39
+ framework: undefined,
40
+ starter: undefined,
41
+ help: false,
15
42
  }
16
43
  const positionals = []
17
44
 
18
- for (const arg of args) {
45
+ for (let i = 0; i < args.length; i += 1) {
46
+ const arg = args[i]
47
+
19
48
  if (arg === "--no-install") {
20
49
  options.noInstall = true
21
50
  continue
22
51
  }
52
+ if (arg === "--no-start") {
53
+ options.noStart = true
54
+ continue
55
+ }
56
+ if (arg === "--here") {
57
+ options.here = true
58
+ continue
59
+ }
60
+ if (arg === "--framework" || arg === "-f" || arg === "--template" || arg === "-t") {
61
+ options.framework = args[i + 1]
62
+ i += 1
63
+ continue
64
+ }
65
+ if (arg === "--starter" || arg === "-s") {
66
+ options.starter = args[i + 1]
67
+ i += 1
68
+ continue
69
+ }
23
70
  if (arg === "--help" || arg === "-h") {
24
71
  options.help = true
25
72
  continue
@@ -31,12 +78,29 @@ function parseArgs(argv) {
31
78
  }
32
79
 
33
80
  function printHelp() {
34
- console.log("Usage: bun create cascade [project-name] [--no-install]")
81
+ console.log("Usage: bun create cascade [project-name] [options]")
82
+ console.log("")
83
+ console.log("Options:")
84
+ console.log(" -f, --framework <name> Framework: core, react, solid")
85
+ console.log(" -s, --starter <name> Starter preset for selected framework")
86
+ console.log(" --here Use current directory")
87
+ console.log(" --no-install Skip bun install")
88
+ console.log(" --no-start Skip bun run dev after install")
89
+ console.log(" -h, --help Show help")
35
90
  console.log("")
36
91
  console.log("Examples:")
37
92
  console.log(" bun create cascade")
38
93
  console.log(" bun create cascade my-app")
39
- console.log(" bun create cascade my-app --no-install")
94
+ console.log(" bun create cascade --here")
95
+ console.log(" bun create cascade my-app -f react -s counter")
96
+ }
97
+
98
+ function normalizePackageName(name) {
99
+ return name
100
+ .trim()
101
+ .toLowerCase()
102
+ .replace(/[^a-z0-9-_]+/g, "-")
103
+ .replace(/^-+|-+$/g, "") || "cascade-app"
40
104
  }
41
105
 
42
106
  function ensureDirectoryIsEmpty(targetDir) {
@@ -49,57 +113,438 @@ function ensureDirectoryIsEmpty(targetDir) {
49
113
  }
50
114
  }
51
115
 
52
- function normalizePackageName(name) {
53
- return name
54
- .trim()
55
- .toLowerCase()
56
- .replace(/[^a-z0-9-_]+/g, "-")
57
- .replace(/^-+|-+$/g, "") || "cascade-app"
116
+ function promptLine(rl, label) {
117
+ return rl.question(label)
58
118
  }
59
119
 
60
- function writeTemplate(targetDir, projectName) {
61
- const templateDir = join(__dirname, "template")
62
- cpSync(templateDir, targetDir, { recursive: true })
120
+ async function selectOption(rl, label, options) {
121
+ console.log("")
122
+ console.log(label)
123
+ for (let i = 0; i < options.length; i += 1) {
124
+ const option = options[i]
125
+ console.log(` ${i + 1}. ${option.label} (${option.id}) - ${option.description}`)
126
+ }
63
127
 
64
- const packageJsonPath = join(targetDir, "package.json")
65
- const packageJsonRaw = readFileSync(packageJsonPath, "utf8")
66
- const packageJson = JSON.parse(packageJsonRaw)
67
- packageJson.name = normalizePackageName(projectName)
68
- writeFileSync(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}\n`)
128
+ while (true) {
129
+ const raw = (await promptLine(rl, "Select a number: ")).trim()
130
+ const index = Number(raw)
131
+ if (Number.isInteger(index) && index >= 1 && index <= options.length) {
132
+ return options[index - 1].id
133
+ }
134
+ console.log("Invalid choice. Try again.")
135
+ }
69
136
  }
70
137
 
71
- function main() {
72
- try {
73
- const { options, positionals } = parseArgs(process.argv)
74
- if (options.help) {
75
- printHelp()
138
+ async function resolveProjectName(rl, options, positionals) {
139
+ if (options.here) {
140
+ return "."
141
+ }
142
+
143
+ if (positionals[0]) {
144
+ return positionals[0]
145
+ }
146
+
147
+ if (!process.stdin.isTTY) {
148
+ return "cascade-app"
149
+ }
150
+
151
+ const locationChoice = await selectOption(rl, "Where should the project be created?", [
152
+ { id: "new", label: "New folder", description: "Create and use a new project directory" },
153
+ { id: "here", label: "Current folder", description: "Use the current directory directly" },
154
+ ])
155
+
156
+ if (locationChoice === "here") {
157
+ return "."
158
+ }
159
+
160
+ const input = (await promptLine(rl, "Project name (default: cascade-app): ")).trim()
161
+ return input || "cascade-app"
162
+ }
163
+
164
+ async function resolveFramework(rl, frameworkArg) {
165
+ if (frameworkArg) {
166
+ const found = FRAMEWORKS.find((entry) => entry.id === frameworkArg)
167
+ if (!found) {
168
+ throw new Error(`Unknown framework: ${frameworkArg}. Use core, react, or solid.`)
169
+ }
170
+ return found.id
171
+ }
172
+
173
+ if (!process.stdin.isTTY) {
174
+ return "core"
175
+ }
176
+
177
+ return selectOption(rl, "Choose a framework:", FRAMEWORKS)
178
+ }
179
+
180
+ async function resolveStarter(rl, framework, starterArg) {
181
+ const choices = STARTERS[framework]
182
+
183
+ if (starterArg) {
184
+ const found = choices.find((entry) => entry.id === starterArg)
185
+ if (!found) {
186
+ const allowed = choices.map((entry) => entry.id).join(", ")
187
+ throw new Error(`Unknown starter '${starterArg}' for ${framework}. Allowed: ${allowed}.`)
188
+ }
189
+ return found.id
190
+ }
191
+
192
+ if (!process.stdin.isTTY) {
193
+ return choices[0].id
194
+ }
195
+
196
+ return selectOption(rl, `Choose a starter for ${framework}:`, choices)
197
+ }
198
+
199
+ function getPackageJson(projectName, framework) {
200
+ const dependencies = {
201
+ "@cascadetui/core": "latest",
202
+ }
203
+
204
+ if (framework === "react") {
205
+ dependencies["@cascadetui/react"] = "latest"
206
+ dependencies.react = "latest"
207
+ }
208
+
209
+ if (framework === "solid") {
210
+ dependencies["@cascadetui/solid"] = "latest"
211
+ dependencies["solid-js"] = "latest"
212
+ }
213
+
214
+ const isJsx = framework !== "core"
215
+ const entry = isJsx ? "src/index.tsx" : "src/index.ts"
216
+
217
+ return {
218
+ name: normalizePackageName(projectName),
219
+ version: "0.0.1",
220
+ private: true,
221
+ type: "module",
222
+ scripts: {
223
+ dev: `bun run ${entry}`,
224
+ },
225
+ dependencies,
226
+ }
227
+ }
228
+
229
+ function getTsConfig(framework) {
230
+ const base = {
231
+ target: "ESNext",
232
+ module: "ESNext",
233
+ moduleResolution: "Bundler",
234
+ strict: true,
235
+ skipLibCheck: true,
236
+ }
237
+
238
+ if (framework === "react") {
239
+ return {
240
+ compilerOptions: {
241
+ ...base,
242
+ lib: ["ESNext", "DOM"],
243
+ jsx: "react-jsx",
244
+ jsxImportSource: "@cascadetui/react",
245
+ },
246
+ include: ["src"],
247
+ }
248
+ }
249
+
250
+ if (framework === "solid") {
251
+ return {
252
+ compilerOptions: {
253
+ ...base,
254
+ jsx: "preserve",
255
+ jsxImportSource: "@cascadetui/solid",
256
+ },
257
+ include: ["src"],
258
+ }
259
+ }
260
+
261
+ return {
262
+ compilerOptions: base,
263
+ include: ["src"],
264
+ }
265
+ }
266
+
267
+ function getSource(framework, starter) {
268
+ const sources = {
269
+ core: {
270
+ minimal: `import { TextRenderable, createCliRenderer } from "@cascadetui/core"
271
+
272
+ const renderer = await createCliRenderer({ exitOnCtrlC: true })
273
+
274
+ const text = new TextRenderable(renderer, {
275
+ content: "Hello from Cascade",
276
+ margin: 2,
277
+ fg: "#00ff99",
278
+ })
279
+
280
+ renderer.root.add(text)
281
+ `,
282
+ counter: `import { TextRenderable, createCliRenderer } from "@cascadetui/core"
283
+
284
+ const renderer = await createCliRenderer({ exitOnCtrlC: true })
285
+ let count = 0
286
+
287
+ const text = new TextRenderable(renderer, {
288
+ content: "Count: 0",
289
+ margin: 2,
290
+ fg: "#00ff99",
291
+ })
292
+
293
+ renderer.root.add(text)
294
+
295
+ setInterval(() => {
296
+ count += 1
297
+ text.content = \`Count: \${count}\`
298
+ }, 1000)
299
+ `,
300
+ layout: `import { BoxRenderable, TextRenderable, createCliRenderer } from "@cascadetui/core"
301
+
302
+ const renderer = await createCliRenderer({ exitOnCtrlC: true })
303
+
304
+ const container = new BoxRenderable(renderer, {
305
+ border: true,
306
+ borderStyle: "single",
307
+ padding: 1,
308
+ margin: 1,
309
+ width: 50,
310
+ height: 9,
311
+ flexDirection: "column",
312
+ })
313
+
314
+ const title = new TextRenderable(renderer, {
315
+ content: "Cascade Core Starter",
316
+ fg: "#00ff99",
317
+ })
318
+
319
+ const subtitle = new TextRenderable(renderer, {
320
+ content: "Press Ctrl+C to exit",
321
+ marginTop: 1,
322
+ fg: "#cccccc",
323
+ })
324
+
325
+ container.add(title)
326
+ container.add(subtitle)
327
+ renderer.root.add(container)
328
+ `,
329
+ },
330
+ react: {
331
+ minimal: `import { createCliRenderer } from "@cascadetui/core"
332
+ import { createRoot } from "@cascadetui/react"
333
+
334
+ function App() {
335
+ return <text content="Hello from Cascade + React" fg="#00ff99" />
336
+ }
337
+
338
+ const renderer = await createCliRenderer({ exitOnCtrlC: true })
339
+ createRoot(renderer).render(<App />)
340
+ `,
341
+ counter: `import { createCliRenderer } from "@cascadetui/core"
342
+ import { createRoot } from "@cascadetui/react"
343
+ import { useEffect, useState } from "react"
344
+
345
+ function App() {
346
+ const [count, setCount] = useState(0)
347
+
348
+ useEffect(() => {
349
+ const timer = setInterval(() => setCount((value) => value + 1), 1000)
350
+ return () => clearInterval(timer)
351
+ }, [])
352
+
353
+ return (
354
+ <box style={{ border: true, padding: 1, margin: 1 }}>
355
+ <text content={\`React counter: \${count}\`} fg="#00ff99" />
356
+ </box>
357
+ )
358
+ }
359
+
360
+ const renderer = await createCliRenderer({ exitOnCtrlC: true })
361
+ createRoot(renderer).render(<App />)
362
+ `,
363
+ login: `import { createCliRenderer } from "@cascadetui/core"
364
+ import { createRoot, useKeyboard } from "@cascadetui/react"
365
+ import { useState } from "react"
366
+
367
+ function App() {
368
+ const [username, setUsername] = useState("")
369
+ const [password, setPassword] = useState("")
370
+ const [focused, setFocused] = useState("username")
371
+ const [status, setStatus] = useState("idle")
372
+
373
+ useKeyboard((key) => {
374
+ if (key.name === "tab") {
375
+ setFocused((value) => (value === "username" ? "password" : "username"))
376
+ }
377
+ })
378
+
379
+ const submit = () => {
380
+ if (username === "admin" && password === "secret") {
381
+ setStatus("success")
76
382
  return
77
383
  }
384
+ setStatus("invalid")
385
+ }
386
+
387
+ return (
388
+ <box style={{ padding: 2, flexDirection: "column" }}>
389
+ <text content="Cascade Login" fg="#00ff99" />
390
+ <box title="Username" style={{ border: true, width: 40, height: 3, marginTop: 1 }}>
391
+ <input focused={focused === "username"} placeholder="admin" onInput={setUsername} onSubmit={submit} />
392
+ </box>
393
+ <box title="Password" style={{ border: true, width: 40, height: 3, marginTop: 1 }}>
394
+ <input focused={focused === "password"} placeholder="secret" onInput={setPassword} onSubmit={submit} />
395
+ </box>
396
+ <text content={\`Status: \${status}\`} marginTop={1} fg={status === "success" ? "green" : "yellow"} />
397
+ </box>
398
+ )
399
+ }
400
+
401
+ const renderer = await createCliRenderer({ exitOnCtrlC: true })
402
+ createRoot(renderer).render(<App />)
403
+ `,
404
+ },
405
+ solid: {
406
+ minimal: `import { render } from "@cascadetui/solid"
407
+
408
+ const App = () => <text content="Hello from Cascade + Solid" fg="#00ff99" />
409
+
410
+ render(App, { exitOnCtrlC: true })
411
+ `,
412
+ counter: `import { render } from "@cascadetui/solid"
413
+ import { createSignal, onCleanup } from "solid-js"
414
+
415
+ const App = () => {
416
+ const [count, setCount] = createSignal(0)
417
+ const timer = setInterval(() => setCount((value) => value + 1), 1000)
418
+ onCleanup(() => clearInterval(timer))
78
419
 
79
- const projectName = positionals[0] ?? "cascade-app"
80
- const targetDir = resolve(process.cwd(), projectName)
420
+ return (
421
+ <box style={{ border: true, padding: 1, margin: 1 }}>
422
+ <text content={\`Solid counter: \${count()}\`} fg="#00ff99" />
423
+ </box>
424
+ )
425
+ }
426
+
427
+ render(App, { exitOnCtrlC: true })
428
+ `,
429
+ input: `import { render } from "@cascadetui/solid"
430
+ import { createSignal } from "solid-js"
431
+
432
+ const App = () => {
433
+ const [value, setValue] = createSignal("")
434
+ const [submitted, setSubmitted] = createSignal("")
435
+
436
+ return (
437
+ <box style={{ padding: 2, flexDirection: "column" }}>
438
+ <text content="Cascade Solid Input" fg="#00ff99" />
439
+ <box title="Message" style={{ border: true, width: 40, height: 3, marginTop: 1 }}>
440
+ <input
441
+ focused
442
+ placeholder="Type something..."
443
+ onInput={setValue}
444
+ onSubmit={(nextValue) => setSubmitted(nextValue)}
445
+ />
446
+ </box>
447
+ <text content={\`Current: \${value()}\`} marginTop={1} />
448
+ <text content={\`Submitted: \${submitted() || "-"}\`} />
449
+ </box>
450
+ )
451
+ }
452
+
453
+ render(App, { exitOnCtrlC: true })
454
+ `,
455
+ },
456
+ }
457
+
458
+ return sources[framework][starter]
459
+ }
460
+
461
+ function writeProject(targetDir, projectName, framework, starter) {
462
+ mkdirSync(targetDir, { recursive: true })
463
+ ensureDirectoryIsEmpty(targetDir)
464
+ mkdirSync(resolve(targetDir, "src"), { recursive: true })
465
+
466
+ const packageJson = getPackageJson(projectName, framework)
467
+ const tsconfig = getTsConfig(framework)
468
+ const isJsx = framework !== "core"
469
+ const fileName = isJsx ? "index.tsx" : "index.ts"
470
+ const source = getSource(framework, starter)
471
+
472
+ writeFileSync(resolve(targetDir, "package.json"), `${JSON.stringify(packageJson, null, 2)}\n`)
473
+ writeFileSync(resolve(targetDir, "tsconfig.json"), `${JSON.stringify(tsconfig, null, 2)}\n`)
474
+ writeFileSync(resolve(targetDir, "src", fileName), source)
475
+
476
+ if (framework === "solid") {
477
+ writeFileSync(resolve(targetDir, "bunfig.toml"), 'preload = ["@cascadetui/solid/preload"]\n')
478
+ }
479
+ }
480
+
481
+ function runCommand(command, args, cwd) {
482
+ const result = spawnSync(command, args, {
483
+ cwd,
484
+ stdio: "inherit",
485
+ shell: process.platform === "win32",
486
+ })
487
+ if (result.status !== 0) {
488
+ throw new Error(`Command failed: ${command} ${args.join(" ")}`)
489
+ }
490
+ }
81
491
 
82
- mkdirSync(targetDir, { recursive: true })
83
- ensureDirectoryIsEmpty(targetDir)
84
- writeTemplate(targetDir, projectName)
492
+ async function main() {
493
+ const { options, positionals } = parseArgs(process.argv)
494
+ if (options.help) {
495
+ printHelp()
496
+ return
497
+ }
498
+
499
+ const rl = createInterface({
500
+ input: process.stdin,
501
+ output: process.stdout,
502
+ })
503
+
504
+ try {
505
+ const rawProjectName = await resolveProjectName(rl, options, positionals)
506
+ const framework = await resolveFramework(rl, options.framework)
507
+ const starter = await resolveStarter(rl, framework, options.starter)
508
+
509
+ const usingCurrentDirectory = rawProjectName === "."
510
+ const targetDir = usingCurrentDirectory ? process.cwd() : resolve(process.cwd(), rawProjectName)
511
+ const packageNameSeed = usingCurrentDirectory ? basename(targetDir) : rawProjectName
512
+
513
+ writeProject(targetDir, packageNameSeed, framework, starter)
85
514
 
86
515
  console.log("")
87
- console.log(`Created project in ${targetDir}`)
516
+ console.log(`Created Cascade project in ${targetDir}`)
517
+ console.log(`Framework: ${framework}`)
518
+ console.log(`Starter: ${starter}`)
519
+
520
+ if (!options.noInstall) {
521
+ console.log("")
522
+ console.log("Installing dependencies with bun...")
523
+ runCommand("bun", ["install"], targetDir)
524
+ }
525
+
526
+ if (!options.noInstall && !options.noStart) {
527
+ console.log("")
528
+ console.log("Starting the project...")
529
+ runCommand("bun", ["run", "dev"], targetDir)
530
+ return
531
+ }
532
+
88
533
  console.log("")
89
534
  console.log("Next steps:")
90
- if (projectName !== ".") {
91
- console.log(` cd ${projectName}`)
535
+ if (!usingCurrentDirectory) {
536
+ console.log(` cd ${rawProjectName}`)
92
537
  }
93
538
  if (options.noInstall) {
94
539
  console.log(" bun install")
95
- } else {
96
- console.log(" bun install")
97
540
  }
98
541
  console.log(" bun run dev")
99
- } catch (error) {
100
- console.error(error instanceof Error ? error.message : String(error))
101
- process.exit(1)
542
+ } finally {
543
+ rl.close()
102
544
  }
103
545
  }
104
546
 
105
- main()
547
+ main().catch((error) => {
548
+ console.error(error instanceof Error ? error.message : String(error))
549
+ process.exit(1)
550
+ })
package/package.json CHANGED
@@ -1,22 +1,22 @@
1
1
  {
2
2
  "name": "create-cascade",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "Create a new Cascade TUI project",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "repository": {
8
8
  "type": "git",
9
- "url": "https://github.com/kirosnn/cascade",
9
+ "url": "git+https://github.com/kirosnn/cascade.git",
10
10
  "directory": "packages/create-cascade"
11
11
  },
12
12
  "bin": {
13
- "create-cascade": "./index.js"
13
+ "create-cascade": "index.js"
14
14
  },
15
15
  "files": [
16
16
  "index.js",
17
- "template"
17
+ "README.md"
18
18
  ],
19
19
  "scripts": {
20
- "publish": "bun scripts/publish.ts"
20
+ "publish:pkg": "bun scripts/publish.ts"
21
21
  }
22
22
  }
@@ -1,12 +0,0 @@
1
- {
2
- "name": "cascade-app",
3
- "version": "0.0.1",
4
- "private": true,
5
- "type": "module",
6
- "scripts": {
7
- "dev": "bun run src/index.ts"
8
- },
9
- "dependencies": {
10
- "@cascadetui/core": "latest"
11
- }
12
- }
@@ -1,12 +0,0 @@
1
- import { createCliRenderer, TextRenderable } from "@cascadetui/core"
2
-
3
- const renderer = createCliRenderer()
4
-
5
- const app = new TextRenderable({
6
- content: "Hello from Cascade",
7
- x: 2,
8
- y: 1,
9
- })
10
-
11
- renderer.root.add(app)
12
- renderer.start()
@@ -1,10 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ESNext",
4
- "module": "ESNext",
5
- "moduleResolution": "Bundler",
6
- "strict": true,
7
- "skipLibCheck": true
8
- },
9
- "include": ["src"]
10
- }