threepointone/glamor

Respect array/arguments order of css()

Opened this issue · 1 comments

New issue from #226 (comment)

An array or multiple arguments can passed to the css() function but that order is not respected when the css is generated. The style objects are just merged into a one object which is then used to generate the css. This makes the style ordering bit random when existing style keys are being overridden.

Example: https://codesandbox.io/s/qjG2XvykR

In real world code I've hit this with glamorous when I have wanted to extend a component and change it's media query behaviour.

Example: https://codesandbox.io/s/VPAvP6mGO

Fixing this would also make the infamous shorthand properties less brittle when extending components in glamorous. Ie. this would work as expected https://codesandbox.io/s/jzgxvZov

It think it comes down to the fact that when a key is being overridden in an object it's position stays the same.

For example here foo is the first key even thou it's the last one set.

> Object.keys(Object.assign({foo: 1}, {bar: 2}, {foo: 3}))
[ 'foo', 'bar' ]

Deleting existing properties before assignment might solve the problem.

function preserveOrder(...styles) {
    return styles.reduce((acc, style) => {
    	Object.entries(style).forEach(([prop, val]) => {
            if (prop in acc) { delete acc[prop] }
            acc[prop] = val
        })
        return acc
    }, {})
}

const mergedStyles = preserveOrder({foo: 1}, {bar: 2}, {foo: 3})
Object.keys(mergedStyles) // => [ 'bar', 'foo' ]