tw-combine
v1.0.0
Published
A utility function that combines clsx and tailwind-merge for optimal Tailwind CSS class merging
Downloads
19
Maintainers
Readme
tw-combine
Uma utility function que combina clsx e tailwind-merge para uma mesclagem otimizada de classes Tailwind CSS.
🚀 Características
- ✅ Combina clsx e tailwind-merge - Melhor dos dois mundos
- ✅ Resolve conflitos automaticamente - Remove classes conflitantes do Tailwind
- ✅ Suporte completo ao TypeScript - Tipagem forte e IntelliSense
- ✅ Bundle pequeno - Apenas ~2KB gzipped
- ✅ Zero dependências - Apenas clsx e tailwind-merge como peer dependencies
- ✅ Compatível com todos os frameworks - React, Vue, Svelte, etc.
📦 Instalação
npm install tw-combine clsx tailwind-mergeyarn add tw-combine clsx tailwind-mergepnpm add tw-combine clsx tailwind-merge🎯 Uso Básico
import { twCombine } from 'tw-combine';
// Combinação simples
twCombine('px-4 py-2', 'bg-blue-500', 'text-white');
// Resultado: 'px-4 py-2 bg-blue-500 text-white'
// Classes condicionais
const isActive = true;
twCombine('px-4', { 'bg-blue-500': isActive }, { 'bg-gray-500': !isActive });
// Resultado: 'px-4 bg-blue-500'
// Resolução de conflitos
twCombine('px-4 px-6', 'py-2 py-4');
// Resultado: 'px-6 py-4' (conflitos resolvidos automaticamente)🔧 Exemplos Avançados
Componente React
import { twCombine } from 'tw-combine';
interface ButtonProps {
variant?: 'primary' | 'secondary';
size?: 'sm' | 'md' | 'lg';
disabled?: boolean;
className?: string;
}
const Button: React.FC<ButtonProps> = ({
variant = 'primary',
size = 'md',
disabled = false,
className,
children
}) => {
return (
<button
className={twCombine(
// Classes base
'px-4 py-2 rounded font-medium transition-colors',
// Variantes
{
'bg-blue-500 text-white hover:bg-blue-600': variant === 'primary',
'bg-gray-200 text-gray-900 hover:bg-gray-300': variant === 'secondary',
},
// Tamanhos
{
'px-2 py-1 text-sm': size === 'sm',
'px-4 py-2 text-base': size === 'md',
'px-6 py-3 text-lg': size === 'lg',
},
// Estados
{
'opacity-50 cursor-not-allowed': disabled,
'cursor-pointer': !disabled,
},
// Classes customizadas
className
)}
disabled={disabled}
>
{children}
</button>
);
};Componente Vue
<template>
<button :class="buttonClasses">
<slot />
</button>
</template>
<script setup lang="ts">
import { computed } from 'vue';
import { twCombine } from 'tw-combine';
interface Props {
variant?: 'primary' | 'secondary';
size?: 'sm' | 'md' | 'lg';
disabled?: boolean;
className?: string;
}
const props = withDefaults(defineProps<Props>(), {
variant: 'primary',
size: 'md',
disabled: false,
});
const buttonClasses = computed(() =>
twCombine(
'px-4 py-2 rounded font-medium transition-colors',
{
'bg-blue-500 text-white hover:bg-blue-600': props.variant === 'primary',
'bg-gray-200 text-gray-900 hover:bg-gray-300': props.variant === 'secondary',
},
{
'px-2 py-1 text-sm': props.size === 'sm',
'px-4 py-2 text-base': props.size === 'md',
'px-6 py-3 text-lg': props.size === 'lg',
},
{
'opacity-50 cursor-not-allowed': props.disabled,
'cursor-pointer': !props.disabled,
},
props.className
)
);
</script>Componente Svelte
<script lang="ts">
import { twCombine } from 'tw-combine';
export let variant: 'primary' | 'secondary' = 'primary';
export let size: 'sm' | 'md' | 'lg' = 'md';
export let disabled: boolean = false;
export let className: string = '';
$: buttonClasses = twCombine(
'px-4 py-2 rounded font-medium transition-colors',
{
'bg-blue-500 text-white hover:bg-blue-600': variant === 'primary',
'bg-gray-200 text-gray-900 hover:bg-gray-300': variant === 'secondary',
},
{
'px-2 py-1 text-sm': size === 'sm',
'px-4 py-2 text-base': size === 'md',
'px-6 py-3 text-lg': size === 'lg',
},
{
'opacity-50 cursor-not-allowed': disabled,
'cursor-pointer': !disabled,
},
className
);
</script>
<button class={buttonClasses} {disabled}>
<slot />
</button>🎨 Casos de Uso Comuns
Cards Responsivos
const cardClasses = twCombine(
'bg-white rounded-lg shadow-md p-6',
'hover:shadow-lg transition-shadow',
{
'border-l-4 border-blue-500': isHighlighted,
'border-l-4 border-gray-300': !isHighlighted,
},
{
'p-4': size === 'sm',
'p-6': size === 'md',
'p-8': size === 'lg',
}
);Navegação com Estados Ativos
const navItemClasses = (isActive: boolean) => twCombine(
'px-4 py-2 rounded-md transition-colors',
{
'bg-blue-100 text-blue-700 font-semibold': isActive,
'text-gray-600 hover:bg-gray-100 hover:text-gray-900': !isActive,
}
);Formulários com Validação
const inputClasses = (hasError: boolean, isDisabled: boolean) => twCombine(
'w-full px-3 py-2 border rounded-md transition-colors',
{
'border-red-300 focus:border-red-500 focus:ring-red-500': hasError,
'border-gray-300 focus:border-blue-500 focus:ring-blue-500': !hasError,
},
{
'opacity-50 cursor-not-allowed': isDisabled,
'cursor-text': !isDisabled,
}
);🔍 Como Funciona
O tw-combine funciona em duas etapas:
- clsx - Combina e filtra classes condicionais, removendo valores falsy
- tailwind-merge - Resolve conflitos entre classes do Tailwind CSS
// Exemplo do processo interno
const classes = ['px-4', 'px-6', { 'py-2': true }, { 'py-4': false }];
// 1. clsx processa as classes
const clsxResult = clsx(...classes); // 'px-4 px-6 py-2'
// 2. tailwind-merge resolve conflitos
const finalResult = twMerge(clsxResult); // 'px-6 py-2'📚 API
twCombine(...classes)
Combina classes CSS usando clsx e resolve conflitos com tailwind-merge.
Parâmetros:
...classes- Array de strings, objetos condicionais, ou valores undefined/null
Retorna:
string- String de classes combinadas e otimizadas
Tipos:
type ClassValue = string | boolean | undefined | null;
type ClassObject = Record<string, boolean | undefined | null>;
function twCombine(...classes: (ClassValue | ClassObject)[]): string;🧪 Testes
npm testnpm run test:watch🛠️ Desenvolvimento
# Instalar dependências
npm install
# Modo desenvolvimento
npm run dev
# Build
npm run build
# Lint
npm run lint
# Type check
npm run type-check📄 Licença
MIT © adachidev
🤝 Contribuição
Contribuições são bem-vindas! Por favor, abra uma issue ou pull request.
🔗 Links Relacionados
- clsx - Utility for constructing className strings
- tailwind-merge - Merge Tailwind CSS classes without style conflicts
- Tailwind CSS - A utility-first CSS framework
