@dashboardpack/core
v1.7.0
Published
Shared UI components, providers, data modules, and utilities for DashboardPack templates
Readme
@dashboardpack/core
Shared UI components, providers, data modules, and utilities for DashboardPack templates (Apex, Zenith, Flux, Ember).
This is a source-only package. It ships untranspiled TypeScript and TSX — there is no build step and no dist/. Consuming apps compile it themselves.
Installation
npm install @dashboardpack/coreAdd it to transpilePackages in next.config.ts so Next.js compiles the source:
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
transpilePackages: ["@dashboardpack/core"],
};
export default nextConfig;Because the package exports raw paths ("./*": "./*"), imports mirror the directory layout:
import { Button } from "@dashboardpack/core/components/ui/button";
import { PageHeader } from "@dashboardpack/core/components/shared/page-header";
import { orders } from "@dashboardpack/core/lib/data";
import { cn } from "@dashboardpack/core/lib/utils";What's inside
| Path | Contents |
| --- | --- |
| components/ui/ | 35 shadcn/ui-style primitives (button, card, dialog, form, live-region, …) |
| components/shared/ | PageHeader, EmptyState, ConfirmDialog, DataTable, LazyChart, DateRangePicker |
| providers/ | ThemeProvider (dark/light/system + resolvedTheme), SidebarProvider (collapse, layout mode, container mode, direction) |
| lib/data-provider/ | DataProvider interface, mock / REST / fixture implementations, and useList / useOne / useMutation |
| lib/navigation/ | Node types plus toTree / toFlat / toSitemap / activeLeaf / validateRegistry |
| lib/rbac/ | can, effectivePermissions, permissionGroups, Can, RequirePermission, usePermissions |
| lib/schemas/ | Shared zod schemas for the user and role forms |
| lib/data/ | Mock data for every page (orders, products, customers, invoices, users, roles, analytics, chat, mail, kanban, calendar, files, notifications) |
| lib/data/paginate.ts | paginate() and the perPage: "all" sentinel |
| lib/data/types.ts | Shared TypeScript interfaces, PERMISSION_KEYS and PermissionKey |
| lib/i18n/ | useTranslations() hook and message files (en, de, fr) |
| lib/utils.ts | cn() and generateInitials() |
Replacing the mock data
Pages talk to a DataProvider, not to the mock modules, so switching to a real API
is a one-line change in the template:
// src/lib/data/provider.ts
export const dataProvider = createMockProvider({ baseUrl: "/api" });
// export const dataProvider = createRestProvider({ baseUrl: process.env.NEXT_PUBLIC_API_URL! });createMockProvider fetches static JSON over HTTP, so loading, error and retry
states are real even with no backend. createRestProvider writes optimistically
and rolls back on failure. createFixtureProvider is for tests, with failNext()
and setLatency().
Mock mutations are in-memory and reset on reload. That is deliberate: persisting them would let a visitor's edits drift from the shipped fixtures, so the demo would stop being reproducible.
Permissions are not security
lib/rbac gates UI affordances. A template built on it ships as static HTML with
its data in public JSON files, so everything is already on the client and no
client-side check can change that. Use it to hide and disable controls, and enforce
the same rules on your server. The module's source says the same thing, at the top,
on purpose.
Peer dependencies
Everything the components import is a peer dependency, so the consuming template controls the versions. React 19 and Next.js 16 are the baseline. See peerDependencies in package.json for the full list and supported ranges.
The only runtime dependencies are @radix-ui/react-slot and sugar-high.
Developing against a template
Do not use npm link. This package keeps its peer dependencies installed so it
can typecheck standalone, and under a link the consumer resolves them from here —
so react-hook-form loads twice from two paths and TypeScript reports Control<T>
from each copy as a distinct type, producing dozens of "not assignable" errors that
do not exist in a real install. Consumers also set preserveSymlinks: true and
resolve.symlinks = false, so a link resolves through the symlinked path regardless.
Copy the published files instead, which reproduces npm install exactly:
./tools/sync-to-consumer.sh ../apex-dashboardThen run the template's own npm run verify.
Checks
npm run verify # typecheck + check:rsc + check:package + testscheck:rsc— fails if a module without"use client"imports theradix-uibarrel. See the Server Component safety section below; this is the guard for the crash that shipped in 1.1.3.check:package— fails if the tarball would ship test files, dev tooling or a build cache, or if a documented entry point is missing.exports: { "./*": "./*" }gives no import-time safety net, so a missing file is a runtime failure for the customer.
Contributing: React Server Component safety
Most components here are client components and carry a "use client" directive. A few are deliberately not client components — button.tsx, breadcrumb.tsx, card.tsx, badge.tsx, avatar.tsx, input.tsx, textarea.tsx, progress.tsx, skeleton.tsx — so that templates can render them from Server Components such as not-found.tsx, layout.tsx, or error pages.
Never import from the radix-ui barrel in a file without "use client".
The barrel eagerly evaluates every Radix primitive on import, and several of them call React.createContext() at module scope. In the React Server Component graph createContext does not exist, so the import crashes the page:
TypeError: React.createContext is not a functionWhether it actually crashes depends on whether the consuming bundler tree-shakes the barrel, which makes it fail on some machines and not others. Import the individual primitive package instead:
// Wrong — pulls in every Radix primitive
import { Slot } from "radix-ui";
// Right — only what is needed, and free of module-scope createContext
import * as Slot from "@radix-ui/react-slot";You can verify a change with:
node --conditions=react-server -e "require('<package-name>')"If that throws createContext is not a function, the package is not safe to import from a Server Component.
This rule caused a shipped regression in 1.2.0 — see CHANGELOG.md.
License
MIT
