@codelusitan/ui-components
v0.1.0
Published
Shared React frontend pieces for CodeLusitan apps: the Keycloak/OIDC auth module and common UI components (ADR-0054).
Readme
@codelusitan/ui-components
Shared React pieces for CodeLusitan apps (ADR-0054). Everything is a peer dependency — the app provides React, the router, the OIDC library and so on, so nothing is bundled twice.
Each import path is its own entry, so an app only needs the peers of what it imports:
| Import | Contents | Peers it needs |
| --- | --- | --- |
| @codelusitan/ui-components/auth | AuthProvider, useAuth, RequireAuth, createOidcConfig, runSilentRenew | react-oidc-context, oidc-client-ts, jwt-decode, react-router-dom |
| @codelusitan/ui-components/components | DataTable, LoadingRows, Modal, PageHeader, StatusBadge, TEXT_ROLE_CLASSES, LOG_LEVEL_ROLES | @radix-ui/react-dialog, lucide-react |
| @codelusitan/ui-components/stat-card | StatCard, Sparkline | recharts, react-router-dom |
| @codelusitan/ui-components/rich-text-editor | RichTextEditor (TipTap) | the @tiptap/* packages |
| @codelusitan/ui-components/styles.css | design tokens + .card / .badge / editor styles | tailwindcss v4 |
Auth (Keycloak, authorization-code flow)
import { AuthProvider, RequireAuth, createOidcConfig } from "@codelusitan/ui-components/auth";
const oidcConfig = createOidcConfig({
clientId: "lusoadmin",
basePath: "/admin", // "" for an app on its own hostname root
});
<AuthProvider config={oidcConfig} tokenStorageKey="lusoadmin.token" adminRole="platform-admin">
<RequireAuth requireAdmin loginPath="/login" forbidden={<p>Sem acesso.</p>}>…</RequireAuth>
</AuthProvider>useAuth()returnstoken, idUser, idTenant, roles, isAdmin, displayName, isLoading, isAuthenticated, login, logout.tokenStorageKeyis optional: when set, the access token is mirrored intolocalStorageunder that key (synced during render, on purpose — see the comment inAuthContext.jsx) for an API client that reads it there. Awindoweventauth:expired, dispatched by that client on a 401, sends the user back through login once.silent-renew.htmlcallsrunSilentRenew()from/auth.- Redirect URIs are
${origin}${basePath}/auth/callback,/login(post-logout) and/silent-renew.html; keepbasePathequal to the router's basename and the bundler'sbase.
Styles (Tailwind v4)
The components use Tailwind utility classes and a few design tokens (bg-surface, rounded-card,
brand-*, …). In the app's CSS, after Tailwind:
@import "tailwindcss";
@import "@codelusitan/ui-components/styles.css";
@source "../node_modules/@codelusitan/ui-components/dist";
@custom-variant dark (&:where(.dark, .dark *));@source is what makes Tailwind find the classes inside the compiled package. The tokens default
to LusoAdmin's theme; an app with its own brand overrides them (e.g. --color-brand-600,
--color-surface) in its own @theme block after the import.
Development
npm test -w @codelusitan/ui-components # vitest + jsdom
npm run build -w @codelusitan/ui-componentsPublishing is manual (npm publish -w @codelusitan/ui-components, which runs the build first),
independent of @codelusitan/genericfunctions.
