InlineWysiwyg crashes after updating Tina node packages

I’ve upgraded the following tina packages:

  • “react-tinacms-editor”: “^0.51.8”,
  • “react-tinacms-inline”: “^0.52.5”,
  • “tinacms”: “^0.41.0”,

Which then made the project crash, because they couldn’t find the module react-final-form. I added it with yarn add which solved that, but then my MarkdownField keeps crashing with the following error:

Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.

Check the render method of `Markdown`.

The Markdown component looks like this:

import Link from 'next/link'
import { BlocksControls } from 'react-tinacms-inline'
import { InlineWysiwyg } from 'react-tinacms-editor'
import ReactMarkdown from 'react-markdown'
import gfm from 'remark-gfm'
import styled from 'styled-components'
import { media } from '../MediaTemplate'


const renderers = {
  link: (props) => {
    if (props.href.substr(0, 4) === 'http') {
      return <StyledAnchor href={props.href} target="_blank" rel="noreferrer">{props.children}</StyledAnchor>
    } else {
      // This is an internal link
      return <Link
        href={props.href}
        as={props.page}
        passHref
      >
        <StyledLink>
          {props.children}
        </StyledLink>
      </Link>
    }
  }
}

function Markdown({ data, index }) {

  return (
    <BlocksControls index={index} focusRing={{ offset: 10 }} insetControls={false} for>
      <ParagraphBackground >
        <ParagraphText>
          <InlineWysiwyg name="markdownBody" format="markdown" >
            <ReactMarkdown plugins={[gfm]} renderers={renderers} source={data.markdownBody} />
          </InlineWysiwyg>
        </ParagraphText>
      </ParagraphBackground>
    </BlocksControls>
  )
}

export const markdownBlock = {
  Component: Markdown,
  template: {
    label: 'Markdown',
    fields: [
    ],
  },
}

I think I can see that the react-tinacms-editor package doesn’t export InlineWysiwyg but Wysiwyg; it still doesn’t work, as it crashed with an error that says:

I’ve looked at the react-tinacms-editor documentation, and tried to implement it in the following way:

import { media } from '../MediaTemplate'
import { useCMS } from '@tinacms/toolkit'
import { useEffect, useState } from 'react'

function Markdown(props) {

  const cms = useCMS()
  const [{ InlineWysiwyg }, setEditor] = useState({})

  useEffect(() => {
    if (!InlineWysiwyg && cms.enabled) {
      import('react-tinacms-editor').then(setEditor)
    }
    return () => (InlineWysiwyg ? setEditor(null) : null)
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [cms.enabled])

  if (InlineWysiwyg) {
    return (
      <InlineWysiwyg {...props} />
    )
  }

  return props.children || "testing"
}

export const markdownBlock = {
  Component: Markdown,
  template: {
    label: 'Markdown',
    fields: [
    ],
  },
}

The component then only returns the string, despite that I can debug into the useEffect where it calls setEditor. I’ve then tried to manually call setEditor(Wysiwyg) like this:

import("react-tinacms-editor").then(
        ({ MarkdownFieldPlugin, HtmlFieldPlugin, Wysiwyg }) => {
          cms.plugins.add(MarkdownFieldPlugin)
          cms.plugins.add(HtmlFieldPlugin)
          setEditor(Wysiwyg)
        })

Which then of course gives another error :sweat_smile:

Error: Should have a queue. This is likely a bug in React. Please file an issue.

What am I missing? The component worked well before as an inline block in a tinaCms form.

Update

I’ve now created a new InlineWysiwyg component that looks like this:


import { useCMS } from '@tinacms/toolkit'
import { useMemo, useState } from 'react'

export function InlineWysiwyg(props) {
  const cms = useCMS()
  const [{ Wysiwyg }, setEditor] = useState({})

  useMemo(() => {
    if (!Wysiwyg && cms.enabled) {
      import("react-tinacms-editor").then(setEditor)
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [cms.enabled])

  console.log("props wysiwyg", props)

  if (Wysiwyg) {
    return (
      <Wysiwyg
        {...props}
        sticky='62px'
        imageProps={{
          /** uploadDir is path from 'public'
           * as NextGithubMediaStore prepends public
           * to the paths. `imageProps` can be overridden
           * on the component, see blog/[slug].
           */
          uploadDir: () => 'img/',
          parse: media => media.id,
          ...props.imageProps,
        }}
        input={{ value: props.children.children || "", onChange: (e) => { console.log("e", e) } }}
      />
    )
  }

  return props.children
}

Where I’ve replaced InlineWysiwyg with Wysiwyg, because that’s what the react-tinacms-editor exports. This component then wrap around the above Markdown component.

I had to add the input prop to it manually, because it crashed where it said that it couldn’t read input value of undefined. The component does render now but it doesn’t change the value in Markdown field which I guess is expected, as the input.onChange() I’ve provided doesn’t do anything.

New Update

Looks like it works if I downgrade the react-tinacms-editor package to version 0.50.0, and converts the InlineWysiwyg component to the following:


import { useCMS } from '@tinacms/toolkit'
import { useEffect, useState } from 'react'

export function InlineWysiwyg(props) {
  const cms = useCMS()
  const [{ InlineWysiwyg }, setEditor] = useState({})

  useEffect(() => {
    if (!InlineWysiwyg && cms.enabled) {
      import("react-tinacms-editor").then(setEditor)
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [cms.enabled])


  if (InlineWysiwyg) {
    return (
      <InlineWysiwyg
        {...props}
        sticky='62px'
        imageProps={{
          /** uploadDir is path from 'public'
           * as NextGithubMediaStore prepends public
           * to the paths. `imageProps` can be overridden
           * on the component, see blog/[slug].
           */
          uploadDir: () => 'img/',
          parse: media => media.id,
          ...props.imageProps,
        }}
      />
    )
  }

  return props.children
}