Closed cgpro closed 1 year ago
I'd need to see a repro to help. seems you misconfigure the use of the plugin
Slowly I get my head wrapped around it (I think), but I am afraid it is not best practice ;-)
Richtext.tsx (with import { render } from 'storyblok-rich-text-react-renderer-ts'; etc.)
blokResolvers: {
['SplitScreenshot']: (props) => {
// fix hirarchy: we need an additional blok property
let extendedProps = {};
extendedProps['blok'] = props;
// @ts-ignore
return <SplitScreenshot {...(extendedProps as SplitScreenshotStoryblok)} />;
},
},
SplitScreenshot.tsx
const SplitScreenshot: FunctionComponent<BlokComponentModel<SplitScreenshotStoryblok>> = ({ blok }) => {...}
If I omit the curly braces around blok, I don't have to copy the props into the new 'blok' property. But then it no longer works outside of richtext fields.
Outside of a rich text field the props are structured like this:
{
blok: {
headline, teaser and so on
}
}
Inside of a rich text field the child blok/components props are structured like this:
{
headline, teaser and so on
}
The property blok ist missing in the hierarchy.
If you see a more elegant approach, I would of course appreciate feedback.
Check out the https://github.com/dohomi/storyblok-rich-text-react-renderer-ts#advanced-usage
You check signatures of your compoenents similar like this:
import { render } from 'storyblok-rich-text-react-renderer-ts'
function RenderRichText({body}){
return render(body,{
defaultBlokResolver: (name, props) => {
console.log(name,props)
return(
<div>
<code>Missing blok resolver for blok type "{name}".</code>
<pre>
<code>{JSON.stringify(props, undefined, 2)}</code>
</pre>
</div>
)
}})
}
The rest of the body part is rendered with fallback components you don't necessarily do anything with them
That's how I think it's a more clean approach:
<SplitScreenshot {...({ blok: props } as SplitScreenshotStoryblok & { blok: SplitScreenshotStoryblok })} />
It's working now. Here is my config with some tailwind customizations. Maybe it helps someone to get started.
Richtext.tsx
import Link from 'next/link';
import Image from 'next/image';
import { render } from 'storyblok-rich-text-react-renderer-ts';
import { ReactNode } from 'react';
// child bloks
import SplitScreenshot from '../tailwindui/hero-sections/SplitScreenshot';
import { SplitScreenshotStoryblok } from '../component-types-sb';
export default function RichText(document) {
return render(document, {
nodeResolvers: {
image: (children, props) => <Image {...props} />,
paragraph: (children) => <p className='mt-8'>{children}</p>,
ordered_list: (children) => (
<ol role='list' className='max-w-xl pl-4 mt-8 space-y-2 text-gray-600 list-decimal'>
{children}
</ol>
),
bullet_list: (children) => (
<ul role='list' className='max-w-xl pl-4 mt-8 space-y-2 text-gray-600 list-disc'>
{children}
</ul>
),
list_item: (children) => {
// a new children array, because the old array is read only
let listChildren: ReactNode[] = [];
// @ts-ignore
children.map((child) => {
// mt-8 is a regular paragraph, within lists we need mt-0
listChildren.push({ ...child, props: { ...child.props, className: 'mt-0' } });
});
return <li className='mt-0'>{listChildren}</li>;
},
},
markResolvers: {
bold: (children) => <strong className='font-semibold text-gray-900'>{children}</strong>,
italic: (children) => <i>{children}</i>,
link: (children, props) => {
const { href, target, linktype } = props;
if (linktype === 'email') {
// Email links: add `mailto:` scheme and map to <a>
return <a href={`mailto:${href}`}>{children}</a>;
}
if (href.match(/^(https?:)?\/\//)) {
// External links: map to <a>
return (
<a href={href} target={target}>
{children}
</a>
);
}
// Internal links: map to <Link>
return (
<Link href={href} legacyBehavior>
<a>{children}</a>
</Link>
);
},
},
blokResolvers: {
['SplitScreenshot']: (props) => {
return (
<SplitScreenshot {...({ blok: props } as SplitScreenshotStoryblok & { blok: SplitScreenshotStoryblok })} />
);
},
},
defaultStringResolver: (str) => <p>{str}</p>,
defaultBlokResolver: (name, props) => (
<div>
<code>Missing blok resolver for blok type {name}.</code>
<pre>
<code>{JSON.stringify(props, undefined, 2)}</code>
</pre>
</div>
),
});
}
Component.tsx
...
import RichText from '../../_helper/Richtext';
...
<p className='mt-6 text-lg leading-8 text-gray-600' {...storyblokEditable(blok)}>
{RichText(blok.teaser)}
</p>
...
Hi,
it works fine, if I don't include any of my custom bloks in my richtext field.
In my Richtext.tsx I have the following blokResolver (Fields: headline and teaser, both are richtexts):
blokResolvers: { ['SplitScreenshot']: (props) => <SplitScreenshot {...props} />, },
and I get the following error:
TypeError: Cannot read properties of undefined (reading 'headline')
Do you have any idea, how to solve this? The example in the repo is very minimal. My SplitScreenshot blok itself works fine too.
Sorry, I'm relatively new to storyblok and next.js ;-) An extended example with a simple blok (with a richtext field) within a richtext would be very handy.