init commit for iPAL-kit plugin
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
import { Fragment } from 'react'
|
||||
|
||||
import type { BlockComponentMap, BlockData, EnhanceProps } from './types.js'
|
||||
|
||||
export type RenderBlocksProps = {
|
||||
/** Block data array from a Payload document (e.g. page.layout). */
|
||||
blocks: BlockData[] | null | undefined
|
||||
/** Client-provided map of blockType → component. */
|
||||
components: BlockComponentMap
|
||||
/**
|
||||
* Optional client hook to inject block-specific props (nav anchors, etc.).
|
||||
* Keeps the engine generic — the plugin knows no concrete block types.
|
||||
*/
|
||||
enhanceProps?: EnhanceProps
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic, server-side block renderer.
|
||||
*
|
||||
* Iterates a document's blocks and renders each via the client's component
|
||||
* map. Unknown blocks are skipped (null), never thrown. Block-specific logic is
|
||||
* delegated to the client's optional `enhanceProps` — the plugin itself is
|
||||
* block-agnostic.
|
||||
*
|
||||
* The client owns components and block schemas (they pass `components` and
|
||||
* define blocks in their config); the plugin owns only the iteration and
|
||||
* wiring. No wrapper markup is added — spacing/layout belong to the client's
|
||||
* components.
|
||||
*
|
||||
* Nested blocks: a block that needs to render child blocks should render its
|
||||
* own <RenderBlocks> and import the registry itself, rather than receiving the
|
||||
* component map as a prop. Passing the map as a prop breaks React Server
|
||||
* Components — functions (client components) can't cross the server→client
|
||||
* boundary via props.
|
||||
*/
|
||||
export function RenderBlocks({ blocks, components, enhanceProps }: RenderBlocksProps) {
|
||||
if (!blocks || !Array.isArray(blocks) || blocks.length === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
{blocks.map((block, index) => {
|
||||
const Component = components[block.blockType]
|
||||
if (!Component) {return null}
|
||||
|
||||
const extra = enhanceProps ? enhanceProps({ allBlocks: blocks, block, index }) : {}
|
||||
|
||||
return <Component key={index} {...block} {...extra} />
|
||||
})}
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export { RenderBlocks } from './RenderBlocks.js'
|
||||
export type { RenderBlocksProps } from './RenderBlocks.js'
|
||||
export type { BlockComponentMap, BlockData, EnhanceProps } from './types.js'
|
||||
@@ -0,0 +1,29 @@
|
||||
import type { ComponentType } from 'react'
|
||||
|
||||
/**
|
||||
* A single block's data as stored by Payload — always has a blockType, plus
|
||||
* arbitrary block-specific fields. The plugin stays generic over the shape.
|
||||
*/
|
||||
export type BlockData = {
|
||||
[key: string]: unknown
|
||||
blockType: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a blockType to the client's component for it.
|
||||
* The client owns the components; the plugin only receives this map.
|
||||
*/
|
||||
export type BlockComponentMap = Record<string, ComponentType<any>>
|
||||
|
||||
/**
|
||||
* Optional per-block prop enhancer supplied by the client.
|
||||
*
|
||||
* Lets the client inject block-specific logic (e.g. collect anchors for a nav
|
||||
* block) without the plugin knowing any concrete block types. Returns extra
|
||||
* props merged into the rendered block.
|
||||
*/
|
||||
export type EnhanceProps = (args: {
|
||||
allBlocks: BlockData[]
|
||||
block: BlockData
|
||||
index: number
|
||||
}) => Record<string, unknown>
|
||||
Reference in New Issue
Block a user