@tantainnovative/ndpr-toolkit
Version:
Nigeria Data Protection Toolkit — enterprise-grade compliance components for the Nigeria Data Protection Act (NDPA) 2023
1,309 lines (1,241 loc) • 45.7 kB
text/typescript
import * as React_2 from 'react';
import React__default from 'react';
export declare const AdaptivePolicyWizard: React__default.FC<AdaptivePolicyWizardProps>;
declare interface AdaptivePolicyWizardProps {
adapter?: StorageAdapter<PolicyDraft>;
onComplete?: (policy: PrivacyPolicy) => void;
classNames?: Record<string, string>;
unstyled?: boolean;
/**
* Initial template context — seeds the wizard with a sector-specific
* pre-fill. Use `templateContextFor('saas' | 'ecommerce' | …)` from
* `/server` (or `/core`) to construct it.
*/
initialContext?: TemplateContext;
}
/**
* Assemble an ordered, NDPA-aligned array of privacy-policy sections from
* a {@link TemplateContext}. This is the canonical "compute the policy"
* function — it produces structured `PolicySection[]` data that downstream
* renderers (`exportHTML`, `exportMarkdown`, `exportPDF`, `exportDOCX`,
* `<PolicyPage />`) consume.
*
* Section composition:
* - **Core sections** (always included): Introduction, Data Collection,
* Legal Basis, Data Usage, Data Sharing, Data Retention, Data Security,
* Data Subject Rights, Contact Information.
* - **Conditional sections** (included based on context flags):
* - `hasChildrenData` → Children's Data Protection (NDPA §31)
* - `hasSensitiveData` → Sensitive / Special-Category Data
* - `hasCrossBorderTransfer` → Cross-Border Transfers (NDPA Part VI)
* - `hasAutomatedDecisions` → Automated Decision-Making (NDPA §37)
*
* Section text uses `«TODO: fieldName»` markers (the `UNFILLED_PREFIX` constant)
* for any required org-info field that's empty in the context. Pair with
* {@link findUnfilledTokens} to surface those before publishing.
*
* @param context - Organisation info, data categories, processing purposes,
* third-party processors, and feature flags. Build a default
* context with `createDefaultContext()` then mutate.
* @returns An ordered array of {@link PolicySection} objects ready to pass
* to `exportHTML(policy)` or `<PolicyPage policy={...} />`.
*
* @example
* ```ts
* import { assemblePolicy, createDefaultContext } from '@tantainnovative/ndpr-toolkit/server';
*
* const ctx = createDefaultContext();
* ctx.org.name = 'Acme Nigeria Ltd';
* ctx.org.privacyEmail = 'privacy@acme.ng';
* ctx.hasCrossBorderTransfer = true;
*
* const sections = assemblePolicy(ctx);
* // sections is a 10-element array (9 core + 1 cross-border)
* ```
*/
export declare function assemblePolicy(context: TemplateContext): PolicySection[];
/** A single gap found during NDPA compliance evaluation. */
export declare interface ComplianceGap {
/** Machine-readable requirement identifier. */
requirementId: string;
/** Human-readable name of the requirement. */
requirement: string;
/** Reference to the relevant NDPA section. */
ndpaSection: string;
/** How severe the gap is. */
severity: 'critical' | 'important' | 'recommended';
/** Explanation of what is missing. */
message: string;
/** Suggested fix type for the UI. */
fixType: 'add_section' | 'add_content' | 'fill_field';
/** Label for the fix action button. */
fixLabel: string;
/** Pre-written content the user can insert to close the gap. */
suggestedContent?: string;
}
/** Result of evaluating a policy against NDPA requirements. */
export declare interface ComplianceResult {
/** Points earned. */
score: number;
/** Maximum achievable points (115). */
maxScore: number;
/** Percentage score (0-100). */
percentage: number;
/** Overall compliance rating. */
rating: 'compliant' | 'nearly_compliant' | 'not_compliant';
/** List of identified compliance gaps. */
gaps: ComplianceGap[];
/** List of requirement ids that passed. */
passed: string[];
}
/**
* Creates a complete business privacy policy template with default
* NDPA-compliant sections and variables.
*
* @returns An object containing the default sections and variables.
*/
export declare function createBusinessPolicyTemplate(): {
sections: PolicySection[];
variables: PolicyVariable[];
};
/**
* Creates a default TemplateContext with sensible empty/initial values.
* Useful for initialising the wizard state before the user begins editing.
*/
export declare function createDefaultContext(): TemplateContext;
/** A user-defined section added to the policy outside the generated ones. */
export declare interface CustomSection {
id: string;
title: string;
content: string;
order: number;
required: false;
}
/** A logical category of personal data the organisation may collect. */
export declare interface DataCategory {
/** Machine-readable identifier. */
id: string;
/** Human-readable label shown in the wizard. */
label: string;
/** Grouping for display and compliance checks. */
group: 'identity' | 'financial' | 'behavioral' | 'sensitive' | 'children';
/** Specific data points within this category. */
dataPoints: string[];
/** Whether this category is currently selected by the user. */
selected: boolean;
}
/**
* Comprehensive set of 16 data categories spanning identity, financial,
* behavioral, sensitive, and children groups. Used to populate the wizard
* and drive adaptive section generation.
*/
export declare const DEFAULT_DATA_CATEGORIES: DataCategory[];
/**
* Default NDPA-compliant privacy policy sections.
* Each section uses {{variable}} placeholders that are resolved at generation time.
*/
export declare const DEFAULT_POLICY_SECTIONS: PolicySection[];
/**
* Default policy variables for NDPA-compliant privacy policies.
* These map to the {{variable}} placeholders used in DEFAULT_POLICY_SECTIONS.
*/
export declare const DEFAULT_POLICY_VARIABLES: PolicyVariable[];
/** Options for DOCX export of the finalised policy. */
declare interface DOCXExportOptions {
includeTOC?: boolean;
filename?: string;
}
/**
* NDPA policy compliance checker.
*
* Evaluates a {@link PrivacyPolicy} against 15 requirements drawn from
* the Nigeria Data Protection Act (NDPA) 2023, producing a scored
* {@link ComplianceResult} with actionable gaps.
*
* Scoring:
* 6 critical @ 10 pts = 60
* 5 important @ 7 pts = 35
* 4 recommended @ 5 pts = 20
* Total max = 115
*
* Rating thresholds:
* >= 100 → compliant
* >= 80 → nearly_compliant
* < 80 → not_compliant
*/
/**
* Evaluates a privacy policy against 15 NDPA 2023 requirements and
* returns a scored compliance result with actionable gap information.
*
* @param policy - The privacy policy to evaluate.
* @param context - The template context that was used to generate the policy.
* @returns A {@link ComplianceResult} with score, rating, gaps, and passed ids.
*/
export declare function evaluatePolicyCompliance(policy: PrivacyPolicy, context: TemplateContext): ComplianceResult;
/**
* Export a PrivacyPolicy as a Word (.docx) Blob using the `docx` library
* (optional peer dependency).
*
* Features:
* - Title paragraph with large bold text
* - Organisation name + version subtitle
* - Optional table of contents placeholder heading
* - All included policy sections as Heading 1 + body paragraphs / bullet lists
* - Running header (org name) and page-number footer on every page
*
* @throws {Error} if the `docx` package is not installed
*/
export declare function exportDOCX(policy: PrivacyPolicy, options?: DOCXExportOptions): Promise<Blob>;
/**
* Export a PrivacyPolicy as a self-contained HTML string.
*
* The returned string includes:
* - An embedded `<style>` block (responsive, dark/light, print-friendly)
* - An `<article>` wrapper with semantic markup
* - A `<nav>` table of contents with anchor links
* - A `<section>` for every included policy section
* - A metadata footer (org name, effective date, version, generator credit)
* - Optional custom CSS injection via `options.customCSS`
*/
export declare function exportHTML(policy: PrivacyPolicy, options?: HTMLExportOptions): string;
/**
* Export a PrivacyPolicy as a clean Markdown string.
*
* Structure:
* ```
* # Policy Title
* _Effective: date | Version: X | Org Name_
*
* ## Table of Contents
* - [Section Title](#anchor)
*
* ## 1. Section Title
* Section content...
* ```
*/
export declare function exportMarkdown(policy: PrivacyPolicy): string;
/**
* Export a PrivacyPolicy to a PDF Blob using jspdf (optional peer dependency).
*
* Requires jspdf >= 4.2.1 (earlier versions carry GHSA-67pg-wm7f-q7fj and
* GHSA-cjw8-79x6-5cj4). This function uses only core jsPDF text/vector APIs —
* never `addImage`, `addJS`, or `.html()` — so jspdf's optional deps
* (canvg, core-js, dompurify, html2canvas) can be omitted (`--omit=optional`).
*
* Features:
* - Optional cover page with title, organisation, date, version and compliance badge
* - Optional table of contents page
* - One section per heading, content reflowed to fit the page
* - Automatic page breaks
* - Page header (org name) and footer (page X of Y) on every page
* - PDF metadata (title, author, subject, keywords)
*
* @throws {Error} if the `jspdf` package is not installed
*/
export declare function exportPDF(policy: PrivacyPolicy, options?: PDFExportOptions): Promise<Blob>;
/**
* Scan rendered policy text for unfilled placeholder tokens.
*
* Detects two token forms:
* - `«TODO: fieldName»` — sentinel emitted by {@link assemblePolicy} when
* a required org-info field is missing from the context.
* - `{{fieldName}}` — mustache token that escaped substitution (either
* because the variable wasn't declared or its value was empty).
*
* Returns a deduplicated list of the field names found. An empty array
* means the rendered text is fully populated.
*
* Two recommended uses:
*
* 1. **CI guard** — assert your canonical org-info fixture renders without
* leaving any tokens behind:
* ```ts
* const html = exportHTML(policy);
* expect(findUnfilledTokens(html)).toEqual([]);
* ```
*
* 2. **Runtime guard** — surface a clear error to compliance officers
* before they publish a policy with `{{orgName}}` visible to visitors:
* ```ts
* const missing = findUnfilledTokens(getPolicyText().fullText);
* if (missing.length) throw new Error(`Policy is missing: ${missing.join(', ')}`);
* ```
*
* @param rendered - The substituted policy text (from `exportHTML`,
* `exportMarkdown`, or `usePrivacyPolicy().getPolicyText().fullText`).
* @returns Deduplicated array of unfilled field names; `[]` if fully filled.
*/
export declare function findUnfilledTokens(rendered: string): string[];
/**
* Generates policy text by replacing variables in a template with organization-specific values
* @param sectionsOrTemplate The policy sections or template string to generate text for
* @param organizationInfoOrVariables The organization information or variable map to use for replacement
* @returns The generated policy text or an object with the generated text and metadata
*/
export declare function generatePolicyText(sectionsOrTemplate: PolicySection[] | string, organizationInfoOrVariables: OrganizationInfo | Record<string, string>): string | {
fullText: string;
sectionTexts: Record<string, string>;
missingVariables: string[];
};
/** Options for HTML export of the finalised policy. */
declare interface HTMLExportOptions {
includeStyles?: boolean;
includePrintCSS?: boolean;
customCSS?: string;
/**
* Theme controlling the embedded design tokens.
*
* - `'light'` (default): emits the light token palette only. No
* `prefers-color-scheme: dark` block is included, so a visitor's OS
* dark-mode setting will NOT recolour the policy. This is the right
* default for an embedded compliance widget — most consumer host sites
* are single-theme and Shadow DOM does not isolate `prefers-color-scheme`.
* - `'dark'`: emits the dark token palette as the primary style.
* - `'auto'`: emits light tokens plus a `@media (prefers-color-scheme: dark)`
* block that swaps to dark on the user's OS preference. Use this when
* your host site genuinely follows OS dark mode and you want the policy
* to match.
*
* Pre-3.4.1 the export effectively behaved like `'auto'` unconditionally,
* which leaked dark colours into light-only host sites via Shadow DOM.
*
* @default 'light'
*/
theme?: 'light' | 'dark' | 'auto';
}
/**
* Policy engine types for the adaptive privacy policy generator.
* These types power the wizard-driven policy builder, compliance checker,
* and export functionality — all aligned with the NDPA 2023.
*/
/** Industry verticals with sector-specific compliance requirements. */
export declare type Industry = 'fintech' | 'healthcare' | 'ecommerce' | 'saas' | 'education' | 'government' | 'other';
/**
* Static metadata for every template — useful for picker UIs that need
* to list available templates with a one-line description.
*/
export declare const ORG_POLICY_TEMPLATE_REGISTRY: Record<OrgPolicyTemplateId, {
id: OrgPolicyTemplateId;
label: string;
description: string;
/** Best-fit org examples to show in the picker. */
examples: readonly string[];
}>;
/**
* Represents organization information for a privacy policy
*/
export declare interface OrganizationInfo {
/** Name of the organization */
name: string;
/** Website URL of the organization */
website: string;
/** Contact email for privacy inquiries */
privacyEmail: string;
/** Physical address of the organization */
address?: string;
/** Phone number for privacy inquiries */
privacyPhone?: string;
/** Name of the Data Protection Officer */
dpoName?: string;
/** Email of the Data Protection Officer */
dpoEmail?: string;
/** Industry or sector of the organization */
industry?: string;
/** NDPC registration number (if registered) */
ndpcRegistrationNumber?: string;
}
/**
* Org-specific privacy-policy templates — pre-filled `TemplateContext`
* factories for the most common Nigerian app shapes.
*
* Each template returns a fully-populated `TemplateContext` with:
* - industry set to the matching `Industry` value
* - the data categories the sector typically collects (selected: true)
* - the processing purposes that match the business model
* - sensitive-data / children / cross-border / automated-decisions flags
* set to the defaults that org type usually needs (a school will have
* children data, a hospital will have sensitive data, etc.)
*
* Templates are guidance starters. The wizard still walks the user through
* every step — they can flip any flag, add/remove categories, or rewrite
* any section before the policy is finalised. The legal-notice footer the
* toolkit ships everywhere applies to the generated output.
*
* @example
* import { templateContextFor } from '@tantainnovative/ndpr-toolkit/server';
* const ctx = templateContextFor('ecommerce', { orgName: 'Acme NG' });
* const draft = assemblePolicy(ctx);
*/
/** Identifiers for the bundled org templates. */
export declare type OrgPolicyTemplateId = 'saas' | 'ecommerce' | 'school' | 'healthcare' | 'procurement';
/** Optional overrides applied on top of a template's defaults. */
export declare interface OrgPolicyTemplateOverrides {
/** Organisation name (e.g. "Acme Nigeria Ltd"). Default: empty. */
orgName?: string;
/** Public website URL. */
website?: string;
/** Privacy contact email. */
privacyEmail?: string;
/** Postal address. */
address?: string;
/** DPO name. Required for DCPMI under NDPA Section 32. */
dpoName?: string;
/** DPO email. Required for the NDPC breach-notification contact. */
dpoEmail?: string;
}
/** Organisation size tiers — affects complexity of generated language. */
export declare type OrgSize = 'startup' | 'midsize' | 'enterprise';
/** Options for PDF export of the finalised policy. */
declare interface PDFExportOptions {
includeCoverPage?: boolean;
includeTOC?: boolean;
includeComplianceBadge?: boolean;
logoUrl?: string;
filename?: string;
}
export declare const Policy: {
Provider: React_2.FC<PolicyProviderProps>;
Generator: React_2.FC<PolicyGeneratorProps>;
Preview: React_2.FC<PolicyPreviewProps>;
Exporter: React_2.FC<PolicyExporterProps>;
};
declare interface PolicyContextValue extends UsePrivacyPolicyReturn {
templates: PolicyTemplate[];
}
/** Represents an in-progress policy being built in the wizard. */
export declare interface PolicyDraft {
/** Unique identifier for the draft. */
id: string;
/** The template context driving section generation. */
templateContext: TemplateContext;
/** Custom sections added by the user. */
customSections: CustomSection[];
/** Per-section content overrides keyed by section id. */
sectionOverrides: Record<string, string>;
/** Ordered list of section ids defining the final order. */
sectionOrder: string[];
/** Current wizard step (0-indexed). */
currentStep: number;
/** Timestamp of the last save. */
lastSavedAt: number;
/** The draft is always in "draft" status until finalised. */
status: 'draft';
}
export declare const PolicyExporter: React__default.FC<PolicyExporterProps>;
declare interface PolicyExporterClassNames {
/** Root container */
root?: string;
/** Header area containing title and description */
header?: string;
/** Title element */
title?: string;
/** Description element */
description?: string;
/** Format selector container */
formatSelector?: string;
/** Individual format option */
formatOption?: string;
/** Export button */
exportButton?: string;
/** Alias for exportButton */
primaryButton?: string;
/** NDPA compliance / export tips notice */
complianceNotice?: string;
/** Preview / export history area */
preview?: string;
}
declare interface PolicyExporterProps {
/**
* The policy content to export
*/
content: string;
/**
* The policy title
*/
title?: string;
/**
* The organization name to include in the exported policy
*/
organizationName?: string;
/**
* The last updated date to include in the exported policy
*/
lastUpdated?: Date;
/**
* Callback function called when the export is complete
*/
onExportComplete?: (format: string, url: string) => void;
/**
* Title displayed on the exporter
* @default "Export Privacy Policy"
*/
componentTitle?: string;
/**
* Description text displayed on the exporter
* @default "Export your NDPA-compliant privacy policy in various formats."
*/
description?: string;
/**
* Custom CSS class for the exporter
*/
className?: string;
/**
* Custom CSS class for the buttons
*/
buttonClassName?: string;
/**
* Whether to show the export history
* @default true
*/
showExportHistory?: boolean;
/**
* Whether to include the NDPA compliance notice in the exported policy
* @default true
*/
includeComplianceNotice?: boolean;
/**
* Whether to include the organization logo in the exported policy
* @default false
*/
includeLogo?: boolean;
/**
* URL of the organization logo
*/
logoUrl?: string;
/**
* Custom CSS styles for the exported policy
*/
customStyles?: string;
/**
* Override class names for internal elements
*/
classNames?: PolicyExporterClassNames;
/**
* If true, removes all default styles. Use with classNames to apply your own.
* @default false
*/
unstyled?: boolean;
}
/**
* Privacy policy generator component. Implements NDPA Section 27 (provision of
* information to the data subject), helping organizations generate compliant
* privacy policies that disclose required information.
*/
export declare const PolicyGenerator: React__default.FC<PolicyGeneratorProps>;
declare interface PolicyGeneratorClassNames {
/** Root container */
root?: string;
/** Header area containing title and description */
header?: string;
/** Title element */
title?: string;
/** Description element */
description?: string;
/** Section list container */
sectionList?: string;
/** Individual section item */
sectionItem?: string;
/** Variable form container */
form?: string;
/** Form input fields */
input?: string;
/** Generate button */
generateButton?: string;
/** Alias for generateButton */
primaryButton?: string;
/** NDPA compliance notice */
complianceNotice?: string;
}
declare interface PolicyGeneratorProps {
/**
* List of policy sections
* @default DEFAULT_POLICY_SECTIONS
*/
sections?: PolicySection[];
/**
* List of policy variables
* @default DEFAULT_POLICY_VARIABLES
*/
variables?: PolicyVariable[];
/**
* Callback function called when the policy is generated
*/
onGenerate: (policy: {
sections: PolicySection[];
variables: PolicyVariable[];
content: string;
}) => void;
/**
* Title displayed on the generator
* @default "NDPA Privacy Policy Generator"
*/
title?: string;
/**
* Description text displayed on the generator
* @default "Generate an NDPA-compliant privacy policy for your organization in accordance with NDPA Section 27."
*/
description?: string;
/**
* Custom CSS class for the generator
*/
className?: string;
/**
* Custom CSS class for the buttons
*/
buttonClassName?: string;
/**
* Text for the generate button
* @default "Generate Policy"
*/
generateButtonText?: string;
/**
* Whether to show a preview of the generated policy
* @default true
*/
showPreview?: boolean;
/**
* Whether to allow editing the policy content
* @default true
*/
allowEditing?: boolean;
/**
* Override class names for internal elements
*/
classNames?: PolicyGeneratorClassNames;
/**
* If true, removes all default styles. Use with classNames to apply your own.
* @default false
*/
unstyled?: boolean;
}
/**
* Renders a full privacy policy from a typed `PrivacyPolicy` object.
*
* ## Choosing a mode
*
* | mode | renders | SEO | host-CSS isolation | best for |
* |------|---------|-----|--------------------|----------|
* | `'shadow'` (default) | Inside a Shadow DOM root, opinionated styles included | ❌ markup is invisible to crawlers (lives in shadow) | ✅ structurally impossible to leak | in-app embeds where you want a polished drop-in widget |
* | `'inline'` | Directly in the host document body | ✅ crawlable markup | ⚠️ consumer styles the markup themselves | SSR'd `/privacy` pages, public legal pages |
*
* Inline mode defaults `includeStyles: false` so bare element selectors
* (`body`, `article`, `h1`...) don't leak into the host page. The rendered
* markup is plain semantic HTML — `<article>`, `<section>`, `<h2>`, `<p>`,
* `<ul>`. Pair it with your own typography to make it look right.
*
* @example **Inline mode + Tailwind `@tailwindcss/typography`**
* ```tsx
* import { PolicyPage } from '@tantainnovative/ndpr-toolkit';
*
* // Wrap with the `prose` class so headings, paragraphs, and lists pick
* // up Tailwind's typography defaults. dark:prose-invert handles dark mode.
* <article className="prose prose-slate dark:prose-invert max-w-3xl mx-auto">
* <PolicyPage policy={policy} mode="inline" />
* </article>
* ```
*
* @example **Inline mode with shadcn-ui typography**
* ```tsx
* <Card>
* <CardContent className="prose dark:prose-invert">
* <PolicyPage policy={policy} mode="inline" />
* </CardContent>
* </Card>
* ```
*
* @example **Inline mode with raw CSS**
* ```css
* .ndpr-policy-page article { font-family: Georgia, serif; line-height: 1.7; }
* .ndpr-policy-page h2 { font-size: 1.5rem; margin-top: 2rem; }
* .ndpr-policy-page section { margin-bottom: 1.5rem; }
* ```
*
* @example **Theming the shadow-mode default**
* ```tsx
* // Brand the policy without leaving shadow mode — pass theme + customCSS.
* <PolicyPage
* policy={policy}
* options={{
* theme: 'auto', // or 'light' (default) / 'dark'
* customCSS: ':root { --color-accent: #1d4ed8; --max-width: 64rem; }',
* }}
* />
* ```
*
* HTML is generated internally by `exportHTML` from a typed `PrivacyPolicy`
* and never contains untrusted user input.
*/
export declare const PolicyPage: React__default.FC<PolicyPageProps>;
declare type PolicyPageMode = 'shadow' | 'inline';
declare interface PolicyPageProps {
policy: PrivacyPolicy;
className?: string;
/**
* Render mode.
*
* - `'shadow'` (default): mounts the rendered policy inside a Shadow DOM
* root, fully isolating the embedded `<style>` block from the host page.
* Use this for in-app embeds where you want the rich, opinionated
* default styling without polluting global CSS. Client-only.
*
* - `'inline'`: injects the policy markup directly into the host document.
* Defaults to `includeStyles: false` so bare element selectors don't
* leak. Pair with your own CSS / design tokens. SSR-safe.
*/
mode?: PolicyPageMode;
/**
* Pass-through to {@link exportHTML}. Lets you toggle `includeStyles`,
* `includePrintCSS`, or inject `customCSS`. Defaults differ by mode:
* shadow mode includes styles; inline mode omits them.
*/
options?: HTMLExportOptions;
}
export declare const PolicyPreview: React__default.FC<PolicyPreviewProps>;
declare interface PolicyPreviewClassNames {
/** Root container */
root?: string;
/** Header area containing title and description */
header?: string;
/** Title element */
title?: string;
/** Description element */
description?: string;
/** Content area wrapping the rendered policy */
content?: string;
/** Individual rendered section container */
section?: string;
/** Section title within rendered content */
sectionTitle?: string;
/** Section content within rendered content */
sectionContent?: string;
/** NDPA compliance notice */
complianceNotice?: string;
}
declare interface PolicyPreviewProps {
/**
* The policy content to preview
*/
content: string;
/**
* The policy sections
*/
sections?: PolicySection[];
/**
* The policy variables
*/
variables?: PolicyVariable[];
/**
* Callback function called when the policy is exported
*/
onExport?: (format: 'pdf' | 'html' | 'markdown' | 'docx') => void;
/**
* Callback function called when the policy is edited
*/
onEdit?: () => void;
/**
* Title displayed on the preview
* @default "Privacy Policy Preview"
*/
title?: string;
/**
* Description text displayed on the preview
* @default "Preview your NDPA-compliant privacy policy before exporting."
*/
description?: string;
/**
* Custom CSS class for the preview
*/
className?: string;
/**
* Custom CSS class for the buttons
*/
buttonClassName?: string;
/**
* Whether to show the export options
* @default true
*/
showExportOptions?: boolean;
/**
* Whether to show the edit button
* @default true
*/
showEditButton?: boolean;
/**
* Whether to show the table of contents
* @default true
*/
showTableOfContents?: boolean;
/**
* Whether to show the policy metadata
* @default true
*/
showMetadata?: boolean;
/**
* The organization name to display in the policy
*/
organizationName?: string;
/**
* The last updated date to display in the policy
*/
lastUpdated?: Date;
/**
* Override class names for internal elements
*/
classNames?: PolicyPreviewClassNames;
/**
* If true, removes all default styles. Use with classNames to apply your own.
* @default false
*/
unstyled?: boolean;
}
export declare const PolicyProvider: React__default.FC<PolicyProviderProps>;
export declare interface PolicyProviderProps {
templates: PolicyTemplate[];
adapter?: StorageAdapter<PrivacyPolicy>;
storageKey?: string;
useLocalStorage?: boolean;
initialPolicy?: PrivacyPolicy;
onGenerate?: (policy: PrivacyPolicy) => void;
children: React__default.ReactNode;
}
/**
* Privacy policy types aligned with NDPA 2023
* Privacy policies must clearly inform data subjects of their rights under the NDPA
*/
/**
* Represents a section in a privacy policy
*/
export declare interface PolicySection {
/** Unique identifier for the section */
id: string;
/** Title of the section */
title: string;
/** Description of the section */
description?: string;
/** Order of the section in the policy */
order?: number;
/** Whether the section is required by NDPA */
required: boolean;
/** Template text for the section */
template: string;
/**
* Default content for the section (legacy field)
* @deprecated Use template instead
*/
defaultContent?: string;
/**
* Custom content for the section (overrides default content)
* @deprecated Use template instead
*/
customContent?: string;
/** Whether the section is included in the policy */
included: boolean;
/** Variables that can be used in the section content */
variables?: string[];
}
/**
* Represents a privacy policy template
*/
export declare interface PolicyTemplate {
/** Unique identifier for the template */
id: string;
/** Name of the template */
name: string;
/** Description of the template */
description: string;
/** Type of organization the template is designed for */
organizationType: 'business' | 'nonprofit' | 'government' | 'educational';
/** Sections included in the template */
sections: PolicySection[];
/** Variables used across the template */
variables: Record<string, {
name: string;
description: string;
required: boolean;
defaultValue?: string;
}>;
/** Version of the template */
version: string;
/** Last updated date of the template */
lastUpdated: number;
/**
* Whether this template is NDPA 2023 compliant
*/
ndpaCompliant: boolean;
}
/**
* Represents a variable in a privacy policy
*/
export declare interface PolicyVariable {
/** Unique identifier for the variable */
id: string;
/** Name of the variable as it appears in the template */
name: string;
/** Description of the variable */
description: string;
/** Default value for the variable */
defaultValue?: string;
/** Current value of the variable */
value: string;
/** Type of input for the variable */
inputType: 'text' | 'textarea' | 'email' | 'url' | 'date' | 'select';
/** Options for select inputs */
options?: string[];
/** Whether the variable is required */
required: boolean;
}
/**
* Represents a generated privacy policy
*/
export declare interface PrivacyPolicy {
/** Unique identifier for the policy */
id: string;
/** Title of the policy */
title: string;
/** Template used to generate the policy */
templateId: string;
/** Organization information */
organizationInfo: OrganizationInfo;
/** Sections of the policy */
sections: PolicySection[];
/** Values for the variables used in the policy */
variableValues: Record<string, string>;
/** Effective date of the policy */
effectiveDate: number;
/** Last updated date of the policy */
lastUpdated: number;
/** Version of the policy */
version: string;
/**
* Applicable legal frameworks
*/
applicableFrameworks?: ('ndpa' | 'ndpr' | 'gdpr' | 'ccpa')[];
}
/** Lawful processing purposes recognised under the NDPA. */
export declare type ProcessingPurpose = 'service_delivery' | 'marketing' | 'analytics' | 'research' | 'legal_compliance' | 'fraud_prevention';
export declare interface StorageAdapter<T = unknown> {
/** Load persisted data. Called once on hook mount. */
load(): T | null | Promise<T | null>;
/** Persist data. Called on every state change. */
save(data: T): void | Promise<void>;
/** Clear persisted data. Called on reset. */
remove(): void | Promise<void>;
}
/** Full context used to generate an adaptive privacy policy. */
export declare interface TemplateContext {
/** Organisation details, extended with industry and size. */
org: OrganizationInfo & {
industry: Industry;
orgSize: OrgSize;
country: string;
};
/** Data categories the organisation collects. */
dataCategories: DataCategory[];
/** Processing purposes relevant to the organisation. */
purposes: ProcessingPurpose[];
/** Whether the organisation processes children's data. */
hasChildrenData: boolean;
/** Whether the organisation processes sensitive/special-category data. */
hasSensitiveData: boolean;
/** Whether the organisation processes financial data. */
hasFinancialData: boolean;
/** Whether data is transferred outside Nigeria. */
hasCrossBorderTransfer: boolean;
/** Whether automated decision-making or profiling is used. */
hasAutomatedDecisions: boolean;
/** Third-party processors that receive personal data. */
thirdPartyProcessors: ThirdPartyProcessor[];
}
/**
* Returns a fresh `TemplateContext` pre-filled for the given org type.
* Pass `overrides` to set organisation details (name, DPO, etc.) inline.
*
* Calling without arguments throws — pass a known template id.
*
* @example
* const ctx = templateContextFor('healthcare', {
* orgName: 'Lagos Heart Centre',
* dpoEmail: 'dpo@lhc.ng',
* });
*/
declare function templateContextFor(id: OrgPolicyTemplateId, overrides?: OrgPolicyTemplateOverrides): TemplateContext;
export { templateContextFor as createOrgTemplate }
export { templateContextFor }
/** A third-party entity that processes data on behalf of the organisation. */
export declare interface ThirdPartyProcessor {
/** Name of the third party. */
name: string;
/** Purpose of sharing data with this processor. */
purpose: string;
/** Country where the processor is located. */
country: string;
}
/**
* Multi-step privacy-policy authoring hook that adapts the generated draft
* to the supplied template context (industry, processing purposes, data
* categories, processors). Auto-persists a draft via the supplied adapter
* and surfaces a live compliance score against the configured rule set.
*
* @example
* ```tsx
* import { useAdaptivePolicyWizard } from '@tantainnovative/ndpr-toolkit/hooks';
*
* function PolicyWizard() {
* const { currentStep, nextStep, policy, complianceScore } = useAdaptivePolicyWizard();
* return (
* <div>
* <p>Step {currentStep} — compliance: {complianceScore}%</p>
* <button onClick={nextStep}>Next</button>
* {policy && <pre>{policy.title}</pre>}
* </div>
* );
* }
* ```
*/
export declare function useAdaptivePolicyWizard(options?: UseAdaptivePolicyWizardOptions): UseAdaptivePolicyWizardReturn;
export declare interface UseAdaptivePolicyWizardOptions {
adapter?: StorageAdapter<PolicyDraft>;
onComplete?: (policy: PrivacyPolicy) => void;
onComplianceChange?: (score: number, gaps: ComplianceGap[]) => void;
/**
* Initial template context. Use an org-template factory like
* `templateContextFor('healthcare')` to start the wizard with a sector-
* specific pre-fill (lawful basis, data categories, sensitive-data flag,
* cross-border default). Defaults to `createDefaultContext()` if omitted.
*
* If an adapter loads a saved draft, the draft's context wins — the
* `initialContext` only seeds the very first session.
*/
initialContext?: TemplateContext;
}
export declare interface UseAdaptivePolicyWizardReturn {
currentStep: number;
goToStep: (step: number) => void;
nextStep: () => void;
prevStep: () => void;
canProceed: boolean;
context: TemplateContext;
updateContext: (updates: Partial<TemplateContext>) => void;
updateOrg: (updates: Partial<TemplateContext['org']>) => void;
toggleDataCategory: (categoryId: string) => void;
togglePurpose: (purpose: string) => void;
addProcessor: (processor: {
name: string;
purpose: string;
country: string;
}) => void;
removeProcessor: (index: number) => void;
policy: PrivacyPolicy | null;
sections: PolicySection[];
customSections: CustomSection[];
addCustomSection: (section: Omit<CustomSection, 'id' | 'required'>) => void;
updateCustomSection: (id: string, updates: Partial<CustomSection>) => void;
removeCustomSection: (id: string) => void;
reorderSections: (sectionId: string, direction: 'up' | 'down') => void;
editSectionContent: (sectionId: string, content: string) => void;
sectionOverrides: Record<string, string>;
complianceScore: number;
complianceResult: ComplianceResult;
complianceGaps: ComplianceGap[];
applyFix: (gapId: string) => void;
handleExportPDF: (options?: PDFExportOptions) => Promise<Blob>;
handleExportDOCX: (options?: DOCXExportOptions) => Promise<Blob>;
handleExportHTML: (options?: HTMLExportOptions) => string;
handleExportMarkdown: () => string;
isDraftSaved: boolean;
lastSavedAt: number | null;
saveDraft: () => Promise<void>;
discardDraft: () => void;
isLoading: boolean;
}
/**
* Convenience wrapper around `usePrivacyPolicy`. With `orgInfo` provided
* and `autoGenerate` enabled (default), `policy` is non-null on the first
* post-load render — no manual `selectTemplate` / `generatePolicy` chaining
* required.
*
* @example
* ```tsx
* const { policy } = useDefaultPrivacyPolicy({
* orgInfo: { name: 'Acme Ltd', email: 'privacy@acme.ng' }
* });
* return policy ? <PolicyPage policy={policy} /> : <Spinner />;
* ```
*/
export declare function useDefaultPrivacyPolicy(options?: UseDefaultPrivacyPolicyOptions): UsePrivacyPolicyReturn;
declare interface UseDefaultPrivacyPolicyOptions {
/**
* Organisation information to pre-fill into the policy. When provided and
* `autoGenerate` is true (the default), the hook will auto-select the
* default template and generate a renderable policy on first commit, so
* `policy` is non-null on the first useful render.
*/
orgInfo?: {
/** Organisation name (maps to `organizationInfo.name` and `orgName` variable) */
name?: string;
/** Privacy contact email (maps to `privacyEmail`) */
email?: string;
/** Organisation website URL */
website?: string;
/** Physical address */
address?: string;
/** Industry / sector descriptor */
industry?: string;
/** Data Protection Officer name */
dpoName?: string;
/** DPO email address */
dpoEmail?: string;
};
/**
* Whether the hook should auto-select the default template and generate
* the policy as soon as it's mounted with `orgInfo`. Set to false to
* retain manual control via `selectTemplate` / `generatePolicy`.
* @default true
*/
autoGenerate?: boolean;
/**
* Storage key for policy data.
* @default "ndpr_privacy_policy"
*/
storageKey?: string;
/**
* Whether to persist policy data in storage. When `false`, the hook
* uses an in-memory no-op adapter and nothing survives a page reload.
* @default true
*/
persist?: boolean;
/**
* @deprecated Renamed to `persist` in v3.5.0 — `useLocalStorage` is
* still accepted for backward compatibility and will be removed in
* v4.0. Use `persist` (or pass an explicit `adapter`) instead.
* @default true
*/
useLocalStorage?: boolean;
/**
* Pluggable storage adapter. When provided, takes precedence over
* storageKey/persist/useLocalStorage.
*/
adapter?: StorageAdapter<PrivacyPolicy>;
}
export declare function usePolicyCompound(): PolicyContextValue;
/**
* Hook for generating NDPA-compliant privacy policies.
*
* @example
* ```tsx
* import { usePrivacyPolicy } from '@tantainnovative/ndpr-toolkit/hooks';
*
* function PolicyBuilder({ templates }) {
* const { policy, selectTemplate, generatePolicy } = usePrivacyPolicy({ templates });
* return (
* <div>
* <button onClick={() => selectTemplate(templates[0].id)}>Select default</button>
* <button onClick={generatePolicy}>Generate</button>
* {policy && <pre>{policy.title}</pre>}
* </div>
* );
* }
* ```
*/
export declare function usePrivacyPolicy({ templates, initialPolicy, adapter, storageKey, persist, useLocalStorage, onGenerate, }: UsePrivacyPolicyOptions): UsePrivacyPolicyReturn;
declare interface UsePrivacyPolicyOptions {
/**
* Available policy templates
*/
templates: PolicyTemplate[];
/**
* Initial policy data (if editing an existing policy)
*/
initialPolicy?: PrivacyPolicy;
/**
* Pluggable storage adapter. When provided, takes precedence over storageKey/useLocalStorage.
*/
adapter?: StorageAdapter<PrivacyPolicy>;
/**
* Storage key for policy data
* @default "ndpr_privacy_policy"
* @deprecated Use adapter instead
*/
storageKey?: string;
/**
* Whether to persist policy data in storage. When `false`, the hook
* uses an in-memory no-op adapter and nothing survives a page reload.
* Prefer `adapter` for richer control (custom backends, async APIs).
*
* @default true
*/
persist?: boolean;
/**
* @deprecated Renamed to `persist` in v3.5.0 — `useLocalStorage` is
* still accepted for backward compatibility and will be removed in
* v4.0. Use `persist` (or pass an explicit `adapter`) instead.
* @default true
*/
useLocalStorage?: boolean;
/**
* Callback function called when a policy is generated
*/
onGenerate?: (policy: PrivacyPolicy) => void;
}
declare interface UsePrivacyPolicyReturn {
/**
* Current policy data
*/
policy: PrivacyPolicy | null;
/**
* Selected template
*/
selectedTemplate: PolicyTemplate | null;
/**
* Organization information
*/
organizationInfo: OrganizationInfo;
/**
* Select a template
*/
selectTemplate: (templateId: string) => boolean;
/**
* Update organization information
*/
updateOrganizationInfo: (updates: Partial<OrganizationInfo>) => void;
/**
* Toggle whether a section is included in the policy
*/
toggleSection: (sectionId: string, included: boolean) => void;
/**
* Update section content
*/
updateSectionContent: (sectionId: string, content: string) => void;
/**
* Update variable values
*/
updateVariableValue: (variable: string, value: string) => void;
/**
* Generate the policy
*/
generatePolicy: () => PrivacyPolicy | null;
/**
* Get the generated policy text
*/
getPolicyText: () => {
fullText: string;
sectionTexts: Record<string, string>;
missingVariables: string[];
};
/**
* Reset the policy
*/
resetPolicy: () => void;
/**
* Check if the policy is valid
*/
isValid: () => {
valid: boolean;
errors: string[];
};
/**
* Whether the adapter is still loading data (relevant for async adapters)
*/
isLoading: boolean;
}
export { }