JSX
ImplementedMarkup in expressions: a tag is a function call, an attribute is a function call, and nothing is special to the compiler.
JSX is surface syntax only. It is rewritten into ordinary calls before anything is hashed (like the pipe), so a JSX program has exactly the hash and types of the calls you would have written by hand, and UCM never sees JSX.
type attr = | Attr(string, string)
type node = | Text(string) | El(string, list<attr>, list<node>)
let text = (s: string): node => Text(s)
let div = (attrs: list<attr>, kids: list<node>): node => El("div", attrs, kids)
let b = (attrs: list<attr>, kids: list<node>): node => El("b", attrs, kids)
let cls = (v: string): attr => Attr("class", v)
let data_id = (v: string): attr => Attr("data-id", v)
let page = (n: string): node =>
<div cls="a" data-id={n}>
hello <b>bold</b>
</div>The rules
- A tag is a call.
<name attrs>children</name>calls the functionnamewith a list of attributes and a list of children. Which function that is depends only on whatnamemeans in scope; the compiler knows nothing about HTML. - An attribute is a call.
name={e}isname(e),name="s"isname("s"), and a barenameisname(true). A dash becomes an underscore (data-idcallsdata_id) and a reserved word gets a trailing underscore (typecallstype_). All attributes of a tag share one list, so they share one type. - A component is just a function of the same shape. There is no capitalised-component rule: in React the case tells a string tag from a variable, but here every tag is a variable. Capitalised names are constructors in Clay, so a capitalised tag is an error.
- Spread.
{...more}splices in a list of attributes; the lists on either side are joined in written order. - Children. Text becomes
text("...")(the functiontextin scope),{e}is the expression itself and must already be a node, and nested elements and fragments are themselves. When text has a line break, lines are trimmed and joined with one space, as in React; text on one line is kept as written. - Fragments.
<>...</>callsfragment(children). - Where
<is JSX. A<that starts an expression. After an expression it is still less-than.
Not yet: namespaced tags (svg:rect), comments inside a tag, entities in text, and a props record for components
(the attribute functions are the props).