BuilderIO / mitosis

Write components once, run everywhere. Compiles to React, Vue, Qwik, Solid, Angular, Svelte, and more.
https://mitosis.builder.io
MIT License
12.22k stars 540 forks source link

Support for class-variance-authority #1244

Open nhensh opened 1 year ago

nhensh commented 1 year ago

I am interested in helping provide a feature!

Yes

Which generators are impacted?

What problem does this feature solve?

Styling the components that have variants, this also works really well with tailwind.

What does the proposed API look like?

My guess would be this would work a bit like how collect-styled-components works but it would allow for CVA variables to be included.

Something like this:

import { Show } from '@builder.io/mitosis';
import { cva } from 'class-variance-authority';

export interface ButtonVariantTypes {
  intent: "primary" | "secondary" | "default";
  size: "small" | "medium" | "large";
  roundness: "square" | "round" | "pill";
}

export interface ButtonProps {
  variants?: ButtonVariantTypes;
  type?: "button" | "submit" | "reset";
  attributes?: any;
  text?: string;
  link?: string;
  openLinkInNewTab?: boolean;
}

export default function Button({
  variants,
  type,
  attributes,
  text,
  link,
  openLinkInNewTab,
}: ButtonProps) {

  const ButtonVariants = cva(
    /* button base style */
    'h-fit text-white uppercase transition-colors duration-150',
    {
      variants: {
        /* button colors */
        intent: {
          primary: 'bg-green-500 hover:bg-green-600',
          secondary: 'bg-red-500 hover:bg-red-600',
          default: 'bg-gray-500 hover:bg-gray-600',
        },

        /* button sizes */
        size: {
          small: ['text-sm', 'py-1', 'px-2'],
          medium: ['text-base', 'py-2', 'px-4'],
          large: ['text-lg', 'py-4', 'px-8'],
        },

        /* button roundness */
        roundness: {
          square: 'rounded-none',
          round: 'rounded-md',
          pill: 'rounded-full',
        },
      },

      // defaults
      defaultVariants: {
        intent: 'default',
        size: 'medium',
        roundness: 'round',
      },
    }
  );

  return (
    <>
      <Show
        when={link}
        else={<span {...attributes}>{text}</span>}
      >
        <button
          {...attributes}
          type={type}
          className={ButtonVariants(
            {
              intent: variants?.intent,
              size: variants?.size,
              roundness: variants?.roundness
            }
          )}
          role="button"
          href={link}
          target={openLinkInNewTab ? '_blank' : undefined}
        >
          {text}
        </button>
      </Show>
    </>
  );
}

Additional Information

https://cva.style/docs

BleedingDev commented 8 months ago

I would love to have this feature. Did you start working on it? :)