-
-
Notifications
You must be signed in to change notification settings - Fork 37
Custom components for mdast nodes #23
Comments
By the way, somehow properties seem get lost along the way. For example the |
Thanks for writing this out in such a detailed issue, it helps a lot :) So, I introduced the recent changes to ensure less stuff is in this project, but that does mean there’s more abstraction, which of course makes things harder. On the other hand, if you create a remark plug-in which sets a Did you see the info at the bottom of Maybe this isn’t enough, and we should implement some other mapping as well, such as somehow passing the original mdast/hast node to a function before passing it to P.S. Whoops, thanks for letting me know, I’ll dig into what’s going on with |
@herrstucki Ah, I forgot that of course sanitation is now on by default, defaulting to GitHub’s mechanism. That’s why all classes are stripped (take this for example: Maybe we should add a note that the sanitation is quite strict? |
So, if I do: const footnoteRenderer = (processor, options) => {
const transformer = (node) => {
const footnoteDefs = node.children.filter(n => n.type === 'footnoteDefinition');
footnoteDefs.forEach(n => {
n.data = {hName: 'Footnote'};
});
};
return transformer;
};
const markdownRenderer = remark().use(footnoteRenderer).use(reactRenderer, {
createElement(name, props, children) {
// Shouldn't `name` be 'Footnote' at some point?
console.log(name, props)
return React.createElement(name, props, children);
}
}) … it doesn't work. Any pointers? |
Regarding sanitation: shouldn't this schema allow {sanitize: {attributes: {'*': ['className']}}} (that doesn't work too 😅 ) |
It doesn’t? I get the correct results: var react = require('react');
var remark = require('remark');
var react = require('remark-react');
var doc = '```js\nfoo()\n```';
var vdom = remark().use(react, {
createElement: react.createElement,
sanitize: {attributes: {'*': ['className']}}
}).process(doc).contents;
console.log(require('util').inspect(vdom, {depth: null})); Yields: { '$$typeof': Symbol(react.element),
type: 'div',
key: 'h-1',
ref: null,
props:
{ children:
[ { '$$typeof': Symbol(react.element),
type: 'pre',
key: 'h-2',
ref: null,
props:
{ children:
[ { '$$typeof': Symbol(react.element),
type: 'code',
key: 'h-3',
ref: null,
props: { className: 'language-js', children: [ 'foo()\n' ] },
_owner: null,
_store: {} } ] },
_owner: null,
_store: {} } ] },
_owner: null,
_store: {} } |
Ah, I passed the |
That being said, this disallows all other attributes. I suggest using a deep cloning mechanism instead, and using // ...
var clone = require('clone');
var schema = clone(require('hast-util-sanitize/lib/github.json'))
// ...
schema.attributes['*'].push('className');
var vdom = remark().use(react, {
// ...
sanitize: schema
}).process(doc).contents;
// ... |
A quick update on this. I ended up just using This has two additional advantages:
So, thanks for creating such a modular system for text processing @wooorm! It's not easy to find the right integration point at first, but once I found it, it was very straight-forward 😄 |
@herrstucki Well, first of all I’m very happy that the way I set it all up allows you to quite easily set this up. 👍 But on the other hand I’m quite unhappy that the changes I made in 4b2e674 caused you to have to work around it. I’d love to see your code; maybe the current set-up already allows that, and the docs need to be changed, or if not, those features should be included! I also wanted to show that the below example shows how remark can be split across server/client:
var unified = require('unified');
var parse = require('remark-parse');
var doc = require('fs').readFileSync('example.md', 'utf8');
var proc = unified().use(parse);
var tree = proc.parse(doc);
// sendToClient(JSON.stringify(tree)); ...and var unified = require('unified');
var react = require('remark-react');
var tree = // JSON.parse(getFromClient())
var proc = unified().use(react);
var vdom = proc.stringify(tree);
// doSomethingWith(vdom); |
Things are still kind of in flux but I'll try to share what I came up with when it's settled a bit. I'm (almost) doing what you suggested in your example. I just don't use {
heading: (node, index /*, parent */) => React.createElement(`h${node.depth}`, {key: index}, visitChildren(node)),
//...
} Kinda off-topic for this repo, but when I split parser and compiler like this, I struggle with plugins which expect |
OK, I’d love to see what you come up with an allow similar behaviour in this project as well, or update the docs accordingly! Regarding failing modules, I’d love to know about those. Could you create issues on their respective projects? Or send me a message on Gitter! |
Hey, I'm struggling with a similar issue. I'd like to have remark render a react component. More specifically, I'd like for this input:
to render
I think I will need a custom tokenization plugin and make use of |
This is a quite different issue, as you’re not really dealing with markdown (which remark is all about), but with stuff embedded in markdown. First, to render Finally, you could also expect all HTML to be in fact JSX. Is there a reason to not allow |
Thanks for the quick response and sorry for not being clear. I mean I'd like for the said input to see the rendered gallery, so the evaluated component. Lets say I use the code from the remark-parse extension example. What I fail to understand is, how do I really introduce a new entity type (e.g.
I'd expect this to, on input |
Ah, nvm, got it!
|
Probably because Hey, I don’t mind helping you, but this issue is not the place. I think the remark channel on Gitter is. EDIT: I now see your comment, glad it worked. |
remarkReactComponents
andcreateElement
are nice but I would like to be able to customize rendering a few levels lower. By the time data gets to those extension points, all semantic information beyond the HTML element is lost.For example, I would like to use my own React components for footnote references and footnote definitions. After some digging (phew 😅 ), I think the point to do that would be at the MDAST level, i.e. through my own plugin which I
use()
before this plugin.Now, I didn't understand how to modify the
footnoteDefinition
node in a way (e.g. by adding acomponent
prop) that gets preserved bymdast-util-to-hast
because it turns unknown nodes intodiv
s and somehow when I setproperties
on a node they don't show up in thecreateElement
props.Maybe this all sounds a bit confusing but currently I am confused 😁 (mainly by the multiple layers of abstraction). I'll try to summarize:
footnoteDefinition
node with a React component which receives the information about footnote definitions as data.createElement
.Maybe @wooorm can shed some light on this?
The text was updated successfully, but these errors were encountered: