@tradalab/lyra
v2.7.0
Published
Tradalab UI kit — shadcn (radix-lyra) primitives, composed components, and app shell for React 19 / Next 16 / Tailwind v4.
Maintainers
Readme
@tradalab/lyra
Tradalab's UI kit — shadcn (
radix-lyrastyle) primitives, composed components, and an app shell for React 19 / Next 16 / Tailwind v4.
ESM-only. Extracted from Tradalab's foundation kit so every company app shares the same component surface.
Install
pnpm add @tradalab/lyra
# peers: react ^19, react-dom ^19 (next ^16 only if you use /shell)The stylesheet pulls in Tailwind v4, so your app needs @tailwindcss/postcss.
/* app/globals.css */
@import "@tradalab/lyra/styles.css";Subpaths
| Subpath | Exports | Boundary |
|---|---|---|
| @tradalab/lyra/utils | cn | server-safe |
| @tradalab/lyra/hooks | useMobile | client |
| @tradalab/lyra/ui | 60 shadcn primitives + AccountMenu, ActionButton, Container | client |
| @tradalab/lyra/shell | AppShell, NavItem, NavGroup, Breadcrumbs, useActiveRoute | client |
| @tradalab/lyra/styles.css | Tailwind v4 base + radix-lyra tokens (light/dark) | CSS |
Client subpaths carry a build-injected "use client"; import them inside a
client tree or pass via children — don't import them into a Server Component's
own module.
import { Button, Card, CardHeader } from "@tradalab/lyra/ui"
import { AppShell, NavItem } from "@tradalab/lyra/shell"Toast
2.0.0 replaced the sonner-based toast with shadcn's Base UI Toast. sonner is
gone — it is no longer a peer dependency, and apps should drop it.
toast is a manager object, not a callable:
import { Toaster, toast } from "@tradalab/lyra/ui"
toast.add({ title: "Saved" })
toast.add({ title: "Upload failed", description: err.message, type: "error" })
const id = toast.add({ title: "Uploading…", type: "loading", timeout: 0 })
toast.close(id)type is "success" | "error" | "info" | "warning" | "loading" — there is no
toast.success("x"). timeout: 0 never auto-dismisses (sonner's duration:
Infinity). Position belongs to the viewport this package styles, so sonner's
position and richColors props have no equivalent. Mount <Toaster/> once —
apps on @tradalab/nekit already get it from NekitProvider.
Develop
make install # pnpm install
make build # tsup + inject-use-client + verify-build-output
make verify # typecheck + lint + test
make ui-add <name> # scaffold a shadcn primitive, adapt, rebuild barrel
make ui-update <name> # overwrite a primitive with the latest upstream version
make ui-sync # re-adapt every primitive + rebuild barrel
make ui-diff # report which primitives changed upstream (exit 1 if any)Staying current with shadcn — make ui-diff compares every primitive
against the live radix-lyra registry and exits non-zero when one has moved.
It normalises away everything the CLI would rewrite anyway (icon-library
placeholders, cn-* template classes, import aliases, prettier line-wrapping),
so what it prints is real change. Prefer it over shadcn add --diff, which
caps its output at five files per run.
A primitive lyra deliberately diverges from carries a customised note in
primitives.lock.json; ui-diff lists those separately instead of failing on
them forever. Document the divergence in a JSDoc block in the file too —
make ui-update will overwrite it, and that note is what tells the next person
to put it back.
Layout — src/<layer>/ with a barrel index.ts; one tsup entry per
subpath; ESM-only to dist/. Layers (enforced by eslint-plugin-boundaries):
utils/hooks (foundation) → ui → shell. No upward imports.
"use client" is not in source — it is injected onto the client entry
artifacts post-build by scripts/inject-use-client.mjs, then asserted by
scripts/verify-build-output.mjs. scripts/sync-ui.mjs adapts shadcn-CLI
output to repo conventions.
Release — pnpm publish --no-git-checks (the prepublishOnly hook builds
first). Published to the npm public registry.
