Skip to content

Commit

Permalink
Merge pull request #389 from Game-as-a-Service/hotfix/buttonv2-disabl…
Browse files Browse the repository at this point in the history
…ed-styles

fix: buttonv2 disabled styles
  • Loading branch information
JohnsonMao authored Jun 3, 2024
2 parents a0d4305 + 7d0ffab commit fc1ff77
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 112 deletions.
45 changes: 9 additions & 36 deletions components/shared/Button/v2/Button.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import type { Meta, StoryObj } from "@storybook/react";
import { Button, ButtonSize, ButtonType } from "./Button";
import { Button, ButtonSize, ButtonVariant } from "./Button";
import { ReactNode } from "react";
import Icon from "../../Icon";

const buttonTypeOptions: (ButtonType | undefined)[] = [
const buttonVariantOptions: (ButtonVariant | undefined)[] = [
undefined,
ButtonType.PRIMARY,
ButtonType.SECONDARY,
ButtonType.HIGHLIGHT,
ButtonVariant.PRIMARY,
ButtonVariant.SECONDARY,
ButtonVariant.HIGHLIGHT,
];

const buttonSizeOptions: (ButtonSize | undefined)[] = [
Expand Down Expand Up @@ -38,46 +38,19 @@ const meta: Meta<typeof Button> = {
children: "Button",
},
argTypes: {
component: {
control: { type: "select" },
options: ["button", "a"],
},
variant: {
control: { type: "select" },
options: buttonTypeOptions,
},
size: {
control: { type: "select" },
options: buttonSizeOptions,
},
iconName: {
control: { type: "select" },
options: buttonIconNameOptions,
description:
"Icon name from `IconV2` component. If `icon` is not `undefinded`, this prop will be ignored.",
},
icon: {
control: { type: "select" },
options: buttonIconOptions,
description:
"Custom icons or any prefix component. If `iconName` is not `undefinded`, this prop will be ignored.",
},
boxFancyClassName: {
control: { type: "text" },
description: "custom class name for inner div",
defaultValue: "",
},
className: {
control: { type: "text" },
description: "custom class name",
defaultValue: "",
},
disabled: {
control: { type: "boolean" },
},
style: {
control: { type: "object" },
description: "custom style",
defaultValue: {},
},
ref: { control: { disable: true } },
},
};

Expand All @@ -92,7 +65,7 @@ export const Playground: Story = {
export const Variant: Story = {
render: (args) => (
<>
{buttonTypeOptions.map((variant) => (
{buttonVariantOptions.map((variant) => (
<Button key={variant} variant={variant} {...args}>
{args.children}
</Button>
Expand Down
4 changes: 2 additions & 2 deletions components/shared/Button/v2/Button.test.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from "react";
import { render, screen } from "@testing-library/react";
import "@testing-library/jest-dom";
import { Button } from "./Button";
import { Button, ButtonVariant } from "./Button";

describe("ButtonV2", () => {
it("should renders button text", () => {
Expand All @@ -16,7 +16,7 @@ describe("ButtonV2", () => {

it("should have correct className", () => {
render(
<Button variant="danger" className="test">
<Button variant={ButtonVariant.PRIMARY} className="test">
Button
</Button>
);
Expand Down
92 changes: 34 additions & 58 deletions components/shared/Button/v2/Button.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,11 @@
import React, {
ElementType,
ReactNode,
forwardRef,
useCallback,
useMemo,
} from "react";
import React, { ReactNode, forwardRef, useCallback } from "react";
import { cn } from "@/lib/utils";
import BoxFancy, { BoxFancyBorderGradientVariant } from "../../BoxFancy";
import { IconNameV2 } from "@/components/shared/Icon/v2/icons";
import IconV2 from "@/components/shared/Icon/v2";
import { PolymorphicComponentProp, PolymorphicRef } from "@/lib/types";
import Icon from "@/components/shared/Icon/v2";
import { PolymorphicRef } from "@/lib/types";

export enum ButtonType {
export enum ButtonVariant {
PRIMARY = "primary",
SECONDARY = "secondary",
HIGHLIGHT = "highlight",
Expand All @@ -22,11 +16,14 @@ export enum ButtonSize {
SMALL = "small",
}

const buttonTypeClasses: Record<ButtonType, string> = {
const commonDisabledClasses =
"disabled:cursor-not-allowed disabled:bg-none disabled:bg-gray-800 disabled:border-gray-500 disabled:text-gray-200 disabled:stroke-gray-200 disabled:fill-gray-200";

const buttonTypeClasses: Record<ButtonVariant, string> = {
primary:
"text-primary-700 bg-primary-200 hover:text-primary-50 hover:bg-primary-300 active:text-primary-50 active:bg-primary-400",
secondary:
"text-primary-200 bg-transparent hover:bg-primary-300/40 active:bg-primary-200/20 disabled:bg-transparent disabled:border-grey-500 disabled:border",
"text-primary-200 bg-transparent hover:bg-primary-300/40 active:bg-primary-200/20 disabled:bg-transparent disabled:border",
highlight:
"text-primary-50 gradient-purple hover:gradient-purple-2 active:gradient-purple-3",
};
Expand All @@ -37,51 +34,42 @@ const buttonSizeClasses: Record<ButtonSize, string> = {
};

interface BaseButtonProps {
variant?: ButtonType;
variant?: ButtonVariant | `${ButtonVariant}`;
size?: ButtonSize;
icon?: ReactNode;
iconName?: IconNameV2;
disabled?: boolean;
// inner div className for styling
boxFancyClassName?: string;
iconClassName?: string;
}

type ButtonProps<C extends ElementType = "button"> = PolymorphicComponentProp<
C,
BaseButtonProps
>;
type ButtonProps = BaseButtonProps & React.ComponentPropsWithoutRef<"button">;

type InnerButtonComponent = <C extends ElementType = "button">(
props: ButtonProps<C>,
ref?: PolymorphicRef<C>
type InnerButtonComponent = (
props: ButtonProps,
ref?: PolymorphicRef<"button">
) => React.ReactElement | null;

const iconTypeClasses: Record<ButtonType, string> = {
const iconTypeClasses: Record<ButtonVariant, string> = {
primary:
"stroke-primary-700 hover:stroke-primary-50 active:stroke-primary-50",
secondary: "stroke-primary-200",
secondary: "stroke-primary-200 disabled:stroke-gray-500",
highlight: "stroke-primary-50",
};

const InteralButton: InnerButtonComponent = (
{
component,
variant = ButtonType.PRIMARY,
variant = ButtonVariant.PRIMARY,
size = ButtonSize.REGULAR,
icon,
iconName,
disabled,
className,
boxFancyClassName,
iconClassName,
children,
onClick,
...otherButtonAttributes
},
ref
) => {
const Component = component || "button";
const handleClick = useCallback(
(event: React.MouseEvent<HTMLButtonElement>) => {
if (disabled) {
Expand All @@ -94,45 +82,33 @@ const InteralButton: InnerButtonComponent = (
[disabled, onClick]
);

const buttonClassName = useMemo(
() =>
cn(
"w-full items-center fz-16-b transition-colors transition-[border-image] ease-in",
"disabled:text-grey-200 disabled:bg-grey-800",
buttonTypeClasses[variant],
buttonSizeClasses[size],
iconTypeClasses[variant],
boxFancyClassName
),
[boxFancyClassName, size, variant]
);

const iconClasses = useMemo(
() => cn("w-6 h-6 stroke-inherit", iconClassName),
[iconClassName]
const boxFancyClassName = cn(
"w-fit items-center fz-16-b transition-colors transition-[border-image] ease-in",
commonDisabledClasses,
buttonTypeClasses[variant],
buttonSizeClasses[size],
iconTypeClasses[variant],
className
);
const iconClasses = cn("w-6 h-6 stroke-inherit", iconClassName);

const borderGradientColor: BoxFancyBorderGradientVariant =
variant === ButtonType.SECONDARY && !disabled ? "purple" : "none";
variant === ButtonVariant.SECONDARY && !disabled ? "purple" : "none";

return (
<Component
<BoxFancy
ref={ref}
className={className}
component={"button"}
borderRadius="full"
borderGradientColor={borderGradientColor}
className={boxFancyClassName}
onClick={handleClick}
disabled={disabled}
{...otherButtonAttributes}
>
<BoxFancy
borderRadius="full"
borderGradientColor={borderGradientColor}
className={buttonClassName}
>
{icon ||
(iconName && <IconV2 name={iconName} className={iconClasses} />)}
<span>{children}</span>
</BoxFancy>
</Component>
{icon || (iconName && <Icon name={iconName} className={iconClasses} />)}
<span>{children}</span>
</BoxFancy>
);
};

Expand Down
32 changes: 16 additions & 16 deletions pages/login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { useRouter } from "next/router";
import { GetStaticProps } from "next";
import { serverSideTranslations } from "next-i18next/serverSideTranslations";

import ButtonV2, { ButtonType } from "@/components/shared/Button/v2";
import ButtonV2, { ButtonVariant } from "@/components/shared/Button/v2";
import Cover from "@/components/shared/Cover";
import IconV2 from "@/components/shared/Icon/v2";

Expand Down Expand Up @@ -66,21 +66,21 @@ const Login: NextPageWithProps = () => {

const loginButtons = useMemo(() => {
return LoginMethods.map(({ text, type, icon }) => (
<ButtonV2
key={type}
component={Link}
href={`${internalEndpoint}/login?type=${type}`}
className={"w-full min-w-[300px] max-w-[50%] xl:max-w-[318px]"}
boxFancyClassName={"text-primary-50"}
iconClassName={cn("stroke-none", {
"fill-current": type === LoginType.GITHUB,
})}
iconName={icon}
variant={ButtonType.SECONDARY}
onClick={(e: SyntheticEvent) => onLoginClick(e, type)}
>
{text}
</ButtonV2>
<Link key={type} href={`${internalEndpoint}/login?type=${type}`}>
<ButtonV2
className={
"w-full min-w-[300px] max-w-[50%] xl:max-w-[318px] text-primary-50"
}
iconClassName={cn("stroke-none", {
"fill-current": type === LoginType.GITHUB,
})}
iconName={icon}
variant={ButtonVariant.SECONDARY}
onClick={(e: SyntheticEvent) => onLoginClick(e, type)}
>
{text}
</ButtonV2>
</Link>
));
}, [internalEndpoint, onLoginClick]);

Expand Down

0 comments on commit fc1ff77

Please sign in to comment.