UNPKG

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
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