callstack / linaria

Zero-runtime CSS in JS library
https://linaria.dev
MIT License
11.49k stars 414 forks source link

Easier way to create multiple related class names #854

Open wereHamster opened 2 years ago

wereHamster commented 2 years ago

Describe the feature

const classes = csss({
  root: `
    font-size: 14px;
    color: black;

    &:hover .{child} {
      color: red
    }
  `,

  child: `
    padding: 10px;
  `,
});

<div className={classes.root>
  <div className={classes.child} />
</div>

Motivation

I've been using Material-UI v4, and the pattern I was using allowed me to generate CSS styles once (basically a one-time overhead during the startup but then no more CSS related code would be executed). With the switch to Emotion, and sx prop, such a pattern is no longer possible and I'm looking for a replacement as my go-to CSS-in-JS solution.

The pattern in question (actually a feature of JSS) allowed me to generate multiple related class names that are interdependent. That is currently possible with Linaria, but it's cumbersome. The example above could be written as

const classes = (() => {
  const child = css`…`
  const root = css`&:hover .${child} { … }`
  return { root, child }
})()

But that is less readable, and I have to manually maintain the dependency tree of the CSS classes.

I was actually thinking of allowing arbitrarily deeply nested objects as input into the csss macro, eg.

const classes = css({
  root: `
    &:hover .{child}: { … }
  `,

  size: {
    small: `…`,
    large: `…`,
  },

  child: `
    .{size.small} & { … }
  `,
});

Because then I could more easily map react props into class names, eg.

function Button(props) {
  return <button className={cx(classes.root, classes.size[props.size])}>…</button>
}

<Button size="small" />

Possible implementations

A new macro that takes an object as input, where arbitrary fields can be template literals, the macro would first construct a dependency tree, call the css macro accordingly on the template literals (after replacing any {ref}-like references with their corresponding string values). When detecting a loop (or cyclic dependencies), throw an error.

Related Issues

Couldn't find any.

Anber commented 2 years ago

Hi @wereHamster It's an interesting proposal but I'm afraid that it's too complicated for implementation since we need to parse CSS in order to find references. However, if you wanna try, I'll be happy to accept a PR.