GithubHelp home page GithubHelp logo

portabletext / react-portabletext Goto Github PK

View Code? Open in Web Editor NEW
281.0 7.0 29.0 4.77 MB

Render Portable Text with React

Home Page: https://portabletext.github.io/react-portabletext/

License: MIT License

TypeScript 99.79% Shell 0.21%
portable-text

react-portabletext's Introduction

@portabletext/react

npm versionnpm bundle sizeBuild Status

Render Portable Text with React.

Migrating from @sanity/block-content-to-react? Refer to the migration docs.

Table of contents

Installation

npm install --save @portabletext/react

Basic usage

import {PortableText} from '@portabletext/react'

<PortableText
  value={[/* array of portable text blocks */]}
  components={/* optional object of custom components to use */}
/>

Styling the output

The rendered HTML does not have any styling applied, so you will either render a parent container with a class name you can target in your CSS, or pass custom components if you want to control the direct markup and CSS of each element.

Customizing components

Default components are provided for all standard features of the Portable Text spec, with logical HTML defaults. You can pass an object of components to use, both to override the defaults and to provide components for your custom content types.

Provided components will be merged with the defaults. In other words, you only need to provide the things you want to override.

Note: Make sure the object does not change on every render - eg do not create the object within a React component, or if you do, use useMemo to ensure referential identity between renders for better performance.

const myPortableTextComponents = {
  types: {
    image: ({value}) => <img src={value.imageUrl} />,
    callToAction: ({value, isInline}) =>
      isInline ? (
        <a href={value.url}>{value.text}</a>
      ) : (
        <div className="callToAction">{value.text}</div>
      ),
  },

  marks: {
    link: ({children, value}) => {
      const rel = !value.href.startsWith('/') ? 'noreferrer noopener' : undefined
      return (
        <a href={value.href} rel={rel}>
          {children}
        </a>
      )
    },
  },
}

const YourComponent = (props) => {
  return <PortableText value={props.value} components={myPortableTextComponents} />
}

Available components

These are the overridable/implementable keys:

types

An object of React components that renders different types of objects that might appear both as part of the input array, or as inline objects within text blocks - eg alongside text spans.

Use the isInline property to check whether or not this is an inline object or a block.

The object has the shape {typeName: ReactComponent}, where typeName is the value set in individual _type attributes.

Example of rendering a custom image object:

import {PortableText} from '@portabletext/react'
import urlBuilder from '@sanity/image-url'
import {getImageDimensions} from '@sanity/asset-utils'

// Barebones lazy-loaded image component
const SampleImageComponent = ({value, isInline}) => {
  const {width, height} = getImageDimensions(value)
  return (
    <img
      src={urlBuilder()
        .image(value)
        .width(isInline ? 100 : 800)
        .fit('max')
        .auto('format')
        .url()}
      alt={value.alt || ' '}
      loading="lazy"
      style={{
        // Display alongside text if image appears inside a block text span
        display: isInline ? 'inline-block' : 'block',

        // Avoid jumping around with aspect-ratio CSS property
        aspectRatio: width / height,
      }}
    />
  )
}

const components = {
  types: {
    image: SampleImageComponent,
    // Any other custom types you have in your content
    // Examples: mapLocation, contactForm, code, featuredProjects, latestNews, etc.
  },
}

const YourComponent = (props) => {
  return <PortableText value={somePortableTextInput} components={components} />
}

marks

Object of React components that renders different types of marks that might appear in spans. Marks can either be simple "decorators" (eg emphasis, underline, italic) or full "annotations" which include associated data (eg links, references, descriptions).

If the mark is a decorator, the component will receive a markType prop which has the name of the decorator (eg em). If the mark is an annotation, it will receive both a markType with the associated _type property (eg link), and a value property with an object holding the data for this mark.

The component also receives a children prop that should (usually) be returned in whatever parent container component makes sense for this mark (eg <a>, <em>).

// `components` object you'll pass to PortableText w/ optional TS definition
import {PortableTextComponents} from '@portabletext/react'

const components: PortableTextComponents = {
  marks: {
    // Ex. 1: custom renderer for the em / italics decorator
    em: ({children}) => <em className="text-gray-600 font-semibold">{children}</em>,

    // Ex. 2: rendering a custom `link` annotation
    link: ({value, children}) => {
      const target = (value?.href || '').startsWith('http') ? '_blank' : undefined
      return (
        <a href={value?.href} target={target} rel={target === '_blank' && 'noindex nofollow'}>
          {children}
        </a>
      )
    },
  },
}

block

An object of React components that renders portable text blocks with different style properties. The object has the shape {styleName: ReactComponent}, where styleName is the value set in individual style attributes on blocks (normal being the default).

// `components` object you'll pass to PortableText
const components = {
  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>,

    // Ex. 2: rendering custom styles
    customHeading: ({children}) => (
      <h2 className="text-lg text-primary text-purple-700">{children}</h2>
    ),
  },
}

The block object can also be set to a single React component, which would handle block styles of any type.

list

Object of React components used to render lists of different types (bullet vs number, for instance, which by default is <ul> and <ol>, respectively).

Note that there is no actual "list" node type in the Portable Text specification, but a series of list item blocks with the same level and listItem properties will be grouped into a virtual one inside of this library.

const 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>,
  },
}

The list property can also be set to a single React component, which would handle lists of any type.

listItem

Object of React components used to render different list item styles. The object has the shape {listItemType: ReactComponent}, where listItemType is the value set in individual listItem attributes on blocks.

const components = {
  listItem: {
    // Ex. 1: customizing common list types
    bullet: ({children}) => <li style={{listStyleType: 'disclosure-closed'}}>{children}</li>,

    // Ex. 2: rendering custom list items
    checkmarks: ({children}) => <li>{children}</li>,
  },
}

The listItem property can also be set to a single React component, which would handle list items of any type.

hardBreak

Component to use for rendering "hard breaks", eg \n inside of text spans.

Will by default render a <br />. Pass false to render as-is (\n)

unknownMark

React component used when encountering a mark type there is no registered component for in the components.marks prop.

unknownType

React component used when encountering an object type there is no registered component for in the components.types prop.

unknownBlockStyle

React component used when encountering a block style there is no registered component for in the components.block prop. Only used if components.block is an object.

unknownList

React component used when encountering a list style there is no registered component for in the components.list prop. Only used if components.list is an object.

unknownListItem

React component used when encountering a list item style there is no registered component for in the components.listItem prop. Only used if components.listItem is an object.

Disabling warnings / handling unknown types

When the library encounters a block, mark, list or list item with a type that is not known (eg it has no corresponding component in the components property), it will by default print a console warning.

To disable this behavior, you can either pass false to the onMissingComponent property, or give it a custom function you want to use to report the error. For instance:

import {PortableText} from '@portabletext/react'

<PortableText
  value={[/* array of portable text blocks */]}
  onMissingComponent={false}
/>

// or, pass it a function:

<PortableText
  value={[/* array of portable text blocks */]}
  onMissingComponent={(message, options) => {
    myErrorLogger.report(message, {
      // eg `someUnknownType`
      type: options.type,

      // 'block' | 'mark' | 'blockStyle' | 'listStyle' | 'listItemStyle'
      nodeType: options.nodeType
    })
  }}
/>

Rendering Plain Text

This module also exports a function (toPlainText()) that will render one or more Portable Text blocks as plain text. This is helpful in cases where formatted text is not supported, or you need to process the raw text value.

For instance, to render an OpenGraph meta description for a page:

import {toPlainText} from '@portabletext/react'

const MetaDescription = (myPortableTextData) => {
  return <meta name="og:description" value={toPlainText(myPortableTextData)} />
}

Or to generate element IDs for headers, in order for them to be linkable:

import {PortableText, toPlainText, PortableTextComponents} from '@portabletext/react'
import slugify from 'slugify'

const LinkableHeader = ({children, value}) => {
  // `value` is the single Portable Text block of this header
  const slug = slugify(toPlainText(value))
  return <h2 id={slug}>{children}</h2>
}

const components: PortableTextComponents = {
  block: {
    h2: LinkableHeader,
  },
}

Typing Portable Text

Portable Text data can be typed using the @portabletext/types package.

Basic usage

Use PortableTextBlock without generics for loosely typed defaults.

import {PortableTextBlock} from '@portabletext/types'

interface MySanityDocument {
  portableTextField: (PortableTextBlock | SomeBlockType)[]
}

Narrow types, marks, inline-blocks and lists

PortableTextBlock supports generics, and has the following signature:

interface PortableTextBlock<
  M extends PortableTextMarkDefinition = PortableTextMarkDefinition,
  C extends TypedObject = ArbitraryTypedObject | PortableTextSpan,
  S extends string = PortableTextBlockStyle,
  L extends string = PortableTextListItemType,
> {}

Create your own, narrowed Portable text type:

import {PortableTextBlock, PortableTextMarkDefinition, PortableTextSpan} from '@portabletext/types'

// MARKS
interface FirstMark extends PortableTextMarkDefinition {
  _type: 'firstMark'
  // ...other fields
}

interface SecondMark extends PortableTextMarkDefinition {
  _type: 'secondMark'
  // ...other fields
}

type CustomMarks = FirstMark | SecondMark

// INLINE BLOCKS

interface MyInlineBlock {
  _type: 'myInlineBlock'
  // ...other fields
}

type InlineBlocks = PortableTextSpan | MyInlineBlock

// STYLES

type TextStyles = 'normal' | 'h1' | 'myCustomStyle'

// LISTS

type ListStyles = 'bullet' | 'myCustomList'

// CUSTOM PORTABLE TEXT BLOCK

// Putting it all together by specifying generics
// all of these are valid:
// type CustomPortableTextBlock = PortableTextBlock<CustomMarks>
// type CustomPortableTextBlock = PortableTextBlock<CustomMarks, InlineBlocks>
// type CustomPortableTextBlock = PortableTextBlock<CustomMarks, InlineBlocks, TextStyles>
type CustomPortableTextBlock = PortableTextBlock<CustomMarks, InlineBlocks, TextStyles, ListStyles>

// Other BLOCKS that can appear inbetween text

interface MyCustomBlock {
  _type: 'myCustomBlock'
  // ...other fields
}

// TYPE FOR PORTABLE TEXT FIELD ITEMS
type PortableTextFieldType = CustomPortableTextBlock | MyCustomBlock

// Using it in your document type
interface MyDocumentType {
  portableTextField: PortableTextFieldType[]
}

License

MIT © Sanity.io

react-portabletext's People

Contributors

christianhg avatar ecoscript[bot] avatar fritz-c avatar geball avatar hdoro avatar kadikraman avatar mariuslundgard avatar renovate[bot] avatar rexxars avatar semantic-release-bot avatar simeongriggs avatar snorrees avatar stipsan avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

react-portabletext's Issues

unknownBlockStyle is not working / does nothing

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>)

Type Guard

react-portable-text.tsx markKey

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

Screenshot 2022-11-20 at 20 24 42

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 <></>
  }

buildMarksTree.ts

website/node_modules/@portabletext/toolkit/src/buildMarksTree.ts. line 94

_key

Screenshot 2022-11-20 at 20 40 22

markDef

Screenshot 2022-11-20 at 20 43 47

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.

typescript example blog rendering of text, images and youtube videos

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.

Change to .mjs breaks usage in Expo web (React Native)

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.

cannot override types block

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

Feature request: Tables

It would be nice to have table customization or configuration possible for it.

If someone have a solution for this, please let me know!!

Can't get item position a list

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:
Screen Shot 2023-02-24 at 6 31 33 PM
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.

[Feature request] Add a component wrapper prop

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?

Warning: validateDOMNesting(...): <p> cannot appear as a descendant of <p>.

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.

Usage with Preact getting error: Type 'Element' is not assignable to type 'ReactNode'.

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.

  • Using Preact
  • Using Portable Text
  • This error happened
✖ 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/**/*"]
}

cc @SamScott3000

Issues using with Nextjs and tailwind

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

ReactServerComponentsError when using with Dynamic Routing in Next.js 13.4 App Router configuration

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'.

Marks Not Rendering

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:

Screenshot 2024-03-14 at 12 34 18 PM

And how I'm defining it in Sanity Studio:

Screenshot 2024-03-14 at 12 37 06 PM

Thanks for any help / guidance!

Named export 'LIST_NEST_MODE_HTML' not found.

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

Module Resolution issues when building with Astro

I have an issue with using this package to build a static site with Astro.

I've created a Codesandbox that renders Portable text.

Codesandbox

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.

Version 2.0.1 breaks backwards compatibility

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

Unknown block type "undefined", specify a component for it in the `components.types` prop

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>
  );
};

Unknown mark type, specify a component for it false positive?

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.

Cannot render embedded image

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} />

typescript example blog rendering of audio player and code block

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.

Hydration errors from nested portable text blocks

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} />
}

How to target p paragraph elements

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

[Feature Request] Provide a sort mechanism to define render order of marks

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.

Issue

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;
}

Proposal

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

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.


Using a curated preset maintained by


Sanity: The Composable Content Cloud

Pending Approval

These branches will be created by Renovate only once you click their checkbox below.

  • chore(deps): update pnpm to v8.15.8
  • chore(deps): update non-major (@commitlint/cli, @commitlint/config-conventional, @sanity/pkg-utils, @sanity/ui, @types/leaflet, @types/react, @types/react-dom, @typescript-eslint/eslint-plugin, @typescript-eslint/parser, esbuild, eslint-plugin-react-hooks, peter-evans/create-pull-request, prettier-plugin-packagejson, react, react-dom, react-is, styled-components, vite, vitest)
  • chore(deps): update dependency npm-run-all2 to v6
  • chore(deps): update dependency react-refractor to v3
  • chore(deps): update peaceiris/actions-gh-pages action to v4
  • chore(deps): update pnpm to v9
  • chore(deps): lock file maintenance
  • 🔐 Create all pending approval PRs at once 🔐

Ignored or Blocked

These are blocked by an existing closed PR and will not be recreated unless you click a checkbox below.

Detected dependencies

github-actions
.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@70a41aba780001da0a30141984ae2a0c95d8704e
.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
npm
package.json
  • @portabletext/toolkit ^2.0.15
  • @portabletext/types ^2.0.13
  • @babel/plugin-proposal-object-rest-spread ^7.20.7
  • @commitlint/cli ^19.2.1
  • @commitlint/config-conventional ^19.1.0
  • @sanity/pkg-utils ^6.4.1
  • @sanity/ui ^2.1.2
  • @types/leaflet ^1.9.9
  • @types/react ^18.2.75
  • @types/react-dom ^18.2.24
  • @types/refractor ^3.4.1
  • @types/ws ^8.5.10
  • @typescript-eslint/eslint-plugin ^7.6.0
  • @typescript-eslint/parser ^7.6.0
  • @vitejs/plugin-react ^4.2.1
  • commitizen ^4.3.0
  • cz-conventional-changelog ^3.3.0
  • esbuild ^0.20.2
  • 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.1
  • eslint-plugin-react-hooks ^4.6.0
  • leaflet ^1.9.4
  • npm-run-all2 ^5.0.2
  • prettier ^3.2.5
  • prettier-plugin-packagejson ^2.4.14
  • react ^18.2.0
  • react-dom ^18.2.0
  • react-is ^18.2.0
  • react-leaflet ^4.2.1
  • react-refractor ^2.1.7
  • refractor ^4.8.1
  • rimraf ^5.0.1
  • rollup-plugin-visualizer ^5.12.0
  • styled-components ^6.1.8
  • typescript ^5.4.5
  • vite ^5.2.8
  • vitest ^1.4.0
  • react ^17 || ^18
  • node ^14.13.1 || >=16.0.0
  • pnpm 8.15.6

  • Check this box to trigger a request for Renovate to run again on this repository

Can't do custom components

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.

Custom objects with children portable text objects are rendered as plain blocks

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

  1. Stricter type checking in this library, e.g.:
    if (isPortableTextBlock(node) && node._type === 'block') {
      return renderBlock(node, index, key, isInline)
    }
  1. 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.
  2. 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.

Type error on build  – 'Li' cannot be used as a JSX component.

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 \|     )

Getting TypeScript errors when using block component

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.

Children prop no longer available in custom block content

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} />
  );
}

PortableText components prop

Issue

  • component props default state of PortableText is only rendering paragraphs for marks

Raw JSON from Sanity Block

"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"
  }
],

BlockContent Component using PortableText

// 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>
  );
};

What is rendered

<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>

Environment

  • "@portabletext/react": "^1.0.2"
  • "gatsby": "^4.7.1",
  • "gatsby-source-sanity": "^7.3.2",
  • "@sanity/all relative packages": "^2.27.0"

Does not currently work with React Native.

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"

Does not work with lists

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>



Build Fail due to ReferenceError: createElement is not defined

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.

Nested Lists?

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

image

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?
image


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?

TypeScript usage?

I would love to have some docs showing how this is supposed to be used with TypeScript!

'React' is declared but its value is never read.

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?

Components documentation

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?

Typescript errors

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})

PortableText Typescript Error

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[]

Anchored Headings for Portable Text

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.

Can't Get Component to work

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}
                    />

react-portable-text has no property 'toPlainText"

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

CleanShot 2023-07-21 at 11 05 23

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.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.