Reusable React TypeScript library for dashboard widgets, grid layout, and advanced data tables. Built for host app integration with drag, resize, actions, and localStorage persistence.
- Dashboard widget grid: drag, resize, duplicate, remove, actions
- Layout persistence: localStorage hydration and commit
- Data table: typed columns, selection, sorting, filtering, inline edit, pagination
- Error boundaries for widgets and tables (enhanced with reset and logging capabilities)
- Pluggable chart adapters (default SVG)
- ESM + CJS + Types build (tsup)
- Vitest unit/integration tests (80%+ coverage target)
- Playwright E2E tests for critical user paths (e.g., drag/resize in DashboardGrid)
- ESLint + Prettier (flat config)
- Changesets (manual release flow)
- Husky (pre-commit + pre-push)
- Enforced public API via
src/index.ts - Tailwind-compatible styling (no dependency)
- React ecosystem:
reactandreact-dom(host-provided)react-router-dom(required for router-integrated components)zod(required for forms)@ciscode/ui-translate-core(optional i18n)
Install in host app:
npm i react react-dom react-router-dom zod @ciscode/ui-translate-coresrc/components– dashboard, table, form, layout, and common UI componentssrc/hooks– reusable React hookssrc/models– typed configs for tables, forms, sidebar, toolbarsrc/index.ts– only public API (no deep imports allowed)
Anything not exported from src/index.ts is considered private.
- Error boundaries now include a reset mechanism and optional logging integration (e.g., Sentry).
- Hooks (
useLogin,usePasswordReset,useRegister) support error reporting and user-friendly messages.
- Integration Tests: Added workflows for
ControlledZodDynamicFormandTableDataCustom. - E2E Tests: Expanded coverage to include
DashboardGriddrag/resize functionality.
npm run dev– start Vite dev server (for docs/examples)npm run preview– preview Vite buildnpm run build– build library todist/(tsup: ESM + CJS + dts)npm test– run unit/integration tests (Vitest)npm run test:cov– run tests with coverage reportnpm run typecheck– TypeScript typechecknpm run lint– ESLintnpm run format– Prettiernpx changeset– create a changeset
Root exports from src/index.ts:
- Components:
DashboardGrid,WidgetContainer,TableDataCustom,Breadcrumb,ControlledZodDynamicForm,Loader,PageTitle,Sidebar,DarkModeSwitcher, etc. - Hooks:
useLocalStorage,useColorMode,useGeneratePageNumbers - Types:
ColumnConfigTable,FieldConfigDynamicForm,SidebarItemModel,ToolbarItemModel, layout types
Internal-only components and utilities are intentionally not exported to avoid coupling. Use the wrapped components provided by the public API.
Some components (e.g., Breadcrumb) rely on React Router. In host apps, wrap your app with RouterProvider from react-router-dom and ensure Link works:
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
const router = createBrowserRouter([{ path: '/', element: <App /> }]);
export function Root() {
return <RouterProvider router={router} />;
}Hooks
useLocalStorage:const [theme, setTheme] = useLocalStorage('color-theme', 'light');
useColorMode:const { colorMode, setColorMode } = useColorMode();
useGeneratePageNumbers:const pages = useGeneratePageNumbers({ currentPage: 1, totalPages: 5 });
Components
-
DashboardGrid:<DashboardGrid widgets={widgets} persistKey="dashboard-layout" />
-
TableDataCustom:import { TableDataCustom, type ColumnConfigTable } from '@ciscode/widgetkit-ui'; type Row = { id: number; name: string }; const columns: ColumnConfigTable<Row>[] = [ { key: 'id', title: 'ID' }, { key: 'name', title: 'Name' }, ]; <TableDataCustom<Row> columns={columns} data={[{ id: 1, name: 'Alice' }]} pagination={{ currentPage: 1, totalPages: 3, totalItems: 1, onPageChange: (p) => console.log(p), }} />;
-
ControlledZodDynamicForm:import { ControlledZodDynamicForm, type FieldConfigDynamicForm } from '@ciscode/widgetkit-ui'; import { z } from 'zod'; const schema = z.object({ name: z.string().min(1) }); const fields: FieldConfigDynamicForm[] = [{ key: 'name', label: 'Name', type: 'text' }]; <ControlledZodDynamicForm fields={fields} schema={schema} values={{ name: '' }} onChangeField={(field, val) => { /* update your form state */ }} onSubmit={(values) => console.log(values)} />;
- Router: switch imports to
react-router-dom(Link,RouterProvider). - Forms:
ControlledZodDynamicFormexpects controlledvaluesandonChangeFieldfor reliability. - Table: use
TableDataCustomwrapper; base-only internals are private. - Exports: import only from the package root — all public APIs are re-exported via
src/index.ts.
- Unit tests live under
tests/unit/and run injsdom. - Coverage uses
v8provider; HTML report is written tocoverage/. - Demo/layout code excluded from coverage; focus is on exported library APIs.
- Pagination icons respond to
document.dirand mirror correctly for RTL. - Components use
ltr:/rtl:Tailwind variants where layout matters.
- Work on a
featurebranch fromdevelop - Merge to
develop - Add a changeset for user-facing changes:
npx changeset - Promote
develop→master - Tag
vX.Y.Zto publish (npm OIDC)
- Run the local examples to preview components:
npm run dev- The examples import from the local source via an alias
@ciscode/widgetkit-ui.
To publish:
- Ensure
npm run prepublishOnlypasses (format, lint, typecheck, tests, build). - Use Changesets to bump versions and generate changelog.
- Publish with
npm publish --provenance.
npm run prepublishOnlysucceeds- Unit coverage ≥ 80%
- E2E smoke/examples pass (optional for host-only packages)
- Changeset created and PR merged
dist/containsindex.js,index.cjs,index.d.ts
This repository is a library. Teams should focus only on library logic, not tooling or release mechanics.