-
Notifications
You must be signed in to change notification settings - Fork 36
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
JSX children as code #561
Comments
Yes, we've discussed something similar in the One exception with your proposed example: I don't think Multiple Children Code BlocksBut I think the bigger issue is how to have multiple code children. Digging up old posts, here's an example I put together with a proposal for treating each top-level line as its own braced block: <div>
user := getUser()
if user?
{name} = user
<h1> `Welcome ${name}!`
<h2>Posts</h2>
for post of posts
<div .post> post.jsx()
↓↓↓
let user
<div>
{user = getUser(), void 0}
{user != null ?
{name} = user,
<h1> {`Welcome ${user.name}!`} </h1>
: void 0
}
<h2>Posts</h2>
{posts.map(post =>
<div class="post"> {post.jsx()}
}
</div> Basically the rule is "wrap each non-JSX child of JSX with braces". If you wanted multiple lines to correspond to a single braced child, you could wrap in Same-Line ChildrenAnother issue is whether we want same-line children to behave differently from different-line children. For example, you could imagine Automatic Fragments with StringsAnother proposal I see is to automatically wrap strings and tags in a fragment, like so: <span>
if message.deleted
" "
<span .label.label-danger>Deleted
↓↓↓
<span>
{message.deleted ?
<>
{" "}
<span .label.label-danger>Deleted</span>
</>
: void 0}
</span> Or maybe Let us know what you think about these further ideas/extensions! |
My original XY problem is I want to |
I reread your feedback 🤓
Agreed 👍🏼
Your example makes sense!
Example (I didn't follow)?
Treating raw strings like <div>
user := getUser()
if user?
{name} = user
<h1> `Welcome ${name}!`
<h2> "Posts"
for post of posts
<div .post> post.jsx() For context the <h2> "Posts" </h2> Except it must be wrapped to satisfy types which requires braces again: <h2> {"Posts"->React.string} </h2> |
I have a new related proposal, which is to use
Examples: Component := (items: Item[]) =>
<ul>> // reminds me of Pug's trailing dot
for item of items
<li>>
if item.type === "link"
<a href=item.url>some link title: >item.title
else
<p>>item.content <div>
> if props.warning
<div .warning>
>props.warning
> if loggedIn()
<Inbox>
<Logout>
> else // special case to allow an else at same indentation level
<Login>
↓↓↓
<div>
{props.warning ?
<div class="warning">
{props.warning}
</div> : void 0
}
{loggedIn() ?
<>
<Inbox/>
<Logout/>
</>
: <Login/>
}
</div> <label>
Comment
>if count > 1
's'
:
↓↓↓
<label>
Comment
{count > 1 ? 's' : void 0}
:
</label> We could allow <Show when=>
data = getData()
data.has data.stuff
fallback=>
<div>Nothing to see here.
>
Welcome!
↓↓↓
<Show when={
data = getData(),
data.has(data.stuff)
} fallback={
<div>Nothing to see here.</div>
}>
Welcome!
</Show> I think I would personally prefer explicit blocks like this, as opposed to implicitly treating all children as code, because it makes it easy to be explicit about when you want multiple code blocks (as above) vs. when you want one code block that requires multiple lines: >do
data := getData() |> formatData
data.sort()
for item of data
<li>>item.title The other advantage is that it's fully backward compatible, so we can do it without a flag like In <div>
. if props.warning
<div .warning>
. 'Warning: '
. props.warning
. if loggedIn()
<Inbox>
<Logout>
else
<Login>
↓↓↓
<div>
{props.warning ?
<div class="warning">
{'Warning: '}
{props.warning}
</div> : void 0
}
{loggedIn() ?
<>
<Inbox/>
<Logout/>
</>
: <Login/>
}
</div> |
My 2¢ with a grain of salt because I'm not actively using Civet 🙏🏼 I like the concept of entering curly mode via some marker. But Alternatively (brainstorming inspired by Pug/Vue hybrid) <div>:=
if props.warning <div .warning>:= props.warning
if loggedIn()
<Inbox>
<Logout>
else <Login> <Show
when:=
data = getData()
data.has data.stuff
fallback:= <div> Nothing to see here.
> Welcome! |
<div>
:= if props.warning then <div .warning>:= props.warning
:= if loggedIn()
<Inbox>
<Logout>
else <Login> (otherwise the code block would be treated as a single code block with one return value, whereas you need multiple here) Note that Unrelated, I had another idea for <div>
if props.warning
<div .warning>
'Warning: '
---
props.warning
---
if loggedIn()
<Inbox>
<Logout>
else
<Login> Currently |
By the way, back to an unambiguous backward-compatible notation, an option other than <Show when=&
data = getData()
data.has data.stuff
fallback=&
<div>Nothing to see here.
>
Welcome!
<div>
& if props.warning
<div .warning>
&props.warning
& if loggedIn()
<Inbox>
<Logout>
else
<Login> I like that it's a different character from Some other ideas for other symbols:
I'm wondering whether we could have two options for breaking backward compatibility:
|
I think |
I haven’t fully delved into the problems of this issue, but I think that it is still necessary to somehow make the following syntax possible: <div>
if items
<h1> "List of items:"
<ul> for item in items
<li> <span> item
else
<span> "No items found" or as the author of the issue suggested: const Component = (items: Item[]) =>
<ul>
for item of items
<li>
if item.type === "link"
<a href=item.url>some link title: {item.title}
else
<p>{item.content} Here's how in Imba language. Is it very difficult to implement this? <div>
user := getUser()
if user?
{name} = user
<h1> `Welcome ${name}!`
<h2>Posts</h2>
for post of posts
<div .post> post.jsx()
↓↓↓
let user
<div>
{user = getUser(), void 0}
{user != null ?
{name} = user,
<h1> {`Welcome ${user.name}!`} </h1>
: void 0
}
<h2>Posts</h2>
{posts.map(post =>
<div class="post"> {post.jsx()}
}
</div> |
If I understand correctly, this is the same as my original proposal. Yes, I think this should be an option, via a directive of |
Yeah, even if it is an additional option like <div>
& if props.warning
<div .warning>
&props.warning
& if loggedIn()
<Inbox>
<Logout>
else
<Login> or this: <div>
if props.warning
<div .warning>
'Warning: '
---
props.warning
---
if loggedIn()
<Inbox>
<Logout>
else
<Login> <div>
. if props.warning
<div .warning>
. 'Warning: '
. props.warning
. if loggedIn()
<Inbox>
<Logout>
else
<Login> Anyway, thanks for your work. I really like civet 🙂 |
FWIW Imba is another Coffee fork I quite enjoy for toy projects that probably influenced my expectations how Civet would behave (as well as ReScript mentioned in the description). |
Hi all! An idea.. const Component = (items: Item[]) =>
<ul>
{for item of items}
<li>
{if item.type === "link"}
<a href=item.url>some link title: {item.title}
{else}
<p>{item.content} A new syntactic construct is introduced: JSX {} with indented children. It treats the children as if it was a <></> fragment indented into the contents of {}. But if an indented {} contains a continuation of a statement ( Other examples: <ul>
{if !items.length}
No items.
{else items.map (item) =>}
<li>{item.text}
<ResizeObserver>
{({width, height}) =>}
{width}x{height}
<span>
{&.toLowerCase()}
{name}
<div>
{switch value}
{{type: "user"}}
{value.name}
{else}
Invalid type |
I ran into a confusing DX issue experimenting with JSX in the playground.
Working example:
Despite being a React instructor (but also CoffeeScript in the past) I intuitively expected Civet to work without braces.
Broken example:
I think code would be a better default for all JSX nodes not only https://civet.dev/cheatsheet#function-children as in:
JSXText
)Proposed example:
Alternatively signal code children with a marker like
do
:The text was updated successfully, but these errors were encountered: