SonoJS
Accessible React + Tailwind component library with calm defaults, first-class RTL/LTR, and a tiny docs/registry shell.
Design system
| Layer | Choice |
|-------|--------|
| Surfaces / text | Zinc neutrals |
| Primary | #2563EB (light) / #396EF0 (dark, AA vs white) |
| Primary label | #FFFFFF on primary (light and dark) |
| Hover / Active | #1D4ED8 / #1E40AF |
| Direction | Inherit dir; logical CSS; DirectionProvider / useDirection |
| Font | Geist + Geist Mono |
| Radius | NY: base 0.625rem · tooltip ~6 · control ~8 · surface 10 |
| Sizes | Nova: Button default h-8 (32) · sm h-7 · lg h-9 · Input h-8 · radius 0.625rem · Sidebar ~240 · Content max ~1280 |
| Spacing | 4px scale (see AGENTS.md Design System Standards) |
RTL/LTR: set dir on , see /docs/direction. Rules: .cursor/rules/sonojs-direction.mdc, registry/README.md.
Develop
npm install
npm run dev
Consumers use the @sonojs/ui CLI (copy-source install):
npx @sonojs/ui@latest init # design system + lib/utils + components.json
npx @sonojs/ui@latest add button # → components/ui/button.tsx
import { Button } from "@/components/ui/button"
Registry payloads: npm run registry:build → public/r/.
Caching and content freshness
Host-agnostic policy (no Redis, no CDN-specific purge APIs):
| Path | Behavior |
|------|----------|
| Docs (/docs/*) | Static at next build (dynamic = "force-static"). Cache-Control: public, max-age=0, must-revalidate so CDNs/browsers revalidate after deploy (avoids year-long s-maxage on HTML). |
| public/r/*.json | Stable URLs; Cache-Control: public, max-age=0, must-revalidate via next.config.ts. Never immutable. |
| /_next/static/* | Next.js defaults (content-hashed, long-lived). Do not override. |
Registry index and item JSON share version + generatedAt from one atomic registry:build. The CLI refuses sonojs add when those diverge.
Verify after deploy / locally
npm run build
npm run start
other terminal:
npm run verify:cache
npm run sonojs -- init --cwd /tmp/sonojs-smoke --overwrite
npm run sonojs -- add button --registry ./public/r --cwd /tmp/sonojs-smoke --overwrite
Manual checks:
curl -I http://127.0.0.1:3000/r/registry.json— expectmax-age=0, must-revalidate.curl -I http://127.0.0.1:3000/r/button.json— same policy.curl -Ia/_next/static/...asset from the page HTML — must not use the/rpolicy.- Change a component →
npm run build→ restart → hard refresh docs and re-fetch/r/button.json— new content. - Client-side navigation may briefly show a pre-deploy RSC payload until a full refresh; hard refresh after deploy is enough.
Add a component
packages/ui/src/components/(single source;.tsx registry:build→public/r/)- Examples under
registry/examples/+/ registry/index.ts scripts/registry-items.mjs+npm run registry:buildlib/docs-nav.ts+ docs:npx @sonojs/ui@latest initthenadd
registry/README.md.