Text.js 0.1
Text.js 0.1 porta un reconciler React 19, il layout Yoga e un App Router basato sul file system alle app che eseguono il rendering nella console DevTools.
Text.js 0.1 ha un tag. È la prima versione con tutti e tre i livelli: @textjs/core disegna i frame nella console, @textjs/react renderizza React 19 in quei frame e textjs aggiunge un App Router e una CLI.
L’App Router
Le route sono cartelle in app/ e seguono le convenzioni dell’App Router di Next.js. Questo è il template dashboard di create-text-app:
app/├── layout.tsx├── page.tsx├── not-found.tsx├── deployments/│ └── [id]/│ └── page.tsx└── api/ └── metrics/ └── route.tsUn layout avvolge ogni pagina al di sotto e mantiene il proprio stato durante la navigazione. <Link> accetta una shortcut, quindi basta un tasto per seguire il link, e activeClassName applica lo stile al link della route corrente:
import type { ReactNode } from "react";import { Box, KeyHint, Text, useTheme, type Metadata } from "textjs";import Link from "textjs/link";export const metadata: Metadata = { title: { default: "Acme", template: "%s · Acme" } };export default function RootLayout({ children }: { children?: ReactNode }): ReactNode { const theme = useTheme(); return ( <Box className="flex-col w-full h-full"> <Box className="flex-row h-1 px-1 gap-3 bg-surface shrink-0"> <Text bold color={theme.fg} wrap="nowrap"> ▼ Acme </Text> <Link href="/" shortcut="1" className="text-muted no-underline" activeClassName="text-fg bold"> 1 Metrics </Link> <Link href="/deployments/dpl_a1" shortcut="2" className="text-muted no-underline" activeClassName="text-fg bold"> 2 Latest deploy </Link> </Box> <Box className="grow flex-col px-2 pt-1">{children}</Box> <Box className="flex-row h-1 gap-2 pl-6 shrink-0 bg-surface"> <KeyHint keys="1-2" label="navigate" /> <KeyHint keys="tab" label="focus" /> <KeyHint keys="F2" label="devtools" /> </Box> </Box> );}I segmenti dinamici funzionano come in Next.js. [id] diventa un parametro, [...slug] cattura il resto del percorso e [[...slug]] corrisponde anche al percorso padre. I segmenti statici hanno la precedenza su quelli dinamici e i gruppi di route come (marketing) organizzano i file senza aggiungere parti all’URL.
import { Box, Text, useInput } from "textjs";import { notFound, useParams, useRouter } from "textjs/navigation";import { DEPLOYMENTS } from "../../../lib/data";export default function DeploymentPage() { const router = useRouter(); const { id } = useParams<{ id: string }>(); const deployment = DEPLOYMENTS.find((d) => d.id === id); useInput((e) => { if (e.key === "escape") router.back(); }); if (!deployment) notFound(); return ( <Box className="flex-col gap-1"> <Text bold>{deployment.id}</Text> <Text>{deployment.branch}</Text> </Box> );}loading.tsx ed error.tsx avvolgono un segmento in un boundary Suspense e in un error boundary. Il componente di errore riceve l’errore e una funzione reset:
import { Box, Text, useInput, type ErrorComponentProps } from "textjs";export default function DeploymentsError({ error, reset }: ErrorComponentProps) { useInput((e) => { if (e.key === "r") reset(); }); return ( <Box className="flex-col grow items-center justify-center gap-1"> <Text bold>Something went wrong loading deployments.</Text> <Text>{error.message}</Text> </Box> );}I route handler si trovano in app/api e restituiscono una Response standard:
export function GET(): Response { return Response.json({ cpu: Math.random(), memory: Math.random(), at: new Date().toISOString() });}Il router mantiene sincronizzato window.location tramite history.pushState, quindi Indietro, Avanti e i deep link funzionano, e scrive metadata.title in document.title. L’app disegna nella console e la pagina ospita un pannello del focus che raccoglie l’input.
La CLI
text devavvia Vite con React Fast Refresh. Salvare un file aggiorna la console sul posto.text buildscrive una build di produzione dell’app e dei suoi route handler.text startserve la build e i route handler.
create-text-app crea la struttura di un progetto a partire dal template starter o dashboard.
L’ispettore
Premi Ctrl+` o F2 in un’app in esecuzione per aprire l’ispettore [▼] nella console. Mostra la route corrispondente e i suoi parametri, le dimensioni del frame, il numero di span e i tempi delle fasi, e il numero di frame saltati dal dirty gate. W disegna il layout Yoga come wireframe.
Altre novità della 0.1
@textjs/react include componenti PascalCase (Box, Text, ScrollBox, Input, Textarea, Select, Tabs, Code, Markdown, Diff, Modal, Spinner), utilità className in stile Tailwind che operano sulle celle e temi. Il layout usa Yoga in WebAssembly.
L’elenco completo è nel registro delle modifiche.