Custom objects with children portable text objects are rendered as plain blocks
dbanisimov opened this issue · 1 comments
The problem
Custom objects that contain portable text blocks, spans or other typed objects in the children
property are rendered as plain blocks. The custom serializer provided in the types is not used in this case, and a regular renderer with a p
tag with a subsequent traversal is used.
For example, an object like this will be affected:
interface CustomObject {
_type: 'customObject';
children: PortableTextBlock[];
someCustomProperty: any;
}
You can see a reproduction in this CodeSandbox (the demo was updated): https://codesandbox.io/p/github/dbanisimov/react-portabletext-repro/draft/jovial-jerry.
Expected behavior
- The custom block should be rendered using the provided serializer according to the
_type
property - (optional) The traversal might continue with the children property of the custom object. This is how it used to work in
sanity-io/block-content-to-react
library, but it might not work for someone who expects to do some custom rendering of children objects.
Possible culprit
The check on this line is using a loose assertion of the block type from @portabletext/toolkit
that accepts any block-like object without checking the type. This check happens before the custom node type check, so it always takes precedence.
Possible fixes
- Stricter type checking in this library, e.g.:
if (isPortableTextBlock(node) && node._type === 'block') {
return renderBlock(node, index, key, isInline)
}
- Stricter type checking in
isPortableTextBlock
from@portabletext/toolkit
. This will make that check much clearer for the user, but the change might break something that depends on it. - Handle custom object types when rendering blocks. Function
renderBlock
can be changed to check the_type
property on a node, call a custom serializer if one found and use the default children traversal.
Use case
Just to provide the context for using custom objects with children that are typed objects themselves:
We're implementing a custom 'link' block. As with normal links it can contain other formatted text spans within it. The natural solution for that was to use portable text within the link itself. We are using a node here instead of a mark, because it's easier to work with nodes than to convert markDefs back and forth. It makes it easier to integrate with other rich text editing libraries that handle links in the nodes tree.
This should fixed in 3.0.0