threepointone/glamor

Nested Properties

Closed this issue · 5 comments

Would there be any interested in a PR to support SCSS-style nested properties?

Example from that page:

.funky {
  font: {
    family: fantasy;
    size: 30em;
    weight: bold;
  }
}

Practically, for glamor, that would mean the following:

{
  fontFamily: 'fantasy',
  fontSize: '30em',
  weight: 'bold',
}

Could be the following:

{
  font: {
    family: 'fantasy',
    size: '30em',
    weight: 'bold',
  },
}

This works for margin, border, padding, etc. Basically any set of rules with a common prefix.

I don't think I want this for glamor, I'm afraid. though I am looking for ideas to make font declarations simpler, but not something as generic as the above. closing this issue, but happy to carry on the conversation if you'd like.

Since opening this issue I noticed that polished supports similar functionality generically for any css-in-js framework:

{
  ...margin('12px', '24px', '36px', '48px')
}

// Becomes:
{
  marginTop: '12px',
  marginRight: '24px',
  marginBottom: '36px',
  marginLeft: '48px'
}

It doesn't currently support fonts. Maybe a generic function as a package could be appropriate? I'd be willing to publish a function that acts as such:

{
   ...nested('font', {
    family: 'fantasy',
    size: '30em',
    weight: 'bold',
  }),
}

I just published the nested-camel package. Different from my initially suggested api as it only accepts a single nested object and will recursively flatten for even more verbose properties such as border-top-style. Usage examples from the README:

import { css } from 'glamor';
import nested from 'nested-camel';

// Use it directly:
const rule = css(nested({
  font: {
    family: 'fantasy',  // fontFamily
    size: '30em',       // fontSize
    weight: 'bold',     // fontWeight
  },
  border: {
    top: {
      style: 'dashed',  // borderTopStyle
      color: 'red',     // borderTopColor
      width: 'thick',   // borderTopWidth
    },
    bottom: {
      style: 'solid',   // borderBottomStyle
      color: 'blue',    // borderBottomColor
      width: 'thin',    // borderBottomWidth
    },
  },
}));

// Use it with object-rest-spread:
const rule2 = css({
  background: 'blue',    // background
  ...nested({
    font: {
      family: 'fantasy', // fontFamily
      size: '30em',      // fontSize
      weight: 'bold',    // fontWeight
    },
  }),
});

// Compose it:
import { compose } from 'ramda';
const ncss = compose(css, nested);

const rule3 = ncss({
  font: {
    family: 'fantasy',  // fontFamily
    size: '30em',       // fontSize
    weight: 'bold',     // fontWeight
  },
  border: {
    top: {
      style: 'dashed',  // borderTopStyle
      color: 'red',     // borderTopColor
      width: 'thick',   // borderTopWidth
    },
    bottom: {
      style: 'light',   // borderBottomStyle
      color: 'blue',    // borderBottomColor
      width: 'thin',    // borderBottomWidth
    },
  },
});
dfsq commented

@knpwrs out of curiosity, why would you even want this, you realize that thisway your CSS becomes so much less optimal and verbose?

@dfsq For the same reason it's in SASS and SCSS to begin with. There are fairly common situations where the shorthand doesn't work or is otherwise unclear. My given example may not express that, but there's a reason this feature exists elsewhere.