portabletext / react-portabletext Goto Github PK
View Code? Open in Web Editor NEWRender Portable Text with React
Home Page: https://portabletext.github.io/react-portabletext/
License: MIT License
Render Portable Text with React
Home Page: https://portabletext.github.io/react-portabletext/
License: MIT License
Current setup:
<PortableText
value={value}
components={{
block: {
h2: (node) => <ClientComponentHeading as="h2" {...node} />,
h3: (node) => <ClientComponentHeading as="h3" {...node} />,
},
}}
/>
Where ClientComponentHeading.tsx is a client component (i.e. 'use client'
)
Which outputs the following error message in the Next.js console:
⨯ Error: Functions cannot be passed directly to Client Components unless you explicitly expose it by marking it with "use server". Or maybe you meant to call this function rather than return it.
<... as="h2" children={[...]} index=... isInline=... node=... value=... renderNode={function renderNode}>
^^^^^^^^^^^^^^^^^^^^^
at stringify (<anonymous>)
at stringify (<anonymous>)
at stringify (<anonymous>)
at stringify (<anonymous>)
digest: "3429654648"
My question is... how can I pass/use a client component in the <PortableText>
?
Making the parent component also a client component does not work as it outputs the following error message:
Error: async/await is not yet supported in Client Components, only Server Components.
This error is often caused by accidentally adding `'use client'` to a module that was originally written for the server.
Hi,
Currently marks render alphabetically and I'm facing a use case where I need to have a mark render before another.
See this codesandbox.
I need elements with .border
to be rendered as child of .color
. Currently border
mark renders first because of alphabetically sorting.
.color {
color: red;
}
.border {
border: 1px solid currentColor;
}
Providing a marksOrder
prop to force some marks to render in a specific order.
All other marks will render after.
Using '*'
will define the position of all others marks ['*', 'myMark']
.
const components = {
marks: {
color: ({children}) => <span className="color">{children}</span>,
border: ({children}) => <span className="border">{children}</span>,
},
marksOrder: ['color', 'border'], // equivalent to `['color', 'border', '*']`
// marksOrder: ['*', 'color', 'border'], // render all before those specifics marks
}
Thanks
It seems text
and span
elements default to their own render functions, even when overridden with the types
object. Is thus to be expected?
It would be nice to have table customization or configuration possible for it.
If someone have a solution for this, please let me know!!
Hi,
We have a Next JS project that is now failing to build due to the following error:
SyntaxError: Named export 'LIST_NEST_MODE_HTML' not found. The requested module '@portabletext/toolkit' is a CommonJS module
It seems to be related to the recent release, wondering if anyone else is having the issue and if there is a solution / work around?
Our project is a next/sanity build
next 12.3.1
yarn 3.2.1
Thanks Tim
For a portable text block, I have a serializer in marks
to specify rendering a component, and within that component, I'm using another portable text block. By default, the topmost div gets wrapped in a <p>
tag, causing hydration errors due to that topmost <p>
tag having children with <div>
and <p>
in it.
So, is there a way to render the block without a <p>
tag automatically wrapping the component, and thus avoid hydration errors?
Here's a simple outline of the code for reference:
const MyApp = () => {
return <PortableText value={body} components={PortableTextComponents} />
}
const PortableTextComponents = {
marks: {
serializer: ({value}) => {
return <MyComponent body={value} />
},
},
}
const MyComponent = ({body}) => {
return <PortableText value={body} />
}
Wondering how we would do something similar to this...
https://www.sanity.io/schemas/anchored-headings-for-portable-text-a6c70b6e - created by @kmelve
I think I understand how to create the new block
definitions for h1, h2 etc..., or a complete handler like in the example above, but in the code below, I don't believe node
is available from props
? And I'm not sure what to return instead of return PortableText.defaultSerializers.types.block(props)
(since defaultSerializers
is no longer on PortableText
)
const components: PortableTextComponents = {
block: props => {
const { node, children } = props
const { style, _key } = node
if (/^h\d/.test(style)) {
const HeadingTag = style
// Even though HTML5 allows id to start with a digit, we append it with a letter to avoid various JS methods to act up and make problems
const headingId = `h${_key}`
return (
<HeadingTag id={headingId}>
<a href={`#${headingId}`} aria-hidden="true" tabIndex={-1}>
#
</a>
<span>{children}</span>
</HeadingTag>
)
}
// ... you can put in other overrides here
// or return the default ones 👇
return PortableText.defaultSerializers.types.block(props)
}
}
Any thoughts or suggestions greatly appreciated.
I'm having an issue with the types for markKey as it's expecting a string but the type could be a string or undefined.
@portabletext/react/src/react-portable-text.tsx line 180
Now if the types are right then we need a way to deal with it possibly being undefined and type-guarded. Or maybe it's already type guided but we are not inferring the type after?
function renderSpan(node: ToolkitNestedPortableTextSpan, _index: number, key: string) {
const {markDef, markType, markKey} = node
const Span = components.marks[markType] || components.unknownMark
const children = node.children.map((child, childIndex) =>
renderNode({node: child, index: childIndex, isInline: true, renderNode})
)
if (Span === components.unknownMark) {
handleMissingComponent(unknownMarkWarning(markType), {nodeType: 'mark', type: markType})
}
const isDefined =<T,> (value: T | undefined): value is T => typeof value !== 'undefined'
if(isDefined(markKey))
return (
<Span
key={key}
text={spanToPlainText(node)}
value={markDef}
markType={markType}
markKey={markKey}
renderNode={renderNode}
>
{children}
</Span>
)
return <></>
}
website/node_modules/@portabletext/toolkit/src/buildMarksTree.ts. line 94
similar issue here with _key, and markDef...
const isDefined =<T,> (value: T | undefined): value is T => typeof value !== 'undefined'
for (const markKey of marksNeeded) {
const markDef = markDefs.find((def) => def._key === markKey)
const markType = markDef ? markDef._type : markKey
const node: ToolkitNestedPortableTextSpan<M> = {
_type: '@span',
children: [],
markType,
markKey,
}
if(isDefined(span._key)) node._key = span._key
if(isDefined(markDef)) node.markDef = markDef
My suggestion would be something like this, but you may have better ideas.
I would love to have some docs showing how this is supposed to be used with TypeScript!
We are useing Sanity 2.x and the webpack parser can not handle the changes introduced in this minor version.
Error in ./node_modules/@portabletext/react/dist/react-portable-text.esm.js
Module parse failed: Unexpected token (12:4)
You may need an appropriate loader to handle this file type.
| marks,
| types,
| ...rest
| } = overrides;
This most likely has to do with the rest/spread syntax. With 2.0.0 the code was this:
const {
block,
list,
listItem,
marks,
types
} = overrides,
rest = _objectWithoutProperties(overrides, _excluded);
return _objectSpread(_objectSpread({}, parent), {}, {
block: mergeDeeply(parent, overrides, "block"),
list: mergeDeeply(parent, overrides, "list"),
listItem: mergeDeeply(parent, overrides, "listItem"),
marks: mergeDeeply(parent, overrides, "marks"),
types: mergeDeeply(parent, overrides, "types")
}, rest);
With the new code it is:
const {
block,
list,
listItem,
marks,
types,
...rest
} = overrides;
return {
...parent,
block: mergeDeeply(parent, overrides, "block"),
list: mergeDeeply(parent, overrides, "list"),
listItem: mergeDeeply(parent, overrides, "listItem"),
marks: mergeDeeply(parent, overrides, "marks"),
types: mergeDeeply(parent, overrides, "types"),
...rest
};
It seems the introduction of a major version of @sanity/pkg-utils
has introduced this change in 32536f6#diff-7ae45ad102eab3b6d7e7896acd08c427a9b25b346470d7bc6507b6481575d519L52
"blockContent": [
{
"_key": "1e1e89d5cc17",
"_type": "block",
"children": [
{
"_key": "169646e523900",
"_type": "span",
"marks": [],
"text": "Block Content"
}
],
"markDefs": [],
"style": "h2"
},
{
"_key": "2a0aeea4e378",
"_type": "block",
"children": [
{
"_key": "1875c0d851d2",
"_type": "span",
"marks": [],
"text": ""
}
],
"markDefs": [],
"style": "normal"
},
{
"_key": "f6bd276c19e2",
"_type": "block",
"children": [
{
"_key": "a07c1c38620a",
"_type": "span",
"marks": [],
"text": "\"Lorem ipsum dolor sit amet, "
},
{
"_key": "555f100a0766",
"_type": "span",
"marks": [
"fb9b93ad297e"
],
"text": "consectetur"
},
{
"_key": "c3c736570215",
"_type": "span",
"marks": [],
"text": " adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore \"magna\" aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. "
},
{
"_key": "6129277bb3a2",
"_type": "span",
"marks": [
"917ed6187abc"
],
"text": "Excepteur sint occaecat"
},
{
"_key": "3245dd0eec72",
"_type": "span",
"marks": [],
"text": " cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\""
}
],
"markDefs": [
{
"_key": "fb9b93ad297e",
"_type": "link",
"href": "https://google.com"
},
{
"_key": "917ed6187abc",
"_type": "link",
"href": "#test"
}
],
"style": "normal"
},
{
"_key": "cc1e07c03566",
"_type": "block",
"children": [
{
"_key": "9bfc7d0b8c3f",
"_type": "span",
"marks": [],
"text": ""
}
],
"markDefs": [],
"style": "normal"
},
{
"_key": "f0c17447acb0",
"_type": "block",
"children": [
{
"_key": "1759fab50603",
"_type": "span",
"marks": [],
"text": "Item One"
}
],
"level": 1,
"listItem": "bullet",
"markDefs": [],
"style": "normal"
},
{
"_key": "4197ac03d360",
"_type": "block",
"children": [
{
"_key": "6afd11704412",
"_type": "span",
"marks": [],
"text": "Item Two"
}
],
"level": 1,
"listItem": "bullet",
"markDefs": [],
"style": "normal"
},
{
"_key": "2fa0377ac532",
"_type": "block",
"children": [
{
"_key": "0282e423c109",
"_type": "span",
"marks": [],
"text": "Item Three"
}
],
"level": 1,
"listItem": "bullet",
"markDefs": [],
"style": "normal"
},
{
"_key": "4866c26a44d5",
"_type": "block",
"children": [
{
"_key": "05f9b12885e4",
"_type": "span",
"marks": [],
"text": ""
}
],
"markDefs": [],
"style": "normal"
},
{
"_key": "10da741b2c38",
"_type": "block",
"children": [
{
"_key": "aeff8d2c1273",
"_type": "span",
"marks": [],
"text": "Item One"
}
],
"level": 1,
"listItem": "number",
"markDefs": [],
"style": "normal"
},
{
"_key": "8db903e89207",
"_type": "block",
"children": [
{
"_key": "b638bffc6db0",
"_type": "span",
"marks": [],
"text": "Item Two"
}
],
"level": 1,
"listItem": "number",
"markDefs": [],
"style": "normal"
},
{
"_key": "cb957b822bb6",
"_type": "block",
"children": [
{
"_key": "a6ffd8cef967",
"_type": "span",
"marks": [],
"text": "Item Three"
}
],
"level": 1,
"listItem": "number",
"markDefs": [],
"style": "normal"
}
],
// react | gatsby
import React from 'react';
// third-party
import { PortableText, PortableTextProps } from '@portabletext/react';
// styles
import styles from './BlockContent.module.scss';
export const BlockContent = ({ value }: PortableTextProps) => {
return (
<div className={styles.block_content}>
<PortableText
value={value}
components={{
marks: {
link: ({ value, children }) => {
const target = (value?.href || '').startsWith('http') ? '_blank' : undefined;
return (
<a href={value?.href} target={target} rel={target === '_blank' && 'noreferrer noopener'}>
{children}
</a>
);
},
},
list: {
bullet: ({ children }) => <ul style={{ listStyleType: 'disc' }}>{children}</ul>,
number: ({ children }) => <ol style={{ listStyleType: 'number' }}>{children}</ol>,
},
}}
/>
</div>
);
};
<div>
<h2>Block Content</h2>
<p></p>
<p>
"Lorem ipsum dolor sit amet, <span class='unknown__pt__mark__fb9b93ad297e'>consectetur</span> adipiscing elit,
sed do eiusmod tempor incididunt ut labore et dolore "magna" aliqua. Ut enim ad minim veniam, quis nostrud
exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit
in voluptate velit esse cillum dolore eu fugiat nulla pariatur.{' '}
<span class='unknown__pt__mark__917ed6187abc'>Excepteur sint occaecat</span> cupidatat non proident, sunt in
culpa qui officia deserunt mollit anim id est laborum."
</p>
<p></p>
<p>Item One</p>
<p>Item Two</p>
<p>Item Three</p>
<p></p>
<p>Item One</p>
<p>Item Two</p>
<p>Item Three</p>
</div>
all relative packages
": "^2.27.0"I can’t build my application anymore on the pages that use Portable Text. In Vercel, I get this build error:
ReferenceError: createElement is not defined
--
12:09:13.246 | at renderBlock (/vercel/path0/web/node_modules/@portabletext/react/dist/react-portable-text.js:397:5)
12:09:13.247 | at renderNode (/vercel/path0/web/node_modules/@portabletext/react/dist/react-portable-text.js:274:14)
12:09:13.247 | at /vercel/path0/web/node_modules/@portabletext/react/dist/react-portable-text.js:245:48
12:09:13.247 | at Array.map (<anonymous>)
12:09:13.247 | at PortableText (/vercel/path0/web/node_modules/@portabletext/react/dist/react-portable-text.js:245:27)
12:09:13.247 | at Wc (/vercel/path0/web/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:68:44)
12:09:13.247 | at Zc (/vercel/path0/web/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:70:253)
12:09:13.247 | at Z (/vercel/path0/web/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:76:89)
12:09:13.248 | at $c (/vercel/path0/web/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:78:98)
12:09:13.248 | at bd (/vercel/path0/web/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js:77:404)
Running Next.js 13.5.4, happens locally and when deploying.
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.
_type
propertysanity-io/block-content-to-react
library, but it might not work for someone who expects to do some custom rendering of children objects.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.
if (isPortableTextBlock(node) && node._type === 'block') {
return renderBlock(node, index, key, isInline)
}
isPortableTextBlock
from @portabletext/toolkit
. This will make that check much clearer for the user, but the change might break something that depends on it.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.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.
Given this basic setup from the README:
const components = {
block: {
h1: ({children}) => <h1 className="text-2xl">{children}</h1>,
}
};
<PortableText value={body} components={components} />
The TypeScript Engine will report this problem on the <PortableText>
components property:
Type '{ block: { h1: ({ children }: { children: any; }) => Element; }; }' is not assignable to type 'Partial<PortableTextReactComponents>'.
Types of property 'block' are incompatible.
Type '{ h1: ({ children }: { children: any; }) => Element; }' is not assignable to type 'PortableTextBlockComponent | Record<string, PortableTextBlockComponent>'.
Type '{ h1: ({ children }: { children: any; }) => Element; }' is not assignable to type 'Record<string, PortableTextBlockComponent>'.
Property 'h1' is incompatible with index signature.
Type '({ children }: { children: any; }) => Element' is not assignable to type 'PortableTextBlockComponent'.
Type '({ children }: { children: any; }) => Element' is not assignable to type 'FunctionComponent<PortableTextComponentProps<PortableTextBlock<PortableTextMarkDefinition, ArbitraryTypedObject | PortableTextSpan, string, string>>>'.
Types of parameters '__0' and 'props' are incompatible.
Type 'PropsWithChildren<PortableTextComponentProps<PortableTextBlock<PortableTextMarkDefinition, ArbitraryTypedObject | PortableTextSpan, string, string>>>' is not assignable to type '{ children: any; }'.
Property 'children' is optional in type 'PortableTextComponentProps<PortableTextBlock<PortableTextMarkDefinition, ArbitraryTypedObject | PortableTextSpan, string, string>> & { ...; }' but required in type '{ children: any; }'.ts(2322)
[types.ts(32, 3): ]()The expected type comes from property 'components' which is declared here on type 'IntrinsicAttributes & PortableTextProps<any>'
The front-end renders fine, but I'm trying to deploy this using NextJS / Vercel and the build is failing.
Note that the problem isn't occurring when using marks
, or types
.
Following the docs here: https://github.com/portabletext/react-portabletext#types
I have a field with _type="testimonial"
, and when I have the following object for components
, PortableText
doesn't do anything.
const myPortableTextComponents = {
block: {
h1: headingHandler,
h2: headingHandler,
h3: headingHandler,
h4: headingHandler,
h5: headingHandler,
h6: headingHandler,
},
types: {
testimonial: (props) => {
console.log(
'\n\n\n\n**************\n** hey **\n**************\n\n\n\n'
)
console.log(props)
return null
},
},
testimonial: (props) => {
console.log(
'\n\n\n\n**************\n** hey **\n**************\n\n\n\n'
)
console.log(props)
return null
},
}
<PortableText
value={node._rawContent}
components={myPortableTextComponents}
/>
As you can see, I'm trying the types
object and the top-level for the components object. Neither work.
it seems that the lib does not handle block customisation in types. I did like this
types: { block: ({ children }) => { console.log("a"); return <span>{children}</span>; }, },
and it does not do anything. I need to do in block part instead
I have an issue with using this package to build a static site with Astro.
I've created a Codesandbox that renders Portable text.
The command npm run dev
sets up a development server and everything resolves and renders fine.
npm run build
throws an error when trying to import the module.
generating static routes
error Named export 'PortableText' not found. The requested module '@portabletext/react' is a CommonJS module, which may not support all module.exports as named exports.
CommonJS modules can always be imported via the default export, for example using:
import pkg from '@portabletext/react';
const { PortableText } = pkg;
at ModuleJob._instantiate (node:internal/modules/esm/module_job:123:21)
at async ModuleJob.run (node:internal/modules/esm/module_job:189:5)
at async Promise.all (index 0)
at async ESMLoader.import (node:internal/modules/esm/loader:533:24)
at async generatePages (file:///project/home/jumbolove/workspace/node_modules/astro/dist/core/build/generate.js:70:20)
at async staticBuild (file:///project/home/jumbolove/workspace/node_modules/astro/dist/core/build/static-build.js:68:7)
at async AstroBuilder.build (file:///project/home/jumbolove/workspace/node_modules/astro/dist/core/build/index.js:83:5)
at async AstroBuilder.run (file:///project/home/jumbolove/workspace/node_modules/astro/dist/core/build/index.js:123:7)
at async build (file:///project/home/jumbolove/workspace/node_modules/astro/dist/core/build/index.js:22:3)
at async runCommand (file:///project/home/jumbolove/workspace/node_modules/astro/dist/cli/index.js:138:14)
I tried the suggestion of importing the whole package, then destructuring the Portable text function, and that also failed to resolve with a different error.
Since the dev server works fine, I'm wondering if there is a config setup missing that treats modules differently on dev vs. build.
Let me know if this is a bug in the way the module is bundled or if the Astro build config should resolve the module with different configs.
This package does not seem to be compatible with Next 13's App directory/server components. When used with Next.js 13, it results in the following error:
Server Error
TypeError: w.createContext is not a function
This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.
Using a curated preset maintained by
Warning
These dependencies are deprecated:
Datasource | Name | Replacement PR? |
---|---|---|
npm | @babel/plugin-proposal-object-rest-spread |
These branches will be created by Renovate only once you click their checkbox below.
@sanity/pkg-utils
, @sanity/ui
, @typescript-eslint/eslint-plugin
, @typescript-eslint/parser
, @vitejs/plugin-react
, esbuild
, prettier
, vite
)These are blocked by an existing closed PR and will not be recreated unless you click a checkbox below.
.github/workflows/format-if-needed.yml
actions/checkout v4
actions/setup-node v4
actions/create-github-app-token v1
peter-evans/create-pull-request v6@6d6857d36972b65feb161a90e484f2984215f83e
.github/workflows/main.yml
actions/checkout v4
actions/setup-node v4
actions/checkout v4
actions/setup-node v4
.github/workflows/release-please.yml
actions/create-github-app-token v1
google-github-actions/release-please-action v3
actions/checkout v4
pnpm/action-setup v2
actions/setup-node v4
peaceiris/actions-gh-pages v3@373f7f263a76c20808c831209c920827a82a2847
package.json
@portabletext/toolkit ^2.0.15
@portabletext/types ^2.0.13
@babel/plugin-proposal-object-rest-spread ^7.20.7
@commitlint/cli ^19.3.0
@commitlint/config-conventional ^19.2.2
@sanity/pkg-utils ^6.9.1
@sanity/ui ^2.3.1
@types/leaflet ^1.9.12
@types/react ^18.3.3
@types/react-dom ^18.3.0
@types/refractor ^3.4.1
@types/ws ^8.5.10
@typescript-eslint/eslint-plugin ^7.12.0
@typescript-eslint/parser ^7.12.0
@vitejs/plugin-react ^4.3.0
commitizen ^4.3.0
cz-conventional-changelog ^3.3.0
esbuild ^0.21.4
esbuild-register ^3.5.0
eslint ^8.57.0
eslint-config-prettier ^9.1.0
eslint-config-sanity ^7.1.2
eslint-plugin-react ^7.34.2
eslint-plugin-react-compiler 0.0.0-experimental-c8b3f72-20240517
eslint-plugin-react-hooks ^4.6.2
leaflet ^1.9.4
npm-run-all2 ^5.0.2
prettier ^3.3.1
prettier-plugin-packagejson ^2.5.0
react ^18.3.1
react-dom ^18.3.1
react-is ^18.3.1
react-leaflet ^4.2.1
react-refractor ^2.2.0
refractor ^4.8.1
rimraf ^5.0.1
rollup-plugin-visualizer ^5.12.0
styled-components ^6.1.11
typescript ^5.4.5
vite ^5.2.13
vitest ^1.6.0
react ^17 || ^18 || >=19.0.0-rc
node ^14.13.1 || >=16.0.0
pnpm 9.1.3
So I use import { PortableText } from '@portabletext/react'
in my Next.js application which uses Sanity as a CMS. Inside Sanity I have the following in my block content
marks: {
// Decorators usually describe a single property – e.g. a typographic
// preference or highlighting by editors.
decorators: [
{ title: "Strong", value: "strong" },
{ title: "Emphasis", value: "em" },
],
// Annotations can be any object structure – e.g. a link or a footnote.
annotations: [
{
name: "internalLink",
title: "Internal Link",
type: "object",
icon: PlugIcon,
fields: [
{
title: "Reference",
name: "reference",
type: "reference",
to: [{ type: "post" }],
},
],
},
],
},
Inside my Next.js application I have the following
import Link from 'next/link'
import { PortableText } from '@portabletext/react'
const InternalLink = ({ children, value }) => (
<Link href={`/${value.slug.current}`} prefetch={false}>
<a>{children}</a>
</Link>
)
const myPortableTextComponents = {
types: {
image: ImageComponent,
},
marks: {
internalLink: InternalLink,
},
}
export const PortableTextComponent = ({ value }) => (
<PortableText components={myPortableTextComponents} value={value} />
)
However, when I build my application I get the following error
Unknown mark type "internalLink", specify a component for it in the `components.marks` option
I am not sure where else defining internalLink
needs to happen in order for this to go away... Adding onMissingComponent={false}
also does not suppress it either.
Im getting error Unknown block type "undefined", specify a component for it in the `components.types` prop
when im trying to display data from sanity in <PortableText/>
Data from sanity:
{
"ms": 16,
"query": "*[_type==\"eucharistDates\"]{dates}",
"result": [
{
"dates": [
{
"_key": "05aa4a7799a3",
"_type": "block",
"children": [
{
"_key": "2173ec501f7b",
"_type": "span",
"marks": [
],
"text": "Sobota 9:00 10:00"
}
],
"markDefs": [
],
"style": "normal"
},
{
"_key": "ddf850d31eb2",
"_type": "block",
"children": [
{
"_key": "0fa21a90dcbc",
"_type": "span",
"marks": [
],
"text": "Niedziela 8:00 10:00 13:00"
}
],
"markDefs": [
],
"style": "normal"
}
]
}
]
}
Next.js code:
import Image from 'next/image';
import PropTypes from 'prop-types';
import { PortableText } from '@portabletext/react';
import heroImage from '../../../../public/hero.jpg';
const components = {
block: {
normal: ({ children }) => <span>{children}</span>,
},
};
const Hero = ({ eucharistDates }) => {
return (
<div className="h-[calc(100vh_-_5rem)] w-screen relative bg-black">
<section className="absolute left-1/2 top-1/2 z-10 flex flex-col text-white text-center transform -translate-x-1/2 -translate-y-1/2">
<h1 className="uppercase text-4xl">
Parafia św. Bartłomieja w Opocznie
</h1>
<PortableText value={eucharistDates} components={components} />
</section>
<Image
src={heroImage}
layout="fill"
objectFit="cover"
placeholder="blur"
draggable={false}
/>
</div>
);
};
Same as in an already closed but not solved issue in block-content-to-react #issue48
List items do not work with react-portable text. For reference I am using Next Js.
import { urlFor } from 'libs/sanity';
import { PortableText } from '@portabletext/react';
const ptComponents = {
types: {
list: {
bullet: ({ children }) => (
<ul className="list-disc list-inside p-4 bg-accent-7">{children}</ul>
),
},
listItem: {
// Ex. 1: customizing common list types
bullet: ({ children }) => (
<li className="text-sm text-indigo">XX{children}</li>
),
},
image: ({ value }) => {
if (!value?.asset?._ref) {
return null;
}
return (
<Image
alt={value.alt || ' '}
src={urlFor(value).width(320).height(240).fit('max').auto('format')}
layout="fill"
objectFit="contain"
/>
);
},
},
};
<div className="text-sm list-disc list-inside p-4 bg-accent-7">
<PortableText
value={product.productSummary}
components={ptComponents}
/>
</div>
I'm trying to create functionality in my code where nested Items in a list may have different bullets if they're nested. Accessing the level
inside value is enough for unordered items but for ordered items, I'd need the item element position with regard to the parent as well. i.e I want to render something like the sanity editor shows while nesting a list:
In this case the type
attribute in <ol/>
works fine but for any other custom ordered kind of bullet I'd need the position in the list.
looking at the types index seems like a good candidate, but when I try to get the index I only get repeated 1's and 3's which either seem broken or its purpose is different, my workaround was to mutate the value prop in the list to add an order
property like this:
bullet: ({ children }) => {
return (
<ul className={style?.bullet}>
{Children.map(children, (child, idx) => {
if (isValidElement(child)) {
child.props.value.order = idx;
}
return child;
})}
</ul>
);
},
And then in the listItem I've access to level and order to render the bullet that I want, but I wanted to ask if is there a better way, or yes it is, index
is the answer but is not actually working.
when building my site Im running into this error both locally and during deployments to vercel.
--
10:34:43.698 |
10:34:43.699 | 1 \| import cjs from './react-portable-text.js';
10:34:43.699 | 2 \|
10:34:43.699 | > 3 \| export const toPlainText = cjs.toPlainText;
10:34:43.699 | \| ^
10:34:43.699 | 4 \| export const PortableText = cjs.PortableText;
10:34:43.699 | 5 \| export const defaultComponents = cjs.defaultComponents;
10:34:43.699 | 6 \| export const mergeComponents = cjs.mergeComponents;
10:34:43.699 |
10:34:43.699 |
10:34:43.699 | WebpackError: TypeError: Cannot read properties of undefined (reading 'toPlain Text')
10:34:43.699 |
10:34:43.699 | - react-portable-text.cjs.mjs:3
10:34:43.699 | [retool-dot-com]/[@portabletext]/react/dist/react-portable-text.cjs.mjs:3:28
10:34:43.700 | - bootstrap:19
10:34:43.700 | retool-dot-com/webpack/bootstrap:19:1
10:34:43.700 |
10:34:43.700 | - pageSanity.js:9
10:34:43.700 | retool-dot-com/src/templates/pageSanity.js:9:9
It makes it seem like this would be the dep packages issue but when using react-portable-text
directly there is no issue. it builds and runs perfectly. there is something about the implementation or version of this package in your package that causes these errors.
Gatsby v4.x
node v16.x
babel/core v7.6
tested this on your package from version 2.0.3 -> 3.0.4 all resulted in the same error.
simply installing react-portable-text
directly and only replacing the props of that component to be serializers
and content
this builds and runs with no issues.
Does not currently work with React Native. So no migration path of old implementation.
const data = [ { _key: "9ec013feda12", _type: "block", children: [ { _key: "09308a7bb41d0", _type: "span", marks: [], text: "Some text here...", }, ], markDefs: [], style: "normal", }, ];
OLD Implementation works fine
<BlockContent blocks={data} />
New
<PortableText value={data} />
Gives error
`Error: Text strings must be rendered within a component.
This error is located at:
in strong (created by strong)
in strong (created by ae)
in p (created by normal)
in normal (created by ae)
in ae (created by ArticleDetailsScreen)
in RCTView (created by View)
in View (created by ArticleDetailsScreen)
in RCTScrollContentView (created by ScrollView)
in RCTScrollView (created by ScrollView)
in ScrollView (created by ScrollView)
in ScrollView (created by ArticleDetailsScreen)
in RCTSafeAreaView
in SafeAreaView (created by ArticleDetailsScreen)
in ArticleDetailsScreen (created by SceneView)
in StaticContainer
in EnsureSingleNavigator (created by SceneView)
in SceneView (created by SceneView)
in RCTView (created by View)
in View (created by DebugContainer)
in DebugContainer (created by MaybeNestedStack)
in MaybeNestedStack (created by SceneView)
in RNSScreen (created by AnimatedComponent)
in AnimatedComponent
in AnimatedComponentWrapper (created by Screen)
in MaybeFreeze (created by Screen)
in Screen (created by SceneView)
in SceneView (created by NativeStackViewInner)
in RNSScreenStack (created by ScreenStack)
in ScreenStack (created by NativeStackViewInner)
in NativeStackViewInner (created by NativeStackView)
in RCTView (created by View)
in View (created by SafeAreaInsetsContext)
in SafeAreaProviderCompat (created by NativeStackView)
in NativeStackView (created by NativeStackNavigator)
in Unknown (created by NativeStackNavigator)
in NativeStackNavigator (created by HomeStackNavigator)
in HomeStackNavigator (created by SceneView)
in StaticContainer
in EnsureSingleNavigator (created by SceneView)
in SceneView (created by BottomTabView)
in RCTView (created by View)
in View (created by Screen)
in RCTView (created by View)
in View (created by Background)
in Background (created by Screen)
in Screen (created by BottomTabView)
in RNSScreen (created by AnimatedComponent)
in AnimatedComponent
in AnimatedComponentWrapper (created by Screen)
in MaybeFreeze (created by Screen)
in Screen (created by MaybeScreen)
in MaybeScreen (created by BottomTabView)
in RNSScreenNavigationContainer (created by ScreenContainer)
in ScreenContainer (created by MaybeScreenContainer)
in MaybeScreenContainer (created by BottomTabView)
in RNCSafeAreaProvider (created by SafeAreaProvider)
in SafeAreaProvider (created by SafeAreaInsetsContext)
in SafeAreaProviderCompat (created by BottomTabView)
in BottomTabView (created by BottomTabNavigator)
in Unknown (created by BottomTabNavigator)
in BottomTabNavigator (created by TabNavigator)
in TabNavigator (created by RootNavigator)
in EnsureSingleNavigator
in BaseNavigationContainer
in ThemeProvider
in NavigationContainerInner (created by RootNavigator)
in RootNavigator (created by App)
in QueryClientProvider (created by ReactQueryProvider)
in ReactQueryProvider (created by App)
in AuthProvider (created by App)
in App (created by ExpoRoot)
in ExpoRoot
in RCTView (created by View)
in View (created by AppContainer)
in DevAppContainer (created by AppContainer)
in RCTView (created by View)
in View (created by AppContainer)
in AppContainer
at node_modules/react-native/Libraries/Core/ExceptionsManager.js:104:6 in reportException
at node_modules/react-native/Libraries/Core/ExceptionsManager.js:172:19 in handleException
at node_modules/react-native/Libraries/Core/setUpErrorHandling.js:24:6 in handleError
at node_modules/expo-error-recovery/build/ErrorRecovery.fx.js:12:21 in ErrorUtils.setGlobalHandler$argument_0`
Tested with
"expo": "~44.0.0"
"react": "17.0.1",
"react-native": "0.64.3",
@portabletext/react": "^1.0.6"
I started to get this type error during build step on Vercel 24 hours ago. Latest sucessfully build was 3 days ago:
Type error: 'Li' cannot be used as a JSX component.
in @portabletext/react
Project: Next JS, Sanity.
Dependencies I use (the relevant parts):
...
"@portabletext/react": "^1.0.4",
"next": "12.1.0",
"react": "17.0.2",
"react-dom": "17.0.2",
"@portabletext/types": "^1.0.3",
"@types/react": "^17.0.42",
"@typescript-eslint/eslint-plugin": "^5.16.0",
"@typescript-eslint/parser": "^5.16.0",
"eslint": "8.11.0",
"eslint-config-next": "12.1.0",
"eslint-config-prettier": "^8.5.0",
"eslint-import-resolver-typescript": "^2.7.0",
"typescript": "^4.6.2"
Error:
./node_modules/@portabletext/react/src/react-portable-text.tsx:136:8
--
09:34:49.278 | Type error: 'Li' cannot be used as a JSX component.
09:34:49.278 | Its element type 'ReactElement<any, any> \| Component<PortableTextComponentProps<PortableTextListItemBlock<PortableTextMarkDefinition, PortableTextSpan, string, string>>, any, any>' is not a valid JSX element.
09:34:49.278 | Type 'Component<PortableTextComponentProps<PortableTextListItemBlock<PortableTextMarkDefinition, PortableTextSpan, string, string>>, any, any>' is not assignable to type 'Element \| ElementClass'.
09:34:49.278 | Type 'Component<PortableTextComponentProps<PortableTextListItemBlock<PortableTextMarkDefinition, PortableTextSpan, string, string>>, any, any>' is not assignable to type 'ElementClass'.
09:34:49.278 | The types returned by 'render()' are incompatible between these types.
09:34:49.278 | Type 'React.ReactNode' is not assignable to type 'import("/vercel/path0/web/node_modules/@types/react-dom/node_modules/@types/react/index").ReactNode'.
09:34:49.278 |
09:34:49.278 | 134 \|
09:34:49.278 | 135 \| return (
09:34:49.278 | > 136 \| <Li key={key} value={node} index={index} isInline={false} renderNode={renderNode}>
09:34:49.278 | \| ^
09:34:49.279 | 137 \| {children}
09:34:49.279 | 138 \| </Li>
09:34:49.279 | 139 \| )
I am upgrading my NextJs/Sanity application to NextJS 13 using Sanity.io and typescript.
The PortableText tag no longer works. The value and components attributes are flagged as an error in Visual Studio Code.
import { PortableText } from "@portabletext/react";
<PortableText value={post?.body} components={components} />
I am getting the following error:
ype 'PortableTextBlockComponent[]' is not assignable to type 'TypedObject | TypedObject[]'. Type 'PortableTextBlockComponent[]' is not assignable to type 'TypedObject[]'. Type 'PortableTextBlockComponent' is not assignable to type 'TypedObject'. Property '_type' is missing in type 'ComponentClass<PortableTextComponentProps<PortableTextBlock<PortableTextMarkDefinition, ArbitraryTypedObject | PortableTextSpan, string, string>>, any>' but required in type 'TypedObject'.ts(2322) index.d.ts(171, 3): '_type' is declared here. react-portable-text.d.ts(163, 3): The expected type comes from property 'value' which is declared here on type 'IntrinsicAttributes & PortableTextProps' (property) PortableTextProps.value: TypedObject | TypedObject[]
I have a list of headings, body, images, etc.
While rendering the block with the help of react-portabletext in a NEXT JS project with Typescript I don't see the image in the rendered HTML. After I have inspected it to look for the image, i see a div like below:
<div style="display:none">[@portabletext/react] Unknown block type "image", specify a component for it in the
components.types prop</div>
In the PortableText
component I am using it like this below:
<PortableText value={data.body} onMissingComponent={false} />
Not able to import into Nextjs app:
node -v: 14.18.1
yarn -v: 1.22
react: 17.0.1
Hi! 👋
Firstly, thanks for your work on this project! 🙂
Today I used patch-package to patch @portabletext/[email protected]
for the project I'm working on.
Here is the diff that solved my problem:
diff --git a/node_modules/@portabletext/react/src/react-portable-text.tsx b/node_modules/@portabletext/react/src/react-portable-text.tsx
index 0b68a71..fb38751 100644
--- a/node_modules/@portabletext/react/src/react-portable-text.tsx
+++ b/node_modules/@portabletext/react/src/react-portable-text.tsx
@@ -79,7 +79,7 @@ const getNodeRenderer = (
components: PortableTextReactComponents,
handleMissingComponent: MissingComponentHandler
): NodeRenderer => {
- function renderNode<N extends TypedObject>(options: Serializable<N>): ReactNode {
+ function renderNode<N extends TypedObject>(options: Serializable<N>): JSX.Element | string {
const {node, index, isInline} = options
const key = node._key || `node-${index}`
This issue body was partially generated by patch-package.
✖ ERROR ./node_modules/@portabletext/react/src/react-portable-text.tsx
ERROR in ./node_modules/@portabletext/react/src/react-portable-text.tsx(87,7):
TS2322: Type 'Element' is not assignable to type 'ReactNode'.
error Command failed with exit code 1.
Managed to get builds working by changing it to JSX.Element | string
Here's my TS config
{
"compilerOptions": {
"strict": true,
"esModuleInterop": true,
"lib": ["DOM", "ES2022"],
"jsx": "react-jsx",
"jsxImportSource": "preact",
/* allowJs
*
* Allows us to use Javascript and Typescript files
* together. This is because we built the new calculators using Typescript.
*/
"allowJs": true,
"noEmit": true /* Do not emit outputs. */,
"skipLibCheck": true,
"plugins": [
{
"name": "typescript-plugin-css-modules",
"options": {
/* Regex that will match anything like `*.css` when used in a ts file. */
"customMatcher": ".+\\.css"
}
}
]
},
"include": ["src/**/*"]
}
I would love to wrap all of my type serializers in error boundaries. Instead of adding one to each of my serializers, I would love to have a prop that I could provide a component that wraps all serializers.
Example usage:
<PortableText
value={value}
components={components}
componentWrapper={({ children }) => (
<ErrorBoundary fallback={<div>Error</div>}>
{children}
</ErrorBoundary>
)}
/>
Is this something you could look into?
The component override unknownBlockStyle
is not working. It seems that when you provide a block
component override, it is merged with the default block-styles, so that there never is an "unknown" block.
For instance if you define
block: {
// Ex. 1: customizing common block types
h1: ({children}) => <h1 className="text-2xl">{children}</h1>,
blockquote: ({children}) => <blockquote className="border-l-purple-500">{children}</blockquote>,
},
unknownBlockStyle: ({children}) => <BlockWrapper>{children}</BlockWrapper>,
}
the block style 'normal' should render with BlockWrapper
, but instead gets render with the default component (<p>
)
I am having a hard time using this library as it seems like I'm not picking up the build js files, but rather typescript is using the source files and having opinions about them! My tsconfig.json
has skipLibCheck: true
. It seems that it is not finding the correct export? I get the above error just by running tsc --noEmit
Right now my solution is to patch
comment out the React references so my project will build.
I pulled down the repo to check things out. It looks like the tsconfig could be updated with "jsx": "react-jsx"
as with React 17+, you no longer need to ghost import React to handle jsx
and they suggest moving away from it. After updating the react eslint extends with "plugin:react/jsx-runtime" and removing the react import, all seemed well...
Except I can't build because of linting errors in react-portable-text.tsx
that exist on main...
Are there settings I need to adjust on my end or can I help put up PR once the build issues get resolved?
Just updated @portabletext/react
to v1.0.4, unfortunately the package no longer functions out of the box under Expo web.
Looks to be related to the change to using .mjs. Can confirm it works when downgrading back to v1.0.3.
Might be related to this: facebook/metro#535, however the package seems to work fine under other (native) Expo targets (Android/iOS).
Minimum repo here: https://github.com/4lun/expo-portabletext-react (run yarn web
)
Error from expo-cli:
###/node_modules/@portabletext/react/dist/react-portable-text.mjs 162:54-73
Can't import the named export 'LIST_NEST_MODE_HTML' from non EcmaScript module (only default export is available)
###/node_modules/@portabletext/react/dist/react-portable-text.mjs 307:15-29
Can't import the named export 'buildMarksTree' from non EcmaScript module (only default export is available)
###/node_modules/@portabletext/react/dist/react-portable-text.mjs 144:38-51
Can't import the named export 'createContext' from non EcmaScript module (only default export is available)
###/node_modules/@portabletext/react/dist/react-portable-text.mjs 186:8-27
Can't import the named export 'isPortableTextBlock' from non EcmaScript module (only default export is available)
###/node_modules/@portabletext/react/dist/react-portable-text.mjs 180:8-35
Can't import the named export 'isPortableTextListItemBlock' from non EcmaScript module (only default export is available)
###/node_modules/@portabletext/react/dist/react-portable-text.mjs 177:8-33
Can't import the named export 'isPortableTextToolkitList' from non EcmaScript module (only default export is available)
###/node_modules/@portabletext/react/dist/react-portable-text.mjs 183:8-33
Can't import the named export 'isPortableTextToolkitSpan' from non EcmaScript module (only default export is available)
###/node_modules/@portabletext/react/dist/react-portable-text.mjs 189:8-37
Can't import the named export 'isPortableTextToolkitTextNode' from non EcmaScript module (only default export is available)
###/node_modules/@portabletext/react/dist/react-portable-text.mjs 162:17-26
Can't import the named export 'nestLists' from non EcmaScript module (only default export is available)
###/node_modules/@portabletext/react/dist/react-portable-text.mjs 250:12-27
Can't import the named export 'spanToPlainText' from non EcmaScript module (only default export is available)
###/node_modules/@portabletext/react/dist/react-portable-text.mjs 163:27-37
Can't import the named export 'useContext' from non EcmaScript module (only default export is available)
###/node_modules/@portabletext/react/dist/react-portable-text.mjs 149:16-23
Can't import the named export 'useMemo' from non EcmaScript module (only default export is available)
###/node_modules/@portabletext/react/dist/react-portable-text.mjs 164:21-28
Can't import the named export 'useMemo' from non EcmaScript module (only default export is available)
###/node_modules/@portabletext/react/dist/react-portable-text.mjs 167:21-28
Can't import the named export 'useMemo' from non EcmaScript module (only default export is available)
###/node_modules/@portabletext/react/dist/react-portable-text.mjs 33:0-52
Can't reexport the named export 'toPlainText' from non EcmaScript module (only default export is available)
Error in browser console:
Uncaught TypeError: undefined is not a function
at Module.../../node_modules/@portabletext/react/dist/react-portable-text.mjs (static/js/bundle.js:6036:83)
Not clear to me if this is mostly an issue with Expo, and/or if there's potentially some sort of webpack config change I can make to resolve it. Any pointers greatly appreciated.
A real example from a blog with next js, typescript and sanity of how to render text, images and youtube videos would be very helpful. If anyone has an example, it would be greatly appreciated, since I find the @portabletext/react guides a bit confusing and they generate errors. Thank you very much.
I'm building a project with Sanity, Typescript, ViteJS and React, and wanted to incorporate the PortableText component.
Unfortunately, when running tsc
I get errors from this package, or more specifically from the toolkit
package. See the errors below.
Seems like this is due to my tsconfig
including this setting: "noUncheckedIndexedAccess": true,
I would expect to be able to use this package with that setting enabled. I think the fix must be employed in the toolkit
package. Could you enable the tsconfig setting noUncheckedIndexedAccess
in toolkit
and then in this repo?
node_modules/@portabletext/react/src/toolkit/buildMarksTree.ts:37:7 - error TS2532: Object is possibly 'undefined'.
37 lastNode.children.push({...span, _type: '@span', children: [], markType: '<unknown>'})
~~~~~~~~
node_modules/@portabletext/react/src/toolkit/buildMarksTree.ts:46:22 - error TS2532: Object is possibly 'undefined'.
46 const mark = nodeStack[pos].markKey
~~~~~~~~~~~~~~
node_modules/@portabletext/react/src/toolkit/buildMarksTree.ts:67:15 - error TS2532: Object is possibly 'undefined'.
67 _key: span._key,
~~~~
node_modules/@portabletext/react/src/toolkit/buildMarksTree.ts:82:28 - error TS2345: Argument of type 'PortableTextSpan | ArbitraryTypedObject | undefined' is not assignable to parameter of type 'PortableTextSpan | TypedObject'.
Type 'undefined' is not assignable to type 'PortableTextSpan | TypedObject'.
82 if (isPortableTextSpan(span)) {
~~~~
node_modules/@portabletext/react/src/toolkit/buildMarksTree.ts:91:58 - error TS2769: No overload matches this call.
Overload 1 of 2, '(...items: ConcatArray<ToolkitTextNode | ToolkitNestedPortableTextSpan<MarkDefinition> | ArbitraryTypedObject>[]): (ToolkitTextNode | ... 1 more ... | ArbitraryTypedObject)[]', gave the following error.
Argument of type 'ArbitraryTypedObject | undefined' is not assignable to parameter of type 'ConcatArray<ToolkitTextNode | ToolkitNestedPortableTextSpan<MarkDefinition> | ArbitraryTypedObject>'.
Type 'undefined' is not assignable to type 'ConcatArray<ToolkitTextNode | ToolkitNestedPortableTextSpan<MarkDefinition> | ArbitraryTypedObject>'.
Overload 2 of 2, '(...items: (ToolkitTextNode | ToolkitNestedPortableTextSpan<MarkDefinition> | ArbitraryTypedObject | ConcatArray<...>)[]): (ToolkitTextNode | ... 1 more ... | ArbitraryTypedObject)[]', gave the following error.
Argument of type 'ArbitraryTypedObject | undefined' is not assignable to parameter of type 'ToolkitTextNode | ToolkitNestedPortableTextSpan<MarkDefinition> | ArbitraryTypedObject | ConcatArray<...>'.
Type 'undefined' is not assignable to type 'ToolkitTextNode | ToolkitNestedPortableTextSpan<MarkDefinition> | ArbitraryTypedObject | ConcatArray<...>'.
91 currentNode.children = currentNode.children.concat(span)
~~~~
node_modules/@portabletext/react/src/toolkit/buildMarksTree.ts:122:43 - error TS2532: Object is possibly 'undefined'.
122 occurences[mark] = occurences[mark] ? occurences[mark] + 1 : 1
~~~~~~~~~~~~~~~~
node_modules/@portabletext/react/src/toolkit/buildMarksTree.ts:128:28 - error TS2345: Argument of type 'PortableTextSpan | TypedObject | undefined' is not assignable to parameter of type 'PortableTextSpan | TypedObject'.
Type 'undefined' is not assignable to type 'PortableTextSpan | TypedObject'.
128 isPortableTextSpan(sibling) &&
~~~~~~~
node_modules/@portabletext/react/src/toolkit/buildMarksTree.ts:171:9 - error TS2532: Object is possibly 'undefined'.
171 if (node._type === '@span' && node.children) {
~~~~
node_modules/@portabletext/react/src/toolkit/buildMarksTree.ts:171:35 - error TS2532: Object is possibly 'undefined'.
171 if (node._type === '@span' && node.children) {
~~~~
node_modules/@portabletext/react/src/toolkit/nestLists.ts:23:26 - error TS2345: Argument of type 'T | undefined' is not assignable to parameter of type 'TypedObject | PortableTextBlock<MarkDefinition, PortableTextSpan | ArbitraryTypedObject>'.
Type 'undefined' is not assignable to type 'TypedObject | PortableTextBlock<MarkDefinition, PortableTextSpan | ArbitraryTypedObject>'.
23 if (!isListItemBlock(block)) {
~~~~~
node_modules/@portabletext/react/src/toolkit/nestLists.ts:24:17 - error TS2345: Argument of type 'T | undefined' is not assignable to parameter of type 'NestListsOutputNode<T>'.
Type 'undefined' is not assignable to type 'NestListsOutputNode<T>'.
24 tree.push(block)
~~~~~
node_modules/@portabletext/react/src/toolkit/nestLists.ts:79:38 - error TS2345: Argument of type 'NestListsOutputNode<T> | undefined' is not assignable to parameter of type 'TypedObject | PortableTextBlock<MarkDefinition, PortableTextSpan | ArbitraryTypedObject>'.
Type 'undefined' is not assignable to type 'TypedObject | PortableTextBlock<MarkDefinition, PortableTextSpan | ArbitraryTypedObject>'.
79 const match = findListMatching(tree[tree.length - 1], block)
~~~~~~~~~~~~~~~~~~~~~
node_modules/@portabletext/react/src/toolkit/nestLists.ts:94:38 - error TS2345: Argument of type 'NestListsOutputNode<T> | undefined' is not assignable to parameter of type 'TypedObject | PortableTextBlock<MarkDefinition, PortableTextSpan | ArbitraryTypedObject>'.
94 const match = findListMatching(tree[tree.length - 1], {level: block.level || 1})
peer deps list ^17, but create-react-app sets up with v18. Does this work with version 18? If so can the peer dep be updated to include it please?
ReactServerComponentsError:
You're importing a component that needs createContext. It only works in a Client Component but none of its parents are marked with "use client", so they're Server Components by default.
import { nestLists, LIST_NEST_MODE_HTML, isPortableTextToolkitList, isPortableTextListItemBlock, isPortableTextToolkitSpan, spanToPlainText, isPortableTextBlock, isPortableTextToolkitTextNode, buildMarksTree } from "@portabletext/toolkit";
export { toPlainText } from "@portabletext/toolkit";
import React, { createContext, useMemo, useContext } from "react";
^^^^^^^^^^^^^
The error was caused by importing '@portabletext/react/dist/react-portable-text.mjs' in './app/blogs/[slug]/page.tsx'.
Maybe one of these should be marked as a client entry with "use client":
The current workaround is likely to wrap it with a customer wrapper that as 'use client'.
A real example from a blog with next js, typescript and sanity of how to render audio player and code block would be very helpful. If anyone has an example, it would be greatly appreciated, since I find the @portabletext/react guides a bit difficult to understand. Thank you very much.
Hi there! Unsure if I'm just doing something wrong, or if it's an actual bug (it's likely the former).
I'm attempting to customize link
components coming back from Sanity, and none of the marks
are rendering inside the view. Here's a reproduction in CodeSandbox. I modified the text, but left everything else the same as it's coming from Sanity. Am I maybe missing something in the query from Sanity (I'm using the pretty standard blog example schema)?
Here's the body
schema for the Sanity schema:
defineField({
name: 'body',
title: 'Body',
type: 'blockContent'
})
and the blockContent
schema:
defineArrayMember({
title: 'Block',
type: 'block',
styles: [
{ title: 'Normal', value: 'normal' },
{ title: 'H1', value: 'h1' },
{ title: 'H2', value: 'h2' },
{ title: 'H3', value: 'h3' },
{ title: 'H4', value: 'h4' },
{ title: 'Quote', value: 'blockquote' }
],
lists: [{ title: 'Bullet', value: 'bullet' }],
marks: {
decorators: [
{ title: 'Strong', value: 'strong' },
{ title: 'Emphasis', value: 'em' }
],
annotations: [
{
title: 'URL',
name: 'link',
type: 'object',
fields: [
{
title: 'URL',
name: 'href',
type: 'url'
}
]
}
]
}
}),
Sanity API Version: 2024-03-10
I should note that in the project where I'm using this, I also have a custom h2
element, and it renders fine. That makes me think I'm missing something obvious with links, or something in the data has changed since the library was last published?
Here's what the HTML output looks like:
And how I'm defining it in Sanity Studio:
Thanks for any help / guidance!
I'm looking for a list of all components that are currently available on portable text that I can serialize, similar with what we find here https://github.com/coreyward/react-portable-text
For instance, under the "block" section in the readme, there's the following comment: // Ex. 1: customizing common block types
. Where can I find a list of these common block types?
I get this console warning when pulling data from Sanity to a React/Gatsby app:
react_devtools_backend.js:3973 Warning: validateDOMNesting(...): <p> cannot appear as a descendant of <p>.
at p
at normal (webpack-internal:///./node_modules/@portabletext/react/dist/react-portable-text.mjs:132:14)
at PortableText (webpack-internal:///./node_modules/@portabletext/react/dist/react-portable-text.mjs:165:10)
Data looks like this (passed as value prop in <Portable Text value={data}/>
:
{
"_key": "422b2df8e2a1",
"_type": "block",
"children": [
{
"_key": "33d2dcb9b87f0",
"_type": "span",
"marks": [],
"text": "Some text here."
}
],
"markDefs": [],
"style": "normal"
}
Happens on all block content. This might not be judged as an error as things do work, but annoying to always have it in the console.
I am struggling to get this to work. This is my code can anybody give me a steer as to what I am doing wrong? There is no effect from the styling component.
const myPortableTextComponents = {
block: {
h1: ({ children }) => {
return (
<h1 style={{ color: "blue" }}>
{children}
</h1>
)
},
}
}
I am calling this with...
<PortableText
value={page.content}
component={myPortableTextComponents}
/>
I am using Sanity.io in my Nextjs project. My nextjs app uses Tailwind. The issue is that on my frontend where users can see my site the styling is not matching what is shown in Sanity.io backend. Some examples would be that my bullet list and number list are missing the dots or the numbers as well as the indent. If I go to my global.css and remove @tailwind base; then everything shows correctly on the frontend as it show on Sanity.io backend. It's like Tailwind has conflicts with PortableText.
Again the formatting that is presented on Sanity backend does not show the same while using the default settings Nextjs with Tailwind. However if I remove the following from the default global.css @tailwind base; everything present on Nextjs frontend the way it should The only problem is that I need Tailwind
Previously with @sanity/block-content-to-react
you could use children
in your custom blocks
component:
import BaseBlockContent from '@sanity/block-content-to-react';
const components = {
types: {
block(props) {
const { children } = props;
return <div>{children}</div>;
}
},
};
function MyPage(props) {
return (
<BaseBlockContent components={components} />
);
}
Now with this package the attribute is no longer available in props. This is the code I'm using to compute it myself as a workaround, which hopefully helps someone else.
import { PortableText } from '@portabletext/react';
import { buildMarksTree } from '@portabletext/toolkit';
const components = {
types: {
block(props) {
const { value, renderNode } = props;
const children = buildMarksTree(value).map((child, i) => (
renderNode({
node: child,
isInline: true,
index: i,
renderNode,
})
));
return <div>{children}</div>;
}
}
};
function MyPage(props) {
return (
<PortableText components={components} />
);
}
I can't find any information on how I can target and style nested lists.
Sanity uses "a series of list item blocks with the same level and listItem properties will be grouped into a virtual one inside of this library." My rich text is inputted as follows
and is seen queried like this:
"2": {
"children": [{ }],
"level": 1,
"listItem": "number",
"markDefs": [],
"style": "normal",
"_key": "2cc0186eb9d3",
"_type": "block"
},
"3": {
"children": [{ }],
"level": 2,
"listItem": "number",
"markDefs": [],
"style": "normal",
"_key": "984f45cfba95",
"_type": "block"
},
"4": {
"children": [{ }],
"level": 2,
"listItem": "number",
"markDefs": [],
"style": "normal",
"_key": "730d9b626b42",
"_type": "block"
}
}
But is rendered without grouping the level 2 items with the same indentation treatment?
export default function RichText({ variant = 'default', richText }) {
let components = {
list: {
// Ex. 1: customizing common list types
bullet: ({ children }) => <ul className="mt-xl">{children}</ul>,
number: ({ children }) => <ol className="mt-lg">{children}</ol>,
// Ex. 2: rendering custom lists
checkmarks: ({ children }) => <ol className="m-auto text-lg">{children}</ol>,
},
listItem: {
number: ({ children }) => <Typography className='boo' paragraph={true} component='li' sx={{ color: 'red' }} >{children}</Typography>,
},
}
return (
<>
{richText.map((block) => {
return (
<PortableText
key={block._key}
value={block}
components={components}
/>
)
})}
</>
)
};
How can we target the second level to style them properly? Am I misunderstanding how the grouping of levels should be operating?
I'm having trouble targeting the default p tags inside a Block. They are marked as span and as far as I can tell, based on the docs, I should be targeting those correctly. I'm obviously missing something though
The data:
"description": [
{
"_key": "0b71cdcbcc5a",
"_type": "block",
"children": [
{
"_key": "259de42897910",
"_type": "span",
"marks": [],
"text": "Some text to see if it works"
}
],
"markDefs": [],
"style": "normal"
}
]
The components (ended up trying whatever I could think of):
const components = {
block: {
span: ({ children }) => <Text>{children}</Text>,
bullet: ({ children }) => <Text>{children}</Text>,
p: ({ children }) => <Text>{children}</Text>,
},
list: {
bullet: ({ children }) => <View>{children}</View>,
number: ({ children }) => <Text>{children}</Text>
},
listItem: {
bullet: ({ children }) => <Text>{children}</Text>
},
marks: {
em: ({children}) => <Text>{children}</Text>,
span: ({children}) => <Text>{children}</Text>,
p: ({children}) => <Text>{children}</Text>,
},
};
Any ideas on where I'm going wrong here? It works just fine for Lists n stuff just somehow not the span / p tags
The only kinda alternative I found so far is using toPlainText
which works but kinda curious if there is another way
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.