@actuate-media/component-blocks
v0.2.1
Published
Extract a Manifest of React component props for use as type-aware CMS blocks.
Readme
@actuate-media/component-blocks
Turn your real React components into typed CMS blocks. This is the first slice of Actuate's "component-aware blocks" — a feature no other headless CMS does well.
What it does
You point this package at a directory of React components, it reads their TypeScript prop types, and emits a JSON manifest. The Actuate CMS uses that manifest to render the right admin form for each component, validate stored content against the real prop shape, and warn you when a content document references a component prop that no longer exists.
Install
pnpm add -D @actuate-media/component-blocksUsage
Programmatic
import { extractManifest } from '@actuate-media/component-blocks'
const manifest = extractManifest({
rootDir: './src/blocks',
filePattern: '**/*.tsx',
})
console.log(manifest.components.map((c) => c.name))
// → ['Hero', 'FeatureGrid', 'Testimonial']CLI
npx actuate-component-blocks extract \
--root ./src/blocks \
--out ./actuate-blocks.jsonWire up the CMS field
In your actuate.config.ts:
import manifest from './actuate-blocks.json' assert { type: 'json' }
export default {
collections: {
pages: {
fields: {
body: {
type: 'componentBlock',
label: 'Page content',
manifest,
// Optional: restrict which components editors can pick
allow: ['Hero', 'FeatureGrid'],
},
},
},
},
}What gets extracted
| TypeScript type | Extracted PropType.kind |
| ----------------------------------------- | ------------------------------------------- |
| string / number / boolean | string / number / boolean |
| "left" \| "right" | enum with the literal values |
| 1 \| 2 \| 3 | enum with the literal values |
| string \| number | union of sub-types |
| { label: string } (inline) | object with the nested fields |
| string[] / Array<string> | array with its itemType |
| Same-file interface X { ... } reference | Resolved to the inline shape |
| Cross-file imports, ReactNode, etc. | reference with targetType: '<the name>' |
| Anything the scanner can't classify | unknown |
The component's displayName comes from the component identifier (or react-docgen-typescript's detected display name). JSDoc on the component populates description; JSDoc on individual props populates each prop's description. Destructuring defaults (e.g. { alignment = 'center' }) are captured as defaultValue.
What's next
This package ships the foundation. The forthcoming slices add:
- An admin form generator that renders the right input per
PropType - A CLI diff tool that flags incompatible prop changes between manifests
- Live-preview rendering of the selected block right inside the editor
- Discriminated-union and migration-prompt support
See docs/component-blocks.md for the design and docs/roadmap-status.md for the full Phase 4 plan.
