Allow "type" to be a function (as a "component")
Closed this issue · 7 comments
Initial checklist
- I read the support docs
- I read the contributing guide
- I agree to follow the code of conduct
- I searched issues and couldn’t find anything (or linked relevant results below)
Problem
Related to #10. If we think it's cool to write unists as JSX, a natural conclusion is we must support components as well.
Solution
I propose to support this pattern:
const root = u(Comp, { id: 1 }, u("leaf", "leaf 1"), u("leaf", "leaf 2"));
Which will be equivalent to
const root = Comp({ id: 1, children: [u("leaf", "leaf 1"), u("leaf", "leaf 2")] });
We don't necessarily need to support "class components", just the simple idea that you can provide a function which will be called with props and children.
Alternatives
If we are to support JSX—there doesn't seem to be another way.
Hmm, not sure, I’d want a really good use case for functions-that-get-called-with-props.
This package is pretty tiny and used in a lot of places, I can see component support getting bigger and bigger and I’d rather not have that
I’d want a really good use case for functions-that-get-called-with-props.
True, I don't really have a compelling use-case that can't be implemented by calling the function myself. I'm just exploring the possibility if we allow writing ASTs as JSX. For example, we can have a component that selectively renders to either a blockquote
, or a paragraph
, and doing so declaratively by keeping it JSX.
I can see component support getting bigger and bigger
The idea of "component" here will be really simple. It would simply be
if (typeof type === "function") {
return type({ ...props, children: value });
}
I wonder whether a good higher-level mdastscript
might be better at all this then?
unist
accepts a string value
as well. Or nothing. And its impossible to discern props
from a node: hast has problems with this too, because button
elements can have a type
property for example: https://github.com/syntax-tree/hastscript/blob/2f8c133920fa57405815de3f3cdc21d1bc892444/lib/core.js#L78
Sigh yeah ambiguity is a problem. We probably can't do all this without deprecating a few APIs. This particular proposal doesn't really introduce ambiguity, though, since I'm proposing to allow Function
in addition to string
as type
, which always exists. #10 is more likely to be ambiguous, but we can still work around it by only collecting rest parameters when there are more than two parameters.
When you say mdastscript
, do you mean a hypothetical new package, or the deprecated existing one, or the newer mdast-builder
? The API design of mdast-builder
looks, frankly, even less appealing to me since it's not compatible with JSX at all.
I’m somewhat open to this, but not super excited about it either.
I’m not really sure what it’ll look like either, and how it’ll be used.
Yep, mdastscript
/mdast-builder
/etc are a hypothetical package that I myself don’t really need (I like how explicit and clear plain objects are, I don’t need to translate function calls to them in my head), but other folks have been asking about over the years.
Is this something you’d want to work on? Or can experiment with in some other place?
- This would make it easy to create broken nodes: those without a
type
field. Especially if we’d want users to write atype
in props, that would then make something like #10 (comment) even harder, because props is than an actual node - Another big question here is what
children
is, it could be a string (in which case you’d getvalue: string
in props), it could be missing (no extra fields in props), it could be an array (children: Array<Node>
in props).
Ok closing, I’m not really sure about the trade offs!