@tantainnovative/ndpr-toolkit 3.6.1 → 3.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/CHANGELOG.md +230 -0
  2. package/README.md +146 -1
  3. package/dist/chunk-2MIQXECH.mjs +3 -0
  4. package/dist/chunk-3GRGYT3P.js +1 -0
  5. package/dist/chunk-5IOC3VAW.js +1 -0
  6. package/dist/chunk-ATFUSHC2.mjs +2 -0
  7. package/dist/{chunk-SJRIOZ4K.mjs → chunk-EFIWANHF.mjs} +1 -1
  8. package/dist/chunk-GQYBS3A7.mjs +0 -0
  9. package/dist/chunk-HXWHL4BD.js +3 -0
  10. package/dist/chunk-OZCNFB5C.js +1 -0
  11. package/dist/chunk-R7545FP4.mjs +1 -0
  12. package/dist/chunk-UKLU6BQF.mjs +1 -0
  13. package/dist/{chunk-I2LMQWK3.js → chunk-W7OLQRJP.js} +2 -2
  14. package/dist/{chunk-RXZFYBUJ.js → chunk-XS3Z4UT7.js} +1 -1
  15. package/dist/core.d.mts +70 -0
  16. package/dist/core.d.ts +70 -0
  17. package/dist/core.js +1 -1
  18. package/dist/core.mjs +1 -1
  19. package/dist/cross-border-lite.d.mts +141 -0
  20. package/dist/cross-border-lite.d.ts +141 -0
  21. package/dist/cross-border-lite.js +2 -0
  22. package/dist/cross-border-lite.mjs +2 -0
  23. package/dist/dsr.js +1 -1
  24. package/dist/dsr.mjs +1 -1
  25. package/dist/headless.d.mts +2391 -0
  26. package/dist/headless.d.ts +2391 -0
  27. package/dist/headless.js +2 -0
  28. package/dist/headless.mjs +2 -0
  29. package/dist/hooks.d.mts +10 -0
  30. package/dist/hooks.d.ts +10 -0
  31. package/dist/hooks.js +1 -1
  32. package/dist/hooks.mjs +1 -1
  33. package/dist/index.d.mts +133 -0
  34. package/dist/index.d.ts +133 -0
  35. package/dist/index.js +1 -1
  36. package/dist/index.mjs +1 -1
  37. package/dist/lawful-basis-lite.d.mts +153 -0
  38. package/dist/lawful-basis-lite.d.ts +153 -0
  39. package/dist/lawful-basis-lite.js +2 -0
  40. package/dist/lawful-basis-lite.mjs +2 -0
  41. package/dist/policy.d.mts +86 -0
  42. package/dist/policy.d.ts +86 -0
  43. package/dist/policy.js +1 -1
  44. package/dist/policy.mjs +1 -1
  45. package/dist/presets-dsr.d.mts +25 -0
  46. package/dist/presets-dsr.d.ts +25 -0
  47. package/dist/presets-dsr.js +1 -1
  48. package/dist/presets-dsr.mjs +1 -1
  49. package/dist/presets-policy.d.mts +71 -0
  50. package/dist/presets-policy.d.ts +71 -0
  51. package/dist/presets-policy.js +1 -1
  52. package/dist/presets-policy.mjs +1 -1
  53. package/dist/presets.d.mts +96 -0
  54. package/dist/presets.d.ts +96 -0
  55. package/dist/presets.js +1 -1
  56. package/dist/presets.mjs +1 -1
  57. package/dist/ropa-lite.d.mts +218 -0
  58. package/dist/ropa-lite.d.ts +218 -0
  59. package/dist/ropa-lite.js +2 -0
  60. package/dist/ropa-lite.mjs +2 -0
  61. package/dist/server.d.mts +70 -0
  62. package/dist/server.d.ts +70 -0
  63. package/dist/server.js +1 -1
  64. package/dist/server.mjs +1 -1
  65. package/package.json +3 -2
  66. package/dist/chunk-BNHQFZHL.mjs +0 -2
  67. package/dist/chunk-O6CUBNXK.mjs +0 -3
  68. package/dist/chunk-RV2VMWZJ.mjs +0 -1
  69. package/dist/chunk-UI536RU2.js +0 -3
  70. package/dist/chunk-W7RBGZCC.js +0 -1
package/CHANGELOG.md CHANGED
@@ -2,6 +2,236 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines.
4
4
 
5
+ ## [3.10.1](https://github.com/mr-tanta/ndpr-toolkit/compare/v3.10.0...v3.10.1) (2026-05-25)
6
+
7
+ Hotfix release. Code and runtime are identical to 3.10.0 — this patch fixes the build/publish pipeline that silently failed every release from 3.8.0 onward, so 3.10.1 is the first version since 3.7.0 to actually reach npm.
8
+
9
+ ### Root cause
10
+
11
+ The dts-rollup post-build step (`scripts/rollup-dts.mjs`) deletes "leftover" hash-suffixed declaration files that tsup emits alongside each rolled-up entry. The 3.8.0 release added new entry names with two hyphens (`lawful-basis-lite`, `cross-border-lite`) — and the hash-suffix regex `/-[A-Za-z0-9_-]{8,}\.d\.m?ts$/` matched those legitimate entries because the trailing `basis-lite` / `border-lite` segments fall inside the 8-char dash-inclusive window. The sweep then deleted `dist/lawful-basis-lite.d.ts` and `dist/cross-border-lite.d.ts` right after rollup, the workflow's entry-points check then failed, and `npm publish` never ran. The git tags / GitHub releases for 3.8.0, 3.8.1, 3.9.0, and 3.10.0 existed; only npm was stuck on 3.7.0.
12
+
13
+ ### Fix
14
+
15
+ - Replaced the regex-based sweep with an explicit allowlist (`new Set([...ENTRIES, 'styles'])`). Any `.d.ts` / `.d.mts` whose basename isn't in the allowed entries gets swept. No more pattern matching against names.
16
+ - Wired the 3.10.0 `/headless` entry into the root `tsup.config.ts` (it had only been wired in `packages/ndpr-toolkit/tsup.config.ts`, which the publish workflow doesn't use) and added it to `CLIENT_ENTRIES` so the `"use client"` banner is injected.
17
+ - Workflow's `Verify entry points` step now covers 22 entries (was 21) — added `headless`.
18
+
19
+ ### Recovery
20
+
21
+ After this patch lands and 3.10.1 publishes successfully, the failed tags (v3.8.0, v3.8.1, v3.9.0, v3.10.0) will be backfilled to npm by cherry-picking this fix onto each tagged commit and re-running the workflow.
22
+
23
+ ## [3.10.0](https://github.com/mr-tanta/ndpr-toolkit/compare/v3.9.0...v3.10.0) (2026-05-25)
24
+
25
+ Phase J of the feedback work — new API surface (theme provider + headless alias) and a production-grade DSR backend reference. Fully additive — no breaking changes.
26
+
27
+ ### `NDPRThemeProvider` — typed theme object → CSS variables
28
+
29
+ A small React Context provider that takes a TypeScript theme object and injects matching `--ndpr-*` CSS custom properties on a wrapping `div`. Syntactic sugar over the existing CSS-variable theming model — unset fields fall through to stylesheet defaults.
30
+
31
+ ```tsx
32
+ import { NDPRThemeProvider, type NDPRTheme } from '@tantainnovative/ndpr-toolkit';
33
+
34
+ const theme: NDPRTheme = {
35
+ colors: { primary: '22 163 74', primaryHover: '21 128 61' }, // RGB triplets
36
+ radius: { base: '0.75rem' },
37
+ font: { sans: '"Inter", system-ui, sans-serif' },
38
+ };
39
+
40
+ <NDPRThemeProvider theme={theme}>
41
+ <App />
42
+ </NDPRThemeProvider>
43
+ ```
44
+
45
+ The `NDPRTheme` interface keys are derived 1:1 from the variables actually defined in `styles.css` — no inventing tokens. Setting `mode: 'dark'` stamps `data-theme="dark"` on the wrapper to activate the stylesheet's dark-mode block. **6 new tests** cover variable injection, key isolation, dark-mode wiring, and className passthrough. Exported from the default entry only (not `/core`) to keep the RSC-safe surface clean.
46
+
47
+ ### `/headless` subpath — alias of `/hooks` for discoverability
48
+
49
+ A pure rename of the existing `/hooks` entry under a more discoverable name. Same exports, same source, same identifiers — `export *` from `hooks-entry.ts`. Useful when consumers grep for "headless" looking for a hooks-only API.
50
+
51
+ ```tsx
52
+ import { useConsent, useDSR, useFocusTrap } from '@tantainnovative/ndpr-toolkit/headless';
53
+ ```
54
+
55
+ **12 new tests** verify that `/headless` and `/hooks` export identical keys and identity-equal values (so the alias can never silently drift). Wired into `package.json` exports, `typesVersions`, and `tsup.config.ts`.
56
+
57
+ ### `examples/dsr-backend-prod/` — production-grade DSR backend
58
+
59
+ A 14-file Next.js 15 / React 19 reference implementation that wires `NDPRSubjectRights` to a real backend pipeline:
60
+
61
+ 1. **Validate** via `validateDsrSubmission` from `/server` — 400 with `{ error, fields }` on invalid payloads.
62
+ 2. **Defense-in-depth** disposable-email blocklist (configurable via `DSR_BLOCKED_EMAIL_DOMAINS`).
63
+ 3. **Persist** to a Prisma `DSRRequest` model with a 30-day `estimatedCompletionAt` (NDPA Part IV §29-36).
64
+ 4. **Confirm** by sending a Resend transactional email — best-effort: the request still succeeds if email fails.
65
+
66
+ Both Prisma and Resend are wrapped in **dual-mode shims**: real clients when `DATABASE_URL` / `RESEND_API_KEY` are set, otherwise a Map-backed mock and a stdout logger. The example runs out of the box with no infrastructure.
67
+
68
+ The 201 response is exactly `{ referenceId, status, estimatedCompletionAt }` — the shape `NDPRSubjectRights.onSubmitSuccess` consumers read from `body` per the 3.8.1 contract.
69
+
70
+ ### Three new docs guides
71
+
72
+ Wired into the Implementation Guides sidebar:
73
+
74
+ - `/docs/guides/theming` — `NDPRThemeProvider`, the full `NDPRTheme` reference, RGB-triplet convention, dark mode, when not to use the provider
75
+ - `/docs/guides/headless` — `/headless` quickstart, the 10 hooks it exposes, adapter wiring, bundle-size note, the relationship to `/hooks`
76
+ - `/docs/guides/production-dsr-backend` — walks through the `examples/dsr-backend-prod` pipeline, response contract, and how to swap in your own database/email stack
77
+
78
+ ### Verification
79
+
80
+ - `tsc --noEmit` clean for the docs site
81
+ - **Full Jest suite: 1192/1192 passing** (was 1173 — +19: 6 ThemeProvider + 12 headless-parity + 1 default-entry exports check)
82
+ - No changes to existing prop types, hook signatures, or storage adapters
83
+
84
+ ## [3.9.0](https://github.com/mr-tanta/ndpr-toolkit/compare/v3.8.1...v3.9.0) (2026-05-25)
85
+
86
+ Examples expansion + Bun quickstart + SSR-safe storage docs. Fully additive — no breaking changes.
87
+
88
+ ### Runnable example apps
89
+
90
+ - **`examples/ecommerce-starter`** — multi-page Next.js 15 / React 19 storefront ("Zuri Market") wiring the toolkit into a realistic Nigerian ecommerce flow: home page, checkout, privacy notice, data-subject rights portal (with `submitTo` + `onSubmitSuccess` rendering a server-issued reference), and an editable cookie preferences page using `useConsent`. Demonstrates the `/presets/consent`, `/presets/dsr`, `/presets/policy`, and `/hooks` subpaths together.
91
+ - **`examples/ssr/nextjs-app-router`** — SSR-safe consent on Next.js 15. Layout reads the consent cookie via `next/headers`, parses it with a small typed helper, and passes the result to a client `ConsentRoot` so the banner hydrates already-resolved (no flash, no hydration warning).
92
+ - **`examples/ssr/remix`** — the same cookie-bridge pattern wired from a Remix `loader` and Vite's `?url` asset import for the stylesheet.
93
+ - **`examples/ssr/astro`** — `Astro.cookies.get` in the page frontmatter, then `<ConsentRoot client:load>` as a React island.
94
+
95
+ Each example is self-contained (own `package.json`, `tsconfig.json`, `next.config.mjs` / `vite.config.ts` / `astro.config.mjs`) so you can copy a directory and `bun install && bun dev` to run it.
96
+
97
+ ### Bun quickstart in the README
98
+
99
+ Root README now includes copy-pasteable Bun + Vite + React and Bun + Next.js 15 (App Router) recipes that go from zero to a working banner in three commands. The npm-published README also gets a one-line Bun install command alongside pnpm/npm.
100
+
101
+ ### SSR-safe storage guide
102
+
103
+ New docs page at **`/docs/guides/server-side-storage`** documenting the cookie-bridge pattern in detail: why `localStorageAdapter` flashes on SSR, how `cookieAdapter` solves it, and worked examples for Next.js App Router, Remix, Astro, and SvelteKit. Wired into the docs sidebar under Implementation Guides.
104
+
105
+ ### npm-published README brought current (3.4.0 → 3.9.0)
106
+
107
+ The README that ships to npm was stale at the 3.4.0 highlights. It now leads with a 3.9.0 "what's new", references back to 3.8.1 (`onSubmitSuccess`), 3.8.0 (Lite Manager variants), 3.6.0 (`onSubmitError`), and 3.5.x (focus management + reduced motion). Adds a "Runnable Examples" section, a typed DSR callbacks snippet in the Presets section, and a Bun install command. Screenshot URLs bumped from `v3.5.2` → `v3.9.0`. Tests badge bumped to 1173.
108
+
109
+ ### Verification
110
+
111
+ - `tsc --noEmit` clean for the docs site
112
+ - **Full Jest suite: 1173/1173 passing** (unchanged from 3.8.1 — no logic changes in the published package)
113
+ - No changes to runtime exports, prop types, or storage adapters
114
+
115
+ ## [3.8.1](https://github.com/mr-tanta/ndpr-toolkit/compare/v3.8.0...v3.8.1) (2026-05-25)
116
+
117
+ Documentation + small API addition patch. Fully additive — no breaking changes.
118
+
119
+ ### `NDPRSubjectRights` — typed `onSubmitSuccess` callback
120
+
121
+ Counterpart to the existing `onSubmitError`. Fires when the `submitTo` POST returns a 2xx response. Receives the `Response`, the submitted `DSRFormSubmission` payload, and the parsed JSON body (or `undefined` if the response had no body or was not valid JSON).
122
+
123
+ ```tsx
124
+ <NDPRSubjectRights
125
+ submitTo="/api/dsr"
126
+ onSubmitSuccess={({ response, data, body }) => {
127
+ const ref = (body as { referenceId?: string })?.referenceId;
128
+ if (ref) router.push(`/dsr-confirmation?ref=${ref}`);
129
+ }}
130
+ onSubmitError={({ error, response }) => {
131
+ console.error('DSR submit failed', error, response?.status);
132
+ }}
133
+ />
134
+ ```
135
+
136
+ The `body` field is `unknown` to force consumers to narrow it themselves before reading fields. **4 new tests** cover both success and failure paths.
137
+
138
+ ### Documentation
139
+
140
+ - **DSR submission payload contract** documented on the Data Subject Rights component page (`/docs/components/data-subject-rights#submission-payload`). Includes the canonical `DSRFormSubmission` TypeScript interface, a concrete JSON example, the recommended response shape, and a working Next.js App Router backend handler.
141
+ - **Accessibility sections** added to ConsentBanner and DSRRequestForm docs pages. Each lists CONCRETE a11y features verified against the source — `useFocusTrap`, escape-to-dismiss, `prefers-reduced-motion` block in the BEM stylesheet, `role="alert"` on errors, `aria-required` + `aria-invalid` wiring on form fields, etc. Features that aren't implemented (e.g. auto-focusing the first invalid field) are NOT claimed — they're suggested as consumer-side recipes instead.
142
+ - **Migration guide 3.5 → 3.8** at `/docs/guides/migrating-3-5-to-3-8`. Covers every minor and patch from 3.5.4 through 3.8.1 with a "what changed / action required" breakdown, a net migration diff for the most common upgrade path (adapter → submitTo + onSubmitSuccess), and a verify checklist. Sidebar entry added under Implementation Guides.
143
+
144
+ ### Verification
145
+
146
+ - `tsc --noEmit` clean for both the library and the docs site
147
+ - **Full Jest suite: 1173/1173 passing** (was 1169 — +4 new submit-callback tests)
148
+ - No changes to the existing `onSubmitError`, `submitTo`, or `submitOptions` props (backward compatible)
149
+
150
+ ## [3.8.0](https://github.com/mr-tanta/ndpr-toolkit/compare/v3.6.2...v3.8.0) (2026-05-24)
151
+
152
+ ### Lite (read-only) variants of the heavy Manager components
153
+
154
+ Three new components — `LawfulBasisTrackerLite`, `ROPAManagerLite`, `CrossBorderTransferManagerLite` — that render the same list-and-summary view as their Full counterparts without the form, validation, write callbacks, or CSV-export utilities. Built for dashboards, audit pages, embedded compliance widgets, and customer-facing transparency pages where users only need to *see* the records.
155
+
156
+ Exposed at new subpath entries:
157
+
158
+ ```ts
159
+ import { LawfulBasisTrackerLite } from '@tantainnovative/ndpr-toolkit/lawful-basis/lite';
160
+ import { ROPAManagerLite } from '@tantainnovative/ndpr-toolkit/ropa/lite';
161
+ import { CrossBorderTransferManagerLite } from '@tantainnovative/ndpr-toolkit/cross-border/lite';
162
+ ```
163
+
164
+ Bundle deltas (minified + tree-shaken, pre-gzip; **transitive closure** of each subpath):
165
+
166
+ | Module | Full | Lite | Saved |
167
+ |---|---|---|---|
168
+ | `/lawful-basis` → `/lawful-basis/lite` | 36.7 KB | 12.7 KB | **65%** |
169
+ | `/cross-border` → `/cross-border/lite` | 53.3 KB | 5.6 KB | **89%** |
170
+ | `/ropa` → `/ropa/lite` | 36.9 KB | 13.2 KB | **64%** |
171
+
172
+ The cross-border Lite saves the most because it does NOT import the 624-row country-adequacy dataset — Lite displays `adequacyStatus` from each transfer record directly instead of recomputing it.
173
+
174
+ Each Lite component accepts an optional `onActivityClick` / `onRecordClick` / `onTransferClick` callback so consumers can render their own detail view on row click. All other props (`title`, `description`, `unstyled`, `classNames`, `showSummary`, `showComplianceGaps`/`showRiskAlerts`) carry the same names and semantics as the Full versions.
175
+
176
+ Existing `/lawful-basis`, `/cross-border`, and `/ropa` entries are unchanged. This release is fully additive — no consumers need to migrate.
177
+
178
+ See the new guide: [Lite vs Full managers](https://ndprtoolkit.com.ng/docs/guides/lite-vs-full).
179
+
180
+ ### Other
181
+
182
+ - Added `lawful-basis-lite`, `cross-border-lite`, `ropa-lite` to the publish workflow's entry-point verification loop. Total verified entries: 21.
183
+
184
+ ## [3.6.2](https://github.com/mr-tanta/ndpr-toolkit/compare/v3.7.0...v3.6.2) (2026-05-24)
185
+
186
+ Compressed Phase D + E + F patch — companion-CLI templates, per-module StackBlitz scaffolds, and a real backend for the `/score` lead-magnet. Main `@tantainnovative/ndpr-toolkit` library has no code changes; the bump is for changelog alignment.
187
+
188
+ ### Companion packages
189
+
190
+ - **`@tantainnovative/create-ndpr@0.3.0`** — the 9 remaining route templates now support all three ORM choices via `{{#if ORM=prisma|drizzle|none}}` conditional blocks. Picking `ORM=none` now scaffolds a fully working in-memory app for every endpoint, not just consent:
191
+ - Next.js routes: dsr, breach, dpia, lawful-basis, cross-border
192
+ - Express routes: consent, dpia, lawful-basis, cross-border
193
+ - **`create-ndpr@1.0.0` (unscoped alias)** — `packages/create-ndpr-unscoped/PUBLISHING.md` documents the one-time manual publish + Trusted Publisher setup so future updates flow through CI.
194
+
195
+ ### Docs
196
+
197
+ - **8 per-module StackBlitz scaffolds** under `examples/stackblitz/{consent,dsr,dpia,breach,policy,lawful-basis,cross-border,ropa}/`. Each is a minimal Next.js 15 + React 19 app that demonstrates ONE preset. Boot any of them in StackBlitz / CodeSandbox with one click — no clone, no install. README has a per-module badge table.
198
+ - **Each recipe page** (`/docs/recipes/*`) now has "Open in StackBlitz" + "Open in CodeSandbox" badges pointing at the matching module's scaffold.
199
+ - **`/score` email capture** now uses a real backend (Web3Forms) when `NEXT_PUBLIC_WEB3FORMS_KEY` is set, with the mailto: path preserved as a graceful fallback when the env var is missing or the request fails. Lead emails arrive as structured fields (name, email, org, score, top recommendations) instead of free-form mail-client output.
200
+
201
+ ### No library code changes
202
+
203
+ `@tantainnovative/ndpr-toolkit` package is unchanged; consumers don't need to upgrade. The version bump keeps the repo, npm, and CHANGELOG in lockstep so the next library feature (3.8.0 with manager-component bundle splitting) lands cleanly.
204
+
205
+ ## [3.7.0](https://github.com/mr-tanta/ndpr-toolkit/compare/v3.6.1...v3.7.0) (2026-05-24)
206
+
207
+ Phase B — Template + Recipe Library. Closes the dev-feedback content gap (feedback items #7 and #9). New API additions are all backward-compatible — 3.6.x consumers upgrade without changes.
208
+
209
+ ### Features
210
+
211
+ * **5 org-specific privacy-policy templates.** New `templateContextFor(id, overrides?)` factory exported from `/`, `/core`, `/server`, and `/policy`. Pre-fills a complete `TemplateContext` with sector-appropriate data categories, lawful-basis defaults, and the right flags for children/sensitive/financial/cross-border/automated-decisions:
212
+ - **`saas`** — startup-shape, cross-border on (overseas cloud), no sensitive
213
+ - **`ecommerce`** — financial on, cross-border on (payment processors), automated-decisions on (fraud)
214
+ - **`school`** — `hasChildrenData: true` (NDPA Section 31 parental consent), education industry
215
+ - **`healthcare`** — `hasSensitiveData: true` (Section 30 medical/biometric), financial on (insurance)
216
+ - **`procurement`** — government industry, financial on, BVN + gov IDs selected
217
+ * **`<NDPRPrivacyPolicy template="…" />` prop.** Drop a template id and the wizard opens already populated. Optional `templateOverrides` for org name/DPO/address. Existing `adapter` + `onComplete` API unchanged.
218
+ * **`ORG_POLICY_TEMPLATE_REGISTRY` constant** — listing of all 5 templates with id, label, description, and example org types. Useful for building a template-picker UI.
219
+ * **`initialContext` prop** added to `<AdaptivePolicyWizard>` and `useAdaptivePolicyWizard()` — lets advanced consumers bypass the template lookup and seed with a hand-built `TemplateContext`.
220
+
221
+ ### Docs
222
+
223
+ * **5 new recipe pages at `/docs/recipes/*`** — production-tested patterns drawn from real adopter feedback:
224
+ - `ecommerce-consent` — checkout flow, cart-abandonment cookies, marketing-pixel gating with `useConsent`
225
+ - `newsletter-consent` — Section 26 affirmative opt-in (no pre-checked boxes), double opt-in pattern, audit-trail snippet
226
+ - `contact-form-disclosure` — minimum-viable Section 27 notice on a public contact form, data-minimisation guidance
227
+ - `careers-rights` — applicant data lawful basis, retention by candidate outcome, automated CV-screening disclosure (Section 37)
228
+ - `admin-dsr-management` — DPO/staff-side workflow: queue, identity verification, 30-day deadline tracking, audit trail
229
+ * **Recipes section added to docs nav + sitemap.** Each recipe page has full SEO meta and is canonicalised.
230
+
231
+ ### Tests
232
+
233
+ * 12 new tests for the org templates (1 per template + override behaviour + registry consistency). Suite now at **1146 passing**.
234
+
5
235
  ## [3.6.1](https://github.com/mr-tanta/ndpr-toolkit/compare/v3.6.0...v3.6.1) (2026-05-24)
6
236
 
7
237
  Phase A of the post-3.6.0 backlog — tooling foundation. Pure plumbing; no API changes on the main library, but `create-ndpr` (scoped) bumps to 0.2.0 and a new unscoped `create-ndpr` alias package ships.
package/README.md CHANGED
@@ -127,6 +127,101 @@ bun create ndpr
127
127
 
128
128
  ---
129
129
 
130
+ ## Bun quickstart
131
+
132
+ Bun is a first-class runtime for the toolkit. Both common React app shapes work without extra config.
133
+
134
+ ### Bun + Vite + React
135
+
136
+ ```bash
137
+ bun create vite@latest my-ndpr-app --template react-ts
138
+ cd my-ndpr-app
139
+ bun install
140
+ bun add @tantainnovative/ndpr-toolkit
141
+ ```
142
+
143
+ ```tsx
144
+ // src/App.tsx
145
+ import { NDPRConsent } from '@tantainnovative/ndpr-toolkit/presets/consent';
146
+ import '@tantainnovative/ndpr-toolkit/styles';
147
+
148
+ export default function App() {
149
+ return (
150
+ <>
151
+ <NDPRConsent
152
+ options={[
153
+ { id: 'essential', label: 'Essential', description: 'Required for the site to function', required: true, purpose: 'Site operation' },
154
+ { id: 'analytics', label: 'Analytics', description: 'Anonymous usage measurement', required: false, purpose: 'Product analytics' },
155
+ { id: 'marketing', label: 'Marketing', description: 'Personalised offers and ads', required: false, purpose: 'Marketing communications' },
156
+ ]}
157
+ />
158
+ <main className="p-6">
159
+ <h1 className="text-3xl font-semibold">My NDPA-compliant app</h1>
160
+ </main>
161
+ </>
162
+ );
163
+ }
164
+ ```
165
+
166
+ ```bash
167
+ bun dev
168
+ ```
169
+
170
+ Vite is client-only by default — no extra wiring needed. The toolkit's preset components ship with the `"use client"` directive already injected.
171
+
172
+ ### Bun + Next.js 15 (App Router)
173
+
174
+ ```bash
175
+ bun create next-app@latest my-ndpr-app --typescript --app --tailwind
176
+ cd my-ndpr-app
177
+ bun add @tantainnovative/ndpr-toolkit
178
+ ```
179
+
180
+ The consent banner is a stateful client component. Mount it from a small client wrapper so the rest of your layout can stay in RSC:
181
+
182
+ ```tsx
183
+ // app/ConsentRoot.tsx
184
+ 'use client';
185
+ import { NDPRConsent } from '@tantainnovative/ndpr-toolkit/presets/consent';
186
+
187
+ export function ConsentRoot() {
188
+ return (
189
+ <NDPRConsent
190
+ options={[
191
+ { id: 'essential', label: 'Essential', description: 'Required for the site to function', required: true, purpose: 'Site operation' },
192
+ { id: 'analytics', label: 'Analytics', description: 'Anonymous usage measurement', required: false, purpose: 'Product analytics' },
193
+ { id: 'marketing', label: 'Marketing', description: 'Personalised offers and ads', required: false, purpose: 'Marketing communications' },
194
+ ]}
195
+ />
196
+ );
197
+ }
198
+ ```
199
+
200
+ ```tsx
201
+ // app/layout.tsx
202
+ import '@tantainnovative/ndpr-toolkit/styles';
203
+ import { ConsentRoot } from './ConsentRoot';
204
+
205
+ export default function RootLayout({ children }: { children: React.ReactNode }) {
206
+ return (
207
+ <html lang="en">
208
+ <body>
209
+ <ConsentRoot />
210
+ {children}
211
+ </body>
212
+ </html>
213
+ );
214
+ }
215
+ ```
216
+
217
+ ```bash
218
+ bun dev
219
+ ```
220
+
221
+ You 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.
222
+
223
+ ---
224
+
130
225
  ## Choose Your Layer
131
226
 
132
227
  Pick exactly what your project needs.
@@ -350,6 +445,34 @@ Every module has an interactive demo. No signup, no setup — try them instantly
350
445
  <em>Left: Data Subject Rights portal with 8 NDPA rights. Right: Breach notification with 72-hour NDPC deadline countdown.</em>
351
446
  </p>
352
447
 
448
+ ### Open any module in your browser (zero install)
449
+
450
+ Each module ships a minimal Next.js scaffold you can fork in StackBlitz or CodeSandbox. One click → working app demonstrating just that module:
451
+
452
+ | Module | NDPA | Open in StackBlitz | Open in CodeSandbox |
453
+ |---|---|---|---|
454
+ | **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) |
455
+ | 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) |
456
+ | 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) |
457
+ | 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) |
458
+ | 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) |
459
+ | 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) |
460
+ | 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) |
461
+ | 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) |
462
+ | 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) |
463
+
464
+ Or 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.
465
+
466
+ ### SSR-safe consent scaffolds
467
+
468
+ Cookie-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.
469
+
470
+ | Framework | Path | Open in StackBlitz |
471
+ |---|---|---|
472
+ | 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) |
473
+ | 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) |
474
+ | 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) |
475
+
353
476
  ---
354
477
 
355
478
  ## All 8 Modules
@@ -390,7 +513,23 @@ import "@tantainnovative/ndpr-toolkit/styles";
390
513
  }
391
514
  ```
392
515
 
393
- Light + dark mode auto-switch via `prefers-color-scheme`, plus an explicit opt-in via `data-theme="dark"` or `.dark` on any ancestor.
516
+ **Theme via typed JS object `NDPRThemeProvider` (new in 3.10.0):**
517
+ ```tsx
518
+ import { NDPRThemeProvider, type NDPRTheme } from '@tantainnovative/ndpr-toolkit';
519
+
520
+ const theme: NDPRTheme = {
521
+ colors: { primary: '22 163 74', primaryHover: '21 128 61' },
522
+ radius: { base: '0.75rem' },
523
+ font: { sans: '"Inter", system-ui, sans-serif' },
524
+ };
525
+
526
+ <NDPRThemeProvider theme={theme}>
527
+ <App />
528
+ </NDPRThemeProvider>
529
+ ```
530
+ The 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).
531
+
532
+ Light + 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`).
394
533
 
395
534
  **Per-instance override via slot map:**
396
535
  ```tsx
@@ -425,6 +564,7 @@ Each component exports its `ClassNames` TypeScript interface for autocomplete. F
425
564
  | `/server` | **Pure validators, generators, scoring, locales, adapters, types — zero React** | `tslib` | **Yes** |
426
565
  | `/core` | Types, utility functions, NDPRProvider | `react`[^core] | Partial |
427
566
  | `/hooks` | React hooks for all 8 modules | `react` | No |
567
+ | `/headless` | **Alias of `/hooks`** — identical exports under a more discoverable name (3.10.0) | `react` | No |
428
568
  | `/presets` | All zero-config preset components (barrel) | `react`, Radix peers | No |
429
569
  | `/presets/consent` | **Just `NDPRConsent`** — narrower barrel for bundle size | `react`, Radix peers | No |
430
570
  | `/presets/dsr` | **Just `NDPRSubjectRights`** | `react`, Radix peers | No |
@@ -436,8 +576,11 @@ Each component exports its `ClassNames` TypeScript interface for autocomplete. F
436
576
  | `/breach` | Breach components + hook | `react` | No |
437
577
  | `/policy` | Policy components + hook | `react`, `jspdf`, `docx` (optional) | No |
438
578
  | `/lawful-basis` | Lawful basis component + hook | `react` | No |
579
+ | `/lawful-basis/lite` | Read-only `LawfulBasisTrackerLite` — ~65% smaller than `/lawful-basis` | `react` | No |
439
580
  | `/cross-border` | Cross-border component + hook | `react` | No |
581
+ | `/cross-border/lite` | Read-only `CrossBorderTransferManagerLite` — ~89% smaller (skips the 624-row adequacy dataset) | `react` | No |
440
582
  | `/ropa` | ROPA component + hook | `react` | No |
583
+ | `/ropa/lite` | Read-only `ROPAManagerLite` — ~64% smaller than `/ropa` | `react` | No |
441
584
  | `/unstyled` | All published components with `unstyled` defaulted to `true` | `react` | No |
442
585
  | `/styles` | Default CSS stylesheet — `import "@tantainnovative/ndpr-toolkit/styles"` once in your app entry | none | N/A |
443
586
 
@@ -458,6 +601,8 @@ The toolkit is published with `sideEffects: ["*.css"]`, so a modern bundler (Vit
458
601
 
459
602
  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.
460
603
 
604
+ 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).
605
+
461
606
  4. **`/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.
462
607
 
463
608
  ---
@@ -0,0 +1,3 @@
1
+ import {c as c$1,d as d$1,a as a$2,b as b$1}from'./chunk-AOHKVFAS.mjs';import {e,c,f}from'./chunk-RMQ7OLNY.mjs';import {a}from'./chunk-DBZSN4WP.mjs';import {b,a as a$1,d}from'./chunk-ZJYULEER.mjs';import {useRef,useState,useEffect,useMemo,useCallback}from'react';var nt=10,Rt="ndpr_policy_draft",_t=2e3;function st(){return `section_${Date.now()}_${Math.random().toString(36).slice(2,9)}`}function it(){return `draft_${Date.now()}_${Math.random().toString(36).slice(2,9)}`}function w(u,A,M){let S=Date.now();return {id:M,title:`Privacy Policy${u.org.name?` \u2014 ${u.org.name}`:""}`,templateId:"adaptive-policy-wizard",organizationInfo:{name:u.org.name,website:u.org.website,privacyEmail:u.org.privacyEmail,address:u.org.address,dpoName:u.org.dpoName,dpoEmail:u.org.dpoEmail,industry:u.org.industry},sections:A,variableValues:{},effectiveDate:S,lastUpdated:S,version:"1.0",applicableFrameworks:["ndpa","ndpr"]}}function Ut(u={}){var K;let{onComplete:A,onComplianceChange:M}=u,S=useRef((K=u.adapter)!=null?K:a(Rt));u.adapter&&(S.current=u.adapter);let f$1=useRef(it()),[P,C]=useState(1),[n,v]=useState(()=>{var t;return (t=u.initialContext)!=null?t:e()}),[b$2,O]=useState([]),[x,I]=useState({}),[E,$]=useState([]),[at,q]=useState(false),[ct,z]=useState(null),[N,U]=useState(true),T=useRef(false),R=useRef(null);useEffect(()=>{let t=false,e=r=>{r&&(f$1.current=r.id,v(r.templateContext),O(r.customSections),I(r.sectionOverrides),$(r.sectionOrder),C(r.currentStep),z(r.lastSavedAt),q(true));};try{let r=S.current.load();r instanceof Promise?r.then(i=>{t||(e(i),U(!1));},()=>{t||U(!1);}):(e(r),U(!1));}catch(r){t||U(false);}return ()=>{t=true;}},[]);let d$2=useMemo(()=>{let e=c(n).map(o=>x[o.id]?b(a$1({},o),{template:x[o.id]}):o),r=b$2.map(o=>{var l;return {id:o.id,title:o.title,template:(l=x[o.id])!=null?l:o.content,order:o.order,required:false,included:true}}),i=[...e,...r];if(E.length>0){let o=new Map(E.map((l,p)=>[l,p]));return [...i].sort((l,p)=>{let m=o.has(l.id)?o.get(l.id):i.length,y=o.has(p.id)?o.get(p.id):i.length;return m-y})}return [...i].sort((o,l)=>{var p,m;return ((p=o.order)!=null?p:0)-((m=l.order)!=null?m:0)})},[n,b$2,x,E]),s=useMemo(()=>!n.org.name&&!n.org.privacyEmail?null:w(n,d$2,f$1.current),[n,d$2]),Y=useMemo(()=>w(e(),[],f$1.current),[]),V=useMemo(()=>f(s!=null?s:Y,n),[s,n,Y]),_=V.percentage,D=V.gaps,j=useRef({score:-1,gaps:[]});useEffect(()=>{let t=j.current;M&&(_!==t.score||D!==t.gaps)&&M(_,D),j.current={score:_,gaps:D};},[_,D,M]);let lt=useMemo(()=>{switch(P){case 1:return n.org.name.trim().length>0&&n.org.privacyEmail.trim().length>0;case 2:return n.dataCategories.some(t=>t.selected);case 3:return n.purposes.length>0;case 4:return true;default:return false}},[P,n]),dt=useCallback(t=>{let e=Math.min(Math.max(1,t),4);e<4&&(T.current=false),C(e);},[]),pt=useCallback(()=>{C(t=>Math.min(t+1,4));},[]),ut=useCallback(()=>{T.current=false,C(t=>Math.max(t-1,1));},[]),mt=useCallback(t=>{v(e=>a$1(a$1({},e),t));},[]),gt=useCallback(t=>{v(e=>b(a$1({},e),{org:a$1(a$1({},e.org),t)}));},[]),ft=useCallback(t=>{v(e=>b(a$1({},e),{dataCategories:e.dataCategories.map(r=>r.id===t?b(a$1({},r),{selected:!r.selected}):r)}));},[]),Pt=useCallback(t=>{v(e=>{let r=t,i=e.purposes.includes(r);return b(a$1({},e),{purposes:i?e.purposes.filter(o=>o!==t):[...e.purposes,r]})});},[]),Ct=useCallback(t=>{v(e=>b(a$1({},e),{thirdPartyProcessors:[...e.thirdPartyProcessors,t]}));},[]),yt=useCallback(t=>{v(e=>b(a$1({},e),{thirdPartyProcessors:e.thirdPartyProcessors.filter((r,i)=>i!==t)}));},[]),St=useCallback(t=>{O(e=>e.length>=nt?e:[...e,b(a$1({},t),{id:st(),required:false})]);},[]),vt=useCallback((t,e)=>{O(r=>r.map(i=>i.id===t?a$1(a$1({},i),e):i));},[]),xt=useCallback(t=>{O(e=>e.filter(r=>r.id!==t)),$(e=>e.filter(r=>r!==t)),I(e=>{let r=a$1({},e);return delete r[t],r});},[]),ht=useCallback((t,e)=>{$(r=>{let i=r.length>0?r:d$2.map(m=>m.id),o=i.indexOf(t);if(o===-1){let m=d$2.map(It=>It.id),y=m.indexOf(t);if(y===-1)return r;let G=e==="up"?y-1:y+1;if(G<0||G>=m.length)return m;let k=[...m];return [k[y],k[G]]=[k[G],k[y]],k}let l=e==="up"?o-1:o+1;if(l<0||l>=i.length)return i;let p=[...i];return [p[o],p[l]]=[p[l],p[o]],p});},[d$2]),Dt=useCallback((t,e)=>{I(r=>b(a$1({},r),{[t]:e}));},[]),bt=useCallback(t=>{let e=D.find(r=>r.requirementId===t);if(e)switch(e.fixType){case "fill_field":{T.current=false;let i=["data-categories-disclosed"],o=["purpose-of-processing"];i.includes(t)?C(2):o.includes(t)?C(3):(C(1));break}case "add_section":{if(!e.suggestedContent)break;O(r=>r.length>=nt?r:[...r,{id:st(),title:e.requirement,content:e.suggestedContent,order:999,required:false}]);break}case "add_content":{if(!e.suggestedContent)break;let r="data-subject-rights";I(i=>{var l,p,m;let o=(m=(p=i[r])!=null?p:(l=d$2.find(y=>y.id===r))==null?void 0:l.template)!=null?m:"";return b(a$1({},i),{[r]:`${o}
2
+
3
+ ${e.suggestedContent}`.trim()})});break}}},[D,d$2]),X=useCallback(t=>({id:f$1.current,templateContext:n,customSections:b$2,sectionOverrides:x,sectionOrder:E,currentStep:t,lastSavedAt:Date.now(),status:"draft"}),[n,b$2,x,E]),Ot=useCallback(()=>d(null,null,function*(){let t=X(P);try{yield Promise.resolve(S.current.save(t)),z(t.lastSavedAt),q(!0);}catch(e){console.warn("[ndpr-toolkit] Failed to save draft:",e);}}),[X,P]),Et=useCallback(()=>{Promise.resolve(S.current.remove()).catch(t=>{console.warn("[ndpr-toolkit] Failed to remove draft:",t);}),f$1.current=it(),T.current=false,v(e()),O([]),I({}),$([]),C(1),q(false),z(null);},[]);useEffect(()=>{if(!N)return R.current&&clearTimeout(R.current),R.current=setTimeout(()=>{let t=X(P);Promise.resolve(S.current.save(t)).then(()=>{z(t.lastSavedAt),q(true);}).catch(e=>{console.warn("[ndpr-toolkit] Auto-save failed:",e);});},_t),()=>{R.current&&clearTimeout(R.current);}},[n,b$2,x,E,P,N,X]),useEffect(()=>{P===4&&s&&A&&!T.current&&(T.current=true,A(s));},[P,s,A]);let Tt=useCallback(t=>d(null,null,function*(){let e=s!=null?s:w(n,d$2,f$1.current);return c$1(e,t)}),[s,n,d$2]),wt=useCallback(t=>d(null,null,function*(){let e=s!=null?s:w(n,d$2,f$1.current);return d$1(e,t)}),[s,n,d$2]),At=useCallback(t=>{let e=s!=null?s:w(n,d$2,f$1.current);return a$2(e,t)},[s,n,d$2]),Mt=useCallback(()=>{let t=s!=null?s:w(n,d$2,f$1.current);return b$1(t)},[s,n,d$2]);return {currentStep:P,goToStep:dt,nextStep:pt,prevStep:ut,canProceed:lt,context:n,updateContext:mt,updateOrg:gt,toggleDataCategory:ft,togglePurpose:Pt,addProcessor:Ct,removeProcessor:yt,policy:s,sections:d$2,customSections:b$2,addCustomSection:St,updateCustomSection:vt,removeCustomSection:xt,reorderSections:ht,editSectionContent:Dt,sectionOverrides:x,complianceScore:_,complianceResult:V,complianceGaps:D,applyFix:bt,handleExportPDF:Tt,handleExportDOCX:wt,handleExportHTML:At,handleExportMarkdown:Mt,isDraftSaved:at,lastSavedAt:ct,saveDraft:Ot,discardDraft:Et,isLoading:N}}export{Ut as a};
@@ -0,0 +1 @@
1
+ 'use strict';var chunkQ64735OC_js=require('./chunk-Q64735OC.js'),chunkRFPLZDIO_js=require('./chunk-RFPLZDIO.js');var x={saas:{id:"saas",label:"SaaS / B2B Software",description:"Multi-tenant cloud software. Account credentials, usage analytics, cross-border transfer to the SaaS vendor, automated processing for features like spam filtering or fraud scoring.",examples:["team collaboration tools","CRM","developer tools","workflow automation"]},ecommerce:{id:"ecommerce",label:"Ecommerce / Online Store",description:"Online retail. Customer identity, payment data, shipping address, cart abandonment cookies, marketing analytics, third-party payment processors.",examples:["online retail","D2C brand","marketplace","food delivery"]},school:{id:"school",label:"School / Education",description:"Educational institution or edtech platform. Student data including minors (NDPA Section 31 \u2014 parental consent required), academic records, attendance, behavioural data for learning analytics.",examples:["K-12 school","edtech app","tutoring platform","online courses"]},healthcare:{id:"healthcare",label:"Healthcare / HealthTech",description:"Medical practice, hospital, telemedicine, or health insurance. Sensitive personal data (NDPA Section 30 \u2014 medical), prescription history, insurance claims, biometric data.",examples:["hospital","telemedicine","pharmacy","health insurance"]},procurement:{id:"procurement",label:"Procurement / B2G",description:"Government procurement, vendor management, public-sector bidding. Vendor company data, tax IDs, beneficial-owner information, contract records, sometimes politically-exposed-person (PEP) data.",examples:["e-procurement portal","vendor registry","government supplier database"]}},a={fullName:"full-name",contactDetails:"contact-details",govIds:"government-ids",credentials:"account-credentials",payment:"payment-info",financialRecords:"financial-records",bvn:"bvn",device:"device-info",usage:"usage-data",location:"location-data",cookies:"cookies",health:"health-data",biometric:"biometric-data",children:"children"};function s(e){let t=new Set(e);return chunkQ64735OC_js.d.map(r=>chunkRFPLZDIO_js.b(chunkRFPLZDIO_js.a({},r),{selected:t.has(r.id)}))}function h(e,t){var r,c,l,d,p,m;return t?chunkRFPLZDIO_js.b(chunkRFPLZDIO_js.a({},e),{org:chunkRFPLZDIO_js.b(chunkRFPLZDIO_js.a({},e.org),{name:(r=t.orgName)!=null?r:e.org.name,website:(c=t.website)!=null?c:e.org.website,privacyEmail:(l=t.privacyEmail)!=null?l:e.org.privacyEmail,address:(d=t.address)!=null?d:e.org.address,dpoName:(p=t.dpoName)!=null?p:e.org.dpoName,dpoEmail:(m=t.dpoEmail)!=null?m:e.org.dpoEmail})}):e}var f=["service_delivery","analytics","marketing","fraud_prevention"],y=["service_delivery","marketing","analytics","fraud_prevention","legal_compliance"],v=["service_delivery","analytics","legal_compliance"],C=["service_delivery","legal_compliance","research"],T=["service_delivery","legal_compliance","fraud_prevention"];function P(){let e=chunkQ64735OC_js.e();return e.org.industry="saas",e.org.orgSize="startup",e.dataCategories=s([a.fullName,a.contactDetails,a.credentials,a.device,a.usage,a.cookies]),e.purposes=f,e.hasChildrenData=false,e.hasSensitiveData=false,e.hasFinancialData=false,e.hasCrossBorderTransfer=true,e.hasAutomatedDecisions=false,e}function S(){let e=chunkQ64735OC_js.e();return e.org.industry="ecommerce",e.org.orgSize="midsize",e.dataCategories=s([a.fullName,a.contactDetails,a.payment,a.financialRecords,a.device,a.usage,a.location,a.cookies]),e.purposes=y,e.hasChildrenData=false,e.hasSensitiveData=false,e.hasFinancialData=true,e.hasCrossBorderTransfer=true,e.hasAutomatedDecisions=true,e}function D(){let e=chunkQ64735OC_js.e();return e.org.industry="education",e.org.orgSize="midsize",e.dataCategories=s([a.fullName,a.contactDetails,a.govIds,a.credentials,a.usage,a.cookies,a.children]),e.purposes=v,e.hasChildrenData=true,e.hasSensitiveData=false,e.hasFinancialData=false,e.hasCrossBorderTransfer=false,e.hasAutomatedDecisions=false,e}function E(){let e=chunkQ64735OC_js.e();return e.org.industry="healthcare",e.org.orgSize="enterprise",e.dataCategories=s([a.fullName,a.contactDetails,a.govIds,a.payment,a.health,a.biometric]),e.purposes=C,e.hasChildrenData=false,e.hasSensitiveData=true,e.hasFinancialData=true,e.hasCrossBorderTransfer=false,e.hasAutomatedDecisions=false,e}function O(){let e=chunkQ64735OC_js.e();return e.org.industry="government",e.org.orgSize="enterprise",e.dataCategories=s([a.fullName,a.contactDetails,a.govIds,a.financialRecords,a.bvn]),e.purposes=T,e.hasChildrenData=false,e.hasSensitiveData=false,e.hasFinancialData=true,e.hasCrossBorderTransfer=false,e.hasAutomatedDecisions=false,e}var g={saas:P,ecommerce:S,school:D,healthcare:E,procurement:O};function _(e,t){let r=g[e];if(!r)throw new Error(`[ndpr-toolkit] Unknown org template id: ${String(e)}. Expected one of: ${Object.keys(g).join(", ")}.`);return h(r(),t)}exports.a=x;exports.b=_;
@@ -0,0 +1 @@
1
+ 'use strict';var chunkW7OLQRJP_js=require('./chunk-W7OLQRJP.js'),chunk3GRGYT3P_js=require('./chunk-3GRGYT3P.js'),chunkRFPLZDIO_js=require('./chunk-RFPLZDIO.js'),react=require('react'),jsxRuntime=require('react/jsx-runtime');var u=d=>{var o=d,{template:e,templateOverrides:r,initialContext:t}=o,l=chunkRFPLZDIO_js.c(o,["template","templateOverrides","initialContext"]);let n=react.useMemo(()=>{if(t)return t;if(e)return chunk3GRGYT3P_js.b(e,r)},[t,e,r]);return jsxRuntime.jsx(chunkW7OLQRJP_js.a,chunkRFPLZDIO_js.b(chunkRFPLZDIO_js.a({},l),{initialContext:n}))};exports.a=u;
@@ -0,0 +1,2 @@
1
+ import {a}from'./chunk-2MIQXECH.mjs';import {a as a$1}from'./chunk-SFGW37LE.mjs';import {d,b,a as a$2}from'./chunk-ZJYULEER.mjs';import Ur,{useId,useState,useEffect}from'react';import {jsxs,jsx,Fragment}from'react/jsx-runtime';var vr=["Organization","Data Collection","Processing","Review & Export"],lr=({currentStep:n,classNames:p,unstyled:r})=>jsx("nav",{"data-ndpr-component":"policy-step-indicator","aria-label":"Policy wizard progress",className:a$1("w-full flex items-center justify-between px-2 py-4",p==null?void 0:p.root,r),children:vr.map((e,d)=>{let t=d+1,i=t<n,u=t===n,b=d===vr.length-1;return jsxs(Ur.Fragment,{children:[jsxs("div",{className:a$1("flex flex-col items-center gap-1",p==null?void 0:p.stepWrapper,r),children:[jsx("div",{"aria-current":u?"step":void 0,"aria-label":`Step ${t}: ${e}${i?" (completed)":u?" (current)":""}`,className:a$1(["flex items-center justify-center rounded-full border-2 font-semibold transition-all",i?"w-8 h-8 bg-[rgb(var(--ndpr-primary))] border-[rgb(var(--ndpr-primary))] text-[rgb(var(--ndpr-primary-foreground))]":u?"w-9 h-9 bg-[rgb(var(--ndpr-primary))] border-[rgb(var(--ndpr-primary))] text-[rgb(var(--ndpr-primary-foreground))] shadow-md":"w-8 h-8 bg-white dark:bg-gray-900 border-gray-300 dark:border-gray-600 text-gray-400 dark:text-gray-500"].join(" "),i?p==null?void 0:p.stepCompleted:u?p==null?void 0:p.stepCurrent:p==null?void 0:p.stepUpcoming,r),children:i?jsx("svg",{className:"w-4 h-4",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:3,"aria-hidden":"true",children:jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M5 13l4 4L19 7"})}):jsx("span",{className:"text-xs leading-none",children:t})}),jsx("span",{className:a$1(["text-xs font-medium hidden sm:block",i||u?"text-[rgb(var(--ndpr-primary))]":"ndpr-card__subtitle"].join(" "),p==null?void 0:p.stepLabel,r),children:e})]}),!b&&jsx("div",{className:a$1(["flex-1 h-0.5 mx-2",i?"bg-[rgb(var(--ndpr-primary))]":"bg-gray-200 dark:bg-gray-700"].join(" "),p==null?void 0:p.connector,r),"aria-hidden":"true"})]},t)})});var $="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md bg-white dark:bg-gray-800 ndpr-text-foreground focus:outline-none focus:ring-2 focus:ring-[rgb(var(--ndpr-ring))] text-sm",Xr="block text-sm font-medium ndpr-text-muted mb-1",A=({id:n,label:p,required:r,description:e,children:d,classNames:t,unstyled:i})=>{let u=e?`${n}-desc`:void 0;return jsxs("div",{className:a$1("flex flex-col",t==null?void 0:t.field,i),children:[jsxs("label",{htmlFor:n,className:a$1(Xr,t==null?void 0:t.label,i),children:[p,r&&jsx("span",{className:"text-red-500 ml-0.5","aria-hidden":"true",children:"*"})]}),e&&jsx("p",{id:u,className:"text-xs ndpr-text-muted mb-1",children:e}),d]})},fr=({context:n,onUpdateOrg:p,classNames:r,unstyled:e})=>{var i,u,l;let d=useId(),t=n.org;return jsxs("div",{"data-ndpr-component":"policy-step-about",className:a$1("ndpr-form-section",r==null?void 0:r.root,e),children:[jsxs("div",{children:[jsx("h2",{className:a$1("ndpr-section-heading",r==null?void 0:r.heading,e),children:"Organisation Details"}),jsxs("p",{className:a$1("ndpr-form-field__hint",r==null?void 0:r.subheading,e),children:["Tell us about your organisation. Fields marked ",jsx("span",{className:"text-red-500","aria-hidden":"true",children:"*"})," are required."]})]}),jsxs("div",{className:a$1("grid grid-cols-1 md:grid-cols-2 gap-4",r==null?void 0:r.grid,e),children:[jsx(A,{id:`${d}-org-name`,label:"Organisation Name",required:true,classNames:r,unstyled:e,children:jsx("input",{id:`${d}-org-name`,type:"text",value:t.name,onChange:b=>p({name:b.target.value}),placeholder:"Acme Corporation",className:a$1($,r==null?void 0:r.input,e),"aria-required":"true"})}),jsx(A,{id:`${d}-website`,label:"Website",required:true,classNames:r,unstyled:e,children:jsx("input",{id:`${d}-website`,type:"url",value:t.website,onChange:b=>p({website:b.target.value}),placeholder:"https://example.com",className:a$1($,r==null?void 0:r.input,e),"aria-required":"true"})}),jsx(A,{id:`${d}-privacy-email`,label:"Privacy Contact Email",required:true,classNames:r,unstyled:e,children:jsx("input",{id:`${d}-privacy-email`,type:"email",value:t.privacyEmail,onChange:b=>p({privacyEmail:b.target.value}),placeholder:"privacy@example.com",className:a$1($,r==null?void 0:r.input,e),"aria-required":"true"})}),jsx(A,{id:`${d}-industry`,label:"Industry",classNames:r,unstyled:e,children:jsxs("select",{id:`${d}-industry`,value:t.industry,onChange:b=>p({industry:b.target.value}),className:a$1($,r==null?void 0:r.select,e),children:[jsx("option",{value:"fintech",children:"Fintech"}),jsx("option",{value:"healthcare",children:"Healthcare"}),jsx("option",{value:"ecommerce",children:"E-commerce"}),jsx("option",{value:"saas",children:"SaaS"}),jsx("option",{value:"education",children:"Education"}),jsx("option",{value:"government",children:"Government"}),jsx("option",{value:"other",children:"Other"})]})}),jsx(A,{id:`${d}-dpo-name`,label:"Data Protection Officer (DPO) Name",classNames:r,unstyled:e,children:jsx("input",{id:`${d}-dpo-name`,type:"text",value:(i=t.dpoName)!=null?i:"",onChange:b=>p({dpoName:b.target.value}),placeholder:"Jane Smith",className:a$1($,r==null?void 0:r.input,e)})}),jsx(A,{id:`${d}-dpo-email`,label:"DPO Email",classNames:r,unstyled:e,children:jsx("input",{id:`${d}-dpo-email`,type:"email",value:(u=t.dpoEmail)!=null?u:"",onChange:b=>p({dpoEmail:b.target.value}),placeholder:"dpo@example.com",className:a$1($,r==null?void 0:r.input,e)})}),jsx(A,{id:`${d}-address`,label:"Registered Address",classNames:r,unstyled:e,children:jsx("input",{id:`${d}-address`,type:"text",value:(l=t.address)!=null?l:"",onChange:b=>p({address:b.target.value}),placeholder:"1 Victoria Island, Lagos, Nigeria",className:a$1($,r==null?void 0:r.input,e)})}),jsx(A,{id:`${d}-org-size`,label:"Organisation Size",classNames:r,unstyled:e,children:jsxs("select",{id:`${d}-org-size`,value:t.orgSize,onChange:b=>p({orgSize:b.target.value}),className:a$1($,r==null?void 0:r.select,e),children:[jsx("option",{value:"startup",children:"Startup (1\u201350 employees)"}),jsx("option",{value:"midsize",children:"Mid-size (51\u2013500 employees)"}),jsx("option",{value:"enterprise",children:"Enterprise (500+ employees)"})]})}),jsx(A,{id:`${d}-country`,label:"Country of Operation",classNames:r,unstyled:e,children:jsx("input",{id:`${d}-country`,type:"text",value:t.country,onChange:b=>p({country:b.target.value}),placeholder:"Nigeria",className:a$1($,r==null?void 0:r.input,e)})})]})]})};var Yr={identity:"Identity",financial:"Financial",behavioral:"Behavioural",sensitive:"Sensitive",children:"Children"},Jr=["identity","financial","behavioral","sensitive","children"],Kr=["sensitive","children"],xr=({categories:n,onToggle:p,classNames:r,unstyled:e})=>{let d=Jr.reduce((t,i)=>{let u=n.filter(l=>l.group===i);return u.length>0&&(t[i]=u),t},{});return jsxs("div",{"data-ndpr-component":"policy-step-data",className:a$1("space-y-8",r==null?void 0:r.root,e),children:[jsxs("div",{children:[jsx("h2",{className:a$1("ndpr-section-heading",r==null?void 0:r.heading,e),children:"Data Categories"}),jsx("p",{id:"data-categories-desc",className:a$1("ndpr-form-field__hint",r==null?void 0:r.subheading,e),children:"Select the categories of personal data your organisation collects. You must select at least one."})]}),Object.entries(d).map(([t,i])=>{let u=Kr.includes(t);return jsxs("div",{className:a$1("space-y-3",r==null?void 0:r.group,e),children:[jsxs("div",{className:a$1("flex items-center gap-2",r==null?void 0:r.groupHeader,e),children:[jsx("h3",{className:a$1("text-sm font-semibold uppercase tracking-wide ndpr-text-muted",r==null?void 0:r.groupTitle,e),children:Yr[t]}),u&&jsx("span",{className:a$1("text-xs font-medium ndpr-text-warning bg-amber-50 dark:bg-amber-900/20 px-2 py-0.5 rounded-full",r==null?void 0:r.sensitiveTag,e),children:"Sensitive"})]}),u&&jsx("p",{className:a$1("text-xs ndpr-text-warning",r==null?void 0:r.sensitiveWarning,e),children:t==="children"?"Processing children's data requires parental consent under NDPA Section 31 and imposes heightened obligations.":"Sensitive/special-category data requires explicit consent and additional safeguards under NDPA Section 30."}),jsx("div",{className:a$1("grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3",r==null?void 0:r.cardsGrid,e),children:i.map(l=>jsx("button",{type:"button",onClick:()=>p(l.id),"aria-pressed":l.selected,className:a$1(["text-left rounded-lg border p-4 transition-all cursor-pointer focus:outline-none focus:ring-2 focus:ring-[rgb(var(--ndpr-ring))]",l.selected?"bg-[rgb(var(--ndpr-primary))]/5 border-[rgb(var(--ndpr-primary))] dark:bg-[rgb(var(--ndpr-primary))]/10":"bg-white dark:bg-gray-800 border-gray-200 dark:border-gray-700 hover:border-gray-300 dark:hover:border-gray-600"].join(" "),r==null?void 0:r.card,e),children:jsxs("div",{className:"flex items-start gap-3",children:[jsx("div",{className:a$1(["mt-0.5 w-4 h-4 rounded border-2 flex-shrink-0 flex items-center justify-center",l.selected?"bg-[rgb(var(--ndpr-primary))] border-[rgb(var(--ndpr-primary))]":"border-gray-300 dark:border-gray-600"].join(" "),r==null?void 0:r.checkbox,e),"aria-hidden":"true",children:l.selected&&jsx("svg",{className:"w-2.5 h-2.5 text-[rgb(var(--ndpr-primary-foreground))]",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:3,children:jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M5 13l4 4L19 7"})})}),jsxs("div",{className:"min-w-0",children:[jsx("p",{className:a$1("text-sm font-medium ndpr-text-foreground",r==null?void 0:r.cardLabel,e),children:l.label}),jsx("p",{className:a$1("text-xs ndpr-text-muted mt-1 leading-relaxed",r==null?void 0:r.cardDataPoints,e),children:l.dataPoints.join(", ")})]})]})},l.id))})]},t)})]})};var Zr=[{value:"service_delivery",label:"Service Delivery",description:"Processing required to deliver the core product or service."},{value:"marketing",label:"Marketing & Communications",description:"Sending promotional messages, newsletters or offers."},{value:"analytics",label:"Analytics & Insights",description:"Analysing usage patterns to improve the product."},{value:"research",label:"Research & Development",description:"Using data to develop new features or products."},{value:"legal_compliance",label:"Legal Compliance",description:"Meeting statutory, regulatory or contractual obligations."},{value:"fraud_prevention",label:"Fraud Prevention & Security",description:"Detecting and preventing fraudulent activity."}],dr="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md bg-white dark:bg-gray-800 ndpr-text-foreground focus:outline-none focus:ring-2 focus:ring-[rgb(var(--ndpr-ring))] text-sm",pr="ndpr-card ndpr-card--compact",gr=({id:n,checked:p,onChange:r})=>jsx("button",{id:n,type:"button",role:"switch","aria-checked":p,onClick:()=>r(!p),className:["relative inline-flex h-6 w-11 flex-shrink-0 rounded-full border-2 border-transparent cursor-pointer transition-colors focus:outline-none focus:ring-2 focus:ring-[rgb(var(--ndpr-ring))]",p?"bg-[rgb(var(--ndpr-primary))]":"bg-gray-200 dark:bg-gray-600"].join(" "),children:jsx("span",{"aria-hidden":"true",className:["pointer-events-none inline-block h-5 w-5 rounded-full bg-white shadow transform ring-0 transition-transform",p?"translate-x-5":"translate-x-0"].join(" ")})}),hr=({context:n,onTogglePurpose:p,onUpdateContext:r,onAddProcessor:e,onRemoveProcessor:d,classNames:t,unstyled:i})=>{let u=useId(),[l,b$1]=useState({name:"",purpose:"",country:""}),[C,g]=useState(false),a=()=>{let{name:v,purpose:c,country:m}=l;!v.trim()||!c.trim()||!m.trim()||(e({name:v.trim(),purpose:c.trim(),country:m.trim()}),b$1({name:"",purpose:"",country:""}),g(false));};return jsxs("div",{"data-ndpr-component":"policy-step-processing",className:a$1("ndpr-form-section",t==null?void 0:t.root,i),children:[jsxs("div",{children:[jsx("h2",{className:a$1("ndpr-section-heading",t==null?void 0:t.heading,i),children:"Processing Details"}),jsx("p",{className:a$1("ndpr-form-field__hint",t==null?void 0:t.subheading,i),children:"Define how and why you process personal data."})]}),jsxs("section",{className:a$1(pr,t==null?void 0:t.section,i),"aria-labelledby":"purposes-heading",children:[jsx("h3",{id:"purposes-heading",className:a$1("text-base font-semibold ndpr-text-foreground",t==null?void 0:t.sectionTitle,i),children:"Processing Purposes"}),jsx("p",{className:a$1("ndpr-form-field__hint",t==null?void 0:t.sectionDescription,i),children:"Select all purposes for which you process personal data. At least one is required."}),jsx("div",{className:a$1("space-y-3",t==null?void 0:t.purposeList,i),children:Zr.map(v=>{let c=n.purposes.includes(v.value),m=`${u}-purpose-${v.value}`,B=`${u}-purpose-desc-${v.value}`;return jsxs("label",{htmlFor:m,className:a$1("flex items-start gap-3 cursor-pointer group",t==null?void 0:t.purposeItem,i),children:[jsx("input",{id:m,type:"checkbox",checked:c,onChange:()=>p(v.value),"aria-describedby":B,className:a$1("mt-0.5 h-4 w-4 rounded border-gray-300 dark:border-gray-600 text-[rgb(var(--ndpr-primary))] focus:ring-[rgb(var(--ndpr-ring))] cursor-pointer",t==null?void 0:t.purposeCheckbox,i)}),jsxs("div",{children:[jsx("p",{className:a$1("text-sm font-medium ndpr-text-foreground",t==null?void 0:t.purposeLabel,i),children:v.label}),jsx("p",{id:B,className:a$1("ndpr-form-field__hint",t==null?void 0:t.purposeDescription,i),children:v.description})]})]},v.value)})})]}),jsxs("section",{className:a$1(pr,t==null?void 0:t.section,i),"aria-labelledby":"thirdparty-heading",children:[jsxs("div",{className:"flex items-center justify-between",children:[jsx("h3",{id:"thirdparty-heading",className:a$1("text-base font-semibold ndpr-text-foreground",t==null?void 0:t.sectionTitle,i),children:"Third-Party Data Sharing"}),jsx(gr,{id:`${u}-thirdparty-toggle`,checked:n.thirdPartyProcessors.length>0||C,onChange:v=>{v?g(true):(n.thirdPartyProcessors.forEach((c,m)=>d(0)),g(false));}})]}),(n.thirdPartyProcessors.length>0||C)&&jsxs("div",{className:a$1("ndpr-form-section",t==null?void 0:t.processorSection,i),children:[n.thirdPartyProcessors.length>0&&jsx("div",{className:a$1("overflow-x-auto",t==null?void 0:t.processorTable,i),children:jsxs("table",{className:"w-full text-sm",children:[jsx("thead",{children:jsxs("tr",{className:a$1("text-left text-xs font-medium ndpr-text-muted border-b border-gray-200 dark:border-gray-700",t==null?void 0:t.tableHeader,i),children:[jsx("th",{className:"pb-2 pr-4",children:"Name"}),jsx("th",{className:"pb-2 pr-4",children:"Purpose"}),jsx("th",{className:"pb-2 pr-4",children:"Country"}),jsx("th",{className:"pb-2"})]})}),jsx("tbody",{className:"divide-y divide-gray-100 dark:divide-gray-700",children:n.thirdPartyProcessors.map((v,c)=>jsxs("tr",{children:[jsx("td",{className:a$1("py-2 pr-4 ndpr-text-foreground",t==null?void 0:t.tableCell,i),children:v.name}),jsx("td",{className:a$1("py-2 pr-4 ndpr-text-muted",t==null?void 0:t.tableCell,i),children:v.purpose}),jsx("td",{className:a$1("py-2 pr-4 ndpr-text-muted",t==null?void 0:t.tableCell,i),children:v.country}),jsx("td",{className:"py-2",children:jsx("button",{type:"button",onClick:()=>d(c),className:a$1("text-red-500 hover:ndpr-text-destructive dark:hover:text-red-300 text-xs font-medium",t==null?void 0:t.removeButton,i),"aria-label":`Remove ${v.name}`,children:"Remove"})})]},c))})]})}),C?jsxs("div",{className:a$1("grid grid-cols-1 sm:grid-cols-3 gap-3 items-end",t==null?void 0:t.processorForm,i),children:[jsxs("div",{children:[jsx("label",{htmlFor:`${u}-proc-name`,className:"block text-xs font-medium ndpr-text-muted mb-1",children:"Processor Name"}),jsx("input",{id:`${u}-proc-name`,type:"text",placeholder:"Processor name",value:l.name,onChange:v=>b$1(c=>b(a$2({},c),{name:v.target.value})),"aria-required":"true",className:a$1(dr,t==null?void 0:t.input,i)})]}),jsxs("div",{children:[jsx("label",{htmlFor:`${u}-proc-purpose`,className:"block text-xs font-medium ndpr-text-muted mb-1",children:"Purpose"}),jsx("input",{id:`${u}-proc-purpose`,type:"text",placeholder:"Purpose",value:l.purpose,onChange:v=>b$1(c=>b(a$2({},c),{purpose:v.target.value})),"aria-required":"true",className:a$1(dr,t==null?void 0:t.input,i)})]}),jsxs("div",{children:[jsx("label",{htmlFor:`${u}-proc-country`,className:"block text-xs font-medium ndpr-text-muted mb-1",children:"Country"}),jsx("input",{id:`${u}-proc-country`,type:"text",placeholder:"Country",value:l.country,onChange:v=>b$1(c=>b(a$2({},c),{country:v.target.value})),"aria-required":"true",className:a$1(dr,t==null?void 0:t.input,i)})]}),jsxs("div",{className:"sm:col-span-3 flex gap-2",children:[jsx("button",{type:"button",onClick:a,className:a$1("ndpr-button ndpr-button--primary ndpr-button--sm",t==null?void 0:t.addButton,i),children:"Add Processor"}),jsx("button",{type:"button",onClick:()=>g(false),className:a$1("ndpr-button ndpr-button--secondary ndpr-button--sm",t==null?void 0:t.cancelButton,i),children:"Cancel"})]})]}):jsxs("button",{type:"button",onClick:()=>g(true),className:a$1("flex items-center gap-1 text-sm text-[rgb(var(--ndpr-primary))] hover:underline font-medium",t==null?void 0:t.addLink,i),children:[jsx("span",{"aria-hidden":"true",children:"+"})," Add processor"]})]})]}),jsxs("section",{className:a$1(pr,t==null?void 0:t.section,i),"aria-labelledby":"disclosures-heading",children:[jsx("h3",{id:"disclosures-heading",className:a$1("text-base font-semibold ndpr-text-foreground",t==null?void 0:t.sectionTitle,i),children:"Additional Disclosures"}),jsxs("div",{className:a$1("ndpr-form-section",t==null?void 0:t.disclosureList,i),children:[jsxs("div",{className:a$1("flex items-start justify-between gap-4",t==null?void 0:t.disclosureItem,i),children:[jsxs("div",{children:[jsx("p",{id:`${u}-cross-border-label`,className:a$1("text-sm font-medium ndpr-text-foreground",t==null?void 0:t.disclosureLabel,i),children:"Cross-border Data Transfers"}),jsx("p",{id:`${u}-cross-border-desc`,className:a$1("text-xs ndpr-text-muted mt-0.5",t==null?void 0:t.disclosureDescription,i),children:"Do you transfer personal data outside Nigeria? This triggers NDPA Chapter 6 obligations."})]}),jsx(gr,{id:`${u}-cross-border-toggle`,checked:n.hasCrossBorderTransfer,onChange:v=>r({hasCrossBorderTransfer:v})})]}),jsxs("div",{className:a$1("flex items-start justify-between gap-4",t==null?void 0:t.disclosureItem,i),children:[jsxs("div",{children:[jsx("p",{id:`${u}-automated-label`,className:a$1("text-sm font-medium ndpr-text-foreground",t==null?void 0:t.disclosureLabel,i),children:"Automated Decision-Making / Profiling"}),jsx("p",{id:`${u}-automated-desc`,className:a$1("text-xs ndpr-text-muted mt-0.5",t==null?void 0:t.disclosureDescription,i),children:"Do you use algorithms or automated systems to make decisions about individuals? Requires disclosure under NDPA Section 37."})]}),jsx(gr,{id:`${u}-automated-toggle`,checked:n.hasAutomatedDecisions,onChange:v=>r({hasAutomatedDecisions:v})})]})]})]})]})};var Cr=({section:n,index:p,isCustom:r,isEditing:e,editedContent:d,onEdit:t,onSaveEdit:i,onCancelEdit:u,onMoveUp:l,onMoveDown:b,onDelete:C,classNames:g,unstyled:a})=>{let[v,c]=useState(d!=null?d:n.template);return useEffect(()=>{d!==void 0&&c(d);},[d]),useEffect(()=>{e&&c(d!=null?d:n.template);},[e,d,n.template]),jsxs("div",{"data-ndpr-component":"policy-section-card",className:a$1("bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg p-4 space-y-3",g==null?void 0:g.root,a),children:[jsxs("div",{className:a$1("flex items-start justify-between gap-2",g==null?void 0:g.header,a),children:[jsxs("div",{className:a$1("flex items-center gap-3 min-w-0",g==null?void 0:g.titleRow,a),children:[jsx("span",{className:a$1("flex-shrink-0 w-7 h-7 rounded-full bg-gray-100 dark:bg-gray-700 ndpr-text-muted text-xs font-semibold flex items-center justify-center",g==null?void 0:g.sectionNumber,a),"aria-hidden":"true",children:p+1}),jsxs("h4",{className:a$1("text-sm font-semibold ndpr-text-foreground truncate",g==null?void 0:g.sectionTitle,a),children:[n.title,r&&jsx("span",{className:a$1("ml-2 text-xs font-normal ndpr-text-muted bg-gray-100 dark:bg-gray-700 px-1.5 py-0.5 rounded",g==null?void 0:g.customBadge,a),children:"Custom"})]})]}),jsxs("div",{className:a$1("flex items-center gap-1 flex-shrink-0",g==null?void 0:g.actions,a),children:[l&&jsx("button",{type:"button",onClick:l,className:a$1("ndpr-button ndpr-button--icon",g==null?void 0:g.moveButton,a),"aria-label":`Move "${n.title}" up`,children:jsx("svg",{className:"w-3.5 h-3.5",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:2,"aria-hidden":"true",children:jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M5 15l7-7 7 7"})})}),b&&jsx("button",{type:"button",onClick:b,className:a$1("ndpr-button ndpr-button--icon",g==null?void 0:g.moveButton,a),"aria-label":`Move "${n.title}" down`,children:jsx("svg",{className:"w-3.5 h-3.5",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:2,"aria-hidden":"true",children:jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M19 9l-7 7-7-7"})})}),!e&&jsx("button",{type:"button",onClick:t,className:a$1("p-1.5 text-gray-400 hover:text-[rgb(var(--ndpr-primary))] rounded hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors",g==null?void 0:g.editButton,a),"aria-label":`Edit "${n.title}"`,children:jsx("svg",{className:"w-3.5 h-3.5",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:2,"aria-hidden":"true",children:jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"})})}),r&&C&&jsx("button",{type:"button",onClick:C,className:a$1("p-1.5 text-gray-400 hover:text-red-500 dark:hover:text-red-400 rounded hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors",g==null?void 0:g.deleteButton,a),"aria-label":`Delete "${n.title}"`,children:jsx("svg",{className:"w-3.5 h-3.5",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:2,"aria-hidden":"true",children:jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"})})})]})]}),e?jsxs("div",{className:a$1("space-y-2",g==null?void 0:g.editArea,a),children:[jsx("textarea",{value:v,onChange:m=>c(m.target.value),rows:8,className:a$1("w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md bg-white dark:bg-gray-800 ndpr-text-foreground focus:outline-none focus:ring-2 focus:ring-[rgb(var(--ndpr-ring))] text-sm font-mono resize-y",g==null?void 0:g.textarea,a),"aria-label":`Edit content for ${n.title}`}),jsxs("div",{className:a$1("flex gap-2",g==null?void 0:g.editActions,a),children:[jsx("button",{type:"button",onClick:()=>i(v),className:a$1("ndpr-button ndpr-button--primary ndpr-button--sm",g==null?void 0:g.saveButton,a),children:"Save"}),jsx("button",{type:"button",onClick:u,className:a$1("ndpr-button ndpr-button--secondary ndpr-button--sm",g==null?void 0:g.cancelButton,a),children:"Cancel"})]})]}):jsx("div",{className:a$1("text-sm ndpr-text-muted leading-relaxed line-clamp-4 whitespace-pre-wrap",g==null?void 0:g.content,a),children:n.template})]})};var kr="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md bg-white dark:bg-gray-800 ndpr-text-foreground focus:outline-none focus:ring-2 focus:ring-[rgb(var(--ndpr-ring))] text-sm",wr=({onAdd:n,nextOrder:p,classNames:r,unstyled:e})=>{let d=useId(),[t,i]=useState(""),[u,l]=useState(""),[b,C]=useState(""),g=()=>{if(!t.trim()){C("Section title is required.");return}if(!u.trim()){C("Section content is required.");return}C(""),n({title:t.trim(),content:u.trim(),order:p}),i(""),l("");};return jsxs("div",{"data-ndpr-component":"custom-section-form",className:a$1("ndpr-card ndpr-card--compact",r==null?void 0:r.root,e),children:[jsx("h4",{className:a$1("ndpr-section-heading",r==null?void 0:r.heading,e),children:"Add Custom Section"}),b&&jsx("p",{role:"alert",className:a$1("text-xs ndpr-text-destructive",r==null?void 0:r.error,e),children:b}),jsxs("div",{className:a$1("space-y-3",r==null?void 0:r.fields,e),children:[jsxs("div",{children:[jsxs("label",{htmlFor:`${d}-custom-section-title`,className:a$1("block text-xs font-medium ndpr-text-muted mb-1",r==null?void 0:r.label,e),children:["Section Title ",jsx("span",{className:"text-red-500","aria-hidden":"true",children:"*"})]}),jsx("input",{id:`${d}-custom-section-title`,type:"text",value:t,onChange:a=>{i(a.target.value),b&&C("");},placeholder:"e.g. Cookie Policy",className:a$1(kr,r==null?void 0:r.input,e),"aria-required":"true"})]}),jsxs("div",{children:[jsxs("label",{htmlFor:`${d}-custom-section-content`,className:a$1("block text-xs font-medium ndpr-text-muted mb-1",r==null?void 0:r.label,e),children:["Content ",jsx("span",{className:"text-red-500","aria-hidden":"true",children:"*"})]}),jsx("textarea",{id:`${d}-custom-section-content`,value:u,onChange:a=>{l(a.target.value),b&&C("");},placeholder:"Write the section content here...",rows:5,className:a$1(`${kr} resize-y`,r==null?void 0:r.textarea,e),"aria-required":"true"})]})]}),jsx("div",{className:a$1("flex items-center gap-2",r==null?void 0:r.footer,e),children:jsx("button",{type:"button",onClick:g,className:a$1("ndpr-button ndpr-button--primary ndpr-button--sm",r==null?void 0:r.addButton,e),children:"Add Section"})})]})};var mr={compliant:{bg:"ndpr-alert ndpr-alert--success",text:"ndpr-text-success",border:"border-green-200 dark:border-green-700"},nearly_compliant:{bg:"bg-amber-50 dark:bg-amber-900/20",text:"ndpr-text-warning",border:"border-amber-200 dark:border-amber-700"},not_compliant:{bg:"ndpr-alert ndpr-alert--destructive",text:"ndpr-text-destructive",border:"border-red-200 dark:border-red-700"}},rt={compliant:"Compliant",nearly_compliant:"Nearly Compliant",not_compliant:"Not Compliant"},s=({icon:n,label:p,description:r,actionLabel:e,loading:d,onClick:t,classNames:i,unstyled:u})=>jsxs("div",{className:a$1("bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg p-4 flex flex-col gap-3",i==null?void 0:i.formatCard,u),children:[jsxs("div",{className:a$1("flex items-center gap-3",i==null?void 0:i.formatHeader,u),children:[jsx("div",{className:a$1("w-10 h-10 rounded-lg bg-gray-100 dark:bg-gray-700 flex items-center justify-center flex-shrink-0",i==null?void 0:i.formatIcon,u),"aria-hidden":"true",children:n}),jsxs("div",{className:"min-w-0",children:[jsx("p",{className:a$1("ndpr-section-heading",i==null?void 0:i.formatLabel,u),children:p}),jsx("p",{className:a$1("ndpr-form-field__hint",i==null?void 0:i.formatDescription,u),children:r})]})]}),jsx("button",{type:"button",onClick:t,disabled:d,className:a$1("w-full px-4 py-2 bg-[rgb(var(--ndpr-primary))] text-[rgb(var(--ndpr-primary-foreground))] rounded-md hover:bg-[rgb(var(--ndpr-primary-hover))] text-sm font-medium disabled:opacity-60 disabled:cursor-not-allowed flex items-center justify-center gap-2",i==null?void 0:i.formatButton,u),children:d?jsxs(Fragment,{children:[jsxs("svg",{className:"animate-spin w-4 h-4",fill:"none",viewBox:"0 0 24 24","aria-hidden":"true",children:[jsx("circle",{className:"opacity-25",cx:"12",cy:"12",r:"10",stroke:"currentColor",strokeWidth:"4"}),jsx("path",{className:"opacity-75",fill:"currentColor",d:"M4 12a8 8 0 018-8v4l3-3-3-3v4a10 10 0 100 10l-1.73-3A8 8 0 014 12z"})]}),"Generating\u2026"]}):e})]}),Sr=({complianceResult:n,onExportPDF:p,onExportDOCX:r,onExportHTML:e,onExportMarkdown:d$1,classNames:t,unstyled:i})=>{var c;let[u,l]=useState(false),[b,C]=useState(false),g=(c=mr[n.rating])!=null?c:mr.not_compliant,a=()=>d(null,null,function*(){l(true);try{yield p();}finally{l(false);}}),v=()=>d(null,null,function*(){C(true);try{yield r();}finally{C(false);}});return jsxs("div",{"data-ndpr-component":"policy-export-panel",className:a$1("ndpr-form-section",t==null?void 0:t.root,i),children:[jsxs("div",{className:a$1(`rounded-lg border p-4 flex items-center gap-4 ${g.bg} ${g.border}`,t==null?void 0:t.complianceSummary,i),children:[jsxs("div",{className:a$1(`text-3xl font-bold ${g.text}`,t==null?void 0:t.complianceScore,i),"aria-label":`Compliance score: ${n.percentage}%`,children:[n.percentage,"%"]}),jsxs("div",{children:[jsx("p",{className:a$1(`text-sm font-semibold ${g.text}`,t==null?void 0:t.complianceRating,i),children:rt[n.rating]}),jsxs("p",{className:a$1("text-xs ndpr-text-muted mt-0.5",t==null?void 0:t.complianceDetail,i),children:[n.score," / ",n.maxScore," points \u2022"," ",n.gaps.length," gap",n.gaps.length!==1?"s":""," remaining"]})]})]}),jsxs("div",{children:[jsx("h3",{className:a$1("ndpr-section-heading",t==null?void 0:t.formatsHeading,i),children:"Export Format"}),jsxs("div",{className:a$1("grid grid-cols-1 sm:grid-cols-2 gap-3",t==null?void 0:t.formatsGrid,i),children:[jsx(s,{icon:jsx("svg",{className:"w-5 h-5 text-red-500",fill:"currentColor",viewBox:"0 0 24 24","aria-hidden":"true",children:jsx("path",{d:"M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8l-6-6zm-1 7V3.5L18.5 9H13zm-3 7v-1h4v1h-4zm0-3v-1h4v1h-4zm-2-5h8v1H8v-1z"})}),label:"PDF",description:"Professional formatted document, ideal for publishing.",actionLabel:"Download PDF",loading:u,onClick:a,classNames:t,unstyled:i}),jsx(s,{icon:jsx("svg",{className:"w-5 h-5 text-blue-500",fill:"currentColor",viewBox:"0 0 24 24","aria-hidden":"true",children:jsx("path",{d:"M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8l-6-6zm-1 7V3.5L18.5 9H13zm-5 8v-5h1.5l1 3 1-3H13v5h-1v-3.5l-.75 2.25h-.5L10 13.5V17H9zm5-1.5h.75c.55 0 .75-.25.75-.75 0-.4-.2-.65-.75-.65H14V15.5zm1 1.5h-2v-4h2c1.1 0 1.75.6 1.75 1.5 0 .55-.25.95-.65 1.15.5.2.8.65.8 1.2 0 1-.65 1.65-1.9 1.65V17zm-.25-1c.6 0 .9-.25.9-.75 0-.45-.3-.75-.9-.75H14V16h.75z"})}),label:"DOCX",description:"Editable Word document for further customisation.",actionLabel:"Download DOCX",loading:b,onClick:v,classNames:t,unstyled:i}),jsx(s,{icon:jsxs("svg",{className:"w-5 h-5 text-orange-500",fill:"currentColor",viewBox:"0 0 24 24","aria-hidden":"true",children:[jsx("path",{d:"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 15H9V8h2v9zm4 0h-2V8h2v9z"}),jsx("path",{d:"M9.5 6.5h1v1h-1zm4 0h1v1h-1z"}),jsx("path",{d:"M5 5h14v2H5zm0 12h14v2H5z"})]}),label:"HTML",description:"Copy-ready HTML to embed on your website.",actionLabel:"Copy HTML",onClick:e,classNames:t,unstyled:i}),jsx(s,{icon:jsx("svg",{className:"w-5 h-5 ndpr-text-muted",fill:"currentColor",viewBox:"0 0 24 24","aria-hidden":"true",children:jsx("path",{d:"M3 5h18v2H3V5zm0 4h12v2H3V9zm0 4h18v2H3v-2zm0 4h12v2H3v-2z"})}),label:"Markdown",description:"Plain-text format for documentation or Git repos.",actionLabel:"Copy Markdown",onClick:d$1,classNames:t,unstyled:i})]})]})]})};var Lr=({sections:n,customSections:p,sectionOverrides:r,complianceResult:e,onEditSection:d,onAddCustomSection:t,onRemoveCustomSection:i,onReorderSection:u,onExportPDF:l,onExportDOCX:b$1,onExportHTML:C,onExportMarkdown:g,classNames:a,unstyled:v})=>{let[c,m]=useState(null),[B,J]=useState(false),Z=new Set(p.map(h=>h.id)),er=(h,F)=>{d(h,F),m(null);},ir=n.length>0?Math.max(...n.map(h=>{var F;return (F=h.order)!=null?F:0}))+1:1;return jsxs("div",{"data-ndpr-component":"policy-step-review",className:a$1("ndpr-form-section",a==null?void 0:a.root,v),children:[jsxs("div",{children:[jsx("h2",{className:a$1("ndpr-section-heading",a==null?void 0:a.heading,v),children:"Review & Export"}),jsx("p",{className:a$1("ndpr-form-field__hint",a==null?void 0:a.subheading,v),children:"Review your generated policy sections, reorder or edit content, then export."})]}),jsx("div",{className:a$1("space-y-3",a==null?void 0:a.sectionList,v),"aria-live":"polite",children:n.map((h,F)=>jsx(Cr,{section:r[h.id]?b(a$2({},h),{template:r[h.id]}):h,index:F,isCustom:Z.has(h.id),isEditing:c===h.id,editedContent:r[h.id],onEdit:()=>m(h.id),onSaveEdit:N=>er(h.id,N),onCancelEdit:()=>m(null),onMoveUp:F>0?()=>u(h.id,"up"):void 0,onMoveDown:F<n.length-1?()=>u(h.id,"down"):void 0,onDelete:Z.has(h.id)?()=>i(h.id):void 0,classNames:a,unstyled:v},h.id))}),!B&&jsxs("button",{type:"button",onClick:()=>J(true),className:a$1("flex items-center gap-2 text-sm text-[rgb(var(--ndpr-primary))] hover:underline font-medium",a==null?void 0:a.addSectionButton,v),children:[jsx("span",{className:a$1("w-5 h-5 rounded-full border-2 border-[rgb(var(--ndpr-primary))] flex items-center justify-center text-xs font-bold leading-none",a==null?void 0:a.addSectionIcon,v),"aria-hidden":"true",children:"+"}),"Add Custom Section"]}),B&&jsxs("div",{className:a$1("space-y-2",a==null?void 0:a.customFormWrapper,v),children:[jsx(wr,{onAdd:h=>{t(h),J(false);},nextOrder:ir,classNames:a,unstyled:v}),jsx("button",{type:"button",onClick:()=>J(false),className:a$1("text-sm ndpr-text-muted hover:underline",a==null?void 0:a.cancelCustomForm,v),children:"Cancel"})]}),jsx("hr",{className:a$1("border-gray-200 dark:border-gray-700",a==null?void 0:a.divider,v)}),jsx(Sr,{complianceResult:e,onExportPDF:l,onExportDOCX:b$1,onExportHTML:C,onExportMarkdown:g,classNames:a,unstyled:v})]})};var Dr={compliant:{stroke:"stroke-green-500 dark:stroke-green-400",text:"ndpr-text-success"},nearly_compliant:{stroke:"stroke-amber-500 dark:stroke-amber-400",text:"ndpr-text-warning"},not_compliant:{stroke:"stroke-red-500 dark:stroke-red-400",text:"ndpr-text-destructive"}},ot={compliant:"Compliant",nearly_compliant:"Nearly Compliant",not_compliant:"Not Compliant"},Fr=({score:n,maxScore:p,rating:r,classNames:e,unstyled:d})=>{var C,g;let t=p>0?Math.round(n/p*100):0,i=(C=Dr[r])!=null?C:Dr.not_compliant,u=36,l=2*Math.PI*u,b=l-t/100*l;return jsxs("div",{"data-ndpr-component":"compliance-score-ring",className:a$1("flex flex-col items-center gap-2",e==null?void 0:e.root,d),children:[jsxs("div",{className:a$1("relative w-24 h-24",e==null?void 0:e.svgWrapper,d),children:[jsxs("svg",{className:"w-24 h-24 -rotate-90",viewBox:"0 0 96 96","aria-hidden":"true",children:[jsx("circle",{cx:"48",cy:"48",r:u,fill:"none",className:"stroke-gray-200 dark:stroke-gray-700",strokeWidth:"8"}),jsx("circle",{cx:"48",cy:"48",r:u,fill:"none",className:i.stroke,strokeWidth:"8",strokeLinecap:"round",strokeDasharray:l,strokeDashoffset:b,style:{transition:"stroke-dashoffset 0.5s ease-out"}})]}),jsx("div",{className:a$1("absolute inset-0 flex flex-col items-center justify-center",e==null?void 0:e.centerText,d),children:jsxs("span",{className:a$1(`text-xl font-bold leading-none ${i.text}`,e==null?void 0:e.scoreValue,d),"aria-label":`${t}% compliance score`,children:[t,"%"]})})]}),jsx("p",{className:a$1(`text-xs font-semibold text-center ${i.text}`,e==null?void 0:e.ratingLabel,d),children:(g=ot[r])!=null?g:r}),jsxs("p",{className:a$1("text-xs ndpr-text-muted text-center",e==null?void 0:e.scoreDetail,d),children:[n," / ",p," pts"]})]})};var it={critical:"ndpr-text-destructive",important:"ndpr-text-warning",recommended:"ndpr-text-info"},Er=({gap:n,isPassed:p,onFix:r,classNames:e,unstyled:d})=>{let[t,i]=useState(false);return jsxs("div",{"data-ndpr-component":"compliance-requirement-item",className:a$1("border-b border-gray-100 dark:border-gray-700 last:border-0 py-2",e==null?void 0:e.root,d),children:[jsxs("button",{type:"button",onClick:()=>!p&&i(u=>!u),className:a$1("w-full flex items-start gap-2 text-left group",e==null?void 0:e.row,d),"aria-expanded":p?void 0:t,"aria-disabled":p,children:[jsx("span",{className:a$1(["mt-0.5 flex-shrink-0 w-4 h-4 rounded-full flex items-center justify-center",p?"bg-green-500":n.severity==="critical"?"bg-red-500":n.severity==="important"?"bg-amber-500":"bg-blue-400"].join(" "),e==null?void 0:e.statusIcon,d),"aria-hidden":"true",children:p?jsx("svg",{className:"w-2.5 h-2.5 text-white",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:3,children:jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M5 13l4 4L19 7"})}):jsx("svg",{className:"w-2.5 h-2.5 text-white",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:3,children:jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M6 18L18 6M6 6l12 12"})})}),jsxs("div",{className:"flex-1 min-w-0",children:[jsxs("div",{className:"flex items-center justify-between gap-1",children:[jsx("p",{className:a$1(`text-xs font-medium ${p?"ndpr-text-muted":"ndpr-text-foreground"}`,e==null?void 0:e.requirementLabel,d),children:n.requirement}),!p&&jsx("svg",{className:`flex-shrink-0 w-3 h-3 text-gray-400 transition-transform ${t?"rotate-180":""}`,fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:2,"aria-hidden":"true",children:jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M19 9l-7 7-7-7"})})]}),jsxs("p",{className:a$1("text-xs text-gray-400 dark:text-gray-500 mt-0.5",e==null?void 0:e.ndpaSection,d),children:["NDPA ",n.ndpaSection]})]})]}),!p&&t&&jsxs("div",{className:a$1("mt-2 ml-6 space-y-2",e==null?void 0:e.detail,d),children:[jsx("p",{className:a$1(`text-xs ${it[n.severity]}`,e==null?void 0:e.message,d),children:n.message}),jsx("button",{type:"button",onClick:()=>{r(n.requirementId),i(false);},className:a$1("text-xs font-medium px-3 py-1 bg-[rgb(var(--ndpr-primary))] text-[rgb(var(--ndpr-primary-foreground))] rounded hover:bg-[rgb(var(--ndpr-primary-hover))]",e==null?void 0:e.fixButton,d),children:n.fixLabel})]})]})};function dt(n,p){let r=p.map(t=>({gap:{requirementId:t,requirement:t.split("-").map(i=>i.charAt(0).toUpperCase()+i.slice(1)).join(" "),ndpaSection:"\u2014",severity:"recommended",message:"",fixType:"fill_field",fixLabel:""},isPassed:true})),e=n.map(t=>({gap:t,isPassed:false})),d={critical:0,important:1,recommended:2};return e.sort((t,i)=>d[t.gap.severity]-d[i.gap.severity]),[...e,...r]}var $r=({complianceResult:n,onFix:p,classNames:r,unstyled:e})=>{let[d,t]=useState(false),i=dt(n.gaps,n.passed);return jsxs("aside",{"data-ndpr-component":"compliance-checker-sidebar",className:a$1("bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg overflow-hidden",r==null?void 0:r.root,e),"aria-label":"NDPA compliance checker",children:[jsxs("div",{className:a$1("flex items-center justify-between px-4 py-3 border-b border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-900/50",r==null?void 0:r.header,e),children:[jsx("h2",{className:a$1("ndpr-section-heading",r==null?void 0:r.title,e),children:"NDPA Compliance"}),jsx("button",{type:"button",onClick:()=>t(u=>!u),className:a$1("p-1 text-gray-400 hover:text-gray-600 dark:hover:text-gray-200 rounded hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors",r==null?void 0:r.collapseButton,e),"aria-expanded":!d,"aria-label":d?"Expand compliance checker":"Collapse compliance checker",children:jsx("svg",{className:`w-4 h-4 transition-transform ${d?"-rotate-90":""}`,fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:2,"aria-hidden":"true",children:jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M19 9l-7 7-7-7"})})})]}),!d&&jsxs("div",{className:a$1("p-4 space-y-4",r==null?void 0:r.body,e),children:[jsx("div",{className:a$1("flex justify-center",r==null?void 0:r.ringWrapper,e),children:jsx(Fr,{score:n.score,maxScore:n.maxScore,rating:n.rating,classNames:r,unstyled:e})}),jsx("div",{className:a$1("grid grid-cols-3 gap-2 text-center",r==null?void 0:r.statsRow,e),children:[{count:n.gaps.filter(u=>u.severity==="critical").length,label:"Critical",color:"ndpr-text-destructive"},{count:n.gaps.filter(u=>u.severity==="important").length,label:"Important",color:"ndpr-text-warning"},{count:n.passed.length,label:"Passed",color:"ndpr-text-success"}].map(({count:u,label:l,color:b})=>jsxs("div",{children:[jsx("p",{className:a$1(`text-base font-bold ${b}`,r==null?void 0:r.statValue,e),children:u}),jsx("p",{className:a$1("ndpr-form-field__hint",r==null?void 0:r.statLabel,e),children:l})]},l))}),jsx("div",{className:a$1("overflow-y-auto max-h-80",r==null?void 0:r.requirementsList,e),children:i.length===0?jsx("p",{className:a$1("ndpr-empty-state",r==null?void 0:r.emptyState,e),children:"No requirements to display."}):i.map(({gap:u,isPassed:l})=>jsx(Er,{gap:u,isPassed:l,onFix:p,classNames:r,unstyled:e},u.requirementId))})]})]})};function pt(n){let p=Date.now()-n;return p<1e4?"just now":p<6e4?`${Math.floor(p/1e3)}s ago`:p<36e5?`${Math.floor(p/6e4)}m ago`:new Date(n).toLocaleTimeString(void 0,{hour:"2-digit",minute:"2-digit"})}var Tr=({lastSavedAt:n,isSaving:p,hasError:r,classNames:e,unstyled:d})=>{let t="idle";if(p?t="saving":r?t="error":n!==null&&(t="saved"),t==="idle")return null;let i=t==="saving"?"Saving\u2026":t==="error"?"Unable to save":`Draft saved ${n?pt(n):""}`;return jsxs("div",{"data-ndpr-component":"draft-save-indicator",role:"status","aria-live":"polite","aria-atomic":"true",className:a$1(`flex items-center gap-1.5 ${t==="error"?"text-red-500 dark:text-red-400":t==="saving"?"ndpr-card__subtitle":"ndpr-text-success"}`,e==null?void 0:e.root,d),children:[t==="saving"&&jsxs("svg",{className:"animate-spin w-3 h-3 flex-shrink-0",fill:"none",viewBox:"0 0 24 24","aria-hidden":"true",children:[jsx("circle",{className:"opacity-25",cx:"12",cy:"12",r:"10",stroke:"currentColor",strokeWidth:"4"}),jsx("path",{className:"opacity-75",fill:"currentColor",d:"M4 12a8 8 0 018-8v4l3-3-3-3v4a10 10 0 100 10l-1.73-3A8 8 0 014 12z"})]}),t==="saved"&&jsx("svg",{className:"w-3 h-3 flex-shrink-0",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:3,"aria-hidden":"true",children:jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M5 13l4 4L19 7"})}),t==="error"&&jsx("svg",{className:"w-3 h-3 flex-shrink-0",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",strokeWidth:2,"aria-hidden":"true",children:jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M12 9v2m0 4h.01M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z"})}),jsx("span",{className:a$1("text-xs font-medium",e==null?void 0:e.text,d),children:i})]})};var Ro=({adapter:n,onComplete:p,classNames:r,unstyled:e,initialContext:d$1})=>{let{currentStep:t,nextStep:i,prevStep:u,canProceed:l,context:b,updateOrg:C,updateContext:g,toggleDataCategory:a$2,togglePurpose:v,addProcessor:c,removeProcessor:m,sections:B,customSections:J,sectionOverrides:Z,editSectionContent:er,addCustomSection:ir,removeCustomSection:h,reorderSections:F,complianceResult:N,applyFix:Ir,handleExportPDF:_r,handleExportDOCX:Mr,handleExportHTML:Br,handleExportMarkdown:zr,lastSavedAt:jr,isLoading:qr}=a({adapter:n,onComplete:p,initialContext:d$1}),nr=(D,K)=>{let O=URL.createObjectURL(D),H=document.createElement("a");H.href=O,H.download=K,H.click(),URL.revokeObjectURL(O);},Or=()=>d(null,null,function*(){let D=yield _r();nr(D,"privacy-policy.pdf");}),Hr=()=>d(null,null,function*(){let D=yield Mr();nr(D,"privacy-policy.docx");}),Wr=()=>{let D=Br();navigator.clipboard.writeText(D).catch(()=>{let K=new Blob([D],{type:"text/html"}),O=URL.createObjectURL(K),H=window.open(O,"_blank");H?H.addEventListener("load",()=>URL.revokeObjectURL(O)):URL.revokeObjectURL(O);});},Gr=()=>{let D=zr();navigator.clipboard.writeText(D).catch(()=>{let K=new Blob([D],{type:"text/markdown"});nr(K,"privacy-policy.md");});};return qr?jsxs("div",{"data-ndpr-component":"adaptive-policy-wizard",className:a$1("flex items-center justify-center min-h-64 text-gray-400 dark:text-gray-500",r==null?void 0:r.root,e),"aria-busy":"true","aria-label":"Loading policy wizard",children:[jsxs("svg",{className:"animate-spin w-6 h-6 mr-2",fill:"none",viewBox:"0 0 24 24","aria-hidden":"true",children:[jsx("circle",{className:"opacity-25",cx:"12",cy:"12",r:"10",stroke:"currentColor",strokeWidth:"4"}),jsx("path",{className:"opacity-75",fill:"currentColor",d:"M4 12a8 8 0 018-8v4l3-3-3-3v4a10 10 0 100 10l-1.73-3A8 8 0 014 12z"})]}),jsx("span",{className:"ndpr-text-sm",children:"Loading\u2026"})]}):jsx("div",{"data-ndpr-component":"adaptive-policy-wizard",className:a$1("min-h-screen bg-gray-50 dark:bg-gray-900",r==null?void 0:r.root,e),children:jsxs("div",{className:a$1("max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8",r==null?void 0:r.container,e),children:[jsxs("div",{className:a$1("flex items-center justify-between mb-6",r==null?void 0:r.topBar,e),children:[jsx("h1",{className:a$1("text-2xl font-bold ndpr-text-foreground",r==null?void 0:r.wizardTitle,e),children:"Privacy Policy Builder"}),jsx(Tr,{lastSavedAt:jr,isSaving:false,hasError:false,classNames:r,unstyled:e})]}),jsx("div",{className:a$1("bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg px-4 mb-6",r==null?void 0:r.stepIndicatorWrapper,e),children:jsx(lr,{currentStep:t,classNames:r,unstyled:e})}),jsxs("div",{className:a$1("flex flex-col lg:flex-row gap-6 items-start",r==null?void 0:r.panels,e),children:[jsxs("main",{"aria-live":"polite",className:a$1("flex-1 min-w-0 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg p-6",r==null?void 0:r.mainPanel,e),children:[t===1&&jsx(fr,{context:b,onUpdateOrg:C,classNames:r,unstyled:e}),t===2&&jsx(xr,{categories:b.dataCategories,onToggle:a$2,classNames:r,unstyled:e}),t===3&&jsx(hr,{context:b,onTogglePurpose:v,onUpdateContext:g,onAddProcessor:c,onRemoveProcessor:m,classNames:r,unstyled:e}),t===4&&jsx(Lr,{sections:B,customSections:J,sectionOverrides:Z,complianceResult:N,onEditSection:er,onAddCustomSection:ir,onRemoveCustomSection:h,onReorderSection:F,onExportPDF:Or,onExportDOCX:Hr,onExportHTML:Wr,onExportMarkdown:Gr,classNames:r,unstyled:e}),jsxs("div",{className:a$1("flex items-center justify-between mt-8 pt-4 border-t border-gray-200 dark:border-gray-700",r==null?void 0:r.navigation,e),children:[jsx("button",{type:"button",onClick:u,disabled:t===1,className:a$1("px-4 py-2 bg-gray-200 dark:bg-gray-700 ndpr-text-foreground rounded-md text-sm font-medium disabled:opacity-40 disabled:cursor-not-allowed hover:bg-gray-300 dark:hover:bg-gray-600 transition-colors",r==null?void 0:r.backButton,e),children:"Back"}),jsx("div",{className:"flex items-center gap-2",children:jsxs("span",{className:a$1("ndpr-form-field__hint",r==null?void 0:r.stepCounter,e),children:["Step ",t," of 4"]})}),t<4?jsx("button",{type:"button",onClick:i,disabled:!l,className:a$1("px-4 py-2 bg-[rgb(var(--ndpr-primary))] text-[rgb(var(--ndpr-primary-foreground))] rounded-md hover:bg-[rgb(var(--ndpr-primary-hover))] text-sm font-medium disabled:opacity-40 disabled:cursor-not-allowed transition-colors",r==null?void 0:r.nextButton,e),children:"Next"}):jsx("span",{})]})]}),jsx("aside",{className:a$1("w-full lg:w-80 flex-shrink-0",r==null?void 0:r.sidebarWrapper,e),children:jsx($r,{complianceResult:N,onFix:Ir,classNames:r,unstyled:e})})]})]})})};
2
+ export{Ro as a};