Open davesnx opened 10 months ago
I second this, being able to write vanilla HTML is super important for lowering friction on tools like Tailwind UI that give you large templates.
I think we can start with some heuristics to turn these into valid OCaml function parameters. For example data-id
could become ~data_dash_id
and x:html
could become ~x_colon_html
.
These aren't ideal, but if we're consistent then these would be learnable , and at least the name is verbose enough to tell you where they come from.
One additional aspect that I think is often overlooked is the ability abstract over attributes. In the current mlx version it is possible to abstract over elements, but attributes are always mapped to labels, which makes them fixed.
Consider the following signature that models HTML:
module Html : sig
type elem
val elem : tag:string -> attr list -> elem list -> elem
val div : attr list -> elem list -> elem
val text : string -> elem
(* ... *)
type attr
val attr : string -> string -> attr
val href : string -> attr
val class_name : string -> attr
(* ... *)
end
This is very similar to how HTML is described in Elm.
One advantage of this approach is that it is possible to refactor attributes:
let html =
let open Html in
let attr = href "#" in
let data = text "Hello"
div [attr; class_name "foo"] [
data;
]
In my opinion, instead of trying to map attributes to labels, which require the attribute to be fixed, it is better to aim for something more generic.
See the examples below for some suggested translations:
<div />
// Mlx.Elem.div [] []
<Foo />
// Foo.make [] []
<Foo.el />
// Foo.el [] []
<div> {v} </div>
// Mlx.Elem.div [] [ v ]
<div> {v1} {v2} </div>
// Mlx.Elem.div [] [ v1; v2 ]
<div> {42} </div>
<div> {"hello"} </div>
// Mlx.Elem.div [] [ Mlx.int 42 ]
// Mlx.Elem.div [] [ Mlx.string "hello" ]
<div a="hello" />
// Mlx.Elem.div [Mlx.Attr.a (Some "hello")] []
<div b />
// Mlx.Elem.div [Mlx.Attr.b None] []
<div data-a data-b="x" />
// Mlx.Elem.div [Mlx.Attr.data "a" None; Mlx.Attr.data "b" (Some "x")] []
<div {my_attr} />
// Mlx.Elem.div [my_attr None] []
<div {Foo.my_attr=42} />
// Mlx.Elem.div [Foo.my_attr (Some 42)] []
Of course, the generated nodes should still be annotated with a ppx attribute in practice.
My main message is that, I think it's as important to abstract over attributes as it is over elements.
Currently Reason JSX is limited to React's JSX, which is ok for newcomers and React devs but very undesired for other libs (Htmx, svelte, solidjs, vue, etc) but also for HTML directly.
Being able to support entirely the HTML spec would be a big win for mlx in this case. The reasonings are beyond libraries, and also integrations with DevTools, copy/paste and learnability.
:
and@
(https://alpinejs.dev):
I'm not sure if it's remotely possible to support some of these features, but having the way to achieve it, it's a must for me. The current situation with Reason JSX is to not be able to use
data-*
attributes directly, and need to React.createElement/cloneElement.