diff --git a/.changeset/nice-beers-kneel.md b/.changeset/nice-beers-kneel.md new file mode 100644 index 00000000..f70a2fe4 --- /dev/null +++ b/.changeset/nice-beers-kneel.md @@ -0,0 +1,5 @@ +--- +'@noaignite/react-utils': minor +--- + +createRenderBlock - `blockType` is now passed to block component diff --git a/.changeset/strange-boxes-fail.md b/.changeset/strange-boxes-fail.md new file mode 100644 index 00000000..c28b1259 --- /dev/null +++ b/.changeset/strange-boxes-fail.md @@ -0,0 +1,5 @@ +--- +'@noaignite/react-utils': minor +--- + +createRenderBlock - adapter `context` argument (prev `additionalData`) is now always an object diff --git a/.changeset/young-suns-beam.md b/.changeset/young-suns-beam.md new file mode 100644 index 00000000..17b1e47d --- /dev/null +++ b/.changeset/young-suns-beam.md @@ -0,0 +1,5 @@ +--- +'@noaignite/react-utils': minor +--- + +createRenderBlock - export new `BlockTypeMap` & `BlockAdapter` types diff --git a/packages/react-utils/src/createRenderBlock.tsx b/packages/react-utils/src/createRenderBlock.tsx index 029a180d..8fac129b 100644 --- a/packages/react-utils/src/createRenderBlock.tsx +++ b/packages/react-utils/src/createRenderBlock.tsx @@ -35,8 +35,8 @@ import { ErrorBoundary, type ErrorBoundaryProps } from './ErrorBoundary' * } * * const adapters = { - * Hero: async (props: HeroData['props'], additionalData, globals): Promise => { - * const { locale } = additionalData + * Hero: async (props: HeroData['props'], context, globals): Promise => { + * const { locale } = context * const { LinkComponent } = globals * * const data = (await fetch( `https://domain.com/${locale}/posts/1`).then((res) => { @@ -76,28 +76,40 @@ import { ErrorBoundary, type ErrorBoundaryProps } from './ErrorBoundary' */ export const createRenderBlock = _createRenderBlock() +/** + * The interface that block data needs to conform to. + */ +export interface BlockTypeMap { + blockType: string + props: Record +} + +/** + * Type helper to set up a block adapter. + */ +export type BlockAdapter< + TInProps extends Record, + TOutProps extends Record, + TContext extends Record, + TGlobals extends Record, +> = (props: TInProps, context: TContext, globals: TGlobals) => Promise | TOutProps + /** * A wrapper around `createRenderBlock` to give the posibility to define the - * `TAdditionalData` type. This is currently a workaround as there is - * currently no way in typescript to partially provide generics while having - * the rest infer. + * `TContext` interface. This is currently a workaround as there is currently + * no way in typescript to partially provide generics while having the rest + * self-infer. * * @see https://github.com/microsoft/TypeScript/issues/10571 * @see https://github.com/microsoft/TypeScript/pull/26349 */ -export function _createRenderBlock< - TAdditionalData extends number | { index: number; [key: string]: unknown }, ->() { +export function _createRenderBlock() { return function __createRenderBlock< TBlocks extends Record>, TGlobals extends Record, TAdapters extends | { - [K in keyof TBlocks]?: ( - props: any, - additionalData: TAdditionalData, - globals: TGlobals, - ) => Promise> | PropsFrom + [K in keyof TBlocks]?: BlockAdapter, TContext, TGlobals> } | undefined, TDefaultProps extends @@ -126,19 +138,18 @@ export function _createRenderBlock< blockType: TBlockType props: keyof TAdapters extends never ? PropsFrom : any }, - indexOrAdditionalData: TAdditionalData, + indexOrContext: number | TContext, ) { const { blockType, props } = data - const { index } = - typeof indexOrAdditionalData === 'number' - ? { index: indexOrAdditionalData } - : indexOrAdditionalData + const context = ( + typeof indexOrContext === 'number' ? { index: indexOrContext } : indexOrContext + ) as TContext if (typeof blockType !== 'string') { if (process.env.NODE_ENV !== 'production') { console.error( 'renderBlock: Block with index `%s` is missing the property `blockType`.', - index, + context.index, ) } return null @@ -148,7 +159,7 @@ export function _createRenderBlock< if (process.env.NODE_ENV !== 'production') { console.error( 'renderBlock: Block with index `%s` and blockType `%s` could not find a matching component.', - index, + context.index, blockType, ) } @@ -163,14 +174,14 @@ export function _createRenderBlock< if (adapters) { const adapter = adapters[blockType] if (typeof adapter === 'function') { - componentProps = await adapter(componentProps, indexOrAdditionalData, globals) + componentProps = await adapter(componentProps, context, globals) } } return ( - + - + )