I'm using more and more hyperapp and must admit I like it. Good job.
What I'm describing here is not bug or direct issue with hyperapp. Just want to raise attention for others who might have similar problem.
The problem is that by default hyperapp doesn't assign any units to style props: width, height, left ...
As result these styles props are silently ignored by the browser. This is nothing special, that's how browsers work. It's same behaviour as assigning style props with bare DOM eg. el.style.height=20 -
would not be applied either.
Normally it's not problem when developer is aware of this, but for people with React background, this would bit surprising, as React handles this somehow.
Example:
Component responsible for rendering usernames from keepassxc db when user click on username login form field).
const CredentialsMenu = ({ top, left }) => {
const style = { position: 'absolute', top, left };
return (
<div style={style}>
<div>
<ul >
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
</div>
</div>
);
};
This component needs to be "aligned" to some html input field
const { bottom, left } = inputElement.getBoundingClientRect();
const menuCoords = { top: bottom + scrollY, left: left + scrollX };
...
<CredentialsMenu {...menuCoords} />
...
top left styles will not be applied, only position 'absolute' will.
Fix is quite easy. Just add px unit, but you have to do it for every component.
Nice idea. What do other people think? @lukejacksonn
Here how Preact does it.
that regex may be somewhat fragile for future css additions, but hyperapp is too size-sensitive to absorb the actual whitelist blacklist [1]. if you don't mind carefully maintaining the regex, then sure, why not?
[1] https://github.com/leeoniya/domvm/blob/3.x-dev/src/view/addons/autoPx.js
@leeoniya Ouch.
yeah, i only include it in domvm's "larger" flavors 馃槅
I'm can't help but wonder if something can be hacked together by changing valueOf on the Number prototype to
Number.prototype.valueOf = function() { return `${this}px` }
Or creating a new prototype, say Pixel:
function Pixel(px) { this.px = px }
Pixel.prototype.valueOf = function () { return `${this.px}px` }
And now
const foo = new Pixel(2)
foo // {px: 2}
foo + '' // 2px
foo + foo // 2px2px :(
Or maybe somehow recognize attributes with suffix px? Like, if you have an object {topPx: 2}, that would be treated as {top: '2px'}? Or {px: {top: 2, left: 3}} would be expanded to {top: '2px', left: '3px'}.
Anyway, I don't think anything like this should be in the core of HA, but I'm wondering if we have an API that would make these "integrations" easier? Does HA allow devs to "hook" into functions for applying properties to DOM elements?
@lazarljubenovic You can use the lifecycle methods (oncreate, onupdate) to mess around to add properties dynamically to dom elements.
Edit: I see what you're asking now: is there some way to modify how hyperapp applies the properties? Not to my knowledge. BUT you could always use the lifecycle methods to go in and "postprocess" properties after hyperapp has done it's thing.
I have noticed this with other properties too (such as opacity) and did wonder if there is anything that can be done about it.. The way preact does it looks pretty legit? Not too large either.
I agree with @lazarljubenovic that this seems unecessary to be in the core of hyperapp, since it will just add weight and isn't necessary for all users.
Baking stuff like this into the framework would help some users, but hinder others and potentially make it harder to debug if you aren't aware of the magical unit conversions behind the scenes. hyperapp's core appeal to me is how simple and non-magical it is.
Some people will put 100% of their styles in CSS.
Those using inline styles should still understand CSS and what units are needed. A couple helper functions to create the strings make it easier.
const px(num) => num + "px"
const pct(num) => num + "%"
const rem(num) => num + "rem"
...
app({
view: () => h('div', {
style: {
maxWidth: px(200),
minHeight: pct(100),
margin: rem(2)
}
},
['Hello'])
})
@SkaterDad as much I agree with you about keeping core simple. Your reasoning is not very strong here. :-)
Baking stuff like this into the framework would help some users, but hinder others and potentially make it harder to debug
But hinder others... There is potentially huge group of people with React, Preact, (you name it) background, whose will be quite surprised that why it's not working when it's working in xyz.
There are IMHO already not very comptabile decisions made. Like lowercase names of event handlers, which doesn't fit well with typescript (until somebody writes types defs, if that's even viable).

But ok, after some thinking, I'm also probably more inclined to not handle this situation in core. Maybe simple mention in the docs, about differences from other big libs might be enough.
But ok, after some thinking, I'm also probably more inclined to not handle this situation in core. Maybe simple mention in the docs, about differences from other big libs might be enough.
Definitely agree with this. Maintaining a FAQ or something of potentially surprising differences to popular libraries would help on-boarding new users.
It seems to be trendy among React-likes to mimic the React API and behavior, but I think it's great to have some differences since it encourages innovation. We all have different backgrounds, but are interested in hyperapp for what it is, a clean functional framework, not necessarily because it's similar to React.
I personally don't really have much React experience (beyond reading), so I never expected the style props in hyperapp to auto-insert a "px" or "%", and it would have confused me. I have done some elm, though, and you have to specify units when defining inline styles.
I think if router is officialy moved into hyperapp/router, it will be possible to create some things like hyperapp/html and hyperapp/css.
import { h, app } from 'hyperapp'
import { div, h1 } from 'hyperapp/html'
import { px, pct, rem } from 'hyperapp/css'
app({
view: () => div({
style: {
maxWidth: px(200),
minHeight: pct(100),
margin: rem(2)
}
},[
h1(null, 'Hello World')
])
})
So, it could be possible to give users a lot of helpers without affecting the core size.
Guys what do you think ? (cc @jbucaran)
Just trying to jump into this conversation. If we are already have a goal to keep core as minimal as possible and include no magic than I think @Swizz idea looks really interesting. There are lots of things which helps while creating big apps, but can hurt those who doesn't need advanced stuff. We already saw some requests to add, but it was out of hyperapp's scope and things like that will come constantly. Having small packages is the way to go in my opinion.
@Swizz Yes, it will be possible.
Before creating an official @hyperapp/xxx, though, I'd like to make sure it's something commonplace enough to be granted "official" status (like the router). In the meantime, hyperapp-xxx packages are up for grabs as you wish. :)
I contribute a lot, by comments, I will need to contribute by code right now.
@jbucaran About @hyperapp/package would you want a common repository structure like a starter repo ?
Could you create a hyperapp/package repository I can fork ?
We can create hyperapp-xxxx and if the community seen interest on it, move it into the Hyperapp org.
Do you want only dependencies free package ? Because hyperapp-html could be a simple wrap around hyperscript-helpers ^^
About @hyperapp/package would you want a common repository structure like a starter repo ?
See for example: https://github.com/hyperapp/router
We can create hyperapp-xxxx and if the community seen interest on it, move it into the Hyperapp org.
Yes, I think this is the best way to go.
Do you want only dependencies free package?
Most likely, but I can compromise, of course.
The problem with separate packages is that I'm afraid we'll end up with 20 routers and 20 "helper" libs that solve the same problem, none of which work well together. I think we need a system to keep track of "official" packages which would have to pass a certain standard in terms of quality. Which is probably why having an organization @hyperapp/package is a good idea: as people build other things, when something looks promising, it can be moved under the organisation.
And about this suggestion.
style: { maxWidth: px(200), minHeight: pct(100), margin: rem(2) }
This is nice and all, but do we really need a package that will append two characters to a number? It's not even hyperapp-relevant.
Which is probably why having an organization @hyperapp/package is a good idea.
@lazarljubenovic Yes, that's the plan.
This is nice and all, but do we really need a package that will append two characters to a number? It's not even hyperapp-relevant.
Fair enough. That's another reason why I don't want to start creating "official" packages willy-nilly.
The router is a good example of an "official" package we must have. SSR/server too.
HRM? Hyperscript utilities? I don't know. Probably a non-official package, in the form of hyperapp-xxx, is best?
@lukejacksonn A simple PR that mimics preact in this instance wouldn't hurt to have. @mauron85 Would you like to work on that?
I just tried implementing this.. and now I am of the opinion that there are too many cases to cover to do _properly_.. and why are we defaulting to px for _dimensional_ properties.. why not rem|em|% 馃 how is this helping anybody?
It will _prevent people getting confused if they enter a numerical value_ is the argument (and it probably does) _but_ it introduces more magic, which might confuse people in when it comes to other key/values pairs. It is just another thing to have to look up and check support for.
I'm with Elm (and CSS) on this.. make it clear to the developer, that they _must_ specify units.
I'm with the side of keeping it minimal... But I think we should definitely document the behavior, so we at least have something to reference in the event someone gets confused and needs help.
Also for the record, it is incredibly easy to parse a number out of a CSS value. Just use parseInt or parseFloat!
parseInt('10px')
// => 10
parseFloat('33.333%')
// => 33.333
// Even the weird ones:
parseFloat('-.33%')
// => -0.33
In rare instances you want to parse the unit, I've created this future-proof package css-get-unit
@jamen How do we decide what unit to add? So, if no unit is given, add px by default?
But I think we should definitely document the behavior, so we at least have something to reference in the event someone gets confused and needs help.
Yes, this is always a good idea. There's currently no section on styling in the docs, so creating one and adding a note about this would be the way to go IMO. It would be nice to add other info about styling in general too.
I say we close here for now, since we are not adding px/unit automatic support to core for the time being.
EDIT: Grammar.
From what I read, the plan I was agreeing to is keep it as it is, and tell the user they need to specify a unit... Because, just putting a number by itself is ambiguous and would depend on the CSS declaration.
I was agreeing what @lukejacksonn had said above:
I just tried implementing this.. and now I am of the opinion that there are too many cases to cover to do _properly_.. and why are we defaulting to
pxfor _dimensional_ properties.. why notrem|em|%how is this helping anybody?It will _prevent people getting confused if they enter a numerical value_ is the argument (and it probably does) _but_ it introduces more magic, which might confuse people in when it comes to other key/values pairs. It is just another thing to have to look up and check support for.
I'm with Elm (and CSS) on this.. make it clear to the developer, that they _must_ specify units.
I can't think of a case where I couldn't store a number in my state and add the unit from the view... Unless the unit had some sort of intrinsic value, like if you were doing conversion between units. But that's rare, and I touched on it above.
@mauron85 Shall we close here? If you want to contribute with some docs on styling in general, that'd be ace 馃挴. If that's not possible at this moment, I know we'll get around it someday as the docs continue to evolve. 馃槂馃憤
EDIT: Grammar.
@jbucaran go ahead close this. I can't give you any promises about the docs. As I'm working on multiple OSS projects already and well also I'm not native english speaker, so I believe there is better person for this job. (Those excuses :-))
@mauron85 Deal! 馃槃:+1:
what about a babel plugin that adds transform number literals with a default unit when it detects css in js?
@Pyrolistical Why not! 馃棥馃槃
Most helpful comment
I agree with @lazarljubenovic that this seems unecessary to be in the core of
hyperapp, since it will just add weight and isn't necessary for all users.Baking stuff like this into the framework would help some users, but hinder others and potentially make it harder to debug if you aren't aware of the magical unit conversions behind the scenes.
hyperapp's core appeal to me is how simple and non-magical it is.Some people will put 100% of their styles in CSS.
Those using inline styles should still understand CSS and what units are needed. A couple helper functions to create the strings make it easier.