POJO style question
Closed this issue · 7 comments
Hello @porsager
just stumbled over this:
in the README.md
under 'Ways of writing CSS', it says:
JS Objects
b({ backgroundColor: 'black', textAlign: 'center', $hover: { backgroundColor: 'red' } })
while the only way I could make it work, was actually a POJO / function mix like this:
b({
margin: '2em',
backgroundColor: 'black',
textAlign: 'center',
}).$hover({ backgroundColor: 'pink '})
I am wondering if this is just a typo in the README.md
or if it was actually supposed to work the POJO way, too?
The POJO way of writing css may be advantageous when it comes to media queries:
I am currently working on a little script to provide React-agnostic styled-components
and styled-system
functionality with lovely bss
doing the heavy lifting under the hood. Consider the following output from a styled-system
type of function such as space
where this
// (attrs :: Object, theme :: Object?) -> Object
function space (attrs, theme = {}) { /* sausage factory */ }
let spacing = space({
p: '1px 2px 3px 4px',
mr: [0, 2, 4, 6],
ml: [1, 3, 5, 7],
mb: [0, 2, 4, 6],
mt: [1, 3, 5, 7]
})
...yields an Object
like this (after some tweaking of the original space function):
{
padding: '1px 2px 3px 4px',
marginTop: '4px'
marginLeft: '4px',
marginRight: '0px'
marginBottom: '0px',
$media: {
'screen and (min-width: 40em)': {
marginBottom: '8px',
marginLeft: '16px',
marginRight: '8px',
marginTop: '16px'
},
'screen and (min-width: 52em)': {
marginBottom: '32px',
marginLeft: '64px',
marginRight: '32px',
marginTop: '64px'
},
'screen and (min-width: 64em)': {
marginBottom: '128px',
marginLeft: '256px',
marginRight: '128px',
marginTop: '256px'
}
}
}
if 'Ways of writing CSS' worked as currently documented, I would be able to just drop the space
yield into bss
as is, right?
const result = bss(spacing)
as opposed to iteratively calling result.$media(ding, dong)
like this:
const { $media } = Object.assign({}, spacing)
delete spacing.$media
let result = bss(spacing)
for (let k in $media) {
result = result.$media(k,$media[k])
}
... which works just fine, but seems more wasteful. But maybe it isn't under the hood. What do you think?
Ah yes, that's supposed to work. Must have been a regression at some point! I'll look into it.
Seems like interesting usage, curious to see what you come up with 😃
Hi @smuemd ... Sorry, the docs are wrong, and I think only true css selectors should be supported.
eg:
b({
':hover': { background: 'blue' },
'@media screen and (min-width: 52em)': { background: 'yellow' }
})
That still doesn't work though, which is a regression from when I added sanitization of raw POJO input. I'll get that fixed, and I'll fix the docs. ;)
If you think it's worth discussing if the syntax you used above should be supported, let's make a new issue for that :)
So, basically - this should be the way // (notice bss was modified with the fix)
Awesome!
true css selectors like this will do:
{
'@media screen and (min-width: 40em)': { marginBottom: '8px', ... }
}
Will require even less modifications on the styled-components
side, since this is what the output already looks like. Maybe not even gonna to fork this then after all.
Re:
curious to see what you come up with 😃
I'd very much appreciate your feedback. The Current WIP is in the first flems already (under the stylething
tab).
Here is an updated link
My thinking so far:
The stylething
code produces a createStyleThing
function which is supposed to work by providing an instance of the vdom lib of your choice (either mithril or react right now) as first argument
import m from 'Mithril'
const stylt = createStyleThing(m, { mode: 'mithril', output: 'class' })
stylt
would work like styled-components
' styled
function on steroids, thanks to the bss
instance under the hood. Its API is currently heavily overloaded:
(a :: String? | Object? | Function?, b :: String? | Object? | Function?, c :: Array Function?) -> Object | Function
So the first two arguments a
and b
can be Strings, Objects or Functions while the third + n arguments, if provided, are expected to be functions
a :: String
accepts hyperscript notation to describe the desired component type or tag and its static properties (using mithrils' hyperscript parser):
stylt('div') // same as stylt()
stylt('div.Box[cool][foo=bar]') // same as stylt('#Cool1.Box[cool][foo=bar]')
stylt('something that will break document createElement()') // same as stylt('div.something.that.will.break.document.createElement()')
// while
stylt(`bc darkred`) // same as stylt('div + bss`bc darkred`)
a :: Object
expects a style definition object
stylt({ backgroundColor: 'darkred' }) // almost the same as stylt('div + bss`bc darkred`)
or an object with style
, class
or className
attributes. So any variation of this should actually also work:
stylt(bss.bc('darkred').$hover(b.backgroundColor('red')))
a :: Function
expects a styled-components
' type function that takes vdom.attrs
or props
as first argument (currently modifying styled-component
to accept a second theme
argument to short circuit its reliance on Reacts' state context
.
stylt(attrs => ({ backgroundColor: attrs.bc || 'darkred' })) // it is actually a bit more complicated with these functions, but this is the gist of it.
b :: String | Object | Function
works exactly like a
. Minus the hyperscript query.
c :: Array Function
expects style yielding functions that work just like argument a :: Function
the stylt
function then should yield a component wrapped in boilerplate that satisfies the requirements of the vdom lib that was originally provided. So usage wise, with all the moving part put together, I am aiming for a happy path that would resemble something like this
import m from 'mithril'
import createStyleThing from 'wherever'
import { space, color, fontSize, maxWidth } from 'a-fork-of-styled-system'
const stylt = createStyleThing(m, { mode: 'mithril', output: 'class', theme: null })
const Box = stylt('.Box.standard', space, color, fontSize)
// would that make sense?
const Betterbox = stylt(Box, 'better', maxWidth)
m.mount(document.body, {
view: () => [
m(Box, {
p: [1,2,3]
color: 'darkgrey',
bc: 'lightblue',
fontsize: [3, 4, 5]
},
'only a box'), // <div class='Box standard bwsrrl31 bwsrrl32'>only a box</div>
m(Betterbox, { maxWidth: 1/2 }, 'mind the cascade') // <div class='Box standard bwsrrl31 better bwsrrl33 bwsrrl34'>mind the cascade</div>
]
})
I am currently looking into appropriating mechanics of styled-system
to integrate with this idea (flems here) (hence my question to clairify the bss API)
I am also wondering what the effect of this will be on the overall performance story. I am currently looking into how to best precompute and cache the parsed output internally so as to prevent component style recomputations on every redraw. This is my biggest concern right now. The flems for sure feels slow as fuck right now (but there is also lots of logging going on, so we will see)
Also I am not sure if the overloading is a bit over the top right now. Maybe I should dial it back to accept string and functions only.
hey @smuemd .. Just wanted to say I'd like to look this through, but I'm pressed for time these days, so it's probably first gonna be next week...
Cool :)
Using nested objects was fixed in ee2bbd5 btw..
I'll release a new version with the fixes later tonight
@porsager Thanks. You're a star!
the styled-system fork is pretty much ready to go
even managed to turn some performance knobs, right there
Stefans-MBP:styled-system smuemd$ node bench
[@v3.1.11] space x 243,901 ops/sec ±3.40% (82 runs sampled)
[@v3.1.11] width x 1,209,751 ops/sec ±1.15% (90 runs sampled)
[@v3.1.11] fontSize x 1,489,248 ops/sec ±1.30% (88 runs sampled)
[@v3.1.11] color x 355,538 ops/sec ±0.76% (88 runs sampled)
[@v3.1.11] style x 1,171,462 ops/sec ±1.37% (85 runs sampled)
[@v3.1.11] width array x 102,102 ops/sec ±1.41% (87 runs sampled)
[@v3.1.11] space array x 98,344 ops/sec ±1.02% (88 runs sampled)
[@v3.1.11] fontSize array x 126,377 ops/sec ±0.81% (89 runs sampled)
[@v3.1.11] color array x 100,871 ops/sec ±1.19% (91 runs sampled)
[@next] space x 1,328,938 ops/sec ±1.00% (88 runs sampled)
[@next] width x 1,585,322 ops/sec ±4.84% (79 runs sampled)
[@next] fontSize x 2,664,783 ops/sec ±1.22% (89 runs sampled)
[@next] color x 856,094 ops/sec ±0.99% (88 runs sampled)
[@next] style x 1,053,963 ops/sec ±1.25% (89 runs sampled)
[@next] width array x 138,927 ops/sec ±1.63% (88 runs sampled)
[@next] space array x 142,151 ops/sec ±1.01% (89 runs sampled)
[@next] fontSize array x 231,577 ops/sec ±2.61% (84 runs sampled)
[@next] color array x 129,403 ops/sec ±1.04% (90 runs sampled)
I will brush up the react-agnostic styled components implementation this week. should have something more presentable to play around with soon.