Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Helper to apply classNames to a dynamic element? #6

Open
mgcrea opened this issue Jan 26, 2023 · 2 comments
Open

Helper to apply classNames to a dynamic element? #6

mgcrea opened this issue Jan 26, 2023 · 2 comments

Comments

@mgcrea
Copy link

mgcrea commented Jan 26, 2023

Would be nice to have a className-like helper when you want to dynamically apply classes according to a variant config.

In my case, I'm playing with a basic <Button />component that would have an icon prop that could receive an ReactElement:

      <Button size="xs" icon={<XMarkIcon />}>
        Default
      </Button>

In this case I'd like to apply some size-based variants to the icon as well, something like:

const iconClassNames = variantClassNames({
  variants: {
    size: {
      xs: "w-4 h-4 -ml-0.5 mr-1",
      sm: "w-4 h-4 -ml-0.5 mr-2",
      md: "w-5 h-5 -ml-1 mr-2",
      lg: "w-6 h-6 -ml-1 mr-3",
      xl: "w-6 h-6 -ml-1 mr-3",
    }
  },
  defaultVariants: {
    size: "md",
  },
});

That could be used this way:

<button>
  {icon ? cloneElement(icon, {className: iconClassNames(props)}) : null}
  {children}
</button>

Do you think this could be useful or would you do it differently (eg. nested styles, etc.)?

@mgcrea mgcrea changed the title Helper to apply className to a dynamic element? Helper to apply classNames to a dynamic element? Jan 26, 2023
@ivome
Copy link
Contributor

ivome commented Jan 30, 2023

The className is passed to the components, so you can just apply it wherever you need it:

function MyCustomComponent(props) {
   const {className} = props;

   return (
    <button>
      {icon ? cloneElement(icon, {className}) : null}
      {children}
    </button>
   );
}

const MyStyledCustomComponent = styled(MyCustomComponent, {
  variants: {
    size: {
      xs: "w-4 h-4 -ml-0.5 mr-1",
      sm: "w-4 h-4 -ml-0.5 mr-2",
      md: "w-5 h-5 -ml-1 mr-2",
      lg: "w-6 h-6 -ml-1 mr-3",
      xl: "w-6 h-6 -ml-1 mr-3",
    }
  },
  defaultVariants: {
    size: "md",
  },
});

Does that work?

@ivome
Copy link
Contributor

ivome commented Jan 30, 2023

Or another option could be to create a wrapper component that passes the className. Something like this should work (haven't test it):

function IconWrapper(props: {
  children: (className: string) => ReactElement,
  className: string
}) {
  const {children, className} = props;
  <>
   {children(className)}
  </>
}

const StyledIcon = styled(IconWrapper, {
  variants: {
    size: {
      xs: "w-4 h-4 -ml-0.5 mr-1",
      sm: "w-4 h-4 -ml-0.5 mr-2",
      md: "w-5 h-5 -ml-1 mr-2",
      lg: "w-6 h-6 -ml-1 mr-3",
      xl: "w-6 h-6 -ml-1 mr-3",
    }
  },
  defaultVariants: {
    size: "md",
  },
}

function Button(props) {
   const {icon, ...rest} = props;
   return (
    <button>
      {icon ? (
        <StyledIcon {...rest}>
           {(className) => cloneElement(icon, {className})}
        </StyledIcon>
        : null}
      {children}
    </button>
  )
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants