paramander / contentful-rich-text-vue-renderer

Render Contentful Rich Text field using Vue
https://www.npmjs.com/package/contentful-rich-text-vue-renderer
MIT License
38 stars 12 forks source link

Optionally removing BLOCKS.PARAGRPHS within BLOCKS.LIST_ITEM (or other nodes) #24

Closed bryanjhickey closed 2 years ago

bryanjhickey commented 3 years ago

Working through an example for REACT but I'm unable to figure our the exact way to accomplish this with Vue

Here is the REACT example:

[BLOCKS.LIST_ITEM]: (node, children) =>
node.content.some(childNode =>
childNode.nodeType === `text` &&
childNode.marks.some(mark => mark.type === MARKS.CODE)) ? children :
<div className="blogpost-text">{children}</div>

Basically, working with nested BLOCK.PARAGRAPH nodes nested inside text elements that should not render the <p> tags.

Any thoughts?

tolgap commented 3 years ago

If you want to remove paragraphs from BLOCKS.LIST_ITEM, and only focus on the content of the paragraphs, you can override it using this following nodeRenderer:

[BLOCKS.LIST_ITEM]: (node, key, h, next) => {
  node.content = node.content.map(listItemNode =>
    listItemNode.nodeType === BLOCKS.PARAGRAPH ? listItemNode.content : listItemNode
  ).flat()
  return h('li', { key }, next(node.content, key, h, next))
},

Here is a Jest test case for easy testing:

const withDocument = content => {
  return {
    nodeType: 'document',
    data: {},
    content: content
  };
};

describe("LIST_ITEM with paragraphs", () => {
  const document = withDocument([
    {
      nodeType: BLOCKS.LIST_ITEM,
      content: [
        {
          nodeType: BLOCKS.PARAGRAPH,
          content: [
            {
              nodeType: 'text',
              value: 'Hello world.',
              marks: [{ type: MARKS.CODE }],
            },
          ]
        },
        {
          nodeType: 'text',
          value: 'Some other text',
          marks: []
        }
      ]
    }
  ]);
  const nodeRenderers = {
    [BLOCKS.LIST_ITEM]: (node, key, h, next) => {
      node.content = node.content.map(listItemNode =>
        listItemNode.nodeType === BLOCKS.PARAGRAPH ? listItemNode.content : listItemNode
      ).flat()
      return h('li', { key }, next(node.content, key, h, next))
    },
  };
  const rendered = mount(RichText, { propsData: { document, nodeRenderers } });

  it("removes the paragraphs from list item", () => {
    expect(rendered.html()).toBe('<li><code>Hello world.</code>Some other text</li>');
  });
});
bryanjhickey commented 3 years ago

Excellent. Thanks so much @tolgap

bryanjhickey commented 3 years ago

EDIT:

I'm building a #nuxt + #contentful site and I'm having an issue with one of the rich text field nodes.

This is the section of code that causes the error:

[BLOCKS.LIST_ITEM]: (node, key, h, next) => {
  node.content = node.content.map(listItemNode =>
    listItemNode.nodeType === BLOCKS.PARAGRAPH ? listItemNode.content : listItemNode
  ).flat()
  return h('li', { key }, next(node.content, key, h, next))
},

The error I'm getting is:

You may have an infinite update loop in a component render function.

I believe the issue lays with the .map method that I'm using to remove <p> tags which are rendered by default as children of BLOCKS.LIST_ITEM nodes by Contentful.

Why is the above code resulting in an infinite update loop? How can I resolve this?

The full code example is here: https://gist.github.com/bryanjhickey/44abe46ed13d30e518d40df19a62000b

I'd be grateful for any help in understanding what I've done wrong here?

tolgap commented 2 years ago

This is fixed in v2.1.0. There was some mutating code in one of the render methods. If the error still persists, please open a new issue 🚀 .