Text.js 0.1
Text.js 0.1 traz um reconciliador React 19, layout Yoga e um App Router baseado no sistema de arquivos para apps que renderizam no console do DevTools.
Text.js 0.1 recebeu uma tag. É a primeira versão com as três camadas: @textjs/core desenha quadros no console, @textjs/react renderiza React 19 nesses quadros, e textjs adiciona um App Router e uma CLI.
App Router
Rotas são pastas em app/, seguindo as convenções do App Router do Next.js. Este é o template dashboard do create-text-app:
app/├── layout.tsx├── page.tsx├── not-found.tsx├── deployments/│ └── [id]/│ └── page.tsx└── api/ └── metrics/ └── route.tsUm layout envolve todas as páginas abaixo dele e mantém seu estado durante a navegação. <Link> recebe um shortcut, então uma única tecla segue o link, e activeClassName estiliza o link para a rota atual:
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> );}Segmentos dinâmicos funcionam da mesma forma que no Next.js. [id] se torna um parâmetro, [...slug] captura o restante do caminho e [[...slug]] também corresponde ao segmento pai. Segmentos estáticos têm prioridade sobre os dinâmicos, e grupos de rotas como (marketing) organizam arquivos sem acrescentar nada à 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 e error.tsx envolvem um segmento em um limite de Suspense e um limite de erro. O componente de erro recebe o erro e uma função 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> );}Manipuladores de rota ficam em app/api e retornam uma Response padrão:
export function GET(): Response { return Response.json({ cpu: Math.random(), memory: Math.random(), at: new Date().toISOString() });}O roteador mantém window.location sincronizado por meio de history.pushState, para que Voltar, Avançar e links diretos funcionem, e grava metadata.title em document.title. O app desenha no console, e a página abriga uma área de foco que captura entradas.
CLI
text devinicia o Vite com React Fast Refresh. Salvar um arquivo atualiza o console no lugar.text buildgrava um build de produção do app e de seus manipuladores de rota.text startserve o build e os manipuladores de rota.
create-text-app cria a estrutura de um projeto a partir do template starter ou dashboard.
Inspetor
Pressione Ctrl+` ou F2 em um app em execução para abrir o inspetor [▼] dentro do console. Ele mostra a rota correspondente e seus parâmetros, o tamanho do quadro, a contagem de spans e os tempos de cada fase, além do número de quadros que o dirty gate ignorou. W desenha o layout do Yoga como um wireframe.
Também na versão 0.1
@textjs/react inclui componentes em PascalCase (Box, Text, ScrollBox, Input, Textarea, Select, Tabs, Code, Markdown, Diff, Modal, Spinner), utilitários de className no estilo Tailwind que funcionam em células e temas. O layout usa Yoga em WebAssembly.
A lista completa está no registro de alterações.