remarkjs / react-remark

React component and hook to use remark to render markdown
https://remarkjs.github.io/react-remark
MIT License
208 stars 7 forks source link

How to retrieve code fence metadata? #1

Closed MatthewCaseres closed 4 years ago

MatthewCaseres commented 4 years ago
import React from "react";
import { Remark } from "@christianmurphy/react-remark";

const mycode = `
\`\`\`lol filename=bashrc
lets go
\`\`\`
`;

export default function Lol() {
  return (
    <Remark
      remarkParseOptions={{ commonmark: true }}
      remarkToRehypeOptions={{ commonmark: true }}
      rehypeReactOptions={{
        createElement: React.createElement,
        components: {
          code: (props) => {
            console.log(props);
            return <code {...props}>{props.children as string}</code>;
          },
        },
      }}
    >
      {mycode}
    </Remark>
  );
}

I am curious how I should retrieve metadata from the code fence. Right now I am seeing {className: "language-lol", children: ["lets go↵"], ...(stuff that doesn't seem to contain what I want)}. Any advice?

Also in your examples the rehypeReactOptions do not have createElement: React.createElement. This field seems to be required, do the docs need updating or am I missing something?

ChristianMurphy commented 4 years ago

Thanks for reaching out @MatthewCaseres!

I am curious how I should retrieve metadata from the code fence

The flow of data is:

                                                             react-remark
+---------------------------------------------------------------------------------------------------------------------------------------------+
|                                                                                                                                             |
|            +----------+        +----------------+        +---------------+       +----------------+       +--------------+                  |
|            |          |        |                |        |               |       |                |       |              |                  |
| -markdown->+  remark  +-mdast->+ remark plugins +-mdast->+ remark-rehype +-hast->+ rehype plugins +-hast->+ rehype-react +-react elements-> |
|            |          |        |                |        |               |       |                |       |              |                  |
|            +----------+        +----------------+        +---------------+       +----------------+       +--------------+                  |
|                                                                                                                                             |
+---------------------------------------------------------------------------------------------------------------------------------------------+

it appears to be parsed by remark https://astexplorer.net/#/gist/70bd13086022edc1c2d4ddf08aaf37d4/53f8f650a5ed1aeb73dad23af9762cc765e946f0 and lost in the translation from mdast to hast remark-rehype (mdast-util-to-hast) https://github.com/syntax-tree/mdast-util-to-hast/blob/914a6b77b9d363c588dcc6ef61f96053ec1b3b1e/lib/handlers/code.js this can be handled by adding a custom handler for code to pass the meta https://github.com/syntax-tree/mdast-util-to-hast/tree/main#optionshandlers Or, by raising an issue at https://github.com/syntax-tree/mdast-util-to-hast/issues to have the meta field passed by default.

Also in your examples the rehypeReactOptions do not have createElement: React.createElement. This field seems to be required, do the docs need updating or am I missing something?

It isn't required. This is tested in the stories https://github.com/ChristianMurphy/react-remark/blob/0fabb1526aca3f615baff8b9c94dce9fc114d9f3/stories/remark-component.stories.tsx (which can be tested live at https://christianmurphy.github.io/react-remark/?path=/story/*) and in the unit tests https://github.com/ChristianMurphy/react-remark/blob/0fabb1526aca3f615baff8b9c94dce9fc114d9f3/test/remark-component.test.tsx#L8 which are passing https://github.com/ChristianMurphy/react-remark/actions/runs/155491590 More information, likely in the form of a runnable example of the issue, would be needed to help track down what's going on in your setup.

MatthewCaseres commented 4 years ago

Thank you so much for the detailed answer. To clarify on the createElement comment, I am talking about the section in the bottom "Pass options" where you have

rehypeReactOptions: {
    components: {
      p: props => <p className="custom-paragraph" {...props} />,
    },
  },

I was saying I think that the pass options section should read like

rehypeReactOptions={{
        createElement: React.createElement,
        components: {
          code: (props) => {
            p: props => <p className="custom-paragraph" {...props} />,
          },
        },
      }}

In @chrstianmurphy/react-remark/dist/index.d.ts there is rehypeReactOptions?: RehypeReactOptions<typeof createElement>; where the options from rehype react are

  interface Options<H extends CreateElementLike> {
    createElement: H
    ...

TypeScript gives me an error when I omit createElement. I could not find any examples in the stories using rehypeReactOptions., Will provide reproducible example if needed.

ChristianMurphy commented 4 years ago

TypeScript gives me an error when I omit createElement

this has been resolved with #2 making createElement inside rehype-react optional