@dennerrondinely/tailor
v0.1.0
Published
A library for creating styled React components with Tailwind CSS in an organized and typed way
Maintainers
Readme
Features
- 🎨 Type-safe styling with TypeScript
- 🎯 Smart class merging
- 📱 Responsive design support
- 🎭 Dynamic class generation based on props
- 🎪 Nested styles
- 🎬 Animation support
Installation
npm install @tailor/react
# or
yarn add @tailor/react
# or
pnpm add @tailor/reactQuick Start
Basic Component
import { craft } from '@tailor/react';
interface ButtonProps {
isActive?: boolean;
disabled?: boolean;
children: React.ReactNode;
}
const Button: React.FC<ButtonProps> = ({ children, ...props }) => (
<button {...props}>{children}</button>
);
const StyledButton = craft(Button)({
base: 'px-4 py-2 rounded font-medium transition-colors',
dynamic: {
'bg-blue-500 text-white': (props) => !props.isActive,
'bg-green-500 text-white': (props) => props.isActive,
'hover:opacity-90': (props) => !props.disabled,
'active:scale-95': (props) => !props.disabled,
'disabled:opacity-50 disabled:cursor-not-allowed': (props) => props.disabled
},
responsive: {
sm: 'text-sm',
md: 'text-base',
lg: 'text-lg'
}
});
// Usage
<StyledButton isActive={true}>Click me</StyledButton>Using Dynamic Classes
Dynamic classes allow you to apply styles based on component props. This is particularly useful for managing component states and variants:
interface DynamicButtonProps {
isActive?: boolean;
disabled?: boolean;
isPressed?: boolean;
children: React.ReactNode;
}
const DynamicButton: React.FC<DynamicButtonProps> = ({ children, ...props }) => (
<button {...props}>{children}</button>
);
const StyledDynamicButton = craft(DynamicButton)({
base: 'px-4 py-2 rounded font-medium transition-all',
dynamic: {
// Base styles based on active state
'bg-blue-500 text-white': (props) => !props.isActive,
'bg-green-500 text-white': (props) => props.isActive,
// Interactive states
'hover:opacity-90': (props) => !props.disabled,
'active:scale-95': (props) => !props.disabled,
// Disabled state
'disabled:opacity-50 disabled:cursor-not-allowed': (props) => props.disabled,
// Additional states
'shadow-lg': (props) => props.isPressed
}
});
// Usage examples
<StyledDynamicButton>Default</StyledDynamicButton>
<StyledDynamicButton isActive>Active</StyledDynamicButton>
<StyledDynamicButton disabled>Disabled</StyledDynamicButton>
<StyledDynamicButton isPressed>Pressed</StyledDynamicButton>Advanced Example with Multiple Conditions
Here's a more complex example showing how to combine multiple conditions and features:
interface StatusCardProps {
status: 'success' | 'error' | 'warning' | 'info';
size?: 'small' | 'medium' | 'large';
disabled?: boolean;
loading?: boolean;
children: React.ReactNode;
}
const StatusCard: React.FC<StatusCardProps> = ({ children, ...props }) => (
<div {...props}>{children}</div>
);
const StyledStatusCard = craft(StatusCard)({
base: 'p-4 rounded-lg shadow transition-all',
dynamic: {
// Status-based styles
'bg-green-100 text-green-800 border-green-200': (props) => props.status === 'success',
'bg-red-100 text-red-800 border-red-200': (props) => props.status === 'error',
'bg-yellow-100 text-yellow-800 border-yellow-200': (props) => props.status === 'warning',
'bg-blue-100 text-blue-800 border-blue-200': (props) => props.status === 'info',
// Size-based styles
'p-2 text-sm': (props) => props.size === 'small',
'p-6 text-lg': (props) => props.size === 'large',
// State-based styles
'opacity-50 cursor-not-allowed': (props) => props.disabled,
'animate-pulse': (props) => props.loading
},
responsive: {
sm: 'text-sm',
md: 'text-base',
lg: 'text-lg'
},
nested: {
'.status-icon': 'mr-2',
'.status-title': 'font-bold mb-1',
'.status-description': 'text-sm opacity-80'
}
});
// Usage examples
<StyledStatusCard status="success" size="small">Success</StyledStatusCard>
<StyledStatusCard status="error" loading>Error</StyledStatusCard>
<StyledStatusCard status="warning" disabled>Warning</StyledStatusCard>
<StyledStatusCard status="info" size="large">Info</StyledStatusCard>Themed Components
You can also use dynamic classes to create themed components:
interface ThemedButtonProps {
theme: 'light' | 'dark';
variant: 'default' | 'primary' | 'success' | 'danger';
disabled?: boolean;
loading?: boolean;
children: React.ReactNode;
}
const ThemedButton: React.FC<ThemedButtonProps> = ({ children, ...props }) => (
<button {...props}>{children}</button>
);
const StyledThemedButton = craft(ThemedButton)({
base: 'px-4 py-2 rounded font-medium transition-all',
dynamic: {
// Light theme variants
'bg-gray-100 text-gray-900 border border-gray-300': (props) =>
props.theme === 'light' && props.variant === 'default',
'bg-blue-100 text-blue-900 border border-blue-300': (props) =>
props.theme === 'light' && props.variant === 'primary',
'bg-green-100 text-green-900 border border-green-300': (props) =>
props.theme === 'light' && props.variant === 'success',
'bg-red-100 text-red-900 border border-red-300': (props) =>
props.theme === 'light' && props.variant === 'danger',
// Dark theme variants
'bg-gray-800 text-gray-100 border border-gray-700': (props) =>
props.theme === 'dark' && props.variant === 'default',
'bg-blue-800 text-blue-100 border border-blue-700': (props) =>
props.theme === 'dark' && props.variant === 'primary',
'bg-green-800 text-green-100 border border-green-700': (props) =>
props.theme === 'dark' && props.variant === 'success',
'bg-red-800 text-red-100 border border-red-700': (props) =>
props.theme === 'dark' && props.variant === 'danger',
// Interactive states
'hover:opacity-90': (props) => !props.disabled && !props.loading,
'active:scale-95': (props) => !props.disabled && !props.loading,
'disabled:opacity-50 disabled:cursor-not-allowed': (props) => props.disabled,
'animate-pulse': (props) => props.loading
}
});
// Usage examples
<StyledThemedButton theme="light" variant="primary">Light Primary</StyledThemedButton>
<StyledThemedButton theme="dark" variant="success">Dark Success</StyledThemedButton>
<StyledThemedButton theme="light" variant="danger" disabled>Light Danger Disabled</StyledThemedButton>
<StyledThemedButton theme="dark" variant="default" loading>Dark Default Loading</StyledThemedButton>API Reference
craft(Component)
Creates a styled version of a React component with Tailwind CSS classes.
Configuration
The craft function accepts a configuration object with the following properties:
base: Base classes applied to the componentdynamic: Object mapping class names to functions that receive props and return boolean valuesresponsive: Object mapping breakpoint names to class namesnested: Object mapping selectors to class names for nested elementsanimation: Object mapping animation names to class names
🎯 TypeScript Support
The library is fully typed and provides autocompletion for all available properties.
🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
📄 License
MIT
