diff --git a/packages/propel/package.json b/packages/propel/package.json index 739df238545..8d0f939b49b 100644 --- a/packages/propel/package.json +++ b/packages/propel/package.json @@ -19,6 +19,7 @@ "./accordion": "./dist/accordion/index.js", "./animated-counter": "./dist/animated-counter/index.js", "./avatar": "./dist/avatar/index.js", + "./button": "./dist/button/index.js", "./calendar": "./dist/calendar/index.js", "./card": "./dist/card/index.js", "./charts/*": "./dist/charts/*/index.js", diff --git a/packages/propel/src/button/button.stories.tsx b/packages/propel/src/button/button.stories.tsx new file mode 100644 index 00000000000..4f017099245 --- /dev/null +++ b/packages/propel/src/button/button.stories.tsx @@ -0,0 +1,119 @@ +import type { Meta, StoryObj } from "@storybook/react-vite"; +import { Button, EButtonVariant, EButtonSize } from "./button"; + +const meta: Meta = { + title: "Components/Button", + component: Button, + parameters: { + layout: "centered", + }, + tags: ["autodocs"], + argTypes: { + variant: { + control: "select", + options: Object.values(EButtonVariant), + }, + size: { + control: "select", + options: Object.values(EButtonSize), + }, + }, +}; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + children: "Button", + }, +}; + +export const Primary: Story = { + args: { + variant: EButtonVariant.PRIMARY, + children: "Primary Button", + }, +}; + +export const Secondary: Story = { + args: { + variant: EButtonVariant.SECONDARY, + children: "Secondary Button", + }, +}; + +export const Outline: Story = { + args: { + variant: EButtonVariant.OUTLINE, + children: "Outline Button", + }, +}; + +export const Ghost: Story = { + args: { + variant: EButtonVariant.GHOST, + children: "Ghost Button", + }, +}; + +export const Destructive: Story = { + args: { + variant: EButtonVariant.DESTRUCTIVE, + children: "Destructive Button", + }, +}; + +export const Small: Story = { + args: { + size: EButtonSize.SM, + children: "Small Button", + }, +}; + +export const Medium: Story = { + args: { + size: EButtonSize.MD, + children: "Medium Button", + }, +}; + +export const Large: Story = { + args: { + size: EButtonSize.LG, + children: "Large Button", + }, +}; + +export const Disabled: Story = { + args: { + disabled: true, + children: "Disabled Button", + }, +}; + +export const AllVariants: Story = { + render: () => ( +
+
+ + + + + +
+
+ ), +}; + +export const AllSizes: Story = { + render: () => ( +
+
+ + + +
+
+ ), +}; diff --git a/packages/propel/src/button/button.tsx b/packages/propel/src/button/button.tsx new file mode 100644 index 00000000000..995b5d3dad6 --- /dev/null +++ b/packages/propel/src/button/button.tsx @@ -0,0 +1,73 @@ +import * as React from "react"; +import { cn } from "../utils"; + +export enum EButtonVariant { + PRIMARY = "primary", + SECONDARY = "secondary", + OUTLINE = "outline", + GHOST = "ghost", + DESTRUCTIVE = "destructive", +} + +export enum EButtonSize { + SM = "sm", + MD = "md", + LG = "lg", +} + +export type TButtonVariant = + | EButtonVariant.PRIMARY + | EButtonVariant.SECONDARY + | EButtonVariant.OUTLINE + | EButtonVariant.GHOST + | EButtonVariant.DESTRUCTIVE; +export type TButtonSize = EButtonSize.SM | EButtonSize.MD | EButtonSize.LG; + +export interface ButtonProps extends React.ButtonHTMLAttributes { + variant?: TButtonVariant; + size?: TButtonSize; + className?: string; + children: React.ReactNode; +} + +const buttonVariants = { + [EButtonVariant.PRIMARY]: "bg-custom-primary-100 text-white hover:bg-custom-primary-200 focus:bg-custom-primary-200", + [EButtonVariant.SECONDARY]: + "bg-custom-background-100 text-custom-text-200 border border-custom-border-200 hover:bg-custom-background-90 focus:bg-custom-background-90", + [EButtonVariant.OUTLINE]: + "border border-custom-primary-100 text-custom-primary-100 bg-transparent hover:bg-custom-primary-100/10 focus:bg-custom-primary-100/20", + [EButtonVariant.GHOST]: "text-custom-text-200 hover:bg-custom-background-90 focus:bg-custom-background-90", + [EButtonVariant.DESTRUCTIVE]: "bg-red-500 text-white hover:bg-red-600 focus:bg-red-600", +}; + +const buttonSizes = { + [EButtonSize.SM]: "px-3 py-1.5 text-xs font-medium", + [EButtonSize.MD]: "px-4 py-2 text-sm font-medium", + [EButtonSize.LG]: "px-6 py-2.5 text-base font-medium", +}; + +const Button = React.forwardRef( + ({ variant = EButtonVariant.PRIMARY, size = EButtonSize.MD, className, children, ...props }, ref) => ( + + ) +); + +Button.displayName = "Button"; + +export { Button }; diff --git a/packages/propel/src/button/index.ts b/packages/propel/src/button/index.ts new file mode 100644 index 00000000000..8827201b535 --- /dev/null +++ b/packages/propel/src/button/index.ts @@ -0,0 +1,2 @@ +export { Button } from "./button"; +export type { ButtonProps } from "./button"; diff --git a/packages/propel/tsdown.config.ts b/packages/propel/tsdown.config.ts index b571adb3107..e53e47d619c 100644 --- a/packages/propel/tsdown.config.ts +++ b/packages/propel/tsdown.config.ts @@ -5,6 +5,7 @@ export default defineConfig({ "src/accordion/index.ts", "src/animated-counter/index.ts", "src/avatar/index.ts", + "src/button/index.ts", "src/calendar/index.ts", "src/card/index.ts", "src/charts/*/index.ts",