8.4 KiB
8.4 KiB
Solid API Reference
Rendering
render(node, rendererOrConfig?)
Renders a Solid component tree into a CLI renderer.
import { render } from "@opentui/solid"
// Simple usage - creates renderer automatically
render(() => <App />)
// With config
render(() => <App />, {
exitOnCtrlC: false,
targetFPS: 60,
})
// With existing renderer
import { createCliRenderer } from "@opentui/core"
const renderer = await createCliRenderer()
render(() => <App />, renderer)
testRender(node, options?)
Create a test renderer for snapshots and tests.
import { testRender } from "@opentui/solid"
const testSetup = await testRender(() => <App />, {
width: 40,
height: 10,
})
// Access test utilities
testSetup.snapshot() // Get current render
testSetup.renderer // Access renderer
extend(components)
Register custom renderables as JSX intrinsic elements.
import { extend } from "@opentui/solid"
import { CustomRenderable } from "./custom"
extend({
custom: CustomRenderable,
})
// Now usable in JSX
<custom prop="value" />
getComponentCatalogue()
Returns the current component catalogue.
import { getComponentCatalogue } from "@opentui/solid"
const catalogue = getComponentCatalogue()
console.log(Object.keys(catalogue))
Hooks
useRenderer()
Access the OpenTUI renderer instance.
import { useRenderer } from "@opentui/solid"
import { onMount } from "solid-js"
function App() {
const renderer = useRenderer()
onMount(() => {
console.log(`Terminal: ${renderer.width}x${renderer.height}`)
renderer.console.show()
})
return <text>Hello</text>
}
useKeyboard(handler, options?)
Handle keyboard events.
import { useKeyboard, useRenderer } from "@opentui/solid"
function App() {
const renderer = useRenderer()
useKeyboard((key) => {
if (key.name === "escape") {
renderer.destroy() // Never use process.exit() directly!
}
if (key.ctrl && key.name === "s") {
saveDocument()
}
})
return <text>Press ESC to exit</text>
}
// With release events
function GameControls() {
const [pressed, setPressed] = createSignal(new Set<string>())
useKeyboard(
(event) => {
setPressed(keys => {
const newKeys = new Set(keys)
if (event.eventType === "release") {
newKeys.delete(event.name)
} else {
newKeys.add(event.name)
}
return newKeys
})
},
{ release: true }
)
return <text>Pressed: {Array.from(pressed()).join(", ")}</text>
}
usePaste(handler)
Handle paste events.
import { usePaste } from "@opentui/solid"
function PasteHandler() {
usePaste((text) => {
console.log("Pasted:", text)
})
return <text>Paste something</text>
}
onResize(callback)
Handle terminal resize events.
import { onResize } from "@opentui/solid"
function App() {
onResize((width, height) => {
console.log(`Resized to ${width}x${height}`)
})
return <text>Resize the terminal</text>
}
useTerminalDimensions()
Get reactive terminal dimensions.
import { useTerminalDimensions } from "@opentui/solid"
function ResponsiveLayout() {
const dimensions = useTerminalDimensions()
return (
<box flexDirection={dimensions().width > 80 ? "row" : "column"}>
<text>Width: {dimensions().width}</text>
<text>Height: {dimensions().height}</text>
</box>
)
}
useSelectionHandler(handler)
Handle text selection events.
import { useSelectionHandler } from "@opentui/solid"
function SelectableText() {
useSelectionHandler((selection) => {
console.log("Selected:", selection.text)
})
return <text selectable>Select this text</text>
}
useTimeline(options?)
Create animations with the timeline system.
import { useTimeline } from "@opentui/solid"
import { createSignal, onMount } from "solid-js"
function AnimatedBox() {
const [width, setWidth] = createSignal(0)
const timeline = useTimeline({
duration: 2000,
loop: false,
})
onMount(() => {
timeline.add(
{ width: 0 },
{
width: 50,
duration: 2000,
ease: "easeOutQuad",
onUpdate: (anim) => {
setWidth(Math.round(anim.targets[0].width))
},
}
)
})
return <box style={{ width: width(), height: 3, backgroundColor: "#6a5acd" }} />
}
Components
Text Component
<text
content="Hello" // Or use children
fg="#FFFFFF" // Foreground color
bg="#000000" // Background color
selectable={true} // Allow text selection
>
{/* Use nested modifier tags for styling */}
<span fg="red">Red</span>
<strong>Bold</strong>
<em>Italic</em>
<u>Underline</u>
<br />
<a href="https://...">Link</a>
</text>
Note
: Do NOT use
bold,italic,underlineas props on<text>. Use nested modifier tags like<strong>,<em>,<u>instead.
Box Component
<box
// Borders
border // Enable border
borderStyle="single" // single | double | rounded | bold
borderColor="#FFFFFF"
title="Title"
titleAlignment="center" // left | center | right
// Colors
backgroundColor="#1a1a2e"
// Layout
flexDirection="row"
justifyContent="center"
alignItems="center"
gap={2}
// Spacing
padding={2}
margin={1}
// Dimensions
width={40}
height={10}
flexGrow={1}
// Events
onMouseDown={(e) => {}}
onMouseUp={(e) => {}}
>
{children}
</box>
Scrollbox Component
<scrollbox
focused // Enable keyboard scrolling
style={{
scrollbarOptions: {
showArrows: true,
trackOptions: {
foregroundColor: "#7aa2f7",
backgroundColor: "#414868",
},
},
}}
>
<For each={items()}>
{(item) => <text>{item}</text>}
</For>
</scrollbox>
Input Component
<input
value={value()}
onInput={(newValue) => setValue(newValue)}
placeholder="Enter text..."
focused
width={30}
/>
Textarea Component
<textarea
value={text()}
onInput={(newValue) => setText(newValue)}
placeholder="Enter multiple lines..."
focused
width={40}
height={10}
/>
Select Component
<select
options={[
{ name: "Option 1", description: "First", value: "1" },
{ name: "Option 2", description: "Second", value: "2" },
]}
onChange={(index, option) => setSelected(option)}
selectedIndex={0}
focused
/>
Tab Select Component (Note: underscore)
<tab_select
options={[
{ name: "Home", description: "Dashboard" },
{ name: "Settings", description: "Configuration" },
]}
onChange={(index, option) => setTab(option)}
tabWidth={20}
focused
/>
ASCII Font Component (Note: underscore)
<ascii_font
text="TITLE"
font="tiny" // tiny | block | slick | shade
color="#FFFFFF"
/>
Code Component
<code
code={sourceCode}
language="typescript"
/>
Line Number Component (Note: underscore)
<line_number
code={sourceCode}
language="typescript"
startLine={1}
highlightedLines={[5]}
/>
Diff Component
<diff
oldCode={originalCode}
newCode={modifiedCode}
language="typescript"
mode="unified" // unified | split
/>
Control Flow
Solid's control flow components work with OpenTUI:
For
import { For } from "solid-js"
<For each={items()}>
{(item, index) => (
<box key={index()}>
<text>{item.name}</text>
</box>
)}
</For>
Show
import { Show } from "solid-js"
<Show when={isVisible()} fallback={<text>Hidden</text>}>
<text>Visible content</text>
</Show>
Switch/Match
import { Switch, Match } from "solid-js"
<Switch>
<Match when={status() === "loading"}>
<text>Loading...</text>
</Match>
<Match when={status() === "error"}>
<text fg="red">Error!</text>
</Match>
<Match when={status() === "success"}>
<text fg="green">Success!</text>
</Match>
</Switch>
Index
import { Index } from "solid-js"
<Index each={items()}>
{(item, index) => (
<text>{index}: {item().name}</text>
)}
</Index>
Special Components
Portal
import { Portal } from "@opentui/solid"
<Portal mount={targetNode}>
<box>Portal content</box>
</Portal>
Dynamic
import { Dynamic } from "@opentui/solid"
<Dynamic
component={isMultiline() ? "textarea" : "input"}
placeholder="Enter text..."
focused
/>