xstyled icon indicating copy to clipboard operation
xstyled copied to clipboard

Variant alternative

Open Nvos opened this issue 3 years ago • 7 comments

I'm considering migrating from styled-system to xstyled. So far migration seems simple expect variants which I found were removed in v2. What is recommended way to handle variants, for example different types of button (e.g. icon, solid, dashed).

Nvos avatar Apr 01 '21 18:04 Nvos

For now you can do it by yourself, personally I use a data-variant:

import styled from '@xstyled/styled-components'

const InnerButton = styled.buttonBox`
  &[data-variant="success"] {
    background-color: emerald-300;
    color: emerald-600;
  }
`

const Button = ({ variant, ...props }) => <InnerButton data-variant={variant} {...props} />

You can also do it directly with x.button.

import { x } from '@xstyled/styled-components'

const variantProps = {
  success: {
    backgroundColor: 'emerald-300',
    color: 'emerald-600',
  }
}

const Button = ({ variant, ...props }) => {
  return <x.button {...variantProps[variant]} {...props} />
}

Pick the best for you but a utility is not helpful :)

gregberge avatar Apr 02 '21 17:04 gregberge

I will add a section in docs about that.

gregberge avatar Apr 02 '21 17:04 gregberge

For now there's no variant way in xstyled but it will be the next focus.

gregberge avatar May 24 '21 08:05 gregberge

@gregberge I'm curious what you're thinking here. I've been using something based on your data-variant idea:

const hoistDataAttrs = mapping => {
  const [oks, nks] = Array.isArray(mapping) ?
    [Object.keys(mapping), Object.values(mapping)] :
    [mapping, mapping.map(k => `data-${k}`)]
  return props => {
    const vs = oks.map(k => props[k]).map(v => v === true ? '' : v)
    return Object.fromEntries([
      // Map variant to data-variant, dropping false and null.
      ...oks.map((ok, i) => [nks[i], vs[ok]])
            .filter(([_, v]) => v !== false && v !== null),
      // Map old keys to undefined so they'll be dropped by styled-components.
      ...oks.map(ok => [ok, undefined]),
    ])
  }
}

const Button = styled.button.attrs(hoistDataAttrs(['variant']))`
  &[data-variant="success"] {
    ...
  }
`

I've been thinking about applying this globally for my own projects, but I haven't tried it yet:

const hoistVariants = hoistDataAttrs(['size', 'variant'])

Object.entries(styled).forEach(([k, v]) => {
  styled[k] = v.attrs(hoistVariants)
})

but maybe you have a new idea?

agriffis avatar May 25 '21 15:05 agriffis

@gregberge I'm curious what you're thinking here. I've been using something based on your data-variant idea:

Hello, I have never industrialized it yet.

gregberge avatar May 31 '21 08:05 gregberge

Hello, i was looking for 'variants' and i found this issue. Just showing here what I tried before:

// theme.js

import {
  defaultTheme
} from '@xstyled/styled-components'

export const theme = {
  ...defaultTheme,
  variants: {
    bPrimary: {
      backgroundColor: "#aaa"
    }
  }
}
// xstyled.config.js

import {
  createCss,
  system,
  compose,
  style,
  themeGetter,
} from "@xstyled/styled-components";

const getVariants = themeGetter({
  name: "variant",
  key: 'variants',
  transform: (value) => {
    return value
  },
});

export const variant = style({
  prop: "variant",
  css: (value) => {
    return value;
  },
  themeGet: getVariants,
});

export const { css, styled, x, createGlobalStyle } = createCss(
  compose(system, variant)
);

Usage example:

<x.button variant="bPrimary">Button</x.button>

This code allow a 'variant' property in all x.* elements, but not worked as expected. It works only with default css values. Example: this code can not transform "backgroundColor: blue-700" in "backgroundColor: #1d4ed8".

I don't know if it's a good code but I leave this code here as an implementation idea.

jorge-armando avatar Aug 01 '21 17:08 jorge-armando

One thing I'd love to see when variants are implemented is the ability to switch the applied variant based on media query. For example, perhaps a Button on mobile would look like a link and on desktop would look like a button (essentially reducing the surface area of how many styles have to be manually wired up with media queries individually.)

quantizor avatar Aug 09 '21 19:08 quantizor