Question on html tag 🧵
@kuzmin_m I added support for :& now (also documented). Bonus: the library also works in ClojureScript now
as for html5: I guess we could default to html5 and make up a way to alter the behavior globally or so.
@kuzmin_m what do you mean with hourglass?
In my company we mark saved for later messages with ⏳ UPD: https://github.com/borkdude/html/issues/4
👍
What do you think about having the ability to merge props?
npx squint-cljs -e '(println #html [:h1 {:id "heading"} "Hello"])'
;; => <h1 id="heading">Hello</h1>
npx squint-cljs -e '(println #html [:h1 (merge {:id "heading"} {:class "h1"}) "Hello"])'
;; => <h1>[object Object]Hello</h1>
With JSX that works like this:
$ npx squint-cljs -e '(println (let [m {:id :heading}] #jsx [:h1 {:& m :class "h1"}"Hello"]))'
file:///private/tmp/sq/.tmp2PrN7M/squint.mjs:4
return <h1 {...m1} class="h1">Hello</h1>;
Obviously that doesn't work with html:
$ npx squint-cljs -e '(println (let [m {:id :heading}] #html [:h1 {:& m :class "h1"}"Hello"]))'
<h1 {...m1} class="h1">Hello</h1>since HTML isn't dynamic
but since there is a dynamic tag function involved, perhaps it's possible to hack something like that
Perhaps given
return squint_html.tag`<h1 {...m1} class="h1">${squint_core.str(m1)}</h1>`;
squint_html.tag could do a string interpolation here on the keys and vals of the map at runtime and replace thatYeah maybe squint shouldn’t manage it then. I am just trying to get as far as I can without writing my own vdom. I do plan to write a vdom for squint at some point
> Yeah maybe squint shouldn’t manage it then It could, given the above idea
Feel free to post an issue, I'm now on the other thing which I am now being distracted from :)
Ok great 🙂
I think I got it already:
$ ./node_cli.js --show -e '(println (let [m {:id :heading}] #html [:h1 {:& m :class "h1"} (:id m)]))'
import * as squint_core from 'squint-cljs/core.js';
import * as squint_html from 'squint-cljs/src/squint/html.js';
squint_core.println((() => {
const m1 = ({ "id": "heading" });
return squint_html.tag`<h1 ${m1} class="h1">${squint_core.get(m1, "id")}</h1>`;
})());
<h1 id="heading" class="h1">heading</h1>I can commit this to master for you to try it out
pushed
Oh wow thanks, was just grabbing a ☕ will try in a sec
This seems to work but there might be edge cases, feel free to report https://squint-cljs.github.io/squint/?src=KGRlZiBhdHRycyB7OnN0eWxlICJjb2xvcjogcmVkIn0pCgooZGVmIGh0bWwgI2h0bWwgWzphIHs6aHJlZiAiaHR0cHM6Ly9jbG9qdXJlLm9yZyIKICAgICAgICAgICAgICAgICAgICAgOiYgYXR0cnN9CiAgICAgICAgICAgICAgICAgIkNsb2p1cmUgcnVsZXMiXSkKCihqcy9jb25zb2xlLmxvZyBodG1sKQoKKGFzLT4gKGpzL2RvY3VtZW50LmNyZWF0ZUVsZW1lbnQgImEiKSAkCiAgKGRvdG8gJCAoc2V0ISAtaW5uZXJIVE1MIGh0bWwpKQogIChqcy9kb2N1bWVudC5ib2R5LnByZXBlbmQgJCkp&repl=false
Yeah working great!
./node_cli.js --show -e '(defn my-button [props] #html [:button {:id "button" :& props}]) (println (my-button {:class "danger"}))'Yeah edge on nil props
./node_cli.js --show -e '(defn my-button [props] #html [:button {:id "button" :& props}]) (println (my-button) (my-button {:class "danger"}))'please make issue, gotta go afk for a bit
why would you write a literal nil with :& though?
runtime nil also has this problem, that's a better example imo: https://squint-cljs.github.io/squint/?src=KGRlZiBhdHRycyBuaWwpCihkZWYgaHRtbCAjaHRtbCBbOmEgezpocmVmICJodHRwczovL2Nsb2p1cmUub3JnIgogICAgICAgICAgICAgICAgICAgICA6JiBhdHRyc30KICAgICAgICAgICAgICAgICAiQ2xvanVyZSBydWxlcyJdKQoKKGpzL2NvbnNvbGUubG9nIGh0bWwp&repl=false
Yeah sorry more the runtime nil
Order of :& also seems important for overriding props:
https://squint-cljs.github.io/squint/?src=KGRlZm4gY2xvanVyZQogIFsmIFtwcm9wc11dCiAgI2h0bWwgWzphIHs6JiBwcm9wcwogICAgICAgICAgICAgOmhyZWYgImh0dHBzOi8vY2xvanVyZS5vcmciCiAgICAgICAgICAgICA6c3R5bGUgImNvbG9yOiBncmVlbiJ9CiAgICAgICAgICJDbG9qdXJlIHJ1bGVzIl0pCgooZGVmIGRlZmF1bHQgKGNsb2p1cmUpKQooZGVmIGRhbmdlciAoY2xvanVyZSB7OnN0eWxlICJjb2xvcjogcmVkIn0pKQoKKGpzL2NvbnNvbGUubG9nIGRlZmF1bHQpCihqcy9jb25zb2xlLmxvZyBkYW5nZXIpCgooYXMtPiAoanMvZG9jdW1lbnQuY3JlYXRlRWxlbWVudCAiYSIpICQKICAoZG90byAkIChzZXQhIC1pbm5lckhUTUwgI2h0bWwgWzpkaXYgZGVmYXVsdCBkYW5nZXJdKSkKICAoanMvZG9jdW1lbnQuYm9keS5wcmVwZW5kICQpKQ%3D%3D&repl=false
doesn’t work if this is changed to:
{:href ""
:style "color: green"
:& props} I would have expected the latter to work in terms of following the rules of spread in JS:
let x = {a: 2};
{a: 1, ...x}; // {a: 2}
{...x, a: 1}; // {a: 1}I pushed some more improvements for rendering css now as well, I'll take a look at your latest comment
ah yes, the order, this sucks because CLJS maps are unordered. There's a workaround for that, yeah, this is a problem
o wait, it hasn't got to do with that even
The rendered HTML is:
<a style="color: red" href="" style="color: green">Clojure rules</a> I guess this is just a browser problem rather than a squint problem
I wonder if :& attributes should always overwrite the other attributes in squints case? As having two style attributes doesn’t really make sense.
The use case would be do have the defaults setup and then use the spread to overwrite the defaults
Yes we know the keys statically so we could pass those to the attr function
I’ll have a look after dinner
so in squint's case:
{:a 1 :& x}
and
{:& x :a 1}
would do the same?Yeah I think that would be the most common thing people would want
$ ./node_cli.js --show -e '(defn my-button [props] #html [:button {:id "button" :& props}]) (println (my-button {:id 2}))'
import * as squint_core from 'squint-cljs/core.js';
import * as squint_html from 'squint-cljs/src/squint/html.js';
var my_button = function (props) {
return squint_html.tag`<button id="button" ${squint_html.attrs(props,new Set(["id"]))}></button>`;
};
squint_core.println(my_button(({ "id": 2 })));
export { my_button }
<button id="button" ></button>pushed
This also works for choosing the prop from the map instead:
(defn my-button [props] #html [:button {:id (:id props "button") :& props}])published 0.7.109 with these changes
I guess I'll have a look at those vite plugin things later next week hopefully :) This was also fun though
In the above example, both end up with the green styling
yes, as discussed
the explicit property always overrides
you replied with "this is the most common use case"
Ah sorry, I meant as in the outcomes would be the same, that the spread is always treated as spread onto, (merge m :&)
I don't understand. I asked here if the position doesn't matter:
{:& x :a 1} imo means that :a 1 always wins, rightbut you preferred the other one?
as the only behavior?
Yeah sorry I thought:
{:a 1 :& x} // x keys would override
{:& x :a 1} // x keys would override
I see ok
we can do that
Sorry about that, I misunderstood
Yeah, I guess I misunderstood too :) I think this requires a little more work and I'm done for today, if you can make an issue I'll fix that next time
You’re too fast 😂
ah what the heck, already on npm ;)
Definitely owe you a few 🍻
yeah I guess this behaves the same as JSX now, pretty sweet
Yeah it’s really awesome!
Will it be possible to use #html in JVM Clojure?
Why not, have you tried it? It might already work?
I assume that your question means: does JS produced with squint on the JVM also support #html: I wouldn't see why not
$ clj
Clojure 1.12.0-alpha7
user=> (require '[squint.compiler :as sc])
nil
user=> (sc/compile-string "#html [:a {:color :blue}]")
"import * as squint_core from 'squint-cljs/core.js';\n`<a color=\"blue\"></a>`;\n"No. I expect it produces a string like hiccup.
it does produce a string (inside of the JavaScript)
Without js 🙂
why not just use hiccup then
Security, supportability and other things
why would hiccup be more unsafe, unsupportable and other things than squint's #html?
Hiccup is in alpha stages for years. It has still inconsistent API: helpers use unsafe hiccup-v1.
#html is very simple, it doesn’t do some magic with for and if macros. And I think it could be a standard way to render html in different platforms.
what magic with for and if are you referring to?
> If the body of the element is a seq, its contents will be expanded out into the element body. This makes working with forms like map and for more convenient: > > user=> (str (h/html [:ul > (for [x (range 1 4)] > [:li x])])) > "<ul><li>1</li><li>2</li><li>3</li></ul>"
https://github.com/weavejester/hiccup/blob/master/src/hiccup/compiler.clj#L241
lazy sequences (and arrays) are also handled the same way in squint #html:
https://x.com/borkdude/status/1794349007076241663/photo/1
what hiccup tries to do there is optimize stuff it can do at compile time so it can skip work at run time
In Squint we should add #html inside for, if, when, let etc. And it is right. I wonder about simple html/xml rendering in jvm clojure, and #html could be the best way to do it
ah you mean you should repeat the #html ok
you mean, like this right?
(h/html [:ul (for [i [1 2 3]] (h/html [:li i]))])#html instead of h/html
yeah but would you have preferred that hiccup worked like that?
I’d prefer don’t use hiccup 🙂 And use #html like I could in squint/cherry
I'll have a look at what's possible
ok, try this: https://github.com/borkdude/html experimental, but with your feedback it can improve
You are very fast! 🙂
1. Is it possible to use #html instead of h/html?
2. Add escaping and raw strings
3. #html [:div {:& props}]
Also there is the most confusing part about HTML5 vs *X*HTML5.
HTML5 uses https://developer.mozilla.org/en-US/docs/Glossary/Void_element. But it’s seems that XHTML5 does not have void elements.
So using XHTML5 we will use simpler rules.
Could you also add a note about doctype and HTML5 vs XHTML5?
escape strings: yes of course, PR welcome, I'm afk for dinner now
posting issues also welcome
metal