opsfuse-ui
v0.1.21
Published
React component library (React 19, TypeScript, Tailwind CSS v4, shadcn-style primitives). Publish as an npm package and consume it from any app; you do **not** need to install shadcn in the host app.
Readme
opsfuse-ui
React component library (React 19, TypeScript, Tailwind CSS v4, shadcn-style primitives). Publish as an npm package and consume it from any app; you do not need to install shadcn in the host app.
Install in an application
Peer dependencies: react and react-dom (same major as this package, e.g. React 19).
npm install opsfuse-uiStyles (once, e.g. in your app entry). Import the bundle that matches your host's Tailwind version, before your own Tailwind/global stylesheet:
// Tailwind v3 host (or no Tailwind):
import "opsfuse-ui/styles.css"; // flat, un-layered
// Tailwind v4 host:
import "opsfuse-ui/styles.layered.css"; // cascade-layered
import "./index.css"; // your own Tailwind/global CSS comes AFTERBoth are precompiled, self-contained CSS — you do not run Tailwind over them.
styles.css(flat) has no@layerblocks, so a Tailwind v3 host's PostCSS pipeline never errors on reserved layer names, and the library's utility classes correctly out-specify the host's un-layered preflight.styles.layered.csskeeps the library inside low-priorityopsfuse-*cascade layers. On a Tailwind v4 host imported first, your app's ownbase/utilitieslayers register later and therefore win — so your preflight and responsive utilities (md:*,hover:*, …) stay authoritative and are never overridden by the library.
Importing opsfuse before your own CSS keeps your rules at higher precedence (later source order on the flat bundle; later-declared layer on the layered bundle), so your className overrides on library components still take effect.
Fonts: the library does not bundle fonts. In Next.js, load fonts in the host app and map them to --font-sans / --font-mono.
// app/layout.tsx (Next.js)
import { Geist, Geist_Mono } from "next/font/google";
const geistSans = Geist({ subsets: ["latin"], variable: "--font-sans" });
const geistMono = Geist_Mono({ subsets: ["latin"], variable: "--font-mono" });
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en" className={`${geistSans.variable} ${geistMono.variable}`}>
<body>{children}</body>
</html>
);
}/* app/globals.css (or your host app global stylesheet) */
:root {
--font-sans: var(--font-geist);
--font-mono: var(--font-geist-mono);
}Theme scope: Design tokens (--radius, shadcn aliases like --background, etc.) apply only under the opsfuse-ui class so your app’s own :root theme is unchanged. Wrap UI that uses this library with OpsfuseThemeProvider.
Available brands: recruitsmartly (default), skillready, worklog, verity.
import { OpsfuseThemeProvider } from "opsfuse-ui";
export default function Layout({ children }: { children: React.ReactNode }) {
return (
<OpsfuseThemeProvider
brand="skillready"
darkMode={false} // optional manual override
className="min-h-svh"
>
{children}
</OpsfuseThemeProvider>
);
}You can also add className="opsfuse-ui" on your own wrapper, or use the OPSFUSE_THEME_SCOPE constant.
Components:
import { Button, cn } from "opsfuse-ui";Entrypoints (recommended for performance-sensitive apps):
| Entrypoint | Use |
|------------|-----|
| opsfuse-ui | Full library (includes everything) |
| opsfuse-ui/core | Core components only (no charts, calendar, carousel, etc.) |
| opsfuse-ui/extended | Heavier components (Chart, Calendar, Carousel, Command, Combobox, Drawer, InputOTP, Sonner) |
| opsfuse-ui/recharts | Re-exported Recharts with theme support |
| opsfuse-ui/icons | Flat re-export of lucide-react icons |
| opsfuse-ui/date-fns | Flat re-export of date-fns utilities |
| opsfuse-ui/date-fns/locale | Flat re-export of date-fns locales |
import { Button, Badge, OpsfuseRoot } from "opsfuse-ui/core";
import { ChartContainer, Calendar } from "opsfuse-ui/extended";
import { Recharts } from "opsfuse-ui/recharts";
import { Home, Search } from "opsfuse-ui/icons";
import { format, addDays } from "opsfuse-ui/date-fns";TypeScript: use moduleResolution "bundler" or "node16" / "nodenext" so package.json exports resolve correctly.
Tailwind v4 content — if you scan the library for classes, include the built bundle:
content: [
"./src/**/*.{js,ts,jsx,tsx}",
"./node_modules/opsfuse-ui/dist/index.js",
],Claude Code Skills
This library includes built-in Claude Code skills to help you build faster and maintain UI consistency. They are automatically installed into your project's .claude/skills/ directory via a postinstall script.
Available skills:
/setup— Step-by-step integration guide/components— Component API reference and usage patterns/color-theme— Design token and typography guide/ui-consistency— Best practices and mandatory code patterns
IDE (VS Code / Cursor) — completions and auto-imports
TypeScript only suggests symbols from packages that are listed in the host app’s package.json (dependencies or devDependencies). Add opsfuse-ui there, then run “TypeScript: Restart TS Server” after install or upgrades.
Optional: set typescript.preferences.includePackageJsonAutoImports to on if you want broader auto-import behavior (the default auto only considers direct package.json dependencies).
Development (this repo)
| Command | Description |
|----------------------|--------------------------------------------------|
| npm run dev | Vite dev server for the demo app |
| npm run build | Demo app build → dist-demo/ |
| npm run build:lib | Library build → dist/ (JS, CSS, types) for npm |
| npm run storybook | Storybook |
License
See repository metadata.
