markdown-to-jsx icon indicating copy to clipboard operation
markdown-to-jsx copied to clipboard

Paragraphs that start with valid HTML element or override do not include element or override within them

Open sunknudsen opened this issue 4 years ago • 2 comments

First things first, thanks for the amazing package.

Here is an example of the issue. I expected valid HTML elements would be included within the <p> tag.

Markdown

# Example

<strong>T</strong>his is a test

<Initial>T</Initial>his is anoter test

React

const Initial = styled.span`
  font-size: 4rem;
  padding-top: 4px;
  margin-right: 10px;
  line-height: 1;
  display: block;
  float: left;
`

<MarkdownToJSX
  options={{
    overrides: {
      Initial: Initial,
    },
  }}
>
  {md}
</MarkdownToJSX>

HTML

<h1 id="example">Example</h1>
<strong>T</strong>
<p>his is a test</p>
<span class="sc-fzpjYC kWuQbB">T</span>
<p>his is anoter test</p>

Expected HTML

<h1 id="example">Example</h1>
<p><strong>T</strong>his is a test</p>
<p><span class="sc-fzpjYC kWuQbB">T</span>his is anoter test</p>

sunknudsen avatar Feb 29 '20 22:02 sunknudsen

@sunknudsen I've come up against the same hurdle - did you manage to find a fix or a workaround?

WarcraftYax avatar Aug 03 '21 13:08 WarcraftYax

If it helps anyone, my workaround is the following:

Define a function that takes the compiler output and re-arranges the children using the logic of "if current child is a component, and the next child is a paragraph that starts with a space (your particular needs might warrant a different condition), then don't keep the current child and instead insert it at the start of the children of the next child".

export function collapseComponentsInsideParagraphsIfNecessary(output) {
  if (!Array.isArray(output.props.children)) return;

  const newChildren = [];
  for (let i = 0; i < output.props.children.length; i++) {
    const child = output.props.children[i];
    if (i === output.props.children.length - 1) {
      newChildren.push(child);
      break;
    }

    const childIsComponent = typeof child.type === 'function';
    if (!childIsComponent) {
      newChildren.push(child);
      continue;
    }

    const nextChild = output.props.children[i + 1];
    const nextChildIsParagraph = nextChild.type === 'p';
    if (!nextChildIsParagraph) {
      newChildren.push(child);
      continue;
    }

    const paragraphBeginsWithSpace =
      nextChild.props.children[0].charAt(0) === ' ';
    if (!paragraphBeginsWithSpace) {
      newChildren.push(child);
      continue;
    }

    nextChild.props.children.unshift(child);
    newChildren.push(nextChild);
    i++;
  }
  output.props.children.splice(0, output.props.children.length);
  newChildren.forEach((child) => output.props.children.push(child));
}

And then use it like:

const output = compiler(markdown, options);
collapseComponentsInsideParagraphsIfNecessary(output);

return <div className={'markdown__content'}>{output}</div>;

Where compiler is import { compiler } from 'markdown-to-jsx';


I would still very much like this to be the default behaviour of the library if the contributors agree that it would be more intuitive.

WarcraftYax avatar Aug 04 '21 10:08 WarcraftYax