@@ -135,8 +89,6 @@ export const Variants: Story = {
const canvas = within(canvasElement);
const buttons = canvas.getAllByRole("button");
await expect(buttons).toHaveLength(6);
-
- // Test hover states
for (const button of buttons) {
await userEvent.hover(button);
await expect(button).toHaveAttribute(
@@ -144,81 +96,47 @@ export const Variants: Story = {
expect.stringContaining("hover:"),
);
}
-
- // Test rounded-full styling on appropriate variants
- const roundedVariants = [
- "default",
- "destructive",
- "outline",
- "secondary",
- "ghost",
- ];
- for (let i = 0; i < 5; i++) {
- await expect(buttons[i]).toHaveAttribute(
- "class",
- expect.stringContaining("rounded-full"),
- );
- }
-
- // Link variant should not have rounded-full
- await expect(buttons[5]).not.toHaveAttribute(
- "class",
- expect.stringContaining("rounded-full"),
- );
},
};
export const Sizes: Story = {
render: (args) => (
-
-
- 🚀
-
+
Small
-
Default
+
+ Default
+
Large
-
-
Deprecated Size:
-
- Primary (deprecated)
-
-
+
+ Primary
+
+
+ 🚀
+
),
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const buttons = canvas.getAllByRole("button");
await expect(buttons).toHaveLength(5);
-
- // Test icon size
- const iconButton = canvas.getByRole("button", { name: /🚀/i });
- await expect(iconButton).toHaveAttribute(
- "class",
- expect.stringContaining("h-9 w-9"),
- );
-
- // Test specific size classes
- const smallButton = canvas.getByRole("button", { name: /Small/i });
- await expect(smallButton).toHaveAttribute(
- "class",
- expect.stringContaining("h-8"),
- );
-
- const defaultButton = canvas.getByRole("button", { name: /Default/i });
- await expect(defaultButton).toHaveAttribute(
- "class",
- expect.stringContaining("h-9"),
- );
-
- const largeButton = canvas.getByRole("button", { name: /Large/i });
- await expect(largeButton).toHaveAttribute(
- "class",
- expect.stringContaining("h-10"),
- );
+ const sizes = ["sm", "default", "lg", "primary", "icon"];
+ const sizeClasses = [
+ "h-8 rounded-md px-3 text-xs",
+ "h-9 px-4 py-2",
+ "h-10 rounded-md px-8",
+ "md:h-14 md:w-44 rounded-2xl h-10 w-28",
+ "h-9 w-9",
+ ];
+ buttons.forEach(async (button, index) => {
+ await expect(button).toHaveAttribute(
+ "class",
+ expect.stringContaining(sizeClasses[index]),
+ );
+ });
},
};
@@ -231,101 +149,39 @@ export const Disabled: Story = {
const canvas = within(canvasElement);
const button = canvas.getByRole("button", { name: /Disabled Button/i });
await expect(button).toBeDisabled();
- await expect(button).toHaveAttribute(
- "class",
- expect.stringContaining("disabled:pointer-events-none"),
- );
- await expect(button).toHaveAttribute(
- "class",
- expect.stringContaining("disabled:opacity-50"),
- );
+ await expect(button).toHaveStyle("pointer-events: none");
await expect(button).not.toHaveFocus();
},
};
export const WithIcon: Story = {
- render: () => (
-
-
-
-
-
-
- Icon Left
-
-
- Icon Right
-
-
-
-
-
-
-
- Icon with automatic gap spacing:
-
-
-
-
-
- Button with Icon
-
-
-
- ),
+ args: {
+ children: (
+ <>
+
+
+
+ Button with Icon
+ >
+ ),
+ },
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
- const buttons = canvas.getAllByRole("button");
- const icons = canvasElement.querySelectorAll("svg");
-
- // Test that SVGs are present
- await expect(icons.length).toBeGreaterThan(0);
-
- // Test for gap-2 class for spacing
- await expect(buttons[0]).toHaveAttribute(
- "class",
- expect.stringContaining("gap-2"),
- );
-
- // Test SVG styling from buttonVariants
- await expect(buttons[0]).toHaveAttribute(
- "class",
- expect.stringContaining("[&_svg]:size-4"),
- );
-
- await expect(buttons[0]).toHaveAttribute(
- "class",
- expect.stringContaining("[&_svg]:shrink-0"),
- );
-
- await expect(buttons[0]).toHaveAttribute(
- "class",
- expect.stringContaining("[&_svg]:pointer-events-none"),
- );
+ const button = canvas.getByRole("button", { name: /Button with Icon/i });
+ const icon = button.querySelector("svg");
+ await expect(icon).toBeInTheDocument();
+ await expect(button).toHaveTextContent("Button with Icon");
},
};
@@ -337,8 +193,10 @@ export const LoadingState: Story = {
render: (args) => (
(
-
-
-
- Default variants have rounded-full style:
-
-
- Default
- Destructive
- Outline
- Secondary
- Ghost
-
-
-
-
- Link variant maintains its original style:
-
-
- Link
-
-
-
- ),
- play: async ({ canvasElement }) => {
- const canvas = within(canvasElement);
- const buttons = canvas.getAllByRole("button");
-
- // Test rounded-full on first 5 buttons
- for (let i = 0; i < 5; i++) {
- await expect(buttons[i]).toHaveAttribute(
- "class",
- expect.stringContaining("rounded-full"),
- );
- }
-
- // Test that link variant doesn't have rounded-full
- await expect(buttons[5]).not.toHaveAttribute(
- "class",
- expect.stringContaining("rounded-full"),
- );
},
};
diff --git a/autogpt_platform/frontend/src/components/ui/button.tsx b/autogpt_platform/frontend/src/components/ui/button.tsx
index 2422982d8d..2239996ac8 100644
--- a/autogpt_platform/frontend/src/components/ui/button.tsx
+++ b/autogpt_platform/frontend/src/components/ui/button.tsx
@@ -5,28 +5,28 @@ import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils";
const buttonVariants = cva(
- "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
+ "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-neutral-950 disabled:pointer-events-none disabled:opacity-50 dark:focus-visible:ring-neutral-300",
{
variants: {
variant: {
default:
- "bg-primary/90 text-primary-foreground shadow hover:bg-primary rounded-full",
+ "bg-neutral-900 text-neutral-50 shadow hover:bg-neutral-900/90 dark:bg-neutral-50 dark:text-neutral-900 dark:hover:bg-neutral-50/90",
destructive:
- "bg-destructive/90 text-destructive-foreground shadow-sm hover:bg-destructive rounded-full",
+ "bg-red-500 text-neutral-50 shadow-sm hover:bg-red-500/90 dark:bg-red-900 dark:text-neutral-50 dark:hover:bg-red-900/90",
outline:
- "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground rounded-full",
+ "border border-neutral-200 bg-white shadow-sm hover:bg-neutral-100 hover:text-neutral-900 dark:border-neutral-800 dark:bg-neutral-950 dark:hover:bg-neutral-800 dark:hover:text-neutral-50",
secondary:
- "bg-secondary/90 text-secondary-foreground shadow-sm hover:bg-secondary rounded-full",
- ghost: "hover:bg-accent hover:text-accent-foreground rounded-full",
- link: "text-primary underline-offset-4 hover:underline",
+ "bg-neutral-100 text-neutral-900 shadow-sm hover:bg-neutral-100/80 dark:bg-neutral-800 dark:text-neutral-50 dark:hover:bg-neutral-800/80",
+ ghost:
+ "hover:bg-neutral-100 hover:text-neutral-900 dark:hover:bg-neutral-800 dark:hover:text-neutral-50",
+ link: "text-neutral-900 underline-offset-4 hover:underline dark:text-neutral-50",
},
size: {
default: "h-9 px-4 py-2",
sm: "h-8 rounded-md px-3 text-xs",
lg: "h-10 rounded-md px-8",
- icon: "h-9 w-9",
- /** @deprecated Use default size with custom classes instead */
primary: "md:h-14 md:w-44 rounded-2xl h-10 w-28",
+ icon: "h-9 w-9",
},
},
defaultVariants: {