From f8e050b0730705f8e29a8af3b60cf55f1c096296 Mon Sep 17 00:00:00 2001 From: Softov Date: Mon, 24 Aug 2026 17:39:41 -0400 Subject: [PATCH] docs: say which package to install, and what each one buys The README opened with an install line and an import and left the reader to infer the rest: that `@textui/kit` alone is enough to get something on screen, that `Panel` and `Table` are a second install, that the catalog is resolved by name and so has to be registered, and that the CLI needs no install at all. None of that was written down. Both files now give npm and pnpm forms, and getting started leads with the kit rather than with `@textui/core` and `@textui/terminal` - those move down to "the pieces underneath", which is what they are once the kit exists. The hand-wired `createApp` hello goes with them; it was the first thing on the page and it is not the first thing to read. The snippets package gains @textui/kit, so kit examples are typechecked like the rest. That immediately caught a `` in the new prose that no snippet defined. The README is not extracted, so its example is byte-identical to the one in getting started rather than a second version to drift. --- README.md | 75 +++++++++++++++++++- docs/getting-started.md | 109 +++++++++++++++++++++++++---- pnpm-lock.yaml | 3 + scripts/docs/snippets/package.json | 1 + 4 files changed, 171 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index d39bfdc..15b8f58 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,53 @@ A dependency-free TypeScript terminal UI runtime. Screens are plain data; JSX is one way to write them. ```bash -npm install @textui/kit @textui/widgets +npm install @textui/kit +``` + +```tsx +import { Box, Text, render, useInput, useState } from '@textui/kit'; + +function Counter() { + const [count, setCount] = useState(0); + useInput((e) => { + if (e.name !== '+') return false; + setCount((c) => c + 1); + return true; + }); + + return ( + + Count: {count} + + to increment, ctrl+c to quit + + ); +} + +const { waitUntilExit } = render(); +await waitUntilExit(); +``` + +> Status: pre-1.0. The surface is still moving. + +## Installing + +One package is enough to have something on screen. The rest are additive, and +nothing pulls in a third-party dependency. + +```bash +npm install @textui/kit # pnpm add @textui/kit +``` + +`@textui/kit` is the runtime, a terminal to put it on, and `render`. `Box`, +`Text`, the hooks and `render` all come from here, and the example above needs +nothing else. + +**For the component catalog** - `Panel`, `Table`, `Row`, `Column`, charts, +overlays, forms - add `@textui/widgets`. Its components are resolved by name at +mount time, so they have to be registered before they can render: + +```bash +npm install @textui/kit @textui/widgets # pnpm add @textui/kit @textui/widgets ``` ```tsx @@ -14,7 +60,32 @@ const { waitUntilExit } = render(, { onBoot: registerBuiltins }); await waitUntilExit(); ``` -> Status: pre-1.0. The surface is still moving. +Forget `onBoot` and the components are missing registrations rather than +missing imports - the screen renders, and says so where they should have been. + +**For a project set up for you**, and for components copied into your source +rather than imported, use the CLI. It needs no install: + +```bash +npx @textui/cli init # pnpm dlx @textui/cli init +npx @textui/cli doctor # what this terminal can actually do +``` + +`doctor` is the one to run first when something renders wrong - it reports the +unicode level, colour depth and keyboard protocol actually detected. + +**Working against the pieces directly** - `@textui/core` and `@textui/terminal` +- is the same thing with a longer name. `@textui/kit` re-exports both and adds +`render`; there is nothing in them it hides. Take them separately when you want +the runtime without a terminal attached, which is what the test harness and the +static renderer do: + +```bash +npm install @textui/core @textui/terminal # pnpm add @textui/core @textui/terminal +``` + +Node >= 22, and TypeScript wants `"jsx": "react-jsx"` with +`"jsxImportSource": "@textui/kit"` - see [getting started](docs/getting-started.md). ## The one idea diff --git a/docs/getting-started.md b/docs/getting-started.md index 6213649..701614a 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -10,12 +10,99 @@ type Service = { name: string; status: string; cpu: string }; # Getting started ```bash -pnpm add @textui/core @textui/terminal +npm install @textui/kit # pnpm add @textui/kit ``` -Node ≥ 22. There are no other dependencies. +Node ≥ 22. There are no other dependencies, and this one package is enough to +put something on screen. -## The smallest thing that runs +## Hello, in full + +`@textui/kit` is the runtime, a terminal to put it on, and `render`. Everything +this example uses comes from it. + +```tsx +import { Box, Text, render, useInput, useState } from '@textui/kit'; + +function Counter() { + const [count, setCount] = useState(0); + useInput((e) => { + if (e.name !== '+') return false; + setCount((c) => c + 1); + return true; + }); + + return ( + + Count: {count} + + to increment, ctrl+c to quit + + ); +} + +const { waitUntilExit } = render(); +await waitUntilExit(); +``` + +`render` mounts and keeps running - it returns a handle rather than a promise, +so the application is up before the next line. `waitUntilExit()` resolves when +it stops, however it stopped. + +For JSX, point the compiler at the runtime: + +```jsonc +// tsconfig.json +{ + "compilerOptions": { + "jsx": "react-jsx", + "jsxImportSource": "@textui/kit" + } +} +``` + +## Adding the catalog + +`Box` and `Text` are host primitives and always available. `Panel`, `Table`, +`Row`, `Column`, the charts, forms and overlays live in `@textui/widgets`, and +are resolved **by name at mount time** - so they have to be registered before +they can render: + +```bash +npm install @textui/widgets # pnpm add @textui/widgets +``` + +```tsx +import { Text, render } from '@textui/kit'; +import { Panel, registerBuiltins } from '@textui/widgets'; + +function Dashboard() { + return ( + + nothing to report + + ); +} + +const { waitUntilExit } = render(, { onBoot: registerBuiltins }); +await waitUntilExit(); +``` + +Forget `onBoot` and nothing throws at compile time: a missing registration is a +runtime miss, rendered visibly where the component should have been. + +## The pieces underneath + +`@textui/kit` re-exports `@textui/core` and [`@textui/terminal`](terminal) +and adds `render`; it hides nothing. Take them +separately when you want the runtime without a terminal attached - which is +what the test harness and the static renderer do - or when you want to own the +wiring: + +```bash +npm install @textui/core @textui/terminal # pnpm add @textui/core @textui/terminal +``` + +Wired by hand, that same hello is: ```tsx import { createApp, WRITER_KEY } from '@textui/core'; @@ -38,19 +125,11 @@ await app.start(); ## JSX -Point the compiler at the runtime: - -```jsonc -// tsconfig.json -{ - "compilerOptions": { - "jsx": "react-jsx", - "jsxImportSource": "@textui/core" - } -} -``` +Working against the pieces directly, `jsxImportSource` is `@textui/core` +rather than `@textui/kit` - the runtime is where the factory lives, and the kit +re-exports it. -Then `` produces `{ component: 'Row', gap: 1 }`. Lowercase names are host primitives - `box`, `text`, `canvas`, `spacer` - and capitalised names are components you import, which is what gives them prop types. +`` produces `{ component: 'Row', gap: 1 }`. Lowercase names are host primitives - `box`, `text`, `canvas`, `spacer` - and capitalised names are components you import, which is what gives them prop types. ```tsx import { useStoreValue } from '@textui/core'; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2fd2152..5a0db73 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -304,6 +304,9 @@ importers: '@textui/documents': specifier: workspace:* version: link:../../../packages/documents + '@textui/kit': + specifier: workspace:* + version: link:../../../packages/facade '@textui/terminal': specifier: workspace:* version: link:../../../packages/terminal diff --git a/scripts/docs/snippets/package.json b/scripts/docs/snippets/package.json index 283211a..5b01888 100644 --- a/scripts/docs/snippets/package.json +++ b/scripts/docs/snippets/package.json @@ -11,6 +11,7 @@ "dependencies": { "@textui/cli": "workspace:*", "@textui/core": "workspace:*", + "@textui/kit": "workspace:*", "@textui/documents": "workspace:*", "@textui/terminal": "workspace:*", "@textui/textide": "workspace:*",