{"id":48111743,"url":"https://github.com/mr-tanta/ndpr-toolkit","last_synced_at":"2026-05-27T02:06:01.094Z","repository":{"id":291181997,"uuid":"976856059","full_name":"mr-tanta/ndpr-toolkit","owner":"mr-tanta","description":"Nigeria Data Protection Toolkit — enterprise-grade React components for NDPA 2023 compliance. Consent management, data subject rights, DPIA, breach notification, privacy policy generator, lawful basis tracking, cross-border transfer assessment, and ROPA.","archived":false,"fork":false,"pushed_at":"2026-04-23T11:29:18.000Z","size":33054,"stargazers_count":6,"open_issues_count":4,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-04-23T12:22:34.144Z","etag":null,"topics":["compliance-toolkit","cross-border-transfer","lawful-basis","ndpa","ndpa-2023","ndpc","nigeria-data-protection","privacy","react-components","ropa","typescript"],"latest_commit_sha":null,"homepage":"http://ndprtoolkit.com.ng/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mr-tanta.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-05-02T22:02:37.000Z","updated_at":"2026-04-23T11:29:22.000Z","dependencies_parsed_at":"2025-05-02T23:23:57.352Z","dependency_job_id":"d448b406-c344-4420-b178-182f9c5e00fc","html_url":"https://github.com/mr-tanta/ndpr-toolkit","commit_stats":null,"previous_names":["tantainnovative/ndpr-toolkit","mr-tanta/ndpr-toolkit"],"tags_count":17,"template":false,"template_full_name":null,"purl":"pkg:github/mr-tanta/ndpr-toolkit","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mr-tanta%2Fndpr-toolkit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mr-tanta%2Fndpr-toolkit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mr-tanta%2Fndpr-toolkit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mr-tanta%2Fndpr-toolkit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mr-tanta","download_url":"https://codeload.github.com/mr-tanta/ndpr-toolkit/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mr-tanta%2Fndpr-toolkit/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32181374,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-23T11:42:27.955Z","status":"ssl_error","status_checked_at":"2026-04-23T11:42:18.877Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["compliance-toolkit","cross-border-transfer","lawful-basis","ndpa","ndpa-2023","ndpc","nigeria-data-protection","privacy","react-components","ropa","typescript"],"created_at":"2026-04-04T16:09:06.148Z","updated_at":"2026-05-27T02:06:01.080Z","avatar_url":"https://github.com/mr-tanta.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# @tantainnovative/ndpr-toolkit\n\n**Compliance infrastructure for the Nigeria Data Protection Act (NDPA) 2023**\n\n[![npm version](https://img.shields.io/npm/v/@tantainnovative/ndpr-toolkit.svg)](https://www.npmjs.com/package/@tantainnovative/ndpr-toolkit)\n[![npm downloads](https://img.shields.io/npm/dm/@tantainnovative/ndpr-toolkit.svg)](https://www.npmjs.com/package/@tantainnovative/ndpr-toolkit)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)\n[![TypeScript](https://img.shields.io/badge/TypeScript-5%2B-3178C6.svg)](https://www.typescriptlang.org/)\n[![CI](https://github.com/mr-tanta/ndpr-toolkit/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/mr-tanta/ndpr-toolkit/actions/workflows/ci.yml)\n[![Bundle Size](https://img.shields.io/bundlephobia/minzip/@tantainnovative/ndpr-toolkit)](https://bundlephobia.com/package/@tantainnovative/ndpr-toolkit)\n\nv3 ships **zero-config presets**, **pluggable storage adapters**, **compound components**, and a **compliance score engine** — eight production-ready modules covering consent, data subject rights, DPIA, breach notification, privacy policies, lawful basis, cross-border transfers, and ROPA.\n\n**[Documentation](https://ndprtoolkit.com.ng)** | **[Live Demos](https://ndprtoolkit.com.ng/ndpr-demos)** | **[npm](https://www.npmjs.com/package/@tantainnovative/ndpr-toolkit)** | **[Blog](https://ndprtoolkit.com.ng/blog)** | **[v3.10.3 Release](https://github.com/mr-tanta/ndpr-toolkit/releases/tag/v3.10.3)**\n\n[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/mr-tanta/ndpr-toolkit/tree/main/examples/nextjs-app)\n[![Open in CodeSandbox](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/p/github/mr-tanta/ndpr-toolkit/main/examples/nextjs-app)\n\n\u003e **What's new in 3.10.x:** Typed theming via `\u003cNDPRThemeProvider\u003e`, a `/headless` subpath alias of `/hooks` for headless-UI consumers, and a production-grade DSR backend reference at `examples/dsr-backend-prod/` (Prisma + Resend behind no-infra shims). New docs guides: [theming](https://ndprtoolkit.com.ng/docs/guides/theming), [headless](https://ndprtoolkit.com.ng/docs/guides/headless), [production-dsr-backend](https://ndprtoolkit.com.ng/docs/guides/production-dsr-backend).\n\u003e\n\u003e **Upgrading from 3.7.x?** See the [3.7 → 3.10 upgrade guide](https://ndprtoolkit.com.ng/docs/guides/upgrading-3-7-to-3-10) — fully additive, no API breaks. Full changelog on [GitHub](https://github.com/mr-tanta/ndpr-toolkit/blob/main/CHANGELOG.md).\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/mr-tanta/ndpr-toolkit/v3.10.3/public/screenshots/hero.png\" alt=\"NDPA Toolkit — NDPA Compliance Made Beautiful\" width=\"800\" /\u003e\n\u003c/p\u003e\n\n---\n\n## The 3-File Quickstart\n\nThree files. Full NDPA consent compliance.\n\n**`app/layout.tsx`**\n```tsx\nimport { NDPRConsent } from '@tantainnovative/ndpr-toolkit/presets';\n\nexport default function RootLayout({ children }: { children: React.ReactNode }) {\n  return (\n    \u003chtml\u003e\n      \u003cbody\u003e\n        {children}\n        \u003cNDPRConsent /\u003e\n      \u003c/body\u003e\n    \u003c/html\u003e\n  );\n}\n```\n\n**`app/api/consent/route.ts`**\n```ts\nimport { NextRequest, NextResponse } from 'next/server';\n\nlet store: unknown = null;\n\nexport async function GET() { return NextResponse.json(store ?? {}); }\nexport async function POST(req: NextRequest) {\n  store = await req.json();\n  return NextResponse.json({ ok: true });\n}\n```\n\n**Persist to your API instead of localStorage:**\n```tsx\nimport { NDPRConsent } from '@tantainnovative/ndpr-toolkit/presets';\nimport { apiAdapter } from '@tantainnovative/ndpr-toolkit/adapters';\n\n\u003cNDPRConsent adapter={apiAdapter('/api/consent')} /\u003e\n```\n\nThat's it. NDPA-compliant consent with server-side persistence in under 20 lines.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/mr-tanta/ndpr-toolkit/v3.10.3/public/screenshots/consent-demo.png\" alt=\"Consent Management Demo — interactive consent banner with state inspector\" width=\"800\" /\u003e\n  \u003cbr /\u003e\n  \u003cem\u003eInteractive consent demo with configurable position, theme, storage, and real-time state inspector\u003c/em\u003e\n\u003c/p\u003e\n\n---\n\n## Install\n\nPick your package manager:\n\n```bash\n# pnpm\npnpm add @tantainnovative/ndpr-toolkit\n\n# Bun\nbun add @tantainnovative/ndpr-toolkit\n\n# npm\nnpm install @tantainnovative/ndpr-toolkit\n\n# Yarn\nyarn add @tantainnovative/ndpr-toolkit\n```\n\nAdd the stylesheet import once in your app entry so components render with default styles:\n\n```ts\n// app/layout.tsx (Next.js App Router) or src/main.tsx (Vite/CRA/Bun)\nimport \"@tantainnovative/ndpr-toolkit/styles\";\n```\n\nThe stylesheet is opinionated but token-driven — override any `--ndpr-*` CSS custom property to theme. Skip this import only if you're using `/unstyled` to bring your own design system.\n\nInstall UI peer dependencies (only needed if you use the higher-level Radix-based components from `/presets`):\n\n```bash\n# pnpm\npnpm add @radix-ui/react-switch @radix-ui/react-tabs @radix-ui/react-label @radix-ui/react-slot lucide-react tailwind-merge clsx class-variance-authority\n\n# Bun\nbun add @radix-ui/react-switch @radix-ui/react-tabs @radix-ui/react-label @radix-ui/react-slot lucide-react tailwind-merge clsx class-variance-authority\n```\n\nOr scaffold instantly with the CLI:\n\n```bash\n# Recommended (idiomatic):\nnpm create ndpr@latest\n\n# Equivalent — pick whichever fits your muscle memory:\nnpx create-ndpr\nnpx @tantainnovative/create-ndpr\npnpm create ndpr\nbun create ndpr\n```\n\n---\n\n## Bun quickstart\n\nBun is a first-class runtime for the toolkit. Both common React app shapes work without extra config.\n\n### Bun + Vite + React\n\n```bash\nbun create vite@latest my-ndpr-app --template react-ts\ncd my-ndpr-app\nbun install\nbun add @tantainnovative/ndpr-toolkit\n```\n\n```tsx\n// src/App.tsx\nimport { NDPRConsent } from '@tantainnovative/ndpr-toolkit/presets/consent';\nimport '@tantainnovative/ndpr-toolkit/styles';\n\nexport default function App() {\n  return (\n    \u003c\u003e\n      \u003cNDPRConsent\n        options={[\n          { id: 'essential', label: 'Essential', description: 'Required for the site to function', required: true, purpose: 'Site operation' },\n          { id: 'analytics', label: 'Analytics', description: 'Anonymous usage measurement', required: false, purpose: 'Product analytics' },\n          { id: 'marketing', label: 'Marketing', description: 'Personalised offers and ads', required: false, purpose: 'Marketing communications' },\n        ]}\n      /\u003e\n      \u003cmain className=\"p-6\"\u003e\n        \u003ch1 className=\"text-3xl font-semibold\"\u003eMy NDPA-compliant app\u003c/h1\u003e\n      \u003c/main\u003e\n    \u003c/\u003e\n  );\n}\n```\n\n```bash\nbun dev\n```\n\nVite is client-only by default — no extra wiring needed. The toolkit's preset components ship with the `\"use client\"` directive already injected.\n\n### Bun + Next.js 15 (App Router)\n\n```bash\nbun create next-app@latest my-ndpr-app --typescript --app --tailwind\ncd my-ndpr-app\nbun add @tantainnovative/ndpr-toolkit\n```\n\nThe consent banner is a stateful client component. Mount it from a small client wrapper so the rest of your layout can stay in RSC:\n\n```tsx\n// app/ConsentRoot.tsx\n'use client';\nimport { NDPRConsent } from '@tantainnovative/ndpr-toolkit/presets/consent';\n\nexport function ConsentRoot() {\n  return (\n    \u003cNDPRConsent\n      options={[\n        { id: 'essential', label: 'Essential', description: 'Required for the site to function', required: true, purpose: 'Site operation' },\n        { id: 'analytics', label: 'Analytics', description: 'Anonymous usage measurement', required: false, purpose: 'Product analytics' },\n        { id: 'marketing', label: 'Marketing', description: 'Personalised offers and ads', required: false, purpose: 'Marketing communications' },\n      ]}\n    /\u003e\n  );\n}\n```\n\n```tsx\n// app/layout.tsx\nimport '@tantainnovative/ndpr-toolkit/styles';\nimport { ConsentRoot } from './ConsentRoot';\n\nexport default function RootLayout({ children }: { children: React.ReactNode }) {\n  return (\n    \u003chtml lang=\"en\"\u003e\n      \u003cbody\u003e\n        \u003cConsentRoot /\u003e\n        {children}\n      \u003c/body\u003e\n    \u003c/html\u003e\n  );\n}\n```\n\n```bash\nbun dev\n```\n\nYou don't need to manually mark the import with `\"use client\"` from `app/layout.tsx` — the preset module already ships the directive in its bundled output, so React Server Components import it cleanly via the client wrapper. For RSC-safe, zero-React imports use `/server` or `/core` instead.\n\n---\n\n## Choose Your Layer\n\nPick exactly what your project needs.\n\n### Presets — zero-config\n\nDrop-in components with sensible defaults. No configuration required.\n\n```tsx\nimport {\n  NDPRConsent,           // Consent banner — works with zero props\n  NDPRSubjectRights,     // DSR request form\n  NDPRBreachReport,      // Breach report form\n  NDPRPrivacyPolicy,     // Policy generator wizard\n  NDPRDPIA,              // DPIA questionnaire\n  NDPRComplianceDashboard, // Visual compliance dashboard\n} from '@tantainnovative/ndpr-toolkit/presets';\n```\n\n### Components — compound pattern\n\nFull control over layout without rebuilding logic.\n\n```tsx\nimport { Consent } from '@tantainnovative/ndpr-toolkit/consent';\n\n\u003cConsent.Provider options={options} onChange={handleSave}\u003e\n  \u003cdiv className=\"my-layout\"\u003e\n    \u003cConsent.OptionList /\u003e\n    \u003cdiv className=\"flex gap-2\"\u003e\n      \u003cConsent.AcceptButton /\u003e\n      \u003cConsent.RejectButton /\u003e\n    \u003c/div\u003e\n  \u003c/div\u003e\n\u003c/Consent.Provider\u003e\n```\n\n### Hooks — headless\n\nStateful hooks for every module. Bring your own UI entirely.\n\n```tsx\nimport { useConsent } from '@tantainnovative/ndpr-toolkit/hooks';\n\nconst { hasConsent, acceptAll, rejectAll, shouldShowBanner } = useConsent({ options });\n```\n\n### Server — strictly RSC-safe, zero React\n\nThe recommended entry for backend and serverless contexts. Pure validators, generators, scoring, locales, and adapters — no React in the import graph. Safe to call from a Next.js Server Component, Edge Function, NestJS controller, or Cloudflare Worker.\n\n```ts\nimport {\n  validateConsent,\n  generatePolicyText,\n  exportHTML,\n  getComplianceScore,\n} from '@tantainnovative/ndpr-toolkit/server';\n```\n\nBuild-output guard tests assert this entry never carries a `\"use client\"` directive and never imports `react` — the RSC-safety contract is structurally enforced.\n\n### Core — types + utilities + Provider\n\nAdds the `NDPRProvider` React Context on top of `/server`'s pure surface. Use when you want types and validators alongside the provider in the same import.\n\n```ts\nimport { NDPRProvider, validateConsent, getComplianceScore } from '@tantainnovative/ndpr-toolkit/core';\n```\n\n### Adapters — pluggable storage\n\nSwap where consent (and other state) is stored without changing any component code.\n\n```ts\nimport { apiAdapter, localStorageAdapter, cookieAdapter } from '@tantainnovative/ndpr-toolkit/adapters';\n```\n\n---\n\n## Pluggable Storage\n\nEvery stateful component accepts an `adapter` prop. Built-in adapters ship out of the box.\n\n```ts\nimport {\n  localStorageAdapter,    // default for browsers\n  sessionStorageAdapter,  // cleared on tab close\n  cookieAdapter,          // server-readable cookies\n  apiAdapter,             // HTTP endpoint (any backend)\n  memoryAdapter,          // in-process, good for SSR / tests\n  composeAdapters,        // fan-out writes to multiple stores\n} from '@tantainnovative/ndpr-toolkit/adapters';\n```\n\n**localStorage (default browser behaviour):**\n```tsx\n\u003cNDPRConsent adapter={localStorageAdapter('ndpr_consent')} /\u003e\n```\n\n**API endpoint:**\n```tsx\n\u003cNDPRConsent adapter={apiAdapter('/api/consent', {\n  headers: { Authorization: `Bearer ${token}` },\n})} /\u003e\n```\n\n**Write to API + keep a local cache:**\n```tsx\nimport { composeAdapters, apiAdapter, localStorageAdapter } from '@tantainnovative/ndpr-toolkit/adapters';\n\n\u003cNDPRConsent adapter={composeAdapters(\n  apiAdapter('/api/consent'),\n  localStorageAdapter('ndpr_consent'),\n)} /\u003e\n```\n\n**Cookie (server-readable, for SSR consent gating):**\n```tsx\n\u003cNDPRConsent adapter={cookieAdapter('ndpr_consent', { expires: 365 })} /\u003e\n```\n\n---\n\n## Compliance Score\n\n`getComplianceScore()` evaluates your posture across all 8 NDPA modules and returns a 0–100 score with rated gaps and prioritised recommendations.\n\n```ts\nimport { getComplianceScore } from '@tantainnovative/ndpr-toolkit/core';\n\nconst report = getComplianceScore({\n  consent: {\n    hasConsentMechanism: true,\n    hasPurposeSpecification: true,\n    hasWithdrawalMechanism: true,\n    hasMinorProtection: false,\n    consentRecordsRetained: true,\n  },\n  dsr: {\n    hasRequestMechanism: true,\n    supportsAccess: true,\n    supportsRectification: false,\n    supportsErasure: false,\n    supportsPortability: false,\n    supportsObjection: false,\n    responseTimelineDays: 30,\n  },\n  dpia: { conductedForHighRisk: true, documentedRisks: true, mitigationMeasures: true },\n  breach: { hasNotificationProcess: true, notifiesWithin72Hours: true, hasRiskAssessment: true, hasRecordKeeping: true },\n  policy: { hasPrivacyPolicy: true, isPubliclyAccessible: true, lastUpdated: '2026-01-01', coversAllSections: true },\n  lawfulBasis: { documentedForAllProcessing: true, hasLegitimateInterestAssessment: false },\n  crossBorder: { hasTransferMechanisms: true, adequacyAssessed: true, ndpcApprovalObtained: false },\n  ropa: { maintained: true, includesAllProcessing: true, lastReviewed: '2026-01-01' },\n});\n\nconsole.log(report.score);         // e.g. 74\nconsole.log(report.rating);        // \"good\" | \"excellent\" | \"needs-work\" | \"critical\"\nconsole.log(report.recommendations[0].priority); // \"critical\"\n```\n\nRender a live dashboard:\n\n```tsx\nimport { NDPRComplianceDashboard } from '@tantainnovative/ndpr-toolkit/presets';\n\n\u003cNDPRComplianceDashboard\n  input={complianceInput}\n  showRecommendations\n  maxRecommendations={5}\n/\u003e\n```\n\n---\n\n## Backend Integration\n\n### CLI scaffolder\n\nScaffold a complete wiring for your stack in seconds:\n\n```bash\nnpx @tantainnovative/create-ndpr\n```\n\nDetects Next.js (App Router or Pages Router) or Express, prompts for your ORM (Prisma / Drizzle / none), and generates API routes, schema, and layout files — no manual copy-pasting.\n\n### Backend recipes\n\n`@tantainnovative/ndpr-recipes` is a reference implementation with production-ready patterns:\n\n| Recipe | What you get |\n|--------|-------------|\n| `prisma/schema.prisma` | All 5 NDPA compliance tables |\n| `src/adapters/prisma-consent.ts` | Prisma `StorageAdapter\u003cConsentSettings\u003e` |\n| `src/adapters/drizzle-consent.ts` | Drizzle `StorageAdapter\u003cConsentSettings\u003e` |\n| `src/nextjs/app-router/` | Consent, DSR, Breach, ROPA, compliance route handlers |\n| `src/express/` | Full NDPR router with consent, DSR, breach, ROPA routes |\n| `src/nextjs/app-router/middleware.ts` | Next.js consent gate middleware |\n\nCopy the files you need into your project. [Browse the recipes →](https://github.com/tantainnovative/ndpr-toolkit/tree/main/packages/ndpr-recipes)\n\n---\n\n## Live Demos\n\nEvery module has an interactive demo. No signup, no setup — try them instantly.\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://ndprtoolkit.com.ng/ndpr-demos\"\u003e\n    \u003cimg src=\"https://raw.githubusercontent.com/mr-tanta/ndpr-toolkit/v3.10.3/public/screenshots/demos-overview.png\" alt=\"8 interactive live demos — zero setup required\" width=\"800\" /\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/mr-tanta/ndpr-toolkit/v3.10.3/public/screenshots/dsr-demo.png\" alt=\"Data Subject Rights — 8 rights with request tracking\" width=\"400\" /\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/mr-tanta/ndpr-toolkit/v3.10.3/public/screenshots/breach-demo.png\" alt=\"Breach Notification — 72-hour countdown with step-by-step workflow\" width=\"400\" /\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cem\u003eLeft: Data Subject Rights portal with 8 NDPA rights. Right: Breach notification with 72-hour NDPC deadline countdown.\u003c/em\u003e\n\u003c/p\u003e\n\n### Open any module in your browser (zero install)\n\nEach module ships a minimal Next.js scaffold you can fork in StackBlitz or CodeSandbox. One click → working app demonstrating just that module:\n\n| Module | NDPA | Open in StackBlitz | Open in CodeSandbox |\n|---|---|---|---|\n| **Ecommerce starter (full app)** | §25–27, §34–38 | [![Open](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/mr-tanta/ndpr-toolkit/tree/main/examples/ecommerce-starter) | [![Open](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/p/github/mr-tanta/ndpr-toolkit/main/examples/ecommerce-starter) |\n| Consent | §26 | [![Open](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/mr-tanta/ndpr-toolkit/tree/main/examples/stackblitz/consent) | [![Open](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/p/github/mr-tanta/ndpr-toolkit/main/examples/stackblitz/consent) |\n| DSR | §34 | [![Open](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/mr-tanta/ndpr-toolkit/tree/main/examples/stackblitz/dsr) | [![Open](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/p/github/mr-tanta/ndpr-toolkit/main/examples/stackblitz/dsr) |\n| DPIA | §28 | [![Open](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/mr-tanta/ndpr-toolkit/tree/main/examples/stackblitz/dpia) | [![Open](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/p/github/mr-tanta/ndpr-toolkit/main/examples/stackblitz/dpia) |\n| Breach | §40 | [![Open](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/mr-tanta/ndpr-toolkit/tree/main/examples/stackblitz/breach) | [![Open](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/p/github/mr-tanta/ndpr-toolkit/main/examples/stackblitz/breach) |\n| Policy | §27 | [![Open](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/mr-tanta/ndpr-toolkit/tree/main/examples/stackblitz/policy) | [![Open](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/p/github/mr-tanta/ndpr-toolkit/main/examples/stackblitz/policy) |\n| Lawful Basis | §25 | [![Open](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/mr-tanta/ndpr-toolkit/tree/main/examples/stackblitz/lawful-basis) | [![Open](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/p/github/mr-tanta/ndpr-toolkit/main/examples/stackblitz/lawful-basis) |\n| Cross-Border | §41–43 | [![Open](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/mr-tanta/ndpr-toolkit/tree/main/examples/stackblitz/cross-border) | [![Open](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/p/github/mr-tanta/ndpr-toolkit/main/examples/stackblitz/cross-border) |\n| RoPA | §29 | [![Open](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/mr-tanta/ndpr-toolkit/tree/main/examples/stackblitz/ropa) | [![Open](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/p/github/mr-tanta/ndpr-toolkit/main/examples/stackblitz/ropa) |\n\nOr open the [all-in-one example](https://stackblitz.com/github/mr-tanta/ndpr-toolkit/tree/main/examples/nextjs-app) that demos every module in a single app.\n\n### SSR-safe consent scaffolds\n\nCookie-bridged consent that hydrates without a flash. Each scaffold reads the `ndpr-consent` cookie on the server, seeds the banner's `show` prop, then lets the browser `cookieAdapter` take over. See the [Server-Side Storage guide](https://ndprtoolkit.com.ng/docs/guides/server-side-storage) for the pattern.\n\n| Framework | Path | Open in StackBlitz |\n|---|---|---|\n| Next.js App Router | [`examples/ssr/nextjs-app-router`](./examples/ssr/nextjs-app-router) | [![Open](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/mr-tanta/ndpr-toolkit/tree/main/examples/ssr/nextjs-app-router) |\n| Remix | [`examples/ssr/remix`](./examples/ssr/remix) | [![Open](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/mr-tanta/ndpr-toolkit/tree/main/examples/ssr/remix) |\n| Astro | [`examples/ssr/astro`](./examples/ssr/astro) | [![Open](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/mr-tanta/ndpr-toolkit/tree/main/examples/ssr/astro) |\n\n---\n\n## All 8 Modules\n\n| Module | Import path | NDPA reference | Key exports |\n|--------|-------------|----------------|-------------|\n| Consent Management | `/consent` | Sections 25–26 | `ConsentBanner`, `ConsentManager`, `Consent.*`, `useConsent` |\n| Data Subject Rights | `/dsr` | Part VI §34–38 | `DSRRequestForm`, `DSRDashboard`, `useDSR` |\n| DPIA | `/dpia` | Section 28 | `DPIAQuestionnaire`, `DPIAReport`, `useDPIA` |\n| Breach Notification | `/breach` | Section 40 | `BreachReportForm`, `BreachRiskAssessment`, `useBreach` |\n| Privacy Policy | `/policy` | Section 27 | `PolicyGenerator`, `PolicyPreview`, `PolicyExporter` |\n| Lawful Basis | `/lawful-basis` | Section 25 | `LawfulBasisTracker`, `useLawfulBasis` |\n| Cross-Border Transfers | `/cross-border` | Part VIII §41–43 | `CrossBorderTransferManager`, `useCrossBorderTransfer` |\n| ROPA | `/ropa` | Section 29 | `ROPAManager`, `useROPA`, `exportROPAToCSV` |\n\n---\n\n## Styling \u0026 Customization\n\nAs of 3.4.0, components ship semantic BEM-style class names (`.ndpr-consent-banner`, `.ndpr-form-field__input`, etc.) backed by a real stylesheet. **Tailwind is no longer required** — the package works in any host so long as you import the stylesheet once.\n\n**Default — works in any host:**\n```ts\n// Once in your app entry\nimport \"@tantainnovative/ndpr-toolkit/styles\";\n```\n```tsx\n\u003cConsentBanner options={options} onSave={handleSave} variant=\"card\" position=\"bottom\" /\u003e\n```\n\n**Theme via CSS custom properties:**\n```css\n/* Override any --ndpr-* token at :root, [data-theme=\"dark\"], or scoped to a parent. */\n:root {\n  --ndpr-primary: 22 163 74;          /* RGB triplet — green-600 */\n  --ndpr-radius: 1rem;\n  --ndpr-font-sans: \"Inter\", system-ui, sans-serif;\n}\n```\n\n**Theme via typed JS object — `NDPRThemeProvider` (new in 3.10.0):**\n```tsx\nimport { NDPRThemeProvider, type NDPRTheme } from '@tantainnovative/ndpr-toolkit';\n\nconst theme: NDPRTheme = {\n  colors: { primary: '22 163 74', primaryHover: '21 128 61' },\n  radius: { base: '0.75rem' },\n  font: { sans: '\"Inter\", system-ui, sans-serif' },\n};\n\n\u003cNDPRThemeProvider theme={theme}\u003e\n  \u003cApp /\u003e\n\u003c/NDPRThemeProvider\u003e\n```\nThe provider wraps children in a single `div` with the `--ndpr-*` variables set inline. Every `NDPRTheme` field is optional and maps 1:1 to a CSS variable defined in the stylesheet — unset fields fall through to defaults. Same end result as raw CSS overrides; pick what fits your codebase. Full reference in [the theming guide](https://ndprtoolkit.com.ng/docs/guides/theming).\n\nLight + dark mode auto-switch via `prefers-color-scheme`, plus an explicit opt-in via `data-theme=\"dark\"` or `.dark` on any ancestor (or `mode: 'dark'` on `NDPRThemeProvider`).\n\n**Per-instance override via slot map:**\n```tsx\n\u003cConsentBanner\n  options={options}\n  onSave={handleSave}\n  classNames={{\n    root: \"my-consent-banner\",\n    acceptButton: \"btn btn-primary\",\n    rejectButton: \"btn btn-secondary\",\n  }}\n/\u003e\n```\n\n**Bring your own design system entirely:**\n```tsx\nimport { ConsentBanner } from '@tantainnovative/ndpr-toolkit/unstyled';\n\n\u003cConsentBanner options={options} onSave={handleSave} classNames={{ /* yours */ }} /\u003e\n```\nThe `/unstyled` entry defaults `unstyled` to `true`, stripping every `.ndpr-*` class so your CSS applies unfiltered. ARIA, focus management, and `data-ndpr-component` attributes are preserved (those are part of the contract, not styling).\n\nEach component exports its `ClassNames` TypeScript interface for autocomplete. Full reference in the [docs](https://ndprtoolkit.com.ng/docs/guides/styling-customization).\n\n---\n\n## Available Import Paths\n\n| Path | What you get | Dependencies | RSC-safe |\n|------|-------------|--------------|:--------:|\n| `.` (default) | Everything | `react`, optional Radix peers for `/presets` | No |\n| `/server` | **Pure validators, generators, scoring, locales, adapters, types — zero React** | `tslib` | **Yes** |\n| `/core` | Types, utility functions, NDPRProvider | `react`[^core] | Partial |\n| `/hooks` | React hooks for all 8 modules | `react` | No |\n| `/headless` | **Alias of `/hooks`** — identical exports under a more discoverable name (3.10.0) | `react` | No |\n| `/presets` | All zero-config preset components (barrel) | `react`, Radix peers | No |\n| `/presets/consent` | **Just `NDPRConsent`** — narrower barrel for bundle size | `react`, Radix peers | No |\n| `/presets/dsr` | **Just `NDPRSubjectRights`** | `react`, Radix peers | No |\n| `/presets/policy` | **Just `NDPRPrivacyPolicy`** | `react`, Radix peers | No |\n| `/adapters` | Storage adapters (localStorage, sessionStorage, cookie, api, memory, composeAdapters) | none | Yes |\n| `/consent` | ConsentBanner, ConsentManager, `Consent.*` compound API, useConsent | `react` | No |\n| `/dsr` | DSR components + hook | `react` | No |\n| `/dpia` | DPIA components + hook | `react` | No |\n| `/breach` | Breach components + hook | `react` | No |\n| `/policy` | Policy components + hook | `react`, `jspdf`, `docx` (optional) | No |\n| `/lawful-basis` | Lawful basis component + hook | `react` | No |\n| `/lawful-basis/lite` | Read-only `LawfulBasisTrackerLite` — ~65% smaller than `/lawful-basis` | `react` | No |\n| `/cross-border` | Cross-border component + hook | `react` | No |\n| `/cross-border/lite` | Read-only `CrossBorderTransferManagerLite` — ~89% smaller (skips the 624-row adequacy dataset) | `react` | No |\n| `/ropa` | ROPA component + hook | `react` | No |\n| `/ropa/lite` | Read-only `ROPAManagerLite` — ~64% smaller than `/ropa` | `react` | No |\n| `/unstyled` | All published components with `unstyled` defaulted to `true` | `react` | No |\n| `/styles` | Default CSS stylesheet — `import \"@tantainnovative/ndpr-toolkit/styles\"` once in your app entry | none | N/A |\n\n[^core]: `/core` re-exports the React `NDPRProvider` for backward compatibility. For strictly server-side imports use `/server` — it carries the same pure validators with no React surface.\n\n### Bundle size guidance\n\nThe toolkit is published with `sideEffects: [\"*.css\"]`, so a modern bundler (Vite, Next.js / Webpack, esbuild, Bun) will tree-shake unused exports. A few practical rules to keep your bundle small:\n\n1. **Prefer narrow subpaths over the root.** `import { useConsent } from '@tantainnovative/ndpr-toolkit/hooks'` is tighter than the same import from `.`. The root entry has more transitive exports and bundlers don't always trace them perfectly.\n\n2. **Use the per-preset subpaths when you only need one preset.** `import { NDPRConsent } from '@tantainnovative/ndpr-toolkit/presets/consent'` is ~4 KB; the full `/presets` barrel is ~8 KB. Same for `/presets/dsr` and `/presets/policy`.\n\n3. **The 3 manager components are intentionally heavy** (each is ~50 KB src — full table + filter + modal + wizard UIs):\n   - `LawfulBasisTracker` (from `/lawful-basis`)\n   - `ROPAManager` (from `/ropa`)\n   - `CrossBorderTransferManager` (from `/cross-border`)\n\n   If your app only needs the hook (e.g. you're rendering ROPA records inside your own admin UI), import from `/hooks` instead of the feature subpath — the hook chunk doesn't drag the manager component into your bundle.\n\n   If your page only needs to *display* records (no Add / Edit / Archive / CSV export), reach for the new **Lite** variants from `/lawful-basis/lite`, `/cross-border/lite`, and `/ropa/lite` instead — they save ~65%, 89%, and 64% respectively. See [Lite vs Full managers](https://ndprtoolkit.com.ng/docs/guides/lite-vs-full).\n\n4. **`/server` carries zero React.** For Server Actions, Route Handlers, scheduled jobs, or compliance-score computation in CI, prefer `/server` and you'll pay no React-tree cost.\n\n---\n\n## NDPA 2023 Overview\n\nThe **Nigeria Data Protection Act (NDPA) 2023** replaced the NDPR 2019 and established the **Nigeria Data Protection Commission (NDPC)** as the independent regulatory body.\n\n| Aspect | NDPR (2019) | NDPA (2023) |\n|--------|-------------|-------------|\n| Legal status | NITDA regulation | Act of the National Assembly |\n| Regulator | NITDA | NDPC (independent commission) |\n| Enforcement | Limited | Independent investigation and penalty powers |\n| Data subject rights | 6 rights | 8 rights (added information + automated decision-making) |\n| Cross-border transfers | Basic provisions | Comprehensive framework with adequacy decisions |\n| Breach notification | 72 hours to NITDA | 72 hours to NDPC (Section 40) |\n| DPIA | Recommended | Required for high-risk processing (Section 28) |\n\n---\n\n## TypeScript\n\nWritten in TypeScript. All types are exported:\n\n```typescript\nimport type {\n  // Consent\n  ConsentOption, ConsentSettings,\n  // DSR\n  DSRRequest, DSRType, DSRStatus,\n  // DPIA\n  DPIAQuestion, DPIASection, DPIAResult,\n  // Breach\n  BreachReport, BreachCategory, RiskAssessment,\n  // Policy\n  PolicySection, PolicyTemplate, PrivacyPolicy,\n  // Lawful Basis\n  LawfulBasis, ProcessingActivity,\n  // Cross-Border\n  CrossBorderTransfer, TransferMechanism,\n  // ROPA\n  ProcessingRecord, RecordOfProcessingActivities,\n  // Compliance score\n  ComplianceInput, ComplianceReport, ComplianceRating,\n  // Storage\n  StorageAdapter,\n} from '@tantainnovative/ndpr-toolkit/core';\n```\n\n---\n\n## Contributing\n\nContributions are welcome. Please read the [Contributing Guide](./CONTRIBUTING.md) before submitting a pull request.\n\n---\n\n## License\n\nMIT\n\n---\n\n## Author\n\n**Abraham Esandayinze Tanta** — Software Engineer \u0026 Data Protection Compliance Specialist\n\n- GitHub: [@mr-tanta](https://github.com/mr-tanta)\n- LinkedIn: [mr-tanta](https://linkedin.com/in/mr-tanta)\n- Organization: [Tanta Innovative](https://github.com/tantainnovative)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmr-tanta%2Fndpr-toolkit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmr-tanta%2Fndpr-toolkit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmr-tanta%2Fndpr-toolkit/lists"}