Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/afraid-steaks-give.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@zenml-io/react-component-library": minor
---

add initial version of the button component to the library
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"changeset": "changeset && pnpm install",
"changeset:publish": "changeset publish",
"changeset:version": "changeset version && pnpm install --lockfile-only",
"dev": "tsup --watch",
"format": "prettier -w src",
"prepare": "husky install",
"prepublishOnly": "pnpm build",
Expand All @@ -58,6 +59,8 @@
"*.{css,js,md,ts,jsx,tsx,ts}": "prettier --write"
},
"dependencies": {
"@radix-ui/react-slot": "^1.0.2",
"class-variance-authority": "^0.7.0",
"clsx": "^2.0.0",
"tailwind-merge": "^1.14.0",
"tailwindcss": "^3.3.3"
Expand Down
16 changes: 12 additions & 4 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

123 changes: 123 additions & 0 deletions src/components/button/Button.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import { Meta } from "@storybook/react";
import { Button } from "./Button";
import { StoryObj } from "@storybook/react";

const meta = {
title: "Elements/Button",
component: Button,
parameters: {
layout: "centered"
},
argTypes: {
onClick: { action: "clicked" },
size: {
description: "defining the size of the button",
control: "select",
defaultValue: "sm",
options: ["sm", "lg", "xl"]
},
intent: {
description: "defining the intent of the button",
defaultValue: "primary",
control: "select",
options: ["primary", "secondary", "danger"]
},
asChild: {
description: "if true, the props of the button are getting merged to the first child",
defaultValue: false,
control: "boolean"
},
emphasis: {
description: "emphasis of the button",
defaultValue: "bold",
control: "select",
options: ["bold", "subtle", "minimal"]
}
},
tags: ["autodocs"]
} satisfies Meta<typeof Button>;

export default meta;

type Story = StoryObj<typeof meta>;

export const Primary: Story = {
args: {
children: "Hello World",
size: "sm",
intent: "primary",
emphasis: "bold"
}
};

export const Secondary: Story = {
args: {
children: "Hello World",
size: "sm",
intent: "secondary",
emphasis: "bold"
}
};

export const Danger: Story = {
args: {
children: "Hello World",
size: "sm",
intent: "danger",
emphasis: "bold"
}
};

export const Small: Story = {
args: {
children: "Hello World",
size: "sm",
intent: "primary",
emphasis: "bold"
}
};

export const Large: Story = {
args: {
children: "Hello World",
size: "lg",
intent: "primary",
emphasis: "bold"
}
};

export const ExtraLarge: Story = {
args: {
children: "Hello World",
size: "xl",
intent: "primary",
emphasis: "bold"
}
};

export const Bold: Story = {
args: {
children: "Hello World",
emphasis: "bold",
size: "xl",
intent: "primary"
}
};

export const Subtle: Story = {
args: {
children: "Hello World",
size: "xl",
emphasis: "subtle",
intent: "primary"
}
};

export const Minimal: Story = {
args: {
children: "Hello World",
size: "xl",
intent: "primary",
emphasis: "minimal"
}
};
102 changes: 102 additions & 0 deletions src/components/button/Button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import React, { ButtonHTMLAttributes } from "react";
import { Slot } from "@radix-ui/react-slot";
import { type VariantProps, cva } from "class-variance-authority";
import { cn } from "../../utilities/index";

const buttonVariants = cva(
"transition-all rounded-md duration-200 flex gap-1 items-center font-semibold disabled:pointer-events-none",
{
variants: {
emphasis: {
bold: "",
subtle: "",
minimal: ""
},
intent: {
primary: "",
secondary: "",
danger: ""
},
size: {
sm: "py-1 px-2",
lg: "py-2 px-3",
xl: "py-3 px-5"
}
},
compoundVariants: [
// Primary
{
emphasis: "bold",
intent: "primary",
class:
"bg-primary-500 text-white hover:bg-primary-400 active:ring-[#E4D8FD] active:bg-primary-500 focus-visible:outline-none active:ring-4 disabled:bg-primary-50"
},
{
emphasis: "subtle",
intent: "primary",
class:
"border border-primary-400 text-primary-600 hover:bg-primary-50 active:bg-primary-100 active:ring-[#E4D8FD] active:ring-4 disabled:border-primary-100 disabled:text-primary-100"
},
{
emphasis: "minimal",
intent: "primary",
class:
"text-primary-600 hover:bg-primary-50 active:bg-primary-100 active:ring-[#E4D8FD] active:ring-4 disabled:text-primary-100"
},
// Secondary
{
emphasis: "bold",
intent: "secondary",
class:
"bg-neutral-200 text-theme-text-primary hover:bg-neutral-300 focus-visible:outline-none active:bg-neutral-400 active:ring-4 active:ring-[#E5E7EB] disabled:text-neutral-300"
},
{
emphasis: "subtle",
intent: "secondary",
class:
"border border-neutral-300 text-neutral-900 hover:bg-neutral-100 active:border-neutral-400 active:bg-neutral-300 active:ring-4 active:ring-neutral-100 disabled:border-neutral-300 disabled:text-neutral-300"
},
{
emphasis: "minimal",
intent: "secondary",
class:
"text-primary-900 hover:bg-neutral-200 active:bg-neutral-300 active:ring-4 active:ring-neutral-100 disabled:text-neutral-300"
},
// Danger
{
emphasis: "bold",
intent: "danger",
class:
"bg-error-600 text-white hover:bg-error-500 active:ring-error-50 active:bg-error-600 focus-visible:outline-none active:ring-4 disabled:bg-error-100"
},
{
emphasis: "subtle",
intent: "danger",
class:
"border border-error-600 text-error-700 hover:bg-error-50 active:bg-error-100 active:ring-4 active:ring-error-50 disabled:border-error-100 disabled:text-error-100"
},
{
emphasis: "minimal",
intent: "danger",
class:
"text-error-700 hover:bg-error-50 active:bg-error-100 active:ring-4 active:ring-error-50 disabled:text-error-100"
}
],
defaultVariants: {
size: "sm",
emphasis: "bold",
intent: "primary"
}
}
);

export interface ButtonProps
extends ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
asChild?: boolean;
}

export function Button({ intent, size, className, asChild, emphasis, ...rest }: ButtonProps) {
const Comp = asChild ? Slot : "button";
return <Comp className={cn(buttonVariants({ intent, size, emphasis }), className)} {...rest} />;
}
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export { cn } from "./utilities/index";
export { zenmlPlugin, zenmlPreset } from "./tailwind/index";
export { Button, ButtonProps } from "./components/button/Button";
File renamed without changes.
File renamed without changes.
File renamed without changes.