init commit for iPAL-kit plugin

This commit is contained in:
2026-07-18 20:30:23 +02:00
parent 10638127a9
commit 5733a9c8bf
119 changed files with 6892 additions and 411 deletions
+53
View File
@@ -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>
)
}
+3
View File
@@ -0,0 +1,3 @@
export { RenderBlocks } from './RenderBlocks.js'
export type { RenderBlocksProps } from './RenderBlocks.js'
export type { BlockComponentMap, BlockData, EnhanceProps } from './types.js'
+29
View File
@@ -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>