Thanks for your helpful reply. Actually I managed to make it work now after taking some time looked deeper into the source code and it’s props definition. It turns out that I wasn’t passing necessary props to the <Blocks /> component. I guess I’ll share my code here so that if anyone having the same issue can learn from my mistake.
IMPORTANT: if you have isRSC: true in any custom component, <Blocks /> can only be used in RSC because of passing builderComponents to registeredComponents props. Workaround to use <Blocks /> in client component is to pass it as props like my example below. More info: Rendering: Composition Patterns | Next.js (nextjs.org)
BurgerButton.tsx:
import { Blocks, BuilderBlock, RegisteredComponent } from '@builder.io/sdk-react-nextjs';
import { BurgerProps, DrawerProps, MantineSize } from '@mantine/core';
import { BurgerButtonClient } from './BurgerButtonClient';
import { CSSProperties, FunctionComponent, ReactNode } from 'react';
import { BuilderContext } from '../../types/builder';
export interface BuilderBlockAttributes {
className?: string;
href?: string;
style?: CSSProperties;
}
// copy from '../../types/builder'
export type BuilderBlockProps<
P = unknown,
L extends { href?: string; children?: ReactNode } = { href?: string; children?: ReactNode },
> = P & {
attributes?: BuilderBlockAttributes;
builderBlock: BuilderBlock;
builderContext: BuilderContext;
builderLinkComponent?: FunctionComponent<L>;
builderComponents: Record<string, RegisteredComponent>;
children?: ReactNode;
};
interface BurgerButtonProps extends BurgerProps {
blocks?: BuilderBlock[];
drawerProps?: Omit<DrawerProps, 'offset'> & {
offset?: {
top?: number;
right?: number;
bottom?: number;
left?: number;
};
size?: MantineSize;
};
}
export const BurgerButton = ({
attributes,
blocks,
// these props are passed by Builder when this component is used in Visual Editor
builderBlock,
builderComponents,
builderContext,
builderLinkComponent,
// end
color,
drawerProps,
lineSize,
size,
}: BuilderBlockProps<BurgerButtonProps>) => {
return (
<BurgerButtonClient
attributes={attributes}
color={color}
drawerProps={drawerProps}
lineSize={lineSize}
size={size}
>
<Blocks
blocks={blocks}
context={builderContext} // was missing
linkComponent={builderLinkComponent} // was missing, not necessary if you don't use linkComponent prop on <Content />
parent={builderBlock.id}
path='component.options.blocks'
registeredComponents={builderComponents} // was missing
/>
</BurgerButtonClient>
);
};
BurgerButtonClient.tsx:
'use client';
import { Burger, BurgerProps, Drawer, DrawerProps } from '@mantine/core';
import { useDisclosure } from '@mantine/hooks';
import { omit } from 'lodash';
import { BuilderBlockProps } from '../../types/builder';
interface BurgerButtonClientProps extends Pick<BuilderBlockProps, 'attributes' | 'children'>, BurgerProps {
drawerProps?: Omit<DrawerProps, 'offset'> & {
offset?: {
top?: number;
right?: number;
bottom?: number;
left?: number;
};
};
}
export const BurgerButtonClient = ({
attributes,
children,
color,
drawerProps,
lineSize,
size,
}: BurgerButtonClientProps) => {
const [opened, { toggle, close }] = useDisclosure();
const { bottom, left, right, top } = drawerProps?.offset ?? {};
return (
<>
<Burger
{...attributes}
color={color}
lineSize={lineSize}
onClick={toggle}
opened={opened}
size={size}
/>
<Drawer
{...omit(drawerProps, 'offset')}
onClose={close}
opened={opened}
overlayProps={{
bottom,
left,
right,
top,
}}
styles={{
inner: {
bottom,
left,
right,
top,
},
}}
>
{children}
</Drawer>
</>
);
};
BurgerButton.register.ts:
import { RegisteredComponent } from '@builder.io/sdk-react-nextjs';
import { BurgerButton } from './BurgerButton';
const BurgerButtonEntry: RegisteredComponent = {
component: BurgerButton,
name: 'BurgerButton',
noWrap: true,
isRSC: true,
inputs: [
{
name: 'color',
type: 'string',
},
{
name: 'lineSize',
type: 'number',
helperText: 'Line size in pixel',
},
{
name: 'size',
type: 'string',
},
{
name: 'drawerProps',
type: 'object',
friendlyName: 'Drawer options',
subFields: [
{
name: 'offset',
type: 'object',
subFields: [
{ name: 'top', type: 'number' },
{ name: 'right', type: 'number' },
{ name: 'bottom', type: 'number' },
{ name: 'left', type: 'number' },
],
},
{ name: 'position', type: 'string', enum: ['left', 'right', 'top', 'bottom'], defaultValue: 'left' },
{ name: 'withCloseButton', type: 'boolean', defaultValue: false },
],
},
{
name: 'blocks',
type: 'uiBlocks',
hideFromUI: true,
defaultValue: []
},
],
};
export { BurgerButtonEntry as BurgerButton };
I really think the documentation should’ve mention this usage somewhere. I hope when @builder.io/sdk-react-nextjs become stable there is an example like mine included in the documentation.
Thanks again for looking into my problem.