rehype-pretty / rehype-pretty-code

Beautiful code blocks for Markdown or MDX.
https://rehype-pretty.pages.dev
MIT License
1.07k stars 64 forks source link

Avoid creating wrappers `<div data-rehype-pretty-code-fragment>` and `<span data-rehype-pretty-code-fragment>`` #50

Closed dimaMachina closed 1 year ago

dimaMachina commented 1 year ago

I want to suggest to avoid creating <div />/<span /> wrappers for code blocks/inline code blocks

Instead, data-rehype-pretty-code-fragment attribute can be attached directly in <pre />/<code /> elements

Before

<div data-rehype-pretty-code-fragment>
  <pre>
    ...

<span data-rehype-pretty-code-fragment>
  <code>
    ...

After

Before

<pre data-rehype-pretty-code-fragment>
  ...

<code data-rehype-pretty-code-fragment>
  ...
atomiks commented 1 year ago

As far as I can remember, this was done when refactoring to a rehype plugin after multiple theme support was added - if you're adding a theme transition, you can position the two light/dark code blocks absolutely in the fragment and then allow the colors to smoothly transition if not using CSS variables with Shiki.

But as it mentions, you should be able to work around it by replacing it with a real fragment in your MDX provider's components object, is it not possible?

Something like:

const components = {
  div(props) {
    if (props['data-rehype-pretty-code-fragment'] != null) {
      return <>{props.children}</>;
    }
    return <div {...props} />;
  }
}
dimaMachina commented 1 year ago

With your solution, it requires some workaround to attach data-rehype-pretty-code-fragment to props.children because it's useful attribute that says it's not a regular pre/code element but parsed by rehype-pretty-code

atomiks commented 1 year ago

That's also possible:

function rehypePrettyCodeTransform(Tag, props) {
  if (props['data-rehype-pretty-code-fragment'] != null) {
    return React.Children.map(props.children, child => {
      return React.cloneElement(child, {
        'data-rehype-pretty-code-fragment': '',
      });
    });
  }

  return <Tag {...props} />;
}

const components = {
  div: props => rehypePrettyCodeTransform('div', props),
  span: props => rehypePrettyCodeTransform('span', props),
};
atomiks commented 1 year ago

[data-rehype-pretty-code-fragment] is also useful for positioning nodes absolutely in general inside the code block, e.g. a language element.

It's also widely used in code searching on GitHub, and in tutorials, so it'd be breaking for no real gain (with a downside), so going to close as it has a workaround if necessary anyway.