Skip to content
This repository has been archived by the owner on Oct 1, 2024. It is now read-only.

JSX Assignment Expressions #15

Closed
ticky opened this issue Jun 29, 2018 · 9 comments
Closed

JSX Assignment Expressions #15

ticky opened this issue Jun 29, 2018 · 9 comments

Comments

@ticky
Copy link
Member

ticky commented Jun 29, 2018

Currently, MDX does not support JSX assignment expressions. This is perhaps the one major missing feature in MDX which is present in Markdown Component Loader (and I’d love to be able to recommend users switch to MDX!)

For example, the following expression is supported in Markdown Component Loader’s JSX:

Here’s a string pulled from somewhere else; {{ window.navigator.userAgent }}!

MDX as it stands does not support inserting variables either at the block or inline level. the only workaround I could find for this is to do something slightly silly like this:

<span children={`Here’s a string pulled from somewhere else; ${window.navigator.userAgent}!`} />

This would also cooperate nicely with #6, which would allow for dynamic inclusion of content passed from parent components!

@johno
Copy link
Member

johno commented Jul 27, 2018

Yeah, this is something we've been thinking over for a little while now. You should be able to get the same functionality without the string interpolation by opening up a JSX block like so:

<span>
  Here’s a string pulled from somewhere else; {window.navigator.userAgent}
</span>

Understandably, that's not an optimal solution. For the time being I planned on focusing on improving our JSX block parsing, but its something we should consider. My primary worry here is that I like the clear division between MD and JSX that MDX currently has. But maybe that's overthinking things 🤔.

@ticky
Copy link
Member Author

ticky commented Jul 27, 2018

Ah, that’s a very good point! I didn’t consider how putting it in a JSX block would attain the JSX semantics. I wonder if that’s a reasonable tradeoff.

I like the clear division between MD and JSX that MDX currently has

Yeah, I understand that, for sure! In Markdown Component Loader I sort of worked around this by allowing explicit inline interpolation using its assignment expressions. If you want to use a React component inline within an otherwise-Markdown line, you can using that form of assignment expression:

This is a line of **Markdown** but here comes a React Component: {{ <PrettyDate /> }}

Also of note is that Markdown Component Loader goes to the trouble of supporting these even inside code blocks (which is why it uses two curly braces for the assignment expressions; it’s trying naïvely to avoid interpreting JS-like function blocks as assignment expressions. I probably should’ve come up with a new syntax, or a cleverer parser, really! 😅)

@davidtheclark
Copy link

It does seem that delimiters separating JS & JSX from Markdown — such as double curly braces —might help a number of issues with MDX, both bugs and feature requests (e.g. mdx-js/mdx#175, mdx-js/mdx#139, mdx-js/mdx#145, mdx-js/mdx#136, mdx-js/mdx#244, mdx-js/mdx#222, mdx-js/mdx#218, mdx-js/mdx#195). I know it would be a significant change that lots of people wouldn't like. But still worth considering, I think?

When I've thought about using MDX instead of jsxtreme-markdown (which is inspired by @ticky's work), the reasons I've continued favoring & working on jsxtreme-markdown seem to mostly relate to the features made possible by delimiters. I know that MDX is striving to be more AST-based than jsxtreme-markdown — with its string replacements that seem hacky (but have turned out pretty practical and stable). Maybe there's some balance to strike that will incorporate the best of both worlds.

@ticky
Copy link
Member Author

ticky commented Sep 6, 2018

I haven’t got myself a good overview of the structure of the existing JSX parsing, but I suspect given that all the layers are to my knowledge AST-based that an inline node type in MDXAST to allow these interpolations would be feasible, and properly part of the parser.

@johno
Copy link
Member

johno commented Dec 15, 2018

I've been thinking about this a bit lately and would like to propose a solution. It isn't currently supported due to limitations in the parser (which I'll be working on this week regardless of whether we decide to support this or not), but I feel like the semantics and syntax here will fit nicely into MDX.

Currently, you are given access to props as soon as you open up a JSX block, but it's clunky for things that are inline. One example of this is when you want to add a prop to a heading. You're forced to add in a component:

# Hello, from <span>{window.location.href}</span>

This doesn't make sense if you don't want a span, and users shouldn't be required to define a component in userland (likely a wrapper around React.Fragment) in order to achieve this type of functionality.

So, I propose a syntax like:

# Hello, from <>{window.location.href}</> and <>{props.foo}</>

Which is equivalent to:

# Hello, from <Fragment>{window.location.href}</Fragment> and <Fragment>{props.foo}</Fragment>

When adding support with this type of syntax we see a few advantages:

  • we aren't inventing syntax, this is supported in React/JSX
  • continues to consider a "JSX block" as the division between traditional markdown and MDX features
  • it should already be supported with <Fragment>{props.foo}</Fragment> but our parser currently doesn't pick it up

Where it might get tricky is handling code blocks. There are likely lots of existing sites that are using <> in their code blocks. How do we determine whether we should attempt to parse in a code block? Do we skip code blocks and inline code altogether? Do we bump a major and require excaping (\<>)?

Also, I don't know if Vue has a notion of a Fragment, so it might be complicated when we add Vue support. I suppose we can cross that bridge when we get to it.

References

@johno
Copy link
Member

johno commented Mar 11, 2019

This has now landed in the v1 alpha and I've documented it in the spec so going to close this. Thanks for your thoughts everyone!

@patricklafrance
Copy link

@johno, does the functionality that landed in v1 support code blocks?

Can't seem to get it working in code blocks. Works fine with headers.

Thank you,

Patrick

@peter-mouland
Copy link

peter-mouland commented May 5, 2020

hey - thanks for a great tool. I have a question around the use of curlies.

How do i undo this behaviour (described in this PR), or ensure that my content editors can use curlies?

ie

<MyJsxComponent>
 my text includes a { curly }
</MyJsxComponent>

Update

the answer is to ask content editors to instead type:

<MyJsxComponent>
 my text includes a {`{`} curley {`}`}
</MyJsxComponent>

@wooorm
Copy link
Member

wooorm commented May 7, 2020

I would suggest using HTML character references instead (the above works now but won’t in v2):

<MyJsxComponent>
 my text includes a &#x7B; curley }
</MyJsxComponent>

Or:

<MyJsxComponent>
 my text includes a &lt; pointy >
</MyJsxComponent>

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Development

No branches or pull requests

6 participants