@rajdeep0510/scaffold-cli 1.0.1 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,28 @@
1
+ name: Publish npm Package
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main # Trigger when pushing to main branch
7
+
8
+ jobs:
9
+ publish:
10
+ runs-on: ubuntu-latest
11
+
12
+ steps:
13
+ - name: Checkout repo
14
+ uses: actions/checkout@v3
15
+
16
+ - name: Setup Node.js
17
+ uses: actions/setup-node@v3
18
+ with:
19
+ node-version: "20"
20
+ registry-url: "https://registry.npmjs.org/"
21
+
22
+ - name: Install dependencies
23
+ run: npm ci
24
+
25
+ - name: Publish to npm
26
+ run: npm publish
27
+ env:
28
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
package/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # scaffold
2
2
 
3
+ ![NPM Version](https://img.shields.io/npm/v/%40rajdeep0510%2Fscaffold-cli)
4
+
3
5
  A CLI tool for creating versatile and modern UI components.
4
6
 
5
7
  ## Import components
@@ -4,73 +4,99 @@ import { fileURLToPath } from 'url'
4
4
  import chalk from 'chalk'
5
5
  import figlet from 'figlet'
6
6
  import ora from 'ora'
7
+ import { execSync } from 'child_process'
7
8
 
8
9
  const __dirname = path.dirname(fileURLToPath(import.meta.url)) // ESM-safe __dirname
9
10
 
10
11
 
11
12
  // banner TODO: remove
12
13
  console.log(
13
- chalk.cyan(
14
- figlet.text('scaffold', { font: 'doom' }, function(err, data) {
15
- if (err) {
16
- console.log('Something went wrong...');
17
- console.dir(err);
18
- return;
19
- }
20
- console.log(data);
21
- })
22
-
23
- )
14
+ chalk.cyan(
15
+ figlet.text('scaffold', { font: 'doom' }, function (err, data) {
16
+ if (err) {
17
+ console.log('Something went wrong...');
18
+ console.dir(err);
19
+ return;
20
+ }
21
+ console.log(data);
22
+ })
23
+
24
+ )
24
25
  )
25
26
 
26
27
  export async function addComponent(name) {
27
- const useSrc = await fs.pathExists('src')
28
- const hasApp = await fs.pathExists(path.join(useSrc ? 'src' : '', 'app'))
29
- const hasPages = await fs.pathExists(path.join(useSrc ? 'src' : '', 'pages'))
28
+ const useSrc = await fs.pathExists('src')
29
+ const hasApp = await fs.pathExists(path.join(useSrc ? 'src' : '', 'app'))
30
+ const hasPages = await fs.pathExists(path.join(useSrc ? 'src' : '', 'pages'))
30
31
 
31
- if (!hasApp && !hasPages) {
32
- console.log(chalk.red('Could not detect Next.js routing structure (no app/ or pages/ directory)'))
33
- return
34
- }
32
+ if (!hasApp && !hasPages) {
33
+ console.log(chalk.red('Could not detect Next.js routing structure (no app/ or pages/ directory)'))
34
+ return
35
+ }
35
36
 
36
- const baseDir = useSrc ? 'src/components/ui' : 'components/ui'
37
- const targetDir = path.join(baseDir, name)
38
- const templateDir = path.resolve(__dirname, '../templates', name)
37
+ const baseDir = useSrc ? 'src/components/ui' : 'components/ui'
38
+ const targetDir = path.join(baseDir, name)
39
+ const templateDir = path.resolve(__dirname, '../templates', name)
39
40
 
40
- // 🔎 check if template folder exists
41
- if (!(await fs.pathExists(templateDir))) {
42
- console.log(chalk.red(`Template folder '${templateDir}' not found.`))
43
- return
44
- }
41
+ // 🔎 check if template folder exists
42
+ if (!(await fs.pathExists(templateDir))) {
43
+ console.log(chalk.red(`Template folder '${templateDir}' not found.`))
44
+ return
45
+ }
45
46
 
46
- // 🔎 validate meta.json before copying
47
- const metaPath = path.join(templateDir, 'meta.json')
48
- if (!(await fs.pathExists(metaPath))) {
49
- console.log(chalk.red(`No meta.json found in template '${name}'`))
50
- return
51
- }
47
+ // 🔎 validate meta.json before copying
48
+ const metaPath = path.join(templateDir, 'meta.json')
49
+ if (!(await fs.pathExists(metaPath))) {
50
+ console.log(chalk.red(`No meta.json found in template '${name}'`))
51
+ return
52
+ }
52
53
 
53
- const meta = await fs.readJson(metaPath)
54
- if (!meta.name || !meta.description || !meta.version) {
55
- console.log(chalk.red(`Invalid meta.json for '${name}'. Missing required fields.`))
56
- return
57
- }
54
+ const meta = await fs.readJson(metaPath)
55
+ if (!meta.name || !meta.description || !meta.version) {
56
+ console.log(chalk.red(`Invalid meta.json for '${name}'. Missing required fields.`))
57
+ return
58
+ }
58
59
 
59
- // 🌀 Spinner while copying
60
- const spinner = ora(`Adding component '${name}'...`).start()
60
+ // 🌀 Spinner while copying
61
+ const spinner = ora(`Adding component '${name}'...`).start()
61
62
 
62
- try {
63
- await fs.ensureDir(targetDir)
64
- await fs.copy(templateDir, targetDir)
63
+ try {
64
+ await fs.ensureDir(targetDir)
65
+ await fs.copy(templateDir, targetDir)
65
66
 
66
- spinner.succeed(chalk.green(`Component '${meta.name}' created at ${targetDir}`))
67
-
68
- console.log(chalk.yellow(`ℹ️ Description:`), chalk.white(meta.description))
69
- console.log(chalk.magenta(`📦 Version:`), chalk.white(meta.version))
70
- console.log(chalk.cyan(`\n👉 Import in Next.js:`))
71
- console.log(chalk.blueBright(` import { ${meta.name} } from "@/components/ui/${name}"\n`))
72
- } catch (err) {
73
- spinner.fail(chalk.red(`Failed to add component '${name}'`))
67
+ // Install dependencies if specified in meta.json
68
+ if (meta.dependencies && (meta.dependencies.npm?.length > 0 || meta.dependencies.peer?.length > 0)) {
69
+ spinner.text = `Installing dependencies for '${name}'...`
70
+
71
+ try {
72
+ if (meta.dependencies.npm?.length > 0) {
73
+ const npmDeps = meta.dependencies.npm.join(' ')
74
+ execSync(`npm install ${npmDeps}`, { stdio: 'inherit' })
75
+ console.log(chalk.green(`✅ Installed npm dependencies: ${npmDeps}`))
76
+ }
77
+
78
+ if (meta.dependencies.peer?.length > 0) {
79
+ const peerDeps = meta.dependencies.peer.join(' ')
80
+ execSync(`npm install --save-peer ${peerDeps}`, { stdio: 'inherit' })
81
+ console.log(chalk.green(`✅ Installed peer dependencies: ${peerDeps}`))
82
+ }
83
+ } catch (err) {
84
+ console.log(chalk.yellow(`⚠️ Warning: Failed to install some dependencies. You may need to install them manually.`))
74
85
  console.error(err)
86
+ }
75
87
  }
88
+
89
+ spinner.succeed(chalk.green(`Component '${meta.name}' created at ${targetDir}`))
90
+
91
+ console.log(chalk.yellow(`ℹ️ Description:`), chalk.white(meta.description))
92
+ console.log(chalk.magenta(`📦 Version:`), chalk.white(meta.version))
93
+ console.log(chalk.magenta(`Author :`), chalk.white(meta.author))
94
+ console.log(chalk.cyan(`\n👉 Import in Next.js:`))
95
+ console.log(chalk.blueBright(` import { ${meta.name} } from "@/components/ui/${name}"\n`))
96
+ } catch (err) {
97
+ spinner.fail(chalk.red(`Failed to add component '${name}'`))
98
+ console.error(err)
99
+ }
76
100
  }
101
+
102
+ // change made TODO:remove
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rajdeep0510/scaffold-cli",
3
- "version": "1.0.1",
3
+ "version": "1.2.0",
4
4
  "description": "This is a CLI app for a UI library which is used for creating versatile and modern UI components.",
5
5
  "main": "bin/index.js",
6
6
  "type": "module",
@@ -0,0 +1,62 @@
1
+ // component.jsx
2
+ import { useState } from "react";
3
+ import PropTypes from "prop-types";
4
+
5
+ export default function Avatar({
6
+ src,
7
+ alt,
8
+ name,
9
+ info,
10
+ size = "md",
11
+ cardPosition = "bottom",
12
+ }) {
13
+ const [showCard, setShowCard] = useState(false);
14
+
15
+ // Avatar size styles
16
+ const sizeClasses = {
17
+ sm: "w-8 h-8",
18
+ md: "w-12 h-12",
19
+ lg: "w-16 h-16",
20
+ };
21
+
22
+ // Hover card position
23
+ const positionClasses =
24
+ cardPosition === "top" ? "bottom-full mb-2" : "top-full mt-2";
25
+
26
+ return (
27
+ <div
28
+ className="relative inline-block"
29
+ onMouseEnter={() => setShowCard(true)}
30
+ onMouseLeave={() => setShowCard(false)}
31
+ >
32
+ {/* Avatar Image */}
33
+ <img
34
+ src={src}
35
+ alt={alt || "Avatar"}
36
+ className={`${sizeClasses[size]} rounded-full object-cover border shadow-sm cursor-pointer`}
37
+ />
38
+
39
+ {/* Hover Card */}
40
+ {showCard && (
41
+ <div
42
+ className={`absolute left-1/2 -translate-x-1/2 ${positionClasses}
43
+ bg-white shadow-lg rounded-2xl p-3 w-48
44
+ border text-sm z-10`}
45
+ >
46
+ <p className="font-extrabold">{name}</p>
47
+ <p className="text-gray-600">{info}</p>
48
+ </div>
49
+ )}
50
+ </div>
51
+ );
52
+ }
53
+
54
+ // PropTypes validation
55
+ Avatar.propTypes = {
56
+ src: PropTypes.string.isRequired,
57
+ alt: PropTypes.string,
58
+ name: PropTypes.string.isRequired,
59
+ info: PropTypes.string,
60
+ size: PropTypes.oneOf(["sm", "md", "lg"]),
61
+ cardPosition: PropTypes.oneOf(["top", "bottom"]),
62
+ };
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Avatar component barrel export
3
+ */
4
+ export { default } from "./component";
5
+ export { default as Avatar } from "./component";
@@ -0,0 +1,92 @@
1
+ {
2
+ "name": "Avatar",
3
+ "description": "An avatar component that displays a profile picture and shows a hover card with name and info.",
4
+ "category": "display",
5
+ "tags": [
6
+ "avatar",
7
+ "profile",
8
+ "hover",
9
+ "info",
10
+ "card",
11
+ "ui",
12
+ "tailwind"
13
+ ],
14
+ "version": "1.0.0",
15
+ "author": "@rajdeep",
16
+ "created": "2025-08-29",
17
+ "dependencies": {
18
+ "npm": [],
19
+ "peer": [
20
+ "react",
21
+ "prop-types"
22
+ ]
23
+ },
24
+ "props": [
25
+ {
26
+ "name": "src",
27
+ "type": "string",
28
+ "required": true,
29
+ "default": "undefined",
30
+ "description": "Image URL or path from public folder for the avatar"
31
+ },
32
+ {
33
+ "name": "alt",
34
+ "type": "string",
35
+ "required": false,
36
+ "default": "Avatar",
37
+ "description": "Alternative text for accessibility"
38
+ },
39
+ {
40
+ "name": "name",
41
+ "type": "string",
42
+ "required": true,
43
+ "default": "undefined",
44
+ "description": "Name displayed in hover card"
45
+ },
46
+ {
47
+ "name": "info",
48
+ "type": "string",
49
+ "required": false,
50
+ "default": "undefined",
51
+ "description": "Additional info displayed in hover card"
52
+ },
53
+ {
54
+ "name": "size",
55
+ "type": "string",
56
+ "required": false,
57
+ "default": "md",
58
+ "description": "Avatar size",
59
+ "options": [
60
+ "sm",
61
+ "md",
62
+ "lg"
63
+ ]
64
+ },
65
+ {
66
+ "name": "cardPosition",
67
+ "type": "string",
68
+ "required": false,
69
+ "default": "bottom",
70
+ "description": "Position of hover card",
71
+ "options": [
72
+ "top",
73
+ "bottom"
74
+ ]
75
+ }
76
+ ],
77
+ "files": [
78
+ "component.jsx",
79
+ "index.js",
80
+ "meta.json"
81
+ ],
82
+ "customization": {
83
+ "styling_notes": "Avatar size is controlled via the 'size' prop. Hover card colors, shadow, and border radius can be customized via Tailwind classes in the component."
84
+ },
85
+ "accessibility": {
86
+ "features": [
87
+ "Hover card provides additional info",
88
+ "Alt text for image for screen readers",
89
+ "Keyboard focus not required but can be extended"
90
+ ]
91
+ }
92
+ }
@@ -0,0 +1,33 @@
1
+ // component.jsx
2
+ import PropTypes from "prop-types";
3
+
4
+ export default function Input({
5
+ type = "text",
6
+ placeholder = "",
7
+ value,
8
+ onChange,
9
+ className = "",
10
+ }) {
11
+ return (
12
+ <input
13
+ type={type}
14
+ placeholder={placeholder}
15
+ value={value}
16
+ onChange={onChange}
17
+ className={`px-3 py-2 rounded-md border outline-none
18
+ transition-all duration-200
19
+ border-gray-300 focus:border-gray-500
20
+ focus:ring-2 focus:ring-gray-300 focus:ring
21
+ ${className}`}
22
+ />
23
+ );
24
+ }
25
+
26
+ // PropTypes validation
27
+ Input.propTypes = {
28
+ type: PropTypes.string,
29
+ placeholder: PropTypes.string,
30
+ value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
31
+ onChange: PropTypes.func,
32
+ className: PropTypes.string,
33
+ };
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Input component barrel export
3
+ */
4
+ export { default } from "./component";
5
+ export { default as Input } from "./component";
@@ -0,0 +1,82 @@
1
+ {
2
+ "name": "Input",
3
+ "description": "A customizable input field component with glow effect on focus.",
4
+ "category": "form",
5
+ "tags": [
6
+ "input",
7
+ "form",
8
+ "field",
9
+ "text",
10
+ "tailwind",
11
+ "ui"
12
+ ],
13
+ "version": "1.0.0",
14
+ "author": "@rajdeep",
15
+ "created": "2025-08-30",
16
+ "dependencies": {
17
+ "npm": [],
18
+ "peer": [
19
+ "react",
20
+ "prop-types"
21
+ ]
22
+ },
23
+ "props": [
24
+ {
25
+ "name": "type",
26
+ "type": "string",
27
+ "required": false,
28
+ "default": "text",
29
+ "description": "The type of the input field",
30
+ "options": [
31
+ "text",
32
+ "email",
33
+ "password",
34
+ "number",
35
+ "url"
36
+ ]
37
+ },
38
+ {
39
+ "name": "placeholder",
40
+ "type": "string",
41
+ "required": false,
42
+ "default": "''",
43
+ "description": "Placeholder text shown when input is empty"
44
+ },
45
+ {
46
+ "name": "value",
47
+ "type": "string | number",
48
+ "required": false,
49
+ "default": "undefined",
50
+ "description": "The value of the input"
51
+ },
52
+ {
53
+ "name": "onChange",
54
+ "type": "function",
55
+ "required": false,
56
+ "default": "undefined",
57
+ "description": "Callback function triggered when input value changes"
58
+ },
59
+ {
60
+ "name": "className",
61
+ "type": "string",
62
+ "required": false,
63
+ "default": "''",
64
+ "description": "Custom Tailwind or CSS classes to style the input"
65
+ }
66
+ ],
67
+ "files": [
68
+ "component.jsx",
69
+ "index.js",
70
+ "meta.json"
71
+ ],
72
+ "customization": {
73
+ "styling_notes": "Input uses Tailwind classes for border, padding, and glow effect. Customize glow using focus:ring utilities."
74
+ },
75
+ "accessibility": {
76
+ "features": [
77
+ "Semantic <input> element",
78
+ "Supports keyboard navigation",
79
+ "Screen reader friendly with placeholder"
80
+ ]
81
+ }
82
+ }
@@ -1,92 +1,85 @@
1
- import React, { useState } from 'react';
2
- import PropTypes from 'prop-types';
1
+ import React from "react";
2
+ import PropTypes from "prop-types";
3
+ import clsx from "clsx";
3
4
 
4
- /**
5
- * A customizable button component with multiple variants and sizes + click animation
6
- */
7
5
  const Button = ({
8
- children,
9
- variant = 'primary',
10
- size = 'md',
11
- disabled = false,
12
- loading = false,
13
- className = '',
14
- onClick,
15
- type = 'button',
16
- ...rest
17
- }) => {
18
- const [isActive, setIsActive] = useState(false);
6
+ children,
7
+ size = "sm",
8
+ disabled = false,
9
+ loading = false,
10
+ className = "",
11
+ onClick,
12
+ type = "button",
13
+ borderColor = "white", // "white" or "black"
14
+ borderWidth = 1,
15
+ borderStyle = "solid",
16
+ borderRadius = "md", // sm, md, lg, xl, full
17
+ ...rest
18
+ }) => {
19
+ const sizeClasses = {
20
+ sm: "h-8 px-3 text-sm",
21
+ md: "h-10 px-4 text-sm",
22
+ lg: "h-12 px-5 text-base",
23
+ xl: "h-14 px-6 text-lg",
24
+ };
19
25
 
20
- const baseStyles = {
21
- display: 'inline-flex',
22
- alignItems: 'center',
23
- justifyContent: 'center',
24
- border: 'none',
25
- borderRadius: '6px',
26
- fontFamily: 'inherit',
27
- fontWeight: '500',
28
- cursor: disabled || loading ? 'not-allowed' : 'pointer',
29
- transition: 'all 0.15s ease-in-out',
30
- opacity: disabled || loading ? 0.6 : 1,
31
- transform: isActive ? 'scale(0.95)' : 'scale(1)', // 👈 shrink effect
32
- };
26
+ const radiusClasses = {
27
+ sm: "rounded-sm",
28
+ md: "rounded-md",
29
+ lg: "rounded-lg",
30
+ xl: "rounded-xl",
31
+ full: "rounded-full",
32
+ };
33
33
 
34
- const variantStyles = {
35
- primary: { backgroundColor: '#3b82f6', color: 'white' },
36
- secondary: { backgroundColor: '#f8fafc', color: '#374151', border: '1px solid #d1d5db' },
37
- destructive: { backgroundColor: '#dc2626', color: 'white' },
38
- outline: { backgroundColor: 'transparent', border: '1px solid #d1d5db', color: '#374151' },
39
- ghost: { backgroundColor: 'transparent', color: '#374151' },
40
- };
34
+ const borderClasses = clsx(
35
+ `border-${borderWidth}`,
36
+ borderStyle !== "solid" && `border-${borderStyle}`,
37
+ borderColor === "white" ? "border-white" : "border-black"
38
+ );
41
39
 
42
- const sizeStyles = {
43
- sm: { height: '32px', padding: '0 12px', fontSize: '14px' },
44
- md: { height: '40px', padding: '0 16px', fontSize: '14px' },
45
- lg: { height: '44px', padding: '0 24px', fontSize: '16px' },
46
- xl: { height: '52px', padding: '0 32px', fontSize: '16px' },
47
- };
40
+ const buttonClasses = clsx(
41
+ "inline-flex items-center justify-center font-medium",
42
+ "transition-transform duration-150 ease-in-out", // smooth animation
43
+ "active:scale-95", // 👈 shrink when clicked
44
+ borderClasses,
45
+ radiusClasses[borderRadius],
46
+ sizeClasses[size],
47
+ disabled || loading ? "opacity-60 cursor-not-allowed" : "cursor-pointer",
48
+ className
49
+ );
48
50
 
49
- const buttonStyles = {
50
- ...baseStyles,
51
- ...variantStyles[variant],
52
- ...sizeStyles[size],
53
- };
54
-
55
- const handleClick = (e) => {
56
- if (disabled || loading) {
57
- e.preventDefault();
58
- return;
59
- }
60
- setIsActive(true);
61
- setTimeout(() => setIsActive(false), 150); // reset after animation
62
- if (onClick) onClick(e);
63
- };
64
-
65
- return (
66
- <button
67
- type={type}
68
- disabled={disabled || loading}
69
- onClick={handleClick}
70
- className={className}
71
- style={buttonStyles}
72
- aria-disabled={disabled || loading}
73
- aria-busy={loading}
74
- {...rest}
75
- >
76
- {loading ? 'Loading...' : children}
77
- </button>
78
- );
51
+ return (
52
+ <button
53
+ type={type}
54
+ disabled={disabled || loading}
55
+ onClick={onClick}
56
+ className={buttonClasses}
57
+ {...rest}
58
+ >
59
+ {loading ? (
60
+ <span className="flex items-center gap-2">
61
+ <span className="w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin" />
62
+ Loading...
63
+ </span>
64
+ ) : (
65
+ children
66
+ )}
67
+ </button>
68
+ );
79
69
  };
80
70
 
81
71
  Button.propTypes = {
82
- children: PropTypes.node,
83
- variant: PropTypes.oneOf(['primary', 'secondary', 'destructive', 'outline', 'ghost']),
84
- size: PropTypes.oneOf(['sm', 'md', 'lg', 'xl']),
85
- disabled: PropTypes.bool,
86
- loading: PropTypes.bool,
87
- className: PropTypes.string,
88
- onClick: PropTypes.func,
89
- type: PropTypes.oneOf(['button', 'submit', 'reset']),
72
+ children: PropTypes.node,
73
+ size: PropTypes.oneOf(["sm", "md", "lg", "xl"]),
74
+ disabled: PropTypes.bool,
75
+ loading: PropTypes.bool,
76
+ className: PropTypes.string,
77
+ onClick: PropTypes.func,
78
+ type: PropTypes.oneOf(["button", "submit", "reset"]),
79
+ borderColor: PropTypes.oneOf(["black", "white"]),
80
+ borderWidth: PropTypes.number,
81
+ borderStyle: PropTypes.oneOf(["solid", "dashed", "dotted", "double"]),
82
+ borderRadius: PropTypes.oneOf(["sm", "md", "lg", "xl", "full"]),
90
83
  };
91
84
 
92
85
  export default Button;
@@ -1,2 +1,6 @@
1
- export { default } from './component';
2
- export { default as Button } from './component';
1
+ /**
2
+ * Button component barrel export
3
+ * This file allows importing the Button component cleanly
4
+ */
5
+ export { default } from "./component";
6
+ export { default as Button } from "./component";
@@ -1,28 +1,152 @@
1
1
  {
2
2
  "name": "Button",
3
- "description": "A customizable button component with multiple variants, sizes, and states.",
3
+ "description": "A customizable button component with size, border, radius, and click animation. Fully compatible with Tailwind CSS for background and text colors.",
4
4
  "category": "form",
5
- "tags": ["button", "interactive", "form", "cta"],
5
+ "tags": [
6
+ "button",
7
+ "interactive",
8
+ "form",
9
+ "cta",
10
+ "action",
11
+ "tailwind"
12
+ ],
6
13
  "version": "1.0.0",
14
+ "author": "@rajdeep",
15
+ "created": "2025-08-28",
7
16
  "dependencies": {
8
- "npm": [],
9
- "peer": ["react", "prop-types"]
17
+ "npm": [
18
+ "clsx"
19
+ ],
20
+ "peer": [
21
+ "react",
22
+ "prop-types"
23
+ ]
10
24
  },
11
25
  "props": [
12
- { "name": "children", "type": "React.ReactNode", "description": "Content inside the button" },
13
- { "name": "variant", "type": "string", "default": "primary", "options": ["primary","secondary","destructive","outline","ghost"] },
14
- { "name": "size", "type": "string", "default": "md", "options": ["sm","md","lg","xl"] },
15
- { "name": "disabled", "type": "boolean", "default": false, "description": "Disable button" },
16
- { "name": "loading", "type": "boolean", "default": false, "description": "Loading state" },
17
- { "name": "className", "type": "string", "description": "Extra CSS classes" },
18
- { "name": "onClick", "type": "function", "description": "Click handler" },
19
- { "name": "type", "type": "string", "default": "button", "options": ["button","submit","reset"] }
26
+ {
27
+ "name": "children",
28
+ "type": "React.ReactNode",
29
+ "required": false,
30
+ "default": "undefined",
31
+ "description": "The content to display inside the button"
32
+ },
33
+ {
34
+ "name": "size",
35
+ "type": "string",
36
+ "required": false,
37
+ "default": "sm",
38
+ "description": "The size of the button",
39
+ "options": [
40
+ "sm",
41
+ "md",
42
+ "lg",
43
+ "xl"
44
+ ]
45
+ },
46
+ {
47
+ "name": "disabled",
48
+ "type": "boolean",
49
+ "required": false,
50
+ "default": "false",
51
+ "description": "Whether the button is disabled and non-interactive"
52
+ },
53
+ {
54
+ "name": "loading",
55
+ "type": "boolean",
56
+ "required": false,
57
+ "default": "false",
58
+ "description": "Whether the button is in a loading state with spinner"
59
+ },
60
+ {
61
+ "name": "className",
62
+ "type": "string",
63
+ "required": false,
64
+ "default": "''",
65
+ "description": "Tailwind or custom classes to style background, text, hover, etc."
66
+ },
67
+ {
68
+ "name": "onClick",
69
+ "type": "function",
70
+ "required": false,
71
+ "default": "undefined",
72
+ "description": "Function to call when the button is clicked"
73
+ },
74
+ {
75
+ "name": "type",
76
+ "type": "string",
77
+ "required": false,
78
+ "default": "button",
79
+ "description": "The HTML button type attribute",
80
+ "options": [
81
+ "button",
82
+ "submit",
83
+ "reset"
84
+ ]
85
+ },
86
+ {
87
+ "name": "borderColor",
88
+ "type": "string",
89
+ "required": false,
90
+ "default": "white",
91
+ "description": "Border color of the button",
92
+ "options": [
93
+ "black",
94
+ "white"
95
+ ]
96
+ },
97
+ {
98
+ "name": "borderWidth",
99
+ "type": "number",
100
+ "required": false,
101
+ "default": "1",
102
+ "description": "Border thickness of the button"
103
+ },
104
+ {
105
+ "name": "borderStyle",
106
+ "type": "string",
107
+ "required": false,
108
+ "default": "solid",
109
+ "description": "Border style of the button",
110
+ "options": [
111
+ "solid",
112
+ "dashed",
113
+ "dotted",
114
+ "double"
115
+ ]
116
+ },
117
+ {
118
+ "name": "borderRadius",
119
+ "type": "string",
120
+ "required": false,
121
+ "default": "md",
122
+ "description": "Border radius for rounded corners",
123
+ "options": [
124
+ "sm",
125
+ "md",
126
+ "lg",
127
+ "xl",
128
+ "full"
129
+ ]
130
+ }
20
131
  ],
21
- "examples": [
22
- { "name": "Basic", "code": "<Button>Click Me</Button>" },
23
- { "name": "Variants", "code": "<><Button variant='primary'>Primary</Button><Button variant='secondary'>Secondary</Button></>" },
24
- { "name": "Sizes", "code": "<><Button size='sm'>Small</Button><Button size='lg'>Large</Button></>" },
25
- { "name": "Loading", "code": "<Button loading>Loading...</Button>" }
132
+ "files": [
133
+ "component.jsx",
134
+ "index.js",
135
+ "meta.json"
26
136
  ],
27
- "files": ["component.jsx", "index.js"]
137
+ "customization": {
138
+ "css_variables": [
139
+ "--button-border-radius",
140
+ "--button-transition"
141
+ ],
142
+ "styling_notes": "Background and text colors are meant to be customized using Tailwind classes via className. Borders and radius are controlled via props."
143
+ },
144
+ "accessibility": {
145
+ "features": [
146
+ "Keyboard navigation support",
147
+ "Screen reader friendly with aria-disabled and aria-busy",
148
+ "Focus visible outline",
149
+ "Semantic <button> element"
150
+ ]
151
+ }
28
152
  }