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

Conditional logic #4

Open
edgarasben opened this issue Oct 20, 2022 · 5 comments
Open

Conditional logic #4

edgarasben opened this issue Oct 20, 2022 · 5 comments

Comments

@edgarasben
Copy link

edgarasben commented Oct 20, 2022

Would it be possible to add conditional logic such as AND, OR and NOT?

For example, I would like to only apply padding if the variant is NOT a link:

NOT:

{
    variants: {
        size: 'sm',
        variant: not('link')
    },
    className: 'xxx'
},

Other conditional examples

AND:

{
    variants: {
        size: 'sm',
        variant: and('link', 'solid', 'subtle')
    },
    className: 'xxx'
},

OR:

{
    variants: {
        size: 'sm',
        variant: or('link', 'solid', 'subtle')
    },
    className: 'xxx'
},
@kevin-nguyen-mirvac
Copy link

I think compoundVariant will solve most conditional logic (one of stitches.dev strongest feature imo)

https://stitches.dev/docs/variants#compound-variants

Is there a specific example where the above won't really work? Just curious.

@druc
Copy link

druc commented Nov 22, 2022

@kevin-nguyen-mirvac compoundVariant works great but you have to write each and every variant.

For example:

const iconClass = variants({
  base: 'text-white',
  variants: {
    size: {
      xs: "w-4 h-4",
      sm: "w-5 h-5",
      base: "w-6 h-6",
      lg: "w-7 h-7",
      xl: "w-8 h-8",
    },
    iconPosition: {
      left: "order-first",
      right: "order-last"
    }
  },
  compoundVariants: [
    {
      variants: {
        size: ["xl", "lg"], // doesn't work, but would be nice to
        iconPosition: 'left'
      },
      className: '-ml-2.5 mr-1'
    },
    {
      variants: {
        size: ["xs", "sm", "base"],  // doesn't work, but would be nice to
        iconPosition: 'left'
      },
      className: '-ml-1.5 mr-1'
    }
  ],
  defaultVariants: {
    size: "base",
    iconPosition: "left"
  },
});

I would gladly submit a PR for this but my typescript's so so bad... - will try it if there's a chance to have it merged 😃

@kevin-nguyen-mirvac
Copy link

Ahh I understand now, this is pretty cool!
I'm surprised this feature request never popped up for stitches.dev.
https://github.com/stitchesjs/stitches/issues?q=condition

This feature though will increase library scope to "Stitch-like API" + more.

If it were to be included, I like it being 'opt in' like @edgarasben sample code.

  variant: or('link', 'solid', 'subtle')
  variant: add('link', 'solid', 'subtle')
  variant: not('link', 'solid', 'subtle')

I'll give this a go though. It'll be cool to see if it'll work even if the author decides to not include it in this library

@edgarasben
Copy link
Author

edgarasben commented Nov 23, 2022

I think compoundVariant will solve most conditional logic (one of stitches.dev strongest feature imo)

https://stitches.dev/docs/variants#compound-variants

Is there a specific example where the above won't really work? Just curious.

Yes, compoundVariants helps with the AND condition, but it's a bit verbose:

        {
            variants: {
                color: 'primary',
                destructive: false,
                variant: 'solid',
                variant: 'subtle',
                variant: 'outline'
            },
            className: 'x'
        }

However, compoundVariants currently doesn't support OR and NOT conditions.

@kevin-nguyen-mirvac
Copy link

Just an update, I got something working that kind of looks like this.

const StyledButton = styled(
  "button",
  {
    base: [
      "rounded-lg w-fit font-sans flex justify-center items-center font-semibold",
      "leading-none relative",
    ],
    variants: {
      size: {
        xs: "py-2 px-4",
        sm: "py-3 px-6 text-[14px] min-w-[100px]",
        md: "py-4 px-5 text-[14px] min-w-[100px]",
        lg: "py-5 px-5 text-[16px] min-w-[100px]",
        icon: "h-[50px] w-[50px] min-w-[50px] hover:text-line p-0 rounded-full",
      },
      variant: {
        primary: "",
        secondary: "",
        error: "bg-error text-white",
      },
      disabled: {
        true: "cursor-not-allowed",
      },
      status: {
        idle: "",
        loading: "bg-dotted-line text-[transparent]",
        success: "bg-success text-[transparent]",
        error: "",
      },
    },
    compoundVariants: [
      {
        variants: {
          variant: {
            OR: ["primary", "secondary"]
          },
          status: "idle",
        },
        className: "text-white bg-black",
      },
      {
        variants: {
          variant: "secondary",
          status: {
            NOT: "idle"
          },
        },
        className: "bg-white border border-dotted-line",
      },
      {
        variants: {
          variant: ["primary", "secondary"],
          disabled: true,
          status: ["idle", "loading"],
        },
        className: "bg-dotted-line",
      },
    ],
    defaultVariants: {
      size: "lg",
      variant: "primary",
      status: "idle",
      disabled: false,
    },
  }
);

some major changes are

  • All class strings have the options to be an array just for the sake of formatting
  • I realized you can't have an AND case because a variant can't be both something at the same time which mean you only need to cater for the OR and NOT cases
    • I kind of liked prisma's SDK for working with nested data so copied their style of having a nested { OR: "...", NOT: "..." }
  • Copied joe-bell/cva and allow you to pass in an array as your variant and it defaults to the OR case (I think this is a common pattern so setting it as a default feels sane)

I'm happy to make this PR if the author thinks it's within the scope of this project. Otherwise I'm working on releasing the below code in maybe my own repo sometime soon.

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

3 participants