Skip to content

Commit c4c2c29

Browse files
feat: add button component (#19)
1 parent 40688df commit c4c2c29

File tree

9 files changed

+246
-4
lines changed

9 files changed

+246
-4
lines changed

.changeset/afraid-steaks-give.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@zenml-io/react-component-library": minor
3+
---
4+
5+
add initial version of the button component to the library

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
"changeset": "changeset && pnpm install",
4747
"changeset:publish": "changeset publish",
4848
"changeset:version": "changeset version && pnpm install --lockfile-only",
49+
"dev": "tsup --watch",
4950
"format": "prettier -w src",
5051
"prepare": "husky install",
5152
"prepublishOnly": "pnpm build",
@@ -58,6 +59,8 @@
5859
"*.{css,js,md,ts,jsx,tsx,ts}": "prettier --write"
5960
},
6061
"dependencies": {
62+
"@radix-ui/react-slot": "^1.0.2",
63+
"class-variance-authority": "^0.7.0",
6164
"clsx": "^2.0.0",
6265
"tailwind-merge": "^1.14.0",
6366
"tailwindcss": "^3.3.3"

pnpm-lock.yaml

Lines changed: 12 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
import { Meta } from "@storybook/react";
2+
import { Button } from "./Button";
3+
import { StoryObj } from "@storybook/react";
4+
5+
const meta = {
6+
title: "Elements/Button",
7+
component: Button,
8+
parameters: {
9+
layout: "centered"
10+
},
11+
argTypes: {
12+
onClick: { action: "clicked" },
13+
size: {
14+
description: "defining the size of the button",
15+
control: "select",
16+
defaultValue: "sm",
17+
options: ["sm", "lg", "xl"]
18+
},
19+
intent: {
20+
description: "defining the intent of the button",
21+
defaultValue: "primary",
22+
control: "select",
23+
options: ["primary", "secondary", "danger"]
24+
},
25+
asChild: {
26+
description: "if true, the props of the button are getting merged to the first child",
27+
defaultValue: false,
28+
control: "boolean"
29+
},
30+
emphasis: {
31+
description: "emphasis of the button",
32+
defaultValue: "bold",
33+
control: "select",
34+
options: ["bold", "subtle", "minimal"]
35+
}
36+
},
37+
tags: ["autodocs"]
38+
} satisfies Meta<typeof Button>;
39+
40+
export default meta;
41+
42+
type Story = StoryObj<typeof meta>;
43+
44+
export const Primary: Story = {
45+
args: {
46+
children: "Hello World",
47+
size: "sm",
48+
intent: "primary",
49+
emphasis: "bold"
50+
}
51+
};
52+
53+
export const Secondary: Story = {
54+
args: {
55+
children: "Hello World",
56+
size: "sm",
57+
intent: "secondary",
58+
emphasis: "bold"
59+
}
60+
};
61+
62+
export const Danger: Story = {
63+
args: {
64+
children: "Hello World",
65+
size: "sm",
66+
intent: "danger",
67+
emphasis: "bold"
68+
}
69+
};
70+
71+
export const Small: Story = {
72+
args: {
73+
children: "Hello World",
74+
size: "sm",
75+
intent: "primary",
76+
emphasis: "bold"
77+
}
78+
};
79+
80+
export const Large: Story = {
81+
args: {
82+
children: "Hello World",
83+
size: "lg",
84+
intent: "primary",
85+
emphasis: "bold"
86+
}
87+
};
88+
89+
export const ExtraLarge: Story = {
90+
args: {
91+
children: "Hello World",
92+
size: "xl",
93+
intent: "primary",
94+
emphasis: "bold"
95+
}
96+
};
97+
98+
export const Bold: Story = {
99+
args: {
100+
children: "Hello World",
101+
emphasis: "bold",
102+
size: "xl",
103+
intent: "primary"
104+
}
105+
};
106+
107+
export const Subtle: Story = {
108+
args: {
109+
children: "Hello World",
110+
size: "xl",
111+
emphasis: "subtle",
112+
intent: "primary"
113+
}
114+
};
115+
116+
export const Minimal: Story = {
117+
args: {
118+
children: "Hello World",
119+
size: "xl",
120+
intent: "primary",
121+
emphasis: "minimal"
122+
}
123+
};

src/components/button/Button.tsx

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import React, { ButtonHTMLAttributes } from "react";
2+
import { Slot } from "@radix-ui/react-slot";
3+
import { type VariantProps, cva } from "class-variance-authority";
4+
import { cn } from "../../utilities/index";
5+
6+
const buttonVariants = cva(
7+
"transition-all rounded-md duration-200 flex gap-1 items-center font-semibold disabled:pointer-events-none",
8+
{
9+
variants: {
10+
emphasis: {
11+
bold: "",
12+
subtle: "",
13+
minimal: ""
14+
},
15+
intent: {
16+
primary: "",
17+
secondary: "",
18+
danger: ""
19+
},
20+
size: {
21+
sm: "py-1 px-2",
22+
lg: "py-2 px-3",
23+
xl: "py-3 px-5"
24+
}
25+
},
26+
compoundVariants: [
27+
// Primary
28+
{
29+
emphasis: "bold",
30+
intent: "primary",
31+
class:
32+
"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"
33+
},
34+
{
35+
emphasis: "subtle",
36+
intent: "primary",
37+
class:
38+
"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"
39+
},
40+
{
41+
emphasis: "minimal",
42+
intent: "primary",
43+
class:
44+
"text-primary-600 hover:bg-primary-50 active:bg-primary-100 active:ring-[#E4D8FD] active:ring-4 disabled:text-primary-100"
45+
},
46+
// Secondary
47+
{
48+
emphasis: "bold",
49+
intent: "secondary",
50+
class:
51+
"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"
52+
},
53+
{
54+
emphasis: "subtle",
55+
intent: "secondary",
56+
class:
57+
"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"
58+
},
59+
{
60+
emphasis: "minimal",
61+
intent: "secondary",
62+
class:
63+
"text-primary-900 hover:bg-neutral-200 active:bg-neutral-300 active:ring-4 active:ring-neutral-100 disabled:text-neutral-300"
64+
},
65+
// Danger
66+
{
67+
emphasis: "bold",
68+
intent: "danger",
69+
class:
70+
"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"
71+
},
72+
{
73+
emphasis: "subtle",
74+
intent: "danger",
75+
class:
76+
"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"
77+
},
78+
{
79+
emphasis: "minimal",
80+
intent: "danger",
81+
class:
82+
"text-error-700 hover:bg-error-50 active:bg-error-100 active:ring-4 active:ring-error-50 disabled:text-error-100"
83+
}
84+
],
85+
defaultVariants: {
86+
size: "sm",
87+
emphasis: "bold",
88+
intent: "primary"
89+
}
90+
}
91+
);
92+
93+
export interface ButtonProps
94+
extends ButtonHTMLAttributes<HTMLButtonElement>,
95+
VariantProps<typeof buttonVariants> {
96+
asChild?: boolean;
97+
}
98+
99+
export function Button({ intent, size, className, asChild, emphasis, ...rest }: ButtonProps) {
100+
const Comp = asChild ? Slot : "button";
101+
return <Comp className={cn(buttonVariants({ intent, size, emphasis }), className)} {...rest} />;
102+
}

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export { cn } from "./utilities/index";
22
export { zenmlPlugin, zenmlPreset } from "./tailwind/index";
3+
export { Button, ButtonProps } from "./components/button/Button";
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)