{"_id":"@bluprynt/forms-viewer","_rev":"6-9df46d22ec85501ec554a957b5d9d024","name":"@bluprynt/forms-viewer","dist-tags":{"latest":"4.1.0"},"versions":{"1.0.0":{"name":"@bluprynt/forms-viewer","version":"1.0.0","_id":"@bluprynt/forms-viewer@1.0.0","maintainers":[{"name":"ivanzotov","email":"ivanzotov@gmail.com"},{"name":"sergeyzbp","email":"sergeyz@bluprynt.com"}],"homepage":"https://blupryntco.github.io/forms-engine/","bugs":{"url":"https://github.com/blupryntco/forms-engine/issues"},"dist":{"shasum":"434f14bf0ef81be65136c56c4c1e358c036af487","tarball":"https://registry.npmjs.org/@bluprynt/forms-viewer/-/forms-viewer-1.0.0.tgz","fileCount":9,"integrity":"sha512-F6/FGErFweScxAvzvIP1UcZG6bGFJFzHvtM0wbbOtMFFILzyr5ki0DtPDlKwmEdtfX1ZesdOanN/80Lpt1xuaw==","signatures":[{"sig":"MEYCIQC/WOpGWDFEA5hzdOfaDcqSAIeYLpSRFswFhoT2yUlZPwIhAMC7KXkfk2gP0FHsBF1pco/5uVGLF52HW4fXFZjrpcw1","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":104901},"main":"./dist/index.cjs","_from":"file:bluprynt-forms-viewer-1.0.0.tgz","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.cjs"}},"scripts":{"dev":"tsdown --watch","lint":"biome check .","test":"jest","build":"tsdown","test:cov":"jest --coverage","test:watch":"jest --watch","check-types":"tsc --noEmit"},"_npmUser":{"name":"sergeyzbp","email":"sergeyz@bluprynt.com"},"_resolved":"/tmp/5063109e2129c0dc2ef585e6f7f99320/bluprynt-forms-viewer-1.0.0.tgz","_integrity":"sha512-F6/FGErFweScxAvzvIP1UcZG6bGFJFzHvtM0wbbOtMFFILzyr5ki0DtPDlKwmEdtfX1ZesdOanN/80Lpt1xuaw==","repository":{"url":"git+https://github.com/blupryntco/forms-engine.git","type":"git","directory":"packages/viewer"},"_npmVersion":"11.9.0","description":"Headless React components for rendering and editing JSON-driven dynamic forms. Pairs with `@bluprynt/forms-core` to handle visibility, validation, and section navigation — you supply the UI components, the viewer wires everything together.","directories":{},"sideEffects":false,"_nodeVersion":"24.14.0","_hasShrinkwrap":false,"devDependencies":{"jest":"29.7.0","react":"19.1.0","tsdown":"0.21.1","ts-jest":"29.4.6","react-dom":"19.1.0","typescript":"5.9.3","@types/jest":"29.5.14","@types/react":"19.1.8","@types/react-dom":"19.1.6","@bluprynt/forms-core":"1.0.0","@testing-library/react":"16.3.2","jest-environment-jsdom":"30.3.0","@repo/typescript-config":"0.0.0"},"peerDependencies":{"react":"^18.0.0 || ^19.0.0","react-dom":"^18.0.0 || ^19.0.0","@bluprynt/forms-core":"1.0.0"},"_npmOperationalInternal":{"tmp":"tmp/forms-viewer_1.0.0_1774003253764_0.17677279684553615","host":"s3://npm-registry-packages-npm-production"}},"2.0.0":{"name":"@bluprynt/forms-viewer","version":"2.0.0","_id":"@bluprynt/forms-viewer@2.0.0","maintainers":[{"name":"ivanzotov","email":"ivanzotov@gmail.com"},{"name":"sergeyzbp","email":"sergeyz@bluprynt.com"}],"homepage":"https://blupryntco.github.io/forms-engine/","bugs":{"url":"https://github.com/blupryntco/forms-engine/issues"},"dist":{"shasum":"b08df8e6d42b719bbefd45af08810d00f5194e1e","tarball":"https://registry.npmjs.org/@bluprynt/forms-viewer/-/forms-viewer-2.0.0.tgz","fileCount":9,"integrity":"sha512-qjsQDu4cESbDtj+sm2UP2V7VSclWsHcMhmZGsZw9UXyxIJ+xtKljYSZi0P9jIs/XBE3/gvolaeX6cBelKReMHg==","signatures":[{"sig":"MEYCIQDYycn0sZg0izcuXUlRsJf5kFvlWa5n6LIJ+5WDHAGh9AIhALOd8J1wB/hXnmbgJJEu+qKLPdEZzE55a6gBFwV+sW9K","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":106763},"main":"./dist/index.cjs","_from":"file:bluprynt-forms-viewer-2.0.0.tgz","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.cjs"}},"scripts":{"dev":"tsdown --watch","lint":"biome check .","test":"jest","build":"tsdown","test:cov":"jest --coverage","test:watch":"jest --watch","check-types":"tsc --noEmit"},"_npmUser":{"name":"sergeyzbp","email":"sergeyz@bluprynt.com"},"_resolved":"/tmp/2d8fbf6e3b848f1b45b2d81d3f0f4f28/bluprynt-forms-viewer-2.0.0.tgz","_integrity":"sha512-qjsQDu4cESbDtj+sm2UP2V7VSclWsHcMhmZGsZw9UXyxIJ+xtKljYSZi0P9jIs/XBE3/gvolaeX6cBelKReMHg==","repository":{"url":"git+https://github.com/blupryntco/forms-engine.git","type":"git","directory":"packages/viewer"},"_npmVersion":"11.9.0","description":"Headless React components for rendering and editing JSON-driven dynamic forms. Pairs with `@bluprynt/forms-core` to handle visibility, validation, and section navigation — you supply the UI components, the viewer wires everything together.","directories":{},"sideEffects":false,"_nodeVersion":"24.14.0","_hasShrinkwrap":false,"devDependencies":{"jest":"29.7.0","react":"19.1.0","tsdown":"0.21.1","ts-jest":"29.4.6","react-dom":"19.1.0","typescript":"5.9.3","@types/jest":"29.5.14","@types/react":"19.1.8","@types/react-dom":"19.1.6","@bluprynt/forms-core":"2.0.0","@testing-library/react":"16.3.2","jest-environment-jsdom":"30.3.0","@repo/typescript-config":"0.0.0"},"peerDependencies":{"react":"^18.0.0 || ^19.0.0","react-dom":"^18.0.0 || ^19.0.0","@bluprynt/forms-core":"2.0.0"},"_npmOperationalInternal":{"tmp":"tmp/forms-viewer_2.0.0_1774354272481_0.23830491181277247","host":"s3://npm-registry-packages-npm-production"}},"3.0.0":{"name":"@bluprynt/forms-viewer","version":"3.0.0","_id":"@bluprynt/forms-viewer@3.0.0","maintainers":[{"name":"ivanzotov","email":"ivanzotov@gmail.com"},{"name":"sergeyzbp","email":"sergeyz@bluprynt.com"}],"homepage":"https://blupryntco.github.io/forms-engine/","bugs":{"url":"https://github.com/blupryntco/forms-engine/issues"},"dist":{"shasum":"efd6be03029be9434cb8d8ed15aa594dc9865682","tarball":"https://registry.npmjs.org/@bluprynt/forms-viewer/-/forms-viewer-3.0.0.tgz","fileCount":9,"integrity":"sha512-73dzH/Lt/lT1yxFJXCEmHy252I2VbvIydudguMSwzxuvNQWHI7i7f2B8ROvXCkXKvOEO7rugF31l6Jbp2W1Gpg==","signatures":[{"sig":"MEQCID0yKmzqA0rL1oSTHlb8joCC+p9ZhsBmEyOsgagGbLt0AiBbxcsl2LICsshq+WK+iBqtXvh7+tNYCB8WPTp3Y2jtTA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":109255},"main":"./dist/index.cjs","_from":"file:bluprynt-forms-viewer-3.0.0.tgz","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.cjs"}},"scripts":{"dev":"tsdown --watch","lint":"biome check .","test":"jest","build":"tsdown","test:cov":"jest --coverage","test:watch":"jest --watch","check-types":"tsc --noEmit"},"_npmUser":{"name":"sergeyzbp","email":"sergeyz@bluprynt.com"},"_resolved":"/tmp/834ca31c2d4c29f54d9e2f23f3d93d07/bluprynt-forms-viewer-3.0.0.tgz","_integrity":"sha512-73dzH/Lt/lT1yxFJXCEmHy252I2VbvIydudguMSwzxuvNQWHI7i7f2B8ROvXCkXKvOEO7rugF31l6Jbp2W1Gpg==","repository":{"url":"git+https://github.com/blupryntco/forms-engine.git","type":"git","directory":"packages/viewer"},"_npmVersion":"11.9.0","description":"Headless React components for rendering and editing JSON-driven dynamic forms. Pairs with `@bluprynt/forms-core` to handle visibility, validation, and section navigation — you supply the UI components, the viewer wires everything together.","directories":{},"sideEffects":false,"_nodeVersion":"24.14.0","_hasShrinkwrap":false,"devDependencies":{"jest":"29.7.0","react":"19.1.0","tsdown":"0.21.1","ts-jest":"29.4.6","react-dom":"19.1.0","typescript":"5.9.3","@types/jest":"29.5.14","@types/react":"19.1.8","@types/react-dom":"19.1.6","@bluprynt/forms-core":"3.0.0","@testing-library/react":"16.3.2","jest-environment-jsdom":"30.3.0","@repo/typescript-config":"0.0.0"},"peerDependencies":{"react":"^18.0.0 || ^19.0.0","react-dom":"^18.0.0 || ^19.0.0","@bluprynt/forms-core":"3.0.0"},"_npmOperationalInternal":{"tmp":"tmp/forms-viewer_3.0.0_1774356360474_0.06998996837213256","host":"s3://npm-registry-packages-npm-production"}},"4.0.1":{"name":"@bluprynt/forms-viewer","version":"4.0.1","_id":"@bluprynt/forms-viewer@4.0.1","maintainers":[{"name":"ivanzotov","email":"ivanzotov@gmail.com"},{"name":"sergeyzbp","email":"sergeyz@bluprynt.com"}],"homepage":"https://blupryntco.github.io/forms-engine/","bugs":{"url":"https://github.com/blupryntco/forms-engine/issues"},"dist":{"shasum":"0a3b9259da500882d31b550c0e5d57f38aebf427","tarball":"https://registry.npmjs.org/@bluprynt/forms-viewer/-/forms-viewer-4.0.1.tgz","fileCount":9,"integrity":"sha512-pRMLxRRB0th6R9bVfx4TqBm1FagWC8+lr8MgpeKZcpa8s3Cj6FUzbYwOazKob+9123L7VzTR87LMWfFE7GrKjA==","signatures":[{"sig":"MEUCIGnSONjohIYg5oGaHA9NO8HnUzhB+SPfmWNtc2n5y3D0AiEA1JH+ZrkisKZeDQ96ygNy/3bH/gE+RBO8DhukH2jI5kQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":109256},"main":"./dist/index.cjs","_from":"file:bluprynt-forms-viewer-4.0.1.tgz","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.cjs"}},"scripts":{"dev":"tsdown --watch","lint":"biome check .","test":"jest","build":"tsdown","test:cov":"jest --coverage","test:watch":"jest --watch","check-types":"tsc --noEmit"},"_npmUser":{"name":"sergeyzbp","email":"sergeyz@bluprynt.com"},"_resolved":"/tmp/9a6da3a461d2d0bb71ef312d60cc408b/bluprynt-forms-viewer-4.0.1.tgz","_integrity":"sha512-pRMLxRRB0th6R9bVfx4TqBm1FagWC8+lr8MgpeKZcpa8s3Cj6FUzbYwOazKob+9123L7VzTR87LMWfFE7GrKjA==","repository":{"url":"git+https://github.com/blupryntco/forms-engine.git","type":"git","directory":"packages/viewer"},"_npmVersion":"11.13.0","description":"Headless React components for rendering and editing JSON-driven dynamic forms. Pairs with `@bluprynt/forms-core` to handle visibility, validation, and section navigation — you supply the UI components, the viewer wires everything together.","directories":{},"sideEffects":false,"_nodeVersion":"24.17.0","_hasShrinkwrap":false,"devDependencies":{"jest":"29.7.0","react":"19.1.0","tsdown":"0.21.1","ts-jest":"29.4.6","react-dom":"19.1.0","typescript":"5.9.3","@types/jest":"29.5.14","@types/react":"19.1.8","@types/react-dom":"19.1.6","@bluprynt/forms-core":"4.0.1","@testing-library/react":"16.3.2","jest-environment-jsdom":"30.3.0","@repo/typescript-config":"0.0.0"},"peerDependencies":{"react":"^18.0.0 || ^19.0.0","react-dom":"^18.0.0 || ^19.0.0","@bluprynt/forms-core":"^4.0.1"},"_npmOperationalInternal":{"tmp":"tmp/forms-viewer_4.0.1_1782736192993_0.6036537774872315","host":"s3://npm-registry-packages-npm-production"}},"4.1.0":{"_id":"@bluprynt/forms-viewer@4.1.0","bugs":{"url":"https://github.com/blupryntco/forms-engine/issues"},"dist":{"shasum":"d1bb056c7a2ad3ac581436e22fab81b64880f316","tarball":"https://registry.npmjs.org/@bluprynt/forms-viewer/-/forms-viewer-4.1.0.tgz","fileCount":9,"integrity":"sha512-F8zCmLdNIpi+Lk455wvROaKNf8tI6ZWjaGKHV9Ip++VjqE/r83WRvoYviy6n8X6yOomIpyRi5y4bcq1foUVw1g==","signatures":[{"sig":"MEUCIAjC2sgeKxuvSNMGUNgT2GXS78yQ0w5jMJ8ogOdNjZmHAiEAoMclyijRh6NrSVXWJ+d8A2a4atlzdt8bFsutbXaexuU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDcQPmb5QtQBOlvreAJMKphqaTGvPDaZh74fDvd9GkdfAIgK0GpLjnELzgeiYohmAL8A46qjj5YfJpVgosRtiXQ1pk="}],"unpackedSize":160228},"main":"./dist/index.cjs","name":"@bluprynt/forms-viewer","_from":"file:bluprynt-forms-viewer-4.1.0.tgz","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.cjs"}},"scripts":{"dev":"tsdown --watch","lint":"biome check .","test":"jest","build":"tsdown","test:cov":"jest --coverage","test:watch":"jest --watch","check-types":"tsc --noEmit"},"version":"4.1.0","_npmUser":{"name":"sergeyzbp","email":"sergeyz@bluprynt.com"},"homepage":"https://blupryntco.github.io/forms-engine/","_resolved":"/tmp/4ba4dee8d35066bb6de9aa1e4a066954/bluprynt-forms-viewer-4.1.0.tgz","_integrity":"sha512-F8zCmLdNIpi+Lk455wvROaKNf8tI6ZWjaGKHV9Ip++VjqE/r83WRvoYviy6n8X6yOomIpyRi5y4bcq1foUVw1g==","repository":{"url":"git+https://github.com/blupryntco/forms-engine.git","type":"git","directory":"packages/viewer"},"_npmVersion":"11.19.0","description":"Headless React components for rendering and editing JSON-driven dynamic forms. Pairs with `@bluprynt/forms-core` to handle visibility, validation, and section navigation — you supply the UI components, the viewer wires everything together.","directories":{},"maintainers":[{"name":"ivanzotov","email":"ivanzotov@gmail.com"},{"name":"sergeyzbp","email":"sergeyz@bluprynt.com"},{"name":"igor-hoodies","email":"igor@hoodies.team"}],"sideEffects":false,"_nodeVersion":"24.20.0","_hasShrinkwrap":false,"devDependencies":{"jest":"29.7.0","react":"19.1.0","tsdown":"0.21.1","ts-jest":"29.4.6","react-dom":"19.1.0","typescript":"5.9.3","@types/jest":"29.5.14","@types/react":"19.1.8","@types/react-dom":"19.1.6","@bluprynt/forms-core":"4.1.0","@testing-library/react":"16.3.2","jest-environment-jsdom":"30.3.0","@repo/typescript-config":"0.0.0"},"peerDependencies":{"react":"^18.0.0 || ^19.0.0","react-dom":"^18.0.0 || ^19.0.0","@bluprynt/forms-core":"^4.1.0"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/forms-viewer_4.1.0_1790091416724_0.046166704493971755"}}},"time":{"created":"2026-03-20T10:40:53.646Z","modified":"2026-09-22T15:36:57.009Z","1.0.0":"2026-03-20T10:40:53.923Z","2.0.0":"2026-03-24T12:11:12.699Z","3.0.0":"2026-03-24T12:46:00.650Z","4.0.1":"2026-06-29T12:29:53.151Z","4.1.0":"2026-09-22T15:36:56.829Z"},"bugs":{"url":"https://github.com/blupryntco/forms-engine/issues"},"homepage":"https://blupryntco.github.io/forms-engine/","repository":{"url":"git+https://github.com/blupryntco/forms-engine.git","type":"git","directory":"packages/viewer"},"description":"Headless React components for rendering and editing JSON-driven dynamic forms. Pairs with `@bluprynt/forms-core` to handle visibility, validation, and section navigation — you supply the UI components, the viewer wires everything together.","maintainers":[{"name":"ivanzotov","email":"ivanzotov@gmail.com"},{"name":"sergeyzbp","email":"sergeyz@bluprynt.com"},{"name":"igor-hoodies","email":"igor@hoodies.team"}],"readme":"# @bluprynt/forms-viewer\n\nHeadless React components for rendering and editing JSON-driven dynamic forms. Pairs with `@bluprynt/forms-core` to handle visibility, validation, and section navigation — you supply the UI components, the viewer wires everything together.\n\n## Key Capabilities\n\n- **Read-only rendering** — `FormViewer` renders a form from a definition and document using your custom view components, with automatic visibility and validation display.\n- **Editable forms** — `FormEditor` renders an editable form with per-field `onChange` handlers, array and array-of-rows item manipulation (add, remove, move), and live re-validation on every change.\n- **Section navigation** — `FormSections` enumerates visible top-level sections (including a synthetic root for ungrouped fields) and tracks the active section.\n- **Validation display** — `FormFieldsValidation` groups field-level errors by field; `FormDocumentValidation` renders document-level errors (schema mismatch, missing `submittedAt`, etc.).\n- **Headless architecture** — all rendering is delegated to component maps you provide (`ViewerComponentMap`, `EditorComponentMap`), so the package has zero UI opinions.\n\n## Installation\n\n```bash\nnpm install @bluprynt/forms-viewer @bluprynt/forms-core ajv react react-dom\n```\n\n`@bluprynt/forms-core`, `react`, and `react-dom` are peer dependencies and must be installed in your project.\n\n## Quick Start\n\n### Setting Up the Form Provider\n\nThe `Form` component compiles the definition, computes visibility, runs validation, and exposes everything via context.\n\n```tsx\nimport type { FC } from 'react'\nimport { Form } from '@bluprynt/forms-viewer'\nimport type { FormDefinition, FormDocument } from '@bluprynt/forms-viewer'\n\nconst definition: FormDefinition = { /* ... */ }\nconst document: FormDocument = { /* ... */ }\n\nconst App: FC = () => {\n  return (\n    <Form definition={definition} data={document}>\n      {/* FormViewer, FormEditor, FormSections, etc. */}\n    </Form>\n  )\n}\n```\n\n`Form` props:\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `definition` | `FormDefinition` | — | The form schema |\n| `data` | `FormDocument` | — | The form values document |\n| `section` | `ROOT \\| number` | — | Active section id (use `ROOT` for ungrouped fields) |\n| `showInlineValidation` | `boolean` | `true` | Whether field components receive validation errors |\n| `children` | `ReactNode` | — | Child components |\n\n### Using FormViewer (Read-Only)\n\nUse `FormViewer` when you only need to display submitted form values without editing. It renders each field through your component map in a read-only mode, applying visibility rules and showing validation state.\n\n```tsx\nimport type { FC } from 'react'\nimport { Form, FormViewer } from '@bluprynt/forms-viewer'\nimport type { ViewerComponentMap } from '@bluprynt/forms-viewer'\n\nconst components: ViewerComponentMap = {\n  string: ({ field, value }) => <p>{field.label}: {value}</p>,\n  number: ({ field, value }) => <p>{field.label}: {value}</p>,\n  boolean: ({ field, value }) => <p>{field.label}: {value ? 'Yes' : 'No'}</p>,\n  date: ({ field, value }) => <p>{field.label}: {value}</p>,\n  select: ({ field, value, options }) => (\n    <p>{field.label}: {options.find(o => o.value === value)?.label}</p>\n  ),\n  array: ({ field, children }) => <div>{field.label}: {children}</div>,\n  file: ({ field, value }) => <p>{field.label}: {value?.name}</p>,\n  section: ({ section, children }) => (\n    <fieldset>\n      <legend>{section.title}</legend>\n      {children}\n    </fieldset>\n  ),\n}\n\nconst ReadOnlyForm: FC = () => {\n  return (\n    <Form definition={definition} data={document}>\n      <FormViewer components={components} />\n    </Form>\n  )\n}\n```\n\n### Using FormEditor (Editable)\n\nUse `FormEditor` when users need to fill in or edit a form. It provides per-field `onChange` handlers and fires a callback on every change with the updated `FormDocument` JSON and current validation result.\n\n```tsx\nimport { useState, type FC } from 'react'\nimport { Form, FormEditor } from '@bluprynt/forms-viewer'\nimport type { EditorComponentMap, FormDocument, FormValidationResult } from '@bluprynt/forms-viewer'\n\nconst components: EditorComponentMap = {\n  string: ({ field, value, onChange }) => (\n    <input value={value ?? ''} onChange={e => onChange(e.target.value)} />\n  ),\n  number: ({ field, value, onChange }) => (\n    <input type=\"number\" value={value ?? ''} onChange={e => onChange(Number(e.target.value))} />\n  ),\n  boolean: ({ field, value, onChange }) => (\n    <input type=\"checkbox\" checked={value ?? false} onChange={e => onChange(e.target.checked)} />\n  ),\n  date: ({ field, value, onChange }) => (\n    <input type=\"date\" value={value ?? ''} onChange={e => onChange(e.target.value)} />\n  ),\n  select: ({ field, value, options, onChange }) => (\n    <select value={value ?? ''} onChange={e => onChange(e.target.value)}>\n      {options.map(o => <option key={o.value} value={o.value}>{o.label}</option>)}\n    </select>\n  ),\n  array: ({ field, children, onAddItem }) => (\n    <div>\n      {children}\n      <button onClick={onAddItem}>Add item</button>\n    </div>\n  ),\n  file: ({ field, value, onChange }) => (\n    <input type=\"file\" onChange={e => { /* handle file */ }} />\n  ),\n  section: ({ section, children }) => (\n    <fieldset>\n      <legend>{section.title}</legend>\n      {children}\n    </fieldset>\n  ),\n}\n\nconst EditableForm: FC = () => {\n  const [data, setData] = useState<FormDocument>(initialDocument)\n\n  const handleChange = (doc: FormDocument, validation: FormValidationResult) => {\n    setData(doc)\n    // validation.valid, validation.fieldErrors, etc.\n  }\n\n  return (\n    <Form definition={definition} data={data}>\n      <FormEditor components={components} onChange={handleChange} />\n    </Form>\n  )\n}\n```\n\n### Using FormSections for Navigation\n\nUse `FormSections` to render form sections as tabs, a sidebar menu, or any other navigation UI and let users switch between them. It enumerates visible top-level sections and tracks the active one.\n\n```tsx\nimport { useState, type FC } from 'react'\nimport { Form, FormViewer, FormSections, ROOT } from '@bluprynt/forms-viewer'\n\nconst FormWithSections: FC = () => {\n  const [activeSection, setActiveSection] = useState<typeof ROOT | number>(ROOT)\n\n  return (\n    <Form definition={definition} data={document} section={activeSection}>\n      <FormSections\n        container={({ children }) => <nav>{children}</nav>}\n        item={({ section, active, select }) => (\n          <button onClick={select} style={{ fontWeight: active ? 'bold' : 'normal' }}>\n            {section.title}\n          </button>\n        )}\n        defaultSectionTitle=\"General\"\n        onSelect={setActiveSection}\n      />\n      <FormViewer components={viewerComponents} />\n    </Form>\n  )\n}\n```\n\n### Using FormFieldsValidation and FormDocumentValidation\n\nUse `FormDocumentValidation` to display document-level errors — schema mismatch, invalid version, missing `submittedAt`, and similar structural issues. Use `FormFieldsValidation` to display field-level errors — values that don't match validation rules defined in the form (required, min/max, pattern, etc.).\n\n```tsx\nimport type { FC } from 'react'\nimport { Form, FormFieldsValidation, FormDocumentValidation } from '@bluprynt/forms-viewer'\n\nconst ValidationSummary: FC = () => {\n  return (\n    <Form definition={definition} data={document}>\n      <FormDocumentValidation\n        container={({ children }) => <div className=\"doc-errors\">{children}</div>}\n        error={({ code, message }) => <p>{message} ({code})</p>}\n      />\n      <FormFieldsValidation\n        container={({ children }) => <div className=\"field-errors\">{children}</div>}\n        field={({ field, errors, children }) => (\n          <div>\n            <strong>{field?.label}</strong>\n            {children}\n          </div>\n        )}\n        error={({ message, rule }) => <p>{message} [{rule}]</p>}\n      />\n    </Form>\n  )\n}\n```\n\n## Component Map Types\n\n### ViewerComponentMap\n\nComponent map for read-only rendering. Each key maps a field type to a React component.\n\n| Key | Props Type | Description |\n|-----|-----------|-------------|\n| `string` | `StringViewProps` | Text field display |\n| `number` | `NumberViewProps` | Numeric field display |\n| `boolean` | `BooleanViewProps` | Boolean field display |\n| `date` | `DateViewProps` | Date field display |\n| `select` | `SelectViewProps` | Select field display (receives `options`) |\n| `array` | `ArrayViewProps` | Array field display (receives `children` for items, `itemDef`) |\n| `array_obj?` | `ArrayObjViewProps` | Array-of-rows display. Receives `itemsDef`, the resolved `kind` (`'list'` \\| `'table'`) and `children: ReactNode[][]`, indexed `children[row][subField]` and aligned with `itemsDef`. |\n| `file` | `FileViewProps` | File field display |\n| `section` | `SectionViewProps` | Section wrapper (receives `children`) |\n| `multiselect?` | `MultiselectViewProps` | Multi-select display. Value is `(string \\| number)[]`; receives `options`. |\n| `static?` | `StaticViewProps` | Display-only text block. Receives **only** `field` — no `value`, `errors` or `suggestion`. |\n| `blockchain?` | `BlockchainViewProps` | CAIP address display. Value is a `string`, stored verbatim. |\n| `sustainability?` | `SustainabilityViewProps` | Sustainability references display. Value is `{ address, ccri?, cmc? }`. |\n| `error?` | `ErrorProps` | Optional inline error renderer |\n\nAll view field props extend `BaseViewFieldProps` which provides `field: FieldContentItem` and `errors: FieldValidationError[]`. `StaticViewProps` is the exception: it carries only `field: StaticFieldContentItem`, whose `text` is the content and whose `label` is an optional heading.\n\n`array_obj`, `multiselect`, `static`, `blockchain` and `sustainability` are **optional** keys, so existing maps keep compiling. A field whose component is not supplied renders nothing rather than throwing.\n\n### EditorComponentMap\n\nComponent map for editable rendering. Extends view props with mutation callbacks.\n\n| Key | Props Type | Description |\n|-----|-----------|-------------|\n| `string` | `StringEditProps` | Text input with `onChange(value)` |\n| `number` | `NumberEditProps` | Numeric input with `onChange(value)` |\n| `boolean` | `BooleanEditProps` | Boolean input with `onChange(value)` |\n| `date` | `DateEditProps` | Date input with `onChange(value)` |\n| `select` | `SelectEditProps` | Select input with `onChange(value)` and `options` |\n| `array` | `ArrayEditProps` | Array editor with `onAddItem`, `onRemoveItem(index)`, `onMoveItem(from, to)` |\n| `array_obj?` | `ArrayObjEditProps` | Array-of-rows editor with the same three row handlers. `onAddItem` appends an empty row; the per-cell `onChange` reaches each sub-field component. |\n| `file` | `FileEditProps` | File input with `onChange(value)` |\n| `section` | `SectionEditProps` | Section wrapper (receives `children`) |\n| `multiselect?` | `MultiselectEditProps` | Checkbox group. `onChange((string \\| number)[] \\| undefined)` — send the whole array. |\n| `static?` | `StaticEditProps` | Display-only text block. Identical to `StaticViewProps`; there is nothing to edit. |\n| `blockchain?` | `BlockchainEditProps` | Text input with `onChange(value)`. The CAIP format is never checked by the engine. |\n| `sustainability?` | `SustainabilityEditProps` | Object editor with `onChange(value)` — send the whole `{ address, ccri, cmc }`. Emit `undefined` when every part is blank. |\n| `error?` | `ErrorProps` | Optional inline error renderer |\n\nAll edit field props extend `BaseEditFieldProps`, which adds `onChange(value)` plus the optional\n`onAcceptSuggestion()` / `onRejectSuggestion()` handlers to the base view props. `StaticEditProps` does\nnot — a static block has no `onChange`, so the same component serves both maps.\n\nEvery field component — read-only and editable — also receives the field's authoring metadata on\n`field` (`description`, `placeholder`, `answer_guidelines`, `reference_id`) and an optional\n`suggestion` (`{ value, confidence, source }`) when the document carries one for that field. Accepting\ncopies the suggested value into the field's value and keeps the suggestion; rejecting removes the\nsuggestion and leaves the value alone. See [CHANGES.md](../../CHANGES.md).\n\n## Exported API\n\n| Export | Kind | Description |\n|--------|------|-------------|\n| `Form` | Component | Context provider — compiles definition, computes visibility and validation |\n| `useFormContext` | Hook | Access form context (definition, data, engine, visibility, validation) |\n| `FormViewer` | Component | Read-only form renderer |\n| `FormEditor` | Component | Editable form renderer with change callbacks |\n| `FormSections` | Component | Section navigation list |\n| `FormFieldsValidation` | Component | Field-level validation error display |\n| `FormDocumentValidation` | Component | Document-level validation error display |\n| `ROOT` | Symbol | Identifies the root (ungrouped fields) section |\n| `ViewerComponentMap` | Type | Component map for `FormViewer` |\n| `EditorComponentMap` | Type | Component map for `FormEditor` |\n| `BaseViewFieldProps` | Type | Base props for view field components |\n| `BaseEditFieldProps` | Type | Base props for edit field components |\n| `ErrorProps` | Type | Props for inline error components |\n| `FormSectionEntry` | Type | Section entry in `FormSections` |\n| `FormSectionItemProps` | Type | Props for section item renderer |\n| `FieldValidationFieldEntry` | Type | Field + errors group in `FormFieldsValidation` |\n| `FormValuesEditor` | Class | Fluent editor for reading and writing form values against a definition |\n| `DocumentError` | Class | Error representing a document-level validation failure |\n| `FormDefinition` | Type | JSON schema describing form structure, fields, sections, and rules |\n| `FormDocument` | Type | JSON document containing user-submitted form values and optional suggestions |\n| `FieldSuggestion` | Type | A machine-proposed answer: `{ value, confidence, source }` |\n| `FormSuggestions` | Type | Sparse map of suggestions keyed by stringified field id |\n| `FormValidationResult` | Type | Validation outcome with document-level and field-level errors |\n| `FieldType` | Type | Union of supported field types (`string`, `number`, `boolean`, `date`, `select`, `multiselect`, `array`, `array_obj`, `file`, `static`, `blockchain`, `sustainability`) |\n| `FileValue` | Type | File field value containing name, MIME type, size, and URL |\n| `SustainabilityValue` | Type | Sustainability field value: `{ address, ccri?, cmc? }` |\n\n## Documentation\n\n- [API Reference](docs/api-reference.md) — detailed description of all exported components, hooks, and types\n- [Architecture](docs/architecture.md) — internal design, data flow, and component structure\n- [Development Guide](docs/development-guide.md) — setup, testing, and contribution guidelines\n","readmeFilename":"README.md"}