diff --git a/.storybook/main.ts b/.storybook/main.ts
index f5fe1c0..098c0fa 100644
--- a/.storybook/main.ts
+++ b/.storybook/main.ts
@@ -31,6 +31,8 @@ const config: StorybookConfig = {
resolve: {
alias: [
{ find: /^@\/components\/(.*)/, replacement: path.resolve(__dirname, "../lib/components/$1") },
+ { find: /^@\/utils\/(.*)/, replacement: path.resolve(__dirname, "../lib/utils/$1") },
+ { find: /^@\/ui\/(.*)/, replacement: path.resolve(__dirname, "../lib/components/ui/$1") },
{ find: /^@\/assets\/(.*)/, replacement: path.resolve(__dirname, "../lib/assets/$1") }
]
}
diff --git a/components.json b/components.json
index f505345..463900b 100644
--- a/components.json
+++ b/components.json
@@ -12,7 +12,7 @@
},
"aliases": {
"components": "@/components",
- "utils": "lib/utils/utils",
+ "utils": "@/utils/utils",
"ui": "@/components/ui"
}
}
\ No newline at end of file
diff --git a/lib/components/button/Button.tsx b/lib/components/button/Button.tsx
index 6a68dc8..2f27f5f 100644
--- a/lib/components/button/Button.tsx
+++ b/lib/components/button/Button.tsx
@@ -1,59 +1,48 @@
-import { twMerge } from "tailwind-merge";
-import {
- primary as primaryStyles,
- secondary as secondaryStyles,
-} from "./Button.styles";
-
+import { Button as ShadcnButton } from "@/ui/button";
// import { primary as primaryStyles, secondary as secondaryStyles } from "@/components/button/Button.styles";
export interface ButtonProps {
/**
* Is this the principal call to action on the page?
*/
- primary?: boolean;
- /**
- * What background color to use
- */
- backgroundColor?: string;
+ variant?:
+ | "default"
+ | "destructive"
+ | "outline"
+ | "secondary"
+ | "ghost"
+ | "link";
/**
* How large should the button be?
*/
- size?: "small" | "medium" | "large";
+ size?: "sm" | "default" | "lg" | "icon";
/**
- * Button contents
+ * Button contents. Can be a string or a React node (e.g. an icon)
*/
- label: string;
+ label: string | React.ReactNode;
/**
* Optional click handler
*/
onClick?: () => void;
+
+ /**
+ * Optional tailwindcss classes
+ */
+ className?: string;
}
/**
- * Primary UI component for user interaction
+ * Button component
*/
export const Button = ({
- primary = false,
- size = "medium",
+ variant = "default",
+ size = "default",
label,
...props
}: ButtonProps) => {
- const classes = [];
- const mode = primary ? primaryStyles : secondaryStyles;
- classes.push(mode);
- if (size === "small") {
- classes.push("text-sm");
- }
- if (size === "medium") {
- classes.push("text-base");
- }
- if (size === "large") {
- classes.push("text-xl");
- }
-
return (
-
+
+ {label}
+
);
};
diff --git a/lib/components/ui/button.tsx b/lib/components/ui/button.tsx
new file mode 100644
index 0000000..7cd9121
--- /dev/null
+++ b/lib/components/ui/button.tsx
@@ -0,0 +1,58 @@
+import * as React from "react";
+import { Slot } from "@radix-ui/react-slot";
+import { cva, type VariantProps } from "class-variance-authority";
+
+import { cn } from "@/utils/utils";
+
+const buttonVariants = cva(
+ "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-white transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-slate-950 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 dark:ring-offset-slate-950 dark:focus-visible:ring-slate-300",
+ {
+ variants: {
+ variant: {
+ default:
+ "bg-slate-900 text-slate-50 hover:bg-slate-900/90 dark:bg-slate-50 dark:text-slate-900 dark:hover:bg-slate-50/90",
+ destructive:
+ "bg-red-500 text-slate-50 hover:bg-red-500/90 dark:bg-red-900 dark:text-slate-50 dark:hover:bg-red-900/90",
+ outline:
+ "border border-slate-200 bg-white hover:bg-slate-100 hover:text-slate-900 dark:border-slate-800 dark:bg-slate-950 dark:hover:bg-slate-800 dark:hover:text-slate-50",
+ secondary:
+ "bg-slate-100 text-slate-900 hover:bg-slate-100/80 dark:bg-slate-800 dark:text-slate-50 dark:hover:bg-slate-800/80",
+ ghost:
+ "hover:bg-slate-100 hover:text-slate-900 dark:hover:bg-slate-800 dark:hover:text-slate-50",
+ link: "text-slate-900 underline-offset-4 hover:underline dark:text-slate-50",
+ },
+ size: {
+ default: "h-10 px-4 py-2",
+ sm: "h-9 rounded-md px-3",
+ lg: "h-11 rounded-md px-8",
+ icon: "h-10 w-10",
+ },
+ },
+ defaultVariants: {
+ variant: "default",
+ size: "default",
+ },
+ },
+);
+
+export interface ButtonProps
+ extends React.ButtonHTMLAttributes,
+ VariantProps {
+ asChild?: boolean;
+}
+
+const Button = React.forwardRef(
+ ({ className, variant, size, asChild = false, ...props }, ref) => {
+ const Comp = asChild ? Slot : "button";
+ return (
+
+ );
+ },
+);
+Button.displayName = "Button";
+
+export { Button, buttonVariants };
diff --git a/lib/tailwind/config.ts b/lib/tailwind/config.ts
index 8756ca9..6393e3e 100644
--- a/lib/tailwind/config.ts
+++ b/lib/tailwind/config.ts
@@ -8,50 +8,36 @@ const theme = {
extend: {
colors: {
brand: {
- 100: "#E1F5FE",
- 200: "#B3E5FC",
- 300: "#81D4FA",
- 400: "#4FC3F7",
- 500: "#29B6F6",
- 600: "#03A9F4",
- 700: "#039BE5",
- 800: "#0288D1",
- 900: "#01579B",
+ 100: "#e0f2fe",
+ 200: "#bae6fd",
+ 300: "#7dd3fc",
+ 400: "#38bdf8",
+ 500: "#0ea5e9",
+ 600: "#0284c7",
+ 700: "#0369a1",
+ 800: "#075985",
+ 900: "#0c4a6e",
+ 950: "#082f49",
},
accent: {
- 100: "#FF80AB",
- 200: "#FF4081",
- 300: "#F50057",
- 400: "#C51162",
- 500: "#880E4F",
- 600: "#AD1457",
- 700: "#C2185B",
- 800: "#D81B60",
- 900: "#E91E63",
- },
- text: {
- primary: "#FFF",
+ primary: "#f8fafc",
secondary: "#757575",
- disabled: "#BDBDBD",
- hint: "#9E9E9E",
- inverted: "#000000", // Changed from white to black
- },
- supporting: {
- success: "#4CAF50", // Green
- error: "#F44336", // Red
- warning: "#FFC107", // Yellow
- info: "#2196F3", // Blue
+ inverted: "#000000",
+ success: "#065f46", // Green
+ error: "#991b1b", // Red
+ warning: "#ca8a04", // Yellow
+ info: "#075985", // Blue
},
neutral: {
- 100: "#F5F5F5",
- 200: "#EEEEEE",
- 300: "#E0E0E0",
- 400: "#BDBDBD",
- 500: "#9E9E9E",
- 600: "#757575",
- 700: "#616161",
- 800: "#424242",
- 900: "#212121",
+ 100: "#f1f5f9",
+ 200: "#e2e8f0",
+ 300: "#cbd5e1",
+ 400: "#94a3b8",
+ 500: "#64748b",
+ 600: "#475569",
+ 700: "#334155",
+ 800: "#1e293b",
+ 900: "#0f172a",
},
},
},
diff --git a/package-lock.json b/package-lock.json
index aebe5c9..241c4e5 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,6 +8,9 @@
"name": "@maany_shr/rage-ui-kit",
"version": "1.0.0-alpha",
"dependencies": {
+ "@heroicons/react": "^2.1.3",
+ "@radix-ui/react-icons": "^1.3.0",
+ "@radix-ui/react-slot": "^1.0.2",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.0",
"lucide-react": "^0.372.0",
@@ -2220,7 +2223,6 @@
"version": "7.24.4",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.4.tgz",
"integrity": "sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA==",
- "dev": true,
"dependencies": {
"regenerator-runtime": "^0.14.0"
},
@@ -2853,6 +2855,14 @@
"integrity": "sha512-cEee/Z+I12mZcFJshKcCqC8tuX5hG3s+d+9nZ3LabqKF1vKdF41B92pJVCBggjAGORAeOzyyDDKrZwIkLffeOQ==",
"dev": true
},
+ "node_modules/@heroicons/react": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/@heroicons/react/-/react-2.1.3.tgz",
+ "integrity": "sha512-fEcPfo4oN345SoqdlCDdSa4ivjaKbk0jTd+oubcgNxnNgAfzysfwWfQUr+51wigiWHQQRiZNd1Ao0M5Y3M2EGg==",
+ "peerDependencies": {
+ "react": ">= 16"
+ }
+ },
"node_modules/@humanwhocodes/config-array": {
"version": "0.11.14",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
@@ -3263,7 +3273,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.1.tgz",
"integrity": "sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==",
- "dev": true,
"dependencies": {
"@babel/runtime": "^7.13.10"
},
@@ -3277,11 +3286,18 @@
}
}
},
+ "node_modules/@radix-ui/react-icons": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-icons/-/react-icons-1.3.0.tgz",
+ "integrity": "sha512-jQxj/0LKgp+j9BiTXz3O3sgs26RNet2iLWmsPyRz2SIcR4q/4SbazXfnYwbAr+vLYKSfc7qxzyGQA1HLlYiuNw==",
+ "peerDependencies": {
+ "react": "^16.x || ^17.x || ^18.x"
+ }
+ },
"node_modules/@radix-ui/react-slot": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.0.2.tgz",
"integrity": "sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==",
- "dev": true,
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-compose-refs": "1.0.1"
@@ -5465,7 +5481,7 @@
"version": "15.7.11",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz",
"integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==",
- "dev": true
+ "devOptional": true
},
"node_modules/@types/qs": {
"version": "6.9.15",
@@ -5483,7 +5499,7 @@
"version": "18.2.48",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.48.tgz",
"integrity": "sha512-qboRCl6Ie70DQQG9hhNREz81jqC1cs9EVNcjQ1AU+jH6NFfSAhVVbrrY/+nSF+Bsk4AOwm9Qa61InvMCyV+H3w==",
- "dev": true,
+ "devOptional": true,
"dependencies": {
"@types/prop-types": "*",
"@types/scheduler": "*",
@@ -5509,7 +5525,7 @@
"version": "0.16.8",
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz",
"integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==",
- "dev": true
+ "devOptional": true
},
"node_modules/@types/semver": {
"version": "7.5.6",
@@ -7503,7 +7519,7 @@
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
- "dev": true
+ "devOptional": true
},
"node_modules/data-urls": {
"version": "5.0.0",
@@ -12525,8 +12541,7 @@
"node_modules/regenerator-runtime": {
"version": "0.14.1",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
- "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
- "dev": true
+ "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="
},
"node_modules/regenerator-transform": {
"version": "0.15.2",
diff --git a/package.json b/package.json
index 8d4843a..68910bd 100644
--- a/package.json
+++ b/package.json
@@ -92,6 +92,9 @@
"vitest": "^1.2.2"
},
"dependencies": {
+ "@heroicons/react": "^2.1.3",
+ "@radix-ui/react-icons": "^1.3.0",
+ "@radix-ui/react-slot": "^1.0.2",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.0",
"lucide-react": "^0.372.0",
diff --git a/stories/components/Button.stories.ts b/stories/components/Button.stories.tsx
similarity index 70%
rename from stories/components/Button.stories.ts
rename to stories/components/Button.stories.tsx
index e87ed70..9adeb07 100644
--- a/stories/components/Button.stories.ts
+++ b/stories/components/Button.stories.tsx
@@ -1,6 +1,7 @@
import type { Meta, StoryObj } from "@storybook/react";
import { Button } from "@/components/button";
+import { Satellite } from "lucide-react";
// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export
const meta = {
@@ -12,10 +13,6 @@ const meta = {
},
// This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs
tags: ["autodocs"],
- // More on argTypes: https://storybook.js.org/docs/api/argtypes
- argTypes: {
- backgroundColor: { control: "color" },
- },
} satisfies Meta;
export default meta;
@@ -23,28 +20,22 @@ type Story = StoryObj;
// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args
export const Primary: Story = {
- args: {
- primary: true,
- label: "Button",
- },
-};
-
-export const Secondary: Story = {
args: {
label: "Button",
},
};
-export const Large: Story = {
+export const TextIcon: Story = {
args: {
- size: "large",
- label: "Button",
+ label: "🚀",
+ size: "icon",
},
};
-export const Small: Story = {
+export const ReactIcon: Story = {
args: {
- size: "small",
- label: "Button",
+ label: ,
+ size: "icon",
+ variant: "outline",
},
};
diff --git a/tsconfig.json b/tsconfig.json
index 6b893d7..170601b 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -23,7 +23,9 @@
"types": ["@testing-library/jest-dom", "vite/client"],
"paths": {
"@/components/*": ["./lib/components/*"],
+ "@/utils/*": ["./lib/utils/*"],
"@/assets/*": ["./lib/assets/*"],
+ "@/ui/*": ["./lib/components/ui/*"],
}
},
"include": ["app", "lib", "tests", "stories"],
diff --git a/vite.config.ts b/vite.config.ts
index 4e033ad..1fa283b 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -19,6 +19,14 @@ export default defineConfig({
find: /^@\/assets\/(.*)/,
replacement: path.resolve(__dirname, "lib/assets/$1"),
},
+ {
+ find: /^@\/ui\/(.*)/,
+ replacement: path.resolve(__dirname, "lib/ui/$1"),
+ },
+ {
+ find: /^@\/utils\/(.*)/,
+ replacement: path.resolve(__dirname, "lib/utils/$1"),
+ },
],
},
test: {
@@ -31,6 +39,14 @@ export default defineConfig({
find: /^@\/assets\/(.*)/,
replacement: path.resolve(__dirname, "lib/assets/$1"),
},
+ {
+ find: /^@\/ui\/(.*)/,
+ replacement: path.resolve(__dirname, "lib/ui/$1"),
+ },
+ {
+ find: /^@\/utils\/(.*)/,
+ replacement: path.resolve(__dirname, "lib/utils/$1"),
+ },
],
clearMocks: true,
globals: true,