simple-react-ui-kits
Version:
A lightweight, customizable React UI component library built with TypeScript and Tailwind CSS
224 lines (214 loc) • 10.2 kB
JavaScript
import React, { useState, useCallback } from 'react';
/**
* Utility function to combine class names
* @param classes - Array of class names or objects with conditional classes
* @returns Combined class string
*/
function cn(...classes) {
return classes
.filter(Boolean)
.map((cls) => {
if (typeof cls === 'string')
return cls;
if (typeof cls === 'object' && cls !== null && !Array.isArray(cls)) {
return Object.entries(cls)
.filter(([, value]) => value)
.map(([key]) => key)
.join(' ');
}
return '';
})
.join(' ')
.trim();
}
const buttonVariants = {
primary: 'bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500',
secondary: 'bg-gray-600 text-white hover:bg-gray-700 focus:ring-gray-500',
outline: 'border border-gray-300 text-gray-700 hover:bg-gray-50 focus:ring-gray-500',
ghost: 'text-gray-700 hover:bg-gray-100 focus:ring-gray-500',
danger: 'bg-red-600 text-white hover:bg-red-700 focus:ring-red-500',
};
const buttonSizes = {
sm: 'px-3 py-1.5 text-sm',
md: 'px-4 py-2 text-base',
lg: 'px-6 py-3 text-lg',
};
const buttonRadius = {
none: 'rounded-none',
sm: 'rounded-sm',
md: 'rounded-md',
lg: 'rounded-lg',
xl: 'rounded-xl',
full: 'rounded-full',
};
const Button = ({ variant = 'primary', size = 'md', loading = false, radius = 'md', disabled, className, children, ...props }) => {
return (React.createElement("button", { className: cn('inline-flex items-center justify-center font-medium transition-colors', 'focus:outline-none focus:ring-2 focus:ring-offset-2', 'disabled:opacity-50 disabled:cursor-not-allowed', buttonVariants[variant], buttonSizes[size], buttonRadius[radius], className), disabled: disabled || loading, ...props },
loading && (React.createElement("svg", { className: "animate-spin -ml-1 mr-2 h-4 w-4", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24" },
React.createElement("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
React.createElement("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" }))),
children));
};
const Input = ({ label, error, helperText, leftIcon, rightIcon, radius = 'md', size = 'md', className, id, ...props }) => {
const inputId = id || `input-${Math.random().toString(36).substr(2, 9)}`;
const inputRadius = {
none: 'rounded-none',
sm: 'rounded-sm',
md: 'rounded-md',
lg: 'rounded-lg',
xl: 'rounded-xl',
full: 'rounded-full',
};
const inputSizes = {
sm: 'px-3 py-2 text-sm',
md: 'px-4 py-3 text-base',
lg: 'px-5 py-4 text-lg',
};
const iconSizes = {
sm: 'h-4 w-4',
md: 'h-5 w-5',
lg: 'h-6 w-6',
};
return (React.createElement("div", { className: "w-full" },
label && (React.createElement("label", { htmlFor: inputId, className: "block text-sm font-semibold text-gray-700 mb-2" }, label)),
React.createElement("div", { className: "relative" },
leftIcon && (React.createElement("div", { className: "absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none" },
React.createElement("div", { className: `${iconSizes[size]} text-gray-400` }, leftIcon))),
React.createElement("input", { id: inputId, className: cn('block w-full border border-gray-300 bg-white', inputRadius[radius], inputSizes[size], 'text-gray-900 placeholder-gray-500', 'focus:outline-none focus:ring-2 focus:ring-offset-0 focus:border-blue-500 focus:ring-blue-500', 'transition-all duration-200 ease-in-out', 'disabled:bg-gray-50 disabled:text-gray-500 disabled:cursor-not-allowed', 'hover:border-gray-400', error && 'border-red-300 text-red-900 placeholder-red-300 focus:border-red-500 focus:ring-red-500', leftIcon ? 'pl-10' : '', rightIcon ? 'pr-10' : '', className), ...props }),
rightIcon && (React.createElement("div", { className: "absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none" },
React.createElement("div", { className: `${iconSizes[size]} text-gray-400` }, rightIcon)))),
error && (React.createElement("p", { className: "mt-2 text-sm text-red-600 flex items-center" },
React.createElement("svg", { className: "w-4 h-4 mr-1", fill: "currentColor", viewBox: "0 0 20 20" },
React.createElement("path", { fillRule: "evenodd", d: "M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z", clipRule: "evenodd" })),
error)),
helperText && !error && (React.createElement("p", { className: "mt-2 text-sm text-gray-500 flex items-center" },
React.createElement("svg", { className: "w-4 h-4 mr-1", fill: "currentColor", viewBox: "0 0 20 20" },
React.createElement("path", { fillRule: "evenodd", d: "M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z", clipRule: "evenodd" })),
helperText))));
};
const Card = ({ className, children, ...props }) => {
return (React.createElement("div", { className: cn('bg-white rounded-lg shadow-sm border border-gray-200', className), ...props }, children));
};
const CardHeader = ({ className, children, ...props }) => {
return (React.createElement("div", { className: cn('px-6 py-4 border-b border-gray-200', className), ...props }, children));
};
const CardBody = ({ className, children, ...props }) => {
return (React.createElement("div", { className: cn('px-6 py-4', className), ...props }, children));
};
const CardFooter = ({ className, children, ...props }) => {
return (React.createElement("div", { className: cn('px-6 py-4 border-t border-gray-200 bg-gray-50', className), ...props }, children));
};
const badgeVariants = {
default: 'bg-gray-100 text-gray-800',
primary: 'bg-blue-100 text-blue-800',
secondary: 'bg-gray-100 text-gray-800',
success: 'bg-green-100 text-green-800',
warning: 'bg-yellow-100 text-yellow-800',
danger: 'bg-red-100 text-red-800',
};
const badgeSizes = {
sm: 'px-2 py-0.5 text-xs',
md: 'px-2.5 py-0.5 text-sm',
lg: 'px-3 py-1 text-base',
};
const Badge = ({ variant = 'default', size = 'md', leftIcon, rightIcon, className, children, ...props }) => {
const iconSizes = {
sm: 'h-3 w-3',
md: 'h-4 w-4',
lg: 'h-5 w-5',
};
return (React.createElement("span", { className: cn('inline-flex items-center rounded-full font-medium', badgeVariants[variant], badgeSizes[size], className), ...props },
leftIcon && (React.createElement("span", { className: `mr-1 ${iconSizes[size]}` }, leftIcon)),
children,
rightIcon && (React.createElement("span", { className: `ml-1 ${iconSizes[size]}` }, rightIcon))));
};
/**
* Custom hook for toggle functionality
* @param initialValue - Initial toggle state
* @returns [state, toggle, setState] - Current state, toggle function, and setter
*/
function useToggle(initialValue = false) {
const [state, setState] = useState(initialValue);
const toggle = useCallback(() => {
setState(prev => !prev);
}, []);
return [state, toggle, setState];
}
/**
* Custom hook for localStorage functionality
* @param key - localStorage key
* @param initialValue - Initial value if key doesn't exist
* @returns [storedValue, setValue] - Current value and setter function
*/
function useLocalStorage(key, initialValue) {
// Get from local storage then parse stored json or return initialValue
const [storedValue, setStoredValue] = useState(() => {
if (typeof window === 'undefined') {
return initialValue;
}
try {
const item = window.localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
}
catch (error) {
console.error(`Error reading localStorage key "${key}":`, error);
return initialValue;
}
});
// Return a wrapped version of useState's setter function that persists the new value to localStorage
const setValue = (value) => {
try {
// Allow value to be a function so we have the same API as useState
const valueToStore = value instanceof Function ? value(storedValue) : value;
setStoredValue(valueToStore);
// Save to local storage
if (typeof window !== 'undefined') {
window.localStorage.setItem(key, JSON.stringify(valueToStore));
}
}
catch (error) {
console.error(`Error setting localStorage key "${key}":`, error);
}
};
return [storedValue, setValue];
}
/**
* Format a number with commas
* @param num - Number to format
* @returns Formatted number string
*/
function formatNumber(num) {
return num.toLocaleString();
}
/**
* Format a date to a readable string
* @param date - Date to format
* @returns Formatted date string
*/
function formatDate(date) {
return date.toLocaleDateString();
}
/**
* Format currency
* @param amount - Amount to format
* @param currency - Currency code (default: USD)
* @returns Formatted currency string
*/
function formatCurrency(amount, currency = 'USD') {
return new Intl.NumberFormat('en-US', {
style: 'currency',
currency,
}).format(amount);
}
/**
* Truncate text to a specified length
* @param text - Text to truncate
* @param maxLength - Maximum length
* @returns Truncated text
*/
function truncateText(text, maxLength) {
if (text.length <= maxLength)
return text;
return text.slice(0, maxLength) + '...';
}
export { Badge, Button, Card, CardBody, CardFooter, CardHeader, Input, cn, formatCurrency, formatDate, formatNumber, truncateText, useLocalStorage, useToggle };
//# sourceMappingURL=index.esm.js.map